diff options
Diffstat (limited to 'sound/core/hwdep.c')
-rw-r--r-- | sound/core/hwdep.c | 91 |
1 files changed, 42 insertions, 49 deletions
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index 27d5bf7266f0..b8c0c8c4d126 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c | |||
@@ -35,8 +35,7 @@ MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); | |||
35 | MODULE_DESCRIPTION("Hardware dependent layer"); | 35 | MODULE_DESCRIPTION("Hardware dependent layer"); |
36 | MODULE_LICENSE("GPL"); | 36 | MODULE_LICENSE("GPL"); |
37 | 37 | ||
38 | static struct snd_hwdep *snd_hwdep_devices[SNDRV_CARDS * SNDRV_MINOR_HWDEPS]; | 38 | static LIST_HEAD(snd_hwdep_devices); |
39 | |||
40 | static DECLARE_MUTEX(register_mutex); | 39 | static DECLARE_MUTEX(register_mutex); |
41 | 40 | ||
42 | static int snd_hwdep_free(struct snd_hwdep *hwdep); | 41 | static int snd_hwdep_free(struct snd_hwdep *hwdep); |
@@ -44,9 +43,19 @@ static int snd_hwdep_dev_free(struct snd_device *device); | |||
44 | static int snd_hwdep_dev_register(struct snd_device *device); | 43 | static int snd_hwdep_dev_register(struct snd_device *device); |
45 | static int snd_hwdep_dev_unregister(struct snd_device *device); | 44 | static int snd_hwdep_dev_unregister(struct snd_device *device); |
46 | 45 | ||
47 | /* | ||
48 | 46 | ||
49 | */ | 47 | static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device) |
48 | { | ||
49 | struct list_head *p; | ||
50 | struct snd_hwdep *hwdep; | ||
51 | |||
52 | list_for_each(p, &snd_hwdep_devices) { | ||
53 | hwdep = list_entry(p, struct snd_hwdep, list); | ||
54 | if (hwdep->card == card && hwdep->device == device) | ||
55 | return hwdep; | ||
56 | } | ||
57 | return NULL; | ||
58 | } | ||
50 | 59 | ||
51 | static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig) | 60 | static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig) |
52 | { | 61 | { |
@@ -77,34 +86,25 @@ static ssize_t snd_hwdep_write(struct file * file, const char __user *buf, | |||
77 | static int snd_hwdep_open(struct inode *inode, struct file * file) | 86 | static int snd_hwdep_open(struct inode *inode, struct file * file) |
78 | { | 87 | { |
79 | int major = imajor(inode); | 88 | int major = imajor(inode); |
80 | int cardnum; | ||
81 | int device; | ||
82 | struct snd_hwdep *hw; | 89 | struct snd_hwdep *hw; |
83 | int err; | 90 | int err; |
84 | wait_queue_t wait; | 91 | wait_queue_t wait; |
85 | 92 | ||
86 | if (major == snd_major) { | 93 | if (major == snd_major) { |
87 | cardnum = SNDRV_MINOR_CARD(iminor(inode)); | 94 | hw = snd_lookup_minor_data(iminor(inode), |
88 | device = SNDRV_MINOR_DEVICE(iminor(inode)) - SNDRV_MINOR_HWDEP; | 95 | SNDRV_DEVICE_TYPE_HWDEP); |
89 | #ifdef CONFIG_SND_OSSEMUL | 96 | #ifdef CONFIG_SND_OSSEMUL |
90 | } else if (major == SOUND_MAJOR) { | 97 | } else if (major == SOUND_MAJOR) { |
91 | cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode)); | 98 | hw = snd_lookup_oss_minor_data(iminor(inode), |
92 | device = 0; | 99 | SNDRV_OSS_DEVICE_TYPE_DMFM); |
93 | #endif | 100 | #endif |
94 | } else | 101 | } else |
95 | return -ENXIO; | 102 | return -ENXIO; |
96 | cardnum %= SNDRV_CARDS; | ||
97 | device %= SNDRV_MINOR_HWDEPS; | ||
98 | hw = snd_hwdep_devices[(cardnum * SNDRV_MINOR_HWDEPS) + device]; | ||
99 | if (hw == NULL) | 103 | if (hw == NULL) |
100 | return -ENODEV; | 104 | return -ENODEV; |
101 | 105 | ||
102 | if (!hw->ops.open) | 106 | if (!hw->ops.open) |
103 | return -ENXIO; | 107 | return -ENXIO; |
104 | #ifdef CONFIG_SND_OSSEMUL | ||
105 | if (major == SOUND_MAJOR && hw->oss_type < 0) | ||
106 | return -ENXIO; | ||
107 | #endif | ||
108 | 108 | ||
109 | if (!try_module_get(hw->card->module)) | 109 | if (!try_module_get(hw->card->module)) |
110 | return -EFAULT; | 110 | return -EFAULT; |
@@ -265,9 +265,6 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, | |||
265 | struct snd_ctl_file * control, | 265 | struct snd_ctl_file * control, |
266 | unsigned int cmd, unsigned long arg) | 266 | unsigned int cmd, unsigned long arg) |
267 | { | 267 | { |
268 | unsigned int tmp; | ||
269 | |||
270 | tmp = card->number * SNDRV_MINOR_HWDEPS; | ||
271 | switch (cmd) { | 268 | switch (cmd) { |
272 | case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: | 269 | case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE: |
273 | { | 270 | { |
@@ -275,14 +272,16 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, | |||
275 | 272 | ||
276 | if (get_user(device, (int __user *)arg)) | 273 | if (get_user(device, (int __user *)arg)) |
277 | return -EFAULT; | 274 | return -EFAULT; |
275 | down(®ister_mutex); | ||
278 | device = device < 0 ? 0 : device + 1; | 276 | device = device < 0 ? 0 : device + 1; |
279 | while (device < SNDRV_MINOR_HWDEPS) { | 277 | while (device < SNDRV_MINOR_HWDEPS) { |
280 | if (snd_hwdep_devices[tmp + device]) | 278 | if (snd_hwdep_search(card, device)) |
281 | break; | 279 | break; |
282 | device++; | 280 | device++; |
283 | } | 281 | } |
284 | if (device >= SNDRV_MINOR_HWDEPS) | 282 | if (device >= SNDRV_MINOR_HWDEPS) |
285 | device = -1; | 283 | device = -1; |
284 | up(®ister_mutex); | ||
286 | if (put_user(device, (int __user *)arg)) | 285 | if (put_user(device, (int __user *)arg)) |
287 | return -EFAULT; | 286 | return -EFAULT; |
288 | return 0; | 287 | return 0; |
@@ -290,17 +289,19 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, | |||
290 | case SNDRV_CTL_IOCTL_HWDEP_INFO: | 289 | case SNDRV_CTL_IOCTL_HWDEP_INFO: |
291 | { | 290 | { |
292 | struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg; | 291 | struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg; |
293 | int device; | 292 | int device, err; |
294 | struct snd_hwdep *hwdep; | 293 | struct snd_hwdep *hwdep; |
295 | 294 | ||
296 | if (get_user(device, &info->device)) | 295 | if (get_user(device, &info->device)) |
297 | return -EFAULT; | 296 | return -EFAULT; |
298 | if (device < 0 || device >= SNDRV_MINOR_HWDEPS) | 297 | down(®ister_mutex); |
299 | return -ENXIO; | 298 | hwdep = snd_hwdep_search(card, device); |
300 | hwdep = snd_hwdep_devices[tmp + device]; | 299 | if (hwdep) |
301 | if (hwdep == NULL) | 300 | err = snd_hwdep_info(hwdep, info); |
302 | return -ENXIO; | 301 | else |
303 | return snd_hwdep_info(hwdep, info); | 302 | err = -ENXIO; |
303 | up(®ister_mutex); | ||
304 | return err; | ||
304 | } | 305 | } |
305 | } | 306 | } |
306 | return -ENOIOCTLCMD; | 307 | return -ENOIOCTLCMD; |
@@ -397,23 +398,22 @@ static int snd_hwdep_dev_free(struct snd_device *device) | |||
397 | static int snd_hwdep_dev_register(struct snd_device *device) | 398 | static int snd_hwdep_dev_register(struct snd_device *device) |
398 | { | 399 | { |
399 | struct snd_hwdep *hwdep = device->device_data; | 400 | struct snd_hwdep *hwdep = device->device_data; |
400 | int idx, err; | 401 | int err; |
401 | char name[32]; | 402 | char name[32]; |
402 | 403 | ||
403 | down(®ister_mutex); | 404 | down(®ister_mutex); |
404 | idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device; | 405 | if (snd_hwdep_search(hwdep->card, hwdep->device)) { |
405 | if (snd_hwdep_devices[idx]) { | ||
406 | up(®ister_mutex); | 406 | up(®ister_mutex); |
407 | return -EBUSY; | 407 | return -EBUSY; |
408 | } | 408 | } |
409 | snd_hwdep_devices[idx] = hwdep; | 409 | list_add_tail(&hwdep->list, &snd_hwdep_devices); |
410 | sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device); | 410 | sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device); |
411 | if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, | 411 | if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, |
412 | hwdep->card, hwdep->device, | 412 | hwdep->card, hwdep->device, |
413 | &snd_hwdep_f_ops, name)) < 0) { | 413 | &snd_hwdep_f_ops, hwdep, name)) < 0) { |
414 | snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n", | 414 | snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n", |
415 | hwdep->card->number, hwdep->device); | 415 | hwdep->card->number, hwdep->device); |
416 | snd_hwdep_devices[idx] = NULL; | 416 | list_del(&hwdep->list); |
417 | up(®ister_mutex); | 417 | up(®ister_mutex); |
418 | return err; | 418 | return err; |
419 | } | 419 | } |
@@ -425,7 +425,7 @@ static int snd_hwdep_dev_register(struct snd_device *device) | |||
425 | } else { | 425 | } else { |
426 | if (snd_register_oss_device(hwdep->oss_type, | 426 | if (snd_register_oss_device(hwdep->oss_type, |
427 | hwdep->card, hwdep->device, | 427 | hwdep->card, hwdep->device, |
428 | &snd_hwdep_f_ops, | 428 | &snd_hwdep_f_ops, hwdep, |
429 | hwdep->oss_dev) < 0) { | 429 | hwdep->oss_dev) < 0) { |
430 | snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n", | 430 | snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n", |
431 | hwdep->card->number, hwdep->device); | 431 | hwdep->card->number, hwdep->device); |
@@ -441,12 +441,10 @@ static int snd_hwdep_dev_register(struct snd_device *device) | |||
441 | static int snd_hwdep_dev_unregister(struct snd_device *device) | 441 | static int snd_hwdep_dev_unregister(struct snd_device *device) |
442 | { | 442 | { |
443 | struct snd_hwdep *hwdep = device->device_data; | 443 | struct snd_hwdep *hwdep = device->device_data; |
444 | int idx; | ||
445 | 444 | ||
446 | snd_assert(hwdep != NULL, return -ENXIO); | 445 | snd_assert(hwdep != NULL, return -ENXIO); |
447 | down(®ister_mutex); | 446 | down(®ister_mutex); |
448 | idx = (hwdep->card->number * SNDRV_MINOR_HWDEPS) + hwdep->device; | 447 | if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) { |
449 | if (snd_hwdep_devices[idx] != hwdep) { | ||
450 | up(®ister_mutex); | 448 | up(®ister_mutex); |
451 | return -EINVAL; | 449 | return -EINVAL; |
452 | } | 450 | } |
@@ -455,7 +453,7 @@ static int snd_hwdep_dev_unregister(struct snd_device *device) | |||
455 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); | 453 | snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); |
456 | #endif | 454 | #endif |
457 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); | 455 | snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); |
458 | snd_hwdep_devices[idx] = NULL; | 456 | list_del(&hwdep->list); |
459 | up(®ister_mutex); | 457 | up(®ister_mutex); |
460 | return snd_hwdep_free(hwdep); | 458 | return snd_hwdep_free(hwdep); |
461 | } | 459 | } |
@@ -467,18 +465,14 @@ static int snd_hwdep_dev_unregister(struct snd_device *device) | |||
467 | static void snd_hwdep_proc_read(struct snd_info_entry *entry, | 465 | static void snd_hwdep_proc_read(struct snd_info_entry *entry, |
468 | struct snd_info_buffer *buffer) | 466 | struct snd_info_buffer *buffer) |
469 | { | 467 | { |
470 | int idx; | 468 | struct list_head *p; |
471 | struct snd_hwdep *hwdep; | 469 | struct snd_hwdep *hwdep; |
472 | 470 | ||
473 | down(®ister_mutex); | 471 | down(®ister_mutex); |
474 | for (idx = 0; idx < SNDRV_CARDS * SNDRV_MINOR_HWDEPS; idx++) { | 472 | list_for_each(p, &snd_hwdep_devices) { |
475 | hwdep = snd_hwdep_devices[idx]; | 473 | hwdep = list_entry(p, struct snd_hwdep, list); |
476 | if (hwdep == NULL) | ||
477 | continue; | ||
478 | snd_iprintf(buffer, "%02i-%02i: %s\n", | 474 | snd_iprintf(buffer, "%02i-%02i: %s\n", |
479 | idx / SNDRV_MINOR_HWDEPS, | 475 | hwdep->card->number, hwdep->device, hwdep->name); |
480 | idx % SNDRV_MINOR_HWDEPS, | ||
481 | hwdep->name); | ||
482 | } | 476 | } |
483 | up(®ister_mutex); | 477 | up(®ister_mutex); |
484 | } | 478 | } |
@@ -493,9 +487,8 @@ static int __init alsa_hwdep_init(void) | |||
493 | { | 487 | { |
494 | struct snd_info_entry *entry; | 488 | struct snd_info_entry *entry; |
495 | 489 | ||
496 | memset(snd_hwdep_devices, 0, sizeof(snd_hwdep_devices)); | ||
497 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { | 490 | if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { |
498 | entry->c.text.read_size = 512; | 491 | entry->c.text.read_size = PAGE_SIZE; |
499 | entry->c.text.read = snd_hwdep_proc_read; | 492 | entry->c.text.read = snd_hwdep_proc_read; |
500 | if (snd_info_register(entry) < 0) { | 493 | if (snd_info_register(entry) < 0) { |
501 | snd_info_free_entry(entry); | 494 | snd_info_free_entry(entry); |