diff options
author | Andreas Mohr <andi@lisas.de> | 2005-11-17 05:03:31 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-01-03 06:17:15 -0500 |
commit | ba7301c7d985d206a5688c69d0a74de3988f6d6c (patch) | |
tree | b060741f2035862e0375630e1dcfc7917defb2d4 /sound/pci/als4000.c | |
parent | a57d15158113cb7f10e662e6df07f445c986a12d (diff) |
[ALSA] ALS4000 update
Modules: SB drivers,ALS4000 driver
some update for the ALS4000 driver (tested with hardware in my PC):
- use common control names according to ControlNames.txt
- add some controls (Master Mono, 3D control)
- optimize struct snd_card_als4000_t layout (performance/size)
- save some bytes via unified error path
- constify some read-only data
- add ToDo list
- move GPL license text to top
- add comments
Signed-off-by: Andreas Mohr <andi@lisas.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/pci/als4000.c')
-rw-r--r-- | sound/pci/als4000.c | 89 |
1 files changed, 54 insertions, 35 deletions
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index d496cc5ab35e..48b5175c59c0 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -6,6 +6,21 @@ | |||
6 | * | 6 | * |
7 | * Framework borrowed from Massimo Piccioni's card-als100.c. | 7 | * Framework borrowed from Massimo Piccioni's card-als100.c. |
8 | * | 8 | * |
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | |||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | * | ||
9 | * NOTES | 24 | * NOTES |
10 | * | 25 | * |
11 | * Since Avance does not provide any meaningful documentation, and I | 26 | * Since Avance does not provide any meaningful documentation, and I |
@@ -43,19 +58,9 @@ | |||
43 | * Set KSound: | 58 | * Set KSound: |
44 | * - value -> some port 0x0c0d | 59 | * - value -> some port 0x0c0d |
45 | * | 60 | * |
46 | * This program is free software; you can redistribute it and/or modify | 61 | * ToDo: |
47 | * it under the terms of the GNU General Public License as published by | 62 | * - Proper shared IRQ handling? |
48 | * the Free Software Foundation; either version 2 of the License, or | 63 | * - power management? (card can do voice wakeup according to datasheet!!) |
49 | * (at your option) any later version. | ||
50 | * | ||
51 | * This program is distributed in the hope that it will be useful, | ||
52 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
53 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
54 | * GNU General Public License for more details. | ||
55 | |||
56 | * You should have received a copy of the GNU General Public License | ||
57 | * along with this program; if not, write to the Free Software | ||
58 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
59 | */ | 64 | */ |
60 | 65 | ||
61 | #include <sound/driver.h> | 66 | #include <sound/driver.h> |
@@ -101,8 +106,9 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address for ALS4000 soundcard. (0 | |||
101 | #endif | 106 | #endif |
102 | 107 | ||
103 | typedef struct { | 108 | typedef struct { |
104 | struct pci_dev *pci; | 109 | /* most frequent access first */ |
105 | unsigned long gcr; | 110 | unsigned long gcr; |
111 | struct pci_dev *pci; | ||
106 | #ifdef SUPPORT_JOYSTICK | 112 | #ifdef SUPPORT_JOYSTICK |
107 | struct gameport *gameport; | 113 | struct gameport *gameport; |
108 | #endif | 114 | #endif |
@@ -146,13 +152,13 @@ static void snd_als4000_set_rate(sb_t *chip, unsigned int rate) | |||
146 | } | 152 | } |
147 | } | 153 | } |
148 | 154 | ||
149 | static void snd_als4000_set_capture_dma(sb_t *chip, dma_addr_t addr, unsigned size) | 155 | static inline void snd_als4000_set_capture_dma(sb_t *chip, dma_addr_t addr, unsigned size) |
150 | { | 156 | { |
151 | snd_als4000_gcr_write(chip, 0xa2, addr); | 157 | snd_als4000_gcr_write(chip, 0xa2, addr); |
152 | snd_als4000_gcr_write(chip, 0xa3, (size-1)); | 158 | snd_als4000_gcr_write(chip, 0xa3, (size-1)); |
153 | } | 159 | } |
154 | 160 | ||
155 | static void snd_als4000_set_playback_dma(sb_t *chip, dma_addr_t addr, unsigned size) | 161 | static inline void snd_als4000_set_playback_dma(sb_t *chip, dma_addr_t addr, unsigned size) |
156 | { | 162 | { |
157 | snd_als4000_gcr_write(chip, 0x91, addr); | 163 | snd_als4000_gcr_write(chip, 0x91, addr); |
158 | snd_als4000_gcr_write(chip, 0x92, (size-1)|0x180000); | 164 | snd_als4000_gcr_write(chip, 0x92, (size-1)|0x180000); |
@@ -177,7 +183,7 @@ static int snd_als4000_get_format(snd_pcm_runtime_t *runtime) | |||
177 | } | 183 | } |
178 | 184 | ||
179 | /* structure for setting up playback */ | 185 | /* structure for setting up playback */ |
180 | static struct { | 186 | static const struct { |
181 | unsigned char dsp_cmd, dma_on, dma_off, format; | 187 | unsigned char dsp_cmd, dma_on, dma_off, format; |
182 | } playback_cmd_vals[]={ | 188 | } playback_cmd_vals[]={ |
183 | /* ALS4000_FORMAT_U8_MONO */ | 189 | /* ALS4000_FORMAT_U8_MONO */ |
@@ -201,7 +207,7 @@ static struct { | |||
201 | 207 | ||
202 | /* structure for setting up capture */ | 208 | /* structure for setting up capture */ |
203 | enum { CMD_WIDTH8=0x04, CMD_SIGNED=0x10, CMD_MONO=0x80, CMD_STEREO=0xA0 }; | 209 | enum { CMD_WIDTH8=0x04, CMD_SIGNED=0x10, CMD_MONO=0x80, CMD_STEREO=0xA0 }; |
204 | static unsigned char capture_cmd_vals[]= | 210 | static const unsigned char capture_cmd_vals[]= |
205 | { | 211 | { |
206 | CMD_WIDTH8|CMD_MONO, /* ALS4000_FORMAT_U8_MONO */ | 212 | CMD_WIDTH8|CMD_MONO, /* ALS4000_FORMAT_U8_MONO */ |
207 | CMD_WIDTH8|CMD_SIGNED|CMD_MONO, /* ALS4000_FORMAT_S8_MONO */ | 213 | CMD_WIDTH8|CMD_SIGNED|CMD_MONO, /* ALS4000_FORMAT_S8_MONO */ |
@@ -228,9 +234,9 @@ static int snd_als4000_hw_free(snd_pcm_substream_t * substream) | |||
228 | 234 | ||
229 | static int snd_als4000_capture_prepare(snd_pcm_substream_t * substream) | 235 | static int snd_als4000_capture_prepare(snd_pcm_substream_t * substream) |
230 | { | 236 | { |
231 | unsigned long flags; | ||
232 | sb_t *chip = snd_pcm_substream_chip(substream); | 237 | sb_t *chip = snd_pcm_substream_chip(substream); |
233 | snd_pcm_runtime_t *runtime = substream->runtime; | 238 | snd_pcm_runtime_t *runtime = substream->runtime; |
239 | unsigned long flags; | ||
234 | unsigned long size; | 240 | unsigned long size; |
235 | unsigned count; | 241 | unsigned count; |
236 | 242 | ||
@@ -256,9 +262,9 @@ static int snd_als4000_capture_prepare(snd_pcm_substream_t * substream) | |||
256 | 262 | ||
257 | static int snd_als4000_playback_prepare(snd_pcm_substream_t *substream) | 263 | static int snd_als4000_playback_prepare(snd_pcm_substream_t *substream) |
258 | { | 264 | { |
259 | unsigned long flags; | ||
260 | sb_t *chip = snd_pcm_substream_chip(substream); | 265 | sb_t *chip = snd_pcm_substream_chip(substream); |
261 | snd_pcm_runtime_t *runtime = substream->runtime; | 266 | snd_pcm_runtime_t *runtime = substream->runtime; |
267 | unsigned long flags; | ||
262 | unsigned long size; | 268 | unsigned long size; |
263 | unsigned count; | 269 | unsigned count; |
264 | 270 | ||
@@ -353,6 +359,18 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(snd_pcm_substream_t * subs | |||
353 | return bytes_to_frames( substream->runtime, result ); | 359 | return bytes_to_frames( substream->runtime, result ); |
354 | } | 360 | } |
355 | 361 | ||
362 | /* FIXME: this IRQ routine doesn't really support IRQ sharing (we always | ||
363 | * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not). | ||
364 | * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK | ||
365 | * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ | ||
366 | * register (alt_port + 0x0e). Probably something could be optimized here to | ||
367 | * query/write one register only... | ||
368 | * And even if both registers need to be queried, then there's still the | ||
369 | * question of whether it's actually correct to ACK PCI IRQ before reading | ||
370 | * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear* | ||
371 | * SB IRQ status. | ||
372 | * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS?? | ||
373 | * */ | ||
356 | static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 374 | static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
357 | { | 375 | { |
358 | sb_t *chip = dev_id; | 376 | sb_t *chip = dev_id; |
@@ -698,8 +716,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
698 | -1, | 716 | -1, |
699 | SB_HW_ALS4000, | 717 | SB_HW_ALS4000, |
700 | &chip)) < 0) { | 718 | &chip)) < 0) { |
701 | snd_card_free(card); | 719 | goto out_err; |
702 | return err; | ||
703 | } | 720 | } |
704 | 721 | ||
705 | chip->pci = pci; | 722 | chip->pci = pci; |
@@ -716,40 +733,42 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
716 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, | 733 | if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_ALS4000, |
717 | gcr+0x30, 1, pci->irq, 0, | 734 | gcr+0x30, 1, pci->irq, 0, |
718 | &chip->rmidi)) < 0) { | 735 | &chip->rmidi)) < 0) { |
719 | snd_card_free(card); | 736 | printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", gcr+0x30); |
720 | printk(KERN_ERR "als4000: no MPU-401device at 0x%lx ?\n", gcr+0x30); | 737 | goto out_err; |
721 | return err; | ||
722 | } | 738 | } |
723 | 739 | ||
724 | if ((err = snd_als4000_pcm(chip, 0)) < 0) { | 740 | if ((err = snd_als4000_pcm(chip, 0)) < 0) { |
725 | snd_card_free(card); | 741 | goto out_err; |
726 | return err; | ||
727 | } | 742 | } |
728 | if ((err = snd_sbmixer_new(chip)) < 0) { | 743 | if ((err = snd_sbmixer_new(chip)) < 0) { |
729 | snd_card_free(card); | 744 | goto out_err; |
730 | return err; | ||
731 | } | 745 | } |
732 | 746 | ||
733 | if (snd_opl3_create(card, gcr+0x10, gcr+0x12, | 747 | if (snd_opl3_create(card, gcr+0x10, gcr+0x12, |
734 | OPL3_HW_AUTO, 1, &opl3) < 0) { | 748 | OPL3_HW_AUTO, 1, &opl3) < 0) { |
735 | printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx ?\n", | 749 | printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n", |
736 | gcr+0x10, gcr+0x12 ); | 750 | gcr+0x10, gcr+0x12 ); |
737 | } else { | 751 | } else { |
738 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { | 752 | if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { |
739 | snd_card_free(card); | 753 | goto out_err; |
740 | return err; | ||
741 | } | 754 | } |
742 | } | 755 | } |
743 | 756 | ||
744 | snd_als4000_create_gameport(acard, dev); | 757 | snd_als4000_create_gameport(acard, dev); |
745 | 758 | ||
746 | if ((err = snd_card_register(card)) < 0) { | 759 | if ((err = snd_card_register(card)) < 0) { |
747 | snd_card_free(card); | 760 | goto out_err; |
748 | return err; | ||
749 | } | 761 | } |
750 | pci_set_drvdata(pci, card); | 762 | pci_set_drvdata(pci, card); |
751 | dev++; | 763 | dev++; |
752 | return 0; | 764 | err = 0; |
765 | goto out; | ||
766 | |||
767 | out_err: | ||
768 | snd_card_free(card); | ||
769 | |||
770 | out: | ||
771 | return err; | ||
753 | } | 772 | } |
754 | 773 | ||
755 | static void __devexit snd_card_als4000_remove(struct pci_dev *pci) | 774 | static void __devexit snd_card_als4000_remove(struct pci_dev *pci) |