tinyalsa: add separate call for pcm prepare

Tinyalsa combines PREPARE and START calls to the driver in the pcm_start()
function.  Typically, this is needed for making a driver allocating hardware
resources that are not related to a PCM stream.

Change-Id: Ic83fad784936bbebab28e8e425debd449182db88
Signed-off-by: Omair Mohammed Abdullah <omair.m.abdullah@linux.intel.com>
Signed-off-by: David Wagner <david.wagner@intel.com>
Signed-off-by: Bruce Beare <bruce.j.beare@intel.com>
Signed-off-by: Jack Ren <jack.ren@intel.com>
Author-Tracking-BZ: 73509
Signed-off-by: Glenn Kasten <gkasten@google.com>
Bug: 16191181
diff --git a/pcm.c b/pcm.c
index 6d85839..a25428e 100644
--- a/pcm.c
+++ b/pcm.c
@@ -245,6 +245,7 @@
     int fd;
     unsigned int flags;
     int running:1;
+    int prepared:1;
     int underruns;
     unsigned int buffer_size;
     unsigned int boundary;
@@ -492,14 +493,16 @@
 
     for (;;) {
         if (!pcm->running) {
-            if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE))
-                return oops(pcm, errno, "cannot prepare channel");
+            int prepare_error = pcm_prepare(pcm);
+            if (prepare_error)
+                return prepare_error;
             if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x))
                 return oops(pcm, errno, "cannot write initial data");
             pcm->running = 1;
             return 0;
         }
         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_WRITEI_FRAMES, &x)) {
+            pcm->prepared = 0;
             pcm->running = 0;
             if (errno == EPIPE) {
                 /* we failed to make our window -- try to restart if we are
@@ -535,6 +538,7 @@
             }
         }
         if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {
+            pcm->prepared = 0;
             pcm->running = 0;
             if (errno == EPIPE) {
                     /* we failed to make our window -- try to restart */
@@ -824,6 +828,7 @@
 
     if (pcm->fd >= 0)
         close(pcm->fd);
+    pcm->prepared = 0;
     pcm->running = 0;
     pcm->buffer_size = 0;
     pcm->fd = -1;
@@ -994,11 +999,24 @@
     return pcm->fd >= 0;
 }
 
-int pcm_start(struct pcm *pcm)
+int pcm_prepare(struct pcm *pcm)
 {
+    if (pcm->prepared)
+        return 0;
+
     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_PREPARE) < 0)
         return oops(pcm, errno, "cannot prepare channel");
 
+    pcm->prepared = 1;
+    return 0;
+}
+
+int pcm_start(struct pcm *pcm)
+{
+    int prepare_error = pcm_prepare(pcm);
+    if (prepare_error)
+        return prepare_error;
+
     if (pcm->flags & PCM_MMAP)
 	    pcm_sync_ptr(pcm, 0);
 
@@ -1014,6 +1032,7 @@
     if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_DROP) < 0)
         return oops(pcm, errno, "cannot stop channel");
 
+    pcm->prepared = 0;
     pcm->running = 0;
     return 0;
 }
@@ -1212,6 +1231,7 @@
 
                 err = pcm_wait(pcm, time);
                 if (err < 0) {
+                    pcm->prepared = 0;
                     pcm->running = 0;
                     oops(pcm, err, "wait error: hw 0x%x app 0x%x avail 0x%x\n",
                         (unsigned int)pcm->mmap_status->hw_ptr,