aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/maestro3.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r--sound/pci/maestro3.c222
1 files changed, 209 insertions, 13 deletions
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c
index 2cf33083d7cc..096f15132853 100644
--- a/sound/pci/maestro3.c
+++ b/sound/pci/maestro3.c
@@ -779,6 +779,12 @@ struct m3_quirk {
779 (e.g. for IrDA on Dell Inspirons) */ 779 (e.g. for IrDA on Dell Inspirons) */
780}; 780};
781 781
782struct m3_hv_quirk {
783 u16 vendor, device, subsystem_vendor, subsystem_device;
784 u32 config; /* ALLEGRO_CONFIG hardware volume bits */
785 int is_omnibook; /* Do HP OmniBook GPIO magic? */
786};
787
782struct m3_list { 788struct m3_list {
783 int curlen; 789 int curlen;
784 int mem_addr; 790 int mem_addr;
@@ -828,6 +834,7 @@ struct snd_m3 {
828 834
829 struct pci_dev *pci; 835 struct pci_dev *pci;
830 struct m3_quirk *quirk; 836 struct m3_quirk *quirk;
837 struct m3_hv_quirk *hv_quirk;
831 838
832 int dacs_active; 839 int dacs_active;
833 int timer_users; 840 int timer_users;
@@ -851,6 +858,11 @@ struct snd_m3 {
851 m3_dma_t *substreams; 858 m3_dma_t *substreams;
852 859
853 spinlock_t reg_lock; 860 spinlock_t reg_lock;
861 spinlock_t ac97_lock;
862
863 snd_kcontrol_t *master_switch;
864 snd_kcontrol_t *master_volume;
865 struct tasklet_struct hwvol_tq;
854 866
855#ifdef CONFIG_PM 867#ifdef CONFIG_PM
856 u16 *suspend_mem; 868 u16 *suspend_mem;
@@ -968,6 +980,71 @@ static struct m3_quirk m3_quirk_list[] = {
968 { NULL } 980 { NULL }
969}; 981};
970 982
983/* These values came from the Windows driver. */
984static struct m3_hv_quirk m3_hv_quirk_list[] = {
985 /* Allegro chips */
986 { 0x125D, 0x1988, 0x0E11, 0x002E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
987 { 0x125D, 0x1988, 0x0E11, 0x0094, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
988 { 0x125D, 0x1988, 0x0E11, 0xB112, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
989 { 0x125D, 0x1988, 0x0E11, 0xB114, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
990 { 0x125D, 0x1988, 0x103C, 0x0012, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
991 { 0x125D, 0x1988, 0x103C, 0x0018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
992 { 0x125D, 0x1988, 0x103C, 0x001C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
993 { 0x125D, 0x1988, 0x103C, 0x001D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
994 { 0x125D, 0x1988, 0x103C, 0x001E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
995 { 0x125D, 0x1988, 0x107B, 0x3350, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
996 { 0x125D, 0x1988, 0x10F7, 0x8338, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
997 { 0x125D, 0x1988, 0x10F7, 0x833C, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
998 { 0x125D, 0x1988, 0x10F7, 0x833D, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
999 { 0x125D, 0x1988, 0x10F7, 0x833E, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1000 { 0x125D, 0x1988, 0x10F7, 0x833F, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1001 { 0x125D, 0x1988, 0x13BD, 0x1018, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1002 { 0x125D, 0x1988, 0x13BD, 0x1019, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1003 { 0x125D, 0x1988, 0x13BD, 0x101A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1004 { 0x125D, 0x1988, 0x14FF, 0x0F03, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1005 { 0x125D, 0x1988, 0x14FF, 0x0F04, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1006 { 0x125D, 0x1988, 0x14FF, 0x0F05, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1007 { 0x125D, 0x1988, 0x156D, 0xB400, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1008 { 0x125D, 0x1988, 0x156D, 0xB795, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1009 { 0x125D, 0x1988, 0x156D, 0xB797, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1010 { 0x125D, 0x1988, 0x156D, 0xC700, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD, 0 },
1011 { 0x125D, 0x1988, 0x1033, 0x80F1, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1012 { 0x125D, 0x1988, 0x103C, 0x001A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 }, /* HP OmniBook 6100 */
1013 { 0x125D, 0x1988, 0x107B, 0x340A, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1014 { 0x125D, 0x1988, 0x107B, 0x3450, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1015 { 0x125D, 0x1988, 0x109F, 0x3134, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1016 { 0x125D, 0x1988, 0x109F, 0x3161, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1017 { 0x125D, 0x1988, 0x144D, 0x3280, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1018 { 0x125D, 0x1988, 0x144D, 0x3281, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1019 { 0x125D, 0x1988, 0x144D, 0xC002, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1020 { 0x125D, 0x1988, 0x144D, 0xC003, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1021 { 0x125D, 0x1988, 0x1509, 0x1740, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1022 { 0x125D, 0x1988, 0x1610, 0x0010, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD | REDUCED_DEBOUNCE, 0 },
1023 { 0x125D, 0x1988, 0x1042, 0x1042, HV_CTRL_ENABLE, 0 },
1024 { 0x125D, 0x1988, 0x107B, 0x9500, HV_CTRL_ENABLE, 0 },
1025 { 0x125D, 0x1988, 0x14FF, 0x0F06, HV_CTRL_ENABLE, 0 },
1026 { 0x125D, 0x1988, 0x1558, 0x8586, HV_CTRL_ENABLE, 0 },
1027 { 0x125D, 0x1988, 0x161F, 0x2011, HV_CTRL_ENABLE, 0 },
1028 /* Maestro3 chips */
1029 { 0x125D, 0x1998, 0x103C, 0x000E, HV_CTRL_ENABLE, 0 },
1030 { 0x125D, 0x1998, 0x103C, 0x0010, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 6000 */
1031 { 0x125D, 0x1998, 0x103C, 0x0011, HV_CTRL_ENABLE, 1 }, /* HP OmniBook 500 */
1032 { 0x125D, 0x1998, 0x103C, 0x001B, HV_CTRL_ENABLE, 0 },
1033 { 0x125D, 0x1998, 0x104D, 0x80A6, HV_CTRL_ENABLE, 0 },
1034 { 0x125D, 0x1998, 0x104D, 0x80AA, HV_CTRL_ENABLE, 0 },
1035 { 0x125D, 0x1998, 0x107B, 0x5300, HV_CTRL_ENABLE, 0 },
1036 { 0x125D, 0x1998, 0x110A, 0x1998, HV_CTRL_ENABLE, 0 },
1037 { 0x125D, 0x1998, 0x13BD, 0x1015, HV_CTRL_ENABLE, 0 },
1038 { 0x125D, 0x1998, 0x13BD, 0x101C, HV_CTRL_ENABLE, 0 },
1039 { 0x125D, 0x1998, 0x13BD, 0x1802, HV_CTRL_ENABLE, 0 },
1040 { 0x125D, 0x1998, 0x1599, 0x0715, HV_CTRL_ENABLE, 0 },
1041 { 0x125D, 0x1998, 0x5643, 0x5643, HV_CTRL_ENABLE, 0 },
1042 { 0x125D, 0x199A, 0x144D, 0x3260, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
1043 { 0x125D, 0x199A, 0x144D, 0x3261, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
1044 { 0x125D, 0x199A, 0x144D, 0xC000, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
1045 { 0x125D, 0x199A, 0x144D, 0xC001, HV_CTRL_ENABLE | REDUCED_DEBOUNCE, 0 },
1046 { 0 }
1047};
971 1048
972/* 1049/*
973 * lowlevel functions 1050 * lowlevel functions
@@ -1565,6 +1642,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s)
1565 } 1642 }
1566} 1643}
1567 1644
1645static void snd_m3_update_hw_volume(unsigned long private_data)
1646{
1647 m3_t *chip = (m3_t *) private_data;
1648 int x, val;
1649 unsigned long flags;
1650
1651 /* Figure out which volume control button was pushed,
1652 based on differences from the default register
1653 values. */
1654 x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee;
1655
1656 /* Reset the volume control registers. */
1657 outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE);
1658 outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE);
1659 outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER);
1660 outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER);
1661
1662 if (!chip->master_switch || !chip->master_volume)
1663 return;
1664
1665 /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */
1666 spin_lock_irqsave(&chip->ac97_lock, flags);
1667
1668 val = chip->ac97->regs[AC97_MASTER_VOL];
1669 switch (x) {
1670 case 0x88:
1671 /* mute */
1672 val ^= 0x8000;
1673 chip->ac97->regs[AC97_MASTER_VOL] = val;
1674 outw(val, chip->iobase + CODEC_DATA);
1675 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1676 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1677 &chip->master_switch->id);
1678 break;
1679 case 0xaa:
1680 /* volume up */
1681 if ((val & 0x7f) > 0)
1682 val--;
1683 if ((val & 0x7f00) > 0)
1684 val -= 0x0100;
1685 chip->ac97->regs[AC97_MASTER_VOL] = val;
1686 outw(val, chip->iobase + CODEC_DATA);
1687 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1688 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1689 &chip->master_volume->id);
1690 break;
1691 case 0x66:
1692 /* volume down */
1693 if ((val & 0x7f) < 0x1f)
1694 val++;
1695 if ((val & 0x7f00) < 0x1f00)
1696 val += 0x0100;
1697 chip->ac97->regs[AC97_MASTER_VOL] = val;
1698 outw(val, chip->iobase + CODEC_DATA);
1699 outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND);
1700 snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
1701 &chip->master_volume->id);
1702 break;
1703 }
1704 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1705}
1706
1568static irqreturn_t 1707static irqreturn_t
1569snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) 1708snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1570{ 1709{
@@ -1576,7 +1715,10 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1576 1715
1577 if (status == 0xff) 1716 if (status == 0xff)
1578 return IRQ_NONE; 1717 return IRQ_NONE;
1579 1718
1719 if (status & HV_INT_PENDING)
1720 tasklet_hi_schedule(&chip->hwvol_tq);
1721
1580 /* 1722 /*
1581 * ack an assp int if its running 1723 * ack an assp int if its running
1582 * and has an int pending 1724 * and has an int pending
@@ -1605,7 +1747,7 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
1605#endif 1747#endif
1606 1748
1607 /* ack ints */ 1749 /* ack ints */
1608 snd_m3_outw(chip, HOST_INT_STATUS, status); 1750 outb(status, chip->iobase + HOST_INT_STATUS);
1609 1751
1610 return IRQ_HANDLED; 1752 return IRQ_HANDLED;
1611} 1753}
@@ -1842,24 +1984,32 @@ static unsigned short
1842snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) 1984snd_m3_ac97_read(ac97_t *ac97, unsigned short reg)
1843{ 1985{
1844 m3_t *chip = ac97->private_data; 1986 m3_t *chip = ac97->private_data;
1987 unsigned long flags;
1988 unsigned short data;
1845 1989
1846 if (snd_m3_ac97_wait(chip)) 1990 if (snd_m3_ac97_wait(chip))
1847 return 0xffff; 1991 return 0xffff;
1992 spin_lock_irqsave(&chip->ac97_lock, flags);
1848 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); 1993 snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND);
1849 if (snd_m3_ac97_wait(chip)) 1994 if (snd_m3_ac97_wait(chip))
1850 return 0xffff; 1995 return 0xffff;
1851 return snd_m3_inw(chip, CODEC_DATA); 1996 data = snd_m3_inw(chip, CODEC_DATA);
1997 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1998 return data;
1852} 1999}
1853 2000
1854static void 2001static void
1855snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) 2002snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val)
1856{ 2003{
1857 m3_t *chip = ac97->private_data; 2004 m3_t *chip = ac97->private_data;
2005 unsigned long flags;
1858 2006
1859 if (snd_m3_ac97_wait(chip)) 2007 if (snd_m3_ac97_wait(chip))
1860 return; 2008 return;
2009 spin_lock_irqsave(&chip->ac97_lock, flags);
1861 snd_m3_outw(chip, val, CODEC_DATA); 2010 snd_m3_outw(chip, val, CODEC_DATA);
1862 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); 2011 snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND);
2012 spin_unlock_irqrestore(&chip->ac97_lock, flags);
1863} 2013}
1864 2014
1865 2015
@@ -1968,6 +2118,7 @@ static int __devinit snd_m3_mixer(m3_t *chip)
1968{ 2118{
1969 ac97_bus_t *pbus; 2119 ac97_bus_t *pbus;
1970 ac97_template_t ac97; 2120 ac97_template_t ac97;
2121 snd_ctl_elem_id_t id;
1971 int err; 2122 int err;
1972 static ac97_bus_ops_t ops = { 2123 static ac97_bus_ops_t ops = {
1973 .write = snd_m3_ac97_write, 2124 .write = snd_m3_ac97_write,
@@ -1988,6 +2139,15 @@ static int __devinit snd_m3_mixer(m3_t *chip)
1988 schedule_timeout(HZ / 10); 2139 schedule_timeout(HZ / 10);
1989 snd_ac97_write(chip->ac97, AC97_PCM, 0); 2140 snd_ac97_write(chip->ac97, AC97_PCM, 0);
1990 2141
2142 memset(&id, 0, sizeof(id));
2143 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2144 strcpy(id.name, "Master Playback Switch");
2145 chip->master_switch = snd_ctl_find_id(chip->card, &id);
2146 memset(&id, 0, sizeof(id));
2147 id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
2148 strcpy(id.name, "Master Playback Volume");
2149 chip->master_volume = snd_ctl_find_id(chip->card, &id);
2150
1991 return 0; 2151 return 0;
1992} 2152}
1993 2153
@@ -2293,6 +2453,7 @@ static int
2293snd_m3_chip_init(m3_t *chip) 2453snd_m3_chip_init(m3_t *chip)
2294{ 2454{
2295 struct pci_dev *pcidev = chip->pci; 2455 struct pci_dev *pcidev = chip->pci;
2456 unsigned long io = chip->iobase;
2296 u32 n; 2457 u32 n;
2297 u16 w; 2458 u16 w;
2298 u8 t; /* makes as much sense as 'n', no? */ 2459 u8 t; /* makes as much sense as 'n', no? */
@@ -2303,8 +2464,27 @@ snd_m3_chip_init(m3_t *chip)
2303 DISABLE_LEGACY); 2464 DISABLE_LEGACY);
2304 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); 2465 pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w);
2305 2466
2467 if (chip->hv_quirk && chip->hv_quirk->is_omnibook) {
2468 /*
2469 * Volume buttons on some HP OmniBook laptops don't work
2470 * correctly. This makes them work for the most part.
2471 *
2472 * Volume up and down buttons on the laptop side work.
2473 * Fn+cursor_up (volme up) works.
2474 * Fn+cursor_down (volume down) doesn't work.
2475 * Fn+F7 (mute) works acts as volume up.
2476 */
2477 outw(~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_MASK);
2478 outw(inw(io + GPIO_DIRECTION) & ~(GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DIRECTION);
2479 outw((GPI_VOL_DOWN|GPI_VOL_UP), io + GPIO_DATA);
2480 outw(0xffff, io + GPIO_MASK);
2481 }
2306 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); 2482 pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n);
2307 n &= REDUCED_DEBOUNCE; 2483 n &= ~(HV_CTRL_ENABLE | REDUCED_DEBOUNCE | HV_BUTTON_FROM_GD);
2484 if (chip->hv_quirk)
2485 n |= chip->hv_quirk->config;
2486 /* For some reason we must always use reduced debounce. */
2487 n |= REDUCED_DEBOUNCE;
2308 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; 2488 n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING;
2309 pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); 2489 pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n);
2310 2490
@@ -2332,6 +2512,12 @@ snd_m3_chip_init(m3_t *chip)
2332 2512
2333 outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); 2513 outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B);
2334 2514
2515 outb(0x00, io + HARDWARE_VOL_CTRL);
2516 outb(0x88, io + SHADOW_MIX_REG_VOICE);
2517 outb(0x88, io + HW_VOL_COUNTER_VOICE);
2518 outb(0x88, io + SHADOW_MIX_REG_MASTER);
2519 outb(0x88, io + HW_VOL_COUNTER_MASTER);
2520
2335 return 0; 2521 return 0;
2336} 2522}
2337 2523
@@ -2341,7 +2527,7 @@ snd_m3_enable_ints(m3_t *chip)
2341 unsigned long io = chip->iobase; 2527 unsigned long io = chip->iobase;
2342 2528
2343 /* TODO: MPU401 not supported yet */ 2529 /* TODO: MPU401 not supported yet */
2344 outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); 2530 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, 2531 outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE,
2346 io + ASSP_CONTROL_C); 2532 io + ASSP_CONTROL_C);
2347} 2533}
@@ -2367,7 +2553,7 @@ static int snd_m3_free(m3_t *chip)
2367 kfree(chip->substreams); 2553 kfree(chip->substreams);
2368 } 2554 }
2369 if (chip->iobase) { 2555 if (chip->iobase) {
2370 snd_m3_outw(chip, HOST_INT_CTRL, 0); /* disable ints */ 2556 outw(0, chip->iobase + HOST_INT_CTRL); /* disable ints */
2371 } 2557 }
2372 2558
2373#ifdef CONFIG_PM 2559#ifdef CONFIG_PM
@@ -2486,7 +2672,7 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
2486 m3_t *chip; 2672 m3_t *chip;
2487 int i, err; 2673 int i, err;
2488 struct m3_quirk *quirk; 2674 struct m3_quirk *quirk;
2489 u16 subsystem_vendor, subsystem_device; 2675 struct m3_hv_quirk *hv_quirk;
2490 static snd_device_ops_t ops = { 2676 static snd_device_ops_t ops = {
2491 .dev_free = snd_m3_dev_free, 2677 .dev_free = snd_m3_dev_free,
2492 }; 2678 };
@@ -2524,18 +2710,25 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
2524 chip->pci = pci; 2710 chip->pci = pci;
2525 chip->irq = -1; 2711 chip->irq = -1;
2526 2712
2527 pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor);
2528 pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device);
2529
2530 for (quirk = m3_quirk_list; quirk->vendor; quirk++) { 2713 for (quirk = m3_quirk_list; quirk->vendor; quirk++) {
2531 if (subsystem_vendor == quirk->vendor && 2714 if (pci->subsystem_vendor == quirk->vendor &&
2532 subsystem_device == quirk->device) { 2715 pci->subsystem_device == quirk->device) {
2533 printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name); 2716 printk(KERN_INFO "maestro3: enabled hack for '%s'\n", quirk->name);
2534 chip->quirk = quirk; 2717 chip->quirk = quirk;
2535 break; 2718 break;
2536 } 2719 }
2537 } 2720 }
2538 2721
2722 for (hv_quirk = m3_hv_quirk_list; hv_quirk->vendor; hv_quirk++) {
2723 if (pci->vendor == hv_quirk->vendor &&
2724 pci->device == hv_quirk->device &&
2725 pci->subsystem_vendor == hv_quirk->subsystem_vendor &&
2726 pci->subsystem_device == hv_quirk->subsystem_device) {
2727 chip->hv_quirk = hv_quirk;
2728 break;
2729 }
2730 }
2731
2539 chip->external_amp = enable_amp; 2732 chip->external_amp = enable_amp;
2540 if (amp_gpio >= 0 && amp_gpio <= 0x0f) 2733 if (amp_gpio >= 0 && amp_gpio <= 0x0f)
2541 chip->amp_gpio = amp_gpio; 2734 chip->amp_gpio = amp_gpio;
@@ -2593,6 +2786,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci,
2593 return err; 2786 return err;
2594 } 2787 }
2595 2788
2789 spin_lock_init(&chip->ac97_lock);
2790 tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip);
2791
2596 if ((err = snd_m3_mixer(chip)) < 0) 2792 if ((err = snd_m3_mixer(chip)) < 0)
2597 return err; 2793 return err;
2598 2794
@@ -2702,7 +2898,7 @@ static struct pci_driver driver = {
2702 2898
2703static int __init alsa_card_m3_init(void) 2899static int __init alsa_card_m3_init(void)
2704{ 2900{
2705 return pci_module_init(&driver); 2901 return pci_register_driver(&driver);
2706} 2902}
2707 2903
2708static void __exit alsa_card_m3_exit(void) 2904static void __exit alsa_card_m3_exit(void)