diff options
author | simokawa <simokawa@FreeBSD.org> | 2004-10-13 05:38:42 +0000 |
---|---|---|
committer | simokawa <simokawa@FreeBSD.org> | 2004-10-13 05:38:42 +0000 |
commit | bc246db21da7264fec412ba93be770e276ab2357 (patch) | |
tree | 3b77c59d53dfdf2c510722e3405df0e1ec988f45 /sys/dev/dcons/dcons.c | |
parent | 35f180990e23f708bc88844a944ad726af2101dd (diff) | |
download | FreeBSD-src-bc246db21da7264fec412ba93be770e276ab2357.zip FreeBSD-src-bc246db21da7264fec412ba93be770e276ab2357.tar.gz |
- Split dcons core code and OS dependent code.
- Implement dcons_ischar() and dcons_load_buffer().
- If loader passed a dcons buffer address, keep using it.
(We still need a patch to cheat memory management system.)
Diffstat (limited to 'sys/dev/dcons/dcons.c')
-rw-r--r-- | sys/dev/dcons/dcons.c | 713 |
1 files changed, 71 insertions, 642 deletions
diff --git a/sys/dev/dcons/dcons.c b/sys/dev/dcons/dcons.c index 284a3b0..b48a504 100644 --- a/sys/dev/dcons/dcons.c +++ b/sys/dev/dcons/dcons.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003 + * Copyright (C) 2003,2004 * Hidetoshi Shimokawa. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -36,387 +36,42 @@ */ #include <sys/param.h> -#if __FreeBSD_version >= 502122 -#include <sys/kdb.h> -#include <gdb/gdb.h> -#endif -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/systm.h> -#include <sys/types.h> -#include <sys/conf.h> -#include <sys/cons.h> -#include <sys/consio.h> -#include <sys/tty.h> -#include <sys/malloc.h> -#include <sys/proc.h> -#include <sys/ucred.h> - -#include <machine/bus.h> -#ifdef __DragonFly__ +#if defined(__DragonFly__) || defined(_BOOT) #include "dcons.h" #else #include <dev/dcons/dcons.h> #endif -#include <ddb/ddb.h> -#include <sys/reboot.h> - -#include <sys/sysctl.h> - -#include "opt_ddb.h" -#include "opt_comconsole.h" -#include "opt_dcons.h" - -#ifndef DCONS_POLL_HZ -#define DCONS_POLL_HZ 100 -#endif - -#ifndef DCONS_BUF_SIZE -#define DCONS_BUF_SIZE (16*1024) -#endif - -#ifndef DCONS_FORCE_CONSOLE -#define DCONS_FORCE_CONSOLE 0 /* Mostly for FreeBSD-4/DragonFly */ -#endif - -#ifndef DCONS_FORCE_GDB -#define DCONS_FORCE_GDB 1 -#endif - -#if __FreeBSD_version >= 500101 -#define CONS_NODEV 1 -#if __FreeBSD_version < 502122 -static struct consdev gdbconsdev; -#endif -#endif - -static d_open_t dcons_open; -static d_close_t dcons_close; -#if defined(__DragonFly__) || __FreeBSD_version < 500104 -static d_ioctl_t dcons_ioctl; -#endif - -static struct cdevsw dcons_cdevsw = { -#ifdef __DragonFly__ -#define CDEV_MAJOR 184 - "dcons", CDEV_MAJOR, D_TTY, NULL, 0, - dcons_open, dcons_close, ttyread, ttywrite, dcons_ioctl, - ttypoll, nommap, nostrategy, nodump, nopsize, -#elif __FreeBSD_version >= 500104 - .d_version = D_VERSION, - .d_open = dcons_open, - .d_close = dcons_close, - .d_name = "dcons", - .d_flags = D_TTY | D_NEEDGIANT, -#else -#define CDEV_MAJOR 184 - /* open */ dcons_open, - /* close */ dcons_close, - /* read */ ttyread, - /* write */ ttywrite, - /* ioctl */ dcons_ioctl, - /* poll */ ttypoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "dcons", - /* major */ CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ D_TTY, -#endif -}; - -#ifndef KLD_MODULE -static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */ -#endif - -/* global data */ -static struct dcons_global dg; -struct dcons_global *dcons_conf; -static int poll_hz = DCONS_POLL_HZ; - -SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console"); -SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0, - "dcons polling rate"); - -static int drv_init = 0; -static struct callout dcons_callout; -struct dcons_buf *dcons_buf; /* for local dconschat */ - -#ifdef __DragonFly__ -#define DEV dev_t -#define THREAD d_thread_t -#elif __FreeBSD_version < 500000 -#define DEV dev_t -#define THREAD struct proc -#else -#define DEV struct cdev * -#define THREAD struct thread -#endif - -/* per device data */ -static struct dcons_softc { - DEV dev; - struct dcons_ch o, i; - int brk_state; -#define DC_GDB 1 - int flags; -} sc[DCONS_NPORT]; -static void dcons_tty_start(struct tty *); -static int dcons_tty_param(struct tty *, struct termios *); -static void dcons_timeout(void *); -static int dcons_drv_init(int); -static int dcons_getc(struct dcons_softc *); -static int dcons_checkc(struct dcons_softc *); -static void dcons_putc(struct dcons_softc *, int); - -static cn_probe_t dcons_cnprobe; -static cn_init_t dcons_cninit; -static cn_getc_t dcons_cngetc; -static cn_checkc_t dcons_cncheckc; -static cn_putc_t dcons_cnputc; - -CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc, - dcons_cncheckc, dcons_cnputc, NULL); - -#if __FreeBSD_version >= 502122 -static gdb_probe_f dcons_dbg_probe; -static gdb_init_f dcons_dbg_init; -static gdb_term_f dcons_dbg_term; -static gdb_getc_f dcons_dbg_getc; -static gdb_checkc_f dcons_dbg_checkc; -static gdb_putc_f dcons_dbg_putc; - -GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term, - dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc); - -extern struct gdb_dbgport *gdb_cur; -#endif - -static int -dcons_open(DEV dev, int flag, int mode, THREAD *td) -{ - struct tty *tp; - int unit, error, s; - - unit = minor(dev); - if (unit != 0) - return (ENXIO); - - tp = dev->si_tty = ttymalloc(dev->si_tty); - tp->t_oproc = dcons_tty_start; - tp->t_param = dcons_tty_param; - tp->t_stop = nottystop; - tp->t_dev = dev; - - error = 0; - - s = spltty(); - if ((tp->t_state & TS_ISOPEN) == 0) { - tp->t_state |= TS_CARR_ON; - ttychars(tp); - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_cflag = TTYDEF_CFLAG|CLOCAL; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - ttsetwater(tp); - } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { - splx(s); - return (EBUSY); - } - splx(s); - -#if __FreeBSD_version < 502113 - error = (*linesw[tp->t_line].l_open)(dev, tp); -#else - error = ttyld_open(tp, dev); -#endif - - return (error); -} - -static int -dcons_close(DEV dev, int flag, int mode, THREAD *td) +int +dcons_ischar(struct dcons_softc *dc) { - int unit; - struct tty *tp; - - unit = minor(dev); - if (unit != 0) - return (ENXIO); - - tp = dev->si_tty; - if (tp->t_state & TS_ISOPEN) { -#if __FreeBSD_version < 502113 - (*linesw[tp->t_line].l_close)(tp, flag); - ttyclose(tp); -#else - ttyld_close(tp, flag); - tty_close(tp); -#endif - } - - return (0); -} - -#if defined(__DragonFly__) || __FreeBSD_version < 500104 -static int -dcons_ioctl(DEV dev, u_long cmd, caddr_t data, int flag, THREAD *td) -{ - int unit; - struct tty *tp; - int error; - - unit = minor(dev); - if (unit != 0) - return (ENXIO); - - tp = dev->si_tty; - error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); - if (error != ENOIOCTL) - return (error); - - error = ttioctl(tp, cmd, data, flag); - if (error != ENOIOCTL) - return (error); - - return (ENOTTY); -} -#endif - -static int -dcons_tty_param(struct tty *tp, struct termios *t) -{ - tp->t_ispeed = t->c_ispeed; - tp->t_ospeed = t->c_ospeed; - tp->t_cflag = t->c_cflag; - return 0; -} - -static void -dcons_tty_start(struct tty *tp) -{ - struct dcons_softc *dc; - int s; - - dc = (struct dcons_softc *)tp->t_dev->si_drv1; - s = spltty(); - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - ttwwakeup(tp); - return; - } - - tp->t_state |= TS_BUSY; - while (tp->t_outq.c_cc != 0) - dcons_putc(dc, getc(&tp->t_outq)); - tp->t_state &= ~TS_BUSY; + u_int32_t ptr, pos, gen, next_gen; + struct dcons_ch *ch; - ttwwakeup(tp); - splx(s); -} + ch = &dc->i; -static void -dcons_timeout(void *v) -{ - struct tty *tp; - struct dcons_softc *dc; - int i, c, polltime; + ptr = ntohl(*ch->ptr); + gen = ptr >> DCONS_GEN_SHIFT; + pos = ptr & DCONS_POS_MASK; + if (gen == ch->gen && pos == ch->pos) + return (0); - for (i = 0; i < DCONS_NPORT; i ++) { - dc = &sc[i]; - tp = dc->dev->si_tty; - while ((c = dcons_checkc(dc)) != -1) - if (tp->t_state & TS_ISOPEN) -#if __FreeBSD_version < 502113 - (*linesw[tp->t_line].l_rint)(c, tp); -#else - ttyld_rint(tp, c); -#endif + next_gen = DCONS_NEXT_GEN(ch->gen); + /* XXX sanity check */ + if ((gen != ch->gen && gen != next_gen) + || (gen == ch->gen && pos < ch->pos)) { + /* generation skipped !! */ + /* XXX discard */ + ch->gen = gen; + ch->pos = pos; + return (0); } - polltime = hz / poll_hz; - if (polltime < 1) - polltime = 1; - callout_reset(&dcons_callout, polltime, dcons_timeout, tp); -} - -static void -dcons_cnprobe(struct consdev *cp) -{ -#ifdef __DragonFly__ - cp->cn_dev = make_dev(&dcons_cdevsw, DCONS_CON, - UID_ROOT, GID_WHEEL, 0600, "dcons"); -#elif __FreeBSD_version >= 501109 - sprintf(cp->cn_name, "dcons"); -#else - cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON); -#endif -#if DCONS_FORCE_CONSOLE - cp->cn_pri = CN_REMOTE; -#else - cp->cn_pri = CN_NORMAL; -#endif -} - -static void -dcons_cninit(struct consdev *cp) -{ - dcons_drv_init(0); -#if CONS_NODEV - cp->cn_arg -#else - cp->cn_dev->si_drv1 -#endif - = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */ -} - -#if CONS_NODEV -static int -dcons_cngetc(struct consdev *cp) -{ - return(dcons_getc((struct dcons_softc *)cp->cn_arg)); -} -static int -dcons_cncheckc(struct consdev *cp) -{ - return(dcons_checkc((struct dcons_softc *)cp->cn_arg)); -} -static void -dcons_cnputc(struct consdev *cp, int c) -{ - dcons_putc((struct dcons_softc *)cp->cn_arg, c); -} -#else -static int -dcons_cngetc(DEV dev) -{ - return(dcons_getc((struct dcons_softc *)dev->si_drv1)); -} -static int -dcons_cncheckc(DEV dev) -{ - return(dcons_checkc((struct dcons_softc *)dev->si_drv1)); -} -static void -dcons_cnputc(DEV dev, int c) -{ - dcons_putc((struct dcons_softc *)dev->si_drv1, c); -} -#endif - -static int -dcons_getc(struct dcons_softc *dc) -{ - int c; - while ((c = dcons_checkc(dc)) == -1); - - return (c & 0xff); + return (1); } -static int +int dcons_checkc(struct dcons_softc *dc) { unsigned char c; @@ -425,8 +80,6 @@ dcons_checkc(struct dcons_softc *dc) ch = &dc->i; - if (dg.dma_tag != NULL) - bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD); ptr = ntohl(*ch->ptr); gen = ptr >> DCONS_GEN_SHIFT; pos = ptr & DCONS_POS_MASK; @@ -451,45 +104,10 @@ dcons_checkc(struct dcons_softc *dc) ch->pos = 0; } -#if __FreeBSD_version >= 502122 -#if KDB && ALT_BREAK_TO_DEBUGGER - if (kdb_alt_break(c, &dc->brk_state)) { - if ((dc->flags & DC_GDB) != 0) { - if (gdb_cur == &dcons_gdb_dbgport) { - kdb_dbbe_select("gdb"); - breakpoint(); - } - } else - breakpoint(); - } -#endif -#else -#if DDB && ALT_BREAK_TO_DEBUGGER - switch (dc->brk_state) { - case STATE1: - if (c == KEY_TILDE) - dc->brk_state = STATE2; - else - dc->brk_state = STATE0; - break; - case STATE2: - dc->brk_state = STATE0; - if (c == KEY_CTRLB) { -#if DCONS_FORCE_GDB - if (dc->flags & DC_GDB) - boothowto |= RB_GDB; -#endif - breakpoint(); - } - } - if (c == KEY_CR) - dc->brk_state = STATE1; -#endif -#endif return (c); } -static void +void dcons_putc(struct dcons_softc *dc, int c) { struct dcons_ch *ch; @@ -503,12 +121,11 @@ dcons_putc(struct dcons_softc *dc, int c) ch->pos = 0; } *ch->ptr = DCONS_MAKE_PTR(ch); - if (dg.dma_tag != NULL) - bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE); } static int -dcons_init_port(int port, int offset, int size) +dcons_init_port(int port, int offset, int size, struct dcons_buf *buf, + struct dcons_softc *sc) { int osize; struct dcons_softc *dc; @@ -519,259 +136,71 @@ dcons_init_port(int port, int offset, int size) dc->o.size = osize; dc->i.size = size - osize; - dc->o.buf = (char *)dg.buf + offset; + dc->o.buf = (char *)buf + offset; dc->i.buf = dc->o.buf + osize; dc->o.gen = dc->i.gen = 0; dc->o.pos = dc->i.pos = 0; - dc->o.ptr = &dg.buf->optr[port]; - dc->i.ptr = &dg.buf->iptr[port]; + dc->o.ptr = &buf->optr[port]; + dc->i.ptr = &buf->iptr[port]; dc->brk_state = STATE0; - dg.buf->osize[port] = htonl(osize); - dg.buf->isize[port] = htonl(size - osize); - dg.buf->ooffset[port] = htonl(offset); - dg.buf->ioffset[port] = htonl(offset + osize); - dg.buf->optr[port] = DCONS_MAKE_PTR(&dc->o); - dg.buf->iptr[port] = DCONS_MAKE_PTR(&dc->i); + buf->osize[port] = htonl(osize); + buf->isize[port] = htonl(size - osize); + buf->ooffset[port] = htonl(offset); + buf->ioffset[port] = htonl(offset + osize); + buf->optr[port] = DCONS_MAKE_PTR(&dc->o); + buf->iptr[port] = DCONS_MAKE_PTR(&dc->i); return(0); } -static int -dcons_drv_init(int stage) -{ - int size, size0, offset; - - if (drv_init) - return(drv_init); - - drv_init = -1; - - bzero(&dg, sizeof(dg)); - dcons_conf = &dg; - dg.cdev = &dcons_consdev; - dg.size = DCONS_BUF_SIZE; - -#ifndef KLD_MODULE - if (stage == 0) /* XXX or cold */ - /* - * DCONS_FORCE_CONSOLE == 1 and statically linked. - * called from cninit(). can't use contigmalloc yet . - */ - dg.buf = (struct dcons_buf *) bssbuf; - else -#endif - /* - * DCONS_FORCE_CONSOLE == 0 or kernel module case. - * if the module is loaded after boot, - * bssbuf could be non-continuous. - */ - dg.buf = (struct dcons_buf *) contigmalloc(dg.size, - M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); - - dcons_buf = dg.buf; - offset = DCONS_HEADER_SIZE; - size = (dg.size - offset); - size0 = size * 3 / 4; - - dcons_init_port(0, offset, size0); - offset += size0; - dcons_init_port(1, offset, size - size0); - dg.buf->version = htonl(DCONS_VERSION); - dg.buf->magic = ntohl(DCONS_MAGIC); - -#if __FreeBSD_version < 502122 -#if DDB && DCONS_FORCE_GDB -#if CONS_NODEV - gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB]; -#if __FreeBSD_version >= 501109 - sprintf(gdbconsdev.cn_name, "dgdb"); -#endif - gdb_arg = &gdbconsdev; -#elif defined(__DragonFly__) - gdbdev = make_dev(&dcons_cdevsw, DCONS_GDB, - UID_ROOT, GID_WHEEL, 0600, "dgdb"); -#else - gdbdev = makedev(CDEV_MAJOR, DCONS_GDB); -#endif - gdb_getc = dcons_cngetc; - gdb_putc = dcons_cnputc; -#endif -#endif - drv_init = 1; - - return 0; -} - - -static int -dcons_attach_port(int port, char *name, int flags) +int +dcons_load_buffer(struct dcons_buf *buf, int size, struct dcons_softc *sc) { + int port, s; struct dcons_softc *dc; - struct tty *tp; - - dc = &sc[port]; - dc->flags = flags; - dc->dev = make_dev(&dcons_cdevsw, port, - UID_ROOT, GID_WHEEL, 0600, name); - tp = ttymalloc(NULL); - - dc->dev->si_drv1 = (void *)dc; - dc->dev->si_tty = tp; - - tp->t_oproc = dcons_tty_start; - tp->t_param = dcons_tty_param; - tp->t_stop = nottystop; - tp->t_dev = dc->dev; - - return(0); -} -static int -dcons_attach(void) -{ - int polltime; - -#ifdef __DragonFly__ - cdevsw_add(&dcons_cdevsw, -1, 0); -#endif - dcons_attach_port(DCONS_CON, "dcons", 0); - dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB); -#if __FreeBSD_version < 500000 - callout_init(&dcons_callout); -#else - callout_init(&dcons_callout, 0); -#endif - polltime = hz / poll_hz; - if (polltime < 1) - polltime = 1; - callout_reset(&dcons_callout, polltime, dcons_timeout, NULL); - return(0); -} - -static int -dcons_detach(int port) -{ - struct tty *tp; - struct dcons_softc *dc; - - dc = &sc[port]; - - tp = dc->dev->si_tty; - - if (tp->t_state & TS_ISOPEN) { - printf("dcons: still opened\n"); -#if __FreeBSD_version < 502113 - (*linesw[tp->t_line].l_close)(tp, 0); - tp->t_gen++; - ttyclose(tp); - ttwakeup(tp); - ttwwakeup(tp); -#else - ttyld_close(tp, 0); - tty_close(tp); -#endif - } - /* XXX - * must wait until all device are closed. - */ -#ifdef __DragonFly__ - tsleep((void *)dc, 0, "dcodtc", hz/4); -#else - tsleep((void *)dc, PWAIT, "dcodtc", hz/4); -#endif - destroy_dev(dc->dev); - - return(0); -} - - -/* cnXXX works only for FreeBSD-5 */ -static int -dcons_modevent(module_t mode, int type, void *data) -{ - int err = 0, ret; - - switch (type) { - case MOD_LOAD: - ret = dcons_drv_init(1); - dcons_attach(); -#if __FreeBSD_version >= 500000 - if (ret == 0) { - dcons_cnprobe(&dcons_consdev); - dcons_cninit(&dcons_consdev); - cnadd(&dcons_consdev); - } -#endif - break; - case MOD_UNLOAD: - printf("dcons: unload\n"); - callout_stop(&dcons_callout); -#if __FreeBSD_version < 502122 -#if DDB && DCONS_FORCE_GDB -#if CONS_NODEV - gdb_arg = NULL; -#else - gdbdev = NULL; -#endif -#endif -#endif -#if __FreeBSD_version >= 500000 - cnremove(&dcons_consdev); -#endif - dcons_detach(DCONS_CON); - dcons_detach(DCONS_GDB); - dg.buf->magic = 0; + if (buf->version != htonl(DCONS_VERSION)) + return (-1); - contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF); + s = DCONS_HEADER_SIZE; + for (port = 0; port < DCONS_NPORT; port ++) { + dc = &sc[port]; + dc->o.size = ntohl(buf->osize[port]); + dc->i.size = ntohl(buf->isize[port]); + dc->o.buf = (char *)buf + ntohl(buf->ooffset[port]); + dc->i.buf = (char *)buf + ntohl(buf->ioffset[port]); + dc->o.gen = ntohl(buf->optr[port]) >> DCONS_GEN_SHIFT; + dc->i.gen = ntohl(buf->iptr[port]) >> DCONS_GEN_SHIFT; + dc->o.pos = ntohl(buf->optr[port]) & DCONS_POS_MASK; + dc->i.pos = ntohl(buf->iptr[port]) & DCONS_POS_MASK; + dc->o.ptr = &buf->optr[port]; + dc->i.ptr = &buf->iptr[port]; + dc->brk_state = STATE0; - break; - case MOD_SHUTDOWN: - dg.buf->magic = 0; - break; - default: - err = EOPNOTSUPP; - break; + s += dc->o.size + dc->i.size; } - return(err); -} - -#if __FreeBSD_version >= 502122 -/* Debugger interface */ -static int -dcons_dbg_probe(void) -{ - return(DCONS_FORCE_GDB); -} + /* sanity check */ + if (s > size) + return (-1); -static void -dcons_dbg_init(void) -{ -} + buf->magic = ntohl(DCONS_MAGIC); -static void -dcons_dbg_term(void) -{ + return (0); } -static void -dcons_dbg_putc(int c) +void +dcons_init(struct dcons_buf *buf, int size, struct dcons_softc *sc) { - dcons_putc(&sc[DCONS_GDB], c); -} + int size0, size1, offset; -static int -dcons_dbg_checkc(void) -{ - return (dcons_checkc(&sc[DCONS_GDB])); -} + offset = DCONS_HEADER_SIZE; + size0 = (size - offset); + size1 = size0 * 3 / 4; /* console port buffer */ -static int -dcons_dbg_getc(void) -{ - return (dcons_getc(&sc[DCONS_GDB])); + dcons_init_port(0, offset, size1, buf, sc); + offset += size1; + dcons_init_port(1, offset, size0 - size1, buf, sc); + buf->version = htonl(DCONS_VERSION); + buf->magic = ntohl(DCONS_MAGIC); } -#endif - -DEV_MODULE(dcons, dcons_modevent, NULL); -MODULE_VERSION(dcons, DCONS_VERSION); |