xref: /openbmc/linux/sound/isa/sb/sb8_main.c (revision 0b26ca68)
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 	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, format);
149 	else if (stereo) {
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;
159 		snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE);
160 		/* force interrupt */
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);
166 	if (stereo) {
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) {
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, count & 0xff);
184 		snd_sbdsp_command(chip, count >> 8);
185 	}
186 	spin_unlock_irqrestore(&chip->reg_lock, flags);
187 	snd_dma_program(dma, 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, 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) {
211 			struct snd_pcm_runtime *runtime = substream->runtime;
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);
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, 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, 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 	}
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, count & 0xff);
309 		snd_sbdsp_command(chip, count >> 8);
310 	}
311 	spin_unlock_irqrestore(&chip->reg_lock, flags);
312 	snd_dma_program(dma, 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, 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) {
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(&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);
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, chip->p_dma_size);
398 	return bytes_to_frames(substream->runtime, 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, chip->c_dma_size);
414 	return bytes_to_frames(substream->runtime, 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(&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) {
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, 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 		}
509 		break;
510 	default:
511 		break;
512 	}
513 	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
514 				      &hw_constraints_clock);
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 	}
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(&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 	if ((err = snd_pcm_new(card, "SB8 DSP", device, 1, 1, &pcm)) < 0)
571 		return err;
572 	sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff);
573 	pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX;
574 	pcm->private_data = chip;
575 
576 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops);
577 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops);
578 
579 	if (chip->dma8 > 3 || chip->dma16 >= 0)
580 		max_prealloc = 128 * 1024;
581 	snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_DEV,
582 				       card->dev, 64*1024, max_prealloc);
583 
584 	return 0;
585 }
586 
587 EXPORT_SYMBOL(snd_sb8dsp_pcm);
588 EXPORT_SYMBOL(snd_sb8dsp_interrupt);
589   /* sb8_midi.c */
590 EXPORT_SYMBOL(snd_sb8dsp_midi_interrupt);
591 EXPORT_SYMBOL(snd_sb8dsp_midi);
592