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

Last change on this file since 153 was 153, checked in by sandervl, 25 years ago

update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.6 KB
Line 
1/* $Id: mixer.c 153 2000-07-23 16:21:57Z sandervl $ */
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
271static const u32 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
315static const u32 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
383static const u32 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 < 36; i++) {
444 if (card->digmix[i] != 0x80000000) {
445 if (((i >= 0) && (i < 4)) || ((i >= 18) && (i < 22)))
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) || (i == 24) || (i == 25))
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 = 36; 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
491static unsigned char LinToLog[100] = { 0, 0, 0, 0,
492 1, 2, 2, 5, 5, 10, 10, 10,
493 16, 19, 20, 22, 24, 25, 27, 27,
494 28, 28, 29, 30, 30, 35, 35, 35,
495 39, 39, 43, 45, 47, 49, 50, 50,
496 60, 60, 70, 72, 72, 74, 74, 74,
497 75, 75, 76, 77, 78, 80, 82, 83,
498 85, 85, 85, 88, 88, 88, 88, 90,
499 90, 93, 93, 93, 95, 95, 95, 95,
500 95, 95, 95, 96, 96, 97, 97, 98,
501 98, 98, 98, 99, 99, 99, 99, 99,
502 99, 99, 99, 99, 100, 100, 100, 100,
503 100, 100, 100, 100, 100, 100, 100, 100};
504
505
506/* calc & set attenuation factor for given channel */
507static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
508{
509#ifndef PCMLEVEL
510#define PCMLEVEL 110 /* almost silence */
511#endif
512 int vol = IFATN_ATTENUATION_MASK; /* silence */
513
514 if (l > 0) {
515 if(l < 100) {
516 l = LinToLog[l];
517 }
518 vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
519 }
520 sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol);
521 DPD(2, "SOUND_MIXER_PCM: channel:%d level:%d attn:%d\n", ch, l, vol);
522
523 return vol;
524#undef PCMLEVEL
525}
526
527/* update value of local PCM volume level (using channel attenuation)
528 *
529 * return 1: in case its local change
530 * 0: if the current process doesn't have entry in table
531 * (it means this process have not opened audio (mixer usually)
532 */
533
534static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1)
535{
536 int i;
537 int mixer = (r1 << 8) | l1;
538
539 //SvL; First call (during mixer init) must return 0 and fill in the
540 // arrwVol array. Only then will update_digital be called.
541 // If this doesn't happen, sound is disabled.
542 // Check here that current->files != 0
543 for (i = 0; i < MAX_PCM_CHANNELS; i++) {
544#ifdef TARGET_OS2
545 if (current->files && sblive_pcm_volume[i].files == current->files) {
546#else
547 if (sblive_pcm_volume[i].files == current->files) {
548#endif
549 sblive_pcm_volume[i].mixer = mixer;
550 if (sblive_pcm_volume[i].opened) {
551 if (sblive_pcm_volume[i].channel_r < NUM_G) {
552 if (sblive_pcm_volume[i].channel_l < NUM_G)
553 sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
554 sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
555 } else {
556 // mono voice
557 if (sblive_pcm_volume[i].channel_l < NUM_G)
558 sblive_pcm_volume[i].attn_l =
559 set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
560 // to correctly handle mono voice here we would need
561 // to go into stereo mode and move the voice to the right & left
562 // looks a bit overcomlicated...
563 }
564
565 }
566 return 1;
567 }
568 }
569 card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
570
571 return 0;
572}
573#endif
574
575int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val)
576{
577 int i;
578 unsigned l1, r1;
579 u16 wval;
580
581 l1 = val & 0xff;
582 r1 = (val >> 8) & 0xff;
583 if (l1 > 100)
584 l1 = 100;
585 if (r1 > 100)
586 r1 = 100;
587
588 DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
589
590 if (!volidx[ch])
591 return -EINVAL;
592#ifdef PRIVATE_PCM_VOLUME
593 if (ch != SOUND_MIXER_PCM)
594#endif
595 card->arrwVol[volidx[ch]] = (r1 << 8) | l1;
596
597 switch (ch) {
598 case SOUND_MIXER_VOLUME:
599 case SOUND_MIXER_DIGITAL1:
600 case SOUND_MIXER_LINE3:
601 DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
602 update_digital(card);
603 return 0;
604 case SOUND_MIXER_PCM:
605 DPF(4, "SOUND_MIXER_PCM\n");
606#ifdef PRIVATE_PCM_VOLUME
607 if (update_pcm_attn(card, l1, r1))
608 return 0;
609#endif
610 update_digital(card);
611 return 0;
612 case SOUND_MIXER_DIGITAL2:
613 case SOUND_MIXER_LINE2:
614 case SOUND_MIXER_LINE1:
615 case SOUND_MIXER_LINE:
616 case SOUND_MIXER_CD:
617 DPD(4, "SOUND_MIXER_%s:\n",
618 (ch == SOUND_MIXER_LINE1) ? "LINE1" :
619 (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD");
620 wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
621 if (wval == 0x2020)
622 wval = 0x8000;
623 else
624 wval -= ((wval & 0x2020) / 0x20);
625 sblive_writeac97(card, volreg[ch], wval);
626 return 0;
627
628 case SOUND_MIXER_OGAIN:
629 case SOUND_MIXER_PHONEIN:
630 DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN");
631 sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
632 return 0;
633
634 case SOUND_MIXER_SPEAKER:
635 DPF(4, "SOUND_MIXER_SPEAKER:\n");
636 sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
637 return 0;
638
639 case SOUND_MIXER_MIC:
640 DPF(4, "SOUND_MIXER_MIC:\n");
641 i = 0;
642 if (l1 >= 30)
643 // 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
644 {
645 l1 -= 30;
646 i = 0x40;
647 }
648 sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
649 return 0;
650
651 case SOUND_MIXER_RECLEV:
652 DPF(4, "SOUND_MIXER_RECLEV:\n");
653
654 wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100);
655 if (wval == 0)
656 wval = 0x8000;
657 else {
658 if (wval & 0xff)
659 wval--;
660 if (wval & 0xff00)
661 wval -= 0x0100;
662 }
663 sblive_writeac97(card, volreg[ch], wval);
664 return 0;
665
666 case SOUND_MIXER_TREBLE:
667 DPF(4, "SOUND_MIXER_TREBLE:\n");
668 set_treble(card, l1, r1);
669 return 0;
670
671 case SOUND_MIXER_BASS:
672 DPF(4, "SOUND_MIXER_BASS:\n");
673 set_bass(card, l1, r1);
674 return 0;
675
676 default:
677 DPF(2, "Got unknown SOUND_MIXER ioctl\n");
678 return -EINVAL;
679 }
680}
681
682static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin)
683{
684 DPF(2, "sblive_mixer_llseek() called\n");
685 return -ESPIPE;
686}
687
688/* Mixer file operations */
689
690/* FIXME: Do we need spinlocks in here? */
691static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
692{
693 static const char id[] = "SBLive";
694 static const char name[] = "Creative SBLive";
695 int i, val;
696 struct emu10k1_card *card = (struct emu10k1_card *) file->private_data;
697 u16 reg;
698
699 switch (cmd) {
700
701 case SOUND_MIXER_INFO:{
702 mixer_info info;
703
704 DPF(4, "SOUND_MIXER_INFO\n");
705
706 strncpy(info.id, id, sizeof(info.id));
707 strncpy(info.name, name, sizeof(info.name));
708
709 info.modify_counter = card->modcnt;
710 if (copy_to_user((void *) arg, &info, sizeof(info)))
711 return -EFAULT;
712
713 return 0;
714 }
715 break;
716 case SOUND_OLD_MIXER_INFO:{
717 _old_mixer_info info;
718
719 DPF(4, "SOUND_OLD_MIXER_INFO\n");
720
721 strncpy(info.id, id, sizeof(info.id));
722 strncpy(info.name, name, sizeof(info.name));
723
724 if (copy_to_user((void *) arg, &info, sizeof(info)))
725 return -EFAULT;
726
727 return 0;
728 }
729 break;
730
731 case OSS_GETVERSION:
732 DPF(4, "OSS_GETVERSION\n");
733 return put_user(SOUND_VERSION, (int *) arg);
734 break;
735
736 case SOUND_MIXER_PRIVATE1:
737 DPF(4, "SOUND_MIXER_PRIVATE1");
738
739 if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix)))
740 return -EFAULT;
741
742 return 0;
743
744 break;
745 case SOUND_MIXER_PRIVATE2:
746 DPF(4, "SOUND_MIXER_PRIVATE2");
747
748 if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix)))
749 return -EFAULT;
750
751 for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
752 sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
753 return 0;
754
755 break;
756
757 default:
758 break;
759 }
760
761 if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
762 return -EINVAL;
763
764 if (_IOC_DIR(cmd) == _IOC_READ) {
765 switch (_IOC_NR(cmd)) {
766 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
767 DPF(2, "SOUND_MIXER_READ_RECSRC\n");
768 sblive_readac97(card, AC97_RECORDSELECT, &reg);
769 return put_user(recsrc[reg & 7], (int *) arg);
770
771 case SOUND_MIXER_DEVMASK: /* Arg contains a bit for each supported device */
772 DPF(4, "SOUND_MIXER_READ_DEVMASK\n");
773 return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
774 SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
775 SOUND_MASK_PCM | SOUND_MASK_VOLUME |
776 SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
777 SOUND_MASK_BASS | SOUND_MASK_TREBLE |
778 SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
779 SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 |
780 SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
781 case SOUND_MIXER_RECMASK: /* Arg contains a bit for each supported recording source */
782 DPF(2, "SOUND_MIXER_READ_RECMASK\n");
783 return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
784 SOUND_MASK_LINE1 | SOUND_MASK_LINE |
785 SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
786 SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR |
787 SOUND_MASK_PCM, (int *) arg);
788
789 case SOUND_MIXER_STEREODEVS: /* Mixer channels supporting stereo */
790 DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
791 return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
792 SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
793 SOUND_MASK_PCM | SOUND_MASK_VOLUME |
794 SOUND_MASK_BASS | SOUND_MASK_TREBLE |
795 SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
796 SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 |
797 SOUND_MASK_LINE2, (int *) arg);
798
799 case SOUND_MIXER_CAPS:
800 DPF(2, "SOUND_MIXER_READ_CAPS\n");
801 return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
802
803#ifdef PRIVATE_PCM_VOLUME
804 case SOUND_MIXER_PCM:
805 // needs to be before default: !!
806 {
807 int i;
808
809 for (i = 0; i < MAX_PCM_CHANNELS; i++) {
810 if (sblive_pcm_volume[i].files == current->files) {
811 return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
812 }
813 }
814 }
815#endif
816 default:
817 i = _IOC_NR(cmd);
818 DPD(4, "SOUND_MIXER_READ(%d)\n", i);
819 if (i >= SOUND_MIXER_NRDEVICES)
820 return -EINVAL;
821#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
822 return mixer_rdch(card, i, (int *) arg);
823#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
824 if (!volidx[i])
825 return -EINVAL;
826 return put_user(card->arrwVol[volidx[i]], (int *) arg);
827
828#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
829 }
830 }
831 /* End of _IOC_READ */
832 if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
833 return -EINVAL;
834
835 /* _IOC_WRITE */
836 card->modcnt++;
837
838 switch (_IOC_NR(cmd)) {
839 case SOUND_MIXER_RECSRC: /* Arg contains a bit for each recording source */
840 DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
841
842 get_user_ret(val, (int *) arg, -EFAULT);
843 i = hweight32(val);
844 if (i == 0)
845 return 0; /*val = mixer_recmask(s); */
846 else if (i > 1) {
847 sblive_readac97(card, AC97_RECORDSELECT, &reg);
848 val &= ~recsrc[reg & 7];
849 }
850
851 for (i = 0; i < 8; i++) {
852 if (val & recsrc[i]) {
853 DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i);
854 sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i);
855 return 0;
856 }
857 }
858 return 0;
859
860 default:
861 i = _IOC_NR(cmd);
862 DPD(4, "SOUND_MIXER_WRITE(%d)\n", i);
863
864 if (i >= SOUND_MIXER_NRDEVICES)
865 return -EINVAL;
866 get_user_ret(val, (int *) arg, -EFAULT);
867 if (emu10k1_mixer_wrch(card, i, val))
868 return -EINVAL;
869
870#ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
871 return mixer_rdch(card, i, (int *) arg);
872#else /* OSS_DOCUMENTED_MIXER_SEMANTICS */
873 return put_user(card->arrwVol[volidx[i]], (int *) arg);
874#endif /* OSS_DOCUMENTED_MIXER_SEMANTICS */
875
876 }
877}
878
879static int emu10k1_mixer_open(struct inode *inode, struct file *file)
880{
881 int minor = MINOR(inode->i_rdev);
882 struct emu10k1_card *card;
883 struct list_head *entry;
884
885 DPF(4, "emu10k1_mixer_open()\n");
886
887 list_for_each(entry, &emu10k1_devs) {
888 card = list_entry(entry, struct emu10k1_card, list);
889
890 if (card->mixer_num == minor)
891 break;
892 }
893
894 if (entry == &emu10k1_devs)
895 return -ENODEV;
896
897 MOD_INC_USE_COUNT;
898
899 file->private_data = card;
900 return 0;
901}
902
903static int emu10k1_mixer_release(struct inode *inode, struct file *file)
904{
905 DPF(3, "emu10k1_mixer_release()\n");
906 MOD_DEC_USE_COUNT;
907 return 0;
908}
909
910#ifdef TARGET_OS2
911//Hello!?! Use standard C!
912struct file_operations emu10k1_mixer_fops =
913{
914 &emu10k1_mixer_llseek,
915 NULL, /* read */
916 NULL, /* write */
917 NULL, /* readdir */
918 NULL, /* select/poll */
919 &emu10k1_mixer_ioctl,
920 NULL, /* mmap */
921 &emu10k1_mixer_open,
922#if LINUX_VERSION_CODE >= 0x020100
923 NULL, /* flush */
924#endif
925 &emu10k1_mixer_release,
926 NULL, /* fsync */
927 NULL, /* fasync */
928 NULL /* check_media_change */
929};
930#else
931struct file_operations emu10k1_mixer_fops = {
932 llseek:emu10k1_mixer_llseek,
933 ioctl:emu10k1_mixer_ioctl,
934 open:emu10k1_mixer_open,
935 release:emu10k1_mixer_release,
936};
937#endif
Note: See TracBrowser for help on using the repository browser.