xref: /openbmc/linux/sound/firewire/fireface/ff.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
217c4e5eaSTakashi Sakamoto /*
317c4e5eaSTakashi Sakamoto  * ff.c - a part of driver for RME Fireface series
417c4e5eaSTakashi Sakamoto  *
517c4e5eaSTakashi Sakamoto  * Copyright (c) 2015-2017 Takashi Sakamoto
617c4e5eaSTakashi Sakamoto  */
717c4e5eaSTakashi Sakamoto 
817c4e5eaSTakashi Sakamoto #include "ff.h"
917c4e5eaSTakashi Sakamoto 
1017c4e5eaSTakashi Sakamoto #define OUI_RME	0x000a35
1117c4e5eaSTakashi Sakamoto 
1217c4e5eaSTakashi Sakamoto MODULE_DESCRIPTION("RME Fireface series Driver");
1317c4e5eaSTakashi Sakamoto MODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
1481c29435STakashi Sakamoto MODULE_LICENSE("GPL");
1517c4e5eaSTakashi Sakamoto 
name_card(struct snd_ff * ff)1617c4e5eaSTakashi Sakamoto static void name_card(struct snd_ff *ff)
1717c4e5eaSTakashi Sakamoto {
1817c4e5eaSTakashi Sakamoto 	struct fw_device *fw_dev = fw_parent_device(ff->unit);
19*a64db0b9STakashi Sakamoto 	static const char *const names[] = {
20782222baSTakashi Sakamoto 		[SND_FF_UNIT_VERSION_FF800]	= "Fireface800",
21782222baSTakashi Sakamoto 		[SND_FF_UNIT_VERSION_FF400]	= "Fireface400",
221f65e668STakashi Sakamoto 		[SND_FF_UNIT_VERSION_UFX]	= "FirefaceUFX",
23782222baSTakashi Sakamoto 		[SND_FF_UNIT_VERSION_UCX]	= "FirefaceUCX",
24062bb452STakashi Sakamoto 		[SND_FF_UNIT_VERSION_802]	= "Fireface802",
25782222baSTakashi Sakamoto 	};
26782222baSTakashi Sakamoto 	const char *name;
27782222baSTakashi Sakamoto 
28782222baSTakashi Sakamoto 	name = names[ff->unit_version];
2917c4e5eaSTakashi Sakamoto 
3017c4e5eaSTakashi Sakamoto 	strcpy(ff->card->driver, "Fireface");
31782222baSTakashi Sakamoto 	strcpy(ff->card->shortname, name);
32782222baSTakashi Sakamoto 	strcpy(ff->card->mixername, name);
3317c4e5eaSTakashi Sakamoto 	snprintf(ff->card->longname, sizeof(ff->card->longname),
34782222baSTakashi Sakamoto 		 "RME %s, GUID %08x%08x at %s, S%d", name,
3517c4e5eaSTakashi Sakamoto 		 fw_dev->config_rom[3], fw_dev->config_rom[4],
3617c4e5eaSTakashi Sakamoto 		 dev_name(&ff->unit->device), 100 << fw_dev->max_speed);
3717c4e5eaSTakashi Sakamoto }
3817c4e5eaSTakashi Sakamoto 
ff_card_free(struct snd_card * card)39324540c4STakashi Sakamoto static void ff_card_free(struct snd_card *card)
40324540c4STakashi Sakamoto {
413babca45STakashi Sakamoto 	struct snd_ff *ff = card->private_data;
423babca45STakashi Sakamoto 
433babca45STakashi Sakamoto 	snd_ff_stream_destroy_duplex(ff);
443babca45STakashi Sakamoto 	snd_ff_transaction_unregister(ff);
45ee5f0b32STakashi Sakamoto 
46c31909faSTakashi Sakamoto 	kfree(ff->msg_parser);
47c31909faSTakashi Sakamoto 
48ee5f0b32STakashi Sakamoto 	mutex_destroy(&ff->mutex);
49ee5f0b32STakashi Sakamoto 	fw_unit_put(ff->unit);
50324540c4STakashi Sakamoto }
51324540c4STakashi Sakamoto 
snd_ff_probe(struct fw_unit * unit,const struct ieee1394_device_id * entry)52ee5f0b32STakashi Sakamoto static int snd_ff_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
53324540c4STakashi Sakamoto {
54ee5f0b32STakashi Sakamoto 	struct snd_card *card;
55ee5f0b32STakashi Sakamoto 	struct snd_ff *ff;
56324540c4STakashi Sakamoto 	int err;
57324540c4STakashi Sakamoto 
58ee5f0b32STakashi Sakamoto 	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*ff), &card);
59324540c4STakashi Sakamoto 	if (err < 0)
60ee5f0b32STakashi Sakamoto 		return err;
61ee5f0b32STakashi Sakamoto 	card->private_free = ff_card_free;
62ee5f0b32STakashi Sakamoto 
63ee5f0b32STakashi Sakamoto 	ff = card->private_data;
64ee5f0b32STakashi Sakamoto 	ff->unit = fw_unit_get(unit);
65ee5f0b32STakashi Sakamoto 	dev_set_drvdata(&unit->device, ff);
66ee5f0b32STakashi Sakamoto 	ff->card = card;
67ee5f0b32STakashi Sakamoto 
68ee5f0b32STakashi Sakamoto 	mutex_init(&ff->mutex);
69ee5f0b32STakashi Sakamoto 	spin_lock_init(&ff->lock);
70ee5f0b32STakashi Sakamoto 	init_waitqueue_head(&ff->hwdep_wait);
71ee5f0b32STakashi Sakamoto 
72ee5f0b32STakashi Sakamoto 	ff->unit_version = entry->version;
73ee5f0b32STakashi Sakamoto 	ff->spec = (const struct snd_ff_spec *)entry->driver_data;
74324540c4STakashi Sakamoto 
7519174295STakashi Sakamoto 	err = snd_ff_transaction_register(ff);
7619174295STakashi Sakamoto 	if (err < 0)
7719174295STakashi Sakamoto 		goto error;
7819174295STakashi Sakamoto 
79324540c4STakashi Sakamoto 	name_card(ff);
80324540c4STakashi Sakamoto 
8175d6d898STakashi Sakamoto 	err = snd_ff_stream_init_duplex(ff);
8275d6d898STakashi Sakamoto 	if (err < 0)
8375d6d898STakashi Sakamoto 		goto error;
8475d6d898STakashi Sakamoto 
85d3fc7aacSTakashi Sakamoto 	snd_ff_proc_init(ff);
86d3fc7aacSTakashi Sakamoto 
87ff2c293eSTakashi Sakamoto 	err = snd_ff_create_midi_devices(ff);
88ff2c293eSTakashi Sakamoto 	if (err < 0)
89ff2c293eSTakashi Sakamoto 		goto error;
90ff2c293eSTakashi Sakamoto 
914b316436STakashi Sakamoto 	err = snd_ff_create_pcm_devices(ff);
924b316436STakashi Sakamoto 	if (err < 0)
934b316436STakashi Sakamoto 		goto error;
944b316436STakashi Sakamoto 
95f656edd5STakashi Sakamoto 	err = snd_ff_create_hwdep_devices(ff);
96f656edd5STakashi Sakamoto 	if (err < 0)
97f656edd5STakashi Sakamoto 		goto error;
98f656edd5STakashi Sakamoto 
99c31909faSTakashi Sakamoto 	if (ff->spec->protocol->msg_parser_size > 0) {
100c31909faSTakashi Sakamoto 		ff->msg_parser = kzalloc(ff->spec->protocol->msg_parser_size, GFP_KERNEL);
101c31909faSTakashi Sakamoto 		if (!ff->msg_parser) {
102c31909faSTakashi Sakamoto 			err = -ENOMEM;
103c31909faSTakashi Sakamoto 			goto error;
104c31909faSTakashi Sakamoto 		}
105c31909faSTakashi Sakamoto 	}
106c31909faSTakashi Sakamoto 
107ee5f0b32STakashi Sakamoto 	err = snd_card_register(card);
108324540c4STakashi Sakamoto 	if (err < 0)
109324540c4STakashi Sakamoto 		goto error;
110324540c4STakashi Sakamoto 
11117c4e5eaSTakashi Sakamoto 	return 0;
112ee5f0b32STakashi Sakamoto error:
113ee5f0b32STakashi Sakamoto 	snd_card_free(card);
114ee5f0b32STakashi Sakamoto 	return err;
11517c4e5eaSTakashi Sakamoto }
11617c4e5eaSTakashi Sakamoto 
snd_ff_update(struct fw_unit * unit)11717c4e5eaSTakashi Sakamoto static void snd_ff_update(struct fw_unit *unit)
11817c4e5eaSTakashi Sakamoto {
119324540c4STakashi Sakamoto 	struct snd_ff *ff = dev_get_drvdata(&unit->device);
120324540c4STakashi Sakamoto 
12119174295STakashi Sakamoto 	snd_ff_transaction_reregister(ff);
12275d6d898STakashi Sakamoto 
12375d6d898STakashi Sakamoto 	snd_ff_stream_update_duplex(ff);
12417c4e5eaSTakashi Sakamoto }
12517c4e5eaSTakashi Sakamoto 
snd_ff_remove(struct fw_unit * unit)12617c4e5eaSTakashi Sakamoto static void snd_ff_remove(struct fw_unit *unit)
12717c4e5eaSTakashi Sakamoto {
12817c4e5eaSTakashi Sakamoto 	struct snd_ff *ff = dev_get_drvdata(&unit->device);
12917c4e5eaSTakashi Sakamoto 
13061ccc6f6STakashi Sakamoto 	// Block till all of ALSA character devices are released.
13161ccc6f6STakashi Sakamoto 	snd_card_free(ff->card);
132324540c4STakashi Sakamoto }
1335b14ec25STakashi Sakamoto 
134a91f6760STakashi Sakamoto static const struct snd_ff_spec spec_ff800 = {
135fc716397STakashi Sakamoto 	.pcm_capture_channels = {28, 20, 12},
136fc716397STakashi Sakamoto 	.pcm_playback_channels = {28, 20, 12},
137a91f6760STakashi Sakamoto 	.midi_in_ports = 1,
138a91f6760STakashi Sakamoto 	.midi_out_ports = 1,
139a91f6760STakashi Sakamoto 	.protocol = &snd_ff_protocol_ff800,
1406d1ef1bbSTakashi Sakamoto 	.midi_high_addr = 0x000200000320ull,
14190089677STakashi Sakamoto 	.midi_addr_range = 12,
142481e09acSTakashi Sakamoto 	.midi_rx_addrs = {0x000080180000ull, 0},
143a91f6760STakashi Sakamoto };
144a91f6760STakashi Sakamoto 
145782fbec7STakashi Sakamoto static const struct snd_ff_spec spec_ff400 = {
14676fdb3a9STakashi Sakamoto 	.pcm_capture_channels = {18, 14, 10},
14776fdb3a9STakashi Sakamoto 	.pcm_playback_channels = {18, 14, 10},
14876fdb3a9STakashi Sakamoto 	.midi_in_ports = 2,
14976fdb3a9STakashi Sakamoto 	.midi_out_ports = 2,
15076fdb3a9STakashi Sakamoto 	.protocol = &snd_ff_protocol_ff400,
1516d1ef1bbSTakashi Sakamoto 	.midi_high_addr = 0x0000801003f4ull,
15290089677STakashi Sakamoto 	.midi_addr_range = SND_FF_MAXIMIM_MIDI_QUADS * 4,
153481e09acSTakashi Sakamoto 	.midi_rx_addrs = {0x000080180000ull, 0x000080190000ull},
15476fdb3a9STakashi Sakamoto };
15576fdb3a9STakashi Sakamoto 
156fd1cc9deSTakashi Sakamoto static const struct snd_ff_spec spec_ucx = {
157fd1cc9deSTakashi Sakamoto 	.pcm_capture_channels = {18, 14, 12},
158fd1cc9deSTakashi Sakamoto 	.pcm_playback_channels = {18, 14, 12},
15973f5537fSTakashi Sakamoto 	.midi_in_ports = 2,
160f0f9f497STakashi Sakamoto 	.midi_out_ports = 2,
161fd1cc9deSTakashi Sakamoto 	.protocol = &snd_ff_protocol_latter,
16273f5537fSTakashi Sakamoto 	.midi_high_addr = 0xffff00000034ull,
16373f5537fSTakashi Sakamoto 	.midi_addr_range = 0x80,
164481e09acSTakashi Sakamoto 	.midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull},
165fd1cc9deSTakashi Sakamoto };
166fd1cc9deSTakashi Sakamoto 
1671f65e668STakashi Sakamoto static const struct snd_ff_spec spec_ufx_802 = {
168062bb452STakashi Sakamoto 	.pcm_capture_channels = {30, 22, 14},
169062bb452STakashi Sakamoto 	.pcm_playback_channels = {30, 22, 14},
170062bb452STakashi Sakamoto 	.midi_in_ports = 1,
171062bb452STakashi Sakamoto 	.midi_out_ports = 1,
172062bb452STakashi Sakamoto 	.protocol = &snd_ff_protocol_latter,
173062bb452STakashi Sakamoto 	.midi_high_addr = 0xffff00000034ull,
174062bb452STakashi Sakamoto 	.midi_addr_range = 0x80,
175062bb452STakashi Sakamoto 	.midi_rx_addrs = {0xffff00000030ull, 0xffff00000030ull},
176062bb452STakashi Sakamoto };
177062bb452STakashi Sakamoto 
17817c4e5eaSTakashi Sakamoto static const struct ieee1394_device_id snd_ff_id_table[] = {
179a91f6760STakashi Sakamoto 	/* Fireface 800 */
180a91f6760STakashi Sakamoto 	{
181a91f6760STakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
182a91f6760STakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
183a91f6760STakashi Sakamoto 				  IEEE1394_MATCH_VERSION |
184a91f6760STakashi Sakamoto 				  IEEE1394_MATCH_MODEL_ID,
185a91f6760STakashi Sakamoto 		.vendor_id	= OUI_RME,
186a91f6760STakashi Sakamoto 		.specifier_id	= OUI_RME,
187c52f232eSTakashi Sakamoto 		.version	= SND_FF_UNIT_VERSION_FF800,
188a91f6760STakashi Sakamoto 		.model_id	= 0x101800,
189a91f6760STakashi Sakamoto 		.driver_data	= (kernel_ulong_t)&spec_ff800,
190a91f6760STakashi Sakamoto 	},
19176fdb3a9STakashi Sakamoto 	/* Fireface 400 */
19276fdb3a9STakashi Sakamoto 	{
19376fdb3a9STakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
19476fdb3a9STakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
19576fdb3a9STakashi Sakamoto 				  IEEE1394_MATCH_VERSION |
19676fdb3a9STakashi Sakamoto 				  IEEE1394_MATCH_MODEL_ID,
19776fdb3a9STakashi Sakamoto 		.vendor_id	= OUI_RME,
198a91f6760STakashi Sakamoto 		.specifier_id	= OUI_RME,
199c52f232eSTakashi Sakamoto 		.version	= SND_FF_UNIT_VERSION_FF400,
20076fdb3a9STakashi Sakamoto 		.model_id	= 0x101800,
20176fdb3a9STakashi Sakamoto 		.driver_data	= (kernel_ulong_t)&spec_ff400,
20276fdb3a9STakashi Sakamoto 	},
2031f65e668STakashi Sakamoto 	// Fireface UFX.
2041f65e668STakashi Sakamoto 	{
2051f65e668STakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
2061f65e668STakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
2071f65e668STakashi Sakamoto 				  IEEE1394_MATCH_VERSION |
2081f65e668STakashi Sakamoto 				  IEEE1394_MATCH_MODEL_ID,
2091f65e668STakashi Sakamoto 		.vendor_id	= OUI_RME,
2101f65e668STakashi Sakamoto 		.specifier_id	= OUI_RME,
2111f65e668STakashi Sakamoto 		.version	= SND_FF_UNIT_VERSION_UFX,
2121f65e668STakashi Sakamoto 		.model_id	= 0x101800,
2131f65e668STakashi Sakamoto 		.driver_data	= (kernel_ulong_t)&spec_ufx_802,
2141f65e668STakashi Sakamoto 	},
215fd1cc9deSTakashi Sakamoto 	// Fireface UCX.
216fd1cc9deSTakashi Sakamoto 	{
217fd1cc9deSTakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
218fd1cc9deSTakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
219fd1cc9deSTakashi Sakamoto 				  IEEE1394_MATCH_VERSION |
220fd1cc9deSTakashi Sakamoto 				  IEEE1394_MATCH_MODEL_ID,
221fd1cc9deSTakashi Sakamoto 		.vendor_id	= OUI_RME,
222fd1cc9deSTakashi Sakamoto 		.specifier_id	= OUI_RME,
223c52f232eSTakashi Sakamoto 		.version	= SND_FF_UNIT_VERSION_UCX,
224fd1cc9deSTakashi Sakamoto 		.model_id	= 0x101800,
225fd1cc9deSTakashi Sakamoto 		.driver_data	= (kernel_ulong_t)&spec_ucx,
226fd1cc9deSTakashi Sakamoto 	},
227062bb452STakashi Sakamoto 	// Fireface 802.
228062bb452STakashi Sakamoto 	{
229062bb452STakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
230062bb452STakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
231062bb452STakashi Sakamoto 				  IEEE1394_MATCH_VERSION |
232062bb452STakashi Sakamoto 				  IEEE1394_MATCH_MODEL_ID,
233062bb452STakashi Sakamoto 		.vendor_id	= OUI_RME,
234062bb452STakashi Sakamoto 		.specifier_id	= OUI_RME,
235062bb452STakashi Sakamoto 		.version	= SND_FF_UNIT_VERSION_802,
236062bb452STakashi Sakamoto 		.model_id	= 0x101800,
2371f65e668STakashi Sakamoto 		.driver_data	= (kernel_ulong_t)&spec_ufx_802,
238062bb452STakashi Sakamoto 	},
23917c4e5eaSTakashi Sakamoto 	{}
24017c4e5eaSTakashi Sakamoto };
24117c4e5eaSTakashi Sakamoto MODULE_DEVICE_TABLE(ieee1394, snd_ff_id_table);
24217c4e5eaSTakashi Sakamoto 
24317c4e5eaSTakashi Sakamoto static struct fw_driver ff_driver = {
24417c4e5eaSTakashi Sakamoto 	.driver = {
24517c4e5eaSTakashi Sakamoto 		.owner	= THIS_MODULE,
2469c0d16acSTakashi Sakamoto 		.name	= KBUILD_MODNAME,
24717c4e5eaSTakashi Sakamoto 		.bus	= &fw_bus_type,
24817c4e5eaSTakashi Sakamoto 	},
24917c4e5eaSTakashi Sakamoto 	.probe    = snd_ff_probe,
25017c4e5eaSTakashi Sakamoto 	.update   = snd_ff_update,
25117c4e5eaSTakashi Sakamoto 	.remove   = snd_ff_remove,
25217c4e5eaSTakashi Sakamoto 	.id_table = snd_ff_id_table,
25317c4e5eaSTakashi Sakamoto };
25417c4e5eaSTakashi Sakamoto 
snd_ff_init(void)25517c4e5eaSTakashi Sakamoto static int __init snd_ff_init(void)
25617c4e5eaSTakashi Sakamoto {
25717c4e5eaSTakashi Sakamoto 	return driver_register(&ff_driver.driver);
25817c4e5eaSTakashi Sakamoto }
25917c4e5eaSTakashi Sakamoto 
snd_ff_exit(void)26017c4e5eaSTakashi Sakamoto static void __exit snd_ff_exit(void)
26117c4e5eaSTakashi Sakamoto {
26217c4e5eaSTakashi Sakamoto 	driver_unregister(&ff_driver.driver);
26317c4e5eaSTakashi Sakamoto }
26417c4e5eaSTakashi Sakamoto 
26517c4e5eaSTakashi Sakamoto module_init(snd_ff_init);
26617c4e5eaSTakashi Sakamoto module_exit(snd_ff_exit);
267