--- /dev/null
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <alsa/asoundlib.h>
+
+#include "pr3_audio.h"
+
+
+#define MODE_NORMAL 0
+#define MODE_RINGTONE 1
+#define MODE_IN_CALL 2
+#define MODE_IN_COMMUNICATION 3
+
+#define DISCONNECT 0x00
+#define DEVICE_OUT_EARPIECE 0x1
+#define DEVICE_OUT_SPEAKER 0x2
+#define DEVICE_OUT_WIRED_HEADSET 0x4
+#define DEVICE_OUT_WIRED_HEADPHONE 0x8
+
+#define A1026_IOCTL_MAGIC 'u'
+
+#define A1026_BOOTUP_INIT _IO(A1026_IOCTL_MAGIC, 0x01)
+#define A1026_SUSPEND _IO(A1026_IOCTL_MAGIC, 0x02)
+#define A1026_ENABLE_CLOCK _IO(A1026_IOCTL_MAGIC, 0x03)
+
+#define ES305B_DEVICE "/dev/audience_es305"
+
+#define FIRMWARE_NAME_MAX_LENGTH 64
+
+static const unsigned char es305b_no_acoustic[] = { 0x80, 0x31, 0x00, 0x06 };
+
+static int a1026_enabled;
+
+static snd_pcm_t *handle_playback = NULL;
+static snd_pcm_t *handle_capture = NULL;
+
+static const char *playback_name(int mode, uint32_t device)
+{
+ switch (device) {
+ case DEVICE_OUT_EARPIECE:
+ return "VoicePlayback_Earpiece_incall";
+ case DEVICE_OUT_SPEAKER:
+ return "VoicePlayback_Speaker_incall";
+ case DEVICE_OUT_WIRED_HEADSET:
+ return "VoicePlayback_Headset_incall";
+ case DEVICE_OUT_WIRED_HEADPHONE:
+ return "VoicePlayback_Headphone_incall";
+ }
+
+ return NULL;
+}
+static const char *capture_name(int mode, uint32_t device)
+{
+ /* No distinction as ALSA mixer control are set during playback
+ * path opening */
+ return "VoiceCapture_incall";
+}
+
+static void pcm_init(void)
+{
+ int card = snd_card_get_index("medfieldaudio");
+
+ dbg("Card index: %d\n", card);
+}
+
+static void pcm_enable(int mode, uint32_t device)
+{
+ const char *pcm_playback;
+ const char *pcm_capture;
+ int err;
+
+ pcm_playback = playback_name(mode, device);
+ pcm_capture = capture_name(mode, device);
+
+ dbg("Playback: %s\n", pcm_playback);
+ dbg("Capture: %s\n", pcm_capture);
+
+ if (!pcm_playback || !pcm_capture)
+ return;
+
+ if (handle_capture) {
+ snd_pcm_close(handle_capture);
+ handle_capture = NULL;
+ }
+
+ if (handle_playback) {
+ snd_pcm_close(handle_playback);
+ handle_playback = NULL;
+ }
+
+ err = snd_pcm_open(&handle_playback, pcm_playback,
+ SND_PCM_STREAM_PLAYBACK, 0);
+ if (err < 0) {
+ err("Failed to open %s\n", pcm_playback);
+ return;
+ }
+
+ err = snd_pcm_open(&handle_capture, pcm_capture,
+ SND_PCM_STREAM_CAPTURE, 0);
+ if (err < 0) {
+ err("Failed to open %s\n", pcm_capture);
+ goto close_playback;
+ }
+
+ err = snd_pcm_set_params(handle_playback,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 2, 48000, 0, 500000); /* 0.5sec */
+ if (err < 0) {
+ err("Failed to set params for %s\n",
+ pcm_playback);
+ goto close_capture;
+ }
+
+ err = snd_pcm_set_params(handle_capture,
+ SND_PCM_FORMAT_S16_LE,
+ SND_PCM_ACCESS_RW_INTERLEAVED,
+ 1, 48000, 1, 500000); /* 0.5sec */
+ if (err < 0) {
+ err("Failed to set params for %s\n",
+ pcm_capture);
+ goto close_capture;
+ }
+
+ return;
+
+close_capture:
+ snd_pcm_close(handle_capture);
+
+close_playback:
+ snd_pcm_close(handle_playback);
+}
+
+static void pcm_disable(void)
+{
+ if (handle_capture) {
+ snd_pcm_close(handle_capture);
+ handle_capture = NULL;
+ }
+
+ if (handle_playback) {
+ snd_pcm_close(handle_playback);
+ handle_playback = NULL;
+ }
+}
+
+static void a1026_init(void)
+{
+ const unsigned char cmd1[] = { 0x80, 0x20, 0x00, 0x00 };
+ const unsigned char cmd2[] = { 0x80, 0x21, 0x00, 0x00 };
+ const char firmware_name[FIRMWARE_NAME_MAX_LENGTH] = {
+ "vpimg_es305b-NH.bin"};
+ unsigned char buf[4];
+ char label[100];
+ ssize_t written, len;
+ unsigned int i;
+ int fd, err;
+
+ dbg("A1026 init\n");
+
+ fd = open(ES305B_DEVICE, O_RDWR, 0);
+ if (fd < 0) {
+ err("Failed to open audience device\n");
+ return;
+ }
+
+ err = ioctl(fd, A1026_ENABLE_CLOCK);
+ if (err < 0) {
+ err("Failed to enable audience clock\n");
+ goto done;
+ }
+
+ err = ioctl(fd, A1026_BOOTUP_INIT, firmware_name);
+ if (err < 0) {
+ err("Failed to boot up audience\n");
+ goto done;
+ }
+
+ dbg("A1026 init done\n");
+
+ written = write(fd, cmd1, sizeof(cmd1));
+ if (written < 0)
+ err("First command failed\n");
+
+ usleep(20000);
+
+ for (i = 0; i < sizeof(label) - 1; i++) {
+ len = read(fd, buf, sizeof(buf));
+ if (len < 0) {
+ err("Read command failed\n");
+ goto suspend;
+ }
+
+ label[i] = buf[3];
+
+ written = write(fd, cmd2, sizeof(cmd2));
+ if (written < 0) {
+ err("Second command failed\n");
+ goto suspend;
+ }
+
+ usleep(5000);
+ }
+
+ err("Firmware: %s\n", label);
+
+ a1026_enabled = 0;
+
+suspend:
+ err = ioctl(fd, A1026_SUSPEND);
+ if (err < 0)
+ err("Failed to suspend audience\n");
+
+done:
+ close(fd);
+}
+
+static void a1026_wakeup(void)
+{
+ ssize_t written;
+ int fd, err;
+
+ dbg("A1026 wakeup\n");
+
+ if (a1026_enabled)
+ return;
+
+ fd = open(ES305B_DEVICE, O_RDWR, 0);
+ if (fd < 0) {
+ err("Failed to open audience device\n");
+ return;
+ }
+
+ err = ioctl(fd, A1026_ENABLE_CLOCK);
+ if (err < 0) {
+ err("Failed to enable audience clock\n");
+ goto done;
+ }
+
+ written = write(fd, es305b_no_acoustic, sizeof(es305b_no_acoustic));
+ if (written < 0)
+ err("Acoustic command failed\n");
+
+ a1026_enabled = 1;
+
+done:
+ close(fd);
+}
+
+static void a1026_suspend(void)
+{
+ int fd, err;
+
+ dbg("A1026 suspend\n");
+
+ if (!a1026_enabled)
+ return;
+
+ fd = open(ES305B_DEVICE, O_RDWR, 0);
+ if (fd < 0) {
+ err("Failed to open audience device\n");
+ return;
+ }
+
+ err = ioctl(fd, A1026_SUSPEND);
+ if (err < 0)
+ err("Failed to suspend audience\n");
+
+ a1026_enabled = 0;
+
+ close(fd);
+}
+
+static void medfield_init(void)
+{
+ a1026_init();
+
+ pcm_init();
+
+ a1026_wakeup();
+
+ usleep(50000);
+
+ /* Enable and disable voice device since otherwise it seems the
+ * first call stays silent */
+ pcm_enable(MODE_IN_CALL, DEVICE_OUT_EARPIECE);
+
+ usleep(100000);
+
+ pcm_disable();
+
+ a1026_suspend();
+}
+
+static void medfield_cleanup(void)
+{
+ pcm_disable();
+
+ a1026_suspend();
+}
+
+static void medfield_enable(int mode, uint32_t device)
+{
+ a1026_wakeup();
+
+ pcm_enable(mode, device);
+}
+
+static void medfield_disable(void)
+{
+ pcm_disable();
+
+ a1026_suspend();
+}
+
+static inline int audio_device_converter(int device)
+{
+ switch (device) {
+ case 0:
+ return DISCONNECT;
+ case CALL_SOUND_PATH_HANDSET:
+ return DEVICE_OUT_EARPIECE;
+ case CALL_SOUND_PATH_SPEAKER:
+ return DEVICE_OUT_SPEAKER;
+ default:
+ return DEVICE_OUT_EARPIECE;
+ }
+}
+
+TReturn pr3_audio_set_sound_path(TcoreHal *hal, int device)
+{
+ int devId = audio_device_converter(device);
+
+ dbg("device Id %d", devId);
+
+ if (devId == DISCONNECT)
+ medfield_disable();
+ else
+ medfield_enable(MODE_IN_CALL, devId);
+
+ return TCORE_RETURN_SUCCESS;
+}
+
+gboolean pr3_audio_init(void)
+{
+ medfield_init();
+
+ return TRUE;
+}
+
+gboolean pr3_audio_unload(void)
+{
+ medfield_cleanup();
+
+ return TRUE;
+}