From: Ondrej Zary on
On Monday 07 December 2009, Ondrej Zary wrote:
> On Friday 04 December 2009, Alan Stern wrote:
> > > With uhci_hcd, rmmod works fine. With ehci_hcd, rmmod hangs the bus -
> > > all urbs fail with -ENOENT:
> > > f67265e8 1428021080 S Bi:1:009:2 -115 128 <
> > > f67265e8 1431508327 C Bi:1:009:2 -108 0
> > > f6726718 1458252464 S Co:1:007:0 s 40 09 0001 0000 0000 0
> > > f6726718 1463261404 C Co:1:007:0 -2 0
> > > f6726978 1463261428 S Co:1:002:0 s 23 08 0070 0001 0000 0
> > > f6726718 1463261509 S Co:1:007:0 s 40 00 0000 0000 0000 0
> > > f6726978 1464273397 C Co:1:002:0 -2 0
> > > f6726718 1468273397 C Co:1:007:0 -2 0
> >
> > This may be a bug in ehci-hcd, a bug in your EHCI hardware, or a bug in
> > the hub. Can you try using a different high-speed hub to see if it
> > makes any difference?
>
> Just tried another hub. Now there are two hubs connected to separate ports
> on the machine. Nexio is the only device connected to the "new" hub. No
> matter where I connect the device or the 2nd hub, it always appears on "Bus
> 001":
>
> Bus 002 Device 002: ID 041e:4068 Creative Technology, Ltd Webcam Live!
> Notebook Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
> Bus 003 Device 002: ID 413c:2003 Dell Computer Corp. Keyboard
> Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
> Bus 005 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
> Bus 004 Device 002: ID 0bda:0158 Realtek Semiconductor Corp. USB 2.0
> multicard reader Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root
> hub
> Bus 001 Device 010: ID 1870:0001 Nexio Co., Ltd iNexio Touchscreen
> controller Bus 001 Device 009: ID 088c:2030 Swecoin AB Ticket Printer TTP
> 2030 Bus 001 Device 008: ID 0403:6001 Future Technology Devices
> International, Ltd FT232 USB-Serial (UART) IC Bus 001 Device 007: ID
> 065a:0001 Optoelectronics Co., Ltd Barcode scanner Bus 001 Device 002: ID
> 2001:f103 D-Link Corp. [hex] DUB-H7 7-port USB 2.0 hub Bus 001 Device 001:
> ID 1d6b:0002 Linux Foundation 2.0 root hub
> Bus 001 Device 005: ID 04cc:1521 Philips Semiconductors USB 2.0 Hub
>
> The problem is still the same. Removing the module causes devices on the
> other hub to fail.
>
> Disconnecting the touchscreen first and then removing the module does not
> cause any problems (with either of the hubs) - so it must be a software
> problem.

Narrowed down the code to this 170-line module which reproduces my
"rmmod usbtouchscreen" problem. Loading this module causes EHCI to fail.
Looks like it fails after calling usb_kill_urb(). Can a buggy device cause
this?

#define DEBUG

#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb.h>

struct crashnexio_usb {
unsigned char *data;
dma_addr_t data_dma;
struct urb *irq;
struct usb_interface *interface;
};

static struct usb_device_id crashnexio_devices[] = {
{USB_DEVICE_AND_INTERFACE_INFO(0x1870, 0x0001, 0x0a, 0x00, 0x00)},
{}
};

#define NEXIO_TIMEOUT 5000
#define NEXIO_BUFSIZE 1024
#define NEXIO_THRESHOLD 50
#define NEXIO_REPT_SIZE 128

static unsigned char nexio_init_pkt[4] = { 0x82, 0x04, 0x0a, 0x0f };

static int nexio_init(struct crashnexio_usb *crashnexio)
{
struct usb_device *dev = interface_to_usbdev(crashnexio->interface);
int ret = -ENOMEM;
int actual_len;
unsigned char *buf;
int input_ep = 0x82, output_ep = 0x01;

printk("%s\n", __func__);

buf = kmalloc(NEXIO_BUFSIZE, GFP_KERNEL);
if (!buf)
goto out_buf;
/* send init command */
memcpy(buf, nexio_init_pkt, sizeof(nexio_init_pkt));
ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, output_ep),
buf, sizeof(nexio_init_pkt), &actual_len,
NEXIO_TIMEOUT);
if (ret < 0)
goto out_buf;
/* read reply */
memset(buf, 0, NEXIO_BUFSIZE);
ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, input_ep),
buf, NEXIO_BUFSIZE, &actual_len,
NEXIO_TIMEOUT);
out_buf:
kfree(buf);
return ret;
}

static void crashnexio_irq(struct urb *urb)
{
int retval;

printk("%s\n", __func__);

switch (urb->status) {
case 0:
/* success */
break;
case -ETIME:
/* this urb is timing out */
dbg("%s - urb timed out - was the device unplugged?",
__func__);
return;
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
case -EPIPE:
/* this urb is terminated, clean up */
dbg("%s - urb shutting down with status: %d",
__func__, urb->status);
return;
default:
dbg("%s - nonzero urb status received: %d",
__func__, urb->status);
goto exit;
}

exit:
retval = usb_submit_urb(urb, GFP_ATOMIC);
if (retval)
err("%s - usb_submit_urb failed with result: %d",
__func__, retval);
}

static int crashnexio_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct crashnexio_usb *crashnexio;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint = NULL;
struct usb_device *udev = interface_to_usbdev(intf);
int err = -ENOMEM;
int i;

printk("%s\n", __func__);

interface = intf->cur_altsetting;
/* find first input endpoint */
for (i = 0; i < interface->desc.bNumEndpoints; i++)
if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) {
endpoint = &interface->endpoint[i].desc;
break;
}
if (!endpoint)
return -ENXIO;

crashnexio = kzalloc(sizeof(struct crashnexio_usb), GFP_KERNEL);
if (!crashnexio)
goto out_free;

crashnexio->data = usb_buffer_alloc(udev, NEXIO_REPT_SIZE,
GFP_KERNEL, &crashnexio->data_dma);
if (!crashnexio->data)
goto out_free;

crashnexio->irq = usb_alloc_urb(0, GFP_KERNEL);
if (!crashnexio->irq) {
dbg("%s - usb_alloc_urb failed: crashnexio->irq", __func__);
goto out_free_buffers;
}

crashnexio->interface = intf;

usb_fill_bulk_urb(crashnexio->irq, udev,
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
crashnexio->data, NEXIO_REPT_SIZE,
crashnexio_irq, crashnexio);

usb_set_intfdata(intf, crashnexio);

nexio_init(crashnexio);

usb_submit_urb(crashnexio->irq, GFP_KERNEL);
/* This will crash all EHCI communication */
usb_kill_urb(crashnexio->irq);

return 0;

out_free_buffers:
usb_buffer_free(udev, NEXIO_REPT_SIZE, crashnexio->data, crashnexio->data_dma);
out_free:
kfree(crashnexio);
return err;
}

MODULE_DEVICE_TABLE(usb, crashnexio_devices);

static struct usb_driver crashnexio_driver = {
.name = "crashnexio",
.probe = crashnexio_probe,
.id_table = crashnexio_devices,
};

static int __init crashnexio_init(void)
{
return usb_register(&crashnexio_driver);
}

module_init(crashnexio_init);

MODULE_LICENSE("GPL");



dmesg when loaded:
[ 29.504260] usb 1-1.7: New USB device found, idVendor=1870, idProduct=0001
[ 29.504277] usb 1-1.7: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 29.504290] usb 1-1.7: Product: iNexio USB
[ 29.504299] usb 1-1.7: Manufacturer: iNexio
[ 29.504529] usb 1-1.7: configuration #1 chosen from 1 choice
[ 29.783276] crashnexio_probe
[ 29.783289] nexio_init
[ 29.783941] crashnexio_irq
[ 29.783954] drivers/input/touchscreen/crashnexio.c: crashnexio_irq - urb shutting down with status: -2
[ 29.784123] usbcore: registered new interface driver crashnexio
[ 46.328105] ftdi_sio ttyUSB0: Unable to write latency timer: -110
....more USB errors


usbmon output:
f60f1d40 1250266541 S Ci:1:009:0 s 80 06 0100 0000 0012 18 <
f60f1d40 1250266801 C Ci:1:009:0 0 18 = 12011001 02000008 70180100 00010102 0301
f60f1d40 1250266844 S Ci:1:009:0 s 80 06 0200 0000 0009 9 <
f60f1d40 1250267057 C Ci:1:009:0 0 9 = 09024300 020100c0 fa
f60f1d40 1250267107 S Ci:1:009:0 s 80 06 0200 0000 0043 67 <
f60f1d40 1250267423 C Ci:1:009:0 0 67 = 09024300 020100c0 fa090400 00010202 00000524 00100104 24020005 24060001
f60f1d40 1250267478 S Ci:1:009:0 s 80 06 0300 0000 00ff 255 <
f60f1d40 1250267673 C Ci:1:009:0 0 6 = 06030904 1204
f60f1d40 1250267734 S Ci:1:009:0 s 80 06 0302 0409 00ff 255 <
f60f1d40 1250267923 C Ci:1:009:0 0 22 = 16036900 4e006500 78006900 6f002000 55005300 4200
f60f1d40 1250267984 S Ci:1:009:0 s 80 06 0301 0409 00ff 255 <
f60f1d40 1250268171 C Ci:1:009:0 0 14 = 0e036900 4e006500 78006900 6f00
f60f1d40 1250268217 S Ci:1:009:0 s 80 06 0303 0409 00ff 255 <
f60f1d40 1255266704 C Ci:1:009:0 -2 0
f60f1d40 1255266822 S Ci:1:009:0 s 80 06 0303 0409 0002 2 <
f60f1c40 1255266840 S Co:1:002:0 s 23 08 8090 0001 0000 0
f60f1c40 1255266930 C Co:1:002:0 0 0
f6527c40 1259050204 S Bo:1:004:1 -115 31 = 55534243 24000000 00000000 00000600 00000000 00000000 00000000 000000
f6527c40 1259050331 C Bo:1:004:1 0 31 >
f6527c40 1259050351 S Bi:1:004:2 -115 13 <
f6527c40 1259050936 C Bi:1:004:2 0 13 = 55534253 24000000 00000000 01
f6527c40 1259050962 S Bo:1:004:1 -115 31 = 55534243 25000000 12000000 80000603 00000012 00000000 00000000 000000
f6527c40 1259051073 C Bo:1:004:1 0 31 >
f64b1f40 1259051111 S Bi:1:004:2 -115 18 <
f64b1f40 1259051960 C Bi:1:004:2 0 18 = 70000200 0000000a 00000000 3a000000 0000
f6527c40 1259052025 S Bi:1:004:2 -115 13 <
f6527c40 1259052320 C Bi:1:004:2 0 13 = 55534253 25000000 00000000 00
f6527c40 1259052471 S Bo:1:004:1 -115 31 = 55534243 26000000 00000000 00000600 00000000 00000000 00000000 000000
f6527c40 1259052573 C Bo:1:004:1 0 31 >
f6527c40 1259052605 S Bi:1:004:2 -115 13 <
f6527c40 1259053074 C Bi:1:004:2 0 13 = 55534253 26000000 00000000 01
f6527c40 1259053116 S Bo:1:004:1 -115 31 = 55534243 27000000 12000000 80000603 00000012 00000000 00000000 000000
f6527c40 1259053186 C Bo:1:004:1 0 31 >
f64b1f40 1259053227 S Bi:1:004:2 -115 18 <
f64b1f40 1259054208 C Bi:1:004:2 0 18 = 70000200 0000000a 00000000 3a000000 0000
f6527c40 1259054264 S Bi:1:004:2 -115 13 <
f6527c40 1259054561 C Bi:1:004:2 0 13 = 55534253 27000000 00000000 00
f60f1d40 1260266607 C Ci:1:009:0 -2 0
f60f1d40 1260266987 S Co:1:009:0 s 00 09 0001 0000 0000 0
f60f1c40 1260267046 S Co:1:002:0 s 23 08 8090 0001 0000 0
f60f1c40 1260267201 C Co:1:002:0 0 0
f60f1d40 1260267449 C Co:1:009:0 0 0
f60f1d40 1260267925 S Ci:1:002:0 s a3 00 0000 0007 0004 4 <


--
Ondrej Zary
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Alan Stern on
On Thu, 10 Dec 2009, Ondrej Zary wrote:

> Narrowed down the code to this 170-line module which reproduces my
> "rmmod usbtouchscreen" problem. Loading this module causes EHCI to fail.
> Looks like it fails after calling usb_kill_urb(). Can a buggy device cause
> this?

I don't think so. But I am getting an idea of what the problem might
be. Try applying the patch below and see if it makes any difference
(make sure that CONFIG_USB_DEBUG is enabled).

If the module stops messing up EHCI, try changing the source code:

> static int crashnexio_probe(struct usb_interface *intf,
> const struct usb_device_id *id)
> {

....

> interface = intf->cur_altsetting;
> /* find first input endpoint */
> for (i = 0; i < interface->desc.bNumEndpoints; i++)
> if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) {
> endpoint = &interface->endpoint[i].desc;
> break;
> }

Does the interface have more than one input endpoint? (What does
"lsusb -v" show for the Nexio?) If it does, how do you know the
endpoint you want is the first one?

....

> usb_fill_bulk_urb(crashnexio->irq, udev,
> usb_rcvintpipe(udev, endpoint->bEndpointAddress),

Either change this to usb_fill_int_urb() or else use usb_rcvbulkpipe().

....

> static int __init crashnexio_init(void)
> {
> return usb_register(&crashnexio_driver);
> }

You should also have an __exit routine.

Alan Stern




Index: 2.6.31/Documentation/usb/error-codes.txt
===================================================================
--- 2.6.31.orig/Documentation/usb/error-codes.txt
+++ 2.6.31/Documentation/usb/error-codes.txt
@@ -41,8 +41,8 @@ USB-specific:

-EFBIG Host controller driver can't schedule that many ISO frames.

--EPIPE Specified endpoint is stalled. For non-control endpoints,
- reset this status with usb_clear_halt().
+-EPIPE The pipe type specified in the URB doesn't match the
+ endpoint's actual type.

-EMSGSIZE (a) endpoint maxpacket size is zero; it is not usable
in the current interface altsetting.
@@ -60,6 +60,8 @@ USB-specific:

-EHOSTUNREACH URB was rejected because the device is suspended.

+-ENOEXEC A control URB doesn't contain a Setup packet.
+

**************************************************************************
* Error codes returned by in urb->status *
Index: 2.6.31/drivers/usb/core/devio.c
===================================================================
--- 2.6.31.orig/drivers/usb/core/devio.c
+++ 2.6.31/drivers/usb/core/devio.c
@@ -1065,7 +1065,10 @@ static int proc_do_submiturb(struct dev_
case USB_ENDPOINT_XFER_CONTROL:
case USB_ENDPOINT_XFER_ISOC:
return -EINVAL;
- /* allow single-shot interrupt transfers, at bogus rates */
+ case USB_ENDPOINT_XFER_INT:
+ /* allow single-shot interrupt transfers */
+ uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+ goto interrupt_urb;
}
uurb->number_of_packets = 0;
if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
@@ -1073,6 +1076,16 @@ static int proc_do_submiturb(struct dev_
snoop(&ps->dev->dev, "bulk urb\n");
break;

+ case USBDEVFS_URB_TYPE_INTERRUPT:
+ if (!usb_endpoint_xfer_int(&ep->desc))
+ return -EINVAL;
+ interrupt_urb:
+ uurb->number_of_packets = 0;
+ if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
+ return -EINVAL;
+ snoop(&ps->dev->dev, "interrupt urb\n");
+ break;
+
case USBDEVFS_URB_TYPE_ISO:
/* arbitrary limit */
if (uurb->number_of_packets < 1 ||
@@ -1105,15 +1118,6 @@ static int proc_do_submiturb(struct dev_
snoop(&ps->dev->dev, "iso urb\n");
break;

- case USBDEVFS_URB_TYPE_INTERRUPT:
- uurb->number_of_packets = 0;
- if (!usb_endpoint_xfer_int(&ep->desc))
- return -EINVAL;
- if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
- return -EINVAL;
- snoop(&ps->dev->dev, "interrupt urb\n");
- break;
-
default:
return -EINVAL;
}
Index: 2.6.31/drivers/usb/core/urb.c
===================================================================
--- 2.6.31.orig/drivers/usb/core/urb.c
+++ 2.6.31/drivers/usb/core/urb.c
@@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_
{
unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
+ static int pipetypes[4] = {
+ PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+ };
+
+ /* Check that pipe's type matches the endpoint's type */
+ if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+ return -EPIPE;

/* enforce simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Ondrej Zary on
On Thursday 10 December 2009, Alan Stern wrote:
> On Thu, 10 Dec 2009, Ondrej Zary wrote:
> > Narrowed down the code to this 170-line module which reproduces my
> > "rmmod usbtouchscreen" problem. Loading this module causes EHCI to fail.
> > Looks like it fails after calling usb_kill_urb(). Can a buggy device
> > cause this?
>
> I don't think so. But I am getting an idea of what the problem might
> be. Try applying the patch below and see if it makes any difference
> (make sure that CONFIG_USB_DEBUG is enabled).

Thank you very much for the patch. It seems to finally solve this long
thread!

I'm running 2.6.32 now (with usbtouchscreen copied from -next) so one hunk
had to be applied manually. With patch applied and CONFIG_USB_DEBUG enabled,
usbtouchscreen stopped working - the urb failed to submit. Return value of
usb_submit_urb() was not checked (and it wasn't my code this time :) Adding
a check revealed that the urb fails to submit with -EPIPE because of
endpoint vs. pipe mismatch.

Fixing that (see the patch below) solved the rmmod problem!

>
> If the module stops messing up EHCI, try changing the source code:
> > static int crashnexio_probe(struct usb_interface *intf,
> > const struct usb_device_id *id)
> > {
>
> ...
>
> > interface = intf->cur_altsetting;
> > /* find first input endpoint */
> > for (i = 0; i < interface->desc.bNumEndpoints; i++)
> > if (usb_endpoint_dir_in(&interface->endpoint[i].desc)) {
> > endpoint = &interface->endpoint[i].desc;
> > break;
> > }
>
> Does the interface have more than one input endpoint? (What does
> "lsusb -v" show for the Nexio?) If it does, how do you know the
> endpoint you want is the first one?

No, there is only one input endpoint:
Bus 001 Device 009: ID 1870:0001 Nexio Co., Ltd iNexio Touchscreen controller
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x1870 Nexio Co., Ltd
idProduct 0x0001 iNexio Touchscreen controller
bcdDevice 1.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xc0
Self Powered
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 0 None
iInterface 0
CDC Header:
bcdCDC 1.10
CDC ACM:
bmCapabilities 0x00
CDC Union:
bMasterInterface 0
bSlaveInterface 1
CDC Call Management:
bmCapabilities 0x00
bDataInterface 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 255
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 10 CDC Data
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x01 EP 1 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0

>
> ...
>
> > usb_fill_bulk_urb(crashnexio->irq, udev,
> > usb_rcvintpipe(udev, endpoint->bEndpointAddress),
>
> Either change this to usb_fill_int_urb() or else use usb_rcvbulkpipe().
>
> ...
>
> > static int __init crashnexio_init(void)
> > {
> > return usb_register(&crashnexio_driver);
> > }
>
> You should also have an __exit routine.

As I'm bad at writing cleanup functions and the purpose was to break EHCI,
the only exit was a reboot :)


--- linux-2.6.32/drivers/input/touchscreen/usbtouchscreen.5 2009-12-11 12:50:35.000000000 +0100
+++ linux-2.6.32/drivers/input/touchscreen/usbtouchscreen.c 2009-12-11 20:15:51.000000000 +0100
@@ -1375,10 +1375,16 @@
input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
type->max_press, 0, 0);

- usb_fill_int_urb(usbtouch->irq, udev,
+ if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
+ usb_fill_int_urb(usbtouch->irq, udev,
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
usbtouch->data, type->rept_size,
usbtouch_irq, usbtouch, endpoint->bInterval);
+ else
+ usb_fill_bulk_urb(usbtouch->irq, udev,
+ usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
+ usbtouch->data, type->rept_size,
+ usbtouch_irq, usbtouch);

usbtouch->irq->dev = udev;
usbtouch->irq->transfer_dma = usbtouch->data_dma;


--
Ondrej Zary
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
From: Alan Stern on
On Fri, 11 Dec 2009, Ondrej Zary wrote:

> On Thursday 10 December 2009, Alan Stern wrote:
> > On Thu, 10 Dec 2009, Ondrej Zary wrote:
> > > Narrowed down the code to this 170-line module which reproduces my
> > > "rmmod usbtouchscreen" problem. Loading this module causes EHCI to fail.
> > > Looks like it fails after calling usb_kill_urb(). Can a buggy device
> > > cause this?
> >
> > I don't think so. But I am getting an idea of what the problem might
> > be. Try applying the patch below and see if it makes any difference
> > (make sure that CONFIG_USB_DEBUG is enabled).
>
> Thank you very much for the patch. It seems to finally solve this long
> thread!

Great!

> I'm running 2.6.32 now (with usbtouchscreen copied from -next) so one hunk
> had to be applied manually. With patch applied and CONFIG_USB_DEBUG enabled,
> usbtouchscreen stopped working - the urb failed to submit. Return value of
> usb_submit_urb() was not checked (and it wasn't my code this time :) Adding
> a check revealed that the urb fails to submit with -EPIPE because of
> endpoint vs. pipe mismatch.
>
> Fixing that (see the patch below) solved the rmmod problem!

> --- linux-2.6.32/drivers/input/touchscreen/usbtouchscreen.5 2009-12-11 12:50:35.000000000 +0100
> +++ linux-2.6.32/drivers/input/touchscreen/usbtouchscreen.c 2009-12-11 20:15:51.000000000 +0100
> @@ -1375,10 +1375,16 @@
> input_set_abs_params(input_dev, ABS_PRESSURE, type->min_press,
> type->max_press, 0, 0);
>
> - usb_fill_int_urb(usbtouch->irq, udev,
> + if (usb_endpoint_type(endpoint) == USB_ENDPOINT_XFER_INT)
> + usb_fill_int_urb(usbtouch->irq, udev,
> usb_rcvintpipe(udev, endpoint->bEndpointAddress),
> usbtouch->data, type->rept_size,
> usbtouch_irq, usbtouch, endpoint->bInterval);
> + else
> + usb_fill_bulk_urb(usbtouch->irq, udev,
> + usb_rcvbulkpipe(udev, endpoint->bEndpointAddress),
> + usbtouch->data, type->rept_size,
> + usbtouch_irq, usbtouch);
>
> usbtouch->irq->dev = udev;
> usbtouch->irq->transfer_dma = usbtouch->data_dma;

Okay. I'll submit my patch. Since it's not a bug fix, it won't go
into the current release or the stable trees, but it should appear in
2.6.33. You should submit your fix to the appropriate maintainer.

This was a tricky problem; I'm glad we finally found the underlying
cause.

Alan Stern

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo(a)vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/