Example #1
0
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);
}
Example #2
0
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);
}
Example #3
0
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;
}
Example #4
0
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;
}
Example #5
0
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;
}