Files
lib_xua/module_dfu/host/xmos_dfu_osx/xmosdfu.cpp
2012-07-31 15:43:52 +01:00

416 lines
11 KiB
C++
Executable File

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libusb.h"
/* the device's vendor and product id */
#define XMOS_VID 0x20b1
#define XMOS_L1_AUDIO2_PID 0x0002
#define XMOS_L1_AUDIO1_PID 0x0003
#define XMOS_L2_AUDIO2_PID 0x0004
unsigned int XMOS_DFU_IF = 0;
#define DFU_REQUEST_TO_DEV 0x21
#define DFU_REQUEST_FROM_DEV 0xa1
// Standard DFU requests
#define DFU_DETACH 0
#define DFU_DNLOAD 1
#define DFU_UPLOAD 2
#define DFU_GETSTATUS 3
#define DFU_CLRSTATUS 4
#define DFU_GETSTATE 5
#define DFU_ABORT 6
// XMOS alternate setting requests
#define XMOS_DFU_RESETDEVICE 0xf0
#define XMOS_DFU_REVERTFACTORY 0xf1
#define XMOS_DFU_RESETINTODFU 0xf2
#define XMOS_DFU_RESETFROMDFU 0xf3
#define XMOS_DFU_SAVESTATE 0xf5
#define XMOS_DFU_RESTORESTATE 0xf6
static libusb_device_handle *devh = NULL;
static int find_xmos_device(unsigned int id)
{
libusb_device *dev;
libusb_device **devs;
int i = 0;
int found = 0;
libusb_get_device_list(NULL, &devs);
while ((dev = devs[i++]) != NULL)
{
struct libusb_device_descriptor desc;
libusb_get_device_descriptor(dev, &desc);
printf("VID = 0x%x, PID = 0x%x\n", desc.idVendor, desc.idProduct);
if (desc.idVendor == XMOS_VID &&
((desc.idProduct == XMOS_L1_AUDIO1_PID) ||
(desc.idProduct == XMOS_L1_AUDIO2_PID) ||
(desc.idProduct == XMOS_L2_AUDIO2_PID)))
{
if (found == id)
{
if (libusb_open(dev, &devh) < 0)
{
return -1;
}
else
{
libusb_config_descriptor *config_desc = NULL;
libusb_get_active_config_descriptor(dev, &config_desc);
if (config_desc != NULL)
{
for (int j = 0; j < config_desc->bNumInterfaces; j++)
{
const libusb_interface_descriptor *inter_desc = ((libusb_interface *)&config_desc->interface[j])->altsetting;
if (inter_desc->bInterfaceClass == 0xFE && inter_desc->bInterfaceSubClass == 0x1)
{
XMOS_DFU_IF = j;
}
}
}
else
{
XMOS_DFU_IF = 0;
}
}
break;
}
found++;
}
}
libusb_free_device_list(devs, 1);
return devh ? 0 : -1;
}
int xmos_dfu_resetdevice(void) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_RESETDEVICE, 0, 0, NULL, 0, 0);
}
int xmos_dfu_revertfactory(void) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_REVERTFACTORY, 0, 0, NULL, 0, 0);
}
int xmos_dfu_resetintodfu(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_RESETINTODFU, 0, interface, NULL, 0, 0);
}
int xmos_dfu_resetfromdfu(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_RESETFROMDFU, 0, interface, NULL, 0, 0);
}
int dfu_detach(unsigned int interface, unsigned int timeout) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, DFU_DETACH, timeout, interface, NULL, 0, 0);
return 0;
}
int dfu_getState(unsigned int interface, unsigned char *state) {
libusb_control_transfer(devh, DFU_REQUEST_FROM_DEV, DFU_GETSTATE, 0, interface, state, 1, 0);
return 0;
}
int dfu_getStatus(unsigned int interface, unsigned char *state, unsigned int *timeout,
unsigned char *nextState, unsigned char *strIndex) {
unsigned int data[2];
libusb_control_transfer(devh, DFU_REQUEST_FROM_DEV, DFU_GETSTATUS, 0, interface, (unsigned char *)data, 6, 0);
*state = data[0] & 0xff;
*timeout = (data[0] >> 8) & 0xffffff;
*nextState = data[1] & 0xff;
*strIndex = (data[1] >> 8) & 0xff;
return 0;
}
int dfu_clrStatus(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, DFU_CLRSTATUS, 0, interface, NULL, 0, 0);
return 0;
}
int dfu_abort(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, DFU_ABORT, 0, interface, NULL, 0, 0);
return 0;
}
int xmos_dfu_save_state(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_SAVESTATE, 0, interface, NULL, 0, 0);
printf("Save state command sent\n");
return 0;
}
int xmos_dfu_restore_state(unsigned int interface) {
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, XMOS_DFU_RESTORESTATE, 0, interface, NULL, 0, 0);
printf("Restore state command sent\n");
return 0;
}
int dfu_download(unsigned int interface, unsigned int block_num, unsigned int size, unsigned char *data) {
//printf("... Downloading block number %d size %d\r", block_num, size);
libusb_control_transfer(devh, DFU_REQUEST_TO_DEV, DFU_DNLOAD, block_num, interface, data, size, 0);
return 0;
}
int dfu_upload(unsigned int interface, unsigned int block_num, unsigned int size, unsigned char*data) {
unsigned int numBytes = 0;
numBytes = libusb_control_transfer(devh, DFU_REQUEST_FROM_DEV, DFU_UPLOAD, block_num, interface, (unsigned char *)data, size, 0);
return numBytes;
}
int write_dfu_image(char *file) {
int i = 0;
FILE* inFile = NULL;
int image_size = 0;
unsigned int num_blocks = 0;
unsigned int block_size = 64;
unsigned int remainder = 0;
unsigned char block_data[256];
unsigned char dfuState = 0;
unsigned char nextDfuState = 0;
unsigned int timeout = 0;
unsigned char strIndex = 0;
unsigned int dfuBlockCount = 0;
inFile = fopen( file, "rb" );
if( inFile == NULL ) {
fprintf(stderr,"Error: Failed to open input data file.\n");
return -1;
}
/* Discover the size of the image. */
if( 0 != fseek( inFile, 0, SEEK_END ) ) {
fprintf(stderr,"Error: Failed to discover input data file size.\n");
return -1;
}
image_size = (int)ftell( inFile );
if( 0 != fseek( inFile, 0, SEEK_SET ) ) {
fprintf(stderr,"Error: Failed to input file pointer.\n");
return -1;
}
num_blocks = image_size/block_size;
remainder = image_size - (num_blocks * block_size);
printf("... Downloading image (%s) to device\n", file);
dfuBlockCount = 0;
for (i = 0; i < num_blocks; i++) {
memset(block_data, 0x0, block_size);
fread(block_data, 1, block_size, inFile);
dfu_download(0, dfuBlockCount, block_size, block_data);
dfu_getStatus(0, &dfuState, &timeout, &nextDfuState, &strIndex);
dfuBlockCount++;
}
if (remainder) {
memset(block_data, 0x0, block_size);
fread(block_data, 1, remainder, inFile);
dfu_download(0, dfuBlockCount, block_size, block_data);
dfu_getStatus(0, &dfuState, &timeout, &nextDfuState, &strIndex);
}
// 0 length download terminates
dfu_download(0, 0, 0, NULL);
dfu_getStatus(0, &dfuState, &timeout, &nextDfuState, &strIndex);
printf("... Download complete\n");
return 0;
}
int read_dfu_image(char *file) {
FILE *outFile = NULL;
unsigned int block_count = 0;
unsigned int block_size = 64;
unsigned char block_data[64];
outFile = fopen( file, "wb" );
if( outFile == NULL ) {
fprintf(stderr,"Error: Failed to open output data file.\n");
return -1;
}
printf("... Uploading image (%s) from device\n", file);
while (1) {
unsigned int numBytes = 0;
numBytes = dfu_upload(0, block_count, 64, block_data);
if (numBytes == 0)
break;
fwrite(block_data, 1, block_size, outFile);
block_count++;
}
fclose(outFile);
}
int main(int argc, char **argv) {
int r = 1;
unsigned char dfuState = 0;
unsigned char nextDfuState = 0;
unsigned int timeout = 0;
unsigned char strIndex = 0;
unsigned int download = 0;
unsigned int upload = 0;
unsigned int revert = 0;
unsigned int save = 0;
unsigned int restore = 0;
char *firmware_filename = NULL;
if (argc < 2) {
fprintf(stderr, "No options passed to dfu application\n");
return -1;
}
if (strcmp(argv[1], "--download") == 0) {
if (argv[2]) {
firmware_filename = argv[2];
} else {
fprintf(stderr, "No filename specified for download option\n");
return -1;
}
download = 1;
} else if (strcmp(argv[1], "--upload") == 0) {
if (argv[2]) {
firmware_filename = argv[2];
} else {
fprintf(stderr, "No filename specified for upload option\n");
return -1;
}
upload = 1;
} else if (strcmp(argv[1], "--revertfactory") == 0) {
revert = 1;
}
else if(strcmp(argv[1], "--savecustomstate") == 0)
{
save = 1;
}
else if(strcmp(argv[1], "--restorecustomstate") == 0)
{
restore = 1;
}
else {
fprintf(stderr, "Invalid option passed to dfu application\n");
return -1;
}
r = libusb_init(NULL);
if (r < 0) {
fprintf(stderr, "failed to initialise libusb\n");
return -1;
}
r = find_xmos_device(0);
if (r < 0) {
fprintf(stderr, "Could not find/open device\n");
return -1;
}
r = libusb_claim_interface(devh, XMOS_DFU_IF);
if (r < 0) {
fprintf(stderr, "Error claiming interface %d %d\n", XMOS_DFU_IF, r);
return -1;
}
printf("XMOS DFU application started - Interface %d claimed\n", XMOS_DFU_IF);
/* Dont go into DFU mode for save/restore */
if(save)
{
xmos_dfu_save_state(XMOS_DFU_IF);
}
else if(restore)
{
xmos_dfu_restore_state(XMOS_DFU_IF);
}
else
{
printf("Detaching device from application mode.\n");
xmos_dfu_resetintodfu(XMOS_DFU_IF);
libusb_release_interface(devh, XMOS_DFU_IF);
libusb_close(devh);
printf("Waiting for device to restart and enter DFU mode...\n");
// Wait for device to enter dfu mode and restart
system("sleep 20");
// NOW IN DFU APPLICATION MODE
r = find_xmos_device(0);
if (r < 0) {
fprintf(stderr, "Could not find/open device\n");
return -1;
}
r = libusb_claim_interface(devh, 0);
if (r != 0)
{
fprintf(stderr, "Error claiming interface 0\n");
switch(r)
{
case LIBUSB_ERROR_NOT_FOUND:
printf("The requested interface does not exist'n");
break;
case LIBUSB_ERROR_BUSY:
printf("Another program or driver has claimed the interface\n");
break;
case LIBUSB_ERROR_NO_DEVICE:
printf("The device has been disconnected\n");
break;
case LIBUSB_ERROR_ACCESS:
printf("Access denied\n");
break;
default:
printf("Unknown error code: %d\n", r);
break;
}
return -1;
}
printf("... DFU firmware upgrade device opened\n");
if (download) {
write_dfu_image(firmware_filename);
xmos_dfu_resetfromdfu(XMOS_DFU_IF);
} else if (upload) {
read_dfu_image(firmware_filename);
xmos_dfu_resetfromdfu(XMOS_DFU_IF);
} else if (revert) {
printf("... Reverting device to factory image\n");
xmos_dfu_revertfactory();
// Give device time to revert firmware
system("sleep 2");
xmos_dfu_resetfromdfu(XMOS_DFU_IF);
}
else{
xmos_dfu_resetfromdfu(XMOS_DFU_IF);
}
printf("... Returning device to application mode\n");
}
// END OF DFU APPLICATION MODE
libusb_release_interface(devh, 0);
libusb_close(devh);
libusb_exit(NULL);
return true;
}