xref: /openbmc/linux/sound/firewire/oxfw/oxfw.c (revision 641e9691)
1da607e19SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21a4e39c2STakashi Sakamoto /*
31a4e39c2STakashi Sakamoto  * oxfw.c - a part of driver for OXFW970/971 based devices
41a4e39c2STakashi Sakamoto  *
51a4e39c2STakashi Sakamoto  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
61a4e39c2STakashi Sakamoto  */
71a4e39c2STakashi Sakamoto 
8e2786ca6STakashi Sakamoto #include "oxfw.h"
91a4e39c2STakashi Sakamoto 
101a4e39c2STakashi Sakamoto #define OXFORD_FIRMWARE_ID_ADDRESS	(CSR_REGISTER_BASE + 0x50000)
111a4e39c2STakashi Sakamoto /* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
121a4e39c2STakashi Sakamoto 
131a4e39c2STakashi Sakamoto #define OXFORD_HARDWARE_ID_ADDRESS	(CSR_REGISTER_BASE + 0x90020)
141a4e39c2STakashi Sakamoto #define OXFORD_HARDWARE_ID_OXFW970	0x39443841
151a4e39c2STakashi Sakamoto #define OXFORD_HARDWARE_ID_OXFW971	0x39373100
161a4e39c2STakashi Sakamoto 
17ec4dba50STakashi Sakamoto #define VENDOR_LOUD		0x000ff2
181a4e39c2STakashi Sakamoto #define VENDOR_GRIFFIN		0x001292
19ec4dba50STakashi Sakamoto #define VENDOR_BEHRINGER	0x001564
201a4e39c2STakashi Sakamoto #define VENDOR_LACIE		0x00d04b
21759a2f40STakashi Sakamoto #define VENDOR_TASCAM		0x00022e
229e2004f9STakashi Sakamoto #define OUI_STANTON		0x001260
23fba43f45STakashi Sakamoto #define OUI_APOGEE		0x0003db
241a4e39c2STakashi Sakamoto 
2513f3a46dSTakashi Sakamoto #define MODEL_SATELLITE		0x00200f
2607a35edcSTakashi Sakamoto #define MODEL_SCS1M		0x001000
2707a35edcSTakashi Sakamoto #define MODEL_DUET_FW		0x01dddd
28cddcd547STakashi Sakamoto #define MODEL_ONYX_1640I	0x001640
2913f3a46dSTakashi Sakamoto 
301a4e39c2STakashi Sakamoto #define SPECIFIER_1394TA	0x00a02d
311a4e39c2STakashi Sakamoto #define VERSION_AVC		0x010001
321a4e39c2STakashi Sakamoto 
331a4e39c2STakashi Sakamoto MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
341a4e39c2STakashi Sakamoto MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
359b446941STakashi Sakamoto MODULE_LICENSE("GPL");
361a4e39c2STakashi Sakamoto MODULE_ALIAS("snd-firewire-speakers");
379e2004f9STakashi Sakamoto MODULE_ALIAS("snd-scs1x");
381a4e39c2STakashi Sakamoto 
39d6ce6bbdSTakashi Sakamoto struct compat_info {
40d6ce6bbdSTakashi Sakamoto 	const char *driver_name;
41d6ce6bbdSTakashi Sakamoto 	const char *vendor_name;
42d6ce6bbdSTakashi Sakamoto 	const char *model_name;
43d6ce6bbdSTakashi Sakamoto };
44d6ce6bbdSTakashi Sakamoto 
detect_loud_models(struct fw_unit * unit)45ec4dba50STakashi Sakamoto static bool detect_loud_models(struct fw_unit *unit)
46ec4dba50STakashi Sakamoto {
47d17f0ce9SColin Ian King 	static const char *const models[] = {
48ec4dba50STakashi Sakamoto 		"Onyxi",
49ec4dba50STakashi Sakamoto 		"Onyx-i",
5003abd33aSTakashi Sakamoto 		"Onyx 1640i",
51ec4dba50STakashi Sakamoto 		"d.Pro",
52ec4dba50STakashi Sakamoto 		"U.420"};
53ec4dba50STakashi Sakamoto 	char model[32];
54ec4dba50STakashi Sakamoto 	int err;
55ec4dba50STakashi Sakamoto 
56ec4dba50STakashi Sakamoto 	err = fw_csr_string(unit->directory, CSR_MODEL,
57ec4dba50STakashi Sakamoto 			    model, sizeof(model));
58ec4dba50STakashi Sakamoto 	if (err < 0)
590d3aba30SDan Carpenter 		return false;
60ec4dba50STakashi Sakamoto 
612cc47d31SYisheng Xie 	return match_string(models, ARRAY_SIZE(models), model) >= 0;
62ec4dba50STakashi Sakamoto }
63ec4dba50STakashi Sakamoto 
name_card(struct snd_oxfw * oxfw,const struct ieee1394_device_id * entry)64b566e972STakashi Sakamoto static int name_card(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry)
651a4e39c2STakashi Sakamoto {
66fec7b753STakashi Sakamoto 	struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
67d6ce6bbdSTakashi Sakamoto 	const struct compat_info *info;
68ec4dba50STakashi Sakamoto 	char vendor[24];
69ec4dba50STakashi Sakamoto 	char model[32];
70fec7b753STakashi Sakamoto 	const char *d, *v, *m;
71fec7b753STakashi Sakamoto 	u32 firmware;
721a4e39c2STakashi Sakamoto 	int err;
731a4e39c2STakashi Sakamoto 
74ec4dba50STakashi Sakamoto 	/* get vendor name from root directory */
75ec4dba50STakashi Sakamoto 	err = fw_csr_string(fw_dev->config_rom + 5, CSR_VENDOR,
76ec4dba50STakashi Sakamoto 			    vendor, sizeof(vendor));
77ec4dba50STakashi Sakamoto 	if (err < 0)
78ec4dba50STakashi Sakamoto 		goto end;
79ec4dba50STakashi Sakamoto 
80ec4dba50STakashi Sakamoto 	/* get model name from unit directory */
81ec4dba50STakashi Sakamoto 	err = fw_csr_string(oxfw->unit->directory, CSR_MODEL,
82ec4dba50STakashi Sakamoto 			    model, sizeof(model));
83ec4dba50STakashi Sakamoto 	if (err < 0)
84ec4dba50STakashi Sakamoto 		goto end;
85ec4dba50STakashi Sakamoto 
86fec7b753STakashi Sakamoto 	err = snd_fw_transaction(oxfw->unit, TCODE_READ_QUADLET_REQUEST,
87fec7b753STakashi Sakamoto 				 OXFORD_FIRMWARE_ID_ADDRESS, &firmware, 4, 0);
88fec7b753STakashi Sakamoto 	if (err < 0)
89fec7b753STakashi Sakamoto 		goto end;
90fec7b753STakashi Sakamoto 	be32_to_cpus(&firmware);
91fec7b753STakashi Sakamoto 
92a092f000STakashi Sakamoto 	if (firmware >> 20 == 0x970)
93a092f000STakashi Sakamoto 		oxfw->quirks |= SND_OXFW_QUIRK_JUMBO_PAYLOAD;
94a092f000STakashi Sakamoto 
95ec4dba50STakashi Sakamoto 	/* to apply card definitions */
96b566e972STakashi Sakamoto 	if (entry->vendor_id == VENDOR_GRIFFIN || entry->vendor_id == VENDOR_LACIE) {
97b566e972STakashi Sakamoto 		info = (const struct compat_info *)entry->driver_data;
9827e66635STakashi Sakamoto 		d = info->driver_name;
9927e66635STakashi Sakamoto 		v = info->vendor_name;
10027e66635STakashi Sakamoto 		m = info->model_name;
101ec4dba50STakashi Sakamoto 	} else {
102ec4dba50STakashi Sakamoto 		d = "OXFW";
103ec4dba50STakashi Sakamoto 		v = vendor;
104ec4dba50STakashi Sakamoto 		m = model;
105ec4dba50STakashi Sakamoto 	}
106fec7b753STakashi Sakamoto 
107fec7b753STakashi Sakamoto 	strcpy(oxfw->card->driver, d);
108fec7b753STakashi Sakamoto 	strcpy(oxfw->card->mixername, m);
109fec7b753STakashi Sakamoto 	strcpy(oxfw->card->shortname, m);
110fec7b753STakashi Sakamoto 
111*641e9691STakashi Iwai 	scnprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
112fec7b753STakashi Sakamoto 		  "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
113fec7b753STakashi Sakamoto 		  v, m, firmware >> 20, firmware & 0xffff,
114fec7b753STakashi Sakamoto 		  fw_dev->config_rom[3], fw_dev->config_rom[4],
115fec7b753STakashi Sakamoto 		  dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
116fec7b753STakashi Sakamoto end:
117fec7b753STakashi Sakamoto 	return err;
1181a4e39c2STakashi Sakamoto }
1191a4e39c2STakashi Sakamoto 
oxfw_card_free(struct snd_card * card)1203babca45STakashi Sakamoto static void oxfw_card_free(struct snd_card *card)
1211a4e39c2STakashi Sakamoto {
1223babca45STakashi Sakamoto 	struct snd_oxfw *oxfw = card->private_data;
1233babca45STakashi Sakamoto 
12406a42a74STakashi Sakamoto 	if (oxfw->has_output || oxfw->has_input)
125779f0dbaSTakashi Sakamoto 		snd_oxfw_stream_destroy_duplex(oxfw);
126b566e972STakashi Sakamoto 
127b566e972STakashi Sakamoto 	mutex_destroy(&oxfw->mutex);
128b566e972STakashi Sakamoto 	fw_unit_put(oxfw->unit);
1291a4e39c2STakashi Sakamoto }
1301a4e39c2STakashi Sakamoto 
detect_quirks(struct snd_oxfw * oxfw,const struct ieee1394_device_id * entry)131b566e972STakashi Sakamoto static int detect_quirks(struct snd_oxfw *oxfw, const struct ieee1394_device_id *entry)
13213f3a46dSTakashi Sakamoto {
13313f3a46dSTakashi Sakamoto 	struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
13413f3a46dSTakashi Sakamoto 	struct fw_csr_iterator it;
13513f3a46dSTakashi Sakamoto 	int key, val;
13613f3a46dSTakashi Sakamoto 	int vendor, model;
13713f3a46dSTakashi Sakamoto 
13827e66635STakashi Sakamoto 	/*
1395ce8cc48STakashi Sakamoto 	 * Add ALSA control elements for two models to keep compatibility to
1405ce8cc48STakashi Sakamoto 	 * old firewire-speaker module.
1415ce8cc48STakashi Sakamoto 	 */
142b566e972STakashi Sakamoto 	if (entry->vendor_id == VENDOR_GRIFFIN)
1433e2f4570STakashi Sakamoto 		return snd_oxfw_add_spkr(oxfw, false);
144b566e972STakashi Sakamoto 	if (entry->vendor_id == VENDOR_LACIE)
1453e2f4570STakashi Sakamoto 		return snd_oxfw_add_spkr(oxfw, true);
1465ce8cc48STakashi Sakamoto 
1475ce8cc48STakashi Sakamoto 	/*
1489e2004f9STakashi Sakamoto 	 * Stanton models supports asynchronous transactions for unique MIDI
1499e2004f9STakashi Sakamoto 	 * messages.
1509e2004f9STakashi Sakamoto 	 */
151b566e972STakashi Sakamoto 	if (entry->vendor_id == OUI_STANTON) {
152b566e972STakashi Sakamoto 		oxfw->quirks |= SND_OXFW_QUIRK_SCS_TRANSACTION;
153b566e972STakashi Sakamoto 		if (entry->model_id == MODEL_SCS1M)
15407a35edcSTakashi Sakamoto 			oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION;
15507a35edcSTakashi Sakamoto 
15607a35edcSTakashi Sakamoto 		// No physical MIDI ports.
157de5126ccSTakashi Sakamoto 		oxfw->midi_input_ports = 0;
158de5126ccSTakashi Sakamoto 		oxfw->midi_output_ports = 0;
159de5126ccSTakashi Sakamoto 
1609e2004f9STakashi Sakamoto 		return snd_oxfw_scs1x_add(oxfw);
161de5126ccSTakashi Sakamoto 	}
1629e2004f9STakashi Sakamoto 
16367bb66d3STakashi Sakamoto 	if (entry->vendor_id == OUI_APOGEE && entry->model_id == MODEL_DUET_FW) {
16467bb66d3STakashi Sakamoto 		oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION |
16567bb66d3STakashi Sakamoto 				SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET;
16667bb66d3STakashi Sakamoto 	}
16707a35edcSTakashi Sakamoto 
1689e2004f9STakashi Sakamoto 	/*
16927e66635STakashi Sakamoto 	 * TASCAM FireOne has physical control and requires a pair of additional
17027e66635STakashi Sakamoto 	 * MIDI ports.
17127e66635STakashi Sakamoto 	 */
172b566e972STakashi Sakamoto 	if (entry->vendor_id == VENDOR_TASCAM) {
17327e66635STakashi Sakamoto 		oxfw->midi_input_ports++;
17427e66635STakashi Sakamoto 		oxfw->midi_output_ports++;
1755ce8cc48STakashi Sakamoto 		return 0;
17627e66635STakashi Sakamoto 	}
17727e66635STakashi Sakamoto 
17813f3a46dSTakashi Sakamoto 	/* Seek from Root Directory of Config ROM. */
17913f3a46dSTakashi Sakamoto 	vendor = model = 0;
18013f3a46dSTakashi Sakamoto 	fw_csr_iterator_init(&it, fw_dev->config_rom + 5);
18113f3a46dSTakashi Sakamoto 	while (fw_csr_iterator_next(&it, &key, &val)) {
18213f3a46dSTakashi Sakamoto 		if (key == CSR_VENDOR)
18313f3a46dSTakashi Sakamoto 			vendor = val;
18413f3a46dSTakashi Sakamoto 		else if (key == CSR_MODEL)
18513f3a46dSTakashi Sakamoto 			model = val;
18613f3a46dSTakashi Sakamoto 	}
18713f3a46dSTakashi Sakamoto 
18864794d6dSTakashi Sakamoto 	if (vendor == VENDOR_LOUD) {
18964794d6dSTakashi Sakamoto 		// Mackie Onyx Satellite with base station has a quirk to report a wrong
19064794d6dSTakashi Sakamoto 		// value in 'dbs' field of CIP header against its format information.
191a6f91693STakashi Sakamoto 		oxfw->quirks |= SND_OXFW_QUIRK_WRONG_DBS;
1925ce8cc48STakashi Sakamoto 
19364794d6dSTakashi Sakamoto 		// OXFW971-based models may transfer events by blocking method.
19464794d6dSTakashi Sakamoto 		if (!(oxfw->quirks & SND_OXFW_QUIRK_JUMBO_PAYLOAD))
19564794d6dSTakashi Sakamoto 			oxfw->quirks |= SND_OXFW_QUIRK_BLOCKING_TRANSMISSION;
196cddcd547STakashi Sakamoto 
197cddcd547STakashi Sakamoto 		if (model == MODEL_ONYX_1640I) {
198cddcd547STakashi Sakamoto 			//Unless receiving packets without NOINFO packet, the device transfers
199cddcd547STakashi Sakamoto 			//mostly half of events in packets than expected.
200cddcd547STakashi Sakamoto 			oxfw->quirks |= SND_OXFW_QUIRK_IGNORE_NO_INFO_PACKET |
201cddcd547STakashi Sakamoto 					SND_OXFW_QUIRK_VOLUNTARY_RECOVERY;
202cddcd547STakashi Sakamoto 		}
20364794d6dSTakashi Sakamoto 	}
20464794d6dSTakashi Sakamoto 
2055ce8cc48STakashi Sakamoto 	return 0;
20613f3a46dSTakashi Sakamoto }
20713f3a46dSTakashi Sakamoto 
oxfw_probe(struct fw_unit * unit,const struct ieee1394_device_id * entry)208b566e972STakashi Sakamoto static int oxfw_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
2091a4e39c2STakashi Sakamoto {
210b566e972STakashi Sakamoto 	struct snd_card *card;
211b566e972STakashi Sakamoto 	struct snd_oxfw *oxfw;
2121a4e39c2STakashi Sakamoto 	int err;
2131a4e39c2STakashi Sakamoto 
214b566e972STakashi Sakamoto 	if (entry->vendor_id == VENDOR_LOUD && entry->model_id == 0 && !detect_loud_models(unit))
215b566e972STakashi Sakamoto 		return -ENODEV;
216ec4dba50STakashi Sakamoto 
217b566e972STakashi Sakamoto 	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*oxfw), &card);
2181a4e39c2STakashi Sakamoto 	if (err < 0)
219b566e972STakashi Sakamoto 		return err;
220b566e972STakashi Sakamoto 	card->private_free = oxfw_card_free;
2215cd1d3f4STakashi Sakamoto 
222b566e972STakashi Sakamoto 	oxfw = card->private_data;
223b566e972STakashi Sakamoto 	oxfw->unit = fw_unit_get(unit);
224b566e972STakashi Sakamoto 	dev_set_drvdata(&unit->device, oxfw);
225b566e972STakashi Sakamoto 	oxfw->card = card;
226b566e972STakashi Sakamoto 
227b566e972STakashi Sakamoto 	mutex_init(&oxfw->mutex);
228b566e972STakashi Sakamoto 	spin_lock_init(&oxfw->lock);
229b566e972STakashi Sakamoto 	init_waitqueue_head(&oxfw->hwdep_wait);
230b566e972STakashi Sakamoto 
231b566e972STakashi Sakamoto 	err = name_card(oxfw, entry);
2325ce8cc48STakashi Sakamoto 	if (err < 0)
2335ce8cc48STakashi Sakamoto 		goto error;
23413f3a46dSTakashi Sakamoto 
2353d016d57STakashi Sakamoto 	err = snd_oxfw_stream_discover(oxfw);
236fec7b753STakashi Sakamoto 	if (err < 0)
237fec7b753STakashi Sakamoto 		goto error;
2381a4e39c2STakashi Sakamoto 
239b566e972STakashi Sakamoto 	err = detect_quirks(oxfw, entry);
2406c29230eSTakashi Sakamoto 	if (err < 0)
2416c29230eSTakashi Sakamoto 		goto error;
2426c29230eSTakashi Sakamoto 
24306a42a74STakashi Sakamoto 	if (oxfw->has_output || oxfw->has_input) {
244779f0dbaSTakashi Sakamoto 		err = snd_oxfw_stream_init_duplex(oxfw);
2456c29230eSTakashi Sakamoto 		if (err < 0)
2466c29230eSTakashi Sakamoto 			goto error;
2476c29230eSTakashi Sakamoto 
2483713d93aSTakashi Sakamoto 		err = snd_oxfw_create_pcm(oxfw);
2491a4e39c2STakashi Sakamoto 		if (err < 0)
2501a4e39c2STakashi Sakamoto 			goto error;
2511a4e39c2STakashi Sakamoto 
2523c96101fSTakashi Sakamoto 		snd_oxfw_proc_init(oxfw);
2533c96101fSTakashi Sakamoto 
25405588d34STakashi Sakamoto 		err = snd_oxfw_create_midi(oxfw);
25505588d34STakashi Sakamoto 		if (err < 0)
25605588d34STakashi Sakamoto 			goto error;
25705588d34STakashi Sakamoto 
2588985f4acSTakashi Sakamoto 		err = snd_oxfw_create_hwdep(oxfw);
2598985f4acSTakashi Sakamoto 		if (err < 0)
2608985f4acSTakashi Sakamoto 			goto error;
26106a42a74STakashi Sakamoto 	}
2628985f4acSTakashi Sakamoto 
263b566e972STakashi Sakamoto 	err = snd_card_register(card);
2641a4e39c2STakashi Sakamoto 	if (err < 0)
2651a4e39c2STakashi Sakamoto 		goto error;
2661a4e39c2STakashi Sakamoto 
2671a4e39c2STakashi Sakamoto 	return 0;
268b566e972STakashi Sakamoto error:
269b566e972STakashi Sakamoto 	snd_card_free(card);
270b566e972STakashi Sakamoto 	return err;
2711a4e39c2STakashi Sakamoto }
2721a4e39c2STakashi Sakamoto 
oxfw_bus_reset(struct fw_unit * unit)2731a4e39c2STakashi Sakamoto static void oxfw_bus_reset(struct fw_unit *unit)
2741a4e39c2STakashi Sakamoto {
2751a4e39c2STakashi Sakamoto 	struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
2761a4e39c2STakashi Sakamoto 
2771a4e39c2STakashi Sakamoto 	fcp_bus_reset(oxfw->unit);
2781a4e39c2STakashi Sakamoto 
27906a42a74STakashi Sakamoto 	if (oxfw->has_output || oxfw->has_input) {
2801a4e39c2STakashi Sakamoto 		mutex_lock(&oxfw->mutex);
281779f0dbaSTakashi Sakamoto 		snd_oxfw_stream_update_duplex(oxfw);
2821a4e39c2STakashi Sakamoto 		mutex_unlock(&oxfw->mutex);
28306a42a74STakashi Sakamoto 	}
2849e2004f9STakashi Sakamoto 
285b566e972STakashi Sakamoto 	if (oxfw->quirks & SND_OXFW_QUIRK_SCS_TRANSACTION)
2869e2004f9STakashi Sakamoto 		snd_oxfw_scs1x_update(oxfw);
2871a4e39c2STakashi Sakamoto }
2881a4e39c2STakashi Sakamoto 
oxfw_remove(struct fw_unit * unit)2891a4e39c2STakashi Sakamoto static void oxfw_remove(struct fw_unit *unit)
2901a4e39c2STakashi Sakamoto {
2911a4e39c2STakashi Sakamoto 	struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
2921a4e39c2STakashi Sakamoto 
29361ccc6f6STakashi Sakamoto 	// Block till all of ALSA character devices are released.
29461ccc6f6STakashi Sakamoto 	snd_card_free(oxfw->card);
2956c29230eSTakashi Sakamoto }
2965b14ec25STakashi Sakamoto 
297d6ce6bbdSTakashi Sakamoto static const struct compat_info griffin_firewave = {
2981a4e39c2STakashi Sakamoto 	.driver_name = "FireWave",
299fec7b753STakashi Sakamoto 	.vendor_name = "Griffin",
300fec7b753STakashi Sakamoto 	.model_name = "FireWave",
3011a4e39c2STakashi Sakamoto };
3021a4e39c2STakashi Sakamoto 
303d6ce6bbdSTakashi Sakamoto static const struct compat_info lacie_speakers = {
3041a4e39c2STakashi Sakamoto 	.driver_name = "FWSpeakers",
305fec7b753STakashi Sakamoto 	.vendor_name = "LaCie",
306fec7b753STakashi Sakamoto 	.model_name = "FireWire Speakers",
3071a4e39c2STakashi Sakamoto };
3081a4e39c2STakashi Sakamoto 
309c127d5cdSTakashi Sakamoto #define OXFW_DEV_ENTRY(vendor, model, data) \
310c127d5cdSTakashi Sakamoto { \
311c127d5cdSTakashi Sakamoto 	.match_flags  = IEEE1394_MATCH_VENDOR_ID | \
312c127d5cdSTakashi Sakamoto 			IEEE1394_MATCH_MODEL_ID | \
313c127d5cdSTakashi Sakamoto 			IEEE1394_MATCH_SPECIFIER_ID | \
314c127d5cdSTakashi Sakamoto 			IEEE1394_MATCH_VERSION, \
315c127d5cdSTakashi Sakamoto 	.vendor_id    = vendor, \
316c127d5cdSTakashi Sakamoto 	.model_id     = model, \
317c127d5cdSTakashi Sakamoto 	.specifier_id = SPECIFIER_1394TA, \
318c127d5cdSTakashi Sakamoto 	.version      = VERSION_AVC, \
319c127d5cdSTakashi Sakamoto 	.driver_data  = (kernel_ulong_t)data, \
320c127d5cdSTakashi Sakamoto }
321c127d5cdSTakashi Sakamoto 
3221a4e39c2STakashi Sakamoto static const struct ieee1394_device_id oxfw_id_table[] = {
32395d0c24dSTakashi Sakamoto 	//
32495d0c24dSTakashi Sakamoto 	// OXFW970 devices:
32595d0c24dSTakashi Sakamoto 	// Initial firmware has a quirk to postpone isoc packet transmission during finishing async
32695d0c24dSTakashi Sakamoto 	// transaction. As a result, several isochronous cycles are skipped to transfer the packets
32795d0c24dSTakashi Sakamoto 	// and the audio data frames which should have been transferred during the cycles are put
32895d0c24dSTakashi Sakamoto 	// into packet at the first isoc cycle after the postpone. Furthermore, the value of SYT
32995d0c24dSTakashi Sakamoto 	// field in CIP header is not reliable as synchronization timing,
33095d0c24dSTakashi Sakamoto 	//
331c127d5cdSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_GRIFFIN, 0x00f970, &griffin_firewave),
332c127d5cdSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_LACIE, 0x00f970, &lacie_speakers),
33395d0c24dSTakashi Sakamoto 	// Behringer,F-Control Audio 202. The value of SYT field is not reliable at all.
334c127d5cdSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_BEHRINGER, 0x00fc22, NULL),
33595d0c24dSTakashi Sakamoto 	// Loud Technologies, Tapco Link.FireWire 4x6. The value of SYT field is always 0xffff.
3362239924bSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_LOUD, 0x000460, NULL),
33795d0c24dSTakashi Sakamoto 	// Loud Technologies, Mackie Onyx Satellite. Although revised version of firmware is
33895d0c24dSTakashi Sakamoto 	// installed to avoid the postpone, the value of SYT field is always 0xffff.
339c59bc10eSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_LOUD, MODEL_SATELLITE, NULL),
34095d0c24dSTakashi Sakamoto 	// Miglia HarmonyAudio. Not yet identified.
34195d0c24dSTakashi Sakamoto 
34295d0c24dSTakashi Sakamoto 	//
34395d0c24dSTakashi Sakamoto 	// OXFW971 devices:
34495d0c24dSTakashi Sakamoto 	// The value of SYT field in CIP header is enough reliable. Both of blocking and non-blocking
34595d0c24dSTakashi Sakamoto 	// transmission methods are available.
34695d0c24dSTakashi Sakamoto 	//
347c59bc10eSTakashi Sakamoto 	// Any Mackie(Loud) models (name string/model id):
348c59bc10eSTakashi Sakamoto 	//  Onyx-i series (former models):	0x081216
349c59bc10eSTakashi Sakamoto 	//  Onyx 1640i:				0x001640
350c59bc10eSTakashi Sakamoto 	//  d.2 pro/d.4 pro (built-in card):	Unknown
351c59bc10eSTakashi Sakamoto 	//  U.420:				Unknown
352c59bc10eSTakashi Sakamoto 	//  U.420d:				Unknown
353ec4dba50STakashi Sakamoto 	{
354ec4dba50STakashi Sakamoto 		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
355ec4dba50STakashi Sakamoto 				  IEEE1394_MATCH_SPECIFIER_ID |
356ec4dba50STakashi Sakamoto 				  IEEE1394_MATCH_VERSION,
357ec4dba50STakashi Sakamoto 		.vendor_id	= VENDOR_LOUD,
358bb5d776bSTakashi Sakamoto 		.model_id	= 0,
359ec4dba50STakashi Sakamoto 		.specifier_id	= SPECIFIER_1394TA,
360ec4dba50STakashi Sakamoto 		.version	= VERSION_AVC,
361ec4dba50STakashi Sakamoto 	},
362c127d5cdSTakashi Sakamoto 	// TASCAM, FireOne.
363c127d5cdSTakashi Sakamoto 	OXFW_DEV_ENTRY(VENDOR_TASCAM, 0x800007, NULL),
364c127d5cdSTakashi Sakamoto 	// Stanton, Stanton Controllers & Systems 1 Mixer (SCS.1m).
36507a35edcSTakashi Sakamoto 	OXFW_DEV_ENTRY(OUI_STANTON, MODEL_SCS1M, NULL),
366c127d5cdSTakashi Sakamoto 	// Stanton, Stanton Controllers & Systems 1 Deck (SCS.1d).
367c127d5cdSTakashi Sakamoto 	OXFW_DEV_ENTRY(OUI_STANTON, 0x002000, NULL),
368c127d5cdSTakashi Sakamoto 	// APOGEE, duet FireWire.
36907a35edcSTakashi Sakamoto 	OXFW_DEV_ENTRY(OUI_APOGEE, MODEL_DUET_FW, NULL),
3701a4e39c2STakashi Sakamoto 	{ }
3711a4e39c2STakashi Sakamoto };
3721a4e39c2STakashi Sakamoto MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
3731a4e39c2STakashi Sakamoto 
3741a4e39c2STakashi Sakamoto static struct fw_driver oxfw_driver = {
3751a4e39c2STakashi Sakamoto 	.driver   = {
3761a4e39c2STakashi Sakamoto 		.owner	= THIS_MODULE,
3771a4e39c2STakashi Sakamoto 		.name	= KBUILD_MODNAME,
3781a4e39c2STakashi Sakamoto 		.bus	= &fw_bus_type,
3791a4e39c2STakashi Sakamoto 	},
3801a4e39c2STakashi Sakamoto 	.probe    = oxfw_probe,
3811a4e39c2STakashi Sakamoto 	.update   = oxfw_bus_reset,
3821a4e39c2STakashi Sakamoto 	.remove   = oxfw_remove,
3831a4e39c2STakashi Sakamoto 	.id_table = oxfw_id_table,
3841a4e39c2STakashi Sakamoto };
3851a4e39c2STakashi Sakamoto 
snd_oxfw_init(void)3861a4e39c2STakashi Sakamoto static int __init snd_oxfw_init(void)
3871a4e39c2STakashi Sakamoto {
3881a4e39c2STakashi Sakamoto 	return driver_register(&oxfw_driver.driver);
3891a4e39c2STakashi Sakamoto }
3901a4e39c2STakashi Sakamoto 
snd_oxfw_exit(void)3911a4e39c2STakashi Sakamoto static void __exit snd_oxfw_exit(void)
3921a4e39c2STakashi Sakamoto {
3931a4e39c2STakashi Sakamoto 	driver_unregister(&oxfw_driver.driver);
3941a4e39c2STakashi Sakamoto }
3951a4e39c2STakashi Sakamoto 
3961a4e39c2STakashi Sakamoto module_init(snd_oxfw_init);
3971a4e39c2STakashi Sakamoto module_exit(snd_oxfw_exit);
398