diff options
Diffstat (limited to 'sound/pci/maestro3.c')
-rw-r--r-- | sound/pci/maestro3.c | 222 |
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 | ||
782 | struct 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 | |||
782 | struct m3_list { | 788 | struct 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. */ | ||
984 | static 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 | ||
1645 | static 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 | |||
1568 | static irqreturn_t | 1707 | static irqreturn_t |
1569 | snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 1708 | snd_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 | |||
1842 | snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) | 1984 | snd_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 | ||
1854 | static void | 2001 | static void |
1855 | snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) | 2002 | snd_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 | |||
2293 | snd_m3_chip_init(m3_t *chip) | 2453 | snd_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 | ||
2703 | static int __init alsa_card_m3_init(void) | 2899 | static 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 | ||
2708 | static void __exit alsa_card_m3_exit(void) | 2904 | static void __exit alsa_card_m3_exit(void) |