1 /* $FreeBSD: head/sys/dev/usb/usb_lookup.c 246194 2013-02-01 07:05:43Z hselasky $ */
2 /*-
3 * Copyright (c) 2008 Hans Petter Selasky. 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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 #include <sys/stdint.h>
28 #include <sys/param.h>
29 #include <sys/queue.h>
30 #include <sys/types.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/bus.h>
34 #include <sys/module.h>
35 #include <sys/lock.h>
36 #include <sys/condvar.h>
37 #include <sys/sysctl.h>
38 #include <sys/unistd.h>
39 #include <sys/callout.h>
40 #include <sys/malloc.h>
41 #include <sys/caps.h>
42 #include <sys/limits.h>
43 #include <sys/endian.h>
44
45 #include <bus/u4b/usb.h>
46 #include <bus/u4b/usbdi.h>
47
48 /*------------------------------------------------------------------------*
49 * usbd_lookup_id_by_info
50 *
51 * This functions takes an array of "struct usb_device_id" and tries
52 * to match the entries with the information in "struct usbd_lookup_info".
53 *
54 * NOTE: The "sizeof_id" parameter must be a multiple of the
55 * usb_device_id structure size. Else the behaviour of this function
56 * is undefined.
57 *
58 * Return values:
59 * NULL: No match found.
60 * Else: Pointer to matching entry.
61 *------------------------------------------------------------------------*/
62 const struct usb_device_id *
usbd_lookup_id_by_info(const struct usb_device_id * id,usb_size_t sizeof_id,const struct usbd_lookup_info * info)63 usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id,
64 const struct usbd_lookup_info *info)
65 {
66 const struct usb_device_id *id_end;
67
68 if (id == NULL) {
69 goto done;
70 }
71 id_end = (const void *)(((const uint8_t *)id) + sizeof_id);
72
73 /*
74 * Keep on matching array entries until we find a match or
75 * until we reach the end of the matching array:
76 */
77 for (; id != id_end; id++) {
78
79 if ((id->match_flag_vendor) &&
80 (id->idVendor != info->idVendor)) {
81 continue;
82 }
83 if ((id->match_flag_product) &&
84 (id->idProduct != info->idProduct)) {
85 continue;
86 }
87 if ((id->match_flag_dev_lo) &&
88 (id->bcdDevice_lo > info->bcdDevice)) {
89 continue;
90 }
91 if ((id->match_flag_dev_hi) &&
92 (id->bcdDevice_hi < info->bcdDevice)) {
93 continue;
94 }
95 if ((id->match_flag_dev_class) &&
96 (id->bDeviceClass != info->bDeviceClass)) {
97 continue;
98 }
99 if ((id->match_flag_dev_subclass) &&
100 (id->bDeviceSubClass != info->bDeviceSubClass)) {
101 continue;
102 }
103 if ((id->match_flag_dev_protocol) &&
104 (id->bDeviceProtocol != info->bDeviceProtocol)) {
105 continue;
106 }
107 if ((id->match_flag_int_class) &&
108 (id->bInterfaceClass != info->bInterfaceClass)) {
109 continue;
110 }
111 if ((id->match_flag_int_subclass) &&
112 (id->bInterfaceSubClass != info->bInterfaceSubClass)) {
113 continue;
114 }
115 if ((id->match_flag_int_protocol) &&
116 (id->bInterfaceProtocol != info->bInterfaceProtocol)) {
117 continue;
118 }
119 /* We found a match! */
120 return (id);
121 }
122
123 done:
124 return (NULL);
125 }
126
127 /*------------------------------------------------------------------------*
128 * usbd_lookup_id_by_uaa - factored out code
129 *
130 * Return values:
131 * 0: Success
132 * Else: Failure
133 *------------------------------------------------------------------------*/
134 int
usbd_lookup_id_by_uaa(const struct usb_device_id * id,usb_size_t sizeof_id,struct usb_attach_arg * uaa)135 usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id,
136 struct usb_attach_arg *uaa)
137 {
138 id = usbd_lookup_id_by_info(id, sizeof_id, &uaa->info);
139 if (id) {
140 /* copy driver info */
141 uaa->driver_info = id->driver_info;
142 return (0);
143 }
144 return (ENXIO);
145 }
146
147 /*------------------------------------------------------------------------*
148 * Export the USB device ID format we use to userspace tools.
149 *------------------------------------------------------------------------*/
150 #if BYTE_ORDER == BIG_ENDIAN
151 #define U16_XOR "8"
152 #define U32_XOR "12"
153 #define U64_XOR "56"
154 #define U8_BITFIELD_XOR "7"
155 #define U16_BITFIELD_XOR "15"
156 #define U32_BITFIELD_XOR "31"
157 #define U64_BITFIELD_XOR "63"
158 #else
159 #define U16_XOR "0"
160 #define U32_XOR "0"
161 #define U64_XOR "0"
162 #define U8_BITFIELD_XOR "0"
163 #define U16_BITFIELD_XOR "0"
164 #define U32_BITFIELD_XOR "0"
165 #define U64_BITFIELD_XOR "0"
166 #endif
167
168 #if USB_HAVE_COMPAT_LINUX
169 #define MFL_SIZE "1"
170 #else
171 #define MFL_SIZE "0"
172 #endif
173
174 #if defined(KLD_MODULE) && (USB_HAVE_ID_SECTION != 0)
175 static const char __section("bus_autoconf_format") __used usb_id_format[] = {
176
177 /* Declare that three different sections use the same format */
178
179 "usb_host_id{256,:}"
180 "usb_device_id{256,:}"
181 "usb_dual_id{256,:}"
182
183 /* List size of fields in the usb_device_id structure */
184
185 #if ULONG_MAX >= 0xFFFFFFFFUL
186 "unused{0,8}"
187 "unused{0,8}"
188 "unused{0,8}"
189 "unused{0,8}"
190 #if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL
191 "unused{0,8}"
192 "unused{0,8}"
193 "unused{0,8}"
194 "unused{0,8}"
195 #endif
196 #else
197 #error "Please update code."
198 #endif
199
200 "idVendor[0]{" U16_XOR ",8}"
201 "idVendor[1]{" U16_XOR ",8}"
202 "idProduct[0]{" U16_XOR ",8}"
203 "idProduct[1]{" U16_XOR ",8}"
204 "bcdDevice_lo[0]{" U16_XOR ",8}"
205 "bcdDevice_lo[1]{" U16_XOR ",8}"
206 "bcdDevice_hi[0]{" U16_XOR ",8}"
207 "bcdDevice_hi[1]{" U16_XOR ",8}"
208
209 "bDeviceClass{0,8}"
210 "bDeviceSubClass{0,8}"
211 "bDeviceProtocol{0,8}"
212 "bInterfaceClass{0,8}"
213 "bInterfaceSubClass{0,8}"
214 "bInterfaceProtocol{0,8}"
215
216 "mf_vendor{" U8_BITFIELD_XOR ",1}"
217 "mf_product{" U8_BITFIELD_XOR ",1}"
218 "mf_dev_lo{" U8_BITFIELD_XOR ",1}"
219 "mf_dev_hi{" U8_BITFIELD_XOR ",1}"
220
221 "mf_dev_class{" U8_BITFIELD_XOR ",1}"
222 "mf_dev_subclass{" U8_BITFIELD_XOR ",1}"
223 "mf_dev_protocol{" U8_BITFIELD_XOR ",1}"
224 "mf_int_class{" U8_BITFIELD_XOR ",1}"
225
226 "mf_int_subclass{" U8_BITFIELD_XOR ",1}"
227 "mf_int_protocol{" U8_BITFIELD_XOR ",1}"
228 "unused{" U8_BITFIELD_XOR ",6}"
229
230 "mfl_vendor{" U16_XOR "," MFL_SIZE "}"
231 "mfl_product{" U16_XOR "," MFL_SIZE "}"
232 "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}"
233 "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}"
234
235 "mfl_dev_class{" U16_XOR "," MFL_SIZE "}"
236 "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}"
237 "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}"
238 "mfl_int_class{" U16_XOR "," MFL_SIZE "}"
239
240 "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}"
241 "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}"
242 "unused{" U16_XOR "," MFL_SIZE "}"
243 "unused{" U16_XOR "," MFL_SIZE "}"
244
245 "unused{" U16_XOR "," MFL_SIZE "}"
246 "unused{" U16_XOR "," MFL_SIZE "}"
247 "unused{" U16_XOR "," MFL_SIZE "}"
248 "unused{" U16_XOR "," MFL_SIZE "}"
249 };
250 #endif
251