tinyalsa: Add support for mmap ops

Bug: 166482201
Test: audio smoke tests

Change-Id: I22a32a3aab02e56af1e6ae901de65e86a94d6196
Signed-off-by: Rohit kumar <rohitkr@codeaurora.org>
Signed-off-by: Phani Kumar Uppalapati <phaniu@codeaurora.org>
diff --git a/include/tinyalsa/pcm_plugin.h b/include/tinyalsa/pcm_plugin.h
index 5d6f503..f1708b1 100644
--- a/include/tinyalsa/pcm_plugin.h
+++ b/include/tinyalsa/pcm_plugin.h
@@ -30,6 +30,8 @@
 #ifndef __PCM_PLUGIN_H__
 #define __PCM_PLUGIN_H__
 
+#include <poll.h>
+
 #define PCM_PLUGIN_OPEN_FN(name)                    \
     int name##_open(struct pcm_plugin **plugin,     \
                     unsigned int card,              \
@@ -63,6 +65,11 @@
     int (*drop) (struct pcm_plugin *plugin);
     int (*ioctl) (struct pcm_plugin *plugin,
                   int cmd, void *arg);
+    void* (*mmap) (struct pcm_plugin *plugin, void *addr, size_t length, int prot,
+                       int flags, off_t offset);
+    int (*munmap) (struct pcm_plugin *plugin, void *addr, size_t length);
+    int (*poll) (struct pcm_plugin *plugin, struct pollfd *pfd, nfds_t nfds,
+        int timeout);
 };
 
 struct pcm_plugin_min_max {
diff --git a/pcm.c b/pcm.c
index dc347af..c885b44 100644
--- a/pcm.c
+++ b/pcm.c
@@ -363,19 +363,19 @@
         return 0;
 
     int page_size = sysconf(_SC_PAGE_SIZE);
-    pcm->mmap_status = mmap(NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED,
-                            pcm->fd, SNDRV_PCM_MMAP_OFFSET_STATUS);
+    pcm->mmap_status = pcm->ops->mmap(pcm->data, NULL, page_size, PROT_READ, MAP_FILE | MAP_SHARED,
+                                      SNDRV_PCM_MMAP_OFFSET_STATUS);
     if (pcm->mmap_status == MAP_FAILED)
         pcm->mmap_status = NULL;
     if (!pcm->mmap_status)
         goto mmap_error;
 
-    pcm->mmap_control = mmap(NULL, page_size, PROT_READ | PROT_WRITE,
-                             MAP_FILE | MAP_SHARED, pcm->fd, SNDRV_PCM_MMAP_OFFSET_CONTROL);
+    pcm->mmap_control = pcm->ops->mmap(pcm->data, NULL, page_size, PROT_READ | PROT_WRITE,
+                             MAP_FILE | MAP_SHARED, SNDRV_PCM_MMAP_OFFSET_CONTROL);
     if (pcm->mmap_control == MAP_FAILED)
         pcm->mmap_control = NULL;
     if (!pcm->mmap_control) {
-        munmap(pcm->mmap_status, page_size);
+        pcm->ops->munmap(pcm->data, pcm->mmap_status, page_size);
         pcm->mmap_status = NULL;
         goto mmap_error;
     }
@@ -410,9 +410,9 @@
     } else {
         int page_size = sysconf(_SC_PAGE_SIZE);
         if (pcm->mmap_status)
-            munmap(pcm->mmap_status, page_size);
+            pcm->ops->munmap(pcm->data, pcm->mmap_status, page_size);
         if (pcm->mmap_control)
-            munmap(pcm->mmap_control, page_size);
+            pcm->ops->munmap(pcm->data, pcm->mmap_control, page_size);
     }
     pcm->mmap_status = NULL;
     pcm->mmap_control = NULL;
@@ -883,7 +883,7 @@
 
     if (pcm->flags & PCM_MMAP) {
         pcm_stop(pcm);
-        munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
+        pcm->ops->munmap(pcm->data, pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
     }
 
     if (pcm->data)
@@ -981,8 +981,9 @@
     pcm->buffer_size = config->period_count * config->period_size;
 
     if (flags & PCM_MMAP) {
-        pcm->mmap_buffer = mmap(NULL, pcm_frames_to_bytes(pcm, pcm->buffer_size),
-                                PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, pcm->fd, 0);
+        pcm->mmap_buffer = pcm->ops->mmap(pcm->data, NULL,
+                pcm_frames_to_bytes(pcm, pcm->buffer_size),
+                PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, 0);
         if (pcm->mmap_buffer == MAP_FAILED) {
             oops(pcm, errno, "failed to mmap buffer %d bytes\n",
                  pcm_frames_to_bytes(pcm, pcm->buffer_size));
@@ -1058,7 +1059,7 @@
 
 fail:
     if (flags & PCM_MMAP)
-        munmap(pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
+        pcm->ops->munmap(pcm->data, pcm->mmap_buffer, pcm_frames_to_bytes(pcm, pcm->buffer_size));
 fail_close:
     pcm->ops->close(pcm->data);
     pcm->data = NULL;
@@ -1225,7 +1226,7 @@
 
     do {
         /* let's wait for avail or timeout */
-        err = poll(&pfd, 1, timeout);
+        err = pcm->ops->poll(pcm->data, &pfd, 1, timeout);
         if (err < 0)
             return -errno;
 
diff --git a/pcm_hw.c b/pcm_hw.c
index 8fd78fb..f19f07b 100644
--- a/pcm_hw.c
+++ b/pcm_hw.c
@@ -38,6 +38,7 @@
 #include <poll.h>
 
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <linux/ioctl.h>
 #include <sound/asound.h>
 #include <tinyalsa/asoundlib.h>
@@ -74,6 +75,25 @@
     return ioctl(hw_data->fd, cmd, arg);
 }
 
+static int pcm_hw_poll(void *data __attribute__((unused)),
+        struct pollfd *pfd, nfds_t nfds, int timeout)
+{
+    return poll(pfd, nfds, timeout);
+}
+
+static void* pcm_hw_mmap(void *data, void *addr, size_t length, int prot,
+                       int flags, off_t offset)
+{
+    struct pcm_hw_data *hw_data = data;
+
+   return mmap(addr, length, prot, flags, hw_data->fd, offset);
+}
+
+static int pcm_hw_munmap(void *data __attribute__((unused)), void *addr, size_t length)
+{
+    return munmap(addr, length);
+}
+
 static int pcm_hw_open(unsigned int card, unsigned int device,
                 unsigned int flags, void **data,
                 __attribute__((unused)) void *node)
@@ -120,4 +140,7 @@
     .open = pcm_hw_open,
     .close = pcm_hw_close,
     .ioctl = pcm_hw_ioctl,
+    .mmap = pcm_hw_mmap,
+    .munmap = pcm_hw_munmap,
+    .poll = pcm_hw_poll,
 };
diff --git a/pcm_io.h b/pcm_io.h
index 2271d76..4d9746d 100644
--- a/pcm_io.h
+++ b/pcm_io.h
@@ -31,11 +31,17 @@
 #ifndef __PCM_H__
 #define __PCM_H__
 
+#include <poll.h>
+
 struct pcm_ops {
     int (*open) (unsigned int card, unsigned int device,
                  unsigned int flags, void **data, void *node);
     void (*close) (void *data);
     int (*ioctl) (void *data, unsigned int cmd, ...);
+    void* (*mmap) (void *data, void *addr, size_t length, int prot, int flags,
+                 off_t offset);
+    int (*munmap) (void *data, void *addr, size_t length);
+    int (*poll) (void *data, struct pollfd *pfd, nfds_t nfds, int timeout);
 };
 
 #endif /* end of __PCM_H__ */
diff --git a/pcm_plugin.c b/pcm_plugin.c
index 12ab34b..14c6cdb 100644
--- a/pcm_plugin.c
+++ b/pcm_plugin.c
@@ -510,12 +510,35 @@
     return plugin->ops->sw_params(plugin, params);
 }
 
+static int convert_plugin_to_pcm_state(int plugin_state)
+{
+    switch (plugin_state) {
+    case PCM_PLUG_STATE_SETUP:
+        return PCM_STATE_SETUP;
+    case PCM_PLUG_STATE_RUNNING:
+        return PCM_STATE_RUNNING;
+    case PCM_PLUG_STATE_PREPARED:
+        return PCM_STATE_PREPARED;
+    case PCM_PLUG_STATE_OPEN:
+        return PCM_STATE_OPEN;
+    }
+
+    return PCM_STATE_OPEN;
+}
+
 static int pcm_plug_sync_ptr(struct pcm_plug_data *plug_data,
                 struct snd_pcm_sync_ptr *sync_ptr)
 {
     struct pcm_plugin *plugin = plug_data->plugin;
+    int ret = -EBADFD;
 
-    return plugin->ops->sync_ptr(plugin, sync_ptr);
+    if (plugin->state >= PCM_PLUG_STATE_SETUP) {
+        ret = plugin->ops->sync_ptr(plugin, sync_ptr);
+        if (ret == 0)
+            sync_ptr->s.status.state = convert_plugin_to_pcm_state(plugin->state);
+    }
+
+    return ret;
 }
 
 static int pcm_plug_writei_frames(struct pcm_plug_data *plug_data,
@@ -546,10 +569,10 @@
 {
     struct pcm_plugin *plugin = plug_data->plugin;
 
-    if (plugin->state != PCM_PLUG_STATE_RUNNING)
+    if (plugin->state >= PCM_PLUG_STATE_SETUP)
+        return plugin->ops->ttstamp(plugin, tstamp);
+    else
         return -EBADFD;
-
-    return plugin->ops->ttstamp(plugin, tstamp);
 }
 
 static int pcm_plug_prepare(struct pcm_plug_data *plug_data)
@@ -648,6 +671,37 @@
     return ret;
 }
 
+static int pcm_plug_poll(void *data, struct pollfd *pfd, nfds_t nfds,
+        int timeout)
+{
+    struct pcm_plug_data *plug_data = data;
+    struct pcm_plugin *plugin = plug_data->plugin;
+
+    return plugin->ops->poll(plugin, pfd, nfds, timeout);
+}
+
+static void* pcm_plug_mmap(void *data, void *addr, size_t length, int prot,
+                       int flags, off_t offset)
+{
+    struct pcm_plug_data *plug_data = data;
+    struct pcm_plugin *plugin = plug_data->plugin;
+
+    if (plugin->state != PCM_PLUG_STATE_SETUP)
+        return NULL;
+    return plugin->ops->mmap(plugin, addr, length, prot, flags, offset);
+}
+
+static int pcm_plug_munmap(void *data, void *addr, size_t length)
+{
+    struct pcm_plug_data *plug_data = data;
+    struct pcm_plugin *plugin = plug_data->plugin;
+
+    if (plugin->state != PCM_PLUG_STATE_SETUP)
+        return -EBADFD;
+
+    return plugin->ops->munmap(plugin, addr, length);
+}
+
 static int pcm_plug_open(unsigned int card, unsigned int device,
                   unsigned int flags, void **data, void *pcm_node)
 {
@@ -669,7 +723,7 @@
 
     dl_hdl = dlopen(so_name, RTLD_NOW);
     if (!dl_hdl) {
-        fprintf(stderr, "%s: unable to open %s\n", __func__, so_name);
+        fprintf(stderr, "%s: unable to open %s: %s\n", __func__, so_name, dlerror());
         goto err_dl_open;
     } else {
         fprintf(stderr, "%s: dlopen successful for %s\n", __func__, so_name);
@@ -739,4 +793,7 @@
     .open = pcm_plug_open,
     .close = pcm_plug_close,
     .ioctl = pcm_plug_ioctl,
+    .mmap = pcm_plug_mmap,
+    .munmap = pcm_plug_munmap,
+    .poll = pcm_plug_poll,
 };