19edf723fSTakashi Sakamoto /* 29edf723fSTakashi Sakamoto * digi00x.c - a part of driver for Digidesign Digi 002/003 family 39edf723fSTakashi Sakamoto * 49edf723fSTakashi Sakamoto * Copyright (c) 2014-2015 Takashi Sakamoto 59edf723fSTakashi Sakamoto * 69edf723fSTakashi Sakamoto * Licensed under the terms of the GNU General Public License, version 2. 79edf723fSTakashi Sakamoto */ 89edf723fSTakashi Sakamoto 99edf723fSTakashi Sakamoto #include "digi00x.h" 109edf723fSTakashi Sakamoto 119edf723fSTakashi Sakamoto MODULE_DESCRIPTION("Digidesign Digi 002/003 family Driver"); 129edf723fSTakashi Sakamoto MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); 139edf723fSTakashi Sakamoto MODULE_LICENSE("GPL v2"); 149edf723fSTakashi Sakamoto 159edf723fSTakashi Sakamoto #define VENDOR_DIGIDESIGN 0x00a07e 16*13e005f9STakashi Sakamoto #define MODEL_CONSOLE 0x000001 17*13e005f9STakashi Sakamoto #define MODEL_RACK 0x000002 189edf723fSTakashi Sakamoto 199edf723fSTakashi Sakamoto static int name_card(struct snd_dg00x *dg00x) 209edf723fSTakashi Sakamoto { 219edf723fSTakashi Sakamoto struct fw_device *fw_dev = fw_parent_device(dg00x->unit); 229edf723fSTakashi Sakamoto char name[32] = {0}; 239edf723fSTakashi Sakamoto char *model; 249edf723fSTakashi Sakamoto int err; 259edf723fSTakashi Sakamoto 269edf723fSTakashi Sakamoto err = fw_csr_string(dg00x->unit->directory, CSR_MODEL, name, 279edf723fSTakashi Sakamoto sizeof(name)); 289edf723fSTakashi Sakamoto if (err < 0) 299edf723fSTakashi Sakamoto return err; 309edf723fSTakashi Sakamoto 319edf723fSTakashi Sakamoto model = skip_spaces(name); 329edf723fSTakashi Sakamoto 339edf723fSTakashi Sakamoto strcpy(dg00x->card->driver, "Digi00x"); 349edf723fSTakashi Sakamoto strcpy(dg00x->card->shortname, model); 359edf723fSTakashi Sakamoto strcpy(dg00x->card->mixername, model); 369edf723fSTakashi Sakamoto snprintf(dg00x->card->longname, sizeof(dg00x->card->longname), 379edf723fSTakashi Sakamoto "Digidesign %s, GUID %08x%08x at %s, S%d", model, 38bd04809bSTakashi Sakamoto fw_dev->config_rom[3], fw_dev->config_rom[4], 399edf723fSTakashi Sakamoto dev_name(&dg00x->unit->device), 100 << fw_dev->max_speed); 409edf723fSTakashi Sakamoto 419edf723fSTakashi Sakamoto return 0; 429edf723fSTakashi Sakamoto } 439edf723fSTakashi Sakamoto 4486c8dd7fSTakashi Sakamoto static void dg00x_free(struct snd_dg00x *dg00x) 459edf723fSTakashi Sakamoto { 463a2a1797STakashi Sakamoto snd_dg00x_stream_destroy_duplex(dg00x); 4744b73088STakashi Sakamoto snd_dg00x_transaction_unregister(dg00x); 483a2a1797STakashi Sakamoto 499edf723fSTakashi Sakamoto fw_unit_put(dg00x->unit); 509edf723fSTakashi Sakamoto 519edf723fSTakashi Sakamoto mutex_destroy(&dg00x->mutex); 529edf723fSTakashi Sakamoto } 539edf723fSTakashi Sakamoto 5486c8dd7fSTakashi Sakamoto static void dg00x_card_free(struct snd_card *card) 559edf723fSTakashi Sakamoto { 5686c8dd7fSTakashi Sakamoto dg00x_free(card->private_data); 5786c8dd7fSTakashi Sakamoto } 5886c8dd7fSTakashi Sakamoto 5986c8dd7fSTakashi Sakamoto static void do_registration(struct work_struct *work) 6086c8dd7fSTakashi Sakamoto { 6186c8dd7fSTakashi Sakamoto struct snd_dg00x *dg00x = 6286c8dd7fSTakashi Sakamoto container_of(work, struct snd_dg00x, dwork.work); 639edf723fSTakashi Sakamoto int err; 649edf723fSTakashi Sakamoto 6586c8dd7fSTakashi Sakamoto if (dg00x->registered) 6686c8dd7fSTakashi Sakamoto return; 6786c8dd7fSTakashi Sakamoto 6886c8dd7fSTakashi Sakamoto err = snd_card_new(&dg00x->unit->device, -1, NULL, THIS_MODULE, 0, 6986c8dd7fSTakashi Sakamoto &dg00x->card); 709edf723fSTakashi Sakamoto if (err < 0) 7186c8dd7fSTakashi Sakamoto return; 729edf723fSTakashi Sakamoto 739edf723fSTakashi Sakamoto err = name_card(dg00x); 749edf723fSTakashi Sakamoto if (err < 0) 759edf723fSTakashi Sakamoto goto error; 769edf723fSTakashi Sakamoto 773a2a1797STakashi Sakamoto err = snd_dg00x_stream_init_duplex(dg00x); 783a2a1797STakashi Sakamoto if (err < 0) 793a2a1797STakashi Sakamoto goto error; 803a2a1797STakashi Sakamoto 81927f17dcSTakashi Sakamoto snd_dg00x_proc_init(dg00x); 82927f17dcSTakashi Sakamoto 830120d0f1STakashi Sakamoto err = snd_dg00x_create_pcm_devices(dg00x); 840120d0f1STakashi Sakamoto if (err < 0) 850120d0f1STakashi Sakamoto goto error; 860120d0f1STakashi Sakamoto 879fbfd38bSTakashi Sakamoto err = snd_dg00x_create_midi_devices(dg00x); 889fbfd38bSTakashi Sakamoto if (err < 0) 899fbfd38bSTakashi Sakamoto goto error; 909fbfd38bSTakashi Sakamoto 91660dd3d5STakashi Sakamoto err = snd_dg00x_create_hwdep_device(dg00x); 92660dd3d5STakashi Sakamoto if (err < 0) 93660dd3d5STakashi Sakamoto goto error; 94660dd3d5STakashi Sakamoto 9544b73088STakashi Sakamoto err = snd_dg00x_transaction_register(dg00x); 9644b73088STakashi Sakamoto if (err < 0) 9744b73088STakashi Sakamoto goto error; 9844b73088STakashi Sakamoto 9986c8dd7fSTakashi Sakamoto err = snd_card_register(dg00x->card); 1009edf723fSTakashi Sakamoto if (err < 0) 1019edf723fSTakashi Sakamoto goto error; 1029edf723fSTakashi Sakamoto 10386c8dd7fSTakashi Sakamoto dg00x->card->private_free = dg00x_card_free; 10486c8dd7fSTakashi Sakamoto dg00x->card->private_data = dg00x; 10586c8dd7fSTakashi Sakamoto dg00x->registered = true; 10686c8dd7fSTakashi Sakamoto 10786c8dd7fSTakashi Sakamoto return; 10886c8dd7fSTakashi Sakamoto error: 10986c8dd7fSTakashi Sakamoto snd_dg00x_transaction_unregister(dg00x); 11086c8dd7fSTakashi Sakamoto snd_dg00x_stream_destroy_duplex(dg00x); 11186c8dd7fSTakashi Sakamoto snd_card_free(dg00x->card); 11286c8dd7fSTakashi Sakamoto dev_info(&dg00x->unit->device, 11386c8dd7fSTakashi Sakamoto "Sound card registration failed: %d\n", err); 11486c8dd7fSTakashi Sakamoto } 11586c8dd7fSTakashi Sakamoto 11686c8dd7fSTakashi Sakamoto static int snd_dg00x_probe(struct fw_unit *unit, 11786c8dd7fSTakashi Sakamoto const struct ieee1394_device_id *entry) 11886c8dd7fSTakashi Sakamoto { 11986c8dd7fSTakashi Sakamoto struct snd_dg00x *dg00x; 12086c8dd7fSTakashi Sakamoto 12186c8dd7fSTakashi Sakamoto /* Allocate this independent of sound card instance. */ 12286c8dd7fSTakashi Sakamoto dg00x = kzalloc(sizeof(struct snd_dg00x), GFP_KERNEL); 12386c8dd7fSTakashi Sakamoto if (dg00x == NULL) 12486c8dd7fSTakashi Sakamoto return -ENOMEM; 12586c8dd7fSTakashi Sakamoto 12686c8dd7fSTakashi Sakamoto dg00x->unit = fw_unit_get(unit); 1279edf723fSTakashi Sakamoto dev_set_drvdata(&unit->device, dg00x); 1289edf723fSTakashi Sakamoto 12986c8dd7fSTakashi Sakamoto mutex_init(&dg00x->mutex); 13086c8dd7fSTakashi Sakamoto spin_lock_init(&dg00x->lock); 13186c8dd7fSTakashi Sakamoto init_waitqueue_head(&dg00x->hwdep_wait); 13286c8dd7fSTakashi Sakamoto 133*13e005f9STakashi Sakamoto dg00x->is_console = entry->model_id == MODEL_CONSOLE; 134*13e005f9STakashi Sakamoto 13586c8dd7fSTakashi Sakamoto /* Allocate and register this sound card later. */ 13686c8dd7fSTakashi Sakamoto INIT_DEFERRABLE_WORK(&dg00x->dwork, do_registration); 13786c8dd7fSTakashi Sakamoto snd_fw_schedule_registration(unit, &dg00x->dwork); 13886c8dd7fSTakashi Sakamoto 13986c8dd7fSTakashi Sakamoto return 0; 1409edf723fSTakashi Sakamoto } 1419edf723fSTakashi Sakamoto 1429edf723fSTakashi Sakamoto static void snd_dg00x_update(struct fw_unit *unit) 1439edf723fSTakashi Sakamoto { 1443a2a1797STakashi Sakamoto struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 1453a2a1797STakashi Sakamoto 14686c8dd7fSTakashi Sakamoto /* Postpone a workqueue for deferred registration. */ 14786c8dd7fSTakashi Sakamoto if (!dg00x->registered) 14886c8dd7fSTakashi Sakamoto snd_fw_schedule_registration(unit, &dg00x->dwork); 14986c8dd7fSTakashi Sakamoto 15044b73088STakashi Sakamoto snd_dg00x_transaction_reregister(dg00x); 15144b73088STakashi Sakamoto 15286c8dd7fSTakashi Sakamoto /* 15386c8dd7fSTakashi Sakamoto * After registration, userspace can start packet streaming, then this 15486c8dd7fSTakashi Sakamoto * code block works fine. 15586c8dd7fSTakashi Sakamoto */ 15686c8dd7fSTakashi Sakamoto if (dg00x->registered) { 1573a2a1797STakashi Sakamoto mutex_lock(&dg00x->mutex); 1583a2a1797STakashi Sakamoto snd_dg00x_stream_update_duplex(dg00x); 1593a2a1797STakashi Sakamoto mutex_unlock(&dg00x->mutex); 1609edf723fSTakashi Sakamoto } 16186c8dd7fSTakashi Sakamoto } 1629edf723fSTakashi Sakamoto 1639edf723fSTakashi Sakamoto static void snd_dg00x_remove(struct fw_unit *unit) 1649edf723fSTakashi Sakamoto { 1659edf723fSTakashi Sakamoto struct snd_dg00x *dg00x = dev_get_drvdata(&unit->device); 1669edf723fSTakashi Sakamoto 16786c8dd7fSTakashi Sakamoto /* 16886c8dd7fSTakashi Sakamoto * Confirm to stop the work for registration before the sound card is 16986c8dd7fSTakashi Sakamoto * going to be released. The work is not scheduled again because bus 17086c8dd7fSTakashi Sakamoto * reset handler is not called anymore. 17186c8dd7fSTakashi Sakamoto */ 17286c8dd7fSTakashi Sakamoto cancel_delayed_work_sync(&dg00x->dwork); 17386c8dd7fSTakashi Sakamoto 17486c8dd7fSTakashi Sakamoto if (dg00x->registered) { 1759edf723fSTakashi Sakamoto /* No need to wait for releasing card object in this context. */ 1769edf723fSTakashi Sakamoto snd_card_free_when_closed(dg00x->card); 17786c8dd7fSTakashi Sakamoto } else { 17886c8dd7fSTakashi Sakamoto /* Don't forget this case. */ 17986c8dd7fSTakashi Sakamoto dg00x_free(dg00x); 18086c8dd7fSTakashi Sakamoto } 1819edf723fSTakashi Sakamoto } 1829edf723fSTakashi Sakamoto 1839edf723fSTakashi Sakamoto static const struct ieee1394_device_id snd_dg00x_id_table[] = { 1849edf723fSTakashi Sakamoto /* Both of 002/003 use the same ID. */ 1859edf723fSTakashi Sakamoto { 1869edf723fSTakashi Sakamoto .match_flags = IEEE1394_MATCH_VENDOR_ID | 1879edf723fSTakashi Sakamoto IEEE1394_MATCH_MODEL_ID, 1889edf723fSTakashi Sakamoto .vendor_id = VENDOR_DIGIDESIGN, 189*13e005f9STakashi Sakamoto .model_id = MODEL_CONSOLE, 190*13e005f9STakashi Sakamoto }, 191*13e005f9STakashi Sakamoto { 192*13e005f9STakashi Sakamoto .match_flags = IEEE1394_MATCH_VENDOR_ID | 193*13e005f9STakashi Sakamoto IEEE1394_MATCH_MODEL_ID, 194*13e005f9STakashi Sakamoto .vendor_id = VENDOR_DIGIDESIGN, 195*13e005f9STakashi Sakamoto .model_id = MODEL_RACK, 1969edf723fSTakashi Sakamoto }, 1979edf723fSTakashi Sakamoto {} 1989edf723fSTakashi Sakamoto }; 1999edf723fSTakashi Sakamoto MODULE_DEVICE_TABLE(ieee1394, snd_dg00x_id_table); 2009edf723fSTakashi Sakamoto 2019edf723fSTakashi Sakamoto static struct fw_driver dg00x_driver = { 2029edf723fSTakashi Sakamoto .driver = { 2039edf723fSTakashi Sakamoto .owner = THIS_MODULE, 2049edf723fSTakashi Sakamoto .name = "snd-firewire-digi00x", 2059edf723fSTakashi Sakamoto .bus = &fw_bus_type, 2069edf723fSTakashi Sakamoto }, 2079edf723fSTakashi Sakamoto .probe = snd_dg00x_probe, 2089edf723fSTakashi Sakamoto .update = snd_dg00x_update, 2099edf723fSTakashi Sakamoto .remove = snd_dg00x_remove, 2109edf723fSTakashi Sakamoto .id_table = snd_dg00x_id_table, 2119edf723fSTakashi Sakamoto }; 2129edf723fSTakashi Sakamoto 2139edf723fSTakashi Sakamoto static int __init snd_dg00x_init(void) 2149edf723fSTakashi Sakamoto { 2159edf723fSTakashi Sakamoto return driver_register(&dg00x_driver.driver); 2169edf723fSTakashi Sakamoto } 2179edf723fSTakashi Sakamoto 2189edf723fSTakashi Sakamoto static void __exit snd_dg00x_exit(void) 2199edf723fSTakashi Sakamoto { 2209edf723fSTakashi Sakamoto driver_unregister(&dg00x_driver.driver); 2219edf723fSTakashi Sakamoto } 2229edf723fSTakashi Sakamoto 2239edf723fSTakashi Sakamoto module_init(snd_dg00x_init); 2249edf723fSTakashi Sakamoto module_exit(snd_dg00x_exit); 225