18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Tascam US-16x08 ALSA driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 by Detlef Urban (onkel@paraair.de) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/usb.h> 108c2ecf20Sopenharmony_ci#include <linux/usb/audio-v2.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <sound/core.h> 138c2ecf20Sopenharmony_ci#include <sound/control.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include "usbaudio.h" 168c2ecf20Sopenharmony_ci#include "mixer.h" 178c2ecf20Sopenharmony_ci#include "helper.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#include "mixer_us16x08.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* USB control message templates */ 228c2ecf20Sopenharmony_cistatic const char route_msg[] = { 238c2ecf20Sopenharmony_ci 0x61, 248c2ecf20Sopenharmony_ci 0x02, 258c2ecf20Sopenharmony_ci 0x03, /* input from master (0x02) or input from computer bus (0x03) */ 268c2ecf20Sopenharmony_ci 0x62, 278c2ecf20Sopenharmony_ci 0x02, 288c2ecf20Sopenharmony_ci 0x01, /* input index (0x01/0x02 eq. left/right) or bus (0x01-0x08) */ 298c2ecf20Sopenharmony_ci 0x41, 308c2ecf20Sopenharmony_ci 0x01, 318c2ecf20Sopenharmony_ci 0x61, 328c2ecf20Sopenharmony_ci 0x02, 338c2ecf20Sopenharmony_ci 0x01, 348c2ecf20Sopenharmony_ci 0x62, 358c2ecf20Sopenharmony_ci 0x02, 368c2ecf20Sopenharmony_ci 0x01, /* output index (0x01-0x08) */ 378c2ecf20Sopenharmony_ci 0x42, 388c2ecf20Sopenharmony_ci 0x01, 398c2ecf20Sopenharmony_ci 0x43, 408c2ecf20Sopenharmony_ci 0x01, 418c2ecf20Sopenharmony_ci 0x00, 428c2ecf20Sopenharmony_ci 0x00 438c2ecf20Sopenharmony_ci}; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistatic const char mix_init_msg1[] = { 468c2ecf20Sopenharmony_ci 0x71, 0x01, 0x00, 0x00 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_cistatic const char mix_init_msg2[] = { 508c2ecf20Sopenharmony_ci 0x62, 0x02, 0x00, 0x61, 0x02, 0x04, 0xb1, 0x01, 0x00, 0x00 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic const char mix_msg_in[] = { 548c2ecf20Sopenharmony_ci /* default message head, equal to all mixers */ 558c2ecf20Sopenharmony_ci 0x61, 0x02, 0x04, 0x62, 0x02, 0x01, 568c2ecf20Sopenharmony_ci 0x81, /* 0x06: Controller ID */ 578c2ecf20Sopenharmony_ci 0x02, /* 0x07: */ 588c2ecf20Sopenharmony_ci 0x00, /* 0x08: Value of common mixer */ 598c2ecf20Sopenharmony_ci 0x00, 608c2ecf20Sopenharmony_ci 0x00 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic const char mix_msg_out[] = { 648c2ecf20Sopenharmony_ci /* default message head, equal to all mixers */ 658c2ecf20Sopenharmony_ci 0x61, 0x02, 0x02, 0x62, 0x02, 0x01, 668c2ecf20Sopenharmony_ci 0x81, /* 0x06: Controller ID */ 678c2ecf20Sopenharmony_ci 0x02, /* 0x07: */ 688c2ecf20Sopenharmony_ci 0x00, /* 0x08: Value of common mixer */ 698c2ecf20Sopenharmony_ci 0x00, 708c2ecf20Sopenharmony_ci 0x00 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const char bypass_msg_out[] = { 748c2ecf20Sopenharmony_ci 0x45, 758c2ecf20Sopenharmony_ci 0x02, 768c2ecf20Sopenharmony_ci 0x01, /* on/off flag */ 778c2ecf20Sopenharmony_ci 0x00, 788c2ecf20Sopenharmony_ci 0x00 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic const char bus_msg_out[] = { 828c2ecf20Sopenharmony_ci 0x44, 838c2ecf20Sopenharmony_ci 0x02, 848c2ecf20Sopenharmony_ci 0x01, /* on/off flag */ 858c2ecf20Sopenharmony_ci 0x00, 868c2ecf20Sopenharmony_ci 0x00 878c2ecf20Sopenharmony_ci}; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic const char comp_msg[] = { 908c2ecf20Sopenharmony_ci /* default message head, equal to all mixers */ 918c2ecf20Sopenharmony_ci 0x61, 0x02, 0x04, 0x62, 0x02, 0x01, 928c2ecf20Sopenharmony_ci 0x91, 938c2ecf20Sopenharmony_ci 0x02, 948c2ecf20Sopenharmony_ci 0xf0, /* 0x08: Threshold db (8) (e0 ... 00) (+-0dB -- -32dB) x-32 */ 958c2ecf20Sopenharmony_ci 0x92, 968c2ecf20Sopenharmony_ci 0x02, 978c2ecf20Sopenharmony_ci 0x0a, /* 0x0b: Ratio (0a,0b,0d,0f,11,14,19,1e,23,28,32,3c,50,a0,ff) */ 988c2ecf20Sopenharmony_ci 0x93, 998c2ecf20Sopenharmony_ci 0x02, 1008c2ecf20Sopenharmony_ci 0x02, /* 0x0e: Attack (0x02 ... 0xc0) (2ms ... 200ms) */ 1018c2ecf20Sopenharmony_ci 0x94, 1028c2ecf20Sopenharmony_ci 0x02, 1038c2ecf20Sopenharmony_ci 0x01, /* 0x11: Release (0x01 ... 0x64) (10ms ... 1000ms) x*10 */ 1048c2ecf20Sopenharmony_ci 0x95, 1058c2ecf20Sopenharmony_ci 0x02, 1068c2ecf20Sopenharmony_ci 0x03, /* 0x14: gain (0 ... 20) (0dB .. 20dB) */ 1078c2ecf20Sopenharmony_ci 0x96, 1088c2ecf20Sopenharmony_ci 0x02, 1098c2ecf20Sopenharmony_ci 0x01, 1108c2ecf20Sopenharmony_ci 0x97, 1118c2ecf20Sopenharmony_ci 0x02, 1128c2ecf20Sopenharmony_ci 0x01, /* 0x1a: main Comp switch (0 ... 1) (off ... on)) */ 1138c2ecf20Sopenharmony_ci 0x00, 1148c2ecf20Sopenharmony_ci 0x00 1158c2ecf20Sopenharmony_ci}; 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_cistatic const char eqs_msq[] = { 1188c2ecf20Sopenharmony_ci /* default message head, equal to all mixers */ 1198c2ecf20Sopenharmony_ci 0x61, 0x02, 0x04, 0x62, 0x02, 0x01, 1208c2ecf20Sopenharmony_ci 0x51, /* 0x06: Controller ID */ 1218c2ecf20Sopenharmony_ci 0x02, 1228c2ecf20Sopenharmony_ci 0x04, /* 0x08: EQ set num (0x01..0x04) (LOW, LOWMID, HIGHMID, HIGH)) */ 1238c2ecf20Sopenharmony_ci 0x52, 1248c2ecf20Sopenharmony_ci 0x02, 1258c2ecf20Sopenharmony_ci 0x0c, /* 0x0b: value dB (0 ... 12) (-12db .. +12db) x-6 */ 1268c2ecf20Sopenharmony_ci 0x53, 1278c2ecf20Sopenharmony_ci 0x02, 1288c2ecf20Sopenharmony_ci 0x0f, /* 0x0e: value freq (32-47) (1.7kHz..18kHz) */ 1298c2ecf20Sopenharmony_ci 0x54, 1308c2ecf20Sopenharmony_ci 0x02, 1318c2ecf20Sopenharmony_ci 0x02, /* 0x11: band width (0-6) (Q16-Q0.25) 2^x/4 (EQ xxMID only) */ 1328c2ecf20Sopenharmony_ci 0x55, 1338c2ecf20Sopenharmony_ci 0x02, 1348c2ecf20Sopenharmony_ci 0x01, /* 0x14: main EQ switch (0 ... 1) (off ... on)) */ 1358c2ecf20Sopenharmony_ci 0x00, 1368c2ecf20Sopenharmony_ci 0x00 1378c2ecf20Sopenharmony_ci}; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* compressor ratio map */ 1408c2ecf20Sopenharmony_cistatic const char ratio_map[] = { 1418c2ecf20Sopenharmony_ci 0x0a, 0x0b, 0x0d, 0x0f, 0x11, 0x14, 0x19, 0x1e, 1428c2ecf20Sopenharmony_ci 0x23, 0x28, 0x32, 0x3c, 0x50, 0xa0, 0xff 1438c2ecf20Sopenharmony_ci}; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci/* route enumeration names */ 1468c2ecf20Sopenharmony_cistatic const char *const route_names[] = { 1478c2ecf20Sopenharmony_ci "Master Left", "Master Right", "Output 1", "Output 2", "Output 3", 1488c2ecf20Sopenharmony_ci "Output 4", "Output 5", "Output 6", "Output 7", "Output 8", 1498c2ecf20Sopenharmony_ci}; 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic int snd_us16x08_recv_urb(struct snd_usb_audio *chip, 1528c2ecf20Sopenharmony_ci unsigned char *buf, int size) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci mutex_lock(&chip->mutex); 1568c2ecf20Sopenharmony_ci snd_usb_ctl_msg(chip->dev, 1578c2ecf20Sopenharmony_ci usb_rcvctrlpipe(chip->dev, 0), 1588c2ecf20Sopenharmony_ci SND_US16X08_URB_METER_REQUEST, 1598c2ecf20Sopenharmony_ci SND_US16X08_URB_METER_REQUESTTYPE, 0, 0, buf, size); 1608c2ecf20Sopenharmony_ci mutex_unlock(&chip->mutex); 1618c2ecf20Sopenharmony_ci return 0; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/* wrapper function to send prepared URB buffer to usb device. Return an error 1658c2ecf20Sopenharmony_ci * code if something went wrong 1668c2ecf20Sopenharmony_ci */ 1678c2ecf20Sopenharmony_cistatic int snd_us16x08_send_urb(struct snd_usb_audio *chip, char *buf, int size) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci return snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 1708c2ecf20Sopenharmony_ci SND_US16X08_URB_REQUEST, SND_US16X08_URB_REQUESTTYPE, 1718c2ecf20Sopenharmony_ci 0, 0, buf, size); 1728c2ecf20Sopenharmony_ci} 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_cistatic int snd_us16x08_route_info(struct snd_kcontrol *kcontrol, 1758c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 1768c2ecf20Sopenharmony_ci{ 1778c2ecf20Sopenharmony_ci return snd_ctl_enum_info(uinfo, 1, 10, route_names); 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_cistatic int snd_us16x08_route_get(struct snd_kcontrol *kcontrol, 1818c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 1848c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* route has no bias */ 1878c2ecf20Sopenharmony_ci ucontrol->value.enumerated.item[0] = elem->cache_val[index]; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int snd_us16x08_route_put(struct snd_kcontrol *kcontrol, 1938c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 1968c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 1978c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 1988c2ecf20Sopenharmony_ci char buf[sizeof(route_msg)]; 1998c2ecf20Sopenharmony_ci int val, val_org, err; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* get the new value (no bias for routes) */ 2028c2ecf20Sopenharmony_ci val = ucontrol->value.enumerated.item[0]; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* sanity check */ 2058c2ecf20Sopenharmony_ci if (val < 0 || val > 9) 2068c2ecf20Sopenharmony_ci return -EINVAL; 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* prepare the message buffer from template */ 2098c2ecf20Sopenharmony_ci memcpy(buf, route_msg, sizeof(route_msg)); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (val < 2) { 2128c2ecf20Sopenharmony_ci /* input comes from a master channel */ 2138c2ecf20Sopenharmony_ci val_org = val; 2148c2ecf20Sopenharmony_ci buf[2] = 0x02; 2158c2ecf20Sopenharmony_ci } else { 2168c2ecf20Sopenharmony_ci /* input comes from a computer channel */ 2178c2ecf20Sopenharmony_ci buf[2] = 0x03; 2188c2ecf20Sopenharmony_ci val_org = val - 2; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci /* place new route selection in URB message */ 2228c2ecf20Sopenharmony_ci buf[5] = (unsigned char) (val_org & 0x0f) + 1; 2238c2ecf20Sopenharmony_ci /* place route selector in URB message */ 2248c2ecf20Sopenharmony_ci buf[13] = index + 1; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(route_msg)); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci if (err > 0) { 2298c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 2308c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 2318c2ecf20Sopenharmony_ci } else { 2328c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set routing, err:%d\n", err); 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci return err > 0 ? 1 : 0; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int snd_us16x08_master_info(struct snd_kcontrol *kcontrol, 2398c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci uinfo->count = 1; 2428c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 2438c2ecf20Sopenharmony_ci uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol); 2448c2ecf20Sopenharmony_ci uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol); 2458c2ecf20Sopenharmony_ci uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol); 2468c2ecf20Sopenharmony_ci return 0; 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int snd_us16x08_master_get(struct snd_kcontrol *kcontrol, 2508c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 2538c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = elem->cache_val[index]; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int snd_us16x08_master_put(struct snd_kcontrol *kcontrol, 2618c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 2648c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 2658c2ecf20Sopenharmony_ci char buf[sizeof(mix_msg_out)]; 2668c2ecf20Sopenharmony_ci int val, err; 2678c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci /* new control value incl. bias*/ 2708c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* sanity check */ 2738c2ecf20Sopenharmony_ci if (val < SND_US16X08_KCMIN(kcontrol) 2748c2ecf20Sopenharmony_ci || val > SND_US16X08_KCMAX(kcontrol)) 2758c2ecf20Sopenharmony_ci return -EINVAL; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* prepare the message buffer from template */ 2788c2ecf20Sopenharmony_ci memcpy(buf, mix_msg_out, sizeof(mix_msg_out)); 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci buf[8] = val - SND_US16X08_KCBIAS(kcontrol); 2818c2ecf20Sopenharmony_ci buf[6] = elem->head.id; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci /* place channel selector in URB message */ 2848c2ecf20Sopenharmony_ci buf[5] = index + 1; 2858c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out)); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (err > 0) { 2888c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 2898c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 2908c2ecf20Sopenharmony_ci } else { 2918c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set master, err:%d\n", err); 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return err > 0 ? 1 : 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int snd_us16x08_bus_put(struct snd_kcontrol *kcontrol, 2988c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 3018c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 3028c2ecf20Sopenharmony_ci char buf[sizeof(mix_msg_out)]; 3038c2ecf20Sopenharmony_ci int val, err = 0; 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* prepare the message buffer from template */ 3088c2ecf20Sopenharmony_ci switch (elem->head.id) { 3098c2ecf20Sopenharmony_ci case SND_US16X08_ID_BYPASS: 3108c2ecf20Sopenharmony_ci memcpy(buf, bypass_msg_out, sizeof(bypass_msg_out)); 3118c2ecf20Sopenharmony_ci buf[2] = val; 3128c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(bypass_msg_out)); 3138c2ecf20Sopenharmony_ci break; 3148c2ecf20Sopenharmony_ci case SND_US16X08_ID_BUSS_OUT: 3158c2ecf20Sopenharmony_ci memcpy(buf, bus_msg_out, sizeof(bus_msg_out)); 3168c2ecf20Sopenharmony_ci buf[2] = val; 3178c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(bus_msg_out)); 3188c2ecf20Sopenharmony_ci break; 3198c2ecf20Sopenharmony_ci case SND_US16X08_ID_MUTE: 3208c2ecf20Sopenharmony_ci memcpy(buf, mix_msg_out, sizeof(mix_msg_out)); 3218c2ecf20Sopenharmony_ci buf[8] = val; 3228c2ecf20Sopenharmony_ci buf[6] = elem->head.id; 3238c2ecf20Sopenharmony_ci buf[5] = 1; 3248c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_out)); 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci if (err > 0) { 3298c2ecf20Sopenharmony_ci elem->cached |= 1; 3308c2ecf20Sopenharmony_ci elem->cache_val[0] = val; 3318c2ecf20Sopenharmony_ci } else { 3328c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set bus parameter, err:%d\n", err); 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci return err > 0 ? 1 : 0; 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_cistatic int snd_us16x08_bus_get(struct snd_kcontrol *kcontrol, 3398c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3408c2ecf20Sopenharmony_ci{ 3418c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci switch (elem->head.id) { 3448c2ecf20Sopenharmony_ci case SND_US16X08_ID_BUSS_OUT: 3458c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = elem->cache_val[0]; 3468c2ecf20Sopenharmony_ci break; 3478c2ecf20Sopenharmony_ci case SND_US16X08_ID_BYPASS: 3488c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = elem->cache_val[0]; 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci case SND_US16X08_ID_MUTE: 3518c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = elem->cache_val[0]; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 0; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci/* gets a current mixer value from common store */ 3598c2ecf20Sopenharmony_cistatic int snd_us16x08_channel_get(struct snd_kcontrol *kcontrol, 3608c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 3638c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = elem->cache_val[index]; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return 0; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int snd_us16x08_channel_put(struct snd_kcontrol *kcontrol, 3718c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 3748c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 3758c2ecf20Sopenharmony_ci char buf[sizeof(mix_msg_in)]; 3768c2ecf20Sopenharmony_ci int val, err; 3778c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci /* sanity check */ 3828c2ecf20Sopenharmony_ci if (val < SND_US16X08_KCMIN(kcontrol) 3838c2ecf20Sopenharmony_ci || val > SND_US16X08_KCMAX(kcontrol)) 3848c2ecf20Sopenharmony_ci return -EINVAL; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci /* prepare URB message from template */ 3878c2ecf20Sopenharmony_ci memcpy(buf, mix_msg_in, sizeof(mix_msg_in)); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* add the bias to the new value */ 3908c2ecf20Sopenharmony_ci buf[8] = val - SND_US16X08_KCBIAS(kcontrol); 3918c2ecf20Sopenharmony_ci buf[6] = elem->head.id; 3928c2ecf20Sopenharmony_ci buf[5] = index + 1; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(mix_msg_in)); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (err > 0) { 3978c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 3988c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 3998c2ecf20Sopenharmony_ci } else { 4008c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set channel, err:%d\n", err); 4018c2ecf20Sopenharmony_ci } 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci return err > 0 ? 1 : 0; 4048c2ecf20Sopenharmony_ci} 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_cistatic int snd_us16x08_mix_info(struct snd_kcontrol *kcontrol, 4078c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci uinfo->count = 1; 4108c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4118c2ecf20Sopenharmony_ci uinfo->value.integer.max = SND_US16X08_KCMAX(kcontrol); 4128c2ecf20Sopenharmony_ci uinfo->value.integer.min = SND_US16X08_KCMIN(kcontrol); 4138c2ecf20Sopenharmony_ci uinfo->value.integer.step = SND_US16X08_KCSTEP(kcontrol); 4148c2ecf20Sopenharmony_ci return 0; 4158c2ecf20Sopenharmony_ci} 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_cistatic int snd_us16x08_comp_get(struct snd_kcontrol *kcontrol, 4188c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 4218c2ecf20Sopenharmony_ci struct snd_us16x08_comp_store *store = elem->private_data; 4228c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 4238c2ecf20Sopenharmony_ci int val_idx = COMP_STORE_IDX(elem->head.id); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = store->val[val_idx][index]; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int snd_us16x08_comp_put(struct snd_kcontrol *kcontrol, 4318c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 4348c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 4358c2ecf20Sopenharmony_ci struct snd_us16x08_comp_store *store = elem->private_data; 4368c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 4378c2ecf20Sopenharmony_ci char buf[sizeof(comp_msg)]; 4388c2ecf20Sopenharmony_ci int val_idx, val; 4398c2ecf20Sopenharmony_ci int err; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* sanity check */ 4448c2ecf20Sopenharmony_ci if (val < SND_US16X08_KCMIN(kcontrol) 4458c2ecf20Sopenharmony_ci || val > SND_US16X08_KCMAX(kcontrol)) 4468c2ecf20Sopenharmony_ci return -EINVAL; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci /* new control value incl. bias*/ 4498c2ecf20Sopenharmony_ci val_idx = elem->head.id - SND_US16X08_ID_COMP_BASE; 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci store->val[val_idx][index] = ucontrol->value.integer.value[0]; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci /* prepare compressor URB message from template */ 4548c2ecf20Sopenharmony_ci memcpy(buf, comp_msg, sizeof(comp_msg)); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* place comp values in message buffer watch bias! */ 4578c2ecf20Sopenharmony_ci buf[8] = store->val[ 4588c2ecf20Sopenharmony_ci COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][index] 4598c2ecf20Sopenharmony_ci - SND_US16X08_COMP_THRESHOLD_BIAS; 4608c2ecf20Sopenharmony_ci buf[11] = ratio_map[store->val[ 4618c2ecf20Sopenharmony_ci COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][index]]; 4628c2ecf20Sopenharmony_ci buf[14] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][index] 4638c2ecf20Sopenharmony_ci + SND_US16X08_COMP_ATTACK_BIAS; 4648c2ecf20Sopenharmony_ci buf[17] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][index] 4658c2ecf20Sopenharmony_ci + SND_US16X08_COMP_RELEASE_BIAS; 4668c2ecf20Sopenharmony_ci buf[20] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][index]; 4678c2ecf20Sopenharmony_ci buf[26] = store->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][index]; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* place channel selector in message buffer */ 4708c2ecf20Sopenharmony_ci buf[5] = index + 1; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(comp_msg)); 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci if (err > 0) { 4758c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 4768c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 4778c2ecf20Sopenharmony_ci } else { 4788c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set compressor, err:%d\n", err); 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci return 1; 4828c2ecf20Sopenharmony_ci} 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_cistatic int snd_us16x08_eqswitch_get(struct snd_kcontrol *kcontrol, 4858c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 4868c2ecf20Sopenharmony_ci{ 4878c2ecf20Sopenharmony_ci int val; 4888c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 4898c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *store = elem->private_data; 4908c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci /* get low switch from cache is enough, cause all bands are together */ 4938c2ecf20Sopenharmony_ci val = store->val[EQ_STORE_BAND_IDX(elem->head.id)] 4948c2ecf20Sopenharmony_ci [EQ_STORE_PARAM_IDX(elem->head.id)][index]; 4958c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = val; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_cistatic int snd_us16x08_eqswitch_put(struct snd_kcontrol *kcontrol, 5018c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 5048c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 5058c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *store = elem->private_data; 5068c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 5078c2ecf20Sopenharmony_ci char buf[sizeof(eqs_msq)]; 5088c2ecf20Sopenharmony_ci int val, err = 0; 5098c2ecf20Sopenharmony_ci int b_idx; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* new control value incl. bias*/ 5128c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0] + SND_US16X08_KCBIAS(kcontrol); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci /* prepare URB message from EQ template */ 5158c2ecf20Sopenharmony_ci memcpy(buf, eqs_msq, sizeof(eqs_msq)); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* place channel index in URB message */ 5188c2ecf20Sopenharmony_ci buf[5] = index + 1; 5198c2ecf20Sopenharmony_ci for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) { 5208c2ecf20Sopenharmony_ci /* all four EQ bands have to be enabled/disabled in once */ 5218c2ecf20Sopenharmony_ci buf[20] = val; 5228c2ecf20Sopenharmony_ci buf[17] = store->val[b_idx][2][index]; 5238c2ecf20Sopenharmony_ci buf[14] = store->val[b_idx][1][index]; 5248c2ecf20Sopenharmony_ci buf[11] = store->val[b_idx][0][index]; 5258c2ecf20Sopenharmony_ci buf[8] = b_idx + 1; 5268c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq)); 5278c2ecf20Sopenharmony_ci if (err < 0) 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci store->val[b_idx][3][index] = val; 5308c2ecf20Sopenharmony_ci msleep(15); 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci if (err > 0) { 5348c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 5358c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 5368c2ecf20Sopenharmony_ci } else { 5378c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set eq switch, err:%d\n", err); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci return 1; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_cistatic int snd_us16x08_eq_get(struct snd_kcontrol *kcontrol, 5448c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci int val; 5478c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 5488c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *store = elem->private_data; 5498c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 5508c2ecf20Sopenharmony_ci int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1; 5518c2ecf20Sopenharmony_ci int p_idx = EQ_STORE_PARAM_IDX(elem->head.id); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci val = store->val[b_idx][p_idx][index]; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = val; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int snd_us16x08_eq_put(struct snd_kcontrol *kcontrol, 5618c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 5648c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 5658c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *store = elem->private_data; 5668c2ecf20Sopenharmony_ci int index = ucontrol->id.index; 5678c2ecf20Sopenharmony_ci char buf[sizeof(eqs_msq)]; 5688c2ecf20Sopenharmony_ci int val, err; 5698c2ecf20Sopenharmony_ci int b_idx = EQ_STORE_BAND_IDX(elem->head.id) - 1; 5708c2ecf20Sopenharmony_ci int p_idx = EQ_STORE_PARAM_IDX(elem->head.id); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci /* sanity check */ 5758c2ecf20Sopenharmony_ci if (val < SND_US16X08_KCMIN(kcontrol) 5768c2ecf20Sopenharmony_ci || val > SND_US16X08_KCMAX(kcontrol)) 5778c2ecf20Sopenharmony_ci return -EINVAL; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /* copy URB buffer from EQ template */ 5808c2ecf20Sopenharmony_ci memcpy(buf, eqs_msq, sizeof(eqs_msq)); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci store->val[b_idx][p_idx][index] = val; 5838c2ecf20Sopenharmony_ci buf[20] = store->val[b_idx][3][index]; 5848c2ecf20Sopenharmony_ci buf[17] = store->val[b_idx][2][index]; 5858c2ecf20Sopenharmony_ci buf[14] = store->val[b_idx][1][index]; 5868c2ecf20Sopenharmony_ci buf[11] = store->val[b_idx][0][index]; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* place channel index in URB buffer */ 5898c2ecf20Sopenharmony_ci buf[5] = index + 1; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* place EQ band in URB buffer */ 5928c2ecf20Sopenharmony_ci buf[8] = b_idx + 1; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci err = snd_us16x08_send_urb(chip, buf, sizeof(eqs_msq)); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci if (err > 0) { 5978c2ecf20Sopenharmony_ci /* store new value in EQ band cache */ 5988c2ecf20Sopenharmony_ci elem->cached |= 1 << index; 5998c2ecf20Sopenharmony_ci elem->cache_val[index] = val; 6008c2ecf20Sopenharmony_ci } else { 6018c2ecf20Sopenharmony_ci usb_audio_dbg(chip, "Failed to set eq param, err:%d\n", err); 6028c2ecf20Sopenharmony_ci } 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return 1; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_info(struct snd_kcontrol *kcontrol, 6088c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci uinfo->count = 34; 6118c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 6128c2ecf20Sopenharmony_ci uinfo->value.integer.max = 0x7FFF; 6138c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci/* calculate compressor index for reduction level request */ 6198c2ecf20Sopenharmony_cistatic int snd_get_meter_comp_index(struct snd_us16x08_meter_store *store) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci int ret; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci /* any channel active */ 6248c2ecf20Sopenharmony_ci if (store->comp_active_index) { 6258c2ecf20Sopenharmony_ci /* check for stereo link */ 6268c2ecf20Sopenharmony_ci if (store->comp_active_index & 0x20) { 6278c2ecf20Sopenharmony_ci /* reset comp_index to left channel*/ 6288c2ecf20Sopenharmony_ci if (store->comp_index - 6298c2ecf20Sopenharmony_ci store->comp_active_index > 1) 6308c2ecf20Sopenharmony_ci store->comp_index = 6318c2ecf20Sopenharmony_ci store->comp_active_index; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci ret = store->comp_index++ & 0x1F; 6348c2ecf20Sopenharmony_ci } else { 6358c2ecf20Sopenharmony_ci /* no stereo link */ 6368c2ecf20Sopenharmony_ci ret = store->comp_active_index; 6378c2ecf20Sopenharmony_ci } 6388c2ecf20Sopenharmony_ci } else { 6398c2ecf20Sopenharmony_ci /* skip channels with no compressor active */ 6408c2ecf20Sopenharmony_ci while (!store->comp_store->val[ 6418c2ecf20Sopenharmony_ci COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)] 6428c2ecf20Sopenharmony_ci [store->comp_index - 1] 6438c2ecf20Sopenharmony_ci && store->comp_index <= SND_US16X08_MAX_CHANNELS) { 6448c2ecf20Sopenharmony_ci store->comp_index++; 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci ret = store->comp_index++; 6478c2ecf20Sopenharmony_ci if (store->comp_index > SND_US16X08_MAX_CHANNELS) 6488c2ecf20Sopenharmony_ci store->comp_index = 1; 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci return ret; 6518c2ecf20Sopenharmony_ci} 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci/* retrieve the meter level values from URB message */ 6548c2ecf20Sopenharmony_cistatic void get_meter_levels_from_urb(int s, 6558c2ecf20Sopenharmony_ci struct snd_us16x08_meter_store *store, 6568c2ecf20Sopenharmony_ci u8 *meter_urb) 6578c2ecf20Sopenharmony_ci{ 6588c2ecf20Sopenharmony_ci int val = MUC2(meter_urb, s) + (MUC3(meter_urb, s) << 8); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && 6618c2ecf20Sopenharmony_ci MUA2(meter_urb, s) == 0x04 && MUB0(meter_urb, s) == 0x62) { 6628c2ecf20Sopenharmony_ci if (MUC0(meter_urb, s) == 0x72) 6638c2ecf20Sopenharmony_ci store->meter_level[MUB2(meter_urb, s) - 1] = val; 6648c2ecf20Sopenharmony_ci if (MUC0(meter_urb, s) == 0xb2) 6658c2ecf20Sopenharmony_ci store->comp_level[MUB2(meter_urb, s) - 1] = val; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci if (MUA0(meter_urb, s) == 0x61 && MUA1(meter_urb, s) == 0x02 && 6688c2ecf20Sopenharmony_ci MUA2(meter_urb, s) == 0x02 && MUB0(meter_urb, s) == 0x62) 6698c2ecf20Sopenharmony_ci store->master_level[MUB2(meter_urb, s) - 1] = val; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci/* Function to retrieve current meter values from the device. 6738c2ecf20Sopenharmony_ci * 6748c2ecf20Sopenharmony_ci * The device needs to be polled for meter values with an initial 6758c2ecf20Sopenharmony_ci * requests. It will return with a sequence of different meter value 6768c2ecf20Sopenharmony_ci * packages. The first request (case 0:) initiate this meter response sequence. 6778c2ecf20Sopenharmony_ci * After the third response, an additional request can be placed, 6788c2ecf20Sopenharmony_ci * to retrieve compressor reduction level value for given channel. This round 6798c2ecf20Sopenharmony_ci * trip channel selector will skip all inactive compressors. 6808c2ecf20Sopenharmony_ci * A mixer can interrupt this round-trip by selecting one ore two (stereo-link) 6818c2ecf20Sopenharmony_ci * specific channels. 6828c2ecf20Sopenharmony_ci */ 6838c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_get(struct snd_kcontrol *kcontrol, 6848c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci int i, set; 6878c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 6888c2ecf20Sopenharmony_ci struct snd_usb_audio *chip = elem->head.mixer->chip; 6898c2ecf20Sopenharmony_ci struct snd_us16x08_meter_store *store = elem->private_data; 6908c2ecf20Sopenharmony_ci u8 meter_urb[64]; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci switch (kcontrol->private_value) { 6938c2ecf20Sopenharmony_ci case 0: { 6948c2ecf20Sopenharmony_ci char tmp[sizeof(mix_init_msg1)]; 6958c2ecf20Sopenharmony_ci 6968c2ecf20Sopenharmony_ci memcpy(tmp, mix_init_msg1, sizeof(mix_init_msg1)); 6978c2ecf20Sopenharmony_ci snd_us16x08_send_urb(chip, tmp, 4); 6988c2ecf20Sopenharmony_ci snd_us16x08_recv_urb(chip, meter_urb, 6998c2ecf20Sopenharmony_ci sizeof(meter_urb)); 7008c2ecf20Sopenharmony_ci kcontrol->private_value++; 7018c2ecf20Sopenharmony_ci break; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci case 1: 7048c2ecf20Sopenharmony_ci snd_us16x08_recv_urb(chip, meter_urb, 7058c2ecf20Sopenharmony_ci sizeof(meter_urb)); 7068c2ecf20Sopenharmony_ci kcontrol->private_value++; 7078c2ecf20Sopenharmony_ci break; 7088c2ecf20Sopenharmony_ci case 2: 7098c2ecf20Sopenharmony_ci snd_us16x08_recv_urb(chip, meter_urb, 7108c2ecf20Sopenharmony_ci sizeof(meter_urb)); 7118c2ecf20Sopenharmony_ci kcontrol->private_value++; 7128c2ecf20Sopenharmony_ci break; 7138c2ecf20Sopenharmony_ci case 3: { 7148c2ecf20Sopenharmony_ci char tmp[sizeof(mix_init_msg2)]; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci memcpy(tmp, mix_init_msg2, sizeof(mix_init_msg2)); 7178c2ecf20Sopenharmony_ci tmp[2] = snd_get_meter_comp_index(store); 7188c2ecf20Sopenharmony_ci snd_us16x08_send_urb(chip, tmp, 10); 7198c2ecf20Sopenharmony_ci snd_us16x08_recv_urb(chip, meter_urb, 7208c2ecf20Sopenharmony_ci sizeof(meter_urb)); 7218c2ecf20Sopenharmony_ci kcontrol->private_value = 0; 7228c2ecf20Sopenharmony_ci break; 7238c2ecf20Sopenharmony_ci } 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci for (set = 0; set < 6; set++) 7278c2ecf20Sopenharmony_ci get_meter_levels_from_urb(set, store, meter_urb); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) { 7308c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i] = 7318c2ecf20Sopenharmony_ci store ? store->meter_level[i] : 0; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i++] = store ? store->master_level[0] : 0; 7358c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i++] = store ? store->master_level[1] : 0; 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci for (i = 2; i < SND_US16X08_MAX_CHANNELS + 2; i++) 7388c2ecf20Sopenharmony_ci ucontrol->value.integer.value[i + SND_US16X08_MAX_CHANNELS] = 7398c2ecf20Sopenharmony_ci store ? store->comp_level[i - 2] : 0; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci return 1; 7428c2ecf20Sopenharmony_ci} 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_cistatic int snd_us16x08_meter_put(struct snd_kcontrol *kcontrol, 7458c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kcontrol->private_data; 7488c2ecf20Sopenharmony_ci struct snd_us16x08_meter_store *store = elem->private_data; 7498c2ecf20Sopenharmony_ci int val; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci val = ucontrol->value.integer.value[0]; 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_ci /* sanity check */ 7548c2ecf20Sopenharmony_ci if (val < 0 || val >= SND_US16X08_MAX_CHANNELS) 7558c2ecf20Sopenharmony_ci return -EINVAL; 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci store->comp_active_index = val; 7588c2ecf20Sopenharmony_ci store->comp_index = val; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return 1; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_ch_boolean_ctl = { 7648c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7658c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 7668c2ecf20Sopenharmony_ci .count = 16, 7678c2ecf20Sopenharmony_ci .info = snd_us16x08_switch_info, 7688c2ecf20Sopenharmony_ci .get = snd_us16x08_channel_get, 7698c2ecf20Sopenharmony_ci .put = snd_us16x08_channel_put, 7708c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1) 7718c2ecf20Sopenharmony_ci}; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_ch_int_ctl = { 7748c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7758c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 7768c2ecf20Sopenharmony_ci .count = 16, 7778c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 7788c2ecf20Sopenharmony_ci .get = snd_us16x08_channel_get, 7798c2ecf20Sopenharmony_ci .put = snd_us16x08_channel_put, 7808c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133) 7818c2ecf20Sopenharmony_ci}; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_pan_int_ctl = { 7848c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7858c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 7868c2ecf20Sopenharmony_ci .count = 16, 7878c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 7888c2ecf20Sopenharmony_ci .get = snd_us16x08_channel_get, 7898c2ecf20Sopenharmony_ci .put = snd_us16x08_channel_put, 7908c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 255) 7918c2ecf20Sopenharmony_ci}; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_master_ctl = { 7948c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 7958c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 7968c2ecf20Sopenharmony_ci .count = 1, 7978c2ecf20Sopenharmony_ci .info = snd_us16x08_master_info, 7988c2ecf20Sopenharmony_ci .get = snd_us16x08_master_get, 7998c2ecf20Sopenharmony_ci .put = snd_us16x08_master_put, 8008c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_FADER_BIAS, 1, 0, 133) 8018c2ecf20Sopenharmony_ci}; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_route_ctl = { 8048c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8058c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8068c2ecf20Sopenharmony_ci .count = 8, 8078c2ecf20Sopenharmony_ci .info = snd_us16x08_route_info, 8088c2ecf20Sopenharmony_ci .get = snd_us16x08_route_get, 8098c2ecf20Sopenharmony_ci .put = snd_us16x08_route_put, 8108c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 9) 8118c2ecf20Sopenharmony_ci}; 8128c2ecf20Sopenharmony_ci 8138c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_bus_ctl = { 8148c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8158c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8168c2ecf20Sopenharmony_ci .count = 1, 8178c2ecf20Sopenharmony_ci .info = snd_us16x08_switch_info, 8188c2ecf20Sopenharmony_ci .get = snd_us16x08_bus_get, 8198c2ecf20Sopenharmony_ci .put = snd_us16x08_bus_put, 8208c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1) 8218c2ecf20Sopenharmony_ci}; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_compswitch_ctl = { 8248c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8258c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8268c2ecf20Sopenharmony_ci .count = 16, 8278c2ecf20Sopenharmony_ci .info = snd_us16x08_switch_info, 8288c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8298c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8308c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1) 8318c2ecf20Sopenharmony_ci}; 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_threshold_ctl = { 8348c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8358c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8368c2ecf20Sopenharmony_ci .count = 16, 8378c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8388c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8398c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8408c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_COMP_THRESHOLD_BIAS, 1, 8418c2ecf20Sopenharmony_ci 0, 0x20) 8428c2ecf20Sopenharmony_ci}; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_ratio_ctl = { 8458c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8468c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8478c2ecf20Sopenharmony_ci .count = 16, 8488c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8498c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8508c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8518c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 8528c2ecf20Sopenharmony_ci sizeof(ratio_map) - 1), /*max*/ 8538c2ecf20Sopenharmony_ci}; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_gain_ctl = { 8568c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8578c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8588c2ecf20Sopenharmony_ci .count = 16, 8598c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8608c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8618c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8628c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x14) 8638c2ecf20Sopenharmony_ci}; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_attack_ctl = { 8668c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8678c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8688c2ecf20Sopenharmony_ci .count = 16, 8698c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8708c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8718c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8728c2ecf20Sopenharmony_ci .private_value = 8738c2ecf20Sopenharmony_ci SND_US16X08_KCSET(SND_US16X08_COMP_ATTACK_BIAS, 1, 0, 0xc6), 8748c2ecf20Sopenharmony_ci}; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_comp_release_ctl = { 8778c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8788c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8798c2ecf20Sopenharmony_ci .count = 16, 8808c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8818c2ecf20Sopenharmony_ci .get = snd_us16x08_comp_get, 8828c2ecf20Sopenharmony_ci .put = snd_us16x08_comp_put, 8838c2ecf20Sopenharmony_ci .private_value = 8848c2ecf20Sopenharmony_ci SND_US16X08_KCSET(SND_US16X08_COMP_RELEASE_BIAS, 1, 0, 0x63), 8858c2ecf20Sopenharmony_ci}; 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_gain_ctl = { 8888c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8898c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 8908c2ecf20Sopenharmony_ci .count = 16, 8918c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 8928c2ecf20Sopenharmony_ci .get = snd_us16x08_eq_get, 8938c2ecf20Sopenharmony_ci .put = snd_us16x08_eq_put, 8948c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 24), 8958c2ecf20Sopenharmony_ci}; 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_low_freq_ctl = { 8988c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 8998c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9008c2ecf20Sopenharmony_ci .count = 16, 9018c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 9028c2ecf20Sopenharmony_ci .get = snd_us16x08_eq_get, 9038c2ecf20Sopenharmony_ci .put = snd_us16x08_eq_put, 9048c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x1F), 9058c2ecf20Sopenharmony_ci}; 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_mid_freq_ctl = { 9088c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9098c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9108c2ecf20Sopenharmony_ci .count = 16, 9118c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 9128c2ecf20Sopenharmony_ci .get = snd_us16x08_eq_get, 9138c2ecf20Sopenharmony_ci .put = snd_us16x08_eq_put, 9148c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x3F) 9158c2ecf20Sopenharmony_ci}; 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_mid_width_ctl = { 9188c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9198c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9208c2ecf20Sopenharmony_ci .count = 16, 9218c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 9228c2ecf20Sopenharmony_ci .get = snd_us16x08_eq_get, 9238c2ecf20Sopenharmony_ci .put = snd_us16x08_eq_put, 9248c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 0x06) 9258c2ecf20Sopenharmony_ci}; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_high_freq_ctl = { 9288c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9298c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9308c2ecf20Sopenharmony_ci .count = 16, 9318c2ecf20Sopenharmony_ci .info = snd_us16x08_mix_info, 9328c2ecf20Sopenharmony_ci .get = snd_us16x08_eq_get, 9338c2ecf20Sopenharmony_ci .put = snd_us16x08_eq_put, 9348c2ecf20Sopenharmony_ci .private_value = 9358c2ecf20Sopenharmony_ci SND_US16X08_KCSET(SND_US16X08_EQ_HIGHFREQ_BIAS, 1, 0, 0x1F) 9368c2ecf20Sopenharmony_ci}; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_eq_switch_ctl = { 9398c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9408c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9418c2ecf20Sopenharmony_ci .count = 16, 9428c2ecf20Sopenharmony_ci .info = snd_us16x08_switch_info, 9438c2ecf20Sopenharmony_ci .get = snd_us16x08_eqswitch_get, 9448c2ecf20Sopenharmony_ci .put = snd_us16x08_eqswitch_put, 9458c2ecf20Sopenharmony_ci .private_value = SND_US16X08_KCSET(SND_US16X08_NO_BIAS, 1, 0, 1) 9468c2ecf20Sopenharmony_ci}; 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_cistatic const struct snd_kcontrol_new snd_us16x08_meter_ctl = { 9498c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9508c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 9518c2ecf20Sopenharmony_ci .count = 1, 9528c2ecf20Sopenharmony_ci .info = snd_us16x08_meter_info, 9538c2ecf20Sopenharmony_ci .get = snd_us16x08_meter_get, 9548c2ecf20Sopenharmony_ci .put = snd_us16x08_meter_put 9558c2ecf20Sopenharmony_ci}; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci/* control store preparation */ 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci/* setup compressor store and assign default value */ 9608c2ecf20Sopenharmony_cistatic struct snd_us16x08_comp_store *snd_us16x08_create_comp_store(void) 9618c2ecf20Sopenharmony_ci{ 9628c2ecf20Sopenharmony_ci int i; 9638c2ecf20Sopenharmony_ci struct snd_us16x08_comp_store *tmp; 9648c2ecf20Sopenharmony_ci 9658c2ecf20Sopenharmony_ci tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 9668c2ecf20Sopenharmony_ci if (!tmp) 9678c2ecf20Sopenharmony_ci return NULL; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) { 9708c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_THRESHOLD)][i] 9718c2ecf20Sopenharmony_ci = 0x20; 9728c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RATIO)][i] = 0x00; 9738c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_GAIN)][i] = 0x00; 9748c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_SWITCH)][i] = 0x00; 9758c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_ATTACK)][i] = 0x00; 9768c2ecf20Sopenharmony_ci tmp->val[COMP_STORE_IDX(SND_US16X08_ID_COMP_RELEASE)][i] = 0x00; 9778c2ecf20Sopenharmony_ci } 9788c2ecf20Sopenharmony_ci return tmp; 9798c2ecf20Sopenharmony_ci} 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci/* setup EQ store and assign default values */ 9828c2ecf20Sopenharmony_cistatic struct snd_us16x08_eq_store *snd_us16x08_create_eq_store(void) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci int i, b_idx; 9858c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *tmp; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); 9888c2ecf20Sopenharmony_ci if (!tmp) 9898c2ecf20Sopenharmony_ci return NULL; 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci for (i = 0; i < SND_US16X08_MAX_CHANNELS; i++) { 9928c2ecf20Sopenharmony_ci for (b_idx = 0; b_idx < SND_US16X08_ID_EQ_BAND_COUNT; b_idx++) { 9938c2ecf20Sopenharmony_ci tmp->val[b_idx][0][i] = 0x0c; 9948c2ecf20Sopenharmony_ci tmp->val[b_idx][3][i] = 0x00; 9958c2ecf20Sopenharmony_ci switch (b_idx) { 9968c2ecf20Sopenharmony_ci case 0: /* EQ Low */ 9978c2ecf20Sopenharmony_ci tmp->val[b_idx][1][i] = 0x05; 9988c2ecf20Sopenharmony_ci tmp->val[b_idx][2][i] = 0xff; 9998c2ecf20Sopenharmony_ci break; 10008c2ecf20Sopenharmony_ci case 1: /* EQ Mid low */ 10018c2ecf20Sopenharmony_ci tmp->val[b_idx][1][i] = 0x0e; 10028c2ecf20Sopenharmony_ci tmp->val[b_idx][2][i] = 0x02; 10038c2ecf20Sopenharmony_ci break; 10048c2ecf20Sopenharmony_ci case 2: /* EQ Mid High */ 10058c2ecf20Sopenharmony_ci tmp->val[b_idx][1][i] = 0x1b; 10068c2ecf20Sopenharmony_ci tmp->val[b_idx][2][i] = 0x02; 10078c2ecf20Sopenharmony_ci break; 10088c2ecf20Sopenharmony_ci case 3: /* EQ High */ 10098c2ecf20Sopenharmony_ci tmp->val[b_idx][1][i] = 0x2f 10108c2ecf20Sopenharmony_ci - SND_US16X08_EQ_HIGHFREQ_BIAS; 10118c2ecf20Sopenharmony_ci tmp->val[b_idx][2][i] = 0xff; 10128c2ecf20Sopenharmony_ci break; 10138c2ecf20Sopenharmony_ci } 10148c2ecf20Sopenharmony_ci } 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci return tmp; 10178c2ecf20Sopenharmony_ci} 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_cistatic struct snd_us16x08_meter_store *snd_us16x08_create_meter_store(void) 10208c2ecf20Sopenharmony_ci{ 10218c2ecf20Sopenharmony_ci struct snd_us16x08_meter_store *tmp; 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci tmp = kzalloc(sizeof(*tmp), GFP_KERNEL); 10248c2ecf20Sopenharmony_ci if (!tmp) 10258c2ecf20Sopenharmony_ci return NULL; 10268c2ecf20Sopenharmony_ci tmp->comp_index = 1; 10278c2ecf20Sopenharmony_ci tmp->comp_active_index = 0; 10288c2ecf20Sopenharmony_ci return tmp; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci/* release elem->private_free as well; called only once for each *_store */ 10328c2ecf20Sopenharmony_cistatic void elem_private_free(struct snd_kcontrol *kctl) 10338c2ecf20Sopenharmony_ci{ 10348c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem = kctl->private_data; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci if (elem) 10378c2ecf20Sopenharmony_ci kfree(elem->private_data); 10388c2ecf20Sopenharmony_ci kfree(elem); 10398c2ecf20Sopenharmony_ci kctl->private_data = NULL; 10408c2ecf20Sopenharmony_ci} 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_cistatic int add_new_ctl(struct usb_mixer_interface *mixer, 10438c2ecf20Sopenharmony_ci const struct snd_kcontrol_new *ncontrol, 10448c2ecf20Sopenharmony_ci int index, int val_type, int channels, 10458c2ecf20Sopenharmony_ci const char *name, void *opt, 10468c2ecf20Sopenharmony_ci bool do_private_free, 10478c2ecf20Sopenharmony_ci struct usb_mixer_elem_info **elem_ret) 10488c2ecf20Sopenharmony_ci{ 10498c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 10508c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem; 10518c2ecf20Sopenharmony_ci int err; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci usb_audio_dbg(mixer->chip, "us16x08 add mixer %s\n", name); 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci elem = kzalloc(sizeof(*elem), GFP_KERNEL); 10568c2ecf20Sopenharmony_ci if (!elem) 10578c2ecf20Sopenharmony_ci return -ENOMEM; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci elem->head.mixer = mixer; 10608c2ecf20Sopenharmony_ci elem->head.resume = NULL; 10618c2ecf20Sopenharmony_ci elem->control = 0; 10628c2ecf20Sopenharmony_ci elem->idx_off = 0; 10638c2ecf20Sopenharmony_ci elem->head.id = index; 10648c2ecf20Sopenharmony_ci elem->val_type = val_type; 10658c2ecf20Sopenharmony_ci elem->channels = channels; 10668c2ecf20Sopenharmony_ci elem->private_data = opt; 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(ncontrol, elem); 10698c2ecf20Sopenharmony_ci if (!kctl) { 10708c2ecf20Sopenharmony_ci kfree(elem); 10718c2ecf20Sopenharmony_ci return -ENOMEM; 10728c2ecf20Sopenharmony_ci } 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (do_private_free) 10758c2ecf20Sopenharmony_ci kctl->private_free = elem_private_free; 10768c2ecf20Sopenharmony_ci else 10778c2ecf20Sopenharmony_ci kctl->private_free = snd_usb_mixer_elem_free; 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ci strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci err = snd_usb_mixer_add_control(&elem->head, kctl); 10828c2ecf20Sopenharmony_ci if (err < 0) 10838c2ecf20Sopenharmony_ci return err; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci if (elem_ret) 10868c2ecf20Sopenharmony_ci *elem_ret = elem; 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci return 0; 10898c2ecf20Sopenharmony_ci} 10908c2ecf20Sopenharmony_ci 10918c2ecf20Sopenharmony_ci/* table of EQ controls */ 10928c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params eq_controls[] = { 10938c2ecf20Sopenharmony_ci { /* EQ switch */ 10948c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_switch_ctl, 10958c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQENABLE, 10968c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 10978c2ecf20Sopenharmony_ci .num_channels = 16, 10988c2ecf20Sopenharmony_ci .name = "EQ Switch", 10998c2ecf20Sopenharmony_ci }, 11008c2ecf20Sopenharmony_ci { /* EQ low gain */ 11018c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_gain_ctl, 11028c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQLOWLEVEL, 11038c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11048c2ecf20Sopenharmony_ci .num_channels = 16, 11058c2ecf20Sopenharmony_ci .name = "EQ Low Volume", 11068c2ecf20Sopenharmony_ci }, 11078c2ecf20Sopenharmony_ci { /* EQ low freq */ 11088c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_low_freq_ctl, 11098c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQLOWFREQ, 11108c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11118c2ecf20Sopenharmony_ci .num_channels = 16, 11128c2ecf20Sopenharmony_ci .name = "EQ Low Frequency", 11138c2ecf20Sopenharmony_ci }, 11148c2ecf20Sopenharmony_ci { /* EQ mid low gain */ 11158c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_gain_ctl, 11168c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQLOWMIDLEVEL, 11178c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11188c2ecf20Sopenharmony_ci .num_channels = 16, 11198c2ecf20Sopenharmony_ci .name = "EQ MidLow Volume", 11208c2ecf20Sopenharmony_ci }, 11218c2ecf20Sopenharmony_ci { /* EQ mid low freq */ 11228c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl, 11238c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQLOWMIDFREQ, 11248c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11258c2ecf20Sopenharmony_ci .num_channels = 16, 11268c2ecf20Sopenharmony_ci .name = "EQ MidLow Frequency", 11278c2ecf20Sopenharmony_ci }, 11288c2ecf20Sopenharmony_ci { /* EQ mid low Q */ 11298c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_mid_width_ctl, 11308c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQLOWMIDWIDTH, 11318c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11328c2ecf20Sopenharmony_ci .num_channels = 16, 11338c2ecf20Sopenharmony_ci .name = "EQ MidLow Q", 11348c2ecf20Sopenharmony_ci }, 11358c2ecf20Sopenharmony_ci { /* EQ mid high gain */ 11368c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_gain_ctl, 11378c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQHIGHMIDLEVEL, 11388c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11398c2ecf20Sopenharmony_ci .num_channels = 16, 11408c2ecf20Sopenharmony_ci .name = "EQ MidHigh Volume", 11418c2ecf20Sopenharmony_ci }, 11428c2ecf20Sopenharmony_ci { /* EQ mid high freq */ 11438c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_mid_freq_ctl, 11448c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQHIGHMIDFREQ, 11458c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11468c2ecf20Sopenharmony_ci .num_channels = 16, 11478c2ecf20Sopenharmony_ci .name = "EQ MidHigh Frequency", 11488c2ecf20Sopenharmony_ci }, 11498c2ecf20Sopenharmony_ci { /* EQ mid high Q */ 11508c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_mid_width_ctl, 11518c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQHIGHMIDWIDTH, 11528c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11538c2ecf20Sopenharmony_ci .num_channels = 16, 11548c2ecf20Sopenharmony_ci .name = "EQ MidHigh Q", 11558c2ecf20Sopenharmony_ci }, 11568c2ecf20Sopenharmony_ci { /* EQ high gain */ 11578c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_gain_ctl, 11588c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQHIGHLEVEL, 11598c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11608c2ecf20Sopenharmony_ci .num_channels = 16, 11618c2ecf20Sopenharmony_ci .name = "EQ High Volume", 11628c2ecf20Sopenharmony_ci }, 11638c2ecf20Sopenharmony_ci { /* EQ low freq */ 11648c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_eq_high_freq_ctl, 11658c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_EQHIGHFREQ, 11668c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11678c2ecf20Sopenharmony_ci .num_channels = 16, 11688c2ecf20Sopenharmony_ci .name = "EQ High Frequency", 11698c2ecf20Sopenharmony_ci }, 11708c2ecf20Sopenharmony_ci}; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci/* table of compressor controls */ 11738c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params comp_controls[] = { 11748c2ecf20Sopenharmony_ci { /* Comp enable */ 11758c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_compswitch_ctl, 11768c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_SWITCH, 11778c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 11788c2ecf20Sopenharmony_ci .num_channels = 16, 11798c2ecf20Sopenharmony_ci .name = "Compressor Switch", 11808c2ecf20Sopenharmony_ci }, 11818c2ecf20Sopenharmony_ci { /* Comp threshold */ 11828c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_comp_threshold_ctl, 11838c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_THRESHOLD, 11848c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11858c2ecf20Sopenharmony_ci .num_channels = 16, 11868c2ecf20Sopenharmony_ci .name = "Compressor Threshold Volume", 11878c2ecf20Sopenharmony_ci }, 11888c2ecf20Sopenharmony_ci { /* Comp ratio */ 11898c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_comp_ratio_ctl, 11908c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_RATIO, 11918c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11928c2ecf20Sopenharmony_ci .num_channels = 16, 11938c2ecf20Sopenharmony_ci .name = "Compressor Ratio", 11948c2ecf20Sopenharmony_ci }, 11958c2ecf20Sopenharmony_ci { /* Comp attack */ 11968c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_comp_attack_ctl, 11978c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_ATTACK, 11988c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 11998c2ecf20Sopenharmony_ci .num_channels = 16, 12008c2ecf20Sopenharmony_ci .name = "Compressor Attack", 12018c2ecf20Sopenharmony_ci }, 12028c2ecf20Sopenharmony_ci { /* Comp release */ 12038c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_comp_release_ctl, 12048c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_RELEASE, 12058c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 12068c2ecf20Sopenharmony_ci .num_channels = 16, 12078c2ecf20Sopenharmony_ci .name = "Compressor Release", 12088c2ecf20Sopenharmony_ci }, 12098c2ecf20Sopenharmony_ci { /* Comp gain */ 12108c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_comp_gain_ctl, 12118c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_COMP_GAIN, 12128c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 12138c2ecf20Sopenharmony_ci .num_channels = 16, 12148c2ecf20Sopenharmony_ci .name = "Compressor Volume", 12158c2ecf20Sopenharmony_ci }, 12168c2ecf20Sopenharmony_ci}; 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci/* table of channel controls */ 12198c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params channel_controls[] = { 12208c2ecf20Sopenharmony_ci { /* Phase */ 12218c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_ch_boolean_ctl, 12228c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_PHASE, 12238c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 12248c2ecf20Sopenharmony_ci .num_channels = 16, 12258c2ecf20Sopenharmony_ci .name = "Phase Switch", 12268c2ecf20Sopenharmony_ci .default_val = 0 12278c2ecf20Sopenharmony_ci }, 12288c2ecf20Sopenharmony_ci { /* Fader */ 12298c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_ch_int_ctl, 12308c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_FADER, 12318c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 12328c2ecf20Sopenharmony_ci .num_channels = 16, 12338c2ecf20Sopenharmony_ci .name = "Line Volume", 12348c2ecf20Sopenharmony_ci .default_val = 127 12358c2ecf20Sopenharmony_ci }, 12368c2ecf20Sopenharmony_ci { /* Mute */ 12378c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_ch_boolean_ctl, 12388c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_MUTE, 12398c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 12408c2ecf20Sopenharmony_ci .num_channels = 16, 12418c2ecf20Sopenharmony_ci .name = "Mute Switch", 12428c2ecf20Sopenharmony_ci .default_val = 0 12438c2ecf20Sopenharmony_ci }, 12448c2ecf20Sopenharmony_ci { /* Pan */ 12458c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_pan_int_ctl, 12468c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_PAN, 12478c2ecf20Sopenharmony_ci .type = USB_MIXER_U16, 12488c2ecf20Sopenharmony_ci .num_channels = 16, 12498c2ecf20Sopenharmony_ci .name = "Pan Left-Right Volume", 12508c2ecf20Sopenharmony_ci .default_val = 127 12518c2ecf20Sopenharmony_ci }, 12528c2ecf20Sopenharmony_ci}; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci/* table of master controls */ 12558c2ecf20Sopenharmony_cistatic const struct snd_us16x08_control_params master_controls[] = { 12568c2ecf20Sopenharmony_ci { /* Master */ 12578c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_master_ctl, 12588c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_FADER, 12598c2ecf20Sopenharmony_ci .type = USB_MIXER_U8, 12608c2ecf20Sopenharmony_ci .num_channels = 16, 12618c2ecf20Sopenharmony_ci .name = "Master Volume", 12628c2ecf20Sopenharmony_ci .default_val = 127 12638c2ecf20Sopenharmony_ci }, 12648c2ecf20Sopenharmony_ci { /* Bypass */ 12658c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_bus_ctl, 12668c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_BYPASS, 12678c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 12688c2ecf20Sopenharmony_ci .num_channels = 16, 12698c2ecf20Sopenharmony_ci .name = "DSP Bypass Switch", 12708c2ecf20Sopenharmony_ci .default_val = 0 12718c2ecf20Sopenharmony_ci }, 12728c2ecf20Sopenharmony_ci { /* Buss out */ 12738c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_bus_ctl, 12748c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_BUSS_OUT, 12758c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 12768c2ecf20Sopenharmony_ci .num_channels = 16, 12778c2ecf20Sopenharmony_ci .name = "Buss Out Switch", 12788c2ecf20Sopenharmony_ci .default_val = 0 12798c2ecf20Sopenharmony_ci }, 12808c2ecf20Sopenharmony_ci { /* Master mute */ 12818c2ecf20Sopenharmony_ci .kcontrol_new = &snd_us16x08_bus_ctl, 12828c2ecf20Sopenharmony_ci .control_id = SND_US16X08_ID_MUTE, 12838c2ecf20Sopenharmony_ci .type = USB_MIXER_BOOLEAN, 12848c2ecf20Sopenharmony_ci .num_channels = 16, 12858c2ecf20Sopenharmony_ci .name = "Master Mute Switch", 12868c2ecf20Sopenharmony_ci .default_val = 0 12878c2ecf20Sopenharmony_ci }, 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci}; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ciint snd_us16x08_controls_create(struct usb_mixer_interface *mixer) 12928c2ecf20Sopenharmony_ci{ 12938c2ecf20Sopenharmony_ci int i, j; 12948c2ecf20Sopenharmony_ci int err; 12958c2ecf20Sopenharmony_ci struct usb_mixer_elem_info *elem; 12968c2ecf20Sopenharmony_ci struct snd_us16x08_comp_store *comp_store; 12978c2ecf20Sopenharmony_ci struct snd_us16x08_meter_store *meter_store; 12988c2ecf20Sopenharmony_ci struct snd_us16x08_eq_store *eq_store; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci /* just check for non-MIDI interface */ 13018c2ecf20Sopenharmony_ci if (mixer->hostif->desc.bInterfaceNumber == 3) { 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci /* add routing control */ 13048c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, &snd_us16x08_route_ctl, 13058c2ecf20Sopenharmony_ci SND_US16X08_ID_ROUTE, USB_MIXER_U8, 8, "Line Out Route", 13068c2ecf20Sopenharmony_ci NULL, false, &elem); 13078c2ecf20Sopenharmony_ci if (err < 0) { 13088c2ecf20Sopenharmony_ci usb_audio_dbg(mixer->chip, 13098c2ecf20Sopenharmony_ci "Failed to create route control, err:%d\n", 13108c2ecf20Sopenharmony_ci err); 13118c2ecf20Sopenharmony_ci return err; 13128c2ecf20Sopenharmony_ci } 13138c2ecf20Sopenharmony_ci for (i = 0; i < 8; i++) 13148c2ecf20Sopenharmony_ci elem->cache_val[i] = i < 2 ? i : i + 2; 13158c2ecf20Sopenharmony_ci elem->cached = 0xff; 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci /* create compressor mixer elements */ 13188c2ecf20Sopenharmony_ci comp_store = snd_us16x08_create_comp_store(); 13198c2ecf20Sopenharmony_ci if (!comp_store) 13208c2ecf20Sopenharmony_ci return -ENOMEM; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci /* add master controls */ 13238c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(master_controls); i++) { 13248c2ecf20Sopenharmony_ci 13258c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, 13268c2ecf20Sopenharmony_ci master_controls[i].kcontrol_new, 13278c2ecf20Sopenharmony_ci master_controls[i].control_id, 13288c2ecf20Sopenharmony_ci master_controls[i].type, 13298c2ecf20Sopenharmony_ci master_controls[i].num_channels, 13308c2ecf20Sopenharmony_ci master_controls[i].name, 13318c2ecf20Sopenharmony_ci comp_store, 13328c2ecf20Sopenharmony_ci i == 0, /* release comp_store only once */ 13338c2ecf20Sopenharmony_ci &elem); 13348c2ecf20Sopenharmony_ci if (err < 0) 13358c2ecf20Sopenharmony_ci return err; 13368c2ecf20Sopenharmony_ci elem->cache_val[0] = master_controls[i].default_val; 13378c2ecf20Sopenharmony_ci elem->cached = 1; 13388c2ecf20Sopenharmony_ci } 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_ci /* add channel controls */ 13418c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(channel_controls); i++) { 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, 13448c2ecf20Sopenharmony_ci channel_controls[i].kcontrol_new, 13458c2ecf20Sopenharmony_ci channel_controls[i].control_id, 13468c2ecf20Sopenharmony_ci channel_controls[i].type, 13478c2ecf20Sopenharmony_ci channel_controls[i].num_channels, 13488c2ecf20Sopenharmony_ci channel_controls[i].name, 13498c2ecf20Sopenharmony_ci comp_store, 13508c2ecf20Sopenharmony_ci false, &elem); 13518c2ecf20Sopenharmony_ci if (err < 0) 13528c2ecf20Sopenharmony_ci return err; 13538c2ecf20Sopenharmony_ci for (j = 0; j < SND_US16X08_MAX_CHANNELS; j++) { 13548c2ecf20Sopenharmony_ci elem->cache_val[j] = 13558c2ecf20Sopenharmony_ci channel_controls[i].default_val; 13568c2ecf20Sopenharmony_ci } 13578c2ecf20Sopenharmony_ci elem->cached = 0xffff; 13588c2ecf20Sopenharmony_ci } 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* create eq store */ 13618c2ecf20Sopenharmony_ci eq_store = snd_us16x08_create_eq_store(); 13628c2ecf20Sopenharmony_ci if (!eq_store) 13638c2ecf20Sopenharmony_ci return -ENOMEM; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci /* add EQ controls */ 13668c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(eq_controls); i++) { 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, 13698c2ecf20Sopenharmony_ci eq_controls[i].kcontrol_new, 13708c2ecf20Sopenharmony_ci eq_controls[i].control_id, 13718c2ecf20Sopenharmony_ci eq_controls[i].type, 13728c2ecf20Sopenharmony_ci eq_controls[i].num_channels, 13738c2ecf20Sopenharmony_ci eq_controls[i].name, 13748c2ecf20Sopenharmony_ci eq_store, 13758c2ecf20Sopenharmony_ci i == 0, /* release eq_store only once */ 13768c2ecf20Sopenharmony_ci NULL); 13778c2ecf20Sopenharmony_ci if (err < 0) 13788c2ecf20Sopenharmony_ci return err; 13798c2ecf20Sopenharmony_ci } 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci /* add compressor controls */ 13828c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(comp_controls); i++) { 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, 13858c2ecf20Sopenharmony_ci comp_controls[i].kcontrol_new, 13868c2ecf20Sopenharmony_ci comp_controls[i].control_id, 13878c2ecf20Sopenharmony_ci comp_controls[i].type, 13888c2ecf20Sopenharmony_ci comp_controls[i].num_channels, 13898c2ecf20Sopenharmony_ci comp_controls[i].name, 13908c2ecf20Sopenharmony_ci comp_store, 13918c2ecf20Sopenharmony_ci false, NULL); 13928c2ecf20Sopenharmony_ci if (err < 0) 13938c2ecf20Sopenharmony_ci return err; 13948c2ecf20Sopenharmony_ci } 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_ci /* create meters store */ 13978c2ecf20Sopenharmony_ci meter_store = snd_us16x08_create_meter_store(); 13988c2ecf20Sopenharmony_ci if (!meter_store) 13998c2ecf20Sopenharmony_ci return -ENOMEM; 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci /* meter function 'get' must access to compressor store 14028c2ecf20Sopenharmony_ci * so place a reference here 14038c2ecf20Sopenharmony_ci */ 14048c2ecf20Sopenharmony_ci meter_store->comp_store = comp_store; 14058c2ecf20Sopenharmony_ci err = add_new_ctl(mixer, &snd_us16x08_meter_ctl, 14068c2ecf20Sopenharmony_ci SND_US16X08_ID_METER, USB_MIXER_U16, 0, "Level Meter", 14078c2ecf20Sopenharmony_ci meter_store, true, NULL); 14088c2ecf20Sopenharmony_ci if (err < 0) 14098c2ecf20Sopenharmony_ci return err; 14108c2ecf20Sopenharmony_ci } 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return 0; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 1415