1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "sound_config.h"
20
21#define __SB_MIXER_C__
22
23#include "sb.h"
24#include "sb_mixer.h"
25
26#include "sb_ess.h"
27
28#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
29
30
31#define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
32
33#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
34 SOUND_MASK_CD | SOUND_MASK_VOLUME)
35
36
37
38
39
40
41#define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
42 SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
43
44#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
45 SOUND_MASK_CD)
46
47#define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
48 SOUND_MASK_CD)
49
50#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
51 SOUND_MASK_CD | \
52 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
53 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
54 SOUND_MASK_IMIX)
55
56
57
58
59#define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \
60 SOUND_MASK_PCM | SOUND_MASK_MIC | \
61 SOUND_MASK_CD | \
62 SOUND_MASK_VOLUME)
63
64static mixer_tab sbpro_mix = {
65MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4),
66MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
67MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
68MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4),
69MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4),
70MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
71MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4),
72MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0),
73MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4),
74MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
75MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
76MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0)
77};
78
79static mixer_tab sb16_mix = {
80MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5),
81MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4),
82MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4),
83MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5),
84MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5),
85MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0),
86MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5),
87MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0),
88MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5),
89MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0),
90MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
91MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2),
92MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2),
93MIX_ENT(SOUND_MIXER_OGAIN, 0x41, 7, 2, 0x42, 7, 2)
94};
95
96static mixer_tab als007_mix =
97{
98MIX_ENT(SOUND_MIXER_VOLUME, 0x62, 7, 4, 0x62, 3, 4),
99MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0),
100MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0),
101MIX_ENT(SOUND_MIXER_SYNTH, 0x66, 7, 4, 0x66, 3, 4),
102MIX_ENT(SOUND_MIXER_PCM, 0x64, 7, 4, 0x64, 3, 4),
103MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0),
104MIX_ENT(SOUND_MIXER_LINE, 0x6e, 7, 4, 0x6e, 3, 4),
105MIX_ENT(SOUND_MIXER_MIC, 0x6a, 2, 3, 0x00, 0, 0),
106MIX_ENT(SOUND_MIXER_CD, 0x68, 7, 4, 0x68, 3, 4),
107MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0),
108MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0),
109MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0),
110MIX_ENT(SOUND_MIXER_IGAIN, 0x00, 0, 0, 0x00, 0, 0),
111MIX_ENT(SOUND_MIXER_OGAIN, 0x00, 0, 0, 0x00, 0, 0)
112};
113
114
115
116
117
118
119static int smg_default_levels[32] =
120{
121 0x2020,
122 0x4b4b,
123 0x4b4b,
124 0x6464,
125 0x6464,
126 0x4b4b,
127 0x4b4b,
128 0x0000,
129 0x4b4b,
130 0x4b4b,
131 0x4b4b,
132 0x4b4b,
133 0x4b4b,
134 0x4b4b,
135 0x4040,
136 0x4040,
137 0x1515
138};
139
140static int sb_default_levels[32] =
141{
142 0x5a5a,
143 0x4b4b,
144 0x4b4b,
145 0x4b4b,
146 0x4b4b,
147 0x4b4b,
148 0x4b4b,
149 0x1010,
150 0x4b4b,
151 0x0000,
152 0x4b4b,
153 0x4b4b,
154 0x4b4b,
155 0x4b4b,
156 0x4040,
157 0x4040,
158 0x1515
159};
160
161static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] =
162{
163 0x00,
164 0x00,
165 0x00,
166 0x40,
167 0x00,
168 0x00,
169 0x10,
170 0x01,
171 0x04,
172 0x00,
173 0x00,
174 0x00,
175 0x00,
176 0x00
177};
178
179static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] =
180{
181 0x00,
182 0x00,
183 0x00,
184 0x20,
185 0x00,
186 0x00,
187 0x08,
188 0x01,
189 0x02,
190 0x00,
191 0x00,
192 0x00,
193 0x00,
194 0x00
195};
196
197static char smw_mix_regs[] =
198{
199 0x0b,
200 0x0d,
201 0x0d,
202 0x05,
203 0x09,
204 0x00,
205 0x03,
206 0x01,
207 0x07,
208 0x00,
209 0x00,
210 0x00,
211 0x00,
212 0x00,
213 0x00,
214 0x00,
215 0x00
216};
217
218static int sbmixnum = 1;
219
220static void sb_mixer_reset(sb_devc * devc);
221
222void sb_mixer_set_stereo(sb_devc * devc, int mode)
223{
224 sb_chgmixer(devc, OUT_FILTER, STEREO_DAC, (mode ? STEREO_DAC : MONO_DAC));
225}
226
227static int detect_mixer(sb_devc * devc)
228{
229
230 return 1;
231}
232
233static void change_bits(sb_devc * devc, unsigned char *regval, int dev, int chn, int newval)
234{
235 unsigned char mask;
236 int shift;
237
238 mask = (1 << (*devc->iomap)[dev][chn].nbits) - 1;
239 newval = (int) ((newval * mask) + 50) / 100;
240
241 shift = (*devc->iomap)[dev][chn].bitoffs - (*devc->iomap)[dev][LEFT_CHN].nbits + 1;
242
243 *regval &= ~(mask << shift);
244 *regval |= (newval & mask) << shift;
245}
246
247static int sb_mixer_get(sb_devc * devc, int dev)
248{
249 if (!((1 << dev) & devc->supported_devices))
250 return -EINVAL;
251 return devc->levels[dev];
252}
253
254void smw_mixer_init(sb_devc * devc)
255{
256 int i;
257
258 sb_setmixer(devc, 0x00, 0x18);
259 sb_setmixer(devc, 0x10, 0x38);
260
261 devc->supported_devices = 0;
262 for (i = 0; i < sizeof(smw_mix_regs); i++)
263 if (smw_mix_regs[i] != 0)
264 devc->supported_devices |= (1 << i);
265
266 devc->supported_rec_devices = devc->supported_devices &
267 ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_PCM | SOUND_MASK_VOLUME);
268 sb_mixer_reset(devc);
269}
270
271int sb_common_mixer_set(sb_devc * devc, int dev, int left, int right)
272{
273 int regoffs;
274 unsigned char val;
275
276 if ((dev < 0) || (dev >= devc->iomap_sz))
277 return -EINVAL;
278
279 regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
280
281 if (regoffs == 0)
282 return -EINVAL;
283
284 val = sb_getmixer(devc, regoffs);
285 change_bits(devc, &val, dev, LEFT_CHN, left);
286
287 if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)
288
289
290 {
291 sb_setmixer(devc, regoffs, val);
292
293
294 regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
295
296 if (regoffs == 0)
297 return left | (left << 8);
298
299
300
301 val = sb_getmixer(devc, regoffs);
302
303
304 }
305 change_bits(devc, &val, dev, RIGHT_CHN, right);
306
307 sb_setmixer(devc, regoffs, val);
308
309 return left | (right << 8);
310}
311
312static int smw_mixer_set(sb_devc * devc, int dev, int left, int right)
313{
314 int reg, val;
315
316 switch (dev)
317 {
318 case SOUND_MIXER_VOLUME:
319 sb_setmixer(devc, 0x0b, 96 - (96 * left / 100));
320 sb_setmixer(devc, 0x0c, 96 - (96 * right / 100));
321 break;
322
323 case SOUND_MIXER_BASS:
324 case SOUND_MIXER_TREBLE:
325 devc->levels[dev] = left | (right << 8);
326
327 val = ((devc->levels[SOUND_MIXER_TREBLE] & 0xff) * 16 / (unsigned) 100) << 4;
328 val |= ((devc->levels[SOUND_MIXER_BASS] & 0xff) * 16 / (unsigned) 100) & 0x0f;
329 sb_setmixer(devc, 0x0d, val);
330
331
332 val = (((devc->levels[SOUND_MIXER_TREBLE] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
333 val |= (((devc->levels[SOUND_MIXER_BASS] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
334 sb_setmixer(devc, 0x0e, val);
335
336 break;
337
338 default:
339
340 if (dev < 0 || dev >= ARRAY_SIZE(smw_mix_regs))
341 return -EINVAL;
342 reg = smw_mix_regs[dev];
343 if (reg == 0)
344 return -EINVAL;
345 sb_setmixer(devc, reg, (24 - (24 * left / 100)) | 0x20);
346 sb_setmixer(devc, reg + 1, (24 - (24 * right / 100)) | 0x40);
347 }
348
349 devc->levels[dev] = left | (right << 8);
350 return left | (right << 8);
351}
352
353static int sb_mixer_set(sb_devc * devc, int dev, int value)
354{
355 int left = value & 0x000000ff;
356 int right = (value & 0x0000ff00) >> 8;
357 int retval;
358
359 if (left > 100)
360 left = 100;
361 if (right > 100)
362 right = 100;
363
364 if ((dev < 0) || (dev > 31))
365 return -EINVAL;
366
367 if (!(devc->supported_devices & (1 << dev)))
368
369
370 return -EINVAL;
371
372
373 switch (devc->model) {
374 case MDL_SMW:
375 retval = smw_mixer_set(devc, dev, left, right);
376 break;
377 case MDL_ESS:
378 retval = ess_mixer_set(devc, dev, left, right);
379 break;
380 default:
381 retval = sb_common_mixer_set(devc, dev, left, right);
382 }
383 if (retval >= 0) devc->levels[dev] = retval;
384
385 return retval;
386}
387
388
389
390
391static void set_recsrc(sb_devc * devc, int src)
392{
393 sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7));
394}
395
396static int set_recmask(sb_devc * devc, int mask)
397{
398 int devmask, i;
399 unsigned char regimageL, regimageR;
400
401 devmask = mask & devc->supported_rec_devices;
402
403 switch (devc->model)
404 {
405 case MDL_SBPRO:
406 case MDL_ESS:
407 case MDL_JAZZ:
408 case MDL_SMW:
409 if (devc->model == MDL_ESS && ess_set_recmask (devc, &devmask)) {
410 break;
411 };
412 if (devmask != SOUND_MASK_MIC &&
413 devmask != SOUND_MASK_LINE &&
414 devmask != SOUND_MASK_CD)
415 {
416
417
418
419
420 devmask &= ~devc->recmask;
421 }
422 if (devmask != SOUND_MASK_MIC &&
423 devmask != SOUND_MASK_LINE &&
424 devmask != SOUND_MASK_CD)
425 {
426
427
428
429
430 devmask = SOUND_MASK_MIC;
431 }
432 if (devmask ^ devc->recmask)
433
434
435 {
436 switch (devmask)
437 {
438 case SOUND_MASK_MIC:
439 set_recsrc(devc, SRC__MIC);
440 break;
441
442 case SOUND_MASK_LINE:
443 set_recsrc(devc, SRC__LINE);
444 break;
445
446 case SOUND_MASK_CD:
447 set_recsrc(devc, SRC__CD);
448 break;
449
450 default:
451 set_recsrc(devc, SRC__MIC);
452 }
453 }
454 break;
455
456 case MDL_SB16:
457 if (!devmask)
458 devmask = SOUND_MASK_MIC;
459
460 if (devc->submodel == SUBMDL_ALS007)
461 {
462 switch (devmask)
463 {
464 case SOUND_MASK_LINE:
465 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_LINE);
466 break;
467 case SOUND_MASK_CD:
468 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_CD);
469 break;
470 case SOUND_MASK_SYNTH:
471 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_SYNTH);
472 break;
473 default:
474 sb_setmixer(devc, ALS007_RECORD_SRC, ALS007_MIC);
475 break;
476 }
477 }
478 else
479 {
480 regimageL = regimageR = 0;
481 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
482 {
483 if ((1 << i) & devmask)
484 {
485 regimageL |= sb16_recmasks_L[i];
486 regimageR |= sb16_recmasks_R[i];
487 }
488 sb_setmixer (devc, SB16_IMASK_L, regimageL);
489 sb_setmixer (devc, SB16_IMASK_R, regimageR);
490 }
491 }
492 break;
493 }
494 devc->recmask = devmask;
495 return devc->recmask;
496}
497
498static int set_outmask(sb_devc * devc, int mask)
499{
500 int devmask, i;
501 unsigned char regimage;
502
503 devmask = mask & devc->supported_out_devices;
504
505 switch (devc->model)
506 {
507 case MDL_SB16:
508 if (devc->submodel == SUBMDL_ALS007)
509 break;
510 else
511 {
512 regimage = 0;
513 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
514 {
515 if ((1 << i) & devmask)
516 {
517 regimage |= (sb16_recmasks_L[i] | sb16_recmasks_R[i]);
518 }
519 sb_setmixer (devc, SB16_OMASK, regimage);
520 }
521 }
522 break;
523 default:
524 break;
525 }
526
527 devc->outmask = devmask;
528 return devc->outmask;
529}
530
531static int sb_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
532{
533 sb_devc *devc = mixer_devs[dev]->devc;
534 int val, ret;
535 int __user *p = arg;
536
537
538
539
540
541
542 if (devc->model == MDL_SB16) {
543 if (cmd == SOUND_MIXER_AGC)
544 {
545 if (get_user(val, p))
546 return -EFAULT;
547 sb_setmixer(devc, 0x43, (~val) & 0x01);
548 return 0;
549 }
550 if (cmd == SOUND_MIXER_3DSE)
551 {
552
553
554 if (devc->minor < 15)
555 return -EINVAL;
556 if (get_user(val, p))
557 return -EFAULT;
558 if (val == 0 || val == 1)
559 sb_chgmixer(devc, AWE_3DSE, 0x01, val);
560 else if (val == 2)
561 {
562 ret = sb_getmixer(devc, AWE_3DSE)&0x01;
563 return put_user(ret, p);
564 }
565 else
566 return -EINVAL;
567 return 0;
568 }
569 }
570 if (((cmd >> 8) & 0xff) == 'M')
571 {
572 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
573 {
574 if (get_user(val, p))
575 return -EFAULT;
576 switch (cmd & 0xff)
577 {
578 case SOUND_MIXER_RECSRC:
579 ret = set_recmask(devc, val);
580 break;
581
582 case SOUND_MIXER_OUTSRC:
583 ret = set_outmask(devc, val);
584 break;
585
586 default:
587 ret = sb_mixer_set(devc, cmd & 0xff, val);
588 }
589 }
590 else switch (cmd & 0xff)
591 {
592 case SOUND_MIXER_RECSRC:
593 ret = devc->recmask;
594 break;
595
596 case SOUND_MIXER_OUTSRC:
597 ret = devc->outmask;
598 break;
599
600 case SOUND_MIXER_DEVMASK:
601 ret = devc->supported_devices;
602 break;
603
604 case SOUND_MIXER_STEREODEVS:
605 ret = devc->supported_devices;
606
607 if (devc->model == MDL_ESS)
608 ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX);
609 else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
610 ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
611 break;
612
613 case SOUND_MIXER_RECMASK:
614 ret = devc->supported_rec_devices;
615 break;
616
617 case SOUND_MIXER_OUTMASK:
618 ret = devc->supported_out_devices;
619 break;
620
621 case SOUND_MIXER_CAPS:
622 ret = devc->mixer_caps;
623 break;
624
625 default:
626 ret = sb_mixer_get(devc, cmd & 0xff);
627 break;
628 }
629 return put_user(ret, p);
630 } else
631 return -EINVAL;
632}
633
634static struct mixer_operations sb_mixer_operations =
635{
636 .owner = THIS_MODULE,
637 .id = "SB",
638 .name = "Sound Blaster",
639 .ioctl = sb_mixer_ioctl
640};
641
642static struct mixer_operations als007_mixer_operations =
643{
644 .owner = THIS_MODULE,
645 .id = "ALS007",
646 .name = "Avance ALS-007",
647 .ioctl = sb_mixer_ioctl
648};
649
650static void sb_mixer_reset(sb_devc * devc)
651{
652 char name[32];
653 int i;
654
655 sprintf(name, "SB_%d", devc->sbmixnum);
656
657 if (devc->sbmo.sm_games)
658 devc->levels = load_mixer_volumes(name, smg_default_levels, 1);
659 else
660 devc->levels = load_mixer_volumes(name, sb_default_levels, 1);
661
662 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
663 sb_mixer_set(devc, i, devc->levels[i]);
664
665 if (devc->model != MDL_ESS || !ess_mixer_reset (devc)) {
666 set_recmask(devc, SOUND_MASK_MIC);
667 };
668}
669
670int sb_mixer_init(sb_devc * devc, struct module *owner)
671{
672 int mixer_type = 0;
673 int m;
674
675 devc->sbmixnum = sbmixnum++;
676 devc->levels = NULL;
677
678 sb_setmixer(devc, 0x00, 0);
679
680 if (!(mixer_type = detect_mixer(devc)))
681 return 0;
682
683 switch (devc->model)
684 {
685 case MDL_ESSPCI:
686 case MDL_YMPCI:
687 case MDL_SBPRO:
688 case MDL_AZTECH:
689 case MDL_JAZZ:
690 devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
691 devc->supported_devices = SBPRO_MIXER_DEVICES;
692 devc->supported_rec_devices = SBPRO_RECORDING_DEVICES;
693 devc->iomap = &sbpro_mix;
694 devc->iomap_sz = ARRAY_SIZE(sbpro_mix);
695 break;
696
697 case MDL_ESS:
698 ess_mixer_init (devc);
699 break;
700
701 case MDL_SMW:
702 devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
703 devc->supported_devices = 0;
704 devc->supported_rec_devices = 0;
705 devc->iomap = &sbpro_mix;
706 devc->iomap_sz = ARRAY_SIZE(sbpro_mix);
707 smw_mixer_init(devc);
708 break;
709
710 case MDL_SB16:
711 devc->mixer_caps = 0;
712 devc->supported_rec_devices = SB16_RECORDING_DEVICES;
713 devc->supported_out_devices = SB16_OUTFILTER_DEVICES;
714 if (devc->submodel != SUBMDL_ALS007)
715 {
716 devc->supported_devices = SB16_MIXER_DEVICES;
717 devc->iomap = &sb16_mix;
718 devc->iomap_sz = ARRAY_SIZE(sb16_mix);
719 }
720 else
721 {
722 devc->supported_devices = ALS007_MIXER_DEVICES;
723 devc->iomap = &als007_mix;
724 devc->iomap_sz = ARRAY_SIZE(als007_mix);
725 }
726 break;
727
728 default:
729 printk(KERN_WARNING "sb_mixer: Unsupported mixer type %d\n", devc->model);
730 return 0;
731 }
732
733 m = sound_alloc_mixerdev();
734 if (m == -1)
735 return 0;
736
737 mixer_devs[m] = kmalloc(sizeof(struct mixer_operations), GFP_KERNEL);
738 if (mixer_devs[m] == NULL)
739 {
740 printk(KERN_ERR "sb_mixer: Can't allocate memory\n");
741 sound_unload_mixerdev(m);
742 return 0;
743 }
744
745 if (devc->submodel != SUBMDL_ALS007)
746 memcpy ((char *) mixer_devs[m], (char *) &sb_mixer_operations, sizeof (struct mixer_operations));
747 else
748 memcpy ((char *) mixer_devs[m], (char *) &als007_mixer_operations, sizeof (struct mixer_operations));
749
750 mixer_devs[m]->devc = devc;
751
752 if (owner)
753 mixer_devs[m]->owner = owner;
754
755 devc->my_mixerdev = m;
756 sb_mixer_reset(devc);
757 return 1;
758}
759
760void sb_mixer_unload(sb_devc *devc)
761{
762 if (devc->my_mixerdev == -1)
763 return;
764
765 kfree(mixer_devs[devc->my_mixerdev]);
766 sound_unload_mixerdev(devc->my_mixerdev);
767 sbmixnum--;
768}
769