File: /usr/src/linux/drivers/sound/pas2_mixer.c

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