| /* |
| * 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 <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdint.h> |
| #include <stdarg.h> |
| #include <sys/types.h> |
| #include <getopt.h> |
| |
| #include "libusb.h" |
| #include "ezusb.h" |
| |
| #if !defined(_WIN32) || defined(__CYGWIN__ ) |
| #include <syslog.h> |
| static bool dosyslog = false; |
| #include <strings.h> |
| #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, ...) |
| __attribute__ ((format (__printf__, 1, 2))); |
| |
| 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 <path> -- Firmware to upload\n"); |
| fprintf(stderr, " -s <path> -- Second stage loader\n"); |
| fprintf(stderr, " -t <type> -- Target type: an21, fx, fx2, fx2lp, fx3\n"); |
| fprintf(stderr, " -d <vid:pid> -- Target device, as an USB VID:PID\n"); |
| fprintf(stderr, " -p <bus,addr> -- 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; i++) { |
| if (strcmp(type, fx_name[i]) == 0) { |
| fx_type = i; |
| break; |
| } |
| } |
| if (i >= FX_TYPE_MAX) { |
| logerror("illegal microcontroller type: %s\n", type); |
| return print_usage(-1); |
| } |
| } |
| |
| /* open the device using libusb */ |
| status = libusb_init(NULL); |
| if (status < 0) { |
| logerror("libusb_init() 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<ARRAYSIZE(known_device); j++) { |
| if ((desc.idVendor == known_device[j].vid) |
| && (desc.idProduct == known_device[j].pid)) { |
| if (// nothing was specified |
| ((type == NULL) && (device_id == NULL) && (device_path == NULL)) || |
| // vid:pid was specified and we have a match |
| ((type == NULL) && (device_id != NULL) && (vid == desc.idVendor) && (pid == desc.idProduct)) || |
| // bus,addr was specified and we have a match |
| ((type == NULL) && (device_path != NULL) && (busnum == _busnum) && (devaddr == _devaddr)) || |
| // type was specified and we have a match |
| ((type != NULL) && (device_id == NULL) && (device_path == NULL) && (fx_type == known_device[j].type)) ) { |
| fx_type = known_device[j].type; |
| vid = desc.idVendor; |
| pid = desc.idProduct; |
| busnum = _busnum; |
| devaddr = _devaddr; |
| break; |
| } |
| } |
| } |
| if (j < ARRAYSIZE(known_device)) { |
| if (verbose) |
| logerror("found device '%s' [%04x:%04x] (%d,%d)\n", |
| known_device[j].designation, vid, pid, busnum, devaddr); |
| break; |
| } |
| } |
| } |
| } |
| if (dev == NULL) { |
| libusb_free_device_list(devs, 1); |
| libusb_exit(NULL); |
| logerror("could not find a known device - please specify type and/or vid:pid and/or bus,dev\n"); |
| return print_usage(-1); |
| } |
| status = libusb_open(dev, &device); |
| libusb_free_device_list(devs, 1); |
| if (status < 0) { |
| logerror("libusb_open() failed: %s\n", libusb_error_name(status)); |
| goto err; |
| } |
| } else if (device_id != NULL) { |
| device = libusb_open_device_with_vid_pid(NULL, (uint16_t)vid, (uint16_t)pid); |
| if (device == NULL) { |
| logerror("libusb_open() failed\n"); |
| goto err; |
| } |
| } |
| |
| /* We need to claim the first interface */ |
| libusb_set_auto_detach_kernel_driver(device, 1); |
| status = libusb_claim_interface(device, 0); |
| if (status != LIBUSB_SUCCESS) { |
| libusb_close(device); |
| logerror("libusb_claim_interface failed: %s\n", libusb_error_name(status)); |
| goto err; |
| } |
| |
| if (verbose) |
| logerror("microcontroller type: %s\n", fx_name[fx_type]); |
| |
| for (i=0; i<ARRAYSIZE(path); i++) { |
| if (path[i] != NULL) { |
| ext = path[i] + strlen(path[i]) - 4; |
| if ((_stricmp(ext, ".hex") == 0) || (strcmp(ext, ".ihx") == 0)) |
| img_type[i] = IMG_TYPE_HEX; |
| else if (_stricmp(ext, ".iic") == 0) |
| img_type[i] = IMG_TYPE_IIC; |
| else if (_stricmp(ext, ".bix") == 0) |
| img_type[i] = IMG_TYPE_BIX; |
| else if (_stricmp(ext, ".img") == 0) |
| img_type[i] = IMG_TYPE_IMG; |
| else { |
| logerror("%s is not a recognized image type\n", path[i]); |
| goto err; |
| } |
| } |
| if (verbose && path[i] != NULL) |
| logerror("%s: type %s\n", path[i], img_name[img_type[i]]); |
| } |
| |
| if (path[LOADER] == NULL) { |
| /* single stage, put into internal memory */ |
| if (verbose > 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; |
| } |