18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * caiaq.c: ALSA driver for caiaq/NativeInstruments devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2007 Daniel Mack <daniel@caiaq.de> 68c2ecf20Sopenharmony_ci * Karsten Wiese <fzu@wemgehoertderstaat.de> 78c2ecf20Sopenharmony_ci*/ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/gfp.h> 158c2ecf20Sopenharmony_ci#include <linux/usb.h> 168c2ecf20Sopenharmony_ci#include <sound/initval.h> 178c2ecf20Sopenharmony_ci#include <sound/core.h> 188c2ecf20Sopenharmony_ci#include <sound/pcm.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "device.h" 218c2ecf20Sopenharmony_ci#include "audio.h" 228c2ecf20Sopenharmony_ci#include "midi.h" 238c2ecf20Sopenharmony_ci#include "control.h" 248c2ecf20Sopenharmony_ci#include "input.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Mack <daniel@caiaq.de>"); 278c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("caiaq USB audio"); 288c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 298c2ecf20Sopenharmony_ciMODULE_SUPPORTED_DEVICE("{{Native Instruments,RigKontrol2}," 308c2ecf20Sopenharmony_ci "{Native Instruments,RigKontrol3}," 318c2ecf20Sopenharmony_ci "{Native Instruments,Kore Controller}," 328c2ecf20Sopenharmony_ci "{Native Instruments,Kore Controller 2}," 338c2ecf20Sopenharmony_ci "{Native Instruments,Audio Kontrol 1}," 348c2ecf20Sopenharmony_ci "{Native Instruments,Audio 2 DJ}," 358c2ecf20Sopenharmony_ci "{Native Instruments,Audio 4 DJ}," 368c2ecf20Sopenharmony_ci "{Native Instruments,Audio 8 DJ}," 378c2ecf20Sopenharmony_ci "{Native Instruments,Traktor Audio 2}," 388c2ecf20Sopenharmony_ci "{Native Instruments,Session I/O}," 398c2ecf20Sopenharmony_ci "{Native Instruments,GuitarRig mobile}," 408c2ecf20Sopenharmony_ci "{Native Instruments,Traktor Kontrol X1}," 418c2ecf20Sopenharmony_ci "{Native Instruments,Traktor Kontrol S4}," 428c2ecf20Sopenharmony_ci "{Native Instruments,Maschine Controller}}"); 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ 458c2ecf20Sopenharmony_cistatic char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ 468c2ecf20Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 498c2ecf20Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for the caiaq sound device"); 508c2ecf20Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 518c2ecf20Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for the caiaq soundcard."); 528c2ecf20Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 538c2ecf20Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable the caiaq soundcard."); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cienum { 568c2ecf20Sopenharmony_ci SAMPLERATE_44100 = 0, 578c2ecf20Sopenharmony_ci SAMPLERATE_48000 = 1, 588c2ecf20Sopenharmony_ci SAMPLERATE_96000 = 2, 598c2ecf20Sopenharmony_ci SAMPLERATE_192000 = 3, 608c2ecf20Sopenharmony_ci SAMPLERATE_88200 = 4, 618c2ecf20Sopenharmony_ci SAMPLERATE_INVALID = 0xff 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cienum { 658c2ecf20Sopenharmony_ci DEPTH_NONE = 0, 668c2ecf20Sopenharmony_ci DEPTH_16 = 1, 678c2ecf20Sopenharmony_ci DEPTH_24 = 2, 688c2ecf20Sopenharmony_ci DEPTH_32 = 3 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic const struct usb_device_id snd_usb_id_table[] = { 728c2ecf20Sopenharmony_ci { 738c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 748c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 758c2ecf20Sopenharmony_ci .idProduct = USB_PID_RIGKONTROL2 768c2ecf20Sopenharmony_ci }, 778c2ecf20Sopenharmony_ci { 788c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 798c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 808c2ecf20Sopenharmony_ci .idProduct = USB_PID_RIGKONTROL3 818c2ecf20Sopenharmony_ci }, 828c2ecf20Sopenharmony_ci { 838c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 848c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 858c2ecf20Sopenharmony_ci .idProduct = USB_PID_KORECONTROLLER 868c2ecf20Sopenharmony_ci }, 878c2ecf20Sopenharmony_ci { 888c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 898c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 908c2ecf20Sopenharmony_ci .idProduct = USB_PID_KORECONTROLLER2 918c2ecf20Sopenharmony_ci }, 928c2ecf20Sopenharmony_ci { 938c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 948c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 958c2ecf20Sopenharmony_ci .idProduct = USB_PID_AK1 968c2ecf20Sopenharmony_ci }, 978c2ecf20Sopenharmony_ci { 988c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 998c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1008c2ecf20Sopenharmony_ci .idProduct = USB_PID_AUDIO8DJ 1018c2ecf20Sopenharmony_ci }, 1028c2ecf20Sopenharmony_ci { 1038c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1048c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1058c2ecf20Sopenharmony_ci .idProduct = USB_PID_SESSIONIO 1068c2ecf20Sopenharmony_ci }, 1078c2ecf20Sopenharmony_ci { 1088c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1098c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1108c2ecf20Sopenharmony_ci .idProduct = USB_PID_GUITARRIGMOBILE 1118c2ecf20Sopenharmony_ci }, 1128c2ecf20Sopenharmony_ci { 1138c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1148c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1158c2ecf20Sopenharmony_ci .idProduct = USB_PID_AUDIO4DJ 1168c2ecf20Sopenharmony_ci }, 1178c2ecf20Sopenharmony_ci { 1188c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1198c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1208c2ecf20Sopenharmony_ci .idProduct = USB_PID_AUDIO2DJ 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1248c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1258c2ecf20Sopenharmony_ci .idProduct = USB_PID_TRAKTORKONTROLX1 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci { 1288c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1298c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1308c2ecf20Sopenharmony_ci .idProduct = USB_PID_TRAKTORKONTROLS4 1318c2ecf20Sopenharmony_ci }, 1328c2ecf20Sopenharmony_ci { 1338c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1348c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1358c2ecf20Sopenharmony_ci .idProduct = USB_PID_TRAKTORAUDIO2 1368c2ecf20Sopenharmony_ci }, 1378c2ecf20Sopenharmony_ci { 1388c2ecf20Sopenharmony_ci .match_flags = USB_DEVICE_ID_MATCH_DEVICE, 1398c2ecf20Sopenharmony_ci .idVendor = USB_VID_NATIVEINSTRUMENTS, 1408c2ecf20Sopenharmony_ci .idProduct = USB_PID_MASCHINECONTROLLER 1418c2ecf20Sopenharmony_ci }, 1428c2ecf20Sopenharmony_ci { /* terminator */ } 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic void usb_ep1_command_reply_dispatch (struct urb* urb) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci int ret; 1488c2ecf20Sopenharmony_ci struct device *dev = &urb->dev->dev; 1498c2ecf20Sopenharmony_ci struct snd_usb_caiaqdev *cdev = urb->context; 1508c2ecf20Sopenharmony_ci unsigned char *buf = urb->transfer_buffer; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (urb->status || !cdev) { 1538c2ecf20Sopenharmony_ci dev_warn(dev, "received EP1 urb->status = %i\n", urb->status); 1548c2ecf20Sopenharmony_ci return; 1558c2ecf20Sopenharmony_ci } 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci switch(buf[0]) { 1588c2ecf20Sopenharmony_ci case EP1_CMD_GET_DEVICE_INFO: 1598c2ecf20Sopenharmony_ci memcpy(&cdev->spec, buf+1, sizeof(struct caiaq_device_spec)); 1608c2ecf20Sopenharmony_ci cdev->spec.fw_version = le16_to_cpu(cdev->spec.fw_version); 1618c2ecf20Sopenharmony_ci dev_dbg(dev, "device spec (firmware %d): audio: %d in, %d out, " 1628c2ecf20Sopenharmony_ci "MIDI: %d in, %d out, data alignment %d\n", 1638c2ecf20Sopenharmony_ci cdev->spec.fw_version, 1648c2ecf20Sopenharmony_ci cdev->spec.num_analog_audio_in, 1658c2ecf20Sopenharmony_ci cdev->spec.num_analog_audio_out, 1668c2ecf20Sopenharmony_ci cdev->spec.num_midi_in, 1678c2ecf20Sopenharmony_ci cdev->spec.num_midi_out, 1688c2ecf20Sopenharmony_ci cdev->spec.data_alignment); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci cdev->spec_received++; 1718c2ecf20Sopenharmony_ci wake_up(&cdev->ep1_wait_queue); 1728c2ecf20Sopenharmony_ci break; 1738c2ecf20Sopenharmony_ci case EP1_CMD_AUDIO_PARAMS: 1748c2ecf20Sopenharmony_ci cdev->audio_parm_answer = buf[1]; 1758c2ecf20Sopenharmony_ci wake_up(&cdev->ep1_wait_queue); 1768c2ecf20Sopenharmony_ci break; 1778c2ecf20Sopenharmony_ci case EP1_CMD_MIDI_READ: 1788c2ecf20Sopenharmony_ci snd_usb_caiaq_midi_handle_input(cdev, buf[1], buf + 3, buf[2]); 1798c2ecf20Sopenharmony_ci break; 1808c2ecf20Sopenharmony_ci case EP1_CMD_READ_IO: 1818c2ecf20Sopenharmony_ci if (cdev->chip.usb_id == 1828c2ecf20Sopenharmony_ci USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ)) { 1838c2ecf20Sopenharmony_ci if (urb->actual_length > sizeof(cdev->control_state)) 1848c2ecf20Sopenharmony_ci urb->actual_length = sizeof(cdev->control_state); 1858c2ecf20Sopenharmony_ci memcpy(cdev->control_state, buf + 1, urb->actual_length); 1868c2ecf20Sopenharmony_ci wake_up(&cdev->ep1_wait_queue); 1878c2ecf20Sopenharmony_ci break; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_USB_CAIAQ_INPUT 1908c2ecf20Sopenharmony_ci fallthrough; 1918c2ecf20Sopenharmony_ci case EP1_CMD_READ_ERP: 1928c2ecf20Sopenharmony_ci case EP1_CMD_READ_ANALOG: 1938c2ecf20Sopenharmony_ci snd_usb_caiaq_input_dispatch(cdev, buf, urb->actual_length); 1948c2ecf20Sopenharmony_ci#endif 1958c2ecf20Sopenharmony_ci break; 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci cdev->ep1_in_urb.actual_length = 0; 1998c2ecf20Sopenharmony_ci ret = usb_submit_urb(&cdev->ep1_in_urb, GFP_ATOMIC); 2008c2ecf20Sopenharmony_ci if (ret < 0) 2018c2ecf20Sopenharmony_ci dev_err(dev, "unable to submit urb. OOM!?\n"); 2028c2ecf20Sopenharmony_ci} 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ciint snd_usb_caiaq_send_command(struct snd_usb_caiaqdev *cdev, 2058c2ecf20Sopenharmony_ci unsigned char command, 2068c2ecf20Sopenharmony_ci const unsigned char *buffer, 2078c2ecf20Sopenharmony_ci int len) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci int actual_len; 2108c2ecf20Sopenharmony_ci struct usb_device *usb_dev = cdev->chip.dev; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci if (!usb_dev) 2138c2ecf20Sopenharmony_ci return -EIO; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (len > EP1_BUFSIZE - 1) 2168c2ecf20Sopenharmony_ci len = EP1_BUFSIZE - 1; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (buffer && len > 0) 2198c2ecf20Sopenharmony_ci memcpy(cdev->ep1_out_buf+1, buffer, len); 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci cdev->ep1_out_buf[0] = command; 2228c2ecf20Sopenharmony_ci return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), 2238c2ecf20Sopenharmony_ci cdev->ep1_out_buf, len+1, &actual_len, 200); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ciint snd_usb_caiaq_send_command_bank(struct snd_usb_caiaqdev *cdev, 2278c2ecf20Sopenharmony_ci unsigned char command, 2288c2ecf20Sopenharmony_ci unsigned char bank, 2298c2ecf20Sopenharmony_ci const unsigned char *buffer, 2308c2ecf20Sopenharmony_ci int len) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci int actual_len; 2338c2ecf20Sopenharmony_ci struct usb_device *usb_dev = cdev->chip.dev; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (!usb_dev) 2368c2ecf20Sopenharmony_ci return -EIO; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci if (len > EP1_BUFSIZE - 2) 2398c2ecf20Sopenharmony_ci len = EP1_BUFSIZE - 2; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (buffer && len > 0) 2428c2ecf20Sopenharmony_ci memcpy(cdev->ep1_out_buf+2, buffer, len); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci cdev->ep1_out_buf[0] = command; 2458c2ecf20Sopenharmony_ci cdev->ep1_out_buf[1] = bank; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, 1), 2488c2ecf20Sopenharmony_ci cdev->ep1_out_buf, len+2, &actual_len, 200); 2498c2ecf20Sopenharmony_ci} 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ciint snd_usb_caiaq_set_audio_params (struct snd_usb_caiaqdev *cdev, 2528c2ecf20Sopenharmony_ci int rate, int depth, int bpp) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci int ret; 2558c2ecf20Sopenharmony_ci char tmp[5]; 2568c2ecf20Sopenharmony_ci struct device *dev = caiaqdev_to_dev(cdev); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci switch (rate) { 2598c2ecf20Sopenharmony_ci case 44100: tmp[0] = SAMPLERATE_44100; break; 2608c2ecf20Sopenharmony_ci case 48000: tmp[0] = SAMPLERATE_48000; break; 2618c2ecf20Sopenharmony_ci case 88200: tmp[0] = SAMPLERATE_88200; break; 2628c2ecf20Sopenharmony_ci case 96000: tmp[0] = SAMPLERATE_96000; break; 2638c2ecf20Sopenharmony_ci case 192000: tmp[0] = SAMPLERATE_192000; break; 2648c2ecf20Sopenharmony_ci default: return -EINVAL; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci switch (depth) { 2688c2ecf20Sopenharmony_ci case 16: tmp[1] = DEPTH_16; break; 2698c2ecf20Sopenharmony_ci case 24: tmp[1] = DEPTH_24; break; 2708c2ecf20Sopenharmony_ci default: return -EINVAL; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci tmp[2] = bpp & 0xff; 2748c2ecf20Sopenharmony_ci tmp[3] = bpp >> 8; 2758c2ecf20Sopenharmony_ci tmp[4] = 1; /* packets per microframe */ 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci dev_dbg(dev, "setting audio params: %d Hz, %d bits, %d bpp\n", 2788c2ecf20Sopenharmony_ci rate, depth, bpp); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci cdev->audio_parm_answer = -1; 2818c2ecf20Sopenharmony_ci ret = snd_usb_caiaq_send_command(cdev, EP1_CMD_AUDIO_PARAMS, 2828c2ecf20Sopenharmony_ci tmp, sizeof(tmp)); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (ret) 2858c2ecf20Sopenharmony_ci return ret; 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!wait_event_timeout(cdev->ep1_wait_queue, 2888c2ecf20Sopenharmony_ci cdev->audio_parm_answer >= 0, HZ)) 2898c2ecf20Sopenharmony_ci return -EPIPE; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (cdev->audio_parm_answer != 1) 2928c2ecf20Sopenharmony_ci dev_dbg(dev, "unable to set the device's audio params\n"); 2938c2ecf20Sopenharmony_ci else 2948c2ecf20Sopenharmony_ci cdev->bpp = bpp; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci return cdev->audio_parm_answer == 1 ? 0 : -EINVAL; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ciint snd_usb_caiaq_set_auto_msg(struct snd_usb_caiaqdev *cdev, 3008c2ecf20Sopenharmony_ci int digital, int analog, int erp) 3018c2ecf20Sopenharmony_ci{ 3028c2ecf20Sopenharmony_ci char tmp[3] = { digital, analog, erp }; 3038c2ecf20Sopenharmony_ci return snd_usb_caiaq_send_command(cdev, EP1_CMD_AUTO_MSG, 3048c2ecf20Sopenharmony_ci tmp, sizeof(tmp)); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void setup_card(struct snd_usb_caiaqdev *cdev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci char val[4]; 3118c2ecf20Sopenharmony_ci struct device *dev = caiaqdev_to_dev(cdev); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* device-specific startup specials */ 3148c2ecf20Sopenharmony_ci switch (cdev->chip.usb_id) { 3158c2ecf20Sopenharmony_ci case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): 3168c2ecf20Sopenharmony_ci /* RigKontrol2 - display centered dash ('-') */ 3178c2ecf20Sopenharmony_ci val[0] = 0x00; 3188c2ecf20Sopenharmony_ci val[1] = 0x00; 3198c2ecf20Sopenharmony_ci val[2] = 0x01; 3208c2ecf20Sopenharmony_ci snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 3); 3218c2ecf20Sopenharmony_ci break; 3228c2ecf20Sopenharmony_ci case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL3): 3238c2ecf20Sopenharmony_ci /* RigKontrol2 - display two centered dashes ('--') */ 3248c2ecf20Sopenharmony_ci val[0] = 0x00; 3258c2ecf20Sopenharmony_ci val[1] = 0x40; 3268c2ecf20Sopenharmony_ci val[2] = 0x40; 3278c2ecf20Sopenharmony_ci val[3] = 0x00; 3288c2ecf20Sopenharmony_ci snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 4); 3298c2ecf20Sopenharmony_ci break; 3308c2ecf20Sopenharmony_ci case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AK1): 3318c2ecf20Sopenharmony_ci /* Audio Kontrol 1 - make USB-LED stop blinking */ 3328c2ecf20Sopenharmony_ci val[0] = 0x00; 3338c2ecf20Sopenharmony_ci snd_usb_caiaq_send_command(cdev, EP1_CMD_WRITE_IO, val, 1); 3348c2ecf20Sopenharmony_ci break; 3358c2ecf20Sopenharmony_ci case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ): 3368c2ecf20Sopenharmony_ci /* Audio 8 DJ - trigger read of current settings */ 3378c2ecf20Sopenharmony_ci cdev->control_state[0] = 0xff; 3388c2ecf20Sopenharmony_ci snd_usb_caiaq_set_auto_msg(cdev, 1, 0, 0); 3398c2ecf20Sopenharmony_ci snd_usb_caiaq_send_command(cdev, EP1_CMD_READ_IO, NULL, 0); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci if (!wait_event_timeout(cdev->ep1_wait_queue, 3428c2ecf20Sopenharmony_ci cdev->control_state[0] != 0xff, HZ)) 3438c2ecf20Sopenharmony_ci return; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* fix up some defaults */ 3468c2ecf20Sopenharmony_ci if ((cdev->control_state[1] != 2) || 3478c2ecf20Sopenharmony_ci (cdev->control_state[2] != 3) || 3488c2ecf20Sopenharmony_ci (cdev->control_state[4] != 2)) { 3498c2ecf20Sopenharmony_ci cdev->control_state[1] = 2; 3508c2ecf20Sopenharmony_ci cdev->control_state[2] = 3; 3518c2ecf20Sopenharmony_ci cdev->control_state[4] = 2; 3528c2ecf20Sopenharmony_ci snd_usb_caiaq_send_command(cdev, 3538c2ecf20Sopenharmony_ci EP1_CMD_WRITE_IO, cdev->control_state, 6); 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci break; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci if (cdev->spec.num_analog_audio_out + 3608c2ecf20Sopenharmony_ci cdev->spec.num_analog_audio_in + 3618c2ecf20Sopenharmony_ci cdev->spec.num_digital_audio_out + 3628c2ecf20Sopenharmony_ci cdev->spec.num_digital_audio_in > 0) { 3638c2ecf20Sopenharmony_ci ret = snd_usb_caiaq_audio_init(cdev); 3648c2ecf20Sopenharmony_ci if (ret < 0) 3658c2ecf20Sopenharmony_ci dev_err(dev, "Unable to set up audio system (ret=%d)\n", ret); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci if (cdev->spec.num_midi_in + 3698c2ecf20Sopenharmony_ci cdev->spec.num_midi_out > 0) { 3708c2ecf20Sopenharmony_ci ret = snd_usb_caiaq_midi_init(cdev); 3718c2ecf20Sopenharmony_ci if (ret < 0) 3728c2ecf20Sopenharmony_ci dev_err(dev, "Unable to set up MIDI system (ret=%d)\n", ret); 3738c2ecf20Sopenharmony_ci } 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_USB_CAIAQ_INPUT 3768c2ecf20Sopenharmony_ci ret = snd_usb_caiaq_input_init(cdev); 3778c2ecf20Sopenharmony_ci if (ret < 0) 3788c2ecf20Sopenharmony_ci dev_err(dev, "Unable to set up input system (ret=%d)\n", ret); 3798c2ecf20Sopenharmony_ci#endif 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* finally, register the card and all its sub-instances */ 3828c2ecf20Sopenharmony_ci ret = snd_card_register(cdev->chip.card); 3838c2ecf20Sopenharmony_ci if (ret < 0) { 3848c2ecf20Sopenharmony_ci dev_err(dev, "snd_card_register() returned %d\n", ret); 3858c2ecf20Sopenharmony_ci snd_card_free(cdev->chip.card); 3868c2ecf20Sopenharmony_ci } 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci ret = snd_usb_caiaq_control_init(cdev); 3898c2ecf20Sopenharmony_ci if (ret < 0) 3908c2ecf20Sopenharmony_ci dev_err(dev, "Unable to set up control system (ret=%d)\n", ret); 3918c2ecf20Sopenharmony_ci} 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_cistatic int create_card(struct usb_device *usb_dev, 3948c2ecf20Sopenharmony_ci struct usb_interface *intf, 3958c2ecf20Sopenharmony_ci struct snd_card **cardp) 3968c2ecf20Sopenharmony_ci{ 3978c2ecf20Sopenharmony_ci int devnum; 3988c2ecf20Sopenharmony_ci int err; 3998c2ecf20Sopenharmony_ci struct snd_card *card; 4008c2ecf20Sopenharmony_ci struct snd_usb_caiaqdev *cdev; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci for (devnum = 0; devnum < SNDRV_CARDS; devnum++) 4038c2ecf20Sopenharmony_ci if (enable[devnum]) 4048c2ecf20Sopenharmony_ci break; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (devnum >= SNDRV_CARDS) 4078c2ecf20Sopenharmony_ci return -ENODEV; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci err = snd_card_new(&intf->dev, 4108c2ecf20Sopenharmony_ci index[devnum], id[devnum], THIS_MODULE, 4118c2ecf20Sopenharmony_ci sizeof(struct snd_usb_caiaqdev), &card); 4128c2ecf20Sopenharmony_ci if (err < 0) 4138c2ecf20Sopenharmony_ci return err; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci cdev = caiaqdev(card); 4168c2ecf20Sopenharmony_ci cdev->chip.dev = usb_dev; 4178c2ecf20Sopenharmony_ci cdev->chip.card = card; 4188c2ecf20Sopenharmony_ci cdev->chip.usb_id = USB_ID(le16_to_cpu(usb_dev->descriptor.idVendor), 4198c2ecf20Sopenharmony_ci le16_to_cpu(usb_dev->descriptor.idProduct)); 4208c2ecf20Sopenharmony_ci spin_lock_init(&cdev->spinlock); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci *cardp = card; 4238c2ecf20Sopenharmony_ci return 0; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int init_card(struct snd_usb_caiaqdev *cdev) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci char *c, usbpath[32]; 4298c2ecf20Sopenharmony_ci struct usb_device *usb_dev = cdev->chip.dev; 4308c2ecf20Sopenharmony_ci struct snd_card *card = cdev->chip.card; 4318c2ecf20Sopenharmony_ci struct device *dev = caiaqdev_to_dev(cdev); 4328c2ecf20Sopenharmony_ci int err, len; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (usb_set_interface(usb_dev, 0, 1) != 0) { 4358c2ecf20Sopenharmony_ci dev_err(dev, "can't set alt interface.\n"); 4368c2ecf20Sopenharmony_ci return -EIO; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci usb_init_urb(&cdev->ep1_in_urb); 4408c2ecf20Sopenharmony_ci usb_init_urb(&cdev->midi_out_urb); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci usb_fill_bulk_urb(&cdev->ep1_in_urb, usb_dev, 4438c2ecf20Sopenharmony_ci usb_rcvbulkpipe(usb_dev, 0x1), 4448c2ecf20Sopenharmony_ci cdev->ep1_in_buf, EP1_BUFSIZE, 4458c2ecf20Sopenharmony_ci usb_ep1_command_reply_dispatch, cdev); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci usb_fill_bulk_urb(&cdev->midi_out_urb, usb_dev, 4488c2ecf20Sopenharmony_ci usb_sndbulkpipe(usb_dev, 0x1), 4498c2ecf20Sopenharmony_ci cdev->midi_out_buf, EP1_BUFSIZE, 4508c2ecf20Sopenharmony_ci snd_usb_caiaq_midi_output_done, cdev); 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* sanity checks of EPs before actually submitting */ 4538c2ecf20Sopenharmony_ci if (usb_urb_ep_type_check(&cdev->ep1_in_urb) || 4548c2ecf20Sopenharmony_ci usb_urb_ep_type_check(&cdev->midi_out_urb)) { 4558c2ecf20Sopenharmony_ci dev_err(dev, "invalid EPs\n"); 4568c2ecf20Sopenharmony_ci return -EINVAL; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci init_waitqueue_head(&cdev->ep1_wait_queue); 4608c2ecf20Sopenharmony_ci init_waitqueue_head(&cdev->prepare_wait_queue); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (usb_submit_urb(&cdev->ep1_in_urb, GFP_KERNEL) != 0) 4638c2ecf20Sopenharmony_ci return -EIO; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci err = snd_usb_caiaq_send_command(cdev, EP1_CMD_GET_DEVICE_INFO, NULL, 0); 4668c2ecf20Sopenharmony_ci if (err) 4678c2ecf20Sopenharmony_ci goto err_kill_urb; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if (!wait_event_timeout(cdev->ep1_wait_queue, cdev->spec_received, HZ)) { 4708c2ecf20Sopenharmony_ci err = -ENODEV; 4718c2ecf20Sopenharmony_ci goto err_kill_urb; 4728c2ecf20Sopenharmony_ci } 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci usb_string(usb_dev, usb_dev->descriptor.iManufacturer, 4758c2ecf20Sopenharmony_ci cdev->vendor_name, CAIAQ_USB_STR_LEN); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci usb_string(usb_dev, usb_dev->descriptor.iProduct, 4788c2ecf20Sopenharmony_ci cdev->product_name, CAIAQ_USB_STR_LEN); 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci strlcpy(card->driver, MODNAME, sizeof(card->driver)); 4818c2ecf20Sopenharmony_ci strlcpy(card->shortname, cdev->product_name, sizeof(card->shortname)); 4828c2ecf20Sopenharmony_ci strlcpy(card->mixername, cdev->product_name, sizeof(card->mixername)); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* if the id was not passed as module option, fill it with a shortened 4858c2ecf20Sopenharmony_ci * version of the product string which does not contain any 4868c2ecf20Sopenharmony_ci * whitespaces */ 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci if (*card->id == '\0') { 4898c2ecf20Sopenharmony_ci char id[sizeof(card->id)]; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci memset(id, 0, sizeof(id)); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci for (c = card->shortname, len = 0; 4948c2ecf20Sopenharmony_ci *c && len < sizeof(card->id); c++) 4958c2ecf20Sopenharmony_ci if (*c != ' ') 4968c2ecf20Sopenharmony_ci id[len++] = *c; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci snd_card_set_id(card, id); 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci usb_make_path(usb_dev, usbpath, sizeof(usbpath)); 5028c2ecf20Sopenharmony_ci snprintf(card->longname, sizeof(card->longname), "%s %s (%s)", 5038c2ecf20Sopenharmony_ci cdev->vendor_name, cdev->product_name, usbpath); 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci setup_card(cdev); 5068c2ecf20Sopenharmony_ci return 0; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci err_kill_urb: 5098c2ecf20Sopenharmony_ci usb_kill_urb(&cdev->ep1_in_urb); 5108c2ecf20Sopenharmony_ci return err; 5118c2ecf20Sopenharmony_ci} 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_cistatic int snd_probe(struct usb_interface *intf, 5148c2ecf20Sopenharmony_ci const struct usb_device_id *id) 5158c2ecf20Sopenharmony_ci{ 5168c2ecf20Sopenharmony_ci int ret; 5178c2ecf20Sopenharmony_ci struct snd_card *card = NULL; 5188c2ecf20Sopenharmony_ci struct usb_device *usb_dev = interface_to_usbdev(intf); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci ret = create_card(usb_dev, intf, &card); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (ret < 0) 5238c2ecf20Sopenharmony_ci return ret; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci usb_set_intfdata(intf, card); 5268c2ecf20Sopenharmony_ci ret = init_card(caiaqdev(card)); 5278c2ecf20Sopenharmony_ci if (ret < 0) { 5288c2ecf20Sopenharmony_ci dev_err(&usb_dev->dev, "unable to init card! (ret=%d)\n", ret); 5298c2ecf20Sopenharmony_ci snd_card_free(card); 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci return 0; 5348c2ecf20Sopenharmony_ci} 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_cistatic void snd_disconnect(struct usb_interface *intf) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct snd_card *card = usb_get_intfdata(intf); 5398c2ecf20Sopenharmony_ci struct device *dev = intf->usb_dev; 5408c2ecf20Sopenharmony_ci struct snd_usb_caiaqdev *cdev; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (!card) 5438c2ecf20Sopenharmony_ci return; 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci cdev = caiaqdev(card); 5468c2ecf20Sopenharmony_ci dev_dbg(dev, "%s(%p)\n", __func__, intf); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci snd_card_disconnect(card); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci#ifdef CONFIG_SND_USB_CAIAQ_INPUT 5518c2ecf20Sopenharmony_ci snd_usb_caiaq_input_free(cdev); 5528c2ecf20Sopenharmony_ci#endif 5538c2ecf20Sopenharmony_ci snd_usb_caiaq_audio_free(cdev); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci usb_kill_urb(&cdev->ep1_in_urb); 5568c2ecf20Sopenharmony_ci usb_kill_urb(&cdev->midi_out_urb); 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci snd_card_free(card); 5598c2ecf20Sopenharmony_ci usb_reset_device(interface_to_usbdev(intf)); 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, snd_usb_id_table); 5648c2ecf20Sopenharmony_cistatic struct usb_driver snd_usb_driver = { 5658c2ecf20Sopenharmony_ci .name = MODNAME, 5668c2ecf20Sopenharmony_ci .probe = snd_probe, 5678c2ecf20Sopenharmony_ci .disconnect = snd_disconnect, 5688c2ecf20Sopenharmony_ci .id_table = snd_usb_id_table, 5698c2ecf20Sopenharmony_ci}; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cimodule_usb_driver(snd_usb_driver); 572