ALSA: usb-audio: avoid freeing umidi object twice
[pandora-kernel.git] / sound / usb / midi.c
index c83f614..7b85324 100644 (file)
@@ -116,6 +116,7 @@ struct snd_usb_midi {
        struct list_head list;
        struct timer_list error_timer;
        spinlock_t disc_lock;
+       struct rw_semaphore disc_rwsem;
        struct mutex mutex;
        u32 usb_id;
        int next_midi_device;
@@ -125,8 +126,9 @@ struct snd_usb_midi {
                struct snd_usb_midi_in_endpoint *in;
        } endpoints[MIDI_MAX_ENDPOINTS];
        unsigned long input_triggered;
-       unsigned int opened;
+       unsigned int opened[2];
        unsigned char disconnected;
+       unsigned char input_running;
 
        struct snd_kcontrol *roland_load_ctl;
 };
@@ -172,6 +174,8 @@ struct snd_usb_midi_in_endpoint {
                u8 running_status_length;
        } ports[0x10];
        u8 seen_f5;
+       bool in_sysex;
+       u8 last_cin;
        u8 error_resubmit;
        int current_port;
 };
@@ -362,6 +366,8 @@ static void snd_usbmidi_error_timer(unsigned long data)
                if (in && in->error_resubmit) {
                        in->error_resubmit = 0;
                        for (j = 0; j < INPUT_URBS; ++j) {
+                               if (atomic_read(&in->urbs[j]->use_count))
+                                       continue;
                                in->urbs[j]->dev = umidi->dev;
                                snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
                        }
@@ -460,6 +466,39 @@ static void snd_usbmidi_maudio_broken_running_status_input(
                }
 }
 
+/*
+ * QinHeng CH345 is buggy: every second packet inside a SysEx has not CIN 4
+ * but the previously seen CIN, but still with three data bytes.
+ */
+static void ch345_broken_sysex_input(struct snd_usb_midi_in_endpoint *ep,
+                                    uint8_t *buffer, int buffer_length)
+{
+       unsigned int i, cin, length;
+
+       for (i = 0; i + 3 < buffer_length; i += 4) {
+               if (buffer[i] == 0 && i > 0)
+                       break;
+               cin = buffer[i] & 0x0f;
+               if (ep->in_sysex &&
+                   cin == ep->last_cin &&
+                   (buffer[i + 1 + (cin == 0x6)] & 0x80) == 0)
+                       cin = 0x4;
+#if 0
+               if (buffer[i + 1] == 0x90) {
+                       /*
+                        * Either a corrupted running status or a real note-on
+                        * message; impossible to detect reliably.
+                        */
+               }
+#endif
+               length = snd_usbmidi_cin_length[cin];
+               snd_usbmidi_input_data(ep, 0, &buffer[i + 1], length);
+               ep->in_sysex = cin == 0x4;
+               if (!ep->in_sysex)
+                       ep->last_cin = cin;
+       }
+}
+
 /*
  * CME protocol: like the standard protocol, but SysEx commands are sent as a
  * single USB packet preceded by a 0x0F byte.
@@ -646,6 +685,12 @@ static struct usb_protocol_ops snd_usbmidi_cme_ops = {
        .output_packet = snd_usbmidi_output_standard_packet,
 };
 
+static struct usb_protocol_ops snd_usbmidi_ch345_broken_sysex_ops = {
+       .input = ch345_broken_sysex_input,
+       .output = snd_usbmidi_standard_output,
+       .output_packet = snd_usbmidi_output_standard_packet,
+};
+
 /*
  * AKAI MPD16 protocol:
  *
@@ -1032,29 +1077,48 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)
        snd_usbmidi_input_start(&umidi->list);
 }
 
-static void substream_open(struct snd_rawmidi_substream *substream, int open)
+static int substream_open(struct snd_rawmidi_substream *substream, int dir,
+                         int open)
 {
        struct snd_usb_midi* umidi = substream->rmidi->private_data;
        struct snd_kcontrol *ctl;
 
+       down_read(&umidi->disc_rwsem);
+       if (umidi->disconnected) {
+               up_read(&umidi->disc_rwsem);
+               return open ? -ENODEV : 0;
+       }
+
        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,
+               if (!umidi->opened[0] && !umidi->opened[1]) {
+                       if (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);
+                               update_roland_altsetting(umidi);
+                       }
                }
+               umidi->opened[dir]++;
+               if (umidi->opened[1])
+                       snd_usbmidi_input_start(&umidi->list);
        } 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,
+               umidi->opened[dir]--;
+               if (!umidi->opened[1])
+                       snd_usbmidi_input_stop(&umidi->list);
+               if (!umidi->opened[0] && !umidi->opened[1]) {
+                       if (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);
+       up_read(&umidi->disc_rwsem);
+       return 0;
 }
 
 static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@ -1062,7 +1126,6 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
        struct snd_usb_midi* umidi = substream->rmidi->private_data;
        struct usbmidi_out_port* port = NULL;
        int i, j;
-       int err;
 
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
                if (umidi->endpoints[i].out)
@@ -1075,22 +1138,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
                snd_BUG();
                return -ENXIO;
        }
-       err = usb_autopm_get_interface(umidi->iface);
-       if (err < 0)
-               return -EIO;
+
        substream->runtime->private_data = port;
        port->state = STATE_UNKNOWN;
-       substream_open(substream, 1);
-       return 0;
+       return substream_open(substream, 0, 1);
 }
 
 static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
 {
-       struct snd_usb_midi* umidi = substream->rmidi->private_data;
-
-       substream_open(substream, 0);
-       usb_autopm_put_interface(umidi->iface);
-       return 0;
+       return substream_open(substream, 0, 0);
 }
 
 static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -1143,14 +1199,12 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
 
 static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
 {
-       substream_open(substream, 1);
-       return 0;
+       return substream_open(substream, 1, 1);
 }
 
 static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
 {
-       substream_open(substream, 0);
-       return 0;
+       return substream_open(substream, 1, 0);
 }
 
 static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
@@ -1313,6 +1367,7 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi,
                 * Various chips declare a packet size larger than 4 bytes, but
                 * do not actually work with larger packets:
                 */
+       case USB_ID(0x0a67, 0x5011): /* Medeli DD305 */
        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 */
@@ -1399,9 +1454,12 @@ void snd_usbmidi_disconnect(struct list_head* p)
         * a timer may submit an URB. To reliably break the cycle
         * a flag under lock must be used
         */
+       down_write(&umidi->disc_rwsem);
        spin_lock_irq(&umidi->disc_lock);
        umidi->disconnected = 1;
        spin_unlock_irq(&umidi->disc_lock);
+       up_write(&umidi->disc_rwsem);
+
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
                if (ep->out)
@@ -2056,12 +2114,15 @@ void snd_usbmidi_input_stop(struct list_head* p)
        unsigned int i, j;
 
        umidi = list_entry(p, struct snd_usb_midi, list);
+       if (!umidi->input_running)
+               return;
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
                struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
                if (ep->in)
                        for (j = 0; j < INPUT_URBS; ++j)
                                usb_kill_urb(ep->in->urbs[j]);
        }
+       umidi->input_running = 0;
 }
 
 static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep)
@@ -2086,8 +2147,11 @@ void snd_usbmidi_input_start(struct list_head* p)
        int i;
 
        umidi = list_entry(p, struct snd_usb_midi, list);
+       if (umidi->input_running || !umidi->opened[1])
+               return;
        for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
                snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
+       umidi->input_running = 1;
 }
 
 /*
@@ -2113,6 +2177,7 @@ int snd_usbmidi_create(struct snd_card *card,
        umidi->usb_protocol_ops = &snd_usbmidi_standard_ops;
        init_timer(&umidi->error_timer);
        spin_lock_init(&umidi->disc_lock);
+       init_rwsem(&umidi->disc_rwsem);
        mutex_init(&umidi->mutex);
        umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
                               le16_to_cpu(umidi->dev->descriptor.idProduct));
@@ -2189,6 +2254,10 @@ int snd_usbmidi_create(struct snd_card *card,
                if (err < 0)
                        break;
 
+               err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
+               break;
+       case QUIRK_MIDI_CH345:
+               umidi->usb_protocol_ops = &snd_usbmidi_ch345_broken_sysex_ops;
                err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints);
                break;
        default:
@@ -2220,14 +2289,12 @@ int snd_usbmidi_create(struct snd_card *card,
        else
                err = snd_usbmidi_create_endpoints(umidi, endpoints);
        if (err < 0) {
-               snd_usbmidi_free(umidi);
                return err;
        }
 
-       list_add_tail(&umidi->list, midi_list);
+       usb_autopm_get_interface_no_resume(umidi->iface);
 
-       for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
-               snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
+       list_add_tail(&umidi->list, midi_list);
        return 0;
 }