.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * ff.c - a part of driver for RME Fireface series |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2015-2017 Takashi Sakamoto |
---|
5 | | - * |
---|
6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
---|
7 | 6 | */ |
---|
8 | 7 | |
---|
9 | 8 | #include "ff.h" |
---|
.. | .. |
---|
17 | 16 | static void name_card(struct snd_ff *ff) |
---|
18 | 17 | { |
---|
19 | 18 | struct fw_device *fw_dev = fw_parent_device(ff->unit); |
---|
| 19 | + const char *const names[] = { |
---|
| 20 | + [SND_FF_UNIT_VERSION_FF800] = "Fireface800", |
---|
| 21 | + [SND_FF_UNIT_VERSION_FF400] = "Fireface400", |
---|
| 22 | + [SND_FF_UNIT_VERSION_UFX] = "FirefaceUFX", |
---|
| 23 | + [SND_FF_UNIT_VERSION_UCX] = "FirefaceUCX", |
---|
| 24 | + [SND_FF_UNIT_VERSION_802] = "Fireface802", |
---|
| 25 | + }; |
---|
| 26 | + const char *name; |
---|
| 27 | + |
---|
| 28 | + name = names[ff->unit_version]; |
---|
20 | 29 | |
---|
21 | 30 | strcpy(ff->card->driver, "Fireface"); |
---|
22 | | - strcpy(ff->card->shortname, ff->spec->name); |
---|
23 | | - strcpy(ff->card->mixername, ff->spec->name); |
---|
| 31 | + strcpy(ff->card->shortname, name); |
---|
| 32 | + strcpy(ff->card->mixername, name); |
---|
24 | 33 | snprintf(ff->card->longname, sizeof(ff->card->longname), |
---|
25 | | - "RME %s, GUID %08x%08x at %s, S%d", ff->spec->name, |
---|
| 34 | + "RME %s, GUID %08x%08x at %s, S%d", name, |
---|
26 | 35 | fw_dev->config_rom[3], fw_dev->config_rom[4], |
---|
27 | 36 | dev_name(&ff->unit->device), 100 << fw_dev->max_speed); |
---|
28 | 37 | } |
---|
29 | 38 | |
---|
30 | | -static void ff_free(struct snd_ff *ff) |
---|
31 | | -{ |
---|
32 | | - snd_ff_stream_destroy_duplex(ff); |
---|
33 | | - snd_ff_transaction_unregister(ff); |
---|
34 | | - |
---|
35 | | - fw_unit_put(ff->unit); |
---|
36 | | - |
---|
37 | | - mutex_destroy(&ff->mutex); |
---|
38 | | - kfree(ff); |
---|
39 | | -} |
---|
40 | | - |
---|
41 | 39 | static void ff_card_free(struct snd_card *card) |
---|
42 | 40 | { |
---|
43 | | - ff_free(card->private_data); |
---|
| 41 | + struct snd_ff *ff = card->private_data; |
---|
| 42 | + |
---|
| 43 | + snd_ff_stream_destroy_duplex(ff); |
---|
| 44 | + snd_ff_transaction_unregister(ff); |
---|
44 | 45 | } |
---|
45 | 46 | |
---|
46 | 47 | static void do_registration(struct work_struct *work) |
---|
.. | .. |
---|
55 | 56 | &ff->card); |
---|
56 | 57 | if (err < 0) |
---|
57 | 58 | return; |
---|
| 59 | + ff->card->private_free = ff_card_free; |
---|
| 60 | + ff->card->private_data = ff; |
---|
58 | 61 | |
---|
59 | 62 | err = snd_ff_transaction_register(ff); |
---|
60 | 63 | if (err < 0) |
---|
.. | .. |
---|
84 | 87 | if (err < 0) |
---|
85 | 88 | goto error; |
---|
86 | 89 | |
---|
87 | | - ff->card->private_free = ff_card_free; |
---|
88 | | - ff->card->private_data = ff; |
---|
89 | 90 | ff->registered = true; |
---|
90 | 91 | |
---|
91 | 92 | return; |
---|
92 | 93 | error: |
---|
93 | | - snd_ff_transaction_unregister(ff); |
---|
94 | | - snd_ff_stream_destroy_duplex(ff); |
---|
95 | 94 | snd_card_free(ff->card); |
---|
96 | 95 | dev_info(&ff->unit->device, |
---|
97 | 96 | "Sound card registration failed: %d\n", err); |
---|
.. | .. |
---|
102 | 101 | { |
---|
103 | 102 | struct snd_ff *ff; |
---|
104 | 103 | |
---|
105 | | - ff = kzalloc(sizeof(struct snd_ff), GFP_KERNEL); |
---|
106 | | - if (ff == NULL) |
---|
| 104 | + ff = devm_kzalloc(&unit->device, sizeof(struct snd_ff), GFP_KERNEL); |
---|
| 105 | + if (!ff) |
---|
107 | 106 | return -ENOMEM; |
---|
108 | | - |
---|
109 | | - /* initialize myself */ |
---|
110 | 107 | ff->unit = fw_unit_get(unit); |
---|
111 | 108 | dev_set_drvdata(&unit->device, ff); |
---|
112 | 109 | |
---|
.. | .. |
---|
114 | 111 | spin_lock_init(&ff->lock); |
---|
115 | 112 | init_waitqueue_head(&ff->hwdep_wait); |
---|
116 | 113 | |
---|
| 114 | + ff->unit_version = entry->version; |
---|
117 | 115 | ff->spec = (const struct snd_ff_spec *)entry->driver_data; |
---|
118 | 116 | |
---|
119 | 117 | /* Register this sound card later. */ |
---|
.. | .. |
---|
149 | 147 | cancel_work_sync(&ff->dwork.work); |
---|
150 | 148 | |
---|
151 | 149 | if (ff->registered) { |
---|
152 | | - /* No need to wait for releasing card object in this context. */ |
---|
153 | | - snd_card_free_when_closed(ff->card); |
---|
154 | | - } else { |
---|
155 | | - /* Don't forget this case. */ |
---|
156 | | - ff_free(ff); |
---|
| 150 | + // Block till all of ALSA character devices are released. |
---|
| 151 | + snd_card_free(ff->card); |
---|
157 | 152 | } |
---|
| 153 | + |
---|
| 154 | + mutex_destroy(&ff->mutex); |
---|
| 155 | + fw_unit_put(ff->unit); |
---|
158 | 156 | } |
---|
159 | 157 | |
---|
| 158 | +static const struct snd_ff_spec spec_ff800 = { |
---|
| 159 | + .pcm_capture_channels = {28, 20, 12}, |
---|
| 160 | + .pcm_playback_channels = {28, 20, 12}, |
---|
| 161 | + .midi_in_ports = 1, |
---|
| 162 | + .midi_out_ports = 1, |
---|
| 163 | + .protocol = &snd_ff_protocol_ff800, |
---|
| 164 | + .midi_high_addr = 0x000200000320ull, |
---|
| 165 | + .midi_addr_range = 12, |
---|
| 166 | + .midi_rx_addrs = {0x000080180000ull, 0}, |
---|
| 167 | +}; |
---|
| 168 | + |
---|
160 | 169 | static const struct snd_ff_spec spec_ff400 = { |
---|
161 | | - .name = "Fireface400", |
---|
162 | 170 | .pcm_capture_channels = {18, 14, 10}, |
---|
163 | 171 | .pcm_playback_channels = {18, 14, 10}, |
---|
164 | 172 | .midi_in_ports = 2, |
---|
165 | 173 | .midi_out_ports = 2, |
---|
166 | 174 | .protocol = &snd_ff_protocol_ff400, |
---|
| 175 | + .midi_high_addr = 0x0000801003f4ull, |
---|
| 176 | + .midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4, |
---|
| 177 | + .midi_rx_addrs = {0x000080180000ull, 0x000080190000ull}, |
---|
| 178 | +}; |
---|
| 179 | + |
---|
| 180 | +static const struct snd_ff_spec spec_ucx = { |
---|
| 181 | + .pcm_capture_channels = {18, 14, 12}, |
---|
| 182 | + .pcm_playback_channels = {18, 14, 12}, |
---|
| 183 | + .midi_in_ports = 2, |
---|
| 184 | + .midi_out_ports = 2, |
---|
| 185 | + .protocol = &snd_ff_protocol_latter, |
---|
| 186 | + .midi_high_addr = 0xffff00000034ull, |
---|
| 187 | + .midi_addr_range = 0x80, |
---|
| 188 | + .midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull}, |
---|
| 189 | +}; |
---|
| 190 | + |
---|
| 191 | +static const struct snd_ff_spec spec_ufx_802 = { |
---|
| 192 | + .pcm_capture_channels = {30, 22, 14}, |
---|
| 193 | + .pcm_playback_channels = {30, 22, 14}, |
---|
| 194 | + .midi_in_ports = 1, |
---|
| 195 | + .midi_out_ports = 1, |
---|
| 196 | + .protocol = &snd_ff_protocol_latter, |
---|
| 197 | + .midi_high_addr = 0xffff00000034ull, |
---|
| 198 | + .midi_addr_range = 0x80, |
---|
| 199 | + .midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull}, |
---|
167 | 200 | }; |
---|
168 | 201 | |
---|
169 | 202 | static const struct ieee1394_device_id snd_ff_id_table[] = { |
---|
| 203 | + /* Fireface 800 */ |
---|
| 204 | + { |
---|
| 205 | + .match_flags = IEEE1394_MATCH_VENDOR_ID | |
---|
| 206 | + IEEE1394_MATCH_SPECIFIER_ID | |
---|
| 207 | + IEEE1394_MATCH_VERSION | |
---|
| 208 | + IEEE1394_MATCH_MODEL_ID, |
---|
| 209 | + .vendor_id = OUI_RME, |
---|
| 210 | + .specifier_id = OUI_RME, |
---|
| 211 | + .version = SND_FF_UNIT_VERSION_FF800, |
---|
| 212 | + .model_id = 0x101800, |
---|
| 213 | + .driver_data = (kernel_ulong_t)&spec_ff800, |
---|
| 214 | + }, |
---|
170 | 215 | /* Fireface 400 */ |
---|
171 | 216 | { |
---|
172 | 217 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
---|
.. | .. |
---|
174 | 219 | IEEE1394_MATCH_VERSION | |
---|
175 | 220 | IEEE1394_MATCH_MODEL_ID, |
---|
176 | 221 | .vendor_id = OUI_RME, |
---|
177 | | - .specifier_id = 0x000a35, |
---|
178 | | - .version = 0x000002, |
---|
| 222 | + .specifier_id = OUI_RME, |
---|
| 223 | + .version = SND_FF_UNIT_VERSION_FF400, |
---|
179 | 224 | .model_id = 0x101800, |
---|
180 | 225 | .driver_data = (kernel_ulong_t)&spec_ff400, |
---|
| 226 | + }, |
---|
| 227 | + // Fireface UFX. |
---|
| 228 | + { |
---|
| 229 | + .match_flags = IEEE1394_MATCH_VENDOR_ID | |
---|
| 230 | + IEEE1394_MATCH_SPECIFIER_ID | |
---|
| 231 | + IEEE1394_MATCH_VERSION | |
---|
| 232 | + IEEE1394_MATCH_MODEL_ID, |
---|
| 233 | + .vendor_id = OUI_RME, |
---|
| 234 | + .specifier_id = OUI_RME, |
---|
| 235 | + .version = SND_FF_UNIT_VERSION_UFX, |
---|
| 236 | + .model_id = 0x101800, |
---|
| 237 | + .driver_data = (kernel_ulong_t)&spec_ufx_802, |
---|
| 238 | + }, |
---|
| 239 | + // Fireface UCX. |
---|
| 240 | + { |
---|
| 241 | + .match_flags = IEEE1394_MATCH_VENDOR_ID | |
---|
| 242 | + IEEE1394_MATCH_SPECIFIER_ID | |
---|
| 243 | + IEEE1394_MATCH_VERSION | |
---|
| 244 | + IEEE1394_MATCH_MODEL_ID, |
---|
| 245 | + .vendor_id = OUI_RME, |
---|
| 246 | + .specifier_id = OUI_RME, |
---|
| 247 | + .version = SND_FF_UNIT_VERSION_UCX, |
---|
| 248 | + .model_id = 0x101800, |
---|
| 249 | + .driver_data = (kernel_ulong_t)&spec_ucx, |
---|
| 250 | + }, |
---|
| 251 | + // Fireface 802. |
---|
| 252 | + { |
---|
| 253 | + .match_flags = IEEE1394_MATCH_VENDOR_ID | |
---|
| 254 | + IEEE1394_MATCH_SPECIFIER_ID | |
---|
| 255 | + IEEE1394_MATCH_VERSION | |
---|
| 256 | + IEEE1394_MATCH_MODEL_ID, |
---|
| 257 | + .vendor_id = OUI_RME, |
---|
| 258 | + .specifier_id = OUI_RME, |
---|
| 259 | + .version = SND_FF_UNIT_VERSION_802, |
---|
| 260 | + .model_id = 0x101800, |
---|
| 261 | + .driver_data = (kernel_ulong_t)&spec_ufx_802, |
---|
181 | 262 | }, |
---|
182 | 263 | {} |
---|
183 | 264 | }; |
---|
.. | .. |
---|
186 | 267 | static struct fw_driver ff_driver = { |
---|
187 | 268 | .driver = { |
---|
188 | 269 | .owner = THIS_MODULE, |
---|
189 | | - .name = "snd-fireface", |
---|
| 270 | + .name = KBUILD_MODNAME, |
---|
190 | 271 | .bus = &fw_bus_type, |
---|
191 | 272 | }, |
---|
192 | 273 | .probe = snd_ff_probe, |
---|