162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * motu.c - a part of driver for MOTU FireWire series 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2015-2017 Takashi Sakamoto <o-takashi@sakamocchi.jp> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "motu.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#define OUI_MOTU 0x0001f2 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ciMODULE_DESCRIPTION("MOTU FireWire driver"); 1362306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); 1462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciconst unsigned int snd_motu_clock_rates[SND_MOTU_CLOCK_RATE_COUNT] = { 1762306a36Sopenharmony_ci /* mode 0 */ 1862306a36Sopenharmony_ci [0] = 44100, 1962306a36Sopenharmony_ci [1] = 48000, 2062306a36Sopenharmony_ci /* mode 1 */ 2162306a36Sopenharmony_ci [2] = 88200, 2262306a36Sopenharmony_ci [3] = 96000, 2362306a36Sopenharmony_ci /* mode 2 */ 2462306a36Sopenharmony_ci [4] = 176400, 2562306a36Sopenharmony_ci [5] = 192000, 2662306a36Sopenharmony_ci}; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void name_card(struct snd_motu *motu) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct fw_device *fw_dev = fw_parent_device(motu->unit); 3162306a36Sopenharmony_ci struct fw_csr_iterator it; 3262306a36Sopenharmony_ci int key, val; 3362306a36Sopenharmony_ci u32 version = 0; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci fw_csr_iterator_init(&it, motu->unit->directory); 3662306a36Sopenharmony_ci while (fw_csr_iterator_next(&it, &key, &val)) { 3762306a36Sopenharmony_ci switch (key) { 3862306a36Sopenharmony_ci case CSR_MODEL: 3962306a36Sopenharmony_ci version = val; 4062306a36Sopenharmony_ci break; 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci strcpy(motu->card->driver, "FW-MOTU"); 4562306a36Sopenharmony_ci strcpy(motu->card->shortname, motu->spec->name); 4662306a36Sopenharmony_ci strcpy(motu->card->mixername, motu->spec->name); 4762306a36Sopenharmony_ci snprintf(motu->card->longname, sizeof(motu->card->longname), 4862306a36Sopenharmony_ci "MOTU %s (version:%06x), GUID %08x%08x at %s, S%d", 4962306a36Sopenharmony_ci motu->spec->name, version, 5062306a36Sopenharmony_ci fw_dev->config_rom[3], fw_dev->config_rom[4], 5162306a36Sopenharmony_ci dev_name(&motu->unit->device), 100 << fw_dev->max_speed); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic void motu_card_free(struct snd_card *card) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci struct snd_motu *motu = card->private_data; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci snd_motu_transaction_unregister(motu); 5962306a36Sopenharmony_ci snd_motu_stream_destroy_duplex(motu); 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci mutex_destroy(&motu->mutex); 6262306a36Sopenharmony_ci fw_unit_put(motu->unit); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic int motu_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci struct snd_card *card; 6862306a36Sopenharmony_ci struct snd_motu *motu; 6962306a36Sopenharmony_ci int err; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*motu), &card); 7262306a36Sopenharmony_ci if (err < 0) 7362306a36Sopenharmony_ci return err; 7462306a36Sopenharmony_ci card->private_free = motu_card_free; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci motu = card->private_data; 7762306a36Sopenharmony_ci motu->unit = fw_unit_get(unit); 7862306a36Sopenharmony_ci dev_set_drvdata(&unit->device, motu); 7962306a36Sopenharmony_ci motu->card = card; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci motu->spec = (const struct snd_motu_spec *)entry->driver_data; 8262306a36Sopenharmony_ci mutex_init(&motu->mutex); 8362306a36Sopenharmony_ci spin_lock_init(&motu->lock); 8462306a36Sopenharmony_ci init_waitqueue_head(&motu->hwdep_wait); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci name_card(motu); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci err = snd_motu_transaction_register(motu); 8962306a36Sopenharmony_ci if (err < 0) 9062306a36Sopenharmony_ci goto error; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci err = snd_motu_stream_init_duplex(motu); 9362306a36Sopenharmony_ci if (err < 0) 9462306a36Sopenharmony_ci goto error; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci snd_motu_proc_init(motu); 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci err = snd_motu_create_pcm_devices(motu); 9962306a36Sopenharmony_ci if (err < 0) 10062306a36Sopenharmony_ci goto error; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci if ((motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_2ND_Q) || 10362306a36Sopenharmony_ci (motu->spec->flags & SND_MOTU_SPEC_RX_MIDI_3RD_Q) || 10462306a36Sopenharmony_ci (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_2ND_Q) || 10562306a36Sopenharmony_ci (motu->spec->flags & SND_MOTU_SPEC_TX_MIDI_3RD_Q)) { 10662306a36Sopenharmony_ci err = snd_motu_create_midi_devices(motu); 10762306a36Sopenharmony_ci if (err < 0) 10862306a36Sopenharmony_ci goto error; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci err = snd_motu_create_hwdep_device(motu); 11262306a36Sopenharmony_ci if (err < 0) 11362306a36Sopenharmony_ci goto error; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (motu->spec->flags & SND_MOTU_SPEC_REGISTER_DSP) { 11662306a36Sopenharmony_ci err = snd_motu_register_dsp_message_parser_new(motu); 11762306a36Sopenharmony_ci if (err < 0) 11862306a36Sopenharmony_ci goto error; 11962306a36Sopenharmony_ci } else if (motu->spec->flags & SND_MOTU_SPEC_COMMAND_DSP) { 12062306a36Sopenharmony_ci err = snd_motu_command_dsp_message_parser_new(motu); 12162306a36Sopenharmony_ci if (err < 0) 12262306a36Sopenharmony_ci goto error; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci err = snd_card_register(card); 12662306a36Sopenharmony_ci if (err < 0) 12762306a36Sopenharmony_ci goto error; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci return 0; 13062306a36Sopenharmony_cierror: 13162306a36Sopenharmony_ci snd_card_free(card); 13262306a36Sopenharmony_ci return err; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic void motu_remove(struct fw_unit *unit) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct snd_motu *motu = dev_get_drvdata(&unit->device); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci // Block till all of ALSA character devices are released. 14062306a36Sopenharmony_ci snd_card_free(motu->card); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void motu_bus_update(struct fw_unit *unit) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct snd_motu *motu = dev_get_drvdata(&unit->device); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* The handler address register becomes initialized. */ 14862306a36Sopenharmony_ci snd_motu_transaction_reregister(motu); 14962306a36Sopenharmony_ci} 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci#define SND_MOTU_DEV_ENTRY(model, data) \ 15262306a36Sopenharmony_ci{ \ 15362306a36Sopenharmony_ci .match_flags = IEEE1394_MATCH_VENDOR_ID | \ 15462306a36Sopenharmony_ci IEEE1394_MATCH_SPECIFIER_ID | \ 15562306a36Sopenharmony_ci IEEE1394_MATCH_VERSION, \ 15662306a36Sopenharmony_ci .vendor_id = OUI_MOTU, \ 15762306a36Sopenharmony_ci .specifier_id = OUI_MOTU, \ 15862306a36Sopenharmony_ci .version = model, \ 15962306a36Sopenharmony_ci .driver_data = (kernel_ulong_t)data, \ 16062306a36Sopenharmony_ci} 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic const struct ieee1394_device_id motu_id_table[] = { 16362306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000001, &snd_motu_spec_828), 16462306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000002, &snd_motu_spec_896), 16562306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000003, &snd_motu_spec_828mk2), 16662306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000005, &snd_motu_spec_896hd), 16762306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000009, &snd_motu_spec_traveler), 16862306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x00000d, &snd_motu_spec_ultralite), 16962306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x00000f, &snd_motu_spec_8pre), 17062306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000015, &snd_motu_spec_828mk3_fw), // FireWire only. 17162306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000019, &snd_motu_spec_ultralite_mk3), // FireWire only. 17262306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x00001b, &snd_motu_spec_traveler_mk3), 17362306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000030, &snd_motu_spec_ultralite_mk3), // Hybrid. 17462306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000035, &snd_motu_spec_828mk3_hybrid), // Hybrid. 17562306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000033, &snd_motu_spec_audio_express), 17662306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000039, &snd_motu_spec_track16), 17762306a36Sopenharmony_ci SND_MOTU_DEV_ENTRY(0x000045, &snd_motu_spec_4pre), 17862306a36Sopenharmony_ci { } 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(ieee1394, motu_id_table); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic struct fw_driver motu_driver = { 18362306a36Sopenharmony_ci .driver = { 18462306a36Sopenharmony_ci .owner = THIS_MODULE, 18562306a36Sopenharmony_ci .name = KBUILD_MODNAME, 18662306a36Sopenharmony_ci .bus = &fw_bus_type, 18762306a36Sopenharmony_ci }, 18862306a36Sopenharmony_ci .probe = motu_probe, 18962306a36Sopenharmony_ci .update = motu_bus_update, 19062306a36Sopenharmony_ci .remove = motu_remove, 19162306a36Sopenharmony_ci .id_table = motu_id_table, 19262306a36Sopenharmony_ci}; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistatic int __init alsa_motu_init(void) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci return driver_register(&motu_driver.driver); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void __exit alsa_motu_exit(void) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci driver_unregister(&motu_driver.driver); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cimodule_init(alsa_motu_init); 20562306a36Sopenharmony_cimodule_exit(alsa_motu_exit); 206