xdebug

next generation of mdebug (work in progress)
git clone http://frotz.net/git/xdebug.git
Log | Files | Refs | README

usb.c (7522B)


      1 // Copyright 2014, Brian Swetland <swetland@frotz.net>
      2 // Licensed under the Apache License, Version 2.0.
      3 
      4 #include <stdlib.h>
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 #include <fcntl.h>
      9 
     10 #include <libusb-1.0/libusb.h>
     11 
     12 #include "usb.h"
     13 
     14 struct usb_handle {
     15 	libusb_device_handle *dev;
     16 	unsigned ei;
     17 	unsigned eo;
     18 };
     19 
     20 int get_sysfs_path(libusb_device* dev, char* path, int max) {
     21 	if (max < 0) return -1;
     22 	uint8_t num[8];
     23 	uint8_t bus = libusb_get_bus_number(dev);
     24 	int count = libusb_get_port_numbers(dev, num, 8);
     25 	if (count < 1) return -1;
     26 	int r = snprintf(path, max, "/sys/bus/usb/devices/%u-%u", bus, num[0]);
     27 	if ((r >= max) || (r < 0)) return -1;
     28 	int len = r;
     29 	for (unsigned n = 1; n < count; n++) {
     30 		r = snprintf(path + len, max - len, ".%u", num[n]);
     31 		if ((r >= (max - len)) || (r < 0)) return -1;
     32 		len += r;
     33 	}
     34 	return len;
     35 }
     36 
     37 int get_vendor_bulk_ifc(struct libusb_config_descriptor *cd, uint8_t* iifc,
     38 			uint8_t *ino, uint8_t *eptin, uint8_t *eptout) {
     39 	const struct libusb_interface_descriptor *id;
     40 	for (unsigned i = 0; i < cd->bNumInterfaces; i++) {
     41 		if (cd->interface[i].num_altsetting != 1) {
     42 			// keep it simple: skip interfaces with alt settings
     43 			continue;
     44 		}
     45 		id = &cd->interface[i].altsetting[0];
     46 		if (id->bInterfaceClass != 0xFF) {
     47 			// require vendor ifc class
     48 			continue;
     49 		}
     50 		if (id->bNumEndpoints != 2) {
     51 			// must have two endpoints
     52 			continue;
     53 		}
     54 		// look for one bulk in, one bulk out
     55 		const struct libusb_endpoint_descriptor *e0 = id->endpoint + 0;
     56 		const struct libusb_endpoint_descriptor *e1 = id->endpoint + 1;
     57 		if ((e0->bmAttributes & 3) != LIBUSB_ENDPOINT_TRANSFER_TYPE_BULK) {
     58 			continue;
     59 		}
     60 		if ((e1->bmAttributes & 3) != LIBUSB_ENDPOINT_TRANSFER_TYPE_BULK) {
     61 			continue;
     62 		}
     63 		if ((e0->bEndpointAddress & 0x80) &&
     64 		    (!(e1->bEndpointAddress & 0x80))) {
     65 			*eptin = e0->bEndpointAddress;
     66 			*eptout = e1->bEndpointAddress;
     67 			goto match;
     68 		} else if ((e1->bEndpointAddress & 0x80) &&
     69 			   (!(e0->bEndpointAddress & 0x80))) {
     70 			*eptin = e1->bEndpointAddress;
     71 			*eptout = e0->bEndpointAddress;
     72 			goto match;
     73 		} else {
     74 			continue;
     75 		}
     76 	}
     77 	return -1;
     78 match:
     79 	*ino = id->bInterfaceNumber;
     80 	*iifc = id->iInterface;
     81 	return 0;
     82 }
     83 
     84 usb_handle *usb_try_open(libusb_device* dev, const char* sn,
     85 			unsigned isn, unsigned iifc,
     86 			unsigned ino, unsigned ei, unsigned eo) {
     87 	unsigned char text[256];
     88 	usb_handle *usb;
     89 	int r;
     90 
     91 	usb = malloc(sizeof(usb_handle));
     92 	if (usb == 0) {
     93 		return NULL;
     94 	}
     95 
     96 	if (libusb_open(dev, &usb->dev) < 0) {
     97 		free(usb);
     98 		return NULL;
     99 	}
    100 
    101 	if (sn && (isn != 0)) {
    102 		r = libusb_get_string_descriptor_ascii(usb->dev, isn, text, 256);
    103 		if (r < 0) {
    104 			goto fail;
    105 		}
    106 		if (strlen(sn) != r) {
    107 			goto fail;
    108 		}
    109 		if (memcmp(text, sn, r)) {
    110 			goto fail;
    111 		}
    112 	}
    113 	if (iifc != 0) {
    114 		r = libusb_get_string_descriptor_ascii(usb->dev, iifc, text, 255);
    115 		if (r < 0) {
    116 			goto fail;
    117 		}
    118 		text[r] = 0;
    119 		if (!strstr((void*)text, "CMSIS-DAP")) {
    120 			goto fail;
    121 		}
    122 	}
    123 
    124 	usb->ei = ei;
    125 	usb->eo = eo;
    126 
    127 	// This causes problems on re-attach.  Maybe need for OSX?
    128 	// On Linux it's completely happy without us explicitly setting a configuration.
    129 	//r = libusb_set_configuration(usb->dev, 1);
    130 	r = libusb_claim_interface(usb->dev, ino);
    131 	if (r < 0) {
    132 		fprintf(stderr, "failed to claim interface #%d\n", ino);
    133 		goto fail;
    134 	}
    135 
    136 #ifdef __APPLE__
    137 	// make sure everyone's data toggles agree
    138 	// makes things worse on Linux, but happy on OSX
    139 	libusb_clear_halt(usb->dev, usb->ei);
    140 	libusb_clear_halt(usb->dev, usb->eo);
    141 #endif
    142 
    143 	return usb;
    144 
    145 fail:
    146 	libusb_close(usb->dev);
    147 	free(usb);
    148 	return NULL;
    149 }
    150 
    151 static int read_sysfs(const char* path, char* text, int len) {
    152 	int fd;
    153 	if ((fd = open(path, O_RDONLY)) < 0) {
    154 		return -1;
    155 	}
    156 	int r = read(fd, text, len);
    157 	if ((r < 1) || (text[r-1] != '\n')) {
    158 		return -1;
    159 	}
    160 	text[r-1] = 0;
    161 	return 0;
    162 }
    163 
    164 static libusb_context *usb_ctx = NULL;
    165 
    166 usb_handle *usb_open(unsigned vid, unsigned pid, const char* sn) {
    167 	usb_handle *usb = NULL;
    168 
    169 	if (usb_ctx == NULL) {
    170 		if (libusb_init(&usb_ctx) < 0) {
    171 			usb_ctx = NULL;
    172 			return NULL;
    173 		}
    174 	}
    175 
    176 	uint8_t ino, eo, ei, iifc;
    177 	libusb_device** list;
    178 	int count = libusb_get_device_list(usb_ctx, &list);
    179 	for (int n = 0; n < count; n++) {
    180 		struct libusb_device_descriptor dd;
    181 		//const struct libusb_interface_descriptor *id;
    182 		if (libusb_get_device_descriptor(list[n], &dd) != 0) {
    183 			continue;
    184 		}
    185 		int isn = dd.iSerialNumber;
    186 		if (vid) {
    187 			// exact match requested
    188 			if ((vid != dd.idVendor) || (pid != dd.idProduct)) {
    189 				continue;
    190 			}
    191 		} else if (dd.bDeviceClass == 0x00) {
    192 			// use interface class: okay
    193 		} else if (dd.bDeviceClass == 0xFF) {
    194 			// vendor class: okay
    195 		} else if ((dd.bDeviceClass == 0xEF) &&
    196 			   (dd.bDeviceSubClass == 0x02) &&
    197 			   (dd.bDeviceProtocol == 0x01)) {
    198 			// interface association descriptor: okay
    199 		} else {
    200 			continue;
    201 		}
    202 		struct libusb_config_descriptor *cd;
    203 		if (libusb_get_active_config_descriptor(list[n], &cd) != 0) {
    204 			continue;
    205 		}
    206 		int r = get_vendor_bulk_ifc(cd, &iifc, &ino, &ei, &eo);
    207 		libusb_free_config_descriptor(cd);
    208 		if (r != 0) {
    209 			continue;
    210 		}
    211 #if 0
    212 		printf("%02x %02x %02x %04x %04x %02x %02x %02x\n",
    213 			dd.bDeviceClass,
    214 			dd.bDeviceSubClass,
    215 			dd.bDeviceProtocol,
    216 			dd.idVendor,
    217 			dd.idProduct,
    218 			ino, ei, eo);
    219 #endif
    220 		// try to validate serialno and interface description
    221 		// using sysfs so we don't need to open the device
    222 		// to rule it out
    223 		char path[512];
    224 		char text[256];
    225 		int len = get_sysfs_path(list[n], path, 512 - 64);
    226 		if (len < 0) {
    227 			// should never happen, but just in case
    228 			continue;
    229 		}
    230 		if (sn) {
    231 			sprintf(path + len, "/serial");
    232 			if (read_sysfs(path, text, sizeof(text)) == 0) {
    233 				if (strcmp(sn, text)) {
    234 					continue;
    235 				}
    236 				// matched here, so don't check after libusb_open()
    237 				isn = 0;
    238 			}
    239 		}
    240 		if (vid == 0) {
    241 			if (iifc == 0) {
    242 				// no interface string at all
    243 				continue;
    244 			}
    245 			// if we're wildcarding it, check interface
    246 			sprintf(path + len, ":%u.%u/interface", 1, 0);
    247 			if (read_sysfs(path, text, sizeof(text)) == 0) {
    248 				if (strstr(text, "CMSIS-DAP") == 0) {
    249 					continue;
    250 				}
    251 				// matched here, so don't check after libusb_open()
    252 				iifc = 0;
    253 			}
    254 		} else {
    255 			// if not wildcarding, don't enforce this check in usb_try_open()
    256 			iifc = 0;
    257 		}
    258 
    259 		if ((usb = usb_try_open(list[n], sn, isn, iifc, ino, ei, eo)) != NULL) {
    260 			break;
    261 		}
    262 	}
    263 	if (count >= 0) {
    264 		libusb_free_device_list(list, 1);
    265 	}
    266 	return usb;
    267 }
    268 
    269 void usb_close(usb_handle *usb) {
    270 	libusb_close(usb->dev);
    271 	free(usb);
    272 }
    273 
    274 int usb_ctrl(usb_handle *usb, void *data,
    275 	uint8_t typ, uint8_t req, uint16_t val, uint16_t idx, uint16_t len) {
    276 	if (usb == NULL) {
    277 		return LIBUSB_ERROR_NO_DEVICE;
    278 	}
    279 	return libusb_control_transfer(usb->dev, typ, req, val, idx, data, len, 5000);
    280 }
    281 
    282 int usb_read(usb_handle *usb, void *data, int len) {
    283 	if (usb == NULL) {
    284 		return LIBUSB_ERROR_NO_DEVICE;
    285 	}
    286 	int xfer = len;
    287 	int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 5000);
    288 	if (r < 0) {
    289 		return r;
    290 	}
    291 	return xfer;
    292 }
    293 
    294 int usb_read_forever(usb_handle *usb, void *data, int len) {
    295 	if (usb == NULL) {
    296 		return LIBUSB_ERROR_NO_DEVICE;
    297 	}
    298 	int xfer = len;
    299 	int r = libusb_bulk_transfer(usb->dev, usb->ei, data, len, &xfer, 0);
    300 	if (r < 0) {
    301 		return r;
    302 	}
    303 	return xfer;
    304 }
    305 
    306 int usb_write(usb_handle *usb, const void *data, int len) {
    307 	if (usb == NULL) {
    308 		return LIBUSB_ERROR_NO_DEVICE;
    309 	}
    310 	int xfer = len;
    311 	int r = libusb_bulk_transfer(usb->dev, usb->eo, (void*) data, len, &xfer, 5000);
    312 	if (r < 0) {
    313 		return r;
    314 	}
    315 	return xfer;
    316 }
    317