Date: Thu, 17 Dec 2009 21:42:10 +0000 (UTC) From: Andrew Thompson <thompsa@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r200653 - in head/sys/dev/usb: . serial Message-ID: <200912172142.nBHLgAkf051560@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: thompsa Date: Thu Dec 17 21:42:10 2009 New Revision: 200653 URL: http://svn.freebsd.org/changeset/base/200653 Log: Use the EVENTHANDLER system to hook into the usb device configuration and perform a function such as ejecting a 3G autoinstaller disk. The eventhandler system properly tracks threads and is safe to unload, remove the setting/clearing of a function pointer in the kernel by u3g(4) which included a tsleep for safety. Modified: head/sys/dev/usb/serial/u3g.c head/sys/dev/usb/usb_device.c head/sys/dev/usb/usb_dynamic.c head/sys/dev/usb/usb_dynamic.h head/sys/dev/usb/usbdi.h Modified: head/sys/dev/usb/serial/u3g.c ============================================================================== --- head/sys/dev/usb/serial/u3g.c Thu Dec 17 21:17:13 2009 (r200652) +++ head/sys/dev/usb/serial/u3g.c Thu Dec 17 21:42:10 2009 (r200653) @@ -122,8 +122,13 @@ static void u3g_stop_read(struct ucom_so static void u3g_start_write(struct ucom_softc *ucom); static void u3g_stop_write(struct ucom_softc *ucom); + +static void u3g_test_autoinst(void *, struct usb_device *, + struct usb_attach_arg *); static int u3g_driver_loaded(struct module *mod, int what, void *arg); +static eventhandler_tag u3g_etag; + static const struct usb_config u3g_config[U3G_N_TRANSFER] = { [U3G_BULK_WR] = { @@ -360,58 +365,48 @@ u3g_sael_m460_init(struct usb_device *ud } } -static int -u3g_lookup_huawei(struct usb_attach_arg *uaa) -{ - /* Calling the lookup function will also set the driver info! */ - return (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa)); -} - /* * The following function handles 3G modem devices (E220, Mobile, * etc.) with auto-install flash disks for Windows/MacOSX on the first * interface. After some command or some delay they change appearance * to a modem. */ -static usb_error_t -u3g_test_huawei_autoinst(struct usb_device *udev, +static void +u3g_test_autoinst(void *arg, struct usb_device *udev, struct usb_attach_arg *uaa) { struct usb_interface *iface; struct usb_interface_descriptor *id; uint32_t flags; - if (udev == NULL) { - return (USB_ERR_INVAL); - } + if (uaa->dev_state != UAA_DEV_READY) + return; + iface = usbd_get_iface(udev, 0); - if (iface == NULL) { - return (USB_ERR_INVAL); - } + if (iface == NULL) + return; id = iface->idesc; - if (id == NULL) { - return (USB_ERR_INVAL); - } - if (id->bInterfaceClass != UICLASS_MASS) { - return (USB_ERR_INVAL); - } - if (u3g_lookup_huawei(uaa)) { + if (id == NULL || id->bInterfaceClass != UICLASS_MASS) + return; + if (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa)) { /* no device match */ - return (USB_ERR_INVAL); + return; } flags = USB_GET_DRIVER_INFO(uaa); if (flags & U3GFL_HUAWEI_INIT) { u3g_huawei_init(udev); } else if (flags & U3GFL_SCSI_EJECT) { - return (usb_test_autoinstall(udev, 0, 1)); + if (usb_test_autoinstall(udev, 0, 1) != 0) + return; } else if (flags & U3GFL_SIERRA_INIT) { u3g_sierra_init(udev); } else { /* no quirks */ - return (USB_ERR_INVAL); + return; } - return (0); /* success */ + uaa->dev_state = UAA_DEV_EJECTING; + return; /* success */ } static int @@ -420,10 +415,11 @@ u3g_driver_loaded(struct module *mod, in switch (what) { case MOD_LOAD: /* register our autoinstall handler */ - usb_test_huawei_autoinst_p = &u3g_test_huawei_autoinst; + u3g_etag = EVENTHANDLER_REGISTER(usb_dev_configured, + u3g_test_autoinst, NULL, EVENTHANDLER_PRI_ANY); break; case MOD_UNLOAD: - usb_test_huawei_unload(NULL); + EVENTHANDLER_DEREGISTER(usb_dev_configured, u3g_etag); break; default: return (EOPNOTSUPP); @@ -445,7 +441,7 @@ u3g_probe(device_t self) if (uaa->info.bInterfaceClass != UICLASS_VENDOR) { return (ENXIO); } - return (u3g_lookup_huawei(uaa)); + return (usbd_lookup_id_by_uaa(u3g_devs, sizeof(u3g_devs), uaa)); } static int Modified: head/sys/dev/usb/usb_device.c ============================================================================== --- head/sys/dev/usb/usb_device.c Thu Dec 17 21:17:13 2009 (r200652) +++ head/sys/dev/usb/usb_device.c Thu Dec 17 21:42:10 2009 (r200653) @@ -1204,6 +1204,7 @@ usb_init_attach_arg(struct usb_device *u uaa->device = udev; uaa->usb_mode = udev->flags.usb_mode; uaa->port = udev->port_no; + uaa->dev_state = UAA_DEV_READY; uaa->info.idVendor = UGETW(udev->ddesc.idVendor); uaa->info.idProduct = UGETW(udev->ddesc.idProduct); @@ -1453,6 +1454,9 @@ usb_alloc_device(device_t parent_dev, st size_t scratch_size; usb_error_t err; uint8_t device_index; + uint8_t config_index; + uint8_t config_quirk; + uint8_t set_config_failed; DPRINTF("parent_dev=%p, bus=%p, parent_hub=%p, depth=%u, " "port_index=%u, port_no=%u, speed=%u, usb_mode=%u\n", @@ -1732,96 +1736,91 @@ usb_alloc_device(device_t parent_dev, st /* fetch the vendor and product strings from the device */ usbd_set_device_strings(udev); - if (udev->flags.usb_mode == USB_MODE_HOST) { - uint8_t config_index; - uint8_t config_quirk; - uint8_t set_config_failed = 0; + if (udev->flags.usb_mode == USB_MODE_DEVICE) { + /* USB device mode setup is complete */ + err = 0; + goto config_done; + } - /* - * Most USB devices should attach to config index 0 by - * default - */ - if (usb_test_quirk(&uaa, UQ_CFG_INDEX_0)) { - config_index = 0; - config_quirk = 1; - } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_1)) { - config_index = 1; - config_quirk = 1; - } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_2)) { - config_index = 2; - config_quirk = 1; - } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_3)) { - config_index = 3; - config_quirk = 1; - } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_4)) { - config_index = 4; - config_quirk = 1; - } else { - config_index = 0; - config_quirk = 0; - } + /* + * Most USB devices should attach to config index 0 by + * default + */ + if (usb_test_quirk(&uaa, UQ_CFG_INDEX_0)) { + config_index = 0; + config_quirk = 1; + } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_1)) { + config_index = 1; + config_quirk = 1; + } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_2)) { + config_index = 2; + config_quirk = 1; + } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_3)) { + config_index = 3; + config_quirk = 1; + } else if (usb_test_quirk(&uaa, UQ_CFG_INDEX_4)) { + config_index = 4; + config_quirk = 1; + } else { + config_index = 0; + config_quirk = 0; + } + set_config_failed = 0; repeat_set_config: - DPRINTF("setting config %u\n", config_index); + DPRINTF("setting config %u\n", config_index); - /* get the USB device configured */ - err = usbd_set_config_index(udev, config_index); - if (err) { - if (udev->ddesc.bNumConfigurations != 0) { - if (!set_config_failed) { - set_config_failed = 1; - /* XXX try to re-enumerate the device */ - err = usbd_req_re_enumerate( - udev, NULL); - if (err == 0) - goto repeat_set_config; - } - DPRINTFN(0, "Failure selecting " - "configuration index %u: %s, port %u, " - "addr %u (ignored)\n", - config_index, usbd_errstr(err), udev->port_no, - udev->address); + /* get the USB device configured */ + err = usbd_set_config_index(udev, config_index); + if (err) { + if (udev->ddesc.bNumConfigurations != 0) { + if (!set_config_failed) { + set_config_failed = 1; + /* XXX try to re-enumerate the device */ + err = usbd_req_re_enumerate(udev, NULL); + if (err == 0) + goto repeat_set_config; } + DPRINTFN(0, "Failure selecting configuration index %u:" + "%s, port %u, addr %u (ignored)\n", + config_index, usbd_errstr(err), udev->port_no, + udev->address); + } + /* + * Some USB devices do not have any configurations. Ignore any + * set config failures! + */ + err = 0; + goto config_done; + } + if (!config_quirk && config_index + 1 < udev->ddesc.bNumConfigurations) { + if ((udev->cdesc->bNumInterface < 2) && + usbd_get_no_descriptors(udev->cdesc, UDESC_ENDPOINT) == 0) { + DPRINTFN(0, "Found no endpoints, trying next config\n"); + config_index++; + goto repeat_set_config; + } + if (config_index == 0) { /* - * Some USB devices do not have any - * configurations. Ignore any set config - * failures! + * Try to figure out if we have an + * auto-install disk there: */ - err = 0; - } else if (config_quirk) { - /* user quirk selects configuration index */ - } else if ((config_index + 1) < udev->ddesc.bNumConfigurations) { - - if ((udev->cdesc->bNumInterface < 2) && - (usbd_get_no_descriptors(udev->cdesc, - UDESC_ENDPOINT) == 0)) { - DPRINTFN(0, "Found no endpoints " - "(trying next config)\n"); + if (usb_test_autoinstall(udev, 0, 0) == 0) { + DPRINTFN(0, "Found possible auto-install " + "disk (trying next config)\n"); config_index++; goto repeat_set_config; } - if (config_index == 0) { - /* - * Try to figure out if we have an - * auto-install disk there: - */ - if (usb_test_autoinstall(udev, 0, 0) == 0) { - DPRINTFN(0, "Found possible auto-install " - "disk (trying next config)\n"); - config_index++; - goto repeat_set_config; - } - } - } else if (usb_test_huawei_autoinst_p(udev, &uaa) == 0) { - DPRINTFN(0, "Found Huawei auto-install disk\n"); - /* leave device unconfigured */ - usb_unconfigure(udev, 0); } - } else { - err = 0; /* set success */ + } + EVENTHANDLER_INVOKE(usb_dev_configured, udev, &uaa); + if (uaa.dev_state != UAA_DEV_READY) { + /* leave device unconfigured */ + usb_unconfigure(udev, 0); } +config_done: DPRINTF("new dev (addr %d), udev=%p, parent_hub=%p\n", udev->address, udev, udev->parent_hub); Modified: head/sys/dev/usb/usb_dynamic.c ============================================================================== --- head/sys/dev/usb/usb_dynamic.c Thu Dec 17 21:17:13 2009 (r200652) +++ head/sys/dev/usb/usb_dynamic.c Thu Dec 17 21:42:10 2009 (r200653) @@ -57,7 +57,6 @@ static usb_handle_req_t usb_temp_get_des static usb_temp_setup_by_index_t usb_temp_setup_by_index_w; static usb_temp_unsetup_t usb_temp_unsetup_w; static usb_test_quirk_t usb_test_quirk_w; -static usb_test_huawei_autoinst_t usb_test_huawei_autoinst_w; static usb_quirk_ioctl_t usb_quirk_ioctl_w; /* global variables */ @@ -65,7 +64,6 @@ usb_handle_req_t *usb_temp_get_desc_p = usb_temp_setup_by_index_t *usb_temp_setup_by_index_p = &usb_temp_setup_by_index_w; usb_temp_unsetup_t *usb_temp_unsetup_p = &usb_temp_unsetup_w; usb_test_quirk_t *usb_test_quirk_p = &usb_test_quirk_w; -usb_test_huawei_autoinst_t *usb_test_huawei_autoinst_p = &usb_test_huawei_autoinst_w; usb_quirk_ioctl_t *usb_quirk_ioctl_p = &usb_quirk_ioctl_w; devclass_t usb_devclass_ptr = NULL; @@ -105,13 +103,6 @@ usb_temp_unsetup_w(struct usb_device *ud } } -static usb_error_t -usb_test_huawei_autoinst_w(struct usb_device *udev, - struct usb_attach_arg *uaa) -{ - return (USB_ERR_INVAL); -} - void usb_quirk_unload(void *arg) { @@ -156,17 +147,3 @@ usb_bus_unload(void *arg) pause("WAIT", hz); } - -void -usb_test_huawei_unload(void *arg) -{ - /* reset function pointers */ - - usb_test_huawei_autoinst_p = &usb_test_huawei_autoinst_w; - - /* wait for CPU to exit the loaded functions, if any */ - - /* XXX this is a tradeoff */ - - pause("WAIT", 16*hz); -} Modified: head/sys/dev/usb/usb_dynamic.h ============================================================================== --- head/sys/dev/usb/usb_dynamic.h Thu Dec 17 21:17:13 2009 (r200652) +++ head/sys/dev/usb/usb_dynamic.h Thu Dec 17 21:42:10 2009 (r200653) @@ -37,8 +37,6 @@ struct usb_device_request; typedef usb_error_t (usb_temp_setup_by_index_t)(struct usb_device *udev, uint16_t index); -typedef usb_error_t (usb_test_huawei_autoinst_t)(struct usb_device *udev, - struct usb_attach_arg *uaa); typedef uint8_t (usb_test_quirk_t)(const struct usbd_lookup_info *info, uint16_t quirk); typedef int (usb_quirk_ioctl_t)(unsigned long cmd, caddr_t data, @@ -51,13 +49,11 @@ extern usb_handle_req_t *usb_temp_get_de extern usb_temp_setup_by_index_t *usb_temp_setup_by_index_p; extern usb_temp_unsetup_t *usb_temp_unsetup_p; extern usb_test_quirk_t *usb_test_quirk_p; -extern usb_test_huawei_autoinst_t *usb_test_huawei_autoinst_p; extern usb_quirk_ioctl_t *usb_quirk_ioctl_p; extern devclass_t usb_devclass_ptr; /* function prototypes */ -void usb_test_huawei_unload(void *); void usb_temp_unload(void *); void usb_quirk_unload(void *); void usb_bus_unload(void *); Modified: head/sys/dev/usb/usbdi.h ============================================================================== --- head/sys/dev/usb/usbdi.h Thu Dec 17 21:17:13 2009 (r200652) +++ head/sys/dev/usb/usbdi.h Thu Dec 17 21:42:10 2009 (r200653) @@ -29,6 +29,7 @@ struct usb_fifo; struct usb_xfer; struct usb_device; +struct usb_attach_arg; struct usb_interface; struct usb_endpoint; struct usb_page_cache; @@ -98,6 +99,13 @@ typedef int (usb_fifo_ioctl_t)(struct us typedef void (usb_fifo_cmd_t)(struct usb_fifo *fifo); typedef void (usb_fifo_filter_t)(struct usb_fifo *fifo, struct usb_mbuf *m); + +/* USB events */ +#include <sys/eventhandler.h> +typedef void (*usb_dev_configured_t)(void *, struct usb_device *, + struct usb_attach_arg *); +EVENTHANDLER_DECLARE(usb_dev_configured, usb_dev_configured_t); + /* * The following macros are used used to convert milliseconds into * HZ. We use 1024 instead of 1000 milliseconds per second to save a @@ -338,6 +346,10 @@ struct usb_attach_arg { enum usb_hc_mode usb_mode; /* host or device mode */ uint8_t port; uint8_t use_generic; /* hint for generic drivers */ + uint8_t dev_state; +#define UAA_DEV_READY 0 +#define UAA_DEV_DISABLED 1 +#define UAA_DEV_EJECTING 2 }; /*
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200912172142.nBHLgAkf051560>