mirror of
https://github.com/eliboa/TegraRcmGUI.git
synced 2024-11-25 03:32:05 +00:00
830 lines
19 KiB
C
830 lines
19 KiB
C
/*
|
|
* Copyright (c) 2011, NVIDIA CORPORATION
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution.
|
|
* * Neither the name of NVIDIA CORPORATION nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
|
|
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/param.h>
|
|
#include <errno.h>
|
|
|
|
#include "nv3p.h"
|
|
#include "usb.h"
|
|
#include "debug.h"
|
|
|
|
/* nv3p command packet format */
|
|
/*|------------32 bits--------------|*/
|
|
/*************************************/
|
|
/* NV3P_VERSION */
|
|
/*-----------------------------------*/
|
|
/* NV3P_PACKET_TYPE_CMD */
|
|
/*-----------------------------------*/
|
|
/* sequence no */
|
|
/*-----------------------------------*/
|
|
/* length of command arguments */
|
|
/*-----------------------------------*/
|
|
/* command, one of: */
|
|
/* NV3P_CMD_GET_PLATFORM_INFO */
|
|
/* NV3P_CMD_DL_BCT */
|
|
/* NV3P_CMD_DL_BL */
|
|
/* NV3P_CMD_STATUS */
|
|
/*-----------------------------------*/
|
|
/* command arguments */
|
|
/* . */
|
|
/* . */
|
|
/* . */
|
|
/*-----------------------------------*/
|
|
/* checksum */
|
|
/*-----------------------------------*/
|
|
|
|
/* nv3p ack packet format */
|
|
/*|------------32 bits--------------|*/
|
|
/*************************************/
|
|
/* NV3P_VERSION */
|
|
/*-----------------------------------*/
|
|
/* NV3P_PACKET_TYPE_ACK */
|
|
/*-----------------------------------*/
|
|
/* sequence no */
|
|
/*-----------------------------------*/
|
|
/* checksum */
|
|
/*-----------------------------------*/
|
|
|
|
/* nv3p nack packet format */
|
|
/*|------------32 bits--------------|*/
|
|
/*************************************/
|
|
/* NV3P_VERSION */
|
|
/*-----------------------------------*/
|
|
/* NV3P_PACKET_TYPE_NACK */
|
|
/*-----------------------------------*/
|
|
/* sequence no */
|
|
/*-----------------------------------*/
|
|
/* nack code */
|
|
/*-----------------------------------*/
|
|
/* checksum */
|
|
/*-----------------------------------*/
|
|
|
|
/* nv3p data packet format */
|
|
/*|------------32 bits--------------|*/
|
|
/*************************************/
|
|
/* NV3P_VERSION */
|
|
/*-----------------------------------*/
|
|
/* NV3P_PACKET_TYPE_DATA */
|
|
/*-----------------------------------*/
|
|
/* sequence no */
|
|
/*-----------------------------------*/
|
|
/* length of data */
|
|
/*-----------------------------------*/
|
|
/* data */
|
|
/* . */
|
|
/* . */
|
|
/* . */
|
|
/*-----------------------------------*/
|
|
/* checksum */
|
|
/*-----------------------------------*/
|
|
|
|
typedef struct nv3p_state {
|
|
usb_device_t *usb;
|
|
uint32_t sequence;
|
|
uint32_t recv_sequence;
|
|
|
|
// for partial reads
|
|
uint32_t bytes_remaining;
|
|
uint32_t recv_checksum;
|
|
|
|
// the last nack code
|
|
uint32_t last_nack;
|
|
} nv3p_state_t;
|
|
|
|
/*
|
|
* double the currently-largest command size, just to have some wiggle-room
|
|
* (updates to commands without fixing this on accident, etc.)
|
|
*/
|
|
#define NV3P_MAX_COMMAND_SIZE (2 << 12)
|
|
|
|
#define NV3P_MAX_ACK_SIZE \
|
|
NV3P_PACKET_SIZE_BASIC + \
|
|
NV3P_PACKET_SIZE_NACK + \
|
|
NV3P_PACKET_SIZE_FOOTER
|
|
|
|
unsigned char s_buffer[NV3P_MAX_COMMAND_SIZE];
|
|
unsigned char s_args[NV3P_MAX_COMMAND_SIZE]; // handed out to clients
|
|
|
|
#define WRITE64( packet, data ) \
|
|
do { \
|
|
(packet)[0] = (uint8_t)((uint64_t)(data)) & 0xff; \
|
|
(packet)[1] = (uint8_t)(((uint64_t)(data)) >> 8) & 0xff; \
|
|
(packet)[2] = (uint8_t)(((uint64_t)(data)) >> 16) & 0xff; \
|
|
(packet)[3] = (uint8_t)(((uint64_t)(data)) >> 24) & 0xff; \
|
|
(packet)[4] = (uint8_t)(((uint64_t)(data)) >> 32) & 0xff; \
|
|
(packet)[5] = (uint8_t)(((uint64_t)(data)) >> 40) & 0xff; \
|
|
(packet)[6] = (uint8_t)(((uint64_t)(data)) >> 48) & 0xff; \
|
|
(packet)[7] = (uint8_t)(((uint64_t)(data)) >> 56) & 0xff; \
|
|
(packet) += 8; \
|
|
} while( 0 )
|
|
|
|
#define WRITE32( packet, data ) \
|
|
do { \
|
|
(packet)[0] = (data) & 0xff; \
|
|
(packet)[1] = ((data) >> 8) & 0xff; \
|
|
(packet)[2] = ((data) >> 16) & 0xff; \
|
|
(packet)[3] = ((data) >> 24) & 0xff; \
|
|
(packet) += 4; \
|
|
} while( 0 )
|
|
|
|
#define WRITE8( packet, data ) \
|
|
do { \
|
|
(packet)[0] = (data) & 0xff; \
|
|
(packet) += 1; \
|
|
} while( 0 )
|
|
|
|
#define READ64( packet, data ) \
|
|
do { \
|
|
(data) = (uint64_t)((packet)[0] \
|
|
| ((uint64_t)((packet)[1]) << 8) \
|
|
| ((uint64_t)((packet)[2]) << 16) \
|
|
| ((uint64_t)((packet)[3]) << 24) \
|
|
| ((uint64_t)((packet)[4]) << 32) \
|
|
| ((uint64_t)((packet)[5]) << 40) \
|
|
| ((uint64_t)((packet)[6]) << 48) \
|
|
| ((uint64_t)((packet)[7]) << 56)); \
|
|
(packet) += 8; \
|
|
} while( 0 )
|
|
|
|
#define READ32( packet, data ) \
|
|
do { \
|
|
(data) = (uint32_t)((packet)[0] \
|
|
| (((packet)[1]) << 8) \
|
|
| (((packet)[2]) << 16) \
|
|
| (((packet)[3]) << 24)); \
|
|
(packet) += 4; \
|
|
} while( 0 )
|
|
|
|
|
|
#define READ8( packet, data ) \
|
|
do { \
|
|
(data) = (packet)[0]; \
|
|
(packet) += 1; \
|
|
} while( 0 )
|
|
|
|
// header structures for fun
|
|
typedef struct {
|
|
uint32_t version;
|
|
uint32_t packet_type;
|
|
uint32_t sequence;
|
|
} nv3p_header_t;
|
|
|
|
static void nv3p_write_header(uint32_t type, uint32_t sequence, uint8_t *packet);
|
|
static void nv3p_write_footer(uint32_t checksum, uint8_t *packet);
|
|
static uint32_t nv3p_cksum(uint8_t *packet, uint32_t length);
|
|
static void nv3p_write_cmd(nv3p_handle_t h3p, uint32_t command, void *args,
|
|
uint32_t *length, uint8_t *packet );
|
|
static int nv3p_wait_ack(nv3p_handle_t h3p);
|
|
static int nv3p_get_cmd_return(nv3p_handle_t h3p, uint32_t command, void *args);
|
|
|
|
static int nv3p_recv_hdr(nv3p_handle_t h3p, nv3p_header_t *hdr,
|
|
uint32_t *checksum );
|
|
static int nv3p_drain_packet(nv3p_handle_t h3p, nv3p_header_t *hdr );
|
|
static void nv3p_nack(nv3p_handle_t h3p, uint32_t code);
|
|
static int nv3p_read(usb_device_t *usb, uint8_t *buf, int len);
|
|
static int nv3p_get_args(nv3p_handle_t h3p, uint32_t command, void **args,
|
|
uint8_t *packet );
|
|
|
|
static void nv3p_write_header(uint32_t type, uint32_t sequence, uint8_t *packet)
|
|
{
|
|
WRITE32(packet, NV3P_VERSION);
|
|
WRITE32(packet, type);
|
|
WRITE32(packet, sequence);
|
|
}
|
|
|
|
static void nv3p_write_footer(uint32_t checksum, uint8_t *packet)
|
|
{
|
|
WRITE32(packet, checksum);
|
|
}
|
|
|
|
/*
|
|
* Just sum the bits. Don't get two's compliment
|
|
*/
|
|
static uint32_t nv3p_cksum(uint8_t *packet, uint32_t length)
|
|
{
|
|
uint32_t i;
|
|
uint32_t sum;
|
|
|
|
sum = 0;
|
|
for (i = 0; i < length; i++) {
|
|
sum += *packet;
|
|
packet++;
|
|
}
|
|
|
|
return sum;
|
|
}
|
|
|
|
int nv3p_open(nv3p_handle_t *h3p, usb_device_t *usb)
|
|
{
|
|
nv3p_state_t *state;
|
|
|
|
state = (nv3p_state_t *)malloc(sizeof(nv3p_state_t));
|
|
if (!state) {
|
|
return ENOMEM;
|
|
}
|
|
memset(state, 0, sizeof(nv3p_state_t));
|
|
state->last_nack = NV3P_NACK_SUCCESS;
|
|
|
|
state->usb = usb;
|
|
|
|
*h3p = state;
|
|
return 0;
|
|
}
|
|
|
|
void nv3p_close(nv3p_handle_t h3p)
|
|
{
|
|
if (h3p)
|
|
free(h3p);
|
|
}
|
|
|
|
int nv3p_cmd_send(nv3p_handle_t h3p, uint32_t command, void *args)
|
|
{
|
|
uint32_t checksum;
|
|
uint32_t length = 0;
|
|
uint8_t *packet;
|
|
uint8_t *tmp;
|
|
int ret = 0;
|
|
|
|
packet = &s_buffer[0];
|
|
|
|
nv3p_write_header(NV3P_PACKET_TYPE_CMD, h3p->sequence, packet);
|
|
|
|
tmp = packet + NV3P_PACKET_SIZE_BASIC;
|
|
nv3p_write_cmd(h3p, command, args, &length, tmp);
|
|
|
|
length += NV3P_PACKET_SIZE_BASIC;
|
|
length += NV3P_PACKET_SIZE_COMMAND;
|
|
|
|
checksum = nv3p_cksum(packet, length);
|
|
checksum = ~checksum + 1;
|
|
tmp = packet + length;
|
|
nv3p_write_footer(checksum, tmp);
|
|
|
|
length += NV3P_PACKET_SIZE_FOOTER;
|
|
|
|
// send the packet
|
|
ret = usb_write(h3p->usb, packet, length);
|
|
if (ret)
|
|
return ret;
|
|
|
|
h3p->sequence++;
|
|
|
|
// wait for ack/nack
|
|
ret = nv3p_wait_ack(h3p);
|
|
if (ret)
|
|
return ret;
|
|
|
|
// some commands have return data
|
|
ret = nv3p_get_cmd_return(h3p, command, args);
|
|
if (ret)
|
|
return ret;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void nv3p_write_cmd(nv3p_handle_t h3p, uint32_t command, void *args,
|
|
uint32_t *length, uint8_t *packet)
|
|
{
|
|
uint8_t *tmp;
|
|
|
|
tmp = packet;
|
|
|
|
switch(command) {
|
|
case NV3P_CMD_GET_PLATFORM_INFO:
|
|
case NV3P_CMD_GET_BCT:
|
|
// no args or output only
|
|
*length = 0;
|
|
WRITE32(tmp, *length);
|
|
WRITE32(tmp, command);
|
|
break;
|
|
case NV3P_CMD_DL_BCT:
|
|
{
|
|
nv3p_cmd_dl_bct_t *a = (nv3p_cmd_dl_bct_t *)args;
|
|
*length = (1 * 4);
|
|
WRITE32(tmp, *length);
|
|
WRITE32(tmp, command);
|
|
WRITE32(tmp, a->length);
|
|
break;
|
|
}
|
|
case NV3P_CMD_DL_BL:
|
|
{
|
|
nv3p_cmd_dl_bl_t *a = (nv3p_cmd_dl_bl_t *)args;
|
|
*length = (2 * 4) + (1 * 8);
|
|
WRITE32(tmp, *length);
|
|
WRITE32(tmp, command);
|
|
WRITE64(tmp, a->length);
|
|
WRITE32(tmp, a->address);
|
|
WRITE32(tmp, a->entry);
|
|
break;
|
|
}
|
|
default:
|
|
dprintf("bad command: 0x%x\n", command);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
static int nv3p_wait_ack(nv3p_handle_t h3p)
|
|
{
|
|
int ret;
|
|
nv3p_header_t hdr = {0,0,0};
|
|
uint32_t recv_checksum = 0, checksum;
|
|
uint32_t length = 0;
|
|
|
|
h3p->last_nack = NV3P_NACK_SUCCESS;
|
|
|
|
ret = nv3p_recv_hdr(h3p, &hdr, &recv_checksum);
|
|
if (ret)
|
|
return ret;
|
|
|
|
length = NV3P_PACKET_SIZE_BASIC;
|
|
switch(hdr.packet_type) {
|
|
case NV3P_PACKET_TYPE_ACK:
|
|
length += NV3P_PACKET_SIZE_ACK;
|
|
break;
|
|
case NV3P_PACKET_TYPE_NACK:
|
|
length += NV3P_PACKET_SIZE_NACK;
|
|
break;
|
|
default:
|
|
dprintf("unknown packet type received: 0x%x\n", hdr.packet_type);
|
|
return EINVAL;
|
|
}
|
|
|
|
if (hdr.packet_type == NV3P_PACKET_TYPE_NACK) {
|
|
// read 4 more bytes to get the error code
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&h3p->last_nack, 4);
|
|
if (ret)
|
|
return ret;
|
|
|
|
recv_checksum += nv3p_cksum((uint8_t *)&h3p->last_nack, 4);
|
|
}
|
|
|
|
// get/verify the checksum
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4);
|
|
if (ret)
|
|
return ret;
|
|
|
|
if (recv_checksum + checksum != 0) {
|
|
return EIO;
|
|
}
|
|
|
|
if (hdr.sequence != h3p->sequence - 1) {
|
|
return EIO;
|
|
}
|
|
|
|
if (hdr.packet_type == NV3P_PACKET_TYPE_NACK) {
|
|
return EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int nv3p_get_cmd_return(nv3p_handle_t h3p, uint32_t command, void *args)
|
|
{
|
|
int ret;
|
|
uint32_t length = 0;
|
|
|
|
switch (command) {
|
|
case NV3P_CMD_GET_PLATFORM_INFO:
|
|
length = sizeof(nv3p_platform_info_t);
|
|
break;
|
|
case NV3P_CMD_GET_BCT:
|
|
length = sizeof(nv3p_bct_info_t);
|
|
break;
|
|
case NV3P_CMD_DL_BCT:
|
|
case NV3P_CMD_DL_BL:
|
|
break;
|
|
default:
|
|
dprintf("unknown command: 0x%x\n", command);
|
|
return EINVAL;
|
|
}
|
|
|
|
|
|
if (length) {
|
|
ret = nv3p_data_recv(h3p, args, length);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int nv3p_recv_hdr(nv3p_handle_t h3p, nv3p_header_t *hdr,
|
|
uint32_t *checksum )
|
|
{
|
|
int ret;
|
|
uint32_t length;
|
|
uint8_t *tmp;
|
|
|
|
tmp = &s_buffer[0];
|
|
length = NV3P_PACKET_SIZE_BASIC;
|
|
ret = nv3p_read(h3p->usb, tmp, length);
|
|
if (ret) {
|
|
dprintf("error reading packet: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
READ32(tmp, hdr->version);
|
|
READ32(tmp, hdr->packet_type);
|
|
READ32(tmp, hdr->sequence);
|
|
|
|
if (hdr->version != NV3P_VERSION) {
|
|
dprintf("version mismatch, expecting NV3P_VERSION(0x%x), got 0x%x\n",
|
|
NV3P_VERSION, hdr->version);
|
|
return EINVAL;
|
|
}
|
|
|
|
h3p->recv_sequence = hdr->sequence;
|
|
|
|
*checksum = nv3p_cksum(&s_buffer[0], length);
|
|
return 0;
|
|
}
|
|
|
|
int nv3p_data_recv(nv3p_handle_t h3p, uint8_t *data, uint32_t length)
|
|
{
|
|
int ret;
|
|
uint8_t *tmp;
|
|
nv3p_header_t hdr = {0,0,0};
|
|
uint32_t checksum;
|
|
uint32_t recv_length;
|
|
|
|
// check for left over stuff from a previous read
|
|
if (h3p->bytes_remaining == 0) {
|
|
// get the basic header, verify it's data
|
|
ret = nv3p_recv_hdr(h3p, &hdr, &h3p->recv_checksum);
|
|
if (ret)
|
|
goto fail;
|
|
|
|
if (hdr.packet_type != NV3P_PACKET_TYPE_DATA)
|
|
return nv3p_drain_packet(h3p, &hdr);
|
|
|
|
tmp = &s_buffer[0];
|
|
|
|
// get length
|
|
ret = nv3p_read(h3p->usb, tmp, (1 * 4));
|
|
if (ret)
|
|
goto fail;
|
|
|
|
READ32(tmp, recv_length);
|
|
|
|
if (!recv_length) {
|
|
ret = EIO;
|
|
goto fail;
|
|
}
|
|
|
|
h3p->recv_checksum += nv3p_cksum((uint8_t *)&recv_length, 4);
|
|
|
|
// setup for partial reads
|
|
h3p->bytes_remaining = recv_length;
|
|
length = MIN(length, recv_length);
|
|
}
|
|
else {
|
|
length = MIN(h3p->bytes_remaining, length);
|
|
}
|
|
|
|
// read the data
|
|
ret = nv3p_read(h3p->usb, data, length);
|
|
if (ret)
|
|
goto fail;
|
|
|
|
h3p->recv_checksum += nv3p_cksum(data, length);
|
|
|
|
h3p->bytes_remaining -= length;
|
|
if (h3p->bytes_remaining == 0) {
|
|
// get/verify the checksum
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4);
|
|
if (ret)
|
|
goto fail;
|
|
|
|
if (h3p->recv_checksum + checksum != 0) {
|
|
ret = EIO;
|
|
goto fail;
|
|
}
|
|
|
|
nv3p_ack(h3p);
|
|
}
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
nv3p_nack(h3p, NV3P_NACK_BAD_DATA);
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int nv3p_drain_packet(nv3p_handle_t h3p, nv3p_header_t *hdr)
|
|
{
|
|
int ret = EIO;
|
|
|
|
/*
|
|
* consume an ack or nack packet. the other packet types are not
|
|
* recoverable.
|
|
*/
|
|
if (hdr->packet_type == NV3P_PACKET_TYPE_ACK ||
|
|
hdr->packet_type == NV3P_PACKET_TYPE_NACK) {
|
|
uint32_t checksum;
|
|
|
|
if (hdr->packet_type == NV3P_PACKET_TYPE_NACK) {
|
|
uint32_t code;
|
|
|
|
// read 4 more bytes to get the error code
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&code, 4);
|
|
if (ret)
|
|
return ret;
|
|
|
|
h3p->last_nack = code;
|
|
}
|
|
|
|
// drain the checksum
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4);
|
|
if (ret)
|
|
return ret;
|
|
|
|
ret = EIO;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void nv3p_ack(nv3p_handle_t h3p)
|
|
{
|
|
uint32_t checksum;
|
|
uint8_t packet[NV3P_MAX_ACK_SIZE];
|
|
uint32_t length;
|
|
|
|
nv3p_write_header(NV3P_PACKET_TYPE_ACK, h3p->recv_sequence, packet);
|
|
|
|
length = NV3P_PACKET_SIZE_BASIC;
|
|
length += NV3P_PACKET_SIZE_ACK;
|
|
|
|
checksum = nv3p_cksum(packet, length);
|
|
checksum = ~checksum + 1;
|
|
nv3p_write_footer(checksum, &packet[length]);
|
|
|
|
length += NV3P_PACKET_SIZE_FOOTER;
|
|
|
|
// send the packet
|
|
usb_write(h3p->usb, packet, length);
|
|
}
|
|
|
|
static void nv3p_nack(nv3p_handle_t h3p, uint32_t code)
|
|
{
|
|
uint32_t checksum;
|
|
uint8_t packet[NV3P_MAX_ACK_SIZE];
|
|
uint8_t *tmp;
|
|
uint32_t length;
|
|
|
|
nv3p_write_header(NV3P_PACKET_TYPE_NACK, h3p->recv_sequence, packet);
|
|
|
|
length = NV3P_PACKET_SIZE_BASIC;
|
|
|
|
tmp = &packet[length];
|
|
|
|
// write the nack code
|
|
WRITE32(tmp, code);
|
|
|
|
length += NV3P_PACKET_SIZE_NACK;
|
|
checksum = nv3p_cksum(packet, length);
|
|
checksum = ~checksum + 1;
|
|
nv3p_write_footer(checksum, tmp);
|
|
|
|
length += NV3P_PACKET_SIZE_FOOTER;
|
|
|
|
// send the packet
|
|
usb_write(h3p->usb, packet, length);
|
|
}
|
|
|
|
static int nv3p_get_args(nv3p_handle_t h3p, uint32_t command, void **args,
|
|
uint8_t *packet )
|
|
{
|
|
uint8_t *tmp = packet;
|
|
uint8_t *buf = &s_args[0];
|
|
|
|
switch(command) {
|
|
case NV3P_CMD_GET_PLATFORM_INFO:
|
|
case NV3P_CMD_GET_BCT:
|
|
// output only
|
|
break;
|
|
case NV3P_CMD_STATUS:
|
|
{
|
|
nv3p_cmd_status_t *a = (nv3p_cmd_status_t *)buf;
|
|
memcpy(a->msg, tmp, NV3P_STRING_MAX);
|
|
tmp += NV3P_STRING_MAX;
|
|
|
|
READ32(tmp, a->code);
|
|
READ32(tmp, a->flags);
|
|
break;
|
|
}
|
|
case NV3P_CMD_DL_BCT:
|
|
{
|
|
nv3p_cmd_dl_bct_t *a = (nv3p_cmd_dl_bct_t *)buf;
|
|
READ32(tmp, a->length);
|
|
break;
|
|
}
|
|
case NV3P_CMD_DL_BL:
|
|
{
|
|
nv3p_cmd_dl_bl_t *a = (nv3p_cmd_dl_bl_t *)buf;
|
|
READ64(tmp, a->length);
|
|
READ32(tmp, a->address);
|
|
READ32(tmp, a->entry);
|
|
break;
|
|
}
|
|
default:
|
|
dprintf("unknown command: 0x%x\n", command);
|
|
return EINVAL;
|
|
}
|
|
|
|
*args = buf;
|
|
return 0;
|
|
}
|
|
|
|
int nv3p_cmd_recv(nv3p_handle_t h3p, uint32_t *command, void **args)
|
|
{
|
|
int ret;
|
|
uint8_t *tmp;
|
|
nv3p_header_t hdr = {0,0,0};
|
|
uint32_t length;
|
|
uint32_t checksum, recv_checksum = 0;
|
|
|
|
// get the basic header, verify it's a command
|
|
ret = nv3p_recv_hdr(h3p, &hdr, &recv_checksum);
|
|
if (ret) {
|
|
dprintf("nv3p_recv_hdr returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
if(hdr.packet_type != NV3P_PACKET_TYPE_CMD) {
|
|
dprintf("expecting NV3P_PACKET_TYPE_CMD(0x%x), got 0x%x\n",
|
|
NV3P_PACKET_TYPE_CMD, hdr.packet_type);
|
|
return nv3p_drain_packet(h3p, &hdr);
|
|
}
|
|
|
|
tmp = &s_buffer[0];
|
|
|
|
// get length and command number
|
|
ret = nv3p_read(h3p->usb, tmp, (2 * 4));
|
|
if (ret) {
|
|
dprintf("nv3p_read() returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
READ32(tmp, length);
|
|
READ32(tmp, *(uint32_t *)command);
|
|
|
|
// read the args
|
|
if (length) {
|
|
ret = nv3p_read(h3p->usb, tmp, length);
|
|
if (ret) {
|
|
dprintf("nv3p_read returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
ret = nv3p_get_args(h3p, *command, args, tmp);
|
|
if (ret) {
|
|
dprintf("nv3p_get_args returned %d\n", ret);
|
|
return ret;
|
|
}
|
|
} else {
|
|
// command may be output only
|
|
ret = nv3p_get_args(h3p, *command, args, 0);
|
|
if (ret)
|
|
*args = 0;
|
|
}
|
|
|
|
length += NV3P_PACKET_SIZE_COMMAND;
|
|
recv_checksum += nv3p_cksum(&s_buffer[0], length);
|
|
|
|
// get/verify the checksum
|
|
ret = nv3p_read(h3p->usb, (uint8_t *)&checksum, 4);
|
|
if (ret) {
|
|
dprintf("nv3p_read returned %d reading checksum\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
if(recv_checksum + checksum != 0) {
|
|
dprintf("checksum mismatch\n");
|
|
return EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int nv3p_data_send(nv3p_handle_t h3p, uint8_t *data, uint32_t length)
|
|
{
|
|
int ret;
|
|
uint32_t checksum;
|
|
uint8_t *packet;
|
|
uint8_t *tmp;
|
|
uint32_t hdrlen;
|
|
|
|
packet = &s_buffer[0];
|
|
|
|
nv3p_write_header(NV3P_PACKET_TYPE_DATA, h3p->sequence, packet);
|
|
tmp = packet + NV3P_PACKET_SIZE_BASIC;
|
|
|
|
// data header
|
|
WRITE32(tmp, length);
|
|
|
|
hdrlen = NV3P_PACKET_SIZE_BASIC + NV3P_PACKET_SIZE_DATA;
|
|
|
|
// checksum
|
|
checksum = nv3p_cksum(packet, hdrlen);
|
|
checksum += nv3p_cksum(data, length);
|
|
checksum = ~checksum + 1;
|
|
|
|
// send the headers
|
|
ret = usb_write(h3p->usb, packet, hdrlen);
|
|
if (ret)
|
|
return ret;
|
|
|
|
// send the data
|
|
ret = usb_write(h3p->usb, data, length);
|
|
if (ret)
|
|
return ret;
|
|
|
|
// send checksum
|
|
ret = usb_write(h3p->usb, (uint8_t *)&checksum, 4);
|
|
if (ret)
|
|
return ret;
|
|
|
|
h3p->sequence++;
|
|
|
|
// wait for ack/nack
|
|
ret = nv3p_wait_ack(h3p);
|
|
if (ret)
|
|
return ret;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int bytesleft = 0;
|
|
uint8_t packet[NV3P_MAX_COMMAND_SIZE];
|
|
int offset = 0;
|
|
|
|
/*
|
|
* nv3p_read() - buffered read, target sometimes pads extra bytes to the
|
|
* end of responses, and we don't handle short reads well,
|
|
* so buffer reads and copy out
|
|
*/
|
|
static int nv3p_read(usb_device_t *usb, uint8_t *buf, int len)
|
|
{
|
|
int actual_len;
|
|
int ret;
|
|
|
|
if (len > sizeof(packet)) {
|
|
dprintf("request for read too big (%d bytes)\n", len);
|
|
return E2BIG;
|
|
}
|
|
|
|
if (len > bytesleft) {
|
|
ret = usb_read(usb, packet, sizeof(packet), &actual_len);
|
|
if (ret) {
|
|
dprintf("USB read failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
offset = 0;
|
|
bytesleft = actual_len;
|
|
|
|
len = MIN(len, actual_len);
|
|
}
|
|
|
|
memcpy(buf, packet + offset, len);
|
|
|
|
offset += len;
|
|
bytesleft -= len;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|