1/* $FreeBSD$ */
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#ifdef USB_GLOBAL_INCLUDE_FILE
28#include USB_GLOBAL_INCLUDE_FILE
29#else
30#include <sys/stdint.h>
31#include <sys/stddef.h>
32#include <sys/param.h>
33#include <sys/queue.h>
34#include <sys/types.h>
35#include <sys/systm.h>
36#include <sys/kernel.h>
37#include <sys/bus.h>
38#include <sys/module.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
41#include <sys/condvar.h>
42#include <sys/sysctl.h>
43#include <sys/sx.h>
44#include <sys/unistd.h>
45#include <sys/callout.h>
46#include <sys/malloc.h>
47#include <sys/priv.h>
48#include <sys/limits.h>
49#include <sys/endian.h>
50
51#include <dev/usb/usb.h>
52#include <dev/usb/usbdi.h>
53#endif			/* USB_GLOBAL_INCLUDE_FILE */
54
55/*------------------------------------------------------------------------*
56 *	usbd_lookup_id_by_info
57 *
58 * This functions takes an array of "struct usb_device_id" and tries
59 * to match the entries with the information in "struct usbd_lookup_info".
60 *
61 * NOTE: The "sizeof_id" parameter must be a multiple of the
62 * usb_device_id structure size. Else the behaviour of this function
63 * is undefined.
64 *
65 * Return values:
66 * NULL: No match found.
67 * Else: Pointer to matching entry.
68 *------------------------------------------------------------------------*/
69const struct usb_device_id *
70usbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id,
71    const struct usbd_lookup_info *info)
72{
73	const struct usb_device_id *id_end;
74
75	if (id == NULL) {
76		goto done;
77	}
78	id_end = (const void *)(((const uint8_t *)id) + sizeof_id);
79
80	/*
81	 * Keep on matching array entries until we find a match or
82	 * until we reach the end of the matching array:
83	 */
84	for (; id != id_end; id++) {
85
86		if ((id->match_flag_vendor) &&
87		    (id->idVendor != info->idVendor)) {
88			continue;
89		}
90		if ((id->match_flag_product) &&
91		    (id->idProduct != info->idProduct)) {
92			continue;
93		}
94		if ((id->match_flag_dev_lo) &&
95		    (id->bcdDevice_lo > info->bcdDevice)) {
96			continue;
97		}
98		if ((id->match_flag_dev_hi) &&
99		    (id->bcdDevice_hi < info->bcdDevice)) {
100			continue;
101		}
102		if ((id->match_flag_dev_class) &&
103		    (id->bDeviceClass != info->bDeviceClass)) {
104			continue;
105		}
106		if ((id->match_flag_dev_subclass) &&
107		    (id->bDeviceSubClass != info->bDeviceSubClass)) {
108			continue;
109		}
110		if ((id->match_flag_dev_protocol) &&
111		    (id->bDeviceProtocol != info->bDeviceProtocol)) {
112			continue;
113		}
114		if ((id->match_flag_int_class) &&
115		    (id->bInterfaceClass != info->bInterfaceClass)) {
116			continue;
117		}
118		if ((id->match_flag_int_subclass) &&
119		    (id->bInterfaceSubClass != info->bInterfaceSubClass)) {
120			continue;
121		}
122		if ((id->match_flag_int_protocol) &&
123		    (id->bInterfaceProtocol != info->bInterfaceProtocol)) {
124			continue;
125		}
126		/* We found a match! */
127		return (id);
128	}
129
130done:
131	return (NULL);
132}
133
134/*------------------------------------------------------------------------*
135 *	usbd_lookup_id_by_uaa - factored out code
136 *
137 * Return values:
138 *    0: Success
139 * Else: Failure
140 *------------------------------------------------------------------------*/
141int
142usbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id,
143    struct usb_attach_arg *uaa)
144{
145	id = usbd_lookup_id_by_info(id, sizeof_id, &uaa->info);
146	if (id) {
147		/* copy driver info */
148		uaa->driver_info = id->driver_info;
149		return (0);
150	}
151	return (ENXIO);
152}
153
154/*------------------------------------------------------------------------*
155 *	Export the USB device ID format we use to userspace tools.
156 *------------------------------------------------------------------------*/
157#if BYTE_ORDER == LITTLE_ENDIAN
158#define	U16_XOR "0"
159#else
160#define	U16_XOR "8"
161#endif
162
163#if defined(KLD_MODULE) && (USB_HAVE_ID_SECTION != 0)
164static const char __section("bus_autoconf_format") __used usb_id_format[] = {
165
166	/* Declare that three different sections use the same format */
167
168	"usb_host_id{256,:}"
169	"usb_device_id{256,:}"
170	"usb_dual_id{256,:}"
171
172	/* List size of fields in the usb_device_id structure */
173
174	"mf_vendor{" U16_XOR ",1}"
175	"mf_product{" U16_XOR ",1}"
176	"mf_dev_lo{" U16_XOR ",1}"
177	"mf_dev_hi{" U16_XOR ",1}"
178
179	"mf_dev_class{" U16_XOR ",1}"
180	"mf_dev_subclass{" U16_XOR ",1}"
181	"mf_dev_protocol{" U16_XOR ",1}"
182	"mf_int_class{" U16_XOR ",1}"
183
184	"mf_int_subclass{" U16_XOR ",1}"
185	"mf_int_protocol{" U16_XOR ",1}"
186	"unused{" U16_XOR ",6}"
187
188	"idVendor[0]{" U16_XOR ",8}"
189	"idVendor[1]{" U16_XOR ",8}"
190	"idProduct[0]{" U16_XOR ",8}"
191	"idProduct[1]{" U16_XOR ",8}"
192	"bcdDevice_lo[0]{" U16_XOR ",8}"
193	"bcdDevice_lo[1]{" U16_XOR ",8}"
194	"bcdDevice_hi[0]{" U16_XOR ",8}"
195	"bcdDevice_hi[1]{" U16_XOR ",8}"
196
197	"bDeviceClass{0,8}"
198	"bDeviceSubClass{0,8}"
199	"bDeviceProtocol{0,8}"
200	"bInterfaceClass{0,8}"
201	"bInterfaceSubClass{0,8}"
202	"bInterfaceProtocol{0,8}"
203
204#if USB_HAVE_COMPAT_LINUX
205	"mfl_vendor{" U16_XOR ",1}"
206	"mfl_product{" U16_XOR ",1}"
207	"mfl_dev_lo{" U16_XOR ",1}"
208	"mfl_dev_hi{" U16_XOR ",1}"
209
210	"mfl_dev_class{" U16_XOR ",1}"
211	"mfl_dev_subclass{" U16_XOR ",1}"
212	"mfl_dev_protocol{" U16_XOR ",1}"
213	"mfl_int_class{" U16_XOR ",1}"
214
215	"mfl_int_subclass{" U16_XOR ",1}"
216	"mfl_int_protocol{" U16_XOR ",1}"
217	"unused{" U16_XOR ",6}"
218#endif
219};
220#endif
221