diff options
author | ed <ed@FreeBSD.org> | 2008-11-01 08:35:28 +0000 |
---|---|---|
committer | ed <ed@FreeBSD.org> | 2008-11-01 08:35:28 +0000 |
commit | c2c324d37976496417e7195d8daae3975be8eaa1 (patch) | |
tree | 92b387a3b5878c3317cf997130d7bc5769e5f6e5 /sys/kern/tty.c | |
parent | ec4658731c7b03d16de04acf5f20aa4dc53635cb (diff) | |
download | FreeBSD-src-c2c324d37976496417e7195d8daae3975be8eaa1.zip FreeBSD-src-c2c324d37976496417e7195d8daae3975be8eaa1.tar.gz |
Reimplement the /dev/console device node.
One of the pieces of code that I had left alone during the development
of the MPSAFE TTY layer, was tty_cons.c. This file actually has two
different functions:
- It contains low-level console input/output routines (cnputc(), etc).
- It creates /dev/console and wraps all its cdevsw calls to the
appropriate TTY.
This commit reimplements the second set of functions by moving it
directly into the TTY layer. /dev/console is now a character device node
that's basically a regular TTY, but does a lookup of `si_drv1' each time
you open it. d_write has also been changed to call log_console().
d_close() is not present, because we must make sure we don't revoke the
TTY after writing a log message to it.
Even though I'm not convinced this is in line with the future directions
of our console code, it is a good move for now. It removes recursive
locking from the top half of the TTY layer. The previous implementation
called into the TTY layer with Giant held.
I'm renaming tty_cons.c to kern_cons.c now. The code hardly contains any
TTY related bits, so we'd better give it a less misleading name.
Tested by: Andrzej Tobola <ato iem pw edu pl>,
Carlos A.M. dos Santos <unixmania gmail com>,
Eygene Ryabinkin <rea-fbsd codelabs ru>
Diffstat (limited to 'sys/kern/tty.c')
-rw-r--r-- | sys/kern/tty.c | 96 |
1 files changed, 87 insertions, 9 deletions
diff --git a/sys/kern/tty.c b/sys/kern/tty.c index 16fda40..8f6f9b2 100644 --- a/sys/kern/tty.c +++ b/sys/kern/tty.c @@ -73,6 +73,10 @@ static struct sx tty_list_sx; SX_SYSINIT(tty_list, &tty_list_sx, "tty list"); static unsigned int tty_list_count = 0; +/* Character device of /dev/console. */ +static struct cdev *dev_console; +static const char *dev_console_filename; + /* * Flags that are supported and stored by this implementation. */ @@ -86,7 +90,7 @@ static unsigned int tty_list_count = 0; HUPCL|CLOCAL|CCTS_OFLOW|CRTS_IFLOW|CDTR_IFLOW|\ CDSR_OFLOW|CCAR_OFLOW) -#define TTY_CALLOUT(tp,d) ((tp)->t_dev != (d)) +#define TTY_CALLOUT(tp,d) ((d) != (tp)->t_dev && (d) != dev_console) /* * Set TTY buffer sizes. @@ -1189,11 +1193,7 @@ tty_wait(struct tty *tp, struct cv *cv) int error; int revokecnt = tp->t_revokecnt; -#if 0 - /* XXX: /dev/console also picks up Giant. */ tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED); -#endif - tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); error = cv_wait_sig(cv, tp->t_mtx); @@ -1215,11 +1215,7 @@ tty_timedwait(struct tty *tp, struct cv *cv, int hz) int error; int revokecnt = tp->t_revokecnt; -#if 0 - /* XXX: /dev/console also picks up Giant. */ tty_lock_assert(tp, MA_OWNED|MA_NOTRECURSED); -#endif - tty_lock_assert(tp, MA_OWNED); MPASS(!tty_gone(tp)); error = cv_timedwait_sig(cv, tp->t_mtx, hz); @@ -1662,6 +1658,10 @@ tty_hiwat_in_unblock(struct tty *tp) ttydevsw_inwakeup(tp); } +/* + * TTY hooks interface. + */ + static int ttyhook_defrint(struct tty *tp, char c, int flags) { @@ -1745,6 +1745,84 @@ ttyhook_unregister(struct tty *tp) tty_rel_free(tp); } +/* + * /dev/console handling. + */ + +static int +ttyconsdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + struct tty *tp; + + /* System has no console device. */ + if (dev_console_filename == NULL) + return (ENXIO); + + /* Look up corresponding TTY by device name. */ + sx_slock(&tty_list_sx); + TAILQ_FOREACH(tp, &tty_list, t_list) { + if (strcmp(dev_console_filename, tty_devname(tp)) == 0) { + dev_console->si_drv1 = tp; + break; + } + } + sx_sunlock(&tty_list_sx); + + /* System console has no TTY associated. */ + if (dev_console->si_drv1 == NULL) + return (ENXIO); + + return (ttydev_open(dev, oflags, devtype, td)); +} + +static int +ttyconsdev_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + + log_console(uio); + + return (ttydev_write(dev, uio, ioflag)); +} + +/* + * /dev/console is a little different than normal TTY's. Unlike regular + * TTY device nodes, this device node will not revoke the entire TTY + * upon closure and all data written to it will be logged. + */ +static struct cdevsw ttyconsdev_cdevsw = { + .d_version = D_VERSION, + .d_open = ttyconsdev_open, + .d_read = ttydev_read, + .d_write = ttyconsdev_write, + .d_ioctl = ttydev_ioctl, + .d_kqfilter = ttydev_kqfilter, + .d_poll = ttydev_poll, + .d_mmap = ttydev_mmap, + .d_name = "ttyconsdev", + .d_flags = D_TTY, +}; + +static void +ttyconsdev_init(void *unused) +{ + + dev_console = make_dev(&ttyconsdev_cdevsw, 0, UID_ROOT, GID_WHEEL, + 0600, "console"); +} + +SYSINIT(tty, SI_SUB_DRIVERS, SI_ORDER_FIRST, ttyconsdev_init, NULL); + +void +ttyconsdev_select(const char *name) +{ + + dev_console_filename = name; +} + +/* + * Debugging routines. + */ + #include "opt_ddb.h" #ifdef DDB #include <ddb/ddb.h> |