pty.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373
  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 <rtthread.h>
  11. #include <tty.h>
  12. #include <tty_ldisc.h>
  13. #define DBG_TAG "PTY"
  14. #ifdef RT_TTY_DEBUG
  15. #define DBG_LVL DBG_LOG
  16. #else
  17. #define DBG_LVL DBG_INFO
  18. #endif /* RT_TTY_DEBUG */
  19. #include <rtdbg.h>
  20. #define PTY_PTS_SIZE 10
  21. static struct tty_struct ptm_driver;
  22. static struct tty_struct pts_drivers[PTY_PTS_SIZE];
  23. static int pts_index = 0;
  24. static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index);
  25. /* check free pts device */
  26. static struct tty_struct *find_freepts(void)
  27. {
  28. for(int i = 0; i < PTY_PTS_SIZE; i++)
  29. {
  30. if (pts_drivers[i].init_flag == TTY_INIT_FLAG_NONE)
  31. {
  32. pts_drivers[i].init_flag = TTY_INIT_FLAG_ALLOCED;
  33. return &pts_drivers[i];
  34. }
  35. }
  36. return RT_NULL;
  37. }
  38. /* Set the lock flag on a pty */
  39. static int pty_set_lock(struct tty_struct *tty, int *arg)
  40. {
  41. int val = *arg;
  42. if (val)
  43. {
  44. tty->pts_lock = val;
  45. }
  46. else
  47. {
  48. tty->pts_lock = val;
  49. }
  50. return 0;
  51. }
  52. static int pty_get_lock(struct tty_struct *tty, int *arg)
  53. {
  54. *arg = tty->pts_lock;
  55. return 0;
  56. }
  57. static int pty_get_index(struct tty_struct *tty, int *arg)
  58. {
  59. *arg = tty->index;
  60. return 0;
  61. }
  62. /* RT-Thread Device Interface */
  63. /*
  64. * This function initializes console device.
  65. */
  66. static rt_err_t pty_device_init(struct rt_device *dev)
  67. {
  68. rt_err_t result = RT_EOK;
  69. int level = 0;
  70. struct tty_struct *tty = RT_NULL;
  71. RT_ASSERT(dev != RT_NULL);
  72. tty = (struct tty_struct *)dev;
  73. level = rt_hw_interrupt_disable();
  74. RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_REGED);
  75. tty->init_flag = TTY_INIT_FLAG_INITED;
  76. rt_hw_interrupt_enable(level);
  77. return result;
  78. }
  79. static rt_err_t pty_device_open(struct rt_device *dev, rt_uint16_t oflag)
  80. {
  81. rt_err_t result = RT_EOK;
  82. return result;
  83. }
  84. static rt_err_t pty_device_close(struct rt_device *dev)
  85. {
  86. rt_err_t result = RT_EOK;
  87. struct tty_struct *tty = (struct tty_struct*)dev;
  88. //struct tty_struct *to = RT_NULL;
  89. if (tty->subtype == PTY_TYPE_MASTER)
  90. {
  91. // to = tty->other_struct;
  92. // to->init_flag = TTY_INIT_FLAG_NONE;
  93. // to->other_struct = RT_NULL;
  94. // to->foreground = RT_NULL;
  95. // to->index = -1;
  96. // tty_ldisc_kill(to);
  97. // tty->other_struct = RT_NULL;
  98. }
  99. else
  100. {
  101. // to = tty->other_struct;
  102. // to->other_struct = RT_NULL;
  103. // tty->init_flag = TTY_INIT_FLAG_NONE;
  104. // tty->other_struct = RT_NULL;
  105. // tty->foreground = RT_NULL;
  106. // tty->index = -1;
  107. // tty->other_struct = RT_NULL;
  108. // tty_ldisc_kill(tty);
  109. }
  110. return result;
  111. }
  112. static rt_size_t pty_device_read(struct rt_device *dev,
  113. rt_off_t pos,
  114. void *buffer,
  115. rt_size_t size)
  116. {
  117. rt_size_t len = 0;
  118. return len;
  119. }
  120. static rt_size_t pty_device_write(struct rt_device *dev,
  121. rt_off_t pos,
  122. const void *buffer,
  123. rt_size_t size)
  124. {
  125. rt_base_t level = 0;
  126. rt_size_t len = 0;
  127. struct tty_struct *tty = RT_NULL;
  128. struct tty_struct *to = RT_NULL;
  129. tty = (struct tty_struct *)dev;
  130. RT_ASSERT(tty != RT_NULL);
  131. RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
  132. to = tty->other_struct;
  133. level = rt_hw_interrupt_disable();
  134. if (to->ldisc->ops->receive_buf)
  135. {
  136. len = to->ldisc->ops->receive_buf(to, (char *)buffer, size);
  137. }
  138. rt_hw_interrupt_enable(level);
  139. return len;
  140. }
  141. static rt_err_t pty_device_control(rt_device_t dev, int cmd, void *args)
  142. {
  143. struct tty_struct *tty = (struct tty_struct *)dev;
  144. switch (cmd)
  145. {
  146. case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
  147. return pty_set_lock(tty, (int *)args);
  148. case TIOCGPTLCK: /* Get PT Lock status */
  149. return pty_get_lock(tty, (int *)args);
  150. case TIOCGPTN: /* Get PT Number */
  151. return pty_get_index(tty, (int *)args);
  152. }
  153. return -ENOIOCTLCMD;
  154. }
  155. static int ptmx_open(struct dfs_fd *fd)
  156. {
  157. int ret = 0;
  158. struct tty_struct *tty = RT_NULL;
  159. struct tty_struct *pts_drv = RT_NULL;
  160. struct tty_ldisc *ld = RT_NULL;
  161. struct rt_lwp *lwp = RT_NULL;
  162. struct rt_wqueue *wq = RT_NULL;
  163. tty = (struct tty_struct *)fd->vnode->data;
  164. RT_ASSERT(tty != RT_NULL);
  165. pts_drv = find_freepts();
  166. if (pts_drv == RT_NULL)
  167. {
  168. LOG_E("free pts driver find fail\n");
  169. return -1;
  170. }
  171. ret = pts_register(tty, pts_drv, pts_index);
  172. if (ret < 0)
  173. {
  174. LOG_E("pts register fail\n");
  175. rt_free(pts_drv);
  176. return -1;
  177. }
  178. pts_index++;
  179. lwp = (struct rt_lwp *)(rt_thread_self()->lwp);
  180. wq = wait_queue_get(lwp, tty);
  181. pts_drv->wait_queue = *wq;
  182. tty->other_struct = pts_drv;
  183. ld = tty->ldisc;
  184. if (ld->ops->open)
  185. {
  186. ret = ld->ops->open(fd);
  187. }
  188. return ret;
  189. }
  190. #ifdef RT_USING_DEVICE_OPS
  191. const static struct rt_device_ops pty_device_ops =
  192. {
  193. pty_device_init,
  194. pty_device_open,
  195. pty_device_close,
  196. pty_device_read,
  197. pty_device_write,
  198. pty_device_control,
  199. };
  200. #endif /* RT_USING_DEVICE_OPS */
  201. static struct dfs_file_ops pts_fops;
  202. static struct dfs_file_ops ptmx_fops;
  203. static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index)
  204. {
  205. rt_err_t ret = RT_EOK;
  206. rt_base_t level = 0;
  207. struct rt_device *device = RT_NULL;
  208. char name[20];
  209. RT_ASSERT(ptm_drv!=RT_NULL);
  210. level = rt_hw_interrupt_disable();
  211. if (pts_drv->init_flag != TTY_INIT_FLAG_ALLOCED)
  212. {
  213. LOG_E("pts%d has been registered\n", pts_index);
  214. ret = (-RT_EBUSY);
  215. goto _exit;
  216. }
  217. device = &pts_drv->parent;
  218. device->type = RT_Device_Class_Char;
  219. #ifdef RT_USING_DEVICE_OPS
  220. device->ops = &pty_device_ops;
  221. #else
  222. device->init = pty_device_init;
  223. device->open = pty_device_open;
  224. device->close = pty_device_close;
  225. device->read = pty_device_read;
  226. device->write = pty_device_write;
  227. device->control = pty_device_control;
  228. #endif /* RT_USING_DEVICE_OPS */
  229. rt_snprintf(name, sizeof(name), "pts%d", pts_index);
  230. ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
  231. if (ret != RT_EOK)
  232. {
  233. LOG_E("pts%d register failed\n", pts_index);
  234. ret = -RT_EIO;
  235. goto _exit;
  236. }
  237. #ifdef RT_USING_POSIX_DEVIO
  238. /* set fops */
  239. tty_set_fops(&pts_fops);
  240. device->fops = &pts_fops;
  241. #endif
  242. pts_drv->type = TTY_DRIVER_TYPE_PTY;
  243. pts_drv->subtype = PTY_TYPE_SLAVE;
  244. pts_drv->pgrp = -1;
  245. pts_drv->session = -1;
  246. pts_drv->foreground = RT_NULL;
  247. pts_drv->index = pts_index;
  248. pts_drv->pts_lock = 1;
  249. rt_wqueue_init(&pts_drv->wait_queue);
  250. tty_ldisc_init(pts_drv);
  251. extern struct termios tty_std_termios;
  252. pts_drv->init_termios = tty_std_termios;
  253. pts_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
  254. pts_drv->init_termios.c_lflag |= ICANON;
  255. pts_drv->init_termios.__c_ispeed = 38400;
  256. pts_drv->init_termios.__c_ospeed = 38400;
  257. pts_drv->other_struct = ptm_drv;
  258. pts_drv->init_flag = TTY_INIT_FLAG_REGED;
  259. _exit:
  260. rt_hw_interrupt_enable(level);
  261. return ret;
  262. }
  263. static int ptmx_register(void)
  264. {
  265. rt_base_t level = 0;
  266. rt_err_t ret = RT_EOK;
  267. struct rt_device *device = RT_NULL;
  268. struct tty_struct *ptm_drv = &ptm_driver;
  269. level = rt_hw_interrupt_disable();
  270. RT_ASSERT(ptm_drv->init_flag == TTY_INIT_FLAG_NONE);
  271. device = &(ptm_drv->parent);
  272. device->type = RT_Device_Class_Char;
  273. #ifdef RT_USING_DEVICE_OPS
  274. device->ops = &pty_device_ops;
  275. #else
  276. device->init = pty_device_init;
  277. device->open = pty_device_open;
  278. device->close = pty_device_close;
  279. device->read = pty_device_read;
  280. device->write = pty_device_write;
  281. device->control = pty_device_control;
  282. #endif /* RT_USING_DEVICE_OPS */
  283. ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
  284. if (ret != RT_EOK)
  285. {
  286. LOG_E("ptmx register fail\n");
  287. ret = -RT_EIO;
  288. goto _exit;
  289. }
  290. #ifdef RT_USING_POSIX_DEVIO
  291. /* set fops */
  292. tty_set_fops(&ptmx_fops);
  293. ptmx_fops.open = ptmx_open;
  294. device->fops = &ptmx_fops;
  295. #endif
  296. ptm_drv->type = TTY_DRIVER_TYPE_PTY;
  297. ptm_drv->subtype = PTY_TYPE_MASTER;
  298. ptm_drv->head = rt_calloc(1, sizeof(struct tty_node));
  299. if (!ptm_drv->head)
  300. {
  301. return -RT_ENOMEM;
  302. }
  303. tty_initstack(ptm_drv->head);
  304. ptm_drv->pgrp = -1;
  305. ptm_drv->session = -1;
  306. ptm_drv->foreground = RT_NULL;
  307. rt_wqueue_init(&ptm_drv->wait_queue);
  308. tty_ldisc_init(ptm_drv);
  309. extern struct termios tty_std_termios;
  310. ptm_drv->init_termios.c_iflag = 0;
  311. ptm_drv->init_termios.c_oflag = 0;
  312. ptm_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
  313. ptm_drv->init_termios.c_lflag = 0;
  314. ptm_drv->init_termios.__c_ispeed = 38400;
  315. ptm_drv->init_termios.__c_ospeed = 38400;
  316. ptm_drv->init_flag = TTY_INIT_FLAG_REGED;
  317. _exit:
  318. rt_hw_interrupt_enable(level);
  319. return ret;
  320. }
  321. INIT_DEVICE_EXPORT(ptmx_register);