git.openpandora.org
/
pandora-kernel.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
ALSA: usb-audio: Avoid autopm calls after disconnection
[pandora-kernel.git]
/
sound
/
usb
/
midi.c
diff --git
a/sound/usb/midi.c
b/sound/usb/midi.c
index
c83f614
..
c0054ee
100644
(file)
--- 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 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;
struct mutex mutex;
u32 usb_id;
int next_midi_device;
@@
-148,6
+149,7
@@
struct snd_usb_midi_out_endpoint {
struct snd_usb_midi_out_endpoint* ep;
struct snd_rawmidi_substream *substream;
int active;
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
uint8_t cable; /* cable number << 4 */
uint8_t state;
#define STATE_UNKNOWN 0
@@
-1037,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;
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) {
mutex_lock(&umidi->mutex);
if (open) {
if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
@@
-1055,6
+1063,7
@@
static void substream_open(struct snd_rawmidi_substream *substream, int open)
}
}
mutex_unlock(&umidi->mutex);
}
}
mutex_unlock(&umidi->mutex);
+ up_read(&umidi->disc_rwsem);
}
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
}
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
@@
-1075,8
+1084,16
@@
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
snd_BUG();
return -ENXIO;
}
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);
err = usb_autopm_get_interface(umidi->iface);
- if (err < 0)
+ 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;
return -EIO;
substream->runtime->private_data = port;
port->state = STATE_UNKNOWN;
@@
-1087,9
+1104,13
@@
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream)
{
struct snd_usb_midi* umidi = substream->rmidi->private_data;
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);
substream_open(substream, 0);
- usb_autopm_put_interface(umidi->iface);
+ 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 0;
}
@@
-1399,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
*/
* 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);
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)
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
if (ep->out)
@@
-2113,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);
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));
mutex_init(&umidi->mutex);
umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor),
le16_to_cpu(umidi->dev->descriptor.idProduct));