ALSA: es1968,maestro3 - Use work for hw-volume control

Instead of tasklet, use workq for handling the hw-volume control.
This reduces lots of spinlocks.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2011-06-14 13:57:02 +02:00
parent 85e4d95da0
commit 30bdee0259
2 changed files with 23 additions and 112 deletions

View File

@ -554,9 +554,8 @@ struct es1968 {
#else #else
struct snd_kcontrol *master_switch; /* for h/w volume control */ struct snd_kcontrol *master_switch; /* for h/w volume control */
struct snd_kcontrol *master_volume; struct snd_kcontrol *master_volume;
spinlock_t ac97_lock;
struct tasklet_struct hwvol_tq;
#endif #endif
struct work_struct hwvol_work;
#ifdef CONFIG_SND_ES1968_RADIO #ifdef CONFIG_SND_ES1968_RADIO
struct snd_tea575x tea; struct snd_tea575x tea;
@ -646,38 +645,23 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip)
static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
{ {
struct es1968 *chip = ac97->private_data; struct es1968 *chip = ac97->private_data;
#ifndef CONFIG_SND_ES1968_INPUT
unsigned long flags;
#endif
snd_es1968_ac97_wait(chip); snd_es1968_ac97_wait(chip);
/* Write the bus */ /* Write the bus */
#ifndef CONFIG_SND_ES1968_INPUT
spin_lock_irqsave(&chip->ac97_lock, flags);
#endif
outw(val, chip->io_port + ESM_AC97_DATA); outw(val, chip->io_port + ESM_AC97_DATA);
/*msleep(1);*/ /*msleep(1);*/
outb(reg, chip->io_port + ESM_AC97_INDEX); outb(reg, chip->io_port + ESM_AC97_INDEX);
/*msleep(1);*/ /*msleep(1);*/
#ifndef CONFIG_SND_ES1968_INPUT
spin_unlock_irqrestore(&chip->ac97_lock, flags);
#endif
} }
static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{ {
u16 data = 0; u16 data = 0;
struct es1968 *chip = ac97->private_data; struct es1968 *chip = ac97->private_data;
#ifndef CONFIG_SND_ES1968_INPUT
unsigned long flags;
#endif
snd_es1968_ac97_wait(chip); snd_es1968_ac97_wait(chip);
#ifndef CONFIG_SND_ES1968_INPUT
spin_lock_irqsave(&chip->ac97_lock, flags);
#endif
outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX);
/*msleep(1);*/ /*msleep(1);*/
@ -685,9 +669,6 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short
data = inw(chip->io_port + ESM_AC97_DATA); data = inw(chip->io_port + ESM_AC97_DATA);
/*msleep(1);*/ /*msleep(1);*/
} }
#ifndef CONFIG_SND_ES1968_INPUT
spin_unlock_irqrestore(&chip->ac97_lock, flags);
#endif
return data; return data;
} }
@ -1904,13 +1885,10 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es)
(without wrap around) in response to volume button presses and then (without wrap around) in response to volume button presses and then
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
of a byte wide register. The meaning of bits 0 and 4 is unknown. */ of a byte wide register. The meaning of bits 0 and 4 is unknown. */
static void es1968_update_hw_volume(unsigned long private_data) static void es1968_update_hw_volume(struct work_struct *work)
{ {
struct es1968 *chip = (struct es1968 *) private_data; struct es1968 *chip = container_of(work, struct es1968, hwvol_work);
int x, val; int x, val;
#ifndef CONFIG_SND_ES1968_INPUT
unsigned long flags;
#endif
/* Figure out which volume control button was pushed, /* Figure out which volume control button was pushed,
based on differences from the default register based on differences from the default register
@ -1929,18 +1907,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
if (! chip->master_switch || ! chip->master_volume) if (! chip->master_switch || ! chip->master_volume)
return; return;
/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ val = snd_ac97_read(chip->ac97, AC97_MASTER);
spin_lock_irqsave(&chip->ac97_lock, flags);
val = chip->ac97->regs[AC97_MASTER];
switch (x) { switch (x) {
case 0x88: case 0x88:
/* mute */ /* mute */
val ^= 0x8000; val ^= 0x8000;
chip->ac97->regs[AC97_MASTER] = val;
outw(val, chip->io_port + ESM_AC97_DATA);
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_switch->id);
break; break;
case 0xaa: case 0xaa:
/* volume up */ /* volume up */
@ -1948,11 +1919,6 @@ static void es1968_update_hw_volume(unsigned long private_data)
val--; val--;
if ((val & 0x7f00) > 0) if ((val & 0x7f00) > 0)
val -= 0x0100; val -= 0x0100;
chip->ac97->regs[AC97_MASTER] = val;
outw(val, chip->io_port + ESM_AC97_DATA);
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_volume->id);
break; break;
case 0x66: case 0x66:
/* volume down */ /* volume down */
@ -1960,14 +1926,11 @@ static void es1968_update_hw_volume(unsigned long private_data)
val++; val++;
if ((val & 0x7f00) < 0x1f00) if ((val & 0x7f00) < 0x1f00)
val += 0x0100; val += 0x0100;
chip->ac97->regs[AC97_MASTER] = val;
outw(val, chip->io_port + ESM_AC97_DATA);
outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_volume->id);
break; break;
} }
spin_unlock_irqrestore(&chip->ac97_lock, flags); if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_volume->id);
#else #else
if (!chip->input_dev) if (!chip->input_dev)
return; return;
@ -2013,11 +1976,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id)
outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); outw(inw(chip->io_port + 4) & 1, chip->io_port + 4);
if (event & ESM_HWVOL_IRQ) if (event & ESM_HWVOL_IRQ)
#ifdef CONFIG_SND_ES1968_INPUT schedule_work(&chip->hwvol_work);
es1968_update_hw_volume((unsigned long)chip);
#else
tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */
#endif
/* else ack 'em all, i imagine */ /* else ack 'em all, i imagine */
outb(0xFF, chip->io_port + 0x1A); outb(0xFF, chip->io_port + 0x1A);
@ -2426,6 +2385,7 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state)
return 0; return 0;
chip->in_suspend = 1; chip->in_suspend = 1;
cancel_work_sync(&chip->hwvol_work);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm); snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97);
@ -2638,6 +2598,7 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = {
static int snd_es1968_free(struct es1968 *chip) static int snd_es1968_free(struct es1968 *chip)
{ {
cancel_work_sync(&chip->hwvol_work);
#ifdef CONFIG_SND_ES1968_INPUT #ifdef CONFIG_SND_ES1968_INPUT
if (chip->input_dev) if (chip->input_dev)
input_unregister_device(chip->input_dev); input_unregister_device(chip->input_dev);
@ -2728,10 +2689,7 @@ static int __devinit snd_es1968_create(struct snd_card *card,
INIT_LIST_HEAD(&chip->buf_list); INIT_LIST_HEAD(&chip->buf_list);
INIT_LIST_HEAD(&chip->substream_list); INIT_LIST_HEAD(&chip->substream_list);
mutex_init(&chip->memory_mutex); mutex_init(&chip->memory_mutex);
#ifndef CONFIG_SND_ES1968_INPUT INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume);
spin_lock_init(&chip->ac97_lock);
tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip);
#endif
chip->card = card; chip->card = card;
chip->pci = pci; chip->pci = pci;
chip->irq = -1; chip->irq = -1;

View File

@ -850,11 +850,10 @@ struct snd_m3 {
struct input_dev *input_dev; struct input_dev *input_dev;
char phys[64]; /* physical device path */ char phys[64]; /* physical device path */
#else #else
spinlock_t ac97_lock;
struct snd_kcontrol *master_switch; struct snd_kcontrol *master_switch;
struct snd_kcontrol *master_volume; struct snd_kcontrol *master_volume;
struct tasklet_struct hwvol_tq;
#endif #endif
struct work_struct hwvol_work;
unsigned int in_suspend; unsigned int in_suspend;
@ -1609,13 +1608,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s)
(without wrap around) in response to volume button presses and then (without wrap around) in response to volume button presses and then
generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7
of a byte wide register. The meaning of bits 0 and 4 is unknown. */ of a byte wide register. The meaning of bits 0 and 4 is unknown. */
static void snd_m3_update_hw_volume(unsigned long private_data) static void snd_m3_update_hw_volume(struct work_struct *work)
{ {
struct snd_m3 *chip = (struct snd_m3 *) private_data; struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work);
int x, val; int x, val;
#ifndef CONFIG_SND_MAESTRO3_INPUT
unsigned long flags;
#endif
/* Figure out which volume control button was pushed, /* Figure out which volume control button was pushed,
based on differences from the default register based on differences from the default register
@ -1645,21 +1641,13 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
if (!chip->master_switch || !chip->master_volume) if (!chip->master_switch || !chip->master_volume)
return; return;
/* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ val = snd_ac97_read(chip->ac97, AC97_MASTER);
spin_lock_irqsave(&chip->ac97_lock, flags);
val = chip->ac97->regs[AC97_MASTER_VOL];
switch (x) { switch (x) {
case 0x88: case 0x88:
/* The counters have not changed, yet we've received a HV /* The counters have not changed, yet we've received a HV
interrupt. According to tests run by various people this interrupt. According to tests run by various people this
happens when pressing the mute button. */ happens when pressing the mute button. */
val ^= 0x8000; val ^= 0x8000;
chip->ac97->regs[AC97_MASTER_VOL] = val;
outw(val, chip->iobase + CODEC_DATA);
outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_switch->id);
break; break;
case 0xaa: case 0xaa:
/* counters increased by 1 -> volume up */ /* counters increased by 1 -> volume up */
@ -1667,11 +1655,6 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
val--; val--;
if ((val & 0x7f00) > 0) if ((val & 0x7f00) > 0)
val -= 0x0100; val -= 0x0100;
chip->ac97->regs[AC97_MASTER_VOL] = val;
outw(val, chip->iobase + CODEC_DATA);
outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_volume->id);
break; break;
case 0x66: case 0x66:
/* counters decreased by 1 -> volume down */ /* counters decreased by 1 -> volume down */
@ -1679,14 +1662,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
val++; val++;
if ((val & 0x7f00) < 0x1f00) if ((val & 0x7f00) < 0x1f00)
val += 0x0100; val += 0x0100;
chip->ac97->regs[AC97_MASTER_VOL] = val;
outw(val, chip->iobase + CODEC_DATA);
outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_volume->id);
break; break;
} }
spin_unlock_irqrestore(&chip->ac97_lock, flags); if (snd_ac97_update(chip->ac97, AC97_MASTER, val))
snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
&chip->master_switch->id);
#else #else
if (!chip->input_dev) if (!chip->input_dev)
return; return;
@ -1730,11 +1710,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
return IRQ_NONE; return IRQ_NONE;
if (status & HV_INT_PENDING) if (status & HV_INT_PENDING)
#ifdef CONFIG_SND_MAESTRO3_INPUT schedule_work(&chip->hwvol_work);
snd_m3_update_hw_volume((unsigned long)chip);
#else
tasklet_schedule(&chip->hwvol_tq);
#endif
/* /*
* ack an assp int if its running * ack an assp int if its running
@ -2000,24 +1976,14 @@ static unsigned short
snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
{ {
struct snd_m3 *chip = ac97->private_data; struct snd_m3 *chip = ac97->private_data;
#ifndef CONFIG_SND_MAESTRO3_INPUT
unsigned long flags;
#endif
unsigned short data = 0xffff; unsigned short data = 0xffff;
if (snd_m3_ac97_wait(chip)) if (snd_m3_ac97_wait(chip))
goto fail; goto fail;
#ifndef CONFIG_SND_MAESTRO3_INPUT
spin_lock_irqsave(&chip->ac97_lock, flags);
#endif
snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
if (snd_m3_ac97_wait(chip)) if (snd_m3_ac97_wait(chip))
goto fail_unlock; goto fail;
data = snd_m3_inw(chip, CODEC_DATA); data = snd_m3_inw(chip, CODEC_DATA);
fail_unlock:
#ifndef CONFIG_SND_MAESTRO3_INPUT
spin_unlock_irqrestore(&chip->ac97_lock, flags);
#endif
fail: fail:
return data; return data;
} }
@ -2026,20 +1992,11 @@ static void
snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
{ {
struct snd_m3 *chip = ac97->private_data; struct snd_m3 *chip = ac97->private_data;
#ifndef CONFIG_SND_MAESTRO3_INPUT
unsigned long flags;
#endif
if (snd_m3_ac97_wait(chip)) if (snd_m3_ac97_wait(chip))
return; return;
#ifndef CONFIG_SND_MAESTRO3_INPUT
spin_lock_irqsave(&chip->ac97_lock, flags);
#endif
snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outw(chip, val, CODEC_DATA);
snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
#ifndef CONFIG_SND_MAESTRO3_INPUT
spin_unlock_irqrestore(&chip->ac97_lock, flags);
#endif
} }
@ -2458,6 +2415,7 @@ static int snd_m3_free(struct snd_m3 *chip)
struct m3_dma *s; struct m3_dma *s;
int i; int i;
cancel_work_sync(&chip->hwvol_work);
#ifdef CONFIG_SND_MAESTRO3_INPUT #ifdef CONFIG_SND_MAESTRO3_INPUT
if (chip->input_dev) if (chip->input_dev)
input_unregister_device(chip->input_dev); input_unregister_device(chip->input_dev);
@ -2511,6 +2469,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state)
return 0; return 0;
chip->in_suspend = 1; chip->in_suspend = 1;
cancel_work_sync(&chip->hwvol_work);
snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
snd_pcm_suspend_all(chip->pcm); snd_pcm_suspend_all(chip->pcm);
snd_ac97_suspend(chip->ac97); snd_ac97_suspend(chip->ac97);
@ -2667,9 +2626,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
} }
spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->reg_lock);
#ifndef CONFIG_SND_MAESTRO3_INPUT
spin_lock_init(&chip->ac97_lock);
#endif
switch (pci->device) { switch (pci->device) {
case PCI_DEVICE_ID_ESS_ALLEGRO: case PCI_DEVICE_ID_ESS_ALLEGRO:
@ -2683,6 +2639,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
chip->card = card; chip->card = card;
chip->pci = pci; chip->pci = pci;
chip->irq = -1; chip->irq = -1;
INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume);
chip->external_amp = enable_amp; chip->external_amp = enable_amp;
if (amp_gpio >= 0 && amp_gpio <= 0x0f) if (amp_gpio >= 0 && amp_gpio <= 0x0f)
@ -2752,10 +2709,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
snd_m3_hv_init(chip); snd_m3_hv_init(chip);
#ifndef CONFIG_SND_MAESTRO3_INPUT
tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
#endif
if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
KBUILD_MODNAME, chip)) { KBUILD_MODNAME, chip)) {
snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq);