4 * Driver for the ICS2101 mixer of GUS v3.7.
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 * Bartlomiej Zolnierkiewicz : added __init to ics2101_mixer_init()
17 #include <linux/init.h>
18 #include <linux/spinlock.h>
19 #include "sound_config.h"
21 #include <linux/ultrasound.h>
26 #define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \
28 SOUND_MASK_CD | SOUND_MASK_VOLUME)
32 extern spinlock_t gus_lock
;
33 static int volumes
[ICS_MIXDEVS
];
34 static int left_fix
[ICS_MIXDEVS
] =
36 static int right_fix
[ICS_MIXDEVS
] =
39 static int scale_vol(int vol
)
42 * Experimental volume scaling by Risto Kankkunen.
43 * This should give smoother volume response than just
44 * a plain multiplication.
53 vol
= (31 * vol
+ 50) / 100;
65 return ((e
<< 4) + vol
);
68 static void write_mix(int dev
, int chn
, int vol
)
72 int ctrl_addr
= dev
<< 3;
73 int attn_addr
= dev
<< 3;
90 spin_lock_irqsave(&gus_lock
, flags
);
91 outb((ctrl_addr
), u_MixSelect
);
92 outb((selector
[dev
]), u_MixData
);
93 outb((attn_addr
), u_MixSelect
);
94 outb(((unsigned char) vol
), u_MixData
);
95 spin_unlock_irqrestore(&gus_lock
,flags
);
98 static int set_volumes(int dev
, int vol
)
100 int left
= vol
& 0x00ff;
101 int right
= (vol
>> 8) & 0x00ff;
112 write_mix(dev
, CHN_LEFT
, left
);
113 write_mix(dev
, CHN_RIGHT
, right
);
115 vol
= left
+ (right
<< 8);
120 static int ics2101_mixer_ioctl(int dev
, unsigned int cmd
, void __user
*arg
)
124 if (((cmd
>> 8) & 0xff) == 'M') {
125 if (_SIOC_DIR(cmd
) & _SIOC_WRITE
) {
127 if (get_user(val
, (int __user
*)arg
))
129 switch (cmd
& 0xff) {
130 case SOUND_MIXER_RECSRC
:
131 return gus_default_mixer_ioctl(dev
, cmd
, arg
);
133 case SOUND_MIXER_MIC
:
134 val
= set_volumes(DEV_MIC
, val
);
138 val
= set_volumes(DEV_CD
, val
);
141 case SOUND_MIXER_LINE
:
142 val
= set_volumes(DEV_LINE
, val
);
145 case SOUND_MIXER_SYNTH
:
146 val
= set_volumes(DEV_GF1
, val
);
149 case SOUND_MIXER_VOLUME
:
150 val
= set_volumes(DEV_VOL
, val
);
156 return put_user(val
, (int __user
*)arg
);
158 switch (cmd
& 0xff) {
162 case SOUND_MIXER_RECSRC
:
163 return gus_default_mixer_ioctl(dev
, cmd
, arg
);
165 case SOUND_MIXER_DEVMASK
:
169 case SOUND_MIXER_STEREODEVS
:
170 val
= SOUND_MASK_LINE
| SOUND_MASK_CD
| SOUND_MASK_SYNTH
| SOUND_MASK_VOLUME
| SOUND_MASK_MIC
;
173 case SOUND_MIXER_RECMASK
:
174 val
= SOUND_MASK_MIC
| SOUND_MASK_LINE
;
177 case SOUND_MIXER_CAPS
:
181 case SOUND_MIXER_MIC
:
182 val
= volumes
[DEV_MIC
];
185 case SOUND_MIXER_LINE
:
186 val
= volumes
[DEV_LINE
];
190 val
= volumes
[DEV_CD
];
193 case SOUND_MIXER_VOLUME
:
194 val
= volumes
[DEV_VOL
];
197 case SOUND_MIXER_SYNTH
:
198 val
= volumes
[DEV_GF1
];
204 return put_user(val
, (int __user
*)arg
);
210 static struct mixer_operations ics2101_mixer_operations
=
212 .owner
= THIS_MODULE
,
214 .name
= "ICS2101 Multimedia Mixer",
215 .ioctl
= ics2101_mixer_ioctl
218 int __init
ics2101_mixer_init(void)
223 if ((n
= sound_alloc_mixerdev()) != -1)
225 mixer_devs
[n
] = &ics2101_mixer_operations
;
228 * Some GUS v3.7 cards had some channels flipped. Disable
229 * the flipping feature if the model id is other than 5.
232 if (inb(u_MixSelect
) != 5)
234 for (i
= 0; i
< ICS_MIXDEVS
; i
++)
236 for (i
= 0; i
< ICS_MIXDEVS
; i
++)
239 set_volumes(DEV_GF1
, 0x5a5a);
240 set_volumes(DEV_CD
, 0x5a5a);
241 set_volumes(DEV_MIC
, 0x0000);
242 set_volumes(DEV_LINE
, 0x5a5a);
243 set_volumes(DEV_VOL
, 0x5a5a);
244 set_volumes(DEV_UNUSED
, 0x0000);