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

Last change on this file since 200 was 198, checked in by sandervl, 24 years ago

master volume fix; update ac97 register

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