DEVFS - remove dev_ops_add(), dev_ops_get(), and get_dev()
[dragonfly.git] / sys / kern / tty_pty.c
CommitLineData
984263bc
MD
1/*
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)tty_pty.c 8.4 (Berkeley) 2/20/95
34 * $FreeBSD: src/sys/kern/tty_pty.c,v 1.74.2.4 2002/02/20 19:58:13 dillon Exp $
8683f632 35 * $DragonFly: src/sys/kern/tty_pty.c,v 1.21 2008/08/13 10:29:38 swildner Exp $
984263bc
MD
36 */
37
38/*
39 * Pseudo-teletype Driver
fef8985e 40 * (Actually two drivers, requiring two dev_ops structures)
984263bc 41 */
1f2de5d4 42#include "use_pty.h" /* XXX */
984263bc 43#include "opt_compat.h"
1f2de5d4 44
984263bc
MD
45#include <sys/param.h>
46#include <sys/systm.h>
47#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
48#include <sys/ioctl_compat.h>
49#endif
50#include <sys/proc.h>
895c1f85 51#include <sys/priv.h>
984263bc
MD
52#include <sys/tty.h>
53#include <sys/conf.h>
54#include <sys/fcntl.h>
55#include <sys/poll.h>
56#include <sys/kernel.h>
57#include <sys/vnode.h>
58#include <sys/signalvar.h>
59#include <sys/malloc.h>
335dda38 60#include <sys/device.h>
e43a034f 61#include <sys/thread2.h>
cd29885a
MD
62#include <vfs/devfs/devfs.h>
63
64DEVFS_DECLARE_CLONE_BITMAP(pty);
65DEVFS_DECLARE_CLONE_BITMAP(pts);
984263bc
MD
66
67MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
68
402ed7e1
RG
69static void ptsstart (struct tty *tp);
70static void ptsstop (struct tty *tp, int rw);
71static void ptcwakeup (struct tty *tp, int flag);
72static void ptyinit (int n);
984263bc
MD
73
74static d_open_t ptsopen;
75static d_close_t ptsclose;
76static d_read_t ptsread;
77static d_write_t ptswrite;
78static d_ioctl_t ptyioctl;
79static d_open_t ptcopen;
80static d_close_t ptcclose;
81static d_read_t ptcread;
82static d_write_t ptcwrite;
83static d_poll_t ptcpoll;
cd29885a 84static d_clone_t ptyclone;
984263bc
MD
85
86#define CDEV_MAJOR_S 5
fef8985e
MD
87static struct dev_ops pts_ops = {
88 { "pts", CDEV_MAJOR_S, D_TTY | D_KQFILTER },
89 .d_open = ptsopen,
90 .d_close = ptsclose,
91 .d_read = ptsread,
92 .d_write = ptswrite,
93 .d_ioctl = ptyioctl,
94 .d_poll = ttypoll,
a32446b7
MD
95 .d_kqfilter = ttykqfilter,
96 .d_revoke = ttyrevoke
984263bc
MD
97};
98
99#define CDEV_MAJOR_C 6
fef8985e
MD
100static struct dev_ops ptc_ops = {
101 { "ptc", CDEV_MAJOR_C, D_TTY | D_KQFILTER | D_MASTER },
102 .d_open = ptcopen,
103 .d_close = ptcclose,
104 .d_read = ptcread,
105 .d_write = ptcwrite,
106 .d_ioctl = ptyioctl,
107 .d_poll = ptcpoll,
a32446b7
MD
108 .d_kqfilter = ttykqfilter,
109 .d_revoke = ttyrevoke
984263bc
MD
110};
111
112#define BUFSIZ 100 /* Chunk size iomoved to/from user */
113
114struct pt_ioctl {
115 int pt_flags;
116 struct selinfo pt_selr, pt_selw;
117 u_char pt_send;
118 u_char pt_ucntl;
119 struct tty pt_tty;
b13267a5 120 cdev_t devs, devc;
984263bc 121 struct prison *pt_prison;
cd29885a 122 short ref_count;
984263bc
MD
123};
124
125#define PF_PKT 0x08 /* packet mode */
126#define PF_STOPPED 0x10 /* user told stopped */
127#define PF_REMOTE 0x20 /* remote and flow controlled input */
128#define PF_NOSTOP 0x40
129#define PF_UCNTL 0x80 /* user control mode */
130
131/*
132 * This function creates and initializes a pts/ptc pair
133 *
134 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
135 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
136 *
137 * XXX: define and add mapping of upper minor bits to allow more
138 * than 256 ptys.
139 */
140static void
c972a82f 141ptyinit(int n)
984263bc 142{
b13267a5 143 cdev_t devs, devc;
984263bc
MD
144 char *names = "pqrsPQRS";
145 struct pt_ioctl *pt;
146
147 /* For now we only map the lower 8 bits of the minor */
148 if (n & ~0xff)
149 return;
150
e7b4468c 151 pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
fef8985e 152 pt->devs = devs = make_dev(&pts_ops, n,
984263bc 153 0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
fef8985e 154 pt->devc = devc = make_dev(&ptc_ops, n,
984263bc
MD
155 0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
156
157 devs->si_drv1 = devc->si_drv1 = pt;
158 devs->si_tty = devc->si_tty = &pt->pt_tty;
159 pt->pt_tty.t_dev = devs;
160 ttyregister(&pt->pt_tty);
161}
162
cd29885a
MD
163static int
164ptyclone(struct dev_clone_args *ap)
165{
166 int unit;
167 struct pt_ioctl *pt;
168
169 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(pty), 256);
170
171 if (unit < 0)
172 return 1;
173
174 pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
175 pt->ref_count++;
176 pt->devc = ap->a_dev = make_only_dev(&ptc_ops, unit, ap->a_cred->cr_ruid, 0, 0600, "ptm/%d", unit);
177 pt->devs = make_dev(&pts_ops, unit, ap->a_cred->cr_ruid, 0, 0600, "pts/%d", unit);
178
179 //reference_dev(pt->devc);
180 //reference_dev(pt->devs);
181
182 pt->devs->si_drv1 = pt->devc->si_drv1 = pt;
183 pt->devs->si_tty = pt->devc->si_tty = &pt->pt_tty;
184 pt->pt_tty.t_dev = pt->devs;
185 ttyregister(&pt->pt_tty);
186
187 return 0;
188}
189
984263bc
MD
190/*ARGSUSED*/
191static int
fef8985e 192ptsopen(struct dev_open_args *ap)
984263bc 193{
b13267a5 194 cdev_t dev = ap->a_head.a_dev;
1fd87d54 195 struct tty *tp;
984263bc 196 int error;
e4c9c0c8 197#if 0
8683f632 198 int minr;
b13267a5 199 cdev_t nextdev;
e4c9c0c8 200#endif
984263bc
MD
201 struct pt_ioctl *pti;
202
e4c9c0c8 203#if 0
8683f632 204 minr = lminor(dev);
984263bc 205 /*
e4c9c0c8
MD
206 * REMOVED gross hack for devfs. also note that makedev()
207 * no longer exists in this form and reference counting makes
208 * this a problem if we don't clean it out later.
984263bc 209 */
984263bc 210 if (minr < 255) {
e4c9c0c8 211 nextdev = make_sub_dev(dev, minr + 1);
984263bc
MD
212 if (!nextdev->si_drv1) {
213 ptyinit(minr + 1);
214 }
215 }
e4c9c0c8 216#endif
984263bc
MD
217 if (!dev->si_drv1)
218 ptyinit(minor(dev));
219 if (!dev->si_drv1)
cd29885a 220 return(ENXIO);
984263bc
MD
221 pti = dev->si_drv1;
222 tp = dev->si_tty;
223 if ((tp->t_state & TS_ISOPEN) == 0) {
224 ttychars(tp); /* Set up default chars */
225 tp->t_iflag = TTYDEF_IFLAG;
226 tp->t_oflag = TTYDEF_OFLAG;
227 tp->t_lflag = TTYDEF_LFLAG;
228 tp->t_cflag = TTYDEF_CFLAG;
229 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
895c1f85 230 } else if ((tp->t_state & TS_XCLUDE) && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
984263bc 231 return (EBUSY);
fef8985e 232 } else if (pti->pt_prison != ap->a_cred->cr_prison) {
984263bc
MD
233 return (EBUSY);
234 }
235 if (tp->t_oproc) /* Ctrlr still around. */
236 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
237 while ((tp->t_state & TS_CARR_ON) == 0) {
fef8985e 238 if (ap->a_oflags & FNONBLOCK)
984263bc 239 break;
377d4740 240 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0);
984263bc
MD
241 if (error)
242 return (error);
243 }
244 error = (*linesw[tp->t_line].l_open)(dev, tp);
245 if (error == 0)
246 ptcwakeup(tp, FREAD|FWRITE);
cd29885a
MD
247
248#if 0
249 /* unix98 pty stuff */
250 if ((!error) && (!memcmp(dev->si_name, "pts/", 4))) {
251 ((struct pt_ioctl *)dev->si_drv1)->ref_count++;
252 //reference_dev(dev);
253 //reference_dev(((struct pt_ioctl *)dev->si_drv1)->devc);
254 //devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(pts), dev->si_uminor-300);
255 }
256#endif
257
984263bc
MD
258 return (error);
259}
260
261static int
fef8985e 262ptsclose(struct dev_close_args *ap)
984263bc 263{
b13267a5 264 cdev_t dev = ap->a_head.a_dev;
1fd87d54 265 struct tty *tp;
984263bc 266 int err;
cd29885a
MD
267#if 0
268 /* unix98 pty stuff */
269 if (!memcmp(dev->si_name, "pts/", 4)) {
270 if (--((struct pt_ioctl *)dev->si_drv1)->ref_count == 0) {
271 kfree(dev->si_drv1, M_PTY);
272 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(pty), dev->si_uminor);
273 destroy_dev(dev);
274 }
275 }
276#endif
984263bc 277 tp = dev->si_tty;
fef8985e 278 err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
984263bc
MD
279 ptsstop(tp, FREAD|FWRITE);
280 (void) ttyclose(tp);
281 return (err);
282}
283
284static int
fef8985e 285ptsread(struct dev_read_args *ap)
984263bc 286{
b13267a5 287 cdev_t dev = ap->a_head.a_dev;
984263bc 288 struct proc *p = curproc;
1fd87d54
RG
289 struct tty *tp = dev->si_tty;
290 struct pt_ioctl *pti = dev->si_drv1;
08f2f1bb
SS
291 struct lwp *lp;
292
984263bc
MD
293 int error = 0;
294
08f2f1bb
SS
295 lp = curthread->td_lwp;
296
984263bc
MD
297again:
298 if (pti->pt_flags & PF_REMOTE) {
299 while (isbackground(p, tp)) {
300 if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
08f2f1bb 301 SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
984263bc
MD
302 p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT)
303 return (EIO);
304 pgsignal(p->p_pgrp, SIGTTIN, 1);
377d4740 305 error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0);
984263bc
MD
306 if (error)
307 return (error);
308 }
309 if (tp->t_canq.c_cc == 0) {
fef8985e 310 if (ap->a_ioflag & IO_NDELAY)
984263bc 311 return (EWOULDBLOCK);
377d4740 312 error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH,
984263bc
MD
313 "ptsin", 0);
314 if (error)
315 return (error);
316 goto again;
317 }
fef8985e 318 while (tp->t_canq.c_cc > 1 && ap->a_uio->uio_resid > 0)
0ced1954 319 if (ureadc(clist_getc(&tp->t_canq), ap->a_uio) < 0) {
984263bc
MD
320 error = EFAULT;
321 break;
322 }
323 if (tp->t_canq.c_cc == 1)
0ced1954 324 clist_getc(&tp->t_canq);
984263bc
MD
325 if (tp->t_canq.c_cc)
326 return (error);
327 } else
328 if (tp->t_oproc)
fef8985e 329 error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
984263bc
MD
330 ptcwakeup(tp, FWRITE);
331 return (error);
332}
333
334/*
335 * Write to pseudo-tty.
336 * Wakeups of controlling tty will happen
337 * indirectly, when tty driver calls ptsstart.
338 */
339static int
fef8985e 340ptswrite(struct dev_write_args *ap)
984263bc 341{
b13267a5 342 cdev_t dev = ap->a_head.a_dev;
1fd87d54 343 struct tty *tp;
984263bc
MD
344
345 tp = dev->si_tty;
346 if (tp->t_oproc == 0)
347 return (EIO);
fef8985e 348 return ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
984263bc
MD
349}
350
351/*
352 * Start output on pseudo-tty.
353 * Wake up process selecting or sleeping for input from controlling tty.
354 */
355static void
c972a82f 356ptsstart(struct tty *tp)
984263bc 357{
1fd87d54 358 struct pt_ioctl *pti = tp->t_dev->si_drv1;
984263bc
MD
359
360 if (tp->t_state & TS_TTSTOP)
361 return;
362 if (pti->pt_flags & PF_STOPPED) {
363 pti->pt_flags &= ~PF_STOPPED;
364 pti->pt_send = TIOCPKT_START;
365 }
366 ptcwakeup(tp, FREAD);
367}
368
369static void
c972a82f 370ptcwakeup(struct tty *tp, int flag)
984263bc
MD
371{
372 struct pt_ioctl *pti = tp->t_dev->si_drv1;
373
374 if (flag & FREAD) {
375 selwakeup(&pti->pt_selr);
376 wakeup(TSA_PTC_READ(tp));
377 }
378 if (flag & FWRITE) {
379 selwakeup(&pti->pt_selw);
380 wakeup(TSA_PTC_WRITE(tp));
381 }
382}
383
384static int
fef8985e 385ptcopen(struct dev_open_args *ap)
984263bc 386{
b13267a5 387 cdev_t dev = ap->a_head.a_dev;
1fd87d54 388 struct tty *tp;
984263bc
MD
389 struct pt_ioctl *pti;
390
391 if (!dev->si_drv1)
392 ptyinit(minor(dev));
393 if (!dev->si_drv1)
394 return(ENXIO);
395 tp = dev->si_tty;
396 if (tp->t_oproc)
397 return (EIO);
398 tp->t_oproc = ptsstart;
399 tp->t_stop = ptsstop;
400 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
401 tp->t_lflag &= ~EXTPROC;
402 pti = dev->si_drv1;
fef8985e 403 pti->pt_prison = ap->a_cred->cr_prison;
984263bc
MD
404 pti->pt_flags = 0;
405 pti->pt_send = 0;
406 pti->pt_ucntl = 0;
cd65363e 407 pti->devs->si_uid = ap->a_cred->cr_uid;
984263bc
MD
408 return (0);
409}
410
411static int
fef8985e 412ptcclose(struct dev_close_args *ap)
984263bc 413{
b13267a5 414 cdev_t dev = ap->a_head.a_dev;
1fd87d54 415 struct tty *tp;
984263bc
MD
416
417 tp = dev->si_tty;
418 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
419
420 /*
421 * XXX MDMBUF makes no sense for ptys but would inhibit the above
422 * l_modem(). CLOCAL makes sense but isn't supported. Special
423 * l_modem()s that ignore carrier drop make no sense for ptys but
424 * may be in use because other parts of the line discipline make
425 * sense for ptys. Recover by doing everything that a normal
426 * ttymodem() would have done except for sending a SIGHUP.
427 */
428 if (tp->t_state & TS_ISOPEN) {
429 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
430 tp->t_state |= TS_ZOMBIE;
431 ttyflush(tp, FREAD | FWRITE);
cd65363e 432 tp->t_dev->si_uid = 0;
984263bc
MD
433 }
434
435 tp->t_oproc = 0; /* mark closed */
cd29885a
MD
436#if 0
437 if (!memcmp(dev->si_name, "ptm/", 4)) {
438 ((struct pt_ioctl *)dev->si_drv1)->devc = NULL;
439 if (--((struct pt_ioctl *)dev->si_drv1)->ref_count == 0) {
440 kfree(dev->si_drv1, M_PTY);
441 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(pty), dev->si_uminor);
442 }
443 //release_dev(dev);
444 //release_dev(((struct pt_ioctl *)dev->si_drv1)->devs);
445 }
446#endif
984263bc
MD
447 return (0);
448}
449
450static int
fef8985e 451ptcread(struct dev_read_args *ap)
984263bc 452{
b13267a5 453 cdev_t dev = ap->a_head.a_dev;
1fd87d54 454 struct tty *tp = dev->si_tty;
984263bc
MD
455 struct pt_ioctl *pti = dev->si_drv1;
456 char buf[BUFSIZ];
457 int error = 0, cc;
458
459 /*
460 * We want to block until the slave
461 * is open, and there's something to read;
462 * but if we lost the slave or we're NBIO,
463 * then return the appropriate error instead.
464 */
465 for (;;) {
466 if (tp->t_state&TS_ISOPEN) {
467 if (pti->pt_flags&PF_PKT && pti->pt_send) {
fef8985e 468 error = ureadc((int)pti->pt_send, ap->a_uio);
984263bc
MD
469 if (error)
470 return (error);
471 if (pti->pt_send & TIOCPKT_IOCTL) {
fef8985e 472 cc = min(ap->a_uio->uio_resid,
984263bc
MD
473 sizeof(tp->t_termios));
474 uiomove((caddr_t)&tp->t_termios, cc,
fef8985e 475 ap->a_uio);
984263bc
MD
476 }
477 pti->pt_send = 0;
478 return (0);
479 }
480 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
fef8985e 481 error = ureadc((int)pti->pt_ucntl, ap->a_uio);
984263bc
MD
482 if (error)
483 return (error);
484 pti->pt_ucntl = 0;
485 return (0);
486 }
487 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
488 break;
489 }
490 if ((tp->t_state & TS_CONNECTED) == 0)
491 return (0); /* EOF */
fef8985e 492 if (ap->a_ioflag & IO_NDELAY)
984263bc 493 return (EWOULDBLOCK);
377d4740 494 error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0);
984263bc
MD
495 if (error)
496 return (error);
497 }
498 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
fef8985e
MD
499 error = ureadc(0, ap->a_uio);
500 while (ap->a_uio->uio_resid > 0 && error == 0) {
501 cc = q_to_b(&tp->t_outq, buf, min(ap->a_uio->uio_resid, BUFSIZ));
984263bc
MD
502 if (cc <= 0)
503 break;
fef8985e 504 error = uiomove(buf, cc, ap->a_uio);
984263bc
MD
505 }
506 ttwwakeup(tp);
507 return (error);
508}
509
510static void
c972a82f 511ptsstop(struct tty *tp, int flush)
984263bc
MD
512{
513 struct pt_ioctl *pti = tp->t_dev->si_drv1;
514 int flag;
515
516 /* note: FLUSHREAD and FLUSHWRITE already ok */
517 if (flush == 0) {
518 flush = TIOCPKT_STOP;
519 pti->pt_flags |= PF_STOPPED;
520 } else
521 pti->pt_flags &= ~PF_STOPPED;
522 pti->pt_send |= flush;
523 /* change of perspective */
524 flag = 0;
525 if (flush & FREAD)
526 flag |= FWRITE;
527 if (flush & FWRITE)
528 flag |= FREAD;
529 ptcwakeup(tp, flag);
530}
531
532static int
fef8985e 533ptcpoll(struct dev_poll_args *ap)
984263bc 534{
b13267a5 535 cdev_t dev = ap->a_head.a_dev;
1fd87d54 536 struct tty *tp = dev->si_tty;
984263bc
MD
537 struct pt_ioctl *pti = dev->si_drv1;
538 int revents = 0;
984263bc 539
fef8985e
MD
540 if ((tp->t_state & TS_CONNECTED) == 0) {
541 ap->a_events = seltrue(dev, ap->a_events) | POLLHUP;
542 return(0);
543 }
984263bc
MD
544
545 /*
546 * Need to block timeouts (ttrstart).
547 */
e43a034f 548 crit_enter();
984263bc 549
fef8985e 550 if (ap->a_events & (POLLIN | POLLRDNORM))
984263bc
MD
551 if ((tp->t_state & TS_ISOPEN) &&
552 ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
553 ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
554 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
fef8985e 555 revents |= ap->a_events & (POLLIN | POLLRDNORM);
984263bc 556
fef8985e 557 if (ap->a_events & (POLLOUT | POLLWRNORM))
984263bc
MD
558 if (tp->t_state & TS_ISOPEN &&
559 ((pti->pt_flags & PF_REMOTE) ?
560 (tp->t_canq.c_cc == 0) :
561 ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
562 (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
fef8985e 563 revents |= ap->a_events & (POLLOUT | POLLWRNORM);
984263bc 564
fef8985e 565 if (ap->a_events & POLLHUP)
984263bc
MD
566 if ((tp->t_state & TS_CARR_ON) == 0)
567 revents |= POLLHUP;
568
569 if (revents == 0) {
fef8985e
MD
570 if (ap->a_events & (POLLIN | POLLRDNORM))
571 selrecord(curthread, &pti->pt_selr);
984263bc 572
fef8985e
MD
573 if (ap->a_events & (POLLOUT | POLLWRNORM))
574 selrecord(curthread, &pti->pt_selw);
984263bc 575 }
e43a034f 576 crit_exit();
984263bc 577
fef8985e
MD
578 ap->a_events = revents;
579 return (0);
984263bc
MD
580}
581
582static int
fef8985e 583ptcwrite(struct dev_write_args *ap)
984263bc 584{
b13267a5 585 cdev_t dev = ap->a_head.a_dev;
1fd87d54
RG
586 struct tty *tp = dev->si_tty;
587 u_char *cp = 0;
588 int cc = 0;
984263bc
MD
589 u_char locbuf[BUFSIZ];
590 int cnt = 0;
591 struct pt_ioctl *pti = dev->si_drv1;
592 int error = 0;
593
594again:
595 if ((tp->t_state&TS_ISOPEN) == 0)
596 goto block;
597 if (pti->pt_flags & PF_REMOTE) {
598 if (tp->t_canq.c_cc)
599 goto block;
fef8985e 600 while ((ap->a_uio->uio_resid > 0 || cc > 0) &&
984263bc
MD
601 tp->t_canq.c_cc < TTYHOG - 1) {
602 if (cc == 0) {
fef8985e 603 cc = min(ap->a_uio->uio_resid, BUFSIZ);
984263bc
MD
604 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
605 cp = locbuf;
fef8985e 606 error = uiomove((caddr_t)cp, cc, ap->a_uio);
984263bc
MD
607 if (error)
608 return (error);
609 /* check again for safety */
610 if ((tp->t_state & TS_ISOPEN) == 0) {
611 /* adjust as usual */
fef8985e 612 ap->a_uio->uio_resid += cc;
984263bc
MD
613 return (EIO);
614 }
615 }
616 if (cc > 0) {
617 cc = b_to_q((char *)cp, cc, &tp->t_canq);
618 /*
619 * XXX we don't guarantee that the canq size
620 * is >= TTYHOG, so the above b_to_q() may
621 * leave some bytes uncopied. However, space
622 * is guaranteed for the null terminator if
623 * we don't fail here since (TTYHOG - 1) is
624 * not a multiple of CBSIZE.
625 */
626 if (cc > 0)
627 break;
628 }
629 }
630 /* adjust for data copied in but not written */
fef8985e 631 ap->a_uio->uio_resid += cc;
0ced1954 632 clist_putc(0, &tp->t_canq);
984263bc
MD
633 ttwakeup(tp);
634 wakeup(TSA_PTS_READ(tp));
635 return (0);
636 }
fef8985e 637 while (ap->a_uio->uio_resid > 0 || cc > 0) {
984263bc 638 if (cc == 0) {
fef8985e 639 cc = min(ap->a_uio->uio_resid, BUFSIZ);
984263bc 640 cp = locbuf;
fef8985e 641 error = uiomove((caddr_t)cp, cc, ap->a_uio);
984263bc
MD
642 if (error)
643 return (error);
644 /* check again for safety */
645 if ((tp->t_state & TS_ISOPEN) == 0) {
646 /* adjust for data copied in but not written */
fef8985e 647 ap->a_uio->uio_resid += cc;
984263bc
MD
648 return (EIO);
649 }
650 }
651 while (cc > 0) {
652 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
653 (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
654 wakeup(TSA_HUP_OR_INPUT(tp));
655 goto block;
656 }
657 (*linesw[tp->t_line].l_rint)(*cp++, tp);
658 cnt++;
659 cc--;
660 }
661 cc = 0;
662 }
663 return (0);
664block:
665 /*
666 * Come here to wait for slave to open, for space
667 * in outq, or space in rawq, or an empty canq.
668 */
669 if ((tp->t_state & TS_CONNECTED) == 0) {
670 /* adjust for data copied in but not written */
fef8985e 671 ap->a_uio->uio_resid += cc;
984263bc
MD
672 return (EIO);
673 }
fef8985e 674 if (ap->a_ioflag & IO_NDELAY) {
984263bc 675 /* adjust for data copied in but not written */
fef8985e 676 ap->a_uio->uio_resid += cc;
984263bc
MD
677 if (cnt == 0)
678 return (EWOULDBLOCK);
679 return (0);
680 }
377d4740 681 error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0);
984263bc
MD
682 if (error) {
683 /* adjust for data copied in but not written */
fef8985e 684 ap->a_uio->uio_resid += cc;
984263bc
MD
685 return (error);
686 }
687 goto again;
688}
689
690/*ARGSUSED*/
691static int
fef8985e 692ptyioctl(struct dev_ioctl_args *ap)
984263bc 693{
b13267a5 694 cdev_t dev = ap->a_head.a_dev;
1fd87d54
RG
695 struct tty *tp = dev->si_tty;
696 struct pt_ioctl *pti = dev->si_drv1;
697 u_char *cc = tp->t_cc;
984263bc
MD
698 int stop, error;
699
335dda38 700 if (dev_dflags(dev) & D_MASTER) {
fef8985e 701 switch (ap->a_cmd) {
984263bc
MD
702
703 case TIOCGPGRP:
704 /*
705 * We avoid calling ttioctl on the controller since,
706 * in that case, tp must be the controlling terminal.
707 */
fef8985e 708 *(int *)ap->a_data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
984263bc
MD
709 return (0);
710
711 case TIOCPKT:
fef8985e 712 if (*(int *)ap->a_data) {
984263bc
MD
713 if (pti->pt_flags & PF_UCNTL)
714 return (EINVAL);
715 pti->pt_flags |= PF_PKT;
716 } else
717 pti->pt_flags &= ~PF_PKT;
718 return (0);
719
720 case TIOCUCNTL:
fef8985e 721 if (*(int *)ap->a_data) {
984263bc
MD
722 if (pti->pt_flags & PF_PKT)
723 return (EINVAL);
724 pti->pt_flags |= PF_UCNTL;
725 } else
726 pti->pt_flags &= ~PF_UCNTL;
727 return (0);
728
729 case TIOCREMOTE:
fef8985e 730 if (*(int *)ap->a_data)
984263bc
MD
731 pti->pt_flags |= PF_REMOTE;
732 else
733 pti->pt_flags &= ~PF_REMOTE;
734 ttyflush(tp, FREAD|FWRITE);
735 return (0);
736 }
737
738 /*
739 * The rest of the ioctls shouldn't be called until
740 * the slave is open.
741 */
742 if ((tp->t_state & TS_ISOPEN) == 0)
743 return (EAGAIN);
744
fef8985e 745 switch (ap->a_cmd) {
984263bc
MD
746#ifdef COMPAT_43
747 case TIOCSETP:
748 case TIOCSETN:
749#endif
750 case TIOCSETD:
751 case TIOCSETA:
752 case TIOCSETAW:
753 case TIOCSETAF:
754 /*
755 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
756 * ttywflush(tp) will hang if there are characters in
757 * the outq.
758 */
759 ndflush(&tp->t_outq, tp->t_outq.c_cc);
760 break;
761
762 case TIOCSIG:
fef8985e
MD
763 if (*(unsigned int *)ap->a_data >= NSIG ||
764 *(unsigned int *)ap->a_data == 0)
984263bc
MD
765 return(EINVAL);
766 if ((tp->t_lflag&NOFLSH) == 0)
767 ttyflush(tp, FREAD|FWRITE);
fef8985e
MD
768 pgsignal(tp->t_pgrp, *(unsigned int *)ap->a_data, 1);
769 if ((*(unsigned int *)ap->a_data == SIGINFO) &&
984263bc
MD
770 ((tp->t_lflag&NOKERNINFO) == 0))
771 ttyinfo(tp);
772 return(0);
773 }
774 }
fef8985e 775 if (ap->a_cmd == TIOCEXT) {
984263bc
MD
776 /*
777 * When the EXTPROC bit is being toggled, we need
778 * to send an TIOCPKT_IOCTL if the packet driver
779 * is turned on.
780 */
fef8985e 781 if (*(int *)ap->a_data) {
984263bc
MD
782 if (pti->pt_flags & PF_PKT) {
783 pti->pt_send |= TIOCPKT_IOCTL;
784 ptcwakeup(tp, FREAD);
785 }
786 tp->t_lflag |= EXTPROC;
787 } else {
788 if ((tp->t_lflag & EXTPROC) &&
789 (pti->pt_flags & PF_PKT)) {
790 pti->pt_send |= TIOCPKT_IOCTL;
791 ptcwakeup(tp, FREAD);
792 }
793 tp->t_lflag &= ~EXTPROC;
794 }
795 return(0);
796 }
fef8985e
MD
797 error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
798 ap->a_fflag, ap->a_cred);
984263bc 799 if (error == ENOIOCTL)
fef8985e 800 error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
984263bc
MD
801 if (error == ENOIOCTL) {
802 if (pti->pt_flags & PF_UCNTL &&
fef8985e
MD
803 (ap->a_cmd & ~0xff) == UIOCCMD(0)) {
804 if (ap->a_cmd & 0xff) {
805 pti->pt_ucntl = (u_char)ap->a_cmd;
984263bc
MD
806 ptcwakeup(tp, FREAD);
807 }
808 return (0);
809 }
810 error = ENOTTY;
811 }
812 /*
813 * If external processing and packet mode send ioctl packet.
814 */
815 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
fef8985e 816 switch(ap->a_cmd) {
984263bc
MD
817 case TIOCSETA:
818 case TIOCSETAW:
819 case TIOCSETAF:
820#ifdef COMPAT_43
821 case TIOCSETP:
822 case TIOCSETN:
823#endif
824#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
825 case TIOCSETC:
826 case TIOCSLTC:
827 case TIOCLBIS:
828 case TIOCLBIC:
829 case TIOCLSET:
830#endif
831 pti->pt_send |= TIOCPKT_IOCTL;
832 ptcwakeup(tp, FREAD);
833 default:
834 break;
835 }
836 }
837 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
838 && CCEQ(cc[VSTART], CTRL('q'));
839 if (pti->pt_flags & PF_NOSTOP) {
840 if (stop) {
841 pti->pt_send &= ~TIOCPKT_NOSTOP;
842 pti->pt_send |= TIOCPKT_DOSTOP;
843 pti->pt_flags &= ~PF_NOSTOP;
844 ptcwakeup(tp, FREAD);
845 }
846 } else {
847 if (!stop) {
848 pti->pt_send &= ~TIOCPKT_DOSTOP;
849 pti->pt_send |= TIOCPKT_NOSTOP;
850 pti->pt_flags |= PF_NOSTOP;
851 ptcwakeup(tp, FREAD);
852 }
853 }
854 return (error);
855}
856
857
402ed7e1 858static void ptc_drvinit (void *unused);
984263bc
MD
859
860static void
c972a82f 861ptc_drvinit(void *unused)
984263bc 862{
cd29885a 863 int i;
cd29885a
MD
864
865 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(pty));
866 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(pts));
867
868#if 0
869 /* Unix98 pty stuff, leave out for now */
870 make_dev(&ptc_ops, 0, 0, 0, 0666, "ptmx");
871 devfs_clone_handler_add("ptmx", ptyclone);
872#endif
873 for (i = 0; i < 256; i++) {
874 ptyinit(i);
875 }
984263bc
MD
876}
877
878SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)