xref: /linux/sound/firewire/digi00x/digi00x.c (revision da607e1969ffbf7a1ba06280ade768f4f5fee8c3)
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