diff options
Diffstat (limited to 'sound/pci/als4000.c')
-rw-r--r-- | sound/pci/als4000.c | 305 |
1 files changed, 205 insertions, 100 deletions
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 92d8c47cd3b2..ba570053d4d5 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * card-als4000.c - driver for Avance Logic ALS4000 based soundcards. | 2 | * card-als4000.c - driver for Avance Logic ALS4000 based soundcards. |
3 | * Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>, | 3 | * Copyright (C) 2000 by Bart Hartgers <bart@etpmod.phys.tue.nl>, |
4 | * Jaroslav Kysela <perex@perex.cz> | 4 | * Jaroslav Kysela <perex@perex.cz> |
5 | * Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com> | 5 | * Copyright (C) 2002, 2008 by Andreas Mohr <hw7oshyuv3001@sneakemail.com> |
6 | * | 6 | * |
7 | * Framework borrowed from Massimo Piccioni's card-als100.c. | 7 | * Framework borrowed from Massimo Piccioni's card-als100.c. |
8 | * | 8 | * |
@@ -27,8 +27,10 @@ | |||
27 | * bought an ALS4000 based soundcard, I was forced to base this driver | 27 | * bought an ALS4000 based soundcard, I was forced to base this driver |
28 | * on reverse engineering. | 28 | * on reverse engineering. |
29 | * | 29 | * |
30 | * Note: this is no longer true. Pretty verbose chip docu (ALS4000a.PDF) | 30 | * Note: this is no longer true (thank you!): |
31 | * can be found on the ALSA web site. | 31 | * pretty verbose chip docu (ALS4000a.PDF) can be found on the ALSA web site. |
32 | * Page numbers stated anywhere below with the "SPECS_PAGE:" tag | ||
33 | * refer to: ALS4000a.PDF specs Ver 1.0, May 28th, 1998. | ||
32 | * | 34 | * |
33 | * The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an | 35 | * The ALS4000 seems to be the PCI-cousin of the ALS100. It contains an |
34 | * ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport | 36 | * ALS100-like SB DSP/mixer, an OPL3 synth, a MPU401 and a gameport |
@@ -59,7 +61,6 @@ | |||
59 | * - value -> some port 0x0c0d | 61 | * - value -> some port 0x0c0d |
60 | * | 62 | * |
61 | * ToDo: | 63 | * ToDo: |
62 | * - Proper shared IRQ handling? | ||
63 | * - by default, don't enable legacy game and use PCI game I/O | 64 | * - by default, don't enable legacy game and use PCI game I/O |
64 | * - power management? (card can do voice wakeup according to datasheet!!) | 65 | * - power management? (card can do voice wakeup according to datasheet!!) |
65 | */ | 66 | */ |
@@ -79,7 +80,7 @@ | |||
79 | #include <sound/sb.h> | 80 | #include <sound/sb.h> |
80 | #include <sound/initval.h> | 81 | #include <sound/initval.h> |
81 | 82 | ||
82 | MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>"); | 83 | MODULE_AUTHOR("Bart Hartgers <bart@etpmod.phys.tue.nl>, Andreas Mohr"); |
83 | MODULE_DESCRIPTION("Avance Logic ALS4000"); | 84 | MODULE_DESCRIPTION("Avance Logic ALS4000"); |
84 | MODULE_LICENSE("GPL"); | 85 | MODULE_LICENSE("GPL"); |
85 | MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}"); | 86 | MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS4000}}"); |
@@ -124,22 +125,22 @@ static struct pci_device_id snd_als4000_ids[] = { | |||
124 | MODULE_DEVICE_TABLE(pci, snd_als4000_ids); | 125 | MODULE_DEVICE_TABLE(pci, snd_als4000_ids); |
125 | 126 | ||
126 | enum als4k_iobase_t { | 127 | enum als4k_iobase_t { |
127 | /* IOx: B == Byte, W = Word, D = DWord */ | 128 | /* IOx: B == Byte, W = Word, D = DWord; SPECS_PAGE: 37 */ |
128 | ALS4K_IOD_00_AC97_ACCESS = 0x00, | 129 | ALS4K_IOD_00_AC97_ACCESS = 0x00, |
129 | ALS4K_IOW_04_AC97_READ = 0x04, | 130 | ALS4K_IOW_04_AC97_READ = 0x04, |
130 | ALS4K_IOB_06_AC97_STATUS = 0x06, | 131 | ALS4K_IOB_06_AC97_STATUS = 0x06, |
131 | ALS4K_IOB_07_IRQSTATUS = 0x07, | 132 | ALS4K_IOB_07_IRQSTATUS = 0x07, |
132 | ALS4K_IOD_08_GCR_DATA = 0x08, | 133 | ALS4K_IOD_08_GCR_DATA = 0x08, |
133 | ALS4K_IOB_0C_GCR_INDEX = 0x0c, | 134 | ALS4K_IOB_0C_GCR_INDEX = 0x0c, |
134 | ALS4K_IOB_0E_SB_MPU_IRQ = 0x0e, | 135 | ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU = 0x0e, |
135 | ALS4K_IOB_10_ADLIB_ADDR0 = 0x10, | 136 | ALS4K_IOB_10_ADLIB_ADDR0 = 0x10, |
136 | ALS4K_IOB_11_ADLIB_ADDR1 = 0x11, | 137 | ALS4K_IOB_11_ADLIB_ADDR1 = 0x11, |
137 | ALS4K_IOB_12_ADLIB_ADDR2 = 0x12, | 138 | ALS4K_IOB_12_ADLIB_ADDR2 = 0x12, |
138 | ALS4K_IOB_13_ADLIB_ADDR3 = 0x13, | 139 | ALS4K_IOB_13_ADLIB_ADDR3 = 0x13, |
139 | ALS4K_IOB_14_MIXER_INDEX = 0x14, | 140 | ALS4K_IOB_14_MIXER_INDEX = 0x14, |
140 | ALS4K_IOB_15_MIXER_DATA = 0x15, | 141 | ALS4K_IOB_15_MIXER_DATA = 0x15, |
141 | ALS4K_IOB_16_ESP_RST_PORT = 0x16, | 142 | ALS4K_IOB_16_ESP_RESET = 0x16, |
142 | ALS4K_IOB_16_CR1E_ACK_PORT = 0x16, /* 2nd function */ | 143 | ALS4K_IOB_16_ACK_FOR_CR1E = 0x16, /* 2nd function */ |
143 | ALS4K_IOB_18_OPL_ADDR0 = 0x18, | 144 | ALS4K_IOB_18_OPL_ADDR0 = 0x18, |
144 | ALS4K_IOB_19_OPL_ADDR1 = 0x19, | 145 | ALS4K_IOB_19_OPL_ADDR1 = 0x19, |
145 | ALS4K_IOB_1A_ESP_RD_DATA = 0x1a, | 146 | ALS4K_IOB_1A_ESP_RD_DATA = 0x1a, |
@@ -154,62 +155,137 @@ enum als4k_iobase_t { | |||
154 | ALS4K_IOB_31_MIDI_COMMAND = 0x31, /* 2nd function */ | 155 | ALS4K_IOB_31_MIDI_COMMAND = 0x31, /* 2nd function */ |
155 | }; | 156 | }; |
156 | 157 | ||
157 | enum als4k_gcr_t { | 158 | enum als4k_iobase_0e_t { |
158 | /* all registers 32bit wide */ | 159 | ALS4K_IOB_0E_MPU_IRQ = 0x10, |
159 | ALS4K_GCR_8C_MISC_CTRL = 0x8c, | 160 | ALS4K_IOB_0E_CR1E_IRQ = 0x40, |
160 | ALS4K_GCR_90_TEST_MODE_REG = 0x90, | 161 | ALS4K_IOB_0E_SB_DMA_IRQ = 0x80, |
161 | ALS4K_GCR_91_DMA0_ADDR = 0x91, | ||
162 | ALS4K_GCR_92_DMA0_MODE_COUNT = 0x92, | ||
163 | ALS4K_GCR_93_DMA1_ADDR = 0x93, | ||
164 | ALS4K_GCR_94_DMA1_MODE_COUNT = 0x94, | ||
165 | ALS4K_GCR_95_DMA3_ADDR = 0x95, | ||
166 | ALS4K_GCR_96_DMA3_MODE_COUNT = 0x96, | ||
167 | ALS4K_GCR_99_DMA_EMULATION_CTRL = 0x99, | ||
168 | ALS4K_GCR_A0_FIFO1_CURRENT_ADDR = 0xa0, | ||
169 | ALS4K_GCR_A1_FIFO1_STATUS_BYTECOUNT = 0xa1, | ||
170 | ALS4K_GCR_A2_FIFO2_PCIADDR = 0xa2, | ||
171 | ALS4K_GCR_A3_FIFO2_COUNT = 0xa3, | ||
172 | ALS4K_GCR_A4_FIFO2_CURRENT_ADDR = 0xa4, | ||
173 | ALS4K_GCR_A5_FIFO1_STATUS_BYTECOUNT = 0xa5, | ||
174 | ALS4K_GCR_A6_PM_CTRL = 0xa6, | ||
175 | ALS4K_GCR_A7_PCI_ACCESS_STORAGE = 0xa7, | ||
176 | ALS4K_GCR_A8_LEGACY_CFG1 = 0xa8, | ||
177 | ALS4K_GCR_A9_LEGACY_CFG2 = 0xa9, | ||
178 | ALS4K_GCR_FF_DUMMY_SCRATCH = 0xff, | ||
179 | }; | 162 | }; |
180 | 163 | ||
181 | enum als4k_gcr_8c_t { | 164 | enum als4k_gcr_t { /* all registers 32bit wide; SPECS_PAGE: 38 to 42 */ |
182 | ALS4K_GCR_8C_IRQ_MASK_CTRL_ENABLE = 0x8000, | 165 | ALS4K_GCR8C_MISC_CTRL = 0x8c, |
183 | ALS4K_GCR_8C_CHIP_REV_MASK = 0xf0000 | 166 | ALS4K_GCR90_TEST_MODE_REG = 0x90, |
167 | ALS4K_GCR91_DMA0_ADDR = 0x91, | ||
168 | ALS4K_GCR92_DMA0_MODE_COUNT = 0x92, | ||
169 | ALS4K_GCR93_DMA1_ADDR = 0x93, | ||
170 | ALS4K_GCR94_DMA1_MODE_COUNT = 0x94, | ||
171 | ALS4K_GCR95_DMA3_ADDR = 0x95, | ||
172 | ALS4K_GCR96_DMA3_MODE_COUNT = 0x96, | ||
173 | ALS4K_GCR99_DMA_EMULATION_CTRL = 0x99, | ||
174 | ALS4K_GCRA0_FIFO1_CURRENT_ADDR = 0xa0, | ||
175 | ALS4K_GCRA1_FIFO1_STATUS_BYTECOUNT = 0xa1, | ||
176 | ALS4K_GCRA2_FIFO2_PCIADDR = 0xa2, | ||
177 | ALS4K_GCRA3_FIFO2_COUNT = 0xa3, | ||
178 | ALS4K_GCRA4_FIFO2_CURRENT_ADDR = 0xa4, | ||
179 | ALS4K_GCRA5_FIFO1_STATUS_BYTECOUNT = 0xa5, | ||
180 | ALS4K_GCRA6_PM_CTRL = 0xa6, | ||
181 | ALS4K_GCRA7_PCI_ACCESS_STORAGE = 0xa7, | ||
182 | ALS4K_GCRA8_LEGACY_CFG1 = 0xa8, | ||
183 | ALS4K_GCRA9_LEGACY_CFG2 = 0xa9, | ||
184 | ALS4K_GCRFF_DUMMY_SCRATCH = 0xff, | ||
184 | }; | 185 | }; |
185 | 186 | ||
186 | static inline void snd_als4000_gcr_write_addr(unsigned long iobase, | 187 | enum als4k_gcr8c_t { |
187 | enum als4k_gcr_t reg, | 188 | ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE = 0x8000, |
188 | u32 val) | 189 | ALS4K_GCR8C_CHIP_REV_MASK = 0xf0000 |
190 | }; | ||
191 | |||
192 | static inline void snd_als4k_iobase_writeb(unsigned long iobase, | ||
193 | enum als4k_iobase_t reg, | ||
194 | u8 val) | ||
189 | { | 195 | { |
190 | outb(reg, iobase + ALS4K_IOB_0C_GCR_INDEX); | 196 | outb(val, iobase + reg); |
191 | outl(val, iobase + ALS4K_IOD_08_GCR_DATA); | ||
192 | } | 197 | } |
193 | 198 | ||
194 | static inline void snd_als4000_gcr_write(struct snd_sb *sb, | 199 | static inline void snd_als4k_iobase_writel(unsigned long iobase, |
200 | enum als4k_iobase_t reg, | ||
201 | u32 val) | ||
202 | { | ||
203 | outl(val, iobase + reg); | ||
204 | } | ||
205 | |||
206 | static inline u8 snd_als4k_iobase_readb(unsigned long iobase, | ||
207 | enum als4k_iobase_t reg) | ||
208 | { | ||
209 | return inb(iobase + reg); | ||
210 | } | ||
211 | |||
212 | static inline u32 snd_als4k_iobase_readl(unsigned long iobase, | ||
213 | enum als4k_iobase_t reg) | ||
214 | { | ||
215 | return inl(iobase + reg); | ||
216 | } | ||
217 | |||
218 | static inline void snd_als4k_gcr_write_addr(unsigned long iobase, | ||
195 | enum als4k_gcr_t reg, | 219 | enum als4k_gcr_t reg, |
196 | u32 val) | 220 | u32 val) |
197 | { | 221 | { |
198 | snd_als4000_gcr_write_addr(sb->alt_port, reg, val); | 222 | snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg); |
223 | snd_als4k_iobase_writel(iobase, ALS4K_IOD_08_GCR_DATA, val); | ||
224 | } | ||
225 | |||
226 | static inline void snd_als4k_gcr_write(struct snd_sb *sb, | ||
227 | enum als4k_gcr_t reg, | ||
228 | u32 val) | ||
229 | { | ||
230 | snd_als4k_gcr_write_addr(sb->alt_port, reg, val); | ||
199 | } | 231 | } |
200 | 232 | ||
201 | static inline u32 snd_als4000_gcr_read_addr(unsigned long iobase, | 233 | static inline u32 snd_als4k_gcr_read_addr(unsigned long iobase, |
202 | enum als4k_gcr_t reg) | 234 | enum als4k_gcr_t reg) |
203 | { | 235 | { |
204 | outb(reg, iobase + ALS4K_IOB_0C_GCR_INDEX); | 236 | /* SPECS_PAGE: 37/38 */ |
205 | return inl(iobase + ALS4K_IOD_08_GCR_DATA); | 237 | snd_als4k_iobase_writeb(iobase, ALS4K_IOB_0C_GCR_INDEX, reg); |
238 | return snd_als4k_iobase_readl(iobase, ALS4K_IOD_08_GCR_DATA); | ||
239 | } | ||
240 | |||
241 | static inline u32 snd_als4k_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg) | ||
242 | { | ||
243 | return snd_als4k_gcr_read_addr(sb->alt_port, reg); | ||
244 | } | ||
245 | |||
246 | enum als4k_cr_t { /* all registers 8bit wide; SPECS_PAGE: 20 to 23 */ | ||
247 | ALS4K_CR0_SB_CONFIG = 0x00, | ||
248 | ALS4K_CR2_MISC_CONTROL = 0x02, | ||
249 | ALS4K_CR3_CONFIGURATION = 0x03, | ||
250 | ALS4K_CR17_FIFO_STATUS = 0x17, | ||
251 | ALS4K_CR18_ESP_MAJOR_VERSION = 0x18, | ||
252 | ALS4K_CR19_ESP_MINOR_VERSION = 0x19, | ||
253 | ALS4K_CR1A_MPU401_UART_MODE_CONTROL = 0x1a, | ||
254 | ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO = 0x1c, | ||
255 | ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI = 0x1d, | ||
256 | ALS4K_CR1E_FIFO2_CONTROL = 0x1e, /* secondary PCM FIFO (recording) */ | ||
257 | ALS4K_CR3A_MISC_CONTROL = 0x3a, | ||
258 | ALS4K_CR3B_CRC32_BYTE0 = 0x3b, /* for testing, activate via CR3A */ | ||
259 | ALS4K_CR3C_CRC32_BYTE1 = 0x3c, | ||
260 | ALS4K_CR3D_CRC32_BYTE2 = 0x3d, | ||
261 | ALS4K_CR3E_CRC32_BYTE3 = 0x3e, | ||
262 | }; | ||
263 | |||
264 | enum als4k_cr0_t { | ||
265 | ALS4K_CR0_DMA_CONTIN_MODE_CTRL = 0x02, /* IRQ/FIFO controlled for 0/1 */ | ||
266 | ALS4K_CR0_DMA_90H_MODE_CTRL = 0x04, /* IRQ/FIFO controlled for 0/1 */ | ||
267 | ALS4K_CR0_MX80_81_REG_WRITE_ENABLE = 0x80, | ||
268 | }; | ||
269 | |||
270 | static inline void snd_als4_cr_write(struct snd_sb *chip, | ||
271 | enum als4k_cr_t reg, | ||
272 | u8 data) | ||
273 | { | ||
274 | /* Control Register is reg | 0xc0 (bit 7, 6 set) on sbmixer_index | ||
275 | * NOTE: assumes chip->mixer_lock to be locked externally already! | ||
276 | * SPECS_PAGE: 6 */ | ||
277 | snd_sbmixer_write(chip, reg | 0xc0, data); | ||
206 | } | 278 | } |
207 | 279 | ||
208 | static inline u32 snd_als4000_gcr_read(struct snd_sb *sb, enum als4k_gcr_t reg) | 280 | static inline u8 snd_als4_cr_read(struct snd_sb *chip, |
281 | enum als4k_cr_t reg) | ||
209 | { | 282 | { |
210 | return snd_als4000_gcr_read_addr(sb->alt_port, reg); | 283 | /* NOTE: assumes chip->mixer_lock to be locked externally already! */ |
284 | return snd_sbmixer_read(chip, reg | 0xc0); | ||
211 | } | 285 | } |
212 | 286 | ||
287 | |||
288 | |||
213 | static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate) | 289 | static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate) |
214 | { | 290 | { |
215 | if (!(chip->mode & SB_RATE_LOCK)) { | 291 | if (!(chip->mode & SB_RATE_LOCK)) { |
@@ -222,16 +298,18 @@ static void snd_als4000_set_rate(struct snd_sb *chip, unsigned int rate) | |||
222 | static inline void snd_als4000_set_capture_dma(struct snd_sb *chip, | 298 | static inline void snd_als4000_set_capture_dma(struct snd_sb *chip, |
223 | dma_addr_t addr, unsigned size) | 299 | dma_addr_t addr, unsigned size) |
224 | { | 300 | { |
225 | snd_als4000_gcr_write(chip, ALS4K_GCR_A2_FIFO2_PCIADDR, addr); | 301 | /* SPECS_PAGE: 40 */ |
226 | snd_als4000_gcr_write(chip, ALS4K_GCR_A3_FIFO2_COUNT, (size-1)); | 302 | snd_als4k_gcr_write(chip, ALS4K_GCRA2_FIFO2_PCIADDR, addr); |
303 | snd_als4k_gcr_write(chip, ALS4K_GCRA3_FIFO2_COUNT, (size-1)); | ||
227 | } | 304 | } |
228 | 305 | ||
229 | static inline void snd_als4000_set_playback_dma(struct snd_sb *chip, | 306 | static inline void snd_als4000_set_playback_dma(struct snd_sb *chip, |
230 | dma_addr_t addr, | 307 | dma_addr_t addr, |
231 | unsigned size) | 308 | unsigned size) |
232 | { | 309 | { |
233 | snd_als4000_gcr_write(chip, ALS4K_GCR_91_DMA0_ADDR, addr); | 310 | /* SPECS_PAGE: 38 */ |
234 | snd_als4000_gcr_write(chip, ALS4K_GCR_92_DMA0_MODE_COUNT, | 311 | snd_als4k_gcr_write(chip, ALS4K_GCR91_DMA0_ADDR, addr); |
312 | snd_als4k_gcr_write(chip, ALS4K_GCR92_DMA0_MODE_COUNT, | ||
235 | (size-1)|0x180000); | 313 | (size-1)|0x180000); |
236 | } | 314 | } |
237 | 315 | ||
@@ -316,7 +394,7 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream) | |||
316 | count = snd_pcm_lib_period_bytes(substream); | 394 | count = snd_pcm_lib_period_bytes(substream); |
317 | 395 | ||
318 | if (chip->capture_format & ALS4000_FORMAT_16BIT) | 396 | if (chip->capture_format & ALS4000_FORMAT_16BIT) |
319 | count >>=1; | 397 | count >>= 1; |
320 | count--; | 398 | count--; |
321 | 399 | ||
322 | spin_lock_irq(&chip->reg_lock); | 400 | spin_lock_irq(&chip->reg_lock); |
@@ -324,8 +402,8 @@ static int snd_als4000_capture_prepare(struct snd_pcm_substream *substream) | |||
324 | snd_als4000_set_capture_dma(chip, runtime->dma_addr, size); | 402 | snd_als4000_set_capture_dma(chip, runtime->dma_addr, size); |
325 | spin_unlock_irq(&chip->reg_lock); | 403 | spin_unlock_irq(&chip->reg_lock); |
326 | spin_lock_irq(&chip->mixer_lock); | 404 | spin_lock_irq(&chip->mixer_lock); |
327 | snd_sbmixer_write(chip, 0xdc, count); | 405 | snd_als4_cr_write(chip, ALS4K_CR1C_FIFO2_BLOCK_LENGTH_LO, count & 0xff); |
328 | snd_sbmixer_write(chip, 0xdd, count>>8); | 406 | snd_als4_cr_write(chip, ALS4K_CR1D_FIFO2_BLOCK_LENGTH_HI, count >> 8); |
329 | spin_unlock_irq(&chip->mixer_lock); | 407 | spin_unlock_irq(&chip->mixer_lock); |
330 | return 0; | 408 | return 0; |
331 | } | 409 | } |
@@ -343,7 +421,7 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream) | |||
343 | count = snd_pcm_lib_period_bytes(substream); | 421 | count = snd_pcm_lib_period_bytes(substream); |
344 | 422 | ||
345 | if (chip->playback_format & ALS4000_FORMAT_16BIT) | 423 | if (chip->playback_format & ALS4000_FORMAT_16BIT) |
346 | count >>=1; | 424 | count >>= 1; |
347 | count--; | 425 | count--; |
348 | 426 | ||
349 | /* FIXME: from second playback on, there's a lot more clicks and pops | 427 | /* FIXME: from second playback on, there's a lot more clicks and pops |
@@ -360,8 +438,8 @@ static int snd_als4000_playback_prepare(struct snd_pcm_substream *substream) | |||
360 | /* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */ | 438 | /* snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); */ |
361 | snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd); | 439 | snd_sbdsp_command(chip, playback_cmd(chip).dsp_cmd); |
362 | snd_sbdsp_command(chip, playback_cmd(chip).format); | 440 | snd_sbdsp_command(chip, playback_cmd(chip).format); |
363 | snd_sbdsp_command(chip, count); | 441 | snd_sbdsp_command(chip, count & 0xff); |
364 | snd_sbdsp_command(chip, count>>8); | 442 | snd_sbdsp_command(chip, count >> 8); |
365 | snd_sbdsp_command(chip, playback_cmd(chip).dma_off); | 443 | snd_sbdsp_command(chip, playback_cmd(chip).dma_off); |
366 | spin_unlock_irq(&chip->reg_lock); | 444 | spin_unlock_irq(&chip->reg_lock); |
367 | 445 | ||
@@ -384,12 +462,14 @@ static int snd_als4000_capture_trigger(struct snd_pcm_substream *substream, int | |||
384 | case SNDRV_PCM_TRIGGER_START: | 462 | case SNDRV_PCM_TRIGGER_START: |
385 | case SNDRV_PCM_TRIGGER_RESUME: | 463 | case SNDRV_PCM_TRIGGER_RESUME: |
386 | chip->mode |= SB_RATE_LOCK_CAPTURE; | 464 | chip->mode |= SB_RATE_LOCK_CAPTURE; |
387 | snd_sbmixer_write(chip, 0xde, capture_cmd(chip)); | 465 | snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL, |
466 | capture_cmd(chip)); | ||
388 | break; | 467 | break; |
389 | case SNDRV_PCM_TRIGGER_STOP: | 468 | case SNDRV_PCM_TRIGGER_STOP: |
390 | case SNDRV_PCM_TRIGGER_SUSPEND: | 469 | case SNDRV_PCM_TRIGGER_SUSPEND: |
391 | chip->mode &= ~SB_RATE_LOCK_CAPTURE; | 470 | chip->mode &= ~SB_RATE_LOCK_CAPTURE; |
392 | snd_sbmixer_write(chip, 0xde, 0); | 471 | snd_als4_cr_write(chip, ALS4K_CR1E_FIFO2_CONTROL, |
472 | capture_cmd(chip)); | ||
393 | break; | 473 | break; |
394 | default: | 474 | default: |
395 | result = -EINVAL; | 475 | result = -EINVAL; |
@@ -430,9 +510,9 @@ static snd_pcm_uframes_t snd_als4000_capture_pointer(struct snd_pcm_substream *s | |||
430 | unsigned int result; | 510 | unsigned int result; |
431 | 511 | ||
432 | spin_lock(&chip->reg_lock); | 512 | spin_lock(&chip->reg_lock); |
433 | result = snd_als4000_gcr_read(chip, ALS4K_GCR_A4_FIFO2_CURRENT_ADDR); | 513 | result = snd_als4k_gcr_read(chip, ALS4K_GCRA4_FIFO2_CURRENT_ADDR); |
434 | result &= 0xffff; | ||
435 | spin_unlock(&chip->reg_lock); | 514 | spin_unlock(&chip->reg_lock); |
515 | result &= 0xffff; | ||
436 | return bytes_to_frames( substream->runtime, result ); | 516 | return bytes_to_frames( substream->runtime, result ); |
437 | } | 517 | } |
438 | 518 | ||
@@ -442,9 +522,9 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream * | |||
442 | unsigned result; | 522 | unsigned result; |
443 | 523 | ||
444 | spin_lock(&chip->reg_lock); | 524 | spin_lock(&chip->reg_lock); |
445 | result = snd_als4000_gcr_read(chip, ALS4K_GCR_A0_FIFO1_CURRENT_ADDR); | 525 | result = snd_als4k_gcr_read(chip, ALS4K_GCRA0_FIFO1_CURRENT_ADDR); |
446 | result &= 0xffff; | ||
447 | spin_unlock(&chip->reg_lock); | 526 | spin_unlock(&chip->reg_lock); |
527 | result &= 0xffff; | ||
448 | return bytes_to_frames( substream->runtime, result ); | 528 | return bytes_to_frames( substream->runtime, result ); |
449 | } | 529 | } |
450 | 530 | ||
@@ -452,46 +532,63 @@ static snd_pcm_uframes_t snd_als4000_playback_pointer(struct snd_pcm_substream * | |||
452 | * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not). | 532 | * return IRQ_HANDLED no matter whether we actually had an IRQ flag or not). |
453 | * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK | 533 | * ALS4000a.PDF writes that while ACKing IRQ in PCI block will *not* ACK |
454 | * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ | 534 | * the IRQ in the SB core, ACKing IRQ in SB block *will* ACK the PCI IRQ |
455 | * register (alt_port + ALS4K_IOB_0E_SB_MPU_IRQ). Probably something | 535 | * register (alt_port + ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU). Probably something |
456 | * could be optimized here to query/write one register only... | 536 | * could be optimized here to query/write one register only... |
457 | * And even if both registers need to be queried, then there's still the | 537 | * And even if both registers need to be queried, then there's still the |
458 | * question of whether it's actually correct to ACK PCI IRQ before reading | 538 | * question of whether it's actually correct to ACK PCI IRQ before reading |
459 | * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear* | 539 | * SB IRQ like we do now, since ALS4000a.PDF mentions that PCI IRQ will *clear* |
460 | * SB IRQ status. | 540 | * SB IRQ status. |
461 | * (hmm, page 38 mentions it the other way around!) | 541 | * (hmm, SPECS_PAGE: 38 mentions it the other way around!) |
462 | * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS?? | 542 | * And do we *really* need the lock here for *reading* SB_DSP4_IRQSTATUS?? |
463 | * */ | 543 | * */ |
464 | static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id) | 544 | static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id) |
465 | { | 545 | { |
466 | struct snd_sb *chip = dev_id; | 546 | struct snd_sb *chip = dev_id; |
467 | unsigned gcr_status; | 547 | unsigned pci_irqstatus; |
468 | unsigned sb_status; | 548 | unsigned sb_irqstatus; |
469 | 549 | ||
470 | /* find out which bit of the ALS4000 produced the interrupt */ | 550 | /* find out which bit of the ALS4000 PCI block produced the interrupt, |
471 | gcr_status = inb(chip->alt_port + ALS4K_IOB_0E_SB_MPU_IRQ); | 551 | SPECS_PAGE: 38, 5 */ |
472 | 552 | pci_irqstatus = snd_als4k_iobase_readb(chip->alt_port, | |
473 | if ((gcr_status & 0x80) && (chip->playback_substream)) /* playback */ | 553 | ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU); |
554 | if ((pci_irqstatus & ALS4K_IOB_0E_SB_DMA_IRQ) | ||
555 | && (chip->playback_substream)) /* playback */ | ||
474 | snd_pcm_period_elapsed(chip->playback_substream); | 556 | snd_pcm_period_elapsed(chip->playback_substream); |
475 | if ((gcr_status & 0x40) && (chip->capture_substream)) /* capturing */ | 557 | if ((pci_irqstatus & ALS4K_IOB_0E_CR1E_IRQ) |
558 | && (chip->capture_substream)) /* capturing */ | ||
476 | snd_pcm_period_elapsed(chip->capture_substream); | 559 | snd_pcm_period_elapsed(chip->capture_substream); |
477 | if ((gcr_status & 0x10) && (chip->rmidi)) /* MPU401 interrupt */ | 560 | if ((pci_irqstatus & ALS4K_IOB_0E_MPU_IRQ) |
561 | && (chip->rmidi)) /* MPU401 interrupt */ | ||
478 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); | 562 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); |
479 | /* release the gcr */ | 563 | /* ACK the PCI block IRQ */ |
480 | outb(gcr_status, chip->alt_port + ALS4K_IOB_0E_SB_MPU_IRQ); | 564 | snd_als4k_iobase_writeb(chip->alt_port, |
565 | ALS4K_IOB_0E_IRQTYPE_SB_CR1E_MPU, pci_irqstatus); | ||
481 | 566 | ||
482 | spin_lock(&chip->mixer_lock); | 567 | spin_lock(&chip->mixer_lock); |
483 | sb_status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); | 568 | /* SPECS_PAGE: 20 */ |
569 | sb_irqstatus = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); | ||
484 | spin_unlock(&chip->mixer_lock); | 570 | spin_unlock(&chip->mixer_lock); |
485 | 571 | ||
486 | if (sb_status & SB_IRQTYPE_8BIT) | 572 | if (sb_irqstatus & SB_IRQTYPE_8BIT) |
487 | snd_sb_ack_8bit(chip); | 573 | snd_sb_ack_8bit(chip); |
488 | if (sb_status & SB_IRQTYPE_16BIT) | 574 | if (sb_irqstatus & SB_IRQTYPE_16BIT) |
489 | snd_sb_ack_16bit(chip); | 575 | snd_sb_ack_16bit(chip); |
490 | if (sb_status & SB_IRQTYPE_MPUIN) | 576 | if (sb_irqstatus & SB_IRQTYPE_MPUIN) |
491 | inb(chip->mpu_port); | 577 | inb(chip->mpu_port); |
492 | if (sb_status & 0x20) | 578 | if (sb_irqstatus & ALS4K_IRQTYPE_CR1E_DMA) |
493 | inb(SBP(chip, RESET)); | 579 | snd_als4k_iobase_readb(chip->alt_port, |
494 | return IRQ_HANDLED; | 580 | ALS4K_IOB_16_ACK_FOR_CR1E); |
581 | |||
582 | /* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n", | ||
583 | pci_irqstatus, sb_irqstatus); */ | ||
584 | |||
585 | /* only ack the things we actually handled above */ | ||
586 | return IRQ_RETVAL( | ||
587 | (pci_irqstatus & (ALS4K_IOB_0E_SB_DMA_IRQ|ALS4K_IOB_0E_CR1E_IRQ| | ||
588 | ALS4K_IOB_0E_MPU_IRQ)) | ||
589 | || (sb_irqstatus & (SB_IRQTYPE_8BIT|SB_IRQTYPE_16BIT| | ||
590 | SB_IRQTYPE_MPUIN|ALS4K_IRQTYPE_CR1E_DMA)) | ||
591 | ); | ||
495 | } | 592 | } |
496 | 593 | ||
497 | /*****************************************************************/ | 594 | /*****************************************************************/ |
@@ -603,7 +700,8 @@ static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device) | |||
603 | struct snd_pcm *pcm; | 700 | struct snd_pcm *pcm; |
604 | int err; | 701 | int err; |
605 | 702 | ||
606 | if ((err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm)) < 0) | 703 | err = snd_pcm_new(chip->card, "ALS4000 DSP", device, 1, 1, &pcm); |
704 | if (err < 0) | ||
607 | return err; | 705 | return err; |
608 | pcm->private_data = chip; | 706 | pcm->private_data = chip; |
609 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | 707 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; |
@@ -637,34 +735,38 @@ static void snd_als4000_set_addr(unsigned long iobase, | |||
637 | cfg1 |= (game_io | 1) << 16; | 735 | cfg1 |= (game_io | 1) << 16; |
638 | if (opl_io > 0) | 736 | if (opl_io > 0) |
639 | cfg1 |= (opl_io | 1); | 737 | cfg1 |= (opl_io | 1); |
640 | snd_als4000_gcr_write_addr(iobase, ALS4K_GCR_A8_LEGACY_CFG1, cfg1); | 738 | snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA8_LEGACY_CFG1, cfg1); |
641 | snd_als4000_gcr_write_addr(iobase, ALS4K_GCR_A9_LEGACY_CFG2, cfg2); | 739 | snd_als4k_gcr_write_addr(iobase, ALS4K_GCRA9_LEGACY_CFG2, cfg2); |
642 | } | 740 | } |
643 | 741 | ||
644 | static void snd_als4000_configure(struct snd_sb *chip) | 742 | static void snd_als4000_configure(struct snd_sb *chip) |
645 | { | 743 | { |
646 | unsigned tmp; | 744 | u8 tmp; |
647 | int i; | 745 | int i; |
648 | 746 | ||
649 | /* do some more configuration */ | 747 | /* do some more configuration */ |
650 | spin_lock_irq(&chip->mixer_lock); | 748 | spin_lock_irq(&chip->mixer_lock); |
651 | tmp = snd_sbmixer_read(chip, 0xc0); | 749 | tmp = snd_als4_cr_read(chip, ALS4K_CR0_SB_CONFIG); |
652 | snd_sbmixer_write(chip, 0xc0, tmp|0x80); | 750 | snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, |
653 | /* always select DMA channel 0, since we do not actually use DMA */ | 751 | tmp|ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); |
752 | /* always select DMA channel 0, since we do not actually use DMA | ||
753 | * SPECS_PAGE: 19/20 */ | ||
654 | snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0); | 754 | snd_sbmixer_write(chip, SB_DSP4_DMASETUP, SB_DMASETUP_DMA0); |
655 | snd_sbmixer_write(chip, 0xc0, tmp&0x7f); | 755 | snd_als4_cr_write(chip, ALS4K_CR0_SB_CONFIG, |
756 | tmp & ~ALS4K_CR0_MX80_81_REG_WRITE_ENABLE); | ||
656 | spin_unlock_irq(&chip->mixer_lock); | 757 | spin_unlock_irq(&chip->mixer_lock); |
657 | 758 | ||
658 | spin_lock_irq(&chip->reg_lock); | 759 | spin_lock_irq(&chip->reg_lock); |
659 | /* enable interrupts */ | 760 | /* enable interrupts */ |
660 | snd_als4000_gcr_write(chip, ALS4K_GCR_8C_MISC_CTRL, | 761 | snd_als4k_gcr_write(chip, ALS4K_GCR8C_MISC_CTRL, |
661 | ALS4K_GCR_8C_IRQ_MASK_CTRL_ENABLE); | 762 | ALS4K_GCR8C_IRQ_MASK_CTRL_ENABLE); |
662 | 763 | ||
663 | for (i = ALS4K_GCR_91_DMA0_ADDR; i <= ALS4K_GCR_96_DMA3_MODE_COUNT; ++i) | 764 | /* SPECS_PAGE: 39 */ |
664 | snd_als4000_gcr_write(chip, i, 0); | 765 | for (i = ALS4K_GCR91_DMA0_ADDR; i <= ALS4K_GCR96_DMA3_MODE_COUNT; ++i) |
766 | snd_als4k_gcr_write(chip, i, 0); | ||
665 | 767 | ||
666 | snd_als4000_gcr_write(chip, ALS4K_GCR_99_DMA_EMULATION_CTRL, | 768 | snd_als4k_gcr_write(chip, ALS4K_GCR99_DMA_EMULATION_CTRL, |
667 | snd_als4000_gcr_read(chip, ALS4K_GCR_99_DMA_EMULATION_CTRL)); | 769 | snd_als4k_gcr_read(chip, ALS4K_GCR99_DMA_EMULATION_CTRL)); |
668 | spin_unlock_irq(&chip->reg_lock); | 770 | spin_unlock_irq(&chip->reg_lock); |
669 | } | 771 | } |
670 | 772 | ||
@@ -739,7 +841,7 @@ static void snd_card_als4000_free( struct snd_card *card ) | |||
739 | struct snd_card_als4000 *acard = card->private_data; | 841 | struct snd_card_als4000 *acard = card->private_data; |
740 | 842 | ||
741 | /* make sure that interrupts are disabled */ | 843 | /* make sure that interrupts are disabled */ |
742 | snd_als4000_gcr_write_addr(acard->iobase, ALS4K_GCR_8C_MISC_CTRL, 0); | 844 | snd_als4k_gcr_write_addr(acard->iobase, ALS4K_GCR8C_MISC_CTRL, 0); |
743 | /* free resources */ | 845 | /* free resources */ |
744 | snd_als4000_free_gameport(acard); | 846 | snd_als4000_free_gameport(acard); |
745 | pci_release_regions(acard->pci); | 847 | pci_release_regions(acard->pci); |
@@ -788,7 +890,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
788 | pci_set_master(pci); | 890 | pci_set_master(pci); |
789 | 891 | ||
790 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, | 892 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, |
791 | sizeof( struct snd_card_als4000 ) ); | 893 | sizeof(*acard) /* private_data: acard */); |
792 | if (card == NULL) { | 894 | if (card == NULL) { |
793 | pci_release_regions(pci); | 895 | pci_release_regions(pci); |
794 | pci_disable_device(pci); | 896 | pci_disable_device(pci); |
@@ -806,6 +908,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
806 | if ((err = snd_sbdsp_create(card, | 908 | if ((err = snd_sbdsp_create(card, |
807 | iobase + ALS4K_IOB_10_ADLIB_ADDR0, | 909 | iobase + ALS4K_IOB_10_ADLIB_ADDR0, |
808 | pci->irq, | 910 | pci->irq, |
911 | /* internally registered as IRQF_SHARED in case of ALS4000 SB */ | ||
809 | snd_als4000_interrupt, | 912 | snd_als4000_interrupt, |
810 | -1, | 913 | -1, |
811 | -1, | 914 | -1, |
@@ -835,8 +938,10 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, | |||
835 | goto out_err; | 938 | goto out_err; |
836 | } | 939 | } |
837 | /* FIXME: ALS4000 has interesting MPU401 configuration features | 940 | /* FIXME: ALS4000 has interesting MPU401 configuration features |
838 | * at CR 0x1A (pass-thru / UART switching, fast MIDI clock, etc.), | 941 | * at ALS4K_CR1A_MPU401_UART_MODE_CONTROL |
839 | * however there doesn't seem to be an ALSA API for this... */ | 942 | * (pass-thru / UART switching, fast MIDI clock, etc.), |
943 | * however there doesn't seem to be an ALSA API for this... | ||
944 | * SPECS_PAGE: 21 */ | ||
840 | 945 | ||
841 | if ((err = snd_als4000_pcm(chip, 0)) < 0) { | 946 | if ((err = snd_als4000_pcm(chip, 0)) < 0) { |
842 | goto out_err; | 947 | goto out_err; |