tty_device.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. #define DBG_TAG "lwp.tty"
  11. #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #define TTY_CONF_INCLUDE_CCHARS
  14. #include "tty_config.h"
  15. #include "tty_internal.h"
  16. #include "terminal.h"
  17. /* configure option: timeout of tty drain wait */
  18. static int tty_drainwait = 5 * 60;
  19. #define TTY_NAME_PREFIX "tty"
  20. static char *alloc_device_name(const char *name)
  21. {
  22. char *tty_dev_name;
  23. long name_buf_len = (sizeof(TTY_NAME_PREFIX) - 1) /* raw prefix */
  24. + rt_strlen(name) /* custom name */
  25. + 1; /* tailing \0 */
  26. tty_dev_name = rt_malloc(name_buf_len);
  27. if (tty_dev_name)
  28. sprintf(tty_dev_name, "%s%s", TTY_NAME_PREFIX, name);
  29. return tty_dev_name;
  30. }
  31. /* character device for tty */
  32. #ifdef RT_USING_DEVICE_OPS
  33. const static struct rt_device_ops tty_dev_ops = {
  34. /* IO directly through device is not allowed */
  35. };
  36. #else
  37. #error Must enable RT_USING_DEVICE_OPS in Kconfig
  38. #endif
  39. static int tty_fops_open(struct dfs_file *file)
  40. {
  41. int rc;
  42. lwp_tty_t tp;
  43. rt_device_t device;
  44. int devtype = 0; /* unused */
  45. if (file->vnode && file->vnode->data)
  46. {
  47. if (file->vnode->ref_count != 1)
  48. {
  49. rc = 0;
  50. }
  51. else
  52. {
  53. device = (rt_device_t)file->vnode->data;
  54. tp = rt_container_of(device, struct lwp_tty, parent);
  55. rc = bsd_ttydev_methods.d_open(tp, file->flags, devtype,
  56. rt_thread_self());
  57. }
  58. }
  59. else
  60. {
  61. rc = -EINVAL;
  62. }
  63. return rc;
  64. }
  65. static int tty_fops_close(struct dfs_file *file)
  66. {
  67. int rc;
  68. lwp_tty_t tp;
  69. rt_device_t device;
  70. int fflags = FFLAGS(file->flags);
  71. int devtype = 0; /* unused */
  72. if (file->vnode && file->vnode->data)
  73. {
  74. if (file->vnode->ref_count != 1)
  75. {
  76. rc = 0;
  77. }
  78. else
  79. {
  80. device = (rt_device_t)file->vnode->data;
  81. tp = rt_container_of(device, struct lwp_tty, parent);
  82. rc = bsd_ttydev_methods.d_close(tp, fflags, devtype, rt_thread_self());
  83. }
  84. }
  85. else
  86. {
  87. rc = -EINVAL;
  88. }
  89. return rc;
  90. }
  91. static int tty_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
  92. {
  93. int rc;
  94. lwp_tty_t tp;
  95. rt_device_t device;
  96. if (file->vnode && file->vnode->data)
  97. {
  98. device = (rt_device_t)file->vnode->data;
  99. tp = rt_container_of(device, struct lwp_tty, parent);
  100. rc = lwp_tty_ioctl_adapter(tp, cmd, file->flags, arg, rt_thread_self());
  101. }
  102. else
  103. {
  104. rc = -EINVAL;
  105. }
  106. return rc;
  107. }
  108. static ssize_t tty_fops_read(struct dfs_file *file, void *buf, size_t count,
  109. off_t *pos)
  110. {
  111. ssize_t rc = 0;
  112. int error;
  113. struct uio uio;
  114. struct iovec iov;
  115. rt_device_t device;
  116. struct lwp_tty *tp;
  117. int ioflags;
  118. int oflags = file->flags;
  119. if (file->vnode && file->vnode->data)
  120. {
  121. device = (rt_device_t)file->vnode->data;
  122. tp = rt_container_of(device, struct lwp_tty, parent);
  123. /* setup ioflags */
  124. ioflags = 0;
  125. if (oflags & O_NONBLOCK)
  126. ioflags |= IO_NDELAY;
  127. /* setup uio parameters */
  128. iov.iov_base = (void *)buf;
  129. iov.iov_len = count;
  130. uio.uio_offset = file->fpos;
  131. uio.uio_resid = count;
  132. uio.uio_iov = &iov;
  133. uio.uio_iovcnt = 1;
  134. uio.uio_rw = UIO_READ;
  135. rc = count;
  136. error = bsd_ttydev_methods.d_read(tp, &uio, ioflags);
  137. rc -= uio.uio_resid;
  138. if (error)
  139. {
  140. LOG_D("%s: failed to write %d bytes of data. error code %d",
  141. __func__, uio.uio_resid, error);
  142. rc = error;
  143. }
  144. /* reset file context */
  145. file->fpos = uio.uio_offset;
  146. }
  147. if (rc)
  148. LOG_D("%s(len=%d, buf=%c \"%d\")", __func__, rc, *((char *)buf),
  149. *((char *)buf));
  150. return rc;
  151. }
  152. static ssize_t tty_fops_write(struct dfs_file *file, const void *buf,
  153. size_t count, off_t *pos)
  154. {
  155. ssize_t rc = 0;
  156. int error;
  157. struct uio uio;
  158. struct iovec iov;
  159. rt_device_t device;
  160. struct lwp_tty *tp;
  161. int ioflags;
  162. int oflags = file->flags;
  163. if (file->vnode && file->vnode->data)
  164. {
  165. device = (rt_device_t)file->vnode->data;
  166. tp = rt_container_of(device, struct lwp_tty, parent);
  167. /* setup ioflags */
  168. ioflags = 0;
  169. if (oflags & O_NONBLOCK)
  170. ioflags |= IO_NDELAY;
  171. /* setup uio parameters */
  172. iov.iov_base = (void *)buf;
  173. iov.iov_len = count;
  174. uio.uio_offset = file->fpos;
  175. uio.uio_resid = count;
  176. uio.uio_iov = &iov;
  177. uio.uio_iovcnt = 1;
  178. uio.uio_rw = UIO_WRITE;
  179. rc = count;
  180. error = bsd_ttydev_methods.d_write(tp, &uio, ioflags);
  181. if (error)
  182. {
  183. rc = error;
  184. LOG_D("%s: failed to write %d bytes of data. error code %d",
  185. __func__, uio.uio_resid, error);
  186. }
  187. else
  188. {
  189. rc -= uio.uio_resid;
  190. }
  191. /* reset file context */
  192. file->fpos = uio.uio_offset;
  193. }
  194. return rc;
  195. }
  196. static int tty_fops_flush(struct dfs_file *file)
  197. {
  198. return -EINVAL;
  199. }
  200. static off_t tty_fops_lseek(struct dfs_file *file, off_t offset, int wherece)
  201. {
  202. return -EINVAL;
  203. }
  204. static int tty_fops_truncate(struct dfs_file *file, off_t offset)
  205. {
  206. /**
  207. * regarding to POSIX.1, TRUNC is not supported for tty device.
  208. * return 0 always to make filesystem happy
  209. */
  210. return 0;
  211. }
  212. static int tty_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
  213. {
  214. int rc;
  215. rt_device_t device;
  216. struct lwp_tty *tp;
  217. if (file->vnode && file->vnode->data)
  218. {
  219. device = (rt_device_t)file->vnode->data;
  220. tp = rt_container_of(device, struct lwp_tty, parent);
  221. rc = bsd_ttydev_methods.d_poll(tp, req, rt_thread_self());
  222. }
  223. else
  224. {
  225. rc = -1;
  226. }
  227. return rc;
  228. }
  229. static int tty_fops_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
  230. {
  231. return -EINVAL;
  232. }
  233. static int tty_fops_lock(struct dfs_file *file, struct file_lock *flock)
  234. {
  235. return -EINVAL;
  236. }
  237. static int tty_fops_flock(struct dfs_file *file, int operation, struct file_lock *flock)
  238. {
  239. return -EINVAL;
  240. }
  241. static struct dfs_file_ops tty_file_ops = {
  242. .open = tty_fops_open,
  243. .close = tty_fops_close,
  244. .ioctl = tty_fops_ioctl,
  245. .read = tty_fops_read,
  246. .write = tty_fops_write,
  247. .flush = tty_fops_flush,
  248. .lseek = tty_fops_lseek,
  249. .truncate = tty_fops_truncate,
  250. .poll = tty_fops_poll,
  251. .mmap = tty_fops_mmap,
  252. .lock = tty_fops_lock,
  253. .flock = tty_fops_flock,
  254. };
  255. rt_inline void device_setup(lwp_tty_t terminal)
  256. {
  257. terminal->parent.type = RT_Device_Class_Char;
  258. #ifdef RT_USING_DEVICE_OPS
  259. terminal->parent.ops = &tty_dev_ops;
  260. #else
  261. #error Must enable RT_USING_DEVICE_OPS in Kconfig
  262. #endif
  263. }
  264. /* register TTY device */
  265. rt_err_t lwp_tty_register(lwp_tty_t terminal, const char *name)
  266. {
  267. rt_err_t rc = -RT_ENOMEM;
  268. const char *tty_name;
  269. char *alloc_name;
  270. if (terminal->t_devsw->tsw_flags & TF_NOPREFIX)
  271. {
  272. alloc_name = RT_NULL;
  273. tty_name = name;
  274. }
  275. else
  276. {
  277. alloc_name = alloc_device_name(name);
  278. tty_name = alloc_name;
  279. }
  280. if (tty_name)
  281. {
  282. device_setup(terminal);
  283. rc = rt_device_register(&terminal->parent, tty_name, 0);
  284. if (rc == RT_EOK)
  285. {
  286. terminal->parent.fops = &tty_file_ops;
  287. LOG_D("%s() /dev/%s device registered", __func__, tty_name);
  288. }
  289. rt_free(alloc_name);
  290. }
  291. return rc;
  292. }
  293. static void tty_init_termios(lwp_tty_t tp)
  294. {
  295. struct termios *t = &tp->t_termios_init_in;
  296. t->c_cflag = TTYDEF_CFLAG;
  297. t->c_iflag = TTYDEF_IFLAG;
  298. t->c_lflag = TTYDEF_LFLAG;
  299. t->c_oflag = TTYDEF_OFLAG;
  300. t->__c_ispeed = TTYDEF_SPEED;
  301. t->__c_ospeed = TTYDEF_SPEED;
  302. memcpy(&t->c_cc, tty_ctrl_charset,
  303. sizeof(tty_ctrl_charset) / sizeof(tty_ctrl_charset[0]));
  304. #ifdef USING_BSD_INIT_LOCK_DEVICE
  305. tp->t_termios_init_out = *t;
  306. #endif /* USING_BSD_INIT_LOCK_DEVICE */
  307. }
  308. lwp_tty_t lwp_tty_create_ext(lwp_ttydevsw_t handle, void *softc,
  309. rt_mutex_t custom_mtx)
  310. {
  311. lwp_tty_t tp;
  312. tp = rt_calloc(1, sizeof(struct lwp_tty)
  313. #ifdef USING_BSD_SIGINFO
  314. + LWP_TTY_PRBUF_SIZE
  315. #endif
  316. );
  317. if (!tp)
  318. return tp;
  319. bsd_devsw_init(handle);
  320. #ifdef USING_BSD_SIGINFO
  321. tp->t_prbufsz = LWP_TTY_PRBUF_SIZE;
  322. #endif
  323. tp->t_devsw = handle;
  324. tp->t_devswsoftc = softc;
  325. tp->t_flags = handle->tsw_flags;
  326. tp->t_drainwait = tty_drainwait;
  327. tty_init_termios(tp);
  328. cv_init(&tp->t_inwait, "ttyin");
  329. cv_init(&tp->t_outwait, "ttyout");
  330. cv_init(&tp->t_outserwait, "ttyosr");
  331. cv_init(&tp->t_bgwait, "ttybg");
  332. cv_init(&tp->t_dcdwait, "ttydcd");
  333. rt_wqueue_init(&tp->t_inpoll);
  334. rt_wqueue_init(&tp->t_outpoll);
  335. /* Allow drivers to use a custom mutex to lock the TTY. */
  336. if (custom_mtx != NULL)
  337. {
  338. tp->t_mtx = custom_mtx;
  339. }
  340. else
  341. {
  342. tp->t_mtx = &tp->t_mtxobj;
  343. rt_mutex_init(&tp->t_mtxobj, "ttydev", RT_IPC_FLAG_PRIO);
  344. }
  345. #ifdef USING_BSD_POLL
  346. knlist_init_mtx(&tp->t_inpoll.si_note, tp->t_mtx);
  347. knlist_init_mtx(&tp->t_outpoll.si_note, tp->t_mtx);
  348. #endif
  349. return tp;
  350. }
  351. lwp_tty_t lwp_tty_create(lwp_ttydevsw_t handle, void *softc)
  352. {
  353. return lwp_tty_create_ext(handle, softc, NULL);
  354. }
  355. void lwp_tty_delete(lwp_tty_t tp)
  356. {
  357. /*
  358. * ttyydev_leave() usually frees the i/o queues earlier, but it is
  359. * not always called between queue allocation and here. The queues
  360. * may be allocated by ioctls on a pty control device without the
  361. * corresponding pty slave device ever being open, or after it is
  362. * closed.
  363. */
  364. ttyinq_free(&tp->t_inq);
  365. ttyoutq_free(&tp->t_outq);
  366. rt_wqueue_wakeup_all(&tp->t_inpoll, (void *)POLLHUP);
  367. rt_wqueue_wakeup_all(&tp->t_outpoll, (void *)POLLHUP);
  368. #ifdef USING_BSD_POLL
  369. knlist_destroy(&tp->t_inpoll.si_note);
  370. knlist_destroy(&tp->t_outpoll.si_note);
  371. #endif
  372. cv_destroy(&tp->t_inwait);
  373. cv_destroy(&tp->t_outwait);
  374. cv_destroy(&tp->t_bgwait);
  375. cv_destroy(&tp->t_dcdwait);
  376. cv_destroy(&tp->t_outserwait);
  377. if (tp->t_mtx == &tp->t_mtxobj)
  378. rt_mutex_detach(&tp->t_mtxobj);
  379. ttydevsw_free(tp);
  380. rt_device_unregister(&tp->parent);
  381. rt_free(tp);
  382. }
  383. /*
  384. * Report on state of foreground process group.
  385. */
  386. void tty_info(struct lwp_tty *tp)
  387. {
  388. /* TODO */
  389. return;
  390. }