aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci
diff options
context:
space:
mode:
authorVille Syrjala <syrjala@sci.fi>2005-05-12 08:19:32 -0400
committerJaroslav Kysela <perex@suse.cz>2005-05-29 04:08:23 -0400
commitdb68d15da00f64bef2c8c822baab42aff39ae774 (patch)
tree193afef1ba4936b7265886360008305024429b5a /sound/pci
parent88491386be67f659e6b2c76c7463c997ce4c4ebb (diff)
[ALSA] maestro3: Add HW volume button support
Maestro3 driver Add support for hardware volume buttons. Signed-off-by: Ville Syrjala <syrjala@sci.fi> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci')
-rw-r--r--sound/pci/maestro3.c107
1 files changed, 103 insertions, 4 deletions
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 293cc10e3cbb..c1c7eeeb199b 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -851,7 +851,12 @@ struct snd_m3 {
851 m3_dma_t *substreams; 851 m3_dma_t *substreams;
852 852
853 spinlock_t reg_lock; 853 spinlock_t reg_lock;
854 spinlock_t ac97_lock;
854 855
856 snd_kcontrol_t *master_switch;
857 snd_kcontrol_t *master_volume;
858 struct tasklet_struct hwvol_tq;
859
855#ifdef CONFIG_PM 860#ifdef CONFIG_PM
856 u16 *suspend_mem; 861 u16 *suspend_mem;
857#endif 862#endif
@@ -1565,6 +1570,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s)
1565 } 1570 }
1566} 1571}
1567 1572
1573static void snd_m3_update_hw_volume(unsigned long private_data)
1574{
1575 m3_t *chip = (m3_t *) private_data;
1576 int x, val;
1577 unsigned long flags;
1578
1579 /* Figure out which volume control button was pushed,
1580 based on differences from the default register
1581 values. */
1582 x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
1583
1584 /* Reset the volume control registers. */
1585 outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
1586 outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
1587 outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
1588 outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
1589
1590 if (!chip->master_switch || !chip->master_volume)
1591 return;
1592
1593 /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
1594 spin_lock_irqsave(&chip->ac97_lock, flags);
1595
1596 val = chip->ac97->regs[AC97_MASTER_VOL];
1597 switch (x) {
1598 case 0x88:
1599 /* mute */
1600 val ^= 0x8000;
1601 chip->ac97->regs[AC97_MASTER_VOL] = val;
1602 outw(val, chip->iobase + CODEC_DATA);
1603 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1604 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1605 &chip->master_switch->id);
1606 break;
1607 case 0xaa:
1608 /* volume up */
1609 if ((val & 0x7f) > 0)
1610 val--;
1611 if ((val & 0x7f00) > 0)
1612 val -= 0x0100;
1613 chip->ac97->regs[AC97_MASTER_VOL] = val;
1614 outw(val, chip->iobase + CODEC_DATA);
1615 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1616 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1617 &chip->master_volume->id);
1618 break;
1619 case 0x66:
1620 /* volume down */
1621 if ((val & 0x7f) < 0x1f)
1622 val++;
1623 if ((val & 0x7f00) < 0x1f00)
1624 val += 0x0100;
1625 chip->ac97->regs[AC97_MASTER_VOL] = val;
1626 outw(val, chip->iobase + CODEC_DATA);
1627 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1628 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1629 &chip->master_volume->id);
1630 break;
1631 }
1632 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1633}
1634
1568static irqreturn_t 1635static irqreturn_t
1569snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) 1636snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1570{ 1637{
@@ -1576,7 +1643,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1576 1643
1577 if (status == 0xff) 1644 if (status == 0xff)
1578 return IRQ_NONE; 1645 return IRQ_NONE;
1579 1646
1647 if (status & HV_INT_PENDING)
1648 tasklet_hi_schedule(&chip->hwvol_tq);
1649
1580 /* 1650 /*
1581 * ack an assp int if its running 1651 * ack an assp int if its running
1582 * and has an int pending 1652 * and has an int pending
@@ -1842,24 +1912,32 @@ static unsigned short
1842snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) 1912snd_m3_ac97_read(ac97_t *ac97, unsigned short reg)
1843{ 1913{
1844 m3_t *chip = ac97->private_data; 1914 m3_t *chip = ac97->private_data;
1915 unsigned long flags;
1916 unsigned short data;
1845 1917
1846 if (snd_m3_ac97_wait(chip)) 1918 if (snd_m3_ac97_wait(chip))
1847 return 0xffff; 1919 return 0xffff;
1920 spin_lock_irqsave(&chip->ac97_lock, flags);
1848 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); 1921 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
1849 if (snd_m3_ac97_wait(chip)) 1922 if (snd_m3_ac97_wait(chip))
1850 return 0xffff; 1923 return 0xffff;
1851 return snd_m3_inw(chip, CODEC_DATA); 1924 data = snd_m3_inw(chip, CODEC_DATA);
1925 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1926 return data;
1852} 1927}
1853 1928
1854static void 1929static void
1855snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) 1930snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
1856{ 1931{
1857 m3_t *chip = ac97->private_data; 1932 m3_t *chip = ac97->private_data;
1933 unsigned long flags;
1858 1934
1859 if (snd_m3_ac97_wait(chip)) 1935 if (snd_m3_ac97_wait(chip))
1860 return; 1936 return;
1937 spin_lock_irqsave(&chip->ac97_lock, flags);
1861 snd_m3_outw(chip, val, CODEC_DATA); 1938 snd_m3_outw(chip, val, CODEC_DATA);
1862 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); 1939 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
1940 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1863} 1941}
1864 1942
1865 1943
@@ -1968,6 +2046,7 @@ static int __devinit snd_m3_mixer(m3_t *chip)
1968{ 2046{
1969 ac97_bus_t *pbus; 2047 ac97_bus_t *pbus;
1970 ac97_template_t ac97; 2048 ac97_template_t ac97;
2049 snd_ctl_elem_id_t id;
1971 int err; 2050 int err;
1972 static ac97_bus_ops_t ops = { 2051 static ac97_bus_ops_t ops = {
1973 .write = snd_m3_ac97_write, 2052 .write = snd_m3_ac97_write,
@@ -1988,6 +2067,15 @@ static int __devinit snd_m3_mixer(m3_t *chip)
1988 schedule_timeout(HZ / 10); 2067 schedule_timeout(HZ / 10);
1989 snd_ac97_write(chip->ac97, AC97_PCM, 0); 2068 snd_ac97_write(chip->ac97, AC97_PCM, 0);
1990 2069
2070 memset(&id, 0, sizeof(id));
2071 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2072 strcpy(id.name, "Master Playback Switch");
2073 chip->master_switch = snd_ctl_find_id(chip->card, &id);
2074 memset(&id, 0, sizeof(id));
2075 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2076 strcpy(id.name, "Master Playback Volume");
2077 chip->master_volume = snd_ctl_find_id(chip->card, &id);
2078
1991 return 0; 2079 return 0;
1992} 2080}
1993 2081
@@ -2293,6 +2381,7 @@ static int
2293snd_m3_chip_init(m3_t *chip) 2381snd_m3_chip_init(m3_t *chip)
2294{ 2382{
2295 struct pci_dev *pcidev = chip->pci; 2383 struct pci_dev *pcidev = chip->pci;
2384 unsigned long io = chip->iobase;
2296 u32 n; 2385 u32 n;
2297 u16 w; 2386 u16 w;
2298 u8 t; /* makes as much sense as 'n', no? */ 2387 u8 t; /* makes as much sense as 'n', no? */
@@ -2304,7 +2393,8 @@ snd_m3_chip_init(m3_t *chip)
2304 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); 2393 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
2305 2394
2306 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); 2395 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
2307 n &= REDUCED_DEBOUNCE; 2396 n &= ~HV_BUTTON_FROM_GD;
2397 n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE;
2308 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 2398 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
2309 pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); 2399 pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
2310 2400
@@ -2332,6 +2422,12 @@ snd_m3_chip_init(m3_t *chip)
2332 2422
2333 outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); 2423 outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B);
2334 2424
2425 outb(0x00, io + HARDWARE_VOL_CTRL);
2426 outb(0x88, io + SHADOW_MIX_REG_VOICE);
2427 outb(0x88, io + HW_VOL_COUNTER_VOICE);
2428 outb(0x88, io + SHADOW_MIX_REG_MASTER);
2429 outb(0x88, io + HW_VOL_COUNTER_MASTER);
2430
2335 return 0; 2431 return 0;
2336} 2432}
2337 2433
@@ -2341,7 +2437,7 @@ snd_m3_enable_ints(m3_t *chip)
2341 unsigned long io = chip->iobase; 2437 unsigned long io = chip->iobase;
2342 2438
2343 /* TODO: MPU401 not supported yet */ 2439 /* TODO: MPU401 not supported yet */
2344 outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); 2440 outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL);
2345 outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, 2441 outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
2346 io + ASSP_CONTROL_C); 2442 io + ASSP_CONTROL_C);
2347} 2443}
@@ -2593,6 +2689,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
2593 return err; 2689 return err;
2594 } 2690 }
2595 2691
2692 spin_lock_init(&chip->ac97_lock);
2693 tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
2694
2596 if ((err = snd_m3_mixer(chip)) < 0) 2695 if ((err = snd_m3_mixer(chip)) < 0)
2597 return err; 2696 return err;
2598 2697