i2schar.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /****************************************************************************
  2. * drivers/i2s/i2schar.c
  3. *
  4. * This is a simple character driver for testing I2C. It is not an audio
  5. * driver but does conform to some of the buffer management heuristics of an
  6. * audio driver. It is not suitable for use in any real driver application
  7. * in its current form.
  8. *
  9. * Copyright (C) 2013, 2017-2018 Gregory Nutt. All rights reserved.
  10. * Author: Gregory Nutt <gnutt@nuttx.org>
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. *
  16. * 1. Redistributions of source code must retain the above copyright
  17. * notice, this list of conditions and the following disclaimer.
  18. * 2. Redistributions in binary form must reproduce the above copyright
  19. * notice, this list of conditions and the following disclaimer in
  20. * the documentation and/or other materials provided with the
  21. * distribution.
  22. * 3. Neither the name NuttX nor the names of its contributors may be
  23. * used to endorse or promote products derived from this software
  24. * without specific prior written permission.
  25. *
  26. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  27. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  28. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  29. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  30. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  31. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  32. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  33. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  34. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  36. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  37. * POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. ****************************************************************************/
  40. /****************************************************************************
  41. * Included Files
  42. ****************************************************************************/
  43. #include <nuttx/config.h>
  44. #include <sys/types.h>
  45. #include <stdint.h>
  46. #include <stdio.h>
  47. #include <fcntl.h>
  48. #include <string.h>
  49. #include <debug.h>
  50. #include <errno.h>
  51. #include <nuttx/kmalloc.h>
  52. #include <nuttx/fs/fs.h>
  53. #include <nuttx/audio/audio.h>
  54. #include <nuttx/audio/i2s.h>
  55. /****************************************************************************
  56. * Pre-processor Definitions
  57. ****************************************************************************/
  58. /* Configuration ************************************************************/
  59. #ifndef CONFIG_AUDIO_I2SCHAR_RXTIMEOUT
  60. # define CONFIG_AUDIO_I2SCHAR_RXTIMEOUT 0
  61. #endif
  62. #ifndef CONFIG_AUDIO_I2SCHAR_TXTIMEOUT
  63. # define CONFIG_AUDIO_I2SCHAR_TXTIMEOUT 0
  64. #endif
  65. /* Device naming ************************************************************/
  66. #define DEVNAME_FMT "/dev/i2schar%d"
  67. #define DEVNAME_FMTLEN (12 + 3 + 1)
  68. /****************************************************************************
  69. * Private Types
  70. ****************************************************************************/
  71. struct i2schar_dev_s
  72. {
  73. FAR struct i2s_dev_s *i2s; /* The lower half i2s driver */
  74. sem_t exclsem; /* Assures mutually exclusive access */
  75. };
  76. /****************************************************************************
  77. * Private Function Prototypes
  78. ****************************************************************************/
  79. /* I2S callback function */
  80. static void i2schar_rxcallback(FAR struct i2s_dev_s *dev,
  81. FAR struct ap_buffer_s *apb, FAR void *arg, int result);
  82. static void i2schar_txcallback(FAR struct i2s_dev_s *dev,
  83. FAR struct ap_buffer_s *apb, FAR void *arg,
  84. int result);
  85. /* Character driver methods */
  86. static ssize_t i2schar_read(FAR struct file *filep, FAR char *buffer,
  87. size_t buflen);
  88. static ssize_t i2schar_write(FAR struct file *filep, FAR const char *buffer,
  89. size_t buflen);
  90. static int i2schar_ioctl(FAR struct file *filep, int cmd, unsigned long arg);
  91. /****************************************************************************
  92. * Private Data
  93. ****************************************************************************/
  94. static const struct file_operations i2schar_fops =
  95. {
  96. NULL, /* open */
  97. NULL, /* close */
  98. i2schar_read, /* read */
  99. i2schar_write, /* write */
  100. NULL, /* seek */
  101. i2schar_ioctl, /* ioctl */
  102. #ifndef CONFIG_DISABLE_POLL
  103. NULL, /* poll */
  104. #endif
  105. };
  106. /****************************************************************************
  107. * Private Functions
  108. ****************************************************************************/
  109. /****************************************************************************
  110. * Name: i2schar_rxcallback
  111. *
  112. * Description:
  113. * I2S RX transfer complete callback.
  114. *
  115. * NOTE: In this test driver, the RX is simply dumped in the bit bucket.
  116. * You would not do this in a real application. You would return the
  117. * received data to the caller via some IPC.
  118. *
  119. * Also, the test buffer is simply freed. This will work if this driver
  120. * has the sole reference to buffer; in that case the buffer will be freed.
  121. * Otherwise -- memory leak! A more efficient design would recyle the
  122. * audio buffers.
  123. *
  124. ****************************************************************************/
  125. static void i2schar_rxcallback(FAR struct i2s_dev_s *dev,
  126. FAR struct ap_buffer_s *apb,
  127. FAR void *arg, int result)
  128. {
  129. FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg;
  130. DEBUGASSERT(priv != NULL && apb != NULL);
  131. UNUSED(priv);
  132. i2sinfo("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result);
  133. /* REVISIT: If you want this to actually do something other than
  134. * test I2S data transfer, then this is the point where you would
  135. * want to pass the received I2S to some application.
  136. */
  137. /* Release our reference to the audio buffer. Hopefully it will be freed
  138. * now.
  139. */
  140. i2sinfo("Freeing apb=%p crefs=%d\n", apb, apb->crefs);
  141. apb_free(apb);
  142. }
  143. /****************************************************************************
  144. * Name: i2schar_txcallback
  145. *
  146. * Description:
  147. * I2S TX transfer complete callback
  148. *
  149. * NOTE: The test buffer is simply freed. This will work if this driver
  150. * has the sole reference to buffer; in that case the buffer will be freed.
  151. * Otherwise -- memory leak! A more efficient design would recyle the
  152. * audio buffers.
  153. *
  154. ****************************************************************************/
  155. static void i2schar_txcallback(FAR struct i2s_dev_s *dev,
  156. FAR struct ap_buffer_s *apb,
  157. FAR void *arg, int result)
  158. {
  159. FAR struct i2schar_dev_s *priv = (FAR struct i2schar_dev_s *)arg;
  160. DEBUGASSERT(priv != NULL && apb != NULL);
  161. UNUSED(priv);
  162. i2sinfo("apb=%p nbytes=%d result=%d\n", apb, apb->nbytes, result);
  163. /* REVISIT: If you want this to actually do something other than
  164. * test I2S data transfer, then this is the point where you would
  165. * want to let some application know that the transfer has complete.
  166. */
  167. /* Release our reference to the audio buffer. Hopefully it will be freed
  168. * now.
  169. */
  170. i2sinfo("Freeing apb=%p crefs=%d\n", apb, apb->crefs);
  171. apb_free(apb);
  172. }
  173. /****************************************************************************
  174. * Name: i2schar_read
  175. *
  176. * Description:
  177. * Standard character driver read method
  178. *
  179. ****************************************************************************/
  180. static ssize_t i2schar_read(FAR struct file *filep, FAR char *buffer,
  181. size_t buflen)
  182. {
  183. FAR struct inode *inode;
  184. FAR struct i2schar_dev_s *priv;
  185. FAR struct ap_buffer_s *apb;
  186. size_t nbytes;
  187. int ret;
  188. i2sinfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
  189. /* Get our private data structure */
  190. DEBUGASSERT(filep != NULL && buffer != NULL);
  191. inode = filep->f_inode;
  192. DEBUGASSERT(inode != NULL);
  193. priv = (FAR struct i2schar_dev_s *)inode->i_private;
  194. DEBUGASSERT(priv != NULL);
  195. /* Verify that the buffer refers to one, correctly sized audio buffer */
  196. DEBUGASSERT(buflen >= sizeof(struct ap_buffer_s));
  197. apb = (FAR struct ap_buffer_s *)buffer;
  198. nbytes = apb->nmaxbytes;
  199. DEBUGASSERT(buflen >= (sizeof(struct ap_buffer_s) + nbytes));
  200. /* Add a reference to the audio buffer */
  201. apb_reference(apb);
  202. /* Get exclusive access to i2c character driver */
  203. ret = nxsem_wait(&priv->exclsem);
  204. if (ret < 0)
  205. {
  206. i2serr("ERROR: nxsem_wait returned: %d\n", ret);
  207. goto errout_with_reference;
  208. }
  209. /* Give the buffer to the I2S driver */
  210. ret = I2S_RECEIVE(priv->i2s, apb, i2schar_rxcallback, priv,
  211. CONFIG_AUDIO_I2SCHAR_RXTIMEOUT);
  212. if (ret < 0)
  213. {
  214. i2serr("ERROR: I2S_RECEIVE returned: %d\n", ret);
  215. goto errout_with_reference;
  216. }
  217. /* Lie to the caller and tell them that all of the bytes have been
  218. * received
  219. */
  220. nxsem_post(&priv->exclsem);
  221. return sizeof(struct ap_buffer_s) + nbytes;
  222. errout_with_reference:
  223. apb_free(apb);
  224. nxsem_post(&priv->exclsem);
  225. return ret;
  226. }
  227. /****************************************************************************
  228. * Name: i2schar_write
  229. *
  230. * Description:
  231. * Standard character driver write method
  232. *
  233. ****************************************************************************/
  234. static ssize_t i2schar_write(FAR struct file *filep, FAR const char *buffer,
  235. size_t buflen)
  236. {
  237. FAR struct inode *inode;
  238. FAR struct i2schar_dev_s *priv;
  239. FAR struct ap_buffer_s *apb;
  240. size_t nbytes;
  241. int ret;
  242. i2sinfo("buffer=%p buflen=%d\n", buffer, (int)buflen);
  243. /* Get our private data structure */
  244. DEBUGASSERT(filep && buffer);
  245. inode = filep->f_inode;
  246. DEBUGASSERT(inode);
  247. priv = (FAR struct i2schar_dev_s *)inode->i_private;
  248. DEBUGASSERT(priv);
  249. /* Verify that the buffer refers to one, correctly sized audio buffer */
  250. DEBUGASSERT(buflen >= sizeof(struct ap_buffer_s));
  251. apb = (FAR struct ap_buffer_s *)buffer;
  252. nbytes = apb->nmaxbytes;
  253. DEBUGASSERT(buflen >= (sizeof(struct ap_buffer_s) + nbytes));
  254. /* Add a reference to the audio buffer */
  255. apb_reference(apb);
  256. /* Get exclusive access to i2c character driver */
  257. ret = nxsem_wait(&priv->exclsem);
  258. if (ret < 0)
  259. {
  260. i2serr("ERROR: nxsem_wait returned: %d\n", ret);
  261. goto errout_with_reference;
  262. }
  263. /* Give the audio buffer to the I2S driver */
  264. ret = I2S_SEND(priv->i2s, apb, i2schar_txcallback, priv,
  265. CONFIG_AUDIO_I2SCHAR_TXTIMEOUT);
  266. if (ret < 0)
  267. {
  268. i2serr("ERROR: I2S_SEND returned: %d\n", ret);
  269. goto errout_with_reference;
  270. }
  271. /* Lie to the caller and tell them that all of the bytes have been
  272. * sent.
  273. */
  274. nxsem_post(&priv->exclsem);
  275. return sizeof(struct ap_buffer_s) + nbytes;
  276. errout_with_reference:
  277. apb_free(apb);
  278. nxsem_post(&priv->exclsem);
  279. return ret;
  280. }
  281. /************************************************************************************
  282. * Name: i2char_ioctl
  283. *
  284. * Description:
  285. * Perform I2S device ioctl if exists
  286. *
  287. ************************************************************************************/
  288. static int i2schar_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
  289. {
  290. FAR struct inode *inode;
  291. FAR struct i2schar_dev_s *priv;
  292. int ret = -ENOTTY;
  293. /* Get our private data structure */
  294. DEBUGASSERT(filep != NULL);
  295. inode = filep->f_inode;
  296. DEBUGASSERT(inode != NULL);
  297. priv = (FAR struct i2schar_dev_s *)inode->i_private;
  298. DEBUGASSERT(priv != NULL && priv->i2s && priv->i2s->ops);
  299. if (priv->i2s->ops->i2s_ioctl)
  300. {
  301. ret = priv->i2s->ops->i2s_ioctl(priv->i2s, cmd, arg);
  302. }
  303. return ret;
  304. }
  305. /****************************************************************************
  306. * Public Functions
  307. ****************************************************************************/
  308. /****************************************************************************
  309. * Name: i2schar_register
  310. *
  311. * Description:
  312. * Create and register the I2S character driver.
  313. *
  314. * The I2S character driver is a simple character driver that supports I2S
  315. * transfers via a read() and write(). The intent of this driver is to
  316. * support I2S testing. It is not an audio driver but does conform to some
  317. * of the buffer management heuristics of an audio driver. It is not
  318. * suitable for use in any real driver application in its current form.
  319. *
  320. * Input Parameters:
  321. * i2s - An instance of the lower half I2S driver
  322. * minor - The device minor number. The I2S character device will be
  323. * registers as /dev/i2scharN where N is the minor number
  324. *
  325. * Returned Value:
  326. * OK if the driver was successfully register; A negated errno value is
  327. * returned on any failure.
  328. *
  329. ****************************************************************************/
  330. int i2schar_register(FAR struct i2s_dev_s *i2s, int minor)
  331. {
  332. FAR struct i2schar_dev_s *priv;
  333. char devname[DEVNAME_FMTLEN];
  334. int ret;
  335. /* Sanity check */
  336. DEBUGASSERT(i2s != NULL && (unsigned)minor < 1000);
  337. /* Allocate a I2S character device structure */
  338. priv = (FAR struct i2schar_dev_s *)kmm_zalloc(sizeof(struct i2schar_dev_s));
  339. if (priv)
  340. {
  341. /* Initialize the I2S character device structure */
  342. priv->i2s = i2s;
  343. nxsem_init(&priv->exclsem, 0, 1);
  344. /* Create the character device name */
  345. snprintf(devname, DEVNAME_FMTLEN, DEVNAME_FMT, minor);
  346. ret = register_driver(devname, &i2schar_fops, 0666, priv);
  347. if (ret < 0)
  348. {
  349. /* Free the device structure if we failed to create the character
  350. * device.
  351. */
  352. kmm_free(priv);
  353. }
  354. /* Return the result of the registration */
  355. return OK;
  356. }
  357. return -ENOMEM;
  358. }