nxcon_kbdin.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. /****************************************************************************
  2. * nuttx/graphics/nxconsole/nxcon_kbdin.c
  3. *
  4. * Copyright (C) 2012 Gregory Nutt. All rights reserved.
  5. * Author: Gregory Nutt <gnutt@nuttx.org>
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in
  15. * the documentation and/or other materials provided with the
  16. * distribution.
  17. * 3. Neither the name NuttX nor the names of its contributors may be
  18. * used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  28. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  29. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. * POSSIBILITY OF SUCH DAMAGE.
  33. *
  34. ****************************************************************************/
  35. /****************************************************************************
  36. * Included Files
  37. ****************************************************************************/
  38. #include <nuttx/config.h>
  39. #include <fcntl.h>
  40. #include <sched.h>
  41. #include <assert.h>
  42. #include <errno.h>
  43. #include <debug.h>
  44. #include "nxcon_internal.h"
  45. #ifdef CONFIG_NXCONSOLE_NXKBDIN
  46. /****************************************************************************
  47. * Pre-processor Definitions
  48. ****************************************************************************/
  49. /****************************************************************************
  50. * Private Function Prototypes
  51. ****************************************************************************/
  52. /****************************************************************************
  53. * Private Data
  54. ****************************************************************************/
  55. /****************************************************************************
  56. * Private Functions
  57. ****************************************************************************/
  58. /****************************************************************************
  59. * Name: nxcon_pollnotify
  60. ****************************************************************************/
  61. #ifndef CONFIG_DISABLE_POLL
  62. static void nxcon_pollnotify(FAR struct nxcon_state_s *priv, pollevent_t eventset)
  63. {
  64. FAR struct pollfd *fds;
  65. irqstate_t flags;
  66. int i;
  67. /* This function may be called from an interrupt handler */
  68. for (i = 0; i < CONFIG_NXCONSOLE_NPOLLWAITERS; i++)
  69. {
  70. flags = irqsave();
  71. fds = priv->fds[i];
  72. if (fds)
  73. {
  74. fds->revents |= (fds->events & eventset);
  75. if (fds->revents != 0)
  76. {
  77. sem_post(fds->sem);
  78. }
  79. }
  80. irqrestore(flags);
  81. }
  82. }
  83. #else
  84. # define nxcon_pollnotify(priv,event)
  85. #endif
  86. /****************************************************************************
  87. * Public Functions
  88. ****************************************************************************/
  89. /****************************************************************************
  90. * Name: nxcon_read
  91. *
  92. * Description:
  93. * The optional NxConsole read method
  94. *
  95. ****************************************************************************/
  96. ssize_t nxcon_read(FAR struct file *filep, FAR char *buffer, size_t len)
  97. {
  98. FAR struct nxcon_state_s *priv;
  99. ssize_t nread;
  100. char ch;
  101. int ret;
  102. /* Recover our private state structure */
  103. DEBUGASSERT(filep && filep->f_priv);
  104. priv = (FAR struct nxcon_state_s *)filep->f_priv;
  105. /* Get exclusive access to the driver structure */
  106. ret = nxcon_semwait(priv);
  107. if (ret < 0)
  108. {
  109. gdbg("ERROR: nxcon_semwait failed\n");
  110. return ret;
  111. }
  112. /* Loop until something is read */
  113. for (nread = 0; nread < len; )
  114. {
  115. /* Get the next byte from the buffer */
  116. if (priv->head == priv->tail)
  117. {
  118. /* The circular buffer is empty. Did we read anything? */
  119. if (nread > 0)
  120. {
  121. /* Yes.. break out to return what we have. */
  122. break;
  123. }
  124. /* If the driver was opened with O_NONBLOCK option, then don't wait.
  125. * Just return EGAIN.
  126. */
  127. if (filep->f_oflags & O_NONBLOCK)
  128. {
  129. nread = -EAGAIN;
  130. break;
  131. }
  132. /* Otherwise, wait for something to be written to the circular
  133. * buffer. Increment the number of waiters so that the nxcon_write()
  134. * will not that it needs to post the semaphore to wake us up.
  135. */
  136. sched_lock();
  137. priv->nwaiters++;
  138. nxcon_sempost(priv);
  139. /* We may now be pre-empted! But that should be okay because we
  140. * have already incremented nwaiters. Pre-emption is disabled
  141. * but will be re-enabled while we are waiting.
  142. */
  143. ret = sem_wait(&priv->waitsem);
  144. /* Pre-emption will be disabled when we return. So the decrementing
  145. * nwaiters here is safe.
  146. */
  147. priv->nwaiters--;
  148. sched_unlock();
  149. /* Did we successfully get the waitsem? */
  150. if (ret >= 0)
  151. {
  152. /* Yes... then retake the mutual exclusion semaphore */
  153. ret = nxcon_semwait(priv);
  154. }
  155. /* Was the semaphore wait successful? Did we successful re-take the
  156. * mutual exclusion semaphore?
  157. */
  158. if (ret < 0)
  159. {
  160. /* No.. One of the two sem_wait's failed. */
  161. int errval = errno;
  162. gdbg("ERROR: nxcon_semwait failed\n");
  163. /* Were we awakened by a signal? Did we read anything before
  164. * we received the signal?
  165. */
  166. if (errval != EINTR || nread >= 0)
  167. {
  168. /* Yes.. return the error. */
  169. nread = -errval;
  170. }
  171. /* Break out to return what we have. Note, we can't exactly
  172. * "break" out because whichever error occurred, we do not hold
  173. * the exclusion semaphore.
  174. */
  175. goto errout_without_sem;
  176. }
  177. }
  178. else
  179. {
  180. /* The circular buffer is not empty, get the next byte from the
  181. * tail index.
  182. */
  183. ch = priv->rxbuffer[priv->tail];
  184. /* Increment the tail index and re-enable interrupts */
  185. if (++priv->tail >= CONFIG_NXCONSOLE_KBDBUFSIZE)
  186. {
  187. priv->tail = 0;
  188. }
  189. /* Add the character to the user buffer */
  190. buffer[nread] = ch;
  191. nread++;
  192. }
  193. }
  194. /* Relinquish the mutual exclusion semaphore */
  195. nxcon_sempost(priv);
  196. /* Notify all poll/select waiters that they can write to the FIFO */
  197. errout_without_sem:
  198. #ifndef CONFIG_DISABLE_POLL
  199. if (nread > 0)
  200. {
  201. nxcon_pollnotify(priv, POLLOUT);
  202. }
  203. #endif
  204. /* Return the number of characters actually read */
  205. return nread;
  206. }
  207. /****************************************************************************
  208. * Name: nxcon_poll
  209. ****************************************************************************/
  210. #ifndef CONFIG_DISABLE_POLL
  211. int nxcon_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
  212. {
  213. FAR struct inode *inode = filep->f_inode;
  214. FAR struct nxcon_state_s *priv;
  215. pollevent_t eventset;
  216. int ndx;
  217. int ret;
  218. int i;
  219. /* Some sanity checking */
  220. DEBUGASSERT(inode && inode->i_private);
  221. priv = inode->i_private;
  222. /* Get exclusive access to the driver structure */
  223. ret = nxcon_semwait(priv);
  224. if (ret < 0)
  225. {
  226. gdbg("ERROR: nxcon_semwait failed\n");
  227. return ret;
  228. }
  229. /* Are we setting up the poll? Or tearing it down? */
  230. if (setup)
  231. {
  232. /* This is a request to set up the poll. Find an available
  233. * slot for the poll structure reference
  234. */
  235. for (i = 0; i < CONFIG_NXCONSOLE_NPOLLWAITERS; i++)
  236. {
  237. /* Find an available slot */
  238. if (!priv->fds[i])
  239. {
  240. /* Bind the poll structure and this slot */
  241. priv->fds[i] = fds;
  242. fds->priv = &priv->fds[i];
  243. break;
  244. }
  245. }
  246. if (i >= CONFIG_NXCONSOLE_NPOLLWAITERS)
  247. {
  248. gdbg("ERROR: Too many poll waiters\n");
  249. fds->priv = NULL;
  250. ret = -EBUSY;
  251. goto errout;
  252. }
  253. /* Should immediately notify on any of the requested events?
  254. * This driver is always available for transmission.
  255. */
  256. eventset = POLLOUT;
  257. /* Check if the receive buffer is empty */
  258. if (priv->head != priv->tail)
  259. {
  260. eventset |= POLLIN;
  261. }
  262. if (eventset)
  263. {
  264. nxcon_pollnotify(priv, eventset);
  265. }
  266. }
  267. else if (fds->priv)
  268. {
  269. /* This is a request to tear down the poll. */
  270. struct pollfd **slot = (struct pollfd **)fds->priv;
  271. #ifdef CONFIG_DEBUG
  272. if (!slot)
  273. {
  274. gdbg("ERROR: No slot\n");
  275. ret = -EIO;
  276. goto errout;
  277. }
  278. #endif
  279. /* Remove all memory of the poll setup */
  280. *slot = NULL;
  281. fds->priv = NULL;
  282. }
  283. errout:
  284. nxcon_sempost(priv);
  285. return ret;
  286. }
  287. #endif
  288. /****************************************************************************
  289. * Name: nxcon_kbdin
  290. *
  291. * Description:
  292. * This function should be driven by the window kbdin callback function
  293. * (see nx.h). When the NxConsole is the top window and keyboard input is
  294. * received on the top window, that window callback should be directed to
  295. * this function. This function will buffer the keyboard data and may
  296. * it available to the NxConsole as stdin.
  297. *
  298. * If CONFIG_NXCONSOLE_NXKBDIN is not selected, then the NxConsole will
  299. * receive its input from stdin (/dev/console). This works great but
  300. * cannot be shared between different windows. Chaos will ensue if you
  301. * try to support multiple NxConsole windows without CONFIG_NXCONSOLE_NXKBDIN
  302. *
  303. * Input Parameters:
  304. * handle - A handle previously returned by nx_register, nxtk_register, or
  305. * nxtool_register.
  306. * buffer - The array of characters
  307. * buflen - The number of characters that are available in buffer[]
  308. *
  309. * Returned Value:
  310. * None
  311. *
  312. ****************************************************************************/
  313. void nxcon_kbdin(NXCONSOLE handle, FAR const uint8_t *buffer, uint8_t buflen)
  314. {
  315. FAR struct nxcon_state_s *priv;
  316. ssize_t nwritten;
  317. int nexthead;
  318. char ch;
  319. int ret;
  320. gvdbg("buflen=%d\n");
  321. DEBUGASSERT(handle);
  322. /* Get the reference to the driver structure from the handle */
  323. priv = (FAR struct nxcon_state_s *)handle;
  324. /* Get exclusive access to the driver structure */
  325. ret = nxcon_semwait(priv);
  326. if (ret < 0)
  327. {
  328. gdbg("ERROR: nxcon_semwait failed\n");
  329. return;
  330. }
  331. /* Loop until all of the bytes have been written. This function may be
  332. * called from an interrupt handler! Semaphores cannot be used!
  333. *
  334. * The write logic only needs to modify the head index. Therefore,
  335. * there is a difference in the way that head and tail are protected:
  336. * tail is protected with a semaphore; tail is protected by disabling
  337. * interrupts.
  338. */
  339. for (nwritten = 0; nwritten < buflen; nwritten++)
  340. {
  341. /* Add the next character */
  342. ch = buffer[nwritten];
  343. /* Calculate the write index AFTER the next byte is add to the ring
  344. * buffer
  345. */
  346. nexthead = priv->head + 1;
  347. if (nexthead >= CONFIG_NXCONSOLE_KBDBUFSIZE)
  348. {
  349. nexthead = 0;
  350. }
  351. /* Would the next write overflow the circular buffer? */
  352. if (nexthead == priv->tail)
  353. {
  354. /* Yes... Return an indication that nothing was saved in the buffer. */
  355. gdbg("ERROR: Keyboard data overrun\n");
  356. break;
  357. }
  358. /* No... copy the byte */
  359. priv->rxbuffer[priv->head] = ch;
  360. priv->head = nexthead;
  361. }
  362. /* Was anything written? */
  363. if (nwritten > 0)
  364. {
  365. int i;
  366. /* Are there threads waiting for read data? */
  367. sched_lock();
  368. for (i = 0; i < priv->nwaiters; i++)
  369. {
  370. /* Yes.. Notify all of the waiting readers that more data is available */
  371. sem_post(&priv->waitsem);
  372. }
  373. /* Notify all poll/select waiters that they can write to the FIFO */
  374. #ifndef CONFIG_DISABLE_POLL
  375. nxcon_pollnotify(priv, POLLIN);
  376. #endif
  377. sched_unlock();
  378. }
  379. nxcon_sempost(priv);
  380. }
  381. #endif /* CONFIG_NXCONSOLE_NXKBDIN */