2 * Hardware dependent layer
3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
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.
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.
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
22 #include <linux/major.h>
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <linux/time.h>
26 #include <linux/mutex.h>
27 #include <linux/module.h>
28 #include <sound/core.h>
29 #include <sound/control.h>
30 #include <sound/minors.h>
31 #include <sound/hwdep.h>
32 #include <sound/info.h>
34 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
35 MODULE_DESCRIPTION("Hardware dependent layer");
36 MODULE_LICENSE("GPL");
38 static LIST_HEAD(snd_hwdep_devices
);
39 static DEFINE_MUTEX(register_mutex
);
41 static int snd_hwdep_dev_free(struct snd_device
*device
);
42 static int snd_hwdep_dev_register(struct snd_device
*device
);
43 static int snd_hwdep_dev_disconnect(struct snd_device
*device
);
46 static struct snd_hwdep
*snd_hwdep_search(struct snd_card
*card
, int device
)
48 struct snd_hwdep
*hwdep
;
50 list_for_each_entry(hwdep
, &snd_hwdep_devices
, list
)
51 if (hwdep
->card
== card
&& hwdep
->device
== device
)
56 static loff_t
snd_hwdep_llseek(struct file
* file
, loff_t offset
, int orig
)
58 struct snd_hwdep
*hw
= file
->private_data
;
60 return hw
->ops
.llseek(hw
, file
, offset
, orig
);
64 static ssize_t
snd_hwdep_read(struct file
* file
, char __user
*buf
,
65 size_t count
, loff_t
*offset
)
67 struct snd_hwdep
*hw
= file
->private_data
;
69 return hw
->ops
.read(hw
, buf
, count
, offset
);
73 static ssize_t
snd_hwdep_write(struct file
* file
, const char __user
*buf
,
74 size_t count
, loff_t
*offset
)
76 struct snd_hwdep
*hw
= file
->private_data
;
78 return hw
->ops
.write(hw
, buf
, count
, offset
);
82 static int snd_hwdep_open(struct inode
*inode
, struct file
* file
)
84 int major
= imajor(inode
);
89 if (major
== snd_major
) {
90 hw
= snd_lookup_minor_data(iminor(inode
),
91 SNDRV_DEVICE_TYPE_HWDEP
);
92 #ifdef CONFIG_SND_OSSEMUL
93 } else if (major
== SOUND_MAJOR
) {
94 hw
= snd_lookup_oss_minor_data(iminor(inode
),
95 SNDRV_OSS_DEVICE_TYPE_DMFM
);
102 if (!try_module_get(hw
->card
->module
)) {
103 snd_card_unref(hw
->card
);
107 init_waitqueue_entry(&wait
, current
);
108 add_wait_queue(&hw
->open_wait
, &wait
);
109 mutex_lock(&hw
->open_mutex
);
111 if (hw
->exclusive
&& hw
->used
> 0) {
119 err
= hw
->ops
.open(hw
, file
);
122 if (err
== -EAGAIN
) {
123 if (file
->f_flags
& O_NONBLOCK
) {
129 set_current_state(TASK_INTERRUPTIBLE
);
130 mutex_unlock(&hw
->open_mutex
);
132 mutex_lock(&hw
->open_mutex
);
133 if (hw
->card
->shutdown
) {
137 if (signal_pending(current
)) {
142 remove_wait_queue(&hw
->open_wait
, &wait
);
144 err
= snd_card_file_add(hw
->card
, file
);
146 file
->private_data
= hw
;
150 hw
->ops
.release(hw
, file
);
153 mutex_unlock(&hw
->open_mutex
);
155 module_put(hw
->card
->module
);
156 snd_card_unref(hw
->card
);
160 static int snd_hwdep_release(struct inode
*inode
, struct file
* file
)
163 struct snd_hwdep
*hw
= file
->private_data
;
164 struct module
*mod
= hw
->card
->module
;
166 mutex_lock(&hw
->open_mutex
);
168 err
= hw
->ops
.release(hw
, file
);
171 mutex_unlock(&hw
->open_mutex
);
172 wake_up(&hw
->open_wait
);
174 snd_card_file_remove(hw
->card
, file
);
179 static unsigned int snd_hwdep_poll(struct file
* file
, poll_table
* wait
)
181 struct snd_hwdep
*hw
= file
->private_data
;
183 return hw
->ops
.poll(hw
, file
, wait
);
187 static int snd_hwdep_info(struct snd_hwdep
*hw
,
188 struct snd_hwdep_info __user
*_info
)
190 struct snd_hwdep_info info
;
192 memset(&info
, 0, sizeof(info
));
193 info
.card
= hw
->card
->number
;
194 strlcpy(info
.id
, hw
->id
, sizeof(info
.id
));
195 strlcpy(info
.name
, hw
->name
, sizeof(info
.name
));
196 info
.iface
= hw
->iface
;
197 if (copy_to_user(_info
, &info
, sizeof(info
)))
202 static int snd_hwdep_dsp_status(struct snd_hwdep
*hw
,
203 struct snd_hwdep_dsp_status __user
*_info
)
205 struct snd_hwdep_dsp_status info
;
208 if (! hw
->ops
.dsp_status
)
210 memset(&info
, 0, sizeof(info
));
211 info
.dsp_loaded
= hw
->dsp_loaded
;
212 if ((err
= hw
->ops
.dsp_status(hw
, &info
)) < 0)
214 if (copy_to_user(_info
, &info
, sizeof(info
)))
219 static int snd_hwdep_dsp_load(struct snd_hwdep
*hw
,
220 struct snd_hwdep_dsp_image __user
*_info
)
222 struct snd_hwdep_dsp_image info
;
225 if (! hw
->ops
.dsp_load
)
227 memset(&info
, 0, sizeof(info
));
228 if (copy_from_user(&info
, _info
, sizeof(info
)))
230 /* check whether the dsp was already loaded */
231 if (hw
->dsp_loaded
& (1 << info
.index
))
233 if (!access_ok(VERIFY_READ
, info
.image
, info
.length
))
235 err
= hw
->ops
.dsp_load(hw
, &info
);
238 hw
->dsp_loaded
|= (1 << info
.index
);
242 static long snd_hwdep_ioctl(struct file
* file
, unsigned int cmd
,
245 struct snd_hwdep
*hw
= file
->private_data
;
246 void __user
*argp
= (void __user
*)arg
;
248 case SNDRV_HWDEP_IOCTL_PVERSION
:
249 return put_user(SNDRV_HWDEP_VERSION
, (int __user
*)argp
);
250 case SNDRV_HWDEP_IOCTL_INFO
:
251 return snd_hwdep_info(hw
, argp
);
252 case SNDRV_HWDEP_IOCTL_DSP_STATUS
:
253 return snd_hwdep_dsp_status(hw
, argp
);
254 case SNDRV_HWDEP_IOCTL_DSP_LOAD
:
255 return snd_hwdep_dsp_load(hw
, argp
);
258 return hw
->ops
.ioctl(hw
, file
, cmd
, arg
);
262 static int snd_hwdep_mmap(struct file
* file
, struct vm_area_struct
* vma
)
264 struct snd_hwdep
*hw
= file
->private_data
;
266 return hw
->ops
.mmap(hw
, file
, vma
);
270 static int snd_hwdep_control_ioctl(struct snd_card
*card
,
271 struct snd_ctl_file
* control
,
272 unsigned int cmd
, unsigned long arg
)
275 case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE
:
279 if (get_user(device
, (int __user
*)arg
))
281 mutex_lock(®ister_mutex
);
285 else if (device
< SNDRV_MINOR_HWDEPS
)
288 device
= SNDRV_MINOR_HWDEPS
;
290 while (device
< SNDRV_MINOR_HWDEPS
) {
291 if (snd_hwdep_search(card
, device
))
295 if (device
>= SNDRV_MINOR_HWDEPS
)
297 mutex_unlock(®ister_mutex
);
298 if (put_user(device
, (int __user
*)arg
))
302 case SNDRV_CTL_IOCTL_HWDEP_INFO
:
304 struct snd_hwdep_info __user
*info
= (struct snd_hwdep_info __user
*)arg
;
306 struct snd_hwdep
*hwdep
;
308 if (get_user(device
, &info
->device
))
310 mutex_lock(®ister_mutex
);
311 hwdep
= snd_hwdep_search(card
, device
);
313 err
= snd_hwdep_info(hwdep
, info
);
316 mutex_unlock(®ister_mutex
);
324 #include "hwdep_compat.c"
326 #define snd_hwdep_ioctl_compat NULL
333 static const struct file_operations snd_hwdep_f_ops
=
335 .owner
= THIS_MODULE
,
336 .llseek
= snd_hwdep_llseek
,
337 .read
= snd_hwdep_read
,
338 .write
= snd_hwdep_write
,
339 .open
= snd_hwdep_open
,
340 .release
= snd_hwdep_release
,
341 .poll
= snd_hwdep_poll
,
342 .unlocked_ioctl
= snd_hwdep_ioctl
,
343 .compat_ioctl
= snd_hwdep_ioctl_compat
,
344 .mmap
= snd_hwdep_mmap
,
347 static void release_hwdep_device(struct device
*dev
)
349 kfree(container_of(dev
, struct snd_hwdep
, dev
));
353 * snd_hwdep_new - create a new hwdep instance
354 * @card: the card instance
356 * @device: the device index (zero-based)
357 * @rhwdep: the pointer to store the new hwdep instance
359 * Creates a new hwdep instance with the given index on the card.
360 * The callbacks (hwdep->ops) must be set on the returned instance
361 * after this call manually by the caller.
363 * Return: Zero if successful, or a negative error code on failure.
365 int snd_hwdep_new(struct snd_card
*card
, char *id
, int device
,
366 struct snd_hwdep
**rhwdep
)
368 struct snd_hwdep
*hwdep
;
370 static struct snd_device_ops ops
= {
371 .dev_free
= snd_hwdep_dev_free
,
372 .dev_register
= snd_hwdep_dev_register
,
373 .dev_disconnect
= snd_hwdep_dev_disconnect
,
376 if (snd_BUG_ON(!card
))
380 hwdep
= kzalloc(sizeof(*hwdep
), GFP_KERNEL
);
384 init_waitqueue_head(&hwdep
->open_wait
);
385 mutex_init(&hwdep
->open_mutex
);
387 hwdep
->device
= device
;
389 strlcpy(hwdep
->id
, id
, sizeof(hwdep
->id
));
391 snd_device_initialize(&hwdep
->dev
, card
);
392 hwdep
->dev
.release
= release_hwdep_device
;
393 dev_set_name(&hwdep
->dev
, "hwC%iD%i", card
->number
, device
);
394 #ifdef CONFIG_SND_OSSEMUL
395 hwdep
->oss_type
= -1;
398 err
= snd_device_new(card
, SNDRV_DEV_HWDEP
, hwdep
, &ops
);
400 put_device(&hwdep
->dev
);
408 EXPORT_SYMBOL(snd_hwdep_new
);
410 static int snd_hwdep_dev_free(struct snd_device
*device
)
412 struct snd_hwdep
*hwdep
= device
->device_data
;
415 if (hwdep
->private_free
)
416 hwdep
->private_free(hwdep
);
417 put_device(&hwdep
->dev
);
421 static int snd_hwdep_dev_register(struct snd_device
*device
)
423 struct snd_hwdep
*hwdep
= device
->device_data
;
424 struct snd_card
*card
= hwdep
->card
;
427 mutex_lock(®ister_mutex
);
428 if (snd_hwdep_search(card
, hwdep
->device
)) {
429 mutex_unlock(®ister_mutex
);
432 list_add_tail(&hwdep
->list
, &snd_hwdep_devices
);
433 err
= snd_register_device(SNDRV_DEVICE_TYPE_HWDEP
,
434 hwdep
->card
, hwdep
->device
,
435 &snd_hwdep_f_ops
, hwdep
, &hwdep
->dev
);
437 dev_err(&hwdep
->dev
, "unable to register\n");
438 list_del(&hwdep
->list
);
439 mutex_unlock(®ister_mutex
);
443 #ifdef CONFIG_SND_OSSEMUL
445 if (hwdep
->oss_type
>= 0) {
446 if (hwdep
->oss_type
== SNDRV_OSS_DEVICE_TYPE_DMFM
&&
448 dev_warn(&hwdep
->dev
,
449 "only hwdep device 0 can be registered as OSS direct FM device!\n");
450 else if (snd_register_oss_device(hwdep
->oss_type
,
452 &snd_hwdep_f_ops
, hwdep
) < 0)
453 dev_warn(&hwdep
->dev
,
454 "unable to register OSS compatibility device\n");
459 mutex_unlock(®ister_mutex
);
463 static int snd_hwdep_dev_disconnect(struct snd_device
*device
)
465 struct snd_hwdep
*hwdep
= device
->device_data
;
467 if (snd_BUG_ON(!hwdep
))
469 mutex_lock(®ister_mutex
);
470 if (snd_hwdep_search(hwdep
->card
, hwdep
->device
) != hwdep
) {
471 mutex_unlock(®ister_mutex
);
474 mutex_lock(&hwdep
->open_mutex
);
475 wake_up(&hwdep
->open_wait
);
476 #ifdef CONFIG_SND_OSSEMUL
478 snd_unregister_oss_device(hwdep
->oss_type
, hwdep
->card
, hwdep
->device
);
480 snd_unregister_device(&hwdep
->dev
);
481 list_del_init(&hwdep
->list
);
482 mutex_unlock(&hwdep
->open_mutex
);
483 mutex_unlock(®ister_mutex
);
487 #ifdef CONFIG_SND_PROC_FS
492 static void snd_hwdep_proc_read(struct snd_info_entry
*entry
,
493 struct snd_info_buffer
*buffer
)
495 struct snd_hwdep
*hwdep
;
497 mutex_lock(®ister_mutex
);
498 list_for_each_entry(hwdep
, &snd_hwdep_devices
, list
)
499 snd_iprintf(buffer
, "%02i-%02i: %s\n",
500 hwdep
->card
->number
, hwdep
->device
, hwdep
->name
);
501 mutex_unlock(®ister_mutex
);
504 static struct snd_info_entry
*snd_hwdep_proc_entry
;
506 static void __init
snd_hwdep_proc_init(void)
508 struct snd_info_entry
*entry
;
510 if ((entry
= snd_info_create_module_entry(THIS_MODULE
, "hwdep", NULL
)) != NULL
) {
511 entry
->c
.text
.read
= snd_hwdep_proc_read
;
512 if (snd_info_register(entry
) < 0) {
513 snd_info_free_entry(entry
);
517 snd_hwdep_proc_entry
= entry
;
520 static void __exit
snd_hwdep_proc_done(void)
522 snd_info_free_entry(snd_hwdep_proc_entry
);
524 #else /* !CONFIG_SND_PROC_FS */
525 #define snd_hwdep_proc_init()
526 #define snd_hwdep_proc_done()
527 #endif /* CONFIG_SND_PROC_FS */
534 static int __init
alsa_hwdep_init(void)
536 snd_hwdep_proc_init();
537 snd_ctl_register_ioctl(snd_hwdep_control_ioctl
);
538 snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl
);
542 static void __exit
alsa_hwdep_exit(void)
544 snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl
);
545 snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl
);
546 snd_hwdep_proc_done();
549 module_init(alsa_hwdep_init
)
550 module_exit(alsa_hwdep_exit
)