Skip to content

Commit

Permalink
sound: usb-audio: use multiple input URBs
Browse files Browse the repository at this point in the history
Some newer USB MIDI interfaces use rather small packet sizes, so to get
enough bandwidth, we have to be able to receive multiple packets in one
USB frame, so we have to use multiple URBs.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Clemens Ladisch authored and Takashi Iwai committed Jul 15, 2009
1 parent 468b8fd commit 4773d1f
Showing 1 changed file with 54 additions and 33 deletions.
87 changes: 54 additions & 33 deletions sound/usb/usbmidi.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
*/
#define ERROR_DELAY_JIFFIES (HZ / 10)

#define INPUT_URBS 7


MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
MODULE_DESCRIPTION("USB Audio/MIDI helper module");
Expand Down Expand Up @@ -143,7 +145,7 @@ struct snd_usb_midi_out_endpoint {

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;
Expand Down Expand Up @@ -306,7 +308,7 @@ 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) {
Expand All @@ -317,8 +319,10 @@ static void snd_usbmidi_error_timer(unsigned long data)
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->chip->dev;
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
}
}
if (umidi->endpoints[i].out)
snd_usbmidi_do_output(umidi->endpoints[i].out);
Expand Down Expand Up @@ -922,12 +926,16 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = {
*/
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]) {
usb_buffer_free(ep->umidi->chip->dev,
ep->urbs[i]->transfer_buffer_length,
ep->urbs[i]->transfer_buffer,
ep->urbs[i]->transfer_dma);
usb_free_urb(ep->urbs[i]);
}
}
kfree(ep);
}
Expand All @@ -943,37 +951,44 @@ 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);
if (!ep)
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);
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;
for (i = 0; i < INPUT_URBS; ++i) {
buffer = usb_buffer_alloc(umidi->chip->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->chip->dev,
pipe, buffer, length,
snd_usbmidi_in_urb_complete,
ep, ep_info->in_interval);
else
usb_fill_bulk_urb(ep->urbs[i], umidi->chip->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;
Expand Down Expand Up @@ -1090,7 +1105,7 @@ 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);
/*
Expand All @@ -1111,7 +1126,8 @@ void snd_usbmidi_disconnect(struct list_head* p)
umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
}
if (ep->in)
usb_kill_urb(ep->in->urb);
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);
Expand Down Expand Up @@ -1692,20 +1708,25 @@ 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;
unsigned int i;

if (!ep)
return;
for (i = 0; i < INPUT_URBS; ++i) {
struct urb* urb = ep->urbs[i];
urb->dev = ep->umidi->chip->dev;
snd_usbmidi_submit_urb(urb, GFP_KERNEL);
}
Expand Down

0 comments on commit 4773d1f

Please sign in to comment.