mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-04-10 16:23:42 +00:00
ALSA: usb-audio: Fix missing autopm for MIDI input
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@ladisch.de>
Tested-by: Clemens Ladisch <clemens@ladisch.de>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
59866da9e4
commit
f5f165418c
1 changed files with 46 additions and 42 deletions
|
@ -126,8 +126,10 @@ struct snd_usb_midi {
|
||||||
struct snd_usb_midi_in_endpoint *in;
|
struct snd_usb_midi_in_endpoint *in;
|
||||||
} endpoints[MIDI_MAX_ENDPOINTS];
|
} endpoints[MIDI_MAX_ENDPOINTS];
|
||||||
unsigned long input_triggered;
|
unsigned long input_triggered;
|
||||||
unsigned int opened;
|
bool autopm_reference;
|
||||||
|
unsigned int opened[2];
|
||||||
unsigned char disconnected;
|
unsigned char disconnected;
|
||||||
|
unsigned char input_running;
|
||||||
|
|
||||||
struct snd_kcontrol *roland_load_ctl;
|
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_usb_midi_out_endpoint* ep;
|
||||||
struct snd_rawmidi_substream *substream;
|
struct snd_rawmidi_substream *substream;
|
||||||
int active;
|
int active;
|
||||||
bool autopm_reference;
|
|
||||||
uint8_t cable; /* cable number << 4 */
|
uint8_t cable; /* cable number << 4 */
|
||||||
uint8_t state;
|
uint8_t state;
|
||||||
#define STATE_UNKNOWN 0
|
#define STATE_UNKNOWN 0
|
||||||
|
@ -1034,36 +1035,58 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi)
|
||||||
snd_usbmidi_input_start(&umidi->list);
|
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_usb_midi* umidi = substream->rmidi->private_data;
|
||||||
struct snd_kcontrol *ctl;
|
struct snd_kcontrol *ctl;
|
||||||
|
int err;
|
||||||
|
|
||||||
down_read(&umidi->disc_rwsem);
|
down_read(&umidi->disc_rwsem);
|
||||||
if (umidi->disconnected) {
|
if (umidi->disconnected) {
|
||||||
up_read(&umidi->disc_rwsem);
|
up_read(&umidi->disc_rwsem);
|
||||||
return;
|
return open ? -ENODEV : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&umidi->mutex);
|
mutex_lock(&umidi->mutex);
|
||||||
if (open) {
|
if (open) {
|
||||||
if (umidi->opened++ == 0 && umidi->roland_load_ctl) {
|
if (!umidi->opened[0] && !umidi->opened[1]) {
|
||||||
ctl = umidi->roland_load_ctl;
|
err = usb_autopm_get_interface(umidi->iface);
|
||||||
ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
umidi->autopm_reference = err >= 0;
|
||||||
snd_ctl_notify(umidi->card,
|
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);
|
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 {
|
} else {
|
||||||
if (--umidi->opened == 0 && umidi->roland_load_ctl) {
|
umidi->opened[dir]--;
|
||||||
ctl = umidi->roland_load_ctl;
|
if (!umidi->opened[1])
|
||||||
ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
|
snd_usbmidi_input_stop(&umidi->list);
|
||||||
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);
|
SNDRV_CTL_EVENT_MASK_INFO, &ctl->id);
|
||||||
|
}
|
||||||
|
if (umidi->autopm_reference)
|
||||||
|
usb_autopm_put_interface(umidi->iface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&umidi->mutex);
|
mutex_unlock(&umidi->mutex);
|
||||||
up_read(&umidi->disc_rwsem);
|
up_read(&umidi->disc_rwsem);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
|
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 snd_usb_midi* umidi = substream->rmidi->private_data;
|
||||||
struct usbmidi_out_port* port = NULL;
|
struct usbmidi_out_port* port = NULL;
|
||||||
int i, j;
|
int i, j;
|
||||||
int err;
|
|
||||||
|
|
||||||
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
|
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
|
||||||
if (umidi->endpoints[i].out)
|
if (umidi->endpoints[i].out)
|
||||||
|
@ -1085,33 +1107,14 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream)
|
||||||
return -ENXIO;
|
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;
|
substream->runtime->private_data = port;
|
||||||
port->state = STATE_UNKNOWN;
|
port->state = STATE_UNKNOWN;
|
||||||
substream_open(substream, 1);
|
return substream_open(substream, 0, 1);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_usbmidi_output_close(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;
|
return substream_open(substream, 0, 0);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, int up)
|
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)
|
static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream)
|
||||||
{
|
{
|
||||||
substream_open(substream, 1);
|
return substream_open(substream, 1, 1);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
|
static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream)
|
||||||
{
|
{
|
||||||
substream_open(substream, 0);
|
return substream_open(substream, 1, 0);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void snd_usbmidi_input_trigger(struct snd_rawmidi_substream *substream, int up)
|
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;
|
unsigned int i, j;
|
||||||
|
|
||||||
umidi = list_entry(p, struct snd_usb_midi, list);
|
umidi = list_entry(p, struct snd_usb_midi, list);
|
||||||
|
if (!umidi->input_running)
|
||||||
|
return;
|
||||||
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
|
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) {
|
||||||
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
|
struct snd_usb_midi_endpoint* ep = &umidi->endpoints[i];
|
||||||
if (ep->in)
|
if (ep->in)
|
||||||
for (j = 0; j < INPUT_URBS; ++j)
|
for (j = 0; j < INPUT_URBS; ++j)
|
||||||
usb_kill_urb(ep->in->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)
|
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;
|
int i;
|
||||||
|
|
||||||
umidi = list_entry(p, struct snd_usb_midi, list);
|
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)
|
for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i)
|
||||||
snd_usbmidi_input_start_ep(umidi->endpoints[i].in);
|
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);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue