xref: /aosp_15_r20/external/flashrom/usb_device.c (revision 0d6140be3aa665ecc836e8907834fcd3e3b018fc)
1 /*
2  * This file is part of the flashrom project.
3  *
4  * Copyright (C) 2020, Google Inc. All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  */
16 
17 #include "programmer.h"
18 #include "spi.h"
19 #include "usb_device.h"
20 
21 #include <assert.h>
22 #include <libusb.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 /*
28  * Possibly extract a programmer parameter and use it to initialize the given
29  * match value structure.
30  */
usb_match_value_init(const struct programmer_cfg * cfg,struct usb_match_value * match,char const * parameter)31 static void usb_match_value_init(const struct programmer_cfg *cfg,
32 				 struct usb_match_value *match,
33 				 char const *parameter)
34 {
35 	char *string = extract_programmer_param_str(cfg, parameter);
36 
37 	match->name = parameter;
38 
39 	if (string) {
40 		match->set = 1;
41 		match->value = strtol(string, NULL, 0);
42 	} else {
43 		match->set = 0;
44 	}
45 
46 	free(string);
47 }
48 
49 #define USB_MATCH_VALUE_INIT(PPARAM, NAME)			\
50 	usb_match_value_init(PPARAM, &match->NAME, #NAME)
51 
usb_match_init(const struct programmer_cfg * cfg,struct usb_match * match)52 void usb_match_init(const struct programmer_cfg *cfg, struct usb_match *match)
53 {
54 	USB_MATCH_VALUE_INIT(cfg, vid);
55 	USB_MATCH_VALUE_INIT(cfg, pid);
56 	USB_MATCH_VALUE_INIT(cfg, bus);
57 	USB_MATCH_VALUE_INIT(cfg, address);
58 	USB_MATCH_VALUE_INIT(cfg, config);
59 	USB_MATCH_VALUE_INIT(cfg, interface);
60 	USB_MATCH_VALUE_INIT(cfg, altsetting);
61 	USB_MATCH_VALUE_INIT(cfg, class);
62 	USB_MATCH_VALUE_INIT(cfg, subclass);
63 	USB_MATCH_VALUE_INIT(cfg, protocol);
64 }
65 
usb_match_value_default(struct usb_match_value * value,long int default_value)66 void usb_match_value_default(struct usb_match_value *value,
67 			     long int default_value)
68 {
69 	if (value->set)
70 		return;
71 
72 	value->set   = 1;
73 	value->value = default_value;
74 }
75 
76 /*
77  * Match the value against a possible user supplied parameter.
78  *
79  * Return:
80  *     0: The user supplied the given parameter and it did not match the value.
81  *     1: Either the user didn't supply the parameter, or they did and it
82  *        matches the given value.
83  */
check_match(struct usb_match_value const * match_value,int value)84 static int check_match(struct usb_match_value const *match_value, int value)
85 {
86 	int reject = match_value->set && (match_value->value != value);
87 
88 	if (reject)
89 		msg_pdbg("USB: Rejecting device because %s = %d != %d\n",
90 			 match_value->name,
91 			 value,
92 			 match_value->value);
93 
94 	return !reject;
95 }
96 
97 /*
98  * Allocate a copy of device and add it to the head of the devices list.
99  */
add_device(struct usb_device * device,struct usb_device ** devices)100 static void add_device(struct usb_device *device,
101 		       struct usb_device **devices)
102 {
103 	struct usb_device *copy = malloc(sizeof(*copy));
104 
105 	assert(copy != NULL);
106 
107 	*copy = *device;
108 
109 	copy->next = *devices;
110 	*devices = copy;
111 
112 	libusb_ref_device(copy->device);
113 }
114 
115 /*
116  * Look through the interfaces of the current device config for a match. Stop
117  * looking after the first valid match is found.
118  *
119  * Return:
120  *     0: No matching interface was found.
121  *     1: A complete match was found and added to the devices list.
122  */
find_interface(struct usb_match const * match,struct usb_device * current,struct usb_device ** devices)123 static int find_interface(struct usb_match const *match,
124 			  struct usb_device *current,
125 			  struct usb_device **devices)
126 {
127 	int i, j;
128 
129 	for (i = 0; i < current->config_descriptor->bNumInterfaces; ++i) {
130 		struct libusb_interface const *interface;
131 
132 		interface = &current->config_descriptor->interface[i];
133 
134 		for (j = 0; j < interface->num_altsetting; ++j) {
135 			struct libusb_interface_descriptor const *descriptor;
136 
137 			descriptor = &interface->altsetting[j];
138 
139 			if (check_match(&match->interface,
140 					descriptor->bInterfaceNumber) &&
141 			    check_match(&match->altsetting,
142 					descriptor->bAlternateSetting) &&
143 			    check_match(&match->class,
144 					descriptor->bInterfaceClass) &&
145 			    check_match(&match->subclass,
146 					descriptor->bInterfaceSubClass) &&
147 			    check_match(&match->protocol,
148 					descriptor->bInterfaceProtocol)) {
149 				current->interface_descriptor = descriptor;
150 				add_device(current, devices);
151 				msg_pdbg("USB: Found matching device\n");
152 				return 1;
153 			}
154 		}
155 	}
156 
157 	return 0;
158 }
159 
160 /*
161  * Look through the configs of the current device for a match.  Stop looking
162  * after the first valid match is found.
163  *
164  * Return:
165  *     0: All configurations successfully checked, one may have been added to
166  *        the list.
167  *     non-zero: There was a failure while checking for a match.
168  */
find_config(struct usb_match const * match,struct usb_device * current,struct libusb_device_descriptor const * device_descriptor,struct usb_device ** devices)169 static int find_config(struct usb_match const *match,
170 		       struct usb_device *current,
171 		       struct libusb_device_descriptor const *device_descriptor,
172 		       struct usb_device **devices)
173 {
174 	int i;
175 
176 	for (i = 0; i < device_descriptor->bNumConfigurations; ++i) {
177 		int ret = LIBUSB(libusb_get_config_descriptor(
178 				current->device, i,
179 				&current->config_descriptor));
180 		if (ret != 0) {
181 			msg_perr("USB: Failed to get config descriptor");
182 			return ret;
183 		}
184 
185 		if (check_match(&match->config,
186 				current->config_descriptor->
187 				bConfigurationValue) &&
188 		    find_interface(match, current, devices))
189 			break;
190 
191 		libusb_free_config_descriptor(current->config_descriptor);
192 	}
193 
194 	return 0;
195 }
196 
usb_device_find(struct usb_match const * match,struct usb_device ** devices)197 int usb_device_find(struct usb_match const *match, struct usb_device **devices)
198 {
199 	libusb_device **list;
200 	ssize_t         count;
201 	ssize_t         i;
202 
203 	*devices = NULL;
204 
205 	int ret = LIBUSB(count = libusb_get_device_list(NULL, &list));
206 	if (ret != 0) {
207 		msg_perr("USB: Failed to get device list");
208 		return ret;
209 	}
210 
211 	for (i = 0; i < count; ++i) {
212 		struct libusb_device_descriptor descriptor;
213 		struct usb_device               current = {
214 			.device = list[i],
215 			.handle = NULL,
216 			.next   = NULL,
217 		};
218 
219 		uint8_t bus     = libusb_get_bus_number(list[i]);
220 		uint8_t address = libusb_get_device_address(list[i]);
221 
222 		msg_pdbg("USB: Inspecting device (Bus %d, Address %d)\n",
223 			 bus,
224 			 address);
225 
226 		ret = LIBUSB(libusb_get_device_descriptor(list[i],
227 							  &descriptor));
228 		if (ret != 0) {
229 			msg_perr("USB: Failed to get device descriptor");
230 			free(*devices);
231 			*devices = NULL;
232 			return ret;
233 		}
234 
235 		if (check_match(&match->vid,     descriptor.idVendor) &&
236 		    check_match(&match->pid,     descriptor.idProduct) &&
237 		    check_match(&match->bus,     bus) &&
238 		    check_match(&match->address, address)) {
239 			ret = find_config(match,
240 					  &current,
241 					  &descriptor,
242 					  devices);
243 			if (ret != 0) {
244 				msg_perr("USB: Failed to find config");
245 				return ret;
246 			}
247 		}
248 	}
249 
250 	libusb_free_device_list(list, 1);
251 
252 	return (*devices == NULL);
253 }
254 
255 /*
256  * If the underlying libusb device is not open, open it.
257  *
258  * Return:
259  *     0: The device was already open or was successfully opened.
260  *     non-zero: There was a failure while opening the device.
261  */
usb_device_open(struct usb_device * device)262 static int usb_device_open(struct usb_device *device)
263 {
264 	if (device->handle == NULL) {
265 		int ret = LIBUSB(libusb_open(device->device, &device->handle));
266 		if (ret != 0) {
267 			msg_perr("USB: Failed to open device\n");
268 			return ret;
269 		}
270 	}
271 
272 	return 0;
273 }
274 
usb_device_show(char const * prefix,struct usb_device * device)275 int usb_device_show(char const *prefix, struct usb_device *device)
276 {
277 	struct libusb_device_descriptor descriptor;
278 	unsigned char                   product[256];
279 	int ret;
280 
281 	ret = usb_device_open(device);
282 	if (ret != 0) {
283 		msg_perr("USB: Failed to open device\n");
284 		return ret;
285 	}
286 
287 	ret = LIBUSB(libusb_get_device_descriptor(device->device, &descriptor));
288 	if (ret != 0) {
289 		msg_perr("USB: Failed to get device descriptor\n");
290 		return ret;
291 	}
292 
293 	ret = LIBUSB(libusb_get_string_descriptor_ascii(
294 			     device->handle,
295 			     descriptor.iProduct,
296 			     product,
297 			     sizeof(product)));
298 	if (ret != 0) {
299 		msg_perr("USB: Failed to get device product string\n");
300 		return ret;
301 	}
302 
303 	product[255] = '\0';
304 
305 	msg_perr("%sbus=0x%02x,address=0x%02x | %s\n",
306 		 prefix,
307 		 libusb_get_bus_number(device->device),
308 		 libusb_get_device_address(device->device),
309 		 product);
310 
311 	return 0;
312 }
313 
usb_device_claim(struct usb_device * device)314 int usb_device_claim(struct usb_device *device)
315 {
316 	int current_config;
317 
318 	int ret = usb_device_open(device);
319 	if (ret != 0) {
320 		msg_perr("USB: Failed to open device\n");
321 		return ret;
322 	}
323 
324 	ret = LIBUSB(libusb_get_configuration(device->handle,
325 					      &current_config));
326 	if (ret != 0) {
327 		msg_perr("USB: Failed to get current device configuration\n");
328 		return ret;
329 	}
330 
331 	if (current_config != device->config_descriptor->bConfigurationValue) {
332 		ret = LIBUSB(libusb_set_configuration(
333 				     device->handle,
334 				     device->
335 				     config_descriptor->
336 				     bConfigurationValue));
337 		if (ret != 0) {
338 			msg_perr("USB: Failed to set new configuration from %d to %d\n",
339 					current_config,
340 					device->config_descriptor->bConfigurationValue);
341 			return ret;
342 		}
343 	}
344 
345 	ret = libusb_detach_kernel_driver(device->handle,
346 		device->interface_descriptor->bInterfaceNumber);
347 	if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND && ret != LIBUSB_ERROR_NOT_SUPPORTED) {
348 		msg_perr("Cannot detach the existing usb driver. %s\n",
349 				libusb_error_name(ret));
350 		return ret;
351 	}
352 
353 	ret = LIBUSB(libusb_claim_interface(device->handle,
354 					    device->
355 					    interface_descriptor->
356 					    bInterfaceNumber));
357 	if (ret != 0) {
358 		msg_perr("USB: Could not claim device interface %d\n",
359 				device->interface_descriptor->bInterfaceNumber);
360 		libusb_attach_kernel_driver(device->handle,
361 			device->interface_descriptor->bInterfaceNumber);
362 		return ret;
363 	}
364 
365 	if (device->interface_descriptor->bAlternateSetting != 0) {
366 		ret = LIBUSB(libusb_set_interface_alt_setting(
367 				     device->handle,
368 				     device->
369 				     interface_descriptor->
370 				     bInterfaceNumber,
371 				     device->
372 				     interface_descriptor->
373 				     bAlternateSetting));
374 		if (ret != 0) {
375 			msg_perr("USB: Failed to set alternate setting %d\n",
376 					device->interface_descriptor->bAlternateSetting);
377 			return ret;
378 		}
379 	}
380 
381 	return 0;
382 }
383 
usb_device_free(struct usb_device * device)384 struct usb_device *usb_device_free(struct usb_device *device)
385 {
386 	struct usb_device *next = device->next;
387 
388 	if (device->handle != NULL) {
389 		libusb_release_interface(device->handle,
390 			device->interface_descriptor->bInterfaceNumber);
391 		libusb_attach_kernel_driver(device->handle,
392 			device->interface_descriptor->bInterfaceNumber);
393 		libusb_close(device->handle);
394 	}
395 
396 	/*
397 	 * This unref balances the ref added in the add_device function.
398 	 */
399 	libusb_unref_device(device->device);
400 	libusb_free_config_descriptor(device->config_descriptor);
401 
402 	free(device);
403 
404 	return next;
405 }
406