diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2014-04-25 09:45:09 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-05-26 08:28:01 -0400 |
commit | a63d3ff1059a4d2236521e4fdbafabfc62b4f81a (patch) | |
tree | 4598ead1e5c0f3e3b09881d361cd892475be1b88 /sound/firewire/fireworks | |
parent | 6a22683e89e2c851f754ebbec0f2a53f2967bc07 (diff) |
ALSA: fireworks: Add MIDI interface
This commit adds a functionality to capture/playback MIDI messages.
When no AMDTP streams are running, this driver starts AMDTP stream for MIDI
stream at current sampling rate.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/firewire/fireworks')
-rw-r--r-- | sound/firewire/fireworks/Makefile | 3 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.c | 6 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks.h | 3 | ||||
-rw-r--r-- | sound/firewire/fireworks/fireworks_midi.c | 147 |
4 files changed, 158 insertions, 1 deletions
diff --git a/sound/firewire/fireworks/Makefile b/sound/firewire/fireworks/Makefile index 52bd15e285b0..a2cecc6d8a4a 100644 --- a/sound/firewire/fireworks/Makefile +++ b/sound/firewire/fireworks/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ | 1 | snd-fireworks-objs := fireworks_transaction.o fireworks_command.o \ |
2 | fireworks_stream.o fireworks_proc.o fireworks.o | 2 | fireworks_stream.o fireworks_proc.o fireworks_midi.o \ |
3 | fireworks.o | ||
3 | obj-m += snd-fireworks.o | 4 | obj-m += snd-fireworks.o |
diff --git a/sound/firewire/fireworks/fireworks.c b/sound/firewire/fireworks/fireworks.c index 311e4a6ef0a6..9204c7c56513 100644 --- a/sound/firewire/fireworks/fireworks.c +++ b/sound/firewire/fireworks/fireworks.c | |||
@@ -226,6 +226,12 @@ efw_probe(struct fw_unit *unit, | |||
226 | 226 | ||
227 | snd_efw_proc_init(efw); | 227 | snd_efw_proc_init(efw); |
228 | 228 | ||
229 | if (efw->midi_out_ports || efw->midi_in_ports) { | ||
230 | err = snd_efw_create_midi_devices(efw); | ||
231 | if (err < 0) | ||
232 | goto error; | ||
233 | } | ||
234 | |||
229 | err = snd_efw_stream_init_duplex(efw); | 235 | err = snd_efw_stream_init_duplex(efw); |
230 | if (err < 0) | 236 | if (err < 0) |
231 | goto error; | 237 | goto error; |
diff --git a/sound/firewire/fireworks/fireworks.h b/sound/firewire/fireworks/fireworks.h index eef7ad89fd4e..d1819696754d 100644 --- a/sound/firewire/fireworks/fireworks.h +++ b/sound/firewire/fireworks/fireworks.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <sound/initval.h> | 22 | #include <sound/initval.h> |
23 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
24 | #include <sound/info.h> | 24 | #include <sound/info.h> |
25 | #include <sound/rawmidi.h> | ||
25 | 26 | ||
26 | #include "../packets-buffer.h" | 27 | #include "../packets-buffer.h" |
27 | #include "../iso-resources.h" | 28 | #include "../iso-resources.h" |
@@ -198,6 +199,8 @@ void snd_efw_stream_destroy_duplex(struct snd_efw *efw); | |||
198 | 199 | ||
199 | void snd_efw_proc_init(struct snd_efw *efw); | 200 | void snd_efw_proc_init(struct snd_efw *efw); |
200 | 201 | ||
202 | int snd_efw_create_midi_devices(struct snd_efw *efw); | ||
203 | |||
201 | #define SND_EFW_DEV_ENTRY(vendor, model) \ | 204 | #define SND_EFW_DEV_ENTRY(vendor, model) \ |
202 | { \ | 205 | { \ |
203 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ | 206 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ |
diff --git a/sound/firewire/fireworks/fireworks_midi.c b/sound/firewire/fireworks/fireworks_midi.c new file mode 100644 index 000000000000..cbf34e99237f --- /dev/null +++ b/sound/firewire/fireworks/fireworks_midi.c | |||
@@ -0,0 +1,147 @@ | |||
1 | /* | ||
2 | * fireworks_midi.c - a part of driver for Fireworks based devices | ||
3 | * | ||
4 | * Copyright (c) 2009-2010 Clemens Ladisch | ||
5 | * Copyright (c) 2013-2014 Takashi Sakamoto | ||
6 | * | ||
7 | * Licensed under the terms of the GNU General Public License, version 2. | ||
8 | */ | ||
9 | #include "fireworks.h" | ||
10 | |||
11 | static int midi_capture_open(struct snd_rawmidi_substream *substream) | ||
12 | { | ||
13 | struct snd_efw *efw = substream->rmidi->private_data; | ||
14 | |||
15 | atomic_inc(&efw->capture_substreams); | ||
16 | return snd_efw_stream_start_duplex(efw, 0); | ||
17 | } | ||
18 | |||
19 | static int midi_playback_open(struct snd_rawmidi_substream *substream) | ||
20 | { | ||
21 | struct snd_efw *efw = substream->rmidi->private_data; | ||
22 | |||
23 | atomic_inc(&efw->playback_substreams); | ||
24 | return snd_efw_stream_start_duplex(efw, 0); | ||
25 | } | ||
26 | |||
27 | static int midi_capture_close(struct snd_rawmidi_substream *substream) | ||
28 | { | ||
29 | struct snd_efw *efw = substream->rmidi->private_data; | ||
30 | |||
31 | atomic_dec(&efw->capture_substreams); | ||
32 | snd_efw_stream_stop_duplex(efw); | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | static int midi_playback_close(struct snd_rawmidi_substream *substream) | ||
38 | { | ||
39 | struct snd_efw *efw = substream->rmidi->private_data; | ||
40 | |||
41 | atomic_dec(&efw->playback_substreams); | ||
42 | snd_efw_stream_stop_duplex(efw); | ||
43 | |||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
48 | { | ||
49 | struct snd_efw *efw = substrm->rmidi->private_data; | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&efw->lock, flags); | ||
53 | |||
54 | if (up) | ||
55 | amdtp_stream_midi_trigger(&efw->tx_stream, | ||
56 | substrm->number, substrm); | ||
57 | else | ||
58 | amdtp_stream_midi_trigger(&efw->tx_stream, | ||
59 | substrm->number, NULL); | ||
60 | |||
61 | spin_unlock_irqrestore(&efw->lock, flags); | ||
62 | } | ||
63 | |||
64 | static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up) | ||
65 | { | ||
66 | struct snd_efw *efw = substrm->rmidi->private_data; | ||
67 | unsigned long flags; | ||
68 | |||
69 | spin_lock_irqsave(&efw->lock, flags); | ||
70 | |||
71 | if (up) | ||
72 | amdtp_stream_midi_trigger(&efw->rx_stream, | ||
73 | substrm->number, substrm); | ||
74 | else | ||
75 | amdtp_stream_midi_trigger(&efw->rx_stream, | ||
76 | substrm->number, NULL); | ||
77 | |||
78 | spin_unlock_irqrestore(&efw->lock, flags); | ||
79 | } | ||
80 | |||
81 | static struct snd_rawmidi_ops midi_capture_ops = { | ||
82 | .open = midi_capture_open, | ||
83 | .close = midi_capture_close, | ||
84 | .trigger = midi_capture_trigger, | ||
85 | }; | ||
86 | |||
87 | static struct snd_rawmidi_ops midi_playback_ops = { | ||
88 | .open = midi_playback_open, | ||
89 | .close = midi_playback_close, | ||
90 | .trigger = midi_playback_trigger, | ||
91 | }; | ||
92 | |||
93 | static void set_midi_substream_names(struct snd_efw *efw, | ||
94 | struct snd_rawmidi_str *str) | ||
95 | { | ||
96 | struct snd_rawmidi_substream *subs; | ||
97 | |||
98 | list_for_each_entry(subs, &str->substreams, list) { | ||
99 | snprintf(subs->name, sizeof(subs->name), | ||
100 | "%s MIDI %d", efw->card->shortname, subs->number + 1); | ||
101 | } | ||
102 | } | ||
103 | |||
104 | int snd_efw_create_midi_devices(struct snd_efw *efw) | ||
105 | { | ||
106 | struct snd_rawmidi *rmidi; | ||
107 | struct snd_rawmidi_str *str; | ||
108 | int err; | ||
109 | |||
110 | /* create midi ports */ | ||
111 | err = snd_rawmidi_new(efw->card, efw->card->driver, 0, | ||
112 | efw->midi_out_ports, efw->midi_in_ports, | ||
113 | &rmidi); | ||
114 | if (err < 0) | ||
115 | return err; | ||
116 | |||
117 | snprintf(rmidi->name, sizeof(rmidi->name), | ||
118 | "%s MIDI", efw->card->shortname); | ||
119 | rmidi->private_data = efw; | ||
120 | |||
121 | if (efw->midi_in_ports > 0) { | ||
122 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT; | ||
123 | |||
124 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, | ||
125 | &midi_capture_ops); | ||
126 | |||
127 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT]; | ||
128 | |||
129 | set_midi_substream_names(efw, str); | ||
130 | } | ||
131 | |||
132 | if (efw->midi_out_ports > 0) { | ||
133 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT; | ||
134 | |||
135 | snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, | ||
136 | &midi_playback_ops); | ||
137 | |||
138 | str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]; | ||
139 | |||
140 | set_midi_substream_names(efw, str); | ||
141 | } | ||
142 | |||
143 | if ((efw->midi_out_ports > 0) && (efw->midi_in_ports > 0)) | ||
144 | rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; | ||
145 | |||
146 | return 0; | ||
147 | } | ||