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 <linux/slab.h>
21 #include "sound_config.h"
23 #define __SB_MIXER_C__
30 #define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD)
32 /* Same as SB Pro, unless I find otherwise */
33 #define SGNXPRO_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
35 #define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \
36 SOUND_MASK_CD | SOUND_MASK_VOLUME)
38 /* SG NX Pro has treble and bass settings on the mixer. The 'speaker'
39 * channel is the COVOX/DisneySoundSource emulation volume control
40 * on the mixer. It does NOT control speaker volume. Should have own
43 #define SGNXPRO_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_BASS| \
44 SOUND_MASK_TREBLE|SOUND_MASK_SPEAKER )
46 #define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \
49 #define SB16_OUTFILTER_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | \
52 #define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
54 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
55 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | \
58 /* These are the only devices that are working at the moment. Others could
59 * be added once they are identified and a method is found to control them.
61 #define ALS007_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | \
62 SOUND_MASK_PCM | SOUND_MASK_MIC | \
66 static mixer_tab sbpro_mix
= {
67 MIX_ENT(SOUND_MIXER_VOLUME
, 0x22, 7, 4, 0x22, 3, 4),
68 MIX_ENT(SOUND_MIXER_BASS
, 0x00, 0, 0, 0x00, 0, 0),
69 MIX_ENT(SOUND_MIXER_TREBLE
, 0x00, 0, 0, 0x00, 0, 0),
70 MIX_ENT(SOUND_MIXER_SYNTH
, 0x26, 7, 4, 0x26, 3, 4),
71 MIX_ENT(SOUND_MIXER_PCM
, 0x04, 7, 4, 0x04, 3, 4),
72 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x00, 0, 0, 0x00, 0, 0),
73 MIX_ENT(SOUND_MIXER_LINE
, 0x2e, 7, 4, 0x2e, 3, 4),
74 MIX_ENT(SOUND_MIXER_MIC
, 0x0a, 2, 3, 0x00, 0, 0),
75 MIX_ENT(SOUND_MIXER_CD
, 0x28, 7, 4, 0x28, 3, 4),
76 MIX_ENT(SOUND_MIXER_IMIX
, 0x00, 0, 0, 0x00, 0, 0),
77 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
78 MIX_ENT(SOUND_MIXER_RECLEV
, 0x00, 0, 0, 0x00, 0, 0)
81 static mixer_tab sb16_mix
= {
82 MIX_ENT(SOUND_MIXER_VOLUME
, 0x30, 7, 5, 0x31, 7, 5),
83 MIX_ENT(SOUND_MIXER_BASS
, 0x46, 7, 4, 0x47, 7, 4),
84 MIX_ENT(SOUND_MIXER_TREBLE
, 0x44, 7, 4, 0x45, 7, 4),
85 MIX_ENT(SOUND_MIXER_SYNTH
, 0x34, 7, 5, 0x35, 7, 5),
86 MIX_ENT(SOUND_MIXER_PCM
, 0x32, 7, 5, 0x33, 7, 5),
87 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x3b, 7, 2, 0x00, 0, 0),
88 MIX_ENT(SOUND_MIXER_LINE
, 0x38, 7, 5, 0x39, 7, 5),
89 MIX_ENT(SOUND_MIXER_MIC
, 0x3a, 7, 5, 0x00, 0, 0),
90 MIX_ENT(SOUND_MIXER_CD
, 0x36, 7, 5, 0x37, 7, 5),
91 MIX_ENT(SOUND_MIXER_IMIX
, 0x3c, 0, 1, 0x00, 0, 0),
92 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
93 MIX_ENT(SOUND_MIXER_RECLEV
, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */
94 MIX_ENT(SOUND_MIXER_IGAIN
, 0x3f, 7, 2, 0x40, 7, 2),
95 MIX_ENT(SOUND_MIXER_OGAIN
, 0x41, 7, 2, 0x42, 7, 2)
98 static mixer_tab als007_mix
=
100 MIX_ENT(SOUND_MIXER_VOLUME
, 0x62, 7, 4, 0x62, 3, 4),
101 MIX_ENT(SOUND_MIXER_BASS
, 0x00, 0, 0, 0x00, 0, 0),
102 MIX_ENT(SOUND_MIXER_TREBLE
, 0x00, 0, 0, 0x00, 0, 0),
103 MIX_ENT(SOUND_MIXER_SYNTH
, 0x66, 7, 4, 0x66, 3, 4),
104 MIX_ENT(SOUND_MIXER_PCM
, 0x64, 7, 4, 0x64, 3, 4),
105 MIX_ENT(SOUND_MIXER_SPEAKER
, 0x00, 0, 0, 0x00, 0, 0),
106 MIX_ENT(SOUND_MIXER_LINE
, 0x6e, 7, 4, 0x6e, 3, 4),
107 MIX_ENT(SOUND_MIXER_MIC
, 0x6a, 2, 3, 0x00, 0, 0),
108 MIX_ENT(SOUND_MIXER_CD
, 0x68, 7, 4, 0x68, 3, 4),
109 MIX_ENT(SOUND_MIXER_IMIX
, 0x00, 0, 0, 0x00, 0, 0),
110 MIX_ENT(SOUND_MIXER_ALTPCM
, 0x00, 0, 0, 0x00, 0, 0),
111 MIX_ENT(SOUND_MIXER_RECLEV
, 0x00, 0, 0, 0x00, 0, 0), /* Obsolete. Use IGAIN */
112 MIX_ENT(SOUND_MIXER_IGAIN
, 0x00, 0, 0, 0x00, 0, 0),
113 MIX_ENT(SOUND_MIXER_OGAIN
, 0x00, 0, 0, 0x00, 0, 0)
117 /* SM_GAMES Master volume is lower and PCM & FM volumes
118 higher than with SB Pro. This improves the
121 static int smg_default_levels
[32] =
123 0x2020, /* Master Volume */
128 0x4b4b, /* PC Speaker */
129 0x4b4b, /* Ext Line */
132 0x4b4b, /* Recording monitor */
134 0x4b4b, /* Recording level */
135 0x4b4b, /* Input gain */
136 0x4b4b, /* Output gain */
142 static int sb_default_levels
[32] =
144 0x5a5a, /* Master Volume */
149 0x4b4b, /* PC Speaker */
150 0x4b4b, /* Ext Line */
153 0x0000, /* Recording monitor */
155 0x4b4b, /* Recording level */
156 0x4b4b, /* Input gain */
157 0x4b4b, /* Output gain */
163 static unsigned char sb16_recmasks_L
[SOUND_MIXER_NRDEVICES
] =
165 0x00, /* SOUND_MIXER_VOLUME */
166 0x00, /* SOUND_MIXER_BASS */
167 0x00, /* SOUND_MIXER_TREBLE */
168 0x40, /* SOUND_MIXER_SYNTH */
169 0x00, /* SOUND_MIXER_PCM */
170 0x00, /* SOUND_MIXER_SPEAKER */
171 0x10, /* SOUND_MIXER_LINE */
172 0x01, /* SOUND_MIXER_MIC */
173 0x04, /* SOUND_MIXER_CD */
174 0x00, /* SOUND_MIXER_IMIX */
175 0x00, /* SOUND_MIXER_ALTPCM */
176 0x00, /* SOUND_MIXER_RECLEV */
177 0x00, /* SOUND_MIXER_IGAIN */
178 0x00 /* SOUND_MIXER_OGAIN */
181 static unsigned char sb16_recmasks_R
[SOUND_MIXER_NRDEVICES
] =
183 0x00, /* SOUND_MIXER_VOLUME */
184 0x00, /* SOUND_MIXER_BASS */
185 0x00, /* SOUND_MIXER_TREBLE */
186 0x20, /* SOUND_MIXER_SYNTH */
187 0x00, /* SOUND_MIXER_PCM */
188 0x00, /* SOUND_MIXER_SPEAKER */
189 0x08, /* SOUND_MIXER_LINE */
190 0x01, /* SOUND_MIXER_MIC */
191 0x02, /* SOUND_MIXER_CD */
192 0x00, /* SOUND_MIXER_IMIX */
193 0x00, /* SOUND_MIXER_ALTPCM */
194 0x00, /* SOUND_MIXER_RECLEV */
195 0x00, /* SOUND_MIXER_IGAIN */
196 0x00 /* SOUND_MIXER_OGAIN */
199 static char smw_mix_regs
[] = /* Left mixer registers */
201 0x0b, /* SOUND_MIXER_VOLUME */
202 0x0d, /* SOUND_MIXER_BASS */
203 0x0d, /* SOUND_MIXER_TREBLE */
204 0x05, /* SOUND_MIXER_SYNTH */
205 0x09, /* SOUND_MIXER_PCM */
206 0x00, /* SOUND_MIXER_SPEAKER */
207 0x03, /* SOUND_MIXER_LINE */
208 0x01, /* SOUND_MIXER_MIC */
209 0x07, /* SOUND_MIXER_CD */
210 0x00, /* SOUND_MIXER_IMIX */
211 0x00, /* SOUND_MIXER_ALTPCM */
212 0x00, /* SOUND_MIXER_RECLEV */
213 0x00, /* SOUND_MIXER_IGAIN */
214 0x00, /* SOUND_MIXER_OGAIN */
215 0x00, /* SOUND_MIXER_LINE1 */
216 0x00, /* SOUND_MIXER_LINE2 */
217 0x00 /* SOUND_MIXER_LINE3 */
220 static int sbmixnum
= 1;
222 static void sb_mixer_reset(sb_devc
* devc
);
224 void sb_mixer_set_stereo(sb_devc
* devc
, int mode
)
226 sb_chgmixer(devc
, OUT_FILTER
, STEREO_DAC
, (mode
? STEREO_DAC
: MONO_DAC
));
229 static int detect_mixer(sb_devc
* devc
)
231 /* Just trust the mixer is there */
235 static void change_bits(sb_devc
* devc
, unsigned char *regval
, int dev
, int chn
, int newval
)
240 mask
= (1 << (*devc
->iomap
)[dev
][chn
].nbits
) - 1;
241 newval
= (int) ((newval
* mask
) + 50) / 100; /* Scale */
243 shift
= (*devc
->iomap
)[dev
][chn
].bitoffs
- (*devc
->iomap
)[dev
][LEFT_CHN
].nbits
+ 1;
245 *regval
&= ~(mask
<< shift
); /* Mask out previous value */
246 *regval
|= (newval
& mask
) << shift
; /* Set the new value */
249 static int sb_mixer_get(sb_devc
* devc
, int dev
)
251 if (!((1 << dev
) & devc
->supported_devices
))
253 return devc
->levels
[dev
];
256 void smw_mixer_init(sb_devc
* devc
)
260 sb_setmixer(devc
, 0x00, 0x18); /* Mute unused (Telephone) line */
261 sb_setmixer(devc
, 0x10, 0x38); /* Config register 2 */
263 devc
->supported_devices
= 0;
264 for (i
= 0; i
< sizeof(smw_mix_regs
); i
++)
265 if (smw_mix_regs
[i
] != 0)
266 devc
->supported_devices
|= (1 << i
);
268 devc
->supported_rec_devices
= devc
->supported_devices
&
269 ~(SOUND_MASK_BASS
| SOUND_MASK_TREBLE
| SOUND_MASK_PCM
| SOUND_MASK_VOLUME
);
270 sb_mixer_reset(devc
);
273 int sb_common_mixer_set(sb_devc
* devc
, int dev
, int left
, int right
)
278 if ((dev
< 0) || (dev
>= devc
->iomap_sz
))
281 regoffs
= (*devc
->iomap
)[dev
][LEFT_CHN
].regno
;
286 val
= sb_getmixer(devc
, regoffs
);
287 change_bits(devc
, &val
, dev
, LEFT_CHN
, left
);
289 if ((*devc
->iomap
)[dev
][RIGHT_CHN
].regno
!= regoffs
) /*
293 sb_setmixer(devc
, regoffs
, val
); /*
296 regoffs
= (*devc
->iomap
)[dev
][RIGHT_CHN
].regno
;
299 return left
| (left
<< 8); /*
300 * Just left channel present
303 val
= sb_getmixer(devc
, regoffs
); /*
307 change_bits(devc
, &val
, dev
, RIGHT_CHN
, right
);
309 sb_setmixer(devc
, regoffs
, val
);
311 return left
| (right
<< 8);
314 static int smw_mixer_set(sb_devc
* devc
, int dev
, int left
, int right
)
320 case SOUND_MIXER_VOLUME
:
321 sb_setmixer(devc
, 0x0b, 96 - (96 * left
/ 100)); /* 96=mute, 0=max */
322 sb_setmixer(devc
, 0x0c, 96 - (96 * right
/ 100));
325 case SOUND_MIXER_BASS
:
326 case SOUND_MIXER_TREBLE
:
327 devc
->levels
[dev
] = left
| (right
<< 8);
328 /* Set left bass and treble values */
329 val
= ((devc
->levels
[SOUND_MIXER_TREBLE
] & 0xff) * 16 / (unsigned) 100) << 4;
330 val
|= ((devc
->levels
[SOUND_MIXER_BASS
] & 0xff) * 16 / (unsigned) 100) & 0x0f;
331 sb_setmixer(devc
, 0x0d, val
);
333 /* Set right bass and treble values */
334 val
= (((devc
->levels
[SOUND_MIXER_TREBLE
] >> 8) & 0xff) * 16 / (unsigned) 100) << 4;
335 val
|= (((devc
->levels
[SOUND_MIXER_BASS
] >> 8) & 0xff) * 16 / (unsigned) 100) & 0x0f;
336 sb_setmixer(devc
, 0x0e, val
);
342 if (dev
< 0 || dev
>= ARRAY_SIZE(smw_mix_regs
))
344 reg
= smw_mix_regs
[dev
];
347 sb_setmixer(devc
, reg
, (24 - (24 * left
/ 100)) | 0x20); /* 24=mute, 0=max */
348 sb_setmixer(devc
, reg
+ 1, (24 - (24 * right
/ 100)) | 0x40);
351 devc
->levels
[dev
] = left
| (right
<< 8);
352 return left
| (right
<< 8);
355 static int sb_mixer_set(sb_devc
* devc
, int dev
, int value
)
357 int left
= value
& 0x000000ff;
358 int right
= (value
& 0x0000ff00) >> 8;
366 if ((dev
< 0) || (dev
> 31))
369 if (!(devc
->supported_devices
& (1 << dev
))) /*
374 /* Differentiate depending on the chipsets */
375 switch (devc
->model
) {
377 retval
= smw_mixer_set(devc
, dev
, left
, right
);
380 retval
= ess_mixer_set(devc
, dev
, left
, right
);
383 retval
= sb_common_mixer_set(devc
, dev
, left
, right
);
385 if (retval
>= 0) devc
->levels
[dev
] = retval
;
391 * set_recsrc doesn't apply to ES188x
393 static void set_recsrc(sb_devc
* devc
, int src
)
395 sb_setmixer(devc
, RECORD_SRC
, (sb_getmixer(devc
, RECORD_SRC
) & ~7) | (src
& 0x7));
398 static int set_recmask(sb_devc
* devc
, int mask
)
401 unsigned char regimageL
, regimageR
;
403 devmask
= mask
& devc
->supported_rec_devices
;
411 if (devc
->model
== MDL_ESS
&& ess_set_recmask (devc
, &devmask
)) {
414 if (devmask
!= SOUND_MASK_MIC
&&
415 devmask
!= SOUND_MASK_LINE
&&
416 devmask
!= SOUND_MASK_CD
)
419 * More than one device selected. Drop the
422 devmask
&= ~devc
->recmask
;
424 if (devmask
!= SOUND_MASK_MIC
&&
425 devmask
!= SOUND_MASK_LINE
&&
426 devmask
!= SOUND_MASK_CD
)
429 * More than one device selected. Default to
432 devmask
= SOUND_MASK_MIC
;
434 if (devmask
^ devc
->recmask
) /*
435 * Input source changed
441 set_recsrc(devc
, SRC__MIC
);
444 case SOUND_MASK_LINE
:
445 set_recsrc(devc
, SRC__LINE
);
449 set_recsrc(devc
, SRC__CD
);
453 set_recsrc(devc
, SRC__MIC
);
460 devmask
= SOUND_MASK_MIC
;
462 if (devc
->submodel
== SUBMDL_ALS007
)
466 case SOUND_MASK_LINE
:
467 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_LINE
);
470 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_CD
);
472 case SOUND_MASK_SYNTH
:
473 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_SYNTH
);
475 default: /* Also takes care of SOUND_MASK_MIC case */
476 sb_setmixer(devc
, ALS007_RECORD_SRC
, ALS007_MIC
);
482 regimageL
= regimageR
= 0;
483 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
485 if ((1 << i
) & devmask
)
487 regimageL
|= sb16_recmasks_L
[i
];
488 regimageR
|= sb16_recmasks_R
[i
];
490 sb_setmixer (devc
, SB16_IMASK_L
, regimageL
);
491 sb_setmixer (devc
, SB16_IMASK_R
, regimageR
);
496 devc
->recmask
= devmask
;
497 return devc
->recmask
;
500 static int set_outmask(sb_devc
* devc
, int mask
)
503 unsigned char regimage
;
505 devmask
= mask
& devc
->supported_out_devices
;
510 if (devc
->submodel
== SUBMDL_ALS007
)
515 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
517 if ((1 << i
) & devmask
)
519 regimage
|= (sb16_recmasks_L
[i
] | sb16_recmasks_R
[i
]);
521 sb_setmixer (devc
, SB16_OMASK
, regimage
);
529 devc
->outmask
= devmask
;
530 return devc
->outmask
;
533 static int sb_mixer_ioctl(int dev
, unsigned int cmd
, void __user
*arg
)
535 sb_devc
*devc
= mixer_devs
[dev
]->devc
;
540 * Use ioctl(fd, SOUND_MIXER_AGC, &mode) to turn AGC off (0) or on (1).
541 * Use ioctl(fd, SOUND_MIXER_3DSE, &mode) to turn 3DSE off (0) or on (1)
542 * or mode==2 put 3DSE state to mode.
544 if (devc
->model
== MDL_SB16
) {
545 if (cmd
== SOUND_MIXER_AGC
)
547 if (get_user(val
, p
))
549 sb_setmixer(devc
, 0x43, (~val
) & 0x01);
552 if (cmd
== SOUND_MIXER_3DSE
)
554 /* I put here 15, but I don't know the exact version.
555 At least my 4.13 havn't 3DSE, 4.16 has it. */
556 if (devc
->minor
< 15)
558 if (get_user(val
, p
))
560 if (val
== 0 || val
== 1)
561 sb_chgmixer(devc
, AWE_3DSE
, 0x01, val
);
564 ret
= sb_getmixer(devc
, AWE_3DSE
)&0x01;
565 return put_user(ret
, p
);
572 if (((cmd
>> 8) & 0xff) == 'M')
574 if (_SIOC_DIR(cmd
) & _SIOC_WRITE
)
576 if (get_user(val
, p
))
580 case SOUND_MIXER_RECSRC
:
581 ret
= set_recmask(devc
, val
);
584 case SOUND_MIXER_OUTSRC
:
585 ret
= set_outmask(devc
, val
);
589 ret
= sb_mixer_set(devc
, cmd
& 0xff, val
);
592 else switch (cmd
& 0xff)
594 case SOUND_MIXER_RECSRC
:
598 case SOUND_MIXER_OUTSRC
:
602 case SOUND_MIXER_DEVMASK
:
603 ret
= devc
->supported_devices
;
606 case SOUND_MIXER_STEREODEVS
:
607 ret
= devc
->supported_devices
;
608 /* The ESS seems to have stereo mic controls */
609 if (devc
->model
== MDL_ESS
)
610 ret
&= ~(SOUND_MASK_SPEAKER
|SOUND_MASK_IMIX
);
611 else if (devc
->model
!= MDL_JAZZ
&& devc
->model
!= MDL_SMW
)
612 ret
&= ~(SOUND_MASK_MIC
| SOUND_MASK_SPEAKER
| SOUND_MASK_IMIX
);
615 case SOUND_MIXER_RECMASK
:
616 ret
= devc
->supported_rec_devices
;
619 case SOUND_MIXER_OUTMASK
:
620 ret
= devc
->supported_out_devices
;
623 case SOUND_MIXER_CAPS
:
624 ret
= devc
->mixer_caps
;
628 ret
= sb_mixer_get(devc
, cmd
& 0xff);
631 return put_user(ret
, p
);
636 static struct mixer_operations sb_mixer_operations
=
638 .owner
= THIS_MODULE
,
640 .name
= "Sound Blaster",
641 .ioctl
= sb_mixer_ioctl
644 static struct mixer_operations als007_mixer_operations
=
646 .owner
= THIS_MODULE
,
648 .name
= "Avance ALS-007",
649 .ioctl
= sb_mixer_ioctl
652 static void sb_mixer_reset(sb_devc
* devc
)
657 sprintf(name
, "SB_%d", devc
->sbmixnum
);
659 if (devc
->sbmo
.sm_games
)
660 devc
->levels
= load_mixer_volumes(name
, smg_default_levels
, 1);
662 devc
->levels
= load_mixer_volumes(name
, sb_default_levels
, 1);
664 for (i
= 0; i
< SOUND_MIXER_NRDEVICES
; i
++)
665 sb_mixer_set(devc
, i
, devc
->levels
[i
]);
667 if (devc
->model
!= MDL_ESS
|| !ess_mixer_reset (devc
)) {
668 set_recmask(devc
, SOUND_MASK_MIC
);
672 int sb_mixer_init(sb_devc
* devc
, struct module
*owner
)
677 devc
->sbmixnum
= sbmixnum
++;
680 sb_setmixer(devc
, 0x00, 0); /* Reset mixer */
682 if (!(mixer_type
= detect_mixer(devc
)))
683 return 0; /* No mixer. Why? */
692 devc
->mixer_caps
= SOUND_CAP_EXCL_INPUT
;
693 devc
->supported_devices
= SBPRO_MIXER_DEVICES
;
694 devc
->supported_rec_devices
= SBPRO_RECORDING_DEVICES
;
695 devc
->iomap
= &sbpro_mix
;
696 devc
->iomap_sz
= ARRAY_SIZE(sbpro_mix
);
700 ess_mixer_init (devc
);
704 devc
->mixer_caps
= SOUND_CAP_EXCL_INPUT
;
705 devc
->supported_devices
= 0;
706 devc
->supported_rec_devices
= 0;
707 devc
->iomap
= &sbpro_mix
;
708 devc
->iomap_sz
= ARRAY_SIZE(sbpro_mix
);
709 smw_mixer_init(devc
);
713 devc
->mixer_caps
= 0;
714 devc
->supported_rec_devices
= SB16_RECORDING_DEVICES
;
715 devc
->supported_out_devices
= SB16_OUTFILTER_DEVICES
;
716 if (devc
->submodel
!= SUBMDL_ALS007
)
718 devc
->supported_devices
= SB16_MIXER_DEVICES
;
719 devc
->iomap
= &sb16_mix
;
720 devc
->iomap_sz
= ARRAY_SIZE(sb16_mix
);
724 devc
->supported_devices
= ALS007_MIXER_DEVICES
;
725 devc
->iomap
= &als007_mix
;
726 devc
->iomap_sz
= ARRAY_SIZE(als007_mix
);
731 printk(KERN_WARNING
"sb_mixer: Unsupported mixer type %d\n", devc
->model
);
735 m
= sound_alloc_mixerdev();
739 mixer_devs
[m
] = kmalloc(sizeof(struct mixer_operations
), GFP_KERNEL
);
740 if (mixer_devs
[m
] == NULL
)
742 printk(KERN_ERR
"sb_mixer: Can't allocate memory\n");
743 sound_unload_mixerdev(m
);
747 if (devc
->submodel
!= SUBMDL_ALS007
)
748 memcpy ((char *) mixer_devs
[m
], (char *) &sb_mixer_operations
, sizeof (struct mixer_operations
));
750 memcpy ((char *) mixer_devs
[m
], (char *) &als007_mixer_operations
, sizeof (struct mixer_operations
));
752 mixer_devs
[m
]->devc
= devc
;
755 mixer_devs
[m
]->owner
= owner
;
757 devc
->my_mixerdev
= m
;
758 sb_mixer_reset(devc
);
762 void sb_mixer_unload(sb_devc
*devc
)
764 if (devc
->my_mixerdev
== -1)
767 kfree(mixer_devs
[devc
->my_mixerdev
]);
768 sound_unload_mixerdev(devc
->my_mixerdev
);