quickdev16/tools/gnusb/bootloader/software/snesram_bootuploader.c
David Voswinkel aedc6dab5b o add gnususb as reference bootloader
o refactor boot loader  cpde
o
2009-05-06 23:55:56 +02:00

316 lines
9.8 KiB
C

/*
* =====================================================================================
*
* Filename: snesram_bootuploader.c
*
* Description:
*
* Version: 1.0
* Created: 05/06/2009 03:06:26 PM
* Revision: none
* Compiler: gcc
*
* Author: David Voswinkel (DV), david@optixx.org
* Company: Optixx
*
* =====================================================================================
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <usb.h>
#include "../usb_cmds.h"
#define USBDEV_SHARED_VENDOR 0x16C0 /* VOTI */
#define USBDEV_SHARED_PRODUCT 0x05DC /* Obdev's free shared PID */
#define USB_VENDORSTRING "www.optixx.org"
#define USB_BOOTLOADERNAME "gnusboot"
#define USB_PRODUCTNAME "gnusb"
#define RETRIES 6
usb_dev_handle *handle = NULL;
unsigned char buffer[8];
int nBytes;
int tries;
static int usbGetStringAscii(usb_dev_handle * dev, int index, int langid, char *buf, int buflen)
{
char buffer[256];
int rval, i;
if ((rval =
usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR,
(USB_DT_STRING << 8) + index, langid, buffer, sizeof(buffer), 1000)) < 0)
return rval;
if (buffer[1] != USB_DT_STRING)
return 0;
if ((unsigned char)buffer[0] < rval)
rval = (unsigned char)buffer[0];
rval /= 2;
/*
* lossy conversion to ISO Latin1
*/
for (i = 1; i < rval; i++) {
if (i > buflen) /* destination buffer overflow */
break;
buf[i - 1] = buffer[2 * i];
if (buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
buf[i - 1] = '?';
}
buf[i - 1] = 0;
return i - 1;
}
static usb_dev_handle *findDevice(char *thedevice)
{
struct usb_bus *bus;
struct usb_device *dev;
usb_dev_handle *handle = 0;
tries++;
usb_find_busses();
usb_find_devices();
for (bus = usb_busses; bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
if (dev->descriptor.idVendor == USBDEV_SHARED_VENDOR && dev->descriptor.idProduct == USBDEV_SHARED_PRODUCT) {
char string[256];
int len;
handle = usb_open(dev); /* we need to open the device in
* order to query strings */
if (!handle) {
fprintf(stderr, "Warning: cannot open USB device: %s\n", usb_strerror());
continue;
}
/*
* now find out whether the device actually is obdev's
* Remote Sensor:
*/
len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, 0x0409, string, sizeof(string));
if (len < 0) {
fprintf(stderr, "warning: cannot query manufacturer for device: %s\n", usb_strerror());
goto skipDevice;
}
/*
* fprintf(stderr, "seen device from vendor ->%s<-\n",
* string);
*/
if (strcmp(string, USB_VENDORSTRING) != 0)
goto skipDevice;
len = usbGetStringAscii(handle, dev->descriptor.iProduct, 0x0409, string, sizeof(string));
if (len < 0) {
fprintf(stderr, "warning: cannot query product for device: %s\n", usb_strerror());
goto skipDevice;
}
/*
* fprintf(stderr, "seen product ->%s<-\n", string);
*/
if (strcmp(string, thedevice) == 0)
break;
skipDevice:
usb_close(handle);
handle = NULL;
}
}
if (handle)
break;
}
if (!handle) {
if (tries < RETRIES) {
handle = findDevice(thedevice);
} else {
fprintf(stderr, "Could not find USB device %s/%s\n", USB_VENDORSTRING, thedevice);
}
}
return handle;
}
static int hextobin(unsigned char c)
{
/*
* http://www.scit.wlv.ac.uk/~jphb/sst/c/cgisd.html Function to
* convert hex character to binary. Returns value or -1 if there is
* any error.
*/
if (isdigit(c))
return c - '0';
else if (isxdigit(c))
return tolower(c) - 'a' + 10;
else
return -1;
}
static void usage(char *name)
{
fprintf(stderr, "\nusage:\n");
fprintf(stderr, " %s -upload file_to_upload.hex upload hex file\n", name);
fprintf(stderr,
" %s -version print version number of both the bootloader and the command line tool\n", name);
fprintf(stderr, " %s -leave leave bootloader and start application\n", name);
fprintf(stderr, " %s -clear_flag clear softjumper\n", name);
fprintf(stderr, "\n");
}
static void save_send_word(unsigned int to_send)
{
unsigned int result;
unsigned int ok;
ok = 0;
while (!ok) {
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_IN, SNESRAM_BOOT_CMD_STATUS, 0, 0, (char *)buffer, sizeof(buffer), 100);
if (nBytes == 1)
ok = buffer[0];
printf(".");
}
buffer[0] = 0;
buffer[1] = 0;
ok = 0;
// while(!ok) {
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_IN, SNESRAM_BOOT_CMD_WRITE, to_send, 0, (char *)buffer, sizeof(buffer), 5000);
if (nBytes == 2) {
result = buffer[0] | (buffer[1] << 8);
if (result != to_send)
printf("COMMUNICATION ERROR: Sent %i but received %i\n", to_send, result);
} else
printf("COMMUNICATION ERROR: Only %i bytes received\n", nBytes);
// }
return;
}
static void send_file(char *filepath)
{
int char_count, i, send_bytes = 0;
int c; // Character read from the file.
unsigned int sendWord = 0; // word to send to uDMX
FILE *fp; // Pointer to the file.
// Open the file
if ((fp = fopen(filepath, "rb")) == NULL) {
printf("File %s open failed!\n", filepath);
exit(1);
};
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_OUT, SNESRAM_BOOT_CMD_START, 0, 0, (char *)buffer, sizeof(buffer), 100);
i = 0;
// Read one character at a time
while ((c = fgetc(fp)) != EOF) {
// hex file lines start with ':'
if (c == ':') {
char_count = 0;
send_bytes = 0;
} else {
char_count++;
printf("%c", c);
// first two characters hold length of data
if (char_count < 3) {
send_bytes += hextobin(c) << ((2 - char_count) * 4);
}
// check if line holds data (record type = 00)
if (char_count == 8) {
if (c != '0')
send_bytes = 0;
printf(" ");
}
// ignore adress part of every line in hex file
if (char_count > 8) {
if (send_bytes) {
sendWord += hextobin(c) << ((3 - i) * 4);
if (i == 3) {
i = -1;
send_bytes -= 2;
printf(" ");
save_send_word(sendWord); // send word over
// USB
sendWord = 0;
}
i++;
}
}
}
}
// write last page to flash if there is anything left over
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_OUT, SNESRAM_BOOT_CMD_FINISH, 0, 0, (char *)buffer, sizeof(buffer), 100);
fclose(fp); /* Close the file. */
}
int main(int argc, char **argv)
{
if (argc < 2) {
usage(argv[0]);
exit(1);
}
char *productName;
// usb_set_debug(1);
usb_init();
productName = USB_PRODUCTNAME;
if (argc > 2) {
if (strcmp(argv[2], "-device") == 0)
productName = argv[3];
}
if (strcmp(argv[1], "-upload") == 0) {
if ((handle = findDevice(USB_BOOTLOADERNAME)) != NULL)
send_file(argv[2]);
} else if (strcmp(argv[1], "-version") == 0) {
printf("Not implemented\n");
} else if (strcmp(argv[1], "-leave") == 0) {
if ((handle = findDevice(USB_BOOTLOADERNAME)) != NULL) {
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_OUT, SNESRAM_BOOT_CMD_LEAVE, 0, 0, (char *)buffer, sizeof(buffer), 100);
}
} else if (strcmp(argv[1], "-enter") == 0) {
if ((handle = findDevice(productName)) != NULL)
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_OUT, SNESRAM_BOOT_CMD_ENTER, 0, 0, (char *)buffer, sizeof(buffer), 100);
} else if (strcmp(argv[1], "-clear_flag") == 0) {
if ((handle = findDevice(USB_BOOTLOADERNAME)) != NULL)
nBytes =
usb_control_msg(handle,
USB_TYPE_VENDOR | USB_RECIP_DEVICE |
USB_ENDPOINT_OUT,
SNESRAM_BOOT_CMD_CLEAR_FLAG, 0, 0, (char *)buffer, sizeof(buffer), 100);
} else
usage(argv[0]);
usb_close(handle);
return 0;
}