Skip to content

Commit 660dd3d

Browse files
takaswietiwai
authored andcommitted
ALSA: firewire-digi00x: add hwdep interface
This commit adds hwdep interface so as the other sound drivers for units on IEEE 1394 bus have. This interface is designed for mixer/control applications. By using this interface, an application can get information about firewire node, can lock/unlock kernel streaming and can get notification at starting/stopping kernel streaming. Signed-off-by: Takashi Sakamoto <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 0120d0f commit 660dd3d

File tree

9 files changed

+273
-8
lines changed

9 files changed

+273
-8
lines changed

include/uapi/sound/asound.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,9 +100,10 @@ enum {
100100
SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */
101101
SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */
102102
SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */
103+
SNDRV_HWDEP_IFACE_FW_DIGI00X, /* Digidesign Digi 002/003 family */
103104

104105
/* Don't forget to change the following: */
105-
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_OXFW
106+
SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_DIGI00X
106107
};
107108

108109
struct snd_hwdep_info {

include/uapi/sound/firewire.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ union snd_firewire_event {
5656
#define SNDRV_FIREWIRE_TYPE_FIREWORKS 2
5757
#define SNDRV_FIREWIRE_TYPE_BEBOB 3
5858
#define SNDRV_FIREWIRE_TYPE_OXFW 4
59+
#define SNDRV_FIREWIRE_TYPE_DIGI00X 5
5960
/* RME, MOTU, ... */
6061

6162
struct snd_firewire_get_info {

sound/firewire/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ config SND_BEBOB
123123
config SND_FIREWIRE_DIGI00X
124124
tristate "Digidesign Digi 002/003 family support"
125125
select SND_FIREWIRE_LIB
126+
select SND_HWDEP
126127
help
127128
Say Y here to include support for Digidesign Digi 002/003 family.
128129
* Digi 002 Console

sound/firewire/digi00x/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
snd-firewire-digi00x-objs := amdtp-dot.o digi00x-stream.o digi00x-proc.o \
2-
digi00x-pcm.o digi00x.o
2+
digi00x-pcm.o digi00x-hwdep.o digi00x.o
33
obj-$(CONFIG_SND_FIREWIRE_DIGI00X) += snd-firewire-digi00x.o
Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,192 @@
1+
/*
2+
* digi00x-hwdep.c - a part of driver for Digidesign Digi 002/003 family
3+
*
4+
* Copyright (c) 2014-2015 Takashi Sakamoto
5+
*
6+
* Licensed under the terms of the GNU General Public License, version 2.
7+
*/
8+
9+
/*
10+
* This codes give three functionality.
11+
*
12+
* 1.get firewire node information
13+
* 2.get notification about starting/stopping stream
14+
* 3.lock/unlock stream
15+
*/
16+
17+
#include "digi00x.h"
18+
19+
static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
20+
loff_t *offset)
21+
{
22+
struct snd_dg00x *dg00x = hwdep->private_data;
23+
DEFINE_WAIT(wait);
24+
union snd_firewire_event event;
25+
26+
spin_lock_irq(&dg00x->lock);
27+
28+
while (!dg00x->dev_lock_changed) {
29+
prepare_to_wait(&dg00x->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
30+
spin_unlock_irq(&dg00x->lock);
31+
schedule();
32+
finish_wait(&dg00x->hwdep_wait, &wait);
33+
if (signal_pending(current))
34+
return -ERESTARTSYS;
35+
spin_lock_irq(&dg00x->lock);
36+
}
37+
38+
memset(&event, 0, sizeof(event));
39+
if (dg00x->dev_lock_changed) {
40+
event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
41+
event.lock_status.status = (dg00x->dev_lock_count > 0);
42+
dg00x->dev_lock_changed = false;
43+
44+
count = min_t(long, count, sizeof(event.lock_status));
45+
}
46+
47+
spin_unlock_irq(&dg00x->lock);
48+
49+
if (copy_to_user(buf, &event, count))
50+
return -EFAULT;
51+
52+
return count;
53+
}
54+
55+
static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
56+
poll_table *wait)
57+
{
58+
struct snd_dg00x *dg00x = hwdep->private_data;
59+
unsigned int events;
60+
61+
poll_wait(file, &dg00x->hwdep_wait, wait);
62+
63+
spin_lock_irq(&dg00x->lock);
64+
if (dg00x->dev_lock_changed)
65+
events = POLLIN | POLLRDNORM;
66+
else
67+
events = 0;
68+
spin_unlock_irq(&dg00x->lock);
69+
70+
return events;
71+
}
72+
73+
static int hwdep_get_info(struct snd_dg00x *dg00x, void __user *arg)
74+
{
75+
struct fw_device *dev = fw_parent_device(dg00x->unit);
76+
struct snd_firewire_get_info info;
77+
78+
memset(&info, 0, sizeof(info));
79+
info.type = SNDRV_FIREWIRE_TYPE_DIGI00X;
80+
info.card = dev->card->index;
81+
*(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
82+
*(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
83+
strlcpy(info.device_name, dev_name(&dev->device),
84+
sizeof(info.device_name));
85+
86+
if (copy_to_user(arg, &info, sizeof(info)))
87+
return -EFAULT;
88+
89+
return 0;
90+
}
91+
92+
static int hwdep_lock(struct snd_dg00x *dg00x)
93+
{
94+
int err;
95+
96+
spin_lock_irq(&dg00x->lock);
97+
98+
if (dg00x->dev_lock_count == 0) {
99+
dg00x->dev_lock_count = -1;
100+
err = 0;
101+
} else {
102+
err = -EBUSY;
103+
}
104+
105+
spin_unlock_irq(&dg00x->lock);
106+
107+
return err;
108+
}
109+
110+
static int hwdep_unlock(struct snd_dg00x *dg00x)
111+
{
112+
int err;
113+
114+
spin_lock_irq(&dg00x->lock);
115+
116+
if (dg00x->dev_lock_count == -1) {
117+
dg00x->dev_lock_count = 0;
118+
err = 0;
119+
} else {
120+
err = -EBADFD;
121+
}
122+
123+
spin_unlock_irq(&dg00x->lock);
124+
125+
return err;
126+
}
127+
128+
static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
129+
{
130+
struct snd_dg00x *dg00x = hwdep->private_data;
131+
132+
spin_lock_irq(&dg00x->lock);
133+
if (dg00x->dev_lock_count == -1)
134+
dg00x->dev_lock_count = 0;
135+
spin_unlock_irq(&dg00x->lock);
136+
137+
return 0;
138+
}
139+
140+
static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
141+
unsigned int cmd, unsigned long arg)
142+
{
143+
struct snd_dg00x *dg00x = hwdep->private_data;
144+
145+
switch (cmd) {
146+
case SNDRV_FIREWIRE_IOCTL_GET_INFO:
147+
return hwdep_get_info(dg00x, (void __user *)arg);
148+
case SNDRV_FIREWIRE_IOCTL_LOCK:
149+
return hwdep_lock(dg00x);
150+
case SNDRV_FIREWIRE_IOCTL_UNLOCK:
151+
return hwdep_unlock(dg00x);
152+
default:
153+
return -ENOIOCTLCMD;
154+
}
155+
}
156+
157+
#ifdef CONFIG_COMPAT
158+
static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
159+
unsigned int cmd, unsigned long arg)
160+
{
161+
return hwdep_ioctl(hwdep, file, cmd,
162+
(unsigned long)compat_ptr(arg));
163+
}
164+
#else
165+
#define hwdep_compat_ioctl NULL
166+
#endif
167+
168+
static const struct snd_hwdep_ops hwdep_ops = {
169+
.read = hwdep_read,
170+
.release = hwdep_release,
171+
.poll = hwdep_poll,
172+
.ioctl = hwdep_ioctl,
173+
.ioctl_compat = hwdep_compat_ioctl,
174+
};
175+
176+
int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x)
177+
{
178+
struct snd_hwdep *hwdep;
179+
int err;
180+
181+
err = snd_hwdep_new(dg00x->card, "Digi00x", 0, &hwdep);
182+
if (err < 0)
183+
return err;
184+
185+
strcpy(hwdep->name, "Digi00x");
186+
hwdep->iface = SNDRV_HWDEP_IFACE_FW_DIGI00X;
187+
hwdep->ops = hwdep_ops;
188+
hwdep->private_data = dg00x;
189+
hwdep->exclusive = true;
190+
191+
return err;
192+
}

sound/firewire/digi00x/digi00x-pcm.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,21 +118,25 @@ static int pcm_open(struct snd_pcm_substream *substream)
118118
unsigned int rate;
119119
int err;
120120

121+
err = snd_dg00x_stream_lock_try(dg00x);
122+
if (err < 0)
123+
goto end;
124+
121125
err = pcm_init_hw_params(dg00x, substream);
122126
if (err < 0)
123-
return err;
127+
goto err_locked;
124128

125129
/* Check current clock source. */
126130
err = snd_dg00x_stream_get_clock(dg00x, &clock);
127131
if (err < 0)
128-
return err;
132+
goto err_locked;
129133
if (clock != SND_DG00X_CLOCK_INTERNAL) {
130134
err = snd_dg00x_stream_check_external_clock(dg00x, &detect);
131135
if (err < 0)
132-
return err;
136+
goto err_locked;
133137
if (!detect) {
134138
err = -EBUSY;
135-
return err;
139+
goto err_locked;
136140
}
137141
}
138142

@@ -141,18 +145,25 @@ static int pcm_open(struct snd_pcm_substream *substream)
141145
amdtp_stream_pcm_running(&dg00x->tx_stream)) {
142146
err = snd_dg00x_stream_get_external_rate(dg00x, &rate);
143147
if (err < 0)
144-
return err;
148+
goto err_locked;
145149
substream->runtime->hw.rate_min = rate;
146150
substream->runtime->hw.rate_max = rate;
147151
}
148152

149153
snd_pcm_set_sync(substream);
150-
154+
end:
155+
return err;
156+
err_locked:
157+
snd_dg00x_stream_lock_release(dg00x);
151158
return err;
152159
}
153160

154161
static int pcm_close(struct snd_pcm_substream *substream)
155162
{
163+
struct snd_dg00x *dg00x = substream->private_data;
164+
165+
snd_dg00x_stream_lock_release(dg00x);
166+
156167
return 0;
157168
}
158169

sound/firewire/digi00x/digi00x-stream.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,3 +379,42 @@ void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x)
379379
amdtp_stream_update(&dg00x->tx_stream);
380380
amdtp_stream_update(&dg00x->rx_stream);
381381
}
382+
383+
void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x)
384+
{
385+
dg00x->dev_lock_changed = true;
386+
wake_up(&dg00x->hwdep_wait);
387+
}
388+
389+
int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x)
390+
{
391+
int err;
392+
393+
spin_lock_irq(&dg00x->lock);
394+
395+
/* user land lock this */
396+
if (dg00x->dev_lock_count < 0) {
397+
err = -EBUSY;
398+
goto end;
399+
}
400+
401+
/* this is the first time */
402+
if (dg00x->dev_lock_count++ == 0)
403+
snd_dg00x_stream_lock_changed(dg00x);
404+
err = 0;
405+
end:
406+
spin_unlock_irq(&dg00x->lock);
407+
return err;
408+
}
409+
410+
void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x)
411+
{
412+
spin_lock_irq(&dg00x->lock);
413+
414+
if (WARN_ON(dg00x->dev_lock_count <= 0))
415+
goto end;
416+
if (--dg00x->dev_lock_count == 0)
417+
snd_dg00x_stream_lock_changed(dg00x);
418+
end:
419+
spin_unlock_irq(&dg00x->lock);
420+
}

sound/firewire/digi00x/digi00x.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ static int snd_dg00x_probe(struct fw_unit *unit,
7272
dg00x->unit = fw_unit_get(unit);
7373

7474
mutex_init(&dg00x->mutex);
75+
spin_lock_init(&dg00x->lock);
76+
init_waitqueue_head(&dg00x->hwdep_wait);
7577

7678
err = name_card(dg00x);
7779
if (err < 0)
@@ -87,6 +89,10 @@ static int snd_dg00x_probe(struct fw_unit *unit,
8789
if (err < 0)
8890
goto error;
8991

92+
err = snd_dg00x_create_hwdep_device(dg00x);
93+
if (err < 0)
94+
goto error;
95+
9096
err = snd_card_register(card);
9197
if (err < 0)
9298
goto error;

sound/firewire/digi00x/digi00x.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
#include <sound/info.h>
2323
#include <sound/pcm.h>
2424
#include <sound/pcm_params.h>
25+
#include <sound/firewire.h>
26+
#include <sound/hwdep.h>
2527

2628
#include "../lib.h"
2729
#include "../iso-resources.h"
@@ -32,6 +34,7 @@ struct snd_dg00x {
3234
struct fw_unit *unit;
3335

3436
struct mutex mutex;
37+
spinlock_t lock;
3538

3639
struct amdtp_stream tx_stream;
3740
struct fw_iso_resources tx_resources;
@@ -40,6 +43,12 @@ struct snd_dg00x {
4043
struct fw_iso_resources rx_resources;
4144

4245
unsigned int substreams_counter;
46+
47+
/* for uapi */
48+
int dev_lock_count;
49+
bool dev_lock_changed;
50+
wait_queue_head_t hwdep_wait;
51+
4352
};
4453

4554
#define DG00X_ADDR_BASE 0xffffe0000000ull
@@ -118,8 +127,13 @@ void snd_dg00x_stream_stop_duplex(struct snd_dg00x *dg00x);
118127
void snd_dg00x_stream_update_duplex(struct snd_dg00x *dg00x);
119128
void snd_dg00x_stream_destroy_duplex(struct snd_dg00x *dg00x);
120129

130+
void snd_dg00x_stream_lock_changed(struct snd_dg00x *dg00x);
131+
int snd_dg00x_stream_lock_try(struct snd_dg00x *dg00x);
132+
void snd_dg00x_stream_lock_release(struct snd_dg00x *dg00x);
133+
121134
void snd_dg00x_proc_init(struct snd_dg00x *dg00x);
122135

123136
int snd_dg00x_create_pcm_devices(struct snd_dg00x *dg00x);
124137

138+
int snd_dg00x_create_hwdep_device(struct snd_dg00x *dg00x);
125139
#endif

0 commit comments

Comments
 (0)