blob: 16b3e1043e97684aadbf360341bd82c4d62f5367 [file] [log] [blame]
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001/*
Weiyin Jiangcba6f962018-03-18 11:52:05 +08002 * Copyright (c) 2013, 2016-2018 The Linux Foundation. All rights reserved.
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07003 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#define LOG_TAG "audio_hw_usb"
21#define LOG_NDEBUG 0
22#define LOG_NDDEBUG 0
23
24#include <errno.h>
25#include <pthread.h>
26#include <stdlib.h>
27#include <cutils/log.h>
28#include <cutils/str_parms.h>
29#include <sys/ioctl.h>
30#include <fcntl.h>
31#include <sys/stat.h>
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -070032#include <system/audio.h>
33#include <tinyalsa/asoundlib.h>
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080034#include <audio_hw.h>
35#include <cutils/properties.h>
Kuirong Wang1cad7142016-05-24 15:21:56 -070036#include <ctype.h>
37#include <math.h>
Vinay Vermaaddfa4a2018-04-29 14:03:38 +053038#include <unistd.h>
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -070039
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053040#ifdef DYNAMIC_LOG_ENABLED
41#include <log_xml_parser.h>
42#define LOG_MASK HAL_MOD_FILE_USB
43#include <log_utils.h>
44#endif
45
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -070046#ifdef USB_HEADSET_ENABLED
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080047#define USB_BUFF_SIZE 2048
48#define CHANNEL_NUMBER_STR "Channels: "
49#define PLAYBACK_PROFILE_STR "Playback:"
50#define CAPTURE_PROFILE_STR "Capture:"
Garmond Leung5fd0b552018-04-17 11:56:12 -070051#define DATA_PACKET_INTERVAL_STR "Data packet interval:"
Kuirong Wang1cad7142016-05-24 15:21:56 -070052#define USB_SIDETONE_GAIN_STR "usb_sidetone_gain"
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080053#define ABS_SUB(A, B) (((A) > (B)) ? ((A) - (B)):((B) - (A)))
54#define SAMPLE_RATE_8000 8000
55#define SAMPLE_RATE_11025 11025
Weiyin Jiangcba6f962018-03-18 11:52:05 +080056#define SAMPLE_RATE_192000 192000
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080057// Supported sample rates for USB
58static uint32_t supported_sample_rates[] =
Haynes Mathew George484e8d22017-07-31 18:55:17 -070059 {384000, 352800, 192000, 176400, 96000, 88200, 64000, 48000, 44100, 32000, 22050, 16000, 11025, 8000};
60static uint32_t supported_sample_rates_mask[2];
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080061
62#define MAX_SAMPLE_RATE_SIZE sizeof(supported_sample_rates)/sizeof(supported_sample_rates[0])
63
Garmond Leung5fd0b552018-04-17 11:56:12 -070064#define DEFAULT_SERVICE_INTERVAL_US 0
65
Haynes Mathew George484e8d22017-07-31 18:55:17 -070066#define _MAX(x, y) (((x) >= (y)) ? (x) : (y))
67#define _MIN(x, y) (((x) <= (y)) ? (x) : (y))
68
Garmond Leung5fd0b552018-04-17 11:56:12 -070069typedef enum usb_usecase_type{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080070 USB_PLAYBACK = 0,
71 USB_CAPTURE,
Garmond Leung5fd0b552018-04-17 11:56:12 -070072} usb_usecase_type_t;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080073
Kuirong Wang1cad7142016-05-24 15:21:56 -070074enum {
75 USB_SIDETONE_ENABLE_INDEX = 0,
76 USB_SIDETONE_VOLUME_INDEX,
77 USB_SIDETONE_MAX_INDEX,
78};
79
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080080struct usb_device_config {
81 struct listnode list;
82 unsigned int bit_width;
83 unsigned int channels;
84 unsigned int rate_size;
85 unsigned int rates[MAX_SAMPLE_RATE_SIZE];
Garmond Leung5fd0b552018-04-17 11:56:12 -070086 unsigned long service_interval_us;
87 usb_usecase_type_t type;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -080088};
89
90struct usb_card_config {
91 struct listnode list;
92 audio_devices_t usb_device_type;
93 int usb_card;
94 struct listnode usb_device_conf_list;
Kuirong Wang1cad7142016-05-24 15:21:56 -070095 struct mixer *usb_snd_mixer;
96 int usb_sidetone_index[USB_SIDETONE_MAX_INDEX];
97 int usb_sidetone_vol_min;
98 int usb_sidetone_vol_max;
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -070099 int endian;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800100};
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700101
102struct usb_module {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800103 struct listnode usb_card_conf_list;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700104 struct audio_device *adev;
Kuirong Wang1cad7142016-05-24 15:21:56 -0700105 int sidetone_gain;
Ashish Jain3e37a702016-11-25 12:27:15 +0530106 bool is_capture_supported;
Garmond Leung5fd0b552018-04-17 11:56:12 -0700107 bool usb_reconfig;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700108};
109
110static struct usb_module *usbmod = NULL;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800111static bool usb_audio_debug_enable = false;
Kuirong Wang1cad7142016-05-24 15:21:56 -0700112static int usb_sidetone_gain = 0;
113
114static const char * const usb_sidetone_enable_str[] = {
115 "Sidetone Playback Switch",
Kuirong Wang4ddd75f2016-09-21 11:20:31 -0700116 "Mic Playback Switch",
Kuirong Wang1cad7142016-05-24 15:21:56 -0700117};
118
119static const char * const usb_sidetone_volume_str[] = {
120 "Sidetone Playback Volume",
121 "Mic Playback Volume",
122};
123
124static void usb_mixer_print_enum(struct mixer_ctl *ctl)
125{
126 unsigned int num_enums;
127 unsigned int i;
128 const char *string;
129
130 num_enums = mixer_ctl_get_num_enums(ctl);
131
132 for (i = 0; i < num_enums; i++) {
133 string = mixer_ctl_get_enum_string(ctl, i);
134 ALOGI("\t%s%s", mixer_ctl_get_value(ctl, 0) == (int)i ? ">" : "", string);
135 }
136}
137
138static void usb_soundcard_detail_control(struct mixer *mixer, const char *control)
139{
140 struct mixer_ctl *ctl;
141 enum mixer_ctl_type type;
142 unsigned int num_values;
143 unsigned int i;
144 int min, max;
145
146 if (isdigit(control[0]))
147 ctl = mixer_get_ctl(mixer, atoi(control));
148 else
149 ctl = mixer_get_ctl_by_name(mixer, control);
150
151 if (!ctl) {
152 fprintf(stderr, "Invalid mixer control\n");
153 return;
154 }
155
156 type = mixer_ctl_get_type(ctl);
157 num_values = mixer_ctl_get_num_values(ctl);
158
159 ALOGI("%s:", mixer_ctl_get_name(ctl));
160
161 for (i = 0; i < num_values; i++) {
162 switch (type) {
163 case MIXER_CTL_TYPE_INT:
164 ALOGI(" %d", mixer_ctl_get_value(ctl, i));
165 break;
166 case MIXER_CTL_TYPE_BOOL:
167 ALOGI(" %s", mixer_ctl_get_value(ctl, i) ? "On" : "Off");
168 break;
169 case MIXER_CTL_TYPE_ENUM:
170 usb_mixer_print_enum(ctl);
171 break;
172 case MIXER_CTL_TYPE_BYTE:
173 ALOGI(" 0x%02x", mixer_ctl_get_value(ctl, i));
174 break;
175 default:
176 ALOGI(" unknown");
177 break;
178 }
179 }
180
181 if (type == MIXER_CTL_TYPE_INT) {
182 min = mixer_ctl_get_range_min(ctl);
183 max = mixer_ctl_get_range_max(ctl);
184 ALOGI(" (range %d->%d)", min, max);
185 }
186}
187
188static void usb_soundcard_list_controls(struct mixer *mixer)
189{
190 struct mixer_ctl *ctl;
191 const char *name, *type;
192 unsigned int num_ctls, num_values;
193 unsigned int i;
194
195 num_ctls = mixer_get_num_ctls(mixer);
196
197 ALOGI("Number of controls: %d\n", num_ctls);
198
199 ALOGI("ctl\ttype\tnum\t%-40s value\n", "name");
200 for (i = 0; i < num_ctls; i++) {
201 ctl = mixer_get_ctl(mixer, i);
202 if (ctl != NULL) {
203 name = mixer_ctl_get_name(ctl);
204 type = mixer_ctl_get_type_string(ctl);
205 num_values = mixer_ctl_get_num_values(ctl);
206 ALOGI("%d\t%s\t%d\t%-40s", i, type, num_values, name);
207 if (name != NULL)
208 usb_soundcard_detail_control(mixer, name);
209 }
210 }
211}
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700212
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800213static int usb_set_dev_id_mixer_ctl(unsigned int usb_usecase_type, int card,
214 char *dev_mixer_ctl_name)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700215{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800216 struct mixer_ctl *ctl;
217 unsigned int dev_token;
218 unsigned int pcm_device_number = 0;
219
220 /*
221 * usb_dev_token_id is 32 bit number and is defined as below:
222 * usb_sound_card_idx(31:16) | usb PCM device ID(15:8) | usb_usecase_type(7:0)
223 */
224 dev_token = (card << 16 ) |
225 (pcm_device_number << 8) | (usb_usecase_type & 0xFF);
226
227 ctl = mixer_get_ctl_by_name(usbmod->adev->mixer, dev_mixer_ctl_name);
228 if (!ctl) {
229 ALOGE("%s: Could not get ctl for mixer cmd - %s",
230 __func__, dev_mixer_ctl_name);
231 return -EINVAL;
232 }
233 mixer_ctl_set_value(ctl, 0, dev_token);
234
235 return 0;
236}
237
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700238static int usb_set_endian_mixer_ctl(int endian, char *endian_mixer_ctl_name)
239{
240 struct mixer_ctl *ctl = mixer_get_ctl_by_name(usbmod->adev->mixer,
241 endian_mixer_ctl_name);
242 if (!ctl) {
243 ALOGE("%s: Could not get ctl for mixer cmd - %s",
244 __func__, endian_mixer_ctl_name);
245 return -EINVAL;
246 }
247
248 switch (endian) {
249 case 0:
250 case 1:
251 mixer_ctl_set_value(ctl, 0, endian);
252 break;
253 default:
254 ALOGW("%s: endianness(%d) not supported",
255 __func__, endian);
256 break;
257 }
258 return 0;
259}
260
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700261static int usb_get_sample_rates(int type, char *rates_str,
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800262 struct usb_device_config *config)
263{
264 uint32_t i;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700265 char *next_sr_string, *temp_ptr;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800266 uint32_t sr, min_sr, max_sr, sr_size = 0;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700267
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800268 /* Sample rate string can be in any of the folloing two bit_widthes:
269 * Rates: 8000 - 48000 (continuous)
270 * Rates: 8000, 44100, 48000
271 * Support both the bit_widths
272 */
273 ALOGV("%s: rates_str %s", __func__, rates_str);
Kuirong Wang591a98a2016-06-27 12:41:41 -0700274 next_sr_string = strtok_r(rates_str, "Rates: ", &temp_ptr);
275 if (next_sr_string == NULL) {
276 ALOGE("%s: could not find min rates string", __func__);
277 return -EINVAL;
278 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800279 if (strstr(rates_str, "continuous") != NULL) {
Kuirong Wang591a98a2016-06-27 12:41:41 -0700280 min_sr = (uint32_t)atoi(next_sr_string);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700281 next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800282 if (next_sr_string == NULL) {
283 ALOGE("%s: could not find max rates string", __func__);
284 return -EINVAL;
285 }
Kuirong Wang591a98a2016-06-27 12:41:41 -0700286 max_sr = (uint32_t)atoi(next_sr_string);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800287
Kuirong Wang591a98a2016-06-27 12:41:41 -0700288 for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800289 if (supported_sample_rates[i] >= min_sr &&
Kuirong Wang591a98a2016-06-27 12:41:41 -0700290 supported_sample_rates[i] <= max_sr) {
Weiyin Jiangcba6f962018-03-18 11:52:05 +0800291 // FIXME: we don't support >192KHz in recording path for now
292 if ((supported_sample_rates[i] > SAMPLE_RATE_192000) &&
293 (type == USB_CAPTURE))
294 continue;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800295 config->rates[sr_size++] = supported_sample_rates[i];
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700296 supported_sample_rates_mask[type] |= (1<<i);
Kuirong Wang591a98a2016-06-27 12:41:41 -0700297 ALOGI_IF(usb_audio_debug_enable,
298 "%s: continuous sample rate supported_sample_rates[%d] %d",
299 __func__, i, supported_sample_rates[i]);
300 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800301 }
Kuirong Wang591a98a2016-06-27 12:41:41 -0700302 } else {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800303 do {
304 sr = (uint32_t)atoi(next_sr_string);
Weiyin Jiangcba6f962018-03-18 11:52:05 +0800305 // FIXME: we don't support >192KHz in recording path for now
306 if ((sr > SAMPLE_RATE_192000) && (type == USB_CAPTURE)) {
307 next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
308 continue;
309 }
310
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800311 for (i = 0; i < MAX_SAMPLE_RATE_SIZE; i++) {
312 if (supported_sample_rates[i] == sr) {
313 ALOGI_IF(usb_audio_debug_enable,
314 "%s: sr %d, supported_sample_rates[%d] %d -> matches!!",
315 __func__, sr, i, supported_sample_rates[i]);
316 config->rates[sr_size++] = supported_sample_rates[i];
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700317 supported_sample_rates_mask[type] |= (1<<i);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800318 }
319 }
320 next_sr_string = strtok_r(NULL, " ,.-", &temp_ptr);
321 } while (next_sr_string != NULL);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700322 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800323 config->rate_size = sr_size;
324 return 0;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700325}
326
Garmond Leung5fd0b552018-04-17 11:56:12 -0700327static int usb_get_service_interval(const char *interval_str_start,
328 struct usb_device_config *usb_device_info)
329{
330 unsigned long interval = 0;
331 char time_unit[8] = {0};
332 int multiplier = 0;
333
334 char *eol = strchr(interval_str_start, '\n');
335 if (!eol) {
336 ALOGE("%s: No EOL found", __func__);
337 return -1;
338 }
339 char *tmp = (char *)calloc(1, eol-interval_str_start+1);
340 if (!tmp) {
341 ALOGE("%s: failed to allocate tmp", __func__);
342 return -1;
343 }
344 memcpy(tmp, interval_str_start, eol-interval_str_start);
345 sscanf(tmp, "%lu %2s", &interval, &time_unit[0]);
346 if (!strcmp(time_unit, "us")) {
347 multiplier = 1;
348 } else if (!strcmp(time_unit, "ms")) {
349 multiplier = 1000;
350 } else if (!strcmp(time_unit, "s")) {
351 multiplier = 1000000;
352 } else {
353 ALOGE("%s: unknown time_unit %s, assume default", __func__, time_unit);
354 interval = DEFAULT_SERVICE_INTERVAL_US;
355 multiplier = 1;
356 }
357 interval *= multiplier;
358 ALOGD("%s: set service_interval_us %lu", __func__, interval);
359 usb_device_info->service_interval_us = interval;
360 free(tmp);
361 return 0;
362}
363
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800364static int usb_get_capability(int type,
365 struct usb_card_config *usb_card_info,
366 int card)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700367{
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700368 int32_t size = 0;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800369 int32_t fd=-1;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800370 int32_t channels_no;
Kuirong Wange9894162016-08-26 15:16:39 -0700371 char *str_start = NULL;
372 char *str_end = NULL;
373 char *channel_start = NULL;
374 char *bit_width_start = NULL;
375 char *rates_str_start = NULL;
376 char *target = NULL;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700377 char *read_buf = NULL;
378 char *rates_str = NULL;
Garmond Leung5fd0b552018-04-17 11:56:12 -0700379 char *interval_str_start = NULL;
Kuirong Wange9894162016-08-26 15:16:39 -0700380 char path[128];
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700381 int ret = 0;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800382 char *bit_width_str = NULL;
383 struct usb_device_config * usb_device_info;
Kuirong Wange9894162016-08-26 15:16:39 -0700384 bool check = false;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700385
Kuirong Wange9894162016-08-26 15:16:39 -0700386 memset(path, 0, sizeof(path));
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800387 ALOGV("%s: for %s", __func__, (type == USB_PLAYBACK) ?
388 PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR);
389
Kuirong Wange9894162016-08-26 15:16:39 -0700390 ret = snprintf(path, sizeof(path), "/proc/asound/card%u/stream0",
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800391 card);
Kuirong Wange9894162016-08-26 15:16:39 -0700392 if(ret < 0) {
393 ALOGE("%s: failed on snprintf (%d) to path %s\n",
394 __func__, ret, path);
395 goto done;
396 }
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700397
398 fd = open(path, O_RDONLY);
399 if (fd <0) {
400 ALOGE("%s: error failed to open config file %s error: %d\n",
401 __func__, path, errno);
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700402 ret = -EINVAL;
403 goto done;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700404 }
405
Apoorv Raghuvanshidad3b782014-01-29 15:31:32 -0800406 read_buf = (char *)calloc(1, USB_BUFF_SIZE + 1);
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700407
408 if (!read_buf) {
409 ALOGE("Failed to create read_buf");
410 ret = -ENOMEM;
411 goto done;
412 }
413
Kuirong Wange9894162016-08-26 15:16:39 -0700414 if(read(fd, read_buf, USB_BUFF_SIZE) < 0) {
415 ALOGE("file read error\n");
416 goto done;
417 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800418 str_start = strstr(read_buf, ((type == USB_PLAYBACK) ?
419 PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700420 if (str_start == NULL) {
421 ALOGE("%s: error %s section not found in usb config file",
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800422 __func__, ((type == USB_PLAYBACK) ?
423 PLAYBACK_PROFILE_STR : CAPTURE_PROFILE_STR));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700424 ret = -EINVAL;
425 goto done;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700426 }
Kuirong Wange9894162016-08-26 15:16:39 -0700427 str_end = strstr(read_buf, ((type == USB_PLAYBACK) ?
428 CAPTURE_PROFILE_STR : PLAYBACK_PROFILE_STR));
429 if (str_end > str_start)
430 check = true;
431
432 ALOGV("%s: usb_config = %s, check %d\n", __func__, str_start, check);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700433
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800434 while (str_start != NULL) {
Kuirong Wange9894162016-08-26 15:16:39 -0700435 str_start = strstr(str_start, "Altset");
436 if ((str_start == NULL) || (check && (str_start >= str_end))) {
437 ALOGV("%s: done parsing %s\n", __func__, str_start);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800438 break;
439 }
Kuirong Wange9894162016-08-26 15:16:39 -0700440 ALOGV("%s: remaining string %s\n", __func__, str_start);
441 str_start += sizeof("Altset");
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800442 usb_device_info = calloc(1, sizeof(struct usb_device_config));
443 if (usb_device_info == NULL) {
444 ALOGE("%s: error unable to allocate memory",
445 __func__);
446 ret = -ENOMEM;
447 break;
448 }
Garmond Leung5fd0b552018-04-17 11:56:12 -0700449 usb_device_info->type = type;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800450 /* Bit bit_width parsing */
451 bit_width_start = strstr(str_start, "Format: ");
452 if (bit_width_start == NULL) {
453 ALOGI("%s: Could not find bit_width string", __func__);
454 free(usb_device_info);
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700455 continue;
456 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800457 target = strchr(bit_width_start, '\n');
458 if (target == NULL) {
459 ALOGI("%s:end of line not found", __func__);
460 free(usb_device_info);
461 continue;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700462 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800463 size = target - bit_width_start;
464 if ((bit_width_str = (char *)malloc(size + 1)) == NULL) {
465 ALOGE("%s: unable to allocate memory to hold bit width strings",
466 __func__);
467 ret = -EINVAL;
468 free(usb_device_info);
469 break;
470 }
471 memcpy(bit_width_str, bit_width_start, size);
472 bit_width_str[size] = '\0';
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700473
474 const char * formats[] = { "S32", "S24_3", "S24", "S16" };
475 const int bit_width[] = { 32, 24, 24, 16};
476 for (size_t i = 0; i < ARRAY_SIZE(formats); i++) {
477 const char * s = strstr(bit_width_str, formats[i]);
478 if (s) {
479 usb_device_info->bit_width = bit_width[i];
480 usb_card_info->endian = strstr(s, "BE") ? 1 : 0;
481 break;
482 }
483 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800484
485 if (bit_width_str)
486 free(bit_width_str);
487
488 /* channels parsing */
489 channel_start = strstr(str_start, CHANNEL_NUMBER_STR);
490 if (channel_start == NULL) {
491 ALOGI("%s: could not find Channels string", __func__);
492 free(usb_device_info);
493 continue;
494 }
495 channels_no = atoi(channel_start + strlen(CHANNEL_NUMBER_STR));
496 usb_device_info->channels = channels_no;
497
498 /* Sample rates parsing */
499 rates_str_start = strstr(str_start, "Rates: ");
500 if (rates_str_start == NULL) {
501 ALOGI("%s: cant find rates string", __func__);
502 free(usb_device_info);
503 continue;
504 }
505 target = strchr(rates_str_start, '\n');
506 if (target == NULL) {
507 ALOGI("%s: end of line not found", __func__);
508 free(usb_device_info);
509 continue;
510 }
511 size = target - rates_str_start;
512 if ((rates_str = (char *)malloc(size + 1)) == NULL) {
513 ALOGE("%s: unable to allocate memory to hold sample rate strings",
514 __func__);
515 ret = -EINVAL;
516 free(usb_device_info);
517 break;
518 }
519 memcpy(rates_str, rates_str_start, size);
520 rates_str[size] = '\0';
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700521 ret = usb_get_sample_rates(type, rates_str, usb_device_info);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800522 if (rates_str)
523 free(rates_str);
524 if (ret < 0) {
525 ALOGI("%s: error unable to get sample rate values",
526 __func__);
527 free(usb_device_info);
528 continue;
529 }
Garmond Leung5fd0b552018-04-17 11:56:12 -0700530 // Data packet interval is an optional field.
531 // Assume 0ms interval if this cannot be read
532 // LPASS USB and HLOS USB will figure out the default to use
533 usb_device_info->service_interval_us = DEFAULT_SERVICE_INTERVAL_US;
534 interval_str_start = strstr(str_start, DATA_PACKET_INTERVAL_STR);
535 if (interval_str_start != NULL) {
536 interval_str_start += strlen(DATA_PACKET_INTERVAL_STR);
537 ret = usb_get_service_interval(interval_str_start, usb_device_info);
538 if (ret < 0) {
539 ALOGE("%s: error unable to get service interval, assume default",
540 __func__);
541 }
542 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800543 /* Add to list if every field is valid */
544 list_add_tail(&usb_card_info->usb_device_conf_list,
545 &usb_device_info->list);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700546 }
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700547
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700548done:
549 if (fd >= 0) close(fd);
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -0700550 if (read_buf) free(read_buf);
551 return ret;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700552}
553
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800554static int usb_get_device_pb_config(struct usb_card_config *usb_card_info,
555 int card)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700556{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800557 int ret;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700558
559 /* get capabilities */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800560 if ((ret = usb_get_capability(USB_PLAYBACK, usb_card_info, card))) {
561 ALOGE("%s: could not get Playback capabilities from usb device",
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700562 __func__);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800563 goto exit;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700564 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800565 usb_set_dev_id_mixer_ctl(USB_PLAYBACK, card, "USB_AUDIO_RX dev_token");
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700566 usb_set_endian_mixer_ctl(usb_card_info->endian, "USB_AUDIO_RX endian");
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800567exit:
568
569 return ret;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700570}
571
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800572static int usb_get_device_cap_config(struct usb_card_config *usb_card_info,
573 int card)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700574{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800575 int ret;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700576
577 /* get capabilities */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800578 if ((ret = usb_get_capability(USB_CAPTURE, usb_card_info, card))) {
579 ALOGE("%s: could not get Playback capabilities from usb device",
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700580 __func__);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800581 goto exit;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700582 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800583 usb_set_dev_id_mixer_ctl(USB_CAPTURE, card, "USB_AUDIO_TX dev_token");
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700584 usb_set_endian_mixer_ctl(usb_card_info->endian, "USB_AUDIO_TX endian");
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700585
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800586exit:
587 return ret;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700588}
589
Kuirong Wang1cad7142016-05-24 15:21:56 -0700590static void usb_get_sidetone_mixer(struct usb_card_config *usb_card_info)
591{
592 struct mixer_ctl *ctl;
593 unsigned int index;
594
595 for (index = 0; index < USB_SIDETONE_MAX_INDEX; index++)
596 usb_card_info->usb_sidetone_index[index] = -1;
597
598 usb_card_info->usb_snd_mixer = mixer_open(usb_card_info->usb_card);
599 for (index = 0;
600 index < sizeof(usb_sidetone_enable_str)/sizeof(usb_sidetone_enable_str[0]);
601 index++) {
602 ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
603 usb_sidetone_enable_str[index]);
604 if (ctl) {
605 usb_card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX] = index;
606 /* Disable device sidetone by default */
607 mixer_ctl_set_value(ctl, 0, false);
608 break;
609 }
610 }
611 for (index = 0;
612 index < sizeof(usb_sidetone_volume_str)/sizeof(usb_sidetone_volume_str[0]);
613 index++) {
614 ctl = mixer_get_ctl_by_name(usb_card_info->usb_snd_mixer,
615 usb_sidetone_volume_str[index]);
616 if (ctl) {
617 usb_card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX] = index;
618 usb_card_info->usb_sidetone_vol_min = mixer_ctl_get_range_min(ctl);
619 usb_card_info->usb_sidetone_vol_max = mixer_ctl_get_range_max(ctl);
620 break;
621 }
622 }
623
624 if ((usb_card_info->usb_snd_mixer != NULL) && (usb_audio_debug_enable))
625 usb_soundcard_list_controls(usb_card_info->usb_snd_mixer);
626
627 return;
628}
629
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700630static inline bool usb_output_device(audio_devices_t device) {
631 // ignore accessory for now
632 if (device == AUDIO_DEVICE_OUT_USB_ACCESSORY)
633 return false;
634 return audio_is_usb_out_device(device);
635}
636
637static inline bool usb_input_device(audio_devices_t device) {
638 // ignore accessory for now
639 if (device == AUDIO_DEVICE_IN_USB_ACCESSORY)
640 return false;
641 return audio_is_usb_in_device(device);
642}
643
644static bool usb_valid_device(audio_devices_t device)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700645{
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700646 return usb_output_device(device) ||
647 usb_input_device(device);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800648}
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700649
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800650static void usb_print_active_device(void){
651 struct listnode *node_i, *node_j;
652 struct usb_device_config *dev_info;
653 struct usb_card_config *card_info;
654 unsigned int i;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700655
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800656 ALOGI("%s", __func__);
657 list_for_each(node_i, &usbmod->usb_card_conf_list) {
658 card_info = node_to_item(node_i, struct usb_card_config, list);
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700659 ALOGI("%s: card_dev_type (0x%x), card_no(%d), %s",
660 __func__, card_info->usb_device_type,
661 card_info->usb_card, card_info->endian ? "BE" : "LE");
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800662 list_for_each(node_j, &card_info->usb_device_conf_list) {
663 dev_info = node_to_item(node_j, struct usb_device_config, list);
664 ALOGI("%s: bit-width(%d) channel(%d)",
Haynes Mathew Georgec8f816c2016-10-25 12:02:02 -0700665 __func__, dev_info->bit_width, dev_info->channels);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800666 for (i = 0; i < dev_info->rate_size; i++)
667 ALOGI("%s: rate %d", __func__, dev_info->rates[i]);
668 }
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -0700669 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800670}
671
672static bool usb_get_best_match_for_bit_width(
673 struct listnode *dev_list,
674 unsigned int stream_bit_width,
675 unsigned int *bit_width)
676{
677 struct listnode *node_i;
678 struct usb_device_config *dev_info;
679 unsigned int candidate = 0;
680
681 list_for_each(node_i, dev_list) {
682 dev_info = node_to_item(node_i, struct usb_device_config, list);
683 ALOGI_IF(usb_audio_debug_enable,
684 "%s: USB bw(%d), stream bw(%d), candidate(%d)",
685 __func__, dev_info->bit_width,
686 stream_bit_width, candidate);
687 if (dev_info->bit_width == stream_bit_width) {
688 *bit_width = dev_info->bit_width;
689 ALOGV("%s: Found match bit-width (%d)",
690 __func__, dev_info->bit_width);
691 goto exit;
692 } else if (candidate == 0) {
693 candidate = dev_info->bit_width;
694 }
695 /*
696 * If stream bit is 24, USB supports both 16 bit and 32 bit, then
697 * higher bit width 32 is picked up instead of 16-bit
698 */
699 else if (ABS_SUB(stream_bit_width, dev_info->bit_width) <
700 ABS_SUB(stream_bit_width, candidate)) {
701 candidate = dev_info->bit_width;
702 }
703 else if ((ABS_SUB(stream_bit_width, dev_info->bit_width) ==
704 ABS_SUB(stream_bit_width, candidate)) &&
705 (dev_info->bit_width > candidate)) {
706 candidate = dev_info->bit_width;
707 }
708 }
709 ALOGV("%s: No match found, use the best candidate bw(%d)",
710 __func__, candidate);
711 *bit_width = candidate;
712exit:
713 return true;
714}
715
716static bool usb_get_best_match_for_channels(
717 struct listnode *dev_list,
718 unsigned int bit_width,
719 unsigned int stream_ch,
720 unsigned int *ch)
721{
722 struct listnode *node_i;
723 struct usb_device_config *dev_info;
724 unsigned int candidate = 0;
725
726 list_for_each(node_i, dev_list) {
727 dev_info = node_to_item(node_i, struct usb_device_config, list);
728 ALOGI_IF(usb_audio_debug_enable,
729 "%s: USB ch(%d)bw(%d), stream ch(%d)bw(%d), candidate(%d)",
730 __func__, dev_info->channels, dev_info->bit_width,
731 stream_ch, bit_width, candidate);
732 if (dev_info->bit_width != bit_width)
733 continue;
734 if (dev_info->channels== stream_ch) {
735 *ch = dev_info->channels;
736 ALOGV("%s: Found match channels (%d)",
737 __func__, dev_info->channels);
738 goto exit;
739 } else if (candidate == 0)
740 candidate = dev_info->channels;
741 /*
742 * If stream channel is 4, USB supports both 3 and 5, then
743 * higher channel 5 is picked up instead of 3
744 */
745 else if (ABS_SUB(stream_ch, dev_info->channels) <
746 ABS_SUB(stream_ch, candidate)) {
747 candidate = dev_info->channels;
748 } else if ((ABS_SUB(stream_ch, dev_info->channels) ==
749 ABS_SUB(stream_ch, candidate)) &&
750 (dev_info->channels > candidate)) {
751 candidate = dev_info->channels;
752 }
753 }
754 ALOGV("%s: No match found, use the best candidate ch(%d)",
755 __func__, candidate);
756 *ch = candidate;
757exit:
758 return true;
759
760}
761
762static bool usb_sample_rate_multiple(
763 unsigned int stream_sample_rate,
764 unsigned int base)
765{
766 return (((stream_sample_rate / base) * base) == stream_sample_rate);
767}
768
769static bool usb_find_sample_rate_candidate(unsigned int base,
770 unsigned stream_rate,
771 unsigned int usb_rate,
772 unsigned int cur_candidate,
773 unsigned int *update_candidate)
774{
775 /* For sample rate, we should consider fracational sample rate as high priority.
776 * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
777 * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
778 */
779 if (!usb_sample_rate_multiple(cur_candidate, base) &&
780 usb_sample_rate_multiple(usb_rate, base)) {
781 *update_candidate = usb_rate;
782 } else if (usb_sample_rate_multiple(cur_candidate, base) &&
783 usb_sample_rate_multiple(usb_rate, base)) {
784 if (ABS_SUB(stream_rate, usb_rate) <
785 ABS_SUB(stream_rate, cur_candidate)) {
786 *update_candidate = usb_rate;
787 } else if ((ABS_SUB(stream_rate, usb_rate) ==
788 ABS_SUB(stream_rate, cur_candidate)) &&
789 (usb_rate > cur_candidate)) {
790 *update_candidate = usb_rate;
791 }
792 } else if (!usb_sample_rate_multiple(cur_candidate, base) &&
793 !usb_sample_rate_multiple(usb_rate, base)) {
794 if (ABS_SUB(stream_rate, usb_rate) <
795 ABS_SUB(stream_rate, cur_candidate)) {
796 *update_candidate = usb_rate;
797 } else if ((ABS_SUB(stream_rate, usb_rate) ==
798 ABS_SUB(stream_rate, cur_candidate)) &&
799 (usb_rate > cur_candidate)) {
800 *update_candidate = usb_rate;
801 }
802 }
803 return true;
804}
805
806static bool usb_get_best_match_for_sample_rate(
807 struct listnode *dev_list,
808 unsigned int bit_width,
809 unsigned int ch,
810 unsigned int stream_sample_rate,
Garmond Leung5fd0b552018-04-17 11:56:12 -0700811 unsigned int *sr,
812 unsigned int service_interval,
813 bool do_service_interval_check)
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800814{
815 struct listnode *node_i;
816 struct usb_device_config *dev_info;
817 unsigned int candidate = 48000;
818 unsigned int base = SAMPLE_RATE_8000;
819 bool multiple_8k = usb_sample_rate_multiple(stream_sample_rate, base);
820 unsigned int i;
821
822 ALOGV("%s: stm ch(%d)bw(%d)sr(%d), stream sample multiple of 8kHz(%d)",
823 __func__, ch, bit_width, stream_sample_rate, multiple_8k);
824
825 list_for_each(node_i, dev_list) {
826 dev_info = node_to_item(node_i, struct usb_device_config, list);
827 ALOGI_IF(usb_audio_debug_enable,
828 "%s: USB ch(%d)bw(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
829 __func__, dev_info->channels, dev_info->bit_width,
830 ch, bit_width, stream_sample_rate, candidate);
Garmond Leung5fd0b552018-04-17 11:56:12 -0700831
832 if ((dev_info->bit_width != bit_width) ||
833 (dev_info->channels != ch) ||
834 (do_service_interval_check && (dev_info->service_interval_us !=
835 service_interval)))
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800836 continue;
837
838 candidate = 0;
839 for (i = 0; i < dev_info->rate_size; i++) {
840 ALOGI_IF(usb_audio_debug_enable,
841 "%s: USB ch(%d)bw(%d)sr(%d), stm ch(%d)bw(%d)sr(%d), candidate(%d)",
842 __func__, dev_info->channels,
843 dev_info->bit_width, dev_info->rates[i],
844 ch, bit_width, stream_sample_rate, candidate);
845 if (stream_sample_rate == dev_info->rates[i]) {
846 *sr = dev_info->rates[i];
847 ALOGV("%s: Found match sample rate (%d)",
848 __func__, dev_info->rates[i]);
849 goto exit;
850 } else if (candidate == 0) {
851 candidate = dev_info->rates[i];
852 /*
853 * For sample rate, we should consider fracational sample rate as high priority.
854 * For example, if the stream is 88.2kHz and USB device support both 44.1kH and
855 * 48kHz sample rate, we should pick 44.1kHz instead of 48kHz
856 */
857 } else if (multiple_8k) {
858 usb_find_sample_rate_candidate(SAMPLE_RATE_8000,
859 stream_sample_rate,
860 dev_info->rates[i],
861 candidate,
862 &candidate);
863 } else {
864 usb_find_sample_rate_candidate(SAMPLE_RATE_11025,
865 stream_sample_rate,
866 dev_info->rates[i],
867 candidate,
868 &candidate);
869 }
870 }
871 }
872 ALOGV("%s: No match found, use the best candidate sr(%d)",
873 __func__, candidate);
874 *sr = candidate;
875exit:
876 return true;
877}
878
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800879static bool usb_audio_backend_apply_policy(struct listnode *dev_list,
880 unsigned int *bit_width,
881 unsigned int *sample_rate,
Ashish Jainb26edfb2016-08-25 00:10:11 +0530882 unsigned int *ch)
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800883{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800884 bool is_usb_supported = true;
885
886 ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) channels (%d)",
Ashish Jainb26edfb2016-08-25 00:10:11 +0530887 __func__, *bit_width, *sample_rate, *ch);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800888 if (list_empty(dev_list)) {
889 *sample_rate = 48000;
890 *bit_width = 16;
Ashish Jainb26edfb2016-08-25 00:10:11 +0530891 *ch = 2;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800892 ALOGI("%s: list is empty,fall back to default setting", __func__);
893 goto exit;
894 }
895 usb_get_best_match_for_bit_width(dev_list, *bit_width, bit_width);
896 usb_get_best_match_for_channels(dev_list,
897 *bit_width,
Ashish Jainb26edfb2016-08-25 00:10:11 +0530898 *ch,
899 ch);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800900 usb_get_best_match_for_sample_rate(dev_list,
901 *bit_width,
Ashish Jainb26edfb2016-08-25 00:10:11 +0530902 *ch,
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800903 *sample_rate,
Garmond Leung5fd0b552018-04-17 11:56:12 -0700904 sample_rate,
905 0 /*service int*/,
906 false /*do service int check*/);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800907exit:
908 ALOGV("%s: Updated sample rate per profile: bit-width(%d) rate(%d) chs(%d)",
Ashish Jainb26edfb2016-08-25 00:10:11 +0530909 __func__, *bit_width, *sample_rate, *ch);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800910 return is_usb_supported;
911}
912
Kuirong Wang1cad7142016-05-24 15:21:56 -0700913static int usb_get_sidetone_gain(struct usb_card_config *card_info)
914{
915 int gain = card_info->usb_sidetone_vol_min + usbmod->sidetone_gain;
916 if (gain > card_info->usb_sidetone_vol_max)
917 gain = card_info->usb_sidetone_vol_max;
918 return gain;
919}
920
921void audio_extn_usb_set_sidetone_gain(struct str_parms *parms,
922 char *value, int len)
923{
924 int err;
925
926 err = str_parms_get_str(parms, USB_SIDETONE_GAIN_STR,
927 value, len);
928 if (err >= 0) {
929 usb_sidetone_gain = pow(10.0, (float)(atoi(value))/10.0);
930 ALOGV("%s: sidetone gain(%s) decimal %d",
931 __func__, value, usb_sidetone_gain);
932 str_parms_del(parms, USB_SIDETONE_GAIN_STR);
933 }
934 return;
935}
936
937int audio_extn_usb_enable_sidetone(int device, bool enable)
938{
939 int ret = -ENODEV;
940 struct listnode *node_i;
941 struct usb_card_config *card_info;
942 int i;
943 ALOGV("%s: card_dev_type (0x%x), sidetone enable(%d)",
944 __func__, device, enable);
945
946 list_for_each(node_i, &usbmod->usb_card_conf_list) {
947 card_info = node_to_item(node_i, struct usb_card_config, list);
948 ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
949 __func__, card_info->usb_device_type, card_info->usb_card);
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700950 if (usb_output_device(card_info->usb_device_type)) {
Kuirong Wang1cad7142016-05-24 15:21:56 -0700951 if ((i = card_info->usb_sidetone_index[USB_SIDETONE_ENABLE_INDEX]) != -1) {
952 struct mixer_ctl *ctl = mixer_get_ctl_by_name(
953 card_info->usb_snd_mixer,
954 usb_sidetone_enable_str[i]);
955 if (ctl)
956 mixer_ctl_set_value(ctl, 0, enable);
957 else
958 break;
959
960 if ((i = card_info->usb_sidetone_index[USB_SIDETONE_VOLUME_INDEX]) != -1) {
961 ctl = mixer_get_ctl_by_name(
962 card_info->usb_snd_mixer,
963 usb_sidetone_volume_str[i]);
964 if (ctl == NULL)
965 ALOGV("%s: sidetone gain mixer command is not found",
966 __func__);
967 else if (enable)
968 mixer_ctl_set_value(ctl, 0,
969 usb_get_sidetone_gain(card_info));
970 }
971 ret = 0;
972 break;
973 }
974 }
975 }
976 return ret;
977}
978
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800979bool audio_extn_usb_is_config_supported(unsigned int *bit_width,
980 unsigned int *sample_rate,
Kuirong Wange9894162016-08-26 15:16:39 -0700981 unsigned int *ch,
982 bool is_playback)
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800983{
984 struct listnode *node_i;
985 struct usb_card_config *card_info;
986 bool is_usb_supported = false;
987
Kuirong Wang27152a12016-11-11 10:20:30 -0800988 ALOGV("%s: from stream: bit-width(%d) sample_rate(%d) ch(%d) is_playback(%d)",
989 __func__, *bit_width, *sample_rate, *ch, is_playback);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800990 list_for_each(node_i, &usbmod->usb_card_conf_list) {
991 card_info = node_to_item(node_i, struct usb_card_config, list);
992 ALOGI_IF(usb_audio_debug_enable,
993 "%s: card_dev_type (0x%x), card_no(%d)",
994 __func__, card_info->usb_device_type, card_info->usb_card);
995 /* Currently only apply the first playback sound card configuration */
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700996 if ((is_playback && usb_output_device(card_info->usb_device_type)) ||
997 (!is_playback && usb_input_device(card_info->usb_device_type))){
Kuirong Wanga9f7cee2016-03-07 11:21:52 -0800998 is_usb_supported = usb_audio_backend_apply_policy(
999 &card_info->usb_device_conf_list,
1000 bit_width,
1001 sample_rate,
1002 ch);
1003 break;
1004 }
1005 }
Ashish Jainb26edfb2016-08-25 00:10:11 +05301006 ALOGV("%s: updated: bit-width(%d) sample_rate(%d) channels (%d)",
1007 __func__, *bit_width, *sample_rate, *ch);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001008
1009 return is_usb_supported;
1010}
1011
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001012int audio_extn_usb_get_max_channels(bool is_playback)
1013{
1014 struct listnode *node_i, *node_j;
1015 struct usb_device_config *dev_info;
1016 struct usb_card_config *card_info;
1017 unsigned int max_ch = 1;
1018 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1019 card_info = node_to_item(node_i, struct usb_card_config, list);
1020 if (usb_output_device(card_info->usb_device_type) && !is_playback)
1021 continue;
1022 else if (usb_input_device(card_info->usb_device_type) && is_playback)
1023 continue;
1024
1025 list_for_each(node_j, &card_info->usb_device_conf_list) {
1026 dev_info = node_to_item(node_j, struct usb_device_config, list);
1027 max_ch = _MAX(max_ch, dev_info->channels);
1028 }
1029 }
1030
1031 return max_ch;
1032}
1033
1034int audio_extn_usb_get_max_bit_width(bool is_playback)
1035{
1036 struct listnode *node_i, *node_j;
1037 struct usb_device_config *dev_info;
1038 struct usb_card_config *card_info;
1039 unsigned int max_bw = 16;
1040 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1041 card_info = node_to_item(node_i, struct usb_card_config, list);
1042 if (usb_output_device(card_info->usb_device_type) && !is_playback)
1043 continue;
1044 else if (usb_input_device(card_info->usb_device_type) && is_playback)
1045 continue;
1046
1047 list_for_each(node_j, &card_info->usb_device_conf_list) {
1048 dev_info = node_to_item(node_j, struct usb_device_config, list);
1049 max_bw = _MAX(max_bw, dev_info->bit_width);
1050 }
1051 }
1052
1053 return max_bw;
1054}
1055
1056int audio_extn_usb_get_sup_sample_rates(bool is_playback,
1057 uint32_t *sample_rates,
1058 uint32_t sample_rate_size)
1059{
1060 int type = is_playback ? USB_PLAYBACK : USB_CAPTURE;
1061
1062 ALOGV("%s supported_sample_rates_mask 0x%x", __func__, supported_sample_rates_mask[type]);
1063 uint32_t bm = supported_sample_rates_mask[type];
1064 uint32_t tries = _MIN(sample_rate_size, (uint32_t)__builtin_popcount(bm));
1065
1066 int i = 0;
1067 while (tries--) {
1068 int idx = __builtin_ffs(bm) - 1;
1069 sample_rates[i++] = supported_sample_rates[idx];
1070 bm &= ~(1<<idx);
1071 }
1072
1073 return i;
1074}
1075
Ashish Jain3e37a702016-11-25 12:27:15 +05301076bool audio_extn_usb_is_capture_supported()
1077{
1078 if (usbmod == NULL) {
1079 ALOGE("%s: USB device object is NULL", __func__);
1080 return false;
1081 }
1082 ALOGV("%s: capture_supported %d",__func__,usbmod->is_capture_supported);
1083 return usbmod->is_capture_supported;
1084}
1085
Zhou Song6f862822017-11-06 17:27:57 +08001086bool audio_extn_usb_is_tunnel_supported()
1087{
1088 return true;
1089}
1090
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001091void audio_extn_usb_add_device(audio_devices_t device, int card)
1092{
1093 struct usb_card_config *usb_card_info;
1094 char check_debug_enable[PROPERTY_VALUE_MAX];
Kuirong Wang27152a12016-11-11 10:20:30 -08001095 struct listnode *node_i;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001096
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -07001097 property_get("vendor.audio.usb.enable.debug", check_debug_enable, NULL);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001098 if (atoi(check_debug_enable)) {
1099 usb_audio_debug_enable = true;
1100 }
1101
1102 ALOGI_IF(usb_audio_debug_enable,
1103 "%s: parameters device(0x%x), card(%d)",
1104 __func__, device, card);
1105 if (usbmod == NULL) {
1106 ALOGE("%s: USB device object is NULL", __func__);
1107 goto exit;
1108 }
1109
1110 if (!(usb_valid_device(device)) || (card < 0)) {
1111 ALOGE("%s:device(0x%x), card(%d)",
1112 __func__, device, card);
1113 goto exit;
1114 }
1115
Kuirong Wang27152a12016-11-11 10:20:30 -08001116 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1117 usb_card_info = node_to_item(node_i, struct usb_card_config, list);
1118 ALOGI_IF(usb_audio_debug_enable,
1119 "%s: list has capability for card_dev_type (0x%x), card_no(%d)",
1120 __func__, usb_card_info->usb_device_type, usb_card_info->usb_card);
1121 /* If we have cached the capability */
1122 if ((usb_card_info->usb_device_type == device) && (usb_card_info->usb_card == card)) {
1123 ALOGV("%s: capability for device(0x%x), card(%d) is cached, no need to update",
1124 __func__, device, card);
1125 goto exit;
1126 }
1127 }
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001128 usb_card_info = calloc(1, sizeof(struct usb_card_config));
1129 if (usb_card_info == NULL) {
1130 ALOGE("%s: error unable to allocate memory",
1131 __func__);
1132 goto exit;
1133 }
1134 list_init(&usb_card_info->usb_device_conf_list);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001135 if (usb_output_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001136 if (!usb_get_device_pb_config(usb_card_info, card)){
1137 usb_card_info->usb_card = card;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001138 usb_card_info->usb_device_type = device;
Kuirong Wang1cad7142016-05-24 15:21:56 -07001139 usb_get_sidetone_mixer(usb_card_info);
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001140 list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
1141 goto exit;
1142 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001143 } else if (usb_input_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001144 if (!usb_get_device_cap_config(usb_card_info, card)) {
1145 usb_card_info->usb_card = card;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001146 usb_card_info->usb_device_type = device;
Ashish Jain3e37a702016-11-25 12:27:15 +05301147 usbmod->is_capture_supported = true;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001148 list_add_tail(&usbmod->usb_card_conf_list, &usb_card_info->list);
1149 goto exit;
1150 }
1151 }
1152 /* free memory in error case */
1153 if (usb_card_info != NULL)
1154 free(usb_card_info);
1155exit:
1156 if (usb_audio_debug_enable)
1157 usb_print_active_device();
1158 return;
1159}
1160
1161void audio_extn_usb_remove_device(audio_devices_t device, int card)
1162{
1163 struct listnode *node_i, *temp_i;
1164 struct listnode *node_j, *temp_j;
1165 struct usb_device_config *dev_info;
1166 struct usb_card_config *card_info;
1167 unsigned int i;
1168
1169 ALOGV("%s: device(0x%x), card(%d)",
1170 __func__, device, card);
1171
1172 if (usbmod == NULL) {
1173 ALOGE("%s: USB device object is NULL", __func__);
1174 goto exit;
1175 }
1176
1177 if (!(usb_valid_device(device)) || (card < 0)) {
1178 ALOGE("%s: Invalid parameters device(0x%x), card(%d)",
1179 __func__, device, card);
1180 goto exit;
1181 }
1182 list_for_each_safe(node_i, temp_i, &usbmod->usb_card_conf_list) {
1183 card_info = node_to_item(node_i, struct usb_card_config, list);
1184 ALOGV("%s: card_dev_type (0x%x), card_no(%d)",
1185 __func__, card_info->usb_device_type, card_info->usb_card);
1186 if ((device == card_info->usb_device_type) && (card == card_info->usb_card)){
1187 list_for_each_safe(node_j, temp_j, &card_info->usb_device_conf_list) {
1188 dev_info = node_to_item(node_j, struct usb_device_config, list);
1189 ALOGV("%s: bit-width(%d) channel(%d)",
1190 __func__, dev_info->bit_width, dev_info->channels);
1191 for (i = 0; i < dev_info->rate_size; i++)
1192 ALOGV("%s: rate %d", __func__, dev_info->rates[i]);
1193
1194 list_remove(node_j);
1195 free(node_to_item(node_j, struct usb_device_config, list));
1196 }
1197 list_remove(node_i);
1198 free(node_to_item(node_i, struct usb_card_config, list));
1199 }
1200 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07001201 if (audio_is_usb_in_device(device)) { // XXX not sure if we need to check for card
1202 usbmod->is_capture_supported = false;
1203 supported_sample_rates_mask[USB_CAPTURE] = 0;
1204 } else
1205 supported_sample_rates_mask[USB_PLAYBACK] = 0;
1206
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001207exit:
1208 if (usb_audio_debug_enable)
1209 usb_print_active_device();
1210
1211 return;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001212}
1213
Kevin Rocardfce19002017-08-07 19:21:36 -07001214bool audio_extn_usb_alive(int card) {
1215 char path[PATH_MAX] = {0};
1216 // snprintf should never fail
1217 (void) snprintf(path, sizeof(path), "/proc/asound/card%u/stream0", card);
1218 return access(path, F_OK) == 0;
1219}
1220
Garmond Leung5fd0b552018-04-17 11:56:12 -07001221unsigned long audio_extn_usb_find_service_interval(bool min,
1222 bool playback) {
1223 struct usb_card_config *card_info = NULL;
1224 struct usb_device_config *dev_info = NULL;
1225 struct listnode *node_i = NULL;
1226 struct listnode *node_j = NULL;
1227 unsigned long interval_us = min ? UINT_MAX : 0;
1228 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1229 card_info = node_to_item(node_i, struct usb_card_config, list);
1230 list_for_each(node_j, &card_info->usb_device_conf_list) {
1231 dev_info = node_to_item(node_j, struct usb_device_config, list);
1232 bool match = (playback && (dev_info->type == USB_PLAYBACK)) ||
1233 (!playback && (dev_info->type == USB_CAPTURE));
1234 if (match) {
1235 interval_us = min ?
1236 _MIN(interval_us, dev_info->service_interval_us) :
1237 _MAX(interval_us, dev_info->service_interval_us);
1238 }
1239 }
1240 break;
1241 }
1242 return interval_us;
1243}
1244
1245int audio_extn_usb_altset_for_service_interval(bool playback,
1246 unsigned long service_interval,
1247 uint32_t *bit_width,
1248 uint32_t *sample_rate,
1249 uint32_t *channels)
1250{
1251 struct usb_card_config *card_info = NULL;
1252 struct usb_device_config *dev_info = NULL;;
1253 struct listnode *node_i = NULL;;
1254 struct listnode *node_j = NULL;;
1255 uint32_t bw = 0;
1256 uint32_t ch = 0;
1257 uint32_t sr = 0;
1258
1259 if (service_interval == 0)
1260 return 0;
1261 /* not a valid service interval to search for */
1262
1263#define FIND_BEST_MATCH(local_var, field, cond) \
1264 list_for_each(node_i, &usbmod->usb_card_conf_list) { \
1265 /* Currently only apply the first playback sound card configuration */ \
1266 card_info = node_to_item(node_i, struct usb_card_config, list); \
1267 list_for_each(node_j, &card_info->usb_device_conf_list) { \
1268 dev_info = node_to_item(node_j, struct usb_device_config, list); \
1269 bool match = (playback && (dev_info->type == USB_PLAYBACK)) || \
1270 (!playback && (dev_info->type == USB_CAPTURE)); \
1271 if (match && (cond)) { \
Garmond Leung003d9ea2018-08-14 17:05:08 -07001272 if (dev_info->field == *field) { \
1273 local_var = dev_info->field; \
1274 break; \
1275 } \
Garmond Leung5fd0b552018-04-17 11:56:12 -07001276 local_var = _MAX(local_var, dev_info->field); \
1277 } \
1278 } \
1279 break; \
1280 }
1281
1282 FIND_BEST_MATCH(bw, bit_width, dev_info->service_interval_us == service_interval);
1283 FIND_BEST_MATCH(ch, channels, \
1284 dev_info->service_interval_us == service_interval && \
1285 dev_info->bit_width == bw);
Garmond Leung003d9ea2018-08-14 17:05:08 -07001286 sr = *sample_rate;
Garmond Leung5fd0b552018-04-17 11:56:12 -07001287 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1288 /* Currently only apply the first playback sound card configuration */
1289 card_info = node_to_item(node_i, struct usb_card_config, list);
1290 if ((playback && usb_output_device(card_info->usb_device_type)) ||
1291 (!playback && usb_input_device(card_info->usb_device_type))) {
1292 usb_get_best_match_for_sample_rate(&card_info->usb_device_conf_list,
1293 bw, ch, sr, &sr,
1294 service_interval,
1295 true);
1296 }
1297 break;
1298 }
1299
1300#define SET_OR_RETURN_ON_ERROR(arg, local_var, cond) \
1301 if (local_var != (cond)) arg = local_var; else return -1;
1302
1303 SET_OR_RETURN_ON_ERROR(*bit_width, bw, 0);
1304 SET_OR_RETURN_ON_ERROR(*sample_rate, sr, 0);
1305 SET_OR_RETURN_ON_ERROR(*channels, ch, 0);
1306 return 0;
1307#undef FIND_BEST_MATCH
1308#undef SET_OR_RETURN_ON_ERROR
1309}
1310
1311int audio_extn_usb_get_service_interval(bool playback,
1312 unsigned long *service_interval)
1313{
1314 const char *ctl_name = "USB_AUDIO_RX service_interval";
1315 struct mixer_ctl *ctl = mixer_get_ctl_by_name(usbmod->adev->mixer,
1316 ctl_name);
1317
1318 if (!playback) {
1319 ALOGE("%s not valid for capture", __func__);
1320 return -1;
1321 }
1322
1323 if (!ctl) {
1324 ALOGV("%s: could not get mixer %s", __func__, ctl_name);
1325 return -1;
1326 }
1327
1328 *service_interval = mixer_ctl_get_value(ctl, 0);
1329 return 0;
1330}
1331
1332int audio_extn_usb_set_service_interval(bool playback,
1333 unsigned long service_interval,
1334 bool *reconfig)
1335{
1336 *reconfig = false;
1337 unsigned long current_service_interval = 0;
1338 const char *ctl_name = "USB_AUDIO_RX service_interval";
1339 struct mixer_ctl *ctl = mixer_get_ctl_by_name(usbmod->adev->mixer,
1340 ctl_name);
1341
1342 if (!playback) {
1343 ALOGE("%s not valid for capture", __func__);
1344 return -1;
1345 }
1346
1347 if (!ctl) {
1348 ALOGV("%s: could not get mixer %s", __func__, ctl_name);
1349 return -1;
1350 }
1351
1352 if (audio_extn_usb_get_service_interval(playback,
1353 &current_service_interval) != 0) {
1354 ALOGE("%s Unable to get current service interval", __func__);
1355 return -1;
1356 }
1357
1358 if (current_service_interval != service_interval) {
1359 mixer_ctl_set_value(ctl, 0, service_interval);
1360 *reconfig = usbmod->usb_reconfig = true;
1361 }
1362 else
1363 *reconfig = usbmod->usb_reconfig = false;
1364 return 0;
1365}
1366
1367int audio_extn_usb_check_and_set_svc_int(struct audio_usecase *uc_info,
1368 bool starting_output_stream)
1369{
1370 struct listnode *node = NULL;
1371 struct audio_usecase *usecase = uc_info;
1372 bool reconfig = false;
1373 bool burst_mode = true;
1374 unsigned long service_interval = 0;
1375 struct audio_device *adev = usbmod->adev;
1376
1377 ALOGV("%s: enter:", __func__);
1378
1379 if ((starting_output_stream == true &&
1380 ((uc_info->id == USECASE_AUDIO_PLAYBACK_MMAP) ||
1381 (uc_info->id == USECASE_AUDIO_PLAYBACK_ULL))) ||
1382 (voice_is_call_state_active(usbmod->adev))) {
1383 burst_mode = false;
1384 } else {
1385 /* set if the valid usecase do not already exist */
1386 list_for_each(node, &adev->usecase_list) {
1387 usecase = node_to_item(node, struct audio_usecase, list);
1388 if (usecase->type == PCM_PLAYBACK &&
1389 audio_is_usb_out_device(usecase->devices & AUDIO_DEVICE_OUT_ALL_USB )) {
1390 switch (usecase->id) {
1391 case USECASE_AUDIO_PLAYBACK_MMAP:
1392 case USECASE_AUDIO_PLAYBACK_ULL:
1393 {
1394 if (uc_info != usecase) {
1395 //another ULL stream exists
1396 ALOGV("%s: another ULL Stream in active use-case list burst mode = false.", __func__);
1397 burst_mode = false;
1398 } else {
1399 ALOGV("%s:current ULL uc is the same as incoming uc_info \
1400 which means we are stopping the output stream, \
1401 we don't want to set burst mode to false", __func__);
1402 }
1403 break;
1404 }
1405 default:
1406 break;
1407 }
1408 }
1409 }
1410 }
1411
1412 ALOGV("%s: burst mode(%d).", __func__,burst_mode);
1413
1414 service_interval =
1415 audio_extn_usb_find_service_interval(!burst_mode, true /*playback*/);
1416
Yunfei Zhang688b9a72018-10-31 10:20:52 +08001417 audio_extn_usb_set_service_interval(true /*playback*/,
1418 service_interval,
1419 &reconfig);
Garmond Leung5fd0b552018-04-17 11:56:12 -07001420
1421 /* no change or not supported or no active usecases */
1422 if (reconfig)
1423 return -1;
1424 return 0;
1425}
1426
1427bool audio_extn_usb_is_reconfig_req()
1428{
1429 return usbmod->usb_reconfig;
1430}
1431
1432void audio_extn_usb_set_reconfig(bool is_required)
1433{
1434 usbmod->usb_reconfig = is_required;
1435}
1436
Sharad Sangled0a50b22018-04-05 23:28:32 +05301437bool audio_extn_usb_connected(struct str_parms *parms) {
1438 int card = -1;
1439 struct listnode *node_i = NULL;
1440 struct usb_card_config *usb_card_info = NULL;
1441 bool usb_connected = false;
1442
Weiyin Jiang63831272018-06-28 11:41:01 +08001443 if ((parms != NULL) && str_parms_get_int(parms, "card", &card) >= 0) {
Sharad Sangled0a50b22018-04-05 23:28:32 +05301444 usb_connected = audio_extn_usb_alive(card);
1445 } else {
1446 list_for_each(node_i, &usbmod->usb_card_conf_list) {
1447 usb_card_info = node_to_item(node_i, struct usb_card_config, list);
1448 if (audio_extn_usb_alive(usb_card_info->usb_card)) {
1449 usb_connected = true;
1450 break;
1451 }
1452 }
1453 }
1454 return usb_connected;
1455}
1456
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001457void audio_extn_usb_init(void *adev)
1458{
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001459 if (usbmod == NULL) {
1460 usbmod = calloc(1, sizeof(struct usb_module));
1461 if (usbmod == NULL) {
1462 ALOGE("%s: error unable to allocate memory", __func__);
1463 goto exit;
1464 }
1465 }
1466 list_init(&usbmod->usb_card_conf_list);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001467 usbmod->adev = (struct audio_device*)adev;
Kuirong Wang1cad7142016-05-24 15:21:56 -07001468 usbmod->sidetone_gain = usb_sidetone_gain;
Ashish Jain3e37a702016-11-25 12:27:15 +05301469 usbmod->is_capture_supported = false;
Garmond Leung5fd0b552018-04-17 11:56:12 -07001470 usbmod->usb_reconfig = false;
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001471exit:
1472 return;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001473}
1474
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08001475void audio_extn_usb_deinit(void)
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001476{
1477 if (NULL != usbmod){
1478 free(usbmod);
1479 usbmod = NULL;
1480 }
1481}
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001482#endif /*USB_HEADSET_ENABLED end*/