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