summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2011-06-24 02:30:02 +0000
committerhselasky <hselasky@FreeBSD.org>2011-06-24 02:30:02 +0000
commitdc0788739aaaf15b40f6d2fded382c167e26133d (patch)
tree6e82b2865a1b1c3596523a9b28c7c73c29ffd4ec /tools
parent1d215b1285ab0897c64a473f1b6b30f0311b87d0 (diff)
downloadFreeBSD-src-dc0788739aaaf15b40f6d2fded382c167e26133d.zip
FreeBSD-src-dc0788739aaaf15b40f6d2fded382c167e26133d.tar.gz
- Move all USB device ID arrays into so-called sections,
sorted according to the mode which they support: host, device or dual mode - Add generic tool to extract these data: tools/bus_autoconf Discussed with: imp Suggested by: Robert Millan <rmh@debian.org> PR: misc/157903 MFC after: 14 days
Diffstat (limited to 'tools')
-rw-r--r--tools/tools/bus_autoconf/Makefile43
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.c321
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.h83
-rw-r--r--tools/tools/bus_autoconf/bus_autoconf.sh64
4 files changed, 511 insertions, 0 deletions
diff --git a/tools/tools/bus_autoconf/Makefile b/tools/tools/bus_autoconf/Makefile
new file mode 100644
index 0000000..c2f1b13
--- /dev/null
+++ b/tools/tools/bus_autoconf/Makefile
@@ -0,0 +1,43 @@
+# $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.
+#
+
+#
+# Example on how to use:
+#
+# make clean all install
+#
+# ./bus_autoconf.sh /boot/kernel/*.ko | less
+#
+
+PROG= bus_autoconf
+MAN=
+BINDIR?= /usr/local/bin
+
+SRCS= bus_autoconf.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
index 0000000..68688af
--- /dev/null
+++ b/tools/tools/bus_autoconf/bus_autoconf.c
@@ -0,0 +1,321 @@
+/* $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.
+ */
+
+/*
+ * Disclaimer: This utility and format is subject to change and not a
+ * comitted interface.
+ */
+
+#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 "bus_autoconf.h"
+
+static char *type;
+static char *file_name;
+static char *module;
+static const char *mode;
+
+static int
+usb_compare(const void *_a, const void *_b)
+{
+ const struct usb_device_id *a = _a;
+ const struct usb_device_id *b = _b;
+
+ 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);
+
+ return (0);
+}
+
+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 & 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;
+#endif
+
+ 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 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_iface) {
+ printf("nomatch 10 {\n"
+ " match \"system\" \"USB\";\n"
+ " match \"subsystem\" \"INTERFACE\";\n"
+ " match \"mode\" \"%s\";\n", mode);
+ } else if (info.is_any) {
+ printf("nomatch 10 {\n"
+ " match \"system\" \"USB\";\n"
+ " match \"subsystem\" \"DEVICE\";\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", module);
+
+ 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);
+
+ usb_sort(id, nid);
+
+ for (x = 0; x != nid;)
+ x += usb_dump(id + x, nid - x);
+
+ free(id);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "bus_autoconf - devd config file generator\n"
+ " -i <input_binary>\n"
+ " -m <module_name>\n"
+ " -t <structure_type>\n"
+ " -h show usage\n"
+ );
+ exit(EX_USAGE);
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *params = "i:m:ht:";
+ int c;
+ int f;
+ off_t off;
+
+ while ((c = getopt(argc, argv, params)) != -1) {
+ switch (c) {
+ case 'i':
+ file_name = optarg;
+ break;
+ case 't':
+ type = optarg;
+ break;
+ case 'm':
+ module = optarg;
+ break;
+ default:
+ usage();
+ break;
+ }
+ }
+
+ if (type == NULL || module == NULL || file_name == NULL)
+ 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);
+
+ return (0);
+}
diff --git a/tools/tools/bus_autoconf/bus_autoconf.h b/tools/tools/bus_autoconf/bus_autoconf.h
new file mode 100644
index 0000000..a247109
--- /dev/null
+++ b/tools/tools/bus_autoconf/bus_autoconf.h
@@ -0,0 +1,83 @@
+/* $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_AUTOCONF_H_
+#define _BUS_AUTOCONF_H_
+
+/* Make sure we get the have compat linux definition. */
+#include <dev/usb/usb.h>
+
+struct usb_device_id {
+
+ /* 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
new file mode 100644
index 0000000..4815572
--- /dev/null
+++ b/tools/tools/bus_autoconf/bus_autoconf.sh
@@ -0,0 +1,64 @@
+#!/bin/sh
+#
+# $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.
+#
+
+OS=FreeBSD
+DOLLAR=$
+
+cat <<EOF
+#
+# ${DOLLAR}${OS}${DOLLAR}
+#
+# This file was automatically generated by "tools/bus_autoconf.sh".
+# Please do not edit!
+#
+
+EOF
+
+for F in $(echo $* | sort)
+do
+H=$(basename ${F} | sed -e "s/\.ko//g")
+
+# USB Host
+objcopy -j usb_host_id -O binary ${F} ${F}.ids 2> /dev/null
+[ -f ${F}.ids ] && (
+bus_autoconf -i ${F}.ids -t usb_host -m ${H} ;
+rm ${F}.ids
+)
+# USB Device
+objcopy -j usb_device_id -O binary ${F} ${F}.ids 2> /dev/null
+[ -f ${F}.ids ] && (
+bus_autoconf -i ${F}.ids -t usb_device -m ${H} ;
+rm ${F}.ids
+)
+# USB Dual mode
+objcopy -j usb_dual_id -O binary ${F} ${F}.ids 2> /dev/null
+[ -f ${F}.ids ] && (
+bus_autoconf -i ${F}.ids -t usb_dual -m ${H} ;
+rm ${F}.ids
+)
+done
OpenPOWER on IntegriCloud