This source file includes following definitions.
- mixer_output
- set_mode
- pas_mixer_set
- mixer_set_levels
- mixer_set_params
- getmixer
- mixer_get_levels
- mixer_get_params
- pas_mixer_reset
- pas_mixer_ioctl
- pas_init_mixer
1 #define _PAS2_MIXER_C_
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 #include "sound_config.h"
33
34 #if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS)
35
36 #include "pas.h"
37
38 #define TRACE(what)
39
40 extern int translat_code;
41
42 static int rec_devices = (SOUND_MASK_MIC);
43 static int mode_control = 0;
44
45 #define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
46 SOUND_MASK_CD | SOUND_MASK_ALTPCM)
47
48 #define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
49 SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \
50 SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \
51 SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD)
52
53 static unsigned short levels[SOUND_MIXER_NRDEVICES] =
54 {
55 0x3232,
56 0x3232,
57 0x3232,
58 0x5050,
59 0x4b4b,
60 0x3232,
61 0x4b4b,
62 0x4b4b,
63 0x4b4b,
64 0x6464,
65 0x4b4b,
66 0x6464};
67
68 static int
69 mixer_output (int right_vol, int left_vol, int div, int bits,
70 int mixer )
71 {
72 int left = left_vol * div / 100;
73 int right = right_vol * div / 100;
74
75
76
77
78
79
80
81
82
83 if (bits & P_M_MV508_MIXER)
84 {
85 left |= mixer;
86 right |= mixer;
87 }
88
89 if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE)
90 {
91 pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER);
92 pas_write (left, PARALLEL_MIXER);
93 right_vol = left_vol;
94 }
95 else
96 {
97 pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER);
98 pas_write (left, PARALLEL_MIXER);
99 pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER);
100 pas_write (right, PARALLEL_MIXER);
101 }
102
103 return (left_vol | (right_vol << 8));
104 }
105
106 void
107 set_mode (int new_mode)
108 {
109 pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER);
110 pas_write (new_mode, PARALLEL_MIXER);
111
112 mode_control = new_mode;
113 }
114
115 static int
116 pas_mixer_set (int whichDev, unsigned int level)
117 {
118 int left, right, devmask, changed, i, mixer = 0;
119
120 TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
121
122 left = level & 0x7f;
123 right = (level & 0x7f00) >> 8;
124
125 if (whichDev < SOUND_MIXER_NRDEVICES)
126 if ((1 << whichDev) & rec_devices)
127 mixer = P_M_MV508_INPUTMIX;
128 else
129 mixer = P_M_MV508_OUTPUTMIX;
130
131 switch (whichDev)
132 {
133 case SOUND_MIXER_VOLUME:
134 levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0);
135 break;
136
137
138
139
140
141 case SOUND_MIXER_BASS:
142 levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0);
143 break;
144 case SOUND_MIXER_TREBLE:
145 levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0);
146 break;
147
148 case SOUND_MIXER_SYNTH:
149 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer);
150 break;
151 case SOUND_MIXER_PCM:
152 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer);
153 break;
154 case SOUND_MIXER_ALTPCM:
155 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer);
156 break;
157 case SOUND_MIXER_SPEAKER:
158 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer);
159 break;
160 case SOUND_MIXER_LINE:
161 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer);
162 break;
163 case SOUND_MIXER_CD:
164 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer);
165 break;
166 case SOUND_MIXER_MIC:
167 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer);
168 break;
169 case SOUND_MIXER_IMIX:
170
171 levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER,
172 P_M_MV508_OUTPUTMIX);
173 break;
174 case SOUND_MIXER_RECLEV:
175 levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0);
176 break;
177
178 case SOUND_MIXER_MUTE:
179 return 0;
180 break;
181
182 case SOUND_MIXER_ENHANCE:
183 i = 0;
184 level &= 0x7f;
185 if (level)
186 i = (level / 20) - 1;
187
188 mode_control &= ~P_M_MV508_ENHANCE_BITS;
189 mode_control |= P_M_MV508_ENHANCE_BITS;
190 set_mode (mode_control);
191
192 if (i)
193 i = (i + 1) * 20;
194 return i;
195 break;
196
197 case SOUND_MIXER_LOUD:
198 mode_control &= ~P_M_MV508_LOUDNESS;
199 if (level)
200 mode_control |= P_M_MV508_LOUDNESS;
201 set_mode (mode_control);
202 return !!level;
203 break;
204
205 case SOUND_MIXER_RECSRC:
206 devmask = level & POSSIBLE_RECORDING_DEVICES;
207
208 changed = devmask ^ rec_devices;
209 rec_devices = devmask;
210
211 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
212 if (changed & (1 << i))
213 {
214 pas_mixer_set (i, levels[i]);
215 }
216 return rec_devices;
217 break;
218
219 default:
220 return RET_ERROR (EINVAL);
221 }
222
223 return (levels[whichDev]);
224 }
225
226
227
228 static int
229 mixer_set_levels (struct sb_mixer_levels *user_l)
230 {
231 #define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15))
232
233 struct sb_mixer_levels l;
234
235 IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l));
236
237 if (l.master.l & ~0xF || l.master.r & ~0xF
238 || l.line.l & ~0xF || l.line.r & ~0xF
239 || l.voc.l & ~0xF || l.voc.r & ~0xF
240 || l.fm.l & ~0xF || l.fm.r & ~0xF
241 || l.cd.l & ~0xF || l.cd.r & ~0xF
242 || l.mic & ~0x7)
243 return (RET_ERROR (EINVAL));
244
245 pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master));
246 pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line));
247 pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc));
248 pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc));
249 pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm));
250 pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd));
251 pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8));
252 return (0);
253 }
254
255
256
257
258
259 static int
260 mixer_set_params (struct sb_mixer_params *user_p)
261 {
262 struct sb_mixer_params p;
263 S_BYTE val;
264 int src;
265 unsigned long flags;
266
267 IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p));
268
269 if (p.record_source != SRC_MIC
270 && p.record_source != SRC_CD
271 && p.record_source != SRC_LINE)
272 return (RET_ERROR (EINVAL));
273
274
275
276
277
278
279
280 DISABLE_INTR (flags);
281
282 val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L;
283 if (!p.dsp_stereo)
284 val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R);
285 pas_write (val, PCM_CONTROL);
286
287 RESTORE_INTR (flags);
288
289 switch (p.record_source)
290 {
291 case SRC_CD:
292 src = SOUND_MASK_CD;
293 break;
294
295 case SRC_LINE:
296 src = SOUND_MASK_LINE;
297 break;
298
299 default:
300 src = SOUND_MASK_MIC;
301 break;
302 }
303
304 pas_mixer_set (SOUND_MIXER_RECSRC, src);
305
306
307
308
309
310 return (0);
311 }
312
313 static int
314 getmixer (int dev, int chn)
315 {
316 if (chn == P_M_MV508_RIGHT)
317 {
318 return (levels[dev] >> 8) & 0x7f;
319 }
320 else
321 {
322 return levels[dev] & 0x7f;
323 }
324 }
325
326
327 static int
328 mixer_get_levels (struct sb_mixer_levels *user_l)
329 {
330
331 struct sb_mixer_levels l;
332
333 l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100;
334 l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100;
335
336 l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100;
337 l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100;
338
339 l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100;
340 l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100;
341
342 l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100;
343 l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100;
344
345 l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100;
346 l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100;
347
348 l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100;
349
350 IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l));
351 return (0);
352 }
353
354
355 static int
356 mixer_get_params (struct sb_mixer_params *user_params)
357 {
358 S_BYTE val;
359 struct sb_mixer_params params;
360
361 switch (rec_devices)
362 {
363 case SOUND_MASK_CD:
364 params.record_source = SRC_CD;
365 break;
366
367 case SOUND_MASK_LINE:
368 params.record_source = SRC_LINE;
369 break;
370
371 case SOUND_MASK_MIC:
372 params.record_source = SRC_MIC;
373 break;
374
375 default:
376 params.record_source = SRC_MIC;
377 pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC);
378 }
379
380 params.hifreq_filter = OFF;
381 params.filter_input = OFF;
382 params.filter_output = OFF;
383
384 val = INB (PCM_CONTROL);
385 params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R));
386
387 IOCTL_TO_USER ((char *) user_params, 0, (char *) ¶ms, sizeof (params));
388 return (0);
389 }
390
391
392
393 static void
394 pas_mixer_reset (void)
395 {
396 int foo;
397
398 TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n"));
399
400 for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
401 pas_mixer_set (foo, levels[foo]);
402
403 set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40);
404 }
405
406 int
407 pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg)
408 {
409 TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
410
411 if (((cmd >> 8) & 0xff) == 'M')
412 {
413 if (cmd & IOC_IN)
414 return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg)));
415 else
416 {
417
418 switch (cmd & 0xff)
419 {
420
421 case SOUND_MIXER_RECSRC:
422 return IOCTL_OUT (arg, rec_devices);
423 break;
424
425 case SOUND_MIXER_STEREODEVS:
426 return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
427 break;
428
429 case SOUND_MIXER_DEVMASK:
430 return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES);
431 break;
432
433 case SOUND_MIXER_RECMASK:
434 return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
435 break;
436
437 case SOUND_MIXER_CAPS:
438 return IOCTL_OUT (arg, 0);
439 break;
440
441 case SOUND_MIXER_MUTE:
442 return IOCTL_OUT (arg, 0);
443 break;
444
445 case SOUND_MIXER_ENHANCE:
446 if (!(mode_control & P_M_MV508_ENHANCE_BITS))
447 return IOCTL_OUT (arg, 0);
448 return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20);
449 break;
450
451 case SOUND_MIXER_LOUD:
452 if (mode_control & P_M_MV508_LOUDNESS)
453 return IOCTL_OUT (arg, 1);
454 return IOCTL_OUT (arg, 0);
455 break;
456
457 default:
458 return IOCTL_OUT (arg, levels[cmd & 0xff]);
459 }
460 }
461 }
462 else
463 {
464 switch (cmd)
465 {
466 case MIXER_IOCTL_SET_LEVELS:
467 mixer_set_levels ((struct sb_mixer_levels *) arg);
468 return mixer_get_levels ((struct sb_mixer_levels *) arg);
469 case MIXER_IOCTL_SET_PARAMS:
470 mixer_set_params ((struct sb_mixer_params *) arg);
471 return mixer_get_params ((struct sb_mixer_params *) arg);
472 case MIXER_IOCTL_READ_LEVELS:
473 return mixer_get_levels ((struct sb_mixer_levels *) arg);
474 case MIXER_IOCTL_READ_PARAMS:
475 return mixer_get_params ((struct sb_mixer_params *) arg);
476 case MIXER_IOCTL_RESET:
477 pas_mixer_reset ();
478 return (0);
479 default:
480 return RET_ERROR (EINVAL);
481 }
482 }
483 return RET_ERROR (EINVAL);
484 }
485
486 static struct mixer_operations pas_mixer_operations =
487 {
488 pas_mixer_ioctl
489 };
490
491 int
492 pas_init_mixer (void)
493 {
494 pas_mixer_reset ();
495
496 mixer_devs[num_mixers++] = &pas_mixer_operations;
497 return 1;
498 }
499
500 #endif