diff options
-rw-r--r-- | tools/tools/bus_autoconf/Makefile | 5 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.c | 375 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.h | 55 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.sh | 57 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf_format_example.txt | 111 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_load_file.c | 72 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_load_file.h | 33 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_sections.c | 223 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_sections.h | 35 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_usb.c | 382 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_usb.h | 73 |
11 files changed, 1005 insertions, 416 deletions
diff --git a/tools/tools/bus_autoconf/Makefile b/tools/tools/bus_autoconf/Makefile index c2f1b13..c7104de 100644 --- a/tools/tools/bus_autoconf/Makefile +++ b/tools/tools/bus_autoconf/Makefile @@ -36,7 +36,10 @@ PROG= bus_autoconf MAN= BINDIR?= /usr/local/bin -SRCS= bus_autoconf.c +SRCS+= bus_autoconf.c +SRCS+= bus_load_file.c +SRCS+= bus_sections.c +SRCS+= bus_usb.c WARNS= 6 diff --git a/tools/tools/bus_autoconf/bus_autoconf.c b/tools/tools/bus_autoconf/bus_autoconf.c index 3ddab5a..adbf6e4 100644 --- a/tools/tools/bus_autoconf/bus_autoconf.c +++ b/tools/tools/bus_autoconf/bus_autoconf.c @@ -33,306 +33,23 @@ #include <stdio.h> #include <stdint.h> #include <stdlib.h> -#include <unistd.h> -#include <sysexits.h> -#include <err.h> -#include <fcntl.h> #include <string.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> #include "bus_autoconf.h" - -static char *type; -static char *file_name; -static const char *mode; - -struct usb_info; -static void usb_dump_sub(struct usb_device_id *, struct usb_info *); - -/* - * To ensure that the correct USB driver is loaded, the driver having - * the most information about the device must be probed first. Then - * more generic drivers shall be probed. - */ -static int -usb_compare(const void *_a, const void *_b) -{ - const struct usb_device_id *a = _a; - const struct usb_device_id *b = _b; - - /* vendor matches first */ - - if (a->match_flag_vendor > b->match_flag_vendor) - return (-1); - if (a->match_flag_vendor < b->match_flag_vendor) - return (1); - - /* product matches first */ - - if (a->match_flag_product > b->match_flag_product) - return (-1); - if (a->match_flag_product < b->match_flag_product) - return (1); - - /* device class matches first */ - - if (a->match_flag_dev_class > b->match_flag_dev_class) - return (-1); - if (a->match_flag_dev_class < b->match_flag_dev_class) - return (1); - - if (a->match_flag_dev_subclass > b->match_flag_dev_subclass) - return (-1); - if (a->match_flag_dev_subclass < b->match_flag_dev_subclass) - return (1); - - /* interface class matches first */ - - if (a->match_flag_int_class > b->match_flag_int_class) - return (-1); - if (a->match_flag_int_class < b->match_flag_int_class) - return (1); - - if (a->match_flag_int_subclass > b->match_flag_int_subclass) - return (-1); - if (a->match_flag_int_subclass < b->match_flag_int_subclass) - return (1); - - if (a->match_flag_int_protocol > b->match_flag_int_protocol) - return (-1); - if (a->match_flag_int_protocol < b->match_flag_int_protocol) - return (1); - - /* then sort according to value */ - - if (a->idVendor > b->idVendor) - return (1); - if (a->idVendor < b->idVendor) - return (-1); - if (a->idProduct > b->idProduct) - return (1); - if (a->idProduct < b->idProduct) - return (-1); - if (a->bDeviceClass > b->bDeviceClass) - return (1); - if (a->bDeviceClass < b->bDeviceClass) - return (-1); - if (a->bDeviceSubClass > b->bDeviceSubClass) - return (1); - if (a->bDeviceSubClass < b->bDeviceSubClass) - return (-1); - if (a->bDeviceProtocol > b->bDeviceProtocol) - return (1); - if (a->bDeviceProtocol < b->bDeviceProtocol) - return (-1); - if (a->bInterfaceClass > b->bInterfaceClass) - return (1); - if (a->bInterfaceClass < b->bInterfaceClass) - return (-1); - if (a->bInterfaceSubClass > b->bInterfaceSubClass) - return (1); - if (a->bInterfaceSubClass < b->bInterfaceSubClass) - return (-1); - if (a->bInterfaceProtocol > b->bInterfaceProtocol) - return (1); - if (a->bInterfaceProtocol < b->bInterfaceProtocol) - return (-1); - - /* in the end sort by module name */ - - return (strcmp(a->module_name, b->module_name)); -} - -static void -usb_sort(struct usb_device_id *id, uint32_t nid) -{ - qsort(id, nid, sizeof(*id), &usb_compare); -} - -struct usb_info { - uint8_t is_iface; - uint8_t is_any; - uint8_t is_vp; - uint8_t is_dev; -}; - -static void -usb_dump_sub(struct usb_device_id *id, struct usb_info *pinfo) -{ -#if USB_HAVE_COMPAT_LINUX - if (id->match_flags != 0) { - if (id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) - id->match_flag_vendor = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) - id->match_flag_product = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) - id->match_flag_dev_lo = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) - id->match_flag_dev_hi = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) - id->match_flag_dev_class = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) - id->match_flag_dev_subclass = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) - id->match_flag_dev_protocol = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) - id->match_flag_int_class = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) - id->match_flag_int_subclass = 1; - if (id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) - id->match_flag_int_protocol = 1; - id->match_flags = 0; - } -#endif - if (pinfo != NULL) { - - pinfo->is_iface = id->match_flag_int_class | - id->match_flag_int_protocol | - id->match_flag_int_subclass; - - pinfo->is_dev = id->match_flag_dev_class | - id->match_flag_dev_subclass; - - pinfo->is_vp = id->match_flag_vendor | - id->match_flag_product; - - pinfo->is_any = pinfo->is_vp + pinfo->is_dev + pinfo->is_iface; - } -} - -static char * -usb_trim(char *ptr) -{ - char *end; - - end = strchr(ptr, ' '); - if (end) - *end = 0; - return (ptr); -} - -static uint32_t -usb_dump(struct usb_device_id *id, uint32_t nid) -{ - uint32_t n = 1; - struct usb_info info; - - usb_dump_sub(id, &info); - - if (info.is_any) { - printf("nomatch 32 {\n" - " match \"bus\" \"uhub[0-9]+\";\n" - " match \"mode\" \"%s\";\n", mode); - } else { - return (n); - } - - if (id->match_flag_vendor) { - printf(" match \"vendor\" \"0x%04x\";\n", - id->idVendor); - } - if (id->match_flag_product) { - uint32_t x; - - if (info.is_any == 1 && info.is_vp == 1) { - /* try to join similar entries */ - while (n < nid) { - usb_dump_sub(id + n, &info); - - if (info.is_any != 1 || info.is_vp != 1) - break; - if (id[n].idVendor != id[0].idVendor) - break; - n++; - } - /* restore infos */ - usb_dump_sub(id, &info); - } - if (n == 1) { - printf(" match \"product\" \"0x%04x\";\n", - id->idProduct); - } else { - printf(" match \"product\" \"("); - - for (x = 0; x != n; x++) { - printf("0x%04x%s", id[x].idProduct, - (x == (n - 1)) ? "" : "|"); - } - - printf(")\";\n"); - } - } - if (id->match_flag_dev_class) { - printf(" match \"devclass\" \"0x%02x\";\n", - id->bDeviceClass); - } - if (id->match_flag_dev_subclass) { - printf(" match \"devsubclass\" \"0x%02x\";\n", - id->bDeviceSubClass); - } - if (id->match_flag_int_class) { - printf(" match \"intclass\" \"0x%02x\";\n", - id->bInterfaceClass); - } - if (id->match_flag_int_subclass) { - printf(" match \"intsubclass\" \"0x%02x\";\n", - id->bInterfaceSubClass); - } - if (id->match_flag_int_protocol) { - printf(" match \"intprotocol\" \"0x%02x\";\n", - id->bInterfaceProtocol); - } - printf(" action \"kldload %s\";\n" - "};\n\n", usb_trim(id->module_name)); - - return (n); -} - -static void -usb_parse_and_dump(int f, off_t size) -{ - struct usb_device_id *id; - uint32_t nid; - uint32_t x; - - if (size % sizeof(struct usb_device_id)) { - errx(EX_NOINPUT, "Size is not divisible by %d", - (int)sizeof(struct usb_device_id)); - } - lseek(f, 0, SEEK_SET); - - id = malloc(size); - if (id == NULL) { - errx(EX_SOFTWARE, "Out of memory"); - } - if (read(f, id, size) != size) { - err(EX_NOINPUT, "Cannot read all data"); - } - nid = size / sizeof(*id); - - for (x = 0; x != nid; x++) { - /* make sure flag bits are correct */ - usb_dump_sub(id + x, NULL); - /* zero terminate string */ - id[x].module_name[sizeof(id[0].module_name) - 1] = 0; - } - - usb_sort(id, nid); - - for (x = 0; x != nid;) - x += usb_dump(id + x, nid - x); - - free(id); - - printf("# %d %s entries processed\n\n", (int)nid, type); -} +#include "bus_sections.h" +#include "bus_load_file.h" +#include "bus_usb.h" static void usage(void) { fprintf(stderr, "bus_autoconf - devd config file generator\n" - " -i <input_binary>\n" - " -t <structure_type>\n" + " -i <structure_type,module.ko>\n" + " -F <format_file>\n" " -h show usage\n" ); exit(EX_USAGE); @@ -341,50 +58,68 @@ usage(void) int main(int argc, char **argv) { - const char *params = "i:ht:"; + const char *params = "i:F:h"; + char *fname; + char *section; + char *module; + char *postfix; + uint8_t *ptr; + uint32_t len; int c; - int f; - off_t off; + int any_opt = 0; while ((c = getopt(argc, argv, params)) != -1) { switch (c) { case 'i': - file_name = optarg; + fname = optarg; + load_file(fname, &ptr, &len); + + module = strchr(fname, ','); + if (module == NULL) { + errx(EX_USAGE, "Invalid input " + "file name '%s'", fname); + } + /* split module and section */ + *module++ = 0; + + /* remove postfix */ + postfix = strchr(module, '.'); + if (postfix) + *postfix = 0; + + /* get section name */ + section = fname; + + /* check section type */ + if (strncmp(section, "usb_", 4) == 0) + usb_import_entries(section, module, ptr, len); + else + errx(EX_USAGE, "Invalid section '%s'", section); + + free(ptr); + + any_opt = 1; break; - case 't': - type = optarg; + + case 'F': + fname = optarg; + load_file(fname, &ptr, &len); + format_parse_entries(ptr, len); + free(ptr); + + any_opt = 1; break; + default: usage(); break; } } - if (type == NULL || file_name == NULL) + if (any_opt == 0) usage(); - f = open(file_name, O_RDONLY); - if (f < 0) - err(EX_NOINPUT, "Cannot open file '%s'", file_name); - - off = lseek(f, 0, SEEK_END); - if (off <= 0) - err(EX_NOINPUT, "Cannot seek to end of file"); - - if (strcmp(type, "usb_host") == 0) { - mode = "host"; - usb_parse_and_dump(f, off); - } else if (strcmp(type, "usb_device") == 0) { - mode = "device"; - usb_parse_and_dump(f, off); - } else if (strcmp(type, "usb_dual") == 0) { - mode = "(host|device)"; - usb_parse_and_dump(f, off); - } else { - err(EX_USAGE, "Unsupported structure type: %s", type); - } - - close(f); + usb_dump_entries(); return (0); } diff --git a/tools/tools/bus_autoconf/bus_autoconf.h b/tools/tools/bus_autoconf/bus_autoconf.h index 7dbc486..0a1ca3f 100644 --- a/tools/tools/bus_autoconf/bus_autoconf.h +++ b/tools/tools/bus_autoconf/bus_autoconf.h @@ -28,59 +28,4 @@ #ifndef _BUS_AUTOCONF_H_ #define _BUS_AUTOCONF_H_ -/* Make sure we get the have compat linux definition. */ -#include <dev/usb/usb.h> - -struct usb_device_id { - - /* Internal field */ - char module_name[32]; - - /* Hook for driver specific information */ - unsigned long driver_info; - - /* Used for product specific matches; the BCD range is inclusive */ - uint16_t idVendor; - uint16_t idProduct; - uint16_t bcdDevice_lo; - uint16_t bcdDevice_hi; - - /* Used for device class matches */ - uint8_t bDeviceClass; - uint8_t bDeviceSubClass; - uint8_t bDeviceProtocol; - - /* Used for interface class matches */ - uint8_t bInterfaceClass; - uint8_t bInterfaceSubClass; - uint8_t bInterfaceProtocol; - - /* Select which fields to match against */ - uint8_t match_flag_vendor:1; - uint8_t match_flag_product:1; - uint8_t match_flag_dev_lo:1; - uint8_t match_flag_dev_hi:1; - uint8_t match_flag_dev_class:1; - uint8_t match_flag_dev_subclass:1; - uint8_t match_flag_dev_protocol:1; - uint8_t match_flag_int_class:1; - uint8_t match_flag_int_subclass:1; - uint8_t match_flag_int_protocol:1; - -#if USB_HAVE_COMPAT_LINUX - /* which fields to match against */ - uint16_t match_flags; -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 -#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 -#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 -#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 -#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 -#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 -#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 -#endif -}; - #endif /* _BUS_AUTOCONF_H_ */ diff --git a/tools/tools/bus_autoconf/bus_autoconf.sh b/tools/tools/bus_autoconf/bus_autoconf.sh index 21a4df0..1d1d038 100644 --- a/tools/tools/bus_autoconf/bus_autoconf.sh +++ b/tools/tools/bus_autoconf/bus_autoconf.sh @@ -29,30 +29,6 @@ OS=FreeBSD DOLLAR=$ -cleanup() -{ - # Cleanup - rm -f usb_dual.ids - rm -f usb_host.ids - rm -f usb_device.ids -} - -usb_format() -{ - [ -f ${1} ] || return - - # Split into one and one record - split -b 32 ${1} ${1}. - - # Prefix each record by the module name - for G in $(ls ${1}.*) - do - printf "%-32s" ${3} >> ${2} - cat ${G} >> ${2} - rm -f ${G} - done -} - cat <<EOF # # ${DOLLAR}${OS}${DOLLAR} @@ -63,33 +39,34 @@ cat <<EOF EOF -# Cleanup -cleanup +rm -f bus_autoconf_format.bin +rm -f bus_autoconf_args.txt for F in $* do -# Get module basename -H=$(basename ${F} | sed -e "s/\.ko//g") +G=$(basename ${F}) + +# Format information +objcopy -j bus_autoconf_format -O binary ${F} temp.ids 2> /dev/null +[ -f temp.ids ] && cat temp.ids >> bus_autoconf_format.bin -# USB Host -objcopy -j usb_host_id -O binary ${F} temp.ids 2> /dev/null -usb_format temp.ids usb_host.ids ${H} +# USB Host mode +objcopy -j usb_host_id -O binary ${F} "usb_host_id,${G}" 2> /dev/null +[ -f "usb_host_id,${G}" ] && (echo -n " -i usb_host_id,${G}" >> bus_autoconf_args.txt) -# USB Device -objcopy -j usb_device_id -O binary ${F} temp.ids 2> /dev/null -usb_format temp.ids usb_device.ids ${H} +# USB Device mode +objcopy -j usb_device_id -O binary ${F} "usb_device_id,${G}" 2> /dev/null +[ -f "usb_device_id,${G}" ] && (echo -n " -i usb_device_id,${G}" >> bus_autoconf_args.txt) # USB Dual mode -objcopy -j usb_dual_id -O binary ${F} temp.ids 2> /dev/null -usb_format temp.ids usb_dual.ids ${H} +objcopy -j usb_dual_id -O binary ${F} "usb_dual_id,${G}" 2> /dev/null +[ -f "usb_dual_id,${G}" ] && (echo -n " -i usb_dual_id,${G}" >> bus_autoconf_args.txt) done # Dump all data -[ -f usb_dual.ids ] && bus_autoconf -i usb_dual.ids -t usb_dual -[ -f usb_host.ids ] && bus_autoconf -i usb_host.ids -t usb_host -[ -f usb_device.ids ] && bus_autoconf -i usb_device.ids -t usb_device +bus_autoconf -F bus_autoconf_format.bin $(cat bus_autoconf_args.txt) # Cleanup -cleanup +rm -f -- bus_autoconf_format.bin $(cat bus_autoconf_args.txt) diff --git a/tools/tools/bus_autoconf/bus_autoconf_format_example.txt b/tools/tools/bus_autoconf/bus_autoconf_format_example.txt new file mode 100644 index 0000000..e118f1f --- /dev/null +++ b/tools/tools/bus_autoconf/bus_autoconf_format_example.txt @@ -0,0 +1,111 @@ +/* $FreeBSD$ */ + +#if BYTE_ORDER == BIG_ENDIAN +#define U16_XOR "8" +#define U32_XOR "12" +#define U64_XOR "56" +#define U8_BITFIELD_XOR "7" +#define U16_BITFIELD_XOR "15" +#define U32_BITFIELD_XOR "31" +#define U64_BITFIELD_XOR "63" +#else +#define U16_XOR "0" +#define U32_XOR "0" +#define U64_XOR "0" +#define U8_BITFIELD_XOR "0" +#define U16_BITFIELD_XOR "0" +#define U32_BITFIELD_XOR "0" +#define U64_BITFIELD_XOR "0" +#endif + +#if USB_HAVE_COMPAT_LINUX +#define MFL_SIZE "1" +#else +#define MFL_SIZE "0" +#endif + +static const char __section("bus_autoconf_format") __used usb_id_format[] = { + + /* + * Declare three different sections that use the same format. + * All sizes are in bits. Fields cannot be greater than + * 8 bits in size. Bitfields having a size greater than 1 + * must fit within the byte in which the bitfield is defined. + */ + + "usb_host_id{256,:}" + "usb_device_id{256,:}" + "usb_dual_id{256,:}" + + /* + * Describe all fields in the usb_device_id structure + * which is found in sys/dev/usb/usbdi.h. + */ + +#if BITS_PER_LONG == 32 || BITS_PER_LONG == 64 + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#if BITS_PER_LONG == 64 + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" + "unused{0,8}" +#endif +#else +#error "Please update code." +#endif + + "idVendor[0]{" U16_XOR ",8}" + "idVendor[1]{" U16_XOR ",8}" + "idProduct[0]{" U16_XOR ",8}" + "idProduct[1]{" U16_XOR ",8}" + "bcdDevice_lo[0]{" U16_XOR ",8}" + "bcdDevice_lo[1]{" U16_XOR ",8}" + "bcdDevice_hi[0]{" U16_XOR ",8}" + "bcdDevice_hi[1]{" U16_XOR ",8}" + + "bDeviceClass{0,8}" + "bDeviceSubClass{0,8}" + "bDeviceProtocol{0,8}" + "bInterfaceClass{0,8}" + "bInterfaceSubClass{0,8}" + "bInterfaceProtocol{0,8}" + +/* NOTE: On big endian machines bitfields are bitreversed. */ + + "mf_vendor{" U8_BITFIELD_XOR ",1}" + "mf_product{" U8_BITFIELD_XOR ",1}" + "mf_dev_lo{" U8_BITFIELD_XOR ",1}" + "mf_dev_hi{" U8_BITFIELD_XOR ",1}" + + "mf_dev_class{" U8_BITFIELD_XOR ",1}" + "mf_dev_subclass{" U8_BITFIELD_XOR ",1}" + "mf_dev_protocol{" U8_BITFIELD_XOR ",1}" + "mf_int_class{" U8_BITFIELD_XOR ",1}" + + "mf_int_subclass{" U8_BITFIELD_XOR ",1}" + "mf_int_protocol{" U8_BITFIELD_XOR ",1}" + "unused{" U8_BITFIELD_XOR ",6}" + + "mfl_vendor{" U16_XOR "," MFL_SIZE "}" + "mfl_product{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_lo{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_hi{" U16_XOR "," MFL_SIZE "}" + + "mfl_dev_class{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_dev_protocol{" U16_XOR "," MFL_SIZE "}" + "mfl_int_class{" U16_XOR "," MFL_SIZE "}" + + "mfl_int_subclass{" U16_XOR "," MFL_SIZE "}" + "mfl_int_protocol{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" + "unused{" U16_XOR "," MFL_SIZE "}" +}; diff --git a/tools/tools/bus_autoconf/bus_load_file.c b/tools/tools/bus_autoconf/bus_load_file.c new file mode 100644 index 0000000..88f806a --- /dev/null +++ b/tools/tools/bus_autoconf/bus_load_file.c @@ -0,0 +1,72 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <fcntl.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> + +#include "bus_load_file.h" + +void +load_file(const char *fname, uint8_t **pptr, uint32_t *plen) +{ + uint8_t *ptr; + uint32_t len; + off_t off; + int f; + + f = open(fname, O_RDONLY); + if (f < 0) + err(EX_NOINPUT, "Cannot open file '%s'", fname); + + off = lseek(f, 0, SEEK_END); + if (off <= 0) + err(EX_NOINPUT, "Cannot seek to end of file"); + + if (lseek(f, 0, SEEK_SET) < 0) + err(EX_NOINPUT, "Cannot seek to beginning of file"); + + len = off; + if (len != off) + err(EX_NOINPUT, "File '%s' is too big", fname); + + ptr = malloc(len); + if (ptr == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + if (read(f, ptr, len) != len) + err(EX_NOINPUT, "Cannot read all data"); + + close(f); + + *pptr = ptr; + *plen = len; +} diff --git a/tools/tools/bus_autoconf/bus_load_file.h b/tools/tools/bus_autoconf/bus_load_file.h new file mode 100644 index 0000000..57e7739 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_load_file.h @@ -0,0 +1,33 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_LOAD_FILE_H_ +#define _BUS_LOAD_FILE_H_ + +void load_file(const char *, uint8_t **, uint32_t *); + +#endif /* _BUS_LOAD_FILE_H_ */ diff --git a/tools/tools/bus_autoconf/bus_sections.c b/tools/tools/bus_autoconf/bus_sections.c new file mode 100644 index 0000000..c326048 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_sections.c @@ -0,0 +1,223 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <sysexits.h> +#include <err.h> +#include <string.h> + +#include <sys/queue.h> + +#include "bus_sections.h" + +#define MAX_STRING 64 + +struct format_info; +typedef TAILQ_HEAD(,format_info) format_info_head_t; +typedef TAILQ_ENTRY(format_info) format_info_entry_t; + +static format_info_head_t format_head = TAILQ_HEAD_INITIALIZER(format_head); + +struct format_info { + format_info_entry_t entry; + format_info_head_t fields; + char name[MAX_STRING]; + uint16_t bit_offset; + uint16_t bit_size; +}; + +static struct format_info * +format_info_new(char *pstr, uint16_t bo, uint16_t bs) +{ + struct format_info *pfi; + + pfi = malloc(sizeof(*pfi)); + if (pfi == NULL) + errx(EX_SOFTWARE, "Out of memory."); + + memset(pfi, 0, sizeof(*pfi)); + + TAILQ_INIT(&pfi->fields); + + strlcpy(pfi->name, pstr, sizeof(pfi->name)); + pfi->bit_offset = bo; + pfi->bit_size = bs; + return (pfi); +} + +static const struct format_info * +format_get_section(const char *section) +{ + const struct format_info *psub; + static const struct format_info *psub_last; + static const char *psub_cache; + + if (psub_cache && strcmp(psub_cache, section) == 0) + return (psub_last); + + TAILQ_FOREACH(psub, &format_head, entry) { + if (strcmp(section, psub->name) == 0) { + psub_cache = section; + psub_last = psub; + return (psub); + } + } + warnx("Section '%s' not found", section); + psub_cache = section; + psub_last = psub; + return (NULL); +} + +uint16_t +format_get_section_size(const char *section) +{ + const struct format_info *pfi; + + pfi = format_get_section(section); + if (pfi == NULL) + return (0); + + return ((pfi->bit_offset + 7) / 8); +} + + +uint8_t +format_get_field(const char *section, const char *field, + const uint8_t *ptr, uint16_t size) +{ + const struct format_info *pfi; + const struct format_info *psub; + uint16_t rem; + uint16_t off; + uint16_t sz; + + pfi = format_get_section(section); + if (pfi == NULL) + return (0); + + /* skip until we find the fields */ + while (pfi && TAILQ_FIRST(&pfi->fields) == NULL) + pfi = TAILQ_NEXT(pfi, entry); + + if (pfi == NULL) + return (0); + + TAILQ_FOREACH(psub, &pfi->fields, entry) { + if (strcmp(field, psub->name) == 0) { + + /* range check */ + if (((psub->bit_offset + psub->bit_size) / 8) > size) + return (0); + + /* compute byte offset */ + rem = psub->bit_offset & 7; + off = psub->bit_offset / 8; + sz = psub->bit_size; + + /* extract bit-field */ + return ((ptr[off] >> rem) & ((1 << sz) - 1)); + } + } + warnx("Field '%s' not found in '%s'", field, pfi->name); + return (0); +} + +void +format_parse_entries(const uint8_t *ptr, uint32_t len) +{ + static const char *command_list = "012345678:"; + const char *cmd; + struct format_info *pfi; + struct format_info *pfi_last = NULL; + char linebuf[3][MAX_STRING]; + uint32_t off = 0; + uint16_t bit_offset = 0; + uint8_t state = 0; + uint8_t cmd_index; + int c; + + /* + * The format we are parsing: + * <string>{string,string}<next_string>{...} + */ + while (len--) { + c = *(ptr++); + + /* skip some characters */ + if (c == 0 || c == '\n' || c == '\r' || c == ' ' || c == '\t') + continue; + + /* accumulate non-field delimiters */ + if (strchr("{,}", c) == NULL) { + if (off < (MAX_STRING - 1)) { + linebuf[state][off] = c; + off++; + } + continue; + } + /* parse keyword */ + linebuf[state][off] = 0; + off = 0; + state++; + if (state == 3) { + /* check for command in command list */ + cmd = strchr(command_list, linebuf[2][0]); + if (cmd != NULL) + cmd_index = cmd - command_list; + else + cmd_index = 255; + + /* + * Check for new field, format is: + * + * <field_name>{bit_offset_xor, bit_size} + */ + if (cmd_index < 9 && pfi_last != NULL) { + pfi = format_info_new(linebuf[0], bit_offset ^ + atoi(linebuf[1]), cmd_index); + TAILQ_INSERT_TAIL(&pfi_last->fields, pfi, entry); + bit_offset += cmd_index; + } + /* + * Check for new section, format is: + * + * <section_name>{section_bit_size, :} + */ + if (cmd_index == 9) { + pfi_last = format_info_new(linebuf[0], + atoi(linebuf[1]), cmd_index); + TAILQ_INSERT_TAIL(&format_head, pfi_last, entry); + bit_offset = 0; + } + state = 0; + continue; + } + } +} diff --git a/tools/tools/bus_autoconf/bus_sections.h b/tools/tools/bus_autoconf/bus_sections.h new file mode 100644 index 0000000..2c4c6fc --- /dev/null +++ b/tools/tools/bus_autoconf/bus_sections.h @@ -0,0 +1,35 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_SECTIONS_H_ +#define _BUS_SECTIONS_H_ + +uint16_t format_get_section_size(const char *); +uint8_t format_get_field(const char *, const char *, const uint8_t *, uint16_t); +void format_parse_entries(const uint8_t *, uint32_t); + +#endif /* _BUS_SECTIONS_H_ */ diff --git a/tools/tools/bus_autoconf/bus_usb.c b/tools/tools/bus_autoconf/bus_usb.c new file mode 100644 index 0000000..e3d60e8 --- /dev/null +++ b/tools/tools/bus_autoconf/bus_usb.c @@ -0,0 +1,382 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <err.h> +#include <sysexits.h> +#include <unistd.h> +#include <sys/queue.h> + +#include "bus_autoconf.h" +#include "bus_sections.h" +#include "bus_usb.h" + +struct usb_blob; +typedef TAILQ_HEAD(,usb_blob) usb_blob_head_t; +typedef TAILQ_ENTRY(usb_blob) usb_blob_entry_t; + +static usb_blob_head_t usb_blob_head = TAILQ_HEAD_INITIALIZER(usb_blob_head); +static uint32_t usb_blob_count; + +struct usb_blob { + usb_blob_entry_t entry; + struct usb_device_id temp; +}; + +/* + * To ensure that the correct USB driver is loaded, the driver having + * the most information about the device must be probed first. Then + * more generic drivers shall be probed. + */ +static int +usb_compare(const void *_a, const void *_b) +{ + const struct usb_device_id *a = _a; + const struct usb_device_id *b = _b; + int retval; + + /* vendor matches first */ + + if (a->match_flag_vendor > b->match_flag_vendor) + return (-1); + if (a->match_flag_vendor < b->match_flag_vendor) + return (1); + + /* product matches first */ + + if (a->match_flag_product > b->match_flag_product) + return (-1); + if (a->match_flag_product < b->match_flag_product) + return (1); + + /* device class matches first */ + + if (a->match_flag_dev_class > b->match_flag_dev_class) + return (-1); + if (a->match_flag_dev_class < b->match_flag_dev_class) + return (1); + + if (a->match_flag_dev_subclass > b->match_flag_dev_subclass) + return (-1); + if (a->match_flag_dev_subclass < b->match_flag_dev_subclass) + return (1); + + /* interface class matches first */ + + if (a->match_flag_int_class > b->match_flag_int_class) + return (-1); + if (a->match_flag_int_class < b->match_flag_int_class) + return (1); + + if (a->match_flag_int_subclass > b->match_flag_int_subclass) + return (-1); + if (a->match_flag_int_subclass < b->match_flag_int_subclass) + return (1); + + if (a->match_flag_int_protocol > b->match_flag_int_protocol) + return (-1); + if (a->match_flag_int_protocol < b->match_flag_int_protocol) + return (1); + + /* then sort according to value */ + + if (a->idVendor > b->idVendor) + return (1); + if (a->idVendor < b->idVendor) + return (-1); + if (a->idProduct > b->idProduct) + return (1); + if (a->idProduct < b->idProduct) + return (-1); + if (a->bDeviceClass > b->bDeviceClass) + return (1); + if (a->bDeviceClass < b->bDeviceClass) + return (-1); + if (a->bDeviceSubClass > b->bDeviceSubClass) + return (1); + if (a->bDeviceSubClass < b->bDeviceSubClass) + return (-1); + if (a->bDeviceProtocol > b->bDeviceProtocol) + return (1); + if (a->bDeviceProtocol < b->bDeviceProtocol) + return (-1); + if (a->bInterfaceClass > b->bInterfaceClass) + return (1); + if (a->bInterfaceClass < b->bInterfaceClass) + return (-1); + if (a->bInterfaceSubClass > b->bInterfaceSubClass) + return (1); + if (a->bInterfaceSubClass < b->bInterfaceSubClass) + return (-1); + if (a->bInterfaceProtocol > b->bInterfaceProtocol) + return (1); + if (a->bInterfaceProtocol < b->bInterfaceProtocol) + return (-1); + + /* in the end sort by module name and mode */ + + retval = strcmp(a->module_name, b->module_name); + if (retval == 0) + retval = strcmp(a->module_mode, b->module_mode); + return (retval); +} + +static void +usb_sort_entries(struct usb_device_id *id, uint32_t nid) +{ + qsort(id, nid, sizeof(*id), &usb_compare); +} + +static void +usb_import_entry(struct usb_device_id *id, const char *type, + const char *module, const uint8_t *ptr, uint16_t size) +{ + const char *mode; + + if (strstr(type, "_host_")) + mode = "host"; + else if (strstr(type, "_device_")) + mode = "device"; + else + mode = "(host|device)"; + + strlcpy(id->module_name, module, sizeof(id->module_name)); + strlcpy(id->module_mode, mode, sizeof(id->module_mode)); + + /* import data from binary object */ + + if (format_get_field(type, "mfl_vendor", ptr, size)) + id->match_flag_vendor = 1; + if (format_get_field(type, "mfl_product", ptr, size)) + id->match_flag_product = 1; + if (format_get_field(type, "mfl_dev_lo", ptr, size)) + id->match_flag_dev_lo = 1; + if (format_get_field(type, "mfl_dev_hi", ptr, size)) + id->match_flag_dev_hi = 1; + if (format_get_field(type, "mfl_dev_class", ptr, size)) + id->match_flag_dev_class = 1; + if (format_get_field(type, "mfl_dev_subclass", ptr, size)) + id->match_flag_dev_subclass = 1; + if (format_get_field(type, "mfl_dev_protocol", ptr, size)) + id->match_flag_dev_protocol = 1; + if (format_get_field(type, "mfl_int_class", ptr, size)) + id->match_flag_int_class = 1; + if (format_get_field(type, "mfl_int_subclass", ptr, size)) + id->match_flag_int_subclass = 1; + if (format_get_field(type, "mfl_int_protocol", ptr, size)) + id->match_flag_int_protocol = 1; + + id->idVendor = format_get_field(type, "idVendor[0]", ptr, size) | + (format_get_field(type, "idVendor[1]", ptr, size) << 8); + id->idProduct = format_get_field(type, "idProduct[0]", ptr, size) | + (format_get_field(type, "idProduct[1]", ptr, size) << 8); + + id->bcdDevice_lo = format_get_field(type, "bcdDevice_lo[0]", ptr, size) | + (format_get_field(type, "bcdDevice_lo[1]", ptr, size) << 8); + + id->bcdDevice_hi = format_get_field(type, "bcdDevice_hi[0]", ptr, size) | + (format_get_field(type, "bcdDevice_hi[1]", ptr, size) << 8); + + id->bDeviceClass = format_get_field(type, "bDeviceClass", ptr, size); + id->bDeviceSubClass = format_get_field(type, "bDeviceSubClass", ptr, size); + id->bDeviceProtocol = format_get_field(type, "bDeviceProtocol", ptr, size); + + id->bInterfaceClass = format_get_field(type, "bInterfaceClass", ptr, size); + id->bInterfaceSubClass = format_get_field(type, "bInterfaceSubClass", ptr, size); + id->bInterfaceProtocol = format_get_field(type, "bInterfaceProtocol", ptr, size); + + if (format_get_field(type, "mf_vendor", ptr, size)) + id->match_flag_vendor = 1; + if (format_get_field(type, "mf_product", ptr, size)) + id->match_flag_product = 1; + if (format_get_field(type, "mf_dev_lo", ptr, size)) + id->match_flag_dev_lo = 1; + if (format_get_field(type, "mf_dev_hi", ptr, size)) + id->match_flag_dev_hi = 1; + if (format_get_field(type, "mf_dev_class", ptr, size)) + id->match_flag_dev_class = 1; + if (format_get_field(type, "mf_dev_subclass", ptr, size)) + id->match_flag_dev_subclass = 1; + if (format_get_field(type, "mf_dev_protocol", ptr, size)) + id->match_flag_dev_protocol = 1; + if (format_get_field(type, "mf_int_class", ptr, size)) + id->match_flag_int_class = 1; + if (format_get_field(type, "mf_int_subclass", ptr, size)) + id->match_flag_int_subclass = 1; + if (format_get_field(type, "mf_int_protocol", ptr, size)) + id->match_flag_int_protocol = 1; + + /* compute some internal fields */ + id->is_iface = id->match_flag_int_class | + id->match_flag_int_protocol | + id->match_flag_int_subclass; + + id->is_dev = id->match_flag_dev_class | + id->match_flag_dev_subclass; + + id->is_vp = id->match_flag_vendor | + id->match_flag_product; + + id->is_any = id->is_vp + id->is_dev + id->is_iface; +} + +static uint32_t +usb_dump(struct usb_device_id *id, uint32_t nid) +{ + uint32_t n = 1; + + if (id->is_any) { + printf("nomatch 32 {\n" + " match \"bus\" \"uhub[0-9]+\";\n" + " match \"mode\" \"%s\";\n", id->module_mode); + } else { + printf("# skipped entry on module %s\n", + id->module_name); + return (n); + } + + if (id->match_flag_vendor) { + printf(" match \"vendor\" \"0x%04x\";\n", + id->idVendor); + } + if (id->match_flag_product) { + uint32_t x; + + if (id->is_any == 1 && id->is_vp == 1) { + /* try to join similar entries */ + while (n < nid) { + if (id[n].is_any != 1 || id[n].is_vp != 1) + break; + if (id[n].idVendor != id[0].idVendor) + break; + n++; + } + } + if (n == 1) { + printf(" match \"product\" \"0x%04x\";\n", + id->idProduct); + } else { + printf(" match \"product\" \"("); + + for (x = 0; x != n; x++) { + printf("0x%04x%s", id[x].idProduct, + (x == (n - 1)) ? "" : "|"); + } + + printf(")\";\n"); + } + } + if (id->match_flag_dev_class) { + printf(" match \"devclass\" \"0x%02x\";\n", + id->bDeviceClass); + } + if (id->match_flag_dev_subclass) { + printf(" match \"devsubclass\" \"0x%02x\";\n", + id->bDeviceSubClass); + } + if (id->match_flag_int_class) { + printf(" match \"intclass\" \"0x%02x\";\n", + id->bInterfaceClass); + } + if (id->match_flag_int_subclass) { + printf(" match \"intsubclass\" \"0x%02x\";\n", + id->bInterfaceSubClass); + } + if (id->match_flag_int_protocol) { + printf(" match \"intprotocol\" \"0x%02x\";\n", + id->bInterfaceProtocol); + } + printf(" action \"kldload %s\";\n" + "};\n\n", id->module_name); + + return (n); +} + +void +usb_import_entries(const char *section, const char *module, + const uint8_t *ptr, uint32_t len) +{ + struct usb_blob *pub; + uint32_t section_size; + uint32_t off; + + section_size = format_get_section_size(section); + if (section_size == 0) { + errx(EX_DATAERR, "Invalid or non-existing " + "section format '%s'", section); + } + if (len % section_size) { + errx(EX_DATAERR, "Length %d is not " + "divisible by %d. Section format '%s'", + len, section_size, section); + } + for (off = 0; off != len; off += section_size) { + pub = malloc(sizeof(*pub)); + if (pub == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + memset(pub, 0, sizeof(*pub)); + + usb_import_entry(&pub->temp, section, + module, ptr + off, section_size); + + TAILQ_INSERT_TAIL(&usb_blob_head, pub, entry); + + usb_blob_count++; + if (usb_blob_count == 0) + errx(EX_SOFTWARE, "Too many entries"); + } +} + +void +usb_dump_entries(void) +{ + struct usb_blob *pub; + struct usb_device_id *id; + uint32_t x; + + id = malloc(usb_blob_count * sizeof(*id)); + if (id == NULL) + errx(EX_SOFTWARE, "Out of memory"); + + /* make linear array of all USB blobs */ + x = 0; + TAILQ_FOREACH(pub, &usb_blob_head, entry) + id[x++] = pub->temp; + + usb_sort_entries(id, usb_blob_count); + + for (x = 0; x != usb_blob_count;) + x += usb_dump(id + x, usb_blob_count - x); + + free(id); + + printf("# %d USB entries processed\n\n", usb_blob_count); +} diff --git a/tools/tools/bus_autoconf/bus_usb.h b/tools/tools/bus_autoconf/bus_usb.h new file mode 100644 index 0000000..378df9a --- /dev/null +++ b/tools/tools/bus_autoconf/bus_usb.h @@ -0,0 +1,73 @@ +/* $FreeBSD$ */ + +/*- + * Copyright (c) 2011 Hans Petter Selasky. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _BUS_USB_H_ +#define _BUS_USB_H_ + +struct usb_device_id { + + /* Internal fields */ + char module_name[32]; + char module_mode[32]; + uint8_t is_iface; + uint8_t is_vp; + uint8_t is_dev; + uint8_t is_any; + + /* Used for product specific matches; the BCD range is inclusive */ + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice_lo; + uint16_t bcdDevice_hi; + + /* Used for device class matches */ + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + + /* Used for interface class matches */ + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + + /* Select which fields to match against */ + uint8_t match_flag_vendor:1; + uint8_t match_flag_product:1; + uint8_t match_flag_dev_lo:1; + uint8_t match_flag_dev_hi:1; + uint8_t match_flag_dev_class:1; + uint8_t match_flag_dev_subclass:1; + uint8_t match_flag_dev_protocol:1; + uint8_t match_flag_int_class:1; + uint8_t match_flag_int_subclass:1; + uint8_t match_flag_int_protocol:1; +}; + +void usb_import_entries(const char *, const char *, const uint8_t *, uint32_t); +void usb_dump_entries(void); + +#endif /* _BUS_USB_H_ */ |