terminal.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2023-11-13 Shell init ver.
  9. */
  10. #ifndef __LWP_TERMINAL_H__
  11. #define __LWP_TERMINAL_H__
  12. #include "bsd_ttyqueue.h"
  13. #include "bsd_ttydisc.h"
  14. #ifdef USING_BSD_HOOK
  15. #include "bsd_ttyhook.h"
  16. #endif
  17. #include <lwp.h>
  18. #include <rtdef.h>
  19. /* include kernel header for termios base definitions */
  20. #include <termios.h>
  21. /* for _POSIX_VDISABLE */
  22. #include <unistd.h>
  23. /*-
  24. * SPDX-License-Identifier: BSD-2-Clause
  25. *
  26. * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
  27. * All rights reserved.
  28. *
  29. * Portions of this software were developed under sponsorship from Snow
  30. * B.V., the Netherlands.
  31. *
  32. * Redistribution and use in source and binary forms, with or without
  33. * modification, are permitted provided that the following conditions
  34. * are met:
  35. * 1. Redistributions of source code must retain the above copyright
  36. * notice, this list of conditions and the following disclaimer.
  37. * 2. Redistributions in binary form must reproduce the above copyright
  38. * notice, this list of conditions and the following disclaimer in the
  39. * documentation and/or other materials provided with the distribution.
  40. *
  41. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  42. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  43. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  44. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  45. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  46. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  47. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  48. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  49. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  50. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  51. * SUCH DAMAGE.
  52. */
  53. struct lwp_tty;
  54. /*
  55. * Driver routines that are called from the line discipline to adjust
  56. * hardware parameters and such.
  57. */
  58. typedef int tsw_open_t(struct lwp_tty *tp);
  59. typedef void tsw_close_t(struct lwp_tty *tp);
  60. typedef void tsw_outwakeup_t(struct lwp_tty *tp);
  61. typedef void tsw_inwakeup_t(struct lwp_tty *tp);
  62. typedef int tsw_ioctl_t(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data,
  63. struct rt_thread *td);
  64. typedef int tsw_cioctl_t(struct lwp_tty *tp, int unit, rt_ubase_t cmd, rt_caddr_t data,
  65. struct rt_thread *td);
  66. typedef int tsw_param_t(struct lwp_tty *tp, struct termios *t);
  67. typedef int tsw_modem_t(struct lwp_tty *tp, int sigon, int sigoff);
  68. typedef int tsw_mmap_t(struct lwp_tty *tp, vm_ooffset_t offset,
  69. vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr);
  70. typedef void tsw_pktnotify_t(struct lwp_tty *tp, char event);
  71. typedef void tsw_free_t(void *softc);
  72. typedef rt_bool_t tsw_busy_t(struct lwp_tty *tp);
  73. struct lwp_ttydevsw
  74. {
  75. unsigned int tsw_flags; /* Default TTY flags. */
  76. tsw_open_t *tsw_open; /* Device opening. */
  77. tsw_close_t *tsw_close; /* Device closure. */
  78. tsw_outwakeup_t *tsw_outwakeup; /* Output available. */
  79. tsw_inwakeup_t *tsw_inwakeup; /* Input can be stored again. */
  80. tsw_ioctl_t *tsw_ioctl; /* ioctl() hooks. */
  81. tsw_cioctl_t *tsw_cioctl; /* ioctl() on control devices. */
  82. tsw_param_t *tsw_param; /* TIOCSETA device parameter setting. */
  83. tsw_modem_t *tsw_modem; /* Modem sigon/sigoff. */
  84. tsw_mmap_t *tsw_mmap; /* mmap() hooks. */
  85. tsw_pktnotify_t *tsw_pktnotify; /* TIOCPKT events. */
  86. tsw_free_t *tsw_free; /* Destructor. */
  87. tsw_busy_t *tsw_busy; /* Draining output. */
  88. void *tsw_spare[3]; /* For future use. */
  89. };
  90. typedef struct lwp_ttydevsw *lwp_ttydevsw_t;
  91. struct lwp_tty
  92. {
  93. struct rt_device parent; /* inherit from Class:RT_Device */
  94. struct rt_mutex *t_mtx; /* TTY lock. */
  95. struct rt_mutex t_mtxobj; /* Per-TTY lock (when not borrowing). */
  96. rt_list_t t_list; /* (l) TTY list entry. */
  97. int t_drainwait; /* (t) TIOCDRAIN timeout seconds. */
  98. unsigned int t_flags; /* (t) Terminal option flags. */
  99. /* Keep flags in sync with db_show_tty and pstat(8). */
  100. #define TF_NOPREFIX 0x00001 /* Don't prepend "tty" to device name. */
  101. #define TF_INITLOCK 0x00002 /* Create init/lock state devices. */
  102. #define TF_CALLOUT 0x00004 /* Create "cua" devices. */
  103. #define TF_OPENED_IN 0x00008 /* "tty" node is in use. */
  104. #define TF_OPENED_OUT 0x00010 /* "cua" node is in use. */
  105. #define TF_OPENED_CONS 0x00020 /* Device in use as console. */
  106. #define TF_OPENED (TF_OPENED_IN | TF_OPENED_OUT | TF_OPENED_CONS)
  107. #define TF_GONE 0x00040 /* Device node is gone. */
  108. #define TF_OPENCLOSE 0x00080 /* Device is in open()/close(). */
  109. #define TF_ASYNC 0x00100 /* Asynchronous I/O enabled. */
  110. #define TF_LITERAL 0x00200 /* Accept the next character literally. */
  111. #define TF_HIWAT_IN 0x00400 /* We've reached the input watermark. */
  112. #define TF_HIWAT_OUT 0x00800 /* We've reached the output watermark. */
  113. #define TF_HIWAT (TF_HIWAT_IN | TF_HIWAT_OUT)
  114. #define TF_STOPPED 0x01000 /* Output flow control - stopped. */
  115. #define TF_EXCLUDE 0x02000 /* Exclusive access. */
  116. #define TF_BYPASS 0x04000 /* Optimized input path. */
  117. #define TF_ZOMBIE 0x08000 /* Modem disconnect received. */
  118. #define TF_HOOK 0x10000 /* TTY has hook attached. */
  119. #define TF_BUSY_IN 0x20000 /* Process busy in read() -- not supported. */
  120. #define TF_BUSY_OUT 0x40000 /* Process busy in write(). */
  121. #define TF_BUSY (TF_BUSY_IN | TF_BUSY_OUT)
  122. unsigned int t_revokecnt; /* (t) revoke() count. */
  123. /* Buffering mechanisms. */
  124. struct ttyinq t_inq; /* (t) Input queue. */
  125. size_t t_inlow; /* (t) Input low watermark. */
  126. struct ttyoutq t_outq; /* (t) Output queue. */
  127. size_t t_outlow; /* (t) Output low watermark. */
  128. /* Sleeping mechanisms. */
  129. struct rt_condvar t_inwait; /* (t) Input wait queue. */
  130. struct rt_condvar t_outwait; /* (t) Output wait queue. */
  131. struct rt_condvar t_outserwait; /* (t) Serial output wait queue. */
  132. struct rt_condvar t_bgwait; /* (t) Background wait queue. */
  133. struct rt_condvar t_dcdwait; /* (t) Carrier Detect wait queue. */
  134. struct rt_wqueue t_inpoll; /* (t) Input poll queue. */
  135. struct rt_wqueue t_outpoll; /* (t) Output poll queue. */
  136. #ifdef USING_BSD_AIO
  137. struct sigio *t_sigio; /* (t) Asynchronous I/O. */
  138. #endif
  139. struct termios t_termios; /* (t) I/O processing flags. */
  140. struct winsize t_winsize; /* (t) Window size. */
  141. unsigned int t_column; /* (t) Current cursor position. */
  142. unsigned int t_writepos; /* (t) Where input was interrupted. */
  143. int t_compatflags; /* (t) COMPAT_43TTY flags. */
  144. /* Init/lock-state devices. */
  145. struct termios t_termios_init_in; /* tty%s.init. */
  146. struct termios t_termios_lock_in; /* tty%s.lock. */
  147. #ifdef USING_BSD_INIT_LOCK_DEVICE
  148. struct termios t_termios_init_out; /* cua%s.init. */
  149. struct termios t_termios_lock_out; /* cua%s.lock. */
  150. #endif /* USING_BSD_INIT_LOCK_DEVICE */
  151. struct lwp_ttydevsw *t_devsw; /* (c) Driver hooks. */
  152. #ifdef USING_BSD_HOOK
  153. struct lwp_ttyhook *t_hook; /* (t) Capture/inject hook. */
  154. #endif
  155. /* Process signal delivery. */
  156. struct rt_processgroup *t_pgrp; /* (t) Foreground process group. */
  157. struct rt_session *t_session; /* (t) Associated session. */
  158. unsigned int t_sessioncnt; /* (t) Backpointing sessions. */
  159. void *t_devswsoftc; /* (c) Soft config, for drivers. */
  160. #ifdef USING_BSD_HOOK
  161. void *t_hooksoftc; /* (t) Soft config, for hooks. */
  162. #endif
  163. #ifdef USING_BSD_CHAR_DEVICE
  164. struct cdev *t_dev; /* (c) Primary character device. */
  165. #endif /* USING_BSD_CHAR_DEVICE */
  166. #ifdef USING_BSD_SIGINFO
  167. size_t t_prbufsz; /* (t) SIGINFO buffer size. */
  168. char t_prbuf[]; /* (t) SIGINFO buffer. */
  169. #endif /* USING_BSD_SIGINFO */
  170. };
  171. typedef struct lwp_tty *lwp_tty_t;
  172. /* Allocation and deallocation. */
  173. void tty_rel_pgrp(struct lwp_tty *tp, struct rt_processgroup *pgrp);
  174. void tty_rel_sess(struct lwp_tty *tp, struct rt_session *sess);
  175. void tty_rel_gone(struct lwp_tty *tp);
  176. /* tty locking mechanism */
  177. #define tty_getlock(tp) ((tp)->t_mtx)
  178. #define tty_lock(tp) rt_mutex_take(tty_getlock(tp), RT_WAITING_FOREVER);
  179. #define tty_unlock(tp) rt_mutex_release(tty_getlock(tp))
  180. #define tty_lock_owned(tp) \
  181. (rt_mutex_get_owner(tty_getlock(tp)) == rt_thread_self())
  182. #define tty_lock_notrecused(tp) (rt_mutex_get_hold(tty_getlock(tp)) == 1)
  183. #define tty_assert_locked(tp) RT_ASSERT(tty_lock_owned(tp))
  184. #define tty_lock_assert(tp, option) \
  185. RT_ASSERT(((option) == (MA_OWNED | MA_NOTRECURSED)) && \
  186. (tty_lock_owned(tp) && tty_lock_notrecused(tp)))
  187. /* System messages. */
  188. int tty_checkoutq(struct lwp_tty *tp);
  189. int tty_putchar(struct lwp_tty *tp, char c);
  190. int tty_putstrn(struct lwp_tty *tp, const char *p, size_t n);
  191. int tty_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, void *data, int fflag,
  192. struct rt_thread *td);
  193. int tty_ioctl_compat(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data, int fflag,
  194. struct rt_thread *td);
  195. void tty_set_winsize(struct lwp_tty *tp, const struct winsize *wsz);
  196. void tty_init_console(struct lwp_tty *tp, speed_t speed);
  197. void tty_flush(struct lwp_tty *tp, int flags);
  198. void tty_hiwat_in_block(struct lwp_tty *tp);
  199. void tty_hiwat_in_unblock(struct lwp_tty *tp);
  200. dev_t tty_udev(struct lwp_tty *tp);
  201. /* tesing on tty */
  202. #define tty_opened(tp) ((tp)->t_flags & TF_OPENED)
  203. #define tty_gone(tp) ((tp)->t_flags & TF_GONE)
  204. #define tty_softc(tp) ((tp)->t_devswsoftc)
  205. #define tty_devname(tp) ((tp)->parent.parent.name)
  206. /**
  207. * @brief TTY registeration on device subsystem
  208. *
  209. * @warning It's the duty of the caller to ensure that the name is not
  210. * identical to any existed registered devices.
  211. *
  212. * @param terminal the target tty device
  213. * @param name name of the device (must be exclusive)
  214. * @return rt_err_t RT_EOK on success
  215. */
  216. rt_err_t lwp_tty_register(lwp_tty_t terminal, const char *name);
  217. /**
  218. * @brief TTY allocation and deallocation. TTY devices can be deallocated when
  219. * the driver doesn't use it anymore, when the TTY isn't a session's
  220. * controlling TTY and when the device node isn't opened through devfs.
  221. *
  222. * @param handle device handle of tty
  223. * @param softc device configuration binding on tty
  224. * @param prefix device name prefix
  225. * @param cutom_mtx the lock provided to protect tty
  226. * @return lwp_tty_t NULL on failure
  227. */
  228. lwp_tty_t lwp_tty_create_ext(lwp_ttydevsw_t handle, void *softc,
  229. rt_mutex_t custom_mtx);
  230. /**
  231. * @brief Handful version of lwp_tty_create_ext
  232. *
  233. * @param softc device configuration binding on tty
  234. * @param cutom_mtx the lock provided to protect tty
  235. * @param prefix device name prefix
  236. * @return lwp_tty_t NULL on failure
  237. */
  238. lwp_tty_t lwp_tty_create(lwp_ttydevsw_t handle, void *softc);
  239. void lwp_tty_delete(lwp_tty_t tp);
  240. void lwp_tty_signal_sessleader(struct lwp_tty *tp, int sig);
  241. void lwp_tty_signal_pgrp(struct lwp_tty *tp, int sig);
  242. /**
  243. * @brief Create a new pseudo-terminal multiplexer
  244. *
  245. * @param root_path path of root mount point of ptyfs
  246. * @return rt_device_t new device object if succeed, otherwise NULL
  247. */
  248. rt_err_t lwp_ptmx_init(rt_device_t ptmx_device, const char *root_path);
  249. #define LWP_CONSOLE_LOWEST_PRIOR 0
  250. #define LWP_CONSOLE_HIGHEST_PRIO INT_MAX
  251. /**
  252. * @brief Register an alternative backend tty device as console
  253. */
  254. rt_err_t lwp_console_register_backend(struct rt_device *bakdev, int prio);
  255. rt_inline int ttydevsw_open(struct lwp_tty *tp)
  256. {
  257. tty_assert_locked(tp);
  258. MPASS(!tty_gone(tp));
  259. return (tp->t_devsw->tsw_open(tp));
  260. }
  261. rt_inline void ttydevsw_close(struct lwp_tty *tp)
  262. {
  263. tty_assert_locked(tp);
  264. MPASS(!tty_gone(tp));
  265. tp->t_devsw->tsw_close(tp);
  266. }
  267. rt_inline void ttydevsw_outwakeup(struct lwp_tty *tp)
  268. {
  269. tty_assert_locked(tp);
  270. MPASS(!tty_gone(tp));
  271. /* Prevent spurious wakeups. */
  272. if (ttydisc_getc_poll(tp) == 0)
  273. return;
  274. tp->t_devsw->tsw_outwakeup(tp);
  275. }
  276. rt_inline void ttydevsw_inwakeup(struct lwp_tty *tp)
  277. {
  278. tty_assert_locked(tp);
  279. MPASS(!tty_gone(tp));
  280. /* Prevent spurious wakeups. */
  281. if (tp->t_flags & TF_HIWAT_IN)
  282. return;
  283. tp->t_devsw->tsw_inwakeup(tp);
  284. }
  285. rt_inline int ttydevsw_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, rt_caddr_t data,
  286. struct rt_thread *td)
  287. {
  288. tty_assert_locked(tp);
  289. MPASS(!tty_gone(tp));
  290. return (tp->t_devsw->tsw_ioctl(tp, cmd, data, td));
  291. }
  292. rt_inline int ttydevsw_cioctl(struct lwp_tty *tp, int unit, rt_ubase_t cmd,
  293. rt_caddr_t data, struct rt_thread *td)
  294. {
  295. tty_assert_locked(tp);
  296. MPASS(!tty_gone(tp));
  297. return (tp->t_devsw->tsw_cioctl(tp, unit, cmd, data, td));
  298. }
  299. rt_inline int ttydevsw_param(struct lwp_tty *tp, struct termios *t)
  300. {
  301. MPASS(!tty_gone(tp));
  302. return (tp->t_devsw->tsw_param(tp, t));
  303. }
  304. rt_inline int ttydevsw_modem(struct lwp_tty *tp, int sigon, int sigoff)
  305. {
  306. MPASS(!tty_gone(tp));
  307. return (tp->t_devsw->tsw_modem(tp, sigon, sigoff));
  308. }
  309. rt_inline int ttydevsw_mmap(struct lwp_tty *tp, vm_ooffset_t offset,
  310. vm_paddr_t *paddr, int nprot, vm_memattr_t *memattr)
  311. {
  312. MPASS(!tty_gone(tp));
  313. return (tp->t_devsw->tsw_mmap(tp, offset, paddr, nprot, memattr));
  314. }
  315. rt_inline void ttydevsw_pktnotify(struct lwp_tty *tp, char event)
  316. {
  317. tty_assert_locked(tp);
  318. MPASS(!tty_gone(tp));
  319. tp->t_devsw->tsw_pktnotify(tp, event);
  320. }
  321. rt_inline void ttydevsw_free(struct lwp_tty *tp)
  322. {
  323. MPASS(tty_gone(tp));
  324. tp->t_devsw->tsw_free(tty_softc(tp));
  325. }
  326. rt_inline rt_bool_t ttydevsw_busy(struct lwp_tty *tp)
  327. {
  328. tty_assert_locked(tp);
  329. MPASS(!tty_gone(tp));
  330. return (tp->t_devsw->tsw_busy(tp));
  331. }
  332. rt_inline size_t ttydisc_read_poll(struct lwp_tty *tp)
  333. {
  334. tty_assert_locked(tp);
  335. return ttyinq_bytescanonicalized(&tp->t_inq);
  336. }
  337. rt_inline size_t ttydisc_write_poll(struct lwp_tty *tp)
  338. {
  339. tty_assert_locked(tp);
  340. return ttyoutq_bytesleft(&tp->t_outq);
  341. }
  342. #endif /* __LWP_TERMINAL_H__ */