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