xref: /openbmc/linux/sound/core/oss/mixer_oss.c (revision 565d76cb)
1 /*
2  *  OSS emulation layer for the mixer interface
3  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4  *
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19  *
20  */
21 
22 #include <linux/init.h>
23 #include <linux/slab.h>
24 #include <linux/time.h>
25 #include <linux/string.h>
26 #include <sound/core.h>
27 #include <sound/minors.h>
28 #include <sound/control.h>
29 #include <sound/info.h>
30 #include <sound/mixer_oss.h>
31 #include <linux/soundcard.h>
32 
33 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
34 
35 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
36 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
37 MODULE_LICENSE("GPL");
38 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
39 
40 static int snd_mixer_oss_open(struct inode *inode, struct file *file)
41 {
42 	struct snd_card *card;
43 	struct snd_mixer_oss_file *fmixer;
44 	int err;
45 
46 	err = nonseekable_open(inode, file);
47 	if (err < 0)
48 		return err;
49 
50 	card = snd_lookup_oss_minor_data(iminor(inode),
51 					 SNDRV_OSS_DEVICE_TYPE_MIXER);
52 	if (card == NULL)
53 		return -ENODEV;
54 	if (card->mixer_oss == NULL)
55 		return -ENODEV;
56 	err = snd_card_file_add(card, file);
57 	if (err < 0)
58 		return err;
59 	fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
60 	if (fmixer == NULL) {
61 		snd_card_file_remove(card, file);
62 		return -ENOMEM;
63 	}
64 	fmixer->card = card;
65 	fmixer->mixer = card->mixer_oss;
66 	file->private_data = fmixer;
67 	if (!try_module_get(card->module)) {
68 		kfree(fmixer);
69 		snd_card_file_remove(card, file);
70 		return -EFAULT;
71 	}
72 	return 0;
73 }
74 
75 static int snd_mixer_oss_release(struct inode *inode, struct file *file)
76 {
77 	struct snd_mixer_oss_file *fmixer;
78 
79 	if (file->private_data) {
80 		fmixer = file->private_data;
81 		module_put(fmixer->card->module);
82 		snd_card_file_remove(fmixer->card, file);
83 		kfree(fmixer);
84 	}
85 	return 0;
86 }
87 
88 static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
89 			      mixer_info __user *_info)
90 {
91 	struct snd_card *card = fmixer->card;
92 	struct snd_mixer_oss *mixer = fmixer->mixer;
93 	struct mixer_info info;
94 
95 	memset(&info, 0, sizeof(info));
96 	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
97 	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
98 	info.modify_counter = card->mixer_oss_change_count;
99 	if (copy_to_user(_info, &info, sizeof(info)))
100 		return -EFAULT;
101 	return 0;
102 }
103 
104 static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
105 				       _old_mixer_info __user *_info)
106 {
107 	struct snd_card *card = fmixer->card;
108 	struct snd_mixer_oss *mixer = fmixer->mixer;
109 	_old_mixer_info info;
110 
111 	memset(&info, 0, sizeof(info));
112 	strlcpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
113 	strlcpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
114 	if (copy_to_user(_info, &info, sizeof(info)))
115 		return -EFAULT;
116 	return 0;
117 }
118 
119 static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
120 {
121 	struct snd_mixer_oss *mixer = fmixer->mixer;
122 	int result = 0;
123 
124 	if (mixer == NULL)
125 		return -EIO;
126 	if (mixer->get_recsrc && mixer->put_recsrc)
127 		result |= SOUND_CAP_EXCL_INPUT;
128 	return result;
129 }
130 
131 static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
132 {
133 	struct snd_mixer_oss *mixer = fmixer->mixer;
134 	struct snd_mixer_oss_slot *pslot;
135 	int result = 0, chn;
136 
137 	if (mixer == NULL)
138 		return -EIO;
139 	for (chn = 0; chn < 31; chn++) {
140 		pslot = &mixer->slots[chn];
141 		if (pslot->put_volume || pslot->put_recsrc)
142 			result |= 1 << chn;
143 	}
144 	return result;
145 }
146 
147 static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
148 {
149 	struct snd_mixer_oss *mixer = fmixer->mixer;
150 	struct snd_mixer_oss_slot *pslot;
151 	int result = 0, chn;
152 
153 	if (mixer == NULL)
154 		return -EIO;
155 	for (chn = 0; chn < 31; chn++) {
156 		pslot = &mixer->slots[chn];
157 		if (pslot->put_volume && pslot->stereo)
158 			result |= 1 << chn;
159 	}
160 	return result;
161 }
162 
163 static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
164 {
165 	struct snd_mixer_oss *mixer = fmixer->mixer;
166 	int result = 0;
167 
168 	if (mixer == NULL)
169 		return -EIO;
170 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
171 		result = mixer->mask_recsrc;
172 	} else {
173 		struct snd_mixer_oss_slot *pslot;
174 		int chn;
175 		for (chn = 0; chn < 31; chn++) {
176 			pslot = &mixer->slots[chn];
177 			if (pslot->put_recsrc)
178 				result |= 1 << chn;
179 		}
180 	}
181 	return result;
182 }
183 
184 static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
185 {
186 	struct snd_mixer_oss *mixer = fmixer->mixer;
187 	int result = 0;
188 
189 	if (mixer == NULL)
190 		return -EIO;
191 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
192 		int err;
193 		unsigned int index;
194 		if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
195 			return err;
196 		result = 1 << index;
197 	} else {
198 		struct snd_mixer_oss_slot *pslot;
199 		int chn;
200 		for (chn = 0; chn < 31; chn++) {
201 			pslot = &mixer->slots[chn];
202 			if (pslot->get_recsrc) {
203 				int active = 0;
204 				pslot->get_recsrc(fmixer, pslot, &active);
205 				if (active)
206 					result |= 1 << chn;
207 			}
208 		}
209 	}
210 	return mixer->oss_recsrc = result;
211 }
212 
213 static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
214 {
215 	struct snd_mixer_oss *mixer = fmixer->mixer;
216 	struct snd_mixer_oss_slot *pslot;
217 	int chn, active;
218 	unsigned int index;
219 	int result = 0;
220 
221 	if (mixer == NULL)
222 		return -EIO;
223 	if (mixer->get_recsrc && mixer->put_recsrc) {	/* exclusive input */
224 		if (recsrc & ~mixer->oss_recsrc)
225 			recsrc &= ~mixer->oss_recsrc;
226 		mixer->put_recsrc(fmixer, ffz(~recsrc));
227 		mixer->get_recsrc(fmixer, &index);
228 		result = 1 << index;
229 	}
230 	for (chn = 0; chn < 31; chn++) {
231 		pslot = &mixer->slots[chn];
232 		if (pslot->put_recsrc) {
233 			active = (recsrc & (1 << chn)) ? 1 : 0;
234 			pslot->put_recsrc(fmixer, pslot, active);
235 		}
236 	}
237 	if (! result) {
238 		for (chn = 0; chn < 31; chn++) {
239 			pslot = &mixer->slots[chn];
240 			if (pslot->get_recsrc) {
241 				active = 0;
242 				pslot->get_recsrc(fmixer, pslot, &active);
243 				if (active)
244 					result |= 1 << chn;
245 			}
246 		}
247 	}
248 	return result;
249 }
250 
251 static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
252 {
253 	struct snd_mixer_oss *mixer = fmixer->mixer;
254 	struct snd_mixer_oss_slot *pslot;
255 	int result = 0, left, right;
256 
257 	if (mixer == NULL || slot > 30)
258 		return -EIO;
259 	pslot = &mixer->slots[slot];
260 	left = pslot->volume[0];
261 	right = pslot->volume[1];
262 	if (pslot->get_volume)
263 		result = pslot->get_volume(fmixer, pslot, &left, &right);
264 	if (!pslot->stereo)
265 		right = left;
266 	if (snd_BUG_ON(left < 0 || left > 100))
267 		return -EIO;
268 	if (snd_BUG_ON(right < 0 || right > 100))
269 		return -EIO;
270 	if (result >= 0) {
271 		pslot->volume[0] = left;
272 		pslot->volume[1] = right;
273 	 	result = (left & 0xff) | ((right & 0xff) << 8);
274 	}
275 	return result;
276 }
277 
278 static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
279 				    int slot, int volume)
280 {
281 	struct snd_mixer_oss *mixer = fmixer->mixer;
282 	struct snd_mixer_oss_slot *pslot;
283 	int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
284 
285 	if (mixer == NULL || slot > 30)
286 		return -EIO;
287 	pslot = &mixer->slots[slot];
288 	if (left > 100)
289 		left = 100;
290 	if (right > 100)
291 		right = 100;
292 	if (!pslot->stereo)
293 		right = left;
294 	if (pslot->put_volume)
295 		result = pslot->put_volume(fmixer, pslot, left, right);
296 	if (result < 0)
297 		return result;
298 	pslot->volume[0] = left;
299 	pslot->volume[1] = right;
300  	return (left & 0xff) | ((right & 0xff) << 8);
301 }
302 
303 static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
304 {
305 	void __user *argp = (void __user *)arg;
306 	int __user *p = argp;
307 	int tmp;
308 
309 	if (snd_BUG_ON(!fmixer))
310 		return -ENXIO;
311 	if (((cmd >> 8) & 0xff) == 'M') {
312 		switch (cmd) {
313 		case SOUND_MIXER_INFO:
314 			return snd_mixer_oss_info(fmixer, argp);
315 		case SOUND_OLD_MIXER_INFO:
316  			return snd_mixer_oss_info_obsolete(fmixer, argp);
317 		case SOUND_MIXER_WRITE_RECSRC:
318 			if (get_user(tmp, p))
319 				return -EFAULT;
320 			tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
321 			if (tmp < 0)
322 				return tmp;
323 			return put_user(tmp, p);
324 		case OSS_GETVERSION:
325 			return put_user(SNDRV_OSS_VERSION, p);
326 		case OSS_ALSAEMULVER:
327 			return put_user(1, p);
328 		case SOUND_MIXER_READ_DEVMASK:
329 			tmp = snd_mixer_oss_devmask(fmixer);
330 			if (tmp < 0)
331 				return tmp;
332 			return put_user(tmp, p);
333 		case SOUND_MIXER_READ_STEREODEVS:
334 			tmp = snd_mixer_oss_stereodevs(fmixer);
335 			if (tmp < 0)
336 				return tmp;
337 			return put_user(tmp, p);
338 		case SOUND_MIXER_READ_RECMASK:
339 			tmp = snd_mixer_oss_recmask(fmixer);
340 			if (tmp < 0)
341 				return tmp;
342 			return put_user(tmp, p);
343 		case SOUND_MIXER_READ_CAPS:
344 			tmp = snd_mixer_oss_caps(fmixer);
345 			if (tmp < 0)
346 				return tmp;
347 			return put_user(tmp, p);
348 		case SOUND_MIXER_READ_RECSRC:
349 			tmp = snd_mixer_oss_get_recsrc(fmixer);
350 			if (tmp < 0)
351 				return tmp;
352 			return put_user(tmp, p);
353 		}
354 	}
355 	if (cmd & SIOC_IN) {
356 		if (get_user(tmp, p))
357 			return -EFAULT;
358 		tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
359 		if (tmp < 0)
360 			return tmp;
361 		return put_user(tmp, p);
362 	} else if (cmd & SIOC_OUT) {
363 		tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
364 		if (tmp < 0)
365 			return tmp;
366 		return put_user(tmp, p);
367 	}
368 	return -ENXIO;
369 }
370 
371 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
372 {
373 	return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
374 }
375 
376 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
377 {
378 	struct snd_mixer_oss_file fmixer;
379 
380 	if (snd_BUG_ON(!card))
381 		return -ENXIO;
382 	if (card->mixer_oss == NULL)
383 		return -ENXIO;
384 	memset(&fmixer, 0, sizeof(fmixer));
385 	fmixer.card = card;
386 	fmixer.mixer = card->mixer_oss;
387 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
388 }
389 
390 #ifdef CONFIG_COMPAT
391 /* all compatible */
392 #define snd_mixer_oss_ioctl_compat	snd_mixer_oss_ioctl
393 #else
394 #define snd_mixer_oss_ioctl_compat	NULL
395 #endif
396 
397 /*
398  *  REGISTRATION PART
399  */
400 
401 static const struct file_operations snd_mixer_oss_f_ops =
402 {
403 	.owner =	THIS_MODULE,
404 	.open =		snd_mixer_oss_open,
405 	.release =	snd_mixer_oss_release,
406 	.llseek =	no_llseek,
407 	.unlocked_ioctl =	snd_mixer_oss_ioctl,
408 	.compat_ioctl =	snd_mixer_oss_ioctl_compat,
409 };
410 
411 /*
412  *  utilities
413  */
414 
415 static long snd_mixer_oss_conv(long val, long omin, long omax, long nmin, long nmax)
416 {
417 	long orange = omax - omin, nrange = nmax - nmin;
418 
419 	if (orange == 0)
420 		return 0;
421 	return ((nrange * (val - omin)) + (orange / 2)) / orange + nmin;
422 }
423 
424 /* convert from alsa native to oss values (0-100) */
425 static long snd_mixer_oss_conv1(long val, long min, long max, int *old)
426 {
427 	if (val == snd_mixer_oss_conv(*old, 0, 100, min, max))
428 		return *old;
429 	return snd_mixer_oss_conv(val, min, max, 0, 100);
430 }
431 
432 /* convert from oss to alsa native values */
433 static long snd_mixer_oss_conv2(long val, long min, long max)
434 {
435 	return snd_mixer_oss_conv(val, 0, 100, min, max);
436 }
437 
438 #if 0
439 static void snd_mixer_oss_recsrce_set(struct snd_card *card, int slot)
440 {
441 	struct snd_mixer_oss *mixer = card->mixer_oss;
442 	if (mixer)
443 		mixer->mask_recsrc |= 1 << slot;
444 }
445 
446 static int snd_mixer_oss_recsrce_get(struct snd_card *card, int slot)
447 {
448 	struct snd_mixer_oss *mixer = card->mixer_oss;
449 	if (mixer && (mixer->mask_recsrc & (1 << slot)))
450 		return 1;
451 	return 0;
452 }
453 #endif
454 
455 #define SNDRV_MIXER_OSS_SIGNATURE		0x65999250
456 
457 #define SNDRV_MIXER_OSS_ITEM_GLOBAL	0
458 #define SNDRV_MIXER_OSS_ITEM_GSWITCH	1
459 #define SNDRV_MIXER_OSS_ITEM_GROUTE	2
460 #define SNDRV_MIXER_OSS_ITEM_GVOLUME	3
461 #define SNDRV_MIXER_OSS_ITEM_PSWITCH	4
462 #define SNDRV_MIXER_OSS_ITEM_PROUTE	5
463 #define SNDRV_MIXER_OSS_ITEM_PVOLUME	6
464 #define SNDRV_MIXER_OSS_ITEM_CSWITCH	7
465 #define SNDRV_MIXER_OSS_ITEM_CROUTE	8
466 #define SNDRV_MIXER_OSS_ITEM_CVOLUME	9
467 #define SNDRV_MIXER_OSS_ITEM_CAPTURE	10
468 
469 #define SNDRV_MIXER_OSS_ITEM_COUNT	11
470 
471 #define SNDRV_MIXER_OSS_PRESENT_GLOBAL	(1<<0)
472 #define SNDRV_MIXER_OSS_PRESENT_GSWITCH	(1<<1)
473 #define SNDRV_MIXER_OSS_PRESENT_GROUTE	(1<<2)
474 #define SNDRV_MIXER_OSS_PRESENT_GVOLUME	(1<<3)
475 #define SNDRV_MIXER_OSS_PRESENT_PSWITCH	(1<<4)
476 #define SNDRV_MIXER_OSS_PRESENT_PROUTE	(1<<5)
477 #define SNDRV_MIXER_OSS_PRESENT_PVOLUME	(1<<6)
478 #define SNDRV_MIXER_OSS_PRESENT_CSWITCH	(1<<7)
479 #define SNDRV_MIXER_OSS_PRESENT_CROUTE	(1<<8)
480 #define SNDRV_MIXER_OSS_PRESENT_CVOLUME	(1<<9)
481 #define SNDRV_MIXER_OSS_PRESENT_CAPTURE	(1<<10)
482 
483 struct slot {
484 	unsigned int signature;
485 	unsigned int present;
486 	unsigned int channels;
487 	unsigned int numid[SNDRV_MIXER_OSS_ITEM_COUNT];
488 	unsigned int capture_item;
489 	struct snd_mixer_oss_assign_table *assigned;
490 	unsigned int allocated: 1;
491 };
492 
493 #define ID_UNKNOWN	((unsigned int)-1)
494 
495 static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, const char *name, int index)
496 {
497 	struct snd_card *card = mixer->card;
498 	struct snd_ctl_elem_id id;
499 
500 	memset(&id, 0, sizeof(id));
501 	id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
502 	strcpy(id.name, name);
503 	id.index = index;
504 	return snd_ctl_find_id(card, &id);
505 }
506 
507 static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
508 					  struct snd_mixer_oss_slot *pslot,
509 					  unsigned int numid,
510 					  int *left, int *right)
511 {
512 	struct snd_ctl_elem_info *uinfo;
513 	struct snd_ctl_elem_value *uctl;
514 	struct snd_kcontrol *kctl;
515 	struct snd_card *card = fmixer->card;
516 
517 	if (numid == ID_UNKNOWN)
518 		return;
519 	down_read(&card->controls_rwsem);
520 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
521 		up_read(&card->controls_rwsem);
522 		return;
523 	}
524 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
525 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
526 	if (uinfo == NULL || uctl == NULL)
527 		goto __unalloc;
528 	if (kctl->info(kctl, uinfo))
529 		goto __unalloc;
530 	if (kctl->get(kctl, uctl))
531 		goto __unalloc;
532 	if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
533 	    uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
534 		goto __unalloc;
535 	*left = snd_mixer_oss_conv1(uctl->value.integer.value[0], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[0]);
536 	if (uinfo->count > 1)
537 		*right = snd_mixer_oss_conv1(uctl->value.integer.value[1], uinfo->value.integer.min, uinfo->value.integer.max, &pslot->volume[1]);
538       __unalloc:
539 	up_read(&card->controls_rwsem);
540       	kfree(uctl);
541       	kfree(uinfo);
542 }
543 
544 static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
545 					 struct snd_mixer_oss_slot *pslot,
546 					 unsigned int numid,
547 					 int *left, int *right,
548 					 int route)
549 {
550 	struct snd_ctl_elem_info *uinfo;
551 	struct snd_ctl_elem_value *uctl;
552 	struct snd_kcontrol *kctl;
553 	struct snd_card *card = fmixer->card;
554 
555 	if (numid == ID_UNKNOWN)
556 		return;
557 	down_read(&card->controls_rwsem);
558 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
559 		up_read(&card->controls_rwsem);
560 		return;
561 	}
562 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
563 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
564 	if (uinfo == NULL || uctl == NULL)
565 		goto __unalloc;
566 	if (kctl->info(kctl, uinfo))
567 		goto __unalloc;
568 	if (kctl->get(kctl, uctl))
569 		goto __unalloc;
570 	if (!uctl->value.integer.value[0]) {
571 		*left = 0;
572 		if (uinfo->count == 1)
573 			*right = 0;
574 	}
575 	if (uinfo->count > 1 && !uctl->value.integer.value[route ? 3 : 1])
576 		*right = 0;
577       __unalloc:
578 	up_read(&card->controls_rwsem);
579       	kfree(uctl);
580 	kfree(uinfo);
581 }
582 
583 static int snd_mixer_oss_get_volume1(struct snd_mixer_oss_file *fmixer,
584 				     struct snd_mixer_oss_slot *pslot,
585 				     int *left, int *right)
586 {
587 	struct slot *slot = pslot->private_data;
588 
589 	*left = *right = 100;
590 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
591 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
592 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
593 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
594 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
595 		snd_mixer_oss_get_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
596 	}
597 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
598 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
599 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
600 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
601 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
602 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
603 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
604 		snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
605 	}
606 	return 0;
607 }
608 
609 static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
610 					  struct snd_mixer_oss_slot *pslot,
611 					  unsigned int numid,
612 					  int left, int right)
613 {
614 	struct snd_ctl_elem_info *uinfo;
615 	struct snd_ctl_elem_value *uctl;
616 	struct snd_kcontrol *kctl;
617 	struct snd_card *card = fmixer->card;
618 	int res;
619 
620 	if (numid == ID_UNKNOWN)
621 		return;
622 	down_read(&card->controls_rwsem);
623 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
624 		up_read(&card->controls_rwsem);
625 		return;
626 	}
627 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
628 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
629 	if (uinfo == NULL || uctl == NULL)
630 		goto __unalloc;
631 	if (kctl->info(kctl, uinfo))
632 		goto __unalloc;
633 	if (uinfo->type == SNDRV_CTL_ELEM_TYPE_BOOLEAN &&
634 	    uinfo->value.integer.min == 0 && uinfo->value.integer.max == 1)
635 		goto __unalloc;
636 	uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
637 	if (uinfo->count > 1)
638 		uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
639 	if ((res = kctl->put(kctl, uctl)) < 0)
640 		goto __unalloc;
641 	if (res > 0)
642 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
643       __unalloc:
644 	up_read(&card->controls_rwsem);
645       	kfree(uctl);
646 	kfree(uinfo);
647 }
648 
649 static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
650 					 struct snd_mixer_oss_slot *pslot,
651 					 unsigned int numid,
652 					 int left, int right,
653 					 int route)
654 {
655 	struct snd_ctl_elem_info *uinfo;
656 	struct snd_ctl_elem_value *uctl;
657 	struct snd_kcontrol *kctl;
658 	struct snd_card *card = fmixer->card;
659 	int res;
660 
661 	if (numid == ID_UNKNOWN)
662 		return;
663 	down_read(&card->controls_rwsem);
664 	if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
665 		up_read(&card->controls_rwsem);
666 		return;
667 	}
668 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
669 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
670 	if (uinfo == NULL || uctl == NULL)
671 		goto __unalloc;
672 	if (kctl->info(kctl, uinfo))
673 		goto __unalloc;
674 	if (uinfo->count > 1) {
675 		uctl->value.integer.value[0] = left > 0 ? 1 : 0;
676 		uctl->value.integer.value[route ? 3 : 1] = right > 0 ? 1 : 0;
677 		if (route) {
678 			uctl->value.integer.value[1] =
679 			uctl->value.integer.value[2] = 0;
680 		}
681 	} else {
682 		uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
683 	}
684 	if ((res = kctl->put(kctl, uctl)) < 0)
685 		goto __unalloc;
686 	if (res > 0)
687 		snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
688       __unalloc:
689 	up_read(&card->controls_rwsem);
690       	kfree(uctl);
691 	kfree(uinfo);
692 }
693 
694 static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
695 				     struct snd_mixer_oss_slot *pslot,
696 				     int left, int right)
697 {
698 	struct slot *slot = pslot->private_data;
699 
700 	if (slot->present & SNDRV_MIXER_OSS_PRESENT_PVOLUME) {
701 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
702 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
703 			snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
704 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
705 		snd_mixer_oss_put_volume1_vol(fmixer, pslot,
706 			slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
707 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
708 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
709 	} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
710 		snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GLOBAL], left, right);
711 	}
712 	if (left || right) {
713 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH)
714 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
715 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH)
716 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
717 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH)
718 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
719 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE)
720 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
721 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE)
722 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
723 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE)
724 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
725 	} else {
726 		if (slot->present & SNDRV_MIXER_OSS_PRESENT_PSWITCH) {
727 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PSWITCH], left, right, 0);
728 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
729 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], left, right, 0);
730 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GSWITCH) {
731 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GSWITCH], left, right, 0);
732 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_PROUTE) {
733 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PROUTE], left, right, 1);
734 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
735 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], left, right, 1);
736 		} else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GROUTE) {
737 			snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GROUTE], left, right, 1);
738 		}
739 	}
740 	return 0;
741 }
742 
743 static int snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
744 					struct snd_mixer_oss_slot *pslot,
745 					int *active)
746 {
747 	struct slot *slot = pslot->private_data;
748 	int left, right;
749 
750 	left = right = 1;
751 	snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], &left, &right, 0);
752 	*active = (left || right) ? 1 : 0;
753 	return 0;
754 }
755 
756 static int snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file *fmixer,
757 					   struct snd_mixer_oss_slot *pslot,
758 					   int *active)
759 {
760 	struct slot *slot = pslot->private_data;
761 	int left, right;
762 
763 	left = right = 1;
764 	snd_mixer_oss_get_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], &left, &right, 1);
765 	*active = (left || right) ? 1 : 0;
766 	return 0;
767 }
768 
769 static int snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file *fmixer,
770 					struct snd_mixer_oss_slot *pslot,
771 					int active)
772 {
773 	struct slot *slot = pslot->private_data;
774 
775 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CSWITCH], active, active, 0);
776 	return 0;
777 }
778 
779 static int snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file *fmixer,
780 					   struct snd_mixer_oss_slot *pslot,
781 					   int active)
782 {
783 	struct slot *slot = pslot->private_data;
784 
785 	snd_mixer_oss_put_volume1_sw(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CROUTE], active, active, 1);
786 	return 0;
787 }
788 
789 static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int *active_index)
790 {
791 	struct snd_card *card = fmixer->card;
792 	struct snd_mixer_oss *mixer = fmixer->mixer;
793 	struct snd_kcontrol *kctl;
794 	struct snd_mixer_oss_slot *pslot;
795 	struct slot *slot;
796 	struct snd_ctl_elem_info *uinfo;
797 	struct snd_ctl_elem_value *uctl;
798 	int err, idx;
799 
800 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
801 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
802 	if (uinfo == NULL || uctl == NULL) {
803 		err = -ENOMEM;
804 		goto __free_only;
805 	}
806 	down_read(&card->controls_rwsem);
807 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
808 	if (! kctl) {
809 		err = -ENOENT;
810 		goto __unlock;
811 	}
812 	if ((err = kctl->info(kctl, uinfo)) < 0)
813 		goto __unlock;
814 	if ((err = kctl->get(kctl, uctl)) < 0)
815 		goto __unlock;
816 	for (idx = 0; idx < 32; idx++) {
817 		if (!(mixer->mask_recsrc & (1 << idx)))
818 			continue;
819 		pslot = &mixer->slots[idx];
820 		slot = pslot->private_data;
821 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
822 			continue;
823 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
824 			continue;
825 		if (slot->capture_item == uctl->value.enumerated.item[0]) {
826 			*active_index = idx;
827 			break;
828 		}
829 	}
830 	err = 0;
831       __unlock:
832      	up_read(&card->controls_rwsem);
833       __free_only:
834       	kfree(uctl);
835       	kfree(uinfo);
836       	return err;
837 }
838 
839 static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned int active_index)
840 {
841 	struct snd_card *card = fmixer->card;
842 	struct snd_mixer_oss *mixer = fmixer->mixer;
843 	struct snd_kcontrol *kctl;
844 	struct snd_mixer_oss_slot *pslot;
845 	struct slot *slot = NULL;
846 	struct snd_ctl_elem_info *uinfo;
847 	struct snd_ctl_elem_value *uctl;
848 	int err;
849 	unsigned int idx;
850 
851 	uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
852 	uctl = kzalloc(sizeof(*uctl), GFP_KERNEL);
853 	if (uinfo == NULL || uctl == NULL) {
854 		err = -ENOMEM;
855 		goto __free_only;
856 	}
857 	down_read(&card->controls_rwsem);
858 	kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
859 	if (! kctl) {
860 		err = -ENOENT;
861 		goto __unlock;
862 	}
863 	if ((err = kctl->info(kctl, uinfo)) < 0)
864 		goto __unlock;
865 	for (idx = 0; idx < 32; idx++) {
866 		if (!(mixer->mask_recsrc & (1 << idx)))
867 			continue;
868 		pslot = &mixer->slots[idx];
869 		slot = pslot->private_data;
870 		if (slot->signature != SNDRV_MIXER_OSS_SIGNATURE)
871 			continue;
872 		if (!(slot->present & SNDRV_MIXER_OSS_PRESENT_CAPTURE))
873 			continue;
874 		if (idx == active_index)
875 			break;
876 		slot = NULL;
877 	}
878 	if (! slot)
879 		goto __unlock;
880 	for (idx = 0; idx < uinfo->count; idx++)
881 		uctl->value.enumerated.item[idx] = slot->capture_item;
882 	err = kctl->put(kctl, uctl);
883 	if (err > 0)
884 		snd_ctl_notify(fmixer->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
885 	err = 0;
886       __unlock:
887 	up_read(&card->controls_rwsem);
888       __free_only:
889 	kfree(uctl);
890 	kfree(uinfo);
891 	return err;
892 }
893 
894 struct snd_mixer_oss_assign_table {
895 	int oss_id;
896 	const char *name;
897 	int index;
898 };
899 
900 static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *slot, const char *name, int index, int item)
901 {
902 	struct snd_ctl_elem_info *info;
903 	struct snd_kcontrol *kcontrol;
904 	struct snd_card *card = mixer->card;
905 	int err;
906 
907 	down_read(&card->controls_rwsem);
908 	kcontrol = snd_mixer_oss_test_id(mixer, name, index);
909 	if (kcontrol == NULL) {
910 		up_read(&card->controls_rwsem);
911 		return 0;
912 	}
913 	info = kmalloc(sizeof(*info), GFP_KERNEL);
914 	if (! info) {
915 		up_read(&card->controls_rwsem);
916 		return -ENOMEM;
917 	}
918 	if ((err = kcontrol->info(kcontrol, info)) < 0) {
919 		up_read(&card->controls_rwsem);
920 		kfree(info);
921 		return err;
922 	}
923 	slot->numid[item] = kcontrol->id.numid;
924 	up_read(&card->controls_rwsem);
925 	if (info->count > slot->channels)
926 		slot->channels = info->count;
927 	slot->present |= 1 << item;
928 	kfree(info);
929 	return 0;
930 }
931 
932 static void snd_mixer_oss_slot_free(struct snd_mixer_oss_slot *chn)
933 {
934 	struct slot *p = chn->private_data;
935 	if (p) {
936 		if (p->allocated && p->assigned) {
937 			kfree(p->assigned->name);
938 			kfree(p->assigned);
939 		}
940 		kfree(p);
941 	}
942 }
943 
944 static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
945 {
946 	int idx = rslot->number; /* remember this */
947 	if (rslot->private_free)
948 		rslot->private_free(rslot);
949 	memset(rslot, 0, sizeof(*rslot));
950 	rslot->number = idx;
951 }
952 
953 /* In a separate function to keep gcc 3.2 happy - do NOT merge this in
954    snd_mixer_oss_build_input! */
955 static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
956 					struct snd_mixer_oss_assign_table *ptr,
957 					struct slot *slot)
958 {
959 	char str[64];
960 	int err;
961 
962 	err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
963 				       SNDRV_MIXER_OSS_ITEM_GLOBAL);
964 	if (err)
965 		return err;
966 	sprintf(str, "%s Switch", ptr->name);
967 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
968 				       SNDRV_MIXER_OSS_ITEM_GSWITCH);
969 	if (err)
970 		return err;
971 	sprintf(str, "%s Route", ptr->name);
972 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
973 				       SNDRV_MIXER_OSS_ITEM_GROUTE);
974 	if (err)
975 		return err;
976 	sprintf(str, "%s Volume", ptr->name);
977 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
978 				       SNDRV_MIXER_OSS_ITEM_GVOLUME);
979 	if (err)
980 		return err;
981 	sprintf(str, "%s Playback Switch", ptr->name);
982 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
983 				       SNDRV_MIXER_OSS_ITEM_PSWITCH);
984 	if (err)
985 		return err;
986 	sprintf(str, "%s Playback Route", ptr->name);
987 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
988 				       SNDRV_MIXER_OSS_ITEM_PROUTE);
989 	if (err)
990 		return err;
991 	sprintf(str, "%s Playback Volume", ptr->name);
992 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
993 				       SNDRV_MIXER_OSS_ITEM_PVOLUME);
994 	if (err)
995 		return err;
996 	sprintf(str, "%s Capture Switch", ptr->name);
997 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
998 				       SNDRV_MIXER_OSS_ITEM_CSWITCH);
999 	if (err)
1000 		return err;
1001 	sprintf(str, "%s Capture Route", ptr->name);
1002 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1003 				       SNDRV_MIXER_OSS_ITEM_CROUTE);
1004 	if (err)
1005 		return err;
1006 	sprintf(str, "%s Capture Volume", ptr->name);
1007 	err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
1008 				       SNDRV_MIXER_OSS_ITEM_CVOLUME);
1009 	if (err)
1010 		return err;
1011 
1012 	return 0;
1013 }
1014 
1015 /*
1016  * build an OSS mixer element.
1017  * ptr_allocated means the entry is dynamically allocated (change via proc file).
1018  * when replace_old = 1, the old entry is replaced with the new one.
1019  */
1020 static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mixer_oss_assign_table *ptr, int ptr_allocated, int replace_old)
1021 {
1022 	struct slot slot;
1023 	struct slot *pslot;
1024 	struct snd_kcontrol *kctl;
1025 	struct snd_mixer_oss_slot *rslot;
1026 	char str[64];
1027 
1028 	/* check if already assigned */
1029 	if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
1030 		return 0;
1031 
1032 	memset(&slot, 0, sizeof(slot));
1033 	memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
1034 	if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
1035 		return 0;
1036 	down_read(&mixer->card->controls_rwsem);
1037 	if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
1038 		struct snd_ctl_elem_info *uinfo;
1039 
1040 		uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
1041 		if (! uinfo) {
1042 			up_read(&mixer->card->controls_rwsem);
1043 			return -ENOMEM;
1044 		}
1045 
1046 		if (kctl->info(kctl, uinfo)) {
1047 			up_read(&mixer->card->controls_rwsem);
1048 			return 0;
1049 		}
1050 		strcpy(str, ptr->name);
1051 		if (!strcmp(str, "Master"))
1052 			strcpy(str, "Mix");
1053 		if (!strcmp(str, "Master Mono"))
1054 			strcpy(str, "Mix Mono");
1055 		slot.capture_item = 0;
1056 		if (!strcmp(uinfo->value.enumerated.name, str)) {
1057 			slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1058 		} else {
1059 			for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
1060 				uinfo->value.enumerated.item = slot.capture_item;
1061 				if (kctl->info(kctl, uinfo)) {
1062 					up_read(&mixer->card->controls_rwsem);
1063 					return 0;
1064 				}
1065 				if (!strcmp(uinfo->value.enumerated.name, str)) {
1066 					slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1067 					break;
1068 				}
1069 			}
1070 		}
1071 		kfree(uinfo);
1072 	}
1073 	up_read(&mixer->card->controls_rwsem);
1074 	if (slot.present != 0) {
1075 		pslot = kmalloc(sizeof(slot), GFP_KERNEL);
1076 		if (! pslot)
1077 			return -ENOMEM;
1078 		*pslot = slot;
1079 		pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1080 		pslot->assigned = ptr;
1081 		pslot->allocated = ptr_allocated;
1082 		rslot = &mixer->slots[ptr->oss_id];
1083 		mixer_slot_clear(rslot);
1084 		rslot->stereo = slot.channels > 1 ? 1 : 0;
1085 		rslot->get_volume = snd_mixer_oss_get_volume1;
1086 		rslot->put_volume = snd_mixer_oss_put_volume1;
1087 		/* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1088 		if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1089 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1090 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1091 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1092 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1093 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1094 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1095 			mixer->mask_recsrc |= 1 << ptr->oss_id;
1096 		}
1097 		rslot->private_data = pslot;
1098 		rslot->private_free = snd_mixer_oss_slot_free;
1099 		return 1;
1100 	}
1101 	return 0;
1102 }
1103 
1104 #ifdef CONFIG_PROC_FS
1105 /*
1106  */
1107 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1108 static char *oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1109 	MIXER_VOL(VOLUME),
1110 	MIXER_VOL(BASS),
1111 	MIXER_VOL(TREBLE),
1112 	MIXER_VOL(SYNTH),
1113 	MIXER_VOL(PCM),
1114 	MIXER_VOL(SPEAKER),
1115 	MIXER_VOL(LINE),
1116 	MIXER_VOL(MIC),
1117 	MIXER_VOL(CD),
1118 	MIXER_VOL(IMIX),
1119 	MIXER_VOL(ALTPCM),
1120 	MIXER_VOL(RECLEV),
1121 	MIXER_VOL(IGAIN),
1122 	MIXER_VOL(OGAIN),
1123 	MIXER_VOL(LINE1),
1124 	MIXER_VOL(LINE2),
1125 	MIXER_VOL(LINE3),
1126 	MIXER_VOL(DIGITAL1),
1127 	MIXER_VOL(DIGITAL2),
1128 	MIXER_VOL(DIGITAL3),
1129 	MIXER_VOL(PHONEIN),
1130 	MIXER_VOL(PHONEOUT),
1131 	MIXER_VOL(VIDEO),
1132 	MIXER_VOL(RADIO),
1133 	MIXER_VOL(MONITOR),
1134 };
1135 
1136 /*
1137  *  /proc interface
1138  */
1139 
1140 static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
1141 				    struct snd_info_buffer *buffer)
1142 {
1143 	struct snd_mixer_oss *mixer = entry->private_data;
1144 	int i;
1145 
1146 	mutex_lock(&mixer->reg_mutex);
1147 	for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1148 		struct slot *p;
1149 
1150 		if (! oss_mixer_names[i])
1151 			continue;
1152 		p = (struct slot *)mixer->slots[i].private_data;
1153 		snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1154 		if (p && p->assigned)
1155 			snd_iprintf(buffer, "\"%s\" %d\n",
1156 				    p->assigned->name,
1157 				    p->assigned->index);
1158 		else
1159 			snd_iprintf(buffer, "\"\" 0\n");
1160 	}
1161 	mutex_unlock(&mixer->reg_mutex);
1162 }
1163 
1164 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
1165 				     struct snd_info_buffer *buffer)
1166 {
1167 	struct snd_mixer_oss *mixer = entry->private_data;
1168 	char line[128], str[32], idxstr[16];
1169 	const char *cptr;
1170 	int ch, idx;
1171 	struct snd_mixer_oss_assign_table *tbl;
1172 	struct slot *slot;
1173 
1174 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
1175 		cptr = snd_info_get_str(str, line, sizeof(str));
1176 		for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1177 			if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1178 				break;
1179 		if (ch >= SNDRV_OSS_MAX_MIXERS) {
1180 			snd_printk(KERN_ERR "mixer_oss: invalid OSS volume '%s'\n", str);
1181 			continue;
1182 		}
1183 		cptr = snd_info_get_str(str, cptr, sizeof(str));
1184 		if (! *str) {
1185 			/* remove the entry */
1186 			mutex_lock(&mixer->reg_mutex);
1187 			mixer_slot_clear(&mixer->slots[ch]);
1188 			mutex_unlock(&mixer->reg_mutex);
1189 			continue;
1190 		}
1191 		snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1192 		idx = simple_strtoul(idxstr, NULL, 10);
1193 		if (idx >= 0x4000) { /* too big */
1194 			snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
1195 			continue;
1196 		}
1197 		mutex_lock(&mixer->reg_mutex);
1198 		slot = (struct slot *)mixer->slots[ch].private_data;
1199 		if (slot && slot->assigned &&
1200 		    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1201 			/* not changed */
1202 			goto __unlock;
1203 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1204 		if (! tbl) {
1205 			snd_printk(KERN_ERR "mixer_oss: no memory\n");
1206 			goto __unlock;
1207 		}
1208 		tbl->oss_id = ch;
1209 		tbl->name = kstrdup(str, GFP_KERNEL);
1210 		if (! tbl->name) {
1211 			kfree(tbl);
1212 			goto __unlock;
1213 		}
1214 		tbl->index = idx;
1215 		if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1216 			kfree(tbl->name);
1217 			kfree(tbl);
1218 		}
1219 	__unlock:
1220 		mutex_unlock(&mixer->reg_mutex);
1221 	}
1222 }
1223 
1224 static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
1225 {
1226 	struct snd_info_entry *entry;
1227 
1228 	entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1229 					   mixer->card->proc_root);
1230 	if (! entry)
1231 		return;
1232 	entry->content = SNDRV_INFO_CONTENT_TEXT;
1233 	entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
1234 	entry->c.text.read = snd_mixer_oss_proc_read;
1235 	entry->c.text.write = snd_mixer_oss_proc_write;
1236 	entry->private_data = mixer;
1237 	if (snd_info_register(entry) < 0) {
1238 		snd_info_free_entry(entry);
1239 		entry = NULL;
1240 	}
1241 	mixer->proc_entry = entry;
1242 }
1243 
1244 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
1245 {
1246 	snd_info_free_entry(mixer->proc_entry);
1247 	mixer->proc_entry = NULL;
1248 }
1249 #else /* !CONFIG_PROC_FS */
1250 #define snd_mixer_oss_proc_init(mix)
1251 #define snd_mixer_oss_proc_done(mix)
1252 #endif /* CONFIG_PROC_FS */
1253 
1254 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
1255 {
1256 	static struct snd_mixer_oss_assign_table table[] = {
1257 		{ SOUND_MIXER_VOLUME, 	"Master",		0 },
1258 		{ SOUND_MIXER_VOLUME, 	"Front",		0 }, /* fallback */
1259 		{ SOUND_MIXER_BASS,	"Tone Control - Bass",	0 },
1260 		{ SOUND_MIXER_TREBLE,	"Tone Control - Treble", 0 },
1261 		{ SOUND_MIXER_SYNTH,	"Synth",		0 },
1262 		{ SOUND_MIXER_SYNTH,	"FM",			0 }, /* fallback */
1263 		{ SOUND_MIXER_SYNTH,	"Music",		0 }, /* fallback */
1264 		{ SOUND_MIXER_PCM,	"PCM",			0 },
1265 		{ SOUND_MIXER_SPEAKER,	"Beep", 		0 },
1266 		{ SOUND_MIXER_SPEAKER,	"PC Speaker", 		0 }, /* fallback */
1267 		{ SOUND_MIXER_SPEAKER,	"Speaker", 		0 }, /* fallback */
1268 		{ SOUND_MIXER_LINE,	"Line", 		0 },
1269 		{ SOUND_MIXER_MIC,	"Mic", 			0 },
1270 		{ SOUND_MIXER_CD,	"CD", 			0 },
1271 		{ SOUND_MIXER_IMIX,	"Monitor Mix", 		0 },
1272 		{ SOUND_MIXER_ALTPCM,	"PCM",			1 },
1273 		{ SOUND_MIXER_ALTPCM,	"Headphone",		0 }, /* fallback */
1274 		{ SOUND_MIXER_ALTPCM,	"Wave",			0 }, /* fallback */
1275 		{ SOUND_MIXER_RECLEV,	"-- nothing --",	0 },
1276 		{ SOUND_MIXER_IGAIN,	"Capture",		0 },
1277 		{ SOUND_MIXER_OGAIN,	"Playback",		0 },
1278 		{ SOUND_MIXER_LINE1,	"Aux",			0 },
1279 		{ SOUND_MIXER_LINE2,	"Aux",			1 },
1280 		{ SOUND_MIXER_LINE3,	"Aux",			2 },
1281 		{ SOUND_MIXER_DIGITAL1,	"Digital",		0 },
1282 		{ SOUND_MIXER_DIGITAL1,	"IEC958",		0 }, /* fallback */
1283 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Optical",	0 }, /* fallback */
1284 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Coaxial",	0 }, /* fallback */
1285 		{ SOUND_MIXER_DIGITAL2,	"Digital",		1 },
1286 		{ SOUND_MIXER_DIGITAL3,	"Digital",		2 },
1287 		{ SOUND_MIXER_PHONEIN,	"Phone",		0 },
1288 		{ SOUND_MIXER_PHONEOUT,	"Master Mono",		0 },
1289 		{ SOUND_MIXER_PHONEOUT,	"Speaker",		0 }, /*fallback*/
1290 		{ SOUND_MIXER_PHONEOUT,	"Mono",			0 }, /*fallback*/
1291 		{ SOUND_MIXER_PHONEOUT,	"Phone",		0 }, /* fallback */
1292 		{ SOUND_MIXER_VIDEO,	"Video",		0 },
1293 		{ SOUND_MIXER_RADIO,	"Radio",		0 },
1294 		{ SOUND_MIXER_MONITOR,	"Monitor",		0 }
1295 	};
1296 	unsigned int idx;
1297 
1298 	for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1299 		snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1300 	if (mixer->mask_recsrc) {
1301 		mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1302 		mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1303 	}
1304 }
1305 
1306 /*
1307  *
1308  */
1309 
1310 static int snd_mixer_oss_free1(void *private)
1311 {
1312 	struct snd_mixer_oss *mixer = private;
1313 	struct snd_card *card;
1314 	int idx;
1315 
1316 	if (!mixer)
1317 		return 0;
1318 	card = mixer->card;
1319 	if (snd_BUG_ON(mixer != card->mixer_oss))
1320 		return -ENXIO;
1321 	card->mixer_oss = NULL;
1322 	for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1323 		struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
1324 		if (chn->private_free)
1325 			chn->private_free(chn);
1326 	}
1327 	kfree(mixer);
1328 	return 0;
1329 }
1330 
1331 static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1332 {
1333 	struct snd_mixer_oss *mixer;
1334 
1335 	if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1336 		char name[128];
1337 		int idx, err;
1338 
1339 		mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1340 		if (mixer == NULL)
1341 			return -ENOMEM;
1342 		mutex_init(&mixer->reg_mutex);
1343 		sprintf(name, "mixer%i%i", card->number, 0);
1344 		if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1345 						   card, 0,
1346 						   &snd_mixer_oss_f_ops, card,
1347 						   name)) < 0) {
1348 			snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
1349 				   card->number, 0);
1350 			kfree(mixer);
1351 			return err;
1352 		}
1353 		mixer->oss_dev_alloc = 1;
1354 		mixer->card = card;
1355 		if (*card->mixername)
1356 			strlcpy(mixer->name, card->mixername, sizeof(mixer->name));
1357 		else
1358 			strlcpy(mixer->name, name, sizeof(mixer->name));
1359 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1360 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1361 				      card->number,
1362 				      mixer->name);
1363 #endif
1364 		for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1365 			mixer->slots[idx].number = idx;
1366 		card->mixer_oss = mixer;
1367 		snd_mixer_oss_build(mixer);
1368 		snd_mixer_oss_proc_init(mixer);
1369 	} else {
1370 		mixer = card->mixer_oss;
1371 		if (mixer == NULL)
1372 			return 0;
1373 		if (mixer->oss_dev_alloc) {
1374 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1375 			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1376 #endif
1377 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1378 			mixer->oss_dev_alloc = 0;
1379 		}
1380 		if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1381 			return 0;
1382 		snd_mixer_oss_proc_done(mixer);
1383 		return snd_mixer_oss_free1(mixer);
1384 	}
1385 	return 0;
1386 }
1387 
1388 static int __init alsa_mixer_oss_init(void)
1389 {
1390 	int idx;
1391 
1392 	snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1393 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
1394 		if (snd_cards[idx])
1395 			snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_REGISTER);
1396 	}
1397 	return 0;
1398 }
1399 
1400 static void __exit alsa_mixer_oss_exit(void)
1401 {
1402 	int idx;
1403 
1404 	snd_mixer_oss_notify_callback = NULL;
1405 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
1406 		if (snd_cards[idx])
1407 			snd_mixer_oss_notify_handler(snd_cards[idx], SND_MIXER_OSS_NOTIFY_FREE);
1408 	}
1409 }
1410 
1411 module_init(alsa_mixer_oss_init)
1412 module_exit(alsa_mixer_oss_exit)
1413 
1414 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
1415