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