Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/oxfw/oxfw-hwdep.c
26451 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* oxfw_hwdep.c - a part of driver for OXFW970/971 based devices
4
*
5
* Copyright (c) 2014 Takashi Sakamoto
6
*/
7
8
/*
9
* This codes give three functionality.
10
*
11
* 1.get firewire node information
12
* 2.get notification about starting/stopping stream
13
* 3.lock/unlock stream
14
*/
15
16
#include "oxfw.h"
17
18
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
19
loff_t *offset)
20
{
21
struct snd_oxfw *oxfw = hwdep->private_data;
22
DEFINE_WAIT(wait);
23
union snd_firewire_event event;
24
25
spin_lock_irq(&oxfw->lock);
26
27
while (!oxfw->dev_lock_changed) {
28
prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
29
spin_unlock_irq(&oxfw->lock);
30
schedule();
31
finish_wait(&oxfw->hwdep_wait, &wait);
32
if (signal_pending(current))
33
return -ERESTARTSYS;
34
spin_lock_irq(&oxfw->lock);
35
}
36
37
memset(&event, 0, sizeof(event));
38
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
39
event.lock_status.status = (oxfw->dev_lock_count > 0);
40
oxfw->dev_lock_changed = false;
41
42
count = min_t(long, count, sizeof(event.lock_status));
43
44
spin_unlock_irq(&oxfw->lock);
45
46
if (copy_to_user(buf, &event, count))
47
return -EFAULT;
48
49
return count;
50
}
51
52
static __poll_t hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
53
poll_table *wait)
54
{
55
struct snd_oxfw *oxfw = hwdep->private_data;
56
__poll_t events;
57
58
poll_wait(file, &oxfw->hwdep_wait, wait);
59
60
spin_lock_irq(&oxfw->lock);
61
if (oxfw->dev_lock_changed)
62
events = EPOLLIN | EPOLLRDNORM;
63
else
64
events = 0;
65
spin_unlock_irq(&oxfw->lock);
66
67
return events;
68
}
69
70
static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
71
{
72
struct fw_device *dev = fw_parent_device(oxfw->unit);
73
struct snd_firewire_get_info info;
74
75
memset(&info, 0, sizeof(info));
76
info.type = SNDRV_FIREWIRE_TYPE_OXFW;
77
info.card = dev->card->index;
78
*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
79
*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
80
strscpy(info.device_name, dev_name(&dev->device),
81
sizeof(info.device_name));
82
83
if (copy_to_user(arg, &info, sizeof(info)))
84
return -EFAULT;
85
86
return 0;
87
}
88
89
static int hwdep_lock(struct snd_oxfw *oxfw)
90
{
91
int err;
92
93
spin_lock_irq(&oxfw->lock);
94
95
if (oxfw->dev_lock_count == 0) {
96
oxfw->dev_lock_count = -1;
97
err = 0;
98
} else {
99
err = -EBUSY;
100
}
101
102
spin_unlock_irq(&oxfw->lock);
103
104
return err;
105
}
106
107
static int hwdep_unlock(struct snd_oxfw *oxfw)
108
{
109
int err;
110
111
spin_lock_irq(&oxfw->lock);
112
113
if (oxfw->dev_lock_count == -1) {
114
oxfw->dev_lock_count = 0;
115
err = 0;
116
} else {
117
err = -EBADFD;
118
}
119
120
spin_unlock_irq(&oxfw->lock);
121
122
return err;
123
}
124
125
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
126
{
127
struct snd_oxfw *oxfw = hwdep->private_data;
128
129
spin_lock_irq(&oxfw->lock);
130
if (oxfw->dev_lock_count == -1)
131
oxfw->dev_lock_count = 0;
132
spin_unlock_irq(&oxfw->lock);
133
134
return 0;
135
}
136
137
static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
138
unsigned int cmd, unsigned long arg)
139
{
140
struct snd_oxfw *oxfw = hwdep->private_data;
141
142
switch (cmd) {
143
case SNDRV_FIREWIRE_IOCTL_GET_INFO:
144
return hwdep_get_info(oxfw, (void __user *)arg);
145
case SNDRV_FIREWIRE_IOCTL_LOCK:
146
return hwdep_lock(oxfw);
147
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
148
return hwdep_unlock(oxfw);
149
default:
150
return -ENOIOCTLCMD;
151
}
152
}
153
154
#ifdef CONFIG_COMPAT
155
static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
156
unsigned int cmd, unsigned long arg)
157
{
158
return hwdep_ioctl(hwdep, file, cmd,
159
(unsigned long)compat_ptr(arg));
160
}
161
#else
162
#define hwdep_compat_ioctl NULL
163
#endif
164
165
int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
166
{
167
static const struct snd_hwdep_ops hwdep_ops = {
168
.read = hwdep_read,
169
.release = hwdep_release,
170
.poll = hwdep_poll,
171
.ioctl = hwdep_ioctl,
172
.ioctl_compat = hwdep_compat_ioctl,
173
};
174
struct snd_hwdep *hwdep;
175
int err;
176
177
err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
178
if (err < 0)
179
goto end;
180
strscpy(hwdep->name, oxfw->card->driver);
181
hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
182
hwdep->ops = hwdep_ops;
183
hwdep->private_data = oxfw;
184
hwdep->exclusive = true;
185
end:
186
return err;
187
}
188
189