1
0

pty.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  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_ssize_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_ssize_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. rt_device_t device = (rt_device_t)fd->vnode->data;
  189. if(fd->vnode->ref_count == 1)
  190. {
  191. ret = rt_device_open(device, fd->flags);
  192. }
  193. return ret;
  194. }
  195. #ifdef RT_USING_DEVICE_OPS
  196. const static struct rt_device_ops pty_device_ops =
  197. {
  198. pty_device_init,
  199. pty_device_open,
  200. pty_device_close,
  201. pty_device_read,
  202. pty_device_write,
  203. pty_device_control,
  204. };
  205. #endif /* RT_USING_DEVICE_OPS */
  206. static struct dfs_file_ops pts_fops;
  207. static struct dfs_file_ops ptmx_fops;
  208. static int pts_register(struct tty_struct *ptm_drv, struct tty_struct *pts_drv, int pts_index)
  209. {
  210. rt_err_t ret = RT_EOK;
  211. rt_base_t level = 0;
  212. struct rt_device *device = RT_NULL;
  213. char name[20];
  214. RT_ASSERT(ptm_drv!=RT_NULL);
  215. level = rt_hw_interrupt_disable();
  216. if (pts_drv->init_flag != TTY_INIT_FLAG_ALLOCED)
  217. {
  218. LOG_E("pts%d has been registered\n", pts_index);
  219. ret = (-RT_EBUSY);
  220. goto _exit;
  221. }
  222. device = &pts_drv->parent;
  223. device->type = RT_Device_Class_Char;
  224. #ifdef RT_USING_DEVICE_OPS
  225. device->ops = &pty_device_ops;
  226. #else
  227. device->init = pty_device_init;
  228. device->open = pty_device_open;
  229. device->close = pty_device_close;
  230. device->read = pty_device_read;
  231. device->write = pty_device_write;
  232. device->control = pty_device_control;
  233. #endif /* RT_USING_DEVICE_OPS */
  234. rt_snprintf(name, sizeof(name), "pts%d", pts_index);
  235. ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
  236. if (ret != RT_EOK)
  237. {
  238. LOG_E("pts%d register failed\n", pts_index);
  239. ret = -RT_EIO;
  240. goto _exit;
  241. }
  242. #ifdef RT_USING_POSIX_DEVIO
  243. /* set fops */
  244. tty_set_fops(&pts_fops);
  245. device->fops = &pts_fops;
  246. #endif
  247. pts_drv->type = TTY_DRIVER_TYPE_PTY;
  248. pts_drv->subtype = PTY_TYPE_SLAVE;
  249. pts_drv->pgrp = -1;
  250. pts_drv->session = -1;
  251. pts_drv->foreground = RT_NULL;
  252. pts_drv->index = pts_index;
  253. pts_drv->pts_lock = 1;
  254. rt_wqueue_init(&pts_drv->wait_queue);
  255. tty_ldisc_init(pts_drv);
  256. extern struct termios tty_std_termios;
  257. pts_drv->init_termios = tty_std_termios;
  258. pts_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
  259. pts_drv->init_termios.c_lflag |= ECHO | ICANON;
  260. pts_drv->init_termios.c_oflag |= ONLCR;
  261. pts_drv->init_termios.__c_ispeed = 38400;
  262. pts_drv->init_termios.__c_ospeed = 38400;
  263. pts_drv->other_struct = ptm_drv;
  264. pts_drv->init_flag = TTY_INIT_FLAG_REGED;
  265. _exit:
  266. rt_hw_interrupt_enable(level);
  267. return ret;
  268. }
  269. static int ptmx_register(void)
  270. {
  271. rt_base_t level = 0;
  272. rt_err_t ret = RT_EOK;
  273. struct rt_device *device = RT_NULL;
  274. struct tty_struct *ptm_drv = &ptm_driver;
  275. level = rt_hw_interrupt_disable();
  276. RT_ASSERT(ptm_drv->init_flag == TTY_INIT_FLAG_NONE);
  277. device = &(ptm_drv->parent);
  278. device->type = RT_Device_Class_Char;
  279. #ifdef RT_USING_DEVICE_OPS
  280. device->ops = &pty_device_ops;
  281. #else
  282. device->init = pty_device_init;
  283. device->open = pty_device_open;
  284. device->close = pty_device_close;
  285. device->read = pty_device_read;
  286. device->write = pty_device_write;
  287. device->control = pty_device_control;
  288. #endif /* RT_USING_DEVICE_OPS */
  289. ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
  290. if (ret != RT_EOK)
  291. {
  292. LOG_E("ptmx register fail\n");
  293. ret = -RT_EIO;
  294. goto _exit;
  295. }
  296. #ifdef RT_USING_POSIX_DEVIO
  297. /* set fops */
  298. tty_set_fops(&ptmx_fops);
  299. ptmx_fops.open = ptmx_open;
  300. device->fops = &ptmx_fops;
  301. #endif
  302. ptm_drv->type = TTY_DRIVER_TYPE_PTY;
  303. ptm_drv->subtype = PTY_TYPE_MASTER;
  304. ptm_drv->head = rt_calloc(1, sizeof(struct tty_node));
  305. if (!ptm_drv->head)
  306. {
  307. return -RT_ENOMEM;
  308. }
  309. tty_initstack(ptm_drv->head);
  310. ptm_drv->pgrp = -1;
  311. ptm_drv->session = -1;
  312. ptm_drv->foreground = RT_NULL;
  313. rt_wqueue_init(&ptm_drv->wait_queue);
  314. tty_ldisc_init(ptm_drv);
  315. extern struct termios tty_std_termios;
  316. ptm_drv->init_termios.c_iflag = 0;
  317. ptm_drv->init_termios.c_oflag = 0;
  318. ptm_drv->init_termios.c_cflag = B38400 | CS8 | CREAD;
  319. ptm_drv->init_termios.c_lflag = 0;
  320. ptm_drv->init_termios.__c_ispeed = 38400;
  321. ptm_drv->init_termios.__c_ospeed = 38400;
  322. ptm_drv->init_flag = TTY_INIT_FLAG_REGED;
  323. _exit:
  324. rt_hw_interrupt_enable(level);
  325. return ret;
  326. }
  327. INIT_DEVICE_EXPORT(ptmx_register);