diff options
author | Takashi Iwai <tiwai@suse.de> | 2011-06-14 07:57:02 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-06-14 07:59:51 -0400 |
commit | 30bdee0259093e114c711943902c834e5c3326c5 (patch) | |
tree | db5f4c2eb1459a1ad210d8ae094c8e515141d6e8 /sound/pci/es1968.c | |
parent | 85e4d95da091e35209338962eca232e70819a485 (diff) |
ALSA: es1968,maestro3 - Use work for hw-volume control
Instead of tasklet, use workq for handling the hw-volume control.
This reduces lots of spinlocks.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/es1968.c')
-rw-r--r-- | sound/pci/es1968.c | 64 |
1 files changed, 11 insertions, 53 deletions
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 3fa46593a3b9..99ea9320c6b5 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
@@ -554,9 +554,8 @@ struct es1968 { | |||
554 | #else | 554 | #else |
555 | struct snd_kcontrol *master_switch; /* for h/w volume control */ | 555 | struct snd_kcontrol *master_switch; /* for h/w volume control */ |
556 | struct snd_kcontrol *master_volume; | 556 | struct snd_kcontrol *master_volume; |
557 | spinlock_t ac97_lock; | ||
558 | struct tasklet_struct hwvol_tq; | ||
559 | #endif | 557 | #endif |
558 | struct work_struct hwvol_work; | ||
560 | 559 | ||
561 | #ifdef CONFIG_SND_ES1968_RADIO | 560 | #ifdef CONFIG_SND_ES1968_RADIO |
562 | struct snd_tea575x tea; | 561 | struct snd_tea575x tea; |
@@ -646,38 +645,23 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip) | |||
646 | static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) | 645 | static void snd_es1968_ac97_write(struct snd_ac97 *ac97, unsigned short reg, unsigned short val) |
647 | { | 646 | { |
648 | struct es1968 *chip = ac97->private_data; | 647 | struct es1968 *chip = ac97->private_data; |
649 | #ifndef CONFIG_SND_ES1968_INPUT | ||
650 | unsigned long flags; | ||
651 | #endif | ||
652 | 648 | ||
653 | snd_es1968_ac97_wait(chip); | 649 | snd_es1968_ac97_wait(chip); |
654 | 650 | ||
655 | /* Write the bus */ | 651 | /* Write the bus */ |
656 | #ifndef CONFIG_SND_ES1968_INPUT | ||
657 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
658 | #endif | ||
659 | outw(val, chip->io_port + ESM_AC97_DATA); | 652 | outw(val, chip->io_port + ESM_AC97_DATA); |
660 | /*msleep(1);*/ | 653 | /*msleep(1);*/ |
661 | outb(reg, chip->io_port + ESM_AC97_INDEX); | 654 | outb(reg, chip->io_port + ESM_AC97_INDEX); |
662 | /*msleep(1);*/ | 655 | /*msleep(1);*/ |
663 | #ifndef CONFIG_SND_ES1968_INPUT | ||
664 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
665 | #endif | ||
666 | } | 656 | } |
667 | 657 | ||
668 | static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) | 658 | static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short reg) |
669 | { | 659 | { |
670 | u16 data = 0; | 660 | u16 data = 0; |
671 | struct es1968 *chip = ac97->private_data; | 661 | struct es1968 *chip = ac97->private_data; |
672 | #ifndef CONFIG_SND_ES1968_INPUT | ||
673 | unsigned long flags; | ||
674 | #endif | ||
675 | 662 | ||
676 | snd_es1968_ac97_wait(chip); | 663 | snd_es1968_ac97_wait(chip); |
677 | 664 | ||
678 | #ifndef CONFIG_SND_ES1968_INPUT | ||
679 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
680 | #endif | ||
681 | outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); | 665 | outb(reg | 0x80, chip->io_port + ESM_AC97_INDEX); |
682 | /*msleep(1);*/ | 666 | /*msleep(1);*/ |
683 | 667 | ||
@@ -685,9 +669,6 @@ static unsigned short snd_es1968_ac97_read(struct snd_ac97 *ac97, unsigned short | |||
685 | data = inw(chip->io_port + ESM_AC97_DATA); | 669 | data = inw(chip->io_port + ESM_AC97_DATA); |
686 | /*msleep(1);*/ | 670 | /*msleep(1);*/ |
687 | } | 671 | } |
688 | #ifndef CONFIG_SND_ES1968_INPUT | ||
689 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | ||
690 | #endif | ||
691 | 672 | ||
692 | return data; | 673 | return data; |
693 | } | 674 | } |
@@ -1904,13 +1885,10 @@ static void snd_es1968_update_pcm(struct es1968 *chip, struct esschan *es) | |||
1904 | (without wrap around) in response to volume button presses and then | 1885 | (without wrap around) in response to volume button presses and then |
1905 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 | 1886 | generating an interrupt. The pair of counters is stored in bits 1-3 and 5-7 |
1906 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ | 1887 | of a byte wide register. The meaning of bits 0 and 4 is unknown. */ |
1907 | static void es1968_update_hw_volume(unsigned long private_data) | 1888 | static void es1968_update_hw_volume(struct work_struct *work) |
1908 | { | 1889 | { |
1909 | struct es1968 *chip = (struct es1968 *) private_data; | 1890 | struct es1968 *chip = container_of(work, struct es1968, hwvol_work); |
1910 | int x, val; | 1891 | int x, val; |
1911 | #ifndef CONFIG_SND_ES1968_INPUT | ||
1912 | unsigned long flags; | ||
1913 | #endif | ||
1914 | 1892 | ||
1915 | /* Figure out which volume control button was pushed, | 1893 | /* Figure out which volume control button was pushed, |
1916 | based on differences from the default register | 1894 | based on differences from the default register |
@@ -1929,18 +1907,11 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1929 | if (! chip->master_switch || ! chip->master_volume) | 1907 | if (! chip->master_switch || ! chip->master_volume) |
1930 | return; | 1908 | return; |
1931 | 1909 | ||
1932 | /* FIXME: we can't call snd_ac97_* functions since here is in tasklet. */ | 1910 | val = snd_ac97_read(chip->ac97, AC97_MASTER); |
1933 | spin_lock_irqsave(&chip->ac97_lock, flags); | ||
1934 | val = chip->ac97->regs[AC97_MASTER]; | ||
1935 | switch (x) { | 1911 | switch (x) { |
1936 | case 0x88: | 1912 | case 0x88: |
1937 | /* mute */ | 1913 | /* mute */ |
1938 | val ^= 0x8000; | 1914 | val ^= 0x8000; |
1939 | chip->ac97->regs[AC97_MASTER] = val; | ||
1940 | outw(val, chip->io_port + ESM_AC97_DATA); | ||
1941 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | ||
1942 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1943 | &chip->master_switch->id); | ||
1944 | break; | 1915 | break; |
1945 | case 0xaa: | 1916 | case 0xaa: |
1946 | /* volume up */ | 1917 | /* volume up */ |
@@ -1948,11 +1919,6 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1948 | val--; | 1919 | val--; |
1949 | if ((val & 0x7f00) > 0) | 1920 | if ((val & 0x7f00) > 0) |
1950 | val -= 0x0100; | 1921 | val -= 0x0100; |
1951 | chip->ac97->regs[AC97_MASTER] = val; | ||
1952 | outw(val, chip->io_port + ESM_AC97_DATA); | ||
1953 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | ||
1954 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1955 | &chip->master_volume->id); | ||
1956 | break; | 1922 | break; |
1957 | case 0x66: | 1923 | case 0x66: |
1958 | /* volume down */ | 1924 | /* volume down */ |
@@ -1960,14 +1926,11 @@ static void es1968_update_hw_volume(unsigned long private_data) | |||
1960 | val++; | 1926 | val++; |
1961 | if ((val & 0x7f00) < 0x1f00) | 1927 | if ((val & 0x7f00) < 0x1f00) |
1962 | val += 0x0100; | 1928 | val += 0x0100; |
1963 | chip->ac97->regs[AC97_MASTER] = val; | ||
1964 | outw(val, chip->io_port + ESM_AC97_DATA); | ||
1965 | outb(AC97_MASTER, chip->io_port + ESM_AC97_INDEX); | ||
1966 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1967 | &chip->master_volume->id); | ||
1968 | break; | 1929 | break; |
1969 | } | 1930 | } |
1970 | spin_unlock_irqrestore(&chip->ac97_lock, flags); | 1931 | if (snd_ac97_update(chip->ac97, AC97_MASTER, val)) |
1932 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
1933 | &chip->master_volume->id); | ||
1971 | #else | 1934 | #else |
1972 | if (!chip->input_dev) | 1935 | if (!chip->input_dev) |
1973 | return; | 1936 | return; |
@@ -2013,11 +1976,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) | |||
2013 | outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); | 1976 | outw(inw(chip->io_port + 4) & 1, chip->io_port + 4); |
2014 | 1977 | ||
2015 | if (event & ESM_HWVOL_IRQ) | 1978 | if (event & ESM_HWVOL_IRQ) |
2016 | #ifdef CONFIG_SND_ES1968_INPUT | 1979 | schedule_work(&chip->hwvol_work); |
2017 | es1968_update_hw_volume((unsigned long)chip); | ||
2018 | #else | ||
2019 | tasklet_schedule(&chip->hwvol_tq); /* we'll do this later */ | ||
2020 | #endif | ||
2021 | 1980 | ||
2022 | /* else ack 'em all, i imagine */ | 1981 | /* else ack 'em all, i imagine */ |
2023 | outb(0xFF, chip->io_port + 0x1A); | 1982 | outb(0xFF, chip->io_port + 0x1A); |
@@ -2426,6 +2385,7 @@ static int es1968_suspend(struct pci_dev *pci, pm_message_t state) | |||
2426 | return 0; | 2385 | return 0; |
2427 | 2386 | ||
2428 | chip->in_suspend = 1; | 2387 | chip->in_suspend = 1; |
2388 | cancel_work_sync(&chip->hwvol_work); | ||
2429 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2389 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2430 | snd_pcm_suspend_all(chip->pcm); | 2390 | snd_pcm_suspend_all(chip->pcm); |
2431 | snd_ac97_suspend(chip->ac97); | 2391 | snd_ac97_suspend(chip->ac97); |
@@ -2638,6 +2598,7 @@ static struct snd_tea575x_ops snd_es1968_tea_ops = { | |||
2638 | 2598 | ||
2639 | static int snd_es1968_free(struct es1968 *chip) | 2599 | static int snd_es1968_free(struct es1968 *chip) |
2640 | { | 2600 | { |
2601 | cancel_work_sync(&chip->hwvol_work); | ||
2641 | #ifdef CONFIG_SND_ES1968_INPUT | 2602 | #ifdef CONFIG_SND_ES1968_INPUT |
2642 | if (chip->input_dev) | 2603 | if (chip->input_dev) |
2643 | input_unregister_device(chip->input_dev); | 2604 | input_unregister_device(chip->input_dev); |
@@ -2728,10 +2689,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, | |||
2728 | INIT_LIST_HEAD(&chip->buf_list); | 2689 | INIT_LIST_HEAD(&chip->buf_list); |
2729 | INIT_LIST_HEAD(&chip->substream_list); | 2690 | INIT_LIST_HEAD(&chip->substream_list); |
2730 | mutex_init(&chip->memory_mutex); | 2691 | mutex_init(&chip->memory_mutex); |
2731 | #ifndef CONFIG_SND_ES1968_INPUT | 2692 | INIT_WORK(&chip->hwvol_work, es1968_update_hw_volume); |
2732 | spin_lock_init(&chip->ac97_lock); | ||
2733 | tasklet_init(&chip->hwvol_tq, es1968_update_hw_volume, (unsigned long)chip); | ||
2734 | #endif | ||
2735 | chip->card = card; | 2693 | chip->card = card; |
2736 | chip->pci = pci; | 2694 | chip->pci = pci; |
2737 | chip->irq = -1; | 2695 | chip->irq = -1; |