summaryrefslogtreecommitdiff
path: root/nuttx/drivers/audio/wm8904.c
diff options
context:
space:
mode:
Diffstat (limited to 'nuttx/drivers/audio/wm8904.c')
-rw-r--r--nuttx/drivers/audio/wm8904.c70
1 files changed, 60 insertions, 10 deletions
diff --git a/nuttx/drivers/audio/wm8904.c b/nuttx/drivers/audio/wm8904.c
index 02f83f375..1120aa2da 100644
--- a/nuttx/drivers/audio/wm8904.c
+++ b/nuttx/drivers/audio/wm8904.c
@@ -451,6 +451,8 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
uint32_t rightlevel;
uint16_t regval;
+ audvdbg("volume=%u mute=%u\n", volume, mute);
+
#ifndef CONFIG_AUDIO_EXCLUDE_BALANCE
/* Calculate the left channel volume level {0..1000} */
@@ -524,6 +526,7 @@ static void wm8904_setvolume(FAR struct wm8904_dev_s *priv, uint16_t volume,
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
{
+ audvdbg("bass=%u\n", bass);
#warning Missing logic
}
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
@@ -541,6 +544,7 @@ static void wm8904_setbass(FAR struct wm8904_dev_s *priv, uint8_t bass)
#ifndef CONFIG_AUDIO_EXCLUDE_TONE
static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
{
+ audvdbg("treble=%u\n", treble);
#warning Missing logic
}
#endif /* CONFIG_AUDIO_EXCLUDE_TONE */
@@ -555,11 +559,10 @@ static void wm8904_settreble(FAR struct wm8904_dev_s *priv, uint8_t treble)
static int wm8904_getcaps(FAR struct audio_lowerhalf_s *dev, int type,
FAR struct audio_caps_s *caps)
{
- audvdbg("Entry\n");
-
/* Validate the structure */
- DEBUGASSERT(caps->ac_len >= sizeof(struct audio_caps_s));
+ DEBUGASSERT(caps && caps->ac_len >= sizeof(struct audio_caps_s));
+ audvdbg("type=%d ac_type=%d\n", type, caps->ac_type);
/* Fill in the caller's structure based on requested info */
@@ -726,6 +729,7 @@ static int wm8904_configure(FAR struct audio_lowerhalf_s *dev,
#endif
int ret = OK;
+ DEBUGASSERT(priv && caps);
audvdbg("ac_type: %d\n", caps->ac_type);
/* Process the configure operation */
@@ -858,6 +862,7 @@ static int wm8904_shutdown(FAR struct audio_lowerhalf_s *dev)
{
FAR struct wm8904_dev_s *priv = (FAR struct wm8904_dev_s *)dev;
+ DEBUGASSERT(priv);
wm8904_reset(priv);
return OK;
}
@@ -881,6 +886,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
int ret;
DEBUGASSERT(i2s && priv && priv->running && apb);
+ audvdbg("apb=%p inflight=%d\n", apb, priv->inflight);
/* We do not place any restriction on the context in which this function
* is called. It may be called from an interrupt handler. Therefore, the
@@ -933,7 +939,7 @@ static void wm8904_senddone(FAR struct i2s_dev_s *i2s,
static void wm8904_returnbuffers(FAR struct wm8904_dev_s *priv)
{
FAR struct ap_buffer_s *apb;
- irqstate_t flags;
+ irqstate_t flags;
/* The doneq and in-flight values might be accessed from the interrupt
* level in some implementations. Not the best design. But we will
@@ -943,14 +949,43 @@ static void wm8904_returnbuffers(FAR struct wm8904_dev_s *priv)
flags = irqsave();
while (dq_peek(&priv->doneq) != NULL)
{
- /* Take next buffer from the queue of completed transfers */
+ /* Take the next buffer from the queue of completed transfers */
apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->doneq);
irqrestore(flags);
+ audvdbg("Returning apb=%p flags=%04x\n", apb, apb->flags);
+
+ /* Are we returning the final buffer in the stream? */
+
+ if ((apb->flags & AUDIO_APB_FINAL) != 0)
+ {
+ /* Both the pending and the done queues should be empty and there
+ * should be no buffers in-flight.
+ */
+
+ DEBUGASSERT(dq_empty(&priv->doneq) && dq_empty(&priv->pendq) &&
+ priv->inflight == 0);
+
+ /* Set the terminating flag. This will, eventually, cause the
+ * worker thread to exit (if it is not already terminating).
+ */
+
+ audvdbg("Terminating\n");
+ priv->terminating = true;
+ }
+
/* Release our reference to the audio buffer */
apb_free(apb);
+
+ /* Send the buffer back up to the previous level. */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
+#else
+ priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
+#endif
flags = irqsave();
}
@@ -993,7 +1028,8 @@ static int wm8904_sendbuffer(FAR struct wm8904_dev_s *priv)
/* Take next buffer from the queue of pending transfers */
apb = (FAR struct ap_buffer_s *)dq_remfirst(&priv->pendq);
- audvdbg("Sending apb=%p, size=%d\n", apb, apb->nbytes);
+ audvdbg("Sending apb=%p, size=%d inflight=%d\n",
+ apb, apb->nbytes, priv->inflight);
/* Increment the number of buffers in-flight before sending in order
* to avoid a possible race condition.
@@ -1082,7 +1118,9 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
WM8904_ENABLE(priv->lower);
wm8904_setvolume(priv, priv->volume, false);
- /* Loop as long as we are supposed to be running */
+ /* Loop as long as we are supposed to be running and as long as we have
+ * buffers in-flight.
+ */
while (priv->running || priv->inflight > 0)
{
@@ -1125,7 +1163,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
*/
case AUDIO_MSG_DATA_REQUEST:
- /* REVISIT this */
+ audvdbg("AUDIO_MSG_DATA_REQUEST\n");
break;
/* Stop the playback */
@@ -1134,6 +1172,7 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
case AUDIO_MSG_STOP:
/* Indicate that we are terminating */
+ audvdbg("AUDIO_MSG_STOP: Terminating\n");
priv->terminating = true;
break;
#endif
@@ -1143,11 +1182,13 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
*/
case AUDIO_MSG_ENQUEUE:
+ audvdbg("AUDIO_MSG_ENQUEUE\n");
break;
/* We will wake up from the I2S callback with this message */
case AUDIO_MSG_COMPLETE:
+ audvdbg("AUDIO_MSG_COMPLETE\n");
wm8904_returnbuffers(priv);
break;
@@ -1170,6 +1211,14 @@ static void *wm8904_workerthread(pthread_addr_t pvarg)
/* Release our reference to the buffer */
apb_free(apb);
+
+ /* Send the buffer back up to the previous level. */
+
+#ifdef CONFIG_AUDIO_MULTI_SESSION
+ priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK, NULL);
+#else
+ priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK);
+#endif
}
wm8904_givesem(&priv->pendsem);
@@ -1386,7 +1435,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
struct audio_msg_s term_msg;
int ret = -EAGAIN;
- audvdbg("Entry\n");
+ audvdbg("apb=%p\n", apb);
/* Take a reference on the new audio buffer */
@@ -1395,7 +1444,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
/* Add the new buffer to the tail of pending audio buffers */
wm8904_takesem(&priv->pendsem);
- apb->flags = AUDIO_APB_OUTPUT_ENQUEUED;
+ apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED;
dq_addlast(&apb->dq_entry, &priv->pendq);
wm8904_givesem(&priv->pendsem);
@@ -1434,6 +1483,7 @@ static int wm8904_enqueuebuffer(FAR struct audio_lowerhalf_s *dev,
static int wm8904_cancelbuffer(FAR struct audio_lowerhalf_s *dev,
FAR struct ap_buffer_s *apb)
{
+ audvdbg("apb=%p\n", apb);
return OK;
}