* Copyright (c) 1982 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
* @(#)tty_pty.c 6.16 (Berkeley) %G%
* (Actually two drivers, requiring two entries in 'cdevsw')
#define NPTY 32 /* crude XXX */
#define BUFSIZ 100 /* Chunk size iomoved to/from user */
struct proc
*pt_selr
, *pt_selw
;
int npty
= NPTY
; /* for pstat -t */
#define PF_PKT 0x08 /* packet mode */
#define PF_STOPPED 0x10 /* user told stopped */
#define PF_REMOTE 0x20 /* remote and flow controlled input */
#define PF_UCNTL 0x80 /* user control mode */
tp
= &pt_tty
[minor(dev
)];
if ((tp
->t_state
& TS_ISOPEN
) == 0) {
ttychars(tp
); /* Set up default chars */
tp
->t_ispeed
= tp
->t_ospeed
= EXTB
;
tp
->t_flags
= 0; /* No features (nor raw mode) */
} else if (tp
->t_state
&TS_XCLUDE
&& u
.u_uid
!= 0)
if (tp
->t_oproc
) /* Ctrlr still around. */
tp
->t_state
|= TS_CARR_ON
;
while ((tp
->t_state
& TS_CARR_ON
) == 0) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
error
= (*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
ptcwakeup(tp
, FREAD
|FWRITE
);
tp
= &pt_tty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_close
)(tp
);
ptcwakeup(tp
, FREAD
|FWRITE
);
register struct tty
*tp
= &pt_tty
[minor(dev
)];
register struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
if (pti
->pt_flags
& PF_REMOTE
) {
while (tp
== u
.u_ttyp
&& u
.u_procp
->p_pgrp
!= tp
->t_pgrp
) {
if ((u
.u_procp
->p_sigignore
& sigmask(SIGTTIN
)) ||
(u
.u_procp
->p_sigmask
& sigmask(SIGTTIN
)) ||
u
.u_procp
->p_flag
&SVFORK
)
gsignal(u
.u_procp
->p_pgrp
, SIGTTIN
);
sleep((caddr_t
)&lbolt
, TTIPRI
);
if (tp
->t_canq
.c_cc
== 0) {
if (tp
->t_state
& TS_NBIO
)
sleep((caddr_t
)&tp
->t_canq
, TTIPRI
);
while (tp
->t_canq
.c_cc
> 1 && uio
->uio_resid
> 0)
if (ureadc(getc(&tp
->t_canq
), uio
) < 0) {
if (tp
->t_canq
.c_cc
== 1)
(void) getc(&tp
->t_canq
);
error
= (*linesw
[tp
->t_line
].l_read
)(tp
, uio
);
* Wakeups of controlling tty will happen
* indirectly, when tty driver calls ptsstart.
tp
= &pt_tty
[minor(dev
)];
return ((*linesw
[tp
->t_line
].l_write
)(tp
, uio
));
* Start output on pseudo-tty.
* Wake up process selecting or sleeping for input from controlling tty.
register struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
if (tp
->t_state
& TS_TTSTOP
)
if (pti
->pt_flags
& PF_STOPPED
) {
pti
->pt_flags
&= ~PF_STOPPED
;
pti
->pt_send
= TIOCPKT_START
;
struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
selwakeup(pti
->pt_selr
, pti
->pt_flags
& PF_RCOLL
);
pti
->pt_flags
&= ~PF_RCOLL
;
wakeup((caddr_t
)&tp
->t_outq
.c_cf
);
selwakeup(pti
->pt_selw
, pti
->pt_flags
& PF_WCOLL
);
pti
->pt_flags
&= ~PF_WCOLL
;
wakeup((caddr_t
)&tp
->t_rawq
.c_cf
);
tp
= &pt_tty
[minor(dev
)];
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 1);
tp
->t_state
|= TS_CARR_ON
;
pti
= &pt_ioctl
[minor(dev
)];
tp
= &pt_tty
[minor(dev
)];
(void)(*linesw
[tp
->t_line
].l_modem
)(tp
, 0);
tp
->t_oproc
= 0; /* mark closed */
register struct tty
*tp
= &pt_tty
[minor(dev
)];
struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
* We want to block until the slave
* is open, and there's something to read;
* but if we lost the slave or we're NBIO,
* then return the appropriate error instead.
if (tp
->t_state
&TS_ISOPEN
) {
if (pti
->pt_flags
&PF_PKT
&& pti
->pt_send
) {
error
= ureadc(pti
->pt_send
, uio
);
if (pti
->pt_flags
&PF_UCNTL
&& pti
->pt_ucntl
) {
error
= ureadc(pti
->pt_ucntl
, uio
);
if (tp
->t_outq
.c_cc
&& (tp
->t_state
&TS_TTSTOP
) == 0)
if ((tp
->t_state
&TS_CARR_ON
) == 0)
if (pti
->pt_flags
&PF_NBIO
)
sleep((caddr_t
)&tp
->t_outq
.c_cf
, TTIPRI
);
if (pti
->pt_flags
& (PF_PKT
|PF_UCNTL
))
while (uio
->uio_resid
> 0 && error
== 0) {
cc
= q_to_b(&tp
->t_outq
, buf
, MIN(uio
->uio_resid
, BUFSIZ
));
error
= uiomove(buf
, cc
, UIO_READ
, uio
);
if (tp
->t_outq
.c_cc
<= TTLOWAT(tp
)) {
if (tp
->t_state
&TS_ASLEEP
) {
tp
->t_state
&= ~TS_ASLEEP
;
wakeup((caddr_t
)&tp
->t_outq
);
selwakeup(tp
->t_wsel
, tp
->t_state
& TS_WCOLL
);
tp
->t_state
&= ~TS_WCOLL
;
struct pt_ioctl
*pti
= &pt_ioctl
[minor(tp
->t_dev
)];
/* note: FLUSHREAD and FLUSHWRITE already ok */
pti
->pt_flags
|= PF_STOPPED
;
pti
->pt_flags
&= ~PF_STOPPED
;
/* change of perspective */
register struct tty
*tp
= &pt_tty
[minor(dev
)];
struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
if ((tp
->t_state
&TS_CARR_ON
) == 0)
if ((tp
->t_state
&TS_ISOPEN
) &&
tp
->t_outq
.c_cc
&& (tp
->t_state
&TS_TTSTOP
) == 0) {
case 0: /* exceptional */
if ((tp
->t_state
&TS_ISOPEN
) &&
(pti
->pt_flags
&PF_PKT
&& pti
->pt_send
||
pti
->pt_flags
&PF_UCNTL
&& pti
->pt_ucntl
)) {
if ((p
= pti
->pt_selr
) && p
->p_wchan
== (caddr_t
)&selwait
)
pti
->pt_flags
|= PF_RCOLL
;
pti
->pt_selr
= u
.u_procp
;
if ((tp
->t_state
&TS_ISOPEN
) &&
((pti
->pt_flags
&PF_REMOTE
) == 0 || tp
->t_canq
.c_cc
== 0)) {
if ((p
= pti
->pt_selw
) && p
->p_wchan
== (caddr_t
)&selwait
)
pti
->pt_flags
|= PF_WCOLL
;
pti
->pt_selw
= u
.u_procp
;
register struct uio
*uio
;
register struct tty
*tp
= &pt_tty
[minor(dev
)];
register struct iovec
*iov
;
struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
if ((tp
->t_state
&TS_ISOPEN
) == 0)
if (pti
->pt_flags
& PF_REMOTE
) {
while (uio
->uio_iovcnt
> 0 && tp
->t_canq
.c_cc
< TTYHOG
- 1) {
cc
= MIN(iov
->iov_len
, BUFSIZ
);
cc
= MIN(cc
, TTYHOG
- 1 - tp
->t_canq
.c_cc
);
error
= uiomove(cp
, cc
, UIO_WRITE
, uio
);
/* check again for safety */
if ((tp
->t_state
&TS_ISOPEN
) == 0)
(void) b_to_q(cp
, cc
, &tp
->t_canq
);
(void) putc(0, &tp
->t_canq
);
wakeup((caddr_t
)&tp
->t_canq
);
while (uio
->uio_iovcnt
> 0) {
cc
= MIN(iov
->iov_len
, BUFSIZ
);
error
= uiomove(cp
, cc
, UIO_WRITE
, uio
);
/* check again for safety */
if ((tp
->t_state
&TS_ISOPEN
) == 0)
if ((tp
->t_rawq
.c_cc
+ tp
->t_canq
.c_cc
) >= TTYHOG
- 2 &&
wakeup((caddr_t
)&tp
->t_rawq
);
(*linesw
[tp
->t_line
].l_rint
)(*cp
++, tp
);
* Come here to wait for slave to open, for space
* in outq, or space in rawq.
if ((tp
->t_state
&TS_CARR_ON
) == 0)
if (pti
->pt_flags
& PF_NBIO
) {
sleep((caddr_t
)&tp
->t_rawq
.c_cf
, TTOPRI
);
ptyioctl(dev
, cmd
, data
, flag
)
register struct tty
*tp
= &pt_tty
[minor(dev
)];
register struct pt_ioctl
*pti
= &pt_ioctl
[minor(dev
)];
* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
* ttywflush(tp) will hang if there are characters in the outq.
if (cdevsw
[major(dev
)].d_open
== ptcopen
)
if (pti
->pt_flags
& PF_UCNTL
)
pti
->pt_flags
&= ~PF_PKT
;
if (pti
->pt_flags
& PF_PKT
)
pti
->pt_flags
|= PF_UCNTL
;
pti
->pt_flags
&= ~PF_UCNTL
;
pti
->pt_flags
|= PF_REMOTE
;
pti
->pt_flags
&= ~PF_REMOTE
;
ttyflush(tp
, FREAD
|FWRITE
);
pti
->pt_flags
|= PF_NBIO
;
pti
->pt_flags
&= ~PF_NBIO
;
while (getc(&tp
->t_outq
) >= 0)
error
= ttioctl(tp
, cmd
, data
, flag
);
* Since we use the tty queues internally,
* pty's can't be switched to disciplines which overwrite
* the queues. We can't tell anything about the discipline
if (linesw
[tp
->t_line
].l_rint
!= ttyinput
) {
(*linesw
[tp
->t_line
].l_close
)(tp
);
(void)(*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
if (pti
->pt_flags
& PF_UCNTL
&&
(cmd
& ~0xff) == _IO(u
,0)) {
pti
->pt_ucntl
= (u_char
)cmd
;
stop
= (tp
->t_flags
& RAW
) == 0 &&
tp
->t_stopc
== CTRL(s
) && tp
->t_startc
== CTRL(q
);
if (pti
->pt_flags
& PF_NOSTOP
) {
pti
->pt_send
&= TIOCPKT_NOSTOP
;
pti
->pt_send
|= TIOCPKT_DOSTOP
;
pti
->pt_flags
&= ~PF_NOSTOP
;
pti
->pt_send
&= ~TIOCPKT_DOSTOP
;
pti
->pt_send
|= TIOCPKT_NOSTOP
;
pti
->pt_flags
|= PF_NOSTOP
;