xref: /linux/sound/isa/sb/sb8_main.c (revision 05a54fa773284d1a7923cdfdd8f0c8dabb98bd26)
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(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 
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(hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS), &t);
86 	}
87 	return 0;
88 }
89 
90 static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream)
91 {
92 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
93 	struct snd_pcm_runtime *runtime = substream->runtime;
94 	unsigned int mixreg, rate, size, count;
95 	unsigned char format;
96 	unsigned char stereo = runtime->channels > 1;
97 	int dma;
98 
99 	rate = runtime->rate;
100 	switch (chip->hardware) {
101 	case SB_HW_JAZZ16:
102 		if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
103 			if (chip->mode & SB_MODE_CAPTURE_16)
104 				return -EBUSY;
105 			else
106 				chip->mode |= SB_MODE_PLAYBACK_16;
107 		}
108 		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
109 		break;
110 	case SB_HW_PRO:
111 		if (runtime->channels > 1) {
112 			if (snd_BUG_ON(rate != SB8_RATE(11025) &&
113 				       rate != SB8_RATE(22050)))
114 				return -EINVAL;
115 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
116 			break;
117 		}
118 		fallthrough;
119 	case SB_HW_201:
120 		if (rate > 23000) {
121 			chip->playback_format = SB_DSP_HI_OUTPUT_AUTO;
122 			break;
123 		}
124 		fallthrough;
125 	case SB_HW_20:
126 		chip->playback_format = SB_DSP_LO_OUTPUT_AUTO;
127 		break;
128 	case SB_HW_10:
129 		chip->playback_format = SB_DSP_OUTPUT;
130 		break;
131 	default:
132 		return -EINVAL;
133 	}
134 	if (chip->mode & SB_MODE_PLAYBACK_16) {
135 		format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
136 		dma = chip->dma16;
137 	} else {
138 		format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
139 		chip->mode |= SB_MODE_PLAYBACK_8;
140 		dma = chip->dma8;
141 	}
142 	size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream);
143 	count = chip->p_period_size = snd_pcm_lib_period_bytes(substream);
144 	scoped_guard(spinlock_irqsave, &chip->reg_lock) {
145 		snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON);
146 		if (chip->hardware == SB_HW_JAZZ16)
147 			snd_sbdsp_command(chip, format);
148 		else if (stereo) {
149 			/* set playback stereo mode */
150 			scoped_guard(spinlock, &chip->mixer_lock) {
151 				mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW);
152 				snd_sbmixer_write(chip, SB_DSP_STEREO_SW, mixreg | 0x02);
153 			}
154 
155 			/* Soundblaster hardware programming reference guide, 3-23 */
156 			snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT);
157 			runtime->dma_area[0] = 0x80;
158 			snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
159 			/* force interrupt */
160 			snd_sbdsp_command(chip, SB_DSP_OUTPUT);
161 			snd_sbdsp_command(chip, 0);
162 			snd_sbdsp_command(chip, 0);
163 		}
164 		snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
165 		if (stereo) {
166 			snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
167 			scoped_guard(spinlock, &chip->mixer_lock) {
168 				/* save output filter status and turn it off */
169 				mixreg = snd_sbmixer_read(chip, SB_DSP_PLAYBACK_FILT);
170 				snd_sbmixer_write(chip, SB_DSP_PLAYBACK_FILT, mixreg | 0x20);
171 			}
172 			/* just use force_mode16 for temporary storate... */
173 			chip->force_mode16 = mixreg;
174 		} else {
175 			snd_sbdsp_command(chip, 256 - runtime->rate_den);
176 		}
177 		if (chip->playback_format != SB_DSP_OUTPUT) {
178 			if (chip->mode & SB_MODE_PLAYBACK_16)
179 				count /= 2;
180 			count--;
181 			snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
182 			snd_sbdsp_command(chip, count & 0xff);
183 			snd_sbdsp_command(chip, count >> 8);
184 		}
185 	}
186 	snd_dma_program(dma, runtime->dma_addr,
187 			size, DMA_MODE_WRITE | DMA_AUTOINIT);
188 	return 0;
189 }
190 
191 static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream,
192 				    int cmd)
193 {
194 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
195 	unsigned int count;
196 
197 	guard(spinlock_irqsave)(&chip->reg_lock);
198 	switch (cmd) {
199 	case SNDRV_PCM_TRIGGER_START:
200 		snd_sbdsp_command(chip, chip->playback_format);
201 		if (chip->playback_format == SB_DSP_OUTPUT) {
202 			count = chip->p_period_size - 1;
203 			snd_sbdsp_command(chip, count & 0xff);
204 			snd_sbdsp_command(chip, count >> 8);
205 		}
206 		break;
207 	case SNDRV_PCM_TRIGGER_STOP:
208 		if (chip->playback_format == SB_DSP_HI_OUTPUT_AUTO) {
209 			struct snd_pcm_runtime *runtime = substream->runtime;
210 			snd_sbdsp_reset(chip);
211 			if (runtime->channels > 1) {
212 				guard(spinlock)(&chip->mixer_lock);
213 				/* restore output filter and set hardware to mono mode */
214 				snd_sbmixer_write(chip, SB_DSP_STEREO_SW, chip->force_mode16 & ~0x02);
215 			}
216 		} else {
217 			snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
218 		}
219 		snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
220 	}
221 	return 0;
222 }
223 
224 static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream)
225 {
226 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
227 	struct snd_pcm_runtime *runtime = substream->runtime;
228 	unsigned int mixreg, rate, size, count;
229 	unsigned char format;
230 	unsigned char stereo = runtime->channels > 1;
231 	int dma;
232 
233 	rate = runtime->rate;
234 	switch (chip->hardware) {
235 	case SB_HW_JAZZ16:
236 		if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) {
237 			if (chip->mode & SB_MODE_PLAYBACK_16)
238 				return -EBUSY;
239 			else
240 				chip->mode |= SB_MODE_CAPTURE_16;
241 		}
242 		chip->capture_format = SB_DSP_LO_INPUT_AUTO;
243 		break;
244 	case SB_HW_PRO:
245 		if (runtime->channels > 1) {
246 			if (snd_BUG_ON(rate != SB8_RATE(11025) &&
247 				       rate != SB8_RATE(22050)))
248 				return -EINVAL;
249 			chip->capture_format = SB_DSP_HI_INPUT_AUTO;
250 			break;
251 		}
252 		chip->capture_format = (rate > 23000) ? SB_DSP_HI_INPUT_AUTO : SB_DSP_LO_INPUT_AUTO;
253 		break;
254 	case SB_HW_201:
255 		if (rate > 13000) {
256 			chip->capture_format = SB_DSP_HI_INPUT_AUTO;
257 			break;
258 		}
259 		fallthrough;
260 	case SB_HW_20:
261 		chip->capture_format = SB_DSP_LO_INPUT_AUTO;
262 		break;
263 	case SB_HW_10:
264 		chip->capture_format = SB_DSP_INPUT;
265 		break;
266 	default:
267 		return -EINVAL;
268 	}
269 	if (chip->mode & SB_MODE_CAPTURE_16) {
270 		format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT;
271 		dma = chip->dma16;
272 	} else {
273 		format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT;
274 		chip->mode |= SB_MODE_CAPTURE_8;
275 		dma = chip->dma8;
276 	}
277 	size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream);
278 	count = chip->c_period_size = snd_pcm_lib_period_bytes(substream);
279 	scoped_guard(spinlock_irqsave, &chip->reg_lock) {
280 		snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
281 		if (chip->hardware == SB_HW_JAZZ16)
282 			snd_sbdsp_command(chip, format);
283 		else if (stereo)
284 			snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT);
285 		snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE);
286 		if (stereo) {
287 			snd_sbdsp_command(chip, 256 - runtime->rate_den / 2);
288 			scoped_guard(spinlock, &chip->mixer_lock) {
289 				/* save input filter status and turn it off */
290 				mixreg = snd_sbmixer_read(chip, SB_DSP_CAPTURE_FILT);
291 				snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, mixreg | 0x20);
292 			}
293 			/* just use force_mode16 for temporary storate... */
294 			chip->force_mode16 = mixreg;
295 		} else {
296 			snd_sbdsp_command(chip, 256 - runtime->rate_den);
297 		}
298 		if (chip->capture_format != SB_DSP_INPUT) {
299 			if (chip->mode & SB_MODE_PLAYBACK_16)
300 				count /= 2;
301 			count--;
302 			snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE);
303 			snd_sbdsp_command(chip, count & 0xff);
304 			snd_sbdsp_command(chip, count >> 8);
305 		}
306 	}
307 	snd_dma_program(dma, runtime->dma_addr,
308 			size, DMA_MODE_READ | DMA_AUTOINIT);
309 	return 0;
310 }
311 
312 static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream,
313 				   int cmd)
314 {
315 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
316 	unsigned int count;
317 
318 	guard(spinlock_irqsave)(&chip->reg_lock);
319 	switch (cmd) {
320 	case SNDRV_PCM_TRIGGER_START:
321 		snd_sbdsp_command(chip, chip->capture_format);
322 		if (chip->capture_format == SB_DSP_INPUT) {
323 			count = chip->c_period_size - 1;
324 			snd_sbdsp_command(chip, count & 0xff);
325 			snd_sbdsp_command(chip, count >> 8);
326 		}
327 		break;
328 	case SNDRV_PCM_TRIGGER_STOP:
329 		if (chip->capture_format == SB_DSP_HI_INPUT_AUTO) {
330 			struct snd_pcm_runtime *runtime = substream->runtime;
331 			snd_sbdsp_reset(chip);
332 			if (runtime->channels > 1) {
333 				/* restore input filter status */
334 				scoped_guard(spinlock, &chip->mixer_lock) {
335 					snd_sbmixer_write(chip, SB_DSP_CAPTURE_FILT, chip->force_mode16);
336 				}
337 				/* set hardware to mono mode */
338 				snd_sbdsp_command(chip, SB_DSP_MONO_8BIT);
339 			}
340 		} else {
341 			snd_sbdsp_command(chip, SB_DSP_DMA8_OFF);
342 		}
343 		snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF);
344 	}
345 	return 0;
346 }
347 
348 irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip)
349 {
350 	struct snd_pcm_substream *substream;
351 
352 	snd_sb_ack_8bit(chip);
353 	switch (chip->mode) {
354 	case SB_MODE_PLAYBACK_16:	/* ok.. playback is active */
355 		if (chip->hardware != SB_HW_JAZZ16)
356 			break;
357 		fallthrough;
358 	case SB_MODE_PLAYBACK_8:
359 		substream = chip->playback_substream;
360 		if (chip->playback_format == SB_DSP_OUTPUT)
361 		    	snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START);
362 		snd_pcm_period_elapsed(substream);
363 		break;
364 	case SB_MODE_CAPTURE_16:
365 		if (chip->hardware != SB_HW_JAZZ16)
366 			break;
367 		fallthrough;
368 	case SB_MODE_CAPTURE_8:
369 		substream = chip->capture_substream;
370 		if (chip->capture_format == SB_DSP_INPUT)
371 		    	snd_sb8_capture_trigger(substream, SNDRV_PCM_TRIGGER_START);
372 		snd_pcm_period_elapsed(substream);
373 		break;
374 	}
375 	return IRQ_HANDLED;
376 }
377 
378 static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *substream)
379 {
380 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
381 	size_t ptr;
382 	int dma;
383 
384 	if (chip->mode & SB_MODE_PLAYBACK_8)
385 		dma = chip->dma8;
386 	else if (chip->mode & SB_MODE_PLAYBACK_16)
387 		dma = chip->dma16;
388 	else
389 		return 0;
390 	ptr = snd_dma_pointer(dma, chip->p_dma_size);
391 	return bytes_to_frames(substream->runtime, ptr);
392 }
393 
394 static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *substream)
395 {
396 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
397 	size_t ptr;
398 	int dma;
399 
400 	if (chip->mode & SB_MODE_CAPTURE_8)
401 		dma = chip->dma8;
402 	else if (chip->mode & SB_MODE_CAPTURE_16)
403 		dma = chip->dma16;
404 	else
405 		return 0;
406 	ptr = snd_dma_pointer(dma, chip->c_dma_size);
407 	return bytes_to_frames(substream->runtime, ptr);
408 }
409 
410 /*
411 
412  */
413 
414 static const struct snd_pcm_hardware snd_sb8_playback =
415 {
416 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
417 				 SNDRV_PCM_INFO_MMAP_VALID),
418 	.formats =		 SNDRV_PCM_FMTBIT_U8,
419 	.rates =		(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
420 				 SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_22050),
421 	.rate_min =		4000,
422 	.rate_max =		23000,
423 	.channels_min =		1,
424 	.channels_max =		1,
425 	.buffer_bytes_max =	65536,
426 	.period_bytes_min =	64,
427 	.period_bytes_max =	65536,
428 	.periods_min =		1,
429 	.periods_max =		1024,
430 	.fifo_size =		0,
431 };
432 
433 static const struct snd_pcm_hardware snd_sb8_capture =
434 {
435 	.info =			(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
436 				 SNDRV_PCM_INFO_MMAP_VALID),
437 	.formats =		SNDRV_PCM_FMTBIT_U8,
438 	.rates =		(SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000 |
439 				 SNDRV_PCM_RATE_11025),
440 	.rate_min =		4000,
441 	.rate_max =		13000,
442 	.channels_min =		1,
443 	.channels_max =		1,
444 	.buffer_bytes_max =	65536,
445 	.period_bytes_min =	64,
446 	.period_bytes_max =	65536,
447 	.periods_min =		1,
448 	.periods_max =		1024,
449 	.fifo_size =		0,
450 };
451 
452 /*
453  *
454  */
455 
456 static int snd_sb8_open(struct snd_pcm_substream *substream)
457 {
458 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
459 	struct snd_pcm_runtime *runtime = substream->runtime;
460 
461 	scoped_guard(spinlock_irqsave, &chip->open_lock) {
462 		if (chip->open)
463 			return -EAGAIN;
464 		chip->open |= SB_OPEN_PCM;
465 	}
466 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
467 		chip->playback_substream = substream;
468 		runtime->hw = snd_sb8_playback;
469 	} else {
470 		chip->capture_substream = substream;
471 		runtime->hw = snd_sb8_capture;
472 	}
473 	switch (chip->hardware) {
474 	case SB_HW_JAZZ16:
475 		if (chip->dma16 == 5 || chip->dma16 == 7)
476 			runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE;
477 		runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000;
478 		runtime->hw.rate_min = 4000;
479 		runtime->hw.rate_max = 50000;
480 		runtime->hw.channels_max = 2;
481 		break;
482 	case SB_HW_PRO:
483 		runtime->hw.rate_max = 44100;
484 		runtime->hw.channels_max = 2;
485 		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
486 				    snd_sb8_hw_constraint_rate_channels, NULL,
487 				    SNDRV_PCM_HW_PARAM_CHANNELS,
488 				    SNDRV_PCM_HW_PARAM_RATE, -1);
489 		snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
490 				     snd_sb8_hw_constraint_channels_rate, NULL,
491 				     SNDRV_PCM_HW_PARAM_RATE, -1);
492 		break;
493 	case SB_HW_201:
494 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
495 			runtime->hw.rate_max = 44100;
496 		} else {
497 			runtime->hw.rate_max = 15000;
498 		}
499 		break;
500 	default:
501 		break;
502 	}
503 	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
504 				      &hw_constraints_clock);
505 	if (chip->dma8 > 3 || chip->dma16 >= 0) {
506 		snd_pcm_hw_constraint_step(runtime, 0,
507 					   SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2);
508 		snd_pcm_hw_constraint_step(runtime, 0,
509 					   SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2);
510 		runtime->hw.buffer_bytes_max = 128 * 1024 * 1024;
511 		runtime->hw.period_bytes_max = 128 * 1024 * 1024;
512 	}
513 	return 0;
514 }
515 
516 static int snd_sb8_close(struct snd_pcm_substream *substream)
517 {
518 	struct snd_sb *chip = snd_pcm_substream_chip(substream);
519 
520 	chip->playback_substream = NULL;
521 	chip->capture_substream = NULL;
522 	guard(spinlock_irqsave)(&chip->open_lock);
523 	chip->open &= ~SB_OPEN_PCM;
524 	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
525 		chip->mode &= ~SB_MODE_PLAYBACK;
526 	else
527 		chip->mode &= ~SB_MODE_CAPTURE;
528 	return 0;
529 }
530 
531 /*
532  *  Initialization part
533  */
534 
535 static const struct snd_pcm_ops snd_sb8_playback_ops = {
536 	.open =			snd_sb8_open,
537 	.close =		snd_sb8_close,
538 	.prepare =		snd_sb8_playback_prepare,
539 	.trigger =		snd_sb8_playback_trigger,
540 	.pointer =		snd_sb8_playback_pointer,
541 };
542 
543 static const struct snd_pcm_ops snd_sb8_capture_ops = {
544 	.open =			snd_sb8_open,
545 	.close =		snd_sb8_close,
546 	.prepare =		snd_sb8_capture_prepare,
547 	.trigger =		snd_sb8_capture_trigger,
548 	.pointer =		snd_sb8_capture_pointer,
549 };
550 
551 int snd_sb8dsp_pcm(struct snd_sb *chip, int device)
552 {
553 	struct snd_card *card = chip->card;
554 	struct snd_pcm *pcm;
555 	int err;
556 	size_t max_prealloc = 64 * 1024;
557 
558 	err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm);
559 	if (err < 0)
560 		return err;
561 	sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
562 	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
563 	pcm->private_data = chip;
564 
565 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
566 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
567 
568 	if (chip->dma8 > 3 || chip->dma16 >= 0)
569 		max_prealloc = 128 * 1024;
570 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
571 				       card->dev, 64*1024, max_prealloc);
572 
573 	return 0;
574 }
575 
576 EXPORT_SYMBOL(snd_sb8dsp_pcm);
577 EXPORT_SYMBOL(snd_sb8dsp_interrupt);
578   /* sb8_midi.c */
579 EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
580 EXPORT_SYMBOL(snd_sb8dsp_midi);
581