0001
0002
0003
0004
0005
0006
0007 #include <linux/major.h>
0008 #include <linux/init.h>
0009 #include <linux/slab.h>
0010 #include <linux/time.h>
0011 #include <linux/mutex.h>
0012 #include <linux/module.h>
0013 #include <linux/sched/signal.h>
0014 #include <sound/core.h>
0015 #include <sound/control.h>
0016 #include <sound/minors.h>
0017 #include <sound/hwdep.h>
0018 #include <sound/info.h>
0019
0020 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
0021 MODULE_DESCRIPTION("Hardware dependent layer");
0022 MODULE_LICENSE("GPL");
0023
0024 static LIST_HEAD(snd_hwdep_devices);
0025 static DEFINE_MUTEX(register_mutex);
0026
0027 static int snd_hwdep_dev_free(struct snd_device *device);
0028 static int snd_hwdep_dev_register(struct snd_device *device);
0029 static int snd_hwdep_dev_disconnect(struct snd_device *device);
0030
0031
0032 static struct snd_hwdep *snd_hwdep_search(struct snd_card *card, int device)
0033 {
0034 struct snd_hwdep *hwdep;
0035
0036 list_for_each_entry(hwdep, &snd_hwdep_devices, list)
0037 if (hwdep->card == card && hwdep->device == device)
0038 return hwdep;
0039 return NULL;
0040 }
0041
0042 static loff_t snd_hwdep_llseek(struct file * file, loff_t offset, int orig)
0043 {
0044 struct snd_hwdep *hw = file->private_data;
0045 if (hw->ops.llseek)
0046 return hw->ops.llseek(hw, file, offset, orig);
0047 return -ENXIO;
0048 }
0049
0050 static ssize_t snd_hwdep_read(struct file * file, char __user *buf,
0051 size_t count, loff_t *offset)
0052 {
0053 struct snd_hwdep *hw = file->private_data;
0054 if (hw->ops.read)
0055 return hw->ops.read(hw, buf, count, offset);
0056 return -ENXIO;
0057 }
0058
0059 static ssize_t snd_hwdep_write(struct file * file, const char __user *buf,
0060 size_t count, loff_t *offset)
0061 {
0062 struct snd_hwdep *hw = file->private_data;
0063 if (hw->ops.write)
0064 return hw->ops.write(hw, buf, count, offset);
0065 return -ENXIO;
0066 }
0067
0068 static int snd_hwdep_open(struct inode *inode, struct file * file)
0069 {
0070 int major = imajor(inode);
0071 struct snd_hwdep *hw;
0072 int err;
0073 wait_queue_entry_t wait;
0074
0075 if (major == snd_major) {
0076 hw = snd_lookup_minor_data(iminor(inode),
0077 SNDRV_DEVICE_TYPE_HWDEP);
0078 #ifdef CONFIG_SND_OSSEMUL
0079 } else if (major == SOUND_MAJOR) {
0080 hw = snd_lookup_oss_minor_data(iminor(inode),
0081 SNDRV_OSS_DEVICE_TYPE_DMFM);
0082 #endif
0083 } else
0084 return -ENXIO;
0085 if (hw == NULL)
0086 return -ENODEV;
0087
0088 if (!try_module_get(hw->card->module)) {
0089 snd_card_unref(hw->card);
0090 return -EFAULT;
0091 }
0092
0093 init_waitqueue_entry(&wait, current);
0094 add_wait_queue(&hw->open_wait, &wait);
0095 mutex_lock(&hw->open_mutex);
0096 while (1) {
0097 if (hw->exclusive && hw->used > 0) {
0098 err = -EBUSY;
0099 break;
0100 }
0101 if (!hw->ops.open) {
0102 err = 0;
0103 break;
0104 }
0105 err = hw->ops.open(hw, file);
0106 if (err >= 0)
0107 break;
0108 if (err == -EAGAIN) {
0109 if (file->f_flags & O_NONBLOCK) {
0110 err = -EBUSY;
0111 break;
0112 }
0113 } else
0114 break;
0115 set_current_state(TASK_INTERRUPTIBLE);
0116 mutex_unlock(&hw->open_mutex);
0117 schedule();
0118 mutex_lock(&hw->open_mutex);
0119 if (hw->card->shutdown) {
0120 err = -ENODEV;
0121 break;
0122 }
0123 if (signal_pending(current)) {
0124 err = -ERESTARTSYS;
0125 break;
0126 }
0127 }
0128 remove_wait_queue(&hw->open_wait, &wait);
0129 if (err >= 0) {
0130 err = snd_card_file_add(hw->card, file);
0131 if (err >= 0) {
0132 file->private_data = hw;
0133 hw->used++;
0134 } else {
0135 if (hw->ops.release)
0136 hw->ops.release(hw, file);
0137 }
0138 }
0139 mutex_unlock(&hw->open_mutex);
0140 if (err < 0)
0141 module_put(hw->card->module);
0142 snd_card_unref(hw->card);
0143 return err;
0144 }
0145
0146 static int snd_hwdep_release(struct inode *inode, struct file * file)
0147 {
0148 int err = 0;
0149 struct snd_hwdep *hw = file->private_data;
0150 struct module *mod = hw->card->module;
0151
0152 mutex_lock(&hw->open_mutex);
0153 if (hw->ops.release)
0154 err = hw->ops.release(hw, file);
0155 if (hw->used > 0)
0156 hw->used--;
0157 mutex_unlock(&hw->open_mutex);
0158 wake_up(&hw->open_wait);
0159
0160 snd_card_file_remove(hw->card, file);
0161 module_put(mod);
0162 return err;
0163 }
0164
0165 static __poll_t snd_hwdep_poll(struct file * file, poll_table * wait)
0166 {
0167 struct snd_hwdep *hw = file->private_data;
0168 if (hw->ops.poll)
0169 return hw->ops.poll(hw, file, wait);
0170 return 0;
0171 }
0172
0173 static int snd_hwdep_info(struct snd_hwdep *hw,
0174 struct snd_hwdep_info __user *_info)
0175 {
0176 struct snd_hwdep_info info;
0177
0178 memset(&info, 0, sizeof(info));
0179 info.card = hw->card->number;
0180 strscpy(info.id, hw->id, sizeof(info.id));
0181 strscpy(info.name, hw->name, sizeof(info.name));
0182 info.iface = hw->iface;
0183 if (copy_to_user(_info, &info, sizeof(info)))
0184 return -EFAULT;
0185 return 0;
0186 }
0187
0188 static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
0189 struct snd_hwdep_dsp_status __user *_info)
0190 {
0191 struct snd_hwdep_dsp_status info;
0192 int err;
0193
0194 if (! hw->ops.dsp_status)
0195 return -ENXIO;
0196 memset(&info, 0, sizeof(info));
0197 info.dsp_loaded = hw->dsp_loaded;
0198 err = hw->ops.dsp_status(hw, &info);
0199 if (err < 0)
0200 return err;
0201 if (copy_to_user(_info, &info, sizeof(info)))
0202 return -EFAULT;
0203 return 0;
0204 }
0205
0206 static int snd_hwdep_dsp_load(struct snd_hwdep *hw,
0207 struct snd_hwdep_dsp_image *info)
0208 {
0209 int err;
0210
0211 if (! hw->ops.dsp_load)
0212 return -ENXIO;
0213 if (info->index >= 32)
0214 return -EINVAL;
0215
0216 if (hw->dsp_loaded & (1u << info->index))
0217 return -EBUSY;
0218 err = hw->ops.dsp_load(hw, info);
0219 if (err < 0)
0220 return err;
0221 hw->dsp_loaded |= (1u << info->index);
0222 return 0;
0223 }
0224
0225 static int snd_hwdep_dsp_load_user(struct snd_hwdep *hw,
0226 struct snd_hwdep_dsp_image __user *_info)
0227 {
0228 struct snd_hwdep_dsp_image info = {};
0229
0230 if (copy_from_user(&info, _info, sizeof(info)))
0231 return -EFAULT;
0232 return snd_hwdep_dsp_load(hw, &info);
0233 }
0234
0235
0236 static long snd_hwdep_ioctl(struct file * file, unsigned int cmd,
0237 unsigned long arg)
0238 {
0239 struct snd_hwdep *hw = file->private_data;
0240 void __user *argp = (void __user *)arg;
0241 switch (cmd) {
0242 case SNDRV_HWDEP_IOCTL_PVERSION:
0243 return put_user(SNDRV_HWDEP_VERSION, (int __user *)argp);
0244 case SNDRV_HWDEP_IOCTL_INFO:
0245 return snd_hwdep_info(hw, argp);
0246 case SNDRV_HWDEP_IOCTL_DSP_STATUS:
0247 return snd_hwdep_dsp_status(hw, argp);
0248 case SNDRV_HWDEP_IOCTL_DSP_LOAD:
0249 return snd_hwdep_dsp_load_user(hw, argp);
0250 }
0251 if (hw->ops.ioctl)
0252 return hw->ops.ioctl(hw, file, cmd, arg);
0253 return -ENOTTY;
0254 }
0255
0256 static int snd_hwdep_mmap(struct file * file, struct vm_area_struct * vma)
0257 {
0258 struct snd_hwdep *hw = file->private_data;
0259 if (hw->ops.mmap)
0260 return hw->ops.mmap(hw, file, vma);
0261 return -ENXIO;
0262 }
0263
0264 static int snd_hwdep_control_ioctl(struct snd_card *card,
0265 struct snd_ctl_file * control,
0266 unsigned int cmd, unsigned long arg)
0267 {
0268 switch (cmd) {
0269 case SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE:
0270 {
0271 int device;
0272
0273 if (get_user(device, (int __user *)arg))
0274 return -EFAULT;
0275 mutex_lock(®ister_mutex);
0276
0277 if (device < 0)
0278 device = 0;
0279 else if (device < SNDRV_MINOR_HWDEPS)
0280 device++;
0281 else
0282 device = SNDRV_MINOR_HWDEPS;
0283
0284 while (device < SNDRV_MINOR_HWDEPS) {
0285 if (snd_hwdep_search(card, device))
0286 break;
0287 device++;
0288 }
0289 if (device >= SNDRV_MINOR_HWDEPS)
0290 device = -1;
0291 mutex_unlock(®ister_mutex);
0292 if (put_user(device, (int __user *)arg))
0293 return -EFAULT;
0294 return 0;
0295 }
0296 case SNDRV_CTL_IOCTL_HWDEP_INFO:
0297 {
0298 struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg;
0299 int device, err;
0300 struct snd_hwdep *hwdep;
0301
0302 if (get_user(device, &info->device))
0303 return -EFAULT;
0304 mutex_lock(®ister_mutex);
0305 hwdep = snd_hwdep_search(card, device);
0306 if (hwdep)
0307 err = snd_hwdep_info(hwdep, info);
0308 else
0309 err = -ENXIO;
0310 mutex_unlock(®ister_mutex);
0311 return err;
0312 }
0313 }
0314 return -ENOIOCTLCMD;
0315 }
0316
0317 #ifdef CONFIG_COMPAT
0318 #include "hwdep_compat.c"
0319 #else
0320 #define snd_hwdep_ioctl_compat NULL
0321 #endif
0322
0323
0324
0325
0326
0327 static const struct file_operations snd_hwdep_f_ops =
0328 {
0329 .owner = THIS_MODULE,
0330 .llseek = snd_hwdep_llseek,
0331 .read = snd_hwdep_read,
0332 .write = snd_hwdep_write,
0333 .open = snd_hwdep_open,
0334 .release = snd_hwdep_release,
0335 .poll = snd_hwdep_poll,
0336 .unlocked_ioctl = snd_hwdep_ioctl,
0337 .compat_ioctl = snd_hwdep_ioctl_compat,
0338 .mmap = snd_hwdep_mmap,
0339 };
0340
0341 static void release_hwdep_device(struct device *dev)
0342 {
0343 kfree(container_of(dev, struct snd_hwdep, dev));
0344 }
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358
0359 int snd_hwdep_new(struct snd_card *card, char *id, int device,
0360 struct snd_hwdep **rhwdep)
0361 {
0362 struct snd_hwdep *hwdep;
0363 int err;
0364 static const struct snd_device_ops ops = {
0365 .dev_free = snd_hwdep_dev_free,
0366 .dev_register = snd_hwdep_dev_register,
0367 .dev_disconnect = snd_hwdep_dev_disconnect,
0368 };
0369
0370 if (snd_BUG_ON(!card))
0371 return -ENXIO;
0372 if (rhwdep)
0373 *rhwdep = NULL;
0374 hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL);
0375 if (!hwdep)
0376 return -ENOMEM;
0377
0378 init_waitqueue_head(&hwdep->open_wait);
0379 mutex_init(&hwdep->open_mutex);
0380 hwdep->card = card;
0381 hwdep->device = device;
0382 if (id)
0383 strscpy(hwdep->id, id, sizeof(hwdep->id));
0384
0385 snd_device_initialize(&hwdep->dev, card);
0386 hwdep->dev.release = release_hwdep_device;
0387 dev_set_name(&hwdep->dev, "hwC%iD%i", card->number, device);
0388 #ifdef CONFIG_SND_OSSEMUL
0389 hwdep->oss_type = -1;
0390 #endif
0391
0392 err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops);
0393 if (err < 0) {
0394 put_device(&hwdep->dev);
0395 return err;
0396 }
0397
0398 if (rhwdep)
0399 *rhwdep = hwdep;
0400 return 0;
0401 }
0402 EXPORT_SYMBOL(snd_hwdep_new);
0403
0404 static int snd_hwdep_dev_free(struct snd_device *device)
0405 {
0406 struct snd_hwdep *hwdep = device->device_data;
0407 if (!hwdep)
0408 return 0;
0409 if (hwdep->private_free)
0410 hwdep->private_free(hwdep);
0411 put_device(&hwdep->dev);
0412 return 0;
0413 }
0414
0415 static int snd_hwdep_dev_register(struct snd_device *device)
0416 {
0417 struct snd_hwdep *hwdep = device->device_data;
0418 struct snd_card *card = hwdep->card;
0419 int err;
0420
0421 mutex_lock(®ister_mutex);
0422 if (snd_hwdep_search(card, hwdep->device)) {
0423 mutex_unlock(®ister_mutex);
0424 return -EBUSY;
0425 }
0426 list_add_tail(&hwdep->list, &snd_hwdep_devices);
0427 err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP,
0428 hwdep->card, hwdep->device,
0429 &snd_hwdep_f_ops, hwdep, &hwdep->dev);
0430 if (err < 0) {
0431 dev_err(&hwdep->dev, "unable to register\n");
0432 list_del(&hwdep->list);
0433 mutex_unlock(®ister_mutex);
0434 return err;
0435 }
0436
0437 #ifdef CONFIG_SND_OSSEMUL
0438 hwdep->ossreg = 0;
0439 if (hwdep->oss_type >= 0) {
0440 if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM &&
0441 hwdep->device)
0442 dev_warn(&hwdep->dev,
0443 "only hwdep device 0 can be registered as OSS direct FM device!\n");
0444 else if (snd_register_oss_device(hwdep->oss_type,
0445 card, hwdep->device,
0446 &snd_hwdep_f_ops, hwdep) < 0)
0447 dev_warn(&hwdep->dev,
0448 "unable to register OSS compatibility device\n");
0449 else
0450 hwdep->ossreg = 1;
0451 }
0452 #endif
0453 mutex_unlock(®ister_mutex);
0454 return 0;
0455 }
0456
0457 static int snd_hwdep_dev_disconnect(struct snd_device *device)
0458 {
0459 struct snd_hwdep *hwdep = device->device_data;
0460
0461 if (snd_BUG_ON(!hwdep))
0462 return -ENXIO;
0463 mutex_lock(®ister_mutex);
0464 if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) {
0465 mutex_unlock(®ister_mutex);
0466 return -EINVAL;
0467 }
0468 mutex_lock(&hwdep->open_mutex);
0469 wake_up(&hwdep->open_wait);
0470 #ifdef CONFIG_SND_OSSEMUL
0471 if (hwdep->ossreg)
0472 snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device);
0473 #endif
0474 snd_unregister_device(&hwdep->dev);
0475 list_del_init(&hwdep->list);
0476 mutex_unlock(&hwdep->open_mutex);
0477 mutex_unlock(®ister_mutex);
0478 return 0;
0479 }
0480
0481 #ifdef CONFIG_SND_PROC_FS
0482
0483
0484
0485
0486 static void snd_hwdep_proc_read(struct snd_info_entry *entry,
0487 struct snd_info_buffer *buffer)
0488 {
0489 struct snd_hwdep *hwdep;
0490
0491 mutex_lock(®ister_mutex);
0492 list_for_each_entry(hwdep, &snd_hwdep_devices, list)
0493 snd_iprintf(buffer, "%02i-%02i: %s\n",
0494 hwdep->card->number, hwdep->device, hwdep->name);
0495 mutex_unlock(®ister_mutex);
0496 }
0497
0498 static struct snd_info_entry *snd_hwdep_proc_entry;
0499
0500 static void __init snd_hwdep_proc_init(void)
0501 {
0502 struct snd_info_entry *entry;
0503
0504 entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL);
0505 if (entry) {
0506 entry->c.text.read = snd_hwdep_proc_read;
0507 if (snd_info_register(entry) < 0) {
0508 snd_info_free_entry(entry);
0509 entry = NULL;
0510 }
0511 }
0512 snd_hwdep_proc_entry = entry;
0513 }
0514
0515 static void __exit snd_hwdep_proc_done(void)
0516 {
0517 snd_info_free_entry(snd_hwdep_proc_entry);
0518 }
0519 #else
0520 #define snd_hwdep_proc_init()
0521 #define snd_hwdep_proc_done()
0522 #endif
0523
0524
0525
0526
0527
0528
0529 static int __init alsa_hwdep_init(void)
0530 {
0531 snd_hwdep_proc_init();
0532 snd_ctl_register_ioctl(snd_hwdep_control_ioctl);
0533 snd_ctl_register_ioctl_compat(snd_hwdep_control_ioctl);
0534 return 0;
0535 }
0536
0537 static void __exit alsa_hwdep_exit(void)
0538 {
0539 snd_ctl_unregister_ioctl(snd_hwdep_control_ioctl);
0540 snd_ctl_unregister_ioctl_compat(snd_hwdep_control_ioctl);
0541 snd_hwdep_proc_done();
0542 }
0543
0544 module_init(alsa_hwdep_init)
0545 module_exit(alsa_hwdep_exit)