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