Loading sound/pci/maestro3.c +103 −4 Original line number Diff line number Diff line Loading @@ -851,6 +851,11 @@ struct snd_m3 { m3_dma_t *substreams; spinlock_t reg_lock; spinlock_t ac97_lock; snd_kcontrol_t *master_switch; snd_kcontrol_t *master_volume; struct tasklet_struct hwvol_tq; #ifdef CONFIG_PM u16 *suspend_mem; Loading Loading @@ -1565,6 +1570,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s) } } static void snd_m3_update_hw_volume(unsigned long private_data) { m3_t *chip = (m3_t *) private_data; int x, val; unsigned long flags; /* Figure out which volume control button was pushed, based on differences from the default register values. */ x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; /* Reset the volume control registers. */ outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); if (!chip->master_switch || !chip->master_volume) return; /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ spin_lock_irqsave(&chip->ac97_lock, flags); val = chip->ac97->regs[AC97_MASTER_VOL]; switch (x) { case 0x88: /* mute */ val ^= 0x8000; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); break; case 0xaa: /* volume up */ if ((val & 0x7f) > 0) val--; if ((val & 0x7f00) > 0) val -= 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; case 0x66: /* volume down */ if ((val & 0x7f) < 0x1f) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; } spin_unlock_irqrestore(&chip->ac97_lock, flags); } static irqreturn_t snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { Loading @@ -1577,6 +1644,9 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status == 0xff) return IRQ_NONE; if (status & HV_INT_PENDING) tasklet_hi_schedule(&chip->hwvol_tq); /* * ack an assp int if its running * and has an int pending Loading Loading @@ -1842,24 +1912,32 @@ static unsigned short snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) { m3_t *chip = ac97->private_data; unsigned long flags; unsigned short data; if (snd_m3_ac97_wait(chip)) return 0xffff; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) return 0xffff; return snd_m3_inw(chip, CODEC_DATA); data = snd_m3_inw(chip, CODEC_DATA); spin_unlock_irqrestore(&chip->ac97_lock, flags); return data; } static void snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { m3_t *chip = ac97->private_data; unsigned long flags; if (snd_m3_ac97_wait(chip)) return; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); spin_unlock_irqrestore(&chip->ac97_lock, flags); } Loading Loading @@ -1968,6 +2046,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) { ac97_bus_t *pbus; ac97_template_t ac97; snd_ctl_elem_id_t id; int err; static ac97_bus_ops_t ops = { .write = snd_m3_ac97_write, Loading @@ -1988,6 +2067,15 @@ static int __devinit snd_m3_mixer(m3_t *chip) schedule_timeout(HZ / 10); snd_ac97_write(chip->ac97, AC97_PCM, 0); memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Switch"); chip->master_switch = snd_ctl_find_id(chip->card, &id); memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Volume"); chip->master_volume = snd_ctl_find_id(chip->card, &id); return 0; } Loading Loading @@ -2293,6 +2381,7 @@ static int snd_m3_chip_init(m3_t *chip) { struct pci_dev *pcidev = chip->pci; unsigned long io = chip->iobase; u32 n; u16 w; u8 t; /* makes as much sense as 'n', no? */ Loading @@ -2304,7 +2393,8 @@ snd_m3_chip_init(m3_t *chip) pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= REDUCED_DEBOUNCE; n &= ~HV_BUTTON_FROM_GD; n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); Loading Loading @@ -2332,6 +2422,12 @@ snd_m3_chip_init(m3_t *chip) outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); outb(0x00, io + HARDWARE_VOL_CTRL); outb(0x88, io + SHADOW_MIX_REG_VOICE); outb(0x88, io + HW_VOL_COUNTER_VOICE); outb(0x88, io + SHADOW_MIX_REG_MASTER); outb(0x88, io + HW_VOL_COUNTER_MASTER); return 0; } Loading @@ -2341,7 +2437,7 @@ snd_m3_enable_ints(m3_t *chip) unsigned long io = chip->iobase; /* TODO: MPU401 not supported yet */ outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } Loading Loading @@ -2593,6 +2689,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, return err; } spin_lock_init(&chip->ac97_lock); tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); if ((err = snd_m3_mixer(chip)) < 0) return err; Loading Loading
sound/pci/maestro3.c +103 −4 Original line number Diff line number Diff line Loading @@ -851,6 +851,11 @@ struct snd_m3 { m3_dma_t *substreams; spinlock_t reg_lock; spinlock_t ac97_lock; snd_kcontrol_t *master_switch; snd_kcontrol_t *master_volume; struct tasklet_struct hwvol_tq; #ifdef CONFIG_PM u16 *suspend_mem; Loading Loading @@ -1565,6 +1570,68 @@ static void snd_m3_update_ptr(m3_t *chip, m3_dma_t *s) } } static void snd_m3_update_hw_volume(unsigned long private_data) { m3_t *chip = (m3_t *) private_data; int x, val; unsigned long flags; /* Figure out which volume control button was pushed, based on differences from the default register values. */ x = inb(chip->iobase + SHADOW_MIX_REG_VOICE) & 0xee; /* Reset the volume control registers. */ outb(0x88, chip->iobase + SHADOW_MIX_REG_VOICE); outb(0x88, chip->iobase + HW_VOL_COUNTER_VOICE); outb(0x88, chip->iobase + SHADOW_MIX_REG_MASTER); outb(0x88, chip->iobase + HW_VOL_COUNTER_MASTER); if (!chip->master_switch || !chip->master_volume) return; /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ spin_lock_irqsave(&chip->ac97_lock, flags); val = chip->ac97->regs[AC97_MASTER_VOL]; switch (x) { case 0x88: /* mute */ val ^= 0x8000; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); break; case 0xaa: /* volume up */ if ((val & 0x7f) > 0) val--; if ((val & 0x7f00) > 0) val -= 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; case 0x66: /* volume down */ if ((val & 0x7f) < 0x1f) val++; if ((val & 0x7f00) < 0x1f00) val += 0x0100; chip->ac97->regs[AC97_MASTER_VOL] = val; outw(val, chip->iobase + CODEC_DATA); outb(AC97_MASTER_VOL, chip->iobase + CODEC_COMMAND); snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); break; } spin_unlock_irqrestore(&chip->ac97_lock, flags); } static irqreturn_t snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) { Loading @@ -1577,6 +1644,9 @@ snd_m3_interrupt(int irq, void *dev_id, struct pt_regs *regs) if (status == 0xff) return IRQ_NONE; if (status & HV_INT_PENDING) tasklet_hi_schedule(&chip->hwvol_tq); /* * ack an assp int if its running * and has an int pending Loading Loading @@ -1842,24 +1912,32 @@ static unsigned short snd_m3_ac97_read(ac97_t *ac97, unsigned short reg) { m3_t *chip = ac97->private_data; unsigned long flags; unsigned short data; if (snd_m3_ac97_wait(chip)) return 0xffff; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outb(chip, 0x80 | (reg & 0x7f), CODEC_COMMAND); if (snd_m3_ac97_wait(chip)) return 0xffff; return snd_m3_inw(chip, CODEC_DATA); data = snd_m3_inw(chip, CODEC_DATA); spin_unlock_irqrestore(&chip->ac97_lock, flags); return data; } static void snd_m3_ac97_write(ac97_t *ac97, unsigned short reg, unsigned short val) { m3_t *chip = ac97->private_data; unsigned long flags; if (snd_m3_ac97_wait(chip)) return; spin_lock_irqsave(&chip->ac97_lock, flags); snd_m3_outw(chip, val, CODEC_DATA); snd_m3_outb(chip, reg & 0x7f, CODEC_COMMAND); spin_unlock_irqrestore(&chip->ac97_lock, flags); } Loading Loading @@ -1968,6 +2046,7 @@ static int __devinit snd_m3_mixer(m3_t *chip) { ac97_bus_t *pbus; ac97_template_t ac97; snd_ctl_elem_id_t id; int err; static ac97_bus_ops_t ops = { .write = snd_m3_ac97_write, Loading @@ -1988,6 +2067,15 @@ static int __devinit snd_m3_mixer(m3_t *chip) schedule_timeout(HZ / 10); snd_ac97_write(chip->ac97, AC97_PCM, 0); memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Switch"); chip->master_switch = snd_ctl_find_id(chip->card, &id); memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; strcpy(id.name, "Master Playback Volume"); chip->master_volume = snd_ctl_find_id(chip->card, &id); return 0; } Loading Loading @@ -2293,6 +2381,7 @@ static int snd_m3_chip_init(m3_t *chip) { struct pci_dev *pcidev = chip->pci; unsigned long io = chip->iobase; u32 n; u16 w; u8 t; /* makes as much sense as 'n', no? */ Loading @@ -2304,7 +2393,8 @@ snd_m3_chip_init(m3_t *chip) pci_write_config_word(pcidev, PCI_LEGACY_AUDIO_CTRL, w); pci_read_config_dword(pcidev, PCI_ALLEGRO_CONFIG, &n); n &= REDUCED_DEBOUNCE; n &= ~HV_BUTTON_FROM_GD; n |= HV_CTRL_ENABLE | REDUCED_DEBOUNCE; n |= PM_CTRL_ENABLE | CLK_DIV_BY_49 | USE_PCI_TIMING; pci_write_config_dword(pcidev, PCI_ALLEGRO_CONFIG, n); Loading Loading @@ -2332,6 +2422,12 @@ snd_m3_chip_init(m3_t *chip) outb(RUN_ASSP, chip->iobase + ASSP_CONTROL_B); outb(0x00, io + HARDWARE_VOL_CTRL); outb(0x88, io + SHADOW_MIX_REG_VOICE); outb(0x88, io + HW_VOL_COUNTER_VOICE); outb(0x88, io + SHADOW_MIX_REG_MASTER); outb(0x88, io + HW_VOL_COUNTER_MASTER); return 0; } Loading @@ -2341,7 +2437,7 @@ snd_m3_enable_ints(m3_t *chip) unsigned long io = chip->iobase; /* TODO: MPU401 not supported yet */ outw(ASSP_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outw(ASSP_INT_ENABLE | HV_INT_ENABLE /*| MPU401_INT_ENABLE*/, io + HOST_INT_CTRL); outb(inb(io + ASSP_CONTROL_C) | ASSP_HOST_INT_ENABLE, io + ASSP_CONTROL_C); } Loading Loading @@ -2593,6 +2689,9 @@ snd_m3_create(snd_card_t *card, struct pci_dev *pci, return err; } spin_lock_init(&chip->ac97_lock); tasklet_init(&chip->hwvol_tq, snd_m3_update_hw_volume, (unsigned long)chip); if ((err = snd_m3_mixer(chip)) < 0) return err; Loading