aboutsummaryrefslogtreecommitdiffstats
path: root/sound/firewire/bebob
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2014-04-25 09:45:20 -0400
committerTakashi Iwai <tiwai@suse.de>2014-05-26 08:31:03 -0400
commit618eabeae711c56d376daa147c6a684116d68705 (patch)
tree5c3aae69f57c84a57437645d40bcd7c0f1b18e67 /sound/firewire/bebob
parentfbbebd2c40795e87f1280ca4d963f7cbe1c83168 (diff)
ALSA: bebob: Add hwdep interface
This interface is designed for mixer/control application. By using hwdep interface, the 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 <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/bebob')
-rw-r--r--sound/firewire/bebob/Makefile2
-rw-r--r--sound/firewire/bebob/bebob.c5
-rw-r--r--sound/firewire/bebob/bebob.h13
-rw-r--r--sound/firewire/bebob/bebob_hwdep.c199
-rw-r--r--sound/firewire/bebob/bebob_midi.c24
-rw-r--r--sound/firewire/bebob/bebob_pcm.c16
-rw-r--r--sound/firewire/bebob/bebob_stream.c39
7 files changed, 291 insertions, 7 deletions
diff --git a/sound/firewire/bebob/Makefile b/sound/firewire/bebob/Makefile
index 533718a5c1e5..78087772a022 100644
--- a/sound/firewire/bebob/Makefile
+++ b/sound/firewire/bebob/Makefile
@@ -1,4 +1,4 @@
1snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \ 1snd-bebob-objs := bebob_command.o bebob_stream.o bebob_proc.o bebob_midi.o \
2 bebob_pcm.o \ 2 bebob_pcm.o bebob_hwdep.o \
3 bebob.o 3 bebob.o
4obj-m += snd-bebob.o 4obj-m += snd-bebob.o
diff --git a/sound/firewire/bebob/bebob.c b/sound/firewire/bebob/bebob.c
index dbd12c360046..b7d70c2e4e87 100644
--- a/sound/firewire/bebob/bebob.c
+++ b/sound/firewire/bebob/bebob.c
@@ -153,6 +153,7 @@ bebob_probe(struct fw_unit *unit,
153 bebob->unit = unit; 153 bebob->unit = unit;
154 mutex_init(&bebob->mutex); 154 mutex_init(&bebob->mutex);
155 spin_lock_init(&bebob->lock); 155 spin_lock_init(&bebob->lock);
156 init_waitqueue_head(&bebob->hwdep_wait);
156 157
157 err = name_device(bebob, entry->vendor_id); 158 err = name_device(bebob, entry->vendor_id);
158 if (err < 0) 159 if (err < 0)
@@ -175,6 +176,10 @@ bebob_probe(struct fw_unit *unit,
175 if (err < 0) 176 if (err < 0)
176 goto error; 177 goto error;
177 178
179 err = snd_bebob_create_hwdep_device(bebob);
180 if (err < 0)
181 goto error;
182
178 err = snd_bebob_stream_init_duplex(bebob); 183 err = snd_bebob_stream_init_duplex(bebob);
179 if (err < 0) 184 if (err < 0)
180 goto error; 185 goto error;
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index b41bb913bac5..e8a5e447ff17 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -24,6 +24,8 @@
24#include <sound/rawmidi.h> 24#include <sound/rawmidi.h>
25#include <sound/pcm.h> 25#include <sound/pcm.h>
26#include <sound/pcm_params.h> 26#include <sound/pcm_params.h>
27#include <sound/firewire.h>
28#include <sound/hwdep.h>
27 29
28#include "../lib.h" 30#include "../lib.h"
29#include "../fcp.h" 31#include "../fcp.h"
@@ -75,6 +77,11 @@ struct snd_bebob {
75 rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES]; 77 rx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
76 78
77 int sync_input_plug; 79 int sync_input_plug;
80
81 /* for uapi */
82 int dev_lock_count;
83 bool dev_lock_changed;
84 wait_queue_head_t hwdep_wait;
78}; 85};
79 86
80static inline int 87static inline int
@@ -175,12 +182,18 @@ void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob);
175void snd_bebob_stream_update_duplex(struct snd_bebob *bebob); 182void snd_bebob_stream_update_duplex(struct snd_bebob *bebob);
176void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob); 183void snd_bebob_stream_destroy_duplex(struct snd_bebob *bebob);
177 184
185void snd_bebob_stream_lock_changed(struct snd_bebob *bebob);
186int snd_bebob_stream_lock_try(struct snd_bebob *bebob);
187void snd_bebob_stream_lock_release(struct snd_bebob *bebob);
188
178void snd_bebob_proc_init(struct snd_bebob *bebob); 189void snd_bebob_proc_init(struct snd_bebob *bebob);
179 190
180int snd_bebob_create_midi_devices(struct snd_bebob *bebob); 191int snd_bebob_create_midi_devices(struct snd_bebob *bebob);
181 192
182int snd_bebob_create_pcm_devices(struct snd_bebob *bebob); 193int snd_bebob_create_pcm_devices(struct snd_bebob *bebob);
183 194
195int snd_bebob_create_hwdep_device(struct snd_bebob *bebob);
196
184#define SND_BEBOB_DEV_ENTRY(vendor, model) \ 197#define SND_BEBOB_DEV_ENTRY(vendor, model) \
185{ \ 198{ \
186 .match_flags = IEEE1394_MATCH_VENDOR_ID | \ 199 .match_flags = IEEE1394_MATCH_VENDOR_ID | \
diff --git a/sound/firewire/bebob/bebob_hwdep.c b/sound/firewire/bebob/bebob_hwdep.c
new file mode 100644
index 000000000000..ce731f4d8b4f
--- /dev/null
+++ b/sound/firewire/bebob/bebob_hwdep.c
@@ -0,0 +1,199 @@
1/*
2 * bebob_hwdep.c - a part of driver for BeBoB based devices
3 *
4 * Copyright (c) 2013-2014 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 infomation
13 * 2.get notification about starting/stopping stream
14 * 3.lock/unlock stream
15 */
16
17#include "bebob.h"
18
19static long
20hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
21 loff_t *offset)
22{
23 struct snd_bebob *bebob = hwdep->private_data;
24 DEFINE_WAIT(wait);
25 union snd_firewire_event event;
26
27 spin_lock_irq(&bebob->lock);
28
29 while (!bebob->dev_lock_changed) {
30 prepare_to_wait(&bebob->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
31 spin_unlock_irq(&bebob->lock);
32 schedule();
33 finish_wait(&bebob->hwdep_wait, &wait);
34 if (signal_pending(current))
35 return -ERESTARTSYS;
36 spin_lock_irq(&bebob->lock);
37 }
38
39 memset(&event, 0, sizeof(event));
40 if (bebob->dev_lock_changed) {
41 event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
42 event.lock_status.status = (bebob->dev_lock_count > 0);
43 bebob->dev_lock_changed = false;
44
45 count = min_t(long, count, sizeof(event.lock_status));
46 }
47
48 spin_unlock_irq(&bebob->lock);
49
50 if (copy_to_user(buf, &event, count))
51 return -EFAULT;
52
53 return count;
54}
55
56static unsigned int
57hwdep_poll(struct snd_hwdep *hwdep, struct file *file, poll_table *wait)
58{
59 struct snd_bebob *bebob = hwdep->private_data;
60 unsigned int events;
61
62 poll_wait(file, &bebob->hwdep_wait, wait);
63
64 spin_lock_irq(&bebob->lock);
65 if (bebob->dev_lock_changed)
66 events = POLLIN | POLLRDNORM;
67 else
68 events = 0;
69 spin_unlock_irq(&bebob->lock);
70
71 return events;
72}
73
74static int
75hwdep_get_info(struct snd_bebob *bebob, void __user *arg)
76{
77 struct fw_device *dev = fw_parent_device(bebob->unit);
78 struct snd_firewire_get_info info;
79
80 memset(&info, 0, sizeof(info));
81 info.type = SNDRV_FIREWIRE_TYPE_BEBOB;
82 info.card = dev->card->index;
83 *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
84 *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
85 strlcpy(info.device_name, dev_name(&dev->device),
86 sizeof(info.device_name));
87
88 if (copy_to_user(arg, &info, sizeof(info)))
89 return -EFAULT;
90
91 return 0;
92}
93
94static int
95hwdep_lock(struct snd_bebob *bebob)
96{
97 int err;
98
99 spin_lock_irq(&bebob->lock);
100
101 if (bebob->dev_lock_count == 0) {
102 bebob->dev_lock_count = -1;
103 err = 0;
104 } else {
105 err = -EBUSY;
106 }
107
108 spin_unlock_irq(&bebob->lock);
109
110 return err;
111}
112
113static int
114hwdep_unlock(struct snd_bebob *bebob)
115{
116 int err;
117
118 spin_lock_irq(&bebob->lock);
119
120 if (bebob->dev_lock_count == -1) {
121 bebob->dev_lock_count = 0;
122 err = 0;
123 } else {
124 err = -EBADFD;
125 }
126
127 spin_unlock_irq(&bebob->lock);
128
129 return err;
130}
131
132static int
133hwdep_release(struct snd_hwdep *hwdep, struct file *file)
134{
135 struct snd_bebob *bebob = hwdep->private_data;
136
137 spin_lock_irq(&bebob->lock);
138 if (bebob->dev_lock_count == -1)
139 bebob->dev_lock_count = 0;
140 spin_unlock_irq(&bebob->lock);
141
142 return 0;
143}
144
145static int
146hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
147 unsigned int cmd, unsigned long arg)
148{
149 struct snd_bebob *bebob = hwdep->private_data;
150
151 switch (cmd) {
152 case SNDRV_FIREWIRE_IOCTL_GET_INFO:
153 return hwdep_get_info(bebob, (void __user *)arg);
154 case SNDRV_FIREWIRE_IOCTL_LOCK:
155 return hwdep_lock(bebob);
156 case SNDRV_FIREWIRE_IOCTL_UNLOCK:
157 return hwdep_unlock(bebob);
158 default:
159 return -ENOIOCTLCMD;
160 }
161}
162
163#ifdef CONFIG_COMPAT
164static int
165hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
166 unsigned int cmd, unsigned long arg)
167{
168 return hwdep_ioctl(hwdep, file, cmd,
169 (unsigned long)compat_ptr(arg));
170}
171#else
172#define hwdep_compat_ioctl NULL
173#endif
174
175static const struct snd_hwdep_ops hwdep_ops = {
176 .read = hwdep_read,
177 .release = hwdep_release,
178 .poll = hwdep_poll,
179 .ioctl = hwdep_ioctl,
180 .ioctl_compat = hwdep_compat_ioctl,
181};
182
183int snd_bebob_create_hwdep_device(struct snd_bebob *bebob)
184{
185 struct snd_hwdep *hwdep;
186 int err;
187
188 err = snd_hwdep_new(bebob->card, "BeBoB", 0, &hwdep);
189 if (err < 0)
190 goto end;
191 strcpy(hwdep->name, "BeBoB");
192 hwdep->iface = SNDRV_HWDEP_IFACE_FW_BEBOB;
193 hwdep->ops = hwdep_ops;
194 hwdep->private_data = bebob;
195 hwdep->exclusive = true;
196end:
197 return err;
198}
199
diff --git a/sound/firewire/bebob/bebob_midi.c b/sound/firewire/bebob/bebob_midi.c
index 120a61b90c59..c04cea2c19a6 100644
--- a/sound/firewire/bebob/bebob_midi.c
+++ b/sound/firewire/bebob/bebob_midi.c
@@ -11,17 +11,35 @@
11static int midi_capture_open(struct snd_rawmidi_substream *substream) 11static int midi_capture_open(struct snd_rawmidi_substream *substream)
12{ 12{
13 struct snd_bebob *bebob = substream->rmidi->private_data; 13 struct snd_bebob *bebob = substream->rmidi->private_data;
14 int err;
15
16 err = snd_bebob_stream_lock_try(bebob);
17 if (err < 0)
18 goto end;
14 19
15 atomic_inc(&bebob->capture_substreams); 20 atomic_inc(&bebob->capture_substreams);
16 return snd_bebob_stream_start_duplex(bebob, 0); 21 err = snd_bebob_stream_start_duplex(bebob, 0);
22 if (err < 0)
23 snd_bebob_stream_lock_release(bebob);
24end:
25 return err;
17} 26}
18 27
19static int midi_playback_open(struct snd_rawmidi_substream *substream) 28static int midi_playback_open(struct snd_rawmidi_substream *substream)
20{ 29{
21 struct snd_bebob *bebob = substream->rmidi->private_data; 30 struct snd_bebob *bebob = substream->rmidi->private_data;
31 int err;
32
33 err = snd_bebob_stream_lock_try(bebob);
34 if (err < 0)
35 goto end;
22 36
23 atomic_inc(&bebob->playback_substreams); 37 atomic_inc(&bebob->playback_substreams);
24 return snd_bebob_stream_start_duplex(bebob, 0); 38 err = snd_bebob_stream_start_duplex(bebob, 0);
39 if (err < 0)
40 snd_bebob_stream_lock_release(bebob);
41end:
42 return err;
25} 43}
26 44
27static int midi_capture_close(struct snd_rawmidi_substream *substream) 45static int midi_capture_close(struct snd_rawmidi_substream *substream)
@@ -31,6 +49,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
31 atomic_dec(&bebob->capture_substreams); 49 atomic_dec(&bebob->capture_substreams);
32 snd_bebob_stream_stop_duplex(bebob); 50 snd_bebob_stream_stop_duplex(bebob);
33 51
52 snd_bebob_stream_lock_release(bebob);
34 return 0; 53 return 0;
35} 54}
36 55
@@ -41,6 +60,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
41 atomic_dec(&bebob->playback_substreams); 60 atomic_dec(&bebob->playback_substreams);
42 snd_bebob_stream_stop_duplex(bebob); 61 snd_bebob_stream_stop_duplex(bebob);
43 62
63 snd_bebob_stream_lock_release(bebob);
44 return 0; 64 return 0;
45} 65}
46 66
diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c
index 7474309dad87..9d868171db4e 100644
--- a/sound/firewire/bebob/bebob_pcm.c
+++ b/sound/firewire/bebob/bebob_pcm.c
@@ -159,13 +159,17 @@ pcm_open(struct snd_pcm_substream *substream)
159 bool internal; 159 bool internal;
160 int err; 160 int err;
161 161
162 err = pcm_init_hw_params(bebob, substream); 162 err = snd_bebob_stream_lock_try(bebob);
163 if (err < 0) 163 if (err < 0)
164 goto end; 164 goto end;
165 165
166 err = pcm_init_hw_params(bebob, substream);
167 if (err < 0)
168 goto err_locked;
169
166 err = snd_bebob_stream_check_internal_clock(bebob, &internal); 170 err = snd_bebob_stream_check_internal_clock(bebob, &internal);
167 if (err < 0) 171 if (err < 0)
168 goto end; 172 goto err_locked;
169 173
170 /* 174 /*
171 * When source of clock is internal or any PCM stream are running, 175 * When source of clock is internal or any PCM stream are running,
@@ -178,7 +182,7 @@ pcm_open(struct snd_pcm_substream *substream)
178 if (err < 0) { 182 if (err < 0) {
179 dev_err(&bebob->unit->device, 183 dev_err(&bebob->unit->device,
180 "fail to get sampling rate: %d\n", err); 184 "fail to get sampling rate: %d\n", err);
181 goto end; 185 goto err_locked;
182 } 186 }
183 187
184 substream->runtime->hw.rate_min = sampling_rate; 188 substream->runtime->hw.rate_min = sampling_rate;
@@ -186,14 +190,18 @@ pcm_open(struct snd_pcm_substream *substream)
186 } 190 }
187 191
188 snd_pcm_set_sync(substream); 192 snd_pcm_set_sync(substream);
189
190end: 193end:
191 return err; 194 return err;
195err_locked:
196 snd_bebob_stream_lock_release(bebob);
197 return err;
192} 198}
193 199
194static int 200static int
195pcm_close(struct snd_pcm_substream *substream) 201pcm_close(struct snd_pcm_substream *substream)
196{ 202{
203 struct snd_bebob *bebob = substream->private_data;
204 snd_bebob_stream_lock_release(bebob);
197 return 0; 205 return 0;
198} 206}
199 207
diff --git a/sound/firewire/bebob/bebob_stream.c b/sound/firewire/bebob/bebob_stream.c
index 46b056c8f2a8..85b4fd661787 100644
--- a/sound/firewire/bebob/bebob_stream.c
+++ b/sound/firewire/bebob/bebob_stream.c
@@ -912,3 +912,42 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob)
912end: 912end:
913 return err; 913 return err;
914} 914}
915
916void snd_bebob_stream_lock_changed(struct snd_bebob *bebob)
917{
918 bebob->dev_lock_changed = true;
919 wake_up(&bebob->hwdep_wait);
920}
921
922int snd_bebob_stream_lock_try(struct snd_bebob *bebob)
923{
924 int err;
925
926 spin_lock_irq(&bebob->lock);
927
928 /* user land lock this */
929 if (bebob->dev_lock_count < 0) {
930 err = -EBUSY;
931 goto end;
932 }
933
934 /* this is the first time */
935 if (bebob->dev_lock_count++ == 0)
936 snd_bebob_stream_lock_changed(bebob);
937 err = 0;
938end:
939 spin_unlock_irq(&bebob->lock);
940 return err;
941}
942
943void snd_bebob_stream_lock_release(struct snd_bebob *bebob)
944{
945 spin_lock_irq(&bebob->lock);
946
947 if (WARN_ON(bebob->dev_lock_count <= 0))
948 goto end;
949 if (--bebob->dev_lock_count == 0)
950 snd_bebob_stream_lock_changed(bebob);
951end:
952 spin_unlock_irq(&bebob->lock);
953}