source: mainline/uspace/lib/usbdev/src/recognise.c@ 6ff23ff

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 6ff23ff was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 9.1 KB
Line 
1/*
2 * Copyright (c) 2010 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup libusbdev
30 * @{
31 */
32/** @file
33 * Functions for recognition of attached devices.
34 */
35
36#include <usb/dev/pipes.h>
37#include <usb/dev/recognise.h>
38#include <usb/dev/request.h>
39#include <usb/classes/classes.h>
40
41#include <assert.h>
42#include <errno.h>
43#include <stdio.h>
44
45/** Get integer part from BCD coded number. */
46#define BCD_INT(a) (((unsigned int)(a)) / 256)
47/** Get fraction part from BCD coded number (as an integer, no less). */
48#define BCD_FRAC(a) (((unsigned int)(a)) % 256)
49
50/** Format for BCD coded number to be used in printf. */
51#define BCD_FMT "%x.%x"
52/** Arguments to printf for BCD coded number. */
53#define BCD_ARGS(a) BCD_INT((a)), BCD_FRAC((a))
54
55/** Add formatted match id.
56 *
57 * @param matches List of match ids where to add to.
58 * @param score Score of the match.
59 * @param format Printf-like format
60 * @return Error code.
61 */
62static errno_t usb_add_match_id(match_id_list_t *matches, int score,
63 char *match_str)
64{
65 assert(matches);
66
67 match_id_t *match_id = create_match_id();
68 if (match_id == NULL) {
69 return ENOMEM;
70 }
71
72 match_id->id = match_str;
73 match_id->score = score;
74 add_match_id(matches, match_id);
75
76 return EOK;
77}
78
79/** Add match id to list or return with error code.
80 *
81 * @param match_ids List of match ids.
82 * @param score Match id score.
83 * @param format Format of the matching string
84 * @param ... Arguments for the format.
85 */
86#define ADD_MATCHID_OR_RETURN(match_ids, score, format, ...) \
87 do { \
88 char *str = NULL; \
89 int __rc = asprintf(&str, format, ##__VA_ARGS__); \
90 if (__rc >= 0) { \
91 errno_t __rc = usb_add_match_id((match_ids), (score), str); \
92 if (__rc != EOK) { \
93 free(str); \
94 return __rc; \
95 } \
96 } else { \
97 return ENOMEM; \
98 } \
99 } while (0)
100
101/** Create device match ids based on its interface.
102 *
103 * @param[in] desc_device Device descriptor.
104 * @param[in] desc_interface Interface descriptor.
105 * @param[out] matches Initialized list of match ids.
106 * @return Error code (the two mentioned are not the only ones).
107 * @retval EINVAL Invalid input parameters (expects non NULL pointers).
108 * @retval ENOENT Device class is not "use interface".
109 */
110errno_t usb_device_create_match_ids_from_interface(
111 const usb_standard_device_descriptor_t *desc_device,
112 const usb_standard_interface_descriptor_t *desc_interface,
113 match_id_list_t *matches)
114{
115 if (desc_interface == NULL || matches == NULL) {
116 return EINVAL;
117 }
118
119 if (desc_interface->interface_class == USB_CLASS_USE_INTERFACE) {
120 return ENOENT;
121 }
122
123 const char *classname = usb_str_class(desc_interface->interface_class);
124 assert(classname != NULL);
125
126#define IFACE_PROTOCOL_FMT "interface&class=%s&subclass=0x%02x&protocol=0x%02x"
127#define IFACE_PROTOCOL_ARGS classname, desc_interface->interface_subclass, \
128 desc_interface->interface_protocol
129
130#define IFACE_SUBCLASS_FMT "interface&class=%s&subclass=0x%02x"
131#define IFACE_SUBCLASS_ARGS classname, desc_interface->interface_subclass
132
133#define IFACE_CLASS_FMT "interface&class=%s"
134#define IFACE_CLASS_ARGS classname
135
136#define VENDOR_RELEASE_FMT "vendor=0x%04x&product=0x%04x&release=" BCD_FMT
137#define VENDOR_RELEASE_ARGS desc_device->vendor_id, desc_device->product_id, \
138 BCD_ARGS(desc_device->device_version)
139
140#define VENDOR_PRODUCT_FMT "vendor=0x%04x&product=0x%04x"
141#define VENDOR_PRODUCT_ARGS desc_device->vendor_id, desc_device->product_id
142
143#define VENDOR_ONLY_FMT "vendor=0x%04x"
144#define VENDOR_ONLY_ARGS desc_device->vendor_id
145
146 /*
147 * If the vendor is specified, create match ids with vendor with
148 * higher score.
149 * Then the same ones without the vendor part.
150 */
151 if ((desc_device != NULL) && (desc_device->vendor_id != 0)) {
152 /* First, interface matches with device release number. */
153 ADD_MATCHID_OR_RETURN(matches, 250,
154 "usb&" VENDOR_RELEASE_FMT "&" IFACE_PROTOCOL_FMT,
155 VENDOR_RELEASE_ARGS, IFACE_PROTOCOL_ARGS);
156 ADD_MATCHID_OR_RETURN(matches, 240,
157 "usb&" VENDOR_RELEASE_FMT "&" IFACE_SUBCLASS_FMT,
158 VENDOR_RELEASE_ARGS, IFACE_SUBCLASS_ARGS);
159 ADD_MATCHID_OR_RETURN(matches, 230,
160 "usb&" VENDOR_RELEASE_FMT "&" IFACE_CLASS_FMT,
161 VENDOR_RELEASE_ARGS, IFACE_CLASS_ARGS);
162
163 /* Next, interface matches without release number. */
164 ADD_MATCHID_OR_RETURN(matches, 220,
165 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_PROTOCOL_FMT,
166 VENDOR_PRODUCT_ARGS, IFACE_PROTOCOL_ARGS);
167 ADD_MATCHID_OR_RETURN(matches, 210,
168 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_SUBCLASS_FMT,
169 VENDOR_PRODUCT_ARGS, IFACE_SUBCLASS_ARGS);
170 ADD_MATCHID_OR_RETURN(matches, 200,
171 "usb&" VENDOR_PRODUCT_FMT "&" IFACE_CLASS_FMT,
172 VENDOR_PRODUCT_ARGS, IFACE_CLASS_ARGS);
173
174 /* Finally, interface matches with only vendor. */
175 ADD_MATCHID_OR_RETURN(matches, 190,
176 "usb&" VENDOR_ONLY_FMT "&" IFACE_PROTOCOL_FMT,
177 VENDOR_ONLY_ARGS, IFACE_PROTOCOL_ARGS);
178 ADD_MATCHID_OR_RETURN(matches, 180,
179 "usb&" VENDOR_ONLY_FMT "&" IFACE_SUBCLASS_FMT,
180 VENDOR_ONLY_ARGS, IFACE_SUBCLASS_ARGS);
181 ADD_MATCHID_OR_RETURN(matches, 170,
182 "usb&" VENDOR_ONLY_FMT "&" IFACE_CLASS_FMT,
183 VENDOR_ONLY_ARGS, IFACE_CLASS_ARGS);
184 }
185
186 /* Now, the same but without any vendor specification. */
187 ADD_MATCHID_OR_RETURN(matches, 160,
188 "usb&" IFACE_PROTOCOL_FMT,
189 IFACE_PROTOCOL_ARGS);
190 ADD_MATCHID_OR_RETURN(matches, 150,
191 "usb&" IFACE_SUBCLASS_FMT,
192 IFACE_SUBCLASS_ARGS);
193 ADD_MATCHID_OR_RETURN(matches, 140,
194 "usb&" IFACE_CLASS_FMT,
195 IFACE_CLASS_ARGS);
196
197#undef IFACE_PROTOCOL_FMT
198#undef IFACE_PROTOCOL_ARGS
199#undef IFACE_SUBCLASS_FMT
200#undef IFACE_SUBCLASS_ARGS
201#undef IFACE_CLASS_FMT
202#undef IFACE_CLASS_ARGS
203#undef VENDOR_RELEASE_FMT
204#undef VENDOR_RELEASE_ARGS
205#undef VENDOR_PRODUCT_FMT
206#undef VENDOR_PRODUCT_ARGS
207#undef VENDOR_ONLY_FMT
208#undef VENDOR_ONLY_ARGS
209
210 /* As a last resort, try fallback driver. */
211 ADD_MATCHID_OR_RETURN(matches, 10, "usb&interface&fallback");
212
213 return EOK;
214}
215
216/** Create DDF match ids from USB device descriptor.
217 *
218 * @param matches List of match ids to extend.
219 * @param device_descriptor Device descriptor returned by given device.
220 * @return Error code.
221 */
222errno_t usb_device_create_match_ids_from_device_descriptor(
223 const usb_standard_device_descriptor_t *device_descriptor,
224 match_id_list_t *matches)
225{
226 /*
227 * Unless the vendor id is 0, the pair idVendor-idProduct
228 * quite uniquely describes the device.
229 */
230 if (device_descriptor->vendor_id != 0) {
231 /* First, with release number. */
232 ADD_MATCHID_OR_RETURN(matches, 100,
233 "usb&vendor=0x%04x&product=0x%04x&release=" BCD_FMT,
234 (int) device_descriptor->vendor_id,
235 (int) device_descriptor->product_id,
236 BCD_ARGS(device_descriptor->device_version));
237
238 /* Next, without release number. */
239 ADD_MATCHID_OR_RETURN(matches, 90,
240 "usb&vendor=0x%04x&product=0x%04x",
241 (int) device_descriptor->vendor_id,
242 (int) device_descriptor->product_id);
243 }
244
245 /* Class match id */
246 ADD_MATCHID_OR_RETURN(matches, 50, "usb&class=%s",
247 usb_str_class(device_descriptor->device_class));
248
249 /* As a last resort, try fallback driver. */
250 ADD_MATCHID_OR_RETURN(matches, 10, "usb&fallback");
251
252 return EOK;
253}
254
255
256/** Create match ids describing attached device.
257 *
258 * @warning The list of match ids @p matches may change even when
259 * function exits with error.
260 *
261 * @param ctrl_pipe Control pipe to given device (session must be already
262 * started).
263 * @param matches Initialized list of match ids.
264 * @return Error code.
265 */
266errno_t usb_device_create_match_ids(usb_pipe_t *ctrl_pipe,
267 match_id_list_t *matches)
268{
269 assert(ctrl_pipe);
270 errno_t rc;
271 /*
272 * Retrieve device descriptor and add matches from it.
273 */
274 usb_standard_device_descriptor_t device_descriptor;
275
276 rc = usb_request_get_device_descriptor(ctrl_pipe, &device_descriptor);
277 if (rc != EOK) {
278 return rc;
279 }
280
281 rc = usb_device_create_match_ids_from_device_descriptor(
282 &device_descriptor, matches);
283 if (rc != EOK) {
284 return rc;
285 }
286
287 return EOK;
288}
289
290/**
291 * @}
292 */
Note: See TracBrowser for help on using the repository browser.