Commit 97664e0e authored by David Brownell's avatar David Brownell Committed by Greg Kroah-Hartman

[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.
parent 54399915
...@@ -99,10 +99,13 @@ config USB_SPEEDTOUCH ...@@ -99,10 +99,13 @@ config USB_SPEEDTOUCH
config USB_TEST config USB_TEST
tristate "USB testing driver (DEVELOPMENT)" tristate "USB testing driver (DEVELOPMENT)"
depends on USB_DEVICEFS && EXPERIMENTAL depends on USB && USB_DEVICEFS && EXPERIMENTAL
help help
This driver is for testing host controller software. It is used This driver is for testing host controller software. It is used
with specialized device firmware for regression and stress testing, with specialized device firmware for regression and stress testing,
to help prevent problems from cropping up with "real" drivers. to help prevent problems from cropping up with "real" drivers.
See <http://www.linux-usb.org/usbtest> for more information,
including sample test device firmware and "how to use it".
...@@ -51,14 +51,10 @@ struct usbtest_info { ...@@ -51,14 +51,10 @@ struct usbtest_info {
}; };
/* this is accessed only through usbfs ioctl calls. /* 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. * tests create other threads if they need them.
* urbs and buffers are allocated dynamically, * urbs and buffers are allocated dynamically,
* and data generated deterministically. * 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 usbtest_dev {
struct usb_interface *intf; struct usb_interface *intf;
...@@ -66,6 +62,7 @@ struct usbtest_dev { ...@@ -66,6 +62,7 @@ struct usbtest_dev {
char id [32]; char id [32];
int in_pipe; int in_pipe;
int out_pipe; int out_pipe;
struct semaphore sem;
#define TBUF_SIZE 256 #define TBUF_SIZE 256
u8 *buf; u8 *buf;
...@@ -282,6 +279,10 @@ static int perform_sglist ( ...@@ -282,6 +279,10 @@ static int perform_sglist (
* or remote wakeup (which needs human interaction). * 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) static int get_altsetting (struct usbtest_dev *dev)
{ {
struct usb_interface *iface = dev->intf; struct usb_interface *iface = dev->intf;
...@@ -366,13 +367,11 @@ static int is_good_config (char *buf, int len) ...@@ -366,13 +367,11 @@ static int is_good_config (char *buf, int len)
case USB_DT_OTHER_SPEED_CONFIG: case USB_DT_OTHER_SPEED_CONFIG:
if (config->bLength != 9) if (config->bLength != 9)
return 0; return 0;
#if 0
/* this bit 'must be 1' but often isn't */ /* 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"); dbg ("high bit of config attributes not set");
return 0; return 0;
} }
#endif
if (config->bmAttributes & 0x1f) /* reserved == 0 */ if (config->bmAttributes & 0x1f) /* reserved == 0 */
return 0; return 0;
break; break;
...@@ -424,7 +423,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -424,7 +423,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
} }
/* [real world] get/set unimplemented if there's only one */ /* [real world] get/set unimplemented if there's only one */
if (iface->num_altsetting == 1) if (realworld && iface->num_altsetting == 1)
continue; continue;
/* [9.4.10] set_interface */ /* [9.4.10] set_interface */
...@@ -446,7 +445,7 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -446,7 +445,7 @@ static int ch9_postconfig (struct usbtest_dev *dev)
} }
/* [real world] get_config unimplemented if there's only one */ /* [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; int expected = udev->actconfig->desc.bConfigurationValue;
/* [9.4.2] get_configuration always works /* [9.4.2] get_configuration always works
...@@ -454,7 +453,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -454,7 +453,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* won't return config descriptors except before set_config. * won't return config descriptors except before set_config.
*/ */
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0), 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); 0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) { if (retval != 1 || dev->buf [0] != expected) {
dbg ("%s get config --> %d (%d)", dev->id, retval, dbg ("%s get config --> %d (%d)", dev->id, retval,
...@@ -563,7 +563,8 @@ static int ch9_postconfig (struct usbtest_dev *dev) ...@@ -563,7 +563,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
* threads and request completion. * 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 usbtest_dev *dev = dev_get_drvdata (&intf->dev);
struct usb_device *udev = testdev_to_usbdev (dev); struct usb_device *udev = testdev_to_usbdev (dev);
...@@ -584,6 +585,9 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b ...@@ -584,6 +585,9 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b
|| param->sglen < 0 || param->vary < 0) || param->sglen < 0 || param->vary < 0)
return -EINVAL; return -EINVAL;
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
/* some devices, like ez-usb default devices, need a non-default /* some devices, like ez-usb default devices, need a non-default
* altsetting to have any active endpoints. some tests change * altsetting to have any active endpoints. some tests change
* altsettings; force a default so most tests don't need to check. * altsettings; force a default so most tests don't need to check.
...@@ -591,12 +595,15 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b ...@@ -591,12 +595,15 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b
if (dev->info->alt >= 0) { if (dev->info->alt >= 0) {
int res; int res;
if (intf->altsetting->desc.bInterfaceNumber) if (intf->altsetting->desc.bInterfaceNumber) {
up (&dev->sem);
return -ENODEV; return -ENODEV;
}
res = set_altsetting (dev, dev->info->alt); res = set_altsetting (dev, dev->info->alt);
if (res) { if (res) {
err ("%s: set altsetting to %d failed, %d", err ("%s: set altsetting to %d failed, %d",
dev->id, dev->info->alt, res); dev->id, dev->info->alt, res);
up (&dev->sem);
return res; return res;
} }
} }
...@@ -770,6 +777,7 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b ...@@ -770,6 +777,7 @@ static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *b
param->duration.tv_usec += 1000 * 1000; param->duration.tv_usec += 1000 * 1000;
param->duration.tv_sec -= 1; param->duration.tv_sec -= 1;
} }
up (&dev->sem);
return retval; return retval;
} }
...@@ -819,6 +827,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id) ...@@ -819,6 +827,7 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
memset (dev, 0, sizeof *dev); memset (dev, 0, sizeof *dev);
info = (struct usbtest_info *) id->driver_info; info = (struct usbtest_info *) id->driver_info;
dev->info = info; dev->info = info;
init_MUTEX (&dev->sem);
/* use the same kind of id the hid driver shows */ /* use the same kind of id the hid driver shows */
snprintf (dev->id, sizeof dev->id, "%s-%s:%d", snprintf (dev->id, sizeof dev->id, "%s-%s:%d",
...@@ -874,6 +883,8 @@ static void usbtest_disconnect (struct usb_interface *intf) ...@@ -874,6 +883,8 @@ static void usbtest_disconnect (struct usb_interface *intf)
{ {
struct usbtest_dev *dev = dev_get_drvdata (&intf->dev); struct usbtest_dev *dev = dev_get_drvdata (&intf->dev);
down (&dev->sem);
dev_set_drvdata (&intf->dev, 0); dev_set_drvdata (&intf->dev, 0);
info ("unbound %s", dev->id); info ("unbound %s", dev->id);
kfree (intf->private_data); kfree (intf->private_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment