Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

PROBLEM: USB ACM device does not work

255 views
Skip to first unread message

Arseniy Lartsev

unread,
Jun 28, 2009, 3:30:13 PM6/28/09
to
I've got a piece of hardware (this one:
http://masterkit.ru/main/set.php?num=1153) which acts like an USB ACM
device and is handeled by the cdc_acm module. /dev/ttyACM0 does appear
but any attempt to write something to the device with a simple
"echo something >/dev/ttyACM0" fails with "Invalid argument" error.

The reason is that the driver calls usb_submit_urb in acm_start_wb()
but doesn't set interval in the urb structure, so it remains zero and
causes usb_submit_urb to return -EINVAL. Reading from device also does
not work due to the same problem in acm_rx_tasklet().

After setting urb interval to 128, this particular device works fine
for me (though I'm not sure that it's a right solution in general).

Corresponding patch (against 2.6.30) is:

--- linux-2.6.30.orig/drivers/usb/class/cdc-acm.c
+++ linux-2.6.30/drivers/usb/class/cdc-acm.c
@@ -182,6 +182,7 @@ static int acm_start_wb(struct acm *acm,
wb->urb->transfer_dma = wb->dmah;
wb->urb->transfer_buffer_length = wb->len;
wb->urb->dev = acm->dev;
+ wb->urb->interval = 128;

if ((rc = usb_submit_urb(wb->urb, GFP_ATOMIC)) < 0) {
dbg("usb_submit_urb(write bulk) failed: %d", rc);
@@ -453,6 +454,7 @@ urbs:
acm_read_bulk, rcv);
rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ rcv->urb->interval = 128;

/* This shouldn't kill the driver as unsuccessful URBs are returned to the
free-urbs-pool and resubmited ASAP */

signature.asc

Oliver Neukum

unread,
Jun 28, 2009, 4:30:16 PM6/28/09
to
Am Sonntag, 28. Juni 2009 20:29:26 schrieb Arseniy Lartsev:
> I've got a piece of hardware (this one:
> http://masterkit.ru/main/set.php?num=1153) which acts like an USB ACM
> device and is handeled by the cdc_acm module. /dev/ttyACM0 does appear
> but any attempt to write something to the device with a simple
> "echo something >/dev/ttyACM0" fails with "Invalid argument" error.
>
> The reason is that the driver calls usb_submit_urb in acm_start_wb()
> but doesn't set interval in the urb structure, so it remains zero and
> causes usb_submit_urb to return -EINVAL. Reading from device also does
> not work due to the same problem in acm_rx_tasklet().

This is supposed to write to bulk endpoints. There's no reason interval
would need to be specified. Something is very odd. Please post "lsusb -v".

Regards
Oliver

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

Arseniy Lartsev

unread,
Jun 28, 2009, 4:40:10 PM6/28/09
to
On Monday 29 June 2009 00:20:49 Oliver Neukum wrote:
> This is supposed to write to bulk endpoints. There's no reason interval
> would need to be specified. Something is very odd. Please post "lsusb -v".

lsusb output follows. The device in question comes first.

Bus 002 Device 005: ID 16c0:05e1 VOTI
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 2 Communications
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x16c0 VOTI
idProduct 0x05e1
bcdDevice 2.00
iManufacturer 1 PROTTOSS
iProduct 2 AVR910 USB Programmer
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 67
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 2 Communications
bInterfaceSubClass 2 Abstract (modem)
bInterfaceProtocol 1 AT-commands (v.25ter)
iInterface 0
CDC Header:
bcdCDC 1.10
CDC ACM:
bmCapabilities 0x02
line coding and serial state
CDC Union:
bMasterInterface 0
bSlaveInterface 1
CDC Call Management:
bmCapabilities 0x03
call management
use DataInterface
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 100
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 0x0008 1x 8 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 0
Device Status: 0x0000
(Bus Powered)

Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 9 Hub
bDeviceSubClass 0 Unused
bDeviceProtocol 0 Full speed (or root) hub
bMaxPacketSize0 64
idVendor 0x1d6b Linux Foundation
idProduct 0x0001 1.1 root hub
bcdDevice 2.06
iManufacturer 3 Linux 2.6.27.23-0.1-default ohci_hcd
iProduct 2 OHCI Host Controller
iSerial 1 0000:00:03.1
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 25
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0 Full speed (or root) hub
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0002 1x 2 bytes
bInterval 255
Hub Descriptor:
bLength 9
bDescriptorType 41
nNbrPorts 3
wHubCharacteristic 0x0002
No power switching (usb 1.0)
Ganged overcurrent protection
bPwrOn2PwrGood 0 * 2 milli seconds
bHubContrCurrent 0 milli Ampere
DeviceRemovable 0x00
PortPwrCtrlMask 0xff
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0100 power
Port 3: 0000.0100 power
Device Status: 0x0003
Self Powered
Remote Wakeup Enabled

Bus 002 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 9 Hub
bDeviceSubClass 0 Unused
bDeviceProtocol 0 Full speed (or root) hub
bMaxPacketSize0 64
idVendor 0x1d6b Linux Foundation
idProduct 0x0001 1.1 root hub
bcdDevice 2.06
iManufacturer 3 Linux 2.6.27.23-0.1-default ohci_hcd
iProduct 2 OHCI Host Controller
iSerial 1 0000:00:03.0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 25
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0 Full speed (or root) hub
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0002 1x 2 bytes
bInterval 255
Hub Descriptor:
bLength 9
bDescriptorType 41
nNbrPorts 3
wHubCharacteristic 0x0002
No power switching (usb 1.0)
Ganged overcurrent protection
bPwrOn2PwrGood 3 * 2 milli seconds
bHubContrCurrent 0 milli Ampere
DeviceRemovable 0x00
PortPwrCtrlMask 0xff
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0300 lowspeed power
Port 3: 0000.0303 lowspeed power enable connect
Device Status: 0x0003
Self Powered
Remote Wakeup Enabled

Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 9 Hub
bDeviceSubClass 0 Unused
bDeviceProtocol 0 Full speed (or root) hub
bMaxPacketSize0 64
idVendor 0x1d6b Linux Foundation
idProduct 0x0002 2.0 root hub
bcdDevice 2.06
iManufacturer 3 Linux 2.6.27.23-0.1-default ehci_hcd
iProduct 2 EHCI Host Controller
iSerial 1 0000:00:03.3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 25
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xe0
Self Powered
Remote Wakeup
MaxPower 0mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 9 Hub
bInterfaceSubClass 0 Unused
bInterfaceProtocol 0 Full speed (or root) hub
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0004 1x 4 bytes
bInterval 12
Hub Descriptor:
bLength 9
bDescriptorType 41
nNbrPorts 6
wHubCharacteristic 0x000a
No power switching (usb 1.0)
Per-port overcurrent protection
bPwrOn2PwrGood 10 * 2 milli seconds
bHubContrCurrent 0 milli Ampere
DeviceRemovable 0x00
PortPwrCtrlMask 0xff
Hub Port Status:
Port 1: 0000.0100 power
Port 2: 0000.0100 power
Port 3: 0000.0100 power
Port 4: 0000.0100 power
Port 5: 0000.0100 power
Port 6: 0000.0100 power
Device Status: 0x0003
Self Powered
Remote Wakeup Enabled

signature.asc

Oliver Neukum

unread,
Jun 28, 2009, 5:00:12 PM6/28/09
to
Am Sonntag, 28. Juni 2009 20:29:26 schrieb Arseniy Lartsev:
> The reason is that the driver calls usb_submit_urb in acm_start_wb()
> but doesn't set interval in the urb structure, so it remains zero and
> causes usb_submit_urb to return -EINVAL. Reading from device also does

That simply does not make sense. Have you confirmed that this check:

switch (xfertype) {
case USB_ENDPOINT_XFER_ISOC:
case USB_ENDPOINT_XFER_INT:
/* too small? */
if (urb->interval <= 0)
return -EINVAL;

really triggers?

Arseniy Lartsev

unread,
Jun 29, 2009, 7:50:15 AM6/29/09
to
Just the same with 2.6.31-rc1-git3.

Any ideas?

signature.asc

Oliver Neukum

unread,
Jun 29, 2009, 9:10:10 AM6/29/09
to
Am Montag, 29. Juni 2009 13:43:45 schrieb Arseniy Lartsev:
> Just the same with 2.6.31-rc1-git3.
>
> Any ideas?

Please printk xfertype in the error case of usb_submit_urb()

Arseniy Lartsev

unread,
Jun 29, 2009, 9:40:07 AM6/29/09
to
On Monday 29 June 2009 17:07:44 Oliver Neukum wrote:
> Please printk xfertype in the error case of usb_submit_urb()
It equals USB_ENDPOINT_XFER_INT.
signature.asc

Oliver Neukum

unread,
Jun 30, 2009, 3:30:15 AM6/30/09
to

Yet, your device shows bulk endpoints. Please enable DEBUG in cdc-acm.c
and recompile with CONFIG_USB_DEBUG.

Arseniy Lartsev

unread,
Jun 30, 2009, 4:20:09 PM6/30/09
to
On Tuesday 30 June 2009 11:22:04 Oliver Neukum wrote:
> Yet, your device shows bulk endpoints. Please enable DEBUG in cdc-acm.c
> and recompile with CONFIG_USB_DEBUG.

I've recompiled four modules usbcore, ehci_hcd, ohci_hcd and cdc-acm with -DDEBUG.
Here is kernel log:

======================== Device plugged in ========================
Jun 30 23:58:34 noteb00k kernel: usb usb1: usb resume
Jun 30 23:58:34 noteb00k kernel: ehci_hcd 0000:00:03.3: resume root hub
Jun 30 23:58:35 noteb00k kernel: ehci_hcd 0000:00:03.3: port 5 low speed --> companion
Jun 30 23:58:35 noteb00k kernel: ehci_hcd 0000:00:03.3: GetStatus port 5 status 003002 POWER OWNER sig=se0 CSC
Jun 30 23:58:35 noteb00k kernel: hub 1-0:1.0: hub_resume
Jun 30 23:58:35 noteb00k kernel: usb usb2: usb resume
Jun 30 23:58:35 noteb00k kernel: hub 1-0:1.0: state 7 ports 6 chg 0000 evt 0000
Jun 30 23:58:35 noteb00k kernel: ohci_hcd 0000:00:03.0: wakeup root hub
Jun 30 23:58:35 noteb00k kernel: hub 2-0:1.0: hub_resume
Jun 30 23:58:35 noteb00k kernel: ohci_hcd 0000:00:03.0: GetStatus roothub.portstatus [2] = 0x00010301 CSC LSDA PPS
CCS
Jun 30 23:58:35 noteb00k kernel: hub 2-0:1.0: port 3: status 0301 change 0001
Jun 30 23:58:35 noteb00k kernel: hub 2-0:1.0: state 7 ports 3 chg 0008 evt 0000
Jun 30 23:58:35 noteb00k kernel: hub 2-0:1.0: port 3, status 0301, change 0000, 1.5 Mb/s
Jun 30 23:58:35 noteb00k kernel: ohci_hcd 0000:00:03.0: GetStatus roothub.portstatus [2] = 0x00100303 PRSC LSDA PPS
PES CCS
Jun 30 23:58:35 noteb00k kernel: usb 2-3: new low speed USB device using ohci_hcd and address 5
Jun 30 23:58:35 noteb00k kernel: ohci_hcd 0000:00:03.0: GetStatus roothub.portstatus [2] = 0x00100303 PRSC LSDA PPS
PES CCS
Jun 30 23:58:35 noteb00k kernel: usb 2-3: skipped 4 descriptors after interface
Jun 30 23:58:35 noteb00k kernel: usb 2-3: config 1 interface 1 altsetting 0 endpoint 0x1 is Bulk; changing to
Interrupt
Jun 30 23:58:35 noteb00k kernel: usb 2-3: config 1 interface 1 altsetting 0 endpoint 0x81 is Bulk; changing to
Interrupt
Jun 30 23:58:35 noteb00k kernel: usb 2-3: default language 0x0409
Jun 30 23:58:35 noteb00k kernel: usb 2-3: udev 5, busnum 2, minor = 132
Jun 30 23:58:35 noteb00k kernel: usb 2-3: New USB device found, idVendor=16c0, idProduct=05e1
Jun 30 23:58:35 noteb00k kernel: usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=0
Jun 30 23:58:35 noteb00k kernel: usb 2-3: Product: AVR910 USB Programmer
Jun 30 23:58:35 noteb00k kernel: usb 2-3: Manufacturer: PROTTOSS
Jun 30 23:58:35 noteb00k kernel: usb 2-3: uevent
Jun 30 23:58:35 noteb00k kernel: usb 2-3: usb_probe_device
Jun 30 23:58:35 noteb00k kernel: usb 2-3: configuration #1 chosen from 1 choice
Jun 30 23:58:35 noteb00k kernel: usb 2-3: adding 2-3:1.0 (config #1, interface 0)
Jun 30 23:58:35 noteb00k kernel: usb 2-3:1.0: uevent
Jun 30 23:58:35 noteb00k kernel: cdc_acm 2-3:1.0: usb_probe_interface
Jun 30 23:58:35 noteb00k kernel: cdc_acm 2-3:1.0: usb_probe_interface - got id
Jun 30 23:58:35 noteb00k kernel: cdc_acm 2-3:1.0: The data interface has switched endpoints
Jun 30 23:58:35 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: interfaces are valid
Jun 30 23:58:35 noteb00k kernel: cdc_acm 2-3:1.0: ttyACM0: USB ACM device
Jun 30 23:58:35 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0
result: 0
Jun 30 23:58:35 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x20 val: 0x0 len: 0x7
result: 7
Jun 30 23:58:35 noteb00k kernel: usb 2-3: adding 2-3:1.1 (config #1, interface 1)
Jun 30 23:58:35 noteb00k kernel: usb 2-3:1.1: uevent
Jun 30 23:58:35 noteb00k kernel: hub 2-0:1.0: state 7 ports 3 chg 0000 evt 0008
Jun 30 23:58:38 noteb00k kernel: hub 1-0:1.0: hub_suspend
Jun 30 23:58:38 noteb00k kernel: usb usb1: bus auto-suspend
Jun 30 23:58:38 noteb00k kernel: ehci_hcd 0000:00:03.3: suspend root hub

======================== echo -n S >/dev/ttyACM0 ========================
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering acm_tty_open.
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x3 len: 0x0
result: 0
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering acm_tty_write to write 1 bytes,
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Get 1 bytes...
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_write_start susp_count: 0
Jun 30 23:58:44 noteb00k kernel: usb_sumbit_urb: failing due to non-positive interval //
Jun 30 23:58:44 noteb00k kernel: usb_submit_urb: xfertype = 3 of 1/3 // these were added by me
Jun 30 23:58:44 noteb00k kernel: xfertype is USB_ENDPOINT_XFER_INT //
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: usb_submit_urb(write bulk) failed: -22
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering acm_rx_tasklet
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_rx_tasklet: ACM not ready
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0
result: 0
Jun 30 23:58:44 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_ctrl_irq - urb shutting down with
status: -2

======================== cat /dev/ttyACM0 ========================
Jun 30 23:58:54 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering acm_tty_open.
Jun 30 23:58:54 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x3 len: 0x0
result: 0
Jun 30 23:58:54 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering acm_rx_tasklet
Jun 30 23:58:54 noteb00k kernel: usb_sumbit_urb: failing due to non-positive interval
Jun 30 23:58:54 noteb00k kernel: usb_submit_urb: xfertype = 3 of 1/3
Jun 30 23:58:54 noteb00k kernel: xfertype is USB_ENDPOINT_XFER_INT
Jun 30 23:58:54 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: input control lines: dcd- dsr- break- ring-
framing- parity- overrun-
Jun 30 23:58:54 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: disconnected from network

======================== Terminate cat with Ctrl+C ========================
Jun 30 23:58:58 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_control_msg: rq: 0x22 val: 0x0 len: 0x0
result: 0
Jun 30 23:58:58 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: acm_ctrl_irq - urb shutting down with
status:-2

======================== Device unplugged ========================
Jun 30 23:59:08 noteb00k kernel: hub 2-0:1.0: state 7 ports 3 chg 0000 evt 0008
Jun 30 23:59:08 noteb00k kernel: ohci_hcd 0000:00:03.0: GetStatus roothub.portstatus [2] = 0x00030300 PESC CSC LSDA
PPS
Jun 30 23:59:08 noteb00k kernel: hub 2-0:1.0: port 3, status 0300, change 0003, 1.5 Mb/s
Jun 30 23:59:08 noteb00k kernel: usb 2-3: USB disconnect, address 5
Jun 30 23:59:08 noteb00k kernel: usb 2-3: unregistering device
Jun 30 23:59:08 noteb00k kernel: usb 2-3: usb_disable_device nuking all URBs
Jun 30 23:59:08 noteb00k kernel: usb 2-3: unregistering interface 2-3:1.0
Jun 30 23:59:08 noteb00k kernel: /w/work/lesh/research/driver/cdc-acm.c: Entering stop_data_traffic
Jun 30 23:59:08 noteb00k kernel: usb 2-3:1.0: uevent
Jun 30 23:59:08 noteb00k kernel: usb 2-3: unregistering interface 2-3:1.1
Jun 30 23:59:08 noteb00k kernel: usb 2-3:1.1: uevent
Jun 30 23:59:08 noteb00k kernel: usb 2-3: uevent
Jun 30 23:59:08 noteb00k kernel: hub 2-0:1.0: debounce: port 3: total 100ms stable 100ms status 0x300
Jun 30 23:59:09 noteb00k kernel: ohci_hcd 0000:00:03.0: auto-stop root hub
Jun 30 23:59:11 noteb00k kernel: hub 2-0:1.0: hub_suspend
Jun 30 23:59:11 noteb00k kernel: usb usb2: bus auto-suspend
Jun 30 23:59:11 noteb00k kernel: ohci_hcd 0000:00:03.0: suspend root hub

signature.asc

Alan Stern

unread,
Jun 30, 2009, 5:10:09 PM6/30/09
to
On Wed, 1 Jul 2009, Arseniy Lartsev wrote:

> On Tuesday 30 June 2009 11:22:04 Oliver Neukum wrote:
> > Yet, your device shows bulk endpoints. Please enable DEBUG in cdc-acm.c
> > and recompile with CONFIG_USB_DEBUG.
>
> I've recompiled four modules usbcore, ehci_hcd, ohci_hcd and cdc-acm with -DDEBUG.
> Here is kernel log:
>
> ======================== Device plugged in ========================

...


> Jun 30 23:58:35 noteb00k kernel: usb 2-3: new low speed USB device using ohci_hcd and address 5

...


> Jun 30 23:58:35 noteb00k kernel: usb 2-3: config 1 interface 1 altsetting 0 endpoint 0x1 is Bulk; changing to
> Interrupt
> Jun 30 23:58:35 noteb00k kernel: usb 2-3: config 1 interface 1 altsetting 0 endpoint 0x81 is Bulk; changing to
> Interrupt

This looks like your problem. Low-speed devices are not allowed to
have bulk endpoints. Linux internally changes them to interrupt
endpoints with interval = 1 and maxpacket size no larger than 8.

Alan Stern

Arseniy Lartsev

unread,
Jul 1, 2009, 5:10:16 AM7/1/09
to
On Wednesday 01 July 2009 01:01:00 Alan Stern wrote:
> This looks like your problem. Low-speed devices are not allowed to
> have bulk endpoints. Linux internally changes them to interrupt
> endpoints with interval = 1 and maxpacket size no larger than 8.

Maybe this device is a little "buggy". But Linux should support buggy devices
as well.

What about something like

--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long
struct acm_ru *rcv;
unsigned long flags;
unsigned char throttled;
+ struct usb_host_endpoint *ep;

dbg("Entering acm_rx_tasklet");

@@ -462,11 +463,20 @@ urbs:

rcv->buffer = buf;

- usb_fill_bulk_urb(rcv->urb, acm->dev,
- acm->rx_endpoint,
- buf->base,
- acm->readsize,
- acm_read_bulk, rcv);
+ ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
+ [usb_pipeendpoint(acm->rx_endpoint)];
+ if (usb_endpoint_xfer_int(&ep->desc))
+ usb_fill_int_urb(rcv->urb, acm->dev,
+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,
+ acm_read_bulk, rcv, 0xff);
+ else
+ usb_fill_bulk_urb(rcv->urb, acm->dev,
+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,
+ acm_read_bulk, rcv);


rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

@@ -1227,9 +1237,14 @@ made_compressed_probe:
goto alloc_fail7;
}

- usb_fill_bulk_urb(snd->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
- NULL, acm->writesize, acm_write_bulk, snd);
+ if (usb_endpoint_xfer_int(epwrite))
+ usb_fill_int_urb(snd->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+ NULL, acm->writesize, acm_write_bulk, snd, 0xff);
+ else
+ usb_fill_bulk_urb(snd->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
+ NULL, acm->writesize, acm_write_bulk, snd);
snd->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
snd->instance = acm;
}

It should work around devices like mine, but should not affect previously
supported devices.

Oliver Neukum

unread,
Jul 1, 2009, 7:00:18 AM7/1/09
to
Am Mittwoch, 1. Juli 2009 11:01:06 schrieb Arseniy Lartsev:
> On Wednesday 01 July 2009 01:01:00 Alan Stern wrote:
> > This looks like your problem. Low-speed devices are not allowed to
> > have bulk endpoints. Linux internally changes them to interrupt
> > endpoints with interval = 1 and maxpacket size no larger than 8.
>
> Maybe this device is a little "buggy". But Linux should support buggy
> devices as well.

Yes, it should. We just needed to understand why it failed.


> + ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
> + [usb_pipeendpoint(acm->rx_endpoint)];
> + if (usb_endpoint_xfer_int(&ep->desc))
> + usb_fill_int_urb(rcv->urb, acm->dev,
> + acm->rx_endpoint,
> + buf->base,
> + acm->readsize,
> + acm_read_bulk, rcv, 0xff);

The patch is good except for this.
We should make sure this interval matches usbcore's value.
Would you care to redo it with that change?

Regards
Oliver

Arseniy Lartsev

unread,
Jul 1, 2009, 7:30:21 AM7/1/09
to
On Wednesday 01 July 2009 14:56:46 Oliver Neukum wrote:
> > + ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in :
> > acm->dev->ep_out) + [usb_pipeendpoint(acm->rx_endpoint)];
> > + if (usb_endpoint_xfer_int(&ep->desc))
> > + usb_fill_int_urb(rcv->urb, acm->dev,
> > + acm->rx_endpoint,
> > + buf->base,
> > + acm->readsize,
> > + acm_read_bulk, rcv, 0xff);
>
> The patch is good except for this.
> We should make sure this interval matches usbcore's value.
> Would you care to redo it with that change?

Am I right that 0xff here should be changed to ep->desc.bInterval (and to
epwrite->bInterval in the other call to usb_fill_int_urb)?

--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long
struct acm_ru *rcv;
unsigned long flags;
unsigned char throttled;
+ struct usb_host_endpoint *ep;

dbg("Entering acm_rx_tasklet");

@@ -462,11 +463,20 @@ urbs:

rcv->buffer = buf;

- usb_fill_bulk_urb(rcv->urb, acm->dev,
- acm->rx_endpoint,
- buf->base,
- acm->readsize,
- acm_read_bulk, rcv);

+ ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
+ [usb_pipeendpoint(acm->rx_endpoint)];
+ if (usb_endpoint_xfer_int(&ep->desc))
+ usb_fill_int_urb(rcv->urb, acm->dev,
+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,

+ acm_read_bulk, rcv, ep->desc.bInterval);
+ else
+ usb_fill_bulk_urb(rcv->urb, acm->dev,


+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,

+ acm_read_bulk, rcv);
rcv->urb->transfer_dma = buf->dma;
rcv->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

@@ -1227,9 +1237,14 @@ made_compressed_probe:
goto alloc_fail7;
}

- usb_fill_bulk_urb(snd->urb, usb_dev,
- usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
- NULL, acm->writesize, acm_write_bulk, snd);
+ if (usb_endpoint_xfer_int(epwrite))
+ usb_fill_int_urb(snd->urb, usb_dev,
+ usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),

+ NULL, acm->writesize, acm_write_bulk, snd, epwrite->bInterval);

signature.asc

Oliver Neukum

unread,
Jul 1, 2009, 7:40:12 AM7/1/09
to
Am Mittwoch, 1. Juli 2009 13:24:55 schrieb Arseniy Lartsev:
> On Wednesday 01 July 2009 14:56:46 Oliver Neukum wrote:
> > > + ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in :
> > > acm->dev->ep_out) + [usb_pipeendpoint(acm->rx_endpoint)];
> > > + if (usb_endpoint_xfer_int(&ep->desc))
> > > + usb_fill_int_urb(rcv->urb, acm->dev,
> > > + acm->rx_endpoint,
> > > + buf->base,
> > > + acm->readsize,
> > > + acm_read_bulk, rcv, 0xff);
> >
> > The patch is good except for this.
> > We should make sure this interval matches usbcore's value.
> > Would you care to redo it with that change?
>
> Am I right that 0xff here should be changed to ep->desc.bInterval (and to
> epwrite->bInterval in the other call to usb_fill_int_urb)?

Yes, exactly. Please add gr...@kroah.com into CC, add a Signed-off-by line
and resend.

Arseniy Lartsev

unread,
Jul 1, 2009, 8:30:14 AM7/1/09
to
On Wednesday 01 July 2009 15:37:48 Oliver Neukum wrote:
> Yes, exactly. Please add gr...@kroah.com into CC, add a Signed-off-by line
> and resend.
ok

Signed-off-by: Arseniy Lartsev <ars3n at yandex dot ru>


--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long
struct acm_ru *rcv;
unsigned long flags;
unsigned char throttled;
+ struct usb_host_endpoint *ep;

dbg("Entering acm_rx_tasklet");

@@ -462,11 +463,20 @@ urbs:

rcv->buffer = buf;

- usb_fill_bulk_urb(rcv->urb, acm->dev,
- acm->rx_endpoint,
- buf->base,
- acm->readsize,
- acm_read_bulk, rcv);

+ ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
+ [usb_pipeendpoint(acm->rx_endpoint)];
+ if (usb_endpoint_xfer_int(&ep->desc))
+ usb_fill_int_urb(rcv->urb, acm->dev,
+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,

+ acm_read_bulk, rcv, ep->desc.bInterval);
+ else

+ usb_fill_bulk_urb(rcv->urb, acm->dev,


+ acm->rx_endpoint,
+ buf->base,
+ acm->readsize,

signature.asc

Greg KH

unread,
Jul 1, 2009, 10:00:16 AM7/1/09
to
On Wed, Jul 01, 2009 at 04:27:26PM +0400, Arseniy Lartsev wrote:
> On Wednesday 01 July 2009 15:37:48 Oliver Neukum wrote:
> > Yes, exactly. Please add gr...@kroah.com into CC, add a Signed-off-by line
> > and resend.
> ok
>
> Signed-off-by: Arseniy Lartsev <ars3n at yandex dot ru>

Real email address please, no "at" or "dot", it messes up our scripts.

And what does this patch do? I need some text for the changelog.

thanks,

greg k-h

Oliver Neukum

unread,
Jul 1, 2009, 10:10:13 AM7/1/09
to
Am Mittwoch, 1. Juli 2009 15:56:49 schrieb Greg KH:
> On Wed, Jul 01, 2009 at 04:27:26PM +0400, Arseniy Lartsev wrote:
> > On Wednesday 01 July 2009 15:37:48 Oliver Neukum wrote:
> > > Yes, exactly. Please add gr...@kroah.com into CC, add a Signed-off-by
> > > line and resend.
> >
> > ok
> >
> > Signed-off-by: Arseniy Lartsev <ars3n at yandex dot ru>
>
> Real email address please, no "at" or "dot", it messes up our scripts.
>
> And what does this patch do? I need some text for the changelog.

This patch introduces a work around for cdc-acm devices which are
low speed contrary to the specification, which requires bulk endpoints
which are banned in low speed and converted by usbcore to virtual
interrupt endpoints if they are used nevertheless.

Regards
Oliver

Alan Stern

unread,
Jul 1, 2009, 10:40:12 AM7/1/09
to
On Wed, 1 Jul 2009, Arseniy Lartsev wrote:

> On Wednesday 01 July 2009 15:37:48 Oliver Neukum wrote:
> > Yes, exactly. Please add gr...@kroah.com into CC, add a Signed-off-by line
> > and resend.
> ok
>
> Signed-off-by: Arseniy Lartsev <ars3n at yandex dot ru>
> --- a/drivers/usb/class/cdc-acm.c
> +++ b/drivers/usb/class/cdc-acm.c
> @@ -387,6 +387,7 @@ static void acm_rx_tasklet(unsigned long
> struct acm_ru *rcv;
> unsigned long flags;
> unsigned char throttled;
> + struct usb_host_endpoint *ep;
>
> dbg("Entering acm_rx_tasklet");
>
> @@ -462,11 +463,20 @@ urbs:
>
> rcv->buffer = buf;
>
> - usb_fill_bulk_urb(rcv->urb, acm->dev,
> - acm->rx_endpoint,
> - buf->base,
> - acm->readsize,
> - acm_read_bulk, rcv);
> + ep = (usb_pipein(acm->rx_endpoint) ? acm->dev->ep_in : acm->dev->ep_out)
> + [usb_pipeendpoint(acm->rx_endpoint)];

Isn't acm->rx_endpoint always going to be IN?

Alan Stern

0 new messages