1
0

tty_ptmx.c 7.7 KB

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