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