summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb
diff options
context:
space:
mode:
authorthompsa <thompsa@FreeBSD.org>2010-04-21 21:51:14 +0000
committerthompsa <thompsa@FreeBSD.org>2010-04-21 21:51:14 +0000
commit31257c45676b6404dfd580abbffec543f3a32962 (patch)
treee4f00b7f9fafb73d2a125c63648a41cef3ed82f7 /sys/dev/usb
parente4ec9310381d70de9e1d9878ec8468b0ff97e4ef (diff)
downloadFreeBSD-src-31257c45676b6404dfd580abbffec543f3a32962.zip
FreeBSD-src-31257c45676b6404dfd580abbffec543f3a32962.tar.gz
Change usb devd events from fake attach to a notify. The ugen device is not a
proper device_t so it faked the devctl event to appear like one, this is now a notify which allows more information to be passed. We notify for both the device attach/detach and for each usb interface. A devd rule can now match on the interface properties, including composite devices which may have a uvideo interface and also usound and possibly uhid too. An example to match a umass device with a scsi subclass and BBB protocol would be notify 100 { match "system" "USB"; match "subsystem" "INTERFACE"; match "type" "ATTACH"; match "intclass" "0x08"; match "intsubclass" "0x06"; match "intprotocol" "0x50"; action ... }; The old attach devctl event has been retained for the moment to make merging to 8.1 easier. This was never compatible with 7.x or earlier due to the ugen regex change needed. Reviewed by: warner MFC after: 1 week
Diffstat (limited to 'sys/dev/usb')
-rw-r--r--sys/dev/usb/usb_device.c98
1 files changed, 94 insertions, 4 deletions
diff --git a/sys/dev/usb/usb_device.c b/sys/dev/usb/usb_device.c
index d7f0c31..f0106ec 100644
--- a/sys/dev/usb/usb_device.c
+++ b/sys/dev/usb/usb_device.c
@@ -45,6 +45,7 @@
#include <sys/priv.h>
#include <sys/conf.h>
#include <sys/fcntl.h>
+#include <sys/sbuf.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
@@ -1834,7 +1835,7 @@ config_done:
printf("%s: <%s> at %s\n", udev->ugen_name, udev->manufacturer,
device_get_nameunit(udev->bus->bdev));
- usb_notify_addq("+", udev);
+ usb_notify_addq("ATTACH", udev);
#endif
done:
if (err) {
@@ -1980,7 +1981,7 @@ usb_free_device(struct usb_device *udev, uint8_t flag)
usb_set_device_state(udev, USB_STATE_DETACHED);
#if USB_HAVE_UGEN
- usb_notify_addq("-", udev);
+ usb_notify_addq("DETACH", udev);
printf("%s: <%s> at %s (disconnected)\n", udev->ugen_name,
udev->manufacturer, device_get_nameunit(bus->bdev));
@@ -2347,13 +2348,23 @@ usbd_get_device_index(struct usb_device *udev)
*
* This function will generate events for dev.
*------------------------------------------------------------------------*/
+#ifndef BURN_BRIDGES
static void
-usb_notify_addq(const char *type, struct usb_device *udev)
+usb_notify_addq_compat(const char *type, struct usb_device *udev)
{
char *data = NULL;
+ const char *ntype;
struct malloc_type *mt;
const size_t buf_size = 512;
+ /* Convert notify type */
+ if (strcmp(type, "ATTACH") == 0)
+ ntype = "+";
+ else if (strcmp(type, "DETACH") == 0)
+ ntype = "-";
+ else
+ return;
+
mtx_lock(&malloc_mtx);
mt = malloc_desc2type("bus"); /* XXX M_BUS */
mtx_unlock(&malloc_mtx);
@@ -2378,7 +2389,7 @@ usb_notify_addq(const char *type, struct usb_device *udev)
"port=%u "
"on "
"%s\n",
- type,
+ ntype,
udev->ugen_name,
UGETW(udev->ddesc.idVendor),
UGETW(udev->ddesc.idProduct),
@@ -2393,6 +2404,85 @@ usb_notify_addq(const char *type, struct usb_device *udev)
devctl_queue_data(data);
}
+#endif
+
+static void
+usb_notify_addq(const char *type, struct usb_device *udev)
+{
+ struct usb_interface *iface;
+ struct sbuf *sb;
+ int i;
+
+#ifndef BURN_BRIDGES
+ usb_notify_addq_compat(type, udev);
+#endif
+
+ /* announce the device */
+ sb = sbuf_new_auto();
+ sbuf_printf(sb,
+ "cdev=%s "
+ "vendor=0x%04x "
+ "product=0x%04x "
+ "devclass=0x%02x "
+ "devsubclass=0x%02x "
+ "sernum=\"%s\" "
+ "release=0x%04x "
+ "port=%u "
+ "parent=%s\n",
+ udev->ugen_name,
+ UGETW(udev->ddesc.idVendor),
+ UGETW(udev->ddesc.idProduct),
+ udev->ddesc.bDeviceClass,
+ udev->ddesc.bDeviceSubClass,
+ udev->serial,
+ UGETW(udev->ddesc.bcdDevice),
+ udev->port_no,
+ udev->parent_hub != NULL ?
+ udev->parent_hub->ugen_name :
+ device_get_nameunit(device_get_parent(udev->bus->bdev)));
+ sbuf_finish(sb);
+ devctl_notify("USB", "DEVICE", type, sbuf_data(sb));
+ sbuf_delete(sb);
+
+ /* announce each interface */
+ for (i = 0; i < USB_IFACE_MAX; i++) {
+ iface = usbd_get_iface(udev, i);
+ if (iface == NULL)
+ break; /* end of interfaces */
+ if (iface->idesc == NULL)
+ continue; /* no interface descriptor */
+
+ sb = sbuf_new_auto();
+ sbuf_printf(sb,
+ "cdev=%s "
+ "vendor=0x%04x "
+ "product=0x%04x "
+ "devclass=0x%02x "
+ "devsubclass=0x%02x "
+ "sernum=\"%s\" "
+ "release=0x%04x "
+ "interface=%d "
+ "endpoints=%d "
+ "intclass=0x%02x "
+ "intsubclass=0x%02x "
+ "intprotocol=0x%02x\n",
+ udev->ugen_name,
+ UGETW(udev->ddesc.idVendor),
+ UGETW(udev->ddesc.idProduct),
+ udev->ddesc.bDeviceClass,
+ udev->ddesc.bDeviceSubClass,
+ udev->serial,
+ UGETW(udev->ddesc.bcdDevice),
+ iface->idesc->bInterfaceNumber,
+ iface->idesc->bNumEndpoints,
+ iface->idesc->bInterfaceClass,
+ iface->idesc->bInterfaceSubClass,
+ iface->idesc->bInterfaceProtocol);
+ sbuf_finish(sb);
+ devctl_notify("USB", "INTERFACE", type, sbuf_data(sb));
+ sbuf_delete(sb);
+ }
+}
/*------------------------------------------------------------------------*
* usb_fifo_free_wrap
OpenPOWER on IntegriCloud