ALSA: line6: Only determine control port properties if needed
[cascardo/linux.git] / sound / usb / line6 / driver.c
index 81b7da8..8a71d45 100644 (file)
@@ -66,10 +66,17 @@ static int line6_start_listen(struct usb_line6 *line6)
 {
        int err;
 
-       usb_fill_int_urb(line6->urb_listen, line6->usbdev,
-               usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
-               line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
-               line6_data_received, line6, line6->interval);
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+               usb_fill_int_urb(line6->urb_listen, line6->usbdev,
+                       usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+                       line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+                       line6_data_received, line6, line6->interval);
+       } else {
+               usb_fill_bulk_urb(line6->urb_listen, line6->usbdev,
+                       usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+                       line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+                       line6_data_received, line6);
+       }
        line6->urb_listen->actual_length = 0;
        err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
        return err;
@@ -90,6 +97,7 @@ static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
                                  int size)
 {
        int i, done = 0;
+       const struct line6_properties *properties = line6->properties;
 
        for (i = 0; i < size; i += line6->max_packet_size) {
                int partial;
@@ -97,15 +105,21 @@ static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
                int frag_size = min(line6->max_packet_size, size - i);
                int retval;
 
-               retval = usb_interrupt_msg(line6->usbdev,
-                                       usb_sndintpipe(line6->usbdev,
-                                               line6->properties->ep_ctrl_w),
-                                       (char *)frag_buf, frag_size,
-                                       &partial, LINE6_TIMEOUT * HZ);
+               if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+                       retval = usb_interrupt_msg(line6->usbdev,
+                                               usb_sndintpipe(line6->usbdev, properties->ep_ctrl_w),
+                                               (char *)frag_buf, frag_size,
+                                               &partial, LINE6_TIMEOUT * HZ);
+               } else {
+                       retval = usb_bulk_msg(line6->usbdev,
+                                               usb_sndbulkpipe(line6->usbdev, properties->ep_ctrl_w),
+                                               (char *)frag_buf, frag_size,
+                                               &partial, LINE6_TIMEOUT * HZ);
+               }
 
                if (retval) {
                        dev_err(line6->ifcdev,
-                               "usb_interrupt_msg failed (%d)\n", retval);
+                               "usb_bulk_msg failed (%d)\n", retval);
                        break;
                }
 
@@ -140,10 +154,17 @@ static int line6_send_raw_message_async_part(struct message *msg,
        int done = msg->done;
        int bytes = min(msg->size - done, line6->max_packet_size);
 
-       usb_fill_int_urb(urb, line6->usbdev,
-               usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
-               (char *)msg->buffer + done, bytes,
-               line6_async_request_sent, msg, line6->interval);
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+               usb_fill_int_urb(urb, line6->usbdev,
+                       usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+                       (char *)msg->buffer + done, bytes,
+                       line6_async_request_sent, msg, line6->interval);
+       } else {
+               usb_fill_bulk_urb(urb, line6->usbdev,
+                       usb_sndbulkpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+                       (char *)msg->buffer + done, bytes,
+                       line6_async_request_sent, msg);
+       }
 
        msg->done += bytes;
        retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -269,26 +290,31 @@ static void line6_data_received(struct urb *urb)
        if (urb->status == -ESHUTDOWN)
                return;
 
-       done =
-           line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+               done =
+                       line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
 
-       if (done < urb->actual_length) {
-               line6_midibuf_ignore(mb, done);
-               dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
-                       done, urb->actual_length);
-       }
+               if (done < urb->actual_length) {
+                       line6_midibuf_ignore(mb, done);
+                       dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
+                               done, urb->actual_length);
+               }
 
-       for (;;) {
-               done =
-                   line6_midibuf_read(mb, line6->buffer_message,
-                                      LINE6_MESSAGE_MAXLEN);
+               for (;;) {
+                       done =
+                               line6_midibuf_read(mb, line6->buffer_message,
+                                               LINE6_MESSAGE_MAXLEN);
 
-               if (done == 0)
-                       break;
+                       if (done == 0)
+                               break;
 
-               line6->message_length = done;
-               line6_midi_receive(line6, line6->buffer_message, done);
+                       line6->message_length = done;
+                       line6_midi_receive(line6, line6->buffer_message, done);
 
+                       if (line6->process_message)
+                               line6->process_message(line6);
+               }
+       } else {
                if (line6->process_message)
                        line6->process_message(line6);
        }
@@ -448,7 +474,9 @@ static void line6_destruct(struct snd_card *card)
        struct usb_device *usbdev = line6->usbdev;
 
        /* free buffer memory first: */
-       kfree(line6->buffer_message);
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI)
+               kfree(line6->buffer_message);
+
        kfree(line6->buffer_listen);
 
        /* then free URBs: */
@@ -462,13 +490,29 @@ static void line6_destruct(struct snd_card *card)
 static void line6_get_interval(struct usb_line6 *line6)
 {
        struct usb_device *usbdev = line6->usbdev;
+       const struct line6_properties *properties = line6->properties;
+       int pipe;
        struct usb_host_endpoint *ep;
-       unsigned pipe = usb_rcvintpipe(usbdev, line6->properties->ep_ctrl_r);
-       unsigned epnum = usb_pipeendpoint(pipe);
 
-       ep = usbdev->ep_in[epnum];
+       if (properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+               pipe =
+                       usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r);
+       } else {
+               pipe =
+                       usb_rcvbulkpipe(line6->usbdev, line6->properties->ep_ctrl_r);
+       }
+       ep = usbdev->ep_in[usb_pipeendpoint(pipe)];
+
        if (ep) {
                line6->interval = ep->desc.bInterval;
+               if (usbdev->speed == USB_SPEED_LOW) {
+                       line6->intervals_per_second = USB_LOW_INTERVALS_PER_SECOND;
+                       line6->iso_buffers = USB_LOW_ISO_BUFFERS;
+               } else {
+                       line6->intervals_per_second = USB_HIGH_INTERVALS_PER_SECOND;
+                       line6->iso_buffers = USB_HIGH_ISO_BUFFERS;
+               }
+
                line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
        } else {
                dev_err(line6->ifcdev,
@@ -487,14 +531,16 @@ static int line6_init_cap_control(struct usb_line6 *line6)
        if (!line6->buffer_listen)
                return -ENOMEM;
 
-       line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
-       if (!line6->buffer_message)
-               return -ENOMEM;
-
        line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
        if (!line6->urb_listen)
                return -ENOMEM;
 
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL_MIDI) {
+               line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+               if (!line6->buffer_message)
+                       return -ENOMEM;
+       }
+
        ret = line6_start_listen(line6);
        if (ret < 0) {
                dev_err(line6->ifcdev, "cannot start listening: %d\n", ret);
@@ -558,6 +604,7 @@ int line6_probe(struct usb_interface *interface,
        /* query interface number */
        interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
 
+       /* TODO reserves the bus bandwidth even without actual transfer */
        ret = usb_set_interface(usbdev, interface_number,
                                properties->altsetting);
        if (ret < 0) {
@@ -565,9 +612,8 @@ int line6_probe(struct usb_interface *interface,
                goto error;
        }
 
-       line6_get_interval(line6);
-
        if (properties->capabilities & LINE6_CAP_CONTROL) {
+               line6_get_interval(line6);
                ret = line6_init_cap_control(line6);
                if (ret < 0)
                        goto error;