tty_pts.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837
  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. #include <ipc/condvar.h>
  11. #include <rid_bitmap.h>
  12. #include <terminal/terminal.h>
  13. #include <terminal/tty_internal.h>
  14. #include <ptyfs.h>
  15. #include <rtthread.h>
  16. /*-
  17. * SPDX-License-Identifier: BSD-2-Clause
  18. *
  19. * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
  20. * All rights reserved.
  21. *
  22. * Portions of this software were developed under sponsorship from Snow
  23. * B.V., the Netherlands.
  24. *
  25. * Redistribution and use in source and binary forms, with or without
  26. * modification, are permitted provided that the following conditions
  27. * are met:
  28. * 1. Redistributions of source code must retain the above copyright
  29. * notice, this list of conditions and the following disclaimer.
  30. * 2. Redistributions in binary form must reproduce the above copyright
  31. * notice, this list of conditions and the following disclaimer in the
  32. * documentation and/or other materials provided with the distribution.
  33. *
  34. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  35. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  36. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  37. * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  38. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  39. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  40. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  41. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  42. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  43. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  44. * SUCH DAMAGE.
  45. */
  46. #define PTS_EXTERNAL
  47. /*
  48. * Per-PTS structure.
  49. *
  50. * List of locks
  51. * (t) locked by tty_lock()
  52. * (c) const until freeing
  53. */
  54. struct pts_softc
  55. {
  56. int pts_unit; /* (c) Device unit number. */
  57. unsigned int pts_flags; /* (t) Device flags. */
  58. #define PTS_PKT 0x1 /* Packet mode. */
  59. #define PTS_FINISHED 0x2 /* Return errors on read()/write(). */
  60. #define PTS_PTLOCKED 0x4 /* ioctl %TIOCSPTLCK/%TIOCGPTLCK */
  61. char pts_pkt; /* (t) Unread packet mode data. */
  62. struct rt_condvar pts_inwait; /* (t) Blocking write() on master. */
  63. struct rt_wqueue pts_inpoll; /* (t) Select queue for write(). */
  64. struct rt_condvar pts_outwait; /* (t) Blocking read() on master. */
  65. struct rt_wqueue pts_outpoll; /* (t) Select queue for read(). */
  66. struct ucred *pts_cred; /* (c) Resource limit. */
  67. rt_device_t pts_master; /** (c) Master device.
  68. * (Note: in rtsmart kernel, we support
  69. * multi-instance ptmx )
  70. */
  71. };
  72. /**
  73. * Controller-side file operations.
  74. * (P)seudo-(T)erminal (M)ultiple(X)er
  75. */
  76. static int ptsdev_read(struct lwp_tty *tp, struct uio *uio,
  77. struct ucred *active_cred, int oflags,
  78. struct rt_thread *td)
  79. {
  80. struct pts_softc *psc = tty_softc(tp);
  81. int error = 0;
  82. char pkt;
  83. if (uio->uio_resid == 0)
  84. return (0);
  85. tty_lock(tp);
  86. for (;;)
  87. {
  88. /*
  89. * Implement packet mode. When packet mode is turned on,
  90. * the first byte contains a bitmask of events that
  91. * occurred (start, stop, flush, window size, etc).
  92. */
  93. if (psc->pts_flags & PTS_PKT && psc->pts_pkt)
  94. {
  95. pkt = psc->pts_pkt;
  96. psc->pts_pkt = 0;
  97. tty_unlock(tp);
  98. error = uiomove(&pkt, 1, uio);
  99. return (error);
  100. }
  101. /*
  102. * Transmit regular data.
  103. *
  104. * XXX: We shouldn't use ttydisc_getc_poll()! Even
  105. * though in this implementation, there is likely going
  106. * to be data, we should just call ttydisc_getc_uio()
  107. * and use its return value to sleep.
  108. */
  109. if (ttydisc_getc_poll(tp))
  110. {
  111. if (psc->pts_flags & PTS_PKT)
  112. {
  113. /*
  114. * XXX: Small race. Fortunately PTY
  115. * consumers aren't multithreaded.
  116. */
  117. tty_unlock(tp);
  118. pkt = TIOCPKT_DATA;
  119. error = uiomove(&pkt, 1, uio);
  120. if (error)
  121. return (error);
  122. tty_lock(tp);
  123. }
  124. error = ttydisc_getc_uio(tp, uio);
  125. break;
  126. }
  127. /* Maybe the device isn't used anyway. */
  128. if (psc->pts_flags & PTS_FINISHED)
  129. break;
  130. /* Wait for more data. */
  131. if (oflags & O_NONBLOCK)
  132. {
  133. error = EWOULDBLOCK;
  134. break;
  135. }
  136. error = cv_wait_sig(&psc->pts_outwait, tp->t_mtx);
  137. if (error != 0)
  138. break;
  139. }
  140. tty_unlock(tp);
  141. return (error);
  142. }
  143. static int ptsdev_write(struct lwp_tty *tp, struct uio *uio,
  144. struct ucred *active_cred, int oflags,
  145. struct rt_thread *td)
  146. {
  147. struct pts_softc *psc = tty_softc(tp);
  148. char ib[256], *ibstart;
  149. size_t iblen, rintlen;
  150. int error = 0;
  151. if (uio->uio_resid == 0)
  152. return (0);
  153. for (;;)
  154. {
  155. ibstart = ib;
  156. iblen = MIN(uio->uio_resid, sizeof ib);
  157. error = uiomove(ib, iblen, uio);
  158. tty_lock(tp);
  159. if (error != 0)
  160. {
  161. iblen = 0;
  162. goto done;
  163. }
  164. /*
  165. * When possible, avoid the slow path. rint_bypass()
  166. * copies all input to the input queue at once.
  167. */
  168. MPASS(iblen > 0);
  169. do
  170. {
  171. rintlen = ttydisc_rint_simple(tp, ibstart, iblen);
  172. ibstart += rintlen;
  173. iblen -= rintlen;
  174. if (iblen == 0)
  175. {
  176. /* All data written. */
  177. break;
  178. }
  179. /* Maybe the device isn't used anyway. */
  180. if (psc->pts_flags & PTS_FINISHED)
  181. {
  182. error = -EIO;
  183. goto done;
  184. }
  185. /* Wait for more data. */
  186. if (oflags & O_NONBLOCK)
  187. {
  188. error = -EWOULDBLOCK;
  189. goto done;
  190. }
  191. /* Wake up users on the slave side. */
  192. ttydisc_rint_done(tp);
  193. error = cv_wait_sig(&psc->pts_inwait, tp->t_mtx);
  194. if (error != 0)
  195. goto done;
  196. } while (iblen > 0);
  197. if (uio->uio_resid == 0)
  198. break;
  199. tty_unlock(tp);
  200. }
  201. done:
  202. ttydisc_rint_done(tp);
  203. tty_unlock(tp);
  204. /*
  205. * Don't account for the part of the buffer that we couldn't
  206. * pass to the TTY.
  207. */
  208. uio->uio_resid += iblen;
  209. return (error);
  210. }
  211. static int ptsdev_ioctl(struct lwp_tty *tp, rt_ubase_t cmd, void *data,
  212. struct ucred *active_cred, int fflags,
  213. struct rt_thread *td)
  214. {
  215. struct pts_softc *psc = tty_softc(tp);
  216. int error = 0, sig;
  217. switch (cmd)
  218. {
  219. #ifdef USING_BSD_IOCTL_EXT
  220. case FIODTYPE:
  221. *(int *)data = D_TTY;
  222. return (0);
  223. #endif
  224. case FIONBIO:
  225. /* This device supports non-blocking operation. */
  226. return (0);
  227. case FIONREAD:
  228. tty_lock(tp);
  229. if (psc->pts_flags & PTS_FINISHED)
  230. {
  231. /* Force read() to be called. */
  232. *(int *)data = 1;
  233. }
  234. else
  235. {
  236. *(int *)data = ttydisc_getc_poll(tp);
  237. }
  238. tty_unlock(tp);
  239. return (0);
  240. #ifdef USING_BSD_IOCTL_EXT
  241. case FIODGNAME:
  242. #ifdef COMPAT_FREEBSD32
  243. case FIODGNAME_32:
  244. #endif
  245. {
  246. struct fiodgname_arg *fgn;
  247. const char *p;
  248. int i;
  249. /* Reverse device name lookups, for ptsname() and ttyname(). */
  250. fgn = data;
  251. p = tty_devname(tp);
  252. i = strlen(p) + 1;
  253. if (i > fgn->len)
  254. return -EINVAL;
  255. return (copyout(p, fiodgname_buf_get_ptr(fgn, cmd), i));
  256. }
  257. #endif
  258. /*
  259. * We need to implement TIOCGPGRP and TIOCGSID here again. When
  260. * called on the pseudo-terminal master, it should not check if
  261. * the terminal is the foreground terminal of the calling
  262. * process.
  263. *
  264. * TIOCGETA is also implemented here. Various Linux PTY routines
  265. * often call isatty(), which is implemented by tcgetattr().
  266. */
  267. case TIOCGETA:
  268. /* Obtain terminal flags through tcgetattr(). */
  269. tty_lock(tp);
  270. *(struct termios *)data = tp->t_termios;
  271. tty_unlock(tp);
  272. return (0);
  273. case TIOCSETAF:
  274. case TIOCSETAW:
  275. /*
  276. * We must make sure we turn tcsetattr() calls of TCSAFLUSH and
  277. * TCSADRAIN into something different. If an application would
  278. * call TCSAFLUSH or TCSADRAIN on the master descriptor, it may
  279. * deadlock waiting for all data to be read.
  280. */
  281. cmd = TIOCSETA;
  282. break;
  283. case TIOCGPTN:
  284. /*
  285. * Get the device unit number.
  286. */
  287. if (psc->pts_unit < 0)
  288. return -ENOTTY;
  289. *(unsigned int *)data = psc->pts_unit;
  290. return (0);
  291. case TIOCGPGRP:
  292. /* Get the foreground process group ID. */
  293. tty_lock(tp);
  294. if (tp->t_pgrp != NULL)
  295. *(int *)data = tp->t_pgrp->pgid;
  296. else
  297. *(int *)data = NO_PID;
  298. tty_unlock(tp);
  299. return (0);
  300. case TIOCGSID:
  301. /* Get the session leader process ID. */
  302. tty_lock(tp);
  303. if (tp->t_session == NULL)
  304. error = -ENOTTY;
  305. else
  306. *(int *)data = tp->t_session->sid;
  307. tty_unlock(tp);
  308. return (error);
  309. #ifdef USING_BSD_IOCTL_EXT
  310. case TIOCPTMASTER:
  311. /* Yes, we are a pseudo-terminal master. */
  312. return (0);
  313. #endif /* USING_BSD_IOCTL_EXT */
  314. case TIOCSIG:
  315. /* Signal the foreground process group. */
  316. sig = *(int *)data;
  317. if (sig < 1 || sig >= _LWP_NSIG)
  318. return -EINVAL;
  319. tty_lock(tp);
  320. lwp_tty_signal_pgrp(tp, sig);
  321. tty_unlock(tp);
  322. return (0);
  323. case TIOCPKT:
  324. /* Enable/disable packet mode. */
  325. tty_lock(tp);
  326. if (*(int *)data)
  327. psc->pts_flags |= PTS_PKT;
  328. else
  329. psc->pts_flags &= ~PTS_PKT;
  330. tty_unlock(tp);
  331. return (0);
  332. }
  333. /* Just redirect this ioctl to the slave device. */
  334. tty_lock(tp);
  335. error = tty_ioctl(tp, cmd, data, fflags, td);
  336. tty_unlock(tp);
  337. if (error == -ENOIOCTL)
  338. error = -ENOTTY;
  339. return error;
  340. }
  341. static int ptsdev_poll(struct lwp_tty *tp, struct rt_pollreq *req,
  342. struct ucred *active_cred, struct rt_thread *td)
  343. {
  344. struct pts_softc *psc = tty_softc(tp);
  345. int revents = 0;
  346. int events = req->_key;
  347. tty_lock(tp);
  348. if (psc->pts_flags & PTS_FINISHED)
  349. {
  350. /* Slave device is not opened. */
  351. tty_unlock(tp);
  352. return ((events & (POLLIN | POLLRDNORM)) | POLLHUP);
  353. }
  354. if (events & (POLLIN | POLLRDNORM))
  355. {
  356. /* See if we can getc something. */
  357. if (ttydisc_getc_poll(tp) || (psc->pts_flags & PTS_PKT && psc->pts_pkt))
  358. revents |= events & (POLLIN | POLLRDNORM);
  359. }
  360. if (events & (POLLOUT | POLLWRNORM))
  361. {
  362. /* See if we can rint something. */
  363. if (ttydisc_rint_poll(tp))
  364. revents |= events & (POLLOUT | POLLWRNORM);
  365. }
  366. /*
  367. * No need to check for POLLHUP here. This device cannot be used
  368. * as a callout device, which means we always have a carrier,
  369. * because the master is.
  370. */
  371. if (revents == 0)
  372. {
  373. /*
  374. * This code might look misleading, but the naming of
  375. * poll events on this side is the opposite of the slave
  376. * device.
  377. */
  378. if (events & (POLLIN | POLLRDNORM))
  379. rt_poll_add(&psc->pts_outpoll, req);
  380. if (events & (POLLOUT | POLLWRNORM))
  381. rt_poll_add(&psc->pts_inpoll, req);
  382. }
  383. tty_unlock(tp);
  384. return (revents);
  385. }
  386. #if USING_BSD_KQUEUE
  387. /*
  388. * kqueue support.
  389. */
  390. static void pts_kqops_read_detach(struct knote *kn)
  391. {
  392. struct file *fp = kn->kn_fp;
  393. struct lwp_tty *tp = fp->f_data;
  394. struct pts_softc *psc = tty_softc(tp);
  395. knlist_remove(&psc->pts_outpoll.si_note, kn, 0);
  396. }
  397. static int pts_kqops_read_event(struct knote *kn, long hint)
  398. {
  399. struct file *fp = kn->kn_fp;
  400. struct lwp_tty *tp = fp->f_data;
  401. struct pts_softc *psc = tty_softc(tp);
  402. if (psc->pts_flags & PTS_FINISHED)
  403. {
  404. kn->kn_flags |= EV_EOF;
  405. return (1);
  406. }
  407. else
  408. {
  409. kn->kn_data = ttydisc_getc_poll(tp);
  410. return (kn->kn_data > 0);
  411. }
  412. }
  413. static void pts_kqops_write_detach(struct knote *kn)
  414. {
  415. struct file *fp = kn->kn_fp;
  416. struct lwp_tty *tp = fp->f_data;
  417. struct pts_softc *psc = tty_softc(tp);
  418. knlist_remove(&psc->pts_inpoll.si_note, kn, 0);
  419. }
  420. static int pts_kqops_write_event(struct knote *kn, long hint)
  421. {
  422. struct file *fp = kn->kn_fp;
  423. struct lwp_tty *tp = fp->f_data;
  424. struct pts_softc *psc = tty_softc(tp);
  425. if (psc->pts_flags & PTS_FINISHED)
  426. {
  427. kn->kn_flags |= EV_EOF;
  428. return (1);
  429. }
  430. else
  431. {
  432. kn->kn_data = ttydisc_rint_poll(tp);
  433. return (kn->kn_data > 0);
  434. }
  435. }
  436. static struct filterops pts_kqops_read = {
  437. .f_isfd = 1,
  438. .f_detach = pts_kqops_read_detach,
  439. .f_event = pts_kqops_read_event,
  440. };
  441. static struct filterops pts_kqops_write = {
  442. .f_isfd = 1,
  443. .f_detach = pts_kqops_write_detach,
  444. .f_event = pts_kqops_write_event,
  445. };
  446. static int ptsdev_kqfilter(struct file *fp, struct knote *kn)
  447. {
  448. struct lwp_tty *tp = fp->f_data;
  449. struct pts_softc *psc = tty_softc(tp);
  450. int error = 0;
  451. tty_lock(tp);
  452. switch (kn->kn_filter)
  453. {
  454. case EVFILT_READ:
  455. kn->kn_fop = &pts_kqops_read;
  456. knlist_add(&psc->pts_outpoll.si_note, kn, 1);
  457. break;
  458. case EVFILT_WRITE:
  459. kn->kn_fop = &pts_kqops_write;
  460. knlist_add(&psc->pts_inpoll.si_note, kn, 1);
  461. break;
  462. default:
  463. error = EINVAL;
  464. break;
  465. }
  466. tty_unlock(tp);
  467. return (error);
  468. }
  469. #endif
  470. #if USING_BSD_STAT
  471. static int ptsdev_stat(struct file *fp, struct stat *sb,
  472. struct ucred *active_cred)
  473. {
  474. struct lwp_tty *tp = fp->f_data;
  475. #ifdef PTS_EXTERNAL
  476. struct pts_softc *psc = tty_softc(tp);
  477. #endif /* PTS_EXTERNAL */
  478. struct cdev *dev = tp->t_dev;
  479. /*
  480. * According to POSIX, we must implement an fstat(). This also
  481. * makes this implementation compatible with Linux binaries,
  482. * because Linux calls fstat() on the pseudo-terminal master to
  483. * obtain st_rdev.
  484. *
  485. * XXX: POSIX also mentions we must fill in st_dev, but how?
  486. */
  487. bzero(sb, sizeof *sb);
  488. #ifdef PTS_EXTERNAL
  489. if (psc->pts_cdev != NULL)
  490. sb->st_ino = sb->st_rdev = dev2udev(psc->pts_cdev);
  491. else
  492. #endif /* PTS_EXTERNAL */
  493. sb->st_ino = sb->st_rdev = tty_udev(tp);
  494. sb->st_atim = dev->si_atime;
  495. sb->st_ctim = dev->si_ctime;
  496. sb->st_mtim = dev->si_mtime;
  497. sb->st_uid = dev->si_uid;
  498. sb->st_gid = dev->si_gid;
  499. sb->st_mode = dev->si_mode | S_IFCHR;
  500. return (0);
  501. }
  502. #endif
  503. static int ptsdev_close(struct lwp_tty *tp, struct rt_thread *td)
  504. {
  505. /* Deallocate TTY device. */
  506. tty_lock(tp);
  507. tty_rel_gone(tp);
  508. #ifdef USING_BSD_VNODE
  509. /* TODO: consider the vnode operation on DFS */
  510. /*
  511. * Open of /dev/ptmx or /dev/ptyXX changes the type of file
  512. * from DTYPE_VNODE to DTYPE_PTS. vn_open() increases vnode
  513. * use count, we need to decrement it, and possibly do other
  514. * required cleanup.
  515. */
  516. if (fp->f_vnode != NULL)
  517. return (vnops.fo_close(fp, td));
  518. #endif /* USING_BSD_VNODE */
  519. return 0;
  520. }
  521. #ifdef USING_BSD_KINFO
  522. static int ptsdev_fill_kinfo(struct file *fp, struct kinfo_file *kif,
  523. struct filedesc *fdp)
  524. {
  525. struct lwp_tty *tp;
  526. kif->kf_type = KF_TYPE_PTS;
  527. tp = fp->f_data;
  528. kif->kf_un.kf_pts.kf_pts_dev = tty_udev(tp);
  529. kif->kf_un.kf_pts.kf_pts_dev_freebsd11 =
  530. kif->kf_un.kf_pts.kf_pts_dev; /* truncate */
  531. strlcpy(kif->kf_path, tty_devname(tp), sizeof(kif->kf_path));
  532. return (0);
  533. }
  534. #endif
  535. struct bsd_fileops bsd_ptsdev_methods = {
  536. .fo_read = ptsdev_read,
  537. .fo_write = ptsdev_write,
  538. // .fo_truncate = invfo_truncate,
  539. .fo_ioctl = ptsdev_ioctl,
  540. .fo_poll = ptsdev_poll,
  541. // .fo_kqfilter = ptsdev_kqfilter,
  542. // .fo_stat = ptsdev_stat,
  543. .fo_close = ptsdev_close,
  544. // .fo_chmod = invfo_chmod,
  545. // .fo_chown = invfo_chown,
  546. // .fo_sendfile = invfo_sendfile,
  547. // .fo_fill_kinfo = ptsdev_fill_kinfo,
  548. .fo_flags = DFLAG_PASSABLE,
  549. };
  550. /*
  551. * Driver-side hooks.
  552. */
  553. static void ptsdrv_outwakeup(struct lwp_tty *tp)
  554. {
  555. struct pts_softc *psc = tty_softc(tp);
  556. cv_broadcast(&psc->pts_outwait);
  557. rt_wqueue_wakeup_all(&psc->pts_outpoll, (void *)POLLIN);
  558. }
  559. static void ptsdrv_inwakeup(struct lwp_tty *tp)
  560. {
  561. struct pts_softc *psc = tty_softc(tp);
  562. cv_broadcast(&psc->pts_inwait);
  563. rt_wqueue_wakeup_all(&psc->pts_inpoll, (void *)POLLOUT);
  564. }
  565. static int ptsdrv_open(struct lwp_tty *tp)
  566. {
  567. struct pts_softc *psc = tty_softc(tp);
  568. /* for ioctl(TIOCSPTLCK) */
  569. if (psc->pts_flags & PTS_PTLOCKED)
  570. return -EIO;
  571. psc->pts_flags &= ~PTS_FINISHED;
  572. return 0;
  573. }
  574. static void ptsdrv_close(struct lwp_tty *tp)
  575. {
  576. struct pts_softc *psc = tty_softc(tp);
  577. /* Wake up any blocked readers/writers. */
  578. psc->pts_flags |= PTS_FINISHED;
  579. ptsdrv_outwakeup(tp);
  580. ptsdrv_inwakeup(tp);
  581. }
  582. static void ptsdrv_pktnotify(struct lwp_tty *tp, char event)
  583. {
  584. struct pts_softc *psc = tty_softc(tp);
  585. /*
  586. * Clear conflicting flags.
  587. */
  588. switch (event)
  589. {
  590. case TIOCPKT_STOP:
  591. psc->pts_pkt &= ~TIOCPKT_START;
  592. break;
  593. case TIOCPKT_START:
  594. psc->pts_pkt &= ~TIOCPKT_STOP;
  595. break;
  596. case TIOCPKT_NOSTOP:
  597. psc->pts_pkt &= ~TIOCPKT_DOSTOP;
  598. break;
  599. case TIOCPKT_DOSTOP:
  600. psc->pts_pkt &= ~TIOCPKT_NOSTOP;
  601. break;
  602. }
  603. psc->pts_pkt |= event;
  604. /**
  605. * Note: on smart, we don't wakeup master until it's willing to accept
  606. * packet event. Because on poll, we setup POLLIN for PTS_PKT only. So There
  607. * is a chance when we wakeup ipc but we can't wakeup user again. Since
  608. * current wakeup will remove the wakequeue node on the meanwhile
  609. */
  610. if (psc->pts_flags & PTS_PKT)
  611. ptsdrv_outwakeup(tp);
  612. }
  613. static void ptsdrv_free(void *softc)
  614. {
  615. struct pts_softc *psc = softc;
  616. /* Make device number available again. */
  617. if (psc->pts_unit >= 0)
  618. ptyfs_unregister_pts(psc->pts_master, psc->pts_unit);
  619. #ifdef USING_BSD_UCRED
  620. chgptscnt(psc->pts_cred->cr_ruidinfo, -1, 0);
  621. racct_sub_cred(psc->pts_cred, RACCT_NPTS, 1);
  622. crfree(psc->pts_cred);
  623. #endif
  624. rt_wqueue_wakeup_all(&psc->pts_inpoll, (void *)POLLHUP);
  625. rt_wqueue_wakeup_all(&psc->pts_outpoll, (void *)POLLHUP);
  626. rt_free(psc);
  627. }
  628. static struct lwp_ttydevsw pts_class = {
  629. .tsw_flags = TF_NOPREFIX,
  630. .tsw_outwakeup = ptsdrv_outwakeup,
  631. .tsw_inwakeup = ptsdrv_inwakeup,
  632. .tsw_open = ptsdrv_open,
  633. .tsw_close = ptsdrv_close,
  634. .tsw_pktnotify = ptsdrv_pktnotify,
  635. .tsw_free = ptsdrv_free,
  636. };
  637. int pts_alloc(int fflags, struct rt_thread *td, struct dfs_file *ptm_file)
  638. {
  639. int unit;
  640. struct lwp_tty *tp;
  641. struct pts_softc *psc;
  642. char name_buf[DIRENT_NAME_MAX];
  643. const char *rootpath;
  644. rt_device_t ptmx_device = ptm_file->vnode->data;
  645. #ifdef USING_BSD_UCRED
  646. struct rt_lwp *p = td->lwp;
  647. int ok, error;
  648. struct ucred *cred = td->td_ucred;
  649. #endif
  650. /* Resource limiting. */
  651. #ifdef USING_BSD_UCRED
  652. LWP_LOCK(p);
  653. error = racct_add(p, RACCT_NPTS, 1);
  654. if (error != 0)
  655. {
  656. LWP_UNLOCK(p);
  657. return -EAGAIN;
  658. }
  659. ok = chgptscnt(cred->cr_ruidinfo, 1, lim_cur(td, RLIMIT_NPTS));
  660. if (!ok)
  661. {
  662. racct_sub(p, RACCT_NPTS, 1);
  663. LWP_UNLOCK(p);
  664. return -EAGAIN;
  665. }
  666. LWP_UNLOCK(p);
  667. #endif
  668. /* Allocate TTY and softc. */
  669. psc = rt_calloc(1, sizeof(struct pts_softc));
  670. cv_init(&psc->pts_inwait, "ptsin");
  671. cv_init(&psc->pts_outwait, "ptsout");
  672. rt_wqueue_init(&psc->pts_inpoll);
  673. rt_wqueue_init(&psc->pts_outpoll);
  674. psc->pts_master = ptmx_device;
  675. #ifdef USING_BSD_UCRED
  676. psc->pts_cred = crhold(cred);
  677. #else
  678. psc->pts_cred = 0;
  679. #endif
  680. tp = lwp_tty_create(&pts_class, psc);
  681. if (!tp)
  682. {
  683. rt_free(psc);
  684. rt_condvar_detach(&psc->pts_inwait);
  685. rt_condvar_detach(&psc->pts_outwait);
  686. return -ENOMEM;
  687. }
  688. /* Try to allocate a new pts uint*/
  689. unit = ptyfs_register_pts(ptmx_device, &tp->parent);
  690. if (unit < 0)
  691. {
  692. #ifdef USING_BSD_UCRED
  693. racct_sub(p, RACCT_NPTS, 1);
  694. chgptscnt(cred->cr_ruidinfo, -1, 0);
  695. #endif
  696. lwp_tty_delete(tp);
  697. return -EAGAIN;
  698. }
  699. psc->pts_unit = unit;
  700. /* Expose the slave device as well. */
  701. #ifdef USING_BSD_UCRED
  702. tty_makedev(tp, td->td_ucred, "pts/%u", psc->pts_unit);
  703. #else
  704. rootpath = ptyfs_get_rootpath(ptmx_device);
  705. RT_ASSERT(rootpath[strlen(rootpath) - 1] != '/');
  706. snprintf(name_buf, DIRENT_NAME_MAX, "%s/%d", rootpath, psc->pts_unit);
  707. /* setup the pts */
  708. lwp_tty_register(tp, name_buf);
  709. /* now this file operating on new pty */
  710. ptm_file->data = tp;
  711. #endif
  712. return 0;
  713. }
  714. void pts_set_lock(lwp_tty_t pts, rt_bool_t is_lock)
  715. {
  716. struct pts_softc *psc = tty_softc(pts);
  717. if (is_lock)
  718. psc->pts_flags |= PTS_PTLOCKED;
  719. else
  720. psc->pts_flags &= ~PTS_PTLOCKED;
  721. }
  722. rt_bool_t pts_is_locked(lwp_tty_t pts)
  723. {
  724. struct pts_softc *psc = tty_softc(pts);
  725. return !!(psc->pts_flags & PTS_PTLOCKED);
  726. }
  727. int pts_get_pktmode(lwp_tty_t pts)
  728. {
  729. struct pts_softc *psc = tty_softc(pts);
  730. return !!(psc->pts_flags & PTS_PKT);
  731. }