Skip site navigation (1)Skip section navigation (2)
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>