static void i2schar_txcallback(FAR struct i2s_dev_s *dev, FAR struct ap_buffer_s *apb, FAR void *arg, int result) { FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg; DEBUGASSERT(priv && apb); i2svdbg("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result); /* REVISIT: If you want this to actually do something other than * test I2S data transfer, then this is the point where you would * want to let some application know that the transfer has complete. */ /* Release our reference to the audio buffer. Hopefully it will be freed * now. */ i2svdbg("Freeing apb=%p crefs=%d\n", apb, apb->crefs); apb_free(apb); }
static void i2schar_rxcallback(FAR struct i2s_dev_s *dev, FAR struct ap_buffer_s *apb, FAR void *arg, int result) { FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg; DEBUGASSERT(priv != NULL && apb != NULL); UNUSED(priv); i2sinfo("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result); /* REVISIT: If you want this to actually do something other than * test I2S data transfer, then this is the point where you would * want to pass the received I2S to some application. */ /* Release our reference to the audio buffer. Hopefully it will be freed * now. */ i2sinfo("Freeing apb=%p crefs=%d\n", apb, apb->crefs); apb_free(apb); }
static ssize_t i2schar_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) { FAR struct inode *inode = filep->f_inode; FAR struct i2schar_dev_s *priv; FAR struct ap_buffer_s *apb; size_t nbytes; int ret; i2svdbg("buffer=%p buflen=%d\n", buffer, (int)buflen); /* Get our private data structure */ DEBUGASSERT(filep && buffer); inode = filep->f_inode; DEBUGASSERT(inode); priv = (FAR struct i2schar_dev_s *)inode->i_private; DEBUGASSERT(priv); /* Verify that the buffer refers to one, correctly sized audio buffer */ DEBUGASSERT(buflen >= sizeof(struct ap_buffer_s)); apb = (FAR struct ap_buffer_s *)buffer; nbytes = apb->nmaxbytes; DEBUGASSERT(buflen >= (sizeof(struct ap_buffer_s) + nbytes)); /* Add a reference to the audio buffer */ apb_reference(apb); /* Get exclusive access to i2c character driver */ ret = sem_wait(&priv->exclsem); if (ret < 0) { ret = -errno; DEBUGASSERT(ret < 0); i2sdbg("ERROR: sem_wait returned: %d\n", ret); goto errout_with_reference; } /* Give the audio buffer to the I2S driver */ ret = I2S_SEND(priv->i2s, apb, i2schar_txcallback, priv, CONFIG_AUDIO_I2SCHAR_TXTIMEOUT); if (ret < 0) { i2sdbg("ERROR: I2S_SEND returned: %d\n", ret); goto errout_with_reference; } /* Lie to the caller and tell them that all of the bytes have been * sent. */ sem_post(&priv->exclsem); return sizeof(struct ap_buffer_s) + nbytes; errout_with_reference: apb_free(apb); sem_post(&priv->exclsem); return ret; }
static int audio_ioctl(FAR struct file *filep, int cmd, unsigned long arg) { FAR struct inode *inode = filep->f_inode; FAR struct audio_upperhalf_s *upper = inode->i_private; FAR struct audio_lowerhalf_s *lower = upper->dev; FAR struct audio_buf_desc_s *bufdesc; #ifdef CONFIG_AUDIO_MULTI_SESSION FAR void *session; #endif int ret; audvdbg("cmd: %d arg: %ld\n", cmd, arg); /* Get exclusive access to the device structures */ ret = sem_wait(&upper->exclsem); if (ret < 0) { return ret; } /* Handle built-in ioctl commands */ switch (cmd) { /* AUDIOIOC_GETCAPS - Get the audio device capabilities. * * ioctl argument: A pointer to the audio_caps_s structure. */ case AUDIOIOC_GETCAPS: { FAR struct audio_caps_s *caps = (FAR struct audio_caps_s*)((uintptr_t)arg); DEBUGASSERT(lower->ops->getcaps != NULL); audvdbg("AUDIOIOC_GETCAPS: Device=%d\n", caps->ac_type); /* Call the lower-half driver capabilities handler */ ret = lower->ops->getcaps(lower, caps->ac_type, caps); } break; case AUDIOIOC_CONFIGURE: { FAR const struct audio_caps_desc_s *caps = (FAR const struct audio_caps_desc_s*)((uintptr_t)arg); DEBUGASSERT(lower->ops->configure != NULL); audvdbg("AUDIOIOC_INITIALIZE: Device=%d\n", caps->caps.ac_type); /* Call the lower-half driver configure handler */ #ifdef CONFIG_AUDIO_MULTI_SESSION ret = lower->ops->configure(lower, caps->session, &caps->caps); #else ret = lower->ops->configure(lower, &caps->caps); #endif } break; case AUDIOIOC_SHUTDOWN: { DEBUGASSERT(lower->ops->shutdown != NULL); audvdbg("AUDIOIOC_SHUTDOWN\n"); /* Call the lower-half driver initialize handler */ ret = lower->ops->shutdown(lower); } break; /* AUDIOIOC_START - Start the audio stream. The AUDIOIOC_SETCHARACTERISTICS * command must have previously been sent. * * ioctl argument: Audio session */ case AUDIOIOC_START: { audvdbg("AUDIOIOC_START\n"); DEBUGASSERT(lower->ops->start != NULL); /* Start the audio stream */ #ifdef CONFIG_AUDIO_MULTI_SESSION session = (FAR void *) arg; ret = audio_start(upper, session); #else ret = audio_start(upper); #endif } break; /* AUDIOIOC_STOP - Stop the audio stream. * * ioctl argument: Audio session */ #ifndef CONFIG_AUDIO_EXCLUDE_STOP case AUDIOIOC_STOP: { audvdbg("AUDIOIOC_STOP\n"); DEBUGASSERT(lower->ops->stop != NULL); if (upper->started) { #ifdef CONFIG_AUDIO_MULTI_SESSION session = (FAR void *) arg; ret = lower->ops->stop(lower, session); #else ret = lower->ops->stop(lower); #endif upper->started = false; } } break; #endif /* CONFIG_AUDIO_EXCLUDE_STOP */ /* AUDIOIOC_PAUSE - Pause the audio stream. * * ioctl argument: Audio session */ #ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME case AUDIOIOC_PAUSE: { audvdbg("AUDIOIOC_PAUSE\n"); DEBUGASSERT(lower->ops->pause != NULL); if (upper->started) { #ifdef CONFIG_AUDIO_MULTI_SESSION session = (FAR void *) arg; ret = lower->ops->pause(lower, session); #else ret = lower->ops->pause(lower); #endif } } break; /* AUDIOIOC_RESUME - Resume the audio stream. * * ioctl argument: Audio session */ case AUDIOIOC_RESUME: { audvdbg("AUDIOIOC_RESUME\n"); DEBUGASSERT(lower->ops->resume != NULL); if (upper->started) { #ifdef CONFIG_AUDIO_MULTI_SESSION session = (FAR void *) arg; ret = lower->ops->resume(lower, session); #else ret = lower->ops->resume(lower); #endif } } break; #endif /* CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME */ /* AUDIOIOC_ALLOCBUFFER - Allocate an audio buffer * * ioctl argument: pointer to an audio_buf_desc_s structure */ case AUDIOIOC_ALLOCBUFFER: { audvdbg("AUDIOIOC_ALLOCBUFFER\n"); bufdesc = (FAR struct audio_buf_desc_s *) arg; if (lower->ops->allocbuffer) { ret = lower->ops->allocbuffer(lower, bufdesc); } else { /* Perform a simple kumalloc operation assuming 1 session */ ret = apb_alloc(bufdesc); } } break; /* AUDIOIOC_FREEBUFFER - Free an audio buffer * * ioctl argument: pointer to an audio_buf_desc_s structure */ case AUDIOIOC_FREEBUFFER: { audvdbg("AUDIOIOC_FREEBUFFER\n"); bufdesc = (FAR struct audio_buf_desc_s *) arg; if (lower->ops->freebuffer) { ret = lower->ops->freebuffer(lower, bufdesc); } else { /* Perform a simple kufree operation */ DEBUGASSERT(bufdesc->u.pBuffer != NULL); apb_free(bufdesc->u.pBuffer); ret = sizeof(struct audio_buf_desc_s); } } break; /* AUDIOIOC_ENQUEUEBUFFER - Enqueue an audio buffer * * ioctl argument: pointer to an audio_buf_desc_s structure */ case AUDIOIOC_ENQUEUEBUFFER: { audvdbg("AUDIOIOC_ENQUEUEBUFFER\n"); DEBUGASSERT(lower->ops->enqueuebuffer != NULL); bufdesc = (FAR struct audio_buf_desc_s *) arg; ret = lower->ops->enqueuebuffer(lower, bufdesc->u.pBuffer); } break; /* AUDIOIOC_REGISTERMQ - Register a client Message Queue * * TODO: This needs to have multi session support. */ case AUDIOIOC_REGISTERMQ: { audvdbg("AUDIOIOC_REGISTERMQ\n"); upper->usermq = (mqd_t) arg; ret = OK; } break; /* AUDIOIOC_UNREGISTERMQ - Register a client Message Queue * * TODO: This needs to have multi session support. */ case AUDIOIOC_UNREGISTERMQ: { audvdbg("AUDIOIOC_UNREGISTERMQ\n"); upper->usermq = NULL; ret = OK; } break; /* AUDIOIOC_RESERVE - Reserve a session with the driver * * ioctl argument - pointer to receive the session context */ case AUDIOIOC_RESERVE: { audvdbg("AUDIOIOC_RESERVE\n"); DEBUGASSERT(lower->ops->reserve != NULL); /* Call lower-half to perform the reservation */ #ifdef CONFIG_AUDIO_MULTI_SESSION ret = lower->ops->reserve(lower, (FAR void **) arg); #else ret = lower->ops->reserve(lower); #endif } break; /* AUDIOIOC_RESERVE - Reserve a session with the driver * * ioctl argument - pointer to receive the session context */ case AUDIOIOC_RELEASE: { audvdbg("AUDIOIOC_RELEASE\n"); DEBUGASSERT(lower->ops->release != NULL); /* Call lower-half to perform the release */ #ifdef CONFIG_AUDIO_MULTI_SESSION ret = lower->ops->release(lower, (FAR void *) arg); #else ret = lower->ops->release(lower); #endif } break; /* Any unrecognized IOCTL commands might be platform-specific ioctl commands */ default: { audvdbg("Forwarding unrecognized cmd: %d arg: %ld\n", cmd, arg); DEBUGASSERT(lower->ops->ioctl != NULL); ret = lower->ops->ioctl(lower, cmd, arg); } break; } sem_post(&upper->exclsem); return ret; }
static ssize_t i2schar_read(FAR struct file *filep, FAR char *buffer, size_t buflen) { FAR struct inode *inode; FAR struct i2schar_dev_s *priv; FAR struct ap_buffer_s *apb; size_t nbytes; int ret; i2sinfo("buffer=%p buflen=%d\n", buffer, (int)buflen); /* Get our private data structure */ DEBUGASSERT(filep != NULL && buffer != NULL); inode = filep->f_inode; DEBUGASSERT(inode != NULL); priv = (FAR struct i2schar_dev_s *)inode->i_private; DEBUGASSERT(priv != NULL); /* Verify that the buffer refers to one, correctly sized audio buffer */ DEBUGASSERT(buflen >= sizeof(struct ap_buffer_s)); apb = (FAR struct ap_buffer_s *)buffer; nbytes = apb->nmaxbytes; DEBUGASSERT(buflen >= (sizeof(struct ap_buffer_s) + nbytes)); /* Add a reference to the audio buffer */ apb_reference(apb); /* Get exclusive access to i2c character driver */ ret = nxsem_wait(&priv->exclsem); if (ret < 0) { i2serr("ERROR: nxsem_wait returned: %d\n", ret); goto errout_with_reference; } /* Give the buffer to the I2S driver */ ret = I2S_RECEIVE(priv->i2s, apb, i2schar_rxcallback, priv, CONFIG_AUDIO_I2SCHAR_RXTIMEOUT); if (ret < 0) { i2serr("ERROR: I2S_RECEIVE returned: %d\n", ret); goto errout_with_reference; } /* Lie to the caller and tell them that all of the bytes have been * received */ nxsem_post(&priv->exclsem); return sizeof(struct ap_buffer_s) + nbytes; errout_with_reference: apb_free(apb); nxsem_post(&priv->exclsem); return ret; }