4 * Copyright (c) 2011 Hans Petter Selasky. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. 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.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include <sys/queue.h>
37 #include "bus_autoconf.h"
38 #include "bus_sections.h"
42 typedef TAILQ_HEAD(,usb_blob) usb_blob_head_t;
43 typedef TAILQ_ENTRY(usb_blob) usb_blob_entry_t;
45 static usb_blob_head_t usb_blob_head = TAILQ_HEAD_INITIALIZER(usb_blob_head);
46 static uint32_t usb_blob_count;
49 usb_blob_entry_t entry;
50 struct usb_device_id temp;
54 * To ensure that the correct USB driver is loaded, the driver having
55 * the most information about the device must be probed first. Then
56 * more generic drivers shall be probed.
59 usb_compare(const void *_a, const void *_b)
61 const struct usb_device_id *a = _a;
62 const struct usb_device_id *b = _b;
65 /* vendor matches first */
67 if (a->match_flag_vendor > b->match_flag_vendor)
69 if (a->match_flag_vendor < b->match_flag_vendor)
72 /* product matches first */
74 if (a->match_flag_product > b->match_flag_product)
76 if (a->match_flag_product < b->match_flag_product)
79 /* device class matches first */
81 if (a->match_flag_dev_class > b->match_flag_dev_class)
83 if (a->match_flag_dev_class < b->match_flag_dev_class)
86 if (a->match_flag_dev_subclass > b->match_flag_dev_subclass)
88 if (a->match_flag_dev_subclass < b->match_flag_dev_subclass)
91 /* interface class matches first */
93 if (a->match_flag_int_class > b->match_flag_int_class)
95 if (a->match_flag_int_class < b->match_flag_int_class)
98 if (a->match_flag_int_subclass > b->match_flag_int_subclass)
100 if (a->match_flag_int_subclass < b->match_flag_int_subclass)
103 if (a->match_flag_int_protocol > b->match_flag_int_protocol)
105 if (a->match_flag_int_protocol < b->match_flag_int_protocol)
108 /* then sort according to value */
110 if (a->idVendor > b->idVendor)
112 if (a->idVendor < b->idVendor)
114 if (a->idProduct > b->idProduct)
116 if (a->idProduct < b->idProduct)
118 if (a->bDeviceClass > b->bDeviceClass)
120 if (a->bDeviceClass < b->bDeviceClass)
122 if (a->bDeviceSubClass > b->bDeviceSubClass)
124 if (a->bDeviceSubClass < b->bDeviceSubClass)
126 if (a->bDeviceProtocol > b->bDeviceProtocol)
128 if (a->bDeviceProtocol < b->bDeviceProtocol)
130 if (a->bInterfaceClass > b->bInterfaceClass)
132 if (a->bInterfaceClass < b->bInterfaceClass)
134 if (a->bInterfaceSubClass > b->bInterfaceSubClass)
136 if (a->bInterfaceSubClass < b->bInterfaceSubClass)
138 if (a->bInterfaceProtocol > b->bInterfaceProtocol)
140 if (a->bInterfaceProtocol < b->bInterfaceProtocol)
143 /* in the end sort by module name and mode */
145 retval = strcmp(a->module_name, b->module_name);
147 retval = strcmp(a->module_mode, b->module_mode);
152 usb_sort_entries(struct usb_device_id *id, uint32_t nid)
154 qsort(id, nid, sizeof(*id), &usb_compare);
158 usb_import_entry(struct usb_device_id *id, const char *type,
159 const char *module, const uint8_t *ptr, uint16_t size)
163 if (strstr(type, "_host_"))
165 else if (strstr(type, "_device_"))
168 mode = "(host|device)";
170 strlcpy(id->module_name, module, sizeof(id->module_name));
171 strlcpy(id->module_mode, mode, sizeof(id->module_mode));
173 /* import data from binary object */
175 if (format_get_field(type, "mfl_vendor", ptr, size))
176 id->match_flag_vendor = 1;
177 if (format_get_field(type, "mfl_product", ptr, size))
178 id->match_flag_product = 1;
179 if (format_get_field(type, "mfl_dev_lo", ptr, size))
180 id->match_flag_dev_lo = 1;
181 if (format_get_field(type, "mfl_dev_hi", ptr, size))
182 id->match_flag_dev_hi = 1;
183 if (format_get_field(type, "mfl_dev_class", ptr, size))
184 id->match_flag_dev_class = 1;
185 if (format_get_field(type, "mfl_dev_subclass", ptr, size))
186 id->match_flag_dev_subclass = 1;
187 if (format_get_field(type, "mfl_dev_protocol", ptr, size))
188 id->match_flag_dev_protocol = 1;
189 if (format_get_field(type, "mfl_int_class", ptr, size))
190 id->match_flag_int_class = 1;
191 if (format_get_field(type, "mfl_int_subclass", ptr, size))
192 id->match_flag_int_subclass = 1;
193 if (format_get_field(type, "mfl_int_protocol", ptr, size))
194 id->match_flag_int_protocol = 1;
196 id->idVendor = format_get_field(type, "idVendor[0]", ptr, size) |
197 (format_get_field(type, "idVendor[1]", ptr, size) << 8);
198 id->idProduct = format_get_field(type, "idProduct[0]", ptr, size) |
199 (format_get_field(type, "idProduct[1]", ptr, size) << 8);
201 id->bcdDevice_lo = format_get_field(type, "bcdDevice_lo[0]", ptr, size) |
202 (format_get_field(type, "bcdDevice_lo[1]", ptr, size) << 8);
204 id->bcdDevice_hi = format_get_field(type, "bcdDevice_hi[0]", ptr, size) |
205 (format_get_field(type, "bcdDevice_hi[1]", ptr, size) << 8);
207 id->bDeviceClass = format_get_field(type, "bDeviceClass", ptr, size);
208 id->bDeviceSubClass = format_get_field(type, "bDeviceSubClass", ptr, size);
209 id->bDeviceProtocol = format_get_field(type, "bDeviceProtocol", ptr, size);
211 id->bInterfaceClass = format_get_field(type, "bInterfaceClass", ptr, size);
212 id->bInterfaceSubClass = format_get_field(type, "bInterfaceSubClass", ptr, size);
213 id->bInterfaceProtocol = format_get_field(type, "bInterfaceProtocol", ptr, size);
215 if (format_get_field(type, "mf_vendor", ptr, size))
216 id->match_flag_vendor = 1;
217 if (format_get_field(type, "mf_product", ptr, size))
218 id->match_flag_product = 1;
219 if (format_get_field(type, "mf_dev_lo", ptr, size))
220 id->match_flag_dev_lo = 1;
221 if (format_get_field(type, "mf_dev_hi", ptr, size))
222 id->match_flag_dev_hi = 1;
223 if (format_get_field(type, "mf_dev_class", ptr, size))
224 id->match_flag_dev_class = 1;
225 if (format_get_field(type, "mf_dev_subclass", ptr, size))
226 id->match_flag_dev_subclass = 1;
227 if (format_get_field(type, "mf_dev_protocol", ptr, size))
228 id->match_flag_dev_protocol = 1;
229 if (format_get_field(type, "mf_int_class", ptr, size))
230 id->match_flag_int_class = 1;
231 if (format_get_field(type, "mf_int_subclass", ptr, size))
232 id->match_flag_int_subclass = 1;
233 if (format_get_field(type, "mf_int_protocol", ptr, size))
234 id->match_flag_int_protocol = 1;
236 /* compute some internal fields */
237 id->is_iface = id->match_flag_int_class |
238 id->match_flag_int_protocol |
239 id->match_flag_int_subclass;
241 id->is_dev = id->match_flag_dev_class |
242 id->match_flag_dev_subclass;
244 id->is_vp = id->match_flag_vendor |
245 id->match_flag_product;
247 id->is_any = id->is_vp + id->is_dev + id->is_iface;
251 usb_dump(struct usb_device_id *id, uint32_t nid)
256 printf("nomatch 32 {\n"
257 " match \"bus\" \"uhub[0-9]+\";\n"
258 " match \"mode\" \"%s\";\n", id->module_mode);
260 printf("# skipped entry on module %s\n",
265 if (id->match_flag_vendor) {
266 printf(" match \"vendor\" \"0x%04x\";\n",
269 if (id->match_flag_product) {
272 if (id->is_any == 1 && id->is_vp == 1) {
273 /* try to join similar entries */
275 if (id[n].is_any != 1 || id[n].is_vp != 1)
277 if (id[n].idVendor != id[0].idVendor)
279 if (strcmp(id[n].module_name, id[0].module_name))
281 if (strcmp(id[n].module_mode, id[0].module_mode))
287 printf(" match \"product\" \"0x%04x\";\n",
290 printf(" match \"product\" \"(");
292 for (x = 0; x != n; x++) {
293 printf("0x%04x%s", id[x].idProduct,
294 (x == (n - 1)) ? "" : "|");
300 if (id->match_flag_dev_class) {
301 printf(" match \"devclass\" \"0x%02x\";\n",
304 if (id->match_flag_dev_subclass) {
305 printf(" match \"devsubclass\" \"0x%02x\";\n",
306 id->bDeviceSubClass);
308 if (id->match_flag_int_class) {
309 printf(" match \"intclass\" \"0x%02x\";\n",
310 id->bInterfaceClass);
312 if (id->match_flag_int_subclass) {
313 printf(" match \"intsubclass\" \"0x%02x\";\n",
314 id->bInterfaceSubClass);
316 if (id->match_flag_int_protocol) {
317 printf(" match \"intprotocol\" \"0x%02x\";\n",
318 id->bInterfaceProtocol);
320 printf(" action \"kldload -n %s\";\n"
321 "};\n\n", id->module_name);
327 usb_import_entries(const char *section, const char *module,
328 const uint8_t *ptr, uint32_t len)
330 struct usb_blob *pub;
331 uint32_t section_size;
334 section_size = format_get_section_size(section);
335 if (section_size == 0) {
336 errx(EX_DATAERR, "Invalid or non-existing "
337 "section format '%s'", section);
339 if (len % section_size) {
340 errx(EX_DATAERR, "Length %d is not "
341 "divisible by %d. Section format '%s'",
342 len, section_size, section);
344 for (off = 0; off != len; off += section_size) {
345 pub = malloc(sizeof(*pub));
347 errx(EX_SOFTWARE, "Out of memory");
349 memset(pub, 0, sizeof(*pub));
351 usb_import_entry(&pub->temp, section,
352 module, ptr + off, section_size);
354 TAILQ_INSERT_TAIL(&usb_blob_head, pub, entry);
357 if (usb_blob_count == 0)
358 errx(EX_SOFTWARE, "Too many entries");
363 usb_dump_entries(void)
365 struct usb_blob *pub;
366 struct usb_device_id *id;
369 id = malloc(usb_blob_count * sizeof(*id));
371 errx(EX_SOFTWARE, "Out of memory");
373 /* make linear array of all USB blobs */
375 TAILQ_FOREACH(pub, &usb_blob_head, entry)
378 usb_sort_entries(id, usb_blob_count);
380 for (x = 0; x != usb_blob_count;)
381 x += usb_dump(id + x, usb_blob_count - x);
385 printf("# %d USB entries processed\n\n", usb_blob_count);