1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Routines for driver control interface
4*4882a593Smuzhiyun * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <linux/threads.h>
8*4882a593Smuzhiyun #include <linux/interrupt.h>
9*4882a593Smuzhiyun #include <linux/module.h>
10*4882a593Smuzhiyun #include <linux/slab.h>
11*4882a593Smuzhiyun #include <linux/vmalloc.h>
12*4882a593Smuzhiyun #include <linux/time.h>
13*4882a593Smuzhiyun #include <linux/mm.h>
14*4882a593Smuzhiyun #include <linux/math64.h>
15*4882a593Smuzhiyun #include <linux/sched/signal.h>
16*4882a593Smuzhiyun #include <sound/core.h>
17*4882a593Smuzhiyun #include <sound/minors.h>
18*4882a593Smuzhiyun #include <sound/info.h>
19*4882a593Smuzhiyun #include <sound/control.h>
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun /* max number of user-defined controls */
22*4882a593Smuzhiyun #define MAX_USER_CONTROLS 32
23*4882a593Smuzhiyun #define MAX_CONTROL_COUNT 1028
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun struct snd_kctl_ioctl {
26*4882a593Smuzhiyun struct list_head list; /* list of all ioctls */
27*4882a593Smuzhiyun snd_kctl_ioctl_func_t fioctl;
28*4882a593Smuzhiyun };
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun static DECLARE_RWSEM(snd_ioctl_rwsem);
31*4882a593Smuzhiyun static LIST_HEAD(snd_control_ioctls);
32*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
33*4882a593Smuzhiyun static LIST_HEAD(snd_control_compat_ioctls);
34*4882a593Smuzhiyun #endif
35*4882a593Smuzhiyun
snd_ctl_open(struct inode * inode,struct file * file)36*4882a593Smuzhiyun static int snd_ctl_open(struct inode *inode, struct file *file)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun unsigned long flags;
39*4882a593Smuzhiyun struct snd_card *card;
40*4882a593Smuzhiyun struct snd_ctl_file *ctl;
41*4882a593Smuzhiyun int i, err;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun err = stream_open(inode, file);
44*4882a593Smuzhiyun if (err < 0)
45*4882a593Smuzhiyun return err;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
48*4882a593Smuzhiyun if (!card) {
49*4882a593Smuzhiyun err = -ENODEV;
50*4882a593Smuzhiyun goto __error1;
51*4882a593Smuzhiyun }
52*4882a593Smuzhiyun err = snd_card_file_add(card, file);
53*4882a593Smuzhiyun if (err < 0) {
54*4882a593Smuzhiyun err = -ENODEV;
55*4882a593Smuzhiyun goto __error1;
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun if (!try_module_get(card->module)) {
58*4882a593Smuzhiyun err = -EFAULT;
59*4882a593Smuzhiyun goto __error2;
60*4882a593Smuzhiyun }
61*4882a593Smuzhiyun ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
62*4882a593Smuzhiyun if (ctl == NULL) {
63*4882a593Smuzhiyun err = -ENOMEM;
64*4882a593Smuzhiyun goto __error;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun INIT_LIST_HEAD(&ctl->events);
67*4882a593Smuzhiyun init_waitqueue_head(&ctl->change_sleep);
68*4882a593Smuzhiyun spin_lock_init(&ctl->read_lock);
69*4882a593Smuzhiyun ctl->card = card;
70*4882a593Smuzhiyun for (i = 0; i < SND_CTL_SUBDEV_ITEMS; i++)
71*4882a593Smuzhiyun ctl->preferred_subdevice[i] = -1;
72*4882a593Smuzhiyun ctl->pid = get_pid(task_pid(current));
73*4882a593Smuzhiyun file->private_data = ctl;
74*4882a593Smuzhiyun write_lock_irqsave(&card->ctl_files_rwlock, flags);
75*4882a593Smuzhiyun list_add_tail(&ctl->list, &card->ctl_files);
76*4882a593Smuzhiyun write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
77*4882a593Smuzhiyun snd_card_unref(card);
78*4882a593Smuzhiyun return 0;
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun __error:
81*4882a593Smuzhiyun module_put(card->module);
82*4882a593Smuzhiyun __error2:
83*4882a593Smuzhiyun snd_card_file_remove(card, file);
84*4882a593Smuzhiyun __error1:
85*4882a593Smuzhiyun if (card)
86*4882a593Smuzhiyun snd_card_unref(card);
87*4882a593Smuzhiyun return err;
88*4882a593Smuzhiyun }
89*4882a593Smuzhiyun
snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)90*4882a593Smuzhiyun static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
91*4882a593Smuzhiyun {
92*4882a593Smuzhiyun unsigned long flags;
93*4882a593Smuzhiyun struct snd_kctl_event *cread;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun spin_lock_irqsave(&ctl->read_lock, flags);
96*4882a593Smuzhiyun while (!list_empty(&ctl->events)) {
97*4882a593Smuzhiyun cread = snd_kctl_event(ctl->events.next);
98*4882a593Smuzhiyun list_del(&cread->list);
99*4882a593Smuzhiyun kfree(cread);
100*4882a593Smuzhiyun }
101*4882a593Smuzhiyun spin_unlock_irqrestore(&ctl->read_lock, flags);
102*4882a593Smuzhiyun }
103*4882a593Smuzhiyun
snd_ctl_release(struct inode * inode,struct file * file)104*4882a593Smuzhiyun static int snd_ctl_release(struct inode *inode, struct file *file)
105*4882a593Smuzhiyun {
106*4882a593Smuzhiyun unsigned long flags;
107*4882a593Smuzhiyun struct snd_card *card;
108*4882a593Smuzhiyun struct snd_ctl_file *ctl;
109*4882a593Smuzhiyun struct snd_kcontrol *control;
110*4882a593Smuzhiyun unsigned int idx;
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun ctl = file->private_data;
113*4882a593Smuzhiyun file->private_data = NULL;
114*4882a593Smuzhiyun card = ctl->card;
115*4882a593Smuzhiyun write_lock_irqsave(&card->ctl_files_rwlock, flags);
116*4882a593Smuzhiyun list_del(&ctl->list);
117*4882a593Smuzhiyun write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
118*4882a593Smuzhiyun down_write(&card->controls_rwsem);
119*4882a593Smuzhiyun list_for_each_entry(control, &card->controls, list)
120*4882a593Smuzhiyun for (idx = 0; idx < control->count; idx++)
121*4882a593Smuzhiyun if (control->vd[idx].owner == ctl)
122*4882a593Smuzhiyun control->vd[idx].owner = NULL;
123*4882a593Smuzhiyun up_write(&card->controls_rwsem);
124*4882a593Smuzhiyun snd_ctl_empty_read_queue(ctl);
125*4882a593Smuzhiyun put_pid(ctl->pid);
126*4882a593Smuzhiyun kfree(ctl);
127*4882a593Smuzhiyun module_put(card->module);
128*4882a593Smuzhiyun snd_card_file_remove(card, file);
129*4882a593Smuzhiyun return 0;
130*4882a593Smuzhiyun }
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun /**
133*4882a593Smuzhiyun * snd_ctl_notify - Send notification to user-space for a control change
134*4882a593Smuzhiyun * @card: the card to send notification
135*4882a593Smuzhiyun * @mask: the event mask, SNDRV_CTL_EVENT_*
136*4882a593Smuzhiyun * @id: the ctl element id to send notification
137*4882a593Smuzhiyun *
138*4882a593Smuzhiyun * This function adds an event record with the given id and mask, appends
139*4882a593Smuzhiyun * to the list and wakes up the user-space for notification. This can be
140*4882a593Smuzhiyun * called in the atomic context.
141*4882a593Smuzhiyun */
snd_ctl_notify(struct snd_card * card,unsigned int mask,struct snd_ctl_elem_id * id)142*4882a593Smuzhiyun void snd_ctl_notify(struct snd_card *card, unsigned int mask,
143*4882a593Smuzhiyun struct snd_ctl_elem_id *id)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun unsigned long flags;
146*4882a593Smuzhiyun struct snd_ctl_file *ctl;
147*4882a593Smuzhiyun struct snd_kctl_event *ev;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (snd_BUG_ON(!card || !id))
150*4882a593Smuzhiyun return;
151*4882a593Smuzhiyun if (card->shutdown)
152*4882a593Smuzhiyun return;
153*4882a593Smuzhiyun read_lock_irqsave(&card->ctl_files_rwlock, flags);
154*4882a593Smuzhiyun #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
155*4882a593Smuzhiyun card->mixer_oss_change_count++;
156*4882a593Smuzhiyun #endif
157*4882a593Smuzhiyun list_for_each_entry(ctl, &card->ctl_files, list) {
158*4882a593Smuzhiyun if (!ctl->subscribed)
159*4882a593Smuzhiyun continue;
160*4882a593Smuzhiyun spin_lock(&ctl->read_lock);
161*4882a593Smuzhiyun list_for_each_entry(ev, &ctl->events, list) {
162*4882a593Smuzhiyun if (ev->id.numid == id->numid) {
163*4882a593Smuzhiyun ev->mask |= mask;
164*4882a593Smuzhiyun goto _found;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun }
167*4882a593Smuzhiyun ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
168*4882a593Smuzhiyun if (ev) {
169*4882a593Smuzhiyun ev->id = *id;
170*4882a593Smuzhiyun ev->mask = mask;
171*4882a593Smuzhiyun list_add_tail(&ev->list, &ctl->events);
172*4882a593Smuzhiyun } else {
173*4882a593Smuzhiyun dev_err(card->dev, "No memory available to allocate event\n");
174*4882a593Smuzhiyun }
175*4882a593Smuzhiyun _found:
176*4882a593Smuzhiyun wake_up(&ctl->change_sleep);
177*4882a593Smuzhiyun spin_unlock(&ctl->read_lock);
178*4882a593Smuzhiyun kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_notify);
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /**
185*4882a593Smuzhiyun * snd_ctl_new - create a new control instance with some elements
186*4882a593Smuzhiyun * @kctl: the pointer to store new control instance
187*4882a593Smuzhiyun * @count: the number of elements in this control
188*4882a593Smuzhiyun * @access: the default access flags for elements in this control
189*4882a593Smuzhiyun * @file: given when locking these elements
190*4882a593Smuzhiyun *
191*4882a593Smuzhiyun * Allocates a memory object for a new control instance. The instance has
192*4882a593Smuzhiyun * elements as many as the given number (@count). Each element has given
193*4882a593Smuzhiyun * access permissions (@access). Each element is locked when @file is given.
194*4882a593Smuzhiyun *
195*4882a593Smuzhiyun * Return: 0 on success, error code on failure
196*4882a593Smuzhiyun */
snd_ctl_new(struct snd_kcontrol ** kctl,unsigned int count,unsigned int access,struct snd_ctl_file * file)197*4882a593Smuzhiyun static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
198*4882a593Smuzhiyun unsigned int access, struct snd_ctl_file *file)
199*4882a593Smuzhiyun {
200*4882a593Smuzhiyun unsigned int idx;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (count == 0 || count > MAX_CONTROL_COUNT)
203*4882a593Smuzhiyun return -EINVAL;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun *kctl = kzalloc(struct_size(*kctl, vd, count), GFP_KERNEL);
206*4882a593Smuzhiyun if (!*kctl)
207*4882a593Smuzhiyun return -ENOMEM;
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun for (idx = 0; idx < count; idx++) {
210*4882a593Smuzhiyun (*kctl)->vd[idx].access = access;
211*4882a593Smuzhiyun (*kctl)->vd[idx].owner = file;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun (*kctl)->count = count;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun return 0;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun /**
219*4882a593Smuzhiyun * snd_ctl_new1 - create a control instance from the template
220*4882a593Smuzhiyun * @ncontrol: the initialization record
221*4882a593Smuzhiyun * @private_data: the private data to set
222*4882a593Smuzhiyun *
223*4882a593Smuzhiyun * Allocates a new struct snd_kcontrol instance and initialize from the given
224*4882a593Smuzhiyun * template. When the access field of ncontrol is 0, it's assumed as
225*4882a593Smuzhiyun * READWRITE access. When the count field is 0, it's assumes as one.
226*4882a593Smuzhiyun *
227*4882a593Smuzhiyun * Return: The pointer of the newly generated instance, or %NULL on failure.
228*4882a593Smuzhiyun */
snd_ctl_new1(const struct snd_kcontrol_new * ncontrol,void * private_data)229*4882a593Smuzhiyun struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
230*4882a593Smuzhiyun void *private_data)
231*4882a593Smuzhiyun {
232*4882a593Smuzhiyun struct snd_kcontrol *kctl;
233*4882a593Smuzhiyun unsigned int count;
234*4882a593Smuzhiyun unsigned int access;
235*4882a593Smuzhiyun int err;
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun if (snd_BUG_ON(!ncontrol || !ncontrol->info))
238*4882a593Smuzhiyun return NULL;
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun count = ncontrol->count;
241*4882a593Smuzhiyun if (count == 0)
242*4882a593Smuzhiyun count = 1;
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun access = ncontrol->access;
245*4882a593Smuzhiyun if (access == 0)
246*4882a593Smuzhiyun access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
247*4882a593Smuzhiyun access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
248*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_VOLATILE |
249*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_INACTIVE |
250*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE |
251*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND |
252*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK |
253*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK);
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun err = snd_ctl_new(&kctl, count, access, NULL);
256*4882a593Smuzhiyun if (err < 0)
257*4882a593Smuzhiyun return NULL;
258*4882a593Smuzhiyun
259*4882a593Smuzhiyun /* The 'numid' member is decided when calling snd_ctl_add(). */
260*4882a593Smuzhiyun kctl->id.iface = ncontrol->iface;
261*4882a593Smuzhiyun kctl->id.device = ncontrol->device;
262*4882a593Smuzhiyun kctl->id.subdevice = ncontrol->subdevice;
263*4882a593Smuzhiyun if (ncontrol->name) {
264*4882a593Smuzhiyun strlcpy(kctl->id.name, ncontrol->name, sizeof(kctl->id.name));
265*4882a593Smuzhiyun if (strcmp(ncontrol->name, kctl->id.name) != 0)
266*4882a593Smuzhiyun pr_warn("ALSA: Control name '%s' truncated to '%s'\n",
267*4882a593Smuzhiyun ncontrol->name, kctl->id.name);
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun kctl->id.index = ncontrol->index;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun kctl->info = ncontrol->info;
272*4882a593Smuzhiyun kctl->get = ncontrol->get;
273*4882a593Smuzhiyun kctl->put = ncontrol->put;
274*4882a593Smuzhiyun kctl->tlv.p = ncontrol->tlv.p;
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun kctl->private_value = ncontrol->private_value;
277*4882a593Smuzhiyun kctl->private_data = private_data;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun return kctl;
280*4882a593Smuzhiyun }
281*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_new1);
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun /**
284*4882a593Smuzhiyun * snd_ctl_free_one - release the control instance
285*4882a593Smuzhiyun * @kcontrol: the control instance
286*4882a593Smuzhiyun *
287*4882a593Smuzhiyun * Releases the control instance created via snd_ctl_new()
288*4882a593Smuzhiyun * or snd_ctl_new1().
289*4882a593Smuzhiyun * Don't call this after the control was added to the card.
290*4882a593Smuzhiyun */
snd_ctl_free_one(struct snd_kcontrol * kcontrol)291*4882a593Smuzhiyun void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun if (kcontrol) {
294*4882a593Smuzhiyun if (kcontrol->private_free)
295*4882a593Smuzhiyun kcontrol->private_free(kcontrol);
296*4882a593Smuzhiyun kfree(kcontrol);
297*4882a593Smuzhiyun }
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_free_one);
300*4882a593Smuzhiyun
snd_ctl_remove_numid_conflict(struct snd_card * card,unsigned int count)301*4882a593Smuzhiyun static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
302*4882a593Smuzhiyun unsigned int count)
303*4882a593Smuzhiyun {
304*4882a593Smuzhiyun struct snd_kcontrol *kctl;
305*4882a593Smuzhiyun
306*4882a593Smuzhiyun /* Make sure that the ids assigned to the control do not wrap around */
307*4882a593Smuzhiyun if (card->last_numid >= UINT_MAX - count)
308*4882a593Smuzhiyun card->last_numid = 0;
309*4882a593Smuzhiyun
310*4882a593Smuzhiyun list_for_each_entry(kctl, &card->controls, list) {
311*4882a593Smuzhiyun if (kctl->id.numid < card->last_numid + 1 + count &&
312*4882a593Smuzhiyun kctl->id.numid + kctl->count > card->last_numid + 1) {
313*4882a593Smuzhiyun card->last_numid = kctl->id.numid + kctl->count - 1;
314*4882a593Smuzhiyun return true;
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun }
317*4882a593Smuzhiyun return false;
318*4882a593Smuzhiyun }
319*4882a593Smuzhiyun
snd_ctl_find_hole(struct snd_card * card,unsigned int count)320*4882a593Smuzhiyun static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun unsigned int iter = 100000;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun while (snd_ctl_remove_numid_conflict(card, count)) {
325*4882a593Smuzhiyun if (--iter == 0) {
326*4882a593Smuzhiyun /* this situation is very unlikely */
327*4882a593Smuzhiyun dev_err(card->dev, "unable to allocate new control numid\n");
328*4882a593Smuzhiyun return -ENOMEM;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun }
331*4882a593Smuzhiyun return 0;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun enum snd_ctl_add_mode {
335*4882a593Smuzhiyun CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun /* add/replace a new kcontrol object; call with card->controls_rwsem locked */
__snd_ctl_add_replace(struct snd_card * card,struct snd_kcontrol * kcontrol,enum snd_ctl_add_mode mode)339*4882a593Smuzhiyun static int __snd_ctl_add_replace(struct snd_card *card,
340*4882a593Smuzhiyun struct snd_kcontrol *kcontrol,
341*4882a593Smuzhiyun enum snd_ctl_add_mode mode)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun struct snd_ctl_elem_id id;
344*4882a593Smuzhiyun unsigned int idx;
345*4882a593Smuzhiyun unsigned int count;
346*4882a593Smuzhiyun struct snd_kcontrol *old;
347*4882a593Smuzhiyun int err;
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun id = kcontrol->id;
350*4882a593Smuzhiyun if (id.index > UINT_MAX - kcontrol->count)
351*4882a593Smuzhiyun return -EINVAL;
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun old = snd_ctl_find_id(card, &id);
354*4882a593Smuzhiyun if (!old) {
355*4882a593Smuzhiyun if (mode == CTL_REPLACE)
356*4882a593Smuzhiyun return -EINVAL;
357*4882a593Smuzhiyun } else {
358*4882a593Smuzhiyun if (mode == CTL_ADD_EXCLUSIVE) {
359*4882a593Smuzhiyun dev_err(card->dev,
360*4882a593Smuzhiyun "control %i:%i:%i:%s:%i is already present\n",
361*4882a593Smuzhiyun id.iface, id.device, id.subdevice, id.name,
362*4882a593Smuzhiyun id.index);
363*4882a593Smuzhiyun return -EBUSY;
364*4882a593Smuzhiyun }
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun err = snd_ctl_remove(card, old);
367*4882a593Smuzhiyun if (err < 0)
368*4882a593Smuzhiyun return err;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun if (snd_ctl_find_hole(card, kcontrol->count) < 0)
372*4882a593Smuzhiyun return -ENOMEM;
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun list_add_tail(&kcontrol->list, &card->controls);
375*4882a593Smuzhiyun card->controls_count += kcontrol->count;
376*4882a593Smuzhiyun kcontrol->id.numid = card->last_numid + 1;
377*4882a593Smuzhiyun card->last_numid += kcontrol->count;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun id = kcontrol->id;
380*4882a593Smuzhiyun count = kcontrol->count;
381*4882a593Smuzhiyun for (idx = 0; idx < count; idx++, id.index++, id.numid++)
382*4882a593Smuzhiyun snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
snd_ctl_add_replace(struct snd_card * card,struct snd_kcontrol * kcontrol,enum snd_ctl_add_mode mode)387*4882a593Smuzhiyun static int snd_ctl_add_replace(struct snd_card *card,
388*4882a593Smuzhiyun struct snd_kcontrol *kcontrol,
389*4882a593Smuzhiyun enum snd_ctl_add_mode mode)
390*4882a593Smuzhiyun {
391*4882a593Smuzhiyun int err = -EINVAL;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun if (! kcontrol)
394*4882a593Smuzhiyun return err;
395*4882a593Smuzhiyun if (snd_BUG_ON(!card || !kcontrol->info))
396*4882a593Smuzhiyun goto error;
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun down_write(&card->controls_rwsem);
399*4882a593Smuzhiyun err = __snd_ctl_add_replace(card, kcontrol, mode);
400*4882a593Smuzhiyun up_write(&card->controls_rwsem);
401*4882a593Smuzhiyun if (err < 0)
402*4882a593Smuzhiyun goto error;
403*4882a593Smuzhiyun return 0;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun error:
406*4882a593Smuzhiyun snd_ctl_free_one(kcontrol);
407*4882a593Smuzhiyun return err;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun /**
411*4882a593Smuzhiyun * snd_ctl_add - add the control instance to the card
412*4882a593Smuzhiyun * @card: the card instance
413*4882a593Smuzhiyun * @kcontrol: the control instance to add
414*4882a593Smuzhiyun *
415*4882a593Smuzhiyun * Adds the control instance created via snd_ctl_new() or
416*4882a593Smuzhiyun * snd_ctl_new1() to the given card. Assigns also an unique
417*4882a593Smuzhiyun * numid used for fast search.
418*4882a593Smuzhiyun *
419*4882a593Smuzhiyun * It frees automatically the control which cannot be added.
420*4882a593Smuzhiyun *
421*4882a593Smuzhiyun * Return: Zero if successful, or a negative error code on failure.
422*4882a593Smuzhiyun *
423*4882a593Smuzhiyun */
snd_ctl_add(struct snd_card * card,struct snd_kcontrol * kcontrol)424*4882a593Smuzhiyun int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
425*4882a593Smuzhiyun {
426*4882a593Smuzhiyun return snd_ctl_add_replace(card, kcontrol, CTL_ADD_EXCLUSIVE);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_add);
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun /**
431*4882a593Smuzhiyun * snd_ctl_replace - replace the control instance of the card
432*4882a593Smuzhiyun * @card: the card instance
433*4882a593Smuzhiyun * @kcontrol: the control instance to replace
434*4882a593Smuzhiyun * @add_on_replace: add the control if not already added
435*4882a593Smuzhiyun *
436*4882a593Smuzhiyun * Replaces the given control. If the given control does not exist
437*4882a593Smuzhiyun * and the add_on_replace flag is set, the control is added. If the
438*4882a593Smuzhiyun * control exists, it is destroyed first.
439*4882a593Smuzhiyun *
440*4882a593Smuzhiyun * It frees automatically the control which cannot be added or replaced.
441*4882a593Smuzhiyun *
442*4882a593Smuzhiyun * Return: Zero if successful, or a negative error code on failure.
443*4882a593Smuzhiyun */
snd_ctl_replace(struct snd_card * card,struct snd_kcontrol * kcontrol,bool add_on_replace)444*4882a593Smuzhiyun int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
445*4882a593Smuzhiyun bool add_on_replace)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun return snd_ctl_add_replace(card, kcontrol,
448*4882a593Smuzhiyun add_on_replace ? CTL_ADD_ON_REPLACE : CTL_REPLACE);
449*4882a593Smuzhiyun }
450*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_replace);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /**
453*4882a593Smuzhiyun * snd_ctl_remove - remove the control from the card and release it
454*4882a593Smuzhiyun * @card: the card instance
455*4882a593Smuzhiyun * @kcontrol: the control instance to remove
456*4882a593Smuzhiyun *
457*4882a593Smuzhiyun * Removes the control from the card and then releases the instance.
458*4882a593Smuzhiyun * You don't need to call snd_ctl_free_one(). You must be in
459*4882a593Smuzhiyun * the write lock - down_write(&card->controls_rwsem).
460*4882a593Smuzhiyun *
461*4882a593Smuzhiyun * Return: 0 if successful, or a negative error code on failure.
462*4882a593Smuzhiyun */
snd_ctl_remove(struct snd_card * card,struct snd_kcontrol * kcontrol)463*4882a593Smuzhiyun int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun struct snd_ctl_elem_id id;
466*4882a593Smuzhiyun unsigned int idx;
467*4882a593Smuzhiyun
468*4882a593Smuzhiyun if (snd_BUG_ON(!card || !kcontrol))
469*4882a593Smuzhiyun return -EINVAL;
470*4882a593Smuzhiyun list_del(&kcontrol->list);
471*4882a593Smuzhiyun card->controls_count -= kcontrol->count;
472*4882a593Smuzhiyun id = kcontrol->id;
473*4882a593Smuzhiyun for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
474*4882a593Smuzhiyun snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);
475*4882a593Smuzhiyun snd_ctl_free_one(kcontrol);
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_remove);
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun /**
481*4882a593Smuzhiyun * snd_ctl_remove_id - remove the control of the given id and release it
482*4882a593Smuzhiyun * @card: the card instance
483*4882a593Smuzhiyun * @id: the control id to remove
484*4882a593Smuzhiyun *
485*4882a593Smuzhiyun * Finds the control instance with the given id, removes it from the
486*4882a593Smuzhiyun * card list and releases it.
487*4882a593Smuzhiyun *
488*4882a593Smuzhiyun * Return: 0 if successful, or a negative error code on failure.
489*4882a593Smuzhiyun */
snd_ctl_remove_id(struct snd_card * card,struct snd_ctl_elem_id * id)490*4882a593Smuzhiyun int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
491*4882a593Smuzhiyun {
492*4882a593Smuzhiyun struct snd_kcontrol *kctl;
493*4882a593Smuzhiyun int ret;
494*4882a593Smuzhiyun
495*4882a593Smuzhiyun down_write(&card->controls_rwsem);
496*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, id);
497*4882a593Smuzhiyun if (kctl == NULL) {
498*4882a593Smuzhiyun up_write(&card->controls_rwsem);
499*4882a593Smuzhiyun return -ENOENT;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun ret = snd_ctl_remove(card, kctl);
502*4882a593Smuzhiyun up_write(&card->controls_rwsem);
503*4882a593Smuzhiyun return ret;
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_remove_id);
506*4882a593Smuzhiyun
507*4882a593Smuzhiyun /**
508*4882a593Smuzhiyun * snd_ctl_remove_user_ctl - remove and release the unlocked user control
509*4882a593Smuzhiyun * @file: active control handle
510*4882a593Smuzhiyun * @id: the control id to remove
511*4882a593Smuzhiyun *
512*4882a593Smuzhiyun * Finds the control instance with the given id, removes it from the
513*4882a593Smuzhiyun * card list and releases it.
514*4882a593Smuzhiyun *
515*4882a593Smuzhiyun * Return: 0 if successful, or a negative error code on failure.
516*4882a593Smuzhiyun */
snd_ctl_remove_user_ctl(struct snd_ctl_file * file,struct snd_ctl_elem_id * id)517*4882a593Smuzhiyun static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
518*4882a593Smuzhiyun struct snd_ctl_elem_id *id)
519*4882a593Smuzhiyun {
520*4882a593Smuzhiyun struct snd_card *card = file->card;
521*4882a593Smuzhiyun struct snd_kcontrol *kctl;
522*4882a593Smuzhiyun int idx, ret;
523*4882a593Smuzhiyun
524*4882a593Smuzhiyun down_write(&card->controls_rwsem);
525*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, id);
526*4882a593Smuzhiyun if (kctl == NULL) {
527*4882a593Smuzhiyun ret = -ENOENT;
528*4882a593Smuzhiyun goto error;
529*4882a593Smuzhiyun }
530*4882a593Smuzhiyun if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
531*4882a593Smuzhiyun ret = -EINVAL;
532*4882a593Smuzhiyun goto error;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun for (idx = 0; idx < kctl->count; idx++)
535*4882a593Smuzhiyun if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
536*4882a593Smuzhiyun ret = -EBUSY;
537*4882a593Smuzhiyun goto error;
538*4882a593Smuzhiyun }
539*4882a593Smuzhiyun ret = snd_ctl_remove(card, kctl);
540*4882a593Smuzhiyun if (ret < 0)
541*4882a593Smuzhiyun goto error;
542*4882a593Smuzhiyun card->user_ctl_count--;
543*4882a593Smuzhiyun error:
544*4882a593Smuzhiyun up_write(&card->controls_rwsem);
545*4882a593Smuzhiyun return ret;
546*4882a593Smuzhiyun }
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun /**
549*4882a593Smuzhiyun * snd_ctl_activate_id - activate/inactivate the control of the given id
550*4882a593Smuzhiyun * @card: the card instance
551*4882a593Smuzhiyun * @id: the control id to activate/inactivate
552*4882a593Smuzhiyun * @active: non-zero to activate
553*4882a593Smuzhiyun *
554*4882a593Smuzhiyun * Finds the control instance with the given id, and activate or
555*4882a593Smuzhiyun * inactivate the control together with notification, if changed.
556*4882a593Smuzhiyun * The given ID data is filled with full information.
557*4882a593Smuzhiyun *
558*4882a593Smuzhiyun * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
559*4882a593Smuzhiyun */
snd_ctl_activate_id(struct snd_card * card,struct snd_ctl_elem_id * id,int active)560*4882a593Smuzhiyun int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
561*4882a593Smuzhiyun int active)
562*4882a593Smuzhiyun {
563*4882a593Smuzhiyun struct snd_kcontrol *kctl;
564*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
565*4882a593Smuzhiyun unsigned int index_offset;
566*4882a593Smuzhiyun int ret;
567*4882a593Smuzhiyun
568*4882a593Smuzhiyun down_write(&card->controls_rwsem);
569*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, id);
570*4882a593Smuzhiyun if (kctl == NULL) {
571*4882a593Smuzhiyun ret = -ENOENT;
572*4882a593Smuzhiyun goto unlock;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun index_offset = snd_ctl_get_ioff(kctl, id);
575*4882a593Smuzhiyun vd = &kctl->vd[index_offset];
576*4882a593Smuzhiyun ret = 0;
577*4882a593Smuzhiyun if (active) {
578*4882a593Smuzhiyun if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
579*4882a593Smuzhiyun goto unlock;
580*4882a593Smuzhiyun vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
581*4882a593Smuzhiyun } else {
582*4882a593Smuzhiyun if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
583*4882a593Smuzhiyun goto unlock;
584*4882a593Smuzhiyun vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
585*4882a593Smuzhiyun }
586*4882a593Smuzhiyun snd_ctl_build_ioff(id, kctl, index_offset);
587*4882a593Smuzhiyun ret = 1;
588*4882a593Smuzhiyun unlock:
589*4882a593Smuzhiyun up_write(&card->controls_rwsem);
590*4882a593Smuzhiyun if (ret > 0)
591*4882a593Smuzhiyun snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
592*4882a593Smuzhiyun return ret;
593*4882a593Smuzhiyun }
594*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
595*4882a593Smuzhiyun
596*4882a593Smuzhiyun /**
597*4882a593Smuzhiyun * snd_ctl_rename_id - replace the id of a control on the card
598*4882a593Smuzhiyun * @card: the card instance
599*4882a593Smuzhiyun * @src_id: the old id
600*4882a593Smuzhiyun * @dst_id: the new id
601*4882a593Smuzhiyun *
602*4882a593Smuzhiyun * Finds the control with the old id from the card, and replaces the
603*4882a593Smuzhiyun * id with the new one.
604*4882a593Smuzhiyun *
605*4882a593Smuzhiyun * Return: Zero if successful, or a negative error code on failure.
606*4882a593Smuzhiyun */
snd_ctl_rename_id(struct snd_card * card,struct snd_ctl_elem_id * src_id,struct snd_ctl_elem_id * dst_id)607*4882a593Smuzhiyun int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
608*4882a593Smuzhiyun struct snd_ctl_elem_id *dst_id)
609*4882a593Smuzhiyun {
610*4882a593Smuzhiyun struct snd_kcontrol *kctl;
611*4882a593Smuzhiyun
612*4882a593Smuzhiyun down_write(&card->controls_rwsem);
613*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, src_id);
614*4882a593Smuzhiyun if (kctl == NULL) {
615*4882a593Smuzhiyun up_write(&card->controls_rwsem);
616*4882a593Smuzhiyun return -ENOENT;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun kctl->id = *dst_id;
619*4882a593Smuzhiyun kctl->id.numid = card->last_numid + 1;
620*4882a593Smuzhiyun card->last_numid += kctl->count;
621*4882a593Smuzhiyun up_write(&card->controls_rwsem);
622*4882a593Smuzhiyun return 0;
623*4882a593Smuzhiyun }
624*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_rename_id);
625*4882a593Smuzhiyun
626*4882a593Smuzhiyun /**
627*4882a593Smuzhiyun * snd_ctl_find_numid - find the control instance with the given number-id
628*4882a593Smuzhiyun * @card: the card instance
629*4882a593Smuzhiyun * @numid: the number-id to search
630*4882a593Smuzhiyun *
631*4882a593Smuzhiyun * Finds the control instance with the given number-id from the card.
632*4882a593Smuzhiyun *
633*4882a593Smuzhiyun * The caller must down card->controls_rwsem before calling this function
634*4882a593Smuzhiyun * (if the race condition can happen).
635*4882a593Smuzhiyun *
636*4882a593Smuzhiyun * Return: The pointer of the instance if found, or %NULL if not.
637*4882a593Smuzhiyun *
638*4882a593Smuzhiyun */
snd_ctl_find_numid(struct snd_card * card,unsigned int numid)639*4882a593Smuzhiyun struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
640*4882a593Smuzhiyun {
641*4882a593Smuzhiyun struct snd_kcontrol *kctl;
642*4882a593Smuzhiyun
643*4882a593Smuzhiyun if (snd_BUG_ON(!card || !numid))
644*4882a593Smuzhiyun return NULL;
645*4882a593Smuzhiyun list_for_each_entry(kctl, &card->controls, list) {
646*4882a593Smuzhiyun if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
647*4882a593Smuzhiyun return kctl;
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun return NULL;
650*4882a593Smuzhiyun }
651*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_find_numid);
652*4882a593Smuzhiyun
653*4882a593Smuzhiyun /**
654*4882a593Smuzhiyun * snd_ctl_find_id - find the control instance with the given id
655*4882a593Smuzhiyun * @card: the card instance
656*4882a593Smuzhiyun * @id: the id to search
657*4882a593Smuzhiyun *
658*4882a593Smuzhiyun * Finds the control instance with the given id from the card.
659*4882a593Smuzhiyun *
660*4882a593Smuzhiyun * The caller must down card->controls_rwsem before calling this function
661*4882a593Smuzhiyun * (if the race condition can happen).
662*4882a593Smuzhiyun *
663*4882a593Smuzhiyun * Return: The pointer of the instance if found, or %NULL if not.
664*4882a593Smuzhiyun *
665*4882a593Smuzhiyun */
snd_ctl_find_id(struct snd_card * card,struct snd_ctl_elem_id * id)666*4882a593Smuzhiyun struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
667*4882a593Smuzhiyun struct snd_ctl_elem_id *id)
668*4882a593Smuzhiyun {
669*4882a593Smuzhiyun struct snd_kcontrol *kctl;
670*4882a593Smuzhiyun
671*4882a593Smuzhiyun if (snd_BUG_ON(!card || !id))
672*4882a593Smuzhiyun return NULL;
673*4882a593Smuzhiyun if (id->numid != 0)
674*4882a593Smuzhiyun return snd_ctl_find_numid(card, id->numid);
675*4882a593Smuzhiyun list_for_each_entry(kctl, &card->controls, list) {
676*4882a593Smuzhiyun if (kctl->id.iface != id->iface)
677*4882a593Smuzhiyun continue;
678*4882a593Smuzhiyun if (kctl->id.device != id->device)
679*4882a593Smuzhiyun continue;
680*4882a593Smuzhiyun if (kctl->id.subdevice != id->subdevice)
681*4882a593Smuzhiyun continue;
682*4882a593Smuzhiyun if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))
683*4882a593Smuzhiyun continue;
684*4882a593Smuzhiyun if (kctl->id.index > id->index)
685*4882a593Smuzhiyun continue;
686*4882a593Smuzhiyun if (kctl->id.index + kctl->count <= id->index)
687*4882a593Smuzhiyun continue;
688*4882a593Smuzhiyun return kctl;
689*4882a593Smuzhiyun }
690*4882a593Smuzhiyun return NULL;
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_find_id);
693*4882a593Smuzhiyun
snd_ctl_card_info(struct snd_card * card,struct snd_ctl_file * ctl,unsigned int cmd,void __user * arg)694*4882a593Smuzhiyun static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
695*4882a593Smuzhiyun unsigned int cmd, void __user *arg)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun struct snd_ctl_card_info *info;
698*4882a593Smuzhiyun
699*4882a593Smuzhiyun info = kzalloc(sizeof(*info), GFP_KERNEL);
700*4882a593Smuzhiyun if (! info)
701*4882a593Smuzhiyun return -ENOMEM;
702*4882a593Smuzhiyun down_read(&snd_ioctl_rwsem);
703*4882a593Smuzhiyun info->card = card->number;
704*4882a593Smuzhiyun strlcpy(info->id, card->id, sizeof(info->id));
705*4882a593Smuzhiyun strlcpy(info->driver, card->driver, sizeof(info->driver));
706*4882a593Smuzhiyun strlcpy(info->name, card->shortname, sizeof(info->name));
707*4882a593Smuzhiyun strlcpy(info->longname, card->longname, sizeof(info->longname));
708*4882a593Smuzhiyun strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
709*4882a593Smuzhiyun strlcpy(info->components, card->components, sizeof(info->components));
710*4882a593Smuzhiyun up_read(&snd_ioctl_rwsem);
711*4882a593Smuzhiyun if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
712*4882a593Smuzhiyun kfree(info);
713*4882a593Smuzhiyun return -EFAULT;
714*4882a593Smuzhiyun }
715*4882a593Smuzhiyun kfree(info);
716*4882a593Smuzhiyun return 0;
717*4882a593Smuzhiyun }
718*4882a593Smuzhiyun
snd_ctl_elem_list(struct snd_card * card,struct snd_ctl_elem_list * list)719*4882a593Smuzhiyun static int snd_ctl_elem_list(struct snd_card *card,
720*4882a593Smuzhiyun struct snd_ctl_elem_list *list)
721*4882a593Smuzhiyun {
722*4882a593Smuzhiyun struct snd_kcontrol *kctl;
723*4882a593Smuzhiyun struct snd_ctl_elem_id id;
724*4882a593Smuzhiyun unsigned int offset, space, jidx;
725*4882a593Smuzhiyun int err = 0;
726*4882a593Smuzhiyun
727*4882a593Smuzhiyun offset = list->offset;
728*4882a593Smuzhiyun space = list->space;
729*4882a593Smuzhiyun
730*4882a593Smuzhiyun down_read(&card->controls_rwsem);
731*4882a593Smuzhiyun list->count = card->controls_count;
732*4882a593Smuzhiyun list->used = 0;
733*4882a593Smuzhiyun if (space > 0) {
734*4882a593Smuzhiyun list_for_each_entry(kctl, &card->controls, list) {
735*4882a593Smuzhiyun if (offset >= kctl->count) {
736*4882a593Smuzhiyun offset -= kctl->count;
737*4882a593Smuzhiyun continue;
738*4882a593Smuzhiyun }
739*4882a593Smuzhiyun for (jidx = offset; jidx < kctl->count; jidx++) {
740*4882a593Smuzhiyun snd_ctl_build_ioff(&id, kctl, jidx);
741*4882a593Smuzhiyun if (copy_to_user(list->pids + list->used, &id,
742*4882a593Smuzhiyun sizeof(id))) {
743*4882a593Smuzhiyun err = -EFAULT;
744*4882a593Smuzhiyun goto out;
745*4882a593Smuzhiyun }
746*4882a593Smuzhiyun list->used++;
747*4882a593Smuzhiyun if (!--space)
748*4882a593Smuzhiyun goto out;
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun offset = 0;
751*4882a593Smuzhiyun }
752*4882a593Smuzhiyun }
753*4882a593Smuzhiyun out:
754*4882a593Smuzhiyun up_read(&card->controls_rwsem);
755*4882a593Smuzhiyun return err;
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun
snd_ctl_elem_list_user(struct snd_card * card,struct snd_ctl_elem_list __user * _list)758*4882a593Smuzhiyun static int snd_ctl_elem_list_user(struct snd_card *card,
759*4882a593Smuzhiyun struct snd_ctl_elem_list __user *_list)
760*4882a593Smuzhiyun {
761*4882a593Smuzhiyun struct snd_ctl_elem_list list;
762*4882a593Smuzhiyun int err;
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun if (copy_from_user(&list, _list, sizeof(list)))
765*4882a593Smuzhiyun return -EFAULT;
766*4882a593Smuzhiyun err = snd_ctl_elem_list(card, &list);
767*4882a593Smuzhiyun if (err)
768*4882a593Smuzhiyun return err;
769*4882a593Smuzhiyun if (copy_to_user(_list, &list, sizeof(list)))
770*4882a593Smuzhiyun return -EFAULT;
771*4882a593Smuzhiyun
772*4882a593Smuzhiyun return 0;
773*4882a593Smuzhiyun }
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun /* Check whether the given kctl info is valid */
snd_ctl_check_elem_info(struct snd_card * card,const struct snd_ctl_elem_info * info)776*4882a593Smuzhiyun static int snd_ctl_check_elem_info(struct snd_card *card,
777*4882a593Smuzhiyun const struct snd_ctl_elem_info *info)
778*4882a593Smuzhiyun {
779*4882a593Smuzhiyun static const unsigned int max_value_counts[] = {
780*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = 128,
781*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_INTEGER] = 128,
782*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = 128,
783*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_BYTES] = 512,
784*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_IEC958] = 1,
785*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_INTEGER64] = 64,
786*4882a593Smuzhiyun };
787*4882a593Smuzhiyun
788*4882a593Smuzhiyun if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
789*4882a593Smuzhiyun info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) {
790*4882a593Smuzhiyun if (card)
791*4882a593Smuzhiyun dev_err(card->dev,
792*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: invalid type %d\n",
793*4882a593Smuzhiyun info->id.iface, info->id.device,
794*4882a593Smuzhiyun info->id.subdevice, info->id.name,
795*4882a593Smuzhiyun info->id.index, info->type);
796*4882a593Smuzhiyun return -EINVAL;
797*4882a593Smuzhiyun }
798*4882a593Smuzhiyun if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED &&
799*4882a593Smuzhiyun info->value.enumerated.items == 0) {
800*4882a593Smuzhiyun if (card)
801*4882a593Smuzhiyun dev_err(card->dev,
802*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: zero enum items\n",
803*4882a593Smuzhiyun info->id.iface, info->id.device,
804*4882a593Smuzhiyun info->id.subdevice, info->id.name,
805*4882a593Smuzhiyun info->id.index);
806*4882a593Smuzhiyun return -EINVAL;
807*4882a593Smuzhiyun }
808*4882a593Smuzhiyun if (info->count > max_value_counts[info->type]) {
809*4882a593Smuzhiyun if (card)
810*4882a593Smuzhiyun dev_err(card->dev,
811*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: invalid count %d\n",
812*4882a593Smuzhiyun info->id.iface, info->id.device,
813*4882a593Smuzhiyun info->id.subdevice, info->id.name,
814*4882a593Smuzhiyun info->id.index, info->count);
815*4882a593Smuzhiyun return -EINVAL;
816*4882a593Smuzhiyun }
817*4882a593Smuzhiyun
818*4882a593Smuzhiyun return 0;
819*4882a593Smuzhiyun }
820*4882a593Smuzhiyun
821*4882a593Smuzhiyun /* The capacity of struct snd_ctl_elem_value.value.*/
822*4882a593Smuzhiyun static const unsigned int value_sizes[] = {
823*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_BOOLEAN] = sizeof(long),
824*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_INTEGER] = sizeof(long),
825*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_ENUMERATED] = sizeof(unsigned int),
826*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_BYTES] = sizeof(unsigned char),
827*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_IEC958] = sizeof(struct snd_aes_iec958),
828*4882a593Smuzhiyun [SNDRV_CTL_ELEM_TYPE_INTEGER64] = sizeof(long long),
829*4882a593Smuzhiyun };
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun #ifdef CONFIG_SND_CTL_VALIDATION
832*4882a593Smuzhiyun /* fill the remaining snd_ctl_elem_value data with the given pattern */
fill_remaining_elem_value(struct snd_ctl_elem_value * control,struct snd_ctl_elem_info * info,u32 pattern)833*4882a593Smuzhiyun static void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
834*4882a593Smuzhiyun struct snd_ctl_elem_info *info,
835*4882a593Smuzhiyun u32 pattern)
836*4882a593Smuzhiyun {
837*4882a593Smuzhiyun size_t offset = value_sizes[info->type] * info->count;
838*4882a593Smuzhiyun
839*4882a593Smuzhiyun offset = (offset + sizeof(u32) - 1) / sizeof(u32);
840*4882a593Smuzhiyun memset32((u32 *)control->value.bytes.data + offset, pattern,
841*4882a593Smuzhiyun sizeof(control->value) / sizeof(u32) - offset);
842*4882a593Smuzhiyun }
843*4882a593Smuzhiyun
844*4882a593Smuzhiyun /* check whether the given integer ctl value is valid */
sanity_check_int_value(struct snd_card * card,const struct snd_ctl_elem_value * control,const struct snd_ctl_elem_info * info,int i)845*4882a593Smuzhiyun static int sanity_check_int_value(struct snd_card *card,
846*4882a593Smuzhiyun const struct snd_ctl_elem_value *control,
847*4882a593Smuzhiyun const struct snd_ctl_elem_info *info,
848*4882a593Smuzhiyun int i)
849*4882a593Smuzhiyun {
850*4882a593Smuzhiyun long long lval, lmin, lmax, lstep;
851*4882a593Smuzhiyun u64 rem;
852*4882a593Smuzhiyun
853*4882a593Smuzhiyun switch (info->type) {
854*4882a593Smuzhiyun default:
855*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
856*4882a593Smuzhiyun lval = control->value.integer.value[i];
857*4882a593Smuzhiyun lmin = 0;
858*4882a593Smuzhiyun lmax = 1;
859*4882a593Smuzhiyun lstep = 0;
860*4882a593Smuzhiyun break;
861*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_INTEGER:
862*4882a593Smuzhiyun lval = control->value.integer.value[i];
863*4882a593Smuzhiyun lmin = info->value.integer.min;
864*4882a593Smuzhiyun lmax = info->value.integer.max;
865*4882a593Smuzhiyun lstep = info->value.integer.step;
866*4882a593Smuzhiyun break;
867*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_INTEGER64:
868*4882a593Smuzhiyun lval = control->value.integer64.value[i];
869*4882a593Smuzhiyun lmin = info->value.integer64.min;
870*4882a593Smuzhiyun lmax = info->value.integer64.max;
871*4882a593Smuzhiyun lstep = info->value.integer64.step;
872*4882a593Smuzhiyun break;
873*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
874*4882a593Smuzhiyun lval = control->value.enumerated.item[i];
875*4882a593Smuzhiyun lmin = 0;
876*4882a593Smuzhiyun lmax = info->value.enumerated.items - 1;
877*4882a593Smuzhiyun lstep = 0;
878*4882a593Smuzhiyun break;
879*4882a593Smuzhiyun }
880*4882a593Smuzhiyun
881*4882a593Smuzhiyun if (lval < lmin || lval > lmax) {
882*4882a593Smuzhiyun dev_err(card->dev,
883*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: value out of range %lld (%lld/%lld) at count %i\n",
884*4882a593Smuzhiyun control->id.iface, control->id.device,
885*4882a593Smuzhiyun control->id.subdevice, control->id.name,
886*4882a593Smuzhiyun control->id.index, lval, lmin, lmax, i);
887*4882a593Smuzhiyun return -EINVAL;
888*4882a593Smuzhiyun }
889*4882a593Smuzhiyun if (lstep) {
890*4882a593Smuzhiyun div64_u64_rem(lval, lstep, &rem);
891*4882a593Smuzhiyun if (rem) {
892*4882a593Smuzhiyun dev_err(card->dev,
893*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: unaligned value %lld (step %lld) at count %i\n",
894*4882a593Smuzhiyun control->id.iface, control->id.device,
895*4882a593Smuzhiyun control->id.subdevice, control->id.name,
896*4882a593Smuzhiyun control->id.index, lval, lstep, i);
897*4882a593Smuzhiyun return -EINVAL;
898*4882a593Smuzhiyun }
899*4882a593Smuzhiyun }
900*4882a593Smuzhiyun
901*4882a593Smuzhiyun return 0;
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun
904*4882a593Smuzhiyun /* perform sanity checks to the given snd_ctl_elem_value object */
sanity_check_elem_value(struct snd_card * card,const struct snd_ctl_elem_value * control,const struct snd_ctl_elem_info * info,u32 pattern)905*4882a593Smuzhiyun static int sanity_check_elem_value(struct snd_card *card,
906*4882a593Smuzhiyun const struct snd_ctl_elem_value *control,
907*4882a593Smuzhiyun const struct snd_ctl_elem_info *info,
908*4882a593Smuzhiyun u32 pattern)
909*4882a593Smuzhiyun {
910*4882a593Smuzhiyun size_t offset;
911*4882a593Smuzhiyun int i, ret = 0;
912*4882a593Smuzhiyun u32 *p;
913*4882a593Smuzhiyun
914*4882a593Smuzhiyun switch (info->type) {
915*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
916*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_INTEGER:
917*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_INTEGER64:
918*4882a593Smuzhiyun case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
919*4882a593Smuzhiyun for (i = 0; i < info->count; i++) {
920*4882a593Smuzhiyun ret = sanity_check_int_value(card, control, info, i);
921*4882a593Smuzhiyun if (ret < 0)
922*4882a593Smuzhiyun return ret;
923*4882a593Smuzhiyun }
924*4882a593Smuzhiyun break;
925*4882a593Smuzhiyun default:
926*4882a593Smuzhiyun break;
927*4882a593Smuzhiyun }
928*4882a593Smuzhiyun
929*4882a593Smuzhiyun /* check whether the remaining area kept untouched */
930*4882a593Smuzhiyun offset = value_sizes[info->type] * info->count;
931*4882a593Smuzhiyun offset = (offset + sizeof(u32) - 1) / sizeof(u32);
932*4882a593Smuzhiyun p = (u32 *)control->value.bytes.data + offset;
933*4882a593Smuzhiyun for (; offset < sizeof(control->value) / sizeof(u32); offset++, p++) {
934*4882a593Smuzhiyun if (*p != pattern) {
935*4882a593Smuzhiyun ret = -EINVAL;
936*4882a593Smuzhiyun break;
937*4882a593Smuzhiyun }
938*4882a593Smuzhiyun *p = 0; /* clear the checked area */
939*4882a593Smuzhiyun }
940*4882a593Smuzhiyun
941*4882a593Smuzhiyun return ret;
942*4882a593Smuzhiyun }
943*4882a593Smuzhiyun #else
fill_remaining_elem_value(struct snd_ctl_elem_value * control,struct snd_ctl_elem_info * info,u32 pattern)944*4882a593Smuzhiyun static inline void fill_remaining_elem_value(struct snd_ctl_elem_value *control,
945*4882a593Smuzhiyun struct snd_ctl_elem_info *info,
946*4882a593Smuzhiyun u32 pattern)
947*4882a593Smuzhiyun {
948*4882a593Smuzhiyun }
949*4882a593Smuzhiyun
sanity_check_elem_value(struct snd_card * card,struct snd_ctl_elem_value * control,struct snd_ctl_elem_info * info,u32 pattern)950*4882a593Smuzhiyun static inline int sanity_check_elem_value(struct snd_card *card,
951*4882a593Smuzhiyun struct snd_ctl_elem_value *control,
952*4882a593Smuzhiyun struct snd_ctl_elem_info *info,
953*4882a593Smuzhiyun u32 pattern)
954*4882a593Smuzhiyun {
955*4882a593Smuzhiyun return 0;
956*4882a593Smuzhiyun }
957*4882a593Smuzhiyun #endif
958*4882a593Smuzhiyun
__snd_ctl_elem_info(struct snd_card * card,struct snd_kcontrol * kctl,struct snd_ctl_elem_info * info,struct snd_ctl_file * ctl)959*4882a593Smuzhiyun static int __snd_ctl_elem_info(struct snd_card *card,
960*4882a593Smuzhiyun struct snd_kcontrol *kctl,
961*4882a593Smuzhiyun struct snd_ctl_elem_info *info,
962*4882a593Smuzhiyun struct snd_ctl_file *ctl)
963*4882a593Smuzhiyun {
964*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
965*4882a593Smuzhiyun unsigned int index_offset;
966*4882a593Smuzhiyun int result;
967*4882a593Smuzhiyun
968*4882a593Smuzhiyun #ifdef CONFIG_SND_DEBUG
969*4882a593Smuzhiyun info->access = 0;
970*4882a593Smuzhiyun #endif
971*4882a593Smuzhiyun result = kctl->info(kctl, info);
972*4882a593Smuzhiyun if (result >= 0) {
973*4882a593Smuzhiyun snd_BUG_ON(info->access);
974*4882a593Smuzhiyun index_offset = snd_ctl_get_ioff(kctl, &info->id);
975*4882a593Smuzhiyun vd = &kctl->vd[index_offset];
976*4882a593Smuzhiyun snd_ctl_build_ioff(&info->id, kctl, index_offset);
977*4882a593Smuzhiyun info->access = vd->access;
978*4882a593Smuzhiyun if (vd->owner) {
979*4882a593Smuzhiyun info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
980*4882a593Smuzhiyun if (vd->owner == ctl)
981*4882a593Smuzhiyun info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
982*4882a593Smuzhiyun info->owner = pid_vnr(vd->owner->pid);
983*4882a593Smuzhiyun } else {
984*4882a593Smuzhiyun info->owner = -1;
985*4882a593Smuzhiyun }
986*4882a593Smuzhiyun if (!snd_ctl_skip_validation(info) &&
987*4882a593Smuzhiyun snd_ctl_check_elem_info(card, info) < 0)
988*4882a593Smuzhiyun result = -EINVAL;
989*4882a593Smuzhiyun }
990*4882a593Smuzhiyun return result;
991*4882a593Smuzhiyun }
992*4882a593Smuzhiyun
snd_ctl_elem_info(struct snd_ctl_file * ctl,struct snd_ctl_elem_info * info)993*4882a593Smuzhiyun static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
994*4882a593Smuzhiyun struct snd_ctl_elem_info *info)
995*4882a593Smuzhiyun {
996*4882a593Smuzhiyun struct snd_card *card = ctl->card;
997*4882a593Smuzhiyun struct snd_kcontrol *kctl;
998*4882a593Smuzhiyun int result;
999*4882a593Smuzhiyun
1000*4882a593Smuzhiyun down_read(&card->controls_rwsem);
1001*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, &info->id);
1002*4882a593Smuzhiyun if (kctl == NULL)
1003*4882a593Smuzhiyun result = -ENOENT;
1004*4882a593Smuzhiyun else
1005*4882a593Smuzhiyun result = __snd_ctl_elem_info(card, kctl, info, ctl);
1006*4882a593Smuzhiyun up_read(&card->controls_rwsem);
1007*4882a593Smuzhiyun return result;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
snd_ctl_elem_info_user(struct snd_ctl_file * ctl,struct snd_ctl_elem_info __user * _info)1010*4882a593Smuzhiyun static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
1011*4882a593Smuzhiyun struct snd_ctl_elem_info __user *_info)
1012*4882a593Smuzhiyun {
1013*4882a593Smuzhiyun struct snd_ctl_elem_info info;
1014*4882a593Smuzhiyun int result;
1015*4882a593Smuzhiyun
1016*4882a593Smuzhiyun if (copy_from_user(&info, _info, sizeof(info)))
1017*4882a593Smuzhiyun return -EFAULT;
1018*4882a593Smuzhiyun result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
1019*4882a593Smuzhiyun if (result < 0)
1020*4882a593Smuzhiyun return result;
1021*4882a593Smuzhiyun result = snd_ctl_elem_info(ctl, &info);
1022*4882a593Smuzhiyun if (result < 0)
1023*4882a593Smuzhiyun return result;
1024*4882a593Smuzhiyun /* drop internal access flags */
1025*4882a593Smuzhiyun info.access &= ~SNDRV_CTL_ELEM_ACCESS_SKIP_CHECK;
1026*4882a593Smuzhiyun if (copy_to_user(_info, &info, sizeof(info)))
1027*4882a593Smuzhiyun return -EFAULT;
1028*4882a593Smuzhiyun return result;
1029*4882a593Smuzhiyun }
1030*4882a593Smuzhiyun
snd_ctl_elem_read(struct snd_card * card,struct snd_ctl_elem_value * control)1031*4882a593Smuzhiyun static int snd_ctl_elem_read(struct snd_card *card,
1032*4882a593Smuzhiyun struct snd_ctl_elem_value *control)
1033*4882a593Smuzhiyun {
1034*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1035*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
1036*4882a593Smuzhiyun unsigned int index_offset;
1037*4882a593Smuzhiyun struct snd_ctl_elem_info info;
1038*4882a593Smuzhiyun const u32 pattern = 0xdeadbeef;
1039*4882a593Smuzhiyun int ret;
1040*4882a593Smuzhiyun
1041*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, &control->id);
1042*4882a593Smuzhiyun if (kctl == NULL)
1043*4882a593Smuzhiyun return -ENOENT;
1044*4882a593Smuzhiyun
1045*4882a593Smuzhiyun index_offset = snd_ctl_get_ioff(kctl, &control->id);
1046*4882a593Smuzhiyun vd = &kctl->vd[index_offset];
1047*4882a593Smuzhiyun if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
1048*4882a593Smuzhiyun return -EPERM;
1049*4882a593Smuzhiyun
1050*4882a593Smuzhiyun snd_ctl_build_ioff(&control->id, kctl, index_offset);
1051*4882a593Smuzhiyun
1052*4882a593Smuzhiyun #ifdef CONFIG_SND_CTL_VALIDATION
1053*4882a593Smuzhiyun /* info is needed only for validation */
1054*4882a593Smuzhiyun memset(&info, 0, sizeof(info));
1055*4882a593Smuzhiyun info.id = control->id;
1056*4882a593Smuzhiyun ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
1057*4882a593Smuzhiyun if (ret < 0)
1058*4882a593Smuzhiyun return ret;
1059*4882a593Smuzhiyun #endif
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun if (!snd_ctl_skip_validation(&info))
1062*4882a593Smuzhiyun fill_remaining_elem_value(control, &info, pattern);
1063*4882a593Smuzhiyun ret = kctl->get(kctl, control);
1064*4882a593Smuzhiyun if (ret < 0)
1065*4882a593Smuzhiyun return ret;
1066*4882a593Smuzhiyun if (!snd_ctl_skip_validation(&info) &&
1067*4882a593Smuzhiyun sanity_check_elem_value(card, control, &info, pattern) < 0) {
1068*4882a593Smuzhiyun dev_err(card->dev,
1069*4882a593Smuzhiyun "control %i:%i:%i:%s:%i: access overflow\n",
1070*4882a593Smuzhiyun control->id.iface, control->id.device,
1071*4882a593Smuzhiyun control->id.subdevice, control->id.name,
1072*4882a593Smuzhiyun control->id.index);
1073*4882a593Smuzhiyun return -EINVAL;
1074*4882a593Smuzhiyun }
1075*4882a593Smuzhiyun return ret;
1076*4882a593Smuzhiyun }
1077*4882a593Smuzhiyun
snd_ctl_elem_read_user(struct snd_card * card,struct snd_ctl_elem_value __user * _control)1078*4882a593Smuzhiyun static int snd_ctl_elem_read_user(struct snd_card *card,
1079*4882a593Smuzhiyun struct snd_ctl_elem_value __user *_control)
1080*4882a593Smuzhiyun {
1081*4882a593Smuzhiyun struct snd_ctl_elem_value *control;
1082*4882a593Smuzhiyun int result;
1083*4882a593Smuzhiyun
1084*4882a593Smuzhiyun control = memdup_user(_control, sizeof(*control));
1085*4882a593Smuzhiyun if (IS_ERR(control))
1086*4882a593Smuzhiyun return PTR_ERR(control);
1087*4882a593Smuzhiyun
1088*4882a593Smuzhiyun result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1089*4882a593Smuzhiyun if (result < 0)
1090*4882a593Smuzhiyun goto error;
1091*4882a593Smuzhiyun
1092*4882a593Smuzhiyun down_read(&card->controls_rwsem);
1093*4882a593Smuzhiyun result = snd_ctl_elem_read(card, control);
1094*4882a593Smuzhiyun up_read(&card->controls_rwsem);
1095*4882a593Smuzhiyun if (result < 0)
1096*4882a593Smuzhiyun goto error;
1097*4882a593Smuzhiyun
1098*4882a593Smuzhiyun if (copy_to_user(_control, control, sizeof(*control)))
1099*4882a593Smuzhiyun result = -EFAULT;
1100*4882a593Smuzhiyun error:
1101*4882a593Smuzhiyun kfree(control);
1102*4882a593Smuzhiyun return result;
1103*4882a593Smuzhiyun }
1104*4882a593Smuzhiyun
snd_ctl_elem_write(struct snd_card * card,struct snd_ctl_file * file,struct snd_ctl_elem_value * control)1105*4882a593Smuzhiyun static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
1106*4882a593Smuzhiyun struct snd_ctl_elem_value *control)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1109*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
1110*4882a593Smuzhiyun unsigned int index_offset;
1111*4882a593Smuzhiyun int result;
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, &control->id);
1114*4882a593Smuzhiyun if (kctl == NULL)
1115*4882a593Smuzhiyun return -ENOENT;
1116*4882a593Smuzhiyun
1117*4882a593Smuzhiyun index_offset = snd_ctl_get_ioff(kctl, &control->id);
1118*4882a593Smuzhiyun vd = &kctl->vd[index_offset];
1119*4882a593Smuzhiyun if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL ||
1120*4882a593Smuzhiyun (file && vd->owner && vd->owner != file)) {
1121*4882a593Smuzhiyun return -EPERM;
1122*4882a593Smuzhiyun }
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun snd_ctl_build_ioff(&control->id, kctl, index_offset);
1125*4882a593Smuzhiyun result = kctl->put(kctl, control);
1126*4882a593Smuzhiyun if (result < 0)
1127*4882a593Smuzhiyun return result;
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun if (result > 0) {
1130*4882a593Smuzhiyun struct snd_ctl_elem_id id = control->id;
1131*4882a593Smuzhiyun snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun
1134*4882a593Smuzhiyun return 0;
1135*4882a593Smuzhiyun }
1136*4882a593Smuzhiyun
snd_ctl_elem_write_user(struct snd_ctl_file * file,struct snd_ctl_elem_value __user * _control)1137*4882a593Smuzhiyun static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
1138*4882a593Smuzhiyun struct snd_ctl_elem_value __user *_control)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun struct snd_ctl_elem_value *control;
1141*4882a593Smuzhiyun struct snd_card *card;
1142*4882a593Smuzhiyun int result;
1143*4882a593Smuzhiyun
1144*4882a593Smuzhiyun control = memdup_user(_control, sizeof(*control));
1145*4882a593Smuzhiyun if (IS_ERR(control))
1146*4882a593Smuzhiyun return PTR_ERR(control);
1147*4882a593Smuzhiyun
1148*4882a593Smuzhiyun card = file->card;
1149*4882a593Smuzhiyun result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1150*4882a593Smuzhiyun if (result < 0)
1151*4882a593Smuzhiyun goto error;
1152*4882a593Smuzhiyun
1153*4882a593Smuzhiyun down_write(&card->controls_rwsem);
1154*4882a593Smuzhiyun result = snd_ctl_elem_write(card, file, control);
1155*4882a593Smuzhiyun up_write(&card->controls_rwsem);
1156*4882a593Smuzhiyun if (result < 0)
1157*4882a593Smuzhiyun goto error;
1158*4882a593Smuzhiyun
1159*4882a593Smuzhiyun if (copy_to_user(_control, control, sizeof(*control)))
1160*4882a593Smuzhiyun result = -EFAULT;
1161*4882a593Smuzhiyun error:
1162*4882a593Smuzhiyun kfree(control);
1163*4882a593Smuzhiyun return result;
1164*4882a593Smuzhiyun }
1165*4882a593Smuzhiyun
snd_ctl_elem_lock(struct snd_ctl_file * file,struct snd_ctl_elem_id __user * _id)1166*4882a593Smuzhiyun static int snd_ctl_elem_lock(struct snd_ctl_file *file,
1167*4882a593Smuzhiyun struct snd_ctl_elem_id __user *_id)
1168*4882a593Smuzhiyun {
1169*4882a593Smuzhiyun struct snd_card *card = file->card;
1170*4882a593Smuzhiyun struct snd_ctl_elem_id id;
1171*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1172*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
1173*4882a593Smuzhiyun int result;
1174*4882a593Smuzhiyun
1175*4882a593Smuzhiyun if (copy_from_user(&id, _id, sizeof(id)))
1176*4882a593Smuzhiyun return -EFAULT;
1177*4882a593Smuzhiyun down_write(&card->controls_rwsem);
1178*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, &id);
1179*4882a593Smuzhiyun if (kctl == NULL) {
1180*4882a593Smuzhiyun result = -ENOENT;
1181*4882a593Smuzhiyun } else {
1182*4882a593Smuzhiyun vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
1183*4882a593Smuzhiyun if (vd->owner != NULL)
1184*4882a593Smuzhiyun result = -EBUSY;
1185*4882a593Smuzhiyun else {
1186*4882a593Smuzhiyun vd->owner = file;
1187*4882a593Smuzhiyun result = 0;
1188*4882a593Smuzhiyun }
1189*4882a593Smuzhiyun }
1190*4882a593Smuzhiyun up_write(&card->controls_rwsem);
1191*4882a593Smuzhiyun return result;
1192*4882a593Smuzhiyun }
1193*4882a593Smuzhiyun
snd_ctl_elem_unlock(struct snd_ctl_file * file,struct snd_ctl_elem_id __user * _id)1194*4882a593Smuzhiyun static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
1195*4882a593Smuzhiyun struct snd_ctl_elem_id __user *_id)
1196*4882a593Smuzhiyun {
1197*4882a593Smuzhiyun struct snd_card *card = file->card;
1198*4882a593Smuzhiyun struct snd_ctl_elem_id id;
1199*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1200*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
1201*4882a593Smuzhiyun int result;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun if (copy_from_user(&id, _id, sizeof(id)))
1204*4882a593Smuzhiyun return -EFAULT;
1205*4882a593Smuzhiyun down_write(&card->controls_rwsem);
1206*4882a593Smuzhiyun kctl = snd_ctl_find_id(card, &id);
1207*4882a593Smuzhiyun if (kctl == NULL) {
1208*4882a593Smuzhiyun result = -ENOENT;
1209*4882a593Smuzhiyun } else {
1210*4882a593Smuzhiyun vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
1211*4882a593Smuzhiyun if (vd->owner == NULL)
1212*4882a593Smuzhiyun result = -EINVAL;
1213*4882a593Smuzhiyun else if (vd->owner != file)
1214*4882a593Smuzhiyun result = -EPERM;
1215*4882a593Smuzhiyun else {
1216*4882a593Smuzhiyun vd->owner = NULL;
1217*4882a593Smuzhiyun result = 0;
1218*4882a593Smuzhiyun }
1219*4882a593Smuzhiyun }
1220*4882a593Smuzhiyun up_write(&card->controls_rwsem);
1221*4882a593Smuzhiyun return result;
1222*4882a593Smuzhiyun }
1223*4882a593Smuzhiyun
1224*4882a593Smuzhiyun struct user_element {
1225*4882a593Smuzhiyun struct snd_ctl_elem_info info;
1226*4882a593Smuzhiyun struct snd_card *card;
1227*4882a593Smuzhiyun char *elem_data; /* element data */
1228*4882a593Smuzhiyun unsigned long elem_data_size; /* size of element data in bytes */
1229*4882a593Smuzhiyun void *tlv_data; /* TLV data */
1230*4882a593Smuzhiyun unsigned long tlv_data_size; /* TLV data size */
1231*4882a593Smuzhiyun void *priv_data; /* private data (like strings for enumerated type) */
1232*4882a593Smuzhiyun };
1233*4882a593Smuzhiyun
snd_ctl_elem_user_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1234*4882a593Smuzhiyun static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
1235*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1236*4882a593Smuzhiyun {
1237*4882a593Smuzhiyun struct user_element *ue = kcontrol->private_data;
1238*4882a593Smuzhiyun unsigned int offset;
1239*4882a593Smuzhiyun
1240*4882a593Smuzhiyun offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
1241*4882a593Smuzhiyun *uinfo = ue->info;
1242*4882a593Smuzhiyun snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
1243*4882a593Smuzhiyun
1244*4882a593Smuzhiyun return 0;
1245*4882a593Smuzhiyun }
1246*4882a593Smuzhiyun
snd_ctl_elem_user_enum_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1247*4882a593Smuzhiyun static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
1248*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
1249*4882a593Smuzhiyun {
1250*4882a593Smuzhiyun struct user_element *ue = kcontrol->private_data;
1251*4882a593Smuzhiyun const char *names;
1252*4882a593Smuzhiyun unsigned int item;
1253*4882a593Smuzhiyun unsigned int offset;
1254*4882a593Smuzhiyun
1255*4882a593Smuzhiyun item = uinfo->value.enumerated.item;
1256*4882a593Smuzhiyun
1257*4882a593Smuzhiyun offset = snd_ctl_get_ioff(kcontrol, &uinfo->id);
1258*4882a593Smuzhiyun *uinfo = ue->info;
1259*4882a593Smuzhiyun snd_ctl_build_ioff(&uinfo->id, kcontrol, offset);
1260*4882a593Smuzhiyun
1261*4882a593Smuzhiyun item = min(item, uinfo->value.enumerated.items - 1);
1262*4882a593Smuzhiyun uinfo->value.enumerated.item = item;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun names = ue->priv_data;
1265*4882a593Smuzhiyun for (; item > 0; --item)
1266*4882a593Smuzhiyun names += strlen(names) + 1;
1267*4882a593Smuzhiyun strcpy(uinfo->value.enumerated.name, names);
1268*4882a593Smuzhiyun
1269*4882a593Smuzhiyun return 0;
1270*4882a593Smuzhiyun }
1271*4882a593Smuzhiyun
snd_ctl_elem_user_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1272*4882a593Smuzhiyun static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
1273*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1274*4882a593Smuzhiyun {
1275*4882a593Smuzhiyun struct user_element *ue = kcontrol->private_data;
1276*4882a593Smuzhiyun unsigned int size = ue->elem_data_size;
1277*4882a593Smuzhiyun char *src = ue->elem_data +
1278*4882a593Smuzhiyun snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
1279*4882a593Smuzhiyun
1280*4882a593Smuzhiyun memcpy(&ucontrol->value, src, size);
1281*4882a593Smuzhiyun return 0;
1282*4882a593Smuzhiyun }
1283*4882a593Smuzhiyun
snd_ctl_elem_user_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1284*4882a593Smuzhiyun static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
1285*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
1286*4882a593Smuzhiyun {
1287*4882a593Smuzhiyun int change;
1288*4882a593Smuzhiyun struct user_element *ue = kcontrol->private_data;
1289*4882a593Smuzhiyun unsigned int size = ue->elem_data_size;
1290*4882a593Smuzhiyun char *dst = ue->elem_data +
1291*4882a593Smuzhiyun snd_ctl_get_ioff(kcontrol, &ucontrol->id) * size;
1292*4882a593Smuzhiyun
1293*4882a593Smuzhiyun change = memcmp(&ucontrol->value, dst, size) != 0;
1294*4882a593Smuzhiyun if (change)
1295*4882a593Smuzhiyun memcpy(dst, &ucontrol->value, size);
1296*4882a593Smuzhiyun return change;
1297*4882a593Smuzhiyun }
1298*4882a593Smuzhiyun
replace_user_tlv(struct snd_kcontrol * kctl,unsigned int __user * buf,unsigned int size)1299*4882a593Smuzhiyun static int replace_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
1300*4882a593Smuzhiyun unsigned int size)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun struct user_element *ue = kctl->private_data;
1303*4882a593Smuzhiyun unsigned int *container;
1304*4882a593Smuzhiyun struct snd_ctl_elem_id id;
1305*4882a593Smuzhiyun unsigned int mask = 0;
1306*4882a593Smuzhiyun int i;
1307*4882a593Smuzhiyun int change;
1308*4882a593Smuzhiyun
1309*4882a593Smuzhiyun if (size > 1024 * 128) /* sane value */
1310*4882a593Smuzhiyun return -EINVAL;
1311*4882a593Smuzhiyun
1312*4882a593Smuzhiyun container = vmemdup_user(buf, size);
1313*4882a593Smuzhiyun if (IS_ERR(container))
1314*4882a593Smuzhiyun return PTR_ERR(container);
1315*4882a593Smuzhiyun
1316*4882a593Smuzhiyun change = ue->tlv_data_size != size;
1317*4882a593Smuzhiyun if (!change)
1318*4882a593Smuzhiyun change = memcmp(ue->tlv_data, container, size) != 0;
1319*4882a593Smuzhiyun if (!change) {
1320*4882a593Smuzhiyun kvfree(container);
1321*4882a593Smuzhiyun return 0;
1322*4882a593Smuzhiyun }
1323*4882a593Smuzhiyun
1324*4882a593Smuzhiyun if (ue->tlv_data == NULL) {
1325*4882a593Smuzhiyun /* Now TLV data is available. */
1326*4882a593Smuzhiyun for (i = 0; i < kctl->count; ++i)
1327*4882a593Smuzhiyun kctl->vd[i].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ;
1328*4882a593Smuzhiyun mask = SNDRV_CTL_EVENT_MASK_INFO;
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun
1331*4882a593Smuzhiyun kvfree(ue->tlv_data);
1332*4882a593Smuzhiyun ue->tlv_data = container;
1333*4882a593Smuzhiyun ue->tlv_data_size = size;
1334*4882a593Smuzhiyun
1335*4882a593Smuzhiyun mask |= SNDRV_CTL_EVENT_MASK_TLV;
1336*4882a593Smuzhiyun for (i = 0; i < kctl->count; ++i) {
1337*4882a593Smuzhiyun snd_ctl_build_ioff(&id, kctl, i);
1338*4882a593Smuzhiyun snd_ctl_notify(ue->card, mask, &id);
1339*4882a593Smuzhiyun }
1340*4882a593Smuzhiyun
1341*4882a593Smuzhiyun return change;
1342*4882a593Smuzhiyun }
1343*4882a593Smuzhiyun
read_user_tlv(struct snd_kcontrol * kctl,unsigned int __user * buf,unsigned int size)1344*4882a593Smuzhiyun static int read_user_tlv(struct snd_kcontrol *kctl, unsigned int __user *buf,
1345*4882a593Smuzhiyun unsigned int size)
1346*4882a593Smuzhiyun {
1347*4882a593Smuzhiyun struct user_element *ue = kctl->private_data;
1348*4882a593Smuzhiyun
1349*4882a593Smuzhiyun if (ue->tlv_data_size == 0 || ue->tlv_data == NULL)
1350*4882a593Smuzhiyun return -ENXIO;
1351*4882a593Smuzhiyun
1352*4882a593Smuzhiyun if (size < ue->tlv_data_size)
1353*4882a593Smuzhiyun return -ENOSPC;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun if (copy_to_user(buf, ue->tlv_data, ue->tlv_data_size))
1356*4882a593Smuzhiyun return -EFAULT;
1357*4882a593Smuzhiyun
1358*4882a593Smuzhiyun return 0;
1359*4882a593Smuzhiyun }
1360*4882a593Smuzhiyun
snd_ctl_elem_user_tlv(struct snd_kcontrol * kctl,int op_flag,unsigned int size,unsigned int __user * buf)1361*4882a593Smuzhiyun static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kctl, int op_flag,
1362*4882a593Smuzhiyun unsigned int size, unsigned int __user *buf)
1363*4882a593Smuzhiyun {
1364*4882a593Smuzhiyun if (op_flag == SNDRV_CTL_TLV_OP_WRITE)
1365*4882a593Smuzhiyun return replace_user_tlv(kctl, buf, size);
1366*4882a593Smuzhiyun else
1367*4882a593Smuzhiyun return read_user_tlv(kctl, buf, size);
1368*4882a593Smuzhiyun }
1369*4882a593Smuzhiyun
snd_ctl_elem_init_enum_names(struct user_element * ue)1370*4882a593Smuzhiyun static int snd_ctl_elem_init_enum_names(struct user_element *ue)
1371*4882a593Smuzhiyun {
1372*4882a593Smuzhiyun char *names, *p;
1373*4882a593Smuzhiyun size_t buf_len, name_len;
1374*4882a593Smuzhiyun unsigned int i;
1375*4882a593Smuzhiyun const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
1376*4882a593Smuzhiyun
1377*4882a593Smuzhiyun if (ue->info.value.enumerated.names_length > 64 * 1024)
1378*4882a593Smuzhiyun return -EINVAL;
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun names = vmemdup_user((const void __user *)user_ptrval,
1381*4882a593Smuzhiyun ue->info.value.enumerated.names_length);
1382*4882a593Smuzhiyun if (IS_ERR(names))
1383*4882a593Smuzhiyun return PTR_ERR(names);
1384*4882a593Smuzhiyun
1385*4882a593Smuzhiyun /* check that there are enough valid names */
1386*4882a593Smuzhiyun buf_len = ue->info.value.enumerated.names_length;
1387*4882a593Smuzhiyun p = names;
1388*4882a593Smuzhiyun for (i = 0; i < ue->info.value.enumerated.items; ++i) {
1389*4882a593Smuzhiyun name_len = strnlen(p, buf_len);
1390*4882a593Smuzhiyun if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
1391*4882a593Smuzhiyun kvfree(names);
1392*4882a593Smuzhiyun return -EINVAL;
1393*4882a593Smuzhiyun }
1394*4882a593Smuzhiyun p += name_len + 1;
1395*4882a593Smuzhiyun buf_len -= name_len + 1;
1396*4882a593Smuzhiyun }
1397*4882a593Smuzhiyun
1398*4882a593Smuzhiyun ue->priv_data = names;
1399*4882a593Smuzhiyun ue->info.value.enumerated.names_ptr = 0;
1400*4882a593Smuzhiyun
1401*4882a593Smuzhiyun return 0;
1402*4882a593Smuzhiyun }
1403*4882a593Smuzhiyun
snd_ctl_elem_user_free(struct snd_kcontrol * kcontrol)1404*4882a593Smuzhiyun static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
1405*4882a593Smuzhiyun {
1406*4882a593Smuzhiyun struct user_element *ue = kcontrol->private_data;
1407*4882a593Smuzhiyun
1408*4882a593Smuzhiyun kvfree(ue->tlv_data);
1409*4882a593Smuzhiyun kvfree(ue->priv_data);
1410*4882a593Smuzhiyun kfree(ue);
1411*4882a593Smuzhiyun }
1412*4882a593Smuzhiyun
snd_ctl_elem_add(struct snd_ctl_file * file,struct snd_ctl_elem_info * info,int replace)1413*4882a593Smuzhiyun static int snd_ctl_elem_add(struct snd_ctl_file *file,
1414*4882a593Smuzhiyun struct snd_ctl_elem_info *info, int replace)
1415*4882a593Smuzhiyun {
1416*4882a593Smuzhiyun struct snd_card *card = file->card;
1417*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1418*4882a593Smuzhiyun unsigned int count;
1419*4882a593Smuzhiyun unsigned int access;
1420*4882a593Smuzhiyun long private_size;
1421*4882a593Smuzhiyun struct user_element *ue;
1422*4882a593Smuzhiyun unsigned int offset;
1423*4882a593Smuzhiyun int err;
1424*4882a593Smuzhiyun
1425*4882a593Smuzhiyun if (!*info->id.name)
1426*4882a593Smuzhiyun return -EINVAL;
1427*4882a593Smuzhiyun if (strnlen(info->id.name, sizeof(info->id.name)) >= sizeof(info->id.name))
1428*4882a593Smuzhiyun return -EINVAL;
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun /* Delete a control to replace them if needed. */
1431*4882a593Smuzhiyun if (replace) {
1432*4882a593Smuzhiyun info->id.numid = 0;
1433*4882a593Smuzhiyun err = snd_ctl_remove_user_ctl(file, &info->id);
1434*4882a593Smuzhiyun if (err)
1435*4882a593Smuzhiyun return err;
1436*4882a593Smuzhiyun }
1437*4882a593Smuzhiyun
1438*4882a593Smuzhiyun /*
1439*4882a593Smuzhiyun * The number of userspace controls are counted control by control,
1440*4882a593Smuzhiyun * not element by element.
1441*4882a593Smuzhiyun */
1442*4882a593Smuzhiyun if (card->user_ctl_count + 1 > MAX_USER_CONTROLS)
1443*4882a593Smuzhiyun return -ENOMEM;
1444*4882a593Smuzhiyun
1445*4882a593Smuzhiyun /* Check the number of elements for this userspace control. */
1446*4882a593Smuzhiyun count = info->owner;
1447*4882a593Smuzhiyun if (count == 0)
1448*4882a593Smuzhiyun count = 1;
1449*4882a593Smuzhiyun
1450*4882a593Smuzhiyun /* Arrange access permissions if needed. */
1451*4882a593Smuzhiyun access = info->access;
1452*4882a593Smuzhiyun if (access == 0)
1453*4882a593Smuzhiyun access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
1454*4882a593Smuzhiyun access &= (SNDRV_CTL_ELEM_ACCESS_READWRITE |
1455*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_INACTIVE |
1456*4882a593Smuzhiyun SNDRV_CTL_ELEM_ACCESS_TLV_WRITE);
1457*4882a593Smuzhiyun
1458*4882a593Smuzhiyun /* In initial state, nothing is available as TLV container. */
1459*4882a593Smuzhiyun if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
1460*4882a593Smuzhiyun access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1461*4882a593Smuzhiyun access |= SNDRV_CTL_ELEM_ACCESS_USER;
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun /*
1464*4882a593Smuzhiyun * Check information and calculate the size of data specific to
1465*4882a593Smuzhiyun * this userspace control.
1466*4882a593Smuzhiyun */
1467*4882a593Smuzhiyun /* pass NULL to card for suppressing error messages */
1468*4882a593Smuzhiyun err = snd_ctl_check_elem_info(NULL, info);
1469*4882a593Smuzhiyun if (err < 0)
1470*4882a593Smuzhiyun return err;
1471*4882a593Smuzhiyun /* user-space control doesn't allow zero-size data */
1472*4882a593Smuzhiyun if (info->count < 1)
1473*4882a593Smuzhiyun return -EINVAL;
1474*4882a593Smuzhiyun private_size = value_sizes[info->type] * info->count;
1475*4882a593Smuzhiyun
1476*4882a593Smuzhiyun /*
1477*4882a593Smuzhiyun * Keep memory object for this userspace control. After passing this
1478*4882a593Smuzhiyun * code block, the instance should be freed by snd_ctl_free_one().
1479*4882a593Smuzhiyun *
1480*4882a593Smuzhiyun * Note that these elements in this control are locked.
1481*4882a593Smuzhiyun */
1482*4882a593Smuzhiyun err = snd_ctl_new(&kctl, count, access, file);
1483*4882a593Smuzhiyun if (err < 0)
1484*4882a593Smuzhiyun return err;
1485*4882a593Smuzhiyun memcpy(&kctl->id, &info->id, sizeof(kctl->id));
1486*4882a593Smuzhiyun kctl->private_data = kzalloc(sizeof(struct user_element) + private_size * count,
1487*4882a593Smuzhiyun GFP_KERNEL);
1488*4882a593Smuzhiyun if (kctl->private_data == NULL) {
1489*4882a593Smuzhiyun kfree(kctl);
1490*4882a593Smuzhiyun return -ENOMEM;
1491*4882a593Smuzhiyun }
1492*4882a593Smuzhiyun kctl->private_free = snd_ctl_elem_user_free;
1493*4882a593Smuzhiyun
1494*4882a593Smuzhiyun /* Set private data for this userspace control. */
1495*4882a593Smuzhiyun ue = (struct user_element *)kctl->private_data;
1496*4882a593Smuzhiyun ue->card = card;
1497*4882a593Smuzhiyun ue->info = *info;
1498*4882a593Smuzhiyun ue->info.access = 0;
1499*4882a593Smuzhiyun ue->elem_data = (char *)ue + sizeof(*ue);
1500*4882a593Smuzhiyun ue->elem_data_size = private_size;
1501*4882a593Smuzhiyun if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
1502*4882a593Smuzhiyun err = snd_ctl_elem_init_enum_names(ue);
1503*4882a593Smuzhiyun if (err < 0) {
1504*4882a593Smuzhiyun snd_ctl_free_one(kctl);
1505*4882a593Smuzhiyun return err;
1506*4882a593Smuzhiyun }
1507*4882a593Smuzhiyun }
1508*4882a593Smuzhiyun
1509*4882a593Smuzhiyun /* Set callback functions. */
1510*4882a593Smuzhiyun if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
1511*4882a593Smuzhiyun kctl->info = snd_ctl_elem_user_enum_info;
1512*4882a593Smuzhiyun else
1513*4882a593Smuzhiyun kctl->info = snd_ctl_elem_user_info;
1514*4882a593Smuzhiyun if (access & SNDRV_CTL_ELEM_ACCESS_READ)
1515*4882a593Smuzhiyun kctl->get = snd_ctl_elem_user_get;
1516*4882a593Smuzhiyun if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
1517*4882a593Smuzhiyun kctl->put = snd_ctl_elem_user_put;
1518*4882a593Smuzhiyun if (access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE)
1519*4882a593Smuzhiyun kctl->tlv.c = snd_ctl_elem_user_tlv;
1520*4882a593Smuzhiyun
1521*4882a593Smuzhiyun /* This function manage to free the instance on failure. */
1522*4882a593Smuzhiyun down_write(&card->controls_rwsem);
1523*4882a593Smuzhiyun err = __snd_ctl_add_replace(card, kctl, CTL_ADD_EXCLUSIVE);
1524*4882a593Smuzhiyun if (err < 0) {
1525*4882a593Smuzhiyun snd_ctl_free_one(kctl);
1526*4882a593Smuzhiyun goto unlock;
1527*4882a593Smuzhiyun }
1528*4882a593Smuzhiyun offset = snd_ctl_get_ioff(kctl, &info->id);
1529*4882a593Smuzhiyun snd_ctl_build_ioff(&info->id, kctl, offset);
1530*4882a593Smuzhiyun /*
1531*4882a593Smuzhiyun * Here we cannot fill any field for the number of elements added by
1532*4882a593Smuzhiyun * this operation because there're no specific fields. The usage of
1533*4882a593Smuzhiyun * 'owner' field for this purpose may cause any bugs to userspace
1534*4882a593Smuzhiyun * applications because the field originally means PID of a process
1535*4882a593Smuzhiyun * which locks the element.
1536*4882a593Smuzhiyun */
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun card->user_ctl_count++;
1539*4882a593Smuzhiyun
1540*4882a593Smuzhiyun unlock:
1541*4882a593Smuzhiyun up_write(&card->controls_rwsem);
1542*4882a593Smuzhiyun return err;
1543*4882a593Smuzhiyun }
1544*4882a593Smuzhiyun
snd_ctl_elem_add_user(struct snd_ctl_file * file,struct snd_ctl_elem_info __user * _info,int replace)1545*4882a593Smuzhiyun static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
1546*4882a593Smuzhiyun struct snd_ctl_elem_info __user *_info, int replace)
1547*4882a593Smuzhiyun {
1548*4882a593Smuzhiyun struct snd_ctl_elem_info info;
1549*4882a593Smuzhiyun int err;
1550*4882a593Smuzhiyun
1551*4882a593Smuzhiyun if (copy_from_user(&info, _info, sizeof(info)))
1552*4882a593Smuzhiyun return -EFAULT;
1553*4882a593Smuzhiyun err = snd_ctl_elem_add(file, &info, replace);
1554*4882a593Smuzhiyun if (err < 0)
1555*4882a593Smuzhiyun return err;
1556*4882a593Smuzhiyun if (copy_to_user(_info, &info, sizeof(info))) {
1557*4882a593Smuzhiyun snd_ctl_remove_user_ctl(file, &info.id);
1558*4882a593Smuzhiyun return -EFAULT;
1559*4882a593Smuzhiyun }
1560*4882a593Smuzhiyun
1561*4882a593Smuzhiyun return 0;
1562*4882a593Smuzhiyun }
1563*4882a593Smuzhiyun
snd_ctl_elem_remove(struct snd_ctl_file * file,struct snd_ctl_elem_id __user * _id)1564*4882a593Smuzhiyun static int snd_ctl_elem_remove(struct snd_ctl_file *file,
1565*4882a593Smuzhiyun struct snd_ctl_elem_id __user *_id)
1566*4882a593Smuzhiyun {
1567*4882a593Smuzhiyun struct snd_ctl_elem_id id;
1568*4882a593Smuzhiyun
1569*4882a593Smuzhiyun if (copy_from_user(&id, _id, sizeof(id)))
1570*4882a593Smuzhiyun return -EFAULT;
1571*4882a593Smuzhiyun return snd_ctl_remove_user_ctl(file, &id);
1572*4882a593Smuzhiyun }
1573*4882a593Smuzhiyun
snd_ctl_subscribe_events(struct snd_ctl_file * file,int __user * ptr)1574*4882a593Smuzhiyun static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
1575*4882a593Smuzhiyun {
1576*4882a593Smuzhiyun int subscribe;
1577*4882a593Smuzhiyun if (get_user(subscribe, ptr))
1578*4882a593Smuzhiyun return -EFAULT;
1579*4882a593Smuzhiyun if (subscribe < 0) {
1580*4882a593Smuzhiyun subscribe = file->subscribed;
1581*4882a593Smuzhiyun if (put_user(subscribe, ptr))
1582*4882a593Smuzhiyun return -EFAULT;
1583*4882a593Smuzhiyun return 0;
1584*4882a593Smuzhiyun }
1585*4882a593Smuzhiyun if (subscribe) {
1586*4882a593Smuzhiyun file->subscribed = 1;
1587*4882a593Smuzhiyun return 0;
1588*4882a593Smuzhiyun } else if (file->subscribed) {
1589*4882a593Smuzhiyun snd_ctl_empty_read_queue(file);
1590*4882a593Smuzhiyun file->subscribed = 0;
1591*4882a593Smuzhiyun }
1592*4882a593Smuzhiyun return 0;
1593*4882a593Smuzhiyun }
1594*4882a593Smuzhiyun
call_tlv_handler(struct snd_ctl_file * file,int op_flag,struct snd_kcontrol * kctl,struct snd_ctl_elem_id * id,unsigned int __user * buf,unsigned int size)1595*4882a593Smuzhiyun static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
1596*4882a593Smuzhiyun struct snd_kcontrol *kctl,
1597*4882a593Smuzhiyun struct snd_ctl_elem_id *id,
1598*4882a593Smuzhiyun unsigned int __user *buf, unsigned int size)
1599*4882a593Smuzhiyun {
1600*4882a593Smuzhiyun static const struct {
1601*4882a593Smuzhiyun int op;
1602*4882a593Smuzhiyun int perm;
1603*4882a593Smuzhiyun } pairs[] = {
1604*4882a593Smuzhiyun {SNDRV_CTL_TLV_OP_READ, SNDRV_CTL_ELEM_ACCESS_TLV_READ},
1605*4882a593Smuzhiyun {SNDRV_CTL_TLV_OP_WRITE, SNDRV_CTL_ELEM_ACCESS_TLV_WRITE},
1606*4882a593Smuzhiyun {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
1607*4882a593Smuzhiyun };
1608*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
1609*4882a593Smuzhiyun int i;
1610*4882a593Smuzhiyun
1611*4882a593Smuzhiyun /* Check support of the request for this element. */
1612*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
1613*4882a593Smuzhiyun if (op_flag == pairs[i].op && (vd->access & pairs[i].perm))
1614*4882a593Smuzhiyun break;
1615*4882a593Smuzhiyun }
1616*4882a593Smuzhiyun if (i == ARRAY_SIZE(pairs))
1617*4882a593Smuzhiyun return -ENXIO;
1618*4882a593Smuzhiyun
1619*4882a593Smuzhiyun if (kctl->tlv.c == NULL)
1620*4882a593Smuzhiyun return -ENXIO;
1621*4882a593Smuzhiyun
1622*4882a593Smuzhiyun /* Write and command operations are not allowed for locked element. */
1623*4882a593Smuzhiyun if (op_flag != SNDRV_CTL_TLV_OP_READ &&
1624*4882a593Smuzhiyun vd->owner != NULL && vd->owner != file)
1625*4882a593Smuzhiyun return -EPERM;
1626*4882a593Smuzhiyun
1627*4882a593Smuzhiyun return kctl->tlv.c(kctl, op_flag, size, buf);
1628*4882a593Smuzhiyun }
1629*4882a593Smuzhiyun
read_tlv_buf(struct snd_kcontrol * kctl,struct snd_ctl_elem_id * id,unsigned int __user * buf,unsigned int size)1630*4882a593Smuzhiyun static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
1631*4882a593Smuzhiyun unsigned int __user *buf, unsigned int size)
1632*4882a593Smuzhiyun {
1633*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
1634*4882a593Smuzhiyun unsigned int len;
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ))
1637*4882a593Smuzhiyun return -ENXIO;
1638*4882a593Smuzhiyun
1639*4882a593Smuzhiyun if (kctl->tlv.p == NULL)
1640*4882a593Smuzhiyun return -ENXIO;
1641*4882a593Smuzhiyun
1642*4882a593Smuzhiyun len = sizeof(unsigned int) * 2 + kctl->tlv.p[1];
1643*4882a593Smuzhiyun if (size < len)
1644*4882a593Smuzhiyun return -ENOMEM;
1645*4882a593Smuzhiyun
1646*4882a593Smuzhiyun if (copy_to_user(buf, kctl->tlv.p, len))
1647*4882a593Smuzhiyun return -EFAULT;
1648*4882a593Smuzhiyun
1649*4882a593Smuzhiyun return 0;
1650*4882a593Smuzhiyun }
1651*4882a593Smuzhiyun
snd_ctl_tlv_ioctl(struct snd_ctl_file * file,struct snd_ctl_tlv __user * buf,int op_flag)1652*4882a593Smuzhiyun static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
1653*4882a593Smuzhiyun struct snd_ctl_tlv __user *buf,
1654*4882a593Smuzhiyun int op_flag)
1655*4882a593Smuzhiyun {
1656*4882a593Smuzhiyun struct snd_ctl_tlv header;
1657*4882a593Smuzhiyun unsigned int __user *container;
1658*4882a593Smuzhiyun unsigned int container_size;
1659*4882a593Smuzhiyun struct snd_kcontrol *kctl;
1660*4882a593Smuzhiyun struct snd_ctl_elem_id id;
1661*4882a593Smuzhiyun struct snd_kcontrol_volatile *vd;
1662*4882a593Smuzhiyun
1663*4882a593Smuzhiyun if (copy_from_user(&header, buf, sizeof(header)))
1664*4882a593Smuzhiyun return -EFAULT;
1665*4882a593Smuzhiyun
1666*4882a593Smuzhiyun /* In design of control core, numerical ID starts at 1. */
1667*4882a593Smuzhiyun if (header.numid == 0)
1668*4882a593Smuzhiyun return -EINVAL;
1669*4882a593Smuzhiyun
1670*4882a593Smuzhiyun /* At least, container should include type and length fields. */
1671*4882a593Smuzhiyun if (header.length < sizeof(unsigned int) * 2)
1672*4882a593Smuzhiyun return -EINVAL;
1673*4882a593Smuzhiyun container_size = header.length;
1674*4882a593Smuzhiyun container = buf->tlv;
1675*4882a593Smuzhiyun
1676*4882a593Smuzhiyun kctl = snd_ctl_find_numid(file->card, header.numid);
1677*4882a593Smuzhiyun if (kctl == NULL)
1678*4882a593Smuzhiyun return -ENOENT;
1679*4882a593Smuzhiyun
1680*4882a593Smuzhiyun /* Calculate index of the element in this set. */
1681*4882a593Smuzhiyun id = kctl->id;
1682*4882a593Smuzhiyun snd_ctl_build_ioff(&id, kctl, header.numid - id.numid);
1683*4882a593Smuzhiyun vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
1684*4882a593Smuzhiyun
1685*4882a593Smuzhiyun if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1686*4882a593Smuzhiyun return call_tlv_handler(file, op_flag, kctl, &id, container,
1687*4882a593Smuzhiyun container_size);
1688*4882a593Smuzhiyun } else {
1689*4882a593Smuzhiyun if (op_flag == SNDRV_CTL_TLV_OP_READ) {
1690*4882a593Smuzhiyun return read_tlv_buf(kctl, &id, container,
1691*4882a593Smuzhiyun container_size);
1692*4882a593Smuzhiyun }
1693*4882a593Smuzhiyun }
1694*4882a593Smuzhiyun
1695*4882a593Smuzhiyun /* Not supported. */
1696*4882a593Smuzhiyun return -ENXIO;
1697*4882a593Smuzhiyun }
1698*4882a593Smuzhiyun
snd_ctl_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1699*4882a593Smuzhiyun static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1700*4882a593Smuzhiyun {
1701*4882a593Smuzhiyun struct snd_ctl_file *ctl;
1702*4882a593Smuzhiyun struct snd_card *card;
1703*4882a593Smuzhiyun struct snd_kctl_ioctl *p;
1704*4882a593Smuzhiyun void __user *argp = (void __user *)arg;
1705*4882a593Smuzhiyun int __user *ip = argp;
1706*4882a593Smuzhiyun int err;
1707*4882a593Smuzhiyun
1708*4882a593Smuzhiyun ctl = file->private_data;
1709*4882a593Smuzhiyun card = ctl->card;
1710*4882a593Smuzhiyun if (snd_BUG_ON(!card))
1711*4882a593Smuzhiyun return -ENXIO;
1712*4882a593Smuzhiyun switch (cmd) {
1713*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_PVERSION:
1714*4882a593Smuzhiyun return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
1715*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_CARD_INFO:
1716*4882a593Smuzhiyun return snd_ctl_card_info(card, ctl, cmd, argp);
1717*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_LIST:
1718*4882a593Smuzhiyun return snd_ctl_elem_list_user(card, argp);
1719*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_INFO:
1720*4882a593Smuzhiyun return snd_ctl_elem_info_user(ctl, argp);
1721*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_READ:
1722*4882a593Smuzhiyun return snd_ctl_elem_read_user(card, argp);
1723*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_WRITE:
1724*4882a593Smuzhiyun return snd_ctl_elem_write_user(ctl, argp);
1725*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_LOCK:
1726*4882a593Smuzhiyun return snd_ctl_elem_lock(ctl, argp);
1727*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
1728*4882a593Smuzhiyun return snd_ctl_elem_unlock(ctl, argp);
1729*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_ADD:
1730*4882a593Smuzhiyun return snd_ctl_elem_add_user(ctl, argp, 0);
1731*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_REPLACE:
1732*4882a593Smuzhiyun return snd_ctl_elem_add_user(ctl, argp, 1);
1733*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_ELEM_REMOVE:
1734*4882a593Smuzhiyun return snd_ctl_elem_remove(ctl, argp);
1735*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
1736*4882a593Smuzhiyun return snd_ctl_subscribe_events(ctl, ip);
1737*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_TLV_READ:
1738*4882a593Smuzhiyun down_read(&ctl->card->controls_rwsem);
1739*4882a593Smuzhiyun err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
1740*4882a593Smuzhiyun up_read(&ctl->card->controls_rwsem);
1741*4882a593Smuzhiyun return err;
1742*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_TLV_WRITE:
1743*4882a593Smuzhiyun down_write(&ctl->card->controls_rwsem);
1744*4882a593Smuzhiyun err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
1745*4882a593Smuzhiyun up_write(&ctl->card->controls_rwsem);
1746*4882a593Smuzhiyun return err;
1747*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_TLV_COMMAND:
1748*4882a593Smuzhiyun down_write(&ctl->card->controls_rwsem);
1749*4882a593Smuzhiyun err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
1750*4882a593Smuzhiyun up_write(&ctl->card->controls_rwsem);
1751*4882a593Smuzhiyun return err;
1752*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_POWER:
1753*4882a593Smuzhiyun return -ENOPROTOOPT;
1754*4882a593Smuzhiyun case SNDRV_CTL_IOCTL_POWER_STATE:
1755*4882a593Smuzhiyun #ifdef CONFIG_PM
1756*4882a593Smuzhiyun return put_user(card->power_state, ip) ? -EFAULT : 0;
1757*4882a593Smuzhiyun #else
1758*4882a593Smuzhiyun return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
1759*4882a593Smuzhiyun #endif
1760*4882a593Smuzhiyun }
1761*4882a593Smuzhiyun down_read(&snd_ioctl_rwsem);
1762*4882a593Smuzhiyun list_for_each_entry(p, &snd_control_ioctls, list) {
1763*4882a593Smuzhiyun err = p->fioctl(card, ctl, cmd, arg);
1764*4882a593Smuzhiyun if (err != -ENOIOCTLCMD) {
1765*4882a593Smuzhiyun up_read(&snd_ioctl_rwsem);
1766*4882a593Smuzhiyun return err;
1767*4882a593Smuzhiyun }
1768*4882a593Smuzhiyun }
1769*4882a593Smuzhiyun up_read(&snd_ioctl_rwsem);
1770*4882a593Smuzhiyun dev_dbg(card->dev, "unknown ioctl = 0x%x\n", cmd);
1771*4882a593Smuzhiyun return -ENOTTY;
1772*4882a593Smuzhiyun }
1773*4882a593Smuzhiyun
snd_ctl_read(struct file * file,char __user * buffer,size_t count,loff_t * offset)1774*4882a593Smuzhiyun static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
1775*4882a593Smuzhiyun size_t count, loff_t * offset)
1776*4882a593Smuzhiyun {
1777*4882a593Smuzhiyun struct snd_ctl_file *ctl;
1778*4882a593Smuzhiyun int err = 0;
1779*4882a593Smuzhiyun ssize_t result = 0;
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun ctl = file->private_data;
1782*4882a593Smuzhiyun if (snd_BUG_ON(!ctl || !ctl->card))
1783*4882a593Smuzhiyun return -ENXIO;
1784*4882a593Smuzhiyun if (!ctl->subscribed)
1785*4882a593Smuzhiyun return -EBADFD;
1786*4882a593Smuzhiyun if (count < sizeof(struct snd_ctl_event))
1787*4882a593Smuzhiyun return -EINVAL;
1788*4882a593Smuzhiyun spin_lock_irq(&ctl->read_lock);
1789*4882a593Smuzhiyun while (count >= sizeof(struct snd_ctl_event)) {
1790*4882a593Smuzhiyun struct snd_ctl_event ev;
1791*4882a593Smuzhiyun struct snd_kctl_event *kev;
1792*4882a593Smuzhiyun while (list_empty(&ctl->events)) {
1793*4882a593Smuzhiyun wait_queue_entry_t wait;
1794*4882a593Smuzhiyun if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
1795*4882a593Smuzhiyun err = -EAGAIN;
1796*4882a593Smuzhiyun goto __end_lock;
1797*4882a593Smuzhiyun }
1798*4882a593Smuzhiyun init_waitqueue_entry(&wait, current);
1799*4882a593Smuzhiyun add_wait_queue(&ctl->change_sleep, &wait);
1800*4882a593Smuzhiyun set_current_state(TASK_INTERRUPTIBLE);
1801*4882a593Smuzhiyun spin_unlock_irq(&ctl->read_lock);
1802*4882a593Smuzhiyun schedule();
1803*4882a593Smuzhiyun remove_wait_queue(&ctl->change_sleep, &wait);
1804*4882a593Smuzhiyun if (ctl->card->shutdown)
1805*4882a593Smuzhiyun return -ENODEV;
1806*4882a593Smuzhiyun if (signal_pending(current))
1807*4882a593Smuzhiyun return -ERESTARTSYS;
1808*4882a593Smuzhiyun spin_lock_irq(&ctl->read_lock);
1809*4882a593Smuzhiyun }
1810*4882a593Smuzhiyun kev = snd_kctl_event(ctl->events.next);
1811*4882a593Smuzhiyun ev.type = SNDRV_CTL_EVENT_ELEM;
1812*4882a593Smuzhiyun ev.data.elem.mask = kev->mask;
1813*4882a593Smuzhiyun ev.data.elem.id = kev->id;
1814*4882a593Smuzhiyun list_del(&kev->list);
1815*4882a593Smuzhiyun spin_unlock_irq(&ctl->read_lock);
1816*4882a593Smuzhiyun kfree(kev);
1817*4882a593Smuzhiyun if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) {
1818*4882a593Smuzhiyun err = -EFAULT;
1819*4882a593Smuzhiyun goto __end;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun spin_lock_irq(&ctl->read_lock);
1822*4882a593Smuzhiyun buffer += sizeof(struct snd_ctl_event);
1823*4882a593Smuzhiyun count -= sizeof(struct snd_ctl_event);
1824*4882a593Smuzhiyun result += sizeof(struct snd_ctl_event);
1825*4882a593Smuzhiyun }
1826*4882a593Smuzhiyun __end_lock:
1827*4882a593Smuzhiyun spin_unlock_irq(&ctl->read_lock);
1828*4882a593Smuzhiyun __end:
1829*4882a593Smuzhiyun return result > 0 ? result : err;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun
snd_ctl_poll(struct file * file,poll_table * wait)1832*4882a593Smuzhiyun static __poll_t snd_ctl_poll(struct file *file, poll_table * wait)
1833*4882a593Smuzhiyun {
1834*4882a593Smuzhiyun __poll_t mask;
1835*4882a593Smuzhiyun struct snd_ctl_file *ctl;
1836*4882a593Smuzhiyun
1837*4882a593Smuzhiyun ctl = file->private_data;
1838*4882a593Smuzhiyun if (!ctl->subscribed)
1839*4882a593Smuzhiyun return 0;
1840*4882a593Smuzhiyun poll_wait(file, &ctl->change_sleep, wait);
1841*4882a593Smuzhiyun
1842*4882a593Smuzhiyun mask = 0;
1843*4882a593Smuzhiyun if (!list_empty(&ctl->events))
1844*4882a593Smuzhiyun mask |= EPOLLIN | EPOLLRDNORM;
1845*4882a593Smuzhiyun
1846*4882a593Smuzhiyun return mask;
1847*4882a593Smuzhiyun }
1848*4882a593Smuzhiyun
1849*4882a593Smuzhiyun /*
1850*4882a593Smuzhiyun * register the device-specific control-ioctls.
1851*4882a593Smuzhiyun * called from each device manager like pcm.c, hwdep.c, etc.
1852*4882a593Smuzhiyun */
_snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn,struct list_head * lists)1853*4882a593Smuzhiyun static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
1854*4882a593Smuzhiyun {
1855*4882a593Smuzhiyun struct snd_kctl_ioctl *pn;
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL);
1858*4882a593Smuzhiyun if (pn == NULL)
1859*4882a593Smuzhiyun return -ENOMEM;
1860*4882a593Smuzhiyun pn->fioctl = fcn;
1861*4882a593Smuzhiyun down_write(&snd_ioctl_rwsem);
1862*4882a593Smuzhiyun list_add_tail(&pn->list, lists);
1863*4882a593Smuzhiyun up_write(&snd_ioctl_rwsem);
1864*4882a593Smuzhiyun return 0;
1865*4882a593Smuzhiyun }
1866*4882a593Smuzhiyun
1867*4882a593Smuzhiyun /**
1868*4882a593Smuzhiyun * snd_ctl_register_ioctl - register the device-specific control-ioctls
1869*4882a593Smuzhiyun * @fcn: ioctl callback function
1870*4882a593Smuzhiyun *
1871*4882a593Smuzhiyun * called from each device manager like pcm.c, hwdep.c, etc.
1872*4882a593Smuzhiyun */
snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)1873*4882a593Smuzhiyun int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
1874*4882a593Smuzhiyun {
1875*4882a593Smuzhiyun return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
1876*4882a593Smuzhiyun }
1877*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_register_ioctl);
1878*4882a593Smuzhiyun
1879*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
1880*4882a593Smuzhiyun /**
1881*4882a593Smuzhiyun * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat
1882*4882a593Smuzhiyun * control-ioctls
1883*4882a593Smuzhiyun * @fcn: ioctl callback function
1884*4882a593Smuzhiyun */
snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)1885*4882a593Smuzhiyun int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1886*4882a593Smuzhiyun {
1887*4882a593Smuzhiyun return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
1888*4882a593Smuzhiyun }
1889*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
1890*4882a593Smuzhiyun #endif
1891*4882a593Smuzhiyun
1892*4882a593Smuzhiyun /*
1893*4882a593Smuzhiyun * de-register the device-specific control-ioctls.
1894*4882a593Smuzhiyun */
_snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,struct list_head * lists)1895*4882a593Smuzhiyun static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
1896*4882a593Smuzhiyun struct list_head *lists)
1897*4882a593Smuzhiyun {
1898*4882a593Smuzhiyun struct snd_kctl_ioctl *p;
1899*4882a593Smuzhiyun
1900*4882a593Smuzhiyun if (snd_BUG_ON(!fcn))
1901*4882a593Smuzhiyun return -EINVAL;
1902*4882a593Smuzhiyun down_write(&snd_ioctl_rwsem);
1903*4882a593Smuzhiyun list_for_each_entry(p, lists, list) {
1904*4882a593Smuzhiyun if (p->fioctl == fcn) {
1905*4882a593Smuzhiyun list_del(&p->list);
1906*4882a593Smuzhiyun up_write(&snd_ioctl_rwsem);
1907*4882a593Smuzhiyun kfree(p);
1908*4882a593Smuzhiyun return 0;
1909*4882a593Smuzhiyun }
1910*4882a593Smuzhiyun }
1911*4882a593Smuzhiyun up_write(&snd_ioctl_rwsem);
1912*4882a593Smuzhiyun snd_BUG();
1913*4882a593Smuzhiyun return -EINVAL;
1914*4882a593Smuzhiyun }
1915*4882a593Smuzhiyun
1916*4882a593Smuzhiyun /**
1917*4882a593Smuzhiyun * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls
1918*4882a593Smuzhiyun * @fcn: ioctl callback function to unregister
1919*4882a593Smuzhiyun */
snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)1920*4882a593Smuzhiyun int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
1921*4882a593Smuzhiyun {
1922*4882a593Smuzhiyun return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
1923*4882a593Smuzhiyun }
1924*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
1927*4882a593Smuzhiyun /**
1928*4882a593Smuzhiyun * snd_ctl_unregister_ioctl_compat - de-register the device-specific compat
1929*4882a593Smuzhiyun * 32bit control-ioctls
1930*4882a593Smuzhiyun * @fcn: ioctl callback function to unregister
1931*4882a593Smuzhiyun */
snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)1932*4882a593Smuzhiyun int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1933*4882a593Smuzhiyun {
1934*4882a593Smuzhiyun return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
1935*4882a593Smuzhiyun }
1936*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
1937*4882a593Smuzhiyun #endif
1938*4882a593Smuzhiyun
snd_ctl_fasync(int fd,struct file * file,int on)1939*4882a593Smuzhiyun static int snd_ctl_fasync(int fd, struct file * file, int on)
1940*4882a593Smuzhiyun {
1941*4882a593Smuzhiyun struct snd_ctl_file *ctl;
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun ctl = file->private_data;
1944*4882a593Smuzhiyun return fasync_helper(fd, file, on, &ctl->fasync);
1945*4882a593Smuzhiyun }
1946*4882a593Smuzhiyun
1947*4882a593Smuzhiyun /* return the preferred subdevice number if already assigned;
1948*4882a593Smuzhiyun * otherwise return -1
1949*4882a593Smuzhiyun */
snd_ctl_get_preferred_subdevice(struct snd_card * card,int type)1950*4882a593Smuzhiyun int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
1951*4882a593Smuzhiyun {
1952*4882a593Smuzhiyun struct snd_ctl_file *kctl;
1953*4882a593Smuzhiyun int subdevice = -1;
1954*4882a593Smuzhiyun unsigned long flags;
1955*4882a593Smuzhiyun
1956*4882a593Smuzhiyun read_lock_irqsave(&card->ctl_files_rwlock, flags);
1957*4882a593Smuzhiyun list_for_each_entry(kctl, &card->ctl_files, list) {
1958*4882a593Smuzhiyun if (kctl->pid == task_pid(current)) {
1959*4882a593Smuzhiyun subdevice = kctl->preferred_subdevice[type];
1960*4882a593Smuzhiyun if (subdevice != -1)
1961*4882a593Smuzhiyun break;
1962*4882a593Smuzhiyun }
1963*4882a593Smuzhiyun }
1964*4882a593Smuzhiyun read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
1965*4882a593Smuzhiyun return subdevice;
1966*4882a593Smuzhiyun }
1967*4882a593Smuzhiyun EXPORT_SYMBOL_GPL(snd_ctl_get_preferred_subdevice);
1968*4882a593Smuzhiyun
1969*4882a593Smuzhiyun /*
1970*4882a593Smuzhiyun * ioctl32 compat
1971*4882a593Smuzhiyun */
1972*4882a593Smuzhiyun #ifdef CONFIG_COMPAT
1973*4882a593Smuzhiyun #include "control_compat.c"
1974*4882a593Smuzhiyun #else
1975*4882a593Smuzhiyun #define snd_ctl_ioctl_compat NULL
1976*4882a593Smuzhiyun #endif
1977*4882a593Smuzhiyun
1978*4882a593Smuzhiyun /*
1979*4882a593Smuzhiyun * INIT PART
1980*4882a593Smuzhiyun */
1981*4882a593Smuzhiyun
1982*4882a593Smuzhiyun static const struct file_operations snd_ctl_f_ops =
1983*4882a593Smuzhiyun {
1984*4882a593Smuzhiyun .owner = THIS_MODULE,
1985*4882a593Smuzhiyun .read = snd_ctl_read,
1986*4882a593Smuzhiyun .open = snd_ctl_open,
1987*4882a593Smuzhiyun .release = snd_ctl_release,
1988*4882a593Smuzhiyun .llseek = no_llseek,
1989*4882a593Smuzhiyun .poll = snd_ctl_poll,
1990*4882a593Smuzhiyun .unlocked_ioctl = snd_ctl_ioctl,
1991*4882a593Smuzhiyun .compat_ioctl = snd_ctl_ioctl_compat,
1992*4882a593Smuzhiyun .fasync = snd_ctl_fasync,
1993*4882a593Smuzhiyun };
1994*4882a593Smuzhiyun
1995*4882a593Smuzhiyun /*
1996*4882a593Smuzhiyun * registration of the control device
1997*4882a593Smuzhiyun */
snd_ctl_dev_register(struct snd_device * device)1998*4882a593Smuzhiyun static int snd_ctl_dev_register(struct snd_device *device)
1999*4882a593Smuzhiyun {
2000*4882a593Smuzhiyun struct snd_card *card = device->device_data;
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun return snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
2003*4882a593Smuzhiyun &snd_ctl_f_ops, card, &card->ctl_dev);
2004*4882a593Smuzhiyun }
2005*4882a593Smuzhiyun
2006*4882a593Smuzhiyun /*
2007*4882a593Smuzhiyun * disconnection of the control device
2008*4882a593Smuzhiyun */
snd_ctl_dev_disconnect(struct snd_device * device)2009*4882a593Smuzhiyun static int snd_ctl_dev_disconnect(struct snd_device *device)
2010*4882a593Smuzhiyun {
2011*4882a593Smuzhiyun struct snd_card *card = device->device_data;
2012*4882a593Smuzhiyun struct snd_ctl_file *ctl;
2013*4882a593Smuzhiyun unsigned long flags;
2014*4882a593Smuzhiyun
2015*4882a593Smuzhiyun read_lock_irqsave(&card->ctl_files_rwlock, flags);
2016*4882a593Smuzhiyun list_for_each_entry(ctl, &card->ctl_files, list) {
2017*4882a593Smuzhiyun wake_up(&ctl->change_sleep);
2018*4882a593Smuzhiyun kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
2019*4882a593Smuzhiyun }
2020*4882a593Smuzhiyun read_unlock_irqrestore(&card->ctl_files_rwlock, flags);
2021*4882a593Smuzhiyun
2022*4882a593Smuzhiyun return snd_unregister_device(&card->ctl_dev);
2023*4882a593Smuzhiyun }
2024*4882a593Smuzhiyun
2025*4882a593Smuzhiyun /*
2026*4882a593Smuzhiyun * free all controls
2027*4882a593Smuzhiyun */
snd_ctl_dev_free(struct snd_device * device)2028*4882a593Smuzhiyun static int snd_ctl_dev_free(struct snd_device *device)
2029*4882a593Smuzhiyun {
2030*4882a593Smuzhiyun struct snd_card *card = device->device_data;
2031*4882a593Smuzhiyun struct snd_kcontrol *control;
2032*4882a593Smuzhiyun
2033*4882a593Smuzhiyun down_write(&card->controls_rwsem);
2034*4882a593Smuzhiyun while (!list_empty(&card->controls)) {
2035*4882a593Smuzhiyun control = snd_kcontrol(card->controls.next);
2036*4882a593Smuzhiyun snd_ctl_remove(card, control);
2037*4882a593Smuzhiyun }
2038*4882a593Smuzhiyun up_write(&card->controls_rwsem);
2039*4882a593Smuzhiyun put_device(&card->ctl_dev);
2040*4882a593Smuzhiyun return 0;
2041*4882a593Smuzhiyun }
2042*4882a593Smuzhiyun
2043*4882a593Smuzhiyun /*
2044*4882a593Smuzhiyun * create control core:
2045*4882a593Smuzhiyun * called from init.c
2046*4882a593Smuzhiyun */
snd_ctl_create(struct snd_card * card)2047*4882a593Smuzhiyun int snd_ctl_create(struct snd_card *card)
2048*4882a593Smuzhiyun {
2049*4882a593Smuzhiyun static const struct snd_device_ops ops = {
2050*4882a593Smuzhiyun .dev_free = snd_ctl_dev_free,
2051*4882a593Smuzhiyun .dev_register = snd_ctl_dev_register,
2052*4882a593Smuzhiyun .dev_disconnect = snd_ctl_dev_disconnect,
2053*4882a593Smuzhiyun };
2054*4882a593Smuzhiyun int err;
2055*4882a593Smuzhiyun
2056*4882a593Smuzhiyun if (snd_BUG_ON(!card))
2057*4882a593Smuzhiyun return -ENXIO;
2058*4882a593Smuzhiyun if (snd_BUG_ON(card->number < 0 || card->number >= SNDRV_CARDS))
2059*4882a593Smuzhiyun return -ENXIO;
2060*4882a593Smuzhiyun
2061*4882a593Smuzhiyun snd_device_initialize(&card->ctl_dev, card);
2062*4882a593Smuzhiyun dev_set_name(&card->ctl_dev, "controlC%d", card->number);
2063*4882a593Smuzhiyun
2064*4882a593Smuzhiyun err = snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
2065*4882a593Smuzhiyun if (err < 0)
2066*4882a593Smuzhiyun put_device(&card->ctl_dev);
2067*4882a593Smuzhiyun return err;
2068*4882a593Smuzhiyun }
2069*4882a593Smuzhiyun
2070*4882a593Smuzhiyun /*
2071*4882a593Smuzhiyun * Frequently used control callbacks/helpers
2072*4882a593Smuzhiyun */
2073*4882a593Smuzhiyun
2074*4882a593Smuzhiyun /**
2075*4882a593Smuzhiyun * snd_ctl_boolean_mono_info - Helper function for a standard boolean info
2076*4882a593Smuzhiyun * callback with a mono channel
2077*4882a593Smuzhiyun * @kcontrol: the kcontrol instance
2078*4882a593Smuzhiyun * @uinfo: info to store
2079*4882a593Smuzhiyun *
2080*4882a593Smuzhiyun * This is a function that can be used as info callback for a standard
2081*4882a593Smuzhiyun * boolean control with a single mono channel.
2082*4882a593Smuzhiyun */
snd_ctl_boolean_mono_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2083*4882a593Smuzhiyun int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
2084*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2085*4882a593Smuzhiyun {
2086*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2087*4882a593Smuzhiyun uinfo->count = 1;
2088*4882a593Smuzhiyun uinfo->value.integer.min = 0;
2089*4882a593Smuzhiyun uinfo->value.integer.max = 1;
2090*4882a593Smuzhiyun return 0;
2091*4882a593Smuzhiyun }
2092*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
2093*4882a593Smuzhiyun
2094*4882a593Smuzhiyun /**
2095*4882a593Smuzhiyun * snd_ctl_boolean_stereo_info - Helper function for a standard boolean info
2096*4882a593Smuzhiyun * callback with stereo two channels
2097*4882a593Smuzhiyun * @kcontrol: the kcontrol instance
2098*4882a593Smuzhiyun * @uinfo: info to store
2099*4882a593Smuzhiyun *
2100*4882a593Smuzhiyun * This is a function that can be used as info callback for a standard
2101*4882a593Smuzhiyun * boolean control with stereo two channels.
2102*4882a593Smuzhiyun */
snd_ctl_boolean_stereo_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)2103*4882a593Smuzhiyun int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
2104*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
2105*4882a593Smuzhiyun {
2106*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
2107*4882a593Smuzhiyun uinfo->count = 2;
2108*4882a593Smuzhiyun uinfo->value.integer.min = 0;
2109*4882a593Smuzhiyun uinfo->value.integer.max = 1;
2110*4882a593Smuzhiyun return 0;
2111*4882a593Smuzhiyun }
2112*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
2113*4882a593Smuzhiyun
2114*4882a593Smuzhiyun /**
2115*4882a593Smuzhiyun * snd_ctl_enum_info - fills the info structure for an enumerated control
2116*4882a593Smuzhiyun * @info: the structure to be filled
2117*4882a593Smuzhiyun * @channels: the number of the control's channels; often one
2118*4882a593Smuzhiyun * @items: the number of control values; also the size of @names
2119*4882a593Smuzhiyun * @names: an array containing the names of all control values
2120*4882a593Smuzhiyun *
2121*4882a593Smuzhiyun * Sets all required fields in @info to their appropriate values.
2122*4882a593Smuzhiyun * If the control's accessibility is not the default (readable and writable),
2123*4882a593Smuzhiyun * the caller has to fill @info->access.
2124*4882a593Smuzhiyun *
2125*4882a593Smuzhiyun * Return: Zero.
2126*4882a593Smuzhiyun */
snd_ctl_enum_info(struct snd_ctl_elem_info * info,unsigned int channels,unsigned int items,const char * const names[])2127*4882a593Smuzhiyun int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
2128*4882a593Smuzhiyun unsigned int items, const char *const names[])
2129*4882a593Smuzhiyun {
2130*4882a593Smuzhiyun info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
2131*4882a593Smuzhiyun info->count = channels;
2132*4882a593Smuzhiyun info->value.enumerated.items = items;
2133*4882a593Smuzhiyun if (!items)
2134*4882a593Smuzhiyun return 0;
2135*4882a593Smuzhiyun if (info->value.enumerated.item >= items)
2136*4882a593Smuzhiyun info->value.enumerated.item = items - 1;
2137*4882a593Smuzhiyun WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name),
2138*4882a593Smuzhiyun "ALSA: too long item name '%s'\n",
2139*4882a593Smuzhiyun names[info->value.enumerated.item]);
2140*4882a593Smuzhiyun strlcpy(info->value.enumerated.name,
2141*4882a593Smuzhiyun names[info->value.enumerated.item],
2142*4882a593Smuzhiyun sizeof(info->value.enumerated.name));
2143*4882a593Smuzhiyun return 0;
2144*4882a593Smuzhiyun }
2145*4882a593Smuzhiyun EXPORT_SYMBOL(snd_ctl_enum_info);
2146