static int perform_recovery(struct cli_state *state, uint8_t bus, uint8_t addr, const char *firmware_file) { int status; libusb_context *ctx; libusb_device_handle *handle = NULL; status = libusb_init(&ctx); if (status != 0) { return CMD_RET_UNKNOWN; } status = find_device(state, ctx, bus, addr, &handle, false); if (status == 0) { status = ezusb_load_ram(handle, firmware_file, FX_TYPE_FX3, IMG_TYPE_IMG, 0); } libusb_close(handle); libusb_exit(ctx); return status; }
int main(int argc, char*argv[]) { const char *link_path = 0; const char *ihex_path = 0; const char *device_path = getenv("DEVICE"); const char *type = 0; const char *stage1 = 0; mode_t mode = 0; int opt; int config = -1; while ((opt = getopt (argc, argv, "2vV?D:I:L:c:lm:s:t:")) != EOF) switch (opt) { case '2': // original version of "-t fx2" type = "fx2"; break; case 'D': device_path = optarg; break; case 'I': ihex_path = optarg; break; case 'L': link_path = optarg; break; case 'V': puts (FXLOAD_VERSION); return 0; case 'c': config = strtoul (optarg, 0, 0); if (config < 0 || config > 255) { logerror("illegal config byte: %s\n", optarg); goto usage; } break; case 'l': openlog(argv[0], LOG_CONS|LOG_NOWAIT|LOG_PERROR, LOG_USER); dosyslog=1; break; case 'm': mode = strtoul(optarg,0,0); mode &= 0777; break; case 's': stage1 = optarg; break; case 't': if (strcmp (optarg, "an21") // original AnchorChips parts && strcmp (optarg, "fx") // updated Cypress versions && strcmp (optarg, "fx2") // Cypress USB 2.0 versions && strcmp (optarg, "fx2lp") // updated FX2 ) { logerror("illegal microcontroller type: %s\n", optarg); goto usage; } type = optarg; break; case 'v': verbose++; break; case '?': default: goto usage; } if (config >= 0) { if (type == 0) { logerror("must specify microcontroller type %s", "to write EEPROM!\n"); goto usage; } if (!stage1 || !ihex_path) { logerror("need 2nd stage loader and firmware %s", "to write EEPROM!\n"); goto usage; } if (link_path || mode) { logerror("links and modes not set up when writing EEPROM\n"); goto usage; } } if (!device_path) { logerror("no device specified!\n"); usage: fputs ("usage: ", stderr); fputs (argv [0], stderr); fputs (" [-vV] [-l] [-t type] [-D devpath]\n", stderr); fputs ("\t\t[-I firmware_hexfile] ", stderr); fputs ("[-s loader] [-c config_byte]\n", stderr); fputs ("\t\t[-L link] [-m mode]\n", stderr); fputs ("... [-D devpath] overrides DEVICE= in env\n", stderr); fputs ("... device types: one of an21, fx, fx2, fx2lp\n", stderr); fputs ("... at least one of -I, -L, -m is required\n", stderr); return -1; } if (ihex_path) { int fd = open(device_path, O_RDWR); int status; int fx2; if (fd == -1) { logerror("%s : %s\n", strerror(errno), device_path); return -1; } if (type == 0) { type = "fx"; /* an21-compatible for most purposes */ fx2 = 0; } else if (strcmp (type, "fx2lp") == 0) fx2 = 2; else fx2 = (strcmp (type, "fx2") == 0); if (verbose) logerror("microcontroller type: %s\n", type); if (stage1) { /* first stage: put loader into internal memory */ if (verbose) logerror("1st stage: load 2nd stage loader\n"); status = ezusb_load_ram (fd, stage1, fx2, 0); if (status != 0) return status; /* second stage ... write either EEPROM, or RAM. */ if (config >= 0) status = ezusb_load_eeprom (fd, ihex_path, type, config); else status = ezusb_load_ram (fd, ihex_path, fx2, 1); if (status != 0) return status; } else { /* single stage, put into internal memory */ if (verbose) logerror("single stage: load on-chip memory\n"); status = ezusb_load_ram (fd, ihex_path, fx2, 0); if (status != 0) return status; } /* some firmware won't renumerate, but typically it will. * link and chmod only make sense without renumeration... */ } if (link_path) { int rc = unlink(link_path); rc = symlink(device_path, link_path); if (rc == -1) { logerror("%s : %s\n", strerror(errno), link_path); return -1; } } if (mode != 0) { int rc = chmod(device_path, mode); if (rc == -1) { logerror("%s : %s\n", strerror(errno), link_path); return -1; } } if (!ihex_path && !link_path && !mode) { logerror("missing request! (firmware, link, or mode)\n"); return -1; } return 0; }
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 i, j, opt, status; 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: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 '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_debug(NULL, 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)) { printf("Check Point 1\n"); // 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)) { printf("Check Point 2\n"); 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)) { printf("Check Point 3\n"); 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)) ) { printf("Check Point 4\n"); fx_type = known_device[j].type; vid = desc.idVendor; pid = desc.idProduct; busnum = _busnum; devaddr = _devaddr; break; } } printf("Check Point 5\n"); } if (j < ARRAYSIZE(known_device)) { printf("Check Point 6\n"); if (verbose) logerror("found device '%s' [%04x:%04x] (%d,%d)\n", known_device[j].designation, vid, pid, busnum, devaddr); break; } } } } if (dev == NULL) { printf("Check Point 7\n"); libusb_free_device_list(devs, 1); 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); if (status < 0) { logerror("libusb_open() failed: %s\n", libusb_error_name(status)); goto err; } libusb_free_device_list(devs, 1); } else if (device_id != NULL) { printf("Check Point 9\n"); printf("Check Point 9 vid %d\n", pid); printf("Check Point 9 pid %d\n", vid); 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 */ printf("Check Point 10\n"); libusb_set_auto_detach_kernel_driver(device, 1); status = libusb_claim_interface(device, 0); if (status != LIBUSB_SUCCESS) { 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]]); } printf("Check Point 11\n"); printf("Check Point 11 img_type[FIRMWARE] %d\n", img_type[FIRMWARE]); printf("Check Point 11 fx_type %d\n", fx_type); /* 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); libusb_release_interface(device, 0); libusb_close(device); libusb_exit(NULL); return status; err: libusb_exit(NULL); return -1; }
// Open connection to a Tacx Fortius // // The Fortius handlebar controller is an EZ-USB device. This is an // embedded system using an 8051 microcontroller. Firmware must be // downloaded to it once it is connected. This firmware is obviously // copyrighted by Tacx and is not distributed with Golden Cheetah. // Instead we ask the user to tell us where it can be found when they // configure the device. (On Windows platforms the firmware is installed // by the standard Tacx software as c:\windows\system32\FortiusSWPID1942Renum.hex). // // So when we open a Fortius device we need to search for an unitialised // handlebar controller 3651:e6be and upload the firmware using the EzUsb // functions. Once that has completed the controller will represent itself // as 3651:1942. // // Firmware will need to be reloaded if the device is disconnected or the // USB controller is reset after sleep/resume. // // The EZUSB code is found in EzUsb.c, which is essentially the code used // in the 'fxload' command on Linux, some minor changes have been made to the // standard code wrt to logging errors. // // The only function we use is: // int ezusb_load_ram (usb_dev_handle *device, const char *path, int fx2, int stage) // device is a usb device handle // path is the filename of the firmware file // fx2 is non-zero to indicate an fx2 device (we pass 0, since the Fortius is fx) // stage is to control two stage loading, we load in a single stage struct usb_dev_handle* LibUsb::OpenFortius() { struct usb_bus* bus; struct usb_device* dev; struct usb_dev_handle* udev; bool programmed = false; // // Search for an UN-INITIALISED Fortius device // for (bus = usb_get_busses(); bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == FORTIUS_VID && dev->descriptor.idProduct == FORTIUS_INIT_PID) { if ((udev = usb_open(dev))) { // LOAD THE FIRMWARE ezusb_load_ram (udev, appsettings->value(NULL, FORTIUS_FIRMWARE, "").toString().toLatin1(), 0, 0); } // Now close the connection, our work here is done usb_close(udev); programmed = true; } } } // We need to rescan devices, since once the Fortius has // been programmed it will present itself again with a // different PID. But it takes its time, so we sleep for // 3 seconds. This may be too short on some operating // systems. We can fix if issues are reported. On my Linux // host running a v3 kernel on an AthlonXP 2 seconds is not // long enough. // // Given this is only required /the first time/ the Fortius // is connected, it can't be that bad? if (programmed == true) { #ifdef WIN32 Sleep(3000); // windows sleep is in milliseconds #else sleep(3); // do not be tempted to reduce this, it really does take that long! #endif usb_find_busses(); usb_find_devices(); } // // Now search for an INITIALISED Fortius device // for (bus = usb_get_busses(); bus; bus = bus->next) { for (dev = bus->devices; dev; dev = dev->next) { if (dev->descriptor.idVendor == FORTIUS_VID && (dev->descriptor.idProduct == FORTIUS_PID || dev->descriptor.idProduct == FORTIUSVR_PID)) { //Avoid noisy output //qDebug() << "Found a Garmin USB2 ANT+ stick"; if ((udev = usb_open(dev))) { if (dev->descriptor.bNumConfigurations) { if ((intf = usb_find_interface(&dev->config[0])) != NULL) { int rc = usb_set_configuration(udev, 1); if (rc < 0) { qDebug()<<"usb_set_configuration Error: "<< usb_strerror(); if (OperatingSystem == LINUX) { // looks like the udev rule has not been implemented qDebug()<<"check permissions on:"<<QString("/dev/bus/usb/%1/%2").arg(bus->dirname).arg(dev->filename); qDebug()<<"did you remember to setup a udev rule for this device?"; } } rc = usb_claim_interface(udev, interface); if (rc < 0) qDebug()<<"usb_claim_interface Error: "<< usb_strerror(); if (OperatingSystem != OSX) { // fails on Mac OS X, we don't actually need it anyway rc = usb_set_altinterface(udev, alternate); if (rc < 0) qDebug()<<"usb_set_altinterface Error: "<< usb_strerror(); } return udev; } } usb_close(udev); } } } } return NULL; }