diff options
author | Hans Petter Selasky <hselasky@FreeBSD.org> | 2011-06-24 02:30:02 +0000 |
---|---|---|
committer | Hans Petter Selasky <hselasky@FreeBSD.org> | 2011-06-24 02:30:02 +0000 |
commit | f1a16106b6317f4cf5b187daeceda7c1468323c9 (patch) | |
tree | 6e82b2865a1b1c3596523a9b28c7c73c29ffd4ec /tools | |
parent | e69dff491d4faeddb7bde8ba3d88881574a29c93 (diff) | |
download | src-f1a16106b6317f4cf5b187daeceda7c1468323c9.tar.gz src-f1a16106b6317f4cf5b187daeceda7c1468323c9.zip |
- 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
Notes
Notes:
svn path=/head/; revision=223486
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/bus_autoconf/Makefile | 43 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.c | 321 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.h | 83 | ||||
-rw-r--r-- | tools/tools/bus_autoconf/bus_autoconf.sh | 64 |
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 000000000000..c2f1b138594a --- /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 000000000000..68688afb25a7 --- /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 000000000000..a247109b2f7d --- /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 000000000000..4815572261af --- /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 |