Routines to set routes on various paths (Speaker and Headphones on Galaxy S2)
[yamaha-mc1n2-audio.git] / yamaha-mc1n2-audio.c
1 /*
2  * Copyright (C) 2012 Paul Kocialkowski <contact@paulk.fr>
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25
26 #include <linux/ioctl.h>
27
28 #define LOG_TAG "Yamaha-MC1N2-Audio"
29 #include <cutils/log.h>
30
31 #include <system/audio.h>
32
33 #include <yamaha-mc1n2-audio.h>
34
35 struct yamaha_mc1n2_audio_pdata *yamaha_mc1n2_audio_platforms[] = {
36         &galaxys2_pdata,
37 };
38
39 int yamaha_mc1n2_audio_platforms_count = sizeof(yamaha_mc1n2_audio_platforms) /
40         sizeof(struct yamaha_mc1n2_audio_pdata *);
41
42 /*
43  * IOCTL
44  */
45
46 int yamaha_mc1n2_audio_ioctl(struct yamaha_mc1n2_audio_pdata *pdata,
47         int command, struct mc1n2_ctrl_args *hw_ctrl)
48 {
49         char *hw_node = NULL;
50         int hw_fd = -1;
51         int rc = -1;
52
53         if(pdata == NULL)
54                 return -1;
55
56         hw_node = yamaha_mc1n2_audio_get_hw_node(pdata);
57         if(hw_node == NULL) {
58                 LOGE("%s: error, missing hw_node!", __func__);
59                 return -1;
60         }
61
62         hw_fd = open(hw_node, O_RDWR);
63         if(hw_fd < 0) {
64                 LOGE("%s: error, unable to open hw_node (fd is %d)!", __func__, hw_fd);
65                 return -1;
66         }
67
68         rc = ioctl(hw_fd, command, hw_ctrl);
69         if(rc < 0) {
70                 LOGE("%s: error, ioctl on hw_node failed (rc is %d)!", __func__, rc);
71                 return -1;
72         }
73
74         close(hw_fd);
75
76         return rc;
77 }
78
79 int yamaha_mc1n2_audio_ioctl_set_ctrl(struct yamaha_mc1n2_audio_pdata *pdata,
80         unsigned long command, void *data, unsigned long update_info)
81 {
82         struct mc1n2_ctrl_args hw_ctrl;
83
84         if(pdata == NULL)
85                 return -1;
86
87         memset(&hw_ctrl, 0, sizeof(hw_ctrl));
88         hw_ctrl.dCmd = command;
89         hw_ctrl.pvPrm = data;
90         hw_ctrl.dPrm = update_info;
91
92         return yamaha_mc1n2_audio_ioctl(pdata, MC1N2_IOCTL_SET_CTRL, &hw_ctrl);
93 }
94
95 int yamaha_mc1n2_audio_ioctl_notify(struct yamaha_mc1n2_audio_pdata *pdata,
96         unsigned long command)
97 {
98         struct mc1n2_ctrl_args hw_ctrl;
99
100         if(pdata == NULL)
101                 return -1;
102
103         memset(&hw_ctrl, 0, sizeof(hw_ctrl));
104         hw_ctrl.dCmd = command;
105
106         return yamaha_mc1n2_audio_ioctl(pdata, MC1N2_IOCTL_NOTIFY, &hw_ctrl);
107 }
108
109 /*
110  * Routines
111  */
112
113 int yamaha_mc1n2_audio_routine_init(struct yamaha_mc1n2_audio_pdata *pdata)
114 {
115         struct yamaha_mc1n2_audio_routine_init *routine = NULL;
116         int rc = -1;
117
118         if(pdata == NULL || pdata->ops == NULL)
119                 return -1;
120
121         routine = pdata->ops->routines.init;
122         if(routine == NULL)
123                 return -1;
124
125         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_DAC,
126                 &routine->dac_info, 0x07);
127         if(rc < 0) {
128                 LOGE("SET_DAC IOCTL failed, aborting!");
129                 return -1;
130         }
131
132         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_ADC,
133                 &routine->adc_info, 0x07);
134         if(rc < 0) {
135                 LOGE("SET_ADC IOCTL failed, aborting!");
136                 return -1;
137         }
138
139         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_SP,
140                 &routine->sp_info, 0x00);
141         if(rc < 0) {
142                 LOGE("SET_SP IOCTL failed, aborting!");
143                 return -1;
144         }
145
146         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_PDM,
147                 &routine->pdm_info, 0x7f);
148         if(rc < 0) {
149                 LOGE("SET_PDM IOCTL failed, aborting!");
150                 return -1;
151         }
152
153         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_DNG,
154                 &routine->dng_info, 0x3f3f3f);
155         if(rc < 0) {
156                 LOGE("SET_DNG IOCTL failed, aborting!");
157                 return -1;
158         }
159
160         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_SYSEQ,
161                 &routine->syseq_info, 0x03);
162         if(rc < 0) {
163                 LOGE("SET_SYSEQ IOCTL failed, aborting!");
164                 return -1;
165         }
166
167         return 0;
168 }
169
170 int yamaha_mc1n2_audio_routine_postopen(struct yamaha_mc1n2_audio_pdata *pdata)
171 {
172         struct yamaha_mc1n2_audio_routine_postopen *routine = NULL;
173         int rc = -1;
174
175         if(pdata == NULL || pdata->ops == NULL)
176                 return -1;
177
178         routine = pdata->ops->routines.postopen;
179         if(routine == NULL)
180                 return -1;
181
182         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_AUDIOENGINE,
183                 &routine->ae_info, 0x0f);
184         if(rc < 0) {
185                 LOGE("SET_AUDIOENGINE IOCTL failed, aborting!");
186                 return -1;
187         }
188
189         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_AUDIOENGINE,
190                 &routine->ae_info, 0x0f);
191         if(rc < 0) {
192                 LOGE("SET_AUDIOENGINE IOCTL failed, aborting!");
193                 return -1;
194         }
195
196         return 0;
197 }
198
199 int yamaha_mc1n2_audio_routine_route_init(struct yamaha_mc1n2_audio_pdata *pdata)
200 {
201         struct yamaha_mc1n2_audio_routine_route *routine = NULL;
202         int rc = -1;
203
204         if(pdata == NULL || pdata->ops == NULL)
205                 return -1;
206
207         routine = pdata->ops->routines.route_init;
208         if(routine == NULL)
209                 return -1;
210
211         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_PATH,
212                 &routine->path_info, 0x00);
213         if(rc < 0) {
214                 LOGE("SET_PATH IOCTL failed, aborting!");
215                 return -1;
216         }
217
218         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_DAC,
219                 &routine->dac_info, 0x07);
220         if(rc < 0) {
221                 LOGE("SET_DAC IOCTL failed, aborting!");
222                 return -1;
223         }
224
225         return 0;
226 }
227
228 int yamaha_mc1n2_audio_routine_route_start(struct yamaha_mc1n2_audio_pdata *pdata)
229 {
230         struct yamaha_mc1n2_audio_routine_route *routine = NULL;
231         int rc = -1;
232         int i;
233
234         if(pdata == NULL || pdata->ops == NULL || pdata->ops->routines.route_start == NULL)
235                 return -1;
236
237         for(i=0 ; i < pdata->ops->routines.route_start_count ; i++) {
238                 if(pdata->ops->routines.route_start[i].device == pdata->device_current &&
239                         pdata->ops->routines.route_start[i].mode == pdata->mode_current) {
240                         routine = &(pdata->ops->routines.route_start[i]);
241                         break;
242                 }
243         }
244
245         if(routine == NULL) {
246                 LOGE("Unable to find route routine for device: 0x%x",
247                         pdata->device_current);
248                 return -1;
249         }
250
251         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_AUDIOENGINE,
252                 &routine->ae_info, 0x0f);
253         if(rc < 0) {
254                 LOGE("SET_AUDIOENGINE IOCTL failed, aborting!");
255                 return -1;
256         }
257
258         rc = yamaha_mc1n2_audio_ioctl_notify(pdata, MCDRV_NOTIFY_MEDIA_PLAY_START);
259         if(rc < 0) {
260                 LOGE("NOTIFY_MEDIA_PLAY_START IOCTL failed, aborting!");
261                 return -1;
262         }
263
264         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_PATH,
265                 &routine->path_info, 0x00);
266         if(rc < 0) {
267                 LOGE("SET_PATH IOCTL failed, aborting!");
268                 return -1;
269         }
270
271         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_DAC,
272                 &routine->dac_info, 0x07);
273         if(rc < 0) {
274                 LOGE("SET_DAC IOCTL failed, aborting!");
275                 return -1;
276         }
277
278         pdata->route_started = 1;
279
280         return 0;
281 }
282
283 int yamaha_mc1n2_audio_routine_route_stop(struct yamaha_mc1n2_audio_pdata *pdata)
284 {
285         struct yamaha_mc1n2_audio_routine_route *routine = NULL;
286         int rc = -1;
287
288         if(pdata == NULL || pdata->ops == NULL)
289                 return -1;
290
291         routine = pdata->ops->routines.route_stop;
292         if(routine == NULL)
293                 return -1;
294
295         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_AUDIOENGINE,
296                 &routine->ae_info, 0x0f);
297         if(rc < 0) {
298                 LOGE("SET_AUDIOENGINE IOCTL failed, aborting!");
299                 return -1;
300         }
301
302         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_PATH,
303                 &routine->path_info, 0x00);
304         if(rc < 0) {
305                 LOGE("SET_PATH IOCTL failed, aborting!");
306                 return -1;
307         }
308
309         rc = yamaha_mc1n2_audio_ioctl_set_ctrl(pdata, MCDRV_SET_DAC,
310                 &routine->dac_info, 0x07);
311         if(rc < 0) {
312                 LOGE("SET_DAC IOCTL failed, aborting!");
313                 return -1;
314         }
315
316         pdata->route_started = 0;
317
318         return 0;
319 }
320
321 /*
322  * Values configuration
323  */
324
325 int yamaha_mc1n2_audio_set_route(struct yamaha_mc1n2_audio_pdata *pdata,
326         audio_devices_t device, audio_mode_t mode)
327 {
328         int rc;
329
330         if(pdata == NULL)
331                 return -1;
332
333         // In this case, we are making sound, so we need to switch now
334         if((pdata->device_current != device || pdata->mode_current != mode) &&
335                 pdata->route_started) {
336                 pdata->device_current = device;
337                 pdata->mode_current = mode;
338
339                 rc = yamaha_mc1n2_audio_routine_route_start(pdata);
340                 return rc;
341         }
342
343         pdata->device_current = device;
344         pdata->mode_current = mode;
345
346         return 0;
347 }
348
349 char *yamaha_mc1n2_audio_get_hw_node(struct yamaha_mc1n2_audio_pdata *pdata)
350 {
351         if(pdata == NULL)
352                 return NULL;
353
354         return pdata->ops->hw_node;
355 }
356
357 /*
358  * Init/Deinit
359  */
360
361 struct yamaha_mc1n2_audio_pdata *yamaha_mc1n2_audio_platform_get(
362         char *device_name)
363 {
364         int i;
365
366         if(device_name == NULL)
367                 return NULL;
368
369         LOGD("Found %d registered platforms",
370                 yamaha_mc1n2_audio_platforms_count);
371
372         for(i=0 ; i < yamaha_mc1n2_audio_platforms_count ; i++) {
373                 if(yamaha_mc1n2_audio_platforms[i] != NULL &&
374                         yamaha_mc1n2_audio_platforms[i]->name != NULL) {
375                         if(strcmp(yamaha_mc1n2_audio_platforms[i]->name, device_name) == 0) {
376                                 return yamaha_mc1n2_audio_platforms[i];
377                         }
378                 }
379         }
380
381         return NULL;
382 }
383
384
385 int yamaha_mc1n2_audio_start(struct yamaha_mc1n2_audio_pdata **pdata_p,
386         char *device_name)
387 {
388         struct yamaha_mc1n2_audio_pdata *pdata = NULL;
389         int rc;
390
391         if(pdata_p == NULL || device_name == NULL)
392                 return -1;
393
394         pdata = yamaha_mc1n2_audio_platform_get(device_name);
395         if(pdata == NULL) {
396                 LOGE("Unable to find requested platform: %s", device_name);
397                 return -1;
398         }
399
400         *pdata_p = pdata;
401
402         return 0;
403 }
404
405 int yamaha_mc1n2_audio_stop(struct yamaha_mc1n2_audio_pdata *pdata)
406 {
407         if(pdata == NULL)
408                 return -1;
409
410         return 0;
411 }