Move set audio path api here
[adaptation/intel_mfld/tel-plugin-mfld-blackbay.git] / src / pr3_audio.c
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <sys/ioctl.h>
4 #include <alsa/asoundlib.h>
5
6 #include "pr3_audio.h"
7
8
9 #define MODE_NORMAL             0
10 #define MODE_RINGTONE           1
11 #define MODE_IN_CALL            2
12 #define MODE_IN_COMMUNICATION   3
13
14 #define DISCONNECT      0x00
15 #define DEVICE_OUT_EARPIECE             0x1
16 #define DEVICE_OUT_SPEAKER              0x2
17 #define DEVICE_OUT_WIRED_HEADSET        0x4
18 #define DEVICE_OUT_WIRED_HEADPHONE      0x8
19
20 #define A1026_IOCTL_MAGIC 'u'
21
22 #define A1026_BOOTUP_INIT       _IO(A1026_IOCTL_MAGIC, 0x01)
23 #define A1026_SUSPEND           _IO(A1026_IOCTL_MAGIC, 0x02)
24 #define A1026_ENABLE_CLOCK      _IO(A1026_IOCTL_MAGIC, 0x03)
25
26 #define ES305B_DEVICE   "/dev/audience_es305"
27
28 #define FIRMWARE_NAME_MAX_LENGTH        64
29
30 static const unsigned char es305b_no_acoustic[] = { 0x80, 0x31, 0x00, 0x06 };
31
32 static int a1026_enabled;
33
34 static snd_pcm_t *handle_playback = NULL;
35 static snd_pcm_t *handle_capture = NULL;
36
37 static const char *playback_name(int mode, uint32_t device)
38 {
39         switch (device) {
40         case DEVICE_OUT_EARPIECE:
41                 return "VoicePlayback_Earpiece_incall";
42         case DEVICE_OUT_SPEAKER:
43                 return "VoicePlayback_Speaker_incall";
44         case DEVICE_OUT_WIRED_HEADSET:
45                 return "VoicePlayback_Headset_incall";
46         case DEVICE_OUT_WIRED_HEADPHONE:
47                 return "VoicePlayback_Headphone_incall";
48         }
49
50         return NULL;
51 }
52 static const char *capture_name(int mode, uint32_t device)
53 {
54         /* No distinction as ALSA mixer control are set during playback
55          * path opening */
56         return "VoiceCapture_incall";
57 }
58
59 static void pcm_init(void)
60 {
61         int card = snd_card_get_index("medfieldaudio");
62
63         dbg("Card index: %d\n", card);
64 }
65
66 static void pcm_enable(int mode, uint32_t device)
67 {
68         const char *pcm_playback;
69         const char *pcm_capture;
70         int err;
71
72         pcm_playback = playback_name(mode, device);
73         pcm_capture = capture_name(mode, device);
74
75         dbg("Playback: %s\n", pcm_playback);
76         dbg("Capture:  %s\n", pcm_capture);
77
78         if (!pcm_playback || !pcm_capture)
79                 return;
80
81         if (handle_capture) {
82                 snd_pcm_close(handle_capture);
83                 handle_capture = NULL;
84         }
85
86         if (handle_playback) {
87                 snd_pcm_close(handle_playback);
88                 handle_playback = NULL;
89         }
90
91         err = snd_pcm_open(&handle_playback, pcm_playback,
92                                         SND_PCM_STREAM_PLAYBACK, 0);
93         if (err < 0) {
94                 err("Failed to open %s\n", pcm_playback);
95                 return;
96         }
97
98         err = snd_pcm_open(&handle_capture, pcm_capture,
99                                         SND_PCM_STREAM_CAPTURE, 0);
100         if (err < 0) {
101                 err("Failed to open %s\n", pcm_capture);
102                 goto close_playback;
103         }
104
105         err = snd_pcm_set_params(handle_playback,
106                                         SND_PCM_FORMAT_S16_LE,
107                                         SND_PCM_ACCESS_RW_INTERLEAVED,
108                                         2, 48000, 0, 500000);   /* 0.5sec */
109         if (err < 0) {
110                 err("Failed to set params for %s\n",
111                                                         pcm_playback);
112                 goto close_capture;
113         }
114
115         err = snd_pcm_set_params(handle_capture,
116                                         SND_PCM_FORMAT_S16_LE,
117                                         SND_PCM_ACCESS_RW_INTERLEAVED,
118                                         1, 48000, 1, 500000);   /* 0.5sec */
119         if (err < 0) {
120                 err("Failed to set params for %s\n",
121                                                         pcm_capture);
122                 goto close_capture;
123         }
124
125         return;
126
127 close_capture:
128         snd_pcm_close(handle_capture);
129
130 close_playback:
131         snd_pcm_close(handle_playback);
132 }
133
134 static void pcm_disable(void)
135 {
136         if (handle_capture) {
137                 snd_pcm_close(handle_capture);
138                 handle_capture = NULL;
139         }
140
141         if (handle_playback) {
142                 snd_pcm_close(handle_playback);
143                 handle_playback = NULL;
144         }
145 }
146
147 static void a1026_init(void)
148 {
149         const unsigned char cmd1[] = { 0x80, 0x20, 0x00, 0x00 };
150         const unsigned char cmd2[] = { 0x80, 0x21, 0x00, 0x00 };
151         const char firmware_name[FIRMWARE_NAME_MAX_LENGTH] = {
152                                                 "vpimg_es305b-NH.bin"};
153         unsigned char buf[4];
154         char label[100];
155         ssize_t written, len;
156         unsigned int i;
157         int fd, err;
158
159         dbg("A1026 init\n");
160
161         fd = open(ES305B_DEVICE, O_RDWR, 0);
162         if (fd < 0) {
163                 err("Failed to open audience device\n");
164                 return;
165         }
166
167         err = ioctl(fd, A1026_ENABLE_CLOCK);
168         if (err < 0) {
169                 err("Failed to enable audience clock\n");
170                 goto done;
171         }
172
173         err = ioctl(fd, A1026_BOOTUP_INIT, firmware_name);
174         if (err < 0) {
175                 err("Failed to boot up audience\n");
176                 goto done;
177         }
178
179         dbg("A1026 init done\n");
180
181         written = write(fd, cmd1, sizeof(cmd1));
182         if (written < 0)
183                 err("First command failed\n");
184
185         usleep(20000);
186
187         for (i = 0; i < sizeof(label) - 1; i++) {
188                 len = read(fd, buf, sizeof(buf));
189                 if (len < 0) {
190                         err("Read command failed\n");
191                         goto suspend;
192                 }
193
194                 label[i] = buf[3];
195
196                 written = write(fd, cmd2, sizeof(cmd2));
197                 if (written < 0) {
198                         err("Second command failed\n");
199                         goto suspend;
200                 }
201
202                 usleep(5000);
203         }
204
205         err("Firmware: %s\n", label);
206
207         a1026_enabled = 0;
208
209 suspend:
210         err = ioctl(fd, A1026_SUSPEND);
211         if (err < 0)
212                 err("Failed to suspend audience\n");
213
214 done:
215         close(fd);
216 }
217
218 static void a1026_wakeup(void)
219 {
220         ssize_t written;
221         int fd, err;
222
223         dbg("A1026 wakeup\n");
224
225         if (a1026_enabled)
226                 return;
227
228         fd = open(ES305B_DEVICE, O_RDWR, 0);
229         if (fd < 0) {
230                 err("Failed to open audience device\n");
231                 return;
232         }
233
234         err = ioctl(fd, A1026_ENABLE_CLOCK);
235         if (err < 0) {
236                 err("Failed to enable audience clock\n");
237                 goto done;
238         }
239
240         written = write(fd, es305b_no_acoustic, sizeof(es305b_no_acoustic));
241         if (written < 0)
242                 err("Acoustic command failed\n");
243
244         a1026_enabled = 1;
245
246 done:
247         close(fd);
248 }
249
250 static void a1026_suspend(void)
251 {
252         int fd, err;
253
254         dbg("A1026 suspend\n");
255
256         if (!a1026_enabled)
257                 return;
258
259         fd = open(ES305B_DEVICE, O_RDWR, 0);
260         if (fd < 0) {
261                 err("Failed to open audience device\n");
262                 return;
263         }
264
265         err = ioctl(fd, A1026_SUSPEND);
266         if (err < 0)
267                 err("Failed to suspend audience\n");
268
269         a1026_enabled = 0;
270
271         close(fd);
272 }
273
274 static void medfield_init(void)
275 {
276         a1026_init();
277
278         pcm_init();
279
280         a1026_wakeup();
281
282         usleep(50000);
283
284         /* Enable and disable voice device since otherwise it seems the
285          * first call stays silent */
286         pcm_enable(MODE_IN_CALL, DEVICE_OUT_EARPIECE);
287
288         usleep(100000);
289
290         pcm_disable();
291
292         a1026_suspend();
293 }
294
295 static void medfield_cleanup(void)
296 {
297         pcm_disable();
298
299         a1026_suspend();
300 }
301
302 static void medfield_enable(int mode, uint32_t device)
303 {
304         a1026_wakeup();
305
306         pcm_enable(mode, device);
307 }
308
309 static void medfield_disable(void)
310 {
311         pcm_disable();
312
313         a1026_suspend();
314 }
315
316 static inline int audio_device_converter(int device)
317 {
318         switch (device) {
319         case 0:
320                 return DISCONNECT;
321         case CALL_SOUND_PATH_HANDSET:
322                 return DEVICE_OUT_EARPIECE;
323         case CALL_SOUND_PATH_SPEAKER:
324                 return DEVICE_OUT_SPEAKER;
325         default:
326                 return DEVICE_OUT_EARPIECE;
327         }
328 }
329
330 TReturn pr3_audio_set_sound_path(TcoreHal *hal, int device)
331 {
332         int devId = audio_device_converter(device);
333
334         dbg("device Id %d", devId);
335
336         if (devId == DISCONNECT)
337                 medfield_disable();
338         else
339                 medfield_enable(MODE_IN_CALL, devId);
340
341         return TCORE_RETURN_SUCCESS;
342 }
343
344 gboolean pr3_audio_init(void)
345 {
346         medfield_init();
347
348         return TRUE;
349 }
350
351 gboolean pr3_audio_unload(void)
352 {
353         medfield_cleanup();
354
355         return TRUE;
356 }