aboutsummaryrefslogtreecommitdiffstats
path: root/include/usb_device.h
blob: 8b7a801066cfb16952aaaeb67ca7c2ea9caefdec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/*
 * This file is part of the flashrom project.
 *
 * Copyright (C) 2020, Google Inc. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef USB_DEVICE_H
#define USB_DEVICE_H

/*
 * USB device matching framework
 *
 * This can be used to match a USB device by a number of different parameters.
 * The parameters can be passed on the command line and defaults can be set
 * by the programmer.
 */

#include <libusb.h>
#include <stdint.h>
#include <stdbool.h>

/*
 * The LIBUSB_ERROR macro converts a libusb failure code into an error code that
 * flashrom recognizes. It does so without displaying an error code allowing us
 * to compare error codes against the library enumeration values.
 */
#define LIBUSB_ERROR(error_code)	(0x20000 | -(error_code))

/*
 * The LIBUSB macro converts a libusb failure code into an error code that
 * flashrom recognizes. It also displays additional libusb specific
 * information about the failure.
 */
#define LIBUSB(expression)						\
	({								\
		int libusb_error__ = (expression);			\
									\
		if (libusb_error__ < 0) {				\
			msg_perr("libusb error: %s:%d %s\n",		\
				 __FILE__,				\
				 __LINE__,				\
				 libusb_error_name(libusb_error__));	\
			libusb_error__ = LIBUSB_ERROR(libusb_error__);	\
		} else {						\
			libusb_error__ = 0;				\
		}							\
									\
		libusb_error__;						\
	})

/*
 * Returns true if the error code falls within the range of valid libusb
 * error codes.
 */
static inline bool usb_device_is_libusb_error(int error_code)
{
	return (0x20000 <= error_code && error_code < 0x20064);
}

/*
 * A USB match and associated value struct are used to encode the information
 * about a device against which we wish to match.  If the value of a
 * usb_match_value has been set then a device must match that value.  The name
 * of the usb_match_value is used to fetch the programmer parameter from the
 * flashrom command line and is the same as the name of the corresponding
 * field in usb_match.
 */
struct usb_match_value {
	char const *name;
	int         value;
	int         set;
};

struct usb_match {
	struct usb_match_value bus;
	struct usb_match_value address;
	struct usb_match_value vid;
	struct usb_match_value pid;
	struct usb_match_value serial;
	struct usb_match_value config;
	struct usb_match_value interface;
	struct usb_match_value altsetting;
	struct usb_match_value class;
	struct usb_match_value subclass;
	struct usb_match_value protocol;
};

/*
 * Initialize a usb_match structure so that each value's name matches the
 * values name in the usb_match structure (so bus.name == "bus"...), and
 * look for each value in the flashrom command line via
 * extract_programmer_param.  If the value is found convert it to an integer
 * using strtol, accepting hex, decimal and octal encoding.
 */
void usb_match_init(struct usb_match *match);

/*
 * Add a default value to a usb_match_value.  This must be done after calling
 * usb_match_init.  If usb_match_init already set the value of a usb_match_value
 * we do nothing, otherwise set the value to default_value.  This ensures that
 * parameters passed on the command line override defaults.
 */
void usb_match_value_default(struct usb_match_value *match,
			     long int default_value);

/*
 * The usb_device structure is an entry in a linked list of devices that were
 * matched by usb_device_find.
 */
struct usb_device {
	struct libusb_device                     *device;
	struct libusb_config_descriptor          *config_descriptor;
	struct libusb_interface_descriptor const *interface_descriptor;

	/*
	 * Initially NULL, the libusb_device_handle is only valid once the
	 * usb_device has been successfully passed to usb_device_show or
	 * usb_device_claim.
	 */
	struct libusb_device_handle *handle;

	/*
	 * Link to next device, or NULL
	 */
	struct usb_device *next;
};

/*
 * Find and return a list of all compatible devices.  Each device is added to
 * the list with its first valid configuration and interface.  If an alternate
 * configuration (config, interface, altsetting...) is desired the specifics
 * can be supplied as programmer parameters.
 *
 * Return:
 *     0: At least one matching device was found.
 *     1: No matching devices were found.
 */
int usb_device_find(struct usb_match const *match, struct usb_device **devices);

/*
 * Display the devices bus and address as well as its product string.  The
 * underlying libusb device is opened if it is not already open.
 *
 * Return:
 *     0: The device information was displayed.
 *     non-zero: There was a failure while displaying the device information.
 */
int usb_device_show(char const *prefix, struct usb_device *device);

/*
 * Open the underlying libusb device, set its config, claim the interface and
 * select the correct alternate interface.
 *
 * Return:
 *     0: The device was successfully claimed.
 *     non-zero: There was a failure while trying to claim the device.
 */
int usb_device_claim(struct usb_device *device);

/*
 * Free a usb_device structure.
 *
 * This ensures that the libusb device is closed and that all allocated
 * handles and descriptors are freed.
 *
 * Return:
 *     The next device in the device list.
 */
struct usb_device *usb_device_free(struct usb_device *device);

#endif /* USB_DEVICE_H */