1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2660dd3d5STakashi Sakamoto /*
3660dd3d5STakashi Sakamoto * digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
4660dd3d5STakashi Sakamoto *
5660dd3d5STakashi Sakamoto * Copyright (c) 2014-2015 Takashi Sakamoto
6660dd3d5STakashi Sakamoto */
7660dd3d5STakashi Sakamoto
8660dd3d5STakashi Sakamoto /*
9660dd3d5STakashi Sakamoto * This codes give three functionality.
10660dd3d5STakashi Sakamoto *
11660dd3d5STakashi Sakamoto * 1.get firewire node information
12660dd3d5STakashi Sakamoto * 2.get notification about starting/stopping stream
13660dd3d5STakashi Sakamoto * 3.lock/unlock stream
1444b73088STakashi Sakamoto * 4.get asynchronous messaging
15660dd3d5STakashi Sakamoto */
16660dd3d5STakashi Sakamoto
17660dd3d5STakashi Sakamoto #include "digi00x.h"
18660dd3d5STakashi Sakamoto
hwdep_read(struct snd_hwdep * hwdep,char __user * buf,long count,loff_t * offset)19660dd3d5STakashi Sakamoto static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
20660dd3d5STakashi Sakamoto loff_t *offset)
21660dd3d5STakashi Sakamoto {
22660dd3d5STakashi Sakamoto struct snd_dg00x *dg00x = hwdep->private_data;
23660dd3d5STakashi Sakamoto DEFINE_WAIT(wait);
24660dd3d5STakashi Sakamoto union snd_firewire_event event;
25660dd3d5STakashi Sakamoto
26660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
27660dd3d5STakashi Sakamoto
2844b73088STakashi Sakamoto while (!dg00x->dev_lock_changed && dg00x->msg == 0) {
29660dd3d5STakashi Sakamoto prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
30660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
31660dd3d5STakashi Sakamoto schedule();
32660dd3d5STakashi Sakamoto finish_wait(&dg00x->hwdep_wait, &wait);
33660dd3d5STakashi Sakamoto if (signal_pending(current))
34660dd3d5STakashi Sakamoto return -ERESTARTSYS;
35660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
36660dd3d5STakashi Sakamoto }
37660dd3d5STakashi Sakamoto
38660dd3d5STakashi Sakamoto memset(&event, 0, sizeof(event));
39660dd3d5STakashi Sakamoto if (dg00x->dev_lock_changed) {
40660dd3d5STakashi Sakamoto event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
41660dd3d5STakashi Sakamoto event.lock_status.status = (dg00x->dev_lock_count > 0);
42660dd3d5STakashi Sakamoto dg00x->dev_lock_changed = false;
43660dd3d5STakashi Sakamoto
44660dd3d5STakashi Sakamoto count = min_t(long, count, sizeof(event.lock_status));
4544b73088STakashi Sakamoto } else {
4644b73088STakashi Sakamoto event.digi00x_message.type =
4744b73088STakashi Sakamoto SNDRV_FIREWIRE_EVENT_DIGI00X_MESSAGE;
4844b73088STakashi Sakamoto event.digi00x_message.message = dg00x->msg;
4944b73088STakashi Sakamoto dg00x->msg = 0;
5044b73088STakashi Sakamoto
5144b73088STakashi Sakamoto count = min_t(long, count, sizeof(event.digi00x_message));
52660dd3d5STakashi Sakamoto }
53660dd3d5STakashi Sakamoto
54660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
55660dd3d5STakashi Sakamoto
56660dd3d5STakashi Sakamoto if (copy_to_user(buf, &event, count))
57660dd3d5STakashi Sakamoto return -EFAULT;
58660dd3d5STakashi Sakamoto
59660dd3d5STakashi Sakamoto return count;
60660dd3d5STakashi Sakamoto }
61660dd3d5STakashi Sakamoto
hwdep_poll(struct snd_hwdep * hwdep,struct file * file,poll_table * wait)62680ef72aSAl Viro static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
63660dd3d5STakashi Sakamoto poll_table *wait)
64660dd3d5STakashi Sakamoto {
65660dd3d5STakashi Sakamoto struct snd_dg00x *dg00x = hwdep->private_data;
66680ef72aSAl Viro __poll_t events;
67660dd3d5STakashi Sakamoto
68660dd3d5STakashi Sakamoto poll_wait(file, &dg00x->hwdep_wait, wait);
69660dd3d5STakashi Sakamoto
70660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
7144b73088STakashi Sakamoto if (dg00x->dev_lock_changed || dg00x->msg)
72a9a08845SLinus Torvalds events = EPOLLIN | EPOLLRDNORM;
73660dd3d5STakashi Sakamoto else
74660dd3d5STakashi Sakamoto events = 0;
75660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
76660dd3d5STakashi Sakamoto
77660dd3d5STakashi Sakamoto return events;
78660dd3d5STakashi Sakamoto }
79660dd3d5STakashi Sakamoto
hwdep_get_info(struct snd_dg00x * dg00x,void __user * arg)80660dd3d5STakashi Sakamoto static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
81660dd3d5STakashi Sakamoto {
82660dd3d5STakashi Sakamoto struct fw_device *dev = fw_parent_device(dg00x->unit);
83660dd3d5STakashi Sakamoto struct snd_firewire_get_info info;
84660dd3d5STakashi Sakamoto
85660dd3d5STakashi Sakamoto memset(&info, 0, sizeof(info));
86660dd3d5STakashi Sakamoto info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;
87660dd3d5STakashi Sakamoto info.card = dev->card->index;
88660dd3d5STakashi Sakamoto *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
89660dd3d5STakashi Sakamoto *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
90*75b1a8f9SJoe Perches strscpy(info.device_name, dev_name(&dev->device),
91660dd3d5STakashi Sakamoto sizeof(info.device_name));
92660dd3d5STakashi Sakamoto
93660dd3d5STakashi Sakamoto if (copy_to_user(arg, &info, sizeof(info)))
94660dd3d5STakashi Sakamoto return -EFAULT;
95660dd3d5STakashi Sakamoto
96660dd3d5STakashi Sakamoto return 0;
97660dd3d5STakashi Sakamoto }
98660dd3d5STakashi Sakamoto
hwdep_lock(struct snd_dg00x * dg00x)99660dd3d5STakashi Sakamoto static int hwdep_lock(struct snd_dg00x *dg00x)
100660dd3d5STakashi Sakamoto {
101660dd3d5STakashi Sakamoto int err;
102660dd3d5STakashi Sakamoto
103660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
104660dd3d5STakashi Sakamoto
105660dd3d5STakashi Sakamoto if (dg00x->dev_lock_count == 0) {
106660dd3d5STakashi Sakamoto dg00x->dev_lock_count = -1;
107660dd3d5STakashi Sakamoto err = 0;
108660dd3d5STakashi Sakamoto } else {
109660dd3d5STakashi Sakamoto err = -EBUSY;
110660dd3d5STakashi Sakamoto }
111660dd3d5STakashi Sakamoto
112660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
113660dd3d5STakashi Sakamoto
114660dd3d5STakashi Sakamoto return err;
115660dd3d5STakashi Sakamoto }
116660dd3d5STakashi Sakamoto
hwdep_unlock(struct snd_dg00x * dg00x)117660dd3d5STakashi Sakamoto static int hwdep_unlock(struct snd_dg00x *dg00x)
118660dd3d5STakashi Sakamoto {
119660dd3d5STakashi Sakamoto int err;
120660dd3d5STakashi Sakamoto
121660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
122660dd3d5STakashi Sakamoto
123660dd3d5STakashi Sakamoto if (dg00x->dev_lock_count == -1) {
124660dd3d5STakashi Sakamoto dg00x->dev_lock_count = 0;
125660dd3d5STakashi Sakamoto err = 0;
126660dd3d5STakashi Sakamoto } else {
127660dd3d5STakashi Sakamoto err = -EBADFD;
128660dd3d5STakashi Sakamoto }
129660dd3d5STakashi Sakamoto
130660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
131660dd3d5STakashi Sakamoto
132660dd3d5STakashi Sakamoto return err;
133660dd3d5STakashi Sakamoto }
134660dd3d5STakashi Sakamoto
hwdep_release(struct snd_hwdep * hwdep,struct file * file)135660dd3d5STakashi Sakamoto static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
136660dd3d5STakashi Sakamoto {
137660dd3d5STakashi Sakamoto struct snd_dg00x *dg00x = hwdep->private_data;
138660dd3d5STakashi Sakamoto
139660dd3d5STakashi Sakamoto spin_lock_irq(&dg00x->lock);
140660dd3d5STakashi Sakamoto if (dg00x->dev_lock_count == -1)
141660dd3d5STakashi Sakamoto dg00x->dev_lock_count = 0;
142660dd3d5STakashi Sakamoto spin_unlock_irq(&dg00x->lock);
143660dd3d5STakashi Sakamoto
144660dd3d5STakashi Sakamoto return 0;
145660dd3d5STakashi Sakamoto }
146660dd3d5STakashi Sakamoto
hwdep_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)147660dd3d5STakashi Sakamoto static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
148660dd3d5STakashi Sakamoto unsigned int cmd, unsigned long arg)
149660dd3d5STakashi Sakamoto {
150660dd3d5STakashi Sakamoto struct snd_dg00x *dg00x = hwdep->private_data;
151660dd3d5STakashi Sakamoto
152660dd3d5STakashi Sakamoto switch (cmd) {
153660dd3d5STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_GET_INFO:
154660dd3d5STakashi Sakamoto return hwdep_get_info(dg00x, (void __user *)arg);
155660dd3d5STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_LOCK:
156660dd3d5STakashi Sakamoto return hwdep_lock(dg00x);
157660dd3d5STakashi Sakamoto case SNDRV_FIREWIRE_IOCTL_UNLOCK:
158660dd3d5STakashi Sakamoto return hwdep_unlock(dg00x);
159660dd3d5STakashi Sakamoto default:
160660dd3d5STakashi Sakamoto return -ENOIOCTLCMD;
161660dd3d5STakashi Sakamoto }
162660dd3d5STakashi Sakamoto }
163660dd3d5STakashi Sakamoto
164660dd3d5STakashi Sakamoto #ifdef CONFIG_COMPAT
hwdep_compat_ioctl(struct snd_hwdep * hwdep,struct file * file,unsigned int cmd,unsigned long arg)165660dd3d5STakashi Sakamoto static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
166660dd3d5STakashi Sakamoto unsigned int cmd, unsigned long arg)
167660dd3d5STakashi Sakamoto {
168660dd3d5STakashi Sakamoto return hwdep_ioctl(hwdep, file, cmd,
169660dd3d5STakashi Sakamoto (unsigned long)compat_ptr(arg));
170660dd3d5STakashi Sakamoto }
171660dd3d5STakashi Sakamoto #else
172660dd3d5STakashi Sakamoto #define hwdep_compat_ioctl NULL
173660dd3d5STakashi Sakamoto #endif
174660dd3d5STakashi Sakamoto
snd_dg00x_create_hwdep_device(struct snd_dg00x * dg00x)175a4e86cbaSTakashi Sakamoto int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
176a4e86cbaSTakashi Sakamoto {
177a4e86cbaSTakashi Sakamoto static const struct snd_hwdep_ops ops = {
178660dd3d5STakashi Sakamoto .read = hwdep_read,
179660dd3d5STakashi Sakamoto .release = hwdep_release,
180660dd3d5STakashi Sakamoto .poll = hwdep_poll,
181660dd3d5STakashi Sakamoto .ioctl = hwdep_ioctl,
182660dd3d5STakashi Sakamoto .ioctl_compat = hwdep_compat_ioctl,
183660dd3d5STakashi Sakamoto };
184660dd3d5STakashi Sakamoto struct snd_hwdep *hwdep;
185660dd3d5STakashi Sakamoto int err;
186660dd3d5STakashi Sakamoto
187660dd3d5STakashi Sakamoto err = snd_hwdep_new(dg00x->card, "Digi00x", 0, &hwdep);
188660dd3d5STakashi Sakamoto if (err < 0)
189660dd3d5STakashi Sakamoto return err;
190660dd3d5STakashi Sakamoto
191660dd3d5STakashi Sakamoto strcpy(hwdep->name, "Digi00x");
192660dd3d5STakashi Sakamoto hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
193a4e86cbaSTakashi Sakamoto hwdep->ops = ops;
194660dd3d5STakashi Sakamoto hwdep->private_data = dg00x;
195660dd3d5STakashi Sakamoto hwdep->exclusive = true;
196660dd3d5STakashi Sakamoto
197660dd3d5STakashi Sakamoto return err;
198660dd3d5STakashi Sakamoto }
199