Home | History | Annotate | Download | only in examples
      1 /*
      2  * Copyright  2001 Stephen Williams (steve (at) icarus.com)
      3  * Copyright  2001-2002 David Brownell (dbrownell (at) users.sourceforge.net)
      4  * Copyright  2008 Roger Williams (rawqux (at) users.sourceforge.net)
      5  * Copyright  2012 Pete Batard (pete (at) akeo.ie)
      6  * Copyright  2013 Federico Manzan (f.manzan (at) gmail.com)
      7  *
      8  *    This source code is free software; you can redistribute it
      9  *    and/or modify it in source code form under the terms of the GNU
     10  *    General Public License as published by the Free Software
     11  *    Foundation; either version 2 of the License, or (at your option)
     12  *    any later version.
     13  *
     14  *    This program is distributed in the hope that it will be useful,
     15  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *    GNU General Public License for more details.
     18  *
     19  *    You should have received a copy of the GNU General Public License
     20  *    along with this program; if not, write to the Free Software
     21  *    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
     22  */
     23 
     24 #include <stdlib.h>
     25 #include <stdio.h>
     26 #include <string.h>
     27 #include <stdint.h>
     28 #include <stdarg.h>
     29 #include <sys/types.h>
     30 #include <getopt.h>
     31 
     32 #include "libusb.h"
     33 #include "ezusb.h"
     34 
     35 #if !defined(_WIN32) || defined(__CYGWIN__ )
     36 #include <syslog.h>
     37 static bool dosyslog = false;
     38 #include <strings.h>
     39 #define _stricmp strcasecmp
     40 #endif
     41 
     42 #ifndef FXLOAD_VERSION
     43 #define FXLOAD_VERSION (__DATE__ " (libusb)")
     44 #endif
     45 
     46 #ifndef ARRAYSIZE
     47 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
     48 #endif
     49 
     50 void logerror(const char *format, ...)
     51 	__attribute__ ((format (__printf__, 1, 2)));
     52 
     53 void logerror(const char *format, ...)
     54 {
     55 	va_list ap;
     56 	va_start(ap, format);
     57 
     58 #if !defined(_WIN32) || defined(__CYGWIN__ )
     59 	if (dosyslog)
     60 		vsyslog(LOG_ERR, format, ap);
     61 	else
     62 #endif
     63 		vfprintf(stderr, format, ap);
     64 	va_end(ap);
     65 }
     66 
     67 static int print_usage(int error_code) {
     68 	fprintf(stderr, "\nUsage: fxload [-v] [-V] [-t type] [-d vid:pid] [-p bus,addr] [-s loader] -i firmware\n");
     69 	fprintf(stderr, "  -i <path>       -- Firmware to upload\n");
     70 	fprintf(stderr, "  -s <path>       -- Second stage loader\n");
     71 	fprintf(stderr, "  -t <type>       -- Target type: an21, fx, fx2, fx2lp, fx3\n");
     72 	fprintf(stderr, "  -d <vid:pid>    -- Target device, as an USB VID:PID\n");
     73 	fprintf(stderr, "  -p <bus,addr>   -- Target device, as a libusb bus number and device address path\n");
     74 	fprintf(stderr, "  -v              -- Increase verbosity\n");
     75 	fprintf(stderr, "  -q              -- Decrease verbosity (silent mode)\n");
     76 	fprintf(stderr, "  -V              -- Print program version\n");
     77 	return error_code;
     78 }
     79 
     80 #define FIRMWARE 0
     81 #define LOADER 1
     82 int main(int argc, char*argv[])
     83 {
     84 	fx_known_device known_device[] = FX_KNOWN_DEVICES;
     85 	const char *path[] = { NULL, NULL };
     86 	const char *device_id = NULL;
     87 	const char *device_path = getenv("DEVICE");
     88 	const char *type = NULL;
     89 	const char *fx_name[FX_TYPE_MAX] = FX_TYPE_NAMES;
     90 	const char *ext, *img_name[] = IMG_TYPE_NAMES;
     91 	int fx_type = FX_TYPE_UNDEFINED, img_type[ARRAYSIZE(path)];
     92 	int opt, status;
     93 	unsigned int i, j;
     94 	unsigned vid = 0, pid = 0;
     95 	unsigned busnum = 0, devaddr = 0, _busnum, _devaddr;
     96 	libusb_device *dev, **devs;
     97 	libusb_device_handle *device = NULL;
     98 	struct libusb_device_descriptor desc;
     99 
    100 	while ((opt = getopt(argc, argv, "qvV?hd:p:i:I:s:S:t:")) != EOF)
    101 		switch (opt) {
    102 
    103 		case 'd':
    104 			device_id = optarg;
    105 			if (sscanf(device_id, "%x:%x" , &vid, &pid) != 2 ) {
    106 				fputs ("please specify VID & PID as \"vid:pid\" in hexadecimal format\n", stderr);
    107 				return -1;
    108 			}
    109 			break;
    110 
    111 		case 'p':
    112 			device_path = optarg;
    113 			if (sscanf(device_path, "%u,%u", &busnum, &devaddr) != 2 ) {
    114 				fputs ("please specify bus number & device number as \"bus,dev\" in decimal format\n", stderr);
    115 				return -1;
    116 			}
    117 			break;
    118 
    119 		case 'i':
    120 		case 'I':
    121 			path[FIRMWARE] = optarg;
    122 			break;
    123 
    124 		case 's':
    125 		case 'S':
    126 			path[LOADER] = optarg;
    127 			break;
    128 
    129 		case 'V':
    130 			puts(FXLOAD_VERSION);
    131 			return 0;
    132 
    133 		case 't':
    134 			type = optarg;
    135 			break;
    136 
    137 		case 'v':
    138 			verbose++;
    139 			break;
    140 
    141 		case 'q':
    142 			verbose--;
    143 			break;
    144 
    145 		case '?':
    146 		case 'h':
    147 		default:
    148 			return print_usage(-1);
    149 
    150 	}
    151 
    152 	if (path[FIRMWARE] == NULL) {
    153 		logerror("no firmware specified!\n");
    154 		return print_usage(-1);
    155 	}
    156 	if ((device_id != NULL) && (device_path != NULL)) {
    157 		logerror("only one of -d or -p can be specified\n");
    158 		return print_usage(-1);
    159 	}
    160 
    161 	/* determine the target type */
    162 	if (type != NULL) {
    163 		for (i=0; i<FX_TYPE_MAX; i++) {
    164 			if (strcmp(type, fx_name[i]) == 0) {
    165 				fx_type = i;
    166 				break;
    167 			}
    168 		}
    169 		if (i >= FX_TYPE_MAX) {
    170 			logerror("illegal microcontroller type: %s\n", type);
    171 			return print_usage(-1);
    172 		}
    173 	}
    174 
    175 	/* open the device using libusb */
    176 	status = libusb_init(NULL);
    177 	if (status < 0) {
    178 		logerror("libusb_init() failed: %s\n", libusb_error_name(status));
    179 		return -1;
    180 	}
    181 	libusb_set_debug(NULL, verbose);
    182 
    183 	/* try to pick up missing parameters from known devices */
    184 	if ((type == NULL) || (device_id == NULL) || (device_path != NULL)) {
    185 		if (libusb_get_device_list(NULL, &devs) < 0) {
    186 			logerror("libusb_get_device_list() failed: %s\n", libusb_error_name(status));
    187 			goto err;
    188 		}
    189 		for (i=0; (dev=devs[i]) != NULL; i++) {
    190 			_busnum = libusb_get_bus_number(dev);
    191 			_devaddr = libusb_get_device_address(dev);
    192 			if ((type != NULL) && (device_path != NULL)) {
    193 				// if both a type and bus,addr were specified, we just need to find our match
    194 				if ((libusb_get_bus_number(dev) == busnum) && (libusb_get_device_address(dev) == devaddr))
    195 					break;
    196 			} else {
    197 				status = libusb_get_device_descriptor(dev, &desc);
    198 				if (status >= 0) {
    199 					if (verbose >= 3) {
    200 						logerror("examining %04x:%04x (%d,%d)\n",
    201 							desc.idVendor, desc.idProduct, _busnum, _devaddr);
    202 					}
    203 					for (j=0; j<ARRAYSIZE(known_device); j++) {
    204 						if ((desc.idVendor == known_device[j].vid)
    205 							&& (desc.idProduct == known_device[j].pid)) {
    206 							if (// nothing was specified
    207 								((type == NULL) && (device_id == NULL) && (device_path == NULL)) ||
    208 								// vid:pid was specified and we have a match
    209 								((type == NULL) && (device_id != NULL) && (vid == desc.idVendor) && (pid == desc.idProduct)) ||
    210 								// bus,addr was specified and we have a match
    211 								((type == NULL) && (device_path != NULL) && (busnum == _busnum) && (devaddr == _devaddr)) ||
    212 								// type was specified and we have a match
    213 								((type != NULL) && (device_id == NULL) && (device_path == NULL) && (fx_type == known_device[j].type)) ) {
    214 								fx_type = known_device[j].type;
    215 								vid = desc.idVendor;
    216 								pid = desc.idProduct;
    217 								busnum = _busnum;
    218 								devaddr = _devaddr;
    219 								break;
    220 							}
    221 						}
    222 					}
    223 					if (j < ARRAYSIZE(known_device)) {
    224 						if (verbose)
    225 							logerror("found device '%s' [%04x:%04x] (%d,%d)\n",
    226 								known_device[j].designation, vid, pid, busnum, devaddr);
    227 						break;
    228 					}
    229 				}
    230 			}
    231 		}
    232 		if (dev == NULL) {
    233 			libusb_free_device_list(devs, 1);
    234 			libusb_exit(NULL);
    235 			logerror("could not find a known device - please specify type and/or vid:pid and/or bus,dev\n");
    236 			return print_usage(-1);
    237 		}
    238 		status = libusb_open(dev, &device);
    239 		libusb_free_device_list(devs, 1);
    240 		if (status < 0) {
    241 			logerror("libusb_open() failed: %s\n", libusb_error_name(status));
    242 			goto err;
    243 		}
    244 	} else if (device_id != NULL) {
    245 		device = libusb_open_device_with_vid_pid(NULL, (uint16_t)vid, (uint16_t)pid);
    246 		if (device == NULL) {
    247 			logerror("libusb_open() failed\n");
    248 			goto err;
    249 		}
    250 	}
    251 
    252 	/* We need to claim the first interface */
    253 	libusb_set_auto_detach_kernel_driver(device, 1);
    254 	status = libusb_claim_interface(device, 0);
    255 	if (status != LIBUSB_SUCCESS) {
    256 		libusb_close(device);
    257 		logerror("libusb_claim_interface failed: %s\n", libusb_error_name(status));
    258 		goto err;
    259 	}
    260 
    261 	if (verbose)
    262 		logerror("microcontroller type: %s\n", fx_name[fx_type]);
    263 
    264 	for (i=0; i<ARRAYSIZE(path); i++) {
    265 		if (path[i] != NULL) {
    266 			ext = path[i] + strlen(path[i]) - 4;
    267 			if ((_stricmp(ext, ".hex") == 0) || (strcmp(ext, ".ihx") == 0))
    268 				img_type[i] = IMG_TYPE_HEX;
    269 			else if (_stricmp(ext, ".iic") == 0)
    270 				img_type[i] = IMG_TYPE_IIC;
    271 			else if (_stricmp(ext, ".bix") == 0)
    272 				img_type[i] = IMG_TYPE_BIX;
    273 			else if (_stricmp(ext, ".img") == 0)
    274 				img_type[i] = IMG_TYPE_IMG;
    275 			else {
    276 				logerror("%s is not a recognized image type\n", path[i]);
    277 				goto err;
    278 			}
    279 		}
    280 		if (verbose && path[i] != NULL)
    281 			logerror("%s: type %s\n", path[i], img_name[img_type[i]]);
    282 	}
    283 
    284 	if (path[LOADER] == NULL) {
    285 		/* single stage, put into internal memory */
    286 		if (verbose > 1)
    287 			logerror("single stage: load on-chip memory\n");
    288 		status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 0);
    289 	} else {
    290 		/* two-stage, put loader into internal memory */
    291 		if (verbose > 1)
    292 			logerror("1st stage: load 2nd stage loader\n");
    293 		status = ezusb_load_ram(device, path[LOADER], fx_type, img_type[LOADER], 0);
    294 		if (status == 0) {
    295 			/* two-stage, put firmware into internal memory */
    296 			if (verbose > 1)
    297 				logerror("2nd state: load on-chip memory\n");
    298 			status = ezusb_load_ram(device, path[FIRMWARE], fx_type, img_type[FIRMWARE], 1);
    299 		}
    300 	}
    301 
    302 	libusb_release_interface(device, 0);
    303 	libusb_close(device);
    304 	libusb_exit(NULL);
    305 	return status;
    306 err:
    307 	libusb_exit(NULL);
    308 	return -1;
    309 }
    310