Branch data Line data Source code
1 : : /*
2 : : * Routines for driver control interface
3 : : * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4 : : *
5 : : *
6 : : * This program is free software; you can redistribute it and/or modify
7 : : * it under the terms of the GNU General Public License as published by
8 : : * the Free Software Foundation; either version 2 of the License, or
9 : : * (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, write to the Free Software
18 : : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 : : *
20 : : */
21 : :
22 : : #include <linux/threads.h>
23 : : #include <linux/interrupt.h>
24 : : #include <linux/module.h>
25 : : #include <linux/slab.h>
26 : : #include <linux/vmalloc.h>
27 : : #include <linux/time.h>
28 : : #include <sound/core.h>
29 : : #include <sound/minors.h>
30 : : #include <sound/info.h>
31 : : #include <sound/control.h>
32 : :
33 : : /* max number of user-defined controls */
34 : : #define MAX_USER_CONTROLS 32
35 : : #define MAX_CONTROL_COUNT 1028
36 : :
37 : : struct snd_kctl_ioctl {
38 : : struct list_head list; /* list of all ioctls */
39 : : snd_kctl_ioctl_func_t fioctl;
40 : : };
41 : :
42 : : static DECLARE_RWSEM(snd_ioctl_rwsem);
43 : : static LIST_HEAD(snd_control_ioctls);
44 : : #ifdef CONFIG_COMPAT
45 : : static LIST_HEAD(snd_control_compat_ioctls);
46 : : #endif
47 : :
48 : 0 : static int snd_ctl_open(struct inode *inode, struct file *file)
49 : : {
50 : : unsigned long flags;
51 : : struct snd_card *card;
52 : : struct snd_ctl_file *ctl;
53 : : int err;
54 : :
55 : 0 : err = nonseekable_open(inode, file);
56 [ # # ]: 0 : if (err < 0)
57 : : return err;
58 : :
59 : 0 : card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
60 [ # # ]: 0 : if (!card) {
61 : : err = -ENODEV;
62 : : goto __error1;
63 : : }
64 : 0 : err = snd_card_file_add(card, file);
65 [ # # ]: 0 : if (err < 0) {
66 : : err = -ENODEV;
67 : : goto __error1;
68 : : }
69 [ # # ]: 0 : if (!try_module_get(card->module)) {
70 : : err = -EFAULT;
71 : : goto __error2;
72 : : }
73 : : ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
74 [ # # ]: 0 : if (ctl == NULL) {
75 : : err = -ENOMEM;
76 : : goto __error;
77 : : }
78 : 0 : INIT_LIST_HEAD(&ctl->events);
79 : 0 : init_waitqueue_head(&ctl->change_sleep);
80 : 0 : spin_lock_init(&ctl->read_lock);
81 : 0 : ctl->card = card;
82 : 0 : ctl->prefer_pcm_subdevice = -1;
83 : 0 : ctl->prefer_rawmidi_subdevice = -1;
84 : 0 : ctl->pid = get_pid(task_pid(current));
85 : 0 : file->private_data = ctl;
86 : 0 : write_lock_irqsave(&card->ctl_files_rwlock, flags);
87 : 0 : list_add_tail(&ctl->list, &card->ctl_files);
88 : 0 : write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
89 : 0 : snd_card_unref(card);
90 : 0 : return 0;
91 : :
92 : : __error:
93 : 0 : module_put(card->module);
94 : : __error2:
95 : 0 : snd_card_file_remove(card, file);
96 : : __error1:
97 [ # # ]: 0 : if (card)
98 : 0 : snd_card_unref(card);
99 : 0 : return err;
100 : : }
101 : :
102 : 0 : static void snd_ctl_empty_read_queue(struct snd_ctl_file * ctl)
103 : : {
104 : : unsigned long flags;
105 : : struct snd_kctl_event *cread;
106 : :
107 : 0 : spin_lock_irqsave(&ctl->read_lock, flags);
108 [ # # ]: 0 : while (!list_empty(&ctl->events)) {
109 : : cread = snd_kctl_event(ctl->events.next);
110 : : list_del(&cread->list);
111 : 0 : kfree(cread);
112 : : }
113 : : spin_unlock_irqrestore(&ctl->read_lock, flags);
114 : 0 : }
115 : :
116 : 0 : static int snd_ctl_release(struct inode *inode, struct file *file)
117 : : {
118 : : unsigned long flags;
119 : : struct snd_card *card;
120 : : struct snd_ctl_file *ctl;
121 : : struct snd_kcontrol *control;
122 : : unsigned int idx;
123 : :
124 : 0 : ctl = file->private_data;
125 : 0 : file->private_data = NULL;
126 : 0 : card = ctl->card;
127 : 0 : write_lock_irqsave(&card->ctl_files_rwlock, flags);
128 : : list_del(&ctl->list);
129 : 0 : write_unlock_irqrestore(&card->ctl_files_rwlock, flags);
130 : 0 : down_write(&card->controls_rwsem);
131 [ # # ]: 0 : list_for_each_entry(control, &card->controls, list)
132 [ # # ]: 0 : for (idx = 0; idx < control->count; idx++)
133 [ # # ]: 0 : if (control->vd[idx].owner == ctl)
134 : 0 : control->vd[idx].owner = NULL;
135 : 0 : up_write(&card->controls_rwsem);
136 : 0 : snd_ctl_empty_read_queue(ctl);
137 : 0 : put_pid(ctl->pid);
138 : 0 : kfree(ctl);
139 : 0 : module_put(card->module);
140 : 0 : snd_card_file_remove(card, file);
141 : 0 : return 0;
142 : : }
143 : :
144 : 0 : void snd_ctl_notify(struct snd_card *card, unsigned int mask,
145 : : struct snd_ctl_elem_id *id)
146 : : {
147 : : unsigned long flags;
148 : : struct snd_ctl_file *ctl;
149 : : struct snd_kctl_event *ev;
150 : :
151 [ # # ]: 0 : if (snd_BUG_ON(!card || !id))
152 : 0 : return;
153 : 0 : read_lock(&card->ctl_files_rwlock);
154 : : #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
155 : : card->mixer_oss_change_count++;
156 : : #endif
157 [ # # ]: 0 : list_for_each_entry(ctl, &card->ctl_files, list) {
158 [ # # ]: 0 : if (!ctl->subscribed)
159 : 0 : continue;
160 : 0 : spin_lock_irqsave(&ctl->read_lock, flags);
161 [ # # ]: 0 : list_for_each_entry(ev, &ctl->events, list) {
162 [ # # ]: 0 : if (ev->id.numid == id->numid) {
163 : 0 : ev->mask |= mask;
164 : 0 : goto _found;
165 : : }
166 : : }
167 : : ev = kzalloc(sizeof(*ev), GFP_ATOMIC);
168 [ # # ]: 0 : if (ev) {
169 : 0 : ev->id = *id;
170 : 0 : ev->mask = mask;
171 : 0 : list_add_tail(&ev->list, &ctl->events);
172 : : } else {
173 : 0 : snd_printk(KERN_ERR "No memory available to allocate event\n");
174 : : }
175 : : _found:
176 : 0 : wake_up(&ctl->change_sleep);
177 : : spin_unlock_irqrestore(&ctl->read_lock, flags);
178 : 0 : kill_fasync(&ctl->fasync, SIGIO, POLL_IN);
179 : : }
180 : : read_unlock(&card->ctl_files_rwlock);
181 : : }
182 : :
183 : : EXPORT_SYMBOL(snd_ctl_notify);
184 : :
185 : : /**
186 : : * snd_ctl_new - create a control instance from the template
187 : : * @control: the control template
188 : : * @access: the default control access
189 : : *
190 : : * Allocates a new struct snd_kcontrol instance and copies the given template
191 : : * to the new instance. It does not copy volatile data (access).
192 : : *
193 : : * Return: The pointer of the new instance, or %NULL on failure.
194 : : */
195 : 0 : static struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control,
196 : : unsigned int access)
197 : : {
198 : : struct snd_kcontrol *kctl;
199 : : unsigned int idx;
200 : :
201 [ # # ][ # # ]: 0 : if (snd_BUG_ON(!control || !control->count))
[ # # ]
202 : : return NULL;
203 : :
204 [ # # ]: 0 : if (control->count > MAX_CONTROL_COUNT)
205 : : return NULL;
206 : :
207 : 0 : kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL);
208 [ # # ]: 0 : if (kctl == NULL) {
209 : 0 : snd_printk(KERN_ERR "Cannot allocate control instance\n");
210 : 0 : return NULL;
211 : : }
212 : 0 : *kctl = *control;
213 [ # # ]: 0 : for (idx = 0; idx < kctl->count; idx++)
214 : 0 : kctl->vd[idx].access = access;
215 : : return kctl;
216 : : }
217 : :
218 : : /**
219 : : * snd_ctl_new1 - create a control instance from the template
220 : : * @ncontrol: the initialization record
221 : : * @private_data: the private data to set
222 : : *
223 : : * Allocates a new struct snd_kcontrol instance and initialize from the given
224 : : * template. When the access field of ncontrol is 0, it's assumed as
225 : : * READWRITE access. When the count field is 0, it's assumes as one.
226 : : *
227 : : * Return: The pointer of the newly generated instance, or %NULL on failure.
228 : : */
229 : 0 : struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
230 : : void *private_data)
231 : : {
232 : : struct snd_kcontrol kctl;
233 : : unsigned int access;
234 : :
235 [ # # ][ # # ]: 0 : if (snd_BUG_ON(!ncontrol || !ncontrol->info))
[ # # ]
236 : : return NULL;
237 : 0 : memset(&kctl, 0, sizeof(kctl));
238 : 0 : kctl.id.iface = ncontrol->iface;
239 : 0 : kctl.id.device = ncontrol->device;
240 : 0 : kctl.id.subdevice = ncontrol->subdevice;
241 [ # # ]: 0 : if (ncontrol->name) {
242 : 0 : strlcpy(kctl.id.name, ncontrol->name, sizeof(kctl.id.name));
243 [ # # ]: 0 : if (strcmp(ncontrol->name, kctl.id.name) != 0)
244 : 0 : snd_printk(KERN_WARNING
245 : : "Control name '%s' truncated to '%s'\n",
246 : : ncontrol->name, kctl.id.name);
247 : : }
248 : 0 : kctl.id.index = ncontrol->index;
249 [ # # ]: 0 : kctl.count = ncontrol->count ? ncontrol->count : 1;
250 [ # # ]: 0 : access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
251 : : (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
252 : : SNDRV_CTL_ELEM_ACCESS_VOLATILE|
253 : : SNDRV_CTL_ELEM_ACCESS_INACTIVE|
254 : : SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE|
255 : : SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND|
256 : : SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK));
257 : 0 : kctl.info = ncontrol->info;
258 : 0 : kctl.get = ncontrol->get;
259 : 0 : kctl.put = ncontrol->put;
260 : 0 : kctl.tlv.p = ncontrol->tlv.p;
261 : 0 : kctl.private_value = ncontrol->private_value;
262 : 0 : kctl.private_data = private_data;
263 : 0 : return snd_ctl_new(&kctl, access);
264 : : }
265 : :
266 : : EXPORT_SYMBOL(snd_ctl_new1);
267 : :
268 : : /**
269 : : * snd_ctl_free_one - release the control instance
270 : : * @kcontrol: the control instance
271 : : *
272 : : * Releases the control instance created via snd_ctl_new()
273 : : * or snd_ctl_new1().
274 : : * Don't call this after the control was added to the card.
275 : : */
276 : 0 : void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
277 : : {
278 [ # # ]: 0 : if (kcontrol) {
279 [ # # ]: 0 : if (kcontrol->private_free)
280 : 0 : kcontrol->private_free(kcontrol);
281 : 0 : kfree(kcontrol);
282 : : }
283 : 0 : }
284 : :
285 : : EXPORT_SYMBOL(snd_ctl_free_one);
286 : :
287 : 0 : static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
288 : : unsigned int count)
289 : : {
290 : : struct snd_kcontrol *kctl;
291 : :
292 [ # # ]: 0 : list_for_each_entry(kctl, &card->controls, list) {
293 [ # # ][ # # ]: 0 : if (kctl->id.numid < card->last_numid + 1 + count &&
294 : 0 : kctl->id.numid + kctl->count > card->last_numid + 1) {
295 : 0 : card->last_numid = kctl->id.numid + kctl->count - 1;
296 : 0 : return true;
297 : : }
298 : : }
299 : : return false;
300 : : }
301 : :
302 : 0 : static int snd_ctl_find_hole(struct snd_card *card, unsigned int count)
303 : : {
304 : : unsigned int iter = 100000;
305 : :
306 [ # # ]: 0 : while (snd_ctl_remove_numid_conflict(card, count)) {
307 [ # # ]: 0 : if (--iter == 0) {
308 : : /* this situation is very unlikely */
309 : 0 : snd_printk(KERN_ERR "unable to allocate new control numid\n");
310 : 0 : return -ENOMEM;
311 : : }
312 : : }
313 : : return 0;
314 : : }
315 : :
316 : : /**
317 : : * snd_ctl_add - add the control instance to the card
318 : : * @card: the card instance
319 : : * @kcontrol: the control instance to add
320 : : *
321 : : * Adds the control instance created via snd_ctl_new() or
322 : : * snd_ctl_new1() to the given card. Assigns also an unique
323 : : * numid used for fast search.
324 : : *
325 : : * It frees automatically the control which cannot be added.
326 : : *
327 : : * Return: Zero if successful, or a negative error code on failure.
328 : : *
329 : : */
330 : 0 : int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
331 : : {
332 : : struct snd_ctl_elem_id id;
333 : : unsigned int idx;
334 : : int err = -EINVAL;
335 : :
336 [ # # ]: 0 : if (! kcontrol)
337 : : return err;
338 [ # # ][ # # ]: 0 : if (snd_BUG_ON(!card || !kcontrol->info))
[ # # ]
339 : : goto error;
340 : 0 : id = kcontrol->id;
341 : 0 : down_write(&card->controls_rwsem);
342 [ # # ]: 0 : if (snd_ctl_find_id(card, &id)) {
343 : 0 : up_write(&card->controls_rwsem);
344 : : snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
345 : : id.iface,
346 : : id.device,
347 : : id.subdevice,
348 : : id.name,
349 : : id.index);
350 : : err = -EBUSY;
351 : 0 : goto error;
352 : : }
353 [ # # ]: 0 : if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
354 : 0 : up_write(&card->controls_rwsem);
355 : : err = -ENOMEM;
356 : 0 : goto error;
357 : : }
358 : 0 : list_add_tail(&kcontrol->list, &card->controls);
359 : 0 : card->controls_count += kcontrol->count;
360 : 0 : kcontrol->id.numid = card->last_numid + 1;
361 : 0 : card->last_numid += kcontrol->count;
362 : 0 : up_write(&card->controls_rwsem);
363 [ # # ]: 0 : for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
364 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
365 : : return 0;
366 : :
367 : : error:
368 : 0 : snd_ctl_free_one(kcontrol);
369 : 0 : return err;
370 : : }
371 : :
372 : : EXPORT_SYMBOL(snd_ctl_add);
373 : :
374 : : /**
375 : : * snd_ctl_replace - replace the control instance of the card
376 : : * @card: the card instance
377 : : * @kcontrol: the control instance to replace
378 : : * @add_on_replace: add the control if not already added
379 : : *
380 : : * Replaces the given control. If the given control does not exist
381 : : * and the add_on_replace flag is set, the control is added. If the
382 : : * control exists, it is destroyed first.
383 : : *
384 : : * It frees automatically the control which cannot be added or replaced.
385 : : *
386 : : * Return: Zero if successful, or a negative error code on failure.
387 : : */
388 : 0 : int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
389 : : bool add_on_replace)
390 : : {
391 : : struct snd_ctl_elem_id id;
392 : : unsigned int idx;
393 : : struct snd_kcontrol *old;
394 : : int ret;
395 : :
396 [ # # ]: 0 : if (!kcontrol)
397 : : return -EINVAL;
398 [ # # ][ # # ]: 0 : if (snd_BUG_ON(!card || !kcontrol->info)) {
[ # # ]
399 : : ret = -EINVAL;
400 : : goto error;
401 : : }
402 : 0 : id = kcontrol->id;
403 : 0 : down_write(&card->controls_rwsem);
404 : 0 : old = snd_ctl_find_id(card, &id);
405 [ # # ]: 0 : if (!old) {
406 [ # # ]: 0 : if (add_on_replace)
407 : : goto add;
408 : 0 : up_write(&card->controls_rwsem);
409 : : ret = -EINVAL;
410 : 0 : goto error;
411 : : }
412 : 0 : ret = snd_ctl_remove(card, old);
413 [ # # ]: 0 : if (ret < 0) {
414 : 0 : up_write(&card->controls_rwsem);
415 : 0 : goto error;
416 : : }
417 : : add:
418 [ # # ]: 0 : if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
419 : 0 : up_write(&card->controls_rwsem);
420 : : ret = -ENOMEM;
421 : 0 : goto error;
422 : : }
423 : 0 : list_add_tail(&kcontrol->list, &card->controls);
424 : 0 : card->controls_count += kcontrol->count;
425 : 0 : kcontrol->id.numid = card->last_numid + 1;
426 : 0 : card->last_numid += kcontrol->count;
427 : 0 : up_write(&card->controls_rwsem);
428 [ # # ]: 0 : for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
429 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
430 : : return 0;
431 : :
432 : : error:
433 : 0 : snd_ctl_free_one(kcontrol);
434 : 0 : return ret;
435 : : }
436 : : EXPORT_SYMBOL(snd_ctl_replace);
437 : :
438 : : /**
439 : : * snd_ctl_remove - remove the control from the card and release it
440 : : * @card: the card instance
441 : : * @kcontrol: the control instance to remove
442 : : *
443 : : * Removes the control from the card and then releases the instance.
444 : : * You don't need to call snd_ctl_free_one(). You must be in
445 : : * the write lock - down_write(&card->controls_rwsem).
446 : : *
447 : : * Return: 0 if successful, or a negative error code on failure.
448 : : */
449 : 0 : int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
450 : : {
451 : : struct snd_ctl_elem_id id;
452 : : unsigned int idx;
453 : :
454 [ # # ]: 0 : if (snd_BUG_ON(!card || !kcontrol))
455 : : return -EINVAL;
456 : : list_del(&kcontrol->list);
457 : 0 : card->controls_count -= kcontrol->count;
458 : 0 : id = kcontrol->id;
459 [ # # ]: 0 : for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
460 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_REMOVE, &id);
461 : 0 : snd_ctl_free_one(kcontrol);
462 : 0 : return 0;
463 : : }
464 : :
465 : : EXPORT_SYMBOL(snd_ctl_remove);
466 : :
467 : : /**
468 : : * snd_ctl_remove_id - remove the control of the given id and release it
469 : : * @card: the card instance
470 : : * @id: the control id to remove
471 : : *
472 : : * Finds the control instance with the given id, removes it from the
473 : : * card list and releases it.
474 : : *
475 : : * Return: 0 if successful, or a negative error code on failure.
476 : : */
477 : 0 : int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
478 : : {
479 : : struct snd_kcontrol *kctl;
480 : : int ret;
481 : :
482 : 0 : down_write(&card->controls_rwsem);
483 : 0 : kctl = snd_ctl_find_id(card, id);
484 [ # # ]: 0 : if (kctl == NULL) {
485 : 0 : up_write(&card->controls_rwsem);
486 : 0 : return -ENOENT;
487 : : }
488 : 0 : ret = snd_ctl_remove(card, kctl);
489 : 0 : up_write(&card->controls_rwsem);
490 : 0 : return ret;
491 : : }
492 : :
493 : : EXPORT_SYMBOL(snd_ctl_remove_id);
494 : :
495 : : /**
496 : : * snd_ctl_remove_user_ctl - remove and release the unlocked user control
497 : : * @file: active control handle
498 : : * @id: the control id to remove
499 : : *
500 : : * Finds the control instance with the given id, removes it from the
501 : : * card list and releases it.
502 : : *
503 : : * Return: 0 if successful, or a negative error code on failure.
504 : : */
505 : 0 : static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
506 : : struct snd_ctl_elem_id *id)
507 : : {
508 : 0 : struct snd_card *card = file->card;
509 : : struct snd_kcontrol *kctl;
510 : : int idx, ret;
511 : :
512 : 0 : down_write(&card->controls_rwsem);
513 : 0 : kctl = snd_ctl_find_id(card, id);
514 [ # # ]: 0 : if (kctl == NULL) {
515 : : ret = -ENOENT;
516 : : goto error;
517 : : }
518 [ # # ]: 0 : if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) {
519 : : ret = -EINVAL;
520 : : goto error;
521 : : }
522 [ # # ]: 0 : for (idx = 0; idx < kctl->count; idx++)
523 [ # # ][ # # ]: 0 : if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) {
524 : : ret = -EBUSY;
525 : : goto error;
526 : : }
527 : 0 : ret = snd_ctl_remove(card, kctl);
528 [ # # ]: 0 : if (ret < 0)
529 : : goto error;
530 : 0 : card->user_ctl_count--;
531 : : error:
532 : 0 : up_write(&card->controls_rwsem);
533 : 0 : return ret;
534 : : }
535 : :
536 : : /**
537 : : * snd_ctl_activate_id - activate/inactivate the control of the given id
538 : : * @card: the card instance
539 : : * @id: the control id to activate/inactivate
540 : : * @active: non-zero to activate
541 : : *
542 : : * Finds the control instance with the given id, and activate or
543 : : * inactivate the control together with notification, if changed.
544 : : *
545 : : * Return: 0 if unchanged, 1 if changed, or a negative error code on failure.
546 : : */
547 : 0 : int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
548 : : int active)
549 : : {
550 : : struct snd_kcontrol *kctl;
551 : : struct snd_kcontrol_volatile *vd;
552 : : unsigned int index_offset;
553 : : int ret;
554 : :
555 : 0 : down_write(&card->controls_rwsem);
556 : 0 : kctl = snd_ctl_find_id(card, id);
557 [ # # ]: 0 : if (kctl == NULL) {
558 : : ret = -ENOENT;
559 : : goto unlock;
560 : : }
561 : : index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
562 : 0 : vd = &kctl->vd[index_offset];
563 : : ret = 0;
564 [ # # ]: 0 : if (active) {
565 [ # # ]: 0 : if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
566 : : goto unlock;
567 : 0 : vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
568 : : } else {
569 [ # # ]: 0 : if (vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)
570 : : goto unlock;
571 : 0 : vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
572 : : }
573 : : ret = 1;
574 : : unlock:
575 : 0 : up_write(&card->controls_rwsem);
576 [ # # ]: 0 : if (ret > 0)
577 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, id);
578 : 0 : return ret;
579 : : }
580 : : EXPORT_SYMBOL_GPL(snd_ctl_activate_id);
581 : :
582 : : /**
583 : : * snd_ctl_rename_id - replace the id of a control on the card
584 : : * @card: the card instance
585 : : * @src_id: the old id
586 : : * @dst_id: the new id
587 : : *
588 : : * Finds the control with the old id from the card, and replaces the
589 : : * id with the new one.
590 : : *
591 : : * Return: Zero if successful, or a negative error code on failure.
592 : : */
593 : 0 : int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
594 : : struct snd_ctl_elem_id *dst_id)
595 : : {
596 : : struct snd_kcontrol *kctl;
597 : :
598 : 0 : down_write(&card->controls_rwsem);
599 : 0 : kctl = snd_ctl_find_id(card, src_id);
600 [ # # ]: 0 : if (kctl == NULL) {
601 : 0 : up_write(&card->controls_rwsem);
602 : 0 : return -ENOENT;
603 : : }
604 : 0 : kctl->id = *dst_id;
605 : 0 : kctl->id.numid = card->last_numid + 1;
606 : 0 : card->last_numid += kctl->count;
607 : 0 : up_write(&card->controls_rwsem);
608 : 0 : return 0;
609 : : }
610 : :
611 : : EXPORT_SYMBOL(snd_ctl_rename_id);
612 : :
613 : : /**
614 : : * snd_ctl_find_numid - find the control instance with the given number-id
615 : : * @card: the card instance
616 : : * @numid: the number-id to search
617 : : *
618 : : * Finds the control instance with the given number-id from the card.
619 : : *
620 : : * The caller must down card->controls_rwsem before calling this function
621 : : * (if the race condition can happen).
622 : : *
623 : : * Return: The pointer of the instance if found, or %NULL if not.
624 : : *
625 : : */
626 : 0 : struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid)
627 : : {
628 : : struct snd_kcontrol *kctl;
629 : :
630 [ # # ]: 0 : if (snd_BUG_ON(!card || !numid))
631 : : return NULL;
632 [ # # ]: 0 : list_for_each_entry(kctl, &card->controls, list) {
633 [ # # ][ # # ]: 0 : if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
634 : : return kctl;
635 : : }
636 : : return NULL;
637 : : }
638 : :
639 : : EXPORT_SYMBOL(snd_ctl_find_numid);
640 : :
641 : : /**
642 : : * snd_ctl_find_id - find the control instance with the given id
643 : : * @card: the card instance
644 : : * @id: the id to search
645 : : *
646 : : * Finds the control instance with the given id from the card.
647 : : *
648 : : * The caller must down card->controls_rwsem before calling this function
649 : : * (if the race condition can happen).
650 : : *
651 : : * Return: The pointer of the instance if found, or %NULL if not.
652 : : *
653 : : */
654 : 0 : struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
655 : : struct snd_ctl_elem_id *id)
656 : : {
657 : : struct snd_kcontrol *kctl;
658 : :
659 [ # # ]: 0 : if (snd_BUG_ON(!card || !id))
660 : : return NULL;
661 [ # # ]: 0 : if (id->numid != 0)
662 : 0 : return snd_ctl_find_numid(card, id->numid);
663 [ # # ]: 0 : list_for_each_entry(kctl, &card->controls, list) {
664 [ # # ]: 0 : if (kctl->id.iface != id->iface)
665 : 0 : continue;
666 [ # # ]: 0 : if (kctl->id.device != id->device)
667 : 0 : continue;
668 [ # # ]: 0 : if (kctl->id.subdevice != id->subdevice)
669 : 0 : continue;
670 [ # # ]: 0 : if (strncmp(kctl->id.name, id->name, sizeof(kctl->id.name)))
671 : 0 : continue;
672 [ # # ]: 0 : if (kctl->id.index > id->index)
673 : 0 : continue;
674 [ # # ]: 0 : if (kctl->id.index + kctl->count <= id->index)
675 : 0 : continue;
676 : : return kctl;
677 : : }
678 : : return NULL;
679 : : }
680 : :
681 : : EXPORT_SYMBOL(snd_ctl_find_id);
682 : :
683 : 0 : static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
684 : : unsigned int cmd, void __user *arg)
685 : : {
686 : : struct snd_ctl_card_info *info;
687 : :
688 : : info = kzalloc(sizeof(*info), GFP_KERNEL);
689 [ # # ]: 0 : if (! info)
690 : : return -ENOMEM;
691 : 0 : down_read(&snd_ioctl_rwsem);
692 : 0 : info->card = card->number;
693 : 0 : strlcpy(info->id, card->id, sizeof(info->id));
694 : 0 : strlcpy(info->driver, card->driver, sizeof(info->driver));
695 : 0 : strlcpy(info->name, card->shortname, sizeof(info->name));
696 : 0 : strlcpy(info->longname, card->longname, sizeof(info->longname));
697 : 0 : strlcpy(info->mixername, card->mixername, sizeof(info->mixername));
698 : 0 : strlcpy(info->components, card->components, sizeof(info->components));
699 : 0 : up_read(&snd_ioctl_rwsem);
700 [ # # ]: 0 : if (copy_to_user(arg, info, sizeof(struct snd_ctl_card_info))) {
701 : 0 : kfree(info);
702 : : return -EFAULT;
703 : : }
704 : 0 : kfree(info);
705 : : return 0;
706 : : }
707 : :
708 : 0 : static int snd_ctl_elem_list(struct snd_card *card,
709 : : struct snd_ctl_elem_list __user *_list)
710 : : {
711 : : struct list_head *plist;
712 : : struct snd_ctl_elem_list list;
713 : : struct snd_kcontrol *kctl;
714 : : struct snd_ctl_elem_id *dst, *id;
715 : : unsigned int offset, space, jidx;
716 : :
717 [ # # ]: 0 : if (copy_from_user(&list, _list, sizeof(list)))
718 : : return -EFAULT;
719 : 0 : offset = list.offset;
720 : 0 : space = list.space;
721 : : /* try limit maximum space */
722 [ # # ]: 0 : if (space > 16384)
723 : : return -ENOMEM;
724 [ # # ]: 0 : if (space > 0) {
725 : : /* allocate temporary buffer for atomic operation */
726 : 0 : dst = vmalloc(space * sizeof(struct snd_ctl_elem_id));
727 [ # # ]: 0 : if (dst == NULL)
728 : : return -ENOMEM;
729 : 0 : down_read(&card->controls_rwsem);
730 : 0 : list.count = card->controls_count;
731 : 0 : plist = card->controls.next;
732 [ # # ]: 0 : while (plist != &card->controls) {
733 [ # # ]: 0 : if (offset == 0)
734 : : break;
735 : : kctl = snd_kcontrol(plist);
736 [ # # ]: 0 : if (offset < kctl->count)
737 : : break;
738 : 0 : offset -= kctl->count;
739 : 0 : plist = plist->next;
740 : : }
741 : 0 : list.used = 0;
742 : : id = dst;
743 [ # # ][ # # ]: 0 : while (space > 0 && plist != &card->controls) {
744 : : kctl = snd_kcontrol(plist);
745 [ # # ][ # # ]: 0 : for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
746 : : snd_ctl_build_ioff(id, kctl, jidx);
747 : 0 : id++;
748 : 0 : space--;
749 : 0 : list.used++;
750 : : }
751 : 0 : plist = plist->next;
752 : : offset = 0;
753 : : }
754 : 0 : up_read(&card->controls_rwsem);
755 [ # # ][ # # ]: 0 : if (list.used > 0 &&
756 : 0 : copy_to_user(list.pids, dst,
757 : 0 : list.used * sizeof(struct snd_ctl_elem_id))) {
758 : 0 : vfree(dst);
759 : 0 : return -EFAULT;
760 : : }
761 : 0 : vfree(dst);
762 : : } else {
763 : 0 : down_read(&card->controls_rwsem);
764 : 0 : list.count = card->controls_count;
765 : 0 : up_read(&card->controls_rwsem);
766 : : }
767 [ # # ]: 0 : if (copy_to_user(_list, &list, sizeof(list)))
768 : : return -EFAULT;
769 : 0 : return 0;
770 : : }
771 : :
772 : 0 : static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
773 : : struct snd_ctl_elem_info *info)
774 : : {
775 : 0 : struct snd_card *card = ctl->card;
776 : : struct snd_kcontrol *kctl;
777 : : struct snd_kcontrol_volatile *vd;
778 : : unsigned int index_offset;
779 : : int result;
780 : :
781 : 0 : down_read(&card->controls_rwsem);
782 : 0 : kctl = snd_ctl_find_id(card, &info->id);
783 [ # # ]: 0 : if (kctl == NULL) {
784 : 0 : up_read(&card->controls_rwsem);
785 : 0 : return -ENOENT;
786 : : }
787 : : #ifdef CONFIG_SND_DEBUG
788 : : info->access = 0;
789 : : #endif
790 : 0 : result = kctl->info(kctl, info);
791 [ # # ]: 0 : if (result >= 0) {
792 : : snd_BUG_ON(info->access);
793 : : index_offset = snd_ctl_get_ioff(kctl, &info->id);
794 : 0 : vd = &kctl->vd[index_offset];
795 : : snd_ctl_build_ioff(&info->id, kctl, index_offset);
796 : 0 : info->access = vd->access;
797 [ # # ]: 0 : if (vd->owner) {
798 : 0 : info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK;
799 [ # # ]: 0 : if (vd->owner == ctl)
800 : 0 : info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER;
801 : 0 : info->owner = pid_vnr(vd->owner->pid);
802 : : } else {
803 : 0 : info->owner = -1;
804 : : }
805 : : }
806 : 0 : up_read(&card->controls_rwsem);
807 : 0 : return result;
808 : : }
809 : :
810 : 0 : static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
811 : : struct snd_ctl_elem_info __user *_info)
812 : : {
813 : : struct snd_ctl_elem_info info;
814 : : int result;
815 : :
816 [ # # ]: 0 : if (copy_from_user(&info, _info, sizeof(info)))
817 : : return -EFAULT;
818 : 0 : snd_power_lock(ctl->card);
819 : 0 : result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
820 [ # # ]: 0 : if (result >= 0)
821 : 0 : result = snd_ctl_elem_info(ctl, &info);
822 : 0 : snd_power_unlock(ctl->card);
823 [ # # ]: 0 : if (result >= 0)
824 [ # # ]: 0 : if (copy_to_user(_info, &info, sizeof(info)))
825 : : return -EFAULT;
826 : 0 : return result;
827 : : }
828 : :
829 : 0 : static int snd_ctl_elem_read(struct snd_card *card,
830 : : struct snd_ctl_elem_value *control)
831 : : {
832 : : struct snd_kcontrol *kctl;
833 : : struct snd_kcontrol_volatile *vd;
834 : : unsigned int index_offset;
835 : : int result;
836 : :
837 : 0 : down_read(&card->controls_rwsem);
838 : 0 : kctl = snd_ctl_find_id(card, &control->id);
839 [ # # ]: 0 : if (kctl == NULL) {
840 : : result = -ENOENT;
841 : : } else {
842 : : index_offset = snd_ctl_get_ioff(kctl, &control->id);
843 : 0 : vd = &kctl->vd[index_offset];
844 [ # # ][ # # ]: 0 : if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
845 : 0 : kctl->get != NULL) {
846 : : snd_ctl_build_ioff(&control->id, kctl, index_offset);
847 : 0 : result = kctl->get(kctl, control);
848 : : } else
849 : : result = -EPERM;
850 : : }
851 : 0 : up_read(&card->controls_rwsem);
852 : 0 : return result;
853 : : }
854 : :
855 : 0 : static int snd_ctl_elem_read_user(struct snd_card *card,
856 : : struct snd_ctl_elem_value __user *_control)
857 : : {
858 : : struct snd_ctl_elem_value *control;
859 : : int result;
860 : :
861 : 0 : control = memdup_user(_control, sizeof(*control));
862 [ # # ]: 0 : if (IS_ERR(control))
863 : 0 : return PTR_ERR(control);
864 : :
865 : : snd_power_lock(card);
866 : 0 : result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
867 [ # # ]: 0 : if (result >= 0)
868 : 0 : result = snd_ctl_elem_read(card, control);
869 : : snd_power_unlock(card);
870 [ # # ]: 0 : if (result >= 0)
871 [ # # ]: 0 : if (copy_to_user(_control, control, sizeof(*control)))
872 : : result = -EFAULT;
873 : 0 : kfree(control);
874 : 0 : return result;
875 : : }
876 : :
877 : 0 : static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
878 : : struct snd_ctl_elem_value *control)
879 : : {
880 : : struct snd_kcontrol *kctl;
881 : : struct snd_kcontrol_volatile *vd;
882 : : unsigned int index_offset;
883 : : int result;
884 : :
885 : 0 : down_read(&card->controls_rwsem);
886 : 0 : kctl = snd_ctl_find_id(card, &control->id);
887 [ # # ]: 0 : if (kctl == NULL) {
888 : : result = -ENOENT;
889 : : } else {
890 : : index_offset = snd_ctl_get_ioff(kctl, &control->id);
891 : 0 : vd = &kctl->vd[index_offset];
892 [ # # ][ # # ]: 0 : if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
893 [ # # ]: 0 : kctl->put == NULL ||
894 [ # # ][ # # ]: 0 : (file && vd->owner && vd->owner != file)) {
895 : : result = -EPERM;
896 : : } else {
897 : : snd_ctl_build_ioff(&control->id, kctl, index_offset);
898 : 0 : result = kctl->put(kctl, control);
899 : : }
900 [ # # ]: 0 : if (result > 0) {
901 : 0 : up_read(&card->controls_rwsem);
902 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
903 : : &control->id);
904 : 0 : return 0;
905 : : }
906 : : }
907 : 0 : up_read(&card->controls_rwsem);
908 : 0 : return result;
909 : : }
910 : :
911 : 0 : static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
912 : : struct snd_ctl_elem_value __user *_control)
913 : : {
914 : : struct snd_ctl_elem_value *control;
915 : : struct snd_card *card;
916 : : int result;
917 : :
918 : 0 : control = memdup_user(_control, sizeof(*control));
919 [ # # ]: 0 : if (IS_ERR(control))
920 : 0 : return PTR_ERR(control);
921 : :
922 : 0 : card = file->card;
923 : : snd_power_lock(card);
924 : 0 : result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
925 [ # # ]: 0 : if (result >= 0)
926 : 0 : result = snd_ctl_elem_write(card, file, control);
927 : : snd_power_unlock(card);
928 [ # # ]: 0 : if (result >= 0)
929 [ # # ]: 0 : if (copy_to_user(_control, control, sizeof(*control)))
930 : : result = -EFAULT;
931 : 0 : kfree(control);
932 : 0 : return result;
933 : : }
934 : :
935 : 0 : static int snd_ctl_elem_lock(struct snd_ctl_file *file,
936 : : struct snd_ctl_elem_id __user *_id)
937 : : {
938 : 0 : struct snd_card *card = file->card;
939 : : struct snd_ctl_elem_id id;
940 : : struct snd_kcontrol *kctl;
941 : : struct snd_kcontrol_volatile *vd;
942 : : int result;
943 : :
944 [ # # ]: 0 : if (copy_from_user(&id, _id, sizeof(id)))
945 : : return -EFAULT;
946 : 0 : down_write(&card->controls_rwsem);
947 : 0 : kctl = snd_ctl_find_id(card, &id);
948 [ # # ]: 0 : if (kctl == NULL) {
949 : : result = -ENOENT;
950 : : } else {
951 : 0 : vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
952 [ # # ]: 0 : if (vd->owner != NULL)
953 : : result = -EBUSY;
954 : : else {
955 : 0 : vd->owner = file;
956 : : result = 0;
957 : : }
958 : : }
959 : 0 : up_write(&card->controls_rwsem);
960 : 0 : return result;
961 : : }
962 : :
963 : 0 : static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
964 : : struct snd_ctl_elem_id __user *_id)
965 : : {
966 : 0 : struct snd_card *card = file->card;
967 : : struct snd_ctl_elem_id id;
968 : : struct snd_kcontrol *kctl;
969 : : struct snd_kcontrol_volatile *vd;
970 : : int result;
971 : :
972 [ # # ]: 0 : if (copy_from_user(&id, _id, sizeof(id)))
973 : : return -EFAULT;
974 : 0 : down_write(&card->controls_rwsem);
975 : 0 : kctl = snd_ctl_find_id(card, &id);
976 [ # # ]: 0 : if (kctl == NULL) {
977 : : result = -ENOENT;
978 : : } else {
979 : 0 : vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
980 [ # # ]: 0 : if (vd->owner == NULL)
981 : : result = -EINVAL;
982 [ # # ]: 0 : else if (vd->owner != file)
983 : : result = -EPERM;
984 : : else {
985 : 0 : vd->owner = NULL;
986 : : result = 0;
987 : : }
988 : : }
989 : 0 : up_write(&card->controls_rwsem);
990 : 0 : return result;
991 : : }
992 : :
993 : : struct user_element {
994 : : struct snd_ctl_elem_info info;
995 : : void *elem_data; /* element data */
996 : : unsigned long elem_data_size; /* size of element data in bytes */
997 : : void *tlv_data; /* TLV data */
998 : : unsigned long tlv_data_size; /* TLV data size */
999 : : void *priv_data; /* private data (like strings for enumerated type) */
1000 : : };
1001 : :
1002 : 0 : static int snd_ctl_elem_user_info(struct snd_kcontrol *kcontrol,
1003 : : struct snd_ctl_elem_info *uinfo)
1004 : : {
1005 : 0 : struct user_element *ue = kcontrol->private_data;
1006 : :
1007 : 0 : *uinfo = ue->info;
1008 : 0 : return 0;
1009 : : }
1010 : :
1011 : 0 : static int snd_ctl_elem_user_enum_info(struct snd_kcontrol *kcontrol,
1012 : : struct snd_ctl_elem_info *uinfo)
1013 : : {
1014 : 0 : struct user_element *ue = kcontrol->private_data;
1015 : : const char *names;
1016 : : unsigned int item;
1017 : :
1018 : 0 : item = uinfo->value.enumerated.item;
1019 : :
1020 : 0 : *uinfo = ue->info;
1021 : :
1022 : 0 : item = min(item, uinfo->value.enumerated.items - 1);
1023 : 0 : uinfo->value.enumerated.item = item;
1024 : :
1025 : 0 : names = ue->priv_data;
1026 [ # # ]: 0 : for (; item > 0; --item)
1027 : 0 : names += strlen(names) + 1;
1028 : 0 : strcpy(uinfo->value.enumerated.name, names);
1029 : :
1030 : 0 : return 0;
1031 : : }
1032 : :
1033 : 0 : static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
1034 : : struct snd_ctl_elem_value *ucontrol)
1035 : : {
1036 : 0 : struct user_element *ue = kcontrol->private_data;
1037 : :
1038 : 0 : memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
1039 : 0 : return 0;
1040 : : }
1041 : :
1042 : 0 : static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
1043 : : struct snd_ctl_elem_value *ucontrol)
1044 : : {
1045 : : int change;
1046 : 0 : struct user_element *ue = kcontrol->private_data;
1047 : :
1048 : 0 : change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
1049 [ # # ]: 0 : if (change)
1050 : 0 : memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
1051 : 0 : return change;
1052 : : }
1053 : :
1054 : 0 : static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
1055 : : int op_flag,
1056 : : unsigned int size,
1057 : : unsigned int __user *tlv)
1058 : : {
1059 : 0 : struct user_element *ue = kcontrol->private_data;
1060 : : int change = 0;
1061 : : void *new_data;
1062 : :
1063 [ # # ]: 0 : if (op_flag > 0) {
1064 [ # # ]: 0 : if (size > 1024 * 128) /* sane value */
1065 : : return -EINVAL;
1066 : :
1067 : 0 : new_data = memdup_user(tlv, size);
1068 [ # # ]: 0 : if (IS_ERR(new_data))
1069 : 0 : return PTR_ERR(new_data);
1070 : 0 : change = ue->tlv_data_size != size;
1071 [ # # ]: 0 : if (!change)
1072 : 0 : change = memcmp(ue->tlv_data, new_data, size);
1073 : 0 : kfree(ue->tlv_data);
1074 : 0 : ue->tlv_data = new_data;
1075 : 0 : ue->tlv_data_size = size;
1076 : : } else {
1077 [ # # ][ # # ]: 0 : if (! ue->tlv_data_size || ! ue->tlv_data)
1078 : : return -ENXIO;
1079 [ # # ]: 0 : if (size < ue->tlv_data_size)
1080 : : return -ENOSPC;
1081 [ # # ]: 0 : if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
1082 : : return -EFAULT;
1083 : : }
1084 : 0 : return change;
1085 : : }
1086 : :
1087 : 0 : static int snd_ctl_elem_init_enum_names(struct user_element *ue)
1088 : : {
1089 : : char *names, *p;
1090 : : size_t buf_len, name_len;
1091 : : unsigned int i;
1092 : 0 : const uintptr_t user_ptrval = ue->info.value.enumerated.names_ptr;
1093 : :
1094 [ # # ]: 0 : if (ue->info.value.enumerated.names_length > 64 * 1024)
1095 : : return -EINVAL;
1096 : :
1097 : 0 : names = memdup_user((const void __user *)user_ptrval,
1098 : : ue->info.value.enumerated.names_length);
1099 [ # # ]: 0 : if (IS_ERR(names))
1100 : 0 : return PTR_ERR(names);
1101 : :
1102 : : /* check that there are enough valid names */
1103 : 0 : buf_len = ue->info.value.enumerated.names_length;
1104 : : p = names;
1105 [ # # ]: 0 : for (i = 0; i < ue->info.value.enumerated.items; ++i) {
1106 : 0 : name_len = strnlen(p, buf_len);
1107 [ # # ][ # # ]: 0 : if (name_len == 0 || name_len >= 64 || name_len == buf_len) {
1108 : 0 : kfree(names);
1109 : 0 : return -EINVAL;
1110 : : }
1111 : 0 : p += name_len + 1;
1112 : 0 : buf_len -= name_len + 1;
1113 : : }
1114 : :
1115 : 0 : ue->priv_data = names;
1116 : 0 : ue->info.value.enumerated.names_ptr = 0;
1117 : :
1118 : 0 : return 0;
1119 : : }
1120 : :
1121 : 0 : static void snd_ctl_elem_user_free(struct snd_kcontrol *kcontrol)
1122 : : {
1123 : 0 : struct user_element *ue = kcontrol->private_data;
1124 : :
1125 : 0 : kfree(ue->tlv_data);
1126 : 0 : kfree(ue->priv_data);
1127 : 0 : kfree(ue);
1128 : 0 : }
1129 : :
1130 : 0 : static int snd_ctl_elem_add(struct snd_ctl_file *file,
1131 : : struct snd_ctl_elem_info *info, int replace)
1132 : : {
1133 : 0 : struct snd_card *card = file->card;
1134 : : struct snd_kcontrol kctl, *_kctl;
1135 : : unsigned int access;
1136 : : long private_size;
1137 : : struct user_element *ue;
1138 : : int idx, err;
1139 : :
1140 [ # # ][ # # ]: 0 : if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
1141 : : return -ENOMEM;
1142 [ # # ]: 0 : if (info->count < 1)
1143 : : return -EINVAL;
1144 [ # # ]: 0 : access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
1145 : : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE|
1146 : : SNDRV_CTL_ELEM_ACCESS_INACTIVE|
1147 : : SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
1148 : 0 : info->id.numid = 0;
1149 : 0 : memset(&kctl, 0, sizeof(kctl));
1150 : 0 : down_write(&card->controls_rwsem);
1151 : 0 : _kctl = snd_ctl_find_id(card, &info->id);
1152 : : err = 0;
1153 [ # # ]: 0 : if (_kctl) {
1154 [ # # ]: 0 : if (replace)
1155 : 0 : err = snd_ctl_remove(card, _kctl);
1156 : : else
1157 : : err = -EBUSY;
1158 : : } else {
1159 [ # # ]: 0 : if (replace)
1160 : : err = -ENOENT;
1161 : : }
1162 : 0 : up_write(&card->controls_rwsem);
1163 [ # # ]: 0 : if (err < 0)
1164 : : return err;
1165 : 0 : memcpy(&kctl.id, &info->id, sizeof(info->id));
1166 [ # # ]: 0 : kctl.count = info->owner ? info->owner : 1;
1167 : 0 : access |= SNDRV_CTL_ELEM_ACCESS_USER;
1168 [ # # ]: 0 : if (info->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED)
1169 : 0 : kctl.info = snd_ctl_elem_user_enum_info;
1170 : : else
1171 : 0 : kctl.info = snd_ctl_elem_user_info;
1172 [ # # ]: 0 : if (access & SNDRV_CTL_ELEM_ACCESS_READ)
1173 : 0 : kctl.get = snd_ctl_elem_user_get;
1174 [ # # ]: 0 : if (access & SNDRV_CTL_ELEM_ACCESS_WRITE)
1175 : 0 : kctl.put = snd_ctl_elem_user_put;
1176 [ # # ]: 0 : if (access & SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE) {
1177 : 0 : kctl.tlv.c = snd_ctl_elem_user_tlv;
1178 : 0 : access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
1179 : : }
1180 [ # # # # : 0 : switch (info->type) {
# # ]
1181 : : case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
1182 : : case SNDRV_CTL_ELEM_TYPE_INTEGER:
1183 : : private_size = sizeof(long);
1184 [ # # ]: 0 : if (info->count > 128)
1185 : : return -EINVAL;
1186 : : break;
1187 : : case SNDRV_CTL_ELEM_TYPE_INTEGER64:
1188 : : private_size = sizeof(long long);
1189 [ # # ]: 0 : if (info->count > 64)
1190 : : return -EINVAL;
1191 : : break;
1192 : : case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
1193 : : private_size = sizeof(unsigned int);
1194 [ # # ][ # # ]: 0 : if (info->count > 128 || info->value.enumerated.items == 0)
1195 : : return -EINVAL;
1196 : : break;
1197 : : case SNDRV_CTL_ELEM_TYPE_BYTES:
1198 : : private_size = sizeof(unsigned char);
1199 [ # # ]: 0 : if (info->count > 512)
1200 : : return -EINVAL;
1201 : : break;
1202 : : case SNDRV_CTL_ELEM_TYPE_IEC958:
1203 : : private_size = sizeof(struct snd_aes_iec958);
1204 [ # # ]: 0 : if (info->count != 1)
1205 : : return -EINVAL;
1206 : : break;
1207 : : default:
1208 : : return -EINVAL;
1209 : : }
1210 : 0 : private_size *= info->count;
1211 : 0 : ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
1212 [ # # ]: 0 : if (ue == NULL)
1213 : : return -ENOMEM;
1214 : 0 : ue->info = *info;
1215 : 0 : ue->info.access = 0;
1216 : 0 : ue->elem_data = (char *)ue + sizeof(*ue);
1217 : 0 : ue->elem_data_size = private_size;
1218 [ # # ]: 0 : if (ue->info.type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
1219 : 0 : err = snd_ctl_elem_init_enum_names(ue);
1220 [ # # ]: 0 : if (err < 0) {
1221 : 0 : kfree(ue);
1222 : 0 : return err;
1223 : : }
1224 : : }
1225 : 0 : kctl.private_free = snd_ctl_elem_user_free;
1226 : 0 : _kctl = snd_ctl_new(&kctl, access);
1227 [ # # ]: 0 : if (_kctl == NULL) {
1228 : 0 : kfree(ue->priv_data);
1229 : 0 : kfree(ue);
1230 : 0 : return -ENOMEM;
1231 : : }
1232 : 0 : _kctl->private_data = ue;
1233 [ # # ]: 0 : for (idx = 0; idx < _kctl->count; idx++)
1234 : 0 : _kctl->vd[idx].owner = file;
1235 : 0 : err = snd_ctl_add(card, _kctl);
1236 [ # # ]: 0 : if (err < 0)
1237 : : return err;
1238 : :
1239 : 0 : down_write(&card->controls_rwsem);
1240 : 0 : card->user_ctl_count++;
1241 : 0 : up_write(&card->controls_rwsem);
1242 : :
1243 : 0 : return 0;
1244 : : }
1245 : :
1246 : 0 : static int snd_ctl_elem_add_user(struct snd_ctl_file *file,
1247 : : struct snd_ctl_elem_info __user *_info, int replace)
1248 : : {
1249 : : struct snd_ctl_elem_info info;
1250 [ # # ]: 0 : if (copy_from_user(&info, _info, sizeof(info)))
1251 : : return -EFAULT;
1252 : 0 : return snd_ctl_elem_add(file, &info, replace);
1253 : : }
1254 : :
1255 : 0 : static int snd_ctl_elem_remove(struct snd_ctl_file *file,
1256 : : struct snd_ctl_elem_id __user *_id)
1257 : : {
1258 : : struct snd_ctl_elem_id id;
1259 : :
1260 [ # # ]: 0 : if (copy_from_user(&id, _id, sizeof(id)))
1261 : : return -EFAULT;
1262 : 0 : return snd_ctl_remove_user_ctl(file, &id);
1263 : : }
1264 : :
1265 : 0 : static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr)
1266 : : {
1267 : : int subscribe;
1268 [ # # ]: 0 : if (get_user(subscribe, ptr))
1269 : : return -EFAULT;
1270 [ # # ]: 0 : if (subscribe < 0) {
1271 : 0 : subscribe = file->subscribed;
1272 [ # # ]: 0 : if (put_user(subscribe, ptr))
1273 : : return -EFAULT;
1274 : 0 : return 0;
1275 : : }
1276 [ # # ]: 0 : if (subscribe) {
1277 : 0 : file->subscribed = 1;
1278 : 0 : return 0;
1279 [ # # ]: 0 : } else if (file->subscribed) {
1280 : 0 : snd_ctl_empty_read_queue(file);
1281 : 0 : file->subscribed = 0;
1282 : : }
1283 : : return 0;
1284 : : }
1285 : :
1286 : 0 : static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
1287 : : struct snd_ctl_tlv __user *_tlv,
1288 : : int op_flag)
1289 : : {
1290 : 0 : struct snd_card *card = file->card;
1291 : : struct snd_ctl_tlv tlv;
1292 : : struct snd_kcontrol *kctl;
1293 : : struct snd_kcontrol_volatile *vd;
1294 : : unsigned int len;
1295 : : int err = 0;
1296 : :
1297 [ # # ]: 0 : if (copy_from_user(&tlv, _tlv, sizeof(tlv)))
1298 : : return -EFAULT;
1299 [ # # ]: 0 : if (tlv.length < sizeof(unsigned int) * 2)
1300 : : return -EINVAL;
1301 : 0 : down_read(&card->controls_rwsem);
1302 : 0 : kctl = snd_ctl_find_numid(card, tlv.numid);
1303 [ # # ]: 0 : if (kctl == NULL) {
1304 : : err = -ENOENT;
1305 : : goto __kctl_end;
1306 : : }
1307 [ # # ]: 0 : if (kctl->tlv.p == NULL) {
1308 : : err = -ENXIO;
1309 : : goto __kctl_end;
1310 : : }
1311 : 0 : vd = &kctl->vd[tlv.numid - kctl->id.numid];
1312 [ # # ][ # # ]: 0 : if ((op_flag == 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) == 0) ||
[ # # ]
1313 [ # # ][ # # ]: 0 : (op_flag > 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_WRITE) == 0) ||
1314 [ # # ]: 0 : (op_flag < 0 && (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND) == 0)) {
1315 : : err = -ENXIO;
1316 : : goto __kctl_end;
1317 : : }
1318 [ # # ]: 0 : if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
1319 [ # # ][ # # ]: 0 : if (vd->owner != NULL && vd->owner != file) {
1320 : : err = -EPERM;
1321 : : goto __kctl_end;
1322 : : }
1323 : 0 : err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
1324 [ # # ]: 0 : if (err > 0) {
1325 : 0 : up_read(&card->controls_rwsem);
1326 : 0 : snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
1327 : 0 : return 0;
1328 : : }
1329 : : } else {
1330 [ # # ]: 0 : if (op_flag) {
1331 : : err = -ENXIO;
1332 : : goto __kctl_end;
1333 : : }
1334 : 0 : len = kctl->tlv.p[1] + 2 * sizeof(unsigned int);
1335 [ # # ]: 0 : if (tlv.length < len) {
1336 : : err = -ENOMEM;
1337 : : goto __kctl_end;
1338 : : }
1339 [ # # ]: 0 : if (copy_to_user(_tlv->tlv, kctl->tlv.p, len))
1340 : : err = -EFAULT;
1341 : : }
1342 : : __kctl_end:
1343 : 0 : up_read(&card->controls_rwsem);
1344 : 0 : return err;
1345 : : }
1346 : :
1347 : 0 : static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1348 : : {
1349 : : struct snd_ctl_file *ctl;
1350 : : struct snd_card *card;
1351 : : struct snd_kctl_ioctl *p;
1352 : 0 : void __user *argp = (void __user *)arg;
1353 : : int __user *ip = argp;
1354 : : int err;
1355 : :
1356 : 0 : ctl = file->private_data;
1357 : 0 : card = ctl->card;
1358 [ # # ]: 0 : if (snd_BUG_ON(!card))
1359 : : return -ENXIO;
1360 [ # # # # : 0 : switch (cmd) {
# # # # #
# # # # #
# # # # ]
1361 : : case SNDRV_CTL_IOCTL_PVERSION:
1362 [ # # ]: 0 : return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
1363 : : case SNDRV_CTL_IOCTL_CARD_INFO:
1364 : 0 : return snd_ctl_card_info(card, ctl, cmd, argp);
1365 : : case SNDRV_CTL_IOCTL_ELEM_LIST:
1366 : 0 : return snd_ctl_elem_list(card, argp);
1367 : : case SNDRV_CTL_IOCTL_ELEM_INFO:
1368 : 0 : return snd_ctl_elem_info_user(ctl, argp);
1369 : : case SNDRV_CTL_IOCTL_ELEM_READ:
1370 : 0 : return snd_ctl_elem_read_user(card, argp);
1371 : : case SNDRV_CTL_IOCTL_ELEM_WRITE:
1372 : 0 : return snd_ctl_elem_write_user(ctl, argp);
1373 : : case SNDRV_CTL_IOCTL_ELEM_LOCK:
1374 : 0 : return snd_ctl_elem_lock(ctl, argp);
1375 : : case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
1376 : 0 : return snd_ctl_elem_unlock(ctl, argp);
1377 : : case SNDRV_CTL_IOCTL_ELEM_ADD:
1378 : 0 : return snd_ctl_elem_add_user(ctl, argp, 0);
1379 : : case SNDRV_CTL_IOCTL_ELEM_REPLACE:
1380 : 0 : return snd_ctl_elem_add_user(ctl, argp, 1);
1381 : : case SNDRV_CTL_IOCTL_ELEM_REMOVE:
1382 : 0 : return snd_ctl_elem_remove(ctl, argp);
1383 : : case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
1384 : 0 : return snd_ctl_subscribe_events(ctl, ip);
1385 : : case SNDRV_CTL_IOCTL_TLV_READ:
1386 : 0 : return snd_ctl_tlv_ioctl(ctl, argp, 0);
1387 : : case SNDRV_CTL_IOCTL_TLV_WRITE:
1388 : 0 : return snd_ctl_tlv_ioctl(ctl, argp, 1);
1389 : : case SNDRV_CTL_IOCTL_TLV_COMMAND:
1390 : 0 : return snd_ctl_tlv_ioctl(ctl, argp, -1);
1391 : : case SNDRV_CTL_IOCTL_POWER:
1392 : : return -ENOPROTOOPT;
1393 : : case SNDRV_CTL_IOCTL_POWER_STATE:
1394 : : #ifdef CONFIG_PM
1395 [ # # ]: 0 : return put_user(card->power_state, ip) ? -EFAULT : 0;
1396 : : #else
1397 : : return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
1398 : : #endif
1399 : : }
1400 : 0 : down_read(&snd_ioctl_rwsem);
1401 [ # # ]: 0 : list_for_each_entry(p, &snd_control_ioctls, list) {
1402 : 0 : err = p->fioctl(card, ctl, cmd, arg);
1403 [ # # ]: 0 : if (err != -ENOIOCTLCMD) {
1404 : 0 : up_read(&snd_ioctl_rwsem);
1405 : 0 : return err;
1406 : : }
1407 : : }
1408 : 0 : up_read(&snd_ioctl_rwsem);
1409 : : snd_printdd("unknown ioctl = 0x%x\n", cmd);
1410 : 0 : return -ENOTTY;
1411 : : }
1412 : :
1413 : 0 : static ssize_t snd_ctl_read(struct file *file, char __user *buffer,
1414 : : size_t count, loff_t * offset)
1415 : : {
1416 : : struct snd_ctl_file *ctl;
1417 : : int err = 0;
1418 : : ssize_t result = 0;
1419 : :
1420 : 0 : ctl = file->private_data;
1421 [ # # ][ # # ]: 0 : if (snd_BUG_ON(!ctl || !ctl->card))
[ # # ]
1422 : : return -ENXIO;
1423 [ # # ]: 0 : if (!ctl->subscribed)
1424 : : return -EBADFD;
1425 [ # # ]: 0 : if (count < sizeof(struct snd_ctl_event))
1426 : : return -EINVAL;
1427 : : spin_lock_irq(&ctl->read_lock);
1428 [ # # ]: 0 : while (count >= sizeof(struct snd_ctl_event)) {
1429 : : struct snd_ctl_event ev;
1430 : : struct snd_kctl_event *kev;
1431 [ # # ]: 0 : while (list_empty(&ctl->events)) {
1432 : : wait_queue_t wait;
1433 [ # # ][ # # ]: 0 : if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
1434 : : err = -EAGAIN;
1435 : 0 : goto __end_lock;
1436 : : }
1437 : 0 : init_waitqueue_entry(&wait, current);
1438 : 0 : add_wait_queue(&ctl->change_sleep, &wait);
1439 : 0 : set_current_state(TASK_INTERRUPTIBLE);
1440 : : spin_unlock_irq(&ctl->read_lock);
1441 : 0 : schedule();
1442 : 0 : remove_wait_queue(&ctl->change_sleep, &wait);
1443 [ # # ]: 0 : if (ctl->card->shutdown)
1444 : 0 : return -ENODEV;
1445 [ # # ]: 0 : if (signal_pending(current))
1446 : : return -ERESTARTSYS;
1447 : : spin_lock_irq(&ctl->read_lock);
1448 : : }
1449 : : kev = snd_kctl_event(ctl->events.next);
1450 : 0 : ev.type = SNDRV_CTL_EVENT_ELEM;
1451 : 0 : ev.data.elem.mask = kev->mask;
1452 : 0 : ev.data.elem.id = kev->id;
1453 : : list_del(&kev->list);
1454 : : spin_unlock_irq(&ctl->read_lock);
1455 : 0 : kfree(kev);
1456 [ # # ]: 0 : if (copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event))) {
1457 : : err = -EFAULT;
1458 : 0 : goto __end;
1459 : : }
1460 : : spin_lock_irq(&ctl->read_lock);
1461 : 0 : buffer += sizeof(struct snd_ctl_event);
1462 : 0 : count -= sizeof(struct snd_ctl_event);
1463 : 0 : result += sizeof(struct snd_ctl_event);
1464 : : }
1465 : : __end_lock:
1466 : : spin_unlock_irq(&ctl->read_lock);
1467 : : __end:
1468 [ # # ]: 0 : return result > 0 ? result : err;
1469 : : }
1470 : :
1471 : 0 : static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
1472 : : {
1473 : : unsigned int mask;
1474 : : struct snd_ctl_file *ctl;
1475 : :
1476 : 0 : ctl = file->private_data;
1477 [ # # ]: 0 : if (!ctl->subscribed)
1478 : : return 0;
1479 : 0 : poll_wait(file, &ctl->change_sleep, wait);
1480 : :
1481 : : mask = 0;
1482 [ # # ]: 0 : if (!list_empty(&ctl->events))
1483 : : mask |= POLLIN | POLLRDNORM;
1484 : :
1485 : 0 : return mask;
1486 : : }
1487 : :
1488 : : /*
1489 : : * register the device-specific control-ioctls.
1490 : : * called from each device manager like pcm.c, hwdep.c, etc.
1491 : : */
1492 : 0 : static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *lists)
1493 : : {
1494 : : struct snd_kctl_ioctl *pn;
1495 : :
1496 : : pn = kzalloc(sizeof(struct snd_kctl_ioctl), GFP_KERNEL);
1497 [ # # ]: 0 : if (pn == NULL)
1498 : : return -ENOMEM;
1499 : 0 : pn->fioctl = fcn;
1500 : 0 : down_write(&snd_ioctl_rwsem);
1501 : 0 : list_add_tail(&pn->list, lists);
1502 : 0 : up_write(&snd_ioctl_rwsem);
1503 : 0 : return 0;
1504 : : }
1505 : :
1506 : 0 : int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
1507 : : {
1508 : 0 : return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
1509 : : }
1510 : :
1511 : : EXPORT_SYMBOL(snd_ctl_register_ioctl);
1512 : :
1513 : : #ifdef CONFIG_COMPAT
1514 : : int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1515 : : {
1516 : : return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
1517 : : }
1518 : :
1519 : : EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
1520 : : #endif
1521 : :
1522 : : /*
1523 : : * de-register the device-specific control-ioctls.
1524 : : */
1525 : 0 : static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
1526 : : struct list_head *lists)
1527 : : {
1528 : : struct snd_kctl_ioctl *p;
1529 : :
1530 [ # # ]: 0 : if (snd_BUG_ON(!fcn))
1531 : : return -EINVAL;
1532 : 0 : down_write(&snd_ioctl_rwsem);
1533 [ # # ]: 0 : list_for_each_entry(p, lists, list) {
1534 [ # # ]: 0 : if (p->fioctl == fcn) {
1535 : : list_del(&p->list);
1536 : 0 : up_write(&snd_ioctl_rwsem);
1537 : 0 : kfree(p);
1538 : 0 : return 0;
1539 : : }
1540 : : }
1541 : 0 : up_write(&snd_ioctl_rwsem);
1542 : : snd_BUG();
1543 : 0 : return -EINVAL;
1544 : : }
1545 : :
1546 : 0 : int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
1547 : : {
1548 : 0 : return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
1549 : : }
1550 : :
1551 : : EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
1552 : :
1553 : : #ifdef CONFIG_COMPAT
1554 : : int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
1555 : : {
1556 : : return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
1557 : : }
1558 : :
1559 : : EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
1560 : : #endif
1561 : :
1562 : 0 : static int snd_ctl_fasync(int fd, struct file * file, int on)
1563 : : {
1564 : : struct snd_ctl_file *ctl;
1565 : :
1566 : 0 : ctl = file->private_data;
1567 : 0 : return fasync_helper(fd, file, on, &ctl->fasync);
1568 : : }
1569 : :
1570 : : /*
1571 : : * ioctl32 compat
1572 : : */
1573 : : #ifdef CONFIG_COMPAT
1574 : : #include "control_compat.c"
1575 : : #else
1576 : : #define snd_ctl_ioctl_compat NULL
1577 : : #endif
1578 : :
1579 : : /*
1580 : : * INIT PART
1581 : : */
1582 : :
1583 : : static const struct file_operations snd_ctl_f_ops =
1584 : : {
1585 : : .owner = THIS_MODULE,
1586 : : .read = snd_ctl_read,
1587 : : .open = snd_ctl_open,
1588 : : .release = snd_ctl_release,
1589 : : .llseek = no_llseek,
1590 : : .poll = snd_ctl_poll,
1591 : : .unlocked_ioctl = snd_ctl_ioctl,
1592 : : .compat_ioctl = snd_ctl_ioctl_compat,
1593 : : .fasync = snd_ctl_fasync,
1594 : : };
1595 : :
1596 : : /*
1597 : : * registration of the control device
1598 : : */
1599 : 0 : static int snd_ctl_dev_register(struct snd_device *device)
1600 : : {
1601 : 0 : struct snd_card *card = device->device_data;
1602 : : int err, cardnum;
1603 : : char name[16];
1604 : :
1605 [ # # ]: 0 : if (snd_BUG_ON(!card))
1606 : : return -ENXIO;
1607 : 0 : cardnum = card->number;
1608 [ # # ]: 0 : if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
1609 : : return -ENXIO;
1610 : 0 : sprintf(name, "controlC%i", cardnum);
1611 [ # # ]: 0 : if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
1612 : : &snd_ctl_f_ops, card, name)) < 0)
1613 : 0 : return err;
1614 : : return 0;
1615 : : }
1616 : :
1617 : : /*
1618 : : * disconnection of the control device
1619 : : */
1620 : 0 : static int snd_ctl_dev_disconnect(struct snd_device *device)
1621 : : {
1622 : 0 : struct snd_card *card = device->device_data;
1623 : : struct snd_ctl_file *ctl;
1624 : : int err, cardnum;
1625 : :
1626 [ # # ]: 0 : if (snd_BUG_ON(!card))
1627 : : return -ENXIO;
1628 : 0 : cardnum = card->number;
1629 [ # # ]: 0 : if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
1630 : : return -ENXIO;
1631 : :
1632 : 0 : read_lock(&card->ctl_files_rwlock);
1633 [ # # ]: 0 : list_for_each_entry(ctl, &card->ctl_files, list) {
1634 : 0 : wake_up(&ctl->change_sleep);
1635 : 0 : kill_fasync(&ctl->fasync, SIGIO, POLL_ERR);
1636 : : }
1637 : : read_unlock(&card->ctl_files_rwlock);
1638 : :
1639 [ # # ]: 0 : if ((err = snd_unregister_device(SNDRV_DEVICE_TYPE_CONTROL,
1640 : : card, -1)) < 0)
1641 : 0 : return err;
1642 : : return 0;
1643 : : }
1644 : :
1645 : : /*
1646 : : * free all controls
1647 : : */
1648 : 0 : static int snd_ctl_dev_free(struct snd_device *device)
1649 : : {
1650 : 0 : struct snd_card *card = device->device_data;
1651 : : struct snd_kcontrol *control;
1652 : :
1653 : 0 : down_write(&card->controls_rwsem);
1654 [ # # ]: 0 : while (!list_empty(&card->controls)) {
1655 : : control = snd_kcontrol(card->controls.next);
1656 : 0 : snd_ctl_remove(card, control);
1657 : : }
1658 : 0 : up_write(&card->controls_rwsem);
1659 : 0 : return 0;
1660 : : }
1661 : :
1662 : : /*
1663 : : * create control core:
1664 : : * called from init.c
1665 : : */
1666 : 0 : int snd_ctl_create(struct snd_card *card)
1667 : : {
1668 : : static struct snd_device_ops ops = {
1669 : : .dev_free = snd_ctl_dev_free,
1670 : : .dev_register = snd_ctl_dev_register,
1671 : : .dev_disconnect = snd_ctl_dev_disconnect,
1672 : : };
1673 : :
1674 [ # # ]: 0 : if (snd_BUG_ON(!card))
1675 : : return -ENXIO;
1676 : 0 : return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);
1677 : : }
1678 : :
1679 : : /*
1680 : : * Frequently used control callbacks/helpers
1681 : : */
1682 : 0 : int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
1683 : : struct snd_ctl_elem_info *uinfo)
1684 : : {
1685 : 0 : uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1686 : 0 : uinfo->count = 1;
1687 : 0 : uinfo->value.integer.min = 0;
1688 : 0 : uinfo->value.integer.max = 1;
1689 : 0 : return 0;
1690 : : }
1691 : :
1692 : : EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
1693 : :
1694 : 0 : int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
1695 : : struct snd_ctl_elem_info *uinfo)
1696 : : {
1697 : 0 : uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
1698 : 0 : uinfo->count = 2;
1699 : 0 : uinfo->value.integer.min = 0;
1700 : 0 : uinfo->value.integer.max = 1;
1701 : 0 : return 0;
1702 : : }
1703 : :
1704 : : EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
1705 : :
1706 : : /**
1707 : : * snd_ctl_enum_info - fills the info structure for an enumerated control
1708 : : * @info: the structure to be filled
1709 : : * @channels: the number of the control's channels; often one
1710 : : * @items: the number of control values; also the size of @names
1711 : : * @names: an array containing the names of all control values
1712 : : *
1713 : : * Sets all required fields in @info to their appropriate values.
1714 : : * If the control's accessibility is not the default (readable and writable),
1715 : : * the caller has to fill @info->access.
1716 : : *
1717 : : * Return: Zero.
1718 : : */
1719 : 0 : int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
1720 : : unsigned int items, const char *const names[])
1721 : : {
1722 : 0 : info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1723 : 0 : info->count = channels;
1724 : 0 : info->value.enumerated.items = items;
1725 [ # # ]: 0 : if (info->value.enumerated.item >= items)
1726 : 0 : info->value.enumerated.item = items - 1;
1727 : 0 : strlcpy(info->value.enumerated.name,
1728 : 0 : names[info->value.enumerated.item],
1729 : : sizeof(info->value.enumerated.name));
1730 : 0 : return 0;
1731 : : }
1732 : : EXPORT_SYMBOL(snd_ctl_enum_info);
|