1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *  OSS emulation layer for the mixer interface
4  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
5  */
6 
7 #include <linux/init.h>
8 #include <linux/slab.h>
9 #include <linux/time.h>
10 #include <linux/string.h>
11 #include <linux/module.h>
12 #include <linux/compat.h>
13 #include <sound/core.h>
14 #include <sound/minors.h>
15 #include <sound/control.h>
16 #include <sound/info.h>
17 #include <sound/mixer_oss.h>
18 #include <linux/soundcard.h>
19 
20 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
21 
22 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
23 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
24 MODULE_LICENSE("GPL");
25 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
26 
snd_mixer_oss_open(struct inode * inode,struct file * file)27 static int snd_mixer_oss_open(struct inode *inode, struct file *file)
28 {
29 	struct snd_card *card;
30 	struct snd_mixer_oss_file *fmixer;
31 	int err;
32 
33 	err = nonseekable_open(inode, file);
34 	if (err < 0)
35 		return err;
36 
37 	card = snd_lookup_oss_minor_data(iminor(inode),
38 					 SNDRV_OSS_DEVICE_TYPE_MIXER);
39 	if (card == NULL)
40 		return -ENODEV;
41 	if (card->mixer_oss == NULL) {
42 		snd_card_unref(card);
43 		return -ENODEV;
44 	}
45 	err = snd_card_file_add(card, file);
46 	if (err < 0) {
47 		snd_card_unref(card);
48 		return err;
49 	}
50 	fmixer = kzalloc(sizeof(*fmixer), GFP_KERNEL);
51 	if (fmixer == NULL) {
52 		snd_card_file_remove(card, file);
53 		snd_card_unref(card);
54 		return -ENOMEM;
55 	}
56 	fmixer->card = card;
57 	fmixer->mixer = card->mixer_oss;
58 	file->private_data = fmixer;
59 	if (!try_module_get(card->module)) {
60 		kfree(fmixer);
61 		snd_card_file_remove(card, file);
62 		snd_card_unref(card);
63 		return -EFAULT;
64 	}
65 	snd_card_unref(card);
66 	return 0;
67 }
68 
snd_mixer_oss_release(struct inode * inode,struct file * file)69 static int snd_mixer_oss_release(struct inode *inode, struct file *file)
70 {
71 	struct snd_mixer_oss_file *fmixer;
72 
73 	if (file->private_data) {
74 		fmixer = file->private_data;
75 		module_put(fmixer->card->module);
76 		snd_card_file_remove(fmixer->card, file);
77 		kfree(fmixer);
78 	}
79 	return 0;
80 }
81 
snd_mixer_oss_info(struct snd_mixer_oss_file * fmixer,mixer_info __user * _info)82 static int snd_mixer_oss_info(struct snd_mixer_oss_file *fmixer,
83 			      mixer_info __user *_info)
84 {
85 	struct snd_card *card = fmixer->card;
86 	struct snd_mixer_oss *mixer = fmixer->mixer;
87 	struct mixer_info info;
88 
89 	memset(&info, 0, sizeof(info));
90 	strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
91 	strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
92 	info.modify_counter = card->mixer_oss_change_count;
93 	if (copy_to_user(_info, &info, sizeof(info)))
94 		return -EFAULT;
95 	return 0;
96 }
97 
snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file * fmixer,_old_mixer_info __user * _info)98 static int snd_mixer_oss_info_obsolete(struct snd_mixer_oss_file *fmixer,
99 				       _old_mixer_info __user *_info)
100 {
101 	struct snd_card *card = fmixer->card;
102 	struct snd_mixer_oss *mixer = fmixer->mixer;
103 	_old_mixer_info info;
104 
105 	memset(&info, 0, sizeof(info));
106 	strscpy(info.id, mixer && mixer->id[0] ? mixer->id : card->driver, sizeof(info.id));
107 	strscpy(info.name, mixer && mixer->name[0] ? mixer->name : card->mixername, sizeof(info.name));
108 	if (copy_to_user(_info, &info, sizeof(info)))
109 		return -EFAULT;
110 	return 0;
111 }
112 
snd_mixer_oss_caps(struct snd_mixer_oss_file * fmixer)113 static int snd_mixer_oss_caps(struct snd_mixer_oss_file *fmixer)
114 {
115 	struct snd_mixer_oss *mixer = fmixer->mixer;
116 	int result = 0;
117 
118 	if (mixer == NULL)
119 		return -EIO;
120 	if (mixer->get_recsrc && mixer->put_recsrc)
121 		result |= SOUND_CAP_EXCL_INPUT;
122 	return result;
123 }
124 
snd_mixer_oss_devmask(struct snd_mixer_oss_file * fmixer)125 static int snd_mixer_oss_devmask(struct snd_mixer_oss_file *fmixer)
126 {
127 	struct snd_mixer_oss *mixer = fmixer->mixer;
128 	struct snd_mixer_oss_slot *pslot;
129 	int result = 0, chn;
130 
131 	if (mixer == NULL)
132 		return -EIO;
133 	for (chn = 0; chn < 31; chn++) {
134 		pslot = &mixer->slots[chn];
135 		if (pslot->put_volume || pslot->put_recsrc)
136 			result |= 1 << chn;
137 	}
138 	return result;
139 }
140 
snd_mixer_oss_stereodevs(struct snd_mixer_oss_file * fmixer)141 static int snd_mixer_oss_stereodevs(struct snd_mixer_oss_file *fmixer)
142 {
143 	struct snd_mixer_oss *mixer = fmixer->mixer;
144 	struct snd_mixer_oss_slot *pslot;
145 	int result = 0, chn;
146 
147 	if (mixer == NULL)
148 		return -EIO;
149 	for (chn = 0; chn < 31; chn++) {
150 		pslot = &mixer->slots[chn];
151 		if (pslot->put_volume && pslot->stereo)
152 			result |= 1 << chn;
153 	}
154 	return result;
155 }
156 
snd_mixer_oss_recmask(struct snd_mixer_oss_file * fmixer)157 static int snd_mixer_oss_recmask(struct snd_mixer_oss_file *fmixer)
158 {
159 	struct snd_mixer_oss *mixer = fmixer->mixer;
160 	int result = 0;
161 
162 	if (mixer == NULL)
163 		return -EIO;
164 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
165 		result = mixer->mask_recsrc;
166 	} else {
167 		struct snd_mixer_oss_slot *pslot;
168 		int chn;
169 		for (chn = 0; chn < 31; chn++) {
170 			pslot = &mixer->slots[chn];
171 			if (pslot->put_recsrc)
172 				result |= 1 << chn;
173 		}
174 	}
175 	return result;
176 }
177 
snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file * fmixer)178 static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
179 {
180 	struct snd_mixer_oss *mixer = fmixer->mixer;
181 	int result = 0;
182 
183 	if (mixer == NULL)
184 		return -EIO;
185 	if (mixer->put_recsrc && mixer->get_recsrc) {	/* exclusive */
186 		int err;
187 		unsigned int index;
188 		if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
189 			return err;
190 		result = 1 << index;
191 	} else {
192 		struct snd_mixer_oss_slot *pslot;
193 		int chn;
194 		for (chn = 0; chn < 31; chn++) {
195 			pslot = &mixer->slots[chn];
196 			if (pslot->get_recsrc) {
197 				int active = 0;
198 				pslot->get_recsrc(fmixer, pslot, &active);
199 				if (active)
200 					result |= 1 << chn;
201 			}
202 		}
203 	}
204 	return mixer->oss_recsrc = result;
205 }
206 
snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file * fmixer,int recsrc)207 static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
208 {
209 	struct snd_mixer_oss *mixer = fmixer->mixer;
210 	struct snd_mixer_oss_slot *pslot;
211 	int chn, active;
212 	unsigned int index;
213 	int result = 0;
214 
215 	if (mixer == NULL)
216 		return -EIO;
217 	if (mixer->get_recsrc && mixer->put_recsrc) {	/* exclusive input */
218 		if (recsrc & ~mixer->oss_recsrc)
219 			recsrc &= ~mixer->oss_recsrc;
220 		mixer->put_recsrc(fmixer, ffz(~recsrc));
221 		mixer->get_recsrc(fmixer, &index);
222 		result = 1 << index;
223 	}
224 	for (chn = 0; chn < 31; chn++) {
225 		pslot = &mixer->slots[chn];
226 		if (pslot->put_recsrc) {
227 			active = (recsrc & (1 << chn)) ? 1 : 0;
228 			pslot->put_recsrc(fmixer, pslot, active);
229 		}
230 	}
231 	if (! result) {
232 		for (chn = 0; chn < 31; chn++) {
233 			pslot = &mixer->slots[chn];
234 			if (pslot->get_recsrc) {
235 				active = 0;
236 				pslot->get_recsrc(fmixer, pslot, &active);
237 				if (active)
238 					result |= 1 << chn;
239 			}
240 		}
241 	}
242 	return result;
243 }
244 
snd_mixer_oss_get_volume(struct snd_mixer_oss_file * fmixer,int slot)245 static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
246 {
247 	struct snd_mixer_oss *mixer = fmixer->mixer;
248 	struct snd_mixer_oss_slot *pslot;
249 	int result = 0, left, right;
250 
251 	if (mixer == NULL || slot > 30)
252 		return -EIO;
253 	pslot = &mixer->slots[slot];
254 	left = pslot->volume[0];
255 	right = pslot->volume[1];
256 	if (pslot->get_volume)
257 		result = pslot->get_volume(fmixer, pslot, &left, &right);
258 	if (!pslot->stereo)
259 		right = left;
260 	if (snd_BUG_ON(left < 0 || left > 100))
261 		return -EIO;
262 	if (snd_BUG_ON(right < 0 || right > 100))
263 		return -EIO;
264 	if (result >= 0) {
265 		pslot->volume[0] = left;
266 		pslot->volume[1] = right;
267 	 	result = (left & 0xff) | ((right & 0xff) << 8);
268 	}
269 	return result;
270 }
271 
snd_mixer_oss_set_volume(struct snd_mixer_oss_file * fmixer,int slot,int volume)272 static int snd_mixer_oss_set_volume(struct snd_mixer_oss_file *fmixer,
273 				    int slot, int volume)
274 {
275 	struct snd_mixer_oss *mixer = fmixer->mixer;
276 	struct snd_mixer_oss_slot *pslot;
277 	int result = 0, left = volume & 0xff, right = (volume >> 8) & 0xff;
278 
279 	if (mixer == NULL || slot > 30)
280 		return -EIO;
281 	pslot = &mixer->slots[slot];
282 	if (left > 100)
283 		left = 100;
284 	if (right > 100)
285 		right = 100;
286 	if (!pslot->stereo)
287 		right = left;
288 	if (pslot->put_volume)
289 		result = pslot->put_volume(fmixer, pslot, left, right);
290 	if (result < 0)
291 		return result;
292 	pslot->volume[0] = left;
293 	pslot->volume[1] = right;
294  	return (left & 0xff) | ((right & 0xff) << 8);
295 }
296 
snd_mixer_oss_ioctl1(struct snd_mixer_oss_file * fmixer,unsigned int cmd,unsigned long arg)297 static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)
298 {
299 	void __user *argp = (void __user *)arg;
300 	int __user *p = argp;
301 	int tmp;
302 
303 	if (snd_BUG_ON(!fmixer))
304 		return -ENXIO;
305 	if (((cmd >> 8) & 0xff) == 'M') {
306 		switch (cmd) {
307 		case SOUND_MIXER_INFO:
308 			return snd_mixer_oss_info(fmixer, argp);
309 		case SOUND_OLD_MIXER_INFO:
310  			return snd_mixer_oss_info_obsolete(fmixer, argp);
311 		case SOUND_MIXER_WRITE_RECSRC:
312 			if (get_user(tmp, p))
313 				return -EFAULT;
314 			tmp = snd_mixer_oss_set_recsrc(fmixer, tmp);
315 			if (tmp < 0)
316 				return tmp;
317 			return put_user(tmp, p);
318 		case OSS_GETVERSION:
319 			return put_user(SNDRV_OSS_VERSION, p);
320 		case OSS_ALSAEMULVER:
321 			return put_user(1, p);
322 		case SOUND_MIXER_READ_DEVMASK:
323 			tmp = snd_mixer_oss_devmask(fmixer);
324 			if (tmp < 0)
325 				return tmp;
326 			return put_user(tmp, p);
327 		case SOUND_MIXER_READ_STEREODEVS:
328 			tmp = snd_mixer_oss_stereodevs(fmixer);
329 			if (tmp < 0)
330 				return tmp;
331 			return put_user(tmp, p);
332 		case SOUND_MIXER_READ_RECMASK:
333 			tmp = snd_mixer_oss_recmask(fmixer);
334 			if (tmp < 0)
335 				return tmp;
336 			return put_user(tmp, p);
337 		case SOUND_MIXER_READ_CAPS:
338 			tmp = snd_mixer_oss_caps(fmixer);
339 			if (tmp < 0)
340 				return tmp;
341 			return put_user(tmp, p);
342 		case SOUND_MIXER_READ_RECSRC:
343 			tmp = snd_mixer_oss_get_recsrc(fmixer);
344 			if (tmp < 0)
345 				return tmp;
346 			return put_user(tmp, p);
347 		}
348 	}
349 	if (cmd & SIOC_IN) {
350 		if (get_user(tmp, p))
351 			return -EFAULT;
352 		tmp = snd_mixer_oss_set_volume(fmixer, cmd & 0xff, tmp);
353 		if (tmp < 0)
354 			return tmp;
355 		return put_user(tmp, p);
356 	} else if (cmd & SIOC_OUT) {
357 		tmp = snd_mixer_oss_get_volume(fmixer, cmd & 0xff);
358 		if (tmp < 0)
359 			return tmp;
360 		return put_user(tmp, p);
361 	}
362 	return -ENXIO;
363 }
364 
snd_mixer_oss_ioctl(struct file * file,unsigned int cmd,unsigned long arg)365 static long snd_mixer_oss_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
366 {
367 	return snd_mixer_oss_ioctl1(file->private_data, cmd, arg);
368 }
369 
snd_mixer_oss_ioctl_card(struct snd_card * card,unsigned int cmd,unsigned long arg)370 int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned long arg)
371 {
372 	struct snd_mixer_oss_file fmixer;
373 
374 	if (snd_BUG_ON(!card))
375 		return -ENXIO;
376 	if (card->mixer_oss == NULL)
377 		return -ENXIO;
378 	memset(&fmixer, 0, sizeof(fmixer));
379 	fmixer.card = card;
380 	fmixer.mixer = card->mixer_oss;
381 	return snd_mixer_oss_ioctl1(&fmixer, cmd, arg);
382 }
383 EXPORT_SYMBOL(snd_mixer_oss_ioctl_card);
384 
385 #ifdef CONFIG_COMPAT
386 /* all compatible */
snd_mixer_oss_ioctl_compat(struct file * file,unsigned int cmd,unsigned long arg)387 static long snd_mixer_oss_ioctl_compat(struct file *file, unsigned int cmd,
388 				       unsigned long arg)
389 {
390 	return snd_mixer_oss_ioctl1(file->private_data, cmd,
391 				    (unsigned long)compat_ptr(arg));
392 }
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 
snd_mixer_oss_conv(long val,long omin,long omax,long nmin,long nmax)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 DIV_ROUND_CLOSEST(nrange * (val - omin), orange) + nmin;
422 }
423 
424 /* convert from alsa native to oss values (0-100) */
snd_mixer_oss_conv1(long val,long min,long max,int * old)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 */
snd_mixer_oss_conv2(long val,long min,long max)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 	const struct snd_mixer_oss_assign_table *assigned;
490 	unsigned int allocated: 1;
491 };
492 
493 #define ID_UNKNOWN	((unsigned int)-1)
494 
snd_mixer_oss_test_id(struct snd_mixer_oss * mixer,const char * name,int index)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 	strscpy(id.name, name, sizeof(id.name));
503 	id.index = index;
504 	return snd_ctl_find_id(card, &id);
505 }
506 
snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,unsigned int numid,int * left,int * right)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 
snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,unsigned int numid,int * left,int * right,int route)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 
snd_mixer_oss_get_volume1(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int * left,int * right)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 
snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,unsigned int numid,int left,int right)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 
snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,unsigned int numid,int left,int right,int route)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 
snd_mixer_oss_put_volume1(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int left,int right)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 
snd_mixer_oss_get_recsrc1_sw(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int * active)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 
snd_mixer_oss_get_recsrc1_route(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int * active)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 
snd_mixer_oss_put_recsrc1_sw(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int active)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 
snd_mixer_oss_put_recsrc1_route(struct snd_mixer_oss_file * fmixer,struct snd_mixer_oss_slot * pslot,int active)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 
snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file * fmixer,unsigned int * active_index)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 
snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file * fmixer,unsigned int active_index)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 
snd_mixer_oss_build_test(struct snd_mixer_oss * mixer,struct slot * slot,const char * name,int index,int item)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 
snd_mixer_oss_slot_free(struct snd_mixer_oss_slot * chn)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_const(p->assigned->name);
938 			kfree_const(p->assigned);
939 		}
940 		kfree(p);
941 	}
942 }
943 
mixer_slot_clear(struct snd_mixer_oss_slot * rslot)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! */
snd_mixer_oss_build_test_all(struct snd_mixer_oss * mixer,const struct snd_mixer_oss_assign_table * ptr,struct slot * slot)955 static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
956 					const 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  */
snd_mixer_oss_build_input(struct snd_mixer_oss * mixer,const struct snd_mixer_oss_assign_table * ptr,int ptr_allocated,int replace_old)1020 static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
1021 				     const struct snd_mixer_oss_assign_table *ptr,
1022 				     int ptr_allocated, int replace_old)
1023 {
1024 	struct slot slot;
1025 	struct slot *pslot;
1026 	struct snd_kcontrol *kctl;
1027 	struct snd_mixer_oss_slot *rslot;
1028 	char str[64];
1029 
1030 	/* check if already assigned */
1031 	if (mixer->slots[ptr->oss_id].get_volume && ! replace_old)
1032 		return 0;
1033 
1034 	memset(&slot, 0, sizeof(slot));
1035 	memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
1036 	if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
1037 		return 0;
1038 	down_read(&mixer->card->controls_rwsem);
1039 	if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
1040 		struct snd_ctl_elem_info *uinfo;
1041 
1042 		uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
1043 		if (! uinfo) {
1044 			up_read(&mixer->card->controls_rwsem);
1045 			return -ENOMEM;
1046 		}
1047 
1048 		if (kctl->info(kctl, uinfo)) {
1049 			up_read(&mixer->card->controls_rwsem);
1050 			kfree(uinfo);
1051 			return 0;
1052 		}
1053 		strcpy(str, ptr->name);
1054 		if (!strcmp(str, "Master"))
1055 			strcpy(str, "Mix");
1056 		if (!strcmp(str, "Master Mono"))
1057 			strcpy(str, "Mix Mono");
1058 		slot.capture_item = 0;
1059 		if (!strcmp(uinfo->value.enumerated.name, str)) {
1060 			slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1061 		} else {
1062 			for (slot.capture_item = 1; slot.capture_item < uinfo->value.enumerated.items; slot.capture_item++) {
1063 				uinfo->value.enumerated.item = slot.capture_item;
1064 				if (kctl->info(kctl, uinfo)) {
1065 					up_read(&mixer->card->controls_rwsem);
1066 					kfree(uinfo);
1067 					return 0;
1068 				}
1069 				if (!strcmp(uinfo->value.enumerated.name, str)) {
1070 					slot.present |= SNDRV_MIXER_OSS_PRESENT_CAPTURE;
1071 					break;
1072 				}
1073 			}
1074 		}
1075 		kfree(uinfo);
1076 	}
1077 	up_read(&mixer->card->controls_rwsem);
1078 	if (slot.present != 0) {
1079 		pslot = kmalloc(sizeof(slot), GFP_KERNEL);
1080 		if (! pslot)
1081 			return -ENOMEM;
1082 		*pslot = slot;
1083 		pslot->signature = SNDRV_MIXER_OSS_SIGNATURE;
1084 		pslot->assigned = ptr;
1085 		pslot->allocated = ptr_allocated;
1086 		rslot = &mixer->slots[ptr->oss_id];
1087 		mixer_slot_clear(rslot);
1088 		rslot->stereo = slot.channels > 1 ? 1 : 0;
1089 		rslot->get_volume = snd_mixer_oss_get_volume1;
1090 		rslot->put_volume = snd_mixer_oss_put_volume1;
1091 		/* note: ES18xx have both Capture Source and XX Capture Volume !!! */
1092 		if (slot.present & SNDRV_MIXER_OSS_PRESENT_CSWITCH) {
1093 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_sw;
1094 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_sw;
1095 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CROUTE) {
1096 			rslot->get_recsrc = snd_mixer_oss_get_recsrc1_route;
1097 			rslot->put_recsrc = snd_mixer_oss_put_recsrc1_route;
1098 		} else if (slot.present & SNDRV_MIXER_OSS_PRESENT_CAPTURE) {
1099 			mixer->mask_recsrc |= 1 << ptr->oss_id;
1100 		}
1101 		rslot->private_data = pslot;
1102 		rslot->private_free = snd_mixer_oss_slot_free;
1103 		return 1;
1104 	}
1105 	return 0;
1106 }
1107 
1108 #ifdef CONFIG_SND_PROC_FS
1109 /*
1110  */
1111 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
1112 static const char * const oss_mixer_names[SNDRV_OSS_MAX_MIXERS] = {
1113 	MIXER_VOL(VOLUME),
1114 	MIXER_VOL(BASS),
1115 	MIXER_VOL(TREBLE),
1116 	MIXER_VOL(SYNTH),
1117 	MIXER_VOL(PCM),
1118 	MIXER_VOL(SPEAKER),
1119 	MIXER_VOL(LINE),
1120 	MIXER_VOL(MIC),
1121 	MIXER_VOL(CD),
1122 	MIXER_VOL(IMIX),
1123 	MIXER_VOL(ALTPCM),
1124 	MIXER_VOL(RECLEV),
1125 	MIXER_VOL(IGAIN),
1126 	MIXER_VOL(OGAIN),
1127 	MIXER_VOL(LINE1),
1128 	MIXER_VOL(LINE2),
1129 	MIXER_VOL(LINE3),
1130 	MIXER_VOL(DIGITAL1),
1131 	MIXER_VOL(DIGITAL2),
1132 	MIXER_VOL(DIGITAL3),
1133 	MIXER_VOL(PHONEIN),
1134 	MIXER_VOL(PHONEOUT),
1135 	MIXER_VOL(VIDEO),
1136 	MIXER_VOL(RADIO),
1137 	MIXER_VOL(MONITOR),
1138 };
1139 
1140 /*
1141  *  /proc interface
1142  */
1143 
snd_mixer_oss_proc_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1144 static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
1145 				    struct snd_info_buffer *buffer)
1146 {
1147 	struct snd_mixer_oss *mixer = entry->private_data;
1148 	int i;
1149 
1150 	mutex_lock(&mixer->reg_mutex);
1151 	for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
1152 		struct slot *p;
1153 
1154 		if (! oss_mixer_names[i])
1155 			continue;
1156 		p = (struct slot *)mixer->slots[i].private_data;
1157 		snd_iprintf(buffer, "%s ", oss_mixer_names[i]);
1158 		if (p && p->assigned)
1159 			snd_iprintf(buffer, "\"%s\" %d\n",
1160 				    p->assigned->name,
1161 				    p->assigned->index);
1162 		else
1163 			snd_iprintf(buffer, "\"\" 0\n");
1164 	}
1165 	mutex_unlock(&mixer->reg_mutex);
1166 }
1167 
snd_mixer_oss_proc_write(struct snd_info_entry * entry,struct snd_info_buffer * buffer)1168 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
1169 				     struct snd_info_buffer *buffer)
1170 {
1171 	struct snd_mixer_oss *mixer = entry->private_data;
1172 	char line[128], str[32], idxstr[16];
1173 	const char *cptr;
1174 	unsigned int idx;
1175 	int ch;
1176 	struct snd_mixer_oss_assign_table *tbl;
1177 	struct slot *slot;
1178 
1179 	while (!snd_info_get_line(buffer, line, sizeof(line))) {
1180 		cptr = snd_info_get_str(str, line, sizeof(str));
1181 		for (ch = 0; ch < SNDRV_OSS_MAX_MIXERS; ch++)
1182 			if (oss_mixer_names[ch] && strcmp(oss_mixer_names[ch], str) == 0)
1183 				break;
1184 		if (ch >= SNDRV_OSS_MAX_MIXERS) {
1185 			pr_err("ALSA: mixer_oss: invalid OSS volume '%s'\n",
1186 			       str);
1187 			continue;
1188 		}
1189 		cptr = snd_info_get_str(str, cptr, sizeof(str));
1190 		if (! *str) {
1191 			/* remove the entry */
1192 			mutex_lock(&mixer->reg_mutex);
1193 			mixer_slot_clear(&mixer->slots[ch]);
1194 			mutex_unlock(&mixer->reg_mutex);
1195 			continue;
1196 		}
1197 		snd_info_get_str(idxstr, cptr, sizeof(idxstr));
1198 		idx = simple_strtoul(idxstr, NULL, 10);
1199 		if (idx >= 0x4000) { /* too big */
1200 			pr_err("ALSA: mixer_oss: invalid index %d\n", idx);
1201 			continue;
1202 		}
1203 		mutex_lock(&mixer->reg_mutex);
1204 		slot = (struct slot *)mixer->slots[ch].private_data;
1205 		if (slot && slot->assigned &&
1206 		    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
1207 			/* not changed */
1208 			goto __unlock;
1209 		tbl = kmalloc(sizeof(*tbl), GFP_KERNEL);
1210 		if (!tbl)
1211 			goto __unlock;
1212 		tbl->oss_id = ch;
1213 		tbl->name = kstrdup(str, GFP_KERNEL);
1214 		if (! tbl->name) {
1215 			kfree(tbl);
1216 			goto __unlock;
1217 		}
1218 		tbl->index = idx;
1219 		if (snd_mixer_oss_build_input(mixer, tbl, 1, 1) <= 0) {
1220 			kfree(tbl->name);
1221 			kfree(tbl);
1222 		}
1223 	__unlock:
1224 		mutex_unlock(&mixer->reg_mutex);
1225 	}
1226 }
1227 
snd_mixer_oss_proc_init(struct snd_mixer_oss * mixer)1228 static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
1229 {
1230 	struct snd_info_entry *entry;
1231 
1232 	entry = snd_info_create_card_entry(mixer->card, "oss_mixer",
1233 					   mixer->card->proc_root);
1234 	if (! entry)
1235 		return;
1236 	entry->content = SNDRV_INFO_CONTENT_TEXT;
1237 	entry->mode = S_IFREG | 0644;
1238 	entry->c.text.read = snd_mixer_oss_proc_read;
1239 	entry->c.text.write = snd_mixer_oss_proc_write;
1240 	entry->private_data = mixer;
1241 	if (snd_info_register(entry) < 0) {
1242 		snd_info_free_entry(entry);
1243 		entry = NULL;
1244 	}
1245 	mixer->proc_entry = entry;
1246 }
1247 
snd_mixer_oss_proc_done(struct snd_mixer_oss * mixer)1248 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
1249 {
1250 	snd_info_free_entry(mixer->proc_entry);
1251 	mixer->proc_entry = NULL;
1252 }
1253 #else /* !CONFIG_SND_PROC_FS */
1254 #define snd_mixer_oss_proc_init(mix)
1255 #define snd_mixer_oss_proc_done(mix)
1256 #endif /* CONFIG_SND_PROC_FS */
1257 
snd_mixer_oss_build(struct snd_mixer_oss * mixer)1258 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
1259 {
1260 	static const struct snd_mixer_oss_assign_table table[] = {
1261 		{ SOUND_MIXER_VOLUME, 	"Master",		0 },
1262 		{ SOUND_MIXER_VOLUME, 	"Front",		0 }, /* fallback */
1263 		{ SOUND_MIXER_BASS,	"Tone Control - Bass",	0 },
1264 		{ SOUND_MIXER_TREBLE,	"Tone Control - Treble", 0 },
1265 		{ SOUND_MIXER_SYNTH,	"Synth",		0 },
1266 		{ SOUND_MIXER_SYNTH,	"FM",			0 }, /* fallback */
1267 		{ SOUND_MIXER_SYNTH,	"Music",		0 }, /* fallback */
1268 		{ SOUND_MIXER_PCM,	"PCM",			0 },
1269 		{ SOUND_MIXER_SPEAKER,	"Beep", 		0 },
1270 		{ SOUND_MIXER_SPEAKER,	"PC Speaker", 		0 }, /* fallback */
1271 		{ SOUND_MIXER_SPEAKER,	"Speaker", 		0 }, /* fallback */
1272 		{ SOUND_MIXER_LINE,	"Line", 		0 },
1273 		{ SOUND_MIXER_MIC,	"Mic", 			0 },
1274 		{ SOUND_MIXER_CD,	"CD", 			0 },
1275 		{ SOUND_MIXER_IMIX,	"Monitor Mix", 		0 },
1276 		{ SOUND_MIXER_ALTPCM,	"PCM",			1 },
1277 		{ SOUND_MIXER_ALTPCM,	"Headphone",		0 }, /* fallback */
1278 		{ SOUND_MIXER_ALTPCM,	"Wave",			0 }, /* fallback */
1279 		{ SOUND_MIXER_RECLEV,	"-- nothing --",	0 },
1280 		{ SOUND_MIXER_IGAIN,	"Capture",		0 },
1281 		{ SOUND_MIXER_OGAIN,	"Playback",		0 },
1282 		{ SOUND_MIXER_LINE1,	"Aux",			0 },
1283 		{ SOUND_MIXER_LINE2,	"Aux",			1 },
1284 		{ SOUND_MIXER_LINE3,	"Aux",			2 },
1285 		{ SOUND_MIXER_DIGITAL1,	"Digital",		0 },
1286 		{ SOUND_MIXER_DIGITAL1,	"IEC958",		0 }, /* fallback */
1287 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Optical",	0 }, /* fallback */
1288 		{ SOUND_MIXER_DIGITAL1,	"IEC958 Coaxial",	0 }, /* fallback */
1289 		{ SOUND_MIXER_DIGITAL2,	"Digital",		1 },
1290 		{ SOUND_MIXER_DIGITAL3,	"Digital",		2 },
1291 		{ SOUND_MIXER_PHONEIN,	"Phone",		0 },
1292 		{ SOUND_MIXER_PHONEOUT,	"Master Mono",		0 },
1293 		{ SOUND_MIXER_PHONEOUT,	"Speaker",		0 }, /*fallback*/
1294 		{ SOUND_MIXER_PHONEOUT,	"Mono",			0 }, /*fallback*/
1295 		{ SOUND_MIXER_PHONEOUT,	"Phone",		0 }, /* fallback */
1296 		{ SOUND_MIXER_VIDEO,	"Video",		0 },
1297 		{ SOUND_MIXER_RADIO,	"Radio",		0 },
1298 		{ SOUND_MIXER_MONITOR,	"Monitor",		0 }
1299 	};
1300 	unsigned int idx;
1301 
1302 	for (idx = 0; idx < ARRAY_SIZE(table); idx++)
1303 		snd_mixer_oss_build_input(mixer, &table[idx], 0, 0);
1304 	if (mixer->mask_recsrc) {
1305 		mixer->get_recsrc = snd_mixer_oss_get_recsrc2;
1306 		mixer->put_recsrc = snd_mixer_oss_put_recsrc2;
1307 	}
1308 }
1309 
1310 /*
1311  *
1312  */
1313 
snd_mixer_oss_free1(void * private)1314 static int snd_mixer_oss_free1(void *private)
1315 {
1316 	struct snd_mixer_oss *mixer = private;
1317 	struct snd_card *card;
1318 	int idx;
1319 
1320 	if (!mixer)
1321 		return 0;
1322 	card = mixer->card;
1323 	if (snd_BUG_ON(mixer != card->mixer_oss))
1324 		return -ENXIO;
1325 	card->mixer_oss = NULL;
1326 	for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
1327 		struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
1328 		if (chn->private_free)
1329 			chn->private_free(chn);
1330 	}
1331 	kfree(mixer);
1332 	return 0;
1333 }
1334 
snd_mixer_oss_notify_handler(struct snd_card * card,int cmd)1335 static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
1336 {
1337 	struct snd_mixer_oss *mixer;
1338 
1339 	if (cmd == SND_MIXER_OSS_NOTIFY_REGISTER) {
1340 		int idx, err;
1341 
1342 		mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
1343 		if (mixer == NULL)
1344 			return -ENOMEM;
1345 		mutex_init(&mixer->reg_mutex);
1346 		if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
1347 						   card, 0,
1348 						   &snd_mixer_oss_f_ops, card)) < 0) {
1349 			dev_err(card->dev,
1350 				"unable to register OSS mixer device %i:%i\n",
1351 				card->number, 0);
1352 			kfree(mixer);
1353 			return err;
1354 		}
1355 		mixer->oss_dev_alloc = 1;
1356 		mixer->card = card;
1357 		if (*card->mixername)
1358 			strscpy(mixer->name, card->mixername, sizeof(mixer->name));
1359 		else
1360 			snprintf(mixer->name, sizeof(mixer->name),
1361 				 "mixer%i", card->number);
1362 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1363 		snd_oss_info_register(SNDRV_OSS_INFO_DEV_MIXERS,
1364 				      card->number,
1365 				      mixer->name);
1366 #endif
1367 		for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++)
1368 			mixer->slots[idx].number = idx;
1369 		card->mixer_oss = mixer;
1370 		snd_mixer_oss_build(mixer);
1371 		snd_mixer_oss_proc_init(mixer);
1372 	} else {
1373 		mixer = card->mixer_oss;
1374 		if (mixer == NULL)
1375 			return 0;
1376 		if (mixer->oss_dev_alloc) {
1377 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
1378 			snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
1379 #endif
1380 			snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
1381 			mixer->oss_dev_alloc = 0;
1382 		}
1383 		if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
1384 			return 0;
1385 		snd_mixer_oss_proc_done(mixer);
1386 		return snd_mixer_oss_free1(mixer);
1387 	}
1388 	return 0;
1389 }
1390 
alsa_mixer_oss_init(void)1391 static int __init alsa_mixer_oss_init(void)
1392 {
1393 	struct snd_card *card;
1394 	int idx;
1395 
1396 	snd_mixer_oss_notify_callback = snd_mixer_oss_notify_handler;
1397 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
1398 		card = snd_card_ref(idx);
1399 		if (card) {
1400 			snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_REGISTER);
1401 			snd_card_unref(card);
1402 		}
1403 	}
1404 	return 0;
1405 }
1406 
alsa_mixer_oss_exit(void)1407 static void __exit alsa_mixer_oss_exit(void)
1408 {
1409 	struct snd_card *card;
1410 	int idx;
1411 
1412 	snd_mixer_oss_notify_callback = NULL;
1413 	for (idx = 0; idx < SNDRV_CARDS; idx++) {
1414 		card = snd_card_ref(idx);
1415 		if (card) {
1416 			snd_mixer_oss_notify_handler(card, SND_MIXER_OSS_NOTIFY_FREE);
1417 			snd_card_unref(card);
1418 		}
1419 	}
1420 }
1421 
1422 module_init(alsa_mixer_oss_init)
1423 module_exit(alsa_mixer_oss_exit)
1424