tty.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2021.12.07 linzhenxing first version
  9. */
  10. #include <dfs_file.h>
  11. #include <dfs_fs.h>
  12. #include <lwp.h>
  13. #include <rtdevice.h>
  14. #include <rtthread.h>
  15. #include <tty.h>
  16. #include <tty_ldisc.h>
  17. #if defined(RT_USING_POSIX_DEVIO)
  18. #include <termios.h>
  19. #endif
  20. #define DBG_TAG "TTY"
  21. #ifdef RT_TTY_DEBUG
  22. #define DBG_LVL DBG_LOG
  23. #else
  24. #define DBG_LVL DBG_INFO
  25. #endif /* RT_TTY_DEBUG */
  26. #include <rtdbg.h>
  27. struct termios tty_std_termios = { /* for the benefit of tty drivers */
  28. .c_iflag = IMAXBEL | IUCLC | INLCR | ICRNL | IGNPAR,
  29. .c_oflag = OPOST,
  30. .c_cflag = B38400 | CS8 | CREAD | HUPCL,
  31. .c_lflag = ISIG | ECHOE | TOSTOP | NOFLSH,
  32. RT_NULL,/* .c_line = N_TTY, */
  33. .c_cc = INIT_C_CC,
  34. .__c_ispeed = 38400,
  35. .__c_ospeed = 38400
  36. };
  37. void tty_initstack(struct tty_node *node)
  38. {
  39. node->lwp = RT_NULL;
  40. node->next = node;
  41. }
  42. static struct tty_node tty_node_cache = { RT_NULL, RT_NULL };
  43. static struct tty_node *_tty_node_alloc(void)
  44. {
  45. struct tty_node *node = tty_node_cache.next;
  46. if (node == RT_NULL)
  47. {
  48. node = rt_calloc(1, sizeof(struct tty_node));
  49. }
  50. else
  51. {
  52. tty_node_cache.next = node->next;
  53. }
  54. return node;
  55. }
  56. static void _tty_node_free(struct tty_node *node)
  57. {
  58. node->next = tty_node_cache.next;
  59. tty_node_cache.next = node;
  60. }
  61. int tty_push(struct tty_node **head, struct rt_lwp *lwp)
  62. {
  63. struct tty_node *node = _tty_node_alloc();
  64. if (!node)
  65. {
  66. return -1;
  67. }
  68. node->lwp = lwp;
  69. node->next = *head;
  70. *head = node;
  71. return 0;
  72. }
  73. struct rt_lwp *tty_pop(struct tty_node **head, struct rt_lwp *target_lwp)
  74. {
  75. struct tty_node *node;
  76. struct rt_lwp *lwp = RT_NULL;
  77. if (!head || !*head)
  78. {
  79. return RT_NULL;
  80. }
  81. node = *head;
  82. if (target_lwp != RT_NULL && node->lwp != target_lwp)
  83. {
  84. struct tty_node *prev = RT_NULL;
  85. while (node != RT_NULL && node->lwp != target_lwp)
  86. {
  87. prev = node;
  88. node = node->next;
  89. }
  90. if (node != RT_NULL)
  91. {
  92. /* prev is impossible equ RT_NULL */
  93. prev->next = node->next;
  94. lwp = target_lwp;
  95. _tty_node_free(node);
  96. }
  97. }
  98. else
  99. {
  100. lwp = (*head)->lwp;
  101. *head = (*head)->next;
  102. node->lwp = RT_NULL;
  103. _tty_node_free(node);
  104. }
  105. return lwp;
  106. }
  107. rt_inline int tty_sigismember(lwp_sigset_t *set, int _sig)
  108. {
  109. unsigned long sig = _sig - 1;
  110. if (_LWP_NSIG_WORDS == 1)
  111. {
  112. return 1 & (set->sig[0] >> sig);
  113. }
  114. else
  115. {
  116. return 1 & (set->sig[sig / _LWP_NSIG_BPW] >> (sig % _LWP_NSIG_BPW));
  117. }
  118. }
  119. static int is_ignored(int sig)
  120. {
  121. return (tty_sigismember(&current->signal_mask, sig) ||
  122. current->signal_handler[sig-1] == SIG_IGN);
  123. }
  124. /**
  125. * tty_check_change - check for POSIX terminal changes
  126. * @tty: tty to check
  127. *
  128. * If we try to write to, or set the state of, a terminal and we're
  129. * not in the foreground, send a SIGTTOU. If the signal is blocked or
  130. * ignored, go ahead and perform the operation. (POSIX 7.2)
  131. *
  132. * Locking: ctrl_lock
  133. */
  134. int __tty_check_change(struct tty_struct *tty, int sig)
  135. {
  136. pid_t pgrp = 0, tty_pgrp = 0;
  137. struct rt_lwp *lwp = tty->foreground;
  138. int ret = 0;
  139. int level = 0;
  140. level = rt_hw_interrupt_disable();
  141. if (current == RT_NULL)
  142. {
  143. rt_hw_interrupt_enable(level);
  144. return 0;
  145. }
  146. if (current->tty != tty)
  147. {
  148. rt_hw_interrupt_enable(level);
  149. return 0;
  150. }
  151. pgrp = current->__pgrp;
  152. tty_pgrp = tty->pgrp;
  153. if (tty_pgrp && (pgrp != tty->pgrp))
  154. {
  155. if (is_ignored(sig))
  156. {
  157. if (sig == SIGTTIN)
  158. {
  159. ret = -EIO;
  160. }
  161. }
  162. else
  163. {
  164. if (lwp)
  165. {
  166. lwp_kill(lwp_to_pid(lwp), sig);
  167. }
  168. }
  169. }
  170. rt_hw_interrupt_enable(level);
  171. if (!tty_pgrp)
  172. {
  173. LOG_D("sig=%d, tty->pgrp == -1!\n", sig);
  174. }
  175. return ret;
  176. }
  177. int tty_check_change(struct tty_struct *tty)
  178. {
  179. return __tty_check_change(tty, SIGTTOU);
  180. }
  181. static int tty_open(struct dfs_fd *fd)
  182. {
  183. int ret = 0;
  184. int noctty = 0;
  185. struct tty_struct *tty = RT_NULL;
  186. struct tty_ldisc *ld = RT_NULL;
  187. tty = (struct tty_struct *)fd->vnode->data;
  188. RT_ASSERT(tty != RT_NULL);
  189. ld = tty->ldisc;
  190. if (ld->ops->open)
  191. {
  192. ret = ld->ops->open(fd);
  193. }
  194. noctty = (fd->flags & O_NOCTTY);
  195. rt_device_t device = (rt_device_t)fd->vnode->data;
  196. if (fd->vnode->ref_count == 1)
  197. {
  198. ret = rt_device_open(device, fd->flags);
  199. }
  200. if (current == RT_NULL) //kernel mode not lwp
  201. {
  202. return ret;
  203. }
  204. if (!noctty &&
  205. current->leader &&
  206. !current->tty &&
  207. tty->session == -1)
  208. {
  209. current->tty = tty;
  210. current->tty_old_pgrp = 0;
  211. tty->session = current->session;
  212. tty->pgrp = current->__pgrp;
  213. tty->foreground = current;
  214. }
  215. return ret;
  216. }
  217. static int tty_close(struct dfs_fd *fd)
  218. {
  219. int ret = 0;
  220. struct tty_struct *tty = RT_NULL;
  221. struct tty_ldisc *ld = RT_NULL;
  222. tty = (struct tty_struct *)fd->vnode->data;
  223. RT_ASSERT(tty != RT_NULL);
  224. ld = tty->ldisc;
  225. if (ld->ops->close)
  226. {
  227. //ld->ops->close(tty);
  228. }
  229. if (fd->vnode->ref_count == 1)
  230. {
  231. ret = rt_device_close((rt_device_t)tty);
  232. }
  233. return ret;
  234. }
  235. static int tiocsctty(struct tty_struct *tty, int arg)
  236. {
  237. if (current->leader &&
  238. (current->session == tty->session))
  239. {
  240. return 0;
  241. }
  242. /*
  243. * The process must be a session leader and
  244. * not have a controlling tty already.
  245. */
  246. if (!current->leader || current->tty)
  247. {
  248. return -EPERM;
  249. }
  250. if (tty->session > 0)
  251. {
  252. LOG_E("this tty have control process\n");
  253. }
  254. current->tty = tty;
  255. current->tty_old_pgrp = 0;
  256. tty->session = current->session;
  257. tty->pgrp = current->__pgrp;
  258. tty->foreground = current;
  259. if (tty->type == TTY_DRIVER_TYPE_PTY)
  260. {
  261. tty->other_struct->foreground = current;
  262. }
  263. return 0;
  264. }
  265. static int tty_ioctl(struct dfs_fd *fd, int cmd, void *args)
  266. {
  267. int ret = 0;
  268. struct tty_struct *tty = RT_NULL;
  269. struct tty_struct *real_tty = RT_NULL;
  270. struct tty_ldisc *ld = RT_NULL;
  271. tty = (struct tty_struct *)fd->vnode->data;
  272. RT_ASSERT(tty != RT_NULL);
  273. if (tty->type == TTY_DRIVER_TYPE_PTY && tty->subtype == PTY_TYPE_MASTER)
  274. {
  275. real_tty = tty->other_struct;
  276. }
  277. else
  278. {
  279. real_tty = tty;
  280. }
  281. switch (cmd)
  282. {
  283. case TIOCSCTTY:
  284. return tiocsctty(real_tty, 1);
  285. }
  286. ld = tty->ldisc;
  287. if (ld->ops->ioctl)
  288. {
  289. ret = ld->ops->ioctl(fd, cmd, args);
  290. }
  291. return ret;
  292. }
  293. static int tty_read(struct dfs_fd *fd, void *buf, size_t count)
  294. {
  295. int ret = 0;
  296. struct tty_struct *tty = RT_NULL;
  297. struct tty_ldisc *ld = RT_NULL;
  298. tty = (struct tty_struct *)fd->vnode->data;
  299. RT_ASSERT(tty != RT_NULL);
  300. ld = tty->ldisc;
  301. if (ld->ops->read)
  302. {
  303. ret = ld->ops->read(fd, buf, count);
  304. }
  305. return ret;
  306. }
  307. static int tty_write(struct dfs_fd *fd, const void *buf, size_t count)
  308. {
  309. int ret = 0;
  310. struct tty_struct *tty = RT_NULL;
  311. struct tty_ldisc *ld = RT_NULL;
  312. tty = (struct tty_struct *)fd->vnode->data;
  313. RT_ASSERT(tty != RT_NULL);
  314. ld = tty->ldisc;
  315. if (ld->ops->write)
  316. {
  317. ret = ld->ops->write(fd, buf, count);
  318. }
  319. return ret;
  320. }
  321. static int tty_poll(struct dfs_fd *fd, struct rt_pollreq *req)
  322. {
  323. int ret = 0;
  324. struct tty_struct *tty = RT_NULL;
  325. struct tty_ldisc *ld = RT_NULL;
  326. tty = (struct tty_struct *)fd->vnode->data;
  327. RT_ASSERT(tty != RT_NULL);
  328. ld = tty->ldisc;
  329. if (ld->ops->poll)
  330. {
  331. ret = ld->ops->poll(fd, req);
  332. }
  333. return ret;
  334. }
  335. static const struct dfs_file_ops tty_fops =
  336. {
  337. tty_open,
  338. tty_close,
  339. tty_ioctl,
  340. tty_read,
  341. tty_write,
  342. RT_NULL, /* flush */
  343. RT_NULL, /* lseek */
  344. RT_NULL, /* getdents */
  345. tty_poll,
  346. };
  347. static const struct dfs_file_ops console_fops =
  348. {
  349. tty_open,
  350. tty_close,
  351. tty_ioctl,
  352. tty_read,
  353. tty_write,
  354. RT_NULL, /* flush */
  355. RT_NULL, /* lseek */
  356. RT_NULL, /* getdents */
  357. tty_poll,
  358. };
  359. void console_init()
  360. {
  361. n_tty_init();
  362. }
  363. void tty_set_fops(struct dfs_file_ops *fops)
  364. {
  365. *fops = tty_fops;
  366. }
  367. void console_set_fops(struct dfs_file_ops *fops)
  368. {
  369. *fops = console_fops;
  370. }