usb_lookup.c revision 246194
1263320Sdim/* $FreeBSD: head/sys/dev/usb/usb_lookup.c 246194 2013-02-01 07:05:43Z hselasky $ */ 2263320Sdim/*- 3263320Sdim * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4263320Sdim * 5263320Sdim * Redistribution and use in source and binary forms, with or without 6263320Sdim * modification, are permitted provided that the following conditions 7263320Sdim * are met: 8263320Sdim * 1. Redistributions of source code must retain the above copyright 9263320Sdim * notice, this list of conditions and the following disclaimer. 10263320Sdim * 2. Redistributions in binary form must reproduce the above copyright 11263320Sdim * notice, this list of conditions and the following disclaimer in the 12263320Sdim * documentation and/or other materials provided with the distribution. 13263320Sdim * 14263320Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15263320Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16263320Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17263320Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18263320Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19263320Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20263320Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21263320Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22263320Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23263320Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24263320Sdim * SUCH DAMAGE. 25263320Sdim */ 26263320Sdim 27263320Sdim#ifdef USB_GLOBAL_INCLUDE_FILE 28263320Sdim#include USB_GLOBAL_INCLUDE_FILE 29263320Sdim#else 30263320Sdim#include <sys/stdint.h> 31263320Sdim#include <sys/stddef.h> 32263320Sdim#include <sys/param.h> 33263320Sdim#include <sys/queue.h> 34263320Sdim#include <sys/types.h> 35263320Sdim#include <sys/systm.h> 36263320Sdim#include <sys/kernel.h> 37263320Sdim#include <sys/bus.h> 38263320Sdim#include <sys/module.h> 39263320Sdim#include <sys/lock.h> 40263320Sdim#include <sys/mutex.h> 41263320Sdim#include <sys/condvar.h> 42263320Sdim#include <sys/sysctl.h> 43263320Sdim#include <sys/sx.h> 44263320Sdim#include <sys/unistd.h> 45263320Sdim#include <sys/callout.h> 46263320Sdim#include <sys/malloc.h> 47263320Sdim#include <sys/priv.h> 48263320Sdim#include <sys/limits.h> 49263320Sdim#include <sys/endian.h> 50263320Sdim 51263320Sdim#include <dev/usb/usb.h> 52263320Sdim#include <dev/usb/usbdi.h> 53263320Sdim#endif /* USB_GLOBAL_INCLUDE_FILE */ 54263320Sdim 55263320Sdim/*------------------------------------------------------------------------* 56263320Sdim * usbd_lookup_id_by_info 57263320Sdim * 58263320Sdim * This functions takes an array of "struct usb_device_id" and tries 59263320Sdim * to match the entries with the information in "struct usbd_lookup_info". 60263320Sdim * 61263320Sdim * NOTE: The "sizeof_id" parameter must be a multiple of the 62263320Sdim * usb_device_id structure size. Else the behaviour of this function 63263320Sdim * is undefined. 64263320Sdim * 65263320Sdim * Return values: 66263320Sdim * NULL: No match found. 67263320Sdim * Else: Pointer to matching entry. 68263320Sdim *------------------------------------------------------------------------*/ 69263320Sdimconst struct usb_device_id * 70263320Sdimusbd_lookup_id_by_info(const struct usb_device_id *id, usb_size_t sizeof_id, 71263320Sdim const struct usbd_lookup_info *info) 72263320Sdim{ 73263320Sdim const struct usb_device_id *id_end; 74263320Sdim 75263320Sdim if (id == NULL) { 76263320Sdim goto done; 77263320Sdim } 78263320Sdim id_end = (const void *)(((const uint8_t *)id) + sizeof_id); 79263320Sdim 80263320Sdim /* 81263320Sdim * Keep on matching array entries until we find a match or 82263320Sdim * until we reach the end of the matching array: 83263320Sdim */ 84263320Sdim for (; id != id_end; id++) { 85263320Sdim 86263320Sdim if ((id->match_flag_vendor) && 87263320Sdim (id->idVendor != info->idVendor)) { 88263320Sdim continue; 89263320Sdim } 90263320Sdim if ((id->match_flag_product) && 91263320Sdim (id->idProduct != info->idProduct)) { 92263320Sdim continue; 93263320Sdim } 94263320Sdim if ((id->match_flag_dev_lo) && 95263320Sdim (id->bcdDevice_lo > info->bcdDevice)) { 96263320Sdim continue; 97263320Sdim } 98263320Sdim if ((id->match_flag_dev_hi) && 99263320Sdim (id->bcdDevice_hi < info->bcdDevice)) { 100263320Sdim continue; 101263320Sdim } 102263320Sdim if ((id->match_flag_dev_class) && 103263320Sdim (id->bDeviceClass != info->bDeviceClass)) { 104263320Sdim continue; 105263320Sdim } 106263320Sdim if ((id->match_flag_dev_subclass) && 107263320Sdim (id->bDeviceSubClass != info->bDeviceSubClass)) { 108263320Sdim continue; 109263320Sdim } 110263320Sdim if ((id->match_flag_dev_protocol) && 111263320Sdim (id->bDeviceProtocol != info->bDeviceProtocol)) { 112263320Sdim continue; 113263320Sdim } 114263320Sdim if ((id->match_flag_int_class) && 115263320Sdim (id->bInterfaceClass != info->bInterfaceClass)) { 116263320Sdim continue; 117263320Sdim } 118263320Sdim if ((id->match_flag_int_subclass) && 119263320Sdim (id->bInterfaceSubClass != info->bInterfaceSubClass)) { 120263320Sdim continue; 121263320Sdim } 122263320Sdim if ((id->match_flag_int_protocol) && 123263320Sdim (id->bInterfaceProtocol != info->bInterfaceProtocol)) { 124263320Sdim continue; 125263320Sdim } 126263320Sdim /* We found a match! */ 127263320Sdim return (id); 128263320Sdim } 129263320Sdim 130263320Sdimdone: 131263320Sdim return (NULL); 132263320Sdim} 133263320Sdim 134263320Sdim/*------------------------------------------------------------------------* 135263320Sdim * usbd_lookup_id_by_uaa - factored out code 136263320Sdim * 137263320Sdim * Return values: 138263320Sdim * 0: Success 139263320Sdim * Else: Failure 140263320Sdim *------------------------------------------------------------------------*/ 141263320Sdimint 142263320Sdimusbd_lookup_id_by_uaa(const struct usb_device_id *id, usb_size_t sizeof_id, 143263320Sdim struct usb_attach_arg *uaa) 144263320Sdim{ 145263320Sdim id = usbd_lookup_id_by_info(id, sizeof_id, &uaa->info); 146263320Sdim if (id) { 147263320Sdim /* copy driver info */ 148263320Sdim uaa->driver_info = id->driver_info; 149263320Sdim return (0); 150263320Sdim } 151263320Sdim return (ENXIO); 152263320Sdim} 153263320Sdim 154263320Sdim/*------------------------------------------------------------------------* 155263320Sdim * Export the USB device ID format we use to userspace tools. 156263320Sdim *------------------------------------------------------------------------*/ 157263320Sdim#if BYTE_ORDER == BIG_ENDIAN 158263320Sdim#define U16_XOR "8" 159263320Sdim#define U32_XOR "12" 160263320Sdim#define U64_XOR "56" 161263320Sdim#define U8_BITFIELD_XOR "7" 162263320Sdim#define U16_BITFIELD_XOR "15" 163263320Sdim#define U32_BITFIELD_XOR "31" 164263320Sdim#define U64_BITFIELD_XOR "63" 165263320Sdim#else 166263320Sdim#define U16_XOR "0" 167263320Sdim#define U32_XOR "0" 168263320Sdim#define U64_XOR "0" 169263320Sdim#define U8_BITFIELD_XOR "0" 170263320Sdim#define U16_BITFIELD_XOR "0" 171263320Sdim#define U32_BITFIELD_XOR "0" 172263320Sdim#define U64_BITFIELD_XOR "0" 173263320Sdim#endif 174263320Sdim 175263320Sdim#if USB_HAVE_COMPAT_LINUX 176263320Sdim#define MFL_SIZE "1" 177263320Sdim#else 178263320Sdim#define MFL_SIZE "0" 179263320Sdim#endif 180263320Sdim 181263320Sdim#if defined(KLD_MODULE) && (USB_HAVE_ID_SECTION != 0) 182263320Sdimstatic const char __section("bus_autoconf_format") __used usb_id_format[] = { 183263320Sdim 184263320Sdim /* Declare that three different sections use the same format */ 185263320Sdim 186263320Sdim "usb_host_id{256,:}" 187263320Sdim "usb_device_id{256,:}" 188263320Sdim "usb_dual_id{256,:}" 189263320Sdim 190263320Sdim /* List size of fields in the usb_device_id structure */ 191263320Sdim 192263320Sdim#if ULONG_MAX >= 0xFFFFFFFFUL 193263320Sdim "unused{0,8}" 194263320Sdim "unused{0,8}" 195263320Sdim "unused{0,8}" 196263320Sdim "unused{0,8}" 197263320Sdim#if ULONG_MAX >= 0xFFFFFFFFFFFFFFFFULL 198263320Sdim "unused{0,8}" 199263320Sdim "unused{0,8}" 200263320Sdim "unused{0,8}" 201263320Sdim "unused{0,8}" 202263320Sdim#endif 203263320Sdim#else 204263320Sdim#error "Please update code." 205263320Sdim#endif 206263320Sdim 207263320Sdim "idVendor[0]{" U16_XOR ",8}" 208263320Sdim "idVendor[1]{" U16_XOR ",8}" 209263320Sdim "idProduct[0]{" U16_XOR ",8}" 210263320Sdim "idProduct[1]{" U16_XOR ",8}" 211263320Sdim "bcdDevice_lo[0]{" U16_XOR ",8}" 212263320Sdim "bcdDevice_lo[1]{" U16_XOR ",8}" 213263320Sdim "bcdDevice_hi[0]{" U16_XOR ",8}" 214263320Sdim "bcdDevice_hi[1]{" U16_XOR ",8}" 215263320Sdim 216263320Sdim "bDeviceClass{0,8}" 217263320Sdim "bDeviceSubClass{0,8}" 218263320Sdim "bDeviceProtocol{0,8}" 219263320Sdim "bInterfaceClass{0,8}" 220263320Sdim "bInterfaceSubClass{0,8}" 221263320Sdim "bInterfaceProtocol{0,8}" 222263320Sdim 223263320Sdim "mf_vendor{" U8_BITFIELD_XOR ",1}" 224263320Sdim "mf_product{" U8_BITFIELD_XOR ",1}" 225263320Sdim "mf_dev_lo{" U8_BITFIELD_XOR ",1}" 226263320Sdim "mf_dev_hi{" U8_BITFIELD_XOR ",1}" 227263320Sdim 228263320Sdim "mf_dev_class{" U8_BITFIELD_XOR ",1}" 229263320Sdim "mf_dev_subclass{" U8_BITFIELD_XOR ",1}" 230263320Sdim "mf_dev_protocol{" U8_BITFIELD_XOR ",1}" 231263320Sdim "mf_int_class{" U8_BITFIELD_XOR ",1}" 232 233 "mf_int_subclass{" U8_BITFIELD_XOR ",1}" 234 "mf_int_protocol{" U8_BITFIELD_XOR ",1}" 235 "unused{" U8_BITFIELD_XOR ",6}" 236 237 "mfl_vendor{" U16_XOR "," MFL_SIZE "}" 238 "mfl_product{" U16_XOR "," MFL_SIZE "}" 239 "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}" 240 "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}" 241 242 "mfl_dev_class{" U16_XOR "," MFL_SIZE "}" 243 "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}" 244 "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}" 245 "mfl_int_class{" U16_XOR "," MFL_SIZE "}" 246 247 "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}" 248 "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}" 249 "unused{" U16_XOR "," MFL_SIZE "}" 250 "unused{" U16_XOR "," MFL_SIZE "}" 251 252 "unused{" U16_XOR "," MFL_SIZE "}" 253 "unused{" U16_XOR "," MFL_SIZE "}" 254 "unused{" U16_XOR "," MFL_SIZE "}" 255 "unused{" U16_XOR "," MFL_SIZE "}" 256}; 257#endif 258