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

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

volume table update

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