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