blob: 1199e2208cc2ff3e291ae7a257cb4c8143ef9c09 [file] [log] [blame]
Balázs Triszkaa68afd52017-05-11 03:19:29 +02001/*
2 * Copyright (c) 2017-2018 The LineageOS Project
3 * Copyright (c) 2017 Balázs Triszka <balika011@protonmail.ch>
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#define LOG_TAG "ultrasound"
19
20#include <errno.h>
21#include <stdlib.h>
22#include <cutils/log.h>
23#include "audio_hw.h"
24#include "platform_api.h"
25#include <platform.h>
26#include "ultrasound.h"
27
28#define ULTRASOUND_CALIBRATION_FILE "/persist/audio/us_cal"
29#define ULTRASOUND_CALIBRATION_MIXER "Ultrasound Calibration Data"
30
31enum {
32 ULTRASOUND_STATUS_DEFAULT,
33 ULTRASOUND_STATUS_STARTED,
34 ULTRASOUND_STATUS_STOPPED,
35};
36
37struct pcm_config pcm_config_us = {
38 .channels = 1,
39 .rate = 96000,
40 .period_size = 1024,
41 .period_count = 2,
42 .format = PCM_FORMAT_S16_LE,
43};
44
45struct ultrasound_device {
46 struct pcm *rx_pcm, *tx_pcm;
47 int state;
48 struct audio_device *adev;
49};
50
51static struct ultrasound_device *us = NULL;
52
53void us_cal_load(void)
54{
55 FILE *f;
56 char buff[5] = {0}, us_cal[64];
57 struct mixer_ctl * ctl;
58 int rc;
59
60 f = fopen(ULTRASOUND_CALIBRATION_FILE, "r");
61 if (!f) {
62 ALOGE("%s: Cannot open calibration file: %s",
63 __func__, ULTRASOUND_CALIBRATION_FILE);
64 return;
65 }
66
67 for (size_t i = 0; i < sizeof(us_cal); i++) {
68 fread(buff, 1, sizeof(buff), f);
69 us_cal[i] = strtol(buff, 0, 16);
70 }
71 fclose(f);
72
73 ctl = mixer_get_ctl_by_name(us->adev->mixer, ULTRASOUND_CALIBRATION_MIXER);
74 if (!ctl) {
75 ALOGE("%s: Could not get ctl for mixer cmd - %s",
76 __func__, ULTRASOUND_CALIBRATION_MIXER);
77 return;
78 }
79
80 rc = mixer_ctl_set_array(ctl, us_cal, sizeof(us_cal));
81 if (rc < 0)
82 ALOGE("%s: Could not set ctl, error:%d ", __func__, rc);
83}
84
85int us_init(struct audio_device *adev)
86{
87 ALOGD("%s: enter", __func__);
88
89 if (us) {
90 ALOGI("%s: ultrasound has been initialized!", __func__);
91 return 0;
92 }
93
94 us = calloc(1, sizeof(struct ultrasound_device));
95 if (!us) {
96 ALOGE("%s: Out of memory!", __func__);
97 return -ENOMEM;
98 }
99
100 us->adev = adev;
101
102 us_cal_load();
103
104 ALOGD("%s: exit, status(0)", __func__);
105
106 return 0;
107}
108
109void us_deinit(void)
110{
111 ALOGD("%s: enter", __func__);
112
113 if (us) {
114 free(us);
115 us = NULL;
116 }
117
118 ALOGD("%s: exit", __func__);
119}
120
121int stop_us(void)
122{
123 struct audio_usecase *rx_usecase, *tx_usecase;
124 int rc = 0;
125
126 ALOGD("%s: enter usecase: ultrasound", __func__);
127
128 us->state = ULTRASOUND_STATUS_STOPPED;
129 if (us->rx_pcm) {
130 pcm_close(us->rx_pcm);
131 us->rx_pcm = NULL;
132 }
133
134 if (us->tx_pcm) {
135 pcm_close(us->tx_pcm);
136 us->tx_pcm = NULL;
137 }
138
139 rx_usecase = get_usecase_from_list(us->adev, USECASE_AUDIO_ULTRASOUND_RX);
140 if (!rx_usecase) {
141 ALOGE("%s: Could not find the usecase (%d) in the list",
142 __func__, USECASE_AUDIO_ULTRASOUND_RX);
143 rc = -EINVAL;
144 } else {
145 disable_audio_route(us->adev, rx_usecase);
146 disable_snd_device(us->adev, rx_usecase->out_snd_device);
147 list_remove(&rx_usecase->list);
148 free(rx_usecase);
149 }
150
151 tx_usecase = get_usecase_from_list(us->adev, USECASE_AUDIO_ULTRASOUND_TX);
152 if (!rx_usecase) {
153 ALOGE("%s: Could not find the usecase (%d) in the list",
154 __func__, USECASE_AUDIO_ULTRASOUND_TX);
155 rc = -EINVAL;
156 } else {
157 disable_audio_route(us->adev, tx_usecase);
158 disable_snd_device(us->adev, tx_usecase->in_snd_device);
159 list_remove(&tx_usecase->list);
160 free(tx_usecase);
161 }
162
163 ALOGD("%s: exit: status(%d)", __func__, rc);
164
165 return rc;
166}
167
168int us_start(void)
169{
170 int rx_device_id, tx_device_id;
171 struct audio_usecase *rx_usecase, *tx_usecase;
172
173 ALOGD("%s: enter", __func__);
174
175 if (!us || us->state == ULTRASOUND_STATUS_STARTED)
176 return -EPERM;
177
178 ALOGD("%s: enter usecase: ultrasound", __func__);
179 rx_device_id = platform_get_pcm_device_id(USECASE_AUDIO_ULTRASOUND_RX, PCM_PLAYBACK);
180 tx_device_id = platform_get_pcm_device_id(USECASE_AUDIO_ULTRASOUND_TX, PCM_CAPTURE);
181 if (rx_device_id < 0 || tx_device_id < 0) {
182 ALOGE("%s: Invalid PCM devices (rx: %d tx: %d) for the usecase(ultrasound)",
183 __func__, rx_device_id, tx_device_id);
184 stop_us();
185 ALOGE("%s: exit: status(%d)", __func__, -EIO);
186 return -EIO;
187 }
188
189 rx_usecase = calloc(1, sizeof(struct audio_usecase));
190 if (!rx_usecase) {
191 ALOGE("%s: Out of memory!", __func__);
192 return -ENOMEM;
193 }
194
195 rx_usecase->type = PCM_PLAYBACK;
196 rx_usecase->out_snd_device = SND_DEVICE_OUT_ULTRASOUND_HANDSET;
197 rx_usecase->id = USECASE_AUDIO_ULTRASOUND_RX;
198 list_add_tail(&us->adev->usecase_list, &rx_usecase->list);
199
200 enable_snd_device(us->adev, SND_DEVICE_OUT_ULTRASOUND_HANDSET);
201 enable_audio_route(us->adev, rx_usecase);
202 ALOGV("%s: Opening PCM playback device card_id(%d) device_id(%d)",
203 __func__, us->adev->snd_card, rx_device_id);
204 us->rx_pcm = pcm_open(us->adev->snd_card, rx_device_id, PCM_OUT, &pcm_config_us);
205 if (us->rx_pcm && !pcm_is_ready(us->rx_pcm)) {
206 ALOGE("%s: %s", __func__, pcm_get_error(us->rx_pcm));
207 stop_us();
208 ALOGE("%s: exit: status(%d)", __func__, -EIO);
209 return -EIO;
210 }
211
212 tx_usecase = calloc(1, sizeof(struct audio_usecase));
213 if (!tx_usecase) {
214 ALOGE("%s: Out of memory!", __func__);
215 return -ENOMEM;
216 }
217
218 tx_usecase->type = PCM_CAPTURE;
219 tx_usecase->in_snd_device = SND_DEVICE_IN_ULTRASOUND_MIC;
220 tx_usecase->id = USECASE_AUDIO_ULTRASOUND_TX;
221 list_add_tail(&us->adev->usecase_list, &tx_usecase->list);
222
223 enable_snd_device(us->adev, SND_DEVICE_IN_ULTRASOUND_MIC);
224 enable_audio_route(us->adev, tx_usecase);
225 ALOGV("%s: Opening PCM capture device card_id(%d) device_id(%d)",
226 __func__, us->adev->snd_card, tx_device_id);
227 us->tx_pcm = pcm_open(us->adev->snd_card, tx_device_id, PCM_IN, &pcm_config_us);
228 if (us->tx_pcm && !pcm_is_ready(us->tx_pcm)) {
229 ALOGD("%s: %s", __func__, pcm_get_error(us->tx_pcm));
230 stop_us();
231 ALOGE("%s: exit: status(%d)", __func__, -EIO);
232 return -EIO;
233 }
234
235 pcm_start(us->rx_pcm);
236 pcm_start(us->tx_pcm);
237 us->state = ULTRASOUND_STATUS_STARTED;
238
239 ALOGD("%s: exit, status(0)", __func__);
240
241 return 0;
242}
243
244int us_stop(void)
245{
246 ALOGD("%s: enter", __func__);
247
248 if (!us || us->state != ULTRASOUND_STATUS_STARTED)
249 return -EPERM;
250
251 stop_us();
252
253 return 0;
254}