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