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