Hello Christian, floe, Guest et al.
After several weeks i investigated the AVR-CDC problem in conjunction
with the linux kernel again. I think there is no good news but i have to
admit again that i don't have any clue of all this usb stuff.
So everything i write is a suggestion. But since there are no better
explanations i think it's justified and i try to abstract my cognitions.
Several times was noticed that CDC does not work with low-speed USB
transfer according to the USB spec. I'm not sure whether this is true
directly.
As far as i have seen there are no bulk-endpoints in the spec for
low-speed USB devices but CDC expects bulk-endpoints according to
the spec. This leads indeed into the situation that CDC should not
work on low-speed USB.
The linux kernel reflects this exactly. However in a few steps:
Up to Kernel Version 2.6.23 there was a small code snippet in
drivers/usb/host/uhci-q.c:
Code: Select all
if (urb->dev->speed == USB_SPEED_LOW)
return -EINVAL;
it is executed for bulk endpoints and therefore they are
ignored at low speed.
Since this is at quite low-level in the uhci code it leads to the
interesting situation that the AVR-CDC Device works nevertheless if
connected to an High-Speed USB2.0 Hub. Because on Host side it is
handled by ehci driver then and the code above will never be executed.
It's easy to use the already mentioned patch for
"drivers/usb/host/uhci-q.c":
Code: Select all
1045,1046c1045,1046
< if (urb->dev->speed == USB_SPEED_LOW)
< return -EINVAL;
---
> // if (urb->dev->speed == USB_SPEED_LOW)
> // return -EINVAL;
Then AVR-CDC works even on direct connected USB Ports using uhci.
Unfortunately with Kernel 2.6.24 there appeared a more generic
solution for the low-speed bulk endpoints in drivers/usb/core/config.c.
It's commented like this:
Code: Select all
/* Some buggy low-speed devices have Bulk endpoints, which is
* explicitly forbidden by the USB spec. In an attempt to make
* them usable, we will try treating them as Interrupt endpoints.
*/
It leads to the following Kernel messages if i plug in my AVR-CDC:
Code: Select all
usb 3-4.7: USB disconnect, address 41
usb 3-4.7: new low speed USB device using ehci_hcd and address 42
usb 3-4.7: config 1 interface 1 altsetting 0 endpoint 0x1 is Bulk; changing to Interrupt
usb 3-4.7: config 1 interface 1 altsetting 0 endpoint 0x81 is Bulk; changing to Interrupt
usb 3-4.7: configuration #1 chosen from 1 choice
cdc_acm 3-4.7:1.0: ttyACM0: USB ACM device
This is bad for AVR-CDC because it does not support interrupt
endpoints. At first i wondered if this would be necessarry at all
because the kernel changes the endpoint from bulk to interrupt already.
Christian mentioned that there is not much difference between bulk and
interrupt endpoints too. Somebody else suggested an adjustment in
AVR-CDC.
So i simply changed the endpoint in the AVR-CDC Code from bulk to
interrupt. The kernel warning disappeared but it still doesn't work.
Then i discovered that there is a generic serial usb driver in the
kernel tree which is derived from the cdc_acm module and i thought it
should work with AVR-CDC too. With the interrupt endpoint enabled
AVR-CDC device the kernel says this:
Code: Select all
usbcore: registered new interface driver usbserial
drivers/usb/serial/usb-serial.c: USB Serial support registered for generic
usbserial_generic 3-4.7:1.0: Generic device with no bulk out, not allowed.
usbserial_generic: probe of 3-4.7:1.0 failed with error -5
usbserial_generic 3-4.7:1.1: Generic device with no bulk out, not allowed.
usbserial_generic: probe of 3-4.7:1.1 failed with error -5
usbcore: registered new interface driver usbserial_generic
drivers/usb/serial/usb-serial.c: USB Serial Driver core
After having a look at usb-serial.c and cdc-acm.c i found that the
driver insists on bulk endpoints but don't get it because the kernel
changed them to interrupt endpoints before or interrupt endpoints are
already introduced by my changed AVR-CDC firmware.
All this conforms very well with the USB specification and therefore
doesn't work.
So i think there is no chance to get the AVR-CDC device with
an unpatched linux kernel newer than 2.4.23 running. And i don't think
that this could ever be fixed by the AVR-CDC firmware since it is a
problem as a matter of principle.
Maybe the most reasonable solution would be to write a driver or a
fixed version of the cdc_acm or usbserial_generic module which can deal
with interrupt endpoints.
But the easiest way is to patch "drivers/usb/core/config.c"
like this:
Code: Select all
139,145c139,149
< dev_warn(ddev, "config %d interface %d altsetting %d "
< "endpoint 0x%X is Bulk; changing to Interrupt\n",
< cfgno, inum, asnum, d->bEndpointAddress);
< endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
< endpoint->desc.bInterval = 1;
< if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
< endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
---
> dev_warn(ddev, "config %d interface %d altsetting %d "
> "endpoint 0x%X is Bulk; this violates USB spec for "
> "low speed devices.\n",
> cfgno, inum, asnum, d->bEndpointAddress);
> // dev_warn(ddev, "config %d interface %d altsetting %d "
> // "endpoint 0x%X is Bulk; changing to Interrupt\n",
> // cfgno, inum, asnum, d->bEndpointAddress);
> // endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
> // endpoint->desc.bInterval = 1;
> // if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
> // endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
I have posted this already in the forum a few weeks ago. But i assume
in most situations both patches are necessary.
It would be very nice if one of the usb experts would write a short
comment whether my ideas could be true.
And sorry for my weak english!
Kind regards,
Klaus