aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/maestro3.c
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-04-23 05:26:42 -0400
committerTakashi Iwai <tiwai@suse.de>2010-04-23 11:09:46 -0400
commiteb581adf25fe9e42197e591926de85459e68b9fd (patch)
tree9967f82156d9ab138c96adefa4771a420470fabe /sound/pci/maestro3.c
parent20133d4cd329af7a02ee5af36bba1796d5ff7b1d (diff)
ALSA: snd-maestro3: Make hardware volume buttons an input device (rev2)
While working on the sound suspend / resume problems with my laptop I noticed that the hardware volume handling code in essence just detects key presses, and then does some hardcoded modification of the master volume based on which key is pressed. This made me think that clearly the right thing to do here is just report these keypresses to userspace and let userspace decide what to with them. This patch adds a Kconfig option which when enabled reports the volume buttons as keypresses using an input device. When enabled this option also gets rid of the ugly direct ac97 writes from the tasklet, the ac97lock and the need for using a tasklet in general. As an added bonus the keys now work identical to volume keys on a (usb) keyboard with multimedia keys, providing visual feedback of the volume level change, and a better range of the volume control (with a properly configured desktop environment). Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r--sound/pci/maestro3.c116
1 files changed, 114 insertions, 2 deletions
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 53d2a5d61baf..217a4dcb259e 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -41,6 +41,7 @@
41#include <linux/vmalloc.h> 41#include <linux/vmalloc.h>
42#include <linux/moduleparam.h> 42#include <linux/moduleparam.h>
43#include <linux/firmware.h> 43#include <linux/firmware.h>
44#include <linux/input.h>
44#include <sound/core.h> 45#include <sound/core.h>
45#include <sound/info.h> 46#include <sound/info.h>
46#include <sound/control.h> 47#include <sound/control.h>
@@ -844,11 +845,17 @@ struct snd_m3 {
844 struct m3_dma *substreams; 845 struct m3_dma *substreams;
845 846
846 spinlock_t reg_lock; 847 spinlock_t reg_lock;
847 spinlock_t ac97_lock;
848 848
849#ifdef CONFIG_SND_MAESTRO3_INPUT
850 struct input_dev *input_dev;
851 char phys[64]; /* physical device path */
852#else
853 spinlock_t ac97_lock;
849 struct snd_kcontrol *master_switch; 854 struct snd_kcontrol *master_switch;
850 struct snd_kcontrol *master_volume; 855 struct snd_kcontrol *master_volume;
851 struct tasklet_struct hwvol_tq; 856 struct tasklet_struct hwvol_tq;
857#endif
858
852 unsigned int in_suspend; 859 unsigned int in_suspend;
853 860
854#ifdef CONFIG_PM 861#ifdef CONFIG_PM
@@ -1606,7 +1613,9 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
1606{ 1613{
1607 struct snd_m3 *chip = (struct snd_m3 *) private_data; 1614 struct snd_m3 *chip = (struct snd_m3 *) private_data;
1608 int x, val; 1615 int x, val;
1616#ifndef CONFIG_SND_MAESTRO3_INPUT
1609 unsigned long flags; 1617 unsigned long flags;
1618#endif
1610 1619
1611 /* Figure out which volume control button was pushed, 1620 /* Figure out which volume control button was pushed,
1612 based on differences from the default register 1621 based on differences from the default register
@@ -1632,6 +1641,7 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
1632 if (chip->in_suspend) 1641 if (chip->in_suspend)
1633 return; 1642 return;
1634 1643
1644#ifndef CONFIG_SND_MAESTRO3_INPUT
1635 if (!chip->master_switch || !chip->master_volume) 1645 if (!chip->master_switch || !chip->master_volume)
1636 return; 1646 return;
1637 1647
@@ -1677,6 +1687,35 @@ static void snd_m3_update_hw_volume(unsigned long private_data)
1677 break; 1687 break;
1678 } 1688 }
1679 spin_unlock_irqrestore(&chip->ac97_lock, flags); 1689 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1690#else
1691 if (!chip->input_dev)
1692 return;
1693
1694 val = 0;
1695 switch (x) {
1696 case 0x88:
1697 /* The counters have not changed, yet we've received a HV
1698 interrupt. According to tests run by various people this
1699 happens when pressing the mute button. */
1700 val = KEY_MUTE;
1701 break;
1702 case 0xaa:
1703 /* counters increased by 1 -> volume up */
1704 val = KEY_VOLUMEUP;
1705 break;
1706 case 0x66:
1707 /* counters decreased by 1 -> volume down */
1708 val = KEY_VOLUMEDOWN;
1709 break;
1710 }
1711
1712 if (val) {
1713 input_report_key(chip->input_dev, val, 1);
1714 input_sync(chip->input_dev);
1715 input_report_key(chip->input_dev, val, 0);
1716 input_sync(chip->input_dev);
1717 }
1718#endif
1680} 1719}
1681 1720
1682static irqreturn_t snd_m3_interrupt(int irq, void *dev_id) 1721static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
@@ -1691,7 +1730,11 @@ static irqreturn_t snd_m3_interrupt(int irq, void *dev_id)
1691 return IRQ_NONE; 1730 return IRQ_NONE;
1692 1731
1693 if (status & HV_INT_PENDING) 1732 if (status & HV_INT_PENDING)
1733#ifdef CONFIG_SND_MAESTRO3_INPUT
1734 snd_m3_update_hw_volume((unsigned long)chip);
1735#else
1694 tasklet_schedule(&chip->hwvol_tq); 1736 tasklet_schedule(&chip->hwvol_tq);
1737#endif
1695 1738
1696 /* 1739 /*
1697 * ack an assp int if its running 1740 * ack an assp int if its running
@@ -1957,18 +2000,24 @@ static unsigned short
1957snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg) 2000snd_m3_ac97_read(struct snd_ac97 *ac97, unsigned short reg)
1958{ 2001{
1959 struct snd_m3 *chip = ac97->private_data; 2002 struct snd_m3 *chip = ac97->private_data;
2003#ifndef CONFIG_SND_MAESTRO3_INPUT
1960 unsigned long flags; 2004 unsigned long flags;
2005#endif
1961 unsigned short data = 0xffff; 2006 unsigned short data = 0xffff;
1962 2007
1963 if (snd_m3_ac97_wait(chip)) 2008 if (snd_m3_ac97_wait(chip))
1964 goto fail; 2009 goto fail;
2010#ifndef CONFIG_SND_MAESTRO3_INPUT
1965 spin_lock_irqsave(&chip->ac97_lock, flags); 2011 spin_lock_irqsave(&chip->ac97_lock, flags);
2012#endif
1966 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); 2013 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
1967 if (snd_m3_ac97_wait(chip)) 2014 if (snd_m3_ac97_wait(chip))
1968 goto fail_unlock; 2015 goto fail_unlock;
1969 data = snd_m3_inw(chip, CODEC_DATA); 2016 data = snd_m3_inw(chip, CODEC_DATA);
1970fail_unlock: 2017fail_unlock:
2018#ifndef CONFIG_SND_MAESTRO3_INPUT
1971 spin_unlock_irqrestore(&chip->ac97_lock, flags); 2019 spin_unlock_irqrestore(&chip->ac97_lock, flags);
2020#endif
1972fail: 2021fail:
1973 return data; 2022 return data;
1974} 2023}
@@ -1977,14 +2026,20 @@ static void
1977snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) 2026snd_m3_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val)
1978{ 2027{
1979 struct snd_m3 *chip = ac97->private_data; 2028 struct snd_m3 *chip = ac97->private_data;
2029#ifndef CONFIG_SND_MAESTRO3_INPUT
1980 unsigned long flags; 2030 unsigned long flags;
2031#endif
1981 2032
1982 if (snd_m3_ac97_wait(chip)) 2033 if (snd_m3_ac97_wait(chip))
1983 return; 2034 return;
2035#ifndef CONFIG_SND_MAESTRO3_INPUT
1984 spin_lock_irqsave(&chip->ac97_lock, flags); 2036 spin_lock_irqsave(&chip->ac97_lock, flags);
2037#endif
1985 snd_m3_outw(chip, val, CODEC_DATA); 2038 snd_m3_outw(chip, val, CODEC_DATA);
1986 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); 2039 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
2040#ifndef CONFIG_SND_MAESTRO3_INPUT
1987 spin_unlock_irqrestore(&chip->ac97_lock, flags); 2041 spin_unlock_irqrestore(&chip->ac97_lock, flags);
2042#endif
1988} 2043}
1989 2044
1990 2045
@@ -2091,7 +2146,9 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
2091{ 2146{
2092 struct snd_ac97_bus *pbus; 2147 struct snd_ac97_bus *pbus;
2093 struct snd_ac97_template ac97; 2148 struct snd_ac97_template ac97;
2149#ifndef CONFIG_SND_MAESTRO3_INPUT
2094 struct snd_ctl_elem_id elem_id; 2150 struct snd_ctl_elem_id elem_id;
2151#endif
2095 int err; 2152 int err;
2096 static struct snd_ac97_bus_ops ops = { 2153 static struct snd_ac97_bus_ops ops = {
2097 .write = snd_m3_ac97_write, 2154 .write = snd_m3_ac97_write,
@@ -2111,6 +2168,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
2111 schedule_timeout_uninterruptible(msecs_to_jiffies(100)); 2168 schedule_timeout_uninterruptible(msecs_to_jiffies(100));
2112 snd_ac97_write(chip->ac97, AC97_PCM, 0); 2169 snd_ac97_write(chip->ac97, AC97_PCM, 0);
2113 2170
2171#ifndef CONFIG_SND_MAESTRO3_INPUT
2114 memset(&elem_id, 0, sizeof(elem_id)); 2172 memset(&elem_id, 0, sizeof(elem_id));
2115 elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 2173 elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2116 strcpy(elem_id.name, "Master Playback Switch"); 2174 strcpy(elem_id.name, "Master Playback Switch");
@@ -2119,6 +2177,7 @@ static int __devinit snd_m3_mixer(struct snd_m3 *chip)
2119 elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 2177 elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2120 strcpy(elem_id.name, "Master Playback Volume"); 2178 strcpy(elem_id.name, "Master Playback Volume");
2121 chip->master_volume = snd_ctl_find_id(chip->card, &elem_id); 2179 chip->master_volume = snd_ctl_find_id(chip->card, &elem_id);
2180#endif
2122 2181
2123 return 0; 2182 return 0;
2124} 2183}
@@ -2398,6 +2457,11 @@ static int snd_m3_free(struct snd_m3 *chip)
2398 struct m3_dma *s; 2457 struct m3_dma *s;
2399 int i; 2458 int i;
2400 2459
2460#ifdef CONFIG_SND_MAESTRO3_INPUT
2461 if (chip->input_dev)
2462 input_unregister_device(chip->input_dev);
2463#endif
2464
2401 if (chip->substreams) { 2465 if (chip->substreams) {
2402 spin_lock_irq(&chip->reg_lock); 2466 spin_lock_irq(&chip->reg_lock);
2403 for (i = 0; i < chip->num_substreams; i++) { 2467 for (i = 0; i < chip->num_substreams; i++) {
@@ -2524,6 +2588,41 @@ static int m3_resume(struct pci_dev *pci)
2524} 2588}
2525#endif /* CONFIG_PM */ 2589#endif /* CONFIG_PM */
2526 2590
2591#ifdef CONFIG_SND_MAESTRO3_INPUT
2592static int __devinit snd_m3_input_register(struct snd_m3 *chip)
2593{
2594 struct input_dev *input_dev;
2595 int err;
2596
2597 input_dev = input_allocate_device();
2598 if (!input_dev)
2599 return -ENOMEM;
2600
2601 snprintf(chip->phys, sizeof(chip->phys), "pci-%s/input0",
2602 pci_name(chip->pci));
2603
2604 input_dev->name = chip->card->driver;
2605 input_dev->phys = chip->phys;
2606 input_dev->id.bustype = BUS_PCI;
2607 input_dev->id.vendor = chip->pci->vendor;
2608 input_dev->id.product = chip->pci->device;
2609 input_dev->dev.parent = &chip->pci->dev;
2610
2611 __set_bit(EV_KEY, input_dev->evbit);
2612 __set_bit(KEY_MUTE, input_dev->keybit);
2613 __set_bit(KEY_VOLUMEDOWN, input_dev->keybit);
2614 __set_bit(KEY_VOLUMEUP, input_dev->keybit);
2615
2616 err = input_register_device(input_dev);
2617 if (err) {
2618 input_free_device(input_dev);
2619 return err;
2620 }
2621
2622 chip->input_dev = input_dev;
2623 return 0;
2624}
2625#endif /* CONFIG_INPUT */
2527 2626
2528/* 2627/*
2529 */ 2628 */
@@ -2567,7 +2666,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2567 } 2666 }
2568 2667
2569 spin_lock_init(&chip->reg_lock); 2668 spin_lock_init(&chip->reg_lock);
2669#ifndef CONFIG_SND_MAESTRO3_INPUT
2570 spin_lock_init(&chip->ac97_lock); 2670 spin_lock_init(&chip->ac97_lock);
2671#endif
2571 2672
2572 switch (pci->device) { 2673 switch (pci->device) {
2573 case PCI_DEVICE_ID_ESS_ALLEGRO: 2674 case PCI_DEVICE_ID_ESS_ALLEGRO:
@@ -2650,7 +2751,9 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2650 2751
2651 snd_m3_hv_init(chip); 2752 snd_m3_hv_init(chip);
2652 2753
2754#ifndef CONFIG_SND_MAESTRO3_INPUT
2653 tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); 2755 tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
2756#endif
2654 2757
2655 if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, 2758 if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED,
2656 card->driver, chip)) { 2759 card->driver, chip)) {
@@ -2682,7 +2785,16 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci,
2682 2785
2683 if ((err = snd_m3_pcm(chip, 0)) < 0) 2786 if ((err = snd_m3_pcm(chip, 0)) < 0)
2684 return err; 2787 return err;
2685 2788
2789#ifdef CONFIG_SND_MAESTRO3_INPUT
2790 if (chip->hv_config & HV_CTRL_ENABLE) {
2791 err = snd_m3_input_register(chip);
2792 if (err)
2793 snd_printk(KERN_WARNING "Input device registration "
2794 "failed with error %i", err);
2795 }
2796#endif
2797
2686 snd_m3_enable_ints(chip); 2798 snd_m3_enable_ints(chip);
2687 snd_m3_assp_continue(chip); 2799 snd_m3_assp_continue(chip);
2688 2800