Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 | 2 | /* |
c1017a4c | 3 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
1da177e4 LT |
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 | * | |
1da177e4 LT |
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 | ||
6cbbfe1c | 19 | #include <linux/io.h> |
1da177e4 LT |
20 | #include <asm/dma.h> |
21 | #include <linux/init.h> | |
22 | #include <linux/time.h> | |
da155d5b | 23 | #include <linux/module.h> |
1da177e4 LT |
24 | #include <sound/core.h> |
25 | #include <sound/sb.h> | |
26 | ||
c1017a4c | 27 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Uros Bizjak <uros@kss-loka.si>"); |
1da177e4 LT |
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 | ||
b078bbfb | 35 | static const struct snd_ratnum clock = { |
1da177e4 LT |
36 | .num = SB8_CLOCK, |
37 | .den_min = 1, | |
38 | .den_max = 256, | |
39 | .den_step = 1, | |
40 | }; | |
41 | ||
b078bbfb | 42 | static const struct snd_pcm_hw_constraint_ratnums hw_constraints_clock = { |
1da177e4 LT |
43 | .nrats = 1, |
44 | .rats = &clock, | |
45 | }; | |
46 | ||
b078bbfb | 47 | static const struct snd_ratnum stereo_clocks[] = { |
1da177e4 LT |
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 | ||
029d64b0 TI |
62 | static int snd_sb8_hw_constraint_rate_channels(struct snd_pcm_hw_params *params, |
63 | struct snd_pcm_hw_rule *rule) | |
1da177e4 | 64 | { |
029d64b0 | 65 | struct snd_interval *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
1da177e4 LT |
66 | if (c->min > 1) { |
67 | unsigned int num = 0, den = 0; | |
68 | int err = snd_interval_ratnum(hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE), | |
69 | 2, stereo_clocks, &num, &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 | ||
029d64b0 TI |
79 | static int snd_sb8_hw_constraint_channels_rate(struct snd_pcm_hw_params *params, |
80 | struct snd_pcm_hw_rule *rule) | |
1da177e4 | 81 | { |
029d64b0 | 82 | struct snd_interval *r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); |
1da177e4 | 83 | if (r->min > SB8_RATE(22050) || r->max <= SB8_RATE(11025)) { |
029d64b0 | 84 | struct snd_interval t = { .min = 1, .max = 1 }; |
1da177e4 LT |
85 | return snd_interval_refine(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t); |
86 | } | |
87 | return 0; | |
88 | } | |
89 | ||
029d64b0 | 90 | static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
91 | { |
92 | unsigned long flags; | |
029d64b0 TI |
93 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
94 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 | 95 | unsigned int mixreg, rate, size, count; |
ad8decb7 KH |
96 | unsigned char format; |
97 | unsigned char stereo = runtime->channels > 1; | |
98 | int dma; | |
1da177e4 LT |
99 | |
100 | rate = runtime->rate; | |
101 | switch (chip->hardware) { | |
ad8decb7 KH |
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; | |
1da177e4 LT |
111 | case SB_HW_PRO: |
112 | if (runtime->channels > 1) { | |
622207dc TI |
113 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
114 | rate != SB8_RATE(22050))) | |
115 | return -EINVAL; | |
1da177e4 LT |
116 | chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; |
117 | break; | |
118 | } | |
c0dbbdad | 119 | fallthrough; |
1da177e4 LT |
120 | case SB_HW_201: |
121 | if (rate > 23000) { | |
122 | chip->playback_format = SB_DSP_HI_OUTPUT_AUTO; | |
123 | break; | |
124 | } | |
c0dbbdad | 125 | fallthrough; |
1da177e4 LT |
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 | } | |
ad8decb7 KH |
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 | } | |
1da177e4 LT |
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); | |
ad8decb7 KH |
147 | if (chip->hardware == SB_HW_JAZZ16) |
148 | snd_sbdsp_command(chip, format); | |
149 | else if (stereo) { | |
1da177e4 LT |
150 | /* set playback stereo mode */ |
151 | spin_lock(&chip->mixer_lock); | |
152 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); | |
153 | snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02); | |
154 | spin_unlock(&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; | |
ad8decb7 | 159 | snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); |
1da177e4 | 160 | /* force interrupt */ |
1da177e4 LT |
161 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); |
162 | snd_sbdsp_command(chip, 0); | |
163 | snd_sbdsp_command(chip, 0); | |
164 | } | |
165 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | |
ad8decb7 | 166 | if (stereo) { |
1da177e4 LT |
167 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
168 | spin_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, mixreg | 0x20); | |
172 | spin_unlock(&chip->mixer_lock); | |
173 | /* just use force_mode16 for temporary storate... */ | |
174 | chip->force_mode16 = mixreg; | |
175 | } else { | |
176 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | |
177 | } | |
178 | if (chip->playback_format != SB_DSP_OUTPUT) { | |
ad8decb7 KH |
179 | if (chip->mode & SB_MODE_PLAYBACK_16) |
180 | count /= 2; | |
1da177e4 LT |
181 | count--; |
182 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | |
183 | snd_sbdsp_command(chip, count & 0xff); | |
184 | snd_sbdsp_command(chip, count >> 8); | |
185 | } | |
186 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
ad8decb7 | 187 | snd_dma_program(dma, runtime->dma_addr, |
1da177e4 LT |
188 | size, DMA_MODE_WRITE | DMA_AUTOINIT); |
189 | return 0; | |
190 | } | |
191 | ||
029d64b0 | 192 | static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, |
1da177e4 LT |
193 | int cmd) |
194 | { | |
195 | unsigned long flags; | |
029d64b0 | 196 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
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, chip->playback_format); | |
203 | if (chip->playback_format == SB_DSP_OUTPUT) { | |
204 | count = chip->p_period_size - 1; | |
205 | snd_sbdsp_command(chip, count & 0xff); | |
206 | snd_sbdsp_command(chip, count >> 8); | |
207 | } | |
208 | break; | |
209 | case SNDRV_PCM_TRIGGER_STOP: | |
210 | if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) { | |
029d64b0 | 211 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
212 | snd_sbdsp_reset(chip); |
213 | if (runtime->channels > 1) { | |
214 | spin_lock(&chip->mixer_lock); | |
215 | /* restore output filter and set hardware to mono mode */ | |
216 | snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02); | |
217 | spin_unlock(&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(&chip->reg_lock, flags); | |
1da177e4 LT |
225 | return 0; |
226 | } | |
227 | ||
029d64b0 | 228 | static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) |
1da177e4 LT |
229 | { |
230 | unsigned long flags; | |
029d64b0 TI |
231 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
232 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 | 233 | unsigned int mixreg, rate, size, count; |
ad8decb7 KH |
234 | unsigned char format; |
235 | unsigned char stereo = runtime->channels > 1; | |
236 | int dma; | |
1da177e4 LT |
237 | |
238 | rate = runtime->rate; | |
239 | switch (chip->hardware) { | |
ad8decb7 KH |
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; | |
1da177e4 LT |
249 | case SB_HW_PRO: |
250 | if (runtime->channels > 1) { | |
622207dc TI |
251 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
252 | rate != SB8_RATE(22050))) | |
253 | return -EINVAL; | |
1da177e4 LT |
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 | } | |
c0dbbdad | 264 | fallthrough; |
1da177e4 LT |
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 | } | |
ad8decb7 KH |
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 | } | |
1da177e4 LT |
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); | |
ad8decb7 KH |
286 | if (chip->hardware == SB_HW_JAZZ16) |
287 | snd_sbdsp_command(chip, format); | |
288 | else if (stereo) | |
1da177e4 LT |
289 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); |
290 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | |
ad8decb7 | 291 | if (stereo) { |
1da177e4 LT |
292 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
293 | spin_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, mixreg | 0x20); | |
297 | spin_unlock(&chip->mixer_lock); | |
298 | /* just use force_mode16 for temporary storate... */ | |
299 | chip->force_mode16 = mixreg; | |
300 | } else { | |
301 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | |
302 | } | |
20cde9e8 | 303 | if (chip->capture_format != SB_DSP_INPUT) { |
ad8decb7 KH |
304 | if (chip->mode & SB_MODE_PLAYBACK_16) |
305 | count /= 2; | |
1da177e4 LT |
306 | count--; |
307 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | |
308 | snd_sbdsp_command(chip, count & 0xff); | |
309 | snd_sbdsp_command(chip, count >> 8); | |
310 | } | |
311 | spin_unlock_irqrestore(&chip->reg_lock, flags); | |
ad8decb7 | 312 | snd_dma_program(dma, runtime->dma_addr, |
1da177e4 LT |
313 | size, DMA_MODE_READ | DMA_AUTOINIT); |
314 | return 0; | |
315 | } | |
316 | ||
029d64b0 | 317 | static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, |
1da177e4 LT |
318 | int cmd) |
319 | { | |
320 | unsigned long flags; | |
029d64b0 | 321 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
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, chip->capture_format); | |
328 | if (chip->capture_format == SB_DSP_INPUT) { | |
329 | count = chip->c_period_size - 1; | |
330 | snd_sbdsp_command(chip, count & 0xff); | |
331 | snd_sbdsp_command(chip, count >> 8); | |
332 | } | |
333 | break; | |
334 | case SNDRV_PCM_TRIGGER_STOP: | |
335 | if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) { | |
029d64b0 | 336 | struct snd_pcm_runtime *runtime = substream->runtime; |
1da177e4 LT |
337 | snd_sbdsp_reset(chip); |
338 | if (runtime->channels > 1) { | |
339 | /* restore input filter status */ | |
340 | spin_lock(&chip->mixer_lock); | |
341 | snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16); | |
342 | spin_unlock(&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(&chip->reg_lock, flags); | |
1da177e4 LT |
352 | return 0; |
353 | } | |
354 | ||
029d64b0 | 355 | irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) |
1da177e4 | 356 | { |
029d64b0 | 357 | struct snd_pcm_substream *substream; |
1da177e4 | 358 | |
1da177e4 LT |
359 | snd_sb_ack_8bit(chip); |
360 | switch (chip->mode) { | |
ad8decb7 KH |
361 | case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ |
362 | if (chip->hardware != SB_HW_JAZZ16) | |
363 | break; | |
c0dbbdad | 364 | fallthrough; |
ad8decb7 | 365 | case SB_MODE_PLAYBACK_8: |
1da177e4 | 366 | substream = chip->playback_substream; |
1da177e4 LT |
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; | |
ad8decb7 KH |
371 | case SB_MODE_CAPTURE_16: |
372 | if (chip->hardware != SB_HW_JAZZ16) | |
373 | break; | |
c0dbbdad | 374 | fallthrough; |
1da177e4 LT |
375 | case SB_MODE_CAPTURE_8: |
376 | substream = chip->capture_substream; | |
1da177e4 LT |
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 | ||
029d64b0 | 385 | static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 386 | { |
029d64b0 | 387 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 | 388 | size_t ptr; |
ad8decb7 | 389 | int dma; |
1da177e4 | 390 | |
ad8decb7 KH |
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 | |
1da177e4 | 396 | return 0; |
ad8decb7 | 397 | ptr = snd_dma_pointer(dma, chip->p_dma_size); |
1da177e4 LT |
398 | return bytes_to_frames(substream->runtime, ptr); |
399 | } | |
400 | ||
029d64b0 | 401 | static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream) |
1da177e4 | 402 | { |
029d64b0 | 403 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 | 404 | size_t ptr; |
ad8decb7 | 405 | int dma; |
1da177e4 | 406 | |
ad8decb7 KH |
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 | |
1da177e4 | 412 | return 0; |
ad8decb7 | 413 | ptr = snd_dma_pointer(dma, chip->c_dma_size); |
1da177e4 LT |
414 | return bytes_to_frames(substream->runtime, ptr); |
415 | } | |
416 | ||
417 | /* | |
418 | ||
419 | */ | |
420 | ||
aec54654 | 421 | static const struct snd_pcm_hardware snd_sb8_playback = |
1da177e4 LT |
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 | ||
aec54654 | 440 | static const struct snd_pcm_hardware snd_sb8_capture = |
1da177e4 LT |
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 | ||
029d64b0 | 463 | static int snd_sb8_open(struct snd_pcm_substream *substream) |
1da177e4 | 464 | { |
029d64b0 TI |
465 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
466 | struct snd_pcm_runtime *runtime = substream->runtime; | |
1da177e4 LT |
467 | unsigned long flags; |
468 | ||
469 | spin_lock_irqsave(&chip->open_lock, flags); | |
470 | if (chip->open) { | |
471 | spin_unlock_irqrestore(&chip->open_lock, flags); | |
472 | return -EAGAIN; | |
473 | } | |
474 | chip->open |= SB_OPEN_PCM; | |
475 | spin_unlock_irqrestore(&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) { | |
ad8decb7 | 484 | case SB_HW_JAZZ16: |
44eba3e8 KH |
485 | if (chip->dma16 == 5 || chip->dma16 == 7) |
486 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; | |
ad8decb7 KH |
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; | |
1da177e4 LT |
492 | case SB_HW_PRO: |
493 | runtime->hw.rate_max = 44100; | |
494 | runtime->hw.channels_max = 2; | |
495 | snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | |
496 | 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, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | |
500 | 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 | } | |
45bbe6c9 | 509 | break; |
1da177e4 LT |
510 | default: |
511 | break; | |
512 | } | |
513 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | |
514 | &hw_constraints_clock); | |
ad8decb7 KH |
515 | if (chip->dma8 > 3 || chip->dma16 >= 0) { |
516 | snd_pcm_hw_constraint_step(runtime, 0, | |
517 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); | |
518 | snd_pcm_hw_constraint_step(runtime, 0, | |
519 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); | |
520 | runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; | |
521 | runtime->hw.period_bytes_max = 128 * 1024 * 1024; | |
522 | } | |
1da177e4 LT |
523 | return 0; |
524 | } | |
525 | ||
029d64b0 | 526 | static int snd_sb8_close(struct snd_pcm_substream *substream) |
1da177e4 LT |
527 | { |
528 | unsigned long flags; | |
029d64b0 | 529 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
1da177e4 LT |
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; | |
ad8decb7 KH |
535 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
536 | chip->mode &= ~SB_MODE_PLAYBACK; | |
537 | else | |
538 | chip->mode &= ~SB_MODE_CAPTURE; | |
1da177e4 LT |
539 | spin_unlock_irqrestore(&chip->open_lock, flags); |
540 | return 0; | |
541 | } | |
542 | ||
543 | /* | |
544 | * Initialization part | |
545 | */ | |
546 | ||
99176853 | 547 | static const struct snd_pcm_ops snd_sb8_playback_ops = { |
1da177e4 LT |
548 | .open = snd_sb8_open, |
549 | .close = snd_sb8_close, | |
1da177e4 LT |
550 | .prepare = snd_sb8_playback_prepare, |
551 | .trigger = snd_sb8_playback_trigger, | |
552 | .pointer = snd_sb8_playback_pointer, | |
553 | }; | |
554 | ||
99176853 | 555 | static const struct snd_pcm_ops snd_sb8_capture_ops = { |
1da177e4 LT |
556 | .open = snd_sb8_open, |
557 | .close = snd_sb8_close, | |
1da177e4 LT |
558 | .prepare = snd_sb8_capture_prepare, |
559 | .trigger = snd_sb8_capture_trigger, | |
560 | .pointer = snd_sb8_capture_pointer, | |
561 | }; | |
562 | ||
8c776299 | 563 | int snd_sb8dsp_pcm(struct snd_sb *chip, int device) |
1da177e4 | 564 | { |
029d64b0 TI |
565 | struct snd_card *card = chip->card; |
566 | struct snd_pcm *pcm; | |
1da177e4 | 567 | int err; |
ad8decb7 | 568 | size_t max_prealloc = 64 * 1024; |
1da177e4 | 569 | |
10dc8ad5 TI |
570 | err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm); |
571 | if (err < 0) | |
1da177e4 LT |
572 | return err; |
573 | sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); | |
574 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | |
575 | pcm->private_data = chip; | |
1da177e4 LT |
576 | |
577 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); | |
578 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); | |
579 | ||
ad8decb7 KH |
580 | if (chip->dma8 > 3 || chip->dma16 >= 0) |
581 | max_prealloc = 128 * 1024; | |
07ed72ba TI |
582 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV, |
583 | card->dev, 64*1024, max_prealloc); | |
1da177e4 | 584 | |
1da177e4 LT |
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); |