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

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

Fixed wave volume, recording gain + wave recording

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