Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/firewire/oxfw/oxfw-hwdep.c
29266 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
57
poll_wait(file, &oxfw->hwdep_wait, wait);
58
59
guard(spinlock_irq)(&oxfw->lock);
60
if (oxfw->dev_lock_changed)
61
return EPOLLIN | EPOLLRDNORM;
62
else
63
return 0;
64
}
65
66
static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
67
{
68
struct fw_device *dev = fw_parent_device(oxfw->unit);
69
struct snd_firewire_get_info info;
70
71
memset(&info, 0, sizeof(info));
72
info.type = SNDRV_FIREWIRE_TYPE_OXFW;
73
info.card = dev->card->index;
74
*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
75
*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
76
strscpy(info.device_name, dev_name(&dev->device),
77
sizeof(info.device_name));
78
79
if (copy_to_user(arg, &info, sizeof(info)))
80
return -EFAULT;
81
82
return 0;
83
}
84
85
static int hwdep_lock(struct snd_oxfw *oxfw)
86
{
87
guard(spinlock_irq)(&oxfw->lock);
88
89
if (oxfw->dev_lock_count == 0) {
90
oxfw->dev_lock_count = -1;
91
return 0;
92
} else {
93
return -EBUSY;
94
}
95
}
96
97
static int hwdep_unlock(struct snd_oxfw *oxfw)
98
{
99
guard(spinlock_irq)(&oxfw->lock);
100
101
if (oxfw->dev_lock_count == -1) {
102
oxfw->dev_lock_count = 0;
103
return 0;
104
} else {
105
return -EBADFD;
106
}
107
}
108
109
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
110
{
111
struct snd_oxfw *oxfw = hwdep->private_data;
112
113
guard(spinlock_irq)(&oxfw->lock);
114
if (oxfw->dev_lock_count == -1)
115
oxfw->dev_lock_count = 0;
116
117
return 0;
118
}
119
120
static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
121
unsigned int cmd, unsigned long arg)
122
{
123
struct snd_oxfw *oxfw = hwdep->private_data;
124
125
switch (cmd) {
126
case SNDRV_FIREWIRE_IOCTL_GET_INFO:
127
return hwdep_get_info(oxfw, (void __user *)arg);
128
case SNDRV_FIREWIRE_IOCTL_LOCK:
129
return hwdep_lock(oxfw);
130
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
131
return hwdep_unlock(oxfw);
132
default:
133
return -ENOIOCTLCMD;
134
}
135
}
136
137
#ifdef CONFIG_COMPAT
138
static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
139
unsigned int cmd, unsigned long arg)
140
{
141
return hwdep_ioctl(hwdep, file, cmd,
142
(unsigned long)compat_ptr(arg));
143
}
144
#else
145
#define hwdep_compat_ioctl NULL
146
#endif
147
148
int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
149
{
150
static const struct snd_hwdep_ops hwdep_ops = {
151
.read = hwdep_read,
152
.release = hwdep_release,
153
.poll = hwdep_poll,
154
.ioctl = hwdep_ioctl,
155
.ioctl_compat = hwdep_compat_ioctl,
156
};
157
struct snd_hwdep *hwdep;
158
int err;
159
160
err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
161
if (err < 0)
162
goto end;
163
strscpy(hwdep->name, oxfw->card->driver);
164
hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
165
hwdep->ops = hwdep_ops;
166
hwdep->private_data = oxfw;
167
hwdep->exclusive = true;
168
end:
169
return err;
170
}
171
172