pty.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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_err_t result = RT_EOK;
  69. struct tty_struct *tty = RT_NULL;
  70. RT_ASSERT(dev != RT_NULL);
  71. tty = (struct tty_struct *)dev;
  72. RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_REGED);
  73. tty->init_flag = TTY_INIT_FLAG_INITED;
  74. return result;
  75. }
  76. static rt_err_t pty_device_open(struct rt_device *dev, rt_uint16_t oflag)
  77. {
  78. rt_err_t result = RT_EOK;
  79. return result;
  80. }
  81. static rt_err_t pty_device_close(struct rt_device *dev)
  82. {
  83. rt_err_t result = RT_EOK;
  84. struct tty_struct *tty = (struct tty_struct*)dev;
  85. //struct tty_struct *to = RT_NULL;
  86. if (tty->subtype == PTY_TYPE_MASTER)
  87. {
  88. // to = tty->other_struct;
  89. // to->init_flag = TTY_INIT_FLAG_NONE;
  90. // to->other_struct = RT_NULL;
  91. // to->foreground = RT_NULL;
  92. // to->index = -1;
  93. // tty_ldisc_kill(to);
  94. // tty->other_struct = RT_NULL;
  95. }
  96. else
  97. {
  98. // to = tty->other_struct;
  99. // to->other_struct = RT_NULL;
  100. // tty->init_flag = TTY_INIT_FLAG_NONE;
  101. // tty->other_struct = RT_NULL;
  102. // tty->foreground = RT_NULL;
  103. // tty->index = -1;
  104. // tty->other_struct = RT_NULL;
  105. // tty_ldisc_kill(tty);
  106. }
  107. return result;
  108. }
  109. static rt_ssize_t pty_device_read(struct rt_device *dev,
  110. rt_off_t pos,
  111. void *buffer,
  112. rt_size_t size)
  113. {
  114. rt_size_t len = 0;
  115. return len;
  116. }
  117. static rt_ssize_t pty_device_write(struct rt_device *dev,
  118. rt_off_t pos,
  119. const void *buffer,
  120. rt_size_t size)
  121. {
  122. rt_size_t len = 0;
  123. rt_base_t level = 0;
  124. struct tty_struct *tty = RT_NULL;
  125. struct tty_struct *to = RT_NULL;
  126. tty = (struct tty_struct *)dev;
  127. RT_ASSERT(tty != RT_NULL);
  128. RT_ASSERT(tty->init_flag == TTY_INIT_FLAG_INITED);
  129. to = tty->other_struct;
  130. level = rt_spin_lock_irqsave(&tty->spinlock);
  131. if (to->ldisc->ops->receive_buf)
  132. {
  133. len = to->ldisc->ops->receive_buf(to, (char *)buffer, size);
  134. }
  135. rt_spin_unlock_irqrestore(&tty->spinlock, level);
  136. return len;
  137. }
  138. static rt_err_t pty_device_control(rt_device_t dev, int cmd, void *args)
  139. {
  140. struct tty_struct *tty = (struct tty_struct *)dev;
  141. switch (cmd)
  142. {
  143. case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */
  144. return pty_set_lock(tty, (int *)args);
  145. case TIOCGPTLCK: /* Get PT Lock status */
  146. return pty_get_lock(tty, (int *)args);
  147. case TIOCGPTN: /* Get PT Number */
  148. return pty_get_index(tty, (int *)args);
  149. }
  150. return -ENOIOCTLCMD;
  151. }
  152. static int ptmx_open(struct dfs_file *fd)
  153. {
  154. int ret = 0;
  155. struct tty_struct *tty = RT_NULL;
  156. struct tty_struct *pts = RT_NULL;
  157. struct tty_ldisc *ld = RT_NULL;
  158. tty = (struct tty_struct *)fd->vnode->data;
  159. RT_ASSERT(tty != RT_NULL);
  160. pts = find_freepts();
  161. if (pts == RT_NULL)
  162. {
  163. LOG_E("No free PTS device found.\n");
  164. return -1;
  165. }
  166. ret = pts_register(tty, pts, pts_index);
  167. if (ret < 0)
  168. {
  169. LOG_E("pts register fail\n");
  170. rt_free(pts);
  171. return -1;
  172. }
  173. pts_index++;
  174. tty->other_struct = pts;
  175. ld = tty->ldisc;
  176. if (ld->ops->open)
  177. {
  178. ret = ld->ops->open(fd);
  179. }
  180. rt_device_t device = (rt_device_t)fd->vnode->data;
  181. if(fd->vnode->ref_count == 1)
  182. {
  183. ret = rt_device_open(device, fd->flags);
  184. }
  185. return ret;
  186. }
  187. #ifdef RT_USING_DEVICE_OPS
  188. const static struct rt_device_ops pty_device_ops =
  189. {
  190. pty_device_init,
  191. pty_device_open,
  192. pty_device_close,
  193. pty_device_read,
  194. pty_device_write,
  195. pty_device_control,
  196. };
  197. #endif /* RT_USING_DEVICE_OPS */
  198. static struct dfs_file_ops pts_fops;
  199. static struct dfs_file_ops ptmx_fops;
  200. static int pts_register(struct tty_struct *ptmx, struct tty_struct *pts, int pts_index)
  201. {
  202. char name[20];
  203. rt_err_t ret = RT_EOK;
  204. struct rt_device *device = RT_NULL;
  205. RT_ASSERT(ptmx!=RT_NULL);
  206. if (pts->init_flag != TTY_INIT_FLAG_ALLOCED)
  207. {
  208. LOG_E("pts%d has been registered\n", pts_index);
  209. ret = (-RT_EBUSY);
  210. }
  211. else
  212. {
  213. tty_init(pts, TTY_DRIVER_TYPE_PTY, PTY_TYPE_SLAVE, NULL);
  214. pts->index = pts_index;
  215. pts->pts_lock = 1;
  216. pts->other_struct = ptmx;
  217. device = &pts->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. }
  236. else
  237. {
  238. #ifdef RT_USING_POSIX_DEVIO
  239. /* set fops */
  240. memcpy(&pts_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
  241. device->fops = &pts_fops;
  242. #endif
  243. }
  244. }
  245. return ret;
  246. }
  247. static int ptmx_register(void)
  248. {
  249. rt_err_t ret = RT_EOK;
  250. struct rt_device *device = RT_NULL;
  251. struct tty_struct *ptmx = &ptm_dev;
  252. RT_ASSERT(ptmx->init_flag == TTY_INIT_FLAG_NONE);
  253. tty_init(ptmx, TTY_DRIVER_TYPE_PTY, PTY_TYPE_MASTER, NULL);
  254. device = &(ptmx->parent);
  255. device->type = RT_Device_Class_Char;
  256. #ifdef RT_USING_DEVICE_OPS
  257. device->ops = &pty_device_ops;
  258. #else
  259. device->init = pty_device_init;
  260. device->open = pty_device_open;
  261. device->close = pty_device_close;
  262. device->read = pty_device_read;
  263. device->write = pty_device_write;
  264. device->control = pty_device_control;
  265. #endif /* RT_USING_DEVICE_OPS */
  266. ret = rt_device_register(device, "ptmx", RT_DEVICE_FLAG_RDWR);
  267. if (ret != RT_EOK)
  268. {
  269. LOG_E("ptmx register fail\n");
  270. ret = -RT_EIO;
  271. }
  272. else
  273. {
  274. #ifdef RT_USING_POSIX_DEVIO
  275. /* set fops */
  276. memcpy(&ptmx_fops, tty_get_fops(), sizeof(struct dfs_file_ops));
  277. ptmx_fops.open = ptmx_open;
  278. device->fops = &ptmx_fops;
  279. #endif
  280. }
  281. return ret;
  282. }
  283. INIT_DEVICE_EXPORT(ptmx_register);