* (Actually two drivers, requiring two entries in 'cdevsw')
#define NPTY 16 /* Number of pseudo-teletypes */
#define BUFSIZ 100 /* Chunk size iomoved from user */
#define ALLDELAYS (NLDELAY|TBDELAY|XTABS|CRDELAY|VTDELAY)
* A pseudo-teletype is a special device which is not unlike a pipe.
* It is used to communicate between two processes. However, it allows
* one to simulate a teletype, including mode setting, interrupt, and
* multiple end of files (all not possible on a pipe). There are
* really two drivers here. One is the device which looks like a TTY
* and can be thought of as the slave device, and hence its routines
* are prefixed with 'pts' (PTY Slave). The other driver can be
* thought of as the controlling device, and its routines are prefixed
* by 'ptc' (PTY Controller). To type on the simulated keyboard of the
* PTY, one does a 'write' to the controlling device. To get the
* simulated printout from the PTY, one does a 'read' on the controlling
* device. Normally, the controlling device is called 'ptyx' and the
* slave device is called 'ttyx' (to make programs like 'who' happy).
struct tty pt_tty
[NPTY
]; /* TTY headers for PTYs */
{ /* Open for PTY Slave */
tp
= &pt_tty
[minor(dev
)];
if((tp
->t_state
& ISOPEN
) == 0) {
ttychars(tp
); /* Set up default chars */
tp
->t_flags
= 0; /* No features (nor raw mode) */
} else if(tp
->t_state
&XCLUDE
&& u
.u_uid
!= 0) {
if(tp
->t_oproc
) /* Ctrlr still around. */
while((tp
->t_state
& CARR_ON
) == 0) {
sleep((caddr_t
)&tp
->t_rawq
, TTIPRI
);
(*linesw
[tp
->t_line
].l_open
)(dev
, tp
);
{ /* Close slave part of PTY */
tp
= &pt_tty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_close
)(tp
);
{ /* Read from PTY, i.e. from data written by controlling device */
tp
= &pt_tty
[minor(dev
)];
(*linesw
[tp
->t_line
].l_read
)(tp
);
/* Wakeup other half if sleeping */
wakeup((caddr_t
)&tp
->t_rawq
.c_cf
);
{ /* Write on PTY, i.e. to be read from
tp
= &pt_tty
[minor(dev
)];
/* Wait for controlling device to be opened */
(*linesw
[tp
->t_line
].l_write
)(tp
);
{ /* Called by 'ttstart' to output a character.
Merely wakes up controlling half, which
wakeup((caddr_t
)&tp
->t_outq
.c_cf
);
{ /* Open for PTY Controller */
tp
= &pt_tty
[minor(dev
)];
tp
->t_oproc
= ptsstart
; /* Set address of start routine */
wakeup((caddr_t
)&tp
->t_rawq
);
{ /* Close controlling part of PTY */
tp
= &pt_tty
[minor(dev
)];
gsignal(tp
->t_pgrp
, SIGHUP
);
tp
->t_state
&= ~CARR_ON
; /* Virtual carrier is gone */
flushtty(tp
, FREAD
|FWRITE
); /* Clean things up */
tp
->t_oproc
= 0; /* Mark as closed */
{ /* Read from PTY's output buffer */
tp
= &pt_tty
[minor(dev
)];
if((tp
->t_state
&(CARR_ON
|ISOPEN
)) == 0)
while(tp
->t_outq
.c_cc
== 0 || /* Wait for something to arrive */
(tp
->t_state
&TTSTOP
)) /* (Woken by ptsstart) */
sleep((caddr_t
)&tp
->t_outq
.c_cf
, TTIPRI
);
while(tp
->t_outq
.c_cc
&& passc(getc(&tp
->t_outq
)) >= 0);
if(tp
->t_outq
.c_cc
<= TTLOWAT(tp
) && (tp
->t_state
&ASLEEP
)) {
mcstart(tp
->t_chan
, (caddr_t
)&tp
->t_outq
);
wakeup((caddr_t
)&tp
->t_outq
);
{ /* Stuff characters into PTY's input buffer */
tp
= &pt_tty
[minor(dev
)];
if((tp
->t_state
&(CARR_ON
|ISOPEN
)) == 0)
cc
= MIN(u
.u_count
, BUFSIZ
);
iomove(cp
, (unsigned)cc
, B_WRITE
);
while(tp
->t_delct
&& tp
->t_rawq
.c_cc
>= TTYHOG
- 2) {
wakeup((caddr_t
)&tp
->t_rawq
);
/* Better than just flushing it! */
/* Wait for something to be read */
sleep((caddr_t
)&tp
->t_rawq
.c_cf
, TTOPRI
);
/* Note: Both slave and controlling device have the same routine for */
/* 'ioctl' (but note check for controller - 4/12/78:mob)*/
ptyioctl(dev
, cmd
, addr
, flag
)
{ /* Read and write status bits */
tp
= &pt_tty
[minor(dev
)];
/* if controller stty then must flush to prevent a hang */
if(cdevsw
[major(dev
)].d_open
== ptcopen
&& cmd
== TIOCSETP
)
while(getc(&tp
->t_outq
) >= 0);
if(ttioctl(tp
, cmd
, addr
, dev
)) {
if(cmd
== TIOCSETP
|| cmd
== TIOCSETN
) {
nld
= tp
->t_flags
& NLDELAY
;
tbd
= tp
->t_flags
& TBDELAY
;
tp
->t_flags
&= ~ALLDELAYS
;
if(tbd
== TBDELAY
) /* Wants tab expansion */
if(nld
== NLDELAY
) /* Allow ANN ARBOR mode. */