diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/isa/sb/sb16_main.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/isa/sb/sb16_main.c')
-rw-r--r-- | sound/isa/sb/sb16_main.c | 916 |
1 files changed, 916 insertions, 0 deletions
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c new file mode 100644 index 000000000000..a6a0fa516268 --- /dev/null +++ b/sound/isa/sb/sb16_main.c | |||
@@ -0,0 +1,916 @@ | |||
1 | /* | ||
2 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
3 | * Routines for control of 16-bit SoundBlaster cards and clones | ||
4 | * Note: This is very ugly hardware which uses one 8-bit DMA channel and | ||
5 | * second 16-bit DMA channel. Unfortunately 8-bit DMA channel can't | ||
6 | * transfer 16-bit samples and 16-bit DMA channels can't transfer | ||
7 | * 8-bit samples. This make full duplex more complicated than | ||
8 | * can be... People, don't buy these soundcards for full 16-bit | ||
9 | * duplex!!! | ||
10 | * Note: 16-bit wide is assigned to first direction which made request. | ||
11 | * With full duplex - playback is preferred with abstract layer. | ||
12 | * | ||
13 | * Note: Some chip revisions have hardware bug. Changing capture | ||
14 | * channel from full-duplex 8bit DMA to 16bit DMA will block | ||
15 | * 16bit DMA transfers from DSP chip (capture) until 8bit transfer | ||
16 | * to DSP chip (playback) starts. This bug can be avoided with | ||
17 | * "16bit DMA Allocation" setting set to Playback or Capture. | ||
18 | * | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License as published by | ||
22 | * the Free Software Foundation; either version 2 of the License, or | ||
23 | * (at your option) any later version. | ||
24 | * | ||
25 | * This program is distributed in the hope that it will be useful, | ||
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
28 | * GNU General Public License for more details. | ||
29 | * | ||
30 | * You should have received a copy of the GNU General Public License | ||
31 | * along with this program; if not, write to the Free Software | ||
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
33 | * | ||
34 | */ | ||
35 | |||
36 | #include <sound/driver.h> | ||
37 | #include <asm/io.h> | ||
38 | #include <asm/dma.h> | ||
39 | #include <linux/init.h> | ||
40 | #include <linux/time.h> | ||
41 | #include <sound/core.h> | ||
42 | #include <sound/sb.h> | ||
43 | #include <sound/sb16_csp.h> | ||
44 | #include <sound/mpu401.h> | ||
45 | #include <sound/control.h> | ||
46 | #include <sound/info.h> | ||
47 | |||
48 | MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | ||
49 | MODULE_DESCRIPTION("Routines for control of 16-bit SoundBlaster cards and clones"); | ||
50 | MODULE_LICENSE("GPL"); | ||
51 | |||
52 | #ifdef CONFIG_SND_SB16_CSP | ||
53 | static void snd_sb16_csp_playback_prepare(sb_t *chip, snd_pcm_runtime_t *runtime) | ||
54 | { | ||
55 | if (chip->hardware == SB_HW_16CSP) { | ||
56 | snd_sb_csp_t *csp = chip->csp; | ||
57 | |||
58 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | ||
59 | /* manually loaded codec */ | ||
60 | if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) && | ||
61 | ((1U << runtime->format) == csp->acc_format)) { | ||
62 | /* Supported runtime PCM format for playback */ | ||
63 | if (csp->ops.csp_use(csp) == 0) { | ||
64 | /* If CSP was successfully acquired */ | ||
65 | goto __start_CSP; | ||
66 | } | ||
67 | } else if ((csp->mode & SNDRV_SB_CSP_MODE_QSOUND) && (csp->q_enabled)) { | ||
68 | /* QSound decoder is loaded and enabled */ | ||
69 | if ((1 << runtime->format) & (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | | ||
70 | SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE)) { | ||
71 | /* Only for simple PCM formats */ | ||
72 | if (csp->ops.csp_use(csp) == 0) { | ||
73 | /* If CSP was successfully acquired */ | ||
74 | goto __start_CSP; | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | } else if (csp->ops.csp_use(csp) == 0) { | ||
79 | /* Acquire CSP and try to autoload hardware codec */ | ||
80 | if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_WRITE)) { | ||
81 | /* Unsupported format, release CSP */ | ||
82 | csp->ops.csp_unuse(csp); | ||
83 | } else { | ||
84 | __start_CSP: | ||
85 | /* Try to start CSP */ | ||
86 | if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_PLAYBACK_16) ? | ||
87 | SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT, | ||
88 | (runtime->channels > 1) ? | ||
89 | SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) { | ||
90 | /* Failed, release CSP */ | ||
91 | csp->ops.csp_unuse(csp); | ||
92 | } else { | ||
93 | /* Success, CSP acquired and running */ | ||
94 | chip->open = SNDRV_SB_CSP_MODE_DSP_WRITE; | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | |||
101 | static void snd_sb16_csp_capture_prepare(sb_t *chip, snd_pcm_runtime_t *runtime) | ||
102 | { | ||
103 | if (chip->hardware == SB_HW_16CSP) { | ||
104 | snd_sb_csp_t *csp = chip->csp; | ||
105 | |||
106 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | ||
107 | /* manually loaded codec */ | ||
108 | if ((csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) && | ||
109 | ((1U << runtime->format) == csp->acc_format)) { | ||
110 | /* Supported runtime PCM format for capture */ | ||
111 | if (csp->ops.csp_use(csp) == 0) { | ||
112 | /* If CSP was successfully acquired */ | ||
113 | goto __start_CSP; | ||
114 | } | ||
115 | } | ||
116 | } else if (csp->ops.csp_use(csp) == 0) { | ||
117 | /* Acquire CSP and try to autoload hardware codec */ | ||
118 | if (csp->ops.csp_autoload(csp, runtime->format, SNDRV_SB_CSP_MODE_DSP_READ)) { | ||
119 | /* Unsupported format, release CSP */ | ||
120 | csp->ops.csp_unuse(csp); | ||
121 | } else { | ||
122 | __start_CSP: | ||
123 | /* Try to start CSP */ | ||
124 | if (csp->ops.csp_start(csp, (chip->mode & SB_MODE_CAPTURE_16) ? | ||
125 | SNDRV_SB_CSP_SAMPLE_16BIT : SNDRV_SB_CSP_SAMPLE_8BIT, | ||
126 | (runtime->channels > 1) ? | ||
127 | SNDRV_SB_CSP_STEREO : SNDRV_SB_CSP_MONO)) { | ||
128 | /* Failed, release CSP */ | ||
129 | csp->ops.csp_unuse(csp); | ||
130 | } else { | ||
131 | /* Success, CSP acquired and running */ | ||
132 | chip->open = SNDRV_SB_CSP_MODE_DSP_READ; | ||
133 | } | ||
134 | } | ||
135 | } | ||
136 | } | ||
137 | } | ||
138 | |||
139 | static void snd_sb16_csp_update(sb_t *chip) | ||
140 | { | ||
141 | if (chip->hardware == SB_HW_16CSP) { | ||
142 | snd_sb_csp_t *csp = chip->csp; | ||
143 | |||
144 | if (csp->qpos_changed) { | ||
145 | spin_lock(&chip->reg_lock); | ||
146 | csp->ops.csp_qsound_transfer (csp); | ||
147 | spin_unlock(&chip->reg_lock); | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | static void snd_sb16_csp_playback_open(sb_t *chip, snd_pcm_runtime_t *runtime) | ||
153 | { | ||
154 | /* CSP decoders (QSound excluded) support only 16bit transfers */ | ||
155 | if (chip->hardware == SB_HW_16CSP) { | ||
156 | snd_sb_csp_t *csp = chip->csp; | ||
157 | |||
158 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | ||
159 | /* manually loaded codec */ | ||
160 | if (csp->mode & SNDRV_SB_CSP_MODE_DSP_WRITE) { | ||
161 | runtime->hw.formats |= csp->acc_format; | ||
162 | } | ||
163 | } else { | ||
164 | /* autoloaded codecs */ | ||
165 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | ||
166 | SNDRV_PCM_FMTBIT_IMA_ADPCM; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static void snd_sb16_csp_playback_close(sb_t *chip) | ||
172 | { | ||
173 | if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_WRITE)) { | ||
174 | snd_sb_csp_t *csp = chip->csp; | ||
175 | |||
176 | if (csp->ops.csp_stop(csp) == 0) { | ||
177 | csp->ops.csp_unuse(csp); | ||
178 | chip->open = 0; | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | |||
183 | static void snd_sb16_csp_capture_open(sb_t *chip, snd_pcm_runtime_t *runtime) | ||
184 | { | ||
185 | /* CSP coders support only 16bit transfers */ | ||
186 | if (chip->hardware == SB_HW_16CSP) { | ||
187 | snd_sb_csp_t *csp = chip->csp; | ||
188 | |||
189 | if (csp->running & SNDRV_SB_CSP_ST_LOADED) { | ||
190 | /* manually loaded codec */ | ||
191 | if (csp->mode & SNDRV_SB_CSP_MODE_DSP_READ) { | ||
192 | runtime->hw.formats |= csp->acc_format; | ||
193 | } | ||
194 | } else { | ||
195 | /* autoloaded codecs */ | ||
196 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW | | ||
197 | SNDRV_PCM_FMTBIT_IMA_ADPCM; | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static void snd_sb16_csp_capture_close(sb_t *chip) | ||
203 | { | ||
204 | if ((chip->hardware == SB_HW_16CSP) && (chip->open == SNDRV_SB_CSP_MODE_DSP_READ)) { | ||
205 | snd_sb_csp_t *csp = chip->csp; | ||
206 | |||
207 | if (csp->ops.csp_stop(csp) == 0) { | ||
208 | csp->ops.csp_unuse(csp); | ||
209 | chip->open = 0; | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | #else | ||
214 | #define snd_sb16_csp_playback_prepare(chip, runtime) /*nop*/ | ||
215 | #define snd_sb16_csp_capture_prepare(chip, runtime) /*nop*/ | ||
216 | #define snd_sb16_csp_update(chip) /*nop*/ | ||
217 | #define snd_sb16_csp_playback_open(chip, runtime) /*nop*/ | ||
218 | #define snd_sb16_csp_playback_close(chip) /*nop*/ | ||
219 | #define snd_sb16_csp_capture_open(chip, runtime) /*nop*/ | ||
220 | #define snd_sb16_csp_capture_close(chip) /*nop*/ | ||
221 | #endif | ||
222 | |||
223 | |||
224 | static void snd_sb16_setup_rate(sb_t *chip, | ||
225 | unsigned short rate, | ||
226 | int channel) | ||
227 | { | ||
228 | unsigned long flags; | ||
229 | |||
230 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
231 | if (chip->mode & (channel == SNDRV_PCM_STREAM_PLAYBACK ? SB_MODE_PLAYBACK_16 : SB_MODE_CAPTURE_16)) | ||
232 | snd_sb_ack_16bit(chip); | ||
233 | else | ||
234 | snd_sb_ack_8bit(chip); | ||
235 | if (!(chip->mode & SB_RATE_LOCK)) { | ||
236 | chip->locked_rate = rate; | ||
237 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_IN); | ||
238 | snd_sbdsp_command(chip, rate >> 8); | ||
239 | snd_sbdsp_command(chip, rate & 0xff); | ||
240 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE_OUT); | ||
241 | snd_sbdsp_command(chip, rate >> 8); | ||
242 | snd_sbdsp_command(chip, rate & 0xff); | ||
243 | } | ||
244 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
245 | } | ||
246 | |||
247 | static int snd_sb16_hw_params(snd_pcm_substream_t * substream, | ||
248 | snd_pcm_hw_params_t * hw_params) | ||
249 | { | ||
250 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | ||
251 | } | ||
252 | |||
253 | static int snd_sb16_hw_free(snd_pcm_substream_t * substream) | ||
254 | { | ||
255 | snd_pcm_lib_free_pages(substream); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int snd_sb16_playback_prepare(snd_pcm_substream_t * substream) | ||
260 | { | ||
261 | unsigned long flags; | ||
262 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
263 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
264 | unsigned char format; | ||
265 | unsigned int size, count, dma; | ||
266 | |||
267 | snd_sb16_csp_playback_prepare(chip, runtime); | ||
268 | if (snd_pcm_format_unsigned(runtime->format) > 0) { | ||
269 | format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO; | ||
270 | } else { | ||
271 | format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO; | ||
272 | } | ||
273 | |||
274 | snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_PLAYBACK); | ||
275 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); | ||
276 | dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16; | ||
277 | snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_WRITE | DMA_AUTOINIT); | ||
278 | |||
279 | count = snd_pcm_lib_period_bytes(substream); | ||
280 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
281 | if (chip->mode & SB_MODE_PLAYBACK_16) { | ||
282 | count >>= 1; | ||
283 | count--; | ||
284 | snd_sbdsp_command(chip, SB_DSP4_OUT16_AI); | ||
285 | snd_sbdsp_command(chip, format); | ||
286 | snd_sbdsp_command(chip, count & 0xff); | ||
287 | snd_sbdsp_command(chip, count >> 8); | ||
288 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | ||
289 | } else { | ||
290 | count--; | ||
291 | snd_sbdsp_command(chip, SB_DSP4_OUT8_AI); | ||
292 | snd_sbdsp_command(chip, format); | ||
293 | snd_sbdsp_command(chip, count & 0xff); | ||
294 | snd_sbdsp_command(chip, count >> 8); | ||
295 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | ||
296 | } | ||
297 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int snd_sb16_playback_trigger(snd_pcm_substream_t * substream, | ||
302 | int cmd) | ||
303 | { | ||
304 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
305 | int result = 0; | ||
306 | |||
307 | spin_lock(&chip->reg_lock); | ||
308 | switch (cmd) { | ||
309 | case SNDRV_PCM_TRIGGER_START: | ||
310 | chip->mode |= SB_RATE_LOCK_PLAYBACK; | ||
311 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | ||
312 | break; | ||
313 | case SNDRV_PCM_TRIGGER_STOP: | ||
314 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF); | ||
315 | /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */ | ||
316 | if (chip->mode & SB_RATE_LOCK_CAPTURE) | ||
317 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | ||
318 | chip->mode &= ~SB_RATE_LOCK_PLAYBACK; | ||
319 | break; | ||
320 | default: | ||
321 | result = -EINVAL; | ||
322 | } | ||
323 | spin_unlock(&chip->reg_lock); | ||
324 | return result; | ||
325 | } | ||
326 | |||
327 | static int snd_sb16_capture_prepare(snd_pcm_substream_t * substream) | ||
328 | { | ||
329 | unsigned long flags; | ||
330 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
331 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
332 | unsigned char format; | ||
333 | unsigned int size, count, dma; | ||
334 | |||
335 | snd_sb16_csp_capture_prepare(chip, runtime); | ||
336 | if (snd_pcm_format_unsigned(runtime->format) > 0) { | ||
337 | format = runtime->channels > 1 ? SB_DSP4_MODE_UNS_STEREO : SB_DSP4_MODE_UNS_MONO; | ||
338 | } else { | ||
339 | format = runtime->channels > 1 ? SB_DSP4_MODE_SIGN_STEREO : SB_DSP4_MODE_SIGN_MONO; | ||
340 | } | ||
341 | snd_sb16_setup_rate(chip, runtime->rate, SNDRV_PCM_STREAM_CAPTURE); | ||
342 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); | ||
343 | dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16; | ||
344 | snd_dma_program(dma, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); | ||
345 | |||
346 | count = snd_pcm_lib_period_bytes(substream); | ||
347 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
348 | if (chip->mode & SB_MODE_CAPTURE_16) { | ||
349 | count >>= 1; | ||
350 | count--; | ||
351 | snd_sbdsp_command(chip, SB_DSP4_IN16_AI); | ||
352 | snd_sbdsp_command(chip, format); | ||
353 | snd_sbdsp_command(chip, count & 0xff); | ||
354 | snd_sbdsp_command(chip, count >> 8); | ||
355 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | ||
356 | } else { | ||
357 | count--; | ||
358 | snd_sbdsp_command(chip, SB_DSP4_IN8_AI); | ||
359 | snd_sbdsp_command(chip, format); | ||
360 | snd_sbdsp_command(chip, count & 0xff); | ||
361 | snd_sbdsp_command(chip, count >> 8); | ||
362 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | ||
363 | } | ||
364 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
365 | return 0; | ||
366 | } | ||
367 | |||
368 | static int snd_sb16_capture_trigger(snd_pcm_substream_t * substream, | ||
369 | int cmd) | ||
370 | { | ||
371 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
372 | int result = 0; | ||
373 | |||
374 | spin_lock(&chip->reg_lock); | ||
375 | switch (cmd) { | ||
376 | case SNDRV_PCM_TRIGGER_START: | ||
377 | chip->mode |= SB_RATE_LOCK_CAPTURE; | ||
378 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | ||
379 | break; | ||
380 | case SNDRV_PCM_TRIGGER_STOP: | ||
381 | snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF); | ||
382 | /* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */ | ||
383 | if (chip->mode & SB_RATE_LOCK_PLAYBACK) | ||
384 | snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON); | ||
385 | chip->mode &= ~SB_RATE_LOCK_CAPTURE; | ||
386 | break; | ||
387 | default: | ||
388 | result = -EINVAL; | ||
389 | } | ||
390 | spin_unlock(&chip->reg_lock); | ||
391 | return result; | ||
392 | } | ||
393 | |||
394 | irqreturn_t snd_sb16dsp_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
395 | { | ||
396 | sb_t *chip = dev_id; | ||
397 | unsigned char status; | ||
398 | int ok; | ||
399 | |||
400 | spin_lock(&chip->mixer_lock); | ||
401 | status = snd_sbmixer_read(chip, SB_DSP4_IRQSTATUS); | ||
402 | spin_unlock(&chip->mixer_lock); | ||
403 | if ((status & SB_IRQTYPE_MPUIN) && chip->rmidi_callback) | ||
404 | chip->rmidi_callback(irq, chip->rmidi->private_data, regs); | ||
405 | if (status & SB_IRQTYPE_8BIT) { | ||
406 | ok = 0; | ||
407 | if (chip->mode & SB_MODE_PLAYBACK_8) { | ||
408 | snd_pcm_period_elapsed(chip->playback_substream); | ||
409 | snd_sb16_csp_update(chip); | ||
410 | ok++; | ||
411 | } | ||
412 | if (chip->mode & SB_MODE_CAPTURE_8) { | ||
413 | snd_pcm_period_elapsed(chip->capture_substream); | ||
414 | ok++; | ||
415 | } | ||
416 | spin_lock(&chip->reg_lock); | ||
417 | if (!ok) | ||
418 | snd_sbdsp_command(chip, SB_DSP_DMA8_OFF); | ||
419 | snd_sb_ack_8bit(chip); | ||
420 | spin_unlock(&chip->reg_lock); | ||
421 | } | ||
422 | if (status & SB_IRQTYPE_16BIT) { | ||
423 | ok = 0; | ||
424 | if (chip->mode & SB_MODE_PLAYBACK_16) { | ||
425 | snd_pcm_period_elapsed(chip->playback_substream); | ||
426 | snd_sb16_csp_update(chip); | ||
427 | ok++; | ||
428 | } | ||
429 | if (chip->mode & SB_MODE_CAPTURE_16) { | ||
430 | snd_pcm_period_elapsed(chip->capture_substream); | ||
431 | ok++; | ||
432 | } | ||
433 | spin_lock(&chip->reg_lock); | ||
434 | if (!ok) | ||
435 | snd_sbdsp_command(chip, SB_DSP_DMA16_OFF); | ||
436 | snd_sb_ack_16bit(chip); | ||
437 | spin_unlock(&chip->reg_lock); | ||
438 | } | ||
439 | return IRQ_HANDLED; | ||
440 | } | ||
441 | |||
442 | /* | ||
443 | |||
444 | */ | ||
445 | |||
446 | static snd_pcm_uframes_t snd_sb16_playback_pointer(snd_pcm_substream_t * substream) | ||
447 | { | ||
448 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
449 | unsigned int dma; | ||
450 | size_t ptr; | ||
451 | |||
452 | dma = (chip->mode & SB_MODE_PLAYBACK_8) ? chip->dma8 : chip->dma16; | ||
453 | ptr = snd_dma_pointer(dma, chip->p_dma_size); | ||
454 | return bytes_to_frames(substream->runtime, ptr); | ||
455 | } | ||
456 | |||
457 | static snd_pcm_uframes_t snd_sb16_capture_pointer(snd_pcm_substream_t * substream) | ||
458 | { | ||
459 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
460 | unsigned int dma; | ||
461 | size_t ptr; | ||
462 | |||
463 | dma = (chip->mode & SB_MODE_CAPTURE_8) ? chip->dma8 : chip->dma16; | ||
464 | ptr = snd_dma_pointer(dma, chip->c_dma_size); | ||
465 | return bytes_to_frames(substream->runtime, ptr); | ||
466 | } | ||
467 | |||
468 | /* | ||
469 | |||
470 | */ | ||
471 | |||
472 | static snd_pcm_hardware_t snd_sb16_playback = | ||
473 | { | ||
474 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
475 | SNDRV_PCM_INFO_MMAP_VALID), | ||
476 | .formats = 0, | ||
477 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100, | ||
478 | .rate_min = 4000, | ||
479 | .rate_max = 44100, | ||
480 | .channels_min = 1, | ||
481 | .channels_max = 2, | ||
482 | .buffer_bytes_max = (128*1024), | ||
483 | .period_bytes_min = 64, | ||
484 | .period_bytes_max = (128*1024), | ||
485 | .periods_min = 1, | ||
486 | .periods_max = 1024, | ||
487 | .fifo_size = 0, | ||
488 | }; | ||
489 | |||
490 | static snd_pcm_hardware_t snd_sb16_capture = | ||
491 | { | ||
492 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | ||
493 | SNDRV_PCM_INFO_MMAP_VALID), | ||
494 | .formats = 0, | ||
495 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_44100, | ||
496 | .rate_min = 4000, | ||
497 | .rate_max = 44100, | ||
498 | .channels_min = 1, | ||
499 | .channels_max = 2, | ||
500 | .buffer_bytes_max = (128*1024), | ||
501 | .period_bytes_min = 64, | ||
502 | .period_bytes_max = (128*1024), | ||
503 | .periods_min = 1, | ||
504 | .periods_max = 1024, | ||
505 | .fifo_size = 0, | ||
506 | }; | ||
507 | |||
508 | /* | ||
509 | * open/close | ||
510 | */ | ||
511 | |||
512 | static int snd_sb16_playback_open(snd_pcm_substream_t * substream) | ||
513 | { | ||
514 | unsigned long flags; | ||
515 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
516 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
517 | |||
518 | spin_lock_irqsave(&chip->open_lock, flags); | ||
519 | if (chip->mode & SB_MODE_PLAYBACK) { | ||
520 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
521 | return -EAGAIN; | ||
522 | } | ||
523 | runtime->hw = snd_sb16_playback; | ||
524 | |||
525 | /* skip if 16 bit DMA was reserved for capture */ | ||
526 | if (chip->force_mode16 & SB_MODE_CAPTURE_16) | ||
527 | goto __skip_16bit; | ||
528 | |||
529 | if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_CAPTURE_16)) { | ||
530 | chip->mode |= SB_MODE_PLAYBACK_16; | ||
531 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | ||
532 | /* Vibra16X hack */ | ||
533 | if (chip->dma16 <= 3) { | ||
534 | runtime->hw.buffer_bytes_max = | ||
535 | runtime->hw.period_bytes_max = 64 * 1024; | ||
536 | } else { | ||
537 | snd_sb16_csp_playback_open(chip, runtime); | ||
538 | } | ||
539 | goto __open_ok; | ||
540 | } | ||
541 | |||
542 | __skip_16bit: | ||
543 | if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_CAPTURE_8)) { | ||
544 | chip->mode |= SB_MODE_PLAYBACK_8; | ||
545 | /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */ | ||
546 | if (chip->dma16 < 0) { | ||
547 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | ||
548 | chip->mode |= SB_MODE_PLAYBACK_16; | ||
549 | } else { | ||
550 | runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8; | ||
551 | } | ||
552 | runtime->hw.buffer_bytes_max = | ||
553 | runtime->hw.period_bytes_max = 64 * 1024; | ||
554 | goto __open_ok; | ||
555 | } | ||
556 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
557 | return -EAGAIN; | ||
558 | |||
559 | __open_ok: | ||
560 | if (chip->hardware == SB_HW_ALS100) | ||
561 | runtime->hw.rate_max = 48000; | ||
562 | if (chip->mode & SB_RATE_LOCK) | ||
563 | runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; | ||
564 | chip->playback_substream = substream; | ||
565 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static int snd_sb16_playback_close(snd_pcm_substream_t * substream) | ||
570 | { | ||
571 | unsigned long flags; | ||
572 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
573 | |||
574 | snd_sb16_csp_playback_close(chip); | ||
575 | spin_lock_irqsave(&chip->open_lock, flags); | ||
576 | chip->playback_substream = NULL; | ||
577 | chip->mode &= ~SB_MODE_PLAYBACK; | ||
578 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | static int snd_sb16_capture_open(snd_pcm_substream_t * substream) | ||
583 | { | ||
584 | unsigned long flags; | ||
585 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
586 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
587 | |||
588 | spin_lock_irqsave(&chip->open_lock, flags); | ||
589 | if (chip->mode & SB_MODE_CAPTURE) { | ||
590 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
591 | return -EAGAIN; | ||
592 | } | ||
593 | runtime->hw = snd_sb16_capture; | ||
594 | |||
595 | /* skip if 16 bit DMA was reserved for playback */ | ||
596 | if (chip->force_mode16 & SB_MODE_PLAYBACK_16) | ||
597 | goto __skip_16bit; | ||
598 | |||
599 | if (chip->dma16 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_16)) { | ||
600 | chip->mode |= SB_MODE_CAPTURE_16; | ||
601 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | ||
602 | /* Vibra16X hack */ | ||
603 | if (chip->dma16 <= 3) { | ||
604 | runtime->hw.buffer_bytes_max = | ||
605 | runtime->hw.period_bytes_max = 64 * 1024; | ||
606 | } else { | ||
607 | snd_sb16_csp_capture_open(chip, runtime); | ||
608 | } | ||
609 | goto __open_ok; | ||
610 | } | ||
611 | |||
612 | __skip_16bit: | ||
613 | if (chip->dma8 >= 0 && !(chip->mode & SB_MODE_PLAYBACK_8)) { | ||
614 | chip->mode |= SB_MODE_CAPTURE_8; | ||
615 | /* DSP v 4.xx can transfer 16bit data through 8bit DMA channel, SBHWPG 2-7 */ | ||
616 | if (chip->dma16 < 0) { | ||
617 | runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE; | ||
618 | chip->mode |= SB_MODE_CAPTURE_16; | ||
619 | } else { | ||
620 | runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S8; | ||
621 | } | ||
622 | runtime->hw.buffer_bytes_max = | ||
623 | runtime->hw.period_bytes_max = 64 * 1024; | ||
624 | goto __open_ok; | ||
625 | } | ||
626 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
627 | return -EAGAIN; | ||
628 | |||
629 | __open_ok: | ||
630 | if (chip->hardware == SB_HW_ALS100) | ||
631 | runtime->hw.rate_max = 48000; | ||
632 | if (chip->mode & SB_RATE_LOCK) | ||
633 | runtime->hw.rate_min = runtime->hw.rate_max = chip->locked_rate; | ||
634 | chip->capture_substream = substream; | ||
635 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
636 | return 0; | ||
637 | } | ||
638 | |||
639 | static int snd_sb16_capture_close(snd_pcm_substream_t * substream) | ||
640 | { | ||
641 | unsigned long flags; | ||
642 | sb_t *chip = snd_pcm_substream_chip(substream); | ||
643 | |||
644 | snd_sb16_csp_capture_close(chip); | ||
645 | spin_lock_irqsave(&chip->open_lock, flags); | ||
646 | chip->capture_substream = NULL; | ||
647 | chip->mode &= ~SB_MODE_CAPTURE; | ||
648 | spin_unlock_irqrestore(&chip->open_lock, flags); | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | /* | ||
653 | * DMA control interface | ||
654 | */ | ||
655 | |||
656 | static int snd_sb16_set_dma_mode(sb_t *chip, int what) | ||
657 | { | ||
658 | if (chip->dma8 < 0 || chip->dma16 < 0) { | ||
659 | snd_assert(what == 0, return -EINVAL); | ||
660 | return 0; | ||
661 | } | ||
662 | if (what == 0) { | ||
663 | chip->force_mode16 = 0; | ||
664 | } else if (what == 1) { | ||
665 | chip->force_mode16 = SB_MODE_PLAYBACK_16; | ||
666 | } else if (what == 2) { | ||
667 | chip->force_mode16 = SB_MODE_CAPTURE_16; | ||
668 | } else { | ||
669 | return -EINVAL; | ||
670 | } | ||
671 | return 0; | ||
672 | } | ||
673 | |||
674 | static int snd_sb16_get_dma_mode(sb_t *chip) | ||
675 | { | ||
676 | if (chip->dma8 < 0 || chip->dma16 < 0) | ||
677 | return 0; | ||
678 | switch (chip->force_mode16) { | ||
679 | case SB_MODE_PLAYBACK_16: | ||
680 | return 1; | ||
681 | case SB_MODE_CAPTURE_16: | ||
682 | return 2; | ||
683 | default: | ||
684 | return 0; | ||
685 | } | ||
686 | } | ||
687 | |||
688 | static int snd_sb16_dma_control_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) | ||
689 | { | ||
690 | static char *texts[3] = { | ||
691 | "Auto", "Playback", "Capture" | ||
692 | }; | ||
693 | |||
694 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
695 | uinfo->count = 1; | ||
696 | uinfo->value.enumerated.items = 3; | ||
697 | if (uinfo->value.enumerated.item > 2) | ||
698 | uinfo->value.enumerated.item = 2; | ||
699 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
700 | return 0; | ||
701 | } | ||
702 | |||
703 | static int snd_sb16_dma_control_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
704 | { | ||
705 | sb_t *chip = snd_kcontrol_chip(kcontrol); | ||
706 | unsigned long flags; | ||
707 | |||
708 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
709 | ucontrol->value.enumerated.item[0] = snd_sb16_get_dma_mode(chip); | ||
710 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static int snd_sb16_dma_control_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | ||
715 | { | ||
716 | sb_t *chip = snd_kcontrol_chip(kcontrol); | ||
717 | unsigned long flags; | ||
718 | unsigned char nval, oval; | ||
719 | int change; | ||
720 | |||
721 | if ((nval = ucontrol->value.enumerated.item[0]) > 2) | ||
722 | return -EINVAL; | ||
723 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
724 | oval = snd_sb16_get_dma_mode(chip); | ||
725 | change = nval != oval; | ||
726 | snd_sb16_set_dma_mode(chip, nval); | ||
727 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
728 | return change; | ||
729 | } | ||
730 | |||
731 | static snd_kcontrol_new_t snd_sb16_dma_control = { | ||
732 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
733 | .name = "16-bit DMA Allocation", | ||
734 | .info = snd_sb16_dma_control_info, | ||
735 | .get = snd_sb16_dma_control_get, | ||
736 | .put = snd_sb16_dma_control_put | ||
737 | }; | ||
738 | |||
739 | /* | ||
740 | * Initialization part | ||
741 | */ | ||
742 | |||
743 | int snd_sb16dsp_configure(sb_t * chip) | ||
744 | { | ||
745 | unsigned long flags; | ||
746 | unsigned char irqreg = 0, dmareg = 0, mpureg; | ||
747 | unsigned char realirq, realdma, realmpureg; | ||
748 | /* note: mpu register should be present only on SB16 Vibra soundcards */ | ||
749 | |||
750 | // printk("codec->irq=%i, codec->dma8=%i, codec->dma16=%i\n", chip->irq, chip->dma8, chip->dma16); | ||
751 | spin_lock_irqsave(&chip->mixer_lock, flags); | ||
752 | mpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP) & ~0x06; | ||
753 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | ||
754 | switch (chip->irq) { | ||
755 | case 2: | ||
756 | case 9: | ||
757 | irqreg |= SB_IRQSETUP_IRQ9; | ||
758 | break; | ||
759 | case 5: | ||
760 | irqreg |= SB_IRQSETUP_IRQ5; | ||
761 | break; | ||
762 | case 7: | ||
763 | irqreg |= SB_IRQSETUP_IRQ7; | ||
764 | break; | ||
765 | case 10: | ||
766 | irqreg |= SB_IRQSETUP_IRQ10; | ||
767 | break; | ||
768 | default: | ||
769 | return -EINVAL; | ||
770 | } | ||
771 | if (chip->dma8 >= 0) { | ||
772 | switch (chip->dma8) { | ||
773 | case 0: | ||
774 | dmareg |= SB_DMASETUP_DMA0; | ||
775 | break; | ||
776 | case 1: | ||
777 | dmareg |= SB_DMASETUP_DMA1; | ||
778 | break; | ||
779 | case 3: | ||
780 | dmareg |= SB_DMASETUP_DMA3; | ||
781 | break; | ||
782 | default: | ||
783 | return -EINVAL; | ||
784 | } | ||
785 | } | ||
786 | if (chip->dma16 >= 0 && chip->dma16 != chip->dma8) { | ||
787 | switch (chip->dma16) { | ||
788 | case 5: | ||
789 | dmareg |= SB_DMASETUP_DMA5; | ||
790 | break; | ||
791 | case 6: | ||
792 | dmareg |= SB_DMASETUP_DMA6; | ||
793 | break; | ||
794 | case 7: | ||
795 | dmareg |= SB_DMASETUP_DMA7; | ||
796 | break; | ||
797 | default: | ||
798 | return -EINVAL; | ||
799 | } | ||
800 | } | ||
801 | switch (chip->mpu_port) { | ||
802 | case 0x300: | ||
803 | mpureg |= 0x04; | ||
804 | break; | ||
805 | case 0x330: | ||
806 | mpureg |= 0x00; | ||
807 | break; | ||
808 | default: | ||
809 | mpureg |= 0x02; /* disable MPU */ | ||
810 | } | ||
811 | spin_lock_irqsave(&chip->mixer_lock, flags); | ||
812 | |||
813 | snd_sbmixer_write(chip, SB_DSP4_IRQSETUP, irqreg); | ||
814 | realirq = snd_sbmixer_read(chip, SB_DSP4_IRQSETUP); | ||
815 | |||
816 | snd_sbmixer_write(chip, SB_DSP4_DMASETUP, dmareg); | ||
817 | realdma = snd_sbmixer_read(chip, SB_DSP4_DMASETUP); | ||
818 | |||
819 | snd_sbmixer_write(chip, SB_DSP4_MPUSETUP, mpureg); | ||
820 | realmpureg = snd_sbmixer_read(chip, SB_DSP4_MPUSETUP); | ||
821 | |||
822 | spin_unlock_irqrestore(&chip->mixer_lock, flags); | ||
823 | if ((~realirq) & irqreg || (~realdma) & dmareg) { | ||
824 | snd_printk("SB16 [0x%lx]: unable to set DMA & IRQ (PnP device?)\n", chip->port); | ||
825 | snd_printk("SB16 [0x%lx]: wanted: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, realirq, realdma, realmpureg); | ||
826 | snd_printk("SB16 [0x%lx]: got: irqreg=0x%x, dmareg=0x%x, mpureg = 0x%x\n", chip->port, irqreg, dmareg, mpureg); | ||
827 | return -ENODEV; | ||
828 | } | ||
829 | return 0; | ||
830 | } | ||
831 | |||
832 | static snd_pcm_ops_t snd_sb16_playback_ops = { | ||
833 | .open = snd_sb16_playback_open, | ||
834 | .close = snd_sb16_playback_close, | ||
835 | .ioctl = snd_pcm_lib_ioctl, | ||
836 | .hw_params = snd_sb16_hw_params, | ||
837 | .hw_free = snd_sb16_hw_free, | ||
838 | .prepare = snd_sb16_playback_prepare, | ||
839 | .trigger = snd_sb16_playback_trigger, | ||
840 | .pointer = snd_sb16_playback_pointer, | ||
841 | }; | ||
842 | |||
843 | static snd_pcm_ops_t snd_sb16_capture_ops = { | ||
844 | .open = snd_sb16_capture_open, | ||
845 | .close = snd_sb16_capture_close, | ||
846 | .ioctl = snd_pcm_lib_ioctl, | ||
847 | .hw_params = snd_sb16_hw_params, | ||
848 | .hw_free = snd_sb16_hw_free, | ||
849 | .prepare = snd_sb16_capture_prepare, | ||
850 | .trigger = snd_sb16_capture_trigger, | ||
851 | .pointer = snd_sb16_capture_pointer, | ||
852 | }; | ||
853 | |||
854 | static void snd_sb16dsp_pcm_free(snd_pcm_t *pcm) | ||
855 | { | ||
856 | snd_pcm_lib_preallocate_free_for_all(pcm); | ||
857 | } | ||
858 | |||
859 | int snd_sb16dsp_pcm(sb_t * chip, int device, snd_pcm_t ** rpcm) | ||
860 | { | ||
861 | snd_card_t *card = chip->card; | ||
862 | snd_pcm_t *pcm; | ||
863 | int err; | ||
864 | |||
865 | if (rpcm) | ||
866 | *rpcm = NULL; | ||
867 | if ((err = snd_pcm_new(card, "SB16 DSP", device, 1, 1, &pcm)) < 0) | ||
868 | return err; | ||
869 | sprintf(pcm->name, "DSP v%i.%i", chip->version >> 8, chip->version & 0xff); | ||
870 | pcm->info_flags = SNDRV_PCM_INFO_JOINT_DUPLEX; | ||
871 | pcm->private_data = chip; | ||
872 | pcm->private_free = snd_sb16dsp_pcm_free; | ||
873 | |||
874 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb16_playback_ops); | ||
875 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb16_capture_ops); | ||
876 | |||
877 | if (chip->dma16 >= 0 && chip->dma8 != chip->dma16) | ||
878 | snd_ctl_add(card, snd_ctl_new1(&snd_sb16_dma_control, chip)); | ||
879 | else | ||
880 | pcm->info_flags = SNDRV_PCM_INFO_HALF_DUPLEX; | ||
881 | |||
882 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
883 | snd_dma_isa_data(), | ||
884 | 64*1024, 128*1024); | ||
885 | |||
886 | if (rpcm) | ||
887 | *rpcm = pcm; | ||
888 | return 0; | ||
889 | } | ||
890 | |||
891 | const snd_pcm_ops_t *snd_sb16dsp_get_pcm_ops(int direction) | ||
892 | { | ||
893 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | ||
894 | &snd_sb16_playback_ops : &snd_sb16_capture_ops; | ||
895 | } | ||
896 | |||
897 | EXPORT_SYMBOL(snd_sb16dsp_pcm); | ||
898 | EXPORT_SYMBOL(snd_sb16dsp_get_pcm_ops); | ||
899 | EXPORT_SYMBOL(snd_sb16dsp_configure); | ||
900 | EXPORT_SYMBOL(snd_sb16dsp_interrupt); | ||
901 | |||
902 | /* | ||
903 | * INIT part | ||
904 | */ | ||
905 | |||
906 | static int __init alsa_sb16_init(void) | ||
907 | { | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | static void __exit alsa_sb16_exit(void) | ||
912 | { | ||
913 | } | ||
914 | |||
915 | module_init(alsa_sb16_init) | ||
916 | module_exit(alsa_sb16_exit) | ||