X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fusb%2Fusbmidi.c;h=2c59afd99611b363651d77afe0e0f2ef26be0ebb;hb=3f17522ce461a31e7ced6311b28fcf5b8a763316;hp=905e33e6068120fd234eb31cdfd30e5cf8257e1a;hpb=e03173fce2f2c233b755f2d668d6d4247a717453;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 905e33e..2c59afd 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2005 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -35,7 +35,6 @@ * SUCH DAMAGE. */ -#include #include #include #include @@ -46,8 +45,13 @@ #include #include #include +#include +#include + #include +#include #include +#include #include "usbaudio.h" @@ -62,6 +66,9 @@ */ #define ERROR_DELAY_JIFFIES (HZ / 10) +#define OUTPUT_URBS 7 +#define INPUT_URBS 7 + MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("USB Audio/MIDI helper module"); @@ -90,35 +97,48 @@ struct snd_usb_midi_endpoint; struct usb_protocol_ops { void (*input)(struct snd_usb_midi_in_endpoint*, uint8_t*, int); - void (*output)(struct snd_usb_midi_out_endpoint*); + void (*output)(struct snd_usb_midi_out_endpoint *ep, struct urb *urb); void (*output_packet)(struct urb*, uint8_t, uint8_t, uint8_t, uint8_t); void (*init_out_endpoint)(struct snd_usb_midi_out_endpoint*); void (*finish_out_endpoint)(struct snd_usb_midi_out_endpoint*); }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; struct usb_protocol_ops* usb_protocol_ops; struct list_head list; struct timer_list error_timer; + spinlock_t disc_lock; + struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; + unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; - int urb_active; + struct out_urb_context { + struct urb *urb; + struct snd_usb_midi_out_endpoint *ep; + } urbs[OUTPUT_URBS]; + unsigned int active_urbs; + unsigned int drain_urbs; int max_transfer; /* size of urb buffer */ struct tasklet_struct tasklet; - + unsigned int next_urb; spinlock_t buffer_lock; struct usbmidi_out_port { @@ -137,13 +157,16 @@ struct snd_usb_midi_out_endpoint { uint8_t data[2]; } ports[0x10]; int current_port; + + wait_queue_head_t drain_wait; }; struct snd_usb_midi_in_endpoint { struct snd_usb_midi* umidi; - struct urb* urb; + struct urb* urbs[INPUT_URBS]; struct usbmidi_in_port { struct snd_rawmidi_substream *substream; + u8 running_status_length; } ports[0x10]; u8 seen_f5; u8 error_resubmit; @@ -180,9 +203,9 @@ static int snd_usbmidi_urb_error(int status) case -ENODEV: return -ENODEV; /* errors that might occur during unplugging */ - case -EPROTO: /* EHCI */ - case -ETIMEDOUT: /* OHCI */ - case -EILSEQ: /* UHCI */ + case -EPROTO: + case -ETIME: + case -EILSEQ: return -EIO; default: snd_printk(KERN_ERR "urb status %d\n", status); @@ -222,7 +245,7 @@ static void dump_urb(const char *type, const u8 *data, int length) /* * Processes the data read from the device. */ -static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) +static void snd_usbmidi_in_urb_complete(struct urb* urb) { struct snd_usb_midi_in_endpoint* ep = urb->context; @@ -242,16 +265,23 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb, struct pt_regs *regs) } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } -static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) +static void snd_usbmidi_out_urb_complete(struct urb* urb) { - struct snd_usb_midi_out_endpoint* ep = urb->context; + struct out_urb_context *context = urb->context; + struct snd_usb_midi_out_endpoint* ep = context->ep; + unsigned int urb_index; spin_lock(&ep->buffer_lock); - ep->urb_active = 0; + urb_index = context - ep->urbs; + ep->active_urbs &= ~(1 << urb_index); + if (unlikely(ep->drain_urbs)) { + ep->drain_urbs &= ~(1 << urb_index); + wake_up(&ep->drain_wait); + } spin_unlock(&ep->buffer_lock); if (urb->status < 0) { int err = snd_usbmidi_urb_error(urb->status); @@ -271,24 +301,38 @@ static void snd_usbmidi_out_urb_complete(struct urb* urb, struct pt_regs *regs) */ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) { - struct urb* urb = ep->urb; + unsigned int urb_index; + struct urb* urb; unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->urb_active || ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } - urb->transfer_buffer_length = 0; - ep->umidi->usb_protocol_ops->output(ep); + urb_index = ep->next_urb; + for (;;) { + if (!(ep->active_urbs & (1 << urb_index))) { + urb = ep->urbs[urb_index].urb; + urb->transfer_buffer_length = 0; + ep->umidi->usb_protocol_ops->output(ep, urb); + if (urb->transfer_buffer_length == 0) + break; - if (urb->transfer_buffer_length > 0) { - dump_urb("sending", urb->transfer_buffer, - urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; - ep->urb_active = snd_usbmidi_submit_urb(urb, GFP_ATOMIC) >= 0; + dump_urb("sending", urb->transfer_buffer, + urb->transfer_buffer_length); + urb->dev = ep->umidi->dev; + if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) + break; + ep->active_urbs |= 1 << urb_index; + } + if (++urb_index >= OUTPUT_URBS) + urb_index = 0; + if (urb_index == ep->next_urb) + break; } + ep->next_urb = urb_index; spin_unlock_irqrestore(&ep->buffer_lock, flags); } @@ -303,32 +347,40 @@ static void snd_usbmidi_out_tasklet(unsigned long data) static void snd_usbmidi_error_timer(unsigned long data) { struct snd_usb_midi *umidi = (struct snd_usb_midi *)data; - int i; + unsigned int i, j; + spin_lock(&umidi->disc_lock); + if (umidi->disconnected) { + spin_unlock(&umidi->disc_lock); + return; + } for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_in_endpoint *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); + for (j = 0; j < INPUT_URBS; ++j) { + in->urbs[j]->dev = umidi->dev; + snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); + } } if (umidi->endpoints[i].out) snd_usbmidi_do_output(umidi->endpoints[i].out); } + spin_unlock(&umidi->disc_lock); } /* helper function to send static data that may not DMA-able */ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, const void *data, int len) { - int err; - void *buf = kmalloc(len, GFP_KERNEL); + int err = 0; + void *buf = kmemdup(data, len, GFP_KERNEL); if (!buf) return -ENOMEM; - memcpy(buf, data, len); dump_urb("sending", buf, len); - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urb->pipe, buf, len, - NULL, 250); + if (ep->urbs[0].urb) + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, + buf, len, NULL, 250); kfree(buf); return err; } @@ -366,6 +418,60 @@ static void snd_usbmidi_midiman_input(struct snd_usb_midi_in_endpoint* ep, } /* + * Buggy M-Audio device: running status on input results in a packet that has + * the data bytes but not the status byte and that is marked with CIN 4. + */ +static void snd_usbmidi_maudio_broken_running_status_input( + struct snd_usb_midi_in_endpoint* ep, + uint8_t* buffer, int buffer_length) +{ + int i; + + for (i = 0; i + 3 < buffer_length; i += 4) + if (buffer[i] != 0) { + int cable = buffer[i] >> 4; + u8 cin = buffer[i] & 0x0f; + struct usbmidi_in_port *port = &ep->ports[cable]; + int length; + + length = snd_usbmidi_cin_length[cin]; + if (cin == 0xf && buffer[i + 1] >= 0xf8) + ; /* realtime msg: no running status change */ + else if (cin >= 0x8 && cin <= 0xe) + /* channel msg */ + port->running_status_length = length - 1; + else if (cin == 0x4 && + port->running_status_length != 0 && + buffer[i + 1] < 0x80) + /* CIN 4 that is not a SysEx */ + length = port->running_status_length; + else + /* + * All other msgs cannot begin running status. + * (A channel msg sent as two or three CIN 0xF + * packets could in theory, but this device + * doesn't use this format.) + */ + port->running_status_length = 0; + snd_usbmidi_input_data(ep, cable, &buffer[i + 1], length); + } +} + +/* + * CME protocol: like the standard protocol, but SysEx commands are sent as a + * single USB packet preceded by a 0x0F byte. + */ +static void snd_usbmidi_cme_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length < 2 || (buffer[0] & 0x0f) != 0x0f) + snd_usbmidi_standard_input(ep, buffer, buffer_length); + else + snd_usbmidi_input_data(ep, buffer[0] >> 4, + &buffer[1], buffer_length - 1); +} + +/* * Adds one USB MIDI packet to the output buffer. */ static void snd_usbmidi_output_standard_packet(struct urb* urb, uint8_t p0, @@ -492,9 +598,9 @@ static void snd_usbmidi_transmit_byte(struct usbmidi_out_port* port, } } -static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_standard_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { - struct urb* urb = ep->urb; int p; /* FIXME: lower-numbered ports can starve higher-numbered ports */ @@ -525,6 +631,18 @@ static struct usb_protocol_ops snd_usbmidi_midiman_ops = { .output_packet = snd_usbmidi_output_midiman_packet, }; +static struct usb_protocol_ops snd_usbmidi_maudio_broken_running_status_ops = { + .input = snd_usbmidi_maudio_broken_running_status_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + +static struct usb_protocol_ops snd_usbmidi_cme_ops = { + .input = snd_usbmidi_cme_input, + .output = snd_usbmidi_standard_output, + .output_packet = snd_usbmidi_output_standard_packet, +}; + /* * Novation USB MIDI protocol: number of data bytes is in the first byte * (when receiving) (+1!) or in the second byte (when sending); data begins @@ -539,14 +657,15 @@ static void snd_usbmidi_novation_input(struct snd_usb_midi_in_endpoint* ep, snd_usbmidi_input_data(ep, 0, &buffer[2], buffer[0] - 1); } -static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { uint8_t* transfer_buffer; int count; if (!ep->ports[0].active) return; - transfer_buffer = ep->urb->transfer_buffer; + transfer_buffer = urb->transfer_buffer; count = snd_rawmidi_transmit(ep->ports[0].substream, &transfer_buffer[2], ep->max_transfer - 2); @@ -556,7 +675,7 @@ static void snd_usbmidi_novation_output(struct snd_usb_midi_out_endpoint* ep) } transfer_buffer[0] = 0; transfer_buffer[1] = count; - ep->urb->transfer_buffer_length = 2 + count; + urb->transfer_buffer_length = 2 + count; } static struct usb_protocol_ops snd_usbmidi_novation_ops = { @@ -574,20 +693,21 @@ static void snd_usbmidi_raw_input(struct snd_usb_midi_in_endpoint* ep, snd_usbmidi_input_data(ep, 0, buffer, buffer_length); } -static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_raw_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int count; if (!ep->ports[0].active) return; count = snd_rawmidi_transmit(ep->ports[0].substream, - ep->urb->transfer_buffer, + urb->transfer_buffer, ep->max_transfer); if (count < 1) { ep->ports[0].active = 0; return; } - ep->urb->transfer_buffer_length = count; + urb->transfer_buffer_length = count; } static struct usb_protocol_ops snd_usbmidi_raw_ops = { @@ -595,6 +715,43 @@ static struct usb_protocol_ops snd_usbmidi_raw_ops = { .output = snd_usbmidi_raw_output, }; +static void snd_usbmidi_us122l_input(struct snd_usb_midi_in_endpoint *ep, + uint8_t *buffer, int buffer_length) +{ + if (buffer_length != 9) + return; + buffer_length = 8; + while (buffer_length && buffer[buffer_length - 1] == 0xFD) + buffer_length--; + if (buffer_length) + snd_usbmidi_input_data(ep, 0, buffer, buffer_length); +} + +static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, + struct urb *urb) +{ + int count; + + if (!ep->ports[0].active) + return; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; + count = snd_rawmidi_transmit(ep->ports[0].substream, + urb->transfer_buffer, + count); + if (count < 1) { + ep->ports[0].active = 0; + return; + } + + memset(urb->transfer_buffer + count, 0xFD, 9 - count); + urb->transfer_buffer_length = count; +} + +static struct usb_protocol_ops snd_usbmidi_122l_ops = { + .input = snd_usbmidi_us122l_input, + .output = snd_usbmidi_us122l_output, +}; + /* * Emagic USB MIDI protocol: raw MIDI with "F5 xx" port switching. */ @@ -676,10 +833,11 @@ static void snd_usbmidi_emagic_input(struct snd_usb_midi_in_endpoint* ep, } } -static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep) +static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep, + struct urb *urb) { int port0 = ep->current_port; - uint8_t* buf = ep->urb->transfer_buffer; + uint8_t* buf = urb->transfer_buffer; int buf_free = ep->max_transfer; int length, i; @@ -719,7 +877,7 @@ static void snd_usbmidi_emagic_output(struct snd_usb_midi_out_endpoint* ep) *buf = 0xff; --buf_free; } - ep->urb->transfer_buffer_length = ep->max_transfer - buf_free; + urb->transfer_buffer_length = ep->max_transfer - buf_free; } static struct usb_protocol_ops snd_usbmidi_emagic_ops = { @@ -730,6 +888,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; + is_light_load = intf->cur_altsetting != intf->altsetting; + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -749,11 +951,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -763,24 +967,55 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) snd_rawmidi_transmit_ack(substream, 1); return; } - tasklet_hi_schedule(&port->ep->tasklet); + tasklet_schedule(&port->ep->tasklet); + } +} + +static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) +{ + struct usbmidi_out_port* port = substream->runtime->private_data; + struct snd_usb_midi_out_endpoint *ep = port->ep; + unsigned int drain_urbs; + DEFINE_WAIT(wait); + long timeout = msecs_to_jiffies(50); + + /* + * The substream buffer is empty, but some data might still be in the + * currently active URBs, so we have to wait for those to complete. + */ + spin_lock_irq(&ep->buffer_lock); + drain_urbs = ep->active_urbs; + if (drain_urbs) { + ep->drain_urbs |= drain_urbs; + do { + prepare_to_wait(&ep->drain_wait, &wait, + TASK_UNINTERRUPTIBLE); + spin_unlock_irq(&ep->buffer_lock); + timeout = schedule_timeout(timeout); + spin_lock_irq(&ep->buffer_lock); + drain_urbs &= ep->drain_urbs; + } while (drain_urbs && timeout); + finish_wait(&ep->drain_wait, &wait); } + spin_unlock_irq(&ep->buffer_lock); } static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -798,6 +1033,7 @@ static struct snd_rawmidi_ops snd_usbmidi_output_ops = { .open = snd_usbmidi_output_open, .close = snd_usbmidi_output_close, .trigger = snd_usbmidi_output_trigger, + .drain = snd_usbmidi_output_drain, }; static struct snd_rawmidi_ops snd_usbmidi_input_ops = { @@ -806,19 +1042,26 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { .trigger = snd_usbmidi_input_trigger }; +static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, + unsigned int buffer_length) +{ + usb_buffer_free(umidi->dev, buffer_length, + urb->transfer_buffer, urb->transfer_dma); + usb_free_urb(urb); +} + /* * Frees an input endpoint. * May be called when ep hasn't been initialized completely. */ static void snd_usbmidi_in_endpoint_delete(struct snd_usb_midi_in_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, - ep->urb->transfer_buffer_length, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); - } + unsigned int i; + + for (i = 0; i < INPUT_URBS; ++i) + if (ep->urbs[i]) + free_urb_and_buffer(ep->umidi, ep->urbs[i], + ep->urbs[i]->transfer_buffer_length); kfree(ep); } @@ -833,6 +1076,7 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, void* buffer; unsigned int pipe; int length; + unsigned int i; rep->in = NULL; ep = kzalloc(sizeof(*ep), GFP_KERNEL); @@ -840,56 +1084,53 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < INPUT_URBS; ++i) { + ep->urbs[i] = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i]) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, - &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_in_endpoint_delete(ep); - return -ENOMEM; + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); + for (i = 0; i < INPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, + &ep->urbs[i]->transfer_dma); + if (!buffer) { + snd_usbmidi_in_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->in_interval) + usb_fill_int_urb(ep->urbs[i], umidi->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, + ep, ep_info->in_interval); + else + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, + pipe, buffer, length, + snd_usbmidi_in_urb_complete, ep); + ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - if (ep_info->in_interval) - usb_fill_int_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep, - ep_info->in_interval); - else - usb_fill_bulk_urb(ep->urb, umidi->chip->dev, pipe, buffer, - length, snd_usbmidi_in_urb_complete, ep); - ep->urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; rep->in = ep; return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits = 0; - - for (; x; x >>= 1) - bits += x & 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. */ static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) { - if (ep->urb) { - usb_buffer_free(ep->umidi->chip->dev, ep->max_transfer, - ep->urb->transfer_buffer, - ep->urb->transfer_dma); - usb_free_urb(ep->urb); - } + unsigned int i; + + for (i = 0; i < OUTPUT_URBS; ++i) + if (ep->urbs[i].urb) + free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, + ep->max_transfer); kfree(ep); } @@ -901,7 +1142,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, struct snd_usb_midi_endpoint* rep) { struct snd_usb_midi_out_endpoint* ep; - int i; + unsigned int i; unsigned int pipe; void* buffer; @@ -911,26 +1152,58 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; ep->umidi = umidi; - ep->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!ep->urb) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + for (i = 0; i < OUTPUT_URBS; ++i) { + ep->urbs[i].urb = usb_alloc_urb(0, GFP_KERNEL); + if (!ep->urbs[i].urb) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + ep->urbs[i].ep = ep; } - /* we never use interrupt output pipes */ - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); - buffer = usb_buffer_alloc(umidi->chip->dev, ep->max_transfer, - GFP_KERNEL, &ep->urb->transfer_dma); - if (!buffer) { - snd_usbmidi_out_endpoint_delete(ep); - return -ENOMEM; + if (ep_info->out_interval) + pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); + else + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + switch (umidi->usb_id) { + default: + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); + break; + /* + * Various chips declare a packet size larger than 4 bytes, but + * do not actually work with larger packets: + */ + case USB_ID(0x0a92, 0x1020): /* ESI M4U */ + case USB_ID(0x1430, 0x474b): /* RedOctane GH MIDI INTERFACE */ + case USB_ID(0x15ca, 0x0101): /* Textech USB Midi Cable */ + case USB_ID(0x15ca, 0x1806): /* Textech USB Midi Cable */ + case USB_ID(0x1a86, 0x752d): /* QinHeng CH345 "USB2.0-MIDI" */ + ep->max_transfer = 4; + break; + } + for (i = 0; i < OUTPUT_URBS; ++i) { + buffer = usb_buffer_alloc(umidi->dev, + ep->max_transfer, GFP_KERNEL, + &ep->urbs[i].urb->transfer_dma); + if (!buffer) { + snd_usbmidi_out_endpoint_delete(ep); + return -ENOMEM; + } + if (ep_info->out_interval) + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i], ep_info->out_interval); + else + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, + pipe, buffer, ep->max_transfer, + snd_usbmidi_out_urb_complete, + &ep->urbs[i]); + ep->urbs[i].urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } - 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); tasklet_init(&ep->tasklet, snd_usbmidi_out_tasklet, (unsigned long)ep); + init_waitqueue_head(&ep->drain_wait); for (i = 0; i < 0x10; ++i) if (ep_info->out_cables & (1 << i)) { @@ -959,6 +1232,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -968,22 +1242,41 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) void snd_usbmidi_disconnect(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); - del_timer_sync(&umidi->error_timer); + /* + * an URB's completion handler may start the timer and + * a timer may submit an URB. To reliably break the cycle + * a flag under lock must be used + */ + spin_lock_irq(&umidi->disc_lock); + umidi->disconnected = 1; + spin_unlock_irq(&umidi->disc_lock); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* 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 (ep->out) { + for (j = 0; j < OUTPUT_URBS; ++j) + usb_kill_urb(ep->out->urbs[j].urb); if (umidi->usb_protocol_ops->finish_out_endpoint) umidi->usb_protocol_ops->finish_out_endpoint(ep->out); } - if (ep->in && ep->in->urb) - usb_kill_urb(ep->in->urb); + if (ep->in) + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); + /* free endpoints here; later call can result in Oops */ + if (ep->out) { + snd_usbmidi_out_endpoint_delete(ep->out); + ep->out = NULL; + } + if (ep->in) { + snd_usbmidi_in_endpoint_delete(ep->in); + ep->in = NULL; + } } + del_timer_sync(&umidi->error_timer); } static void snd_usbmidi_rawmidi_free(struct snd_rawmidi *rmidi) @@ -1010,97 +1303,163 @@ static struct snd_rawmidi_substream *snd_usbmidi_find_substream(struct snd_usb_m * "(product) MIDI (n)" schema because they aren't external MIDI ports, * such as internal control or synthesizer ports. */ -static struct { +static struct port_info { u32 id; - int port; - const char *name_format; -} snd_usbmidi_port_names[] = { + short int port; + short int voices; + const char *name; + unsigned int seq_flags; +} snd_usbmidi_port_info[] = { +#define PORT_INFO(vendor, product, num, name_, voices_, flags) \ + { .id = USB_ID(vendor, product), \ + .port = num, .voices = voices_, \ + .name = name_, .seq_flags = flags } +#define EXTERNAL_PORT(vendor, product, num, name) \ + PORT_INFO(vendor, product, num, name, 0, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_PORT) +#define CONTROL_PORT(vendor, product, num, name) \ + PORT_INFO(vendor, product, num, name, 0, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE) +#define ROLAND_SYNTH_PORT(vendor, product, num, name, voices) \ + PORT_INFO(vendor, product, num, name, voices, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ + SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) +#define SOUNDCANVAS_PORT(vendor, product, num, name, voices) \ + PORT_INFO(vendor, product, num, name, voices, \ + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GM2 | \ + SNDRV_SEQ_PORT_TYPE_MIDI_GS | \ + SNDRV_SEQ_PORT_TYPE_MIDI_XG | \ + SNDRV_SEQ_PORT_TYPE_MIDI_MT32 | \ + SNDRV_SEQ_PORT_TYPE_HARDWARE | \ + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER) /* Roland UA-100 */ - { USB_ID(0x0582, 0x0000), 2, "%s Control" }, + CONTROL_PORT(0x0582, 0x0000, 2, "%s Control"), /* Roland SC-8850 */ - { USB_ID(0x0582, 0x0003), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0003), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0003), 2, "%s Part C" }, - { USB_ID(0x0582, 0x0003), 3, "%s Part D" }, - { USB_ID(0x0582, 0x0003), 4, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0003), 5, "%s MIDI 2" }, + SOUNDCANVAS_PORT(0x0582, 0x0003, 0, "%s Part A", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 1, "%s Part B", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 2, "%s Part C", 128), + SOUNDCANVAS_PORT(0x0582, 0x0003, 3, "%s Part D", 128), + EXTERNAL_PORT(0x0582, 0x0003, 4, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0003, 5, "%s MIDI 2"), /* Roland U-8 */ - { USB_ID(0x0582, 0x0004), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0004), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x0004, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x0004, 1, "%s Control"), /* Roland SC-8820 */ - { USB_ID(0x0582, 0x0007), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0007), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0007), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x0007, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x0007, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x0007, 2, "%s MIDI"), /* Roland SK-500 */ - { USB_ID(0x0582, 0x000b), 0, "%s Part A" }, - { USB_ID(0x0582, 0x000b), 1, "%s Part B" }, - { USB_ID(0x0582, 0x000b), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x000b, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x000b, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x000b, 2, "%s MIDI"), /* Roland SC-D70 */ - { USB_ID(0x0582, 0x000c), 0, "%s Part A" }, - { USB_ID(0x0582, 0x000c), 1, "%s Part B" }, - { USB_ID(0x0582, 0x000c), 2, "%s MIDI" }, + SOUNDCANVAS_PORT(0x0582, 0x000c, 0, "%s Part A", 64), + SOUNDCANVAS_PORT(0x0582, 0x000c, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x000c, 2, "%s MIDI"), /* Edirol UM-880 */ - { USB_ID(0x0582, 0x0014), 8, "%s Control" }, + CONTROL_PORT(0x0582, 0x0014, 8, "%s Control"), /* Edirol SD-90 */ - { USB_ID(0x0582, 0x0016), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0016), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0016), 2, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0016), 3, "%s MIDI 2" }, + ROLAND_SYNTH_PORT(0x0582, 0x0016, 0, "%s Part A", 128), + ROLAND_SYNTH_PORT(0x0582, 0x0016, 1, "%s Part B", 128), + EXTERNAL_PORT(0x0582, 0x0016, 2, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0016, 3, "%s MIDI 2"), /* Edirol UM-550 */ - { USB_ID(0x0582, 0x0023), 5, "%s Control" }, + CONTROL_PORT(0x0582, 0x0023, 5, "%s Control"), /* Edirol SD-20 */ - { USB_ID(0x0582, 0x0027), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0027), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0027), 2, "%s MIDI" }, + ROLAND_SYNTH_PORT(0x0582, 0x0027, 0, "%s Part A", 64), + ROLAND_SYNTH_PORT(0x0582, 0x0027, 1, "%s Part B", 64), + EXTERNAL_PORT(0x0582, 0x0027, 2, "%s MIDI"), /* Edirol SD-80 */ - { USB_ID(0x0582, 0x0029), 0, "%s Part A" }, - { USB_ID(0x0582, 0x0029), 1, "%s Part B" }, - { USB_ID(0x0582, 0x0029), 2, "%s MIDI 1" }, - { USB_ID(0x0582, 0x0029), 3, "%s MIDI 2" }, + ROLAND_SYNTH_PORT(0x0582, 0x0029, 0, "%s Part A", 128), + ROLAND_SYNTH_PORT(0x0582, 0x0029, 1, "%s Part B", 128), + EXTERNAL_PORT(0x0582, 0x0029, 2, "%s MIDI 1"), + EXTERNAL_PORT(0x0582, 0x0029, 3, "%s MIDI 2"), /* Edirol UA-700 */ - { USB_ID(0x0582, 0x002b), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x002b), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x002b, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x002b, 1, "%s Control"), /* Roland VariOS */ - { USB_ID(0x0582, 0x002f), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x002f), 1, "%s External MIDI" }, - { USB_ID(0x0582, 0x002f), 2, "%s Sync" }, + EXTERNAL_PORT(0x0582, 0x002f, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x002f, 1, "%s External MIDI"), + EXTERNAL_PORT(0x0582, 0x002f, 2, "%s Sync"), /* Edirol PCR */ - { USB_ID(0x0582, 0x0033), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0033), 1, "%s 1" }, - { USB_ID(0x0582, 0x0033), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x0033, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x0033, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x0033, 2, "%s 2"), /* BOSS GS-10 */ - { USB_ID(0x0582, 0x003b), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x003b), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x003b, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x003b, 1, "%s Control"), /* Edirol UA-1000 */ - { USB_ID(0x0582, 0x0044), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0044), 1, "%s Control" }, + EXTERNAL_PORT(0x0582, 0x0044, 0, "%s MIDI"), + CONTROL_PORT(0x0582, 0x0044, 1, "%s Control"), /* Edirol UR-80 */ - { USB_ID(0x0582, 0x0048), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x0048), 1, "%s 1" }, - { USB_ID(0x0582, 0x0048), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x0048, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x0048, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x0048, 2, "%s 2"), /* Edirol PCR-A */ - { USB_ID(0x0582, 0x004d), 0, "%s MIDI" }, - { USB_ID(0x0582, 0x004d), 1, "%s 1" }, - { USB_ID(0x0582, 0x004d), 2, "%s 2" }, + EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"), + EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"), + EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"), + /* Edirol UM-3EX */ + CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"), /* M-Audio MidiSport 8x8 */ - { USB_ID(0x0763, 0x1031), 8, "%s Control" }, - { USB_ID(0x0763, 0x1033), 8, "%s Control" }, + CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"), + CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"), /* MOTU Fastlane */ - { USB_ID(0x07fd, 0x0001), 0, "%s MIDI A" }, - { USB_ID(0x07fd, 0x0001), 1, "%s MIDI B" }, + EXTERNAL_PORT(0x07fd, 0x0001, 0, "%s MIDI A"), + EXTERNAL_PORT(0x07fd, 0x0001, 1, "%s MIDI B"), /* Emagic Unitor8/AMT8/MT4 */ - { USB_ID(0x086a, 0x0001), 8, "%s Broadcast" }, - { USB_ID(0x086a, 0x0002), 8, "%s Broadcast" }, - { USB_ID(0x086a, 0x0003), 4, "%s Broadcast" }, - /* Edirol UM-3ex */ - { USB_ID(0x0582, 0x009a), 3, "%s Control" }, + EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), + EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), + EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), + /* Access Music Virus TI */ + EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), + PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_HARDWARE | + SNDRV_SEQ_PORT_TYPE_SYNTHESIZER), }; +static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { + if (snd_usbmidi_port_info[i].id == umidi->usb_id && + snd_usbmidi_port_info[i].port == number) + return &snd_usbmidi_port_info[i]; + } + return NULL; +} + +static void snd_usbmidi_get_port_info(struct snd_rawmidi *rmidi, int number, + struct snd_seq_port_info *seq_port_info) +{ + struct snd_usb_midi *umidi = rmidi->private_data; + struct port_info *port_info; + + /* TODO: read port flags from descriptors */ + port_info = find_port_info(umidi, number); + if (port_info) { + seq_port_info->type = port_info->seq_flags; + seq_port_info->midi_voices = port_info->voices; + } +} + static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, int stream, int number, struct snd_rawmidi_substream ** rsubstream) { - int i; + struct port_info *port_info; const char *name_format; struct snd_rawmidi_substream *substream = snd_usbmidi_find_substream(umidi, stream, number); @@ -1110,16 +1469,10 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, } /* TODO: read port name from jack descriptor */ - name_format = "%s MIDI %d"; - for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_names); ++i) { - if (snd_usbmidi_port_names[i].id == umidi->chip->usb_id && - snd_usbmidi_port_names[i].port == number) { - name_format = snd_usbmidi_port_names[i].name_format; - break; - } - } + port_info = find_port_info(umidi, number); + name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1189,7 +1542,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, if (hostif->extralen >= 7 && ms_header->bLength >= 7 && ms_header->bDescriptorType == USB_DT_CS_INTERFACE && - ms_header->bDescriptorSubtype == HEADER) + ms_header->bDescriptorSubtype == UAC_HEADER) snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", ms_header->bcdMSC[1], ms_header->bcdMSC[0]); else @@ -1199,25 +1552,31 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, for (i = 0; i < intfd->bNumEndpoints; ++i) { hostep = &hostif->endpoint[i]; ep = get_ep_desc(hostep); - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK && - (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_bulk(ep) && !usb_endpoint_xfer_int(ep)) continue; ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra; if (hostep->extralen < 4 || ms_ep->bLength < 4 || ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || - ms_ep->bDescriptorSubtype != MS_GENERAL) + ms_ep->bDescriptorSubtype != UAC_MS_GENERAL) continue; - if ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { + if (usb_endpoint_dir_out(ep)) { if (endpoints[epidx].out_ep) { if (++epidx >= MIDI_MAX_ENDPOINTS) { snd_printk(KERN_WARNING "too many endpoints\n"); break; } } - endpoints[epidx].out_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + endpoints[epidx].out_ep = usb_endpoint_num(ep); + if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->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); @@ -1228,9 +1587,11 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, break; } } - endpoints[epidx].in_ep = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + endpoints[epidx].in_ep = usb_endpoint_num(ep); + if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; + else if (snd_usb_get_speed(umidi->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); @@ -1239,6 +1600,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1262,8 +1669,12 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1279,7 +1690,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1293,20 +1704,20 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, for (i = 0; i < intfd->bNumEndpoints; ++i) { epd = get_endpoint(hostif, i); - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK && - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) + if (!usb_endpoint_xfer_bulk(epd) && + !usb_endpoint_xfer_int(epd)) continue; if (out_eps < max_endpoints && - (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) { - endpoint[out_eps].out_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + usb_endpoint_dir_out(epd)) { + endpoint[out_eps].out_ep = usb_endpoint_num(epd); + if (usb_endpoint_xfer_int(epd)) endpoint[out_eps].out_interval = epd->bInterval; ++out_eps; } if (in_eps < max_endpoints && - (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) { - endpoint[in_eps].in_ep = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - if ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + usb_endpoint_dir_in(epd)) { + endpoint[in_eps].in_ep = usb_endpoint_num(epd); + if (usb_endpoint_xfer_int(epd)) endpoint[in_eps].in_interval = epd->bInterval; ++in_eps; } @@ -1358,10 +1769,10 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, for (cs_desc = hostif->extra; cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; cs_desc += cs_desc[0]) { - if (cs_desc[1] == CS_AUDIO_INTERFACE) { - if (cs_desc[2] == MIDI_IN_JACK) + if (cs_desc[1] == USB_DT_CS_INTERFACE) { + if (cs_desc[2] == UAC_MIDI_IN_JACK) endpoint->in_cables = (endpoint->in_cables << 1) | 1; - else if (cs_desc[2] == MIDI_OUT_JACK) + else if (cs_desc[2] == UAC_MIDI_OUT_JACK) endpoint->out_cables = (endpoint->out_cables << 1) | 1; } } @@ -1405,27 +1816,26 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, } epd = get_endpoint(hostif, 0); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) { + if (!usb_endpoint_dir_in(epd) || !usb_endpoint_xfer_int(epd)) { snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n"); return -ENXIO; } epd = get_endpoint(hostif, 2); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { + if (!usb_endpoint_dir_out(epd) || !usb_endpoint_xfer_bulk(epd)) { snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n"); return -ENXIO; } if (endpoint->out_cables > 0x0001) { epd = get_endpoint(hostif, 4); - if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT || - (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) { + if (!usb_endpoint_dir_out(epd) || + !usb_endpoint_xfer_bulk(epd)) { snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n"); return -ENXIO; } } ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; + ep_info.out_interval = 0; ep_info.out_cables = endpoint->out_cables & 0x5555; err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]); if (err < 0) @@ -1457,21 +1867,26 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi, return 0; } +static struct snd_rawmidi_global_ops snd_usbmidi_ops = { + .get_port_info = snd_usbmidi_get_port_info, +}; + static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, int out_ports, int in_ports) { struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->ops = &snd_usbmidi_ops; rmidi->private_data = umidi; rmidi->private_free = snd_usbmidi_rawmidi_free; snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_usbmidi_output_ops); @@ -1487,21 +1902,26 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, void snd_usbmidi_input_stop(struct list_head* p) { struct snd_usb_midi* umidi; - int i; + unsigned int i, j; umidi = list_entry(p, struct snd_usb_midi, list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i]; if (ep->in) - usb_kill_urb(ep->in->urb); + for (j = 0; j < INPUT_URBS; ++j) + usb_kill_urb(ep->in->urbs[j]); } } static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) { - if (ep) { - struct urb* urb = ep->urb; - urb->dev = ep->umidi->chip->dev; + unsigned int i; + + if (!ep) + return; + for (i = 0; i < INPUT_URBS; ++i) { + struct urb* urb = ep->urbs[i]; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1522,9 +1942,10 @@ void snd_usbmidi_input_start(struct list_head* p) /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1534,11 +1955,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); + spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1547,7 +1973,13 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + umidi->usb_protocol_ops = + &snd_usbmidi_maudio_broken_running_status_ops; break; + case QUIRK_MIDI_US122L: + umidi->usb_protocol_ops = &snd_usbmidi_122l_ops; + /* fall through */ case QUIRK_MIDI_FIXED_ENDPOINT: memcpy(&endpoints[0], quirk->data, sizeof(struct snd_usb_midi_endpoint_info)); @@ -1566,8 +1998,18 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi->usb_protocol_ops = &snd_usbmidi_novation_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; - case QUIRK_MIDI_RAW: + case QUIRK_MIDI_FASTLANE: umidi->usb_protocol_ops = &snd_usbmidi_raw_ops; + /* + * Interface 1 contains isochronous endpoints, but with the same + * numbers as in interface 0. Since it is interface 1 that the + * USB core has most recently seen, these descriptors are now + * associated with the endpoint numbers. This will foul up our + * attempts to submit bulk/interrupt URBs to the endpoints in + * interface 0, so we have to make sure that the USB core looks + * again at interface 0 by calling usb_set_interface() on it. + */ + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -1576,7 +2018,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, sizeof(struct snd_usb_midi_endpoint_info)); err = snd_usbmidi_detect_endpoints(umidi, &endpoints[0], 1); break; - case QUIRK_MIDI_MIDITECH: + case QUIRK_MIDI_CME: + umidi->usb_protocol_ops = &snd_usbmidi_cme_ops; err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; default: @@ -1593,8 +2036,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { @@ -1612,14 +2055,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect);