/* * Copyright © 2001 Stephen Williams (steve@icarus.com) * Copyright © 2001-2002 David Brownell (dbrownell@users.sourceforge.net) * Copyright © 2008 Roger Williams (rawqux@users.sourceforge.net) * Copyright © 2012 Pete Batard (pete@akeo.ie) * Copyright © 2013 Federico Manzan (f.manzan@gmail.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU * General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #include #include #include #include #include #include #include #include #include "libusb.h" #include "ezusb.h" #if !defined(_WIN32) || defined(__CYGWIN__) #include static bool dosyslog = false; #include #define _stricmp strcasecmp #endif #ifndef FXLOAD_VERSION #define FXLOAD_VERSION (__DATE__ " (libusb)") #endif #ifndef ARRAYSIZE #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) #endif void logerror(const char *format, ...) { va_list ap; va_start(ap, format); #if !defined(_WIN32) || defined(__CYGWIN__) if (dosyslog) vsyslog(LOG_ERR, format, ap); else #endif vfprintf(stderr, format, ap); va_end(ap); } static int print_usage(int error_code) { fprintf(stderr, "\nUsage: fxload [-v] [-V] [-t type] [-d vid:pid] [-p bus,addr] [-s loader] -i firmware\n"); fprintf(stderr, " -i -- Firmware to upload\n"); fprintf(stderr, " -s -- Second stage loader\n"); fprintf(stderr, " -t -- Target type: an21, fx, fx2, fx2lp, fx3\n"); fprintf(stderr, " -d -- Target device, as an USB VID:PID\n"); fprintf(stderr, " -p -- Target device, as a libusb bus number and device address path\n"); fprintf(stderr, " -v -- Increase verbosity\n"); fprintf(stderr, " -q -- Decrease verbosity (silent mode)\n"); fprintf(stderr, " -V -- Print program version\n"); return error_code; } #define FIRMWARE 0 #define LOADER 1 int main(int argc, char*argv[]) { fx_known_device known_device[] = FX_KNOWN_DEVICES; const char *path[] = { NULL, NULL }; const char *device_id = NULL; const char *device_path = getenv("DEVICE"); const char *type = NULL; const char *fx_name[FX_TYPE_MAX] = FX_TYPE_NAMES; const char *ext, *img_name[] = IMG_TYPE_NAMES; int fx_type = FX_TYPE_UNDEFINED, img_type[ARRAYSIZE(path)]; int opt, status; unsigned int i, j; unsigned vid = 0, pid = 0; unsigned busnum = 0, devaddr = 0, _busnum, _devaddr; libusb_device *dev, **devs; libusb_device_handle *device = NULL; struct libusb_device_descriptor desc; while ((opt = getopt(argc, argv, "qvV?hd:p:i:I:s:S:t:")) != EOF) switch (opt) { case 'd': device_id = optarg; if (sscanf(device_id, "%x:%x" , &vid, &pid) != 2 ) { fputs ("please specify VID & PID as \"vid:pid\" in hexadecimal format\n", stderr); return -1; } break; case 'p': device_path = optarg; if (sscanf(device_path, "%u,%u", &busnum, &devaddr) != 2 ) { fputs ("please specify bus number & device number as \"bus,dev\" in decimal format\n", stderr); return -1; } break; case 'i': case 'I': path[FIRMWARE] = optarg; break; case 's': case 'S': path[LOADER] = optarg; break; case 'V': puts(FXLOAD_VERSION); return 0; case 't': type = optarg; break; case 'v': verbose++; break; case 'q': verbose--; break; case '?': case 'h': default: return print_usage(-1); } if (path[FIRMWARE] == NULL) { logerror("no firmware specified!\n"); return print_usage(-1); } if ((device_id != NULL) && (device_path != NULL)) { logerror("only one of -d or -p can be specified\n"); return print_usage(-1); } /* determine the target type */ if (type != NULL) { for (i=0; i= FX_TYPE_MAX) { logerror("illegal microcontroller type: %s\n", type); return print_usage(-1); } } /* open the device using libusb */ status = libusb_init_context(/*ctx=*/NULL, /*options=*/NULL, /*num_options=*/0); if (status < 0) { logerror("libusb_init_context() failed: %s\n", libusb_error_name(status)); return -1; } libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, verbose); /* try to pick up missing parameters from known devices */ if ((type == NULL) || (device_id == NULL) || (device_path != NULL)) { if (libusb_get_device_list(NULL, &devs) < 0) { logerror("libusb_get_device_list() failed: %s\n", libusb_error_name(status)); goto err; } for (i=0; (dev=devs[i]) != NULL; i++) { _busnum = libusb_get_bus_number(dev); _devaddr = libusb_get_device_address(dev); if ((type != NULL) && (device_path != NULL)) { // if both a type and bus,addr were specified, we just need to find our match if ((libusb_get_bus_number(dev) == busnum) && (libusb_get_device_address(dev) == devaddr)) break; } else { status = libusb_get_device_descriptor(dev, &desc); if (status >= 0) { if (verbose >= 3) { logerror("examining %04x:%04x (%d,%d)\n", desc.idVendor, desc.idProduct, _busnum, _devaddr); } for (j=0; j 1) logerror("single stage: load on-chip memory\n"); status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 0); } else { /* two-stage, put loader into internal memory */ if (verbose > 1) logerror("1st stage: load 2nd stage loader\n"); status = ezusb_load_ram(device, path[LOADER], fx_type, img_type[LOADER], 0); if (status == 0) { /* two-stage, put firmware into internal memory */ if (verbose > 1) logerror("2nd state: load on-chip memory\n"); status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 1); } } libusb_release_interface(device, 0); libusb_close(device); libusb_exit(NULL); return status; err: libusb_exit(NULL); return -1; }