119af57b4STakashi Sakamoto /* 219af57b4STakashi Sakamoto * dice_hwdep.c - a part of driver for DICE based devices 319af57b4STakashi Sakamoto * 419af57b4STakashi Sakamoto * Copyright (c) Clemens Ladisch <clemens@ladisch.de> 519af57b4STakashi Sakamoto * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp> 619af57b4STakashi Sakamoto * 719af57b4STakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 819af57b4STakashi Sakamoto */ 919af57b4STakashi Sakamoto 1019af57b4STakashi Sakamoto #include "dice.h" 1119af57b4STakashi Sakamoto 1219af57b4STakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, 1319af57b4STakashi Sakamoto long count, loff_t *offset) 1419af57b4STakashi Sakamoto { 1519af57b4STakashi Sakamoto struct snd_dice *dice = hwdep->private_data; 1619af57b4STakashi Sakamoto DEFINE_WAIT(wait); 1719af57b4STakashi Sakamoto union snd_firewire_event event; 1819af57b4STakashi Sakamoto 1919af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 2019af57b4STakashi Sakamoto 2119af57b4STakashi Sakamoto while (!dice->dev_lock_changed && dice->notification_bits == 0) { 2219af57b4STakashi Sakamoto prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE); 2319af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 2419af57b4STakashi Sakamoto schedule(); 2519af57b4STakashi Sakamoto finish_wait(&dice->hwdep_wait, &wait); 2619af57b4STakashi Sakamoto if (signal_pending(current)) 2719af57b4STakashi Sakamoto return -ERESTARTSYS; 2819af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 2919af57b4STakashi Sakamoto } 3019af57b4STakashi Sakamoto 3119af57b4STakashi Sakamoto memset(&event, 0, sizeof(event)); 3219af57b4STakashi Sakamoto if (dice->dev_lock_changed) { 3319af57b4STakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS; 3419af57b4STakashi Sakamoto event.lock_status.status = dice->dev_lock_count > 0; 3519af57b4STakashi Sakamoto dice->dev_lock_changed = false; 3619af57b4STakashi Sakamoto 3719af57b4STakashi Sakamoto count = min_t(long, count, sizeof(event.lock_status)); 3819af57b4STakashi Sakamoto } else { 3919af57b4STakashi Sakamoto event.dice_notification.type = 4019af57b4STakashi Sakamoto SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION; 4119af57b4STakashi Sakamoto event.dice_notification.notification = dice->notification_bits; 4219af57b4STakashi Sakamoto dice->notification_bits = 0; 4319af57b4STakashi Sakamoto 4419af57b4STakashi Sakamoto count = min_t(long, count, sizeof(event.dice_notification)); 4519af57b4STakashi Sakamoto } 4619af57b4STakashi Sakamoto 4719af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 4819af57b4STakashi Sakamoto 4919af57b4STakashi Sakamoto if (copy_to_user(buf, &event, count)) 5019af57b4STakashi Sakamoto return -EFAULT; 5119af57b4STakashi Sakamoto 5219af57b4STakashi Sakamoto return count; 5319af57b4STakashi Sakamoto } 5419af57b4STakashi Sakamoto 5519af57b4STakashi Sakamoto static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file, 5619af57b4STakashi Sakamoto poll_table *wait) 5719af57b4STakashi Sakamoto { 5819af57b4STakashi Sakamoto struct snd_dice *dice = hwdep->private_data; 5919af57b4STakashi Sakamoto unsigned int events; 6019af57b4STakashi Sakamoto 6119af57b4STakashi Sakamoto poll_wait(file, &dice->hwdep_wait, wait); 6219af57b4STakashi Sakamoto 6319af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 6419af57b4STakashi Sakamoto if (dice->dev_lock_changed || dice->notification_bits != 0) 6519af57b4STakashi Sakamoto events = POLLIN | POLLRDNORM; 6619af57b4STakashi Sakamoto else 6719af57b4STakashi Sakamoto events = 0; 6819af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 6919af57b4STakashi Sakamoto 7019af57b4STakashi Sakamoto return events; 7119af57b4STakashi Sakamoto } 7219af57b4STakashi Sakamoto 7319af57b4STakashi Sakamoto static int hwdep_get_info(struct snd_dice *dice, void __user *arg) 7419af57b4STakashi Sakamoto { 7519af57b4STakashi Sakamoto struct fw_device *dev = fw_parent_device(dice->unit); 7619af57b4STakashi Sakamoto struct snd_firewire_get_info info; 7719af57b4STakashi Sakamoto 7819af57b4STakashi Sakamoto memset(&info, 0, sizeof(info)); 7919af57b4STakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_DICE; 8019af57b4STakashi Sakamoto info.card = dev->card->index; 8119af57b4STakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]); 8219af57b4STakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]); 8319af57b4STakashi Sakamoto strlcpy(info.device_name, dev_name(&dev->device), 8419af57b4STakashi Sakamoto sizeof(info.device_name)); 8519af57b4STakashi Sakamoto 8619af57b4STakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info))) 8719af57b4STakashi Sakamoto return -EFAULT; 8819af57b4STakashi Sakamoto 8919af57b4STakashi Sakamoto return 0; 9019af57b4STakashi Sakamoto } 9119af57b4STakashi Sakamoto 9219af57b4STakashi Sakamoto static int hwdep_lock(struct snd_dice *dice) 9319af57b4STakashi Sakamoto { 9419af57b4STakashi Sakamoto int err; 9519af57b4STakashi Sakamoto 9619af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 9719af57b4STakashi Sakamoto 9819af57b4STakashi Sakamoto if (dice->dev_lock_count == 0) { 9919af57b4STakashi Sakamoto dice->dev_lock_count = -1; 10019af57b4STakashi Sakamoto err = 0; 10119af57b4STakashi Sakamoto } else { 10219af57b4STakashi Sakamoto err = -EBUSY; 10319af57b4STakashi Sakamoto } 10419af57b4STakashi Sakamoto 10519af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 10619af57b4STakashi Sakamoto 10719af57b4STakashi Sakamoto return err; 10819af57b4STakashi Sakamoto } 10919af57b4STakashi Sakamoto 11019af57b4STakashi Sakamoto static int hwdep_unlock(struct snd_dice *dice) 11119af57b4STakashi Sakamoto { 11219af57b4STakashi Sakamoto int err; 11319af57b4STakashi Sakamoto 11419af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 11519af57b4STakashi Sakamoto 11619af57b4STakashi Sakamoto if (dice->dev_lock_count == -1) { 11719af57b4STakashi Sakamoto dice->dev_lock_count = 0; 11819af57b4STakashi Sakamoto err = 0; 11919af57b4STakashi Sakamoto } else { 12019af57b4STakashi Sakamoto err = -EBADFD; 12119af57b4STakashi Sakamoto } 12219af57b4STakashi Sakamoto 12319af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 12419af57b4STakashi Sakamoto 12519af57b4STakashi Sakamoto return err; 12619af57b4STakashi Sakamoto } 12719af57b4STakashi Sakamoto 12819af57b4STakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file) 12919af57b4STakashi Sakamoto { 13019af57b4STakashi Sakamoto struct snd_dice *dice = hwdep->private_data; 13119af57b4STakashi Sakamoto 13219af57b4STakashi Sakamoto spin_lock_irq(&dice->lock); 13319af57b4STakashi Sakamoto if (dice->dev_lock_count == -1) 13419af57b4STakashi Sakamoto dice->dev_lock_count = 0; 13519af57b4STakashi Sakamoto spin_unlock_irq(&dice->lock); 13619af57b4STakashi Sakamoto 13719af57b4STakashi Sakamoto return 0; 13819af57b4STakashi Sakamoto } 13919af57b4STakashi Sakamoto 14019af57b4STakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file, 14119af57b4STakashi Sakamoto unsigned int cmd, unsigned long arg) 14219af57b4STakashi Sakamoto { 14319af57b4STakashi Sakamoto struct snd_dice *dice = hwdep->private_data; 14419af57b4STakashi Sakamoto 14519af57b4STakashi Sakamoto switch (cmd) { 14619af57b4STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO: 14719af57b4STakashi Sakamoto return hwdep_get_info(dice, (void __user *)arg); 14819af57b4STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK: 14919af57b4STakashi Sakamoto return hwdep_lock(dice); 15019af57b4STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK: 15119af57b4STakashi Sakamoto return hwdep_unlock(dice); 15219af57b4STakashi Sakamoto default: 15319af57b4STakashi Sakamoto return -ENOIOCTLCMD; 15419af57b4STakashi Sakamoto } 15519af57b4STakashi Sakamoto } 15619af57b4STakashi Sakamoto 15719af57b4STakashi Sakamoto #ifdef CONFIG_COMPAT 15819af57b4STakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file, 15919af57b4STakashi Sakamoto unsigned int cmd, unsigned long arg) 16019af57b4STakashi Sakamoto { 16119af57b4STakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd, 16219af57b4STakashi Sakamoto (unsigned long)compat_ptr(arg)); 16319af57b4STakashi Sakamoto } 16419af57b4STakashi Sakamoto #else 16519af57b4STakashi Sakamoto #define hwdep_compat_ioctl NULL 16619af57b4STakashi Sakamoto #endif 16719af57b4STakashi Sakamoto 16819af57b4STakashi Sakamoto int snd_dice_create_hwdep(struct snd_dice *dice) 16919af57b4STakashi Sakamoto { 17019af57b4STakashi Sakamoto static const struct snd_hwdep_ops ops = { 17119af57b4STakashi Sakamoto .read = hwdep_read, 17219af57b4STakashi Sakamoto .release = hwdep_release, 17319af57b4STakashi Sakamoto .poll = hwdep_poll, 17419af57b4STakashi Sakamoto .ioctl = hwdep_ioctl, 17519af57b4STakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl, 17619af57b4STakashi Sakamoto }; 17719af57b4STakashi Sakamoto struct snd_hwdep *hwdep; 17819af57b4STakashi Sakamoto int err; 17919af57b4STakashi Sakamoto 18019af57b4STakashi Sakamoto err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep); 18119af57b4STakashi Sakamoto if (err < 0) 18219af57b4STakashi Sakamoto return err; 18319af57b4STakashi Sakamoto strcpy(hwdep->name, "DICE"); 18419af57b4STakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE; 18519af57b4STakashi Sakamoto hwdep->ops = ops; 18619af57b4STakashi Sakamoto hwdep->private_data = dice; 18719af57b4STakashi Sakamoto hwdep->exclusive = true; 18819af57b4STakashi Sakamoto 18919af57b4STakashi Sakamoto return 0; 19019af57b4STakashi Sakamoto } 191