tty_ptmx.c 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  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-12-07 Shell init ver.
  9. */
  10. #define DBG_TAG "lwp.tty"
  11. #define DBG_LVL DBG_INFO
  12. #include <rtdbg.h>
  13. #include "tty_config.h"
  14. #include "tty_internal.h"
  15. #include "bsd_porting.h"
  16. #include "terminal.h"
  17. #include <fcntl.h>
  18. static struct dfs_file_ops ptm_fops;
  19. static int ptm_fops_open(struct dfs_file *file)
  20. {
  21. int rc;
  22. rt_uint32_t oflags = file->flags;
  23. rt_thread_t cur_thr = rt_thread_self();
  24. if (file->vnode && file->vnode->data)
  25. {
  26. /**
  27. * Filter out illegal flags
  28. */
  29. if ((oflags & ~(O_RDWR | O_NOCTTY | O_CLOEXEC | O_LARGEFILE)) == 0)
  30. {
  31. rc = pts_alloc(FFLAGS(oflags & O_ACCMODE), cur_thr, file);
  32. /* detached operation from devfs */
  33. if (rc == 0)
  34. file->vnode->fops = &ptm_fops;
  35. }
  36. else
  37. {
  38. rc = -EINVAL;
  39. }
  40. }
  41. else
  42. {
  43. rc = -EINVAL;
  44. }
  45. return rc;
  46. }
  47. static int ptm_fops_close(struct dfs_file *file)
  48. {
  49. int rc;
  50. lwp_tty_t tp;
  51. rt_device_t device;
  52. if (file->data)
  53. {
  54. device = (rt_device_t)file->data;
  55. tp = rt_container_of(device, struct lwp_tty, parent);
  56. rc = bsd_ptsdev_methods.fo_close(tp, rt_thread_self());
  57. }
  58. else
  59. {
  60. rc = -EINVAL;
  61. }
  62. return rc;
  63. }
  64. static ssize_t ptm_fops_read(struct dfs_file *file, void *buf, size_t count,
  65. off_t *pos)
  66. {
  67. ssize_t rc = 0;
  68. int error;
  69. struct uio uio;
  70. struct iovec iov;
  71. rt_device_t device;
  72. struct lwp_tty *tp;
  73. int oflags = file->flags;
  74. if (file->data)
  75. {
  76. device = (rt_device_t)file->data;
  77. tp = rt_container_of(device, struct lwp_tty, parent);
  78. /* setup uio parameters */
  79. iov.iov_base = (void *)buf;
  80. iov.iov_len = count;
  81. uio.uio_offset = file->fpos;
  82. uio.uio_resid = count;
  83. uio.uio_iov = &iov;
  84. uio.uio_iovcnt = 1;
  85. uio.uio_rw = UIO_READ;
  86. rc = count;
  87. error =
  88. bsd_ptsdev_methods.fo_read(tp, &uio, 0, oflags, rt_thread_self());
  89. rc -= uio.uio_resid;
  90. if (error)
  91. {
  92. rc = error;
  93. }
  94. /* reset file context */
  95. file->fpos = uio.uio_offset;
  96. }
  97. return rc;
  98. }
  99. static ssize_t ptm_fops_write(struct dfs_file *file, const void *buf,
  100. size_t count, off_t *pos)
  101. {
  102. ssize_t rc = 0;
  103. int error;
  104. struct uio uio;
  105. struct iovec iov;
  106. rt_device_t device;
  107. struct lwp_tty *tp;
  108. int oflags = file->flags;
  109. if (file->data)
  110. {
  111. device = (rt_device_t)file->data;
  112. tp = rt_container_of(device, struct lwp_tty, parent);
  113. /* setup uio parameters */
  114. iov.iov_base = (void *)buf;
  115. iov.iov_len = count;
  116. uio.uio_offset = file->fpos;
  117. uio.uio_resid = count;
  118. uio.uio_iov = &iov;
  119. uio.uio_iovcnt = 1;
  120. uio.uio_rw = UIO_WRITE;
  121. rc = count;
  122. error =
  123. bsd_ptsdev_methods.fo_write(tp, &uio, 0, oflags, rt_thread_self());
  124. if (error)
  125. {
  126. rc = error;
  127. }
  128. else
  129. {
  130. rc -= uio.uio_resid;
  131. }
  132. /* reset file context */
  133. file->fpos = uio.uio_offset;
  134. }
  135. return rc;
  136. }
  137. static int ptm_fops_ioctl(struct dfs_file *file, int cmd, void *arg)
  138. {
  139. int rc;
  140. lwp_tty_t tp;
  141. rt_device_t device;
  142. rt_ubase_t cmd_normal = (unsigned int)cmd;
  143. if (file->data)
  144. {
  145. device = (rt_device_t)file->data;
  146. tp = rt_container_of(device, struct lwp_tty, parent);
  147. switch (cmd_normal)
  148. {
  149. case TIOCSPTLCK:
  150. {
  151. int is_lock;
  152. if (lwp_get_from_user(&is_lock, arg, sizeof(int)) != sizeof(int))
  153. return -EFAULT;
  154. pts_set_lock(tp, is_lock);
  155. rc = 0;
  156. }
  157. break;
  158. case TIOCGPTLCK:
  159. {
  160. int is_lock = pts_is_locked(tp);
  161. if (lwp_put_to_user(arg, &is_lock, sizeof(int)) != sizeof(int))
  162. return -EFAULT;
  163. rc = 0;
  164. }
  165. break;
  166. case TIOCGPKT:
  167. {
  168. int pktmode = pts_get_pktmode(tp);
  169. if (lwp_put_to_user(arg, &pktmode, sizeof(int)) != sizeof(int))
  170. return -EFAULT;
  171. rc = 0;
  172. }
  173. break;
  174. default:
  175. rc = bsd_ptsdev_methods.fo_ioctl(
  176. tp, cmd_normal, arg, 0, FFLAGS(file->flags), rt_thread_self());
  177. break;
  178. }
  179. }
  180. else
  181. {
  182. rc = -EINVAL;
  183. }
  184. return rc;
  185. }
  186. static int ptm_fops_flush(struct dfs_file *file)
  187. {
  188. return -EINVAL;
  189. }
  190. static off_t ptm_fops_lseek(struct dfs_file *file, off_t offset, int wherece)
  191. {
  192. return -EINVAL;
  193. }
  194. static int ptm_fops_truncate(struct dfs_file *file, off_t offset)
  195. {
  196. return -EINVAL;
  197. }
  198. static int ptm_fops_poll(struct dfs_file *file, struct rt_pollreq *req)
  199. {
  200. int rc;
  201. rt_device_t device;
  202. struct lwp_tty *tp;
  203. if (file->data)
  204. {
  205. device = (rt_device_t)file->data;
  206. tp = rt_container_of(device, struct lwp_tty, parent);
  207. rc = bsd_ptsdev_methods.fo_poll(tp, req, 0, rt_thread_self());
  208. }
  209. else
  210. {
  211. rc = -1;
  212. }
  213. return rc;
  214. }
  215. static int ptm_fops_mmap(struct dfs_file *file, struct lwp_avl_struct *mmap)
  216. {
  217. return -EINVAL;
  218. }
  219. static int ptm_fops_lock(struct dfs_file *file, struct file_lock *flock)
  220. {
  221. return -EINVAL;
  222. }
  223. static int ptm_fops_flock(struct dfs_file *file, int operation, struct file_lock *flock)
  224. {
  225. return -EINVAL;
  226. }
  227. static struct dfs_file_ops ptm_fops = {
  228. .open = ptm_fops_open,
  229. .close = ptm_fops_close,
  230. .ioctl = ptm_fops_ioctl,
  231. .read = ptm_fops_read,
  232. .write = ptm_fops_write,
  233. .flush = ptm_fops_flush,
  234. .lseek = ptm_fops_lseek,
  235. .truncate = ptm_fops_truncate,
  236. .poll = ptm_fops_poll,
  237. .mmap = ptm_fops_mmap,
  238. .lock = ptm_fops_lock,
  239. .flock = ptm_fops_flock,
  240. };
  241. rt_err_t lwp_ptmx_init(rt_device_t ptmx_device, const char *root_path)
  242. {
  243. char *device_name;
  244. int root_len;
  245. const char *dev_rel_path;
  246. rt_err_t rc;
  247. root_len = strlen(root_path);
  248. dev_rel_path = "/ptmx";
  249. device_name = rt_malloc(root_len + sizeof("/ptmx"));
  250. if (device_name)
  251. {
  252. /* Register device */
  253. sprintf(device_name, "%s%s", root_path, dev_rel_path);
  254. rt_device_register(ptmx_device, device_name, 0);
  255. /* Setup fops */
  256. ptmx_device->fops = &ptm_fops;
  257. rt_free(device_name);
  258. rc = RT_EOK;
  259. }
  260. else
  261. {
  262. rc = -RT_ENOMEM;
  263. }
  264. return rc;
  265. }
  266. /* system level ptmx */
  267. static struct rt_device sysptmx;
  268. static struct dfs_file_ops sysptmx_file_ops;
  269. static rt_err_t sysptmx_readlink(struct rt_device *dev, char *buf, int len)
  270. {
  271. int rc = 0;
  272. /* TODO: support multi-root ? */
  273. strncpy(buf, "pts/ptmx", len);
  274. return rc;
  275. }
  276. static int _sys_ptmx_init(void)
  277. {
  278. rt_err_t rc;
  279. rt_device_t sysptmx_rtdev = &sysptmx;
  280. /* setup system level device */
  281. sysptmx_rtdev->type = RT_Device_Class_Char;
  282. sysptmx_rtdev->ops = RT_NULL;
  283. rc = rt_device_register(sysptmx_rtdev, "ptmx", RT_DEVICE_FLAG_DYNAMIC);
  284. if (rc == RT_EOK)
  285. {
  286. sysptmx_rtdev->readlink = &sysptmx_readlink;
  287. sysptmx_rtdev->fops = &sysptmx_file_ops;
  288. }
  289. return rc;
  290. }
  291. INIT_DEVICE_EXPORT(_sys_ptmx_init);