[kernel] r19716 - in dists/trunk/linux/debian: . patches patches/bugfix/all
Ben Hutchings
benh at alioth.debian.org
Sun Jan 6 21:24:31 UTC 2013
Author: benh
Date: Sun Jan 6 21:24:30 2013
New Revision: 19716
Log:
ALSA: usb-audio: Avoid autopm calls after disconnection; Fix missing autopm for MIDI input (Closes: #664068)
Added:
dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Avoid-autopm-calls-after-disconnectio.patch
dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Fix-missing-autopm-for-MIDI-input.patch
Modified:
dists/trunk/linux/debian/changelog
dists/trunk/linux/debian/patches/series
Modified: dists/trunk/linux/debian/changelog
==============================================================================
--- dists/trunk/linux/debian/changelog Sun Jan 6 21:20:45 2013 (r19715)
+++ dists/trunk/linux/debian/changelog Sun Jan 6 21:24:30 2013 (r19716)
@@ -6,6 +6,8 @@
* ath6kl: Do not use virt_addr_valid() (fixes FTBFS on mips,mipsel)
* [armel/iop32x,armel/ixp4xx] Make IPV6 a module again due to kernel
size limit (fixes FTBFS)
+ * ALSA: usb-audio: Avoid autopm calls after disconnection; Fix missing
+ autopm for MIDI input (Closes: #664068)
-- Ben Hutchings <ben at decadent.org.uk> Sun, 06 Jan 2013 04:39:12 +0000
Added: dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Avoid-autopm-calls-after-disconnectio.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Avoid-autopm-calls-after-disconnectio.patch Sun Jan 6 21:24:30 2013 (r19716)
@@ -0,0 +1,101 @@
+From: Takashi Iwai <tiwai at suse.de>
+Date: Mon, 3 Dec 2012 11:12:46 +0100
+Subject: [1/2] ALSA: usb-audio: Avoid autopm calls after disconnection
+
+commit 59866da9e4ae54819e3c4e0a8f426bdb0c2ef993 upstream.
+
+Add a similar protection against the disconnection race and the
+invalid use of usb instance after disconnection, as well as we've done
+for the USB audio PCM.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=51201
+
+Reviewd-by: Clemens Ladisch <clemens at ladisch.de>
+Tested-by: Clemens Ladisch <clemens at ladisch.de>
+Signed-off-by: Takashi Iwai <tiwai at suse.de>
+---
+ sound/usb/midi.c | 23 ++++++++++++++++++++++-
+ 1 file changed, 22 insertions(+), 1 deletion(-)
+
+diff --git a/sound/usb/midi.c b/sound/usb/midi.c
+index eeefbce..c0054ee 100644
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -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;
+@@ -1038,6 +1039,12 @@ static void substream_open(struct snd_rawmidi_substream *substream, 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;
++ }
++
+ mutex_lock(&umidi->mutex);
+ if (open) {
+ if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
+@@ -1056,6 +1063,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open)
+ }
+ }
+ mutex_unlock(&umidi->mutex);
++ up_read(&umidi->disc_rwsem);
+ }
+
+ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
+@@ -1076,8 +1084,15 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
+ snd_BUG();
+ return -ENXIO;
+ }
++
++ down_read(&umidi->disc_rwsem);
++ if (umidi->disconnected) {
++ up_read(&umidi->disc_rwsem);
++ return -ENODEV;
++ }
+ err = usb_autopm_get_interface(umidi->iface);
+ port->autopm_reference = err >= 0;
++ up_read(&umidi->disc_rwsem);
+ if (err < 0 && err != -EACCES)
+ return -EIO;
+ substream->runtime->private_data = port;
+@@ -1092,8 +1107,10 @@ static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
+ struct usbmidi_out_port *port = substream->runtime->private_data;
+
+ substream_open(substream, 0);
+- if (port->autopm_reference)
++ down_read(&umidi->disc_rwsem);
++ if (!umidi->disconnected && port->autopm_reference)
+ usb_autopm_put_interface(umidi->iface);
++ up_read(&umidi->disc_rwsem);
+ return 0;
+ }
+
+@@ -1403,9 +1420,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)
+@@ -2117,6 +2137,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));
Added: dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Fix-missing-autopm-for-MIDI-input.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/trunk/linux/debian/patches/bugfix/all/ALSA-usb-audio-Fix-missing-autopm-for-MIDI-input.patch Sun Jan 6 21:24:30 2013 (r19716)
@@ -0,0 +1,217 @@
+From: Takashi Iwai <tiwai at suse.de>
+Date: Mon, 3 Dec 2012 11:30:50 +0100
+Subject: [2/2] ALSA: usb-audio: Fix missing autopm for MIDI input
+
+commit f5f165418cabf2218eb466c0e94693b8b1aee88b upstream.
+
+The commit [88a8516a: ALSA: usbaudio: implement USB autosuspend] added
+the support of autopm for USB MIDI output, but it didn't take the MIDI
+input into account.
+
+This patch adds the following for fixing the autopm:
+- Manage the URB start at the first MIDI input stream open, instead of
+ the time of instance creation
+- Move autopm code to the common substream_open()
+- Make snd_usbmidi_input_start/_stop() more robust and add the running
+ state check
+
+Reviewd-by: Clemens Ladisch <clemens at ladisch.de>
+Tested-by: Clemens Ladisch <clemens at ladisch.de>
+Signed-off-by: Takashi Iwai <tiwai at suse.de>
+---
+ sound/usb/midi.c | 88 ++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 46 insertions(+), 42 deletions(-)
+
+diff --git a/sound/usb/midi.c b/sound/usb/midi.c
+index c0054ee..34b9bb7 100644
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -126,8 +126,10 @@ struct snd_usb_midi {
+ struct snd_usb_midi_in_endpoint *in;
+ } endpoints[MIDI_MAX_ENDPOINTS];
+ unsigned long input_triggered;
+- unsigned int opened;
++ bool autopm_reference;
++ unsigned int opened[2];
+ unsigned char disconnected;
++ unsigned char input_running;
+
+ struct snd_kcontrol *roland_load_ctl;
+ };
+@@ -149,7 +151,6 @@ struct snd_usb_midi_out_endpoint {
+ struct snd_usb_midi_out_endpoint* ep;
+ struct snd_rawmidi_substream *substream;
+ int active;
+- bool autopm_reference;
+ uint8_t cable; /* cable number << 4 */
+ uint8_t state;
+ #define STATE_UNKNOWN 0
+@@ -1034,36 +1035,58 @@ 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;
++ int err;
+
+ down_read(&umidi->disc_rwsem);
+ if (umidi->disconnected) {
+ up_read(&umidi->disc_rwsem);
+- return;
++ 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]) {
++ err = usb_autopm_get_interface(umidi->iface);
++ umidi->autopm_reference = err >= 0;
++ if (err < 0 && err != -EACCES) {
++ mutex_unlock(&umidi->mutex);
++ up_read(&umidi->disc_rwsem);
++ return -EIO;
++ }
++ 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);
++ }
++ if (umidi->autopm_reference)
++ usb_autopm_put_interface(umidi->iface);
+ }
+ }
+ mutex_unlock(&umidi->mutex);
+ up_read(&umidi->disc_rwsem);
++ return 0;
+ }
+
+ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
+@@ -1071,7 +1094,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)
+@@ -1085,33 +1107,14 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
+ return -ENXIO;
+ }
+
+- down_read(&umidi->disc_rwsem);
+- if (umidi->disconnected) {
+- up_read(&umidi->disc_rwsem);
+- return -ENODEV;
+- }
+- err = usb_autopm_get_interface(umidi->iface);
+- port->autopm_reference = err >= 0;
+- up_read(&umidi->disc_rwsem);
+- if (err < 0 && err != -EACCES)
+- 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;
+- struct usbmidi_out_port *port = substream->runtime->private_data;
+-
+- substream_open(substream, 0);
+- down_read(&umidi->disc_rwsem);
+- if (!umidi->disconnected && port->autopm_reference)
+- usb_autopm_put_interface(umidi->iface);
+- up_read(&umidi->disc_rwsem);
+- return 0;
++ return substream_open(substream, 0, 0);
+ }
+
+ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
+@@ -1164,14 +1167,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)
+@@ -2080,12 +2081,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)
+@@ -2110,8 +2114,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;
+ }
+
+ /*
+@@ -2250,9 +2257,6 @@ int snd_usbmidi_create(struct snd_card *card,
+ }
+
+ 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;
+ }
+
Modified: dists/trunk/linux/debian/patches/series
==============================================================================
--- dists/trunk/linux/debian/patches/series Sun Jan 6 21:20:45 2013 (r19715)
+++ dists/trunk/linux/debian/patches/series Sun Jan 6 21:24:30 2013 (r19716)
@@ -70,3 +70,5 @@
debian/mgag200-disable-autoload.patch
clean-modules-without-link-vmlinux.sh.patch
bugfix/all/ath6kl-do-not-use-virt_addr_valid.patch
+bugfix/all/ALSA-usb-audio-Avoid-autopm-calls-after-disconnectio.patch
+bugfix/all/ALSA-usb-audio-Fix-missing-autopm-for-MIDI-input.patch
More information about the Kernel-svn-changes
mailing list