Colin Fletcher wrote:
> I'll be very glad to test any clever patches, though...
If you don't want to wait for the public SourceForge CVS ...
--- alsa-kernel/usb/usbmidi.c 25 Jul 2005 15:17:40 -0000 1.51
+++ alsa-kernel/usb/usbmidi.c 2 Aug 2005 14:26:52 -0000 1.52
@@ -44,6 +44,7 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/slab.h>
+#include <linux/timer.h>
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/minors.h>
@@ -56,6 +57,12 @@
*/
/* #define DUMP_PACKETS */
+/*
+ * how long to wait after some USB errors, so that khubd can disconnect() us
+ * without too many spurious errors
+ */
+#define ERROR_DELAY_JIFFIES (HZ / 10)
+
MODULE_AUTHOR("Clemens Ladisch <[EMAIL PROTECTED]>");
MODULE_DESCRIPTION("USB Audio/MIDI helper module");
@@ -100,6 +107,7 @@
snd_rawmidi_t* rmidi;
struct usb_protocol_ops* usb_protocol_ops;
struct list_head list;
+ struct timer_list error_timer;
struct snd_usb_midi_endpoint {
snd_usb_midi_out_endpoint_t *out;
@@ -141,7 +149,8 @@
struct usbmidi_in_port {
snd_rawmidi_substream_t* substream;
} ports[0x10];
- int seen_f5;
+ u8 seen_f5;
+ u8 error_resubmit;
int current_port;
};
@@ -167,14 +176,22 @@
*/
static int snd_usbmidi_urb_error(int status)
{
- if (status == -ENOENT)
- return status; /* killed */
- if (status == -EILSEQ ||
- status == -ECONNRESET ||
- status == -ETIMEDOUT)
- return -ENODEV; /* device removed/shutdown */
- snd_printk(KERN_ERR "urb status %d\n", status);
- return 0; /* continue */
+ switch (status) {
+ /* manually unlinked, or device gone */
+ case -ENOENT:
+ case -ECONNRESET:
+ case -ESHUTDOWN:
+ case -ENODEV:
+ return -ENODEV;
+ /* errors that might occur during unplugging */
+ case -EPROTO: /* EHCI */
+ case -ETIMEDOUT: /* OHCI */
+ case -EILSEQ: /* UHCI */
+ return -EIO;
+ default:
+ snd_printk(KERN_ERR "urb status %d\n", status);
+ return 0; /* continue */
+ }
}
/*
@@ -218,8 +235,15 @@
ep->umidi->usb_protocol_ops->input(ep, urb->transfer_buffer,
urb->actual_length);
} else {
- if (snd_usbmidi_urb_error(urb->status) < 0)
+ int err = snd_usbmidi_urb_error(urb->status);
+ if (err < 0) {
+ if (err != -ENODEV) {
+ ep->error_resubmit = 1;
+ mod_timer(&ep->umidi->error_timer,
+ jiffies + ERROR_DELAY_JIFFIES);
+ }
return;
+ }
}
if (usb_pipe_needs_resubmit(urb->pipe)) {
@@ -236,8 +260,13 @@
ep->urb_active = 0;
spin_unlock(&ep->buffer_lock);
if (urb->status < 0) {
- if (snd_usbmidi_urb_error(urb->status) < 0)
+ int err = snd_usbmidi_urb_error(urb->status);
+ if (err < 0) {
+ if (err != -ENODEV)
+ mod_timer(&ep->umidi->error_timer,
+ jiffies + ERROR_DELAY_JIFFIES);
return;
+ }
}
snd_usbmidi_do_output(ep);
}
@@ -276,6 +305,24 @@
snd_usbmidi_do_output(ep);
}
+/* called after transfers had been interrupted due to some USB error */
+static void snd_usbmidi_error_timer(unsigned long data)
+{
+ snd_usb_midi_t *umidi = (snd_usb_midi_t *)data;
+ int i;
+
+ for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
+ snd_usb_midi_in_endpoint_t *in = umidi->endpoints[i].in;
+ if (in && in->error_resubmit) {
+ in->error_resubmit = 0;
+ in->urb->dev = umidi->chip->dev;
+ snd_usbmidi_submit_urb(in->urb, GFP_ATOMIC);
+ }
+ if (umidi->endpoints[i].out)
+ snd_usbmidi_do_output(umidi->endpoints[i].out);
+ }
+}
+
/* helper function to send static data that may not DMA-able */
static int send_bulk_static_data(snd_usb_midi_out_endpoint_t* ep,
const void *data, int len)
@@ -832,8 +879,6 @@
*/
static void snd_usbmidi_out_endpoint_delete(snd_usb_midi_out_endpoint_t* ep)
{
- if (ep->tasklet.func)
- tasklet_kill(&ep->tasklet);
if (ep->urb) {
kfree(ep->urb->transfer_buffer);
usb_free_urb(ep->urb);
@@ -918,8 +963,11 @@
int i;
umidi = list_entry(p, snd_usb_midi_t, list);
+ del_timer_sync(&umidi->error_timer);
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
snd_usb_midi_endpoint_t* ep = &umidi->endpoints[i];
+ if (ep->out)
+ tasklet_kill(&ep->out->tasklet);
if (ep->out && ep->out->urb) {
usb_kill_urb(ep->out->urb);
if (umidi->usb_protocol_ops->finish_out_endpoint)
@@ -1480,6 +1528,9 @@
umidi->iface = iface;
umidi->quirk = quirk;
umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
+ init_timer(&umidi->error_timer);
+ umidi->error_timer.function = snd_usbmidi_error_timer;
+ umidi->error_timer.data = (unsigned long)umidi;
/* detect the endpoint(s) to use */
memset(endpoints, 0, sizeof(endpoints));
-------------------------------------------------------
SF.Net email is sponsored by: Discover Easy Linux Migration Strategies
from IBM. Find simple to follow Roadmaps, straightforward articles,
informative Webcasts and more! Get everything you need to get up to
speed, fast. http://ads.osdn.com/?ad_id=7477&alloc_id=16492&op=click
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel