| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * motu.c - a part of driver for MOTU FireWire series |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> |
|---|
| 5 | | - * |
|---|
| 6 | | - * Licensed under the terms of the GNU General Public License, version 2. |
|---|
| 7 | 6 | */ |
|---|
| 8 | 7 | |
|---|
| 9 | 8 | #include "motu.h" |
|---|
| .. | .. |
|---|
| 52 | 51 | dev_name(&motu->unit->device), 100 << fw_dev->max_speed); |
|---|
| 53 | 52 | } |
|---|
| 54 | 53 | |
|---|
| 55 | | -static void motu_free(struct snd_motu *motu) |
|---|
| 56 | | -{ |
|---|
| 57 | | - snd_motu_transaction_unregister(motu); |
|---|
| 58 | | - |
|---|
| 59 | | - snd_motu_stream_destroy_duplex(motu); |
|---|
| 60 | | - fw_unit_put(motu->unit); |
|---|
| 61 | | - |
|---|
| 62 | | - mutex_destroy(&motu->mutex); |
|---|
| 63 | | - kfree(motu); |
|---|
| 64 | | -} |
|---|
| 65 | | - |
|---|
| 66 | | -/* |
|---|
| 67 | | - * This module releases the FireWire unit data after all ALSA character devices |
|---|
| 68 | | - * are released by applications. This is for releasing stream data or finishing |
|---|
| 69 | | - * transactions safely. Thus at returning from .remove(), this module still keep |
|---|
| 70 | | - * references for the unit. |
|---|
| 71 | | - */ |
|---|
| 72 | 54 | static void motu_card_free(struct snd_card *card) |
|---|
| 73 | 55 | { |
|---|
| 74 | | - motu_free(card->private_data); |
|---|
| 56 | + struct snd_motu *motu = card->private_data; |
|---|
| 57 | + |
|---|
| 58 | + snd_motu_transaction_unregister(motu); |
|---|
| 59 | + snd_motu_stream_destroy_duplex(motu); |
|---|
| 75 | 60 | } |
|---|
| 76 | 61 | |
|---|
| 77 | 62 | static void do_registration(struct work_struct *work) |
|---|
| .. | .. |
|---|
| 86 | 71 | &motu->card); |
|---|
| 87 | 72 | if (err < 0) |
|---|
| 88 | 73 | return; |
|---|
| 74 | + motu->card->private_free = motu_card_free; |
|---|
| 75 | + motu->card->private_data = motu; |
|---|
| 89 | 76 | |
|---|
| 90 | 77 | name_card(motu); |
|---|
| 91 | 78 | |
|---|
| .. | .. |
|---|
| 120 | 107 | if (err < 0) |
|---|
| 121 | 108 | goto error; |
|---|
| 122 | 109 | |
|---|
| 123 | | - /* |
|---|
| 124 | | - * After registered, motu instance can be released corresponding to |
|---|
| 125 | | - * releasing the sound card instance. |
|---|
| 126 | | - */ |
|---|
| 127 | | - motu->card->private_free = motu_card_free; |
|---|
| 128 | | - motu->card->private_data = motu; |
|---|
| 129 | 110 | motu->registered = true; |
|---|
| 130 | 111 | |
|---|
| 131 | 112 | return; |
|---|
| 132 | 113 | error: |
|---|
| 133 | | - snd_motu_transaction_unregister(motu); |
|---|
| 134 | | - snd_motu_stream_destroy_duplex(motu); |
|---|
| 135 | 114 | snd_card_free(motu->card); |
|---|
| 136 | 115 | dev_info(&motu->unit->device, |
|---|
| 137 | 116 | "Sound card registration failed: %d\n", err); |
|---|
| .. | .. |
|---|
| 143 | 122 | struct snd_motu *motu; |
|---|
| 144 | 123 | |
|---|
| 145 | 124 | /* Allocate this independently of sound card instance. */ |
|---|
| 146 | | - motu = kzalloc(sizeof(struct snd_motu), GFP_KERNEL); |
|---|
| 147 | | - if (motu == NULL) |
|---|
| 125 | + motu = devm_kzalloc(&unit->device, sizeof(struct snd_motu), GFP_KERNEL); |
|---|
| 126 | + if (!motu) |
|---|
| 148 | 127 | return -ENOMEM; |
|---|
| 149 | | - |
|---|
| 150 | | - motu->spec = (const struct snd_motu_spec *)entry->driver_data; |
|---|
| 151 | 128 | motu->unit = fw_unit_get(unit); |
|---|
| 152 | 129 | dev_set_drvdata(&unit->device, motu); |
|---|
| 153 | 130 | |
|---|
| 131 | + motu->spec = (const struct snd_motu_spec *)entry->driver_data; |
|---|
| 154 | 132 | mutex_init(&motu->mutex); |
|---|
| 155 | 133 | spin_lock_init(&motu->lock); |
|---|
| 156 | 134 | init_waitqueue_head(&motu->hwdep_wait); |
|---|
| .. | .. |
|---|
| 174 | 152 | cancel_delayed_work_sync(&motu->dwork); |
|---|
| 175 | 153 | |
|---|
| 176 | 154 | if (motu->registered) { |
|---|
| 177 | | - /* No need to wait for releasing card object in this context. */ |
|---|
| 178 | | - snd_card_free_when_closed(motu->card); |
|---|
| 179 | | - } else { |
|---|
| 180 | | - /* Don't forget this case. */ |
|---|
| 181 | | - motu_free(motu); |
|---|
| 155 | + // Block till all of ALSA character devices are released. |
|---|
| 156 | + snd_card_free(motu->card); |
|---|
| 182 | 157 | } |
|---|
| 158 | + |
|---|
| 159 | + mutex_destroy(&motu->mutex); |
|---|
| 160 | + fw_unit_put(motu->unit); |
|---|
| 183 | 161 | } |
|---|
| 184 | 162 | |
|---|
| 185 | 163 | static void motu_bus_update(struct fw_unit *unit) |
|---|
| .. | .. |
|---|
| 194 | 172 | snd_motu_transaction_reregister(motu); |
|---|
| 195 | 173 | } |
|---|
| 196 | 174 | |
|---|
| 197 | | -static const struct snd_motu_spec motu_828mk2 = { |
|---|
| 198 | | - .name = "828mk2", |
|---|
| 199 | | - .protocol = &snd_motu_protocol_v2, |
|---|
| 200 | | - .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | |
|---|
| 201 | | - SND_MOTU_SPEC_TX_MICINST_CHUNK | |
|---|
| 202 | | - SND_MOTU_SPEC_TX_RETURN_CHUNK | |
|---|
| 203 | | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | |
|---|
| 204 | | - SND_MOTU_SPEC_HAS_OPT_IFACE_A | |
|---|
| 205 | | - SND_MOTU_SPEC_RX_MIDI_2ND_Q | |
|---|
| 206 | | - SND_MOTU_SPEC_TX_MIDI_2ND_Q, |
|---|
| 207 | | - |
|---|
| 208 | | - .analog_in_ports = 8, |
|---|
| 209 | | - .analog_out_ports = 8, |
|---|
| 210 | | -}; |
|---|
| 211 | | - |
|---|
| 212 | | -const struct snd_motu_spec snd_motu_spec_traveler = { |
|---|
| 213 | | - .name = "Traveler", |
|---|
| 214 | | - .protocol = &snd_motu_protocol_v2, |
|---|
| 215 | | - .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | |
|---|
| 216 | | - SND_MOTU_SPEC_SUPPORT_CLOCK_X4 | |
|---|
| 217 | | - SND_MOTU_SPEC_TX_RETURN_CHUNK | |
|---|
| 218 | | - SND_MOTU_SPEC_HAS_AESEBU_IFACE | |
|---|
| 219 | | - SND_MOTU_SPEC_HAS_OPT_IFACE_A | |
|---|
| 220 | | - SND_MOTU_SPEC_RX_MIDI_2ND_Q | |
|---|
| 221 | | - SND_MOTU_SPEC_TX_MIDI_2ND_Q, |
|---|
| 222 | | - |
|---|
| 223 | | - .analog_in_ports = 8, |
|---|
| 224 | | - .analog_out_ports = 8, |
|---|
| 225 | | -}; |
|---|
| 226 | | - |
|---|
| 227 | | -static const struct snd_motu_spec motu_828mk3 = { |
|---|
| 228 | | - .name = "828mk3", |
|---|
| 229 | | - .protocol = &snd_motu_protocol_v3, |
|---|
| 230 | | - .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | |
|---|
| 231 | | - SND_MOTU_SPEC_SUPPORT_CLOCK_X4 | |
|---|
| 232 | | - SND_MOTU_SPEC_TX_MICINST_CHUNK | |
|---|
| 233 | | - SND_MOTU_SPEC_TX_RETURN_CHUNK | |
|---|
| 234 | | - SND_MOTU_SPEC_TX_REVERB_CHUNK | |
|---|
| 235 | | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | |
|---|
| 236 | | - SND_MOTU_SPEC_HAS_OPT_IFACE_A | |
|---|
| 237 | | - SND_MOTU_SPEC_HAS_OPT_IFACE_B | |
|---|
| 238 | | - SND_MOTU_SPEC_RX_MIDI_3RD_Q | |
|---|
| 239 | | - SND_MOTU_SPEC_TX_MIDI_3RD_Q, |
|---|
| 240 | | - |
|---|
| 241 | | - .analog_in_ports = 8, |
|---|
| 242 | | - .analog_out_ports = 8, |
|---|
| 243 | | -}; |
|---|
| 244 | | - |
|---|
| 245 | | -static const struct snd_motu_spec motu_audio_express = { |
|---|
| 246 | | - .name = "AudioExpress", |
|---|
| 247 | | - .protocol = &snd_motu_protocol_v3, |
|---|
| 248 | | - .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | |
|---|
| 249 | | - SND_MOTU_SPEC_TX_MICINST_CHUNK | |
|---|
| 250 | | - SND_MOTU_SPEC_TX_RETURN_CHUNK | |
|---|
| 251 | | - SND_MOTU_SPEC_RX_SEPARETED_MAIN | |
|---|
| 252 | | - SND_MOTU_SPEC_RX_MIDI_2ND_Q | |
|---|
| 253 | | - SND_MOTU_SPEC_TX_MIDI_3RD_Q, |
|---|
| 254 | | - .analog_in_ports = 2, |
|---|
| 255 | | - .analog_out_ports = 4, |
|---|
| 256 | | -}; |
|---|
| 257 | | - |
|---|
| 258 | | -static const struct snd_motu_spec motu_4pre = { |
|---|
| 259 | | - .name = "4pre", |
|---|
| 260 | | - .protocol = &snd_motu_protocol_v3, |
|---|
| 261 | | - .flags = SND_MOTU_SPEC_SUPPORT_CLOCK_X2 | |
|---|
| 262 | | - SND_MOTU_SPEC_TX_MICINST_CHUNK | |
|---|
| 263 | | - SND_MOTU_SPEC_TX_RETURN_CHUNK | |
|---|
| 264 | | - SND_MOTU_SPEC_RX_SEPARETED_MAIN, |
|---|
| 265 | | - .analog_in_ports = 2, |
|---|
| 266 | | - .analog_out_ports = 2, |
|---|
| 267 | | -}; |
|---|
| 268 | | - |
|---|
| 269 | 175 | #define SND_MOTU_DEV_ENTRY(model, data) \ |
|---|
| 270 | 176 | { \ |
|---|
| 271 | 177 | .match_flags = IEEE1394_MATCH_VENDOR_ID | \ |
|---|
| .. | .. |
|---|
| 278 | 184 | } |
|---|
| 279 | 185 | |
|---|
| 280 | 186 | static const struct ieee1394_device_id motu_id_table[] = { |
|---|
| 281 | | - SND_MOTU_DEV_ENTRY(0x000003, &motu_828mk2), |
|---|
| 187 | + SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2), |
|---|
| 282 | 188 | SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), |
|---|
| 283 | | - SND_MOTU_DEV_ENTRY(0x000015, &motu_828mk3), /* FireWire only. */ |
|---|
| 284 | | - SND_MOTU_DEV_ENTRY(0x000035, &motu_828mk3), /* Hybrid. */ |
|---|
| 285 | | - SND_MOTU_DEV_ENTRY(0x000033, &motu_audio_express), |
|---|
| 286 | | - SND_MOTU_DEV_ENTRY(0x000045, &motu_4pre), |
|---|
| 189 | + SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite), |
|---|
| 190 | + SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre), |
|---|
| 191 | + SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3), // FireWire only. |
|---|
| 192 | + SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only. |
|---|
| 193 | + SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3), // Hybrid. |
|---|
| 194 | + SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express), |
|---|
| 195 | + SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre), |
|---|
| 287 | 196 | { } |
|---|
| 288 | 197 | }; |
|---|
| 289 | 198 | MODULE_DEVICE_TABLE(ieee1394, motu_id_table); |
|---|