1 2 /* 3 * sound/oss/pas2_mixer.c 4 * 5 * Mixer routines for the Pro Audio Spectrum cards. 6 */ 7 8 /* 9 * Copyright (C) by Hannu Savolainen 1993-1997 10 * 11 * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) 12 * Version 2 (June 1991). See the "COPYING" file distributed with this software 13 * for more info. 14 */ 15 /* 16 * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) 17 * Bartlomiej Zolnierkiewicz : added __init to pas_init_mixer() 18 */ 19 #include <linux/init.h> 20 #include "sound_config.h" 21 22 #include "pas2.h" 23 24 extern int pas_translate_code; 25 extern char pas_model; 26 extern int *pas_osp; 27 extern int pas_audiodev; 28 29 static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ 30 static int mode_control; 31 32 #define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ 33 SOUND_MASK_CD | SOUND_MASK_ALTPCM) 34 35 #define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ 36 SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ 37 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV) 38 39 static int *levels; 40 41 static int default_levels[32] = 42 { 43 0x3232, /* Master Volume */ 44 0x3232, /* Bass */ 45 0x3232, /* Treble */ 46 0x5050, /* FM */ 47 0x4b4b, /* PCM */ 48 0x3232, /* PC Speaker */ 49 0x4b4b, /* Ext Line */ 50 0x4b4b, /* Mic */ 51 0x4b4b, /* CD */ 52 0x6464, /* Recording monitor */ 53 0x4b4b, /* SB PCM */ 54 0x6464 /* Recording level */ 55 }; 56 57 void mix_write(unsigned char data,int ioaddr)58 mix_write(unsigned char data, int ioaddr) 59 { 60 /* 61 * The Revision D cards have a problem with their MVA508 interface. The 62 * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and 63 * MSBs out of the output byte and to do a 16-bit out to the mixer port - 64 * 1. We need to do this because it isn't timing problem but chip access 65 * sequence problem. 66 */ 67 68 if (pas_model == 4) 69 { 70 outw(data | (data << 8), (ioaddr + pas_translate_code) - 1); 71 outb((0x80), 0); 72 } else 73 pas_write(data, ioaddr); 74 } 75 76 static int mixer_output(int right_vol,int left_vol,int div,int bits,int mixer)77 mixer_output(int right_vol, int left_vol, int div, int bits, 78 int mixer) /* Input or output mixer */ 79 { 80 int left = left_vol * div / 100; 81 int right = right_vol * div / 100; 82 83 84 if (bits & 0x10) 85 { 86 left |= mixer; 87 right |= mixer; 88 } 89 if (bits == 0x03 || bits == 0x04) 90 { 91 mix_write(0x80 | bits, 0x078B); 92 mix_write(left, 0x078B); 93 right_vol = left_vol; 94 } else 95 { 96 mix_write(0x80 | 0x20 | bits, 0x078B); 97 mix_write(left, 0x078B); 98 mix_write(0x80 | 0x40 | bits, 0x078B); 99 mix_write(right, 0x078B); 100 } 101 102 return (left_vol | (right_vol << 8)); 103 } 104 105 static void set_mode(int new_mode)106 set_mode(int new_mode) 107 { 108 mix_write(0x80 | 0x05, 0x078B); 109 mix_write(new_mode, 0x078B); 110 111 mode_control = new_mode; 112 } 113 114 static int pas_mixer_set(int whichDev,unsigned int level)115 pas_mixer_set(int whichDev, unsigned int level) 116 { 117 int left, right, devmask, changed, i, mixer = 0; 118 119 left = level & 0x7f; 120 right = (level & 0x7f00) >> 8; 121 122 if (whichDev < SOUND_MIXER_NRDEVICES) { 123 if ((1 << whichDev) & rec_devices) 124 mixer = 0x20; 125 else 126 mixer = 0x00; 127 } 128 129 switch (whichDev) 130 { 131 case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ 132 levels[whichDev] = mixer_output(right, left, 63, 0x01, 0); 133 break; 134 135 /* 136 * Note! Bass and Treble are mono devices. Will use just the left 137 * channel. 138 */ 139 case SOUND_MIXER_BASS: /* Bass (0-12) */ 140 levels[whichDev] = mixer_output(right, left, 12, 0x03, 0); 141 break; 142 case SOUND_MIXER_TREBLE: /* Treble (0-12) */ 143 levels[whichDev] = mixer_output(right, left, 12, 0x04, 0); 144 break; 145 146 case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ 147 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x00, mixer); 148 break; 149 case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ 150 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x05, mixer); 151 break; 152 case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ 153 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x07, mixer); 154 break; 155 case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ 156 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x06, mixer); 157 break; 158 case SOUND_MIXER_LINE: /* External line (0-31) */ 159 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x02, mixer); 160 break; 161 case SOUND_MIXER_CD: /* CD (0-31) */ 162 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x03, mixer); 163 break; 164 case SOUND_MIXER_MIC: /* External microphone (0-31) */ 165 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x04, mixer); 166 break; 167 case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Output mixer only) */ 168 levels[whichDev] = mixer_output(right, left, 31, 0x10 | 0x01, 169 0x00); 170 break; 171 case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ 172 levels[whichDev] = mixer_output(right, left, 15, 0x02, 0); 173 break; 174 175 176 case SOUND_MIXER_RECSRC: 177 devmask = level & POSSIBLE_RECORDING_DEVICES; 178 179 changed = devmask ^ rec_devices; 180 rec_devices = devmask; 181 182 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) 183 if (changed & (1 << i)) 184 { 185 pas_mixer_set(i, levels[i]); 186 } 187 return rec_devices; 188 break; 189 190 default: 191 return -EINVAL; 192 } 193 194 return (levels[whichDev]); 195 } 196 197 /*****/ 198 199 static void pas_mixer_reset(void)200 pas_mixer_reset(void) 201 { 202 int foo; 203 204 for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) 205 pas_mixer_set(foo, levels[foo]); 206 207 set_mode(0x04 | 0x01); 208 } 209 pas_mixer_ioctl(int dev,unsigned int cmd,void __user * arg)210 static int pas_mixer_ioctl(int dev, unsigned int cmd, void __user *arg) 211 { 212 int level,v ; 213 int __user *p = (int __user *)arg; 214 215 if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */ 216 if (get_user(level, p)) 217 return -EFAULT; 218 if (level == -1) /* Return current settings */ 219 level = (mode_control & 0x04); 220 else { 221 mode_control &= ~0x04; 222 if (level) 223 mode_control |= 0x04; 224 set_mode(mode_control); 225 } 226 level = !!level; 227 return put_user(level, p); 228 } 229 if (cmd == SOUND_MIXER_PRIVATE2) { /* Set enhance bit */ 230 if (get_user(level, p)) 231 return -EFAULT; 232 if (level == -1) { /* Return current settings */ 233 if (!(mode_control & 0x03)) 234 level = 0; 235 else 236 level = ((mode_control & 0x03) + 1) * 20; 237 } else { 238 int i = 0; 239 240 level &= 0x7f; 241 if (level) 242 i = (level / 20) - 1; 243 mode_control &= ~0x03; 244 mode_control |= i & 0x03; 245 set_mode(mode_control); 246 if (i) 247 i = (i + 1) * 20; 248 level = i; 249 } 250 return put_user(level, p); 251 } 252 if (cmd == SOUND_MIXER_PRIVATE3) { /* Set mute bit */ 253 if (get_user(level, p)) 254 return -EFAULT; 255 if (level == -1) /* Return current settings */ 256 level = !(pas_read(0x0B8A) & 0x20); 257 else { 258 if (level) 259 pas_write(pas_read(0x0B8A) & (~0x20), 0x0B8A); 260 else 261 pas_write(pas_read(0x0B8A) | 0x20, 0x0B8A); 262 263 level = !(pas_read(0x0B8A) & 0x20); 264 } 265 return put_user(level, p); 266 } 267 if (((cmd >> 8) & 0xff) == 'M') { 268 if (get_user(v, p)) 269 return -EFAULT; 270 if (_SIOC_DIR(cmd) & _SIOC_WRITE) { 271 v = pas_mixer_set(cmd & 0xff, v); 272 } else { 273 switch (cmd & 0xff) { 274 case SOUND_MIXER_RECSRC: 275 v = rec_devices; 276 break; 277 278 case SOUND_MIXER_STEREODEVS: 279 v = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE); 280 break; 281 282 case SOUND_MIXER_DEVMASK: 283 v = SUPPORTED_MIXER_DEVICES; 284 break; 285 286 case SOUND_MIXER_RECMASK: 287 v = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES; 288 break; 289 290 case SOUND_MIXER_CAPS: 291 v = 0; /* No special capabilities */ 292 break; 293 294 default: 295 v = levels[cmd & 0xff]; 296 break; 297 } 298 } 299 return put_user(v, p); 300 } 301 return -EINVAL; 302 } 303 304 static struct mixer_operations pas_mixer_operations = 305 { 306 .owner = THIS_MODULE, 307 .id = "PAS16", 308 .name = "Pro Audio Spectrum 16", 309 .ioctl = pas_mixer_ioctl 310 }; 311 312 int __init pas_init_mixer(void)313 pas_init_mixer(void) 314 { 315 int d; 316 317 levels = load_mixer_volumes("PAS16_1", default_levels, 1); 318 319 pas_mixer_reset(); 320 321 if ((d = sound_alloc_mixerdev()) != -1) 322 { 323 audio_devs[pas_audiodev]->mixer_dev = d; 324 mixer_devs[d] = &pas_mixer_operations; 325 } 326 return 1; 327 } 328