summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2011-06-25 13:44:05 +0000
committerhselasky <hselasky@FreeBSD.org>2011-06-25 13:44:05 +0000
commit0407380ca2f3a97fa613b6e84c1f802a283cd467 (patch)
tree6acfb50903a692d632f6c40ae06775b109cb1621 /tools
parent7571a340690fd7faeab96fe8ce55b12f82c862c8 (diff)
downloadFreeBSD-src-0407380ca2f3a97fa613b6e84c1f802a283cd467.zip
FreeBSD-src-0407380ca2f3a97fa613b6e84c1f802a283cd467.tar.gz
- Improve bus_autoconf tool.
- Implement simple and generic language which can be used to describe any kind of device ID structures. - Fix endian issues. - Add an example format file. Suggested by: imp @ MFC after: 14 days
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/bus_autoconf/Makefile5
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.c375
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.h55
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.sh57
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf_format_example.txt111
-rw-r--r--tools/tools/bus_autoconf/bus_load_file.c72
-rw-r--r--tools/tools/bus_autoconf/bus_load_file.h33
-rw-r--r--tools/tools/bus_autoconf/bus_sections.c223
-rw-r--r--tools/tools/bus_autoconf/bus_sections.h35
-rw-r--r--tools/tools/bus_autoconf/bus_usb.c382
-rw-r--r--tools/tools/bus_autoconf/bus_usb.h73
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_ */
OpenPOWER on IntegriCloud