Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | |
3 | * Routines for control of 16-bit SoundBlaster cards and clones | |
4 | * Note: This is very ugly hardware which uses one 8-bit DMA channel and | |
5 | * second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't | |
6 | * transfer 16-bit samples and 16-bit DMA channels can't transfer | |
7 | * 8-bit samples. This make full duplex more complicated than | |
8 | * can be... People, don't buy these soundcards for full 16-bit | |
9 | * duplex!!! | |
10 | * Note: 16-bit wide is assigned to first direction which made request. | |
11 | * With full duplex - playback is preferred with abstract layer. | |
12 | * | |
13 | * Note: Some chip revisions have hardware bug. Changing capture | |
14 | * channel from full-duplex 8bit DMA to 16bit DMA will block | |
15 | * 16bit DMA transfers from DSP chip (capture) until 8bit transfer | |
16 | * to DSP chip (playback) starts. This bug can be avoided with | |
17 | * "16bit DMA Allocation" setting set to Playback or Capture. | |
18 | * | |
19 | * | |
20 | * This program is free software; you can redistribute it and/or modify | |
21 | * it under the terms of the GNU General Public License as published by | |
22 | * the Free Software Foundation; either version 2 of the License, or | |
23 | * (at your option) any later version. | |
24 | * | |
25 | * This program is distributed in the hope that it will be useful, | |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
28 | * GNU General Public License for more details. | |
29 | * | |
30 | * You should have received a copy of the GNU General Public License | |
31 | * along with this program; if not, write to the Free Software | |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
33 | * | |
34 | */ | |
35 | ||
36 | #include <sound/driver.h> | |
37 | #include <asm/io.h> | |
38 | #include <asm/dma.h> | |
39 | #include <linux/init.h> | |
40 | #include <linux/time.h> | |
41 | #include <sound/core.h> | |
42 | #include <sound/sb.h> | |
43 | #include <sound/sb16_csp.h> | |
44 | #include <sound/mpu401.h> | |
45 | #include <sound/control.h> | |
46 | #include <sound/info.h> | |
47 | ||
48 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | |
49 | MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones"); | |
50 | MODULE_LICENSE("GPL"); | |
51 | ||
52 | #ifdef CONFIG_SND_SB16_CSP | |
53 | static void snd_sb16_csp_playback_prepare(sb_t *chip, snd_pcm_runtime_t *runtime) | |
54 | { | |
55 | if (chip->hardware == SB_HW_16CSP) { | |
56 | snd_sb_csp_t *csp = chip->csp; | |
57 | ||
58 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | |
59 | /* manually loaded codec */ | |
60 | if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) && | |
61 | ((1U << runtime->format) == csp->acc_format)) { | |
62 | /* Supported runtime PCM format for playback */ | |
63 | if (csp->ops.csp_use(csp) == 0) { | |
64 | /* If CSP was successfully acquired */ | |
65 | goto __start_CSP; | |
66 | } | |
67 | } else if ((csp->mode & SNDRV_SB_CSP_MODE_QSOUND) && (csp->q_enabled)) { | |
68 | /* QSound decoder is loaded and enabled */ | |
69 | if ((1 << runtime->format) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | |
70 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE)) { | |
71 | /* Only for simple PCM formats */ | |
72 | if (csp->ops.csp_use(csp) == 0) { | |
73 | /* If CSP was successfully acquired */ | |
74 | goto __start_CSP; | |
75 | } | |
76 | } | |
77 | } | |
78 | } else if (csp->ops.csp_use(csp) == 0) { | |
79 | /* Acquire CSP and try to autoload hardware codec */ | |
80 | if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_WRITE)) { | |
81 | /* Unsupported format, release CSP */ | |
82 | csp->ops.csp_unuse(csp); | |
83 | } else { | |
84 | __start_CSP: | |
85 | /* Try to start CSP */ | |
86 | if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_PLAYBACK_16) ? | |
87 | SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT, | |
88 | (runtime->channels > 1) ? | |
89 | SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) { | |
90 | /* Failed, release CSP */ | |
91 | csp->ops.csp_unuse(csp); | |
92 | } else { | |
93 | /* Success, CSP acquired and running */ | |
94 | chip->open = SNDRV_SB_CSP_MODE_DSP_WRITE; | |
95 | } | |
96 | } | |
97 | } | |
98 | } | |
99 | } | |
100 | ||
101 | static void snd_sb16_csp_capture_prepare(sb_t *chip, snd_pcm_runtime_t *runtime) | |
102 | { | |
103 | if (chip->hardware == SB_HW_16CSP) { | |
104 | snd_sb_csp_t *csp = chip->csp; | |
105 | ||
106 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | |
107 | /* manually loaded codec */ | |
108 | if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) && | |
109 | ((1U << runtime->format) == csp->acc_format)) { | |
110 | /* Supported runtime PCM format for capture */ | |
111 | if (csp->ops.csp_use(csp) == 0) { | |
112 | /* If CSP was successfully acquired */ | |
113 | goto __start_CSP; | |
114 | } | |
115 | } | |
116 | } else if (csp->ops.csp_use(csp) == 0) { | |
117 | /* Acquire CSP and try to autoload hardware codec */ | |
118 | if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_READ)) { | |
119 | /* Unsupported format, release CSP */ | |
120 | csp->ops.csp_unuse(csp); | |
121 | } else { | |
122 | __start_CSP: | |
123 | /* Try to start CSP */ | |
124 | if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_CAPTURE_16) ? | |
125 | SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT, | |
126 | (runtime->channels > 1) ? | |
127 | SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) { | |
128 | /* Failed, release CSP */ | |
129 | csp->ops.csp_unuse(csp); | |
130 | } else { | |
131 | /* Success, CSP acquired and running */ | |
132 | chip->open = SNDRV_SB_CSP_MODE_DSP_READ; | |
133 | } | |
134 | } | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | static void snd_sb16_csp_update(sb_t *chip) | |
140 | { | |
141 | if (chip->hardware == SB_HW_16CSP) { | |
142 | snd_sb_csp_t *csp = chip->csp; | |
143 | ||
144 | if (csp->qpos_changed) { | |
145 | spin_lock(&chip->reg_lock); | |
146 | csp->ops.csp_qsound_transfer (csp); | |
147 | spin_unlock(&chip->reg_lock); | |
148 | } | |
149 | } | |
150 | } | |
151 | ||
152 | static void snd_sb16_csp_playback_open(sb_t *chip, snd_pcm_runtime_t *runtime) | |
153 | { | |
154 | /* CSP decoders (QSound excluded) support only 16bit transfers */ | |
155 | if (chip->hardware == SB_HW_16CSP) { | |
156 | snd_sb_csp_t *csp = chip->csp; | |
157 | ||
158 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | |
159 | /* manually loaded codec */ | |
160 | if (csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) { | |
161 | runtime->hw.formats |= csp->acc_format; | |
162 | } | |
163 | } else { | |
164 | /* autoloaded codecs */ | |
165 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | |
166 | SNDRV_PCM_FMTBIT_IMA_ADPCM; | |
167 | } | |
168 | } | |
169 | } | |
170 | ||
171 | static void snd_sb16_csp_playback_close(sb_t *chip) | |
172 | { | |
173 | if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_WRITE)) { | |
174 | snd_sb_csp_t *csp = chip->csp; | |
175 | ||
176 | if (csp->ops.csp_stop(csp) == 0) { | |
177 | csp->ops.csp_unuse(csp); | |
178 | chip->open = 0; | |
179 | } | |
180 | } | |
181 | } | |
182 | ||
183 | static void snd_sb16_csp_capture_open(sb_t *chip, snd_pcm_runtime_t *runtime) | |
184 | { | |
185 | /* CSP coders support only 16bit transfers */ | |
186 | if (chip->hardware == SB_HW_16CSP) { | |
187 | snd_sb_csp_t *csp = chip->csp; | |
188 | ||
189 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | |
190 | /* manually loaded codec */ | |
191 | if (csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) { | |
192 | runtime->hw.formats |= csp->acc_format; | |
193 | } | |
194 | } else { | |
195 | /* autoloaded codecs */ | |
196 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | |
197 | SNDRV_PCM_FMTBIT_IMA_ADPCM; | |
198 | } | |
199 | } | |
200 | } | |
201 | ||
202 | static void snd_sb16_csp_capture_close(sb_t *chip) | |
203 | { | |
204 | if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_READ)) { | |
205 | snd_sb_csp_t *csp = chip->csp; | |
206 | ||
207 | if (csp->ops.csp_stop(csp) == 0) { | |
208 | csp->ops.csp_unuse(csp); | |
209 | chip->open = 0; | |
210 | } | |
211 | } | |
212 | } | |
213 | #else | |
214 | #define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/ | |
215 | #define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/ | |
216 | #define snd_sb16_csp_update(chip) /*nop*/ | |
217 | #define snd_sb16_csp_playback_open(chip, runtime) /*nop*/ | |
218 | #define snd_sb16_csp_playback_close(chip) /*nop*/ | |
219 | #define snd_sb16_csp_capture_open(chip, runtime) /*nop*/ | |
220 | #define snd_sb16_csp_capture_close(chip) /*nop*/ | |
221 | #endif | |
222 | ||
223 | ||
224 | static void snd_sb16_setup_rate(sb_t *chip, | |
225 | unsigned short rate, | |
226 | int channel) | |
227 | { | |
228 | unsigned long flags; | |
229 | ||
230 | spin_lock_irqsave(&chip->reg_lock, flags); | |
231 | if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16)) | |
232 | snd_sb_ack_16bit(chip); | |
233 | else | |
234 | snd_sb_ack_8bit(chip); | |
235 | if (!(chip->mode & SB_RATE_LOCK)) { | |
236 | chip->locked_rate = rate; | |
237 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_IN); | |
238 | snd_sbdsp_command(chip, rate >> 8); | |
239 | snd_sbdsp_command(chip, rate & 0xff); | |
240 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT); | |
241 | snd_sbdsp_command(chip, rate >> 8); | |
242 | snd_sbdsp_command(chip, rate & 0xff); | |
243 | } | |
244 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
245 | } | |
246 | ||
247 | static int snd_sb16_hw_params(snd_pcm_substream_t * substream, | |
248 | snd_pcm_hw_params_t * hw_params) | |
249 | { | |
250 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | |
251 | } | |
252 | ||
253 | static int snd_sb16_hw_free(snd_pcm_substream_t * substream) | |
254 | { | |
255 | snd_pcm_lib_free_pages(substream); | |
256 | return 0; | |
257 | } | |
258 | ||
259 | static int snd_sb16_playback_prepare(snd_pcm_substream_t * substream) | |
260 | { | |
261 | unsigned long flags; | |
262 | sb_t *chip = snd_pcm_substream_chip(substream); | |
263 | snd_pcm_runtime_t *runtime = substream->runtime; | |
264 | unsigned char format; | |
265 | unsigned int size, count, dma; | |
266 | ||
267 | snd_sb16_csp_playback_prepare(chip, runtime); | |
268 | if (snd_pcm_format_unsigned(runtime->format) > 0) { | |
269 | format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO; | |
270 | } else { | |
271 | format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO; | |
272 | } | |
273 | ||
274 | snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_PLAYBACK); | |
275 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); | |
276 | dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16; | |
277 | snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); | |
278 | ||
279 | count = snd_pcm_lib_period_bytes(substream); | |
280 | spin_lock_irqsave(&chip->reg_lock, flags); | |
281 | if (chip->mode & SB_MODE_PLAYBACK_16) { | |
282 | count >>= 1; | |
283 | count--; | |
284 | snd_sbdsp_command(chip, SB_DSP4_OUT16_AI); | |
285 | snd_sbdsp_command(chip, format); | |
286 | snd_sbdsp_command(chip, count & 0xff); | |
287 | snd_sbdsp_command(chip, count >> 8); | |
288 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | |
289 | } else { | |
290 | count--; | |
291 | snd_sbdsp_command(chip, SB_DSP4_OUT8_AI); | |
292 | snd_sbdsp_command(chip, format); | |
293 | snd_sbdsp_command(chip, count & 0xff); | |
294 | snd_sbdsp_command(chip, count >> 8); | |
295 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | |
296 | } | |
297 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
298 | return 0; | |
299 | } | |
300 | ||
301 | static int snd_sb16_playback_trigger(snd_pcm_substream_t * substream, | |
302 | int cmd) | |
303 | { | |
304 | sb_t *chip = snd_pcm_substream_chip(substream); | |
305 | int result = 0; | |
306 | ||
307 | spin_lock(&chip->reg_lock); | |
308 | switch (cmd) { | |
309 | case SNDRV_PCM_TRIGGER_START: | |
310 | chip->mode |= SB_RATE_LOCK_PLAYBACK; | |
311 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | |
312 | break; | |
313 | case SNDRV_PCM_TRIGGER_STOP: | |
314 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF); | |
315 | /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */ | |
316 | if (chip->mode & SB_RATE_LOCK_CAPTURE) | |
317 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | |
318 | chip->mode &= ~SB_RATE_LOCK_PLAYBACK; | |
319 | break; | |
320 | default: | |
321 | result = -EINVAL; | |
322 | } | |
323 | spin_unlock(&chip->reg_lock); | |
324 | return result; | |
325 | } | |
326 | ||
327 | static int snd_sb16_capture_prepare(snd_pcm_substream_t * substream) | |
328 | { | |
329 | unsigned long flags; | |
330 | sb_t *chip = snd_pcm_substream_chip(substream); | |
331 | snd_pcm_runtime_t *runtime = substream->runtime; | |
332 | unsigned char format; | |
333 | unsigned int size, count, dma; | |
334 | ||
335 | snd_sb16_csp_capture_prepare(chip, runtime); | |
336 | if (snd_pcm_format_unsigned(runtime->format) > 0) { | |
337 | format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO; | |
338 | } else { | |
339 | format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO; | |
340 | } | |
341 | snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_CAPTURE); | |
342 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); | |
343 | dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16; | |
344 | snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); | |
345 | ||
346 | count = snd_pcm_lib_period_bytes(substream); | |
347 | spin_lock_irqsave(&chip->reg_lock, flags); | |
348 | if (chip->mode & SB_MODE_CAPTURE_16) { | |
349 | count >>= 1; | |
350 | count--; | |
351 | snd_sbdsp_command(chip, SB_DSP4_IN16_AI); | |
352 | snd_sbdsp_command(chip, format); | |
353 | snd_sbdsp_command(chip, count & 0xff); | |
354 | snd_sbdsp_command(chip, count >> 8); | |
355 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | |
356 | } else { | |
357 | count--; | |
358 | snd_sbdsp_command(chip, SB_DSP4_IN8_AI); | |
359 | snd_sbdsp_command(chip, format); | |
360 | snd_sbdsp_command(chip, count & 0xff); | |
361 | snd_sbdsp_command(chip, count >> 8); | |
362 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | |
363 | } | |
364 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
365 | return 0; | |
366 | } | |
367 | ||
368 | static int snd_sb16_capture_trigger(snd_pcm_substream_t * substream, | |
369 | int cmd) | |
370 | { | |
371 | sb_t *chip = snd_pcm_substream_chip(substream); | |
372 | int result = 0; | |
373 | ||
374 | spin_lock(&chip->reg_lock); | |
375 | switch (cmd) { | |
376 | case SNDRV_PCM_TRIGGER_START: | |
377 | chip->mode |= SB_RATE_LOCK_CAPTURE; | |
378 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | |
379 | break; | |
380 | case SNDRV_PCM_TRIGGER_STOP: | |
381 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF); | |
382 | /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */ | |
383 | if (chip->mode & SB_RATE_LOCK_PLAYBACK) | |
384 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | |
385 | chip->mode &= ~SB_RATE_LOCK_CAPTURE; | |
386 | break; | |
387 | default: | |
388 | result = -EINVAL; | |
389 | } | |
390 | spin_unlock(&chip->reg_lock); | |
391 | return result; | |
392 | } | |
393 | ||
394 | irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |
395 | { | |
396 | sb_t *chip = dev_id; | |
397 | unsigned char status; | |
398 | int ok; | |
399 | ||
400 | spin_lock(&chip->mixer_lock); | |
401 | status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); | |
402 | spin_unlock(&chip->mixer_lock); | |
403 | if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback) | |
404 | chip->rmidi_callback(irq, chip->rmidi->private_data, regs); | |
405 | if (status & SB_IRQTYPE_8BIT) { | |
406 | ok = 0; | |
407 | if (chip->mode & SB_MODE_PLAYBACK_8) { | |
408 | snd_pcm_period_elapsed(chip->playback_substream); | |
409 | snd_sb16_csp_update(chip); | |
410 | ok++; | |
411 | } | |
412 | if (chip->mode & SB_MODE_CAPTURE_8) { | |
413 | snd_pcm_period_elapsed(chip->capture_substream); | |
414 | ok++; | |
415 | } | |
416 | spin_lock(&chip->reg_lock); | |
417 | if (!ok) | |
418 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | |
419 | snd_sb_ack_8bit(chip); | |
420 | spin_unlock(&chip->reg_lock); | |
421 | } | |
422 | if (status & SB_IRQTYPE_16BIT) { | |
423 | ok = 0; | |
424 | if (chip->mode & SB_MODE_PLAYBACK_16) { | |
425 | snd_pcm_period_elapsed(chip->playback_substream); | |
426 | snd_sb16_csp_update(chip); | |
427 | ok++; | |
428 | } | |
429 | if (chip->mode & SB_MODE_CAPTURE_16) { | |
430 | snd_pcm_period_elapsed(chip->capture_substream); | |
431 | ok++; | |
432 | } | |
433 | spin_lock(&chip->reg_lock); | |
434 | if (!ok) | |
435 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | |
436 | snd_sb_ack_16bit(chip); | |
437 | spin_unlock(&chip->reg_lock); | |
438 | } | |
439 | return IRQ_HANDLED; | |
440 | } | |
441 | ||
442 | /* | |
443 | ||
444 | */ | |
445 | ||
446 | static snd_pcm_uframes_t snd_sb16_playback_pointer(snd_pcm_substream_t * substream) | |
447 | { | |
448 | sb_t *chip = snd_pcm_substream_chip(substream); | |
449 | unsigned int dma; | |
450 | size_t ptr; | |
451 | ||
452 | dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16; | |
453 | ptr = snd_dma_pointer(dma, chip->p_dma_size); | |
454 | return bytes_to_frames(substream->runtime, ptr); | |
455 | } | |
456 | ||
457 | static snd_pcm_uframes_t snd_sb16_capture_pointer(snd_pcm_substream_t * substream) | |
458 | { | |
459 | sb_t *chip = snd_pcm_substream_chip(substream); | |
460 | unsigned int dma; | |
461 | size_t ptr; | |
462 | ||
463 | dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16; | |
464 | ptr = snd_dma_pointer(dma, chip->c_dma_size); | |
465 | return bytes_to_frames(substream->runtime, ptr); | |
466 | } | |
467 | ||
468 | /* | |
469 | ||
470 | */ | |
471 | ||
472 | static snd_pcm_hardware_t snd_sb16_playback = | |
473 | { | |
474 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | |
475 | SNDRV_PCM_INFO_MMAP_VALID), | |
476 | .formats = 0, | |
477 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100, | |
478 | .rate_min = 4000, | |
479 | .rate_max = 44100, | |
480 | .channels_min = 1, | |
481 | .channels_max = 2, | |
482 | .buffer_bytes_max = (128*1024), | |
483 | .period_bytes_min = 64, | |
484 | .period_bytes_max = (128*1024), | |
485 | .periods_min = 1, | |
486 | .periods_max = 1024, | |
487 | .fifo_size = 0, | |
488 | }; | |
489 | ||
490 | static snd_pcm_hardware_t snd_sb16_capture = | |
491 | { | |
492 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | |
493 | SNDRV_PCM_INFO_MMAP_VALID), | |
494 | .formats = 0, | |
495 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100, | |
496 | .rate_min = 4000, | |
497 | .rate_max = 44100, | |
498 | .channels_min = 1, | |
499 | .channels_max = 2, | |
500 | .buffer_bytes_max = (128*1024), | |
501 | .period_bytes_min = 64, | |
502 | .period_bytes_max = (128*1024), | |
503 | .periods_min = 1, | |
504 | .periods_max = 1024, | |
505 | .fifo_size = 0, | |
506 | }; | |
507 | ||
508 | /* | |
509 | * open/close | |
510 | */ | |
511 | ||
512 | static int snd_sb16_playback_open(snd_pcm_substream_t * substream) | |
513 | { | |
514 | unsigned long flags; | |
515 | sb_t *chip = snd_pcm_substream_chip(substream); | |
516 | snd_pcm_runtime_t *runtime = substream->runtime; | |
517 | ||
518 | spin_lock_irqsave(&chip->open_lock, flags); | |
519 | if (chip->mode & SB_MODE_PLAYBACK) { | |
520 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
521 | return -EAGAIN; | |
522 | } | |
523 | runtime->hw = snd_sb16_playback; | |
524 | ||
525 | /* skip if 16 bit DMA was reserved for capture */ | |
526 | if (chip->force_mode16 & SB_MODE_CAPTURE_16) | |
527 | goto __skip_16bit; | |
528 | ||
529 | if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_CAPTURE_16)) { | |
530 | chip->mode |= SB_MODE_PLAYBACK_16; | |
531 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | |
532 | /* Vibra16X hack */ | |
533 | if (chip->dma16 <= 3) { | |
534 | runtime->hw.buffer_bytes_max = | |
535 | runtime->hw.period_bytes_max = 64 * 1024; | |
536 | } else { | |
537 | snd_sb16_csp_playback_open(chip, runtime); | |
538 | } | |
539 | goto __open_ok; | |
540 | } | |
541 | ||
542 | __skip_16bit: | |
543 | if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_CAPTURE_8)) { | |
544 | chip->mode |= SB_MODE_PLAYBACK_8; | |
545 | /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */ | |
546 | if (chip->dma16 < 0) { | |
547 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | |
548 | chip->mode |= SB_MODE_PLAYBACK_16; | |
549 | } else { | |
550 | runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8; | |
551 | } | |
552 | runtime->hw.buffer_bytes_max = | |
553 | runtime->hw.period_bytes_max = 64 * 1024; | |
554 | goto __open_ok; | |
555 | } | |
556 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
557 | return -EAGAIN; | |
558 | ||
559 | __open_ok: | |
560 | if (chip->hardware == SB_HW_ALS100) | |
561 | runtime->hw.rate_max = 48000; | |
562 | if (chip->mode & SB_RATE_LOCK) | |
563 | runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; | |
564 | chip->playback_substream = substream; | |
565 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
566 | return 0; | |
567 | } | |
568 | ||
569 | static int snd_sb16_playback_close(snd_pcm_substream_t * substream) | |
570 | { | |
571 | unsigned long flags; | |
572 | sb_t *chip = snd_pcm_substream_chip(substream); | |
573 | ||
574 | snd_sb16_csp_playback_close(chip); | |
575 | spin_lock_irqsave(&chip->open_lock, flags); | |
576 | chip->playback_substream = NULL; | |
577 | chip->mode &= ~SB_MODE_PLAYBACK; | |
578 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
579 | return 0; | |
580 | } | |
581 | ||
582 | static int snd_sb16_capture_open(snd_pcm_substream_t * substream) | |
583 | { | |
584 | unsigned long flags; | |
585 | sb_t *chip = snd_pcm_substream_chip(substream); | |
586 | snd_pcm_runtime_t *runtime = substream->runtime; | |
587 | ||
588 | spin_lock_irqsave(&chip->open_lock, flags); | |
589 | if (chip->mode & SB_MODE_CAPTURE) { | |
590 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
591 | return -EAGAIN; | |
592 | } | |
593 | runtime->hw = snd_sb16_capture; | |
594 | ||
595 | /* skip if 16 bit DMA was reserved for playback */ | |
596 | if (chip->force_mode16 & SB_MODE_PLAYBACK_16) | |
597 | goto __skip_16bit; | |
598 | ||
599 | if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_16)) { | |
600 | chip->mode |= SB_MODE_CAPTURE_16; | |
601 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | |
602 | /* Vibra16X hack */ | |
603 | if (chip->dma16 <= 3) { | |
604 | runtime->hw.buffer_bytes_max = | |
605 | runtime->hw.period_bytes_max = 64 * 1024; | |
606 | } else { | |
607 | snd_sb16_csp_capture_open(chip, runtime); | |
608 | } | |
609 | goto __open_ok; | |
610 | } | |
611 | ||
612 | __skip_16bit: | |
613 | if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_8)) { | |
614 | chip->mode |= SB_MODE_CAPTURE_8; | |
615 | /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */ | |
616 | if (chip->dma16 < 0) { | |
617 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | |
618 | chip->mode |= SB_MODE_CAPTURE_16; | |
619 | } else { | |
620 | runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8; | |
621 | } | |
622 | runtime->hw.buffer_bytes_max = | |
623 | runtime->hw.period_bytes_max = 64 * 1024; | |
624 | goto __open_ok; | |
625 | } | |
626 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
627 | return -EAGAIN; | |
628 | ||
629 | __open_ok: | |
630 | if (chip->hardware == SB_HW_ALS100) | |
631 | runtime->hw.rate_max = 48000; | |
632 | if (chip->mode & SB_RATE_LOCK) | |
633 | runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; | |
634 | chip->capture_substream = substream; | |
635 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
636 | return 0; | |
637 | } | |
638 | ||
639 | static int snd_sb16_capture_close(snd_pcm_substream_t * substream) | |
640 | { | |
641 | unsigned long flags; | |
642 | sb_t *chip = snd_pcm_substream_chip(substream); | |
643 | ||
644 | snd_sb16_csp_capture_close(chip); | |
645 | spin_lock_irqsave(&chip->open_lock, flags); | |
646 | chip->capture_substream = NULL; | |
647 | chip->mode &= ~SB_MODE_CAPTURE; | |
648 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
649 | return 0; | |
650 | } | |
651 | ||
652 | /* | |
653 | * DMA control interface | |
654 | */ | |
655 | ||
656 | static int snd_sb16_set_dma_mode(sb_t *chip, int what) | |
657 | { | |
658 | if (chip->dma8 < 0 || chip->dma16 < 0) { | |
659 | snd_assert(what == 0, return -EINVAL); | |
660 | return 0; | |
661 | } | |
662 | if (what == 0) { | |
663 | chip->force_mode16 = 0; | |
664 | } else if (what == 1) { | |
665 | chip->force_mode16 = SB_MODE_PLAYBACK_16; | |
666 | } else if (what == 2) { | |
667 | chip->force_mode16 = SB_MODE_CAPTURE_16; | |
668 | } else { | |
669 | return -EINVAL; | |
670 | } | |
671 | return 0; | |
672 | } | |
673 | ||
674 | static int snd_sb16_get_dma_mode(sb_t *chip) | |
675 | { | |
676 | if (chip->dma8 < 0 || chip->dma16 < 0) | |
677 | return 0; | |
678 | switch (chip->force_mode16) { | |
679 | case SB_MODE_PLAYBACK_16: | |
680 | return 1; | |
681 | case SB_MODE_CAPTURE_16: | |
682 | return 2; | |
683 | default: | |
684 | return 0; | |
685 | } | |
686 | } | |
687 | ||
688 | static int snd_sb16_dma_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | |
689 | { | |
690 | static char *texts[3] = { | |
691 | "Auto", "Playback", "Capture" | |
692 | }; | |
693 | ||
694 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | |
695 | uinfo->count = 1; | |
696 | uinfo->value.enumerated.items = 3; | |
697 | if (uinfo->value.enumerated.item > 2) | |
698 | uinfo->value.enumerated.item = 2; | |
699 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | |
700 | return 0; | |
701 | } | |
702 | ||
703 | static int snd_sb16_dma_control_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | |
704 | { | |
705 | sb_t *chip = snd_kcontrol_chip(kcontrol); | |
706 | unsigned long flags; | |
707 | ||
708 | spin_lock_irqsave(&chip->reg_lock, flags); | |
709 | ucontrol->value.enumerated.item[0] = snd_sb16_get_dma_mode(chip); | |
710 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
711 | return 0; | |
712 | } | |
713 | ||
714 | static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | |
715 | { | |
716 | sb_t *chip = snd_kcontrol_chip(kcontrol); | |
717 | unsigned long flags; | |
718 | unsigned char nval, oval; | |
719 | int change; | |
720 | ||
721 | if ((nval = ucontrol->value.enumerated.item[0]) > 2) | |
722 | return -EINVAL; | |
723 | spin_lock_irqsave(&chip->reg_lock, flags); | |
724 | oval = snd_sb16_get_dma_mode(chip); | |
725 | change = nval != oval; | |
726 | snd_sb16_set_dma_mode(chip, nval); | |
727 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
728 | return change; | |
729 | } | |
730 | ||
731 | static snd_kcontrol_new_t snd_sb16_dma_control = { | |
67ed4161 | 732 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, |
1da177e4 LT |
733 | .name = "16-bit DMA Allocation", |
734 | .info = snd_sb16_dma_control_info, | |
735 | .get = snd_sb16_dma_control_get, | |
736 | .put = snd_sb16_dma_control_put | |
737 | }; | |
738 | ||
739 | /* | |
740 | * Initialization part | |
741 | */ | |
742 | ||
743 | int snd_sb16dsp_configure(sb_t * chip) | |
744 | { | |
745 | unsigned long flags; | |
746 | unsigned char irqreg = 0, dmareg = 0, mpureg; | |
747 | unsigned char realirq, realdma, realmpureg; | |
748 | /* note: mpu register should be present only on SB16 Vibra soundcards */ | |
749 | ||
99b359ba | 750 | // printk(KERN_DEBUG "codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16); |
1da177e4 LT |
751 | spin_lock_irqsave(&chip->mixer_lock, flags); |
752 | mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06; | |
753 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | |
754 | switch (chip->irq) { | |
755 | case 2: | |
756 | case 9: | |
757 | irqreg |= SB_IRQSETUP_IRQ9; | |
758 | break; | |
759 | case 5: | |
760 | irqreg |= SB_IRQSETUP_IRQ5; | |
761 | break; | |
762 | case 7: | |
763 | irqreg |= SB_IRQSETUP_IRQ7; | |
764 | break; | |
765 | case 10: | |
766 | irqreg |= SB_IRQSETUP_IRQ10; | |
767 | break; | |
768 | default: | |
769 | return -EINVAL; | |
770 | } | |
771 | if (chip->dma8 >= 0) { | |
772 | switch (chip->dma8) { | |
773 | case 0: | |
774 | dmareg |= SB_DMASETUP_DMA0; | |
775 | break; | |
776 | case 1: | |
777 | dmareg |= SB_DMASETUP_DMA1; | |
778 | break; | |
779 | case 3: | |
780 | dmareg |= SB_DMASETUP_DMA3; | |
781 | break; | |
782 | default: | |
783 | return -EINVAL; | |
784 | } | |
785 | } | |
786 | if (chip->dma16 >= 0 && chip->dma16 != chip->dma8) { | |
787 | switch (chip->dma16) { | |
788 | case 5: | |
789 | dmareg |= SB_DMASETUP_DMA5; | |
790 | break; | |
791 | case 6: | |
792 | dmareg |= SB_DMASETUP_DMA6; | |
793 | break; | |
794 | case 7: | |
795 | dmareg |= SB_DMASETUP_DMA7; | |
796 | break; | |
797 | default: | |
798 | return -EINVAL; | |
799 | } | |
800 | } | |
801 | switch (chip->mpu_port) { | |
802 | case 0x300: | |
803 | mpureg |= 0x04; | |
804 | break; | |
805 | case 0x330: | |
806 | mpureg |= 0x00; | |
807 | break; | |
808 | default: | |
809 | mpureg |= 0x02; /* disable MPU */ | |
810 | } | |
811 | spin_lock_irqsave(&chip->mixer_lock, flags); | |
812 | ||
813 | snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg); | |
814 | realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP); | |
815 | ||
816 | snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg); | |
817 | realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP); | |
818 | ||
819 | snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg); | |
820 | realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP); | |
821 | ||
822 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | |
823 | if ((~realirq) & irqreg || (~realdma) & dmareg) { | |
99b359ba TI |
824 | snd_printk(KERN_ERR "SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port); |
825 | snd_printk(KERN_ERR "SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg); | |
826 | snd_printk(KERN_ERR "SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg); | |
1da177e4 LT |
827 | return -ENODEV; |
828 | } | |
829 | return 0; | |
830 | } | |
831 | ||
832 | static snd_pcm_ops_t snd_sb16_playback_ops = { | |
833 | .open = snd_sb16_playback_open, | |
834 | .close = snd_sb16_playback_close, | |
835 | .ioctl = snd_pcm_lib_ioctl, | |
836 | .hw_params = snd_sb16_hw_params, | |
837 | .hw_free = snd_sb16_hw_free, | |
838 | .prepare = snd_sb16_playback_prepare, | |
839 | .trigger = snd_sb16_playback_trigger, | |
840 | .pointer = snd_sb16_playback_pointer, | |
841 | }; | |
842 | ||
843 | static snd_pcm_ops_t snd_sb16_capture_ops = { | |
844 | .open = snd_sb16_capture_open, | |
845 | .close = snd_sb16_capture_close, | |
846 | .ioctl = snd_pcm_lib_ioctl, | |
847 | .hw_params = snd_sb16_hw_params, | |
848 | .hw_free = snd_sb16_hw_free, | |
849 | .prepare = snd_sb16_capture_prepare, | |
850 | .trigger = snd_sb16_capture_trigger, | |
851 | .pointer = snd_sb16_capture_pointer, | |
852 | }; | |
853 | ||
854 | static void snd_sb16dsp_pcm_free(snd_pcm_t *pcm) | |
855 | { | |
856 | snd_pcm_lib_preallocate_free_for_all(pcm); | |
857 | } | |
858 | ||
859 | int snd_sb16dsp_pcm(sb_t * chip, int device, snd_pcm_t ** rpcm) | |
860 | { | |
861 | snd_card_t *card = chip->card; | |
862 | snd_pcm_t *pcm; | |
863 | int err; | |
864 | ||
865 | if (rpcm) | |
866 | *rpcm = NULL; | |
867 | if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0) | |
868 | return err; | |
869 | sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); | |
870 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | |
871 | pcm->private_data = chip; | |
872 | pcm->private_free = snd_sb16dsp_pcm_free; | |
873 | ||
874 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); | |
875 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); | |
876 | ||
877 | if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) | |
878 | snd_ctl_add(card, snd_ctl_new1(&snd_sb16_dma_control, chip)); | |
879 | else | |
880 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | |
881 | ||
882 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | |
883 | snd_dma_isa_data(), | |
884 | 64*1024, 128*1024); | |
885 | ||
886 | if (rpcm) | |
887 | *rpcm = pcm; | |
888 | return 0; | |
889 | } | |
890 | ||
891 | const snd_pcm_ops_t *snd_sb16dsp_get_pcm_ops(int direction) | |
892 | { | |
893 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | |
894 | &snd_sb16_playback_ops : &snd_sb16_capture_ops; | |
895 | } | |
896 | ||
897 | EXPORT_SYMBOL(snd_sb16dsp_pcm); | |
898 | EXPORT_SYMBOL(snd_sb16dsp_get_pcm_ops); | |
899 | EXPORT_SYMBOL(snd_sb16dsp_configure); | |
900 | EXPORT_SYMBOL(snd_sb16dsp_interrupt); | |
901 | ||
902 | /* | |
903 | * INIT part | |
904 | */ | |
905 | ||
906 | static int __init alsa_sb16_init(void) | |
907 | { | |
908 | return 0; | |
909 | } | |
910 | ||
911 | static void __exit alsa_sb16_exit(void) | |
912 | { | |
913 | } | |
914 | ||
915 | module_init(alsa_sb16_init) | |
916 | module_exit(alsa_sb16_exit) |