-#include <linux/config.h>
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-# define DEBUG
-#endif
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <linux/usb.h>
sg = kmalloc (nents * sizeof *sg, SLAB_KERNEL);
if (!sg)
return NULL;
- memset (sg, 0, nents * sizeof *sg);
for (i = 0; i < nents; i++) {
char *buf;
+ unsigned j;
- buf = kmalloc (size, SLAB_KERNEL);
+ buf = kzalloc (size, SLAB_KERNEL);
if (!buf) {
free_sglist (sg, i);
return NULL;
}
- memset (buf, 0, size);
/* kmalloc pages are always physically contiguous! */
- sg [i].page = virt_to_page (buf);
- sg [i].offset = offset_in_page (buf);
- sg [i].length = size;
+ sg_init_one(&sg[i], buf, size);
+
+ switch (pattern) {
+ case 0:
+ /* already zeroed */
+ break;
+ case 1:
+ for (j = 0; j < size; j++)
+ *buf++ = (u8) (j % 63);
+ break;
+ }
if (vary) {
size += vary;
usb_sg_wait (req);
retval = req->status;
+ /* FIXME check resulting data pattern */
+
/* FIXME if endpoint halted, clear halt (and log) */
}
static unsigned realworld = 1;
module_param (realworld, uint, 0);
-MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
+MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance");
static int get_altsetting (struct usbtest_dev *dev)
{
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
USB_REQ_GET_INTERFACE, USB_DIR_IN|USB_RECIP_INTERFACE,
0, iface->altsetting [0].desc.bInterfaceNumber,
- dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
+ dev->buf, 1, USB_CTRL_GET_TIMEOUT);
switch (retval) {
case 1:
return dev->buf [0];
return 0;
}
- le16_to_cpus (&config->wTotalLength);
- if (config->wTotalLength == len) /* read it all */
+ if (le16_to_cpu(config->wTotalLength) == len) /* read it all */
return 1;
- if (config->wTotalLength >= TBUF_SIZE) /* max partial read */
+ if (le16_to_cpu(config->wTotalLength) >= TBUF_SIZE) /* max partial read */
return 1;
dbg ("bogus config descriptor read size");
return 0;
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
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, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
- dev_dbg (&iface->dev,
- "get config --> %d (%d)\n", retval,
- expected);
+ dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+ retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
}
}
/* and sometimes [9.2.6.6] speed dependent descriptors */
- if (udev->descriptor.bcdUSB == 0x0200) { /* pre-swapped */
+ if (le16_to_cpu(udev->descriptor.bcdUSB) == 0x0200) {
struct usb_qualifier_descriptor *d = NULL;
/* device qualifier [9.6.2] */
if (u == urb || !u->dev)
continue;
+ spin_unlock(&ctx->lock);
status = usb_unlink_urb (u);
+ spin_lock(&ctx->lock);
switch (status) {
case -EINPROGRESS:
case -EBUSY:
* as with bulk/intr sglists, sglen is the queue depth; it also
* controls which subtests run (more tests than sglen) or rerun.
*/
- urb = kmalloc (param->sglen * sizeof (struct urb *), SLAB_KERNEL);
+ urb = kcalloc(param->sglen, sizeof(struct urb *), SLAB_KERNEL);
if (!urb)
- goto cleanup;
- memset (urb, 0, param->sglen * sizeof (struct urb *));
+ return -ENOMEM;
for (i = 0; i < param->sglen; i++) {
int pipe = usb_rcvctrlpipe (udev, 0);
unsigned len;
case 13: // short read, resembling case 10
req.wValue = cpu_to_le16 ((USB_DT_CONFIG << 8) | 0);
// last data packet "should" be DATA1, not DATA0
- len = 1024 - udev->epmaxpacketin [0];
+ len = 1024 - udev->descriptor.bMaxPacketSize0;
expected = -EREMOTEIO;
break;
case 14: // short read; try to fill the last packet
req.wValue = cpu_to_le16 ((USB_DT_DEVICE << 8) | 0);
// device descriptor size == 18 bytes
- len = udev->epmaxpacketin [0];
+ len = udev->descriptor.bMaxPacketSize0;
switch (len) {
case 8: len = 24; break;
case 16: len = 32; break;
reqp->number = i % NUM_SUBCASES;
reqp->expected = expected;
u->setup_packet = (char *) &reqp->setup;
+ u->transfer_flags |= URB_NO_SETUP_DMA_MAP;
u->context = &context;
u->complete = ctrl_complete;
- u->transfer_flags |= URB_ASYNC_UNLINK;
}
/* queue the urbs */
urb = simple_alloc_urb (testdev_to_usbdev (dev), pipe, size);
if (!urb)
return -ENOMEM;
- urb->transfer_flags |= URB_ASYNC_UNLINK;
urb->context = &completion;
urb->complete = unlink1_callback;
retval = usb_control_msg (urb->dev, usb_sndctrlpipe (urb->dev, 0),
USB_REQ_SET_FEATURE, USB_RECIP_ENDPOINT,
USB_ENDPOINT_HALT, ep,
- NULL, 0, HZ * USB_CTRL_SET_TIMEOUT);
+ NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval < 0) {
dbg ("ep %02x couldn't set halt, %d", ep, retval);
return retval;
struct urb *urb;
urb = simple_alloc_urb (testdev_to_usbdev (dev), 0, 512);
- if (urb == 0)
+ if (urb == NULL)
return -ENOMEM;
if (dev->in_pipe) {
static int ctrl_out (struct usbtest_dev *dev,
unsigned count, unsigned length, unsigned vary)
{
- unsigned i, j, len, retval;
+ unsigned i, j, len;
+ int retval;
u8 *buf;
char *what = "?";
struct usb_device *udev;
-
- if (length > 0xffff || vary >= length)
+
+ if (length < 1 || length > 0xffff || vary >= length)
return -EINVAL;
buf = kmalloc(length, SLAB_KERNEL);
buf [j] = i + j;
retval = usb_control_msg (udev, usb_sndctrlpipe (udev,0),
0x5b, USB_DIR_OUT|USB_TYPE_VENDOR,
- 0, 0, buf, len, HZ * USB_CTRL_SET_TIMEOUT);
+ 0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
if (retval != len) {
what = "write";
+ if (retval >= 0) {
+ INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+ retval, len);
+ retval = -EBADMSG;
+ }
break;
}
/* read it back -- assuming nothing intervened!! */
retval = usb_control_msg (udev, usb_rcvctrlpipe (udev,0),
0x5c, USB_DIR_IN|USB_TYPE_VENDOR,
- 0, 0, buf, len, HZ * USB_CTRL_GET_TIMEOUT);
+ 0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
if (retval != len) {
what = "read";
+ if (retval >= 0) {
+ INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+ retval, len);
+ retval = -EBADMSG;
+ }
break;
}
}
len += vary;
+
+ /* [real world] the "zero bytes IN" case isn't really used.
+ * hardware can easily trip up in this wierd case, since its
+ * status stage is IN, not OUT like other ep0in transfers.
+ */
if (len > length)
- len = 0;
+ len = realworld ? 1 : 0;
}
if (retval < 0)
unsigned pending;
spinlock_t lock;
struct completion done;
+ int submit_error;
unsigned long errors;
+ unsigned long packet_count;
struct usbtest_dev *dev;
};
spin_lock(&ctx->lock);
ctx->count--;
+ ctx->packet_count += urb->number_of_packets;
if (urb->error_count > 0)
ctx->errors += urb->error_count;
+ else if (urb->status != 0)
+ ctx->errors += urb->number_of_packets;
- if (urb->status == 0 && ctx->count > (ctx->pending - 1)) {
+ if (urb->status == 0 && ctx->count > (ctx->pending - 1)
+ && !ctx->submit_error) {
int status = usb_submit_urb (urb, GFP_ATOMIC);
switch (status) {
case 0:
status);
/* FALLTHROUGH */
case -ENODEV: /* disconnected */
+ case -ESHUTDOWN: /* endpoint disabled */
+ ctx->submit_error = 1;
break;
}
}
if (ctx->pending == 0) {
if (ctx->errors)
dev_dbg (&ctx->dev->intf->dev,
- "iso test, %lu errors\n",
- ctx->errors);
+ "iso test, %lu errors out of %lu\n",
+ ctx->errors, ctx->packet_count);
complete (&ctx->done);
- } else
+ }
done:
spin_unlock(&ctx->lock);
}
if (bytes < 0 || !desc)
return NULL;
- maxp = 0x7ff & desc->wMaxPacketSize;
- maxp *= 1 + (0x3 & (desc->wMaxPacketSize >> 11));
+ maxp = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
+ maxp *= 1 + (0x3 & (le16_to_cpu(desc->wMaxPacketSize) >> 11));
packets = (bytes + maxp - 1) / maxp;
urb = usb_alloc_urb (packets, SLAB_KERNEL);
struct usb_device *udev;
unsigned i;
unsigned long packets = 0;
- int status;
+ int status = 0;
struct urb *urbs[10]; /* FIXME no limit */
if (param->sglen > 10)
return -EDOM;
+ memset(&context, 0, sizeof context);
context.count = param->iterations * param->sglen;
- context.pending = param->sglen;
- context.errors = 0;
context.dev = dev;
init_completion (&context.done);
spin_lock_init (&context.lock);
"... iso period %d %sframes, wMaxPacket %04x\n",
1 << (desc->bInterval - 1),
(udev->speed == USB_SPEED_HIGH) ? "micro" : "",
- desc->wMaxPacketSize);
+ le16_to_cpu(desc->wMaxPacketSize));
for (i = 0; i < param->sglen; i++) {
urbs [i] = iso_alloc_urb (udev, pipe, desc,
spin_lock_irq (&context.lock);
for (i = 0; i < param->sglen; i++) {
+ ++context.pending;
status = usb_submit_urb (urbs [i], SLAB_ATOMIC);
if (status < 0) {
ERROR (dev, "submit iso[%d], error %d\n", i, status);
- if (i == 0)
+ if (i == 0) {
+ spin_unlock_irq (&context.lock);
goto fail;
+ }
simple_free_urb (urbs [i]);
context.pending--;
+ context.submit_error = 1;
+ break;
}
}
spin_unlock_irq (&context.lock);
wait_for_completion (&context.done);
- return 0;
+
+ /*
+ * Isochronous transfers are expected to fail sometimes. As an
+ * arbitrary limit, we will report an error if any submissions
+ * fail or if the transfer failure rate is > 10%.
+ */
+ if (status != 0)
+ ;
+ else if (context.submit_error)
+ status = -EACCES;
+ else if (context.errors > context.packet_count / 10)
+ status = -EIO;
+ return status;
fail:
for (i = 0; i < param->sglen; i++) {
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
+ if (intf->dev.power.power_state.event != PM_EVENT_ON) {
+ up (&dev->sem);
+ return -EHOSTUNREACH;
+ }
+
/* 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.
case 14:
if (!dev->info->ctrl_out)
break;
- dev_dbg (&intf->dev, "TEST 14: %d ep0out, 0..%d vary %d\n",
- param->iterations, param->length, param->vary);
+ dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
+ param->iterations,
+ realworld ? 1 : 0, param->length,
+ param->vary);
retval = ctrl_out (dev, param->iterations,
param->length, param->vary);
break;
/* specify devices by module parameters? */
if (id->match_flags == 0) {
/* vendor match required, product match optional */
- if (!vendor || udev->descriptor.idVendor != (u16)vendor)
+ if (!vendor || le16_to_cpu(udev->descriptor.idVendor) != (u16)vendor)
return -ENODEV;
- if (product && udev->descriptor.idProduct != (u16)product)
+ if (product && le16_to_cpu(udev->descriptor.idProduct) != (u16)product)
return -ENODEV;
dbg ("matched module params, vend=0x%04x prod=0x%04x",
- udev->descriptor.idVendor,
- udev->descriptor.idProduct);
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct));
}
#endif
- dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+ dev = kzalloc(sizeof(*dev), SLAB_KERNEL);
if (!dev)
return -ENOMEM;
- memset (dev, 0, sizeof *dev);
info = (struct usbtest_info *) id->driver_info;
dev->info = info;
init_MUTEX (&dev->sem);
dev->intf = intf;
/* cacheline-aligned scratch for i/o */
- if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == 0) {
+ if ((dev->buf = kmalloc (TBUF_SIZE, SLAB_KERNEL)) == NULL) {
kfree (dev);
return -ENOMEM;
}
return 0;
}
+static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
+{
+ return 0;
+}
+
+static int usbtest_resume (struct usb_interface *intf)
+{
+ return 0;
+}
+
+
static void usbtest_disconnect (struct usb_interface *intf)
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
MODULE_DEVICE_TABLE (usb, id_table);
static struct usb_driver usbtest_driver = {
- .owner = THIS_MODULE,
.name = "usbtest",
.id_table = id_table,
.probe = usbtest_probe,
.ioctl = usbtest_ioctl,
.disconnect = usbtest_disconnect,
+ .suspend = usbtest_suspend,
+ .resume = usbtest_resume,
};
/*-------------------------------------------------------------------------*/