diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-06-14 07:57:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-06-14 07:59:51 -0400 |
commit | 30bdee0259093e114c711943902c834e5c3326c5 (patch) | |
tree | db5f4c2eb1459a1ad210d8ae094c8e515141d6e8 /sound/pci/maestro3.c | |
parent | 85e4d95da091e35209338962eca232e70819a485 (diff) |
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>
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r-- | sound/pci/maestro3.c | 71 |
1 files changed, 12 insertions, 59 deletions
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 64f6f627f4c2..0378126e6272 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
@@ -850,11 +850,10 @@ struct snd_m3 { | |||
850 | struct input_dev *input_dev; | 850 | struct input_dev *input_dev; |
851 | char phys[64]; /* physical device path */ | 851 | char phys[64]; /* physical device path */ |
852 | #else | 852 | #else |
853 | spinlock_t ac97_lock; | ||
854 | struct snd_kcontrol *master_switch; | 853 | struct snd_kcontrol *master_switch; |
855 | struct snd_kcontrol *master_volume; | 854 | struct snd_kcontrol *master_volume; |
856 | struct tasklet_struct hwvol_tq; | ||
857 | #endif | 855 | #endif |
856 | struct work_struct hwvol_work; | ||
858 | 857 | ||
859 | unsigned int in_suspend; | 858 | unsigned int in_suspend; |
860 | 859 | ||
@@ -1609,13 +1608,10 @@ static void snd_m3_update_ptr(struct snd_m3 *chip, struct m3_dma *s) | |||
1609 | (without wrap around) in response to volume button presses and then | 1608 | (without wrap around) in response to volume button presses and then |
1610 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 | 1609 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 |
1611 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ | 1610 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ |
1612 | static void snd_m3_update_hw_volume(unsigned long private_data) | 1611 | static void snd_m3_update_hw_volume(struct work_struct *work) |
1613 | { | 1612 | { |
1614 | struct snd_m3 *chip = (struct snd_m3 *) private_data; | 1613 | struct snd_m3 *chip = container_of(work, struct snd_m3, hwvol_work); |
1615 | int x, val; | 1614 | int x, val; |
1616 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
1617 | unsigned long flags; | ||
1618 | #endif | ||
1619 | 1615 | ||
1620 | /* Figure out which volume control button was pushed, | 1616 | /* Figure out which volume control button was pushed, |
1621 | based on differences from the default register | 1617 | based on differences from the default register |
@@ -1645,21 +1641,13 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1645 | if (!chip->master_switch || !chip->master_volume) | 1641 | if (!chip->master_switch || !chip->master_volume) |
1646 | return; | 1642 | return; |
1647 | 1643 | ||
1648 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ | 1644 | val = snd_ac97_read(chip->ac97, AC97_MASTER); |
1649 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
1650 | |||
1651 | val = chip->ac97->regs[AC97_MASTER_VOL]; | ||
1652 | switch (x) { | 1645 | switch (x) { |
1653 | case 0x88: | 1646 | case 0x88: |
1654 | /* The counters have not changed, yet we've received a HV | 1647 | /* The counters have not changed, yet we've received a HV |
1655 | interrupt. According to tests run by various people this | 1648 | interrupt. According to tests run by various people this |
1656 | happens when pressing the mute button. */ | 1649 | happens when pressing the mute button. */ |
1657 | val ^= 0x8000; | 1650 | val ^= 0x8000; |
1658 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1659 | outw(val, chip->iobase + CODEC_DATA); | ||
1660 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1661 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1662 | &chip->master_switch->id); | ||
1663 | break; | 1651 | break; |
1664 | case 0xaa: | 1652 | case 0xaa: |
1665 | /* counters increased by 1 -> volume up */ | 1653 | /* counters increased by 1 -> volume up */ |
@@ -1667,11 +1655,6 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1667 | val--; | 1655 | val--; |
1668 | if ((val & 0x7f00) > 0) | 1656 | if ((val & 0x7f00) > 0) |
1669 | val -= 0x0100; | 1657 | val -= 0x0100; |
1670 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1671 | outw(val, chip->iobase + CODEC_DATA); | ||
1672 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1673 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1674 | &chip->master_volume->id); | ||
1675 | break; | 1658 | break; |
1676 | case 0x66: | 1659 | case 0x66: |
1677 | /* counters decreased by 1 -> volume down */ | 1660 | /* counters decreased by 1 -> volume down */ |
@@ -1679,14 +1662,11 @@ static void snd_m3_update_hw_volume(unsigned long private_data) | |||
1679 | val++; | 1662 | val++; |
1680 | if ((val & 0x7f00) < 0x1f00) | 1663 | if ((val & 0x7f00) < 0x1f00) |
1681 | val += 0x0100; | 1664 | val += 0x0100; |
1682 | chip->ac97->regs[AC97_MASTER_VOL] = val; | ||
1683 | outw(val, chip->iobase + CODEC_DATA); | ||
1684 | outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); | ||
1685 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1686 | &chip->master_volume->id); | ||
1687 | break; | 1665 | break; |
1688 | } | 1666 | } |
1689 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1667 | if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) |
1668 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1669 | &chip->master_switch->id); | ||
1690 | #else | 1670 | #else |
1691 | if (!chip->input_dev) | 1671 | if (!chip->input_dev) |
1692 | return; | 1672 | return; |
@@ -1730,11 +1710,7 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) | |||
1730 | return IRQ_NONE; | 1710 | return IRQ_NONE; |
1731 | 1711 | ||
1732 | if (status & HV_INT_PENDING) | 1712 | if (status & HV_INT_PENDING) |
1733 | #ifdef CONFIG_SND_MAESTRO3_INPUT | 1713 | schedule_work(&chip->hwvol_work); |
1734 | snd_m3_update_hw_volume((unsigned long)chip); | ||
1735 | #else | ||
1736 | tasklet_schedule(&chip->hwvol_tq); | ||
1737 | #endif | ||
1738 | 1714 | ||
1739 | /* | 1715 | /* |
1740 | * ack an assp int if its running | 1716 | * ack an assp int if its running |
@@ -2000,24 +1976,14 @@ static unsigned short | |||
2000 | snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 1976 | snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
2001 | { | 1977 | { |
2002 | struct snd_m3 *chip = ac97->private_data; | 1978 | struct snd_m3 *chip = ac97->private_data; |
2003 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2004 | unsigned long flags; | ||
2005 | #endif | ||
2006 | unsigned short data = 0xffff; | 1979 | unsigned short data = 0xffff; |
2007 | 1980 | ||
2008 | if (snd_m3_ac97_wait(chip)) | 1981 | if (snd_m3_ac97_wait(chip)) |
2009 | goto fail; | 1982 | goto fail; |
2010 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2011 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
2012 | #endif | ||
2013 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); | 1983 | snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); |
2014 | if (snd_m3_ac97_wait(chip)) | 1984 | if (snd_m3_ac97_wait(chip)) |
2015 | goto fail_unlock; | 1985 | goto fail; |
2016 | data = snd_m3_inw(chip, CODEC_DATA); | 1986 | data = snd_m3_inw(chip, CODEC_DATA); |
2017 | fail_unlock: | ||
2018 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2019 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
2020 | #endif | ||
2021 | fail: | 1987 | fail: |
2022 | return data; | 1988 | return data; |
2023 | } | 1989 | } |
@@ -2026,20 +1992,11 @@ static void | |||
2026 | snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) | 1992 | snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) |
2027 | { | 1993 | { |
2028 | struct snd_m3 *chip = ac97->private_data; | 1994 | struct snd_m3 *chip = ac97->private_data; |
2029 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2030 | unsigned long flags; | ||
2031 | #endif | ||
2032 | 1995 | ||
2033 | if (snd_m3_ac97_wait(chip)) | 1996 | if (snd_m3_ac97_wait(chip)) |
2034 | return; | 1997 | return; |
2035 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2036 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
2037 | #endif | ||
2038 | snd_m3_outw(chip, val, CODEC_DATA); | 1998 | snd_m3_outw(chip, val, CODEC_DATA); |
2039 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); | 1999 | snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); |
2040 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2041 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
2042 | #endif | ||
2043 | } | 2000 | } |
2044 | 2001 | ||
2045 | 2002 | ||
@@ -2458,6 +2415,7 @@ static int snd_m3_free(struct snd_m3 *chip) | |||
2458 | struct m3_dma *s; | 2415 | struct m3_dma *s; |
2459 | int i; | 2416 | int i; |
2460 | 2417 | ||
2418 | cancel_work_sync(&chip->hwvol_work); | ||
2461 | #ifdef CONFIG_SND_MAESTRO3_INPUT | 2419 | #ifdef CONFIG_SND_MAESTRO3_INPUT |
2462 | if (chip->input_dev) | 2420 | if (chip->input_dev) |
2463 | input_unregister_device(chip->input_dev); | 2421 | input_unregister_device(chip->input_dev); |
@@ -2511,6 +2469,7 @@ static int m3_suspend(struct pci_dev *pci, pm_message_t state) | |||
2511 | return 0; | 2469 | return 0; |
2512 | 2470 | ||
2513 | chip->in_suspend = 1; | 2471 | chip->in_suspend = 1; |
2472 | cancel_work_sync(&chip->hwvol_work); | ||
2514 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2473 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2515 | snd_pcm_suspend_all(chip->pcm); | 2474 | snd_pcm_suspend_all(chip->pcm); |
2516 | snd_ac97_suspend(chip->ac97); | 2475 | snd_ac97_suspend(chip->ac97); |
@@ -2667,9 +2626,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2667 | } | 2626 | } |
2668 | 2627 | ||
2669 | spin_lock_init(&chip->reg_lock); | 2628 | spin_lock_init(&chip->reg_lock); |
2670 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2671 | spin_lock_init(&chip->ac97_lock); | ||
2672 | #endif | ||
2673 | 2629 | ||
2674 | switch (pci->device) { | 2630 | switch (pci->device) { |
2675 | case PCI_DEVICE_ID_ESS_ALLEGRO: | 2631 | case PCI_DEVICE_ID_ESS_ALLEGRO: |
@@ -2683,6 +2639,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2683 | chip->card = card; | 2639 | chip->card = card; |
2684 | chip->pci = pci; | 2640 | chip->pci = pci; |
2685 | chip->irq = -1; | 2641 | chip->irq = -1; |
2642 | INIT_WORK(&chip->hwvol_work, snd_m3_update_hw_volume); | ||
2686 | 2643 | ||
2687 | chip->external_amp = enable_amp; | 2644 | chip->external_amp = enable_amp; |
2688 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) | 2645 | if (amp_gpio >= 0 && amp_gpio <= 0x0f) |
@@ -2752,10 +2709,6 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, | |||
2752 | 2709 | ||
2753 | snd_m3_hv_init(chip); | 2710 | snd_m3_hv_init(chip); |
2754 | 2711 | ||
2755 | #ifndef CONFIG_SND_MAESTRO3_INPUT | ||
2756 | tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); | ||
2757 | #endif | ||
2758 | |||
2759 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, | 2712 | if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, |
2760 | KBUILD_MODNAME, chip)) { | 2713 | KBUILD_MODNAME, chip)) { |
2761 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); | 2714 | snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); |