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