blob: cb435e2bdf8076a233eabff8edc6dd756227593a [file] [log] [blame]
Kévin Redon26a66092018-10-10 00:30:23 +02001/* libisb utilities
2 *
3 * (C) 2010-2016 by Harald Welte <hwelte@hmw-consulting.de>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19#include <errno.h>
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <stdint.h>
24#include <string.h>
25
26#include <libusb.h>
27
28#include "libusb_util.h"
29
30static char path_buf[USB_MAX_PATH_LEN];
31
32static char *get_path(libusb_device *dev)
33{
34#if (defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102) || (defined(LIBUSBX_API_VERSION) && LIBUSBX_API_VERSION >= 0x01000102)
35 uint8_t path[8];
36 int r,j;
37 r = libusb_get_port_numbers(dev, path, sizeof(path));
38 if (r > 0) {
39 sprintf(path_buf,"%d-%d",libusb_get_bus_number(dev),path[0]);
40 for (j = 1; j < r; j++){
41 sprintf(path_buf+strlen(path_buf),".%d",path[j]);
42 };
43 }
44 return path_buf;
45#else
46# warning "libusb too old - building without USB path support!"
47 return NULL;
48#endif
49}
50
51static int match_dev_id(const struct libusb_device_descriptor *desc, const struct dev_id *id)
52{
53 if ((desc->idVendor == id->vendor_id) && (desc->idProduct == id->product_id))
54 return 1;
55 return 0;
56}
57
58
59static int match_dev_ids(const struct libusb_device_descriptor *desc, const struct dev_id *ids)
60{
61 const struct dev_id *id;
62
63 for (id = ids; id->vendor_id || id->product_id; id++) {
64 if (match_dev_id(desc, id))
65 return 1;
66 }
67 return 0;
68}
69
70libusb_device **find_matching_usb_devs(const struct dev_id *dev_ids)
71{
72 libusb_device **list;
73 libusb_device **out = calloc(256, sizeof(libusb_device *));
74 libusb_device **cur = out;
75 unsigned int i;
76 int rc;
77
78 if (!out)
79 return NULL;
80
81 rc = libusb_get_device_list(NULL, &list);
82 if (rc <= 0) {
83 perror("No USB devices found");
84 free(out);
85 return NULL;
86 }
87
88 for (i = 0; list[i] != NULL; i++) {
89 struct libusb_device_descriptor dev_desc;
90 libusb_device *dev = list[i];
91
92 rc = libusb_get_device_descriptor(dev, &dev_desc);
93 if (rc < 0) {
94 perror("Couldn't get device descriptor\n");
95 libusb_unref_device(dev);
96 continue;
97 }
98
99 if (match_dev_ids(&dev_desc, dev_ids)) {
100 *cur = dev;
101 cur++;
102 /* FIXME: overflow check */
103 } else
104 libusb_unref_device(dev);
105 }
106 if (cur == out) {
107 libusb_free_device_list(list, 1);
108 free(out);
109 return NULL;
110 }
111
112 libusb_free_device_list(list, 0);
113 return out;
114}
115
116int dev_find_matching_interfaces(libusb_device *dev, int class, int sub_class, int protocol,
117 struct usb_interface_match *out, unsigned int out_len)
118{
119 struct libusb_device_descriptor dev_desc;
120 int rc, i, out_idx = 0;
121 uint8_t addr;
122 char *path;
123
124 rc = libusb_get_device_descriptor(dev, &dev_desc);
125 if (rc < 0) {
126 perror("Couldn't get device descriptor\n");
127 return -EIO;
128 }
129
130 addr = libusb_get_device_address(dev);
131 path = get_path(dev);
132
133 /* iterate over all configurations */
134 for (i = 0; i < dev_desc.bNumConfigurations; i++) {
135 struct libusb_config_descriptor *conf_desc;
136 int j;
137
138 rc = libusb_get_config_descriptor(dev, i, &conf_desc);
139 if (rc < 0) {
140 fprintf(stderr, "Couldn't get config descriptor %u\n", i);
141 continue;
142 }
143 /* iterate over all interfaces */
144 for (j = 0; j < conf_desc->bNumInterfaces; j++) {
145 const struct libusb_interface *intf = &conf_desc->interface[j];
146 int k;
147 /* iterate over all alternate settings */
148 for (k = 0; k < intf->num_altsetting; k++) {
149 const struct libusb_interface_descriptor *if_desc;
150 if_desc = &intf->altsetting[k];
151 if (class >= 0 && if_desc->bInterfaceClass != class)
152 continue;
153 if (sub_class >= 0 && if_desc->bInterfaceSubClass != sub_class)
154 continue;
155 if (protocol >= 0 && if_desc->bInterfaceProtocol != protocol)
156 continue;
157 /* MATCH! */
158 out[out_idx].usb_dev = dev;
159 out[out_idx].vendor = dev_desc.idVendor;
160 out[out_idx].product = dev_desc.idProduct;
161 out[out_idx].addr = addr;
162 strncpy(out[out_idx].path, path, sizeof(out[out_idx].path));
163 out[out_idx].path[sizeof(out[out_idx].path)-1] = '\0';
164 out[out_idx].configuration = conf_desc->bConfigurationValue;
165 out[out_idx].interface = if_desc->bInterfaceNumber;
166 out[out_idx].altsetting = if_desc->bAlternateSetting;
167 out[out_idx].class = if_desc->bInterfaceClass;
168 out[out_idx].sub_class = if_desc->bInterfaceSubClass;
169 out[out_idx].protocol = if_desc->bInterfaceProtocol;
170 out[out_idx].string_idx = if_desc->iInterface;
171 out_idx++;
172 if (out_idx >= out_len)
173 return out_idx;
174 }
175 }
176 }
177 return out_idx;
178}
179
180int usb_match_interfaces(libusb_context *ctx, const struct dev_id *dev_ids,
181 int class, int sub_class, int protocol,
182 struct usb_interface_match *out, unsigned int out_len)
183{
184 struct usb_interface_match *out_cur = out;
185 unsigned int out_len_remain = out_len;
186 libusb_device **list;
187 libusb_device **dev;
188
189 list = find_matching_usb_devs(dev_ids);
190 if (!list)
191 return 0;
192
193 for (dev = list; *dev; dev++) {
194 int rc;
195
196#if 0
197 struct libusb_device_descriptor dev_desc;
198 uint8_t ports[8];
199 uint8_t addr;
200 rc = libusb_get_device_descriptor(*dev, &dev_desc);
201 if (rc < 0) {
202 perror("Cannot get device descriptor");
203 continue;
204 }
205
206 addr = libusb_get_device_address(*dev);
207
208 rc = libusb_get_port_numbers(*dev, ports, sizeof(ports));
209 if (rc < 0) {
210 perror("Cannot get device path");
211 continue;
212 }
213
214 printf("Found USB Device %04x:%04x at address %d\n",
215 dev_desc.idVendor, dev_desc.idProduct, addr);
216#endif
217
218 rc = dev_find_matching_interfaces(*dev, class, sub_class, protocol, out_cur, out_len_remain);
219 if (rc < 0)
220 continue;
221 out_cur += rc;
222 out_len_remain -= rc;
223
224 }
225 return out_len - out_len_remain;
226}
227
228libusb_device_handle *usb_open_claim_interface(libusb_context *ctx,
229 const struct usb_interface_match *ifm)
230{
231 int rc, config;
232 struct dev_id dev_ids[] = { { ifm->vendor, ifm->product }, { 0, 0 } };
233 libusb_device **list;
234 libusb_device **dev;
235 libusb_device_handle *usb_devh = NULL;
236
237 list = find_matching_usb_devs(dev_ids);
238 if (!list) {
239 perror("No USB device with matching VID/PID");
240 return NULL;
241 }
242
243 for (dev = list; *dev; dev++) {
244 int addr;
245 char *path;
246
247 addr = libusb_get_device_address(*dev);
248 path = get_path(*dev);
249 if ((ifm->addr && addr == ifm->addr) ||
250 (strlen(ifm->path) && !strcmp(path, ifm->path))) {
251 rc = libusb_open(*dev, &usb_devh);
252 if (rc < 0) {
253 fprintf(stderr, "Cannot open device: %s\n", libusb_error_name(rc));
254 usb_devh = NULL;
255 break;
256 }
257 rc = libusb_get_configuration(usb_devh, &config);
258 if (rc < 0) {
259 fprintf(stderr, "Cannot get current configuration: %s\n", libusb_error_name(rc));
260 libusb_close(usb_devh);
261 usb_devh = NULL;
262 break;
263 }
264 if (config != ifm->configuration) {
265 rc = libusb_set_configuration(usb_devh, ifm->configuration);
266 if (rc < 0) {
267 fprintf(stderr, "Cannot set configuration: %s\n", libusb_error_name(rc));
268 libusb_close(usb_devh);
269 usb_devh = NULL;
270 break;
271 }
272 }
273 rc = libusb_claim_interface(usb_devh, ifm->interface);
274 if (rc < 0) {
275 fprintf(stderr, "Cannot claim interface: %s\n", libusb_error_name(rc));
276 libusb_close(usb_devh);
277 usb_devh = NULL;
278 break;
279 }
280 rc = libusb_set_interface_alt_setting(usb_devh, ifm->interface, ifm->altsetting);
281 if (rc < 0) {
282 fprintf(stderr, "Cannot set interface altsetting: %s\n", libusb_error_name(rc));
283 libusb_release_interface(usb_devh, ifm->interface);
284 libusb_close(usb_devh);
285 usb_devh = NULL;
286 break;
287 }
288 }
289 }
290
291 /* unref / free list */
292 for (dev = list; *dev; dev++)
293 libusb_unref_device(*dev);
294 free(list);
295
296 return usb_devh;
297}