pty.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  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. * 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_dev;
  22. static struct tty_struct pts_devs[PTY_PTS_SIZE];
  23. static int pts_index = 0;
  24. static int pts_register(struct tty_struct *ptmx, struct tty_struct *pts, 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_devs[i].init_flag == TTY_INIT_FLAG_NONE)
  31. {
  32. pts_devs[i].init_flag = TTY_INIT_FLAG_ALLOCED;
  33. return &pts_devs[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_ubase_t level = 0;
  69. rt_err_t result = RT_EOK;
  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_size_t len = 0;
  126. rt_base_t level = 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_file *fd)
  156. {
  157. int ret = 0;
  158. struct tty_struct *tty = RT_NULL;
  159. struct tty_struct *pts = RT_NULL;
  160. struct tty_ldisc *ld = RT_NULL;
  161. tty = (struct tty_struct *)fd->vnode->data;
  162. RT_ASSERT(tty != RT_NULL);
  163. pts = find_freepts();
  164. if (pts == RT_NULL)
  165. {
  166. LOG_E("No free PTS device found.\n");
  167. return -1;
  168. }
  169. ret = pts_register(tty, pts, pts_index);
  170. if (ret < 0)
  171. {
  172. LOG_E("pts register fail\n");
  173. rt_free(pts);
  174. return -1;
  175. }
  176. pts_index++;
  177. tty->other_struct = pts;
  178. ld = tty->ldisc;
  179. if (ld->ops->open)
  180. {
  181. ret = ld->ops->open(fd);
  182. }
  183. rt_device_t device = (rt_device_t)fd->vnode->data;
  184. if(fd->vnode->ref_count == 1)
  185. {
  186. ret = rt_device_open(device, fd->flags);
  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 *ptmx, struct tty_struct *pts, int pts_index)
  204. {
  205. char name[20];
  206. rt_err_t ret = RT_EOK;
  207. struct rt_device *device = RT_NULL;
  208. RT_ASSERT(ptmx!=RT_NULL);
  209. if (pts->init_flag != TTY_INIT_FLAG_ALLOCED)
  210. {
  211. LOG_E("pts%d has been registered\n", pts_index);
  212. ret = (-RT_EBUSY);
  213. }
  214. else
  215. {
  216. tty_init(pts, TTY_DRIVER_TYPE_PTY, PTY_TYPE_SLAVE, NULL);
  217. pts->index = pts_index;
  218. pts->pts_lock = 1;
  219. pts->other_struct = ptmx;
  220. device = &pts->parent;
  221. device->type = RT_Device_Class_Char;
  222. #ifdef RT_USING_DEVICE_OPS
  223. device->ops = &pty_device_ops;
  224. #else
  225. device->init = pty_device_init;
  226. device->open = pty_device_open;
  227. device->close = pty_device_close;
  228. device->read = pty_device_read;
  229. device->write = pty_device_write;
  230. device->control = pty_device_control;
  231. #endif /* RT_USING_DEVICE_OPS */
  232. rt_snprintf(name, sizeof(name), "pts%d", pts_index);
  233. ret = rt_device_register(device, name, RT_DEVICE_FLAG_RDWR);
  234. if (ret != RT_EOK)
  235. {
  236. LOG_E("pts%d register failed\n", pts_index);
  237. ret = -RT_EIO;
  238. }
  239. else
  240. {
  241. #ifdef RT_USING_POSIX_DEVIO
  242. /* set fops */
  243. memcpy(&pts_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
  244. device->fops = &pts_fops;
  245. #endif
  246. }
  247. }
  248. return ret;
  249. }
  250. static int ptmx_register(void)
  251. {
  252. rt_err_t ret = RT_EOK;
  253. struct rt_device *device = RT_NULL;
  254. struct tty_struct *ptmx = &ptm_dev;
  255. RT_ASSERT(ptmx->init_flag == TTY_INIT_FLAG_NONE);
  256. tty_init(ptmx, TTY_DRIVER_TYPE_PTY, PTY_TYPE_MASTER, NULL);
  257. device = &(ptmx->parent);
  258. device->type = RT_Device_Class_Char;
  259. #ifdef RT_USING_DEVICE_OPS
  260. device->ops = &pty_device_ops;
  261. #else
  262. device->init = pty_device_init;
  263. device->open = pty_device_open;
  264. device->close = pty_device_close;
  265. device->read = pty_device_read;
  266. device->write = pty_device_write;
  267. device->control = pty_device_control;
  268. #endif /* RT_USING_DEVICE_OPS */
  269. ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
  270. if (ret != RT_EOK)
  271. {
  272. LOG_E("ptmx register fail\n");
  273. ret = -RT_EIO;
  274. }
  275. else
  276. {
  277. #ifdef RT_USING_POSIX_DEVIO
  278. /* set fops */
  279. memcpy(&ptmx_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
  280. ptmx_fops.open = ptmx_open;
  281. device->fops = &ptmx_fops;
  282. #endif
  283. }
  284. return ret;
  285. }
  286. INIT_DEVICE_EXPORT(ptmx_register);