18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bebob.c - a part of driver for BeBoB based devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2013-2014 Takashi Sakamoto 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * BeBoB is 'BridgeCo enhanced Breakout Box'. This is installed to firewire 108c2ecf20Sopenharmony_ci * devices with DM1000/DM1100/DM1500 chipset. It gives common way for host 118c2ecf20Sopenharmony_ci * system to handle BeBoB based devices. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "bebob.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("BridgeCo BeBoB driver"); 178c2ecf20Sopenharmony_ciMODULE_AUTHOR("Takashi Sakamoto <o-takashi@sakamocchi.jp>"); 188c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 218c2ecf20Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; 228c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "card index"); 268c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 278c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string"); 288c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 298c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "enable BeBoB sound card"); 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(devices_mutex); 328c2ecf20Sopenharmony_cistatic DECLARE_BITMAP(devices_used, SNDRV_CARDS); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/* Offsets from information register. */ 358c2ecf20Sopenharmony_ci#define INFO_OFFSET_BEBOB_VERSION 0x08 368c2ecf20Sopenharmony_ci#define INFO_OFFSET_GUID 0x10 378c2ecf20Sopenharmony_ci#define INFO_OFFSET_HW_MODEL_ID 0x18 388c2ecf20Sopenharmony_ci#define INFO_OFFSET_HW_MODEL_REVISION 0x1c 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define VEN_EDIROL 0x000040ab 418c2ecf20Sopenharmony_ci#define VEN_PRESONUS 0x00000a92 428c2ecf20Sopenharmony_ci#define VEN_BRIDGECO 0x000007f5 438c2ecf20Sopenharmony_ci#define VEN_MACKIE1 0x0000000f 448c2ecf20Sopenharmony_ci#define VEN_MACKIE2 0x00000ff2 458c2ecf20Sopenharmony_ci#define VEN_STANTON 0x00001260 468c2ecf20Sopenharmony_ci#define VEN_TASCAM 0x0000022e 478c2ecf20Sopenharmony_ci#define VEN_BEHRINGER 0x00001564 488c2ecf20Sopenharmony_ci#define VEN_APOGEE 0x000003db 498c2ecf20Sopenharmony_ci#define VEN_ESI 0x00000f1b 508c2ecf20Sopenharmony_ci#define VEN_ACOUSTIC 0x00000002 518c2ecf20Sopenharmony_ci#define VEN_CME 0x0000000a 528c2ecf20Sopenharmony_ci#define VEN_PHONIC 0x00001496 538c2ecf20Sopenharmony_ci#define VEN_LYNX 0x000019e5 548c2ecf20Sopenharmony_ci#define VEN_ICON 0x00001a9e 558c2ecf20Sopenharmony_ci#define VEN_PRISMSOUND 0x00001198 568c2ecf20Sopenharmony_ci#define VEN_TERRATEC 0x00000aac 578c2ecf20Sopenharmony_ci#define VEN_YAMAHA 0x0000a0de 588c2ecf20Sopenharmony_ci#define VEN_FOCUSRITE 0x0000130e 598c2ecf20Sopenharmony_ci#define VEN_MAUDIO1 0x00000d6c 608c2ecf20Sopenharmony_ci#define VEN_MAUDIO2 0x000007f5 618c2ecf20Sopenharmony_ci#define VEN_DIGIDESIGN 0x00a07e 628c2ecf20Sopenharmony_ci#define OUI_SHOUYO 0x002327 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000 658c2ecf20Sopenharmony_ci#define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060 668c2ecf20Sopenharmony_ci#define MODEL_MAUDIO_FW1814 0x00010071 678c2ecf20Sopenharmony_ci#define MODEL_MAUDIO_PROJECTMIX 0x00010091 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic int 708c2ecf20Sopenharmony_ciname_device(struct snd_bebob *bebob) 718c2ecf20Sopenharmony_ci{ 728c2ecf20Sopenharmony_ci struct fw_device *fw_dev = fw_parent_device(bebob->unit); 738c2ecf20Sopenharmony_ci char vendor[24] = {0}; 748c2ecf20Sopenharmony_ci char model[32] = {0}; 758c2ecf20Sopenharmony_ci u32 hw_id; 768c2ecf20Sopenharmony_ci u32 data[2] = {0}; 778c2ecf20Sopenharmony_ci u32 revision; 788c2ecf20Sopenharmony_ci u32 version; 798c2ecf20Sopenharmony_ci int err; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* get vendor name from root directory */ 828c2ecf20Sopenharmony_ci err = fw_csr_string(fw_dev->config_rom + 5, CSR_VENDOR, 838c2ecf20Sopenharmony_ci vendor, sizeof(vendor)); 848c2ecf20Sopenharmony_ci if (err < 0) 858c2ecf20Sopenharmony_ci goto end; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci /* get model name from unit directory */ 888c2ecf20Sopenharmony_ci err = fw_csr_string(bebob->unit->directory, CSR_MODEL, 898c2ecf20Sopenharmony_ci model, sizeof(model)); 908c2ecf20Sopenharmony_ci if (err < 0) 918c2ecf20Sopenharmony_ci goto end; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* get hardware id */ 948c2ecf20Sopenharmony_ci err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_HW_MODEL_ID, 958c2ecf20Sopenharmony_ci &hw_id); 968c2ecf20Sopenharmony_ci if (err < 0) 978c2ecf20Sopenharmony_ci goto end; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* get hardware revision */ 1008c2ecf20Sopenharmony_ci err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_HW_MODEL_REVISION, 1018c2ecf20Sopenharmony_ci &revision); 1028c2ecf20Sopenharmony_ci if (err < 0) 1038c2ecf20Sopenharmony_ci goto end; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci /* get GUID */ 1068c2ecf20Sopenharmony_ci err = snd_bebob_read_block(bebob->unit, INFO_OFFSET_GUID, 1078c2ecf20Sopenharmony_ci data, sizeof(data)); 1088c2ecf20Sopenharmony_ci if (err < 0) 1098c2ecf20Sopenharmony_ci goto end; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_BEBOB_VERSION, 1128c2ecf20Sopenharmony_ci &version); 1138c2ecf20Sopenharmony_ci if (err < 0) 1148c2ecf20Sopenharmony_ci goto end; 1158c2ecf20Sopenharmony_ci bebob->version = version; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci strcpy(bebob->card->driver, "BeBoB"); 1188c2ecf20Sopenharmony_ci strcpy(bebob->card->shortname, model); 1198c2ecf20Sopenharmony_ci strcpy(bebob->card->mixername, model); 1208c2ecf20Sopenharmony_ci snprintf(bebob->card->longname, sizeof(bebob->card->longname), 1218c2ecf20Sopenharmony_ci "%s %s (id:%d, rev:%d), GUID %08x%08x at %s, S%d", 1228c2ecf20Sopenharmony_ci vendor, model, hw_id, revision, 1238c2ecf20Sopenharmony_ci data[0], data[1], dev_name(&bebob->unit->device), 1248c2ecf20Sopenharmony_ci 100 << fw_dev->max_speed); 1258c2ecf20Sopenharmony_ciend: 1268c2ecf20Sopenharmony_ci return err; 1278c2ecf20Sopenharmony_ci} 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cistatic void 1308c2ecf20Sopenharmony_cibebob_card_free(struct snd_card *card) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct snd_bebob *bebob = card->private_data; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci mutex_lock(&devices_mutex); 1358c2ecf20Sopenharmony_ci clear_bit(bebob->card_index, devices_used); 1368c2ecf20Sopenharmony_ci mutex_unlock(&devices_mutex); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci snd_bebob_stream_destroy_duplex(bebob); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic const struct snd_bebob_spec * 1428c2ecf20Sopenharmony_ciget_saffire_spec(struct fw_unit *unit) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci char name[24] = {0}; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0) 1478c2ecf20Sopenharmony_ci return NULL; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (strcmp(name, "SaffireLE") == 0) 1508c2ecf20Sopenharmony_ci return &saffire_le_spec; 1518c2ecf20Sopenharmony_ci else 1528c2ecf20Sopenharmony_ci return &saffire_spec; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic bool 1568c2ecf20Sopenharmony_cicheck_audiophile_booted(struct fw_unit *unit) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci char name[28] = {0}; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (fw_csr_string(unit->directory, CSR_MODEL, name, sizeof(name)) < 0) 1618c2ecf20Sopenharmony_ci return false; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return strncmp(name, "FW Audiophile Bootloader", 24) != 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void 1678c2ecf20Sopenharmony_cido_registration(struct work_struct *work) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct snd_bebob *bebob = 1708c2ecf20Sopenharmony_ci container_of(work, struct snd_bebob, dwork.work); 1718c2ecf20Sopenharmony_ci unsigned int card_index; 1728c2ecf20Sopenharmony_ci int err; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (bebob->registered) 1758c2ecf20Sopenharmony_ci return; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci mutex_lock(&devices_mutex); 1788c2ecf20Sopenharmony_ci for (card_index = 0; card_index < SNDRV_CARDS; card_index++) { 1798c2ecf20Sopenharmony_ci if (!test_bit(card_index, devices_used) && enable[card_index]) 1808c2ecf20Sopenharmony_ci break; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci if (card_index >= SNDRV_CARDS) { 1838c2ecf20Sopenharmony_ci mutex_unlock(&devices_mutex); 1848c2ecf20Sopenharmony_ci return; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci err = snd_card_new(&bebob->unit->device, index[card_index], 1888c2ecf20Sopenharmony_ci id[card_index], THIS_MODULE, 0, &bebob->card); 1898c2ecf20Sopenharmony_ci if (err < 0) { 1908c2ecf20Sopenharmony_ci mutex_unlock(&devices_mutex); 1918c2ecf20Sopenharmony_ci return; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci set_bit(card_index, devices_used); 1948c2ecf20Sopenharmony_ci mutex_unlock(&devices_mutex); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci bebob->card->private_free = bebob_card_free; 1978c2ecf20Sopenharmony_ci bebob->card->private_data = bebob; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci err = name_device(bebob); 2008c2ecf20Sopenharmony_ci if (err < 0) 2018c2ecf20Sopenharmony_ci goto error; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci if (bebob->spec == &maudio_special_spec) { 2048c2ecf20Sopenharmony_ci if (bebob->entry->model_id == MODEL_MAUDIO_FW1814) 2058c2ecf20Sopenharmony_ci err = snd_bebob_maudio_special_discover(bebob, true); 2068c2ecf20Sopenharmony_ci else 2078c2ecf20Sopenharmony_ci err = snd_bebob_maudio_special_discover(bebob, false); 2088c2ecf20Sopenharmony_ci } else { 2098c2ecf20Sopenharmony_ci err = snd_bebob_stream_discover(bebob); 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci if (err < 0) 2128c2ecf20Sopenharmony_ci goto error; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci err = snd_bebob_stream_init_duplex(bebob); 2158c2ecf20Sopenharmony_ci if (err < 0) 2168c2ecf20Sopenharmony_ci goto error; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci snd_bebob_proc_init(bebob); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (bebob->midi_input_ports > 0 || bebob->midi_output_ports > 0) { 2218c2ecf20Sopenharmony_ci err = snd_bebob_create_midi_devices(bebob); 2228c2ecf20Sopenharmony_ci if (err < 0) 2238c2ecf20Sopenharmony_ci goto error; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci err = snd_bebob_create_pcm_devices(bebob); 2278c2ecf20Sopenharmony_ci if (err < 0) 2288c2ecf20Sopenharmony_ci goto error; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci err = snd_bebob_create_hwdep_device(bebob); 2318c2ecf20Sopenharmony_ci if (err < 0) 2328c2ecf20Sopenharmony_ci goto error; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci err = snd_card_register(bebob->card); 2358c2ecf20Sopenharmony_ci if (err < 0) 2368c2ecf20Sopenharmony_ci goto error; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci bebob->registered = true; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return; 2418c2ecf20Sopenharmony_cierror: 2428c2ecf20Sopenharmony_ci snd_card_free(bebob->card); 2438c2ecf20Sopenharmony_ci dev_info(&bebob->unit->device, 2448c2ecf20Sopenharmony_ci "Sound card registration failed: %d\n", err); 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_cistatic int 2488c2ecf20Sopenharmony_cibebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry) 2498c2ecf20Sopenharmony_ci{ 2508c2ecf20Sopenharmony_ci struct snd_bebob *bebob; 2518c2ecf20Sopenharmony_ci const struct snd_bebob_spec *spec; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci if (entry->vendor_id == VEN_FOCUSRITE && 2548c2ecf20Sopenharmony_ci entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH) 2558c2ecf20Sopenharmony_ci spec = get_saffire_spec(unit); 2568c2ecf20Sopenharmony_ci else if (entry->vendor_id == VEN_MAUDIO1 && 2578c2ecf20Sopenharmony_ci entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH && 2588c2ecf20Sopenharmony_ci !check_audiophile_booted(unit)) 2598c2ecf20Sopenharmony_ci spec = NULL; 2608c2ecf20Sopenharmony_ci else 2618c2ecf20Sopenharmony_ci spec = (const struct snd_bebob_spec *)entry->driver_data; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci if (spec == NULL) { 2648c2ecf20Sopenharmony_ci if (entry->vendor_id == VEN_MAUDIO1 || 2658c2ecf20Sopenharmony_ci entry->vendor_id == VEN_MAUDIO2) 2668c2ecf20Sopenharmony_ci return snd_bebob_maudio_load_firmware(unit); 2678c2ecf20Sopenharmony_ci else 2688c2ecf20Sopenharmony_ci return -ENODEV; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci /* Allocate this independent of sound card instance. */ 2728c2ecf20Sopenharmony_ci bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob), 2738c2ecf20Sopenharmony_ci GFP_KERNEL); 2748c2ecf20Sopenharmony_ci if (!bebob) 2758c2ecf20Sopenharmony_ci return -ENOMEM; 2768c2ecf20Sopenharmony_ci bebob->unit = fw_unit_get(unit); 2778c2ecf20Sopenharmony_ci dev_set_drvdata(&unit->device, bebob); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci bebob->entry = entry; 2808c2ecf20Sopenharmony_ci bebob->spec = spec; 2818c2ecf20Sopenharmony_ci mutex_init(&bebob->mutex); 2828c2ecf20Sopenharmony_ci spin_lock_init(&bebob->lock); 2838c2ecf20Sopenharmony_ci init_waitqueue_head(&bebob->hwdep_wait); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* Allocate and register this sound card later. */ 2868c2ecf20Sopenharmony_ci INIT_DEFERRABLE_WORK(&bebob->dwork, do_registration); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci if (entry->vendor_id != VEN_MAUDIO1 || 2898c2ecf20Sopenharmony_ci (entry->model_id != MODEL_MAUDIO_FW1814 && 2908c2ecf20Sopenharmony_ci entry->model_id != MODEL_MAUDIO_PROJECTMIX)) { 2918c2ecf20Sopenharmony_ci snd_fw_schedule_registration(unit, &bebob->dwork); 2928c2ecf20Sopenharmony_ci } else { 2938c2ecf20Sopenharmony_ci /* 2948c2ecf20Sopenharmony_ci * This is a workaround. This bus reset seems to have an effect 2958c2ecf20Sopenharmony_ci * to make devices correctly handling transactions. Without 2968c2ecf20Sopenharmony_ci * this, the devices have gap_count mismatch. This causes much 2978c2ecf20Sopenharmony_ci * failure of transaction. 2988c2ecf20Sopenharmony_ci * 2998c2ecf20Sopenharmony_ci * Just after registration, user-land application receive 3008c2ecf20Sopenharmony_ci * signals from dbus and starts I/Os. To avoid I/Os till the 3018c2ecf20Sopenharmony_ci * future bus reset, registration is done in next update(). 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, 3048c2ecf20Sopenharmony_ci false, true); 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci return 0; 3088c2ecf20Sopenharmony_ci} 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci/* 3118c2ecf20Sopenharmony_ci * This driver doesn't update streams in bus reset handler. 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * DM1000/ DM1100/DM1500 chipsets with BeBoB firmware transfer packets with 3148c2ecf20Sopenharmony_ci * discontinued counter at bus reset. This discontinuity is immediately 3158c2ecf20Sopenharmony_ci * detected in packet streaming layer, then it sets XRUN to PCM substream. 3168c2ecf20Sopenharmony_ci * 3178c2ecf20Sopenharmony_ci * ALSA PCM applications can know the XRUN by getting -EPIPE from PCM operation. 3188c2ecf20Sopenharmony_ci * Then, they can recover the PCM substream by executing ioctl(2) with 3198c2ecf20Sopenharmony_ci * SNDRV_PCM_IOCTL_PREPARE. 'struct snd_pcm_ops.prepare' is called and drivers 3208c2ecf20Sopenharmony_ci * restart packet streaming. 3218c2ecf20Sopenharmony_ci * 3228c2ecf20Sopenharmony_ci * The above processing may be executed before this bus-reset handler is 3238c2ecf20Sopenharmony_ci * executed. When this handler updates streams with current isochronous 3248c2ecf20Sopenharmony_ci * channels, the streams already have the current ones. 3258c2ecf20Sopenharmony_ci */ 3268c2ecf20Sopenharmony_cistatic void 3278c2ecf20Sopenharmony_cibebob_update(struct fw_unit *unit) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct snd_bebob *bebob = dev_get_drvdata(&unit->device); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (bebob == NULL) 3328c2ecf20Sopenharmony_ci return; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Postpone a workqueue for deferred registration. */ 3358c2ecf20Sopenharmony_ci if (!bebob->registered) 3368c2ecf20Sopenharmony_ci snd_fw_schedule_registration(unit, &bebob->dwork); 3378c2ecf20Sopenharmony_ci else 3388c2ecf20Sopenharmony_ci fcp_bus_reset(bebob->unit); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic void bebob_remove(struct fw_unit *unit) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct snd_bebob *bebob = dev_get_drvdata(&unit->device); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (bebob == NULL) 3468c2ecf20Sopenharmony_ci return; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci /* 3498c2ecf20Sopenharmony_ci * Confirm to stop the work for registration before the sound card is 3508c2ecf20Sopenharmony_ci * going to be released. The work is not scheduled again because bus 3518c2ecf20Sopenharmony_ci * reset handler is not called anymore. 3528c2ecf20Sopenharmony_ci */ 3538c2ecf20Sopenharmony_ci cancel_delayed_work_sync(&bebob->dwork); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (bebob->registered) { 3568c2ecf20Sopenharmony_ci // Block till all of ALSA character devices are released. 3578c2ecf20Sopenharmony_ci snd_card_free(bebob->card); 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci mutex_destroy(&bebob->mutex); 3618c2ecf20Sopenharmony_ci fw_unit_put(bebob->unit); 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_cistatic const struct snd_bebob_rate_spec normal_rate_spec = { 3658c2ecf20Sopenharmony_ci .get = &snd_bebob_stream_get_rate, 3668c2ecf20Sopenharmony_ci .set = &snd_bebob_stream_set_rate 3678c2ecf20Sopenharmony_ci}; 3688c2ecf20Sopenharmony_cistatic const struct snd_bebob_spec spec_normal = { 3698c2ecf20Sopenharmony_ci .clock = NULL, 3708c2ecf20Sopenharmony_ci .rate = &normal_rate_spec, 3718c2ecf20Sopenharmony_ci .meter = NULL 3728c2ecf20Sopenharmony_ci}; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic const struct ieee1394_device_id bebob_id_table[] = { 3758c2ecf20Sopenharmony_ci /* Edirol, FA-66 */ 3768c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010049, &spec_normal), 3778c2ecf20Sopenharmony_ci /* Edirol, FA-101 */ 3788c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010048, &spec_normal), 3798c2ecf20Sopenharmony_ci /* Presonus, FIREBOX */ 3808c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010000, &spec_normal), 3818c2ecf20Sopenharmony_ci /* PreSonus, FIREPOD/FP10 */ 3828c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010066, &spec_normal), 3838c2ecf20Sopenharmony_ci /* PreSonus, Inspire1394 */ 3848c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PRESONUS, 0x00010001, &spec_normal), 3858c2ecf20Sopenharmony_ci /* BridgeCo, RDAudio1 */ 3868c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010048, &spec_normal), 3878c2ecf20Sopenharmony_ci /* BridgeCo, Audio5 */ 3888c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal), 3898c2ecf20Sopenharmony_ci /* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */ 3908c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal), 3918c2ecf20Sopenharmony_ci // Mackie, d.2 (optional Firewire card with DM1000). 3928c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal), 3938c2ecf20Sopenharmony_ci /* Stanton, ScratchAmp */ 3948c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal), 3958c2ecf20Sopenharmony_ci /* Tascam, IF-FW DM */ 3968c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TASCAM, 0x00010067, &spec_normal), 3978c2ecf20Sopenharmony_ci /* Behringer, XENIX UFX 1204 */ 3988c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00001204, &spec_normal), 3998c2ecf20Sopenharmony_ci /* Behringer, XENIX UFX 1604 */ 4008c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00001604, &spec_normal), 4018c2ecf20Sopenharmony_ci /* Behringer, Digital Mixer X32 series (X-UF Card) */ 4028c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00000006, &spec_normal), 4038c2ecf20Sopenharmony_ci /* Behringer, F-Control Audio 1616 */ 4048c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x001616, &spec_normal), 4058c2ecf20Sopenharmony_ci /* Behringer, F-Control Audio 610 */ 4068c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x000610, &spec_normal), 4078c2ecf20Sopenharmony_ci /* Apogee Electronics, Rosetta 200/400 (X-FireWire card) */ 4088c2ecf20Sopenharmony_ci /* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */ 4098c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal), 4108c2ecf20Sopenharmony_ci /* Apogee Electronics, Ensemble */ 4118c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal), 4128c2ecf20Sopenharmony_ci /* ESI, Quatafire610 */ 4138c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal), 4148c2ecf20Sopenharmony_ci /* AcousticReality, eARMasterOne */ 4158c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_ACOUSTIC, 0x00000002, &spec_normal), 4168c2ecf20Sopenharmony_ci /* CME, MatrixKFW */ 4178c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal), 4188c2ecf20Sopenharmony_ci /* Phonic, Helix Board 12 MkII */ 4198c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00050000, &spec_normal), 4208c2ecf20Sopenharmony_ci /* Phonic, Helix Board 18 MkII */ 4218c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00060000, &spec_normal), 4228c2ecf20Sopenharmony_ci /* Phonic, Helix Board 24 MkII */ 4238c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00070000, &spec_normal), 4248c2ecf20Sopenharmony_ci /* Phonic, Helix Board 12 Universal/18 Universal/24 Universal */ 4258c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00000000, &spec_normal), 4268c2ecf20Sopenharmony_ci /* Lynx, Aurora 8/16 (LT-FW) */ 4278c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_LYNX, 0x00000001, &spec_normal), 4288c2ecf20Sopenharmony_ci /* ICON, FireXon */ 4298c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_ICON, 0x00000001, &spec_normal), 4308c2ecf20Sopenharmony_ci /* PrismSound, Orpheus */ 4318c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PRISMSOUND, 0x00010048, &spec_normal), 4328c2ecf20Sopenharmony_ci /* PrismSound, ADA-8XR */ 4338c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_PRISMSOUND, 0x0000ada8, &spec_normal), 4348c2ecf20Sopenharmony_ci /* TerraTec Electronic GmbH, PHASE 88 Rack FW */ 4358c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000003, &phase88_rack_spec), 4368c2ecf20Sopenharmony_ci /* TerraTec Electronic GmbH, PHASE 24 FW */ 4378c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000004, &yamaha_terratec_spec), 4388c2ecf20Sopenharmony_ci /* TerraTec Electronic GmbH, Phase X24 FW */ 4398c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000007, &yamaha_terratec_spec), 4408c2ecf20Sopenharmony_ci /* TerraTec Electronic GmbH, EWS MIC2/MIC8 */ 4418c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000005, &spec_normal), 4428c2ecf20Sopenharmony_ci /* Terratec Electronic GmbH, Aureon 7.1 Firewire */ 4438c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal), 4448c2ecf20Sopenharmony_ci /* Yamaha, GO44 */ 4458c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000b, &yamaha_terratec_spec), 4468c2ecf20Sopenharmony_ci /* YAMAHA, GO46 */ 4478c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_YAMAHA, 0x0010000c, &yamaha_terratec_spec), 4488c2ecf20Sopenharmony_ci /* Focusrite, SaffirePro 26 I/O */ 4498c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec), 4508c2ecf20Sopenharmony_ci /* Focusrite, SaffirePro 10 I/O */ 4518c2ecf20Sopenharmony_ci { 4528c2ecf20Sopenharmony_ci // The combination of vendor_id and model_id is the same as the 4538c2ecf20Sopenharmony_ci // same as the one of Liquid Saffire 56. 4548c2ecf20Sopenharmony_ci .match_flags = IEEE1394_MATCH_VENDOR_ID | 4558c2ecf20Sopenharmony_ci IEEE1394_MATCH_MODEL_ID | 4568c2ecf20Sopenharmony_ci IEEE1394_MATCH_SPECIFIER_ID | 4578c2ecf20Sopenharmony_ci IEEE1394_MATCH_VERSION, 4588c2ecf20Sopenharmony_ci .vendor_id = VEN_FOCUSRITE, 4598c2ecf20Sopenharmony_ci .model_id = 0x000006, 4608c2ecf20Sopenharmony_ci .specifier_id = 0x00a02d, 4618c2ecf20Sopenharmony_ci .version = 0x010001, 4628c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&saffirepro_10_spec, 4638c2ecf20Sopenharmony_ci }, 4648c2ecf20Sopenharmony_ci /* Focusrite, Saffire(no label and LE) */ 4658c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH, 4668c2ecf20Sopenharmony_ci &saffire_spec), 4678c2ecf20Sopenharmony_ci /* M-Audio, Firewire 410 */ 4688c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010058, NULL), /* bootloader */ 4698c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010046, &maudio_fw410_spec), 4708c2ecf20Sopenharmony_ci /* M-Audio, Firewire Audiophile */ 4718c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_AUDIOPHILE_BOTH, 4728c2ecf20Sopenharmony_ci &maudio_audiophile_spec), 4738c2ecf20Sopenharmony_ci /* M-Audio, Firewire Solo */ 4748c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010062, &maudio_solo_spec), 4758c2ecf20Sopenharmony_ci /* M-Audio, Ozonic */ 4768c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x0000000a, &maudio_ozonic_spec), 4778c2ecf20Sopenharmony_ci /* M-Audio NRV10 */ 4788c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec), 4798c2ecf20Sopenharmony_ci /* M-Audio, ProFireLightbridge */ 4808c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal), 4818c2ecf20Sopenharmony_ci /* Firewire 1814 */ 4828c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010070, NULL), /* bootloader */ 4838c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814, 4848c2ecf20Sopenharmony_ci &maudio_special_spec), 4858c2ecf20Sopenharmony_ci /* M-Audio ProjectMix */ 4868c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX, 4878c2ecf20Sopenharmony_ci &maudio_special_spec), 4888c2ecf20Sopenharmony_ci /* Digidesign Mbox 2 Pro */ 4898c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal), 4908c2ecf20Sopenharmony_ci // Toneweal FW66. 4918c2ecf20Sopenharmony_ci SND_BEBOB_DEV_ENTRY(OUI_SHOUYO, 0x020002, &spec_normal), 4928c2ecf20Sopenharmony_ci /* IDs are unknown but able to be supported */ 4938c2ecf20Sopenharmony_ci /* Apogee, Mini-ME Firewire */ 4948c2ecf20Sopenharmony_ci /* Apogee, Mini-DAC Firewire */ 4958c2ecf20Sopenharmony_ci /* Cakawalk, Sonar Power Studio 66 */ 4968c2ecf20Sopenharmony_ci /* CME, UF400e */ 4978c2ecf20Sopenharmony_ci /* ESI, Quotafire XL */ 4988c2ecf20Sopenharmony_ci /* Infrasonic, DewX */ 4998c2ecf20Sopenharmony_ci /* Infrasonic, Windy6 */ 5008c2ecf20Sopenharmony_ci /* Mackie, Digital X Bus x.200 */ 5018c2ecf20Sopenharmony_ci /* Mackie, Digital X Bus x.400 */ 5028c2ecf20Sopenharmony_ci /* Phonic, HB 12 */ 5038c2ecf20Sopenharmony_ci /* Phonic, HB 24 */ 5048c2ecf20Sopenharmony_ci /* Phonic, HB 18 */ 5058c2ecf20Sopenharmony_ci /* Phonic, FireFly 202 */ 5068c2ecf20Sopenharmony_ci /* Phonic, FireFly 302 */ 5078c2ecf20Sopenharmony_ci /* Rolf Spuler, Firewire Guitar */ 5088c2ecf20Sopenharmony_ci {} 5098c2ecf20Sopenharmony_ci}; 5108c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(ieee1394, bebob_id_table); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic struct fw_driver bebob_driver = { 5138c2ecf20Sopenharmony_ci .driver = { 5148c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5158c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 5168c2ecf20Sopenharmony_ci .bus = &fw_bus_type, 5178c2ecf20Sopenharmony_ci }, 5188c2ecf20Sopenharmony_ci .probe = bebob_probe, 5198c2ecf20Sopenharmony_ci .update = bebob_update, 5208c2ecf20Sopenharmony_ci .remove = bebob_remove, 5218c2ecf20Sopenharmony_ci .id_table = bebob_id_table, 5228c2ecf20Sopenharmony_ci}; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int __init 5258c2ecf20Sopenharmony_cisnd_bebob_init(void) 5268c2ecf20Sopenharmony_ci{ 5278c2ecf20Sopenharmony_ci return driver_register(&bebob_driver.driver); 5288c2ecf20Sopenharmony_ci} 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_cistatic void __exit 5318c2ecf20Sopenharmony_cisnd_bebob_exit(void) 5328c2ecf20Sopenharmony_ci{ 5338c2ecf20Sopenharmony_ci driver_unregister(&bebob_driver.driver); 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cimodule_init(snd_bebob_init); 5378c2ecf20Sopenharmony_cimodule_exit(snd_bebob_exit); 538