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