1*da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 29edf723fSTakashi Sakamoto /* 39edf723fSTakashi Sakamoto * digi00x.c - a part of driver for Digidesign Digi 002/003 family 49edf723fSTakashi Sakamoto * 59edf723fSTakashi Sakamoto * Copyright (c) 2014-2015 Takashi Sakamoto 69edf723fSTakashi Sakamoto */ 79edf723fSTakashi Sakamoto 89edf723fSTakashi Sakamoto #include "digi00x.h" 99edf723fSTakashi Sakamoto 109edf723fSTakashi Sakamoto MODULE_DESCRIPTION("Digidesign Digi 002/003 family Driver"); 119edf723fSTakashi Sakamoto MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); 129edf723fSTakashi Sakamoto MODULE_LICENSE("GPL v2"); 139edf723fSTakashi Sakamoto 149edf723fSTakashi Sakamoto #define VENDOR_DIGIDESIGN 0x00a07e 1513e005f9STakashi Sakamoto #define MODEL_CONSOLE 0x000001 1613e005f9STakashi Sakamoto #define MODEL_RACK 0x000002 179edf723fSTakashi Sakamoto 189edf723fSTakashi Sakamoto static int name_card(struct snd_dg00x *dg00x) 199edf723fSTakashi Sakamoto { 209edf723fSTakashi Sakamoto struct fw_device *fw_dev = fw_parent_device(dg00x->unit); 219edf723fSTakashi Sakamoto char name[32] = {0}; 229edf723fSTakashi Sakamoto char *model; 239edf723fSTakashi Sakamoto int err; 249edf723fSTakashi Sakamoto 259edf723fSTakashi Sakamoto err = fw_csr_string(dg00x->unit->directory, CSR_MODEL, name, 269edf723fSTakashi Sakamoto sizeof(name)); 279edf723fSTakashi Sakamoto if (err < 0) 289edf723fSTakashi Sakamoto return err; 299edf723fSTakashi Sakamoto 309edf723fSTakashi Sakamoto model = skip_spaces(name); 319edf723fSTakashi Sakamoto 329edf723fSTakashi Sakamoto strcpy(dg00x->card->driver, "Digi00x"); 339edf723fSTakashi Sakamoto strcpy(dg00x->card->shortname, model); 349edf723fSTakashi Sakamoto strcpy(dg00x->card->mixername, model); 359edf723fSTakashi Sakamoto snprintf(dg00x->card->longname, sizeof(dg00x->card->longname), 369edf723fSTakashi Sakamoto "Digidesign %s, GUID %08x%08x at %s, S%d", model, 37bd04809bSTakashi Sakamoto fw_dev->config_rom[3], fw_dev->config_rom[4], 389edf723fSTakashi Sakamoto dev_name(&dg00x->unit->device), 100 << fw_dev->max_speed); 399edf723fSTakashi Sakamoto 409edf723fSTakashi Sakamoto return 0; 419edf723fSTakashi Sakamoto } 429edf723fSTakashi Sakamoto 4386c8dd7fSTakashi Sakamoto static void dg00x_card_free(struct snd_card *card) 449edf723fSTakashi Sakamoto { 453babca45STakashi Sakamoto struct snd_dg00x *dg00x = card->private_data; 463babca45STakashi Sakamoto 473babca45STakashi Sakamoto snd_dg00x_stream_destroy_duplex(dg00x); 483babca45STakashi Sakamoto snd_dg00x_transaction_unregister(dg00x); 4986c8dd7fSTakashi Sakamoto } 5086c8dd7fSTakashi Sakamoto 5186c8dd7fSTakashi Sakamoto static void do_registration(struct work_struct *work) 5286c8dd7fSTakashi Sakamoto { 5386c8dd7fSTakashi Sakamoto struct snd_dg00x *dg00x = 5486c8dd7fSTakashi Sakamoto container_of(work, struct snd_dg00x, dwork.work); 559edf723fSTakashi Sakamoto int err; 569edf723fSTakashi Sakamoto 5786c8dd7fSTakashi Sakamoto if (dg00x->registered) 5886c8dd7fSTakashi Sakamoto return; 5986c8dd7fSTakashi Sakamoto 6086c8dd7fSTakashi Sakamoto err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0, 6186c8dd7fSTakashi Sakamoto &dg00x->card); 629edf723fSTakashi Sakamoto if (err < 0) 6386c8dd7fSTakashi Sakamoto return; 643babca45STakashi Sakamoto dg00x->card->private_free = dg00x_card_free; 653babca45STakashi Sakamoto dg00x->card->private_data = dg00x; 669edf723fSTakashi Sakamoto 679edf723fSTakashi Sakamoto err = name_card(dg00x); 689edf723fSTakashi Sakamoto if (err < 0) 699edf723fSTakashi Sakamoto goto error; 709edf723fSTakashi Sakamoto 713a2a1797STakashi Sakamoto err = snd_dg00x_stream_init_duplex(dg00x); 723a2a1797STakashi Sakamoto if (err < 0) 733a2a1797STakashi Sakamoto goto error; 743a2a1797STakashi Sakamoto 75927f17dcSTakashi Sakamoto snd_dg00x_proc_init(dg00x); 76927f17dcSTakashi Sakamoto 770120d0f1STakashi Sakamoto err = snd_dg00x_create_pcm_devices(dg00x); 780120d0f1STakashi Sakamoto if (err < 0) 790120d0f1STakashi Sakamoto goto error; 800120d0f1STakashi Sakamoto 819fbfd38bSTakashi Sakamoto err = snd_dg00x_create_midi_devices(dg00x); 829fbfd38bSTakashi Sakamoto if (err < 0) 839fbfd38bSTakashi Sakamoto goto error; 849fbfd38bSTakashi Sakamoto 85660dd3d5STakashi Sakamoto err = snd_dg00x_create_hwdep_device(dg00x); 86660dd3d5STakashi Sakamoto if (err < 0) 87660dd3d5STakashi Sakamoto goto error; 88660dd3d5STakashi Sakamoto 8944b73088STakashi Sakamoto err = snd_dg00x_transaction_register(dg00x); 9044b73088STakashi Sakamoto if (err < 0) 9144b73088STakashi Sakamoto goto error; 9244b73088STakashi Sakamoto 9386c8dd7fSTakashi Sakamoto err = snd_card_register(dg00x->card); 949edf723fSTakashi Sakamoto if (err < 0) 959edf723fSTakashi Sakamoto goto error; 969edf723fSTakashi Sakamoto 9786c8dd7fSTakashi Sakamoto dg00x->registered = true; 9886c8dd7fSTakashi Sakamoto 9986c8dd7fSTakashi Sakamoto return; 10086c8dd7fSTakashi Sakamoto error: 10186c8dd7fSTakashi Sakamoto snd_card_free(dg00x->card); 10286c8dd7fSTakashi Sakamoto dev_info(&dg00x->unit->device, 10386c8dd7fSTakashi Sakamoto "Sound card registration failed: %d\n", err); 10486c8dd7fSTakashi Sakamoto } 10586c8dd7fSTakashi Sakamoto 10686c8dd7fSTakashi Sakamoto static int snd_dg00x_probe(struct fw_unit *unit, 10786c8dd7fSTakashi Sakamoto const struct ieee1394_device_id *entry) 10886c8dd7fSTakashi Sakamoto { 10986c8dd7fSTakashi Sakamoto struct snd_dg00x *dg00x; 11086c8dd7fSTakashi Sakamoto 11186c8dd7fSTakashi Sakamoto /* Allocate this independent of sound card instance. */ 112366a20d7STakashi Sakamoto dg00x = devm_kzalloc(&unit->device, sizeof(struct snd_dg00x), 113366a20d7STakashi Sakamoto GFP_KERNEL); 114366a20d7STakashi Sakamoto if (!dg00x) 11586c8dd7fSTakashi Sakamoto return -ENOMEM; 11686c8dd7fSTakashi Sakamoto 11786c8dd7fSTakashi Sakamoto dg00x->unit = fw_unit_get(unit); 1189edf723fSTakashi Sakamoto dev_set_drvdata(&unit->device, dg00x); 1199edf723fSTakashi Sakamoto 12086c8dd7fSTakashi Sakamoto mutex_init(&dg00x->mutex); 12186c8dd7fSTakashi Sakamoto spin_lock_init(&dg00x->lock); 12286c8dd7fSTakashi Sakamoto init_waitqueue_head(&dg00x->hwdep_wait); 12386c8dd7fSTakashi Sakamoto 12413e005f9STakashi Sakamoto dg00x->is_console = entry->model_id == MODEL_CONSOLE; 12513e005f9STakashi Sakamoto 12686c8dd7fSTakashi Sakamoto /* Allocate and register this sound card later. */ 12786c8dd7fSTakashi Sakamoto INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); 12886c8dd7fSTakashi Sakamoto snd_fw_schedule_registration(unit, &dg00x->dwork); 12986c8dd7fSTakashi Sakamoto 13086c8dd7fSTakashi Sakamoto return 0; 1319edf723fSTakashi Sakamoto } 1329edf723fSTakashi Sakamoto 1339edf723fSTakashi Sakamoto static void snd_dg00x_update(struct fw_unit *unit) 1349edf723fSTakashi Sakamoto { 1353a2a1797STakashi Sakamoto struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 1363a2a1797STakashi Sakamoto 13786c8dd7fSTakashi Sakamoto /* Postpone a workqueue for deferred registration. */ 13886c8dd7fSTakashi Sakamoto if (!dg00x->registered) 13986c8dd7fSTakashi Sakamoto snd_fw_schedule_registration(unit, &dg00x->dwork); 14086c8dd7fSTakashi Sakamoto 14144b73088STakashi Sakamoto snd_dg00x_transaction_reregister(dg00x); 14244b73088STakashi Sakamoto 14386c8dd7fSTakashi Sakamoto /* 14486c8dd7fSTakashi Sakamoto * After registration, userspace can start packet streaming, then this 14586c8dd7fSTakashi Sakamoto * code block works fine. 14686c8dd7fSTakashi Sakamoto */ 14786c8dd7fSTakashi Sakamoto if (dg00x->registered) { 1483a2a1797STakashi Sakamoto mutex_lock(&dg00x->mutex); 1493a2a1797STakashi Sakamoto snd_dg00x_stream_update_duplex(dg00x); 1503a2a1797STakashi Sakamoto mutex_unlock(&dg00x->mutex); 1519edf723fSTakashi Sakamoto } 15286c8dd7fSTakashi Sakamoto } 1539edf723fSTakashi Sakamoto 1549edf723fSTakashi Sakamoto static void snd_dg00x_remove(struct fw_unit *unit) 1559edf723fSTakashi Sakamoto { 1569edf723fSTakashi Sakamoto struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 1579edf723fSTakashi Sakamoto 15886c8dd7fSTakashi Sakamoto /* 15986c8dd7fSTakashi Sakamoto * Confirm to stop the work for registration before the sound card is 16086c8dd7fSTakashi Sakamoto * going to be released. The work is not scheduled again because bus 16186c8dd7fSTakashi Sakamoto * reset handler is not called anymore. 16286c8dd7fSTakashi Sakamoto */ 16386c8dd7fSTakashi Sakamoto cancel_delayed_work_sync(&dg00x->dwork); 16486c8dd7fSTakashi Sakamoto 16586c8dd7fSTakashi Sakamoto if (dg00x->registered) { 16661ccc6f6STakashi Sakamoto // Block till all of ALSA character devices are released. 16761ccc6f6STakashi Sakamoto snd_card_free(dg00x->card); 16886c8dd7fSTakashi Sakamoto } 1695b14ec25STakashi Sakamoto 1705b14ec25STakashi Sakamoto mutex_destroy(&dg00x->mutex); 1715b14ec25STakashi Sakamoto fw_unit_put(dg00x->unit); 1729edf723fSTakashi Sakamoto } 1739edf723fSTakashi Sakamoto 1749edf723fSTakashi Sakamoto static const struct ieee1394_device_id snd_dg00x_id_table[] = { 1759edf723fSTakashi Sakamoto /* Both of 002/003 use the same ID. */ 1769edf723fSTakashi Sakamoto { 1779edf723fSTakashi Sakamoto .match_flags = IEEE1394_MATCH_VENDOR_ID | 1789edf723fSTakashi Sakamoto IEEE1394_MATCH_MODEL_ID, 1799edf723fSTakashi Sakamoto .vendor_id = VENDOR_DIGIDESIGN, 18013e005f9STakashi Sakamoto .model_id = MODEL_CONSOLE, 18113e005f9STakashi Sakamoto }, 18213e005f9STakashi Sakamoto { 18313e005f9STakashi Sakamoto .match_flags = IEEE1394_MATCH_VENDOR_ID | 18413e005f9STakashi Sakamoto IEEE1394_MATCH_MODEL_ID, 18513e005f9STakashi Sakamoto .vendor_id = VENDOR_DIGIDESIGN, 18613e005f9STakashi Sakamoto .model_id = MODEL_RACK, 1879edf723fSTakashi Sakamoto }, 1889edf723fSTakashi Sakamoto {} 1899edf723fSTakashi Sakamoto }; 1909edf723fSTakashi Sakamoto MODULE_DEVICE_TABLE(ieee1394, snd_dg00x_id_table); 1919edf723fSTakashi Sakamoto 1929edf723fSTakashi Sakamoto static struct fw_driver dg00x_driver = { 1939edf723fSTakashi Sakamoto .driver = { 1949edf723fSTakashi Sakamoto .owner = THIS_MODULE, 1959edf723fSTakashi Sakamoto .name = "snd-firewire-digi00x", 1969edf723fSTakashi Sakamoto .bus = &fw_bus_type, 1979edf723fSTakashi Sakamoto }, 1989edf723fSTakashi Sakamoto .probe = snd_dg00x_probe, 1999edf723fSTakashi Sakamoto .update = snd_dg00x_update, 2009edf723fSTakashi Sakamoto .remove = snd_dg00x_remove, 2019edf723fSTakashi Sakamoto .id_table = snd_dg00x_id_table, 2029edf723fSTakashi Sakamoto }; 2039edf723fSTakashi Sakamoto 2049edf723fSTakashi Sakamoto static int __init snd_dg00x_init(void) 2059edf723fSTakashi Sakamoto { 2069edf723fSTakashi Sakamoto return driver_register(&dg00x_driver.driver); 2079edf723fSTakashi Sakamoto } 2089edf723fSTakashi Sakamoto 2099edf723fSTakashi Sakamoto static void __exit snd_dg00x_exit(void) 2109edf723fSTakashi Sakamoto { 2119edf723fSTakashi Sakamoto driver_unregister(&dg00x_driver.driver); 2129edf723fSTakashi Sakamoto } 2139edf723fSTakashi Sakamoto 2149edf723fSTakashi Sakamoto module_init(snd_dg00x_init); 2159edf723fSTakashi Sakamoto module_exit(snd_dg00x_exit); 216