xref: /aosp_15_r20/external/gsc-utils/util/usb_if.c (revision 4f2df630800bdcf1d4f0decf95d8a1cb87344f5f)
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