--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <limits.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <trbnet.h>
+#include <trberror.h>
+
+static const uint16_t CtrlReg = 0xd000;
+static const uint16_t SetupReg = 0xd001;
+static const uint16_t BlockRam = 0xd100;
+static uint32_t* trbBuffer = NULL;
+static uint8_t** pageBuffer = NULL;
+static uint16_t* pageBufferAddress = NULL;
+
+static uint8_t* imageBuffer = NULL;
+
+/* Maximum number of endpoints */
+#define NUM_ENDPOINTS 1024
+
+/* 32-Bit Words: */
+#define BLOCKRAM_SIZE 64
+#define TRB_BUFFER_SIZE (BLOCKRAM_SIZE * NUM_ENDPOINTS + NUM_ENDPOINTS)
+
+/* Bytes: */
+#define PAGE_SIZE 256
+#define NUM_PAGES 16384
+#define BLOCK_SIZE (64 * 1024)
+#define NUM_BLOCKS 64
+
+#define PAGE_BUFFER_SIZE (PAGE_SIZE * NUM_ENDPOINTS)
+
+static const uint32_t manId[1] = {
+ 0x0000471f
+};
+
+static const char bussy[4][5] = {
+ "|\b",
+ "/\b",
+ "-\b",
+ "\\\b"
+};
+
+#define NUM_MAN_IDS 1
+
+/* ------ MAIN ---------------------------------------------------------- */
+
+static FILE *imageFile = NULL;
+
+static void atexit0()
+{
+ if (imageFile != NULL) {
+ fclose(imageFile);
+ }
+}
+
+static void sigHandler(int sig)
+{
+ if (sig == SIGTERM) fprintf(stderr, "caught SIGTERM\n");
+ if (sig == SIGINT) fprintf(stderr, "caught SIGINT\n");
+
+ exit(128 + sig);
+}
+
+static const unsigned int timeout = 10000;
+
+static int readSetupRegister(uint16_t trb_address,
+ uint8_t value[NUM_ENDPOINTS])
+{
+ unsigned int ctr = 0;
+ int status = -1;
+ int c;
+ int i;
+
+ /* Wait until NoMoreData is withdrawn */
+ do {
+ if ((status = trb_register_read(trb_address, SetupReg,
+ trbBuffer, TRB_BUFFER_SIZE)) == -1) {
+ trb_error("Error readSetupRegister");
+ return -1;
+ }
+
+ /* Check timeout */
+ if (ctr >= timeout) {
+ fprintf(stderr, "Error readSetupRegister, timeout\n");
+ return -1;
+ }
+ ctr++;
+ } while (trb_term.status_channel == 0x04);
+
+ if (trb_term.status_channel != 0) {
+ trb_error("Error readSetupRegister Status");
+ return -1;
+ }
+
+ if (status <= 0) {
+ fprintf(stderr, "Error readSetupRegister, length\n");
+ return -1;
+ }
+
+ c = 0;
+ for (i = 1; i < status; i += 2) {
+ if (value != NULL) value[c] = (uint8_t)((trbBuffer[i] >> 24) & 0xff);
+ c++;
+ }
+
+ return c;
+}
+
+static int writeSetupRegister(uint16_t trb_address, uint8_t value)
+{
+ unsigned int ctr = 0;
+ int status = -1;
+
+ /* Wait until NoMoreData is withdrawn */
+ do {
+ if ((status = trb_register_write(trb_address, SetupReg,
+ (uint32_t)(value << 24))) == -1) {
+ trb_error("Error writeSetupRegister");
+ return -1;
+ }
+
+ /* Check timeout */
+ if (ctr >= timeout) {
+ fprintf(stderr, "Error writeSetupRegister, timeout\n");
+ return -1;
+ }
+ ctr++;
+ } while (trb_term.status_channel != 0);
+
+ if (trb_term.status_channel != 0) {
+ trb_error("Error writeSetupRegister Status");
+ return -1;
+ }
+
+ return 1;
+}
+
+static int readCtrlRegister(uint16_t trb_address,
+ uint32_t value[NUM_ENDPOINTS])
+{
+ unsigned int ctr = 0;
+ int status = -1;
+ int c;
+ int i;
+
+ /* Wait until NoMoreData is withdrawn */
+ do {
+ if ((status = trb_register_read(trb_address, SetupReg,
+ trbBuffer, TRB_BUFFER_SIZE)) == -1) {
+ trb_error("Error readCtrlRegister");
+ return -1;
+ }
+
+ /* Check timeout */
+ if (ctr >= timeout) {
+ fprintf(stderr, "Error readCtrlRegister, timeout\n");
+ return -1;
+ }
+ ctr++;
+ } while (trb_term.status_channel != 0);
+
+ if (status <= 0) {
+ fprintf(stderr, "Error readCtrlRegister, length\n");
+ return -1;
+ }
+
+ c = 0;
+ for (i = 1; i < status; i += 2) {
+ if (value != NULL) value[c] = trbBuffer[i];
+ c++;
+ }
+
+ return c;
+}
+
+static int writeCtrlRegister(uint16_t trb_address, uint32_t value)
+{
+ unsigned int ctr = 0;
+ int status = -1;
+
+ /* Wait until NoMoreData is withdrawn */
+ do {
+ if ((status = trb_register_write(trb_address, CtrlReg,
+ value)) == -1) {
+ trb_error("Error writeCtrlRegister");
+ return -1;
+ }
+
+ /* Check timeout */
+ if (ctr >= timeout) {
+ fprintf(stderr, "Error writeCtrlRegister, timeout\n");
+ return -1;
+ }
+ ctr++;
+ } while (trb_term.status_channel != 0);
+
+ return 1;
+}
+
+static int sendCommand(uint16_t trb_address, uint32_t cmd, uint8_t max)
+{
+ if (writeSetupRegister(trb_address, max) == -1) {
+ return -1;
+ }
+ if (writeCtrlRegister(trb_address, cmd) == -1) {
+ return -1;
+ }
+ if (readCtrlRegister(trb_address, NULL) == -1) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int checkStatus(uint16_t trb_address)
+{
+ uint32_t trbcmd;
+ int status;
+ int ret = 0;
+ int i;
+
+ /* Read Status Register */
+ trbcmd = 0x05 << 24;
+ if (sendCommand(trb_address, trbcmd, 0) == -1) {
+ return -1;
+ }
+
+ if ((status =
+ trb_register_read(trb_address, BlockRam, trbBuffer,
+ TRB_BUFFER_SIZE)) == -1) {
+ trb_error("Error > checkStatus");
+ exit(EXIT_FAILURE);
+ }
+
+ if (status <= 0) {
+ return -1;
+ }
+
+ for (i = 0; i < status; i += 2) {
+ fprintf(stderr, "Status: 0x%02x\n", trbBuffer[i + 1] & 0xff);
+ if (((trbBuffer[i + 1] >> 5) & 0x01) == 1) {
+ fprintf(stderr, "Erase or program error on EndPoint 0x%04x\n",
+ trbBuffer[i] & 0xffff);
+ return -1; /* Fatal Error */
+ }
+ if ((trbBuffer[i + 1] & 0x01) == 1) {
+ ret = -2; /* One is busy */
+ }
+ }
+
+ return ret;
+}
+
+static int readPage(uint16_t trb_address, uint32_t pageNumber,
+ uint32_t numBytes)
+{
+ uint32_t* temp = NULL;
+ uint32_t* end = NULL;
+ unsigned int endPoint;
+ uint16_t size = 0;
+ uint32_t trbcmd;
+ int status = -1;
+
+ if (pageNumber >= NUM_PAGES) return -1;
+ if ((numBytes > PAGE_SIZE) || (numBytes == 0)) return -1;
+
+ trbcmd = (0x03 << 24) | ((pageNumber * PAGE_SIZE) & 0xffffff);
+ if (sendCommand(trb_address, trbcmd, numBytes - 1) == -1) {
+ return -1;
+ }
+
+ size = (numBytes / 4) + (numBytes % 4 != 0 ? 1 : 0);
+ if ((status = trb_register_read_mem(trb_address, BlockRam, 0, size,
+ trbBuffer, TRB_BUFFER_SIZE))
+ == -1) {
+ trb_error("readPage");
+ exit(EXIT_FAILURE);
+ }
+
+ if (status <= 0) {
+ return -1;
+ }
+
+ /* Copy trbBuffer to pageBuffer and check content */
+ endPoint = 0;
+ temp = trbBuffer;
+ end = trbBuffer + status;
+ while (temp < trbBuffer + status) {
+ unsigned int len = (*temp >> 16) & 0xffff;
+ unsigned int address = *temp & 0xffff;
+ unsigned int c;
+
+ if (len != size) {
+ fprintf(stderr,
+ "Error > readPage: Invalid len %d returned by endpoint 0x%04x\n",
+ len, address);
+ }
+
+ /* read one page */
+ pageBufferAddress[endPoint] = address;
+ for (c = 0; c < (len * 4); c++) {
+ if ((c % 4) == 0) {
+ temp++;
+ }
+ pageBuffer[endPoint][c] = (*temp >> ((c % 4) * 8)) & 0xff;
+ }
+ temp++;
+ endPoint++;
+ }
+
+ return endPoint;
+}
+
+
+static int writePage(uint16_t trb_address, uint32_t pageNumber,
+ const uint8_t* pageBuffer, uint32_t numBytes)
+{
+ uint32_t* temp = NULL;
+ uint16_t size = 0;
+ uint32_t trbcmd;
+ unsigned int c;
+ int status = -1;
+
+ if (pageNumber >= NUM_PAGES) return -1;
+ if ((numBytes > PAGE_SIZE) || (numBytes == 0)) return -1;
+
+ /* Copy pageBuffer to trbBuffer */
+ temp = trbBuffer - 1;
+ for (c = 0; c < numBytes; c++) {
+ if ((c % 4) == 0) {
+ temp++;
+ temp = 0;
+ }
+ *temp |= (pageBuffer[c] << ((c % 4) * 8));
+ }
+
+ /* Transfer trbBuffer */
+ size = temp - trbBuffer + 1;
+ if ((status = trb_register_write_mem(trb_address, BlockRam, 0,
+ trbBuffer, size))
+ == -1) {
+ trb_error("Error > writePage: tranfer trbBuffer");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Enable writing */
+ if (sendCommand(trb_address, 0x06 << 24, 0) == -1) {
+ fprintf(stderr, "Error > writePage: write enable\n");
+ return -1;
+ }
+
+ /* Write page */
+ trbcmd = (0x02 << 24) | ((pageNumber * PAGE_SIZE) & 0xffffff);
+ if (sendCommand(trb_address, trbcmd, numBytes - 1) == -1) {
+ fprintf(stderr, "Error > writePage: write page\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int checkManId(uint16_t trb_address)
+{
+ uint32_t trbcmd;
+ int status;
+ int i;
+
+
+ /* Read MeanId */
+ trbcmd = 0x9f << 24;
+ if (sendCommand(trb_address, trbcmd, 3) == -1) {
+ return -1;
+ }
+
+ if ((status =
+ trb_register_read(trb_address, BlockRam, trbBuffer,
+ TRB_BUFFER_SIZE)) == -1) {
+ trb_error("Error > checkMeanId");
+ exit(EXIT_FAILURE);
+ }
+
+ if (status <= 0) {
+ return -1;
+ }
+
+ for (i = 0; i < status; i += 2) {
+ unsigned int id;
+ int accepted = -1;
+ for (id = 0; id < NUM_MAN_IDS; id++) {
+ if (trbBuffer[i + 1] == manId[id]) {
+ accepted = 0;
+ break;
+ }
+ }
+ if (accepted == -1) {
+ fprintf(stderr, "Invalid ManId 0x%04x on EndPoint 0x%04x\n",
+ trbBuffer[i + 1], trbBuffer[i] & 0xffff);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+void usage(const char *progName)
+{
+ printf("Usage: %s [-h] [-d level] <COMMAND>\n",
+ progName);
+ printf("Options:\n");
+ printf(" -h give this help\n");
+ printf(" -d turn on Debugging Information\n");
+ printf("\nCommands:\n");
+ printf(" program <trbaddress> <file> -> \n");
+ printf(" verify <trbaddress> <file> -> \n");
+ printf(" backup <trbaddress> <file> -> \n");
+ printf(" restore <trbaddress> <file> -> \n");
+}
+
+int main(int argc, char ** argv)
+{
+ /*
+ uint32_t page[PAGE_SIZE];
+ sigset_t blockSet;
+ */
+ unsigned int i;
+
+ trb_debug = 0;
+
+ /* Parse Arguments */
+ while ((i = getopt(argc, argv, "+hd:")) != -1) {
+ switch (i) {
+ case '?':
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ case 'h':
+ usage(basename(argv[0]));
+ exit(EXIT_SUCCESS);
+ case 'd':
+ trb_debug = strtoul(optarg, NULL, 0);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (argc - optind < 1) {
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+
+ if (init_ports() == -1) {
+ trb_error("Init_Ports");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Allocate memory for buffers */
+
+ /* Buffer holding the TRBNet packages, e.g. use by trb_read_register */
+ trbBuffer = (uint32_t*)malloc(sizeof(uint32_t) * TRB_BUFFER_SIZE);
+ if (trbBuffer == NULL) {
+ abort();
+ }
+
+ /* Buffer holding the pages of the endpoints */
+ pageBuffer = (uint8_t**)malloc(sizeof(uint8_t*) * NUM_ENDPOINTS);
+ if (pageBuffer == NULL) {
+ abort();
+ }
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ pageBuffer[i] = (uint8_t*)malloc(sizeof(uint8_t) * PAGE_SIZE);
+ if (pageBuffer[i] == NULL) abort();
+ }
+
+ /* Buffer holding the corresponding TRBAddresses */
+ pageBufferAddress = (uint16_t*)malloc(sizeof(uint16_t) * NUM_ENDPOINTS);
+ if (pageBufferAddress == NULL) {
+ abort();
+ }
+
+ /* Buffer holding the entire rom-image */
+ imageBuffer = (uint8_t*)malloc(sizeof(uint8_t) * PAGE_SIZE * NUM_PAGES);
+ if (imageBuffer == NULL) {
+ abort();
+ }
+
+ if (strcmp(argv[optind], "program") == 0) {
+ if (argc - optind != 3) {
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+ uint16_t trb_address = strtoul(argv[optind + 1], NULL, 0);
+ char* imageFileName = argv[optind + 2];
+
+ fprintf(stderr,
+ "Start flashing ImageFile '%s' to TRB_Address 0x%04x\n",
+ imageFileName, trb_address);
+
+ } else if (strcmp(argv[optind], "backup") == 0) {
+
+ /*********************************************************/
+ /* Backup Image */
+ /*********************************************************/
+
+ uint16_t trb_address;
+ char* imageFileName;
+ FILE* imageFile = NULL;
+ unsigned int page;
+
+ if (argc - optind != 3) {
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+ trb_address = strtoul(argv[optind + 1], NULL, 0);
+ imageFileName = argv[optind + 2];
+
+ if (trb_address >= 0xff00) {
+ fprintf(stderr,
+ "Broadcast addresses are not supported by this command\n");
+ exit(EXIT_FAILURE);
+ }
+
+ imageFile = fopen(imageFileName, "w+");
+ if (imageFile == NULL) {
+ fprintf(stderr, "Could not open Imagefile %s: %s\n",
+ imageFileName, strerror(errno));
+ }
+
+ if (checkManId(trb_address) == -1) {
+ exit(EXIT_FAILURE);
+ }
+
+ if (checkStatus(trb_address) < 0) {
+ exit(EXIT_FAILURE);
+ }
+
+ /* Write Pages to file */
+ fprintf(stderr, "Writing entire flashrom of EndPoint 0x%04x to file '%s' ",
+ trb_address, imageFileName);
+ for (page = 0; page < NUM_PAGES; page++) {
+ if (readPage(trb_address, page, 256) == -1) {
+ fprintf(stderr, "Error reading Page# %d, aborting..\n", page);
+ fclose(imageFile);
+ exit(EXIT_FAILURE);
+ }
+ if (fwrite((void*)pageBuffer[0], PAGE_SIZE, 1, imageFile) != 1) {
+ fprintf(stderr, "Error writing Page# %d to file, aborting..\n", page);
+ fclose(imageFile);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, "%s", bussy[page % 4]);
+ }
+ fprintf(stderr, " \nDone\n");
+
+ fclose(imageFile);
+
+ } else if (strcmp(argv[optind], "restore") == 0) {
+
+ /*********************************************************/
+ /* Restore Image */
+ /*********************************************************/
+
+ uint16_t trb_address;
+ char* imageFileName;
+ FILE* imageFile = NULL;
+ size_t size;
+ unsigned int block;
+ unsigned int page;
+ int status;
+ unsigned int i;
+
+ if (argc - optind != 3) {
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+ trb_address = strtoul(argv[optind + 1], NULL, 0);
+ imageFileName = argv[optind + 2];
+
+ /* Check for correct ManId */
+ if (checkManId(trb_address) == -1) {
+ fprintf(stderr, "Invalid ManId(s), aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Read in image */
+ imageFile = fopen(imageFileName, "r");
+ if (imageFile == NULL) {
+ fprintf(stderr, "Could not open ImageFile %s: %s\n",
+ imageFileName, strerror(errno));
+ }
+
+ size = fread((void*)imageBuffer, PAGE_SIZE, NUM_PAGES, imageFile);
+
+ if (size != NUM_PAGES) {
+ fprintf(stderr, "Invalid ImageFile %s, aborting\n", imageFileName);
+ exit(EXIT_FAILURE);
+ }
+ fclose(imageFile);
+
+ /* Check ImageBuffer ??? */
+
+ page = 0;
+ for (block = 0; block < NUM_BLOCKS; block++) {
+ /* Enable writing */
+ if (sendCommand(trb_address, 0x06 << 24, 0) == -1) {
+ fprintf(stderr, "Error > restore: write enable, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Unprotect sector */
+ if (sendCommand(trb_address, 0x39 << 24 | (BLOCK_SIZE * block), 3)
+ == -1) {
+ fprintf(stderr, "Error > restore: unprotect sector #%d, aborting\n",
+ block);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Enable writing */
+ if (sendCommand(trb_address, 0x06 << 24, 0) == -1) {
+ fprintf(stderr, "Error > restore: write enable, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Erase block */
+ if (sendCommand(trb_address, 0xd8 << 24 | (BLOCK_SIZE * block), 3)
+ == -1) {
+ fprintf(stderr, "Error > restore: erase block #%d, aborting\n",
+ block);
+ exit(EXIT_FAILURE);
+ }
+
+ /* Wait for not busy and check status */
+ while ((status = checkStatus(trb_address) == -2)) {
+ fprintf(stderr, "Wait..\n");
+ }
+
+ if (status != 0) {
+ fprintf(stderr, "Error > restore: invalid status, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /* Now write pages */
+ for (i = 0; i < (BLOCK_SIZE / PAGE_SIZE); i++) {
+ status = writePage(trb_address, page,
+ imageBuffer + page * PAGE_SIZE, PAGE_SIZE);
+ if (status == -1) {
+ fprintf(stderr, "Error > restore: writePage, aborting\n");
+ exit(EXIT_FAILURE);
+ }
+ page++;
+ }
+ }
+
+ } else if (strcmp(argv[optind], "test") == 0) {
+ uint16_t trb_address;
+ uint32_t pageNumber;
+ char* imageFileName;
+ unsigned int i;
+ int status;
+
+ if (argc - optind != 3) {
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+ trb_address = strtoul(argv[optind + 1], NULL, 0);
+ pageNumber = strtoul(argv[optind + 2], NULL, 0);
+ imageFileName = argv[optind + 2];
+
+
+ fprintf(stderr,
+ "Start flashing ImageFile '%s' to TRB_Address 0x%04x\n",
+ imageFileName, trb_address);
+
+#if 0
+
+ if (sendCommand(trb_address, 0x05 << 24, 0) == -1) {
+ exit(EXIT_FAILURE);
+ }
+ if (trb_register_read(trb_address, BlockRam, buffer, 2) == -1) {
+ trb_error("readStatus");
+ exit(EXIT_FAILURE);
+ }
+ fprintf(stderr, "Satus: 0x%08x\n", buffer[1]);
+#endif
+
+ if ((status = readPage(trb_address, pageNumber, 256)) == -1) {
+ fprintf(stderr, "Error reading Page\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < status; i++) {
+ fprintf(stderr, "EndPoint: 0x%04x\n", pageBufferAddress[i]);
+ int c;
+ for (c = 0; c < 256; c++) {
+ fprintf(stderr, "%d: 0x%02x\n", c, pageBuffer[i][c]);
+ }
+ }
+#if 0
+ checkManId(trb_address);
+ checkStatus(trb_address);
+ sendCommand(trb_address, 0x06 << 24, 0);
+ checkStatus(trb_address);
+ sendCommand(trb_address, 0x04 << 24, 0);
+ printf("S: %d\n", checkStatus(trb_address));
+#endif
+ } else {
+ /* Invalid command */
+ usage(basename(argv[0]));
+ exit(EXIT_FAILURE);
+ }
+
+#if 0
+ fprintf(stderr,
+ "Start flashing ImageFile '%s' to TRB_Address 0x%04x\n",
+ imageFileName, trb_address);
+
+ /* open port */
+ init_ports();
+
+ /* Open ImageFile */
+ imageFile = fopen(imageFileName, "r");
+ if (imageFile == NULL) {
+ perror("Error opening ImageFile");
+ exit(EXIT_FAILURE);
+ }
+
+
+ while (feof(imageFile) == 0) {
+ size_t size;
+ /* clear buffer */
+ for (i = 0 ; i < PAGE_SIZE; i++) {
+ page[i] = 0xffffffff;
+ }
+
+ if ((size = fread((void*)page, 4, PAGE_SIZE, imageFile)) != PAGE_SIZE) {
+ fprintf(stderr, "Error reading ImageFile, size = %d\n", size);
+ exit(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, "\n\n");
+ for (i = 0 ; i < PAGE_SIZE; i++) {
+ fprintf(stderr, "0x%08x\n", page[i]);
+ }
+ }
+#endif
+
+#if 0
+ /* Set Signalhandler */
+ atexit(atexit0);
+ signal(SIGINT, sigHandler);
+ signal(SIGTERM, sigHandler);
+
+ /* Set signal mask for blocking */
+ sigemptyset(&blockSet);
+ sigaddset(&blockSet, SIGINT);
+ sigaddset(&blockSet, SIGTERM);
+#endif
+
+ /* Free memory */
+ free(pageBufferAddress);
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ free(pageBuffer[i]);
+ }
+ free(pageBuffer);
+ free(trbBuffer);
+ free(imageBuffer);
+
+ exit(EXIT_SUCCESS);
+}