Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/tty_ttydisc.c
Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
ttydisc_optimize(tp); | ttydisc_optimize(tp); | ||||
} | } | ||||
void | void | ||||
ttydisc_close(struct tty *tp) | ttydisc_close(struct tty *tp) | ||||
{ | { | ||||
ttydisc_assert_locked(tp); | |||||
/* Clean up our flags when leaving the discipline. */ | /* Clean up our flags when leaving the discipline. */ | ||||
tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE); | tp->t_flags &= ~(TF_STOPPED|TF_HIWAT|TF_ZOMBIE); | ||||
tp->t_termios.c_lflag &= ~FLUSHO; | tp->t_termios.c_lflag &= ~FLUSHO; | ||||
/* | /* | ||||
* POSIX states that we must drain output and flush input on | * POSIX states that we must drain output and flush input on | ||||
* last close. Draining has already been done if possible. | * last close. Draining has already been done if possible. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 297 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int | int | ||||
ttydisc_read(struct tty *tp, struct uio *uio, int ioflag) | ttydisc_read(struct tty *tp, struct uio *uio, int ioflag) | ||||
{ | { | ||||
int error; | int error; | ||||
tty_assert_locked(tp); | tty_assert_locked(tp); | ||||
ttydisc_assert_locked(tp); | |||||
if (uio->uio_resid == 0) | if (uio->uio_resid == 0) | ||||
return (0); | return (0); | ||||
if (CMP_FLAG(l, ICANON)) | if (CMP_FLAG(l, ICANON)) | ||||
error = ttydisc_read_canonical(tp, uio, ioflag); | error = ttydisc_read_canonical(tp, uio, ioflag); | ||||
else if (tp->t_termios.c_cc[VTIME] == 0) | else if (tp->t_termios.c_cc[VTIME] == 0) | ||||
error = ttydisc_read_raw_no_timer(tp, uio, ioflag); | error = ttydisc_read_raw_no_timer(tp, uio, ioflag); | ||||
▲ Show 20 Lines • Show All 116 Lines • ▼ Show 20 Lines | |||||
ttydisc_write(struct tty *tp, struct uio *uio, int ioflag) | ttydisc_write(struct tty *tp, struct uio *uio, int ioflag) | ||||
{ | { | ||||
char ob[TTY_STACKBUF]; | char ob[TTY_STACKBUF]; | ||||
char *obstart; | char *obstart; | ||||
int error = 0; | int error = 0; | ||||
unsigned int oblen = 0; | unsigned int oblen = 0; | ||||
tty_assert_locked(tp); | tty_assert_locked(tp); | ||||
ttydisc_assert_locked(tp); | |||||
if (tp->t_flags & TF_ZOMBIE) | if (tp->t_flags & TF_ZOMBIE) | ||||
return (EIO); | return (EIO); | ||||
/* | /* | ||||
* We don't need to check whether the process is the foreground | * We don't need to check whether the process is the foreground | ||||
* process group or if we have a carrier. This is already done | * process group or if we have a carrier. This is already done | ||||
* in ttydev_write(). | * in ttydev_write(). | ||||
*/ | */ | ||||
while (uio->uio_resid > 0) { | while (uio->uio_resid > 0) { | ||||
unsigned int nlen; | unsigned int nlen; | ||||
MPASS(oblen == 0); | MPASS(oblen == 0); | ||||
if (CMP_FLAG(l, FLUSHO)) { | if (CMP_FLAG(l, FLUSHO)) { | ||||
uio->uio_offset += uio->uio_resid; | uio->uio_offset += uio->uio_resid; | ||||
uio->uio_resid = 0; | uio->uio_resid = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* Step 1: read data. */ | /* Step 1: read data. */ | ||||
obstart = ob; | obstart = ob; | ||||
nlen = MIN(uio->uio_resid, sizeof ob); | nlen = MIN(uio->uio_resid, sizeof ob); | ||||
tty_unlock(tp); | ttydisc_unlock(tp); | ||||
error = uiomove(ob, nlen, uio); | error = uiomove(ob, nlen, uio); | ||||
tty_lock(tp); | ttydisc_lock(tp); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
oblen = nlen; | oblen = nlen; | ||||
if (tty_gone(tp)) { | |||||
error = ENXIO; | |||||
break; | |||||
} | |||||
MPASS(oblen > 0); | MPASS(oblen > 0); | ||||
/* Step 2: process data. */ | /* Step 2: process data. */ | ||||
do { | do { | ||||
unsigned int plen, wlen; | unsigned int plen, wlen; | ||||
if (CMP_FLAG(l, FLUSHO)) { | if (CMP_FLAG(l, FLUSHO)) { | ||||
uio->uio_offset += uio->uio_resid; | uio->uio_offset += uio->uio_resid; | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | done: | ||||
*/ | */ | ||||
uio->uio_resid += oblen; | uio->uio_resid += oblen; | ||||
return (error); | return (error); | ||||
} | } | ||||
void | void | ||||
ttydisc_optimize(struct tty *tp) | ttydisc_optimize(struct tty *tp) | ||||
{ | { | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (ttyhook_hashook(tp, rint_bypass)) { | if (ttyhook_hashook(tp, rint_bypass)) { | ||||
tp->t_flags |= TF_BYPASS; | tp->t_flags |= TF_BYPASS; | ||||
} else if (ttyhook_hashook(tp, rint)) { | } else if (ttyhook_hashook(tp, rint)) { | ||||
tp->t_flags &= ~TF_BYPASS; | tp->t_flags &= ~TF_BYPASS; | ||||
} else if (!CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) && | } else if (!CMP_FLAG(i, ICRNL|IGNCR|IMAXBEL|INLCR|ISTRIP|IXON) && | ||||
(!CMP_FLAG(i, BRKINT) || CMP_FLAG(i, IGNBRK)) && | (!CMP_FLAG(i, BRKINT) || CMP_FLAG(i, IGNBRK)) && | ||||
(!CMP_FLAG(i, PARMRK) || | (!CMP_FLAG(i, PARMRK) || | ||||
CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) && | CMP_FLAG(i, IGNPAR|IGNBRK) == (IGNPAR|IGNBRK)) && | ||||
!CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) { | !CMP_FLAG(l, ECHO|ICANON|IEXTEN|ISIG|PENDIN)) { | ||||
tp->t_flags |= TF_BYPASS; | tp->t_flags |= TF_BYPASS; | ||||
} else { | } else { | ||||
tp->t_flags &= ~TF_BYPASS; | tp->t_flags &= ~TF_BYPASS; | ||||
} | } | ||||
} | } | ||||
void | void | ||||
ttydisc_modem(struct tty *tp, int open) | ttydisc_modem(struct tty *tp, int open) | ||||
{ | { | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (open) | if (open) | ||||
cv_broadcast(&tp->t_dcdwait); | cv_broadcast(&tp->t_dcdwait); | ||||
/* | /* | ||||
* Ignore modem status lines when CLOCAL is turned on, but don't | * Ignore modem status lines when CLOCAL is turned on, but don't | ||||
* enter the zombie state when the TTY isn't opened, because | * enter the zombie state when the TTY isn't opened, because | ||||
* that would cause the TTY to be in zombie state after being | * that would cause the TTY to be in zombie state after being | ||||
▲ Show 20 Lines • Show All 308 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
ttydisc_rint(struct tty *tp, char c, int flags) | ttydisc_rint(struct tty *tp, char c, int flags) | ||||
{ | { | ||||
int signal, quote = 0; | int signal, quote = 0; | ||||
char ob[3] = { 0xff, 0x00 }; | char ob[3] = { 0xff, 0x00 }; | ||||
size_t ol; | size_t ol; | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
atomic_add_long(&tty_nin, 1); | atomic_add_long(&tty_nin, 1); | ||||
if (ttyhook_hashook(tp, rint)) | if (ttyhook_hashook(tp, rint)) | ||||
return ttyhook_rint(tp, c, flags); | return ttyhook_rint(tp, c, flags); | ||||
if (tp->t_flags & TF_BYPASS) | if (tp->t_flags & TF_BYPASS) | ||||
goto processed; | goto processed; | ||||
▲ Show 20 Lines • Show All 240 Lines • ▼ Show 20 Lines | ttydisc_rint_simple(struct tty *tp, const void *buf, size_t len) | ||||
return (cbuf - (const char *)buf); | return (cbuf - (const char *)buf); | ||||
} | } | ||||
size_t | size_t | ||||
ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len) | ttydisc_rint_bypass(struct tty *tp, const void *buf, size_t len) | ||||
{ | { | ||||
size_t ret; | size_t ret; | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
MPASS(tp->t_flags & TF_BYPASS); | MPASS(tp->t_flags & TF_BYPASS); | ||||
atomic_add_long(&tty_nin, len); | atomic_add_long(&tty_nin, len); | ||||
if (ttyhook_hashook(tp, rint_bypass)) | if (ttyhook_hashook(tp, rint_bypass)) | ||||
return ttyhook_rint_bypass(tp, buf, len); | return ttyhook_rint_bypass(tp, buf, len); | ||||
ret = ttyinq_write(&tp->t_inq, buf, len, 0); | ret = ttyinq_write(&tp->t_inq, buf, len, 0); | ||||
ttyinq_canonicalize(&tp->t_inq); | ttyinq_canonicalize(&tp->t_inq); | ||||
if (ret < len) | if (ret < len) | ||||
tty_hiwat_in_block(tp); | tty_hiwat_in_block(tp); | ||||
return (ret); | return (ret); | ||||
} | } | ||||
void | void | ||||
ttydisc_rint_done(struct tty *tp) | ttydisc_rint_done(struct tty *tp) | ||||
{ | { | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (ttyhook_hashook(tp, rint_done)) | if (ttyhook_hashook(tp, rint_done)) | ||||
ttyhook_rint_done(tp); | ttyhook_rint_done(tp); | ||||
/* Wake up readers. */ | /* Wake up readers. */ | ||||
tty_wakeup(tp, FREAD); | tty_wakeup(tp, FREAD); | ||||
/* Wake up driver for echo. */ | /* Wake up driver for echo. */ | ||||
ttydevsw_outwakeup(tp); | ttydevsw_outwakeup(tp); | ||||
} | } | ||||
size_t | size_t | ||||
ttydisc_rint_poll(struct tty *tp) | ttydisc_rint_poll(struct tty *tp) | ||||
{ | { | ||||
size_t l; | size_t l; | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (ttyhook_hashook(tp, rint_poll)) | if (ttyhook_hashook(tp, rint_poll)) | ||||
return ttyhook_rint_poll(tp); | return ttyhook_rint_poll(tp); | ||||
/* | /* | ||||
* XXX: Still allow character input when there's no space in the | * XXX: Still allow character input when there's no space in the | ||||
* buffers, but we haven't entered the high watermark. This is | * buffers, but we haven't entered the high watermark. This is | ||||
* to allow backspace characters to be inserted when in | * to allow backspace characters to be inserted when in | ||||
Show All 26 Lines | ttydisc_wakeup_watermark(struct tty *tp) | ||||
} | } | ||||
tty_wakeup(tp, FWRITE); | tty_wakeup(tp, FWRITE); | ||||
} | } | ||||
size_t | size_t | ||||
ttydisc_getc(struct tty *tp, void *buf, size_t len) | ttydisc_getc(struct tty *tp, void *buf, size_t len) | ||||
{ | { | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (tp->t_flags & TF_STOPPED) | if (tp->t_flags & TF_STOPPED) | ||||
return (0); | return (0); | ||||
if (ttyhook_hashook(tp, getc_inject)) | if (ttyhook_hashook(tp, getc_inject)) | ||||
return ttyhook_getc_inject(tp, buf, len); | return ttyhook_getc_inject(tp, buf, len); | ||||
len = ttyoutq_read(&tp->t_outq, buf, len); | len = ttyoutq_read(&tp->t_outq, buf, len); | ||||
Show All 10 Lines | |||||
int | int | ||||
ttydisc_getc_uio(struct tty *tp, struct uio *uio) | ttydisc_getc_uio(struct tty *tp, struct uio *uio) | ||||
{ | { | ||||
int error = 0; | int error = 0; | ||||
ssize_t obytes = uio->uio_resid; | ssize_t obytes = uio->uio_resid; | ||||
size_t len; | size_t len; | ||||
char buf[TTY_STACKBUF]; | char buf[TTY_STACKBUF]; | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (tp->t_flags & TF_STOPPED) | if (tp->t_flags & TF_STOPPED) | ||||
return (0); | return (0); | ||||
/* | /* | ||||
* When a TTY hook is attached, we cannot perform unbuffered | * When a TTY hook is attached, we cannot perform unbuffered | ||||
* copying to userspace. Just call ttydisc_getc() and | * copying to userspace. Just call ttydisc_getc() and | ||||
* temporarily store data in a shadow buffer. | * temporarily store data in a shadow buffer. | ||||
*/ | */ | ||||
if (ttyhook_hashook(tp, getc_capture) || | if (ttyhook_hashook(tp, getc_capture) || | ||||
ttyhook_hashook(tp, getc_inject)) { | ttyhook_hashook(tp, getc_inject)) { | ||||
while (uio->uio_resid > 0) { | while (uio->uio_resid > 0) { | ||||
/* Read to shadow buffer. */ | /* Read to shadow buffer. */ | ||||
len = ttydisc_getc(tp, buf, | len = ttydisc_getc(tp, buf, | ||||
MIN(uio->uio_resid, sizeof buf)); | MIN(uio->uio_resid, sizeof buf)); | ||||
if (len == 0) | if (len == 0) | ||||
break; | break; | ||||
/* Copy to userspace. */ | /* Copy to userspace. */ | ||||
tty_unlock(tp); | ttydisc_unlock(tp); | ||||
error = uiomove(buf, len, uio); | error = uiomove(buf, len, uio); | ||||
tty_lock(tp); | ttydisc_lock(tp); | ||||
if (error != 0) | if (error != 0) | ||||
break; | break; | ||||
} | } | ||||
} else { | } else { | ||||
error = ttyoutq_read_uio(&tp->t_outq, tp, uio); | error = ttyoutq_read_uio(&tp->t_outq, tp, uio); | ||||
ttydisc_wakeup_watermark(tp); | ttydisc_wakeup_watermark(tp); | ||||
atomic_add_long(&tty_nout, obytes - uio->uio_resid); | atomic_add_long(&tty_nout, obytes - uio->uio_resid); | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
size_t | size_t | ||||
ttydisc_getc_poll(struct tty *tp) | ttydisc_getc_poll(struct tty *tp) | ||||
{ | { | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (tp->t_flags & TF_STOPPED) | if (tp->t_flags & TF_STOPPED) | ||||
return (0); | return (0); | ||||
if (ttyhook_hashook(tp, getc_poll)) | if (ttyhook_hashook(tp, getc_poll)) | ||||
return ttyhook_getc_poll(tp); | return ttyhook_getc_poll(tp); | ||||
return ttyoutq_bytesused(&tp->t_outq); | return ttyoutq_bytesused(&tp->t_outq); | ||||
} | } | ||||
/* | /* | ||||
* XXX: not really related to the TTYDISC, but we'd better put | * XXX: not really related to the TTYDISC, but we'd better put | ||||
* tty_putchar() here, because we need to perform proper output | * tty_putchar() here, because we need to perform proper output | ||||
* processing. | * processing. | ||||
*/ | */ | ||||
int | int | ||||
tty_putstrn(struct tty *tp, const char *p, size_t n) | tty_putstrn(struct tty *tp, const char *p, size_t n) | ||||
{ | { | ||||
size_t i; | size_t i; | ||||
tty_assert_locked(tp); | ttydisc_assert_locked(tp); | ||||
if (tty_gone(tp)) | if (tty_gone(tp)) | ||||
return (-1); | return (-1); | ||||
for (i = 0; i < n; i++) | for (i = 0; i < n; i++) | ||||
ttydisc_echo_force(tp, p[i], 0); | ttydisc_echo_force(tp, p[i], 0); | ||||
tp->t_writepos = tp->t_column; | tp->t_writepos = tp->t_column; | ||||
Show All 11 Lines |