4 * The low level mixer driver for the Sound Blaster compatible cards.
7 * Copyright (C) by Hannu Savolainen 1993-1997
9 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
10 * Version 2 (June 1991). See the "COPYING" file distributed with this software
14 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
15 * Rolf Fokkens (Dec 20 1998) : Moved ESS stuff into sb_ess.[ch]
16 * Stanislav Voronyi <stas@esc.kharkov.com> : Support for AWE 3DSE device (Jun 7 1999)
19 #include "sound_config.h"
21 #define __SB_MIXER_C__
28 #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
30 /* Same as SB Pro, unless I find otherwise */
31 #define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
33 #define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
34 SOUND_MASK_CD | SOUND_MASK_VOLUME)
36 /* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
37 * channel is the COVOX/DisneySoundSource emulation volume control
38 * on the mixer. It does NOT control speaker volume. Should have own
41 #define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
42 SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
44 #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
47 #define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
50 #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
52 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
53 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
56 /* These are the only devices that are working at the moment. Others could
57 * be added once they are identified and a method is found to control them.
59 #define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \
60 SOUND_MASK_PCM | SOUND_MASK_MIC | \
64 static mixer_tab sbpro_mix
= {
65 MIX_ENT(SOUND_MIXER_VOLUME
, 0x22, 7, 4, 0x22, 3, 4),
66 MIX_ENT(SOUND_MIXER_BASS
, 0x00, 0, 0, 0x00, 0, 0),
67 MIX_ENT(SOUND_MIXER_TREBLE
, 0x00, 0, 0, 0x00, 0, 0),
68 MIX_ENT(SOUND_MIXER_SYNTH
, 0x26, 7, 4, 0x26, 3, 4),
69 MIX_ENT(SOUND_MIXER_PCM
, 0x04, 7, 4, 0x04, 3, 4),
70 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x00, 0, 0, 0x00, 0, 0),
71 MIX_ENT(SOUND_MIXER_LINE
, 0x2e, 7, 4, 0x2e, 3, 4),
72 MIX_ENT(SOUND_MIXER_MIC
, 0x0a, 2, 3, 0x00, 0, 0),
73 MIX_ENT(SOUND_MIXER_CD
, 0x28, 7, 4, 0x28, 3, 4),
74 MIX_ENT(SOUND_MIXER_IMIX
, 0x00, 0, 0, 0x00, 0, 0),
75 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
76 MIX_ENT(SOUND_MIXER_RECLEV
, 0x00, 0, 0, 0x00, 0, 0)
79 static mixer_tab sb16_mix
= {
80 MIX_ENT(SOUND_MIXER_VOLUME
, 0x30, 7, 5, 0x31, 7, 5),
81 MIX_ENT(SOUND_MIXER_BASS
, 0x46, 7, 4, 0x47, 7, 4),
82 MIX_ENT(SOUND_MIXER_TREBLE
, 0x44, 7, 4, 0x45, 7, 4),
83 MIX_ENT(SOUND_MIXER_SYNTH
, 0x34, 7, 5, 0x35, 7, 5),
84 MIX_ENT(SOUND_MIXER_PCM
, 0x32, 7, 5, 0x33, 7, 5),
85 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x3b, 7, 2, 0x00, 0, 0),
86 MIX_ENT(SOUND_MIXER_LINE
, 0x38, 7, 5, 0x39, 7, 5),
87 MIX_ENT(SOUND_MIXER_MIC
, 0x3a, 7, 5, 0x00, 0, 0),
88 MIX_ENT(SOUND_MIXER_CD
, 0x36, 7, 5, 0x37, 7, 5),
89 MIX_ENT(SOUND_MIXER_IMIX
, 0x3c, 0, 1, 0x00, 0, 0),
90 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
91 MIX_ENT(SOUND_MIXER_RECLEV
, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
92 MIX_ENT(SOUND_MIXER_IGAIN
, 0x3f, 7, 2, 0x40, 7, 2),
93 MIX_ENT(SOUND_MIXER_OGAIN
, 0x41, 7, 2, 0x42, 7, 2)
96 static mixer_tab als007_mix
=
98 MIX_ENT(SOUND_MIXER_VOLUME
, 0x62, 7, 4, 0x62, 3, 4),
99 MIX_ENT(SOUND_MIXER_BASS
, 0x00, 0, 0, 0x00, 0, 0),
100 MIX_ENT(SOUND_MIXER_TREBLE
, 0x00, 0, 0, 0x00, 0, 0),
101 MIX_ENT(SOUND_MIXER_SYNTH
, 0x66, 7, 4, 0x66, 3, 4),
102 MIX_ENT(SOUND_MIXER_PCM
, 0x64, 7, 4, 0x64, 3, 4),
103 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x00, 0, 0, 0x00, 0, 0),
104 MIX_ENT(SOUND_MIXER_LINE
, 0x6e, 7, 4, 0x6e, 3, 4),
105 MIX_ENT(SOUND_MIXER_MIC
, 0x6a, 2, 3, 0x00, 0, 0),
106 MIX_ENT(SOUND_MIXER_CD
, 0x68, 7, 4, 0x68, 3, 4),
107 MIX_ENT(SOUND_MIXER_IMIX
, 0x00, 0, 0, 0x00, 0, 0),
108 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
109 MIX_ENT(SOUND_MIXER_RECLEV
, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */
110 MIX_ENT(SOUND_MIXER_IGAIN
, 0x00, 0, 0, 0x00, 0, 0),
111 MIX_ENT(SOUND_MIXER_OGAIN
, 0x00, 0, 0, 0x00, 0, 0)
115 /* SM_GAMES Master volume is lower and PCM & FM volumes
116 higher than with SB Pro. This improves the
119 static int smg_default_levels
[32] =
121 0x2020, /* Master Volume */
126 0x4b4b, /* PC Speaker */
127 0x4b4b, /* Ext Line */
130 0x4b4b, /* Recording monitor */
132 0x4b4b, /* Recording level */
133 0x4b4b, /* Input gain */
134 0x4b4b, /* Output gain */
140 static int sb_default_levels
[32] =
142 0x5a5a, /* Master Volume */
147 0x4b4b, /* PC Speaker */
148 0x4b4b, /* Ext Line */
151 0x0000, /* Recording monitor */
153 0x4b4b, /* Recording level */
154 0x4b4b, /* Input gain */
155 0x4b4b, /* Output gain */
161 static unsigned char sb16_recmasks_L
[SOUND_MIXER_NRDEVICES
] =
163 0x00, /* SOUND_MIXER_VOLUME */
164 0x00, /* SOUND_MIXER_BASS */
165 0x00, /* SOUND_MIXER_TREBLE */
166 0x40, /* SOUND_MIXER_SYNTH */
167 0x00, /* SOUND_MIXER_PCM */
168 0x00, /* SOUND_MIXER_SPEAKER */
169 0x10, /* SOUND_MIXER_LINE */
170 0x01, /* SOUND_MIXER_MIC */
171 0x04, /* SOUND_MIXER_CD */
172 0x00, /* SOUND_MIXER_IMIX */
173 0x00, /* SOUND_MIXER_ALTPCM */
174 0x00, /* SOUND_MIXER_RECLEV */
175 0x00, /* SOUND_MIXER_IGAIN */
176 0x00 /* SOUND_MIXER_OGAIN */
179 static unsigned char sb16_recmasks_R
[SOUND_MIXER_NRDEVICES
] =
181 0x00, /* SOUND_MIXER_VOLUME */
182 0x00, /* SOUND_MIXER_BASS */
183 0x00, /* SOUND_MIXER_TREBLE */
184 0x20, /* SOUND_MIXER_SYNTH */
185 0x00, /* SOUND_MIXER_PCM */
186 0x00, /* SOUND_MIXER_SPEAKER */
187 0x08, /* SOUND_MIXER_LINE */
188 0x01, /* SOUND_MIXER_MIC */
189 0x02, /* SOUND_MIXER_CD */
190 0x00, /* SOUND_MIXER_IMIX */
191 0x00, /* SOUND_MIXER_ALTPCM */
192 0x00, /* SOUND_MIXER_RECLEV */
193 0x00, /* SOUND_MIXER_IGAIN */
194 0x00 /* SOUND_MIXER_OGAIN */
197 static char smw_mix_regs
[] = /* Left mixer registers */
199 0x0b, /* SOUND_MIXER_VOLUME */
200 0x0d, /* SOUND_MIXER_BASS */
201 0x0d, /* SOUND_MIXER_TREBLE */
202 0x05, /* SOUND_MIXER_SYNTH */
203 0x09, /* SOUND_MIXER_PCM */
204 0x00, /* SOUND_MIXER_SPEAKER */
205 0x03, /* SOUND_MIXER_LINE */
206 0x01, /* SOUND_MIXER_MIC */
207 0x07, /* SOUND_MIXER_CD */
208 0x00, /* SOUND_MIXER_IMIX */
209 0x00, /* SOUND_MIXER_ALTPCM */
210 0x00, /* SOUND_MIXER_RECLEV */
211 0x00, /* SOUND_MIXER_IGAIN */
212 0x00, /* SOUND_MIXER_OGAIN */
213 0x00, /* SOUND_MIXER_LINE1 */
214 0x00, /* SOUND_MIXER_LINE2 */
215 0x00 /* SOUND_MIXER_LINE3 */
218 static int sbmixnum
= 1;
220 static void sb_mixer_reset(sb_devc
* devc
);
222 void sb_mixer_set_stereo(sb_devc
* devc
, int mode
)
224 sb_chgmixer(devc
, OUT_FILTER
, STEREO_DAC
, (mode
? STEREO_DAC
: MONO_DAC
));
227 static int detect_mixer(sb_devc
* devc
)
229 /* Just trust the mixer is there */
233 static void change_bits(sb_devc
* devc
, unsigned char *regval
, int dev
, int chn
, int newval
)
238 mask
= (1 << (*devc
->iomap
)[dev
][chn
].nbits
) - 1;
239 newval
= (int) ((newval
* mask
) + 50) / 100; /* Scale */
241 shift
= (*devc
->iomap
)[dev
][chn
].bitoffs
- (*devc
->iomap
)[dev
][LEFT_CHN
].nbits
+ 1;
243 *regval
&= ~(mask
<< shift
); /* Mask out previous value */
244 *regval
|= (newval
& mask
) << shift
; /* Set the new value */
247 static int sb_mixer_get(sb_devc
* devc
, int dev
)
249 if (!((1 << dev
) & devc
->supported_devices
))
251 return devc
->levels
[dev
];
254 void smw_mixer_init(sb_devc
* devc
)
258 sb_setmixer(devc
, 0x00, 0x18); /* Mute unused (Telephone) line */
259 sb_setmixer(devc
, 0x10, 0x38); /* Config register 2 */
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
);
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
);
271 int sb_common_mixer_set(sb_devc
* devc
, int dev
, int left
, int right
)
276 regoffs
= (*devc
->iomap
)[dev
][LEFT_CHN
].regno
;
281 if ((dev
< 0) || (dev
>= devc
->iomap_sz
))
284 val
= sb_getmixer(devc
, regoffs
);
285 change_bits(devc
, &val
, dev
, LEFT_CHN
, left
);
287 if ((*devc
->iomap
)[dev
][RIGHT_CHN
].regno
!= regoffs
) /*
291 sb_setmixer(devc
, regoffs
, val
); /*
294 regoffs
= (*devc
->iomap
)[dev
][RIGHT_CHN
].regno
;
297 return left
| (left
<< 8); /*
298 * Just left channel present
301 val
= sb_getmixer(devc
, regoffs
); /*
305 change_bits(devc
, &val
, dev
, RIGHT_CHN
, right
);
307 sb_setmixer(devc
, regoffs
, val
);
309 return left
| (right
<< 8);
312 static int smw_mixer_set(sb_devc
* devc
, int dev
, int left
, int right
)
318 case SOUND_MIXER_VOLUME
:
319 sb_setmixer(devc
, 0x0b, 96 - (96 * left
/ 100)); /* 96=mute, 0=max */
320 sb_setmixer(devc
, 0x0c, 96 - (96 * right
/ 100));
323 case SOUND_MIXER_BASS
:
324 case SOUND_MIXER_TREBLE
:
325 devc
->levels
[dev
] = left
| (right
<< 8);
326 /* Set left bass and treble values */
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
);
331 /* Set right bass and treble values */
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
);
340 if (dev
< 0 || dev
>= ARRAY_SIZE(smw_mix_regs
))
342 reg
= smw_mix_regs
[dev
];
345 sb_setmixer(devc
, reg
, (24 - (24 * left
/ 100)) | 0x20); /* 24=mute, 0=max */
346 sb_setmixer(devc
, reg
+ 1, (24 - (24 * right
/ 100)) | 0x40);
349 devc
->levels
[dev
] = left
| (right
<< 8);
350 return left
| (right
<< 8);
353 static int sb_mixer_set(sb_devc
* devc
, int dev
, int value
)
355 int left
= value
& 0x000000ff;
356 int right
= (value
& 0x0000ff00) >> 8;
364 if ((dev
< 0) || (dev
> 31))
367 if (!(devc
->supported_devices
& (1 << dev
))) /*
372 /* Differentiate depending on the chipsets */
373 switch (devc
->model
) {
375 retval
= smw_mixer_set(devc
, dev
, left
, right
);
378 retval
= ess_mixer_set(devc
, dev
, left
, right
);
381 retval
= sb_common_mixer_set(devc
, dev
, left
, right
);
383 if (retval
>= 0) devc
->levels
[dev
] = retval
;
389 * set_recsrc doesn't apply to ES188x
391 static void set_recsrc(sb_devc
* devc
, int src
)
393 sb_setmixer(devc
, RECORD_SRC
, (sb_getmixer(devc
, RECORD_SRC
) & ~7) | (src
& 0x7));
396 static int set_recmask(sb_devc
* devc
, int mask
)
399 unsigned char regimageL
, regimageR
;
401 devmask
= mask
& devc
->supported_rec_devices
;
409 if (devc
->model
== MDL_ESS
&& ess_set_recmask (devc
, &devmask
)) {
412 if (devmask
!= SOUND_MASK_MIC
&&
413 devmask
!= SOUND_MASK_LINE
&&
414 devmask
!= SOUND_MASK_CD
)
417 * More than one device selected. Drop the
420 devmask
&= ~devc
->recmask
;
422 if (devmask
!= SOUND_MASK_MIC
&&
423 devmask
!= SOUND_MASK_LINE
&&
424 devmask
!= SOUND_MASK_CD
)
427 * More than one device selected. Default to
430 devmask
= SOUND_MASK_MIC
;
432 if (devmask
^ devc
->recmask
) /*
433 * Input source changed
439 set_recsrc(devc
, SRC__MIC
);
442 case SOUND_MASK_LINE
:
443 set_recsrc(devc
, SRC__LINE
);
447 set_recsrc(devc
, SRC__CD
);
451 set_recsrc(devc
, SRC__MIC
);
458 devmask
= SOUND_MASK_MIC
;
460 if (devc
->submodel
== SUBMDL_ALS007
)
464 case SOUND_MASK_LINE
:
465 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_LINE
);
468 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_CD
);
470 case SOUND_MASK_SYNTH
:
471 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_SYNTH
);
473 default: /* Also takes care of SOUND_MASK_MIC case */
474 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_MIC
);
480 regimageL
= regimageR
= 0;
481 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
483 if ((1 << i
) & devmask
)
485 regimageL
|= sb16_recmasks_L
[i
];
486 regimageR
|= sb16_recmasks_R
[i
];
488 sb_setmixer (devc
, SB16_IMASK_L
, regimageL
);
489 sb_setmixer (devc
, SB16_IMASK_R
, regimageR
);
494 devc
->recmask
= devmask
;
495 return devc
->recmask
;
498 static int set_outmask(sb_devc
* devc
, int mask
)
501 unsigned char regimage
;
503 devmask
= mask
& devc
->supported_out_devices
;
508 if (devc
->submodel
== SUBMDL_ALS007
)
513 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
515 if ((1 << i
) & devmask
)
517 regimage
|= (sb16_recmasks_L
[i
] | sb16_recmasks_R
[i
]);
519 sb_setmixer (devc
, SB16_OMASK
, regimage
);
527 devc
->outmask
= devmask
;
528 return devc
->outmask
;
531 static int sb_mixer_ioctl(int dev
, unsigned int cmd
, void __user
*arg
)
533 sb_devc
*devc
= mixer_devs
[dev
]->devc
;
538 * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1).
539 * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1)
540 * or mode==2 put 3DSE state to mode.
542 if (devc
->model
== MDL_SB16
) {
543 if (cmd
== SOUND_MIXER_AGC
)
545 if (get_user(val
, p
))
547 sb_setmixer(devc
, 0x43, (~val
) & 0x01);
550 if (cmd
== SOUND_MIXER_3DSE
)
552 /* I put here 15, but I don't know the exact version.
553 At least my 4.13 havn't 3DSE, 4.16 has it. */
554 if (devc
->minor
< 15)
556 if (get_user(val
, p
))
558 if (val
== 0 || val
== 1)
559 sb_chgmixer(devc
, AWE_3DSE
, 0x01, val
);
562 ret
= sb_getmixer(devc
, AWE_3DSE
)&0x01;
563 return put_user(ret
, p
);
570 if (((cmd
>> 8) & 0xff) == 'M')
572 if (_SIOC_DIR(cmd
) & _SIOC_WRITE
)
574 if (get_user(val
, p
))
578 case SOUND_MIXER_RECSRC
:
579 ret
= set_recmask(devc
, val
);
582 case SOUND_MIXER_OUTSRC
:
583 ret
= set_outmask(devc
, val
);
587 ret
= sb_mixer_set(devc
, cmd
& 0xff, val
);
590 else switch (cmd
& 0xff)
592 case SOUND_MIXER_RECSRC
:
596 case SOUND_MIXER_OUTSRC
:
600 case SOUND_MIXER_DEVMASK
:
601 ret
= devc
->supported_devices
;
604 case SOUND_MIXER_STEREODEVS
:
605 ret
= devc
->supported_devices
;
606 /* The ESS seems to have stereo mic controls */
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
);
613 case SOUND_MIXER_RECMASK
:
614 ret
= devc
->supported_rec_devices
;
617 case SOUND_MIXER_OUTMASK
:
618 ret
= devc
->supported_out_devices
;
621 case SOUND_MIXER_CAPS
:
622 ret
= devc
->mixer_caps
;
626 ret
= sb_mixer_get(devc
, cmd
& 0xff);
629 return put_user(ret
, p
);
634 static struct mixer_operations sb_mixer_operations
=
636 .owner
= THIS_MODULE
,
638 .name
= "Sound Blaster",
639 .ioctl
= sb_mixer_ioctl
642 static struct mixer_operations als007_mixer_operations
=
644 .owner
= THIS_MODULE
,
646 .name
= "Avance ALS-007",
647 .ioctl
= sb_mixer_ioctl
650 static void sb_mixer_reset(sb_devc
* devc
)
655 sprintf(name
, "SB_%d", devc
->sbmixnum
);
657 if (devc
->sbmo
.sm_games
)
658 devc
->levels
= load_mixer_volumes(name
, smg_default_levels
, 1);
660 devc
->levels
= load_mixer_volumes(name
, sb_default_levels
, 1);
662 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
663 sb_mixer_set(devc
, i
, devc
->levels
[i
]);
665 if (devc
->model
!= MDL_ESS
|| !ess_mixer_reset (devc
)) {
666 set_recmask(devc
, SOUND_MASK_MIC
);
670 int sb_mixer_init(sb_devc
* devc
, struct module
*owner
)
675 devc
->sbmixnum
= sbmixnum
++;
678 sb_setmixer(devc
, 0x00, 0); /* Reset mixer */
680 if (!(mixer_type
= detect_mixer(devc
)))
681 return 0; /* No mixer. Why? */
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
);
698 ess_mixer_init (devc
);
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
);
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
)
716 devc
->supported_devices
= SB16_MIXER_DEVICES
;
717 devc
->iomap
= &sb16_mix
;
718 devc
->iomap_sz
= ARRAY_SIZE(sb16_mix
);
722 devc
->supported_devices
= ALS007_MIXER_DEVICES
;
723 devc
->iomap
= &als007_mix
;
724 devc
->iomap_sz
= ARRAY_SIZE(als007_mix
);
729 printk(KERN_WARNING
"sb_mixer: Unsupported mixer type %d\n", devc
->model
);
733 m
= sound_alloc_mixerdev();
737 mixer_devs
[m
] = (struct mixer_operations
*)kmalloc(sizeof(struct mixer_operations
), GFP_KERNEL
);
738 if (mixer_devs
[m
] == NULL
)
740 printk(KERN_ERR
"sb_mixer: Can't allocate memory\n");
741 sound_unload_mixerdev(m
);
745 if (devc
->submodel
!= SUBMDL_ALS007
)
746 memcpy ((char *) mixer_devs
[m
], (char *) &sb_mixer_operations
, sizeof (struct mixer_operations
));
748 memcpy ((char *) mixer_devs
[m
], (char *) &als007_mixer_operations
, sizeof (struct mixer_operations
));
750 mixer_devs
[m
]->devc
= devc
;
753 mixer_devs
[m
]->owner
= owner
;
755 devc
->my_mixerdev
= m
;
756 sb_mixer_reset(devc
);
760 void sb_mixer_unload(sb_devc
*devc
)
762 if (devc
->my_mixerdev
== -1)
765 kfree(mixer_devs
[devc
->my_mixerdev
]);
766 sound_unload_mixerdev(devc
->my_mixerdev
);