162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * bebob.c - a part of driver for BeBoB based devices
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * BeBoB is 'BridgeCo enhanced Breakout Box'. This is installed to firewire
1062306a36Sopenharmony_ci * devices with DM1000/DM1100/DM1500 chipset. It gives common way for host
1162306a36Sopenharmony_ci * system to handle BeBoB based devices.
1262306a36Sopenharmony_ci */
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "bebob.h"
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ciMODULE_DESCRIPTION("BridgeCo BeBoB driver");
1762306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>");
1862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic int index[SNDRV_CARDS]	= SNDRV_DEFAULT_IDX;
2162306a36Sopenharmony_cistatic char *id[SNDRV_CARDS]	= SNDRV_DEFAULT_STR;
2262306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS]	= SNDRV_DEFAULT_ENABLE_PNP;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444);
2562306a36Sopenharmony_ciMODULE_PARM_DESC(index, "card index");
2662306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444);
2762306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string");
2862306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444);
2962306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "enable BeBoB sound card");
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cistatic DEFINE_MUTEX(devices_mutex);
3262306a36Sopenharmony_cistatic DECLARE_BITMAP(devices_used, SNDRV_CARDS);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/* Offsets from information register. */
3562306a36Sopenharmony_ci#define INFO_OFFSET_BEBOB_VERSION	0x08
3662306a36Sopenharmony_ci#define INFO_OFFSET_GUID		0x10
3762306a36Sopenharmony_ci#define INFO_OFFSET_HW_MODEL_ID		0x18
3862306a36Sopenharmony_ci#define INFO_OFFSET_HW_MODEL_REVISION	0x1c
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define VEN_EDIROL	0x000040ab
4162306a36Sopenharmony_ci#define VEN_PRESONUS	0x00000a92
4262306a36Sopenharmony_ci#define VEN_BRIDGECO	0x000007f5
4362306a36Sopenharmony_ci#define VEN_MACKIE	0x00000ff2
4462306a36Sopenharmony_ci#define VEN_STANTON	0x00001260
4562306a36Sopenharmony_ci#define VEN_TASCAM	0x0000022e
4662306a36Sopenharmony_ci#define VEN_BEHRINGER	0x00001564
4762306a36Sopenharmony_ci#define VEN_APOGEE	0x000003db
4862306a36Sopenharmony_ci#define VEN_ESI		0x00000f1b
4962306a36Sopenharmony_ci#define VEN_CME		0x0000000a
5062306a36Sopenharmony_ci#define VEN_PHONIC	0x00001496
5162306a36Sopenharmony_ci#define VEN_LYNX	0x000019e5
5262306a36Sopenharmony_ci#define VEN_ICON	0x00001a9e
5362306a36Sopenharmony_ci#define VEN_PRISMSOUND	0x00001198
5462306a36Sopenharmony_ci#define VEN_TERRATEC	0x00000aac
5562306a36Sopenharmony_ci#define VEN_YAMAHA	0x0000a0de
5662306a36Sopenharmony_ci#define VEN_FOCUSRITE	0x0000130e
5762306a36Sopenharmony_ci#define VEN_MAUDIO	0x00000d6c
5862306a36Sopenharmony_ci#define VEN_DIGIDESIGN	0x00a07e
5962306a36Sopenharmony_ci#define OUI_SHOUYO	0x002327
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define MODEL_FOCUSRITE_SAFFIRE_BOTH	0x00000000
6262306a36Sopenharmony_ci#define MODEL_MAUDIO_AUDIOPHILE_BOTH	0x00010060
6362306a36Sopenharmony_ci#define MODEL_MAUDIO_FW1814		0x00010071
6462306a36Sopenharmony_ci#define MODEL_MAUDIO_PROJECTMIX		0x00010091
6562306a36Sopenharmony_ci#define MODEL_MAUDIO_PROFIRELIGHTBRIDGE	0x000100a1
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int
6862306a36Sopenharmony_ciname_device(struct snd_bebob *bebob)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	struct fw_device *fw_dev = fw_parent_device(bebob->unit);
7162306a36Sopenharmony_ci	char vendor[24] = {0};
7262306a36Sopenharmony_ci	char model[32] = {0};
7362306a36Sopenharmony_ci	u32 hw_id;
7462306a36Sopenharmony_ci	u32 data[2] = {0};
7562306a36Sopenharmony_ci	u32 revision;
7662306a36Sopenharmony_ci	int err;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	/* get vendor name from root directory */
7962306a36Sopenharmony_ci	err = fw_csr_string(fw_dev->config_rom + 5, CSR_VENDOR,
8062306a36Sopenharmony_ci			    vendor, sizeof(vendor));
8162306a36Sopenharmony_ci	if (err < 0)
8262306a36Sopenharmony_ci		goto end;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	/* get model name from unit directory */
8562306a36Sopenharmony_ci	err = fw_csr_string(bebob->unit->directory, CSR_MODEL,
8662306a36Sopenharmony_ci			    model, sizeof(model));
8762306a36Sopenharmony_ci	if (err < 0)
8862306a36Sopenharmony_ci		goto end;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* get hardware id */
9162306a36Sopenharmony_ci	err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_HW_MODEL_ID,
9262306a36Sopenharmony_ci				  &hw_id);
9362306a36Sopenharmony_ci	if (err < 0)
9462306a36Sopenharmony_ci		goto end;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	/* get hardware revision */
9762306a36Sopenharmony_ci	err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_HW_MODEL_REVISION,
9862306a36Sopenharmony_ci				  &revision);
9962306a36Sopenharmony_ci	if (err < 0)
10062306a36Sopenharmony_ci		goto end;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	/* get GUID */
10362306a36Sopenharmony_ci	err = snd_bebob_read_block(bebob->unit, INFO_OFFSET_GUID,
10462306a36Sopenharmony_ci				   data, sizeof(data));
10562306a36Sopenharmony_ci	if (err < 0)
10662306a36Sopenharmony_ci		goto end;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	strcpy(bebob->card->driver, "BeBoB");
10962306a36Sopenharmony_ci	strcpy(bebob->card->shortname, model);
11062306a36Sopenharmony_ci	strcpy(bebob->card->mixername, model);
11162306a36Sopenharmony_ci	snprintf(bebob->card->longname, sizeof(bebob->card->longname),
11262306a36Sopenharmony_ci		 "%s %s (id:%d, rev:%d), GUID %08x%08x at %s, S%d",
11362306a36Sopenharmony_ci		 vendor, model, hw_id, revision,
11462306a36Sopenharmony_ci		 data[0], data[1], dev_name(&bebob->unit->device),
11562306a36Sopenharmony_ci		 100 << fw_dev->max_speed);
11662306a36Sopenharmony_ciend:
11762306a36Sopenharmony_ci	return err;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void
12162306a36Sopenharmony_cibebob_card_free(struct snd_card *card)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct snd_bebob *bebob = card->private_data;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
12662306a36Sopenharmony_ci	clear_bit(bebob->card_index, devices_used);
12762306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	snd_bebob_stream_destroy_duplex(bebob);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	mutex_destroy(&bebob->mutex);
13262306a36Sopenharmony_ci	fw_unit_put(bebob->unit);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic const struct snd_bebob_spec *
13662306a36Sopenharmony_ciget_saffire_spec(struct fw_unit *unit)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	char name[24] = {0};
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0)
14162306a36Sopenharmony_ci		return NULL;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (strcmp(name, "SaffireLE") == 0)
14462306a36Sopenharmony_ci		return &saffire_le_spec;
14562306a36Sopenharmony_ci	else
14662306a36Sopenharmony_ci		return &saffire_spec;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic bool
15062306a36Sopenharmony_cicheck_audiophile_booted(struct fw_unit *unit)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	char name[28] = {0};
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0)
15562306a36Sopenharmony_ci		return false;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return strncmp(name, "FW Audiophile Bootloader", 24) != 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic int detect_quirks(struct snd_bebob *bebob, const struct ieee1394_device_id *entry)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	if (entry->vendor_id == VEN_MAUDIO) {
16362306a36Sopenharmony_ci		switch (entry->model_id) {
16462306a36Sopenharmony_ci		case MODEL_MAUDIO_PROFIRELIGHTBRIDGE:
16562306a36Sopenharmony_ci			// M-Audio ProFire Lightbridge has a quirk to transfer packets with
16662306a36Sopenharmony_ci			// discontinuous cycle or data block counter in early stage of packet
16762306a36Sopenharmony_ci			// streaming. The cycle span from the first packet with event is variable.
16862306a36Sopenharmony_ci			bebob->quirks |= SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC;
16962306a36Sopenharmony_ci			break;
17062306a36Sopenharmony_ci		case MODEL_MAUDIO_FW1814:
17162306a36Sopenharmony_ci		case MODEL_MAUDIO_PROJECTMIX:
17262306a36Sopenharmony_ci			// At high sampling rate, M-Audio special firmware transmits empty packet
17362306a36Sopenharmony_ci			// with the value of dbc incremented by 8.
17462306a36Sopenharmony_ci			bebob->quirks |= SND_BEBOB_QUIRK_WRONG_DBC;
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci		default:
17762306a36Sopenharmony_ci			break;
17862306a36Sopenharmony_ci		}
17962306a36Sopenharmony_ci	}
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return 0;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	unsigned int card_index;
18762306a36Sopenharmony_ci	struct snd_card *card;
18862306a36Sopenharmony_ci	struct snd_bebob *bebob;
18962306a36Sopenharmony_ci	const struct snd_bebob_spec *spec;
19062306a36Sopenharmony_ci	int err;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (entry->vendor_id == VEN_FOCUSRITE &&
19362306a36Sopenharmony_ci	    entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)
19462306a36Sopenharmony_ci		spec = get_saffire_spec(unit);
19562306a36Sopenharmony_ci	else if (entry->vendor_id == VEN_MAUDIO &&
19662306a36Sopenharmony_ci		 entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH &&
19762306a36Sopenharmony_ci		 !check_audiophile_booted(unit))
19862306a36Sopenharmony_ci		spec = NULL;
19962306a36Sopenharmony_ci	else
20062306a36Sopenharmony_ci		spec = (const struct snd_bebob_spec *)entry->driver_data;
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (spec == NULL) {
20362306a36Sopenharmony_ci		// To boot up M-Audio models.
20462306a36Sopenharmony_ci		if (entry->vendor_id == VEN_MAUDIO || entry->vendor_id == VEN_BRIDGECO)
20562306a36Sopenharmony_ci			return snd_bebob_maudio_load_firmware(unit);
20662306a36Sopenharmony_ci		else
20762306a36Sopenharmony_ci			return -ENODEV;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	mutex_lock(&devices_mutex);
21162306a36Sopenharmony_ci	for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
21262306a36Sopenharmony_ci		if (!test_bit(card_index, devices_used) && enable[card_index])
21362306a36Sopenharmony_ci			break;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci	if (card_index >= SNDRV_CARDS) {
21662306a36Sopenharmony_ci		mutex_unlock(&devices_mutex);
21762306a36Sopenharmony_ci		return -ENOENT;
21862306a36Sopenharmony_ci	}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
22162306a36Sopenharmony_ci			   sizeof(*bebob), &card);
22262306a36Sopenharmony_ci	if (err < 0) {
22362306a36Sopenharmony_ci		mutex_unlock(&devices_mutex);
22462306a36Sopenharmony_ci		return err;
22562306a36Sopenharmony_ci	}
22662306a36Sopenharmony_ci	card->private_free = bebob_card_free;
22762306a36Sopenharmony_ci	set_bit(card_index, devices_used);
22862306a36Sopenharmony_ci	mutex_unlock(&devices_mutex);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	bebob = card->private_data;
23162306a36Sopenharmony_ci	bebob->unit = fw_unit_get(unit);
23262306a36Sopenharmony_ci	dev_set_drvdata(&unit->device, bebob);
23362306a36Sopenharmony_ci	bebob->card = card;
23462306a36Sopenharmony_ci	bebob->card_index = card_index;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	bebob->spec = spec;
23762306a36Sopenharmony_ci	mutex_init(&bebob->mutex);
23862306a36Sopenharmony_ci	spin_lock_init(&bebob->lock);
23962306a36Sopenharmony_ci	init_waitqueue_head(&bebob->hwdep_wait);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	err = name_device(bebob);
24262306a36Sopenharmony_ci	if (err < 0)
24362306a36Sopenharmony_ci		goto error;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	err = detect_quirks(bebob, entry);
24662306a36Sopenharmony_ci	if (err < 0)
24762306a36Sopenharmony_ci		goto error;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	if (bebob->spec == &maudio_special_spec) {
25062306a36Sopenharmony_ci		if (entry->model_id == MODEL_MAUDIO_FW1814)
25162306a36Sopenharmony_ci			err = snd_bebob_maudio_special_discover(bebob, true);
25262306a36Sopenharmony_ci		else
25362306a36Sopenharmony_ci			err = snd_bebob_maudio_special_discover(bebob, false);
25462306a36Sopenharmony_ci	} else {
25562306a36Sopenharmony_ci		err = snd_bebob_stream_discover(bebob);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci	if (err < 0)
25862306a36Sopenharmony_ci		goto error;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	err = snd_bebob_stream_init_duplex(bebob);
26162306a36Sopenharmony_ci	if (err < 0)
26262306a36Sopenharmony_ci		goto error;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	snd_bebob_proc_init(bebob);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	if (bebob->midi_input_ports > 0 || bebob->midi_output_ports > 0) {
26762306a36Sopenharmony_ci		err = snd_bebob_create_midi_devices(bebob);
26862306a36Sopenharmony_ci		if (err < 0)
26962306a36Sopenharmony_ci			goto error;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	err = snd_bebob_create_pcm_devices(bebob);
27362306a36Sopenharmony_ci	if (err < 0)
27462306a36Sopenharmony_ci		goto error;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	err = snd_bebob_create_hwdep_device(bebob);
27762306a36Sopenharmony_ci	if (err < 0)
27862306a36Sopenharmony_ci		goto error;
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	err = snd_card_register(card);
28162306a36Sopenharmony_ci	if (err < 0)
28262306a36Sopenharmony_ci		goto error;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (entry->vendor_id == VEN_MAUDIO &&
28562306a36Sopenharmony_ci	    (entry->model_id == MODEL_MAUDIO_FW1814 || entry->model_id == MODEL_MAUDIO_PROJECTMIX)) {
28662306a36Sopenharmony_ci		// This is a workaround. This bus reset seems to have an effect to make devices
28762306a36Sopenharmony_ci		// correctly handling transactions. Without this, the devices have gap_count
28862306a36Sopenharmony_ci		// mismatch. This causes much failure of transaction.
28962306a36Sopenharmony_ci		//
29062306a36Sopenharmony_ci		// Just after registration, user-land application receive signals from dbus and
29162306a36Sopenharmony_ci		// starts I/Os. To avoid I/Os till the future bus reset, registration is done in
29262306a36Sopenharmony_ci		// next update().
29362306a36Sopenharmony_ci		fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, false, true);
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	return 0;
29762306a36Sopenharmony_cierror:
29862306a36Sopenharmony_ci	snd_card_free(card);
29962306a36Sopenharmony_ci	return err;
30062306a36Sopenharmony_ci}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci/*
30362306a36Sopenharmony_ci * This driver doesn't update streams in bus reset handler.
30462306a36Sopenharmony_ci *
30562306a36Sopenharmony_ci * DM1000/ DM1100/DM1500 chipsets with BeBoB firmware transfer packets with
30662306a36Sopenharmony_ci * discontinued counter at bus reset. This discontinuity is immediately
30762306a36Sopenharmony_ci * detected in packet streaming layer, then it sets XRUN to PCM substream.
30862306a36Sopenharmony_ci *
30962306a36Sopenharmony_ci * ALSA PCM applications can know the XRUN by getting -EPIPE from PCM operation.
31062306a36Sopenharmony_ci * Then, they can recover the PCM substream by executing ioctl(2) with
31162306a36Sopenharmony_ci * SNDRV_PCM_IOCTL_PREPARE. 'struct snd_pcm_ops.prepare' is called and drivers
31262306a36Sopenharmony_ci * restart packet streaming.
31362306a36Sopenharmony_ci *
31462306a36Sopenharmony_ci * The above processing may be executed before this bus-reset handler is
31562306a36Sopenharmony_ci * executed. When this handler updates streams with current isochronous
31662306a36Sopenharmony_ci * channels, the streams already have the current ones.
31762306a36Sopenharmony_ci */
31862306a36Sopenharmony_cistatic void
31962306a36Sopenharmony_cibebob_update(struct fw_unit *unit)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct snd_bebob *bebob = dev_get_drvdata(&unit->device);
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (bebob == NULL)
32462306a36Sopenharmony_ci		return;
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	fcp_bus_reset(bebob->unit);
32762306a36Sopenharmony_ci}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_cistatic void bebob_remove(struct fw_unit *unit)
33062306a36Sopenharmony_ci{
33162306a36Sopenharmony_ci	struct snd_bebob *bebob = dev_get_drvdata(&unit->device);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	if (bebob == NULL)
33462306a36Sopenharmony_ci		return;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	// Block till all of ALSA character devices are released.
33762306a36Sopenharmony_ci	snd_card_free(bebob->card);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_cistatic const struct snd_bebob_rate_spec normal_rate_spec = {
34162306a36Sopenharmony_ci	.get	= &snd_bebob_stream_get_rate,
34262306a36Sopenharmony_ci	.set	= &snd_bebob_stream_set_rate
34362306a36Sopenharmony_ci};
34462306a36Sopenharmony_cistatic const struct snd_bebob_spec spec_normal = {
34562306a36Sopenharmony_ci	.clock	= NULL,
34662306a36Sopenharmony_ci	.rate	= &normal_rate_spec,
34762306a36Sopenharmony_ci	.meter	= NULL
34862306a36Sopenharmony_ci};
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci#define SPECIFIER_1394TA	0x00a02d
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci// The immediate entry for version in unit directory differs depending on models:
35362306a36Sopenharmony_ci//  * 0x010001
35462306a36Sopenharmony_ci//  * 0x014001
35562306a36Sopenharmony_ci#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
35662306a36Sopenharmony_ci{ \
35762306a36Sopenharmony_ci	.match_flags	= IEEE1394_MATCH_VENDOR_ID | \
35862306a36Sopenharmony_ci			  IEEE1394_MATCH_MODEL_ID | \
35962306a36Sopenharmony_ci			  IEEE1394_MATCH_SPECIFIER_ID, \
36062306a36Sopenharmony_ci	.vendor_id	= vendor, \
36162306a36Sopenharmony_ci	.model_id	= model, \
36262306a36Sopenharmony_ci	.specifier_id	= SPECIFIER_1394TA, \
36362306a36Sopenharmony_ci	.driver_data	= (kernel_ulong_t)data \
36462306a36Sopenharmony_ci}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_cistatic const struct ieee1394_device_id bebob_id_table[] = {
36762306a36Sopenharmony_ci	/* Edirol, FA-66 */
36862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010049, &spec_normal),
36962306a36Sopenharmony_ci	/* Edirol, FA-101 */
37062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010048, &spec_normal),
37162306a36Sopenharmony_ci	/* Presonus, FIREBOX */
37262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010000, &spec_normal),
37362306a36Sopenharmony_ci	/* PreSonus, FIREPOD/FP10 */
37462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010066, &spec_normal),
37562306a36Sopenharmony_ci	/* PreSonus, Inspire1394 */
37662306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010001, &spec_normal),
37762306a36Sopenharmony_ci	/* BridgeCo, RDAudio1 */
37862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010048, &spec_normal),
37962306a36Sopenharmony_ci	/* BridgeCo, Audio5 */
38062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
38162306a36Sopenharmony_ci	/* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
38262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
38362306a36Sopenharmony_ci	// Mackie, d.2 (optional Firewire card with DM1000).
38462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
38562306a36Sopenharmony_ci	/* Stanton, ScratchAmp */
38662306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
38762306a36Sopenharmony_ci	/* Tascam, IF-FW DM */
38862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TASCAM, 0x00010067, &spec_normal),
38962306a36Sopenharmony_ci	/* Behringer, XENIX UFX 1204 */
39062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00001204, &spec_normal),
39162306a36Sopenharmony_ci	/* Behringer, XENIX UFX 1604 */
39262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00001604, &spec_normal),
39362306a36Sopenharmony_ci	/* Behringer, Digital Mixer X32 series (X-UF Card) */
39462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00000006, &spec_normal),
39562306a36Sopenharmony_ci	/*  Behringer, F-Control Audio 1616 */
39662306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x001616, &spec_normal),
39762306a36Sopenharmony_ci	/*  Behringer, F-Control Audio 610 */
39862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x000610, &spec_normal),
39962306a36Sopenharmony_ci	/* Apogee Electronics, Rosetta 200/400 (X-FireWire card) */
40062306a36Sopenharmony_ci	/* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */
40162306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal),
40262306a36Sopenharmony_ci	/* Apogee Electronics, Ensemble */
40362306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
40462306a36Sopenharmony_ci	/* ESI, Quatafire610 */
40562306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
40662306a36Sopenharmony_ci	/* CME, MatrixKFW */
40762306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal),
40862306a36Sopenharmony_ci	// Phonic Helix Board 12 FireWire MkII.
40962306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00050000, &spec_normal),
41062306a36Sopenharmony_ci	// Phonic Helix Board 18 FireWire MkII.
41162306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00060000, &spec_normal),
41262306a36Sopenharmony_ci	// Phonic Helix Board 24 FireWire MkII.
41362306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00070000, &spec_normal),
41462306a36Sopenharmony_ci	// Phonic FireFly 808 FireWire.
41562306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00080000, &spec_normal),
41662306a36Sopenharmony_ci	// Phonic FireFly 202, 302, 808 Universal.
41762306a36Sopenharmony_ci	// Phinic Helix Board 12/18/24 FireWire, 12/18/24 Universal
41862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00000000, &spec_normal),
41962306a36Sopenharmony_ci	/* Lynx, Aurora 8/16 (LT-FW) */
42062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_LYNX, 0x00000001, &spec_normal),
42162306a36Sopenharmony_ci	/* ICON, FireXon */
42262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_ICON, 0x00000001, &spec_normal),
42362306a36Sopenharmony_ci	/* PrismSound, Orpheus */
42462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PRISMSOUND, 0x00010048, &spec_normal),
42562306a36Sopenharmony_ci	/* PrismSound, ADA-8XR */
42662306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_PRISMSOUND, 0x0000ada8, &spec_normal),
42762306a36Sopenharmony_ci	/* TerraTec Electronic GmbH, PHASE 88 Rack FW */
42862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000003, &phase88_rack_spec),
42962306a36Sopenharmony_ci	/* TerraTec Electronic GmbH, PHASE 24 FW */
43062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000004, &yamaha_terratec_spec),
43162306a36Sopenharmony_ci	/* TerraTec Electronic GmbH, Phase X24 FW */
43262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000007, &yamaha_terratec_spec),
43362306a36Sopenharmony_ci	/* TerraTec Electronic GmbH, EWS MIC2/MIC8 */
43462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000005, &spec_normal),
43562306a36Sopenharmony_ci	// Terratec Electronic GmbH, Aureon 7.1 Firewire.
43662306a36Sopenharmony_ci	// AcousticReality, eAR Master One, Eroica, Figaro, and Ciaccona. Perhaps Terratec OEM.
43762306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal),
43862306a36Sopenharmony_ci	/* Yamaha, GO44 */
43962306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_terratec_spec),
44062306a36Sopenharmony_ci	/* YAMAHA, GO46 */
44162306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_terratec_spec),
44262306a36Sopenharmony_ci	/* Focusrite, SaffirePro 26 I/O */
44362306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec),
44462306a36Sopenharmony_ci	/* Focusrite, SaffirePro 10 I/O */
44562306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x000006, &saffirepro_10_spec),
44662306a36Sopenharmony_ci	/* Focusrite, Saffire(no label and LE) */
44762306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH,
44862306a36Sopenharmony_ci			    &saffire_spec),
44962306a36Sopenharmony_ci	// M-Audio, Firewire 410. The vendor field is left as BridgeCo. AG.
45062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010058, NULL),
45162306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010046, &maudio_fw410_spec),
45262306a36Sopenharmony_ci	/* M-Audio, Firewire Audiophile */
45362306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_AUDIOPHILE_BOTH,
45462306a36Sopenharmony_ci			    &maudio_audiophile_spec),
45562306a36Sopenharmony_ci	/* M-Audio, Firewire Solo */
45662306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010062, &maudio_solo_spec),
45762306a36Sopenharmony_ci	/* M-Audio, Ozonic */
45862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x0000000a, &maudio_ozonic_spec),
45962306a36Sopenharmony_ci	/* M-Audio NRV10 */
46062306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010081, &maudio_nrv10_spec),
46162306a36Sopenharmony_ci	/* M-Audio, ProFireLightbridge */
46262306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROFIRELIGHTBRIDGE, &spec_normal),
46362306a36Sopenharmony_ci	/* Firewire 1814 */
46462306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010070, NULL),	/* bootloader */
46562306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_FW1814,
46662306a36Sopenharmony_ci			    &maudio_special_spec),
46762306a36Sopenharmony_ci	/* M-Audio ProjectMix */
46862306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROJECTMIX,
46962306a36Sopenharmony_ci			    &maudio_special_spec),
47062306a36Sopenharmony_ci	/* Digidesign Mbox 2 Pro */
47162306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal),
47262306a36Sopenharmony_ci	// Toneweal FW66.
47362306a36Sopenharmony_ci	SND_BEBOB_DEV_ENTRY(OUI_SHOUYO, 0x020002, &spec_normal),
47462306a36Sopenharmony_ci	/* IDs are unknown but able to be supported */
47562306a36Sopenharmony_ci	/*  Apogee, Mini-ME Firewire */
47662306a36Sopenharmony_ci	/*  Apogee, Mini-DAC Firewire */
47762306a36Sopenharmony_ci	/*  Cakawalk, Sonar Power Studio 66 */
47862306a36Sopenharmony_ci	/*  CME, UF400e */
47962306a36Sopenharmony_ci	/*  ESI, Quotafire XL */
48062306a36Sopenharmony_ci	/*  Infrasonic, DewX */
48162306a36Sopenharmony_ci	/*  Infrasonic, Windy6 */
48262306a36Sopenharmony_ci	/*  Mackie, Digital X Bus x.200 */
48362306a36Sopenharmony_ci	/*  Mackie, Digital X Bus x.400 */
48462306a36Sopenharmony_ci	/*  Rolf Spuler, Firewire Guitar */
48562306a36Sopenharmony_ci	{}
48662306a36Sopenharmony_ci};
48762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(ieee1394, bebob_id_table);
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_cistatic struct fw_driver bebob_driver = {
49062306a36Sopenharmony_ci	.driver = {
49162306a36Sopenharmony_ci		.owner	= THIS_MODULE,
49262306a36Sopenharmony_ci		.name	= KBUILD_MODNAME,
49362306a36Sopenharmony_ci		.bus	= &fw_bus_type,
49462306a36Sopenharmony_ci	},
49562306a36Sopenharmony_ci	.probe    = bebob_probe,
49662306a36Sopenharmony_ci	.update	  = bebob_update,
49762306a36Sopenharmony_ci	.remove   = bebob_remove,
49862306a36Sopenharmony_ci	.id_table = bebob_id_table,
49962306a36Sopenharmony_ci};
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_cistatic int __init
50262306a36Sopenharmony_cisnd_bebob_init(void)
50362306a36Sopenharmony_ci{
50462306a36Sopenharmony_ci	return driver_register(&bebob_driver.driver);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_cistatic void __exit
50862306a36Sopenharmony_cisnd_bebob_exit(void)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	driver_unregister(&bebob_driver.driver);
51162306a36Sopenharmony_ci}
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_cimodule_init(snd_bebob_init);
51462306a36Sopenharmony_cimodule_exit(snd_bebob_exit);
515