butrus.butrus wrote:Also, isn't the usb-midi interface using BULK transfers?
Yes, it's true, but newer kernels change low-speed bulk transfer automagically to int transfers to save bandwidth (and AVR cycles).
butrus.butrus wrote:Could You tell us, what is the kernel patch used for?
The patches below (extracted from kernel version 2.6.24.3) do this bulk->int change and let the kernel recognize low-speed midi devices, the old 2.6.22.1-rt9 kernel said: "unknown device speed".
If you're using a new kernel >=2.6.23 there is no need for this patch. But I use the older 2.6.22.1-rt9 kernel because it works much better with my old laptop and jack, with newer ones I get xruns.
The patch consists of two parts: one for /usr/src/linux/drivers/usb/core/config.c:
Code: Select all
--- config.c 2007-07-10 20:56:30.000000000 +0200
+++ config.c.2.6.24.3 2008-01-24 23:58:37.000000000 +0100
@@ -124,6 +130,21 @@
endpoint->desc.bInterval = n;
}
+ /* 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.
+ */
+ if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
+ usb_endpoint_xfer_bulk(d)) {
+ 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);
+ }
+
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
the second one for /usr/src/linux/sound/usb/usbaudio.c and .../usbmidi.c:
Code: Select all
--- usbaudio.c 2007-07-10 20:56:30.000000000 +0200
+++ usbaudio.c.2.6.24.3 2008-01-24 23:58:37.000000000 +0100
@@ -3381,7 +3390,8 @@
*rchip = NULL;
- if (snd_usb_get_speed(dev) != USB_SPEED_FULL &&
+ if (snd_usb_get_speed(dev) != USB_SPEED_LOW &&
+ snd_usb_get_speed(dev) != USB_SPEED_FULL &&
snd_usb_get_speed(dev) != USB_SPEED_HIGH) {
snd_printk(KERN_ERR "unknown device speed %d\n", snd_usb_get_speed(dev));
return -ENXIO;
@@ -3455,7 +3465,9 @@
usb_make_path(dev, card->longname + len, sizeof(card->longname) - len);
strlcat(card->longname,
- snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" : ", high speed",
+ snd_usb_get_speed(dev) == USB_SPEED_LOW ? ", low speed" :
+ snd_usb_get_speed(dev) == USB_SPEED_FULL ? ", full speed" :
+ ", high speed",
sizeof(card->longname));
snd_usb_audio_create_proc(chip);
--- linux-2.6.22.1-rt9/sound/usb/usbmidi.c 2007-07-10 20:56:30.000000000 +0200
+++ linux-2.6.24.3-rt3/sound/usb/usbmidi.c 2008-01-24 23:58:37.000000000 +0100
@@ -963,8 +983,10 @@
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
}
- /* we never use interrupt output pipes */
- pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
+ if (ep_info->out_interval)
+ pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep);
+ else
+ pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep);
if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */
/* FIXME: we need more URBs to get reasonable bandwidth here: */
ep->max_transfer = 4;
@@ -976,8 +998,14 @@
snd_usbmidi_out_endpoint_delete(ep);
return -ENOMEM;
}
- usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer,
- ep->max_transfer, snd_usbmidi_out_urb_complete, ep);
+ if (ep_info->out_interval)
+ usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer,
+ ep->max_transfer, snd_usbmidi_out_urb_complete,
+ ep, ep_info->out_interval);
+ else
+ usb_fill_bulk_urb(ep->urb, umidi->chip->dev,
+ pipe, buffer, ep->max_transfer,
+ snd_usbmidi_out_urb_complete, ep);
ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
spin_lock_init(&ep->buffer_lock);
@@ -1323,6 +1351,13 @@
endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
endpoints[epidx].out_interval = ep->bInterval;
+ else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
+ /*
+ * Low speed bulk transfers don't exist, so
+ * force interrupt transfers for devices like
+ * ESI MIDI Mate that try to use them anyway.
+ */
+ endpoints[epidx].out_interval = 1;
endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
@@ -1336,6 +1371,8 @@
endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
endpoints[epidx].in_interval = ep->bInterval;
+ else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW)
+ endpoints[epidx].in_interval = 1;
endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n",
ep->bEndpointAddress, ms_ep->bNumEmbMIDIJack);
I hadn't much time for this project the last weeks - so there isn't much to see until now. I'll try to set up a webpage with schematics and a (sample) source code this weekend.
Ciao Martin