source: sbliveos2/trunk/sblive/mixer.c@ 145

Last change on this file since 145 was 142, checked in by ktk, 25 years ago

Import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1/* $Id: mixer.c 142 2000-04-23 14:55:46Z ktk $ */
2
3
4/*
5 **********************************************************************
6 * mixer.c - /dev/mixer interface for emu10k1 driver
7 * Copyright 1999, 2000 Creative Labs, Inc.
8 *
9 * This program uses some code from es1371.c, Copyright 1998-1999
10 * Thomas Sailer
11 *
12 **********************************************************************
13 *
14 * Date Author Summary of changes
15 * ---- ------ ------------------
16 * October 20, 1999 Bertrand Lee base code release
17 * November 2, 1999 Alan Cox cleaned up stuff
18 *
19 **********************************************************************
20 *
21 * This program is free software; you can redistribute it and/or
22 * modify it under the terms of the GNU General Public License as
23 * published by the Free Software Foundation; either version 2 of
24 * the License, or (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public
32 * License along with this program; if not, write to the Free
33 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
34 * USA.
35 *
36 **********************************************************************
37 */
38
39#define __NO_VERSION__ /* Kernel version only defined once */
40#include <linux/module.h>
41#include <asm/uaccess.h>
42
43#include "hwaccess.h"
44
45#define AC97_PESSIMISTIC
46#undef OSS_DOCUMENTED_MIXER_SEMANTICS
47
48#define vol_to_hw_5(swvol) (31 - (((swvol) * 31) / 100))
49#define vol_to_hw_4(swvol) (15 - (((swvol) * 15) / 100))
50
51#define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
52#define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
53
54#ifdef PRIVATE_PCM_VOLUME
55struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
56#endif
57
58/* --------------------------------------------------------------------- */
59
60/*
61 * hweightN: returns the hamming weight (i.e. the number
62 * of bits set) of a N-bit word
63 */
64
65#ifdef hweight32
66#undef hweight32
67#endif
68
69extern __inline__ unsigned int hweight32(unsigned int w)
70{
71 unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
72
73 res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
74 res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
75 res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
76 return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
77}
78
79/* Mapping arrays */
80static const unsigned int recsrc[] = {
81 SOUND_MASK_MIC,
82 SOUND_MASK_CD,
83 SOUND_MASK_VIDEO,
84 SOUND_MASK_LINE1,
85 SOUND_MASK_LINE,
86 SOUND_MASK_VOLUME,
87 SOUND_MASK_OGAIN, /* Used to be PHONEOUT */
88 SOUND_MASK_PHONEIN,
89 SOUND_MASK_TREBLE,
90 SOUND_MASK_BASS,
91 SOUND_MASK_MONITOR,
92 SOUND_MASK_PCM,
93};
94
95#ifdef TARGET_OS2
96static const unsigned char volreg[SOUND_MIXER_NRDEVICES] =
97{
98 AC97_MASTERVOLUME, //SOUND_MIXER_VOLUME
99 AC97_GENERALPUPOSE, //SOUND_MIXER_BASS
100 AC97_MASTERTONE, //SOUND_MIXER_TREBLE
101 0, //SOUND_MIXER_SYNTH
102 AC97_PCMOUTVOLUME, //SOUND_MIXER_PCM
103 AC97_PCBEEPVOLUME, //SOUND_MIXER_SPEAKER
104 AC97_LINEINVOLUME, //SOUND_MIXER_LINE
105 AC97_MICVOLUME, //SOUND_MIXER_MIC
106 AC97_CDVOLUME, //SOUND_MIXER_CD
107 0, //SOUND_MIXER_IMIX
108 0, //SOUND_MIXER_ALTPCM
109 AC97_RECORDGAIN, //SOUND_MIXER_RECLEV
110 AC97_RECORDGAIN, //SOUND_MIXER_IGAIN
111 AC97_MASTERVOLUMEMONO, //SOUND_MIXER_OGAIN
112 AC97_AUXVOLUME, //SOUND_MIXER_LINE1
113 AC97_PCMOUTVOLUME, //SOUND_MIXER_LINE2
114 0, //SOUND_MIXER_LINE3
115 0, //SOUND_MIXER_DIGITAL1
116 AC97_MASTERVOLUME, //SOUND_MIXER_DIGITAL2
117 0, //SOUND_MIXER_DIGITAL3
118 AC97_PHONEVOLUME, //SOUND_MIXER_PHONEIN
119 AC97_HEADPHONEVOLUME, //SOUND_MIXER_PHONEOUT
120 AC97_VIDEOVOLUME, //SOUND_MIXER_VIDEO
121 0, //SOUND_MIXER_RADIO
122 0, //SOUND_MIXER_MONITOR
123};
124#else
125static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
126 /* 5 bit stereo */
127 [SOUND_MIXER_LINE] = AC97_LINEINVOLUME,
128 [SOUND_MIXER_CD] = AC97_CDVOLUME,
129 [SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME,
130 [SOUND_MIXER_LINE1] = AC97_AUXVOLUME,
131
132/* [SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME, */
133 /* 5 bit stereo, setting 6th bit equal to maximum attenuation */
134
135/* [SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME, */
136 [SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME,
137 /* 5 bit mono, setting 6th bit equal to maximum attenuation */
138 [SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO,
139 /* 5 bit mono */
140 [SOUND_MIXER_PHONEIN] = AC97_PHONEVOLUME,
141 /* 4 bit mono but shifted by 1 */
142 [SOUND_MIXER_SPEAKER] = AC97_PCBEEPVOLUME,
143 /* 5 bit mono, 7th bit = preamp */
144 [SOUND_MIXER_MIC] = AC97_MICVOLUME,
145 /* 4 bit stereo */
146 [SOUND_MIXER_RECLEV] = AC97_RECORDGAIN,
147 /* 4 bit mono */
148 [SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
149 /* test code */
150 [SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
151 [SOUND_MIXER_TREBLE] = AC97_MASTERTONE,
152 [SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME,
153 [SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME
154};
155#endif //TARGET_OS2
156
157#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
158
159#define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
160
161/* FIXME: mixer_rdch() is broken. */
162
163static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg)
164{
165 u16 reg;
166 int j;
167 int nL, nR;
168
169 switch (ch) {
170 case SOUND_MIXER_LINE:
171 case SOUND_MIXER_CD:
172 case SOUND_MIXER_VIDEO:
173 case SOUND_MIXER_LINE1:
174 case SOUND_MIXER_PCM:
175 case SOUND_MIXER_VOLUME:
176 sblive_readac97(card, volreg[ch], &reg);
177 nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
178 nR = (~(reg & 0x1f) * 100) / 32;
179 DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR);
180 return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
181
182 case SOUND_MIXER_OGAIN:
183 case SOUND_MIXER_PHONEIN:
184 sblive_readac97(card, volreg[ch], &reg);
185 return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg);
186
187 case SOUND_MIXER_SPEAKER:
188 sblive_readac97(card, volreg[ch], &reg);
189 return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg);
190
191 case SOUND_MIXER_MIC:
192 sblive_readac97(card, volreg[ch], &reg);
193 return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg);
194
195 case SOUND_MIXER_RECLEV:
196 sblive_readac97(card, volreg[ch], &reg);
197 nL = ((~(reg >> 8) & 0x1f) * 100) / 16;
198 nR = (~(reg & 0x1f) * 100) / 16;
199 return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
200
201 case SOUND_MIXER_TREBLE:
202 case SOUND_MIXER_BASS:
203 return put_user(0x0000, (int *) arg);
204 default:
205 return -EINVAL;
206 }
207}
208
209#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
210
211#ifdef TARGET_OS2
212static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
213{
214 6, //SOUND_MIXER_VOLUME
215 15, //SOUND_MIXER_BASS
216 14, //SOUND_MIXER_TREBLE
217 0, //SOUND_MIXER_SYNTH
218 5, //SOUND_MIXER_PCM
219 10, //SOUND_MIXER_SPEAKER
220 1, //SOUND_MIXER_LINE
221 11, //SOUND_MIXER_MIC
222 2, //SOUND_MIXER_CD
223 0, //SOUND_MIXER_IMIX
224 16, //SOUND_MIXER_ALTPCM
225 12, //SOUND_MIXER_RECLEV
226 13, //SOUND_MIXER_IGAIN
227 8, //SOUND_MIXER_OGAIN
228 4, //SOUND_MIXER_LINE1
229 16, //SOUND_MIXER_LINE2
230 17, //SOUND_MIXER_LINE3
231 18, //SOUND_MIXER_DIGITAL1
232 19, //SOUND_MIXER_DIGITAL2
233 0, //SOUND_MIXER_DIGITAL3
234 9, //SOUND_MIXER_PHONEIN
235 7, //SOUND_MIXER_PHONEOUT
236 3, //SOUND_MIXER_VIDEO
237 0, //SOUND_MIXER_RADIO
238 0, //SOUND_MIXER_MONITOR
239};
240#else
241static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = {
242 /* 5 bit stereo */
243 [SOUND_MIXER_LINE] = 1,
244 [SOUND_MIXER_CD] = 2,
245 [SOUND_MIXER_VIDEO] = 3,
246 [SOUND_MIXER_LINE1] = 4,
247 [SOUND_MIXER_PCM] = 5,
248 /* 6 bit stereo */
249 [SOUND_MIXER_VOLUME] = 6,
250 [SOUND_MIXER_PHONEOUT] = 7,
251 /* 6 bit mono */
252 [SOUND_MIXER_OGAIN] = 8,
253 [SOUND_MIXER_PHONEIN] = 9,
254 /* 4 bit mono but shifted by 1 */
255 [SOUND_MIXER_SPEAKER] = 10,
256 /* 6 bit mono + preamp */
257 [SOUND_MIXER_MIC] = 11,
258 /* 4 bit stereo */
259 [SOUND_MIXER_RECLEV] = 12,
260 /* 4 bit mono */
261 [SOUND_MIXER_IGAIN] = 13,
262 [SOUND_MIXER_TREBLE] = 14,
263 [SOUND_MIXER_BASS] = 15,
264 [SOUND_MIXER_LINE2] = 16,
265 [SOUND_MIXER_LINE3] = 17,
266 [SOUND_MIXER_DIGITAL1] = 18,
267 [SOUND_MIXER_DIGITAL2] = 19
268};
269#endif //TARGET_OS2
270
271u32 bass_table[41][5] = {
272 { 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
273 { 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
274 { 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
275 { 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
276 { 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
277 { 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
278 { 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
279 { 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
280 { 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
281 { 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
282 { 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
283 { 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
284 { 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
285 { 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
286 { 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
287 { 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
288 { 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
289 { 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
290 { 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
291 { 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
292 { 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
293 { 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
294 { 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
295 { 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
296 { 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
297 { 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
298 { 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
299 { 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
300 { 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
301 { 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
302 { 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
303 { 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
304 { 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
305 { 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
306 { 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
307 { 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
308 { 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
309 { 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
310 { 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
311 { 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
312 { 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
313};
314
315u32 treble_table[41][5] = {
316 { 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
317 { 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
318 { 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
319 { 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
320 { 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
321 { 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
322 { 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
323 { 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
324 { 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
325 { 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
326 { 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
327 { 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
328 { 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
329 { 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
330 { 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
331 { 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
332 { 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
333 { 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
334 { 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
335 { 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
336 { 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
337 { 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
338 { 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
339 { 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
340 { 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
341 { 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
342 { 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
343 { 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
344 { 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
345 { 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
346 { 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
347 { 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
348 { 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
349 { 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
350 { 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
351 { 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
352 { 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
353 { 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
354 { 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
355 { 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
356 { 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
357};
358
359static void set_bass(struct emu10k1_card *card, int l, int r)
360{
361 int i;
362
363 l = (l * 40 + 50) / 100;
364 r = (r * 40 + 50) / 100;
365 for (i = 0; i < 5; i++) {
366 sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]);
367 sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]);
368 }
369}
370
371static void set_treble(struct emu10k1_card *card, int l, int r)
372{
373 int i;
374
375 l = (l * 40 + 50) / 100;
376 r = (r * 40 + 50) / 100;
377 for (i = 0; i < 5; i++) {
378 sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]);
379 sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]);
380 }
381}
382
383u32 db_table[101] = {
384 0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
385 0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
386 0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
387 0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
388 0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
389 0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
390 0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
391 0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
392 0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
393 0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
394 0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
395 0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
396 0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
397 0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
398 0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
399 0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
400 0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
401 0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
402 0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
403 0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
404 0x7fffffff,
405};
406
407static void update_digital(struct emu10k1_card *card)
408{
409 int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
410 u64 j;
411
412 i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
413 l1 = (i & 0xff);
414 r1 = ((i >> 8) & 0xff);
415 i = card->arrwVol[volidx[SOUND_MIXER_LINE3]];
416 l2 = i & 0xff;
417 r2 = (i >> 8) & 0xff;
418
419 i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
420 l3 = i & 0xff;
421 r3 = (i >> 8) & 0xff;
422
423 i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]];
424 l4 = i & 0xff;
425 r4 = (i >> 8) & 0xff;
426
427 i = (r1 * r2) / 50;
428 if (r2 > 50)
429 r2 = 2 * r1 - i;
430 else {
431 r2 = r1;
432 r1 = i;
433 }
434
435 i = (l1 * l2) / 50;
436 if (l2 > 50)
437 l2 = 2 * l1 - i;
438 else {
439 l2 = l1;
440 l1 = i;
441 }
442
443 for (i = 0; i < 18; i++) {
444 if (card->digmix[i] != 0x80000000) {
445 if ((i >= 0) && (i < 4))
446 j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]);
447 else if ((i == 6) || (i == 7))
448 j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]);
449 else
450 j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31;
451 card->digmix[i] = j >> 31;
452 sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
453 }
454 }
455
456 for (i = 72; i < 90; i++) {
457 if (card->digmix[i] != 0x80000000) {
458 if ((i >= 72) && (i < 76))
459 j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]);
460 else if ((i == 78) || (i == 79))
461 j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]);
462 else
463 j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31;
464 card->digmix[i] = j >> 31;
465 sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
466 }
467 }
468
469 for (i = 18; i <= 90; i += 18) {
470 if (i != 72) {
471 for (k = 0; k < 4; k++)
472 if (card->digmix[i + k] != 0x80000000) {
473 card->digmix[i + k] = db_table[l3];
474 sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]);
475 }
476 if (card->digmix[i + 6] != 0x80000000) {
477 card->digmix[i + 6] = db_table[l4];
478 sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]);
479 }
480 if (card->digmix[i + 7] != 0x80000000) {
481 card->digmix[i + 7] = db_table[r4];
482 sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
483 }
484 }
485 }
486
487}
488
489#ifdef PRIVATE_PCM_VOLUME
490
491/* calc & set attenuation factor for given channel */
492static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
493{
494#ifndef PCMLEVEL
495#define PCMLEVEL 140 // almost silence
496#endif
497 int vol = IFATN_ATTENUATION_MASK; // silence
498
499 if (l > 0)
500 vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
501 sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol);
502 DPD(2, "SOUND_MIXER_PCM: channel:%d level:%d attn:%d\n", ch, l, vol);
503
504 return vol;
505#undef PCMLEVEL
506}
507
508/* update value of local PCM volume level (using channel attenuation)
509 *
510 * return 1: in case its local change
511 * 0: if the current process doesn't have entry in table
512 * (it means this process have not opened audio (mixer usually)
513 */
514
515static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1)
516{
517 int i;
518 int mixer = (r1 << 8) | l1;
519
520 //SvL; First call (during mixer init) must return 0 and fill in the
521 // arrwVol array. Only then will update_digital be called.
522 // If this doesn't happen, sound is disabled.
523 // Check here that current->files != 0
524 for (i = 0; i < MAX_PCM_CHANNELS; i++) {
525 if (current->files && sblive_pcm_volume[i].files == current->files) {
526 sblive_pcm_volume[i].mixer = mixer;
527 if (sblive_pcm_volume[i].opened) {
528 if (sblive_pcm_volume[i].channel_r < NUM_G) {
529 if (sblive_pcm_volume[i].channel_l < NUM_G)
530 sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
531 sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
532 } else {
533 // mono voice
534 if (sblive_pcm_volume[i].channel_l < NUM_G)
535 sblive_pcm_volume[i].attn_l =
536 set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
537 // to correctly handle mono voice here we would need
538 // to go into stereo mode and move the voice to the right & left
539 // looks a bit overcomlicated...
540 }
541
542 }
543 return 1;
544 }
545 }
546 if (i == MAX_PCM_CHANNELS)
547 card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
548
549 return 0;
550}
551#endif
552
553int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val)
554{
555 int i;
556 unsigned l1, r1;
557 u16 wval;
558
559 l1 = val & 0xff;
560 r1 = (val >> 8) & 0xff;
561 if (l1 > 100)
562 l1 = 100;
563 if (r1 > 100)
564 r1 = 100;
565
566 DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
567
568 if (!volidx[ch])
569 return -EINVAL;
570#ifdef PRIVATE_PCM_VOLUME
571 if (ch != SOUND_MIXER_PCM)
572#endif
573 card->arrwVol[volidx[ch]] = (r1 << 8) | l1;
574
575 switch (ch) {
576 case SOUND_MIXER_VOLUME:
577 case SOUND_MIXER_DIGITAL1:
578 case SOUND_MIXER_LINE3:
579 DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
580 update_digital(card);
581 return 0;
582 case SOUND_MIXER_PCM:
583 DPF(4, "SOUND_MIXER_PCM\n");
584#ifdef PRIVATE_PCM_VOLUME
585 if (update_pcm_attn(card, l1, r1))
586 return 0;
587#endif
588 update_digital(card);
589 return 0;
590 case SOUND_MIXER_DIGITAL2:
591 case SOUND_MIXER_LINE2:
592 case SOUND_MIXER_LINE1:
593 case SOUND_MIXER_LINE:
594 case SOUND_MIXER_CD:
595 DPD(4, "SOUND_MIXER_%s:\n",
596 (ch == SOUND_MIXER_LINE1) ? "LINE1" :
597 (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD");
598 wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
599 if (wval == 0x2020)
600 wval = 0x8000;
601 else
602 wval -= ((wval & 0x2020) / 0x20);
603 sblive_writeac97(card, volreg[ch], wval);
604 return 0;
605
606 case SOUND_MIXER_OGAIN:
607 case SOUND_MIXER_PHONEIN:
608 DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN");
609 sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
610 return 0;
611
612 case SOUND_MIXER_SPEAKER:
613 DPF(4, "SOUND_MIXER_SPEAKER:\n");
614 sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
615 return 0;
616
617 case SOUND_MIXER_MIC:
618 DPF(4, "SOUND_MIXER_MIC:\n");
619 i = 0;
620 if (l1 >= 30)
621 // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
622 {
623 l1 -= 30;
624 i = 0x40;
625 }
626 sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
627 return 0;
628
629 case SOUND_MIXER_RECLEV:
630 DPF(4, "SOUND_MIXER_RECLEV:\n");
631
632 wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100);
633 if (wval == 0)
634 wval = 0x8000;
635 else {
636 if (wval & 0xff)
637 wval--;
638 if (wval & 0xff00)
639 wval -= 0x0100;
640 }
641 sblive_writeac97(card, volreg[ch], wval);
642 return 0;
643
644 case SOUND_MIXER_TREBLE:
645 DPF(4, "SOUND_MIXER_TREBLE:\n");
646 set_treble(card, l1, r1);
647 return 0;
648
649 case SOUND_MIXER_BASS:
650 DPF(4, "SOUND_MIXER_BASS:\n");
651 set_bass(card, l1, r1);
652 return 0;
653
654 default:
655 DPF(2, "Got unknown SOUND_MIXER ioctl\n");
656 return -EINVAL;
657 }
658}
659
660static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin)
661{
662 DPF(2, "sblive_mixer_llseek() called\n");
663 return -ESPIPE;
664}
665
666/* Mixer file operations */
667
668/* FIXME: Do we need spinlocks in here? */
669static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
670{
671 static const char id[] = "SBLive";
672 static const char name[] = "Creative SBLive";
673 int i, val;
674 struct emu10k1_card *card = (struct emu10k1_card *) file->private_data;
675 u16 reg;
676
677 switch (cmd) {
678
679 case SOUND_MIXER_INFO:{
680 mixer_info info;
681
682 DPF(4, "SOUND_MIXER_INFO\n");
683
684 strncpy(info.id, id, sizeof(info.id));
685 strncpy(info.name, name, sizeof(info.name));
686
687 info.modify_counter = card->modcnt;
688 if (copy_to_user((void *) arg, &info, sizeof(info)))
689 return -EFAULT;
690
691 return 0;
692 }
693 break;
694 case SOUND_OLD_MIXER_INFO:{
695 _old_mixer_info info;
696
697 DPF(4, "SOUND_OLD_MIXER_INFO\n");
698
699 strncpy(info.id, id, sizeof(info.id));
700 strncpy(info.name, name, sizeof(info.name));
701
702 if (copy_to_user((void *) arg, &info, sizeof(info)))
703 return -EFAULT;
704
705 return 0;
706 }
707 break;
708
709 case OSS_GETVERSION:
710 DPF(4, "OSS_GETVERSION\n");
711 return put_user(SOUND_VERSION, (int *) arg);
712 break;
713
714 case SOUND_MIXER_PRIVATE1:
715 DPF(4, "SOUND_MIXER_PRIVATE1");
716
717 if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix)))
718 return -EFAULT;
719
720 return 0;
721
722 break;
723 case SOUND_MIXER_PRIVATE2:
724 DPF(4, "SOUND_MIXER_PRIVATE2");
725
726 if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix)))
727 return -EFAULT;
728
729 for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
730 sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
731 return 0;
732
733 break;
734
735 default:
736 break;
737 }
738
739 if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
740 return -EINVAL;
741
742 if (_IOC_DIR(cmd) == _IOC_READ) {
743 switch (_IOC_NR(cmd)) {
744 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
745 DPF(2, "SOUND_MIXER_READ_RECSRC\n");
746 sblive_readac97(card, AC97_RECORDSELECT, &reg);
747 return put_user(recsrc[reg & 7], (int *) arg);
748
749 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
750 DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
751 return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
752 SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
753 SOUND_MASK_PCM | SOUND_MASK_VOLUME |
754 SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
755 SOUND_MASK_BASS | SOUND_MASK_TREBLE |
756 SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
757 SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
758 SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
759 case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
760 DPF(2, "SOUND_MIXER_READ_RECMASK\n");
761 return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
762 SOUND_MASK_LINE1 | SOUND_MASK_LINE |
763 SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
764 SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR |
765 SOUND_MASK_PCM, (int *) arg);
766
767 case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
768 DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
769 return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
770 SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
771 SOUND_MASK_PCM | SOUND_MASK_VOLUME |
772 SOUND_MASK_BASS | SOUND_MASK_TREBLE |
773 SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
774 SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
775 SOUND_MASK_LINE2, (int *) arg);
776
777 case SOUND_MIXER_CAPS:
778 DPF(2, "SOUND_MIXER_READ_CAPS\n");
779 return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
780
781#ifdef PRIVATE_PCM_VOLUME
782 case SOUND_MIXER_PCM:
783 // needs to be before default: !!
784 {
785 int i;
786
787 for (i = 0; i < MAX_PCM_CHANNELS; i++) {
788 if (sblive_pcm_volume[i].files == current->files) {
789 return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
790 }
791 }
792 }
793#endif
794 default:
795 i = _IOC_NR(cmd);
796 DPD(4, "SOUND_MIXER_READ(%d)\n", i);
797 if (i >= SOUND_MIXER_NRDEVICES)
798 return -EINVAL;
799#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
800 return mixer_rdch(card, i, (int *) arg);
801#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
802 if (!volidx[i])
803 return -EINVAL;
804 return put_user(card->arrwVol[volidx[i]], (int *) arg);
805
806#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
807 }
808 }
809 /* End of _IOC_READ */
810 if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
811 return -EINVAL;
812
813 /* _IOC_WRITE */
814 card->modcnt++;
815
816 switch (_IOC_NR(cmd)) {
817 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
818 DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
819
820 get_user_ret(val, (int *) arg, -EFAULT);
821 i = hweight32(val);
822 if (i == 0)
823 return 0; /*val = mixer_recmask(s); */
824 else if (i > 1) {
825 sblive_readac97(card, AC97_RECORDSELECT, &reg);
826 val &= ~recsrc[reg & 7];
827 }
828
829 for (i = 0; i < 8; i++) {
830 if (val & recsrc[i]) {
831 DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i);
832 sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i);
833 return 0;
834 }
835 }
836 return 0;
837
838 default:
839 i = _IOC_NR(cmd);
840 DPD(4, "SOUND_MIXER_WRITE(%d)\n", i);
841
842 if (i >= SOUND_MIXER_NRDEVICES)
843 return -EINVAL;
844 get_user_ret(val, (int *) arg, -EFAULT);
845 if (emu10k1_mixer_wrch(card, i, val))
846 return -EINVAL;
847
848#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
849 return mixer_rdch(card, i, (int *) arg);
850#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
851 return put_user(card->arrwVol[volidx[i]], (int *) arg);
852#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
853
854 }
855}
856
857static int emu10k1_mixer_open(struct inode *inode, struct file *file)
858{
859 int minor = MINOR(inode->i_rdev);
860 struct emu10k1_card *card;
861 struct list_head *entry;
862
863 DPF(4, "emu10k1_mixer_open()\n");
864
865 list_for_each(entry, &emu10k1_devs) {
866 card = list_entry(entry, struct emu10k1_card, list);
867
868 if (card->mixer_num == minor)
869 break;
870 }
871
872 if (entry == &emu10k1_devs)
873 return -ENODEV;
874
875 MOD_INC_USE_COUNT;
876
877 file->private_data = card;
878 return 0;
879}
880
881static int emu10k1_mixer_release(struct inode *inode, struct file *file)
882{
883 DPF(3, "emu10k1_mixer_release()\n");
884 MOD_DEC_USE_COUNT;
885 return 0;
886}
887
888#ifdef TARGET_OS2
889//Hello!?! Use standard C!
890struct file_operations emu10k1_mixer_fops =
891{
892 &emu10k1_mixer_llseek,
893 NULL, /* read */
894 NULL, /* write */
895 NULL, /* readdir */
896 NULL, /* select/poll */
897 &emu10k1_mixer_ioctl,
898 NULL, /* mmap */
899 &emu10k1_mixer_open,
900#if LINUX_VERSION_CODE >= 0x020100
901 NULL, /* flush */
902#endif
903 &emu10k1_mixer_release,
904 NULL, /* fsync */
905 NULL, /* fasync */
906 NULL /* check_media_change */
907};
908#else
909struct file_operations emu10k1_mixer_fops = {
910 llseek:emu10k1_mixer_llseek,
911 ioctl:emu10k1_mixer_ioctl,
912 open:emu10k1_mixer_open,
913 release:emu10k1_mixer_release,
914};
915#endif
Note: See TracBrowser for help on using the repository browser.