1 /*
2 * Copyright 2018 The ChromiumOS Authors
3 * Use of this source code is governed by a BSD-style license that can be
4 * found in the LICENSE file.
5 */
6
7 #include <stdbool.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11
12 #include "usb_if.h"
13
14 /* Return 0 on error, since it's never gonna be EP 0 */
find_endpoint(const struct libusb_interface_descriptor * iface,uint16_t subclass,uint16_t protocol,struct usb_endpoint * uep)15 static int find_endpoint(const struct libusb_interface_descriptor *iface,
16 uint16_t subclass, uint16_t protocol,
17 struct usb_endpoint *uep)
18 {
19 const struct libusb_endpoint_descriptor *ep;
20
21 if (iface->bInterfaceClass == 255 &&
22 iface->bInterfaceSubClass == subclass &&
23 iface->bInterfaceProtocol == protocol && iface->bNumEndpoints) {
24 ep = &iface->endpoint[0];
25 uep->ep_num = ep->bEndpointAddress & 0x7f;
26 uep->chunk_len = ep->wMaxPacketSize;
27 return 1;
28 }
29
30 return 0;
31 }
32
33 /* Return -1 on error */
find_interface(uint16_t subclass,uint16_t protocol,struct usb_endpoint * uep)34 static int find_interface(uint16_t subclass, uint16_t protocol,
35 struct usb_endpoint *uep)
36 {
37 int iface_num = -1;
38 int r, i, j;
39 struct libusb_device *dev;
40 struct libusb_config_descriptor *conf = 0;
41 const struct libusb_interface *iface0;
42 const struct libusb_interface_descriptor *iface;
43
44 dev = libusb_get_device(uep->devh);
45 r = libusb_get_active_config_descriptor(dev, &conf);
46 if (r < 0) {
47 USB_ERROR("libusb_get_active_config_descriptor", r);
48 goto out;
49 }
50
51 for (i = 0; i < conf->bNumInterfaces; i++) {
52 iface0 = &conf->interface[i];
53 for (j = 0; j < iface0->num_altsetting; j++) {
54 iface = &iface0->altsetting[j];
55 if (find_endpoint(iface, subclass, protocol, uep)) {
56 iface_num = i;
57 goto out;
58 }
59 }
60 }
61
62 out:
63 libusb_free_config_descriptor(conf);
64 return iface_num;
65 }
66
check_device(libusb_device * dev,uint16_t vid,uint16_t * pid,int pid_count,const char * serial)67 static libusb_device_handle *check_device(libusb_device *dev, uint16_t vid,
68 uint16_t *pid, int pid_count,
69 const char *serial)
70 {
71 struct libusb_device_descriptor desc;
72 libusb_device_handle *handle = NULL;
73 char sn[256];
74 size_t sn_size = 0;
75 bool match_failed = false;
76 bool pid_matches = false;
77 int i;
78
79 if (libusb_get_device_descriptor(dev, &desc) < 0)
80 return NULL;
81
82 if (libusb_open(dev, &handle) != LIBUSB_SUCCESS)
83 return NULL;
84
85 if (desc.iSerialNumber && serial) {
86 sn_size = libusb_get_string_descriptor_ascii(
87 handle, desc.iSerialNumber, (unsigned char *)sn,
88 sizeof(sn));
89 }
90 /*
91 * If the VID, PID, and serial number don't match, then it's not the
92 * correct device. Close the handle and return NULL.
93 */
94 match_failed |= vid && vid != desc.idVendor;
95 match_failed |= serial && ((sn_size != strlen(serial)) ||
96 memcmp(sn, serial, sn_size));
97 for (i = 0; i < pid_count; i++)
98 pid_matches |= pid[i] == desc.idProduct;
99 match_failed |= pid_count && !pid_matches;
100
101 if (match_failed) {
102 libusb_close(handle);
103 return NULL;
104 }
105 return handle;
106 }
107
usb_findit(const char * serial,uint16_t vid,uint16_t * pid,int pid_count,uint16_t subclass,uint16_t protocol,struct usb_endpoint * uep)108 int usb_findit(const char *serial, uint16_t vid, uint16_t *pid, int pid_count,
109 uint16_t subclass, uint16_t protocol, struct usb_endpoint *uep)
110 {
111 int iface_num, r, i;
112 libusb_device **devs;
113 libusb_device_handle *devh = NULL;
114 libusb_device_handle *search_handle = NULL;
115 ssize_t count;
116
117 memset(uep, 0, sizeof(*uep));
118
119 /* Must supply either serial or vendor and product ids. */
120 if (!serial && !(vid && pid && pid_count))
121 goto terminate_usb_findit;
122
123 r = libusb_init(NULL);
124 if (r < 0) {
125 USB_ERROR("libusb_init", r);
126 goto terminate_usb_findit;
127 }
128
129 printf("finding_device ");
130 if (vid) {
131 for (i = 0; i < pid_count; i++)
132 printf("%04x:%04x ", vid, pid[i]);
133 }
134 if (serial)
135 printf("%s", serial);
136 printf("\n");
137
138 count = libusb_get_device_list(NULL, &devs);
139 if (count < 0)
140 goto terminate_usb_findit;
141
142 for (i = 0; i < count; i++) {
143 search_handle =
144 check_device(devs[i], vid, pid, pid_count, serial);
145 if (search_handle) {
146 if (devh)
147 break;
148 devh = search_handle;
149 }
150 }
151
152 libusb_free_device_list(devs, 1);
153
154 if (devh) {
155 uep->devh = devh;
156 if (search_handle && search_handle != devh) {
157 fprintf(stderr, "Found multiple devices. "
158 "Please specify --serial\n");
159 libusb_close(search_handle);
160 goto terminate_usb_findit;
161 }
162 printf("Found device.\n");
163 } else {
164 fprintf(stderr, "Can't find device\n");
165 goto terminate_usb_findit;
166 }
167
168 iface_num = find_interface(subclass, protocol, uep);
169 if (iface_num < 0) {
170 fprintf(stderr, "USB interface %d is not found\n", uep->ep_num);
171 goto terminate_usb_findit;
172 }
173 if (!uep->chunk_len) {
174 fprintf(stderr, "wMaxPacketSize isn't valid\n");
175 goto terminate_usb_findit;
176 }
177
178 printf("found interface %d endpoint %d, chunk_len %d\n", iface_num,
179 uep->ep_num, uep->chunk_len);
180
181 libusb_set_auto_detach_kernel_driver(uep->devh, 1);
182 r = libusb_claim_interface(uep->devh, iface_num);
183 if (r < 0) {
184 USB_ERROR("libusb_claim_interface", r);
185 goto terminate_usb_findit;
186 }
187
188 printf("READY\n-------\n");
189 return 0;
190
191 terminate_usb_findit:
192 if (uep->devh)
193 usb_shut_down(uep);
194 return -1;
195 }
196
usb_trx(struct usb_endpoint * uep,void * outbuf,int outlen,void * inbuf,int inlen,int allow_less,size_t * rxed_count)197 int usb_trx(struct usb_endpoint *uep, void *outbuf, int outlen, void *inbuf,
198 int inlen, int allow_less, size_t *rxed_count)
199 {
200 int r, actual;
201
202 /* Send data out */
203 if (outbuf && outlen) {
204 actual = 0;
205 r = libusb_bulk_transfer(uep->devh, uep->ep_num, outbuf, outlen,
206 &actual, 1000);
207 if (r < 0) {
208 USB_ERROR("libusb_bulk_transfer", r);
209 return -1;
210 }
211 if (actual != outlen) {
212 fprintf(stderr, "%s:%d, only sent %d/%d bytes\n",
213 __FILE__, __LINE__, actual, outlen);
214 usb_shut_down(uep);
215 }
216 }
217
218 /* Read reply back */
219 if (inbuf && inlen) {
220 actual = 0;
221 r = libusb_bulk_transfer(uep->devh, uep->ep_num | 0x80, inbuf,
222 inlen, &actual, 1000);
223 if (r < 0) {
224 USB_ERROR("libusb_bulk_transfer", r);
225 return -1;
226 }
227 if ((actual != inlen) && !allow_less) {
228 fprintf(stderr, "%s:%d, only received %d/%d bytes\n",
229 __FILE__, __LINE__, actual, inlen);
230 usb_shut_down(uep);
231 }
232
233 if (rxed_count)
234 *rxed_count = actual;
235 }
236
237 return 0;
238 }
239
usb_shut_down(struct usb_endpoint * uep)240 void usb_shut_down(struct usb_endpoint *uep)
241 {
242 libusb_close(uep->devh);
243 libusb_exit(NULL);
244 }
245