nxterm_kbdin.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. /****************************************************************************
  2. * graphics/nxterm/nxterm_kbdin.c
  3. *
  4. * Licensed to the Apache Software Foundation (ASF) under one or more
  5. * contributor license agreements. See the NOTICE file distributed with
  6. * this work for additional information regarding copyright ownership. The
  7. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  8. * "License"); you may not use this file except in compliance with the
  9. * License. You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  15. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  16. * License for the specific language governing permissions and limitations
  17. * under the License.
  18. *
  19. ****************************************************************************/
  20. /****************************************************************************
  21. * Included Files
  22. ****************************************************************************/
  23. #include <nuttx/config.h>
  24. #include <inttypes.h>
  25. #include <fcntl.h>
  26. #include <sched.h>
  27. #include <assert.h>
  28. #include <poll.h>
  29. #include <errno.h>
  30. #include <debug.h>
  31. #include <nuttx/irq.h>
  32. #include "nxterm.h"
  33. #ifdef CONFIG_NXTERM_NXKBDIN
  34. /****************************************************************************
  35. * Private Functions
  36. ****************************************************************************/
  37. /****************************************************************************
  38. * Name: nxterm_pollnotify
  39. ****************************************************************************/
  40. static void nxterm_pollnotify(FAR struct nxterm_state_s *priv,
  41. pollevent_t eventset)
  42. {
  43. FAR struct pollfd *fds;
  44. irqstate_t flags;
  45. int i;
  46. /* This function may be called from an interrupt handler */
  47. for (i = 0; i < CONFIG_NXTERM_NPOLLWAITERS; i++)
  48. {
  49. flags = enter_critical_section();
  50. fds = priv->fds[i];
  51. if (fds)
  52. {
  53. fds->revents |= (fds->events & eventset);
  54. if (fds->revents != 0)
  55. {
  56. nxsem_post(fds->sem);
  57. }
  58. }
  59. leave_critical_section(flags);
  60. }
  61. }
  62. /****************************************************************************
  63. * Public Functions
  64. ****************************************************************************/
  65. /****************************************************************************
  66. * Name: nxterm_read
  67. *
  68. * Description:
  69. * The optional NxTerm read method
  70. *
  71. ****************************************************************************/
  72. ssize_t nxterm_read(FAR struct file *filep, FAR char *buffer, size_t len)
  73. {
  74. FAR struct nxterm_state_s *priv;
  75. ssize_t nread;
  76. char ch;
  77. int ret;
  78. /* Recover our private state structure */
  79. DEBUGASSERT(filep && filep->f_priv);
  80. priv = (FAR struct nxterm_state_s *)filep->f_priv;
  81. /* Get exclusive access to the driver structure */
  82. ret = nxterm_semwait(priv);
  83. if (ret < 0)
  84. {
  85. gerr("ERROR: nxterm_semwait failed\n");
  86. return ret;
  87. }
  88. /* Loop until something is read */
  89. for (nread = 0; nread < len; )
  90. {
  91. /* Get the next byte from the buffer */
  92. if (priv->head == priv->tail)
  93. {
  94. /* The circular buffer is empty. Did we read anything? */
  95. if (nread > 0)
  96. {
  97. /* Yes.. break out to return what we have. */
  98. break;
  99. }
  100. /* If the driver was opened with O_NONBLOCK option, then
  101. * don't wait. Just return EGAIN.
  102. */
  103. if (filep->f_oflags & O_NONBLOCK)
  104. {
  105. nread = -EAGAIN;
  106. break;
  107. }
  108. /* Otherwise, wait for something to be written to the circular
  109. * buffer. Increment the number of waiters so that the
  110. * nxterm_write() will not that it needs to post the semaphore
  111. * to wake us up.
  112. */
  113. sched_lock();
  114. priv->nwaiters++;
  115. nxterm_sempost(priv);
  116. /* We may now be pre-empted! But that should be okay because we
  117. * have already incremented nwaiters. Pre-emption is disabled
  118. * but will be re-enabled while we are waiting.
  119. */
  120. ret = nxsem_wait(&priv->waitsem);
  121. /* Pre-emption will be disabled when we return. So the
  122. * decrementing nwaiters here is safe.
  123. */
  124. priv->nwaiters--;
  125. sched_unlock();
  126. /* Did we successfully get the waitsem? */
  127. if (ret >= 0)
  128. {
  129. /* Yes... then retake the mutual exclusion semaphore */
  130. ret = nxterm_semwait(priv);
  131. }
  132. /* Was the semaphore wait successful? Did we successful re-take the
  133. * mutual exclusion semaphore?
  134. */
  135. if (ret < 0)
  136. {
  137. /* No.. One of the two nxterm_semwait's failed. */
  138. gerr("ERROR: nxterm_semwait failed\n");
  139. /* Were we awakened by a signal? Did we read anything before
  140. * we received the signal?
  141. */
  142. if (ret != -EINTR || nread >= 0)
  143. {
  144. /* Yes.. return the error. */
  145. nread = ret;
  146. }
  147. /* Break out to return what we have. Note, we can't exactly
  148. * "break" out because whichever error occurred, we do not hold
  149. * the exclusion semaphore.
  150. */
  151. goto errout_without_sem;
  152. }
  153. }
  154. else
  155. {
  156. /* The circular buffer is not empty, get the next byte from the
  157. * tail index.
  158. */
  159. ch = priv->rxbuffer[priv->tail];
  160. /* Increment the tail index and re-enable interrupts */
  161. if (++priv->tail >= CONFIG_NXTERM_KBDBUFSIZE)
  162. {
  163. priv->tail = 0;
  164. }
  165. /* Add the character to the user buffer */
  166. buffer[nread] = ch;
  167. nread++;
  168. }
  169. }
  170. /* Relinquish the mutual exclusion semaphore */
  171. nxterm_sempost(priv);
  172. /* Notify all poll/select waiters that they can write to the FIFO */
  173. errout_without_sem:
  174. if (nread > 0)
  175. {
  176. nxterm_pollnotify(priv, POLLOUT);
  177. }
  178. /* Return the number of characters actually read */
  179. return nread;
  180. }
  181. /****************************************************************************
  182. * Name: nxterm_poll
  183. ****************************************************************************/
  184. int nxterm_poll(FAR struct file *filep, FAR struct pollfd *fds, bool setup)
  185. {
  186. FAR struct inode *inode = filep->f_inode;
  187. FAR struct nxterm_state_s *priv;
  188. pollevent_t eventset;
  189. int ret;
  190. int i;
  191. /* Some sanity checking */
  192. DEBUGASSERT(inode && inode->i_private);
  193. priv = inode->i_private;
  194. /* Get exclusive access to the driver structure */
  195. ret = nxterm_semwait(priv);
  196. if (ret < 0)
  197. {
  198. gerr("ERROR: nxterm_semwait failed\n");
  199. return ret;
  200. }
  201. /* Are we setting up the poll? Or tearing it down? */
  202. if (setup)
  203. {
  204. /* This is a request to set up the poll. Find an available
  205. * slot for the poll structure reference
  206. */
  207. for (i = 0; i < CONFIG_NXTERM_NPOLLWAITERS; i++)
  208. {
  209. /* Find an available slot */
  210. if (!priv->fds[i])
  211. {
  212. /* Bind the poll structure and this slot */
  213. priv->fds[i] = fds;
  214. fds->priv = &priv->fds[i];
  215. break;
  216. }
  217. }
  218. if (i >= CONFIG_NXTERM_NPOLLWAITERS)
  219. {
  220. gerr("ERROR: Too many poll waiters\n");
  221. fds->priv = NULL;
  222. ret = -EBUSY;
  223. goto errout;
  224. }
  225. /* Should immediately notify on any of the requested events?
  226. * This driver is always available for transmission.
  227. */
  228. eventset = POLLOUT;
  229. /* Check if the receive buffer is empty */
  230. if (priv->head != priv->tail)
  231. {
  232. eventset |= POLLIN;
  233. }
  234. if (eventset)
  235. {
  236. nxterm_pollnotify(priv, eventset);
  237. }
  238. }
  239. else if (fds->priv)
  240. {
  241. /* This is a request to tear down the poll. */
  242. struct pollfd **slot = (struct pollfd **)fds->priv;
  243. #ifdef CONFIG_DEBUG_GRAPHICS
  244. if (!slot)
  245. {
  246. gerr("ERROR: No slot\n");
  247. ret = -EIO;
  248. goto errout;
  249. }
  250. #endif
  251. /* Remove all memory of the poll setup */
  252. *slot = NULL;
  253. fds->priv = NULL;
  254. }
  255. errout:
  256. nxterm_sempost(priv);
  257. return ret;
  258. }
  259. /****************************************************************************
  260. * Name: nxterm_kbdin
  261. *
  262. * Description:
  263. * This function should be driven by the window kbdin callback function
  264. * (see nx.h). When the NxTerm is the top window and keyboard input is
  265. * received on the top window, that window callback should be directed to
  266. * this function. This function will buffer the keyboard data and makE
  267. * it available to the NxTerm as stdin.
  268. *
  269. * If CONFIG_NXTERM_NXKBDIN is not selected, then the NxTerm will
  270. * receive its input from stdin (/dev/console). This works great but
  271. * cannot be shared between different windows. Chaos will ensue if you
  272. * try to support multiple NxTerm windows without CONFIG_NXTERM_NXKBDIN
  273. *
  274. * Input Parameters:
  275. * handle - A handle previously returned by nx_register, nxtk_register, or
  276. * nxtool_register.
  277. * buffer - The array of characters
  278. * buflen - The number of characters that are available in buffer[]
  279. *
  280. * Returned Value:
  281. * None
  282. *
  283. ****************************************************************************/
  284. void nxterm_kbdin(NXTERM handle, FAR const uint8_t *buffer, uint8_t buflen)
  285. {
  286. FAR struct nxterm_state_s *priv;
  287. ssize_t nwritten;
  288. int nexthead;
  289. char ch;
  290. int ret;
  291. ginfo("buflen=%" PRId8 "\n", buflen);
  292. DEBUGASSERT(handle);
  293. /* Get the reference to the driver structure from the handle */
  294. priv = (FAR struct nxterm_state_s *)handle;
  295. /* Get exclusive access to the driver structure */
  296. ret = nxterm_semwait(priv);
  297. if (ret < 0)
  298. {
  299. gerr("ERROR: nxterm_semwait failed\n");
  300. return;
  301. }
  302. /* Loop until all of the bytes have been written. This function may be
  303. * called from an interrupt handler! Semaphores cannot be used!
  304. *
  305. * The write logic only needs to modify the head index. Therefore,
  306. * there is a difference in the way that head and tail are protected:
  307. * tail is protected with a semaphore; tail is protected by disabling
  308. * interrupts.
  309. */
  310. for (nwritten = 0; nwritten < buflen; nwritten++)
  311. {
  312. /* Add the next character */
  313. ch = buffer[nwritten];
  314. /* Calculate the write index AFTER the next byte is add to the ring
  315. * buffer
  316. */
  317. nexthead = priv->head + 1;
  318. if (nexthead >= CONFIG_NXTERM_KBDBUFSIZE)
  319. {
  320. nexthead = 0;
  321. }
  322. /* Would the next write overflow the circular buffer? */
  323. if (nexthead == priv->tail)
  324. {
  325. /* Yes... Return an indication that nothing was saved in
  326. * the buffer.
  327. */
  328. gerr("ERROR: Keyboard data overrun\n");
  329. break;
  330. }
  331. /* No... copy the byte */
  332. priv->rxbuffer[priv->head] = ch;
  333. priv->head = nexthead;
  334. }
  335. /* Was anything written? */
  336. if (nwritten > 0)
  337. {
  338. int i;
  339. /* Are there threads waiting for read data? */
  340. sched_lock();
  341. /* Notify all poll/select waiters that they can read from the FIFO */
  342. nxterm_pollnotify(priv, POLLIN);
  343. for (i = 0; i < priv->nwaiters; i++)
  344. {
  345. /* Yes.. Notify all of the waiting readers that more data is
  346. * available
  347. */
  348. nxsem_post(&priv->waitsem);
  349. }
  350. sched_unlock();
  351. }
  352. nxterm_sempost(priv);
  353. }
  354. #endif /* CONFIG_NXTERM_NXKBDIN */