1 /*
2  **********************************************************************
3  *     mixer.c - /dev/mixer interface for emu10k1 driver
4  *     Copyright 1999, 2000 Creative Labs, Inc.
5  *
6  **********************************************************************
7  *
8  *     Date                 Author          Summary of changes
9  *     ----                 ------          ------------------
10  *     October 20, 1999     Bertrand Lee    base code release
11  *     November 2, 1999     Alan Cox        cleaned up stuff
12  *
13  **********************************************************************
14  *
15  *     This program is free software; you can redistribute it and/or
16  *     modify it under the terms of the GNU General Public License as
17  *     published by the Free Software Foundation; either version 2 of
18  *     the License, or (at your option) any later version.
19  *
20  *     This program is distributed in the hope that it will be useful,
21  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
22  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  *     GNU General Public License for more details.
24  *
25  *     You should have received a copy of the GNU General Public
26  *     License along with this program; if not, write to the Free
27  *     Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
28  *     USA.
29  *
30  **********************************************************************
31  */
32 
33 #define __NO_VERSION__		/* Kernel version only defined once */
34 #include <linux/module.h>
35 #include <linux/version.h>
36 #include <asm/uaccess.h>
37 #include <linux/fs.h>
38 
39 #include "hwaccess.h"
40 #include "8010.h"
41 #include "recmgr.h"
42 
43 
44 static const u32 bass_table[41][5] = {
45 	{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
46 	{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
47 	{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
48 	{ 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
49 	{ 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
50 	{ 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
51 	{ 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
52 	{ 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
53 	{ 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
54 	{ 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
55 	{ 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
56 	{ 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
57 	{ 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
58 	{ 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
59 	{ 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
60 	{ 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
61 	{ 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
62 	{ 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
63 	{ 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
64 	{ 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
65 	{ 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
66 	{ 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
67 	{ 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
68 	{ 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
69 	{ 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
70 	{ 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
71 	{ 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
72 	{ 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
73 	{ 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
74 	{ 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
75 	{ 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
76 	{ 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
77 	{ 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
78 	{ 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
79 	{ 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
80 	{ 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
81 	{ 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
82 	{ 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
83 	{ 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
84 	{ 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
85 	{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
86 };
87 
88 static const u32 treble_table[41][5] = {
89 	{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
90 	{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
91 	{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
92 	{ 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
93 	{ 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
94 	{ 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
95 	{ 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
96 	{ 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
97 	{ 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
98 	{ 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
99 	{ 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
100 	{ 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
101 	{ 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
102 	{ 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
103 	{ 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
104 	{ 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
105 	{ 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
106 	{ 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
107 	{ 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
108 	{ 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
109 	{ 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
110 	{ 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
111 	{ 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
112 	{ 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
113 	{ 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
114 	{ 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
115 	{ 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
116 	{ 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
117 	{ 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
118 	{ 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
119 	{ 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
120 	{ 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
121 	{ 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
122 	{ 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
123 	{ 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
124 	{ 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
125 	{ 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
126 	{ 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
127 	{ 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
128 	{ 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
129 	{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
130 };
131 
132 
set_bass(struct emu10k1_card * card,int l,int r)133 static void set_bass(struct emu10k1_card *card, int l, int r)
134 {
135 	int i;
136 
137 	l = (l * 40 + 50) / 100;
138 	r = (r * 40 + 50) / 100;
139 
140 	for (i = 0; i < 5; i++)
141 		sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_BASS][0] + i, 0, bass_table[l][i]);
142 }
143 
set_treble(struct emu10k1_card * card,int l,int r)144 static void set_treble(struct emu10k1_card *card, int l, int r)
145 {
146 	int i;
147 
148 	l = (l * 40 + 50) / 100;
149 	r = (r * 40 + 50) / 100;
150 
151 	for (i = 0; i < 5; i++)
152 		sblive_writeptr(card, GPR_BASE + card->mgr.ctrl_gpr[SOUND_MIXER_TREBLE][0] + i , 0, treble_table[l][i]);
153 }
154 
155 const char volume_params[SOUND_MIXER_NRDEVICES]= {
156 /* Used by the ac97 driver */
157 	[SOUND_MIXER_VOLUME]	=	VOL_6BIT,
158 	[SOUND_MIXER_BASS]	=	VOL_4BIT,
159 	[SOUND_MIXER_TREBLE]	=	VOL_4BIT,
160 	[SOUND_MIXER_PCM]	=	VOL_5BIT,
161 	[SOUND_MIXER_SPEAKER]	=	VOL_4BIT,
162 	[SOUND_MIXER_LINE]	=	VOL_5BIT,
163 	[SOUND_MIXER_MIC]	=	VOL_5BIT,
164 	[SOUND_MIXER_CD]	=	VOL_5BIT,
165 	[SOUND_MIXER_ALTPCM]	=	VOL_6BIT,
166 	[SOUND_MIXER_IGAIN]	=	VOL_4BIT,
167 	[SOUND_MIXER_LINE1]	=	VOL_5BIT,
168 	[SOUND_MIXER_PHONEIN]	= 	VOL_5BIT,
169 	[SOUND_MIXER_PHONEOUT]	= 	VOL_6BIT,
170 	[SOUND_MIXER_VIDEO]	=	VOL_5BIT,
171 /* Not used by the ac97 driver */
172 	[SOUND_MIXER_SYNTH]	=	VOL_5BIT,
173 	[SOUND_MIXER_IMIX]	=	VOL_5BIT,
174 	[SOUND_MIXER_RECLEV]	=	VOL_5BIT,
175 	[SOUND_MIXER_OGAIN]	=	VOL_5BIT,
176 	[SOUND_MIXER_LINE2]	=	VOL_5BIT,
177 	[SOUND_MIXER_LINE3]	=	VOL_5BIT,
178 	[SOUND_MIXER_DIGITAL1]	=	VOL_5BIT,
179 	[SOUND_MIXER_DIGITAL2]	=	VOL_5BIT,
180 	[SOUND_MIXER_DIGITAL3]	=	VOL_5BIT,
181 	[SOUND_MIXER_RADIO]	=	VOL_5BIT,
182 	[SOUND_MIXER_MONITOR]	=	VOL_5BIT
183 };
184 
185 /* Mixer file operations */
emu10k1_private_mixer(struct emu10k1_card * card,unsigned int cmd,unsigned long arg)186 static int emu10k1_private_mixer(struct emu10k1_card *card, unsigned int cmd, unsigned long arg)
187 {
188 	struct mixer_private_ioctl *ctl;
189 	struct dsp_patch *patch;
190 	u32 size, page;
191 	int addr, size_reg, i, ret;
192 	unsigned int id, ch;
193 
194 	switch (cmd) {
195 
196 	case SOUND_MIXER_PRIVATE3:
197 
198 		ctl = (struct mixer_private_ioctl *) kmalloc(sizeof(struct mixer_private_ioctl), GFP_KERNEL);
199 		if (ctl == NULL)
200 			return -ENOMEM;
201 
202 		if (copy_from_user(ctl, (void *) arg, sizeof(struct mixer_private_ioctl))) {
203 			kfree(ctl);
204 			return -EFAULT;
205 		}
206 
207 		ret = 0;
208 		switch (ctl->cmd) {
209 #ifdef DBGEMU
210 		case CMD_WRITEFN0:
211 			emu10k1_writefn0(card, ctl->val[0], ctl->val[1]);
212 			break;
213 
214 		case CMD_WRITEPTR:
215 			if (ctl->val[1] >= 0x40 || ctl->val[0] > 0xff) {
216 				ret = -EINVAL;
217 				break;
218 			}
219 
220 			if ((ctl->val[0] & 0x7ff) > 0x3f)
221 				ctl->val[1] = 0x00;
222 
223 			sblive_writeptr(card, ctl->val[0], ctl->val[1], ctl->val[2]);
224 
225 			break;
226 #endif
227 		case CMD_READFN0:
228 			ctl->val[2] = emu10k1_readfn0(card, ctl->val[0]);
229 
230 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
231 				ret = -EFAULT;
232 
233 			break;
234 
235 		case CMD_READPTR:
236 			if (ctl->val[1] >= 0x40 || (ctl->val[0] & 0x7ff) > 0xff) {
237 				ret = -EINVAL;
238 				break;
239 			}
240 
241 			if ((ctl->val[0] & 0x7ff) > 0x3f)
242 				ctl->val[1] = 0x00;
243 
244 			ctl->val[2] = sblive_readptr(card, ctl->val[0], ctl->val[1]);
245 
246 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
247 				ret = -EFAULT;
248 
249 			break;
250 
251 		case CMD_SETRECSRC:
252 			switch (ctl->val[0]) {
253 			case WAVERECORD_AC97:
254 				if (card->is_aps) {
255 					ret = -EINVAL;
256 					break;
257 				}
258 
259 				card->wavein.recsrc = WAVERECORD_AC97;
260 				break;
261 
262 			case WAVERECORD_MIC:
263 				card->wavein.recsrc = WAVERECORD_MIC;
264 				break;
265 
266 			case WAVERECORD_FX:
267 				card->wavein.recsrc = WAVERECORD_FX;
268 				card->wavein.fxwc = ctl->val[1] & 0xffff;
269 
270 				if (!card->wavein.fxwc)
271 					ret = -EINVAL;
272 
273 				break;
274 
275 			default:
276 				ret = -EINVAL;
277 				break;
278 			}
279 			break;
280 
281 		case CMD_GETRECSRC:
282 			ctl->val[0] = card->wavein.recsrc;
283 			ctl->val[1] = card->wavein.fxwc;
284 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
285 				ret = -EFAULT;
286 
287 			break;
288 
289 		case CMD_GETVOICEPARAM:
290 			ctl->val[0] = card->waveout.send_routing[0];
291 			ctl->val[1] = card->waveout.send_a[0] | card->waveout.send_b[0] << 8 |
292 			    	      card->waveout.send_c[0] << 16 | card->waveout.send_d[0] << 24;
293 
294 			ctl->val[2] = card->waveout.send_routing[1];
295 			ctl->val[3] = card->waveout.send_a[1] | card->waveout.send_b[1] << 8 |
296 				      card->waveout.send_c[1] << 16 | card->waveout.send_d[1] << 24;
297 
298 			ctl->val[4] = card->waveout.send_routing[2];
299 			ctl->val[5] = card->waveout.send_a[2] | card->waveout.send_b[2] << 8 |
300 				     card->waveout.send_c[2] << 16 | card->waveout.send_d[2] << 24;
301 
302 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
303 				ret = -EFAULT;
304 
305 			break;
306 
307 		case CMD_SETVOICEPARAM:
308 			card->waveout.send_routing[0] = ctl->val[0] & 0xffff;
309 			card->waveout.send_a[0] = ctl->val[1] & 0xff;
310 			card->waveout.send_b[0] = (ctl->val[1] >> 8) & 0xff;
311 			card->waveout.send_c[0] = (ctl->val[1] >> 16) & 0xff;
312 			card->waveout.send_d[0] = (ctl->val[1] >> 24) & 0xff;
313 
314 			card->waveout.send_routing[1] = ctl->val[2] & 0xffff;
315 			card->waveout.send_a[1] = ctl->val[3] & 0xff;
316 			card->waveout.send_b[1] = (ctl->val[3] >> 8) & 0xff;
317 			card->waveout.send_c[1] = (ctl->val[3] >> 16) & 0xff;
318 			card->waveout.send_d[1] = (ctl->val[3] >> 24) & 0xff;
319 
320 			card->waveout.send_routing[2] = ctl->val[4] & 0xffff;
321 			card->waveout.send_a[2] = ctl->val[5] & 0xff;
322 			card->waveout.send_b[2] = (ctl->val[5] >> 8) & 0xff;
323 			card->waveout.send_c[2] = (ctl->val[5] >> 16) & 0xff;
324 			card->waveout.send_d[2] = (ctl->val[5] >> 24) & 0xff;
325 
326 			break;
327 
328 		case CMD_SETMCH_FX:
329 			card->mchannel_fx = ctl->val[0] & 0x000f;
330 			break;
331 
332 		case CMD_GETPATCH:
333 			if (ctl->val[0] == 0) {
334 				if (copy_to_user((void *) arg, &card->mgr.rpatch, sizeof(struct dsp_rpatch)))
335                                 	ret = -EFAULT;
336 			} else {
337 				if ((ctl->val[0] - 1) / PATCHES_PER_PAGE >= card->mgr.current_pages) {
338 					ret = -EINVAL;
339 					break;
340 				}
341 
342 				if (copy_to_user((void *) arg, PATCH(&card->mgr, ctl->val[0] - 1), sizeof(struct dsp_patch)))
343 					ret = -EFAULT;
344 			}
345 
346 			break;
347 
348 		case CMD_GETGPR:
349 			id = ctl->val[0];
350 
351 			if (id > NUM_GPRS) {
352 				ret = -EINVAL;
353 				break;
354 			}
355 
356 			if (copy_to_user((void *) arg, &card->mgr.gpr[id], sizeof(struct dsp_gpr)))
357 				ret = -EFAULT;
358 
359 			break;
360 
361 		case CMD_GETCTLGPR:
362 			addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, &((char *) ctl->val)[PATCH_NAME_SIZE]);
363 			ctl->val[0] = sblive_readptr(card, addr, 0);
364 
365 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
366 				ret = -EFAULT;
367 
368 			break;
369 
370 		case CMD_SETPATCH:
371 			if (ctl->val[0] == 0)
372 				memcpy(&card->mgr.rpatch, &ctl->val[1], sizeof(struct dsp_rpatch));
373 			else {
374 				page = (ctl->val[0] - 1) / PATCHES_PER_PAGE;
375 				if (page > MAX_PATCHES_PAGES) {
376 					ret = -EINVAL;
377 					break;
378 				}
379 
380 				if (page >= card->mgr.current_pages) {
381 					for (i = card->mgr.current_pages; i < page + 1; i++) {
382 				                card->mgr.patch[i] = (void *)__get_free_page(GFP_KERNEL);
383 						if(card->mgr.patch[i] == NULL) {
384 							card->mgr.current_pages = i;
385 							ret = -ENOMEM;
386 							break;
387 						}
388 						memset(card->mgr.patch[i], 0, PAGE_SIZE);
389 					}
390 					card->mgr.current_pages = page + 1;
391 				}
392 
393 				patch = PATCH(&card->mgr, ctl->val[0] - 1);
394 
395 				memcpy(patch, &ctl->val[1], sizeof(struct dsp_patch));
396 
397 				if (patch->code_size == 0) {
398 					for(i = page + 1; i < card->mgr.current_pages; i++)
399                                                 free_page((unsigned long) card->mgr.patch[i]);
400 
401 					card->mgr.current_pages = page + 1;
402 				}
403 			}
404 			break;
405 
406 		case CMD_SETGPR:
407 			if (ctl->val[0] > NUM_GPRS) {
408 				ret = -EINVAL;
409 				break;
410 			}
411 
412 			memcpy(&card->mgr.gpr[ctl->val[0]], &ctl->val[1], sizeof(struct dsp_gpr));
413 			break;
414 
415 		case CMD_SETCTLGPR:
416 			addr = emu10k1_find_control_gpr(&card->mgr, (char *) ctl->val, (char *) ctl->val + PATCH_NAME_SIZE);
417 			emu10k1_set_control_gpr(card, addr, *((s32 *)((char *) ctl->val + 2 * PATCH_NAME_SIZE)), 0);
418 			break;
419 
420 		case CMD_SETGPOUT:
421 			if (ctl->val[0] > 2 || ctl->val[1] > 1) {
422 				ret= -EINVAL;
423 				break;
424 			}
425 
426 			emu10k1_writefn0(card, (1 << 24) | (((ctl->val[0]) + 10) << 16) | HCFG, ctl->val[1]);
427 			break;
428 
429 		case CMD_GETGPR2OSS:
430 			id = ctl->val[0];
431 			ch = ctl->val[1];
432 
433 			if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
434 				ret = -EINVAL;
435 				break;
436 			}
437 
438 			ctl->val[2] = card->mgr.ctrl_gpr[id][ch];
439 
440 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
441 				ret = -EFAULT;
442 
443 			break;
444 
445 		case CMD_SETGPR2OSS:
446 			id = ctl->val[0];
447 			/* 0 == left, 1 == right */
448 			ch = ctl->val[1];
449 			addr = ctl->val[2];
450 
451 			if (id >= SOUND_MIXER_NRDEVICES || ch >= 2) {
452 				ret = -EINVAL;
453 				break;
454 			}
455 
456 			card->mgr.ctrl_gpr[id][ch] = addr;
457 
458 			if (card->is_aps)
459 				break;
460 
461 			if (addr >= 0) {
462 				unsigned int state = card->ac97->mixer_state[id];
463 
464 				if (ch == 1) {
465 					state >>= 8;
466 					card->ac97->stereo_mixers |= (1 << id);
467 				}
468 
469 				card->ac97->supported_mixers |= (1 << id);
470 
471 				if (id == SOUND_MIXER_TREBLE) {
472 					set_treble(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
473 				} else if (id == SOUND_MIXER_BASS) {
474 					set_bass(card, card->ac97->mixer_state[id] & 0xff, (card->ac97->mixer_state[id] >> 8) & 0xff);
475 				} else
476 					emu10k1_set_volume_gpr(card, addr, state & 0xff,
477 							       volume_params[id]);
478 			} else {
479 				card->ac97->stereo_mixers &= ~(1 << id);
480 				card->ac97->stereo_mixers |= card->ac97_stereo_mixers;
481 
482 				if (ch == 0) {
483 					card->ac97->supported_mixers &= ~(1 << id);
484 					card->ac97->supported_mixers |= card->ac97_supported_mixers;
485 				}
486 			}
487 			break;
488 
489 		case CMD_SETPASSTHROUGH:
490 			card->pt.selected = ctl->val[0] ? 1 : 0;
491 			if (card->pt.state != PT_STATE_INACTIVE)
492 				break;
493 
494 			card->pt.spcs_to_use = ctl->val[0] & 0x07;
495 			break;
496 
497 		case CMD_PRIVATE3_VERSION:
498 			ctl->val[0]=PRIVATE3_VERSION;
499 			if (copy_to_user((void *) arg, ctl, sizeof(struct mixer_private_ioctl)))
500 				ret = -EFAULT;
501 			break;
502 
503 		case CMD_AC97_BOOST:
504 			if(ctl->val[0])
505 				emu10k1_ac97_write(card->ac97, 0x18, 0x0);
506 			else
507 				emu10k1_ac97_write(card->ac97, 0x18, 0x0808);
508 			break;
509 		default:
510 			ret = -EINVAL;
511 			break;
512 		}
513 
514 		kfree(ctl);
515 		return ret;
516 		break;
517 
518 	case SOUND_MIXER_PRIVATE4:
519 
520 		if (copy_from_user(&size, (void *) arg, sizeof(size)))
521 			return -EFAULT;
522 
523 		DPD(2, "External tram size %#x\n", size);
524 
525 		if (size > 0x1fffff)
526 			return -EINVAL;
527 
528 		size_reg = 0;
529 
530 		if (size != 0) {
531 			size = (size - 1) >> 14;
532 
533 			while (size) {
534 				size >>= 1;
535 				size_reg++;
536 			}
537 
538 			size = 0x4000 << size_reg;
539 		}
540 
541 		DPD(2, "External tram size %#x %#x\n", size, size_reg);
542 
543 		if (size != card->tankmem.size) {
544 			if (card->tankmem.size > 0) {
545 				emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 1);
546 
547 				sblive_writeptr_tag(card, 0, TCB, 0, TCBS, 0, TAGLIST_END);
548 
549 				pci_free_consistent(card->pci_dev, card->tankmem.size, card->tankmem.addr, card->tankmem.dma_handle);
550 
551 				card->tankmem.size = 0;
552 			}
553 
554 			if (size != 0) {
555 				card->tankmem.addr = pci_alloc_consistent(card->pci_dev, size, &card->tankmem.dma_handle);
556 				if (card->tankmem.addr == NULL)
557 					return -ENOMEM;
558 
559 				card->tankmem.size = size;
560 
561 				sblive_writeptr_tag(card, 0, TCB, (u32) card->tankmem.dma_handle, TCBS, size_reg, TAGLIST_END);
562 
563 				emu10k1_writefn0(card, HCFG_LOCKTANKCACHE, 0);
564 			}
565 		}
566 		return 0;
567 		break;
568 
569 	default:
570 		break;
571 	}
572 
573 	return -EINVAL;
574 }
575 
emu10k1_dsp_mixer(struct emu10k1_card * card,unsigned int oss_mixer,unsigned long arg)576 static int emu10k1_dsp_mixer(struct emu10k1_card *card, unsigned int oss_mixer, unsigned long arg)
577 {
578 	unsigned int left, right;
579 	int val;
580 	int scale;
581 
582 	card->ac97->modcnt++;
583 
584 	if (get_user(val, (int *)arg))
585 		return -EFAULT;
586 
587 	/* cleanse input a little */
588 	right = ((val >> 8)  & 0xff);
589 	left = (val  & 0xff);
590 
591 	if (right > 100) right = 100;
592 	if (left > 100) left = 100;
593 
594 	card->ac97->mixer_state[oss_mixer] = (right << 8) | left;
595 	if (oss_mixer == SOUND_MIXER_TREBLE) {
596 		set_treble(card, left, right);
597 		return 0;
598 	} if (oss_mixer == SOUND_MIXER_BASS) {
599 		set_bass(card, left, right);
600 		return 0;
601 	}
602 
603 	if (oss_mixer == SOUND_MIXER_VOLUME)
604 		scale = 1 << card->ac97->bit_resolution;
605 	else
606 		scale = volume_params[oss_mixer];
607 
608 	emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][0], left, scale);
609 	emu10k1_set_volume_gpr(card, card->mgr.ctrl_gpr[oss_mixer][1], right, scale);
610 
611 	if (card->ac97_supported_mixers & (1 << oss_mixer))
612 		card->ac97->write_mixer(card->ac97, oss_mixer, left, right);
613 
614 	return 0;
615 }
616 
emu10k1_mixer_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)617 static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
618 {
619 	int ret;
620 	struct emu10k1_card *card = file->private_data;
621 	unsigned int oss_mixer = _IOC_NR(cmd);
622 
623 	ret = -EINVAL;
624 	if (!card->is_aps) {
625 		if (cmd == SOUND_MIXER_INFO) {
626 			mixer_info info;
627 
628 			strncpy(info.id, card->ac97->name, sizeof(info.id));
629 			strncpy(info.name, "Creative SBLive - Emu10k1", sizeof(info.name));
630 			info.modify_counter = card->ac97->modcnt;
631 
632 			if (copy_to_user((void *)arg, &info, sizeof(info)))
633 				return -EFAULT;
634 
635 			return 0;
636 		}
637 
638 		if ((_SIOC_DIR(cmd) == (_SIOC_WRITE|_SIOC_READ)) && oss_mixer <= SOUND_MIXER_NRDEVICES)
639 			ret = emu10k1_dsp_mixer(card, oss_mixer, arg);
640 		else
641 			ret = card->ac97->mixer_ioctl(card->ac97, cmd, arg);
642 	}
643 
644 	if (ret < 0)
645 		ret = emu10k1_private_mixer(card, cmd, arg);
646 
647 	return ret;
648 }
649 
emu10k1_mixer_open(struct inode * inode,struct file * file)650 static int emu10k1_mixer_open(struct inode *inode, struct file *file)
651 {
652 	int minor = MINOR(inode->i_rdev);
653 	struct emu10k1_card *card = NULL;
654 	struct list_head *entry;
655 
656 	DPF(4, "emu10k1_mixer_open()\n");
657 
658 	list_for_each(entry, &emu10k1_devs) {
659 		card = list_entry(entry, struct emu10k1_card, list);
660 
661 		if (card->ac97->dev_mixer == minor)
662 			goto match;
663 	}
664 
665 	return -ENODEV;
666 
667       match:
668 	file->private_data = card;
669 	return 0;
670 }
671 
emu10k1_mixer_release(struct inode * inode,struct file * file)672 static int emu10k1_mixer_release(struct inode *inode, struct file *file)
673 {
674 	DPF(4, "emu10k1_mixer_release()\n");
675 	return 0;
676 }
677 
678 struct file_operations emu10k1_mixer_fops = {
679 	owner:		THIS_MODULE,
680 	llseek:		no_llseek,
681 	ioctl:		emu10k1_mixer_ioctl,
682 	open:		emu10k1_mixer_open,
683 	release:	emu10k1_mixer_release,
684 };
685