Add a tool to keep the devd(8) database in sync with our USB device support.
authorSascha Wildner <saw@online.de>
Wed, 12 Mar 2014 20:09:08 +0000 (21:09 +0100)
committerSascha Wildner <saw@online.de>
Wed, 12 Mar 2014 20:09:08 +0000 (21:09 +0100)
Taken-from: FreeBSD

tools/tools/bus_autoconf/Makefile [new file with mode: 0644]
tools/tools/bus_autoconf/bus_autoconf.c [new file with mode: 0644]
tools/tools/bus_autoconf/bus_autoconf.h [new file with mode: 0644]
tools/tools/bus_autoconf/bus_autoconf.sh [new file with mode: 0644]
tools/tools/bus_autoconf/bus_autoconf_format_example.txt [new file with mode: 0644]
tools/tools/bus_autoconf/bus_load_file.c [new file with mode: 0644]
tools/tools/bus_autoconf/bus_load_file.h [new file with mode: 0644]
tools/tools/bus_autoconf/bus_sections.c [new file with mode: 0644]
tools/tools/bus_autoconf/bus_sections.h [new file with mode: 0644]
tools/tools/bus_autoconf/bus_usb.c [new file with mode: 0644]
tools/tools/bus_autoconf/bus_usb.h [new file with mode: 0644]

diff --git a/tools/tools/bus_autoconf/Makefile b/tools/tools/bus_autoconf/Makefile
new file mode 100644 (file)
index 0000000..adbf791
--- /dev/null
@@ -0,0 +1,46 @@
+# $FreeBSD: head/tools/tools/bus_autoconf/Makefile 223534 2011-06-25 13:44:05Z hselasky $
+#
+# 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.
+#
+
+#
+# Example on how to use:
+#
+# make clean all install
+#
+# sh ./bus_autoconf.sh /boot/kernel/*.ko | less
+#
+
+PROG=  bus_autoconf
+MAN=
+BINDIR?= /usr/local/bin
+
+SRCS+= bus_autoconf.c
+SRCS+= bus_load_file.c
+SRCS+= bus_sections.c
+SRCS+= bus_usb.c
+
+WARNS= 6
+
+.include <bsd.prog.mk>
diff --git a/tools/tools/bus_autoconf/bus_autoconf.c b/tools/tools/bus_autoconf/bus_autoconf.c
new file mode 100644 (file)
index 0000000..7494af9
--- /dev/null
@@ -0,0 +1,125 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_autoconf.c 228975 2011-12-30 00:04:11Z uqs $ */
+
+/*-
+ * 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.
+ */
+
+/*
+ * Disclaimer: This utility and format is subject to change and not a
+ * committed interface.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#include "bus_autoconf.h"
+#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 <structure_type,module.ko>\n"
+           "   -F <format_file>\n"
+           "   -h show usage\n"
+       );
+       exit(EX_USAGE);
+}
+
+int
+main(int argc, char **argv)
+{
+       const char *params = "i:F:h";
+       char *fname;
+       char *section;
+       char *module;
+       char *postfix;
+       uint8_t *ptr;
+       uint32_t len;
+       int c;
+       int any_opt = 0;
+
+       while ((c = getopt(argc, argv, params)) != -1) {
+               switch (c) {
+               case 'i':
+                       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 'F':
+                       fname = optarg;
+                       load_file(fname, &ptr, &len);
+                       format_parse_entries(ptr, len);
+                       free(ptr);
+
+                       any_opt = 1;
+                       break;
+
+               default:
+                       usage();
+                       break;
+               }
+       }
+
+       if (any_opt == 0)
+               usage();
+
+       usb_dump_entries();
+
+       return (0);
+}
diff --git a/tools/tools/bus_autoconf/bus_autoconf.h b/tools/tools/bus_autoconf/bus_autoconf.h
new file mode 100644 (file)
index 0000000..b4d7128
--- /dev/null
@@ -0,0 +1,31 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_autoconf.h 223534 2011-06-25 13:44:05Z hselasky $ */
+
+/*-
+ * 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_AUTOCONF_H_
+#define        _BUS_AUTOCONF_H_
+
+#endif                                 /* _BUS_AUTOCONF_H_ */
diff --git a/tools/tools/bus_autoconf/bus_autoconf.sh b/tools/tools/bus_autoconf/bus_autoconf.sh
new file mode 100644 (file)
index 0000000..d83d4a0
--- /dev/null
@@ -0,0 +1,78 @@
+#!/bin/sh
+#
+# $FreeBSD: head/tools/tools/bus_autoconf/bus_autoconf.sh 258333 2013-11-19 00:43:53Z markj $
+#
+# 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.
+#
+
+OS=FreeBSD
+DOLLAR=$
+OBJCOPY=objcopy
+
+cat <<EOF
+#
+# ${DOLLAR}${OS}${DOLLAR}
+#
+# This file was automatically generated by "tools/tools/bus_autoconf/bus_autoconf.sh".
+# Please do not edit!
+#
+
+EOF
+
+rm -f bus_autoconf_format.bin
+rm -f bus_autoconf_args.txt
+rm -f bus_autoconf.ids
+
+for F in $*
+do
+
+G=$(basename ${F})
+
+# Format information
+${OBJCOPY} -j bus_autoconf_format -O binary ${F} bus_autoconf.ids 2> /dev/null
+[ -f bus_autoconf.ids ] && cat bus_autoconf.ids >> bus_autoconf_format.bin
+
+# 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 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} "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
+bus_autoconf -F bus_autoconf_format.bin $(cat bus_autoconf_args.txt)
+
+# Cleanup
+rm -f -- \
+    $(cat bus_autoconf_args.txt) \
+    bus_autoconf_args.txt \
+    bus_autoconf_format.bin \
+    bus_autoconf.ids
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 (file)
index 0000000..7e9679e
--- /dev/null
@@ -0,0 +1,111 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_autoconf_format_example.txt 223534 2011-06-25 13:44:05Z hselasky $ */
+
+#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 (file)
index 0000000..cfa57eb
--- /dev/null
@@ -0,0 +1,76 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_load_file.c 255122 2013-09-01 14:06:57Z ian $ */
+
+/*-
+ * 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;
+       ssize_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 '%s'", fname);
+       }
+
+       if (lseek(f, 0, SEEK_SET) < 0) {
+               err(EX_NOINPUT, "Cannot seek to "
+                   "beginning of file '%s'", fname);
+       }
+
+       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 (file)
index 0000000..001f6f4
--- /dev/null
@@ -0,0 +1,33 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_load_file.h 223534 2011-06-25 13:44:05Z hselasky $ */
+
+/*-
+ * 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 (file)
index 0000000..e786ffd
--- /dev/null
@@ -0,0 +1,223 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_sections.c 223534 2011-06-25 13:44:05Z hselasky $ */
+
+/*-
+ * 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 (file)
index 0000000..8e03415
--- /dev/null
@@ -0,0 +1,35 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_sections.h 223534 2011-06-25 13:44:05Z hselasky $ */
+
+/*-
+ * 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 (file)
index 0000000..96c4eb2
--- /dev/null
@@ -0,0 +1,386 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_usb.c 233110 2012-03-18 09:47:27Z hselasky $ */
+
+/*-
+ * 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;
+                               if (strcmp(id[n].module_name, id[0].module_name))
+                                       break;
+                               if (strcmp(id[n].module_mode, id[0].module_mode))
+                                       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 -n %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 (file)
index 0000000..7b9d491
--- /dev/null
@@ -0,0 +1,73 @@
+/* $FreeBSD: head/tools/tools/bus_autoconf/bus_usb.h 223534 2011-06-25 13:44:05Z hselasky $ */
+
+/*-
+ * 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_ */