]>
Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
c1017a4c | 2 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
3 | * Uros Bizjak <uros@kss-loka.si> |
4 | * | |
5 | * Routines for control of 8-bit SoundBlaster cards and clones | |
6 | * Please note: I don't have access to old SB8 soundcards. | |
7 | * | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | * | |
23 | * -- | |
24 | * | |
25 | * Thu Apr 29 20:36:17 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk> | |
26 | * DSP can't respond to commands whilst in "high speed" mode. Caused | |
27 | * glitching during playback. Fixed. | |
28 | * | |
29 | * Wed Jul 12 22:02:55 CEST 2000 Uros Bizjak <uros@kss-loka.si> | |
30 | * Cleaned up and rewrote lowlevel routines. | |
31 | */ | |
32 | ||
6cbbfe1c | 33 | #include <linux/io.h> |
1da177e4 LT |
34 | #include <asm/dma.h> |
35 | #include <linux/init.h> | |
36 | #include <linux/time.h> | |
da155d5b | 37 | #include <linux/module.h> |
1da177e4 LT |
38 | #include <sound/core.h> |
39 | #include <sound/sb.h> | |
40 | ||
c1017a4c | 41 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>"); |
1da177e4 LT |
42 | MODULE_DESCRIPTION("Routines for control of 8-bit SoundBlaster cards and clones"); |
43 | MODULE_LICENSE("GPL"); | |
44 | ||
45 | #define SB8_CLOCK 1000000 | |
46 | #define SB8_DEN(v) ((SB8_CLOCK + (v) / 2) / (v)) | |
47 | #define SB8_RATE(v) (SB8_CLOCK / SB8_DEN(v)) | |
48 | ||
b078bbfb | 49 | static const struct snd_ratnum clock = { |
1da177e4 LT |
50 | .num = SB8_CLOCK, |
51 | .den_min = 1, | |
52 | .den_max = 256, | |
53 | .den_step = 1, | |
54 | }; | |
55 | ||
b078bbfb | 56 | static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = { |
1da177e4 LT |
57 | .nrats = 1, |
58 | .rats = &clock, | |
59 | }; | |
60 | ||
b078bbfb | 61 | static const struct snd_ratnum stereo_clocks[] = { |
1da177e4 LT |
62 | { |
63 | .num = SB8_CLOCK, | |
64 | .den_min = SB8_DEN(22050), | |
65 | .den_max = SB8_DEN(22050), | |
66 | .den_step = 1, | |
67 | }, | |
68 | { | |
69 | .num = SB8_CLOCK, | |
70 | .den_min = SB8_DEN(11025), | |
71 | .den_max = SB8_DEN(11025), | |
72 | .den_step = 1, | |
73 | } | |
74 | }; | |
75 | ||
029d64b0 TI |
76 | static int snd_sb8_hw_constraint_rate_channels(struct snd_pcm_hw_params *params, |
77 | struct snd_pcm_hw_rule *rule) | |
1da177e4 | 78 | { |
029d64b0 | 79 | struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
1da177e4 LT |
80 | if (c->min > 1) { |
81 | unsigned int num = 0, den = 0; | |
82 | int err = snd_interval_ratnum(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE), | |
83 | 2, stereo_clocks, &num, &den); | |
84 | if (err >= 0 && den) { | |
85 | params->rate_num = num; | |
86 | params->rate_den = den; | |
87 | } | |
88 | return err; | |
89 | } | |
90 | return 0; | |
91 | } | |
92 | ||
029d64b0 TI |
93 | static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params, |
94 | struct snd_pcm_hw_rule *rule) | |
1da177e4 | 95 | { |
029d64b0 | 96 | struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
1da177e4 | 97 | if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) { |
029d64b0 | 98 | struct snd_interval t = { .min = 1, .max = 1 }; |
1da177e4 LT |
99 | return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t); |
100 | } | |
101 | return 0; | |
102 | } | |
103 | ||
029d64b0 | 104 | static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
105 | { |
106 | unsigned long flags; | |
029d64b0 TI |
107 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
108 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 | 109 | unsigned int mixreg, rate, size, count; |
ad8decb7 KH |
110 | unsigned char format; |
111 | unsigned char stereo = runtime->channels > 1; | |
112 | int dma; | |
1da177e4 LT |
113 | |
114 | rate = runtime->rate; | |
115 | switch (chip->hardware) { | |
ad8decb7 KH |
116 | case SB_HW_JAZZ16: |
117 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | |
118 | if (chip->mode & SB_MODE_CAPTURE_16) | |
119 | return -EBUSY; | |
120 | else | |
121 | chip->mode |= SB_MODE_PLAYBACK_16; | |
122 | } | |
123 | chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; | |
124 | break; | |
1da177e4 LT |
125 | case SB_HW_PRO: |
126 | if (runtime->channels > 1) { | |
622207dc TI |
127 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
128 | rate != SB8_RATE(22050))) | |
129 | return -EINVAL; | |
1da177e4 LT |
130 | chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; |
131 | break; | |
132 | } | |
133 | /* fallthru */ | |
134 | case SB_HW_201: | |
135 | if (rate > 23000) { | |
136 | chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; | |
137 | break; | |
138 | } | |
139 | /* fallthru */ | |
140 | case SB_HW_20: | |
141 | chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; | |
142 | break; | |
143 | case SB_HW_10: | |
144 | chip->playback_format = SB_DSP_OUTPUT; | |
145 | break; | |
146 | default: | |
147 | return -EINVAL; | |
148 | } | |
ad8decb7 KH |
149 | if (chip->mode & SB_MODE_PLAYBACK_16) { |
150 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | |
151 | dma = chip->dma16; | |
152 | } else { | |
153 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | |
154 | chip->mode |= SB_MODE_PLAYBACK_8; | |
155 | dma = chip->dma8; | |
156 | } | |
1da177e4 LT |
157 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); |
158 | count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); | |
159 | spin_lock_irqsave(&chip->reg_lock, flags); | |
160 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); | |
ad8decb7 KH |
161 | if (chip->hardware == SB_HW_JAZZ16) |
162 | snd_sbdsp_command(chip, format); | |
163 | else if (stereo) { | |
1da177e4 LT |
164 | /* set playback stereo mode */ |
165 | spin_lock(&chip->mixer_lock); | |
166 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); | |
167 | snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); | |
168 | spin_unlock(&chip->mixer_lock); | |
169 | ||
170 | /* Soundblaster hardware programming reference guide, 3-23 */ | |
171 | snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); | |
172 | runtime->dma_area[0] = 0x80; | |
ad8decb7 | 173 | snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); |
1da177e4 | 174 | /* force interrupt */ |
1da177e4 LT |
175 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); |
176 | snd_sbdsp_command(chip, 0); | |
177 | snd_sbdsp_command(chip, 0); | |
178 | } | |
179 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | |
ad8decb7 | 180 | if (stereo) { |
1da177e4 LT |
181 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
182 | spin_lock(&chip->mixer_lock); | |
183 | /* save output filter status and turn it off */ | |
184 | mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT); | |
185 | snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20); | |
186 | spin_unlock(&chip->mixer_lock); | |
187 | /* just use force_mode16 for temporary storate... */ | |
188 | chip->force_mode16 = mixreg; | |
189 | } else { | |
190 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | |
191 | } | |
192 | if (chip->playback_format != SB_DSP_OUTPUT) { | |
ad8decb7 KH |
193 | if (chip->mode & SB_MODE_PLAYBACK_16) |
194 | count /= 2; | |
1da177e4 LT |
195 | count--; |
196 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | |
197 | snd_sbdsp_command(chip, count & 0xff); | |
198 | snd_sbdsp_command(chip, count >> 8); | |
199 | } | |
200 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
ad8decb7 | 201 | snd_dma_program(dma, runtime->dma_addr, |
1da177e4 LT |
202 | size, DMA_MODE_WRITE | DMA_AUTOINIT); |
203 | return 0; | |
204 | } | |
205 | ||
029d64b0 | 206 | static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, |
1da177e4 LT |
207 | int cmd) |
208 | { | |
209 | unsigned long flags; | |
029d64b0 | 210 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
211 | unsigned int count; |
212 | ||
213 | spin_lock_irqsave(&chip->reg_lock, flags); | |
214 | switch (cmd) { | |
215 | case SNDRV_PCM_TRIGGER_START: | |
216 | snd_sbdsp_command(chip, chip->playback_format); | |
217 | if (chip->playback_format == SB_DSP_OUTPUT) { | |
218 | count = chip->p_period_size - 1; | |
219 | snd_sbdsp_command(chip, count & 0xff); | |
220 | snd_sbdsp_command(chip, count >> 8); | |
221 | } | |
222 | break; | |
223 | case SNDRV_PCM_TRIGGER_STOP: | |
224 | if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) { | |
029d64b0 | 225 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
226 | snd_sbdsp_reset(chip); |
227 | if (runtime->channels > 1) { | |
228 | spin_lock(&chip->mixer_lock); | |
229 | /* restore output filter and set hardware to mono mode */ | |
230 | snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02); | |
231 | spin_unlock(&chip->mixer_lock); | |
232 | } | |
233 | } else { | |
234 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | |
235 | } | |
236 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | |
237 | } | |
238 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
1da177e4 LT |
239 | return 0; |
240 | } | |
241 | ||
029d64b0 TI |
242 | static int snd_sb8_hw_params(struct snd_pcm_substream *substream, |
243 | struct snd_pcm_hw_params *hw_params) | |
1da177e4 LT |
244 | { |
245 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | |
246 | } | |
247 | ||
029d64b0 | 248 | static int snd_sb8_hw_free(struct snd_pcm_substream *substream) |
1da177e4 LT |
249 | { |
250 | snd_pcm_lib_free_pages(substream); | |
251 | return 0; | |
252 | } | |
253 | ||
029d64b0 | 254 | static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
255 | { |
256 | unsigned long flags; | |
029d64b0 TI |
257 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
258 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 | 259 | unsigned int mixreg, rate, size, count; |
ad8decb7 KH |
260 | unsigned char format; |
261 | unsigned char stereo = runtime->channels > 1; | |
262 | int dma; | |
1da177e4 LT |
263 | |
264 | rate = runtime->rate; | |
265 | switch (chip->hardware) { | |
ad8decb7 KH |
266 | case SB_HW_JAZZ16: |
267 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | |
268 | if (chip->mode & SB_MODE_PLAYBACK_16) | |
269 | return -EBUSY; | |
270 | else | |
271 | chip->mode |= SB_MODE_CAPTURE_16; | |
272 | } | |
273 | chip->capture_format = SB_DSP_LO_INPUT_AUTO; | |
274 | break; | |
1da177e4 LT |
275 | case SB_HW_PRO: |
276 | if (runtime->channels > 1) { | |
622207dc TI |
277 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
278 | rate != SB8_RATE(22050))) | |
279 | return -EINVAL; | |
1da177e4 LT |
280 | chip->capture_format = SB_DSP_HI_INPUT_AUTO; |
281 | break; | |
282 | } | |
283 | chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO; | |
284 | break; | |
285 | case SB_HW_201: | |
286 | if (rate > 13000) { | |
287 | chip->capture_format = SB_DSP_HI_INPUT_AUTO; | |
288 | break; | |
289 | } | |
290 | /* fallthru */ | |
291 | case SB_HW_20: | |
292 | chip->capture_format = SB_DSP_LO_INPUT_AUTO; | |
293 | break; | |
294 | case SB_HW_10: | |
295 | chip->capture_format = SB_DSP_INPUT; | |
296 | break; | |
297 | default: | |
298 | return -EINVAL; | |
299 | } | |
ad8decb7 KH |
300 | if (chip->mode & SB_MODE_CAPTURE_16) { |
301 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | |
302 | dma = chip->dma16; | |
303 | } else { | |
304 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | |
305 | chip->mode |= SB_MODE_CAPTURE_8; | |
306 | dma = chip->dma8; | |
307 | } | |
1da177e4 LT |
308 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); |
309 | count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); | |
310 | spin_lock_irqsave(&chip->reg_lock, flags); | |
311 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | |
ad8decb7 KH |
312 | if (chip->hardware == SB_HW_JAZZ16) |
313 | snd_sbdsp_command(chip, format); | |
314 | else if (stereo) | |
1da177e4 LT |
315 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); |
316 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | |
ad8decb7 | 317 | if (stereo) { |
1da177e4 LT |
318 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
319 | spin_lock(&chip->mixer_lock); | |
320 | /* save input filter status and turn it off */ | |
321 | mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT); | |
322 | snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20); | |
323 | spin_unlock(&chip->mixer_lock); | |
324 | /* just use force_mode16 for temporary storate... */ | |
325 | chip->force_mode16 = mixreg; | |
326 | } else { | |
327 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | |
328 | } | |
20cde9e8 | 329 | if (chip->capture_format != SB_DSP_INPUT) { |
ad8decb7 KH |
330 | if (chip->mode & SB_MODE_PLAYBACK_16) |
331 | count /= 2; | |
1da177e4 LT |
332 | count--; |
333 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | |
334 | snd_sbdsp_command(chip, count & 0xff); | |
335 | snd_sbdsp_command(chip, count >> 8); | |
336 | } | |
337 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
ad8decb7 | 338 | snd_dma_program(dma, runtime->dma_addr, |
1da177e4 LT |
339 | size, DMA_MODE_READ | DMA_AUTOINIT); |
340 | return 0; | |
341 | } | |
342 | ||
029d64b0 | 343 | static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, |
1da177e4 LT |
344 | int cmd) |
345 | { | |
346 | unsigned long flags; | |
029d64b0 | 347 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
348 | unsigned int count; |
349 | ||
350 | spin_lock_irqsave(&chip->reg_lock, flags); | |
351 | switch (cmd) { | |
352 | case SNDRV_PCM_TRIGGER_START: | |
353 | snd_sbdsp_command(chip, chip->capture_format); | |
354 | if (chip->capture_format == SB_DSP_INPUT) { | |
355 | count = chip->c_period_size - 1; | |
356 | snd_sbdsp_command(chip, count & 0xff); | |
357 | snd_sbdsp_command(chip, count >> 8); | |
358 | } | |
359 | break; | |
360 | case SNDRV_PCM_TRIGGER_STOP: | |
361 | if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) { | |
029d64b0 | 362 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
363 | snd_sbdsp_reset(chip); |
364 | if (runtime->channels > 1) { | |
365 | /* restore input filter status */ | |
366 | spin_lock(&chip->mixer_lock); | |
367 | snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16); | |
368 | spin_unlock(&chip->mixer_lock); | |
369 | /* set hardware to mono mode */ | |
370 | snd_sbdsp_command(chip, SB_DSP_MONO_8BIT); | |
371 | } | |
372 | } else { | |
373 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | |
374 | } | |
375 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | |
376 | } | |
377 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
1da177e4 LT |
378 | return 0; |
379 | } | |
380 | ||
029d64b0 | 381 | irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) |
1da177e4 | 382 | { |
029d64b0 | 383 | struct snd_pcm_substream *substream; |
1da177e4 | 384 | |
1da177e4 LT |
385 | snd_sb_ack_8bit(chip); |
386 | switch (chip->mode) { | |
ad8decb7 KH |
387 | case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ |
388 | if (chip->hardware != SB_HW_JAZZ16) | |
389 | break; | |
390 | /* fallthru */ | |
391 | case SB_MODE_PLAYBACK_8: | |
1da177e4 | 392 | substream = chip->playback_substream; |
1da177e4 LT |
393 | if (chip->playback_format == SB_DSP_OUTPUT) |
394 | snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); | |
395 | snd_pcm_period_elapsed(substream); | |
396 | break; | |
ad8decb7 KH |
397 | case SB_MODE_CAPTURE_16: |
398 | if (chip->hardware != SB_HW_JAZZ16) | |
399 | break; | |
400 | /* fallthru */ | |
1da177e4 LT |
401 | case SB_MODE_CAPTURE_8: |
402 | substream = chip->capture_substream; | |
1da177e4 LT |
403 | if (chip->capture_format == SB_DSP_INPUT) |
404 | snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START); | |
405 | snd_pcm_period_elapsed(substream); | |
406 | break; | |
407 | } | |
408 | return IRQ_HANDLED; | |
409 | } | |
410 | ||
029d64b0 | 411 | static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 412 | { |
029d64b0 | 413 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 | 414 | size_t ptr; |
ad8decb7 | 415 | int dma; |
1da177e4 | 416 | |
ad8decb7 KH |
417 | if (chip->mode & SB_MODE_PLAYBACK_8) |
418 | dma = chip->dma8; | |
419 | else if (chip->mode & SB_MODE_PLAYBACK_16) | |
420 | dma = chip->dma16; | |
421 | else | |
1da177e4 | 422 | return 0; |
ad8decb7 | 423 | ptr = snd_dma_pointer(dma, chip->p_dma_size); |
1da177e4 LT |
424 | return bytes_to_frames(substream->runtime, ptr); |
425 | } | |
426 | ||
029d64b0 | 427 | static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 428 | { |
029d64b0 | 429 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 | 430 | size_t ptr; |
ad8decb7 | 431 | int dma; |
1da177e4 | 432 | |
ad8decb7 KH |
433 | if (chip->mode & SB_MODE_CAPTURE_8) |
434 | dma = chip->dma8; | |
435 | else if (chip->mode & SB_MODE_CAPTURE_16) | |
436 | dma = chip->dma16; | |
437 | else | |
1da177e4 | 438 | return 0; |
ad8decb7 | 439 | ptr = snd_dma_pointer(dma, chip->c_dma_size); |
1da177e4 LT |
440 | return bytes_to_frames(substream->runtime, ptr); |
441 | } | |
442 | ||
443 | /* | |
444 | ||
445 | */ | |
446 | ||
aec54654 | 447 | static const struct snd_pcm_hardware snd_sb8_playback = |
1da177e4 LT |
448 | { |
449 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | |
450 | SNDRV_PCM_INFO_MMAP_VALID), | |
451 | .formats = SNDRV_PCM_FMTBIT_U8, | |
452 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 | | |
453 | SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050), | |
454 | .rate_min = 4000, | |
455 | .rate_max = 23000, | |
456 | .channels_min = 1, | |
457 | .channels_max = 1, | |
458 | .buffer_bytes_max = 65536, | |
459 | .period_bytes_min = 64, | |
460 | .period_bytes_max = 65536, | |
461 | .periods_min = 1, | |
462 | .periods_max = 1024, | |
463 | .fifo_size = 0, | |
464 | }; | |
465 | ||
aec54654 | 466 | static const struct snd_pcm_hardware snd_sb8_capture = |
1da177e4 LT |
467 | { |
468 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | |
469 | SNDRV_PCM_INFO_MMAP_VALID), | |
470 | .formats = SNDRV_PCM_FMTBIT_U8, | |
471 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 | | |
472 | SNDRV_PCM_RATE_11025), | |
473 | .rate_min = 4000, | |
474 | .rate_max = 13000, | |
475 | .channels_min = 1, | |
476 | .channels_max = 1, | |
477 | .buffer_bytes_max = 65536, | |
478 | .period_bytes_min = 64, | |
479 | .period_bytes_max = 65536, | |
480 | .periods_min = 1, | |
481 | .periods_max = 1024, | |
482 | .fifo_size = 0, | |
483 | }; | |
484 | ||
485 | /* | |
486 | * | |
487 | */ | |
488 | ||
029d64b0 | 489 | static int snd_sb8_open(struct snd_pcm_substream *substream) |
1da177e4 | 490 | { |
029d64b0 TI |
491 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
492 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
493 | unsigned long flags; |
494 | ||
495 | spin_lock_irqsave(&chip->open_lock, flags); | |
496 | if (chip->open) { | |
497 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
498 | return -EAGAIN; | |
499 | } | |
500 | chip->open |= SB_OPEN_PCM; | |
501 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
502 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
503 | chip->playback_substream = substream; | |
504 | runtime->hw = snd_sb8_playback; | |
505 | } else { | |
506 | chip->capture_substream = substream; | |
507 | runtime->hw = snd_sb8_capture; | |
508 | } | |
509 | switch (chip->hardware) { | |
ad8decb7 | 510 | case SB_HW_JAZZ16: |
44eba3e8 KH |
511 | if (chip->dma16 == 5 || chip->dma16 == 7) |
512 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; | |
ad8decb7 KH |
513 | runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; |
514 | runtime->hw.rate_min = 4000; | |
515 | runtime->hw.rate_max = 50000; | |
516 | runtime->hw.channels_max = 2; | |
517 | break; | |
1da177e4 LT |
518 | case SB_HW_PRO: |
519 | runtime->hw.rate_max = 44100; | |
520 | runtime->hw.channels_max = 2; | |
521 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | |
522 | snd_sb8_hw_constraint_rate_channels, NULL, | |
523 | SNDRV_PCM_HW_PARAM_CHANNELS, | |
524 | SNDRV_PCM_HW_PARAM_RATE, -1); | |
525 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | |
526 | snd_sb8_hw_constraint_channels_rate, NULL, | |
527 | SNDRV_PCM_HW_PARAM_RATE, -1); | |
528 | break; | |
529 | case SB_HW_201: | |
530 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | |
531 | runtime->hw.rate_max = 44100; | |
532 | } else { | |
533 | runtime->hw.rate_max = 15000; | |
534 | } | |
535 | default: | |
536 | break; | |
537 | } | |
538 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | |
539 | &hw_constraints_clock); | |
ad8decb7 KH |
540 | if (chip->dma8 > 3 || chip->dma16 >= 0) { |
541 | snd_pcm_hw_constraint_step(runtime, 0, | |
542 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); | |
543 | snd_pcm_hw_constraint_step(runtime, 0, | |
544 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); | |
545 | runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; | |
546 | runtime->hw.period_bytes_max = 128 * 1024 * 1024; | |
547 | } | |
1da177e4 LT |
548 | return 0; |
549 | } | |
550 | ||
029d64b0 | 551 | static int snd_sb8_close(struct snd_pcm_substream *substream) |
1da177e4 LT |
552 | { |
553 | unsigned long flags; | |
029d64b0 | 554 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
555 | |
556 | chip->playback_substream = NULL; | |
557 | chip->capture_substream = NULL; | |
558 | spin_lock_irqsave(&chip->open_lock, flags); | |
559 | chip->open &= ~SB_OPEN_PCM; | |
ad8decb7 KH |
560 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
561 | chip->mode &= ~SB_MODE_PLAYBACK; | |
562 | else | |
563 | chip->mode &= ~SB_MODE_CAPTURE; | |
1da177e4 LT |
564 | spin_unlock_irqrestore(&chip->open_lock, flags); |
565 | return 0; | |
566 | } | |
567 | ||
568 | /* | |
569 | * Initialization part | |
570 | */ | |
571 | ||
99176853 | 572 | static const struct snd_pcm_ops snd_sb8_playback_ops = { |
1da177e4 LT |
573 | .open = snd_sb8_open, |
574 | .close = snd_sb8_close, | |
575 | .ioctl = snd_pcm_lib_ioctl, | |
576 | .hw_params = snd_sb8_hw_params, | |
577 | .hw_free = snd_sb8_hw_free, | |
578 | .prepare = snd_sb8_playback_prepare, | |
579 | .trigger = snd_sb8_playback_trigger, | |
580 | .pointer = snd_sb8_playback_pointer, | |
581 | }; | |
582 | ||
99176853 | 583 | static const struct snd_pcm_ops snd_sb8_capture_ops = { |
1da177e4 LT |
584 | .open = snd_sb8_open, |
585 | .close = snd_sb8_close, | |
586 | .ioctl = snd_pcm_lib_ioctl, | |
587 | .hw_params = snd_sb8_hw_params, | |
588 | .hw_free = snd_sb8_hw_free, | |
589 | .prepare = snd_sb8_capture_prepare, | |
590 | .trigger = snd_sb8_capture_trigger, | |
591 | .pointer = snd_sb8_capture_pointer, | |
592 | }; | |
593 | ||
8c776299 | 594 | int snd_sb8dsp_pcm(struct snd_sb *chip, int device) |
1da177e4 | 595 | { |
029d64b0 TI |
596 | struct snd_card *card = chip->card; |
597 | struct snd_pcm *pcm; | |
1da177e4 | 598 | int err; |
ad8decb7 | 599 | size_t max_prealloc = 64 * 1024; |
1da177e4 | 600 | |
1da177e4 LT |
601 | if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0) |
602 | return err; | |
603 | sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); | |
604 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | |
605 | pcm->private_data = chip; | |
1da177e4 LT |
606 | |
607 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); | |
608 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); | |
609 | ||
ad8decb7 KH |
610 | if (chip->dma8 > 3 || chip->dma16 >= 0) |
611 | max_prealloc = 128 * 1024; | |
1da177e4 LT |
612 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
613 | snd_dma_isa_data(), | |
ad8decb7 | 614 | 64*1024, max_prealloc); |
1da177e4 | 615 | |
1da177e4 LT |
616 | return 0; |
617 | } | |
618 | ||
619 | EXPORT_SYMBOL(snd_sb8dsp_pcm); | |
620 | EXPORT_SYMBOL(snd_sb8dsp_interrupt); | |
621 | /* sb8_midi.c */ | |
622 | EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt); | |
623 | EXPORT_SYMBOL(snd_sb8dsp_midi); |