blob: 3236e41408f63422e1a85face4b4ae309d677ef4 [file] [log] [blame]
Harald Welte822d66e2017-03-06 20:58:03 +01001#include <errno.h>
2#include <unistd.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <stdint.h>
Harald Weltea6016352017-05-11 01:31:45 +02006#include <string.h>
Harald Welte822d66e2017-03-06 20:58:03 +01007
8#include <libusb.h>
9
10#include "libusb_util.h"
11
Harald Weltea6016352017-05-11 01:31:45 +020012static char path_buf[USB_MAX_PATH_LEN];
13
14static char *get_path(libusb_device *dev)
15{
16#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
17 uint8_t path[8];
18 int r,j;
19 r = libusb_get_port_numbers(dev, path, sizeof(path));
20 if (r > 0) {
21 sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
22 for (j = 1; j < r; j++){
23 sprintf(path_buf+strlen(path_buf),".%d",path[j]);
24 };
25 }
26 return path_buf;
27#else
28# warning "libusb too old - building without USB path support!"
29 return NULL;
30#endif
31}
32
Harald Welte822d66e2017-03-06 20:58:03 +010033static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
34{
35 if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
36 return 1;
37 return 0;
38}
39
40
41static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
42{
43 const struct dev_id *id;
44
45 for (id = ids; id->vendor_id || id->product_id; id++) {
46 if (match_dev_id(desc, id))
47 return 1;
48 }
49 return 0;
50}
51
52libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
53{
54 libusb_device **list;
55 libusb_device **out = calloc(256, sizeof(libusb_device *));
56 libusb_device **cur = out;
57 unsigned int i;
58 int rc;
59
60 if (!out)
61 return NULL;
62
63 rc = libusb_get_device_list(NULL, &list);
64 if (rc <= 0) {
65 perror("No USB devices found");
66 free(out);
67 return NULL;
68 }
69
70 for (i = 0; list[i] != NULL; i++) {
71 struct libusb_device_descriptor dev_desc;
72 libusb_device *dev = list[i];
73
74 rc = libusb_get_device_descriptor(dev, &dev_desc);
75 if (rc < 0) {
76 perror("Couldn't get device descriptor\n");
77 libusb_unref_device(dev);
78 continue;
79 }
80
81 if (match_dev_ids(&dev_desc, dev_ids)) {
82 *cur = dev;
83 cur++;
84 /* FIXME: overflow check */
85 } else
86 libusb_unref_device(dev);
87 }
88 if (cur == out) {
89 libusb_free_device_list(list, 1);
90 free(out);
91 return NULL;
92 }
93
94 libusb_free_device_list(list, 0);
95 return out;
96}
97
98int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
99 struct usb_interface_match *out, unsigned int out_len)
100{
101 struct libusb_device_descriptor dev_desc;
102 int rc, i, out_idx = 0;
103 uint8_t addr;
Harald Weltea6016352017-05-11 01:31:45 +0200104 char *path;
Harald Welte822d66e2017-03-06 20:58:03 +0100105
106 rc = libusb_get_device_descriptor(dev, &dev_desc);
107 if (rc < 0) {
108 perror("Couldn't get device descriptor\n");
109 return -EIO;
110 }
111
112 addr = libusb_get_device_address(dev);
Harald Weltea6016352017-05-11 01:31:45 +0200113 path = get_path(dev);
Harald Welte822d66e2017-03-06 20:58:03 +0100114
115 /* iterate over all configurations */
116 for (i = 0; i < dev_desc.bNumConfigurations; i++) {
117 struct libusb_config_descriptor *conf_desc;
118 int j;
119
120 rc = libusb_get_config_descriptor(dev, i, &conf_desc);
121 if (rc < 0) {
122 fprintf(stderr, "Couldn't get config descriptor %u\n", i);
123 continue;
124 }
125 /* iterate over all interfaces */
126 for (j = 0; j < conf_desc->bNumInterfaces; j++) {
127 const struct libusb_interface *intf = &conf_desc->interface[j];
128 int k;
129 /* iterate over all alternate settings */
130 for (k = 0; k < intf->num_altsetting; k++) {
131 const struct libusb_interface_descriptor *if_desc;
132 if_desc = &intf->altsetting[k];
133 if (class > 0 && if_desc->bInterfaceClass != class)
134 continue;
135 if (sub_class > 0 && if_desc->bInterfaceSubClass != sub_class)
136 continue;
137 if (protocol > 0 && if_desc->bInterfaceProtocol != protocol)
138 continue;
139 /* MATCH! */
140 out[out_idx].usb_dev = dev;
141 out[out_idx].vendor = dev_desc.idVendor;
142 out[out_idx].product = dev_desc.idProduct;
143 out[out_idx].addr = addr;
Harald Weltea6016352017-05-11 01:31:45 +0200144 strncpy(out[out_idx].path, path, sizeof(out[out_idx].path));
145 out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
Harald Welte822d66e2017-03-06 20:58:03 +0100146 out[out_idx].configuration = conf_desc->bConfigurationValue;
147 out[out_idx].interface = if_desc->bInterfaceNumber;
148 out[out_idx].altsetting = if_desc->bAlternateSetting;
149 out[out_idx].class = if_desc->bInterfaceClass;
150 out[out_idx].sub_class = if_desc->bInterfaceSubClass;
151 out[out_idx].protocol = if_desc->bInterfaceProtocol;
152 out[out_idx].string_idx = if_desc->iInterface;
153 out_idx++;
154 if (out_idx >= out_len)
155 return out_idx;
156 }
157 }
158 }
159 return out_idx;
160}
161
162int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
163 int class, int sub_class, int protocol,
164 struct usb_interface_match *out, unsigned int out_len)
165{
166 struct usb_interface_match *out_cur = out;
167 unsigned int out_len_remain = out_len;
168 libusb_device **list;
169 libusb_device **dev;
170
171 list = find_matching_usb_devs(dev_ids);
172 if (!list)
173 return 0;
174
175 for (dev = list; *dev; dev++) {
176 int rc;
177
178#if 0
179 struct libusb_device_descriptor dev_desc;
180 uint8_t ports[8];
181 uint8_t addr;
182 rc = libusb_get_device_descriptor(*dev, &dev_desc);
183 if (rc < 0) {
184 perror("Cannot get device descriptor");
185 continue;
186 }
187
188 addr = libusb_get_device_address(*dev);
189
190 rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
191 if (rc < 0) {
192 perror("Cannot get device path");
193 continue;
194 }
195
196 printf("Found USB Device %04x:%04x at address %d\n",
197 dev_desc.idVendor, dev_desc.idProduct, addr);
198#endif
199
200 rc = dev_find_matching_interfaces(*dev, 255, 2, -1, out_cur, out_len_remain);
201 if (rc < 0)
202 continue;
203 out_cur += rc;
204 out_len_remain -= rc;
205
206 }
207 return out_len - out_len_remain;
208}
209
210libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
211 const struct usb_interface_match *ifm)
212{
213 int rc, config;
214 struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
215 libusb_device **list;
216 libusb_device **dev;
217 libusb_device_handle *usb_devh = NULL;
218
219 list = find_matching_usb_devs(dev_ids);
220 if (!list) {
221 perror("No USB device with matching VID/PID");
222 return NULL;
223 }
224
225 for (dev = list; *dev; dev++) {
226 int addr;
Harald Weltea6016352017-05-11 01:31:45 +0200227 char *path;
Harald Welte822d66e2017-03-06 20:58:03 +0100228
229 addr = libusb_get_device_address(*dev);
Harald Weltea6016352017-05-11 01:31:45 +0200230 path = get_path(*dev);
231 if ((ifm->addr && addr == ifm->addr) ||
232 (strlen(ifm->path) && !strcmp(path, ifm->path))) {
Harald Welte822d66e2017-03-06 20:58:03 +0100233 rc = libusb_open(*dev, &usb_devh);
234 if (rc < 0) {
235 perror("Cannot open device");
236 break;
237 }
238 rc = libusb_get_configuration(usb_devh, &config);
239 if (rc < 0) {
240 perror("Cannot get current configuration");
241 libusb_close(usb_devh);
242 break;
243 }
244 if (config != ifm->configuration) {
245 rc = libusb_set_configuration(usb_devh, ifm->configuration);
246 if (rc < 0) {
247 perror("Cannot set configuration");
248 libusb_close(usb_devh);
249 break;
250 }
251 }
252 rc = libusb_claim_interface(usb_devh, ifm->interface);
253 if (rc < 0) {
254 perror("Cannot claim interface");
255 libusb_close(usb_devh);
256 break;
257 }
258 rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
259 if (rc < 0) {
260 perror("Cannot set interface altsetting");
261 libusb_release_interface(usb_devh, ifm->interface);
262 libusb_close(usb_devh);
263 break;
264 }
265 }
266 }
267
268 /* unref / free list */
269 for (dev = list; *dev; dev++)
270 libusb_unref_device(*dev);
271 free(list);
272
273 return usb_devh;
274}