ChangeSet 1.855.9.8, 2002/11/05 11:07:55-08:00, david-b@pacbell.net [PATCH] usbtest, Kconfig and misc Minor patches: - resend of the Config.in patch, updated to Kconfig, plus makes 'usbtest' modular when usb is; - hmm, "usbfs" isn't locking here. protect. fix is basically from martin: add/use a semaphore. - that one-liner to make sure get_configuration is called correctly (with funkier test firmware). - new 'realworld' module param can be used to turn off the real-world accomodations and be stricter about what device failures make ch9 tests fail. diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig --- a/drivers/usb/misc/Kconfig Tue Nov 5 16:10:32 2002 +++ b/drivers/usb/misc/Kconfig Tue Nov 5 16:10:32 2002 @@ -99,10 +99,13 @@ config USB_TEST tristate "USB testing driver (DEVELOPMENT)" - depends on USB_DEVICEFS && EXPERIMENTAL + depends on USB && USB_DEVICEFS && EXPERIMENTAL help This driver is for testing host controller software. It is used with specialized device firmware for regression and stress testing, to help prevent problems from cropping up with "real" drivers. + + See for more information, + including sample test device firmware and "how to use it". diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c --- a/drivers/usb/misc/usbtest.c Tue Nov 5 16:10:32 2002 +++ b/drivers/usb/misc/usbtest.c Tue Nov 5 16:10:32 2002 @@ -51,14 +51,10 @@ }; /* this is accessed only through usbfs ioctl calls. - * one ioctl to issue a test ... no locking needed!!! + * one ioctl to issue a test ... one lock per device. * tests create other threads if they need them. * urbs and buffers are allocated dynamically, * and data generated deterministically. - * - * there's a minor complication on rmmod, since - * usbfs.disconnect() waits till our ioctl completes. - * unplug works fine since we'll see real i/o errors. */ struct usbtest_dev { struct usb_interface *intf; @@ -66,6 +62,7 @@ char id [32]; int in_pipe; int out_pipe; + struct semaphore sem; #define TBUF_SIZE 256 u8 *buf; @@ -282,6 +279,10 @@ * or remote wakeup (which needs human interaction). */ +static int realworld = 1; +MODULE_PARM (realworld, "i"); +MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance"); + static int get_altsetting (struct usbtest_dev *dev) { struct usb_interface *iface = dev->intf; @@ -366,13 +367,11 @@ case USB_DT_OTHER_SPEED_CONFIG: if (config->bLength != 9) return 0; -#if 0 /* this bit 'must be 1' but often isn't */ - if (!(config->bmAttributes & 0x80)) { + if (!realworld && !(config->bmAttributes & 0x80)) { dbg ("high bit of config attributes not set"); return 0; } -#endif if (config->bmAttributes & 0x1f) /* reserved == 0 */ return 0; break; @@ -424,7 +423,7 @@ } /* [real world] get/set unimplemented if there's only one */ - if (iface->num_altsetting == 1) + if (realworld && iface->num_altsetting == 1) continue; /* [9.4.10] set_interface */ @@ -446,7 +445,7 @@ } /* [real world] get_config unimplemented if there's only one */ - if (udev->descriptor.bNumConfigurations != 1) { + if (!realworld || udev->descriptor.bNumConfigurations != 1) { int expected = udev->actconfig->desc.bConfigurationValue; /* [9.4.2] get_configuration always works @@ -454,7 +453,8 @@ * won't return config descriptors except before set_config. */ retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0), - USB_REQ_GET_CONFIGURATION, USB_RECIP_DEVICE, + USB_REQ_GET_CONFIGURATION, + USB_DIR_IN | USB_RECIP_DEVICE, 0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT); if (retval != 1 || dev->buf [0] != expected) { dbg ("%s get config --> %d (%d)", dev->id, retval, @@ -563,7 +563,8 @@ * threads and request completion. */ -static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) +static int +usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf) { struct usbtest_dev *dev = dev_get_drvdata (&intf->dev); struct usb_device *udev = testdev_to_usbdev (dev); @@ -584,6 +585,9 @@ || param->sglen < 0 || param->vary < 0) return -EINVAL; + if (down_interruptible (&dev->sem)) + return -ERESTARTSYS; + /* some devices, like ez-usb default devices, need a non-default * altsetting to have any active endpoints. some tests change * altsettings; force a default so most tests don't need to check. @@ -591,12 +595,15 @@ if (dev->info->alt >= 0) { int res; - if (intf->altsetting->desc.bInterfaceNumber) + if (intf->altsetting->desc.bInterfaceNumber) { + up (&dev->sem); return -ENODEV; + } res = set_altsetting (dev, dev->info->alt); if (res) { err ("%s: set altsetting to %d failed, %d", dev->id, dev->info->alt, res); + up (&dev->sem); return res; } } @@ -770,6 +777,7 @@ param->duration.tv_usec += 1000 * 1000; param->duration.tv_sec -= 1; } + up (&dev->sem); return retval; } @@ -819,6 +827,7 @@ memset (dev, 0, sizeof *dev); info = (struct usbtest_info *) id->driver_info; dev->info = info; + init_MUTEX (&dev->sem); /* use the same kind of id the hid driver shows */ snprintf (dev->id, sizeof dev->id, "%s-%s:%d", @@ -873,6 +882,8 @@ static void usbtest_disconnect (struct usb_interface *intf) { struct usbtest_dev *dev = dev_get_drvdata (&intf->dev); + + down (&dev->sem); dev_set_drvdata (&intf->dev, 0); info ("unbound %s", dev->id);