3 * Hidetoshi Shimokawa. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
16 * This product includes software developed by Hidetoshi Shimokawa.
18 * 4. Neither the name of the author nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * $Id: dcons.c,v 1.65 2003/10/24 03:24:55 simokawa Exp $
35 * $FreeBSD: src/sys/dev/dcons/dcons.c,v 1.16 2004/07/15 20:47:37 phk Exp $
36 * $DragonFly: src/sys/dev/misc/dcons/dcons.c,v 1.2 2004/09/23 06:18:46 simokawa Exp $
39 #include <sys/param.h>
40 #if __FreeBSD_version >= 502122
44 #include <sys/kernel.h>
45 #include <sys/module.h>
46 #include <sys/systm.h>
47 #include <sys/types.h>
50 #include <sys/consio.h>
52 #include <sys/malloc.h>
54 #include <sys/ucred.h>
56 #include <machine/bus.h>
61 #include <dev/dcons/dcons.h>
65 #include <sys/reboot.h>
67 #include <sys/sysctl.h>
70 #include "opt_comconsole.h"
71 #include "opt_dcons.h"
74 #define DCONS_POLL_HZ 100
77 #ifndef DCONS_BUF_SIZE
78 #define DCONS_BUF_SIZE (16*1024)
81 #ifndef DCONS_FORCE_CONSOLE
82 #define DCONS_FORCE_CONSOLE 0 /* Mostly for FreeBSD-4/DragonFly */
85 #ifndef DCONS_FORCE_GDB
86 #define DCONS_FORCE_GDB 1
89 #if __FreeBSD_version >= 500101
91 #if __FreeBSD_version < 502122
92 static struct consdev gdbconsdev;
96 static d_open_t dcons_open;
97 static d_close_t dcons_close;
98 #if defined(__DragonFly__) || __FreeBSD_version < 500104
99 static d_ioctl_t dcons_ioctl;
102 static struct cdevsw dcons_cdevsw = {
104 #define CDEV_MAJOR 184
105 "dcons", CDEV_MAJOR, D_TTY, NULL, 0,
106 dcons_open, dcons_close, ttyread, ttywrite, dcons_ioctl,
107 ttypoll, nommap, nostrategy, nodump, nopsize,
108 #elif __FreeBSD_version >= 500104
109 .d_version = D_VERSION,
110 .d_open = dcons_open,
111 .d_close = dcons_close,
113 .d_flags = D_TTY | D_NEEDGIANT,
115 #define CDEV_MAJOR 184
116 /* open */ dcons_open,
117 /* close */ dcons_close,
119 /* write */ ttywrite,
120 /* ioctl */ dcons_ioctl,
123 /* strategy */ nostrategy,
125 /* major */ CDEV_MAJOR,
133 static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */
137 static struct dcons_global dg;
138 struct dcons_global *dcons_conf;
139 static int poll_hz = DCONS_POLL_HZ;
141 SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console");
142 SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0,
143 "dcons polling rate");
145 static int drv_init = 0;
146 static struct callout dcons_callout;
147 struct dcons_buf *dcons_buf; /* for local dconschat */
151 #define THREAD d_thread_t
152 #elif __FreeBSD_version < 500000
154 #define THREAD struct proc
156 #define DEV struct cdev *
157 #define THREAD struct thread
160 /* per device data */
161 static struct dcons_softc {
163 struct dcons_ch o, i;
168 static void dcons_tty_start(struct tty *);
169 static int dcons_tty_param(struct tty *, struct termios *);
170 static void dcons_timeout(void *);
171 static int dcons_drv_init(int);
172 static int dcons_getc(struct dcons_softc *);
173 static int dcons_checkc(struct dcons_softc *);
174 static void dcons_putc(struct dcons_softc *, int);
176 static cn_probe_t dcons_cnprobe;
177 static cn_init_t dcons_cninit;
178 static cn_getc_t dcons_cngetc;
179 static cn_checkc_t dcons_cncheckc;
180 static cn_putc_t dcons_cnputc;
182 CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc,
183 dcons_cncheckc, dcons_cnputc, NULL);
185 #if __FreeBSD_version >= 502122
186 static gdb_probe_f dcons_dbg_probe;
187 static gdb_init_f dcons_dbg_init;
188 static gdb_term_f dcons_dbg_term;
189 static gdb_getc_f dcons_dbg_getc;
190 static gdb_checkc_f dcons_dbg_checkc;
191 static gdb_putc_f dcons_dbg_putc;
193 GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term,
194 dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc);
196 extern struct gdb_dbgport *gdb_cur;
200 dcons_open(DEV dev, int flag, int mode, THREAD *td)
209 tp = dev->si_tty = ttymalloc(dev->si_tty);
210 tp->t_oproc = dcons_tty_start;
211 tp->t_param = dcons_tty_param;
212 tp->t_stop = nottystop;
218 if ((tp->t_state & TS_ISOPEN) == 0) {
219 tp->t_state |= TS_CARR_ON;
221 tp->t_iflag = TTYDEF_IFLAG;
222 tp->t_oflag = TTYDEF_OFLAG;
223 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
224 tp->t_lflag = TTYDEF_LFLAG;
225 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
227 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) {
233 #if __FreeBSD_version < 502113
234 error = (*linesw[tp->t_line].l_open)(dev, tp);
236 error = ttyld_open(tp, dev);
243 dcons_close(DEV dev, int flag, int mode, THREAD *td)
253 if (tp->t_state & TS_ISOPEN) {
254 #if __FreeBSD_version < 502113
255 (*linesw[tp->t_line].l_close)(tp, flag);
258 ttyld_close(tp, flag);
267 #if defined(__DragonFly__) || __FreeBSD_version < 500104
269 dcons_ioctl(DEV dev, u_long cmd, caddr_t data, int flag, THREAD *td)
280 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
281 if (error != ENOIOCTL)
284 error = ttioctl(tp, cmd, data, flag);
285 if (error != ENOIOCTL)
293 dcons_tty_param(struct tty *tp, struct termios *t)
295 tp->t_ispeed = t->c_ispeed;
296 tp->t_ospeed = t->c_ospeed;
297 tp->t_cflag = t->c_cflag;
302 dcons_tty_start(struct tty *tp)
304 struct dcons_softc *dc;
307 dc = (struct dcons_softc *)tp->t_dev->si_drv1;
309 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
314 tp->t_state |= TS_BUSY;
315 while (tp->t_outq.c_cc != 0)
316 dcons_putc(dc, getc(&tp->t_outq));
317 tp->t_state &= ~TS_BUSY;
324 dcons_timeout(void *v)
327 struct dcons_softc *dc;
330 for (i = 0; i < DCONS_NPORT; i ++) {
332 tp = dc->dev->si_tty;
333 while ((c = dcons_checkc(dc)) != -1)
334 if (tp->t_state & TS_ISOPEN)
335 #if __FreeBSD_version < 502113
336 (*linesw[tp->t_line].l_rint)(c, tp);
341 polltime = hz / poll_hz;
344 callout_reset(&dcons_callout, polltime, dcons_timeout, tp);
348 dcons_cnprobe(struct consdev *cp)
351 cp->cn_dev = make_dev(&dcons_cdevsw, DCONS_CON,
352 UID_ROOT, GID_WHEEL, 0600, "dcons");
353 #elif __FreeBSD_version >= 501109
354 sprintf(cp->cn_name, "dcons");
356 cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON);
358 #if DCONS_FORCE_CONSOLE
359 cp->cn_pri = CN_REMOTE;
361 cp->cn_pri = CN_NORMAL;
366 dcons_cninit(struct consdev *cp)
374 = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
379 dcons_cngetc(struct consdev *cp)
381 return(dcons_getc((struct dcons_softc *)cp->cn_arg));
384 dcons_cncheckc(struct consdev *cp)
386 return(dcons_checkc((struct dcons_softc *)cp->cn_arg));
389 dcons_cnputc(struct consdev *cp, int c)
391 dcons_putc((struct dcons_softc *)cp->cn_arg, c);
395 dcons_cngetc(DEV dev)
397 return(dcons_getc((struct dcons_softc *)dev->si_drv1));
400 dcons_cncheckc(DEV dev)
402 return(dcons_checkc((struct dcons_softc *)dev->si_drv1));
405 dcons_cnputc(DEV dev, int c)
407 dcons_putc((struct dcons_softc *)dev->si_drv1, c);
412 dcons_getc(struct dcons_softc *dc)
416 while ((c = dcons_checkc(dc)) == -1);
422 dcons_checkc(struct dcons_softc *dc)
425 u_int32_t ptr, pos, gen, next_gen;
430 if (dg.dma_tag != NULL)
431 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD);
432 ptr = ntohl(*ch->ptr);
433 gen = ptr >> DCONS_GEN_SHIFT;
434 pos = ptr & DCONS_POS_MASK;
435 if (gen == ch->gen && pos == ch->pos)
438 next_gen = DCONS_NEXT_GEN(ch->gen);
439 /* XXX sanity check */
440 if ((gen != ch->gen && gen != next_gen)
441 || (gen == ch->gen && pos < ch->pos)) {
442 /* generation skipped !! */
449 c = ch->buf[ch->pos];
451 if (ch->pos >= ch->size) {
456 #if __FreeBSD_version >= 502122
457 #if KDB && ALT_BREAK_TO_DEBUGGER
458 if (kdb_alt_break(c, &dc->brk_state)) {
459 if ((dc->flags & DC_GDB) != 0) {
460 if (gdb_cur == &dcons_gdb_dbgport) {
461 kdb_dbbe_select("gdb");
469 #if DDB && ALT_BREAK_TO_DEBUGGER
470 switch (dc->brk_state) {
473 dc->brk_state = STATE2;
475 dc->brk_state = STATE0;
478 dc->brk_state = STATE0;
479 if (c == KEY_CTRLB) {
481 if (dc->flags & DC_GDB)
488 dc->brk_state = STATE1;
495 dcons_putc(struct dcons_softc *dc, int c)
501 ch->buf[ch->pos] = c;
503 if (ch->pos >= ch->size) {
504 ch->gen = DCONS_NEXT_GEN(ch->gen);
507 *ch->ptr = DCONS_MAKE_PTR(ch);
508 if (dg.dma_tag != NULL)
509 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE);
513 dcons_init_port(int port, int offset, int size)
516 struct dcons_softc *dc;
520 osize = size * 3 / 4;
523 dc->i.size = size - osize;
524 dc->o.buf = (char *)dg.buf + offset;
525 dc->i.buf = dc->o.buf + osize;
526 dc->o.gen = dc->i.gen = 0;
527 dc->o.pos = dc->i.pos = 0;
528 dc->o.ptr = &dg.buf->optr[port];
529 dc->i.ptr = &dg.buf->iptr[port];
530 dc->brk_state = STATE0;
531 dg.buf->osize[port] = htonl(osize);
532 dg.buf->isize[port] = htonl(size - osize);
533 dg.buf->ooffset[port] = htonl(offset);
534 dg.buf->ioffset[port] = htonl(offset + osize);
535 dg.buf->optr[port] = DCONS_MAKE_PTR(&dc->o);
536 dg.buf->iptr[port] = DCONS_MAKE_PTR(&dc->i);
542 dcons_drv_init(int stage)
544 int size, size0, offset;
551 bzero(&dg, sizeof(dg));
553 dg.cdev = &dcons_consdev;
554 dg.size = DCONS_BUF_SIZE;
557 if (stage == 0) /* XXX or cold */
559 * DCONS_FORCE_CONSOLE == 1 and statically linked.
560 * called from cninit(). can't use contigmalloc yet .
562 dg.buf = (struct dcons_buf *) bssbuf;
566 * DCONS_FORCE_CONSOLE == 0 or kernel module case.
567 * if the module is loaded after boot,
568 * bssbuf could be non-continuous.
570 dg.buf = (struct dcons_buf *) contigmalloc(dg.size,
571 M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
574 offset = DCONS_HEADER_SIZE;
575 size = (dg.size - offset);
576 size0 = size * 3 / 4;
578 dcons_init_port(0, offset, size0);
580 dcons_init_port(1, offset, size - size0);
581 dg.buf->version = htonl(DCONS_VERSION);
582 dg.buf->magic = ntohl(DCONS_MAGIC);
584 #if __FreeBSD_version < 502122
585 #if DDB && DCONS_FORCE_GDB
587 gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB];
588 #if __FreeBSD_version >= 501109
589 sprintf(gdbconsdev.cn_name, "dgdb");
591 gdb_arg = &gdbconsdev;
592 #elif defined(__DragonFly__)
593 gdbdev = make_dev(&dcons_cdevsw, DCONS_GDB,
594 UID_ROOT, GID_WHEEL, 0600, "dgdb");
596 gdbdev = makedev(CDEV_MAJOR, DCONS_GDB);
598 gdb_getc = dcons_cngetc;
599 gdb_putc = dcons_cnputc;
609 dcons_attach_port(int port, char *name, int flags)
611 struct dcons_softc *dc;
616 dc->dev = make_dev(&dcons_cdevsw, port,
617 UID_ROOT, GID_WHEEL, 0600, name);
618 tp = ttymalloc(NULL);
620 dc->dev->si_drv1 = (void *)dc;
621 dc->dev->si_tty = tp;
623 tp->t_oproc = dcons_tty_start;
624 tp->t_param = dcons_tty_param;
625 tp->t_stop = nottystop;
637 cdevsw_add(&dcons_cdevsw, -1, 0);
639 dcons_attach_port(DCONS_CON, "dcons", 0);
640 dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB);
641 #if __FreeBSD_version < 500000
642 callout_init(&dcons_callout);
644 callout_init(&dcons_callout, 0);
646 polltime = hz / poll_hz;
649 callout_reset(&dcons_callout, polltime, dcons_timeout, NULL);
654 dcons_detach(int port)
657 struct dcons_softc *dc;
661 tp = dc->dev->si_tty;
663 if (tp->t_state & TS_ISOPEN) {
664 printf("dcons: still opened\n");
665 #if __FreeBSD_version < 502113
666 (*linesw[tp->t_line].l_close)(tp, 0);
677 * must wait until all device are closed.
680 tsleep((void *)dc, 0, "dcodtc", hz/4);
682 tsleep((void *)dc, PWAIT, "dcodtc", hz/4);
684 destroy_dev(dc->dev);
690 /* cnXXX works only for FreeBSD-5 */
692 dcons_modevent(module_t mode, int type, void *data)
698 ret = dcons_drv_init(1);
700 #if __FreeBSD_version >= 500000
702 dcons_cnprobe(&dcons_consdev);
703 dcons_cninit(&dcons_consdev);
704 cnadd(&dcons_consdev);
709 printf("dcons: unload\n");
710 callout_stop(&dcons_callout);
711 #if __FreeBSD_version < 502122
712 #if DDB && DCONS_FORCE_GDB
720 #if __FreeBSD_version >= 500000
721 cnremove(&dcons_consdev);
723 dcons_detach(DCONS_CON);
724 dcons_detach(DCONS_GDB);
727 contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF);
739 #if __FreeBSD_version >= 502122
740 /* Debugger interface */
743 dcons_dbg_probe(void)
745 return(DCONS_FORCE_GDB);
759 dcons_dbg_putc(int c)
761 dcons_putc(&sc[DCONS_GDB], c);
765 dcons_dbg_checkc(void)
767 return (dcons_checkc(&sc[DCONS_GDB]));
773 return (dcons_getc(&sc[DCONS_GDB]));
777 DEV_MODULE(dcons, dcons_modevent, NULL);
778 MODULE_VERSION(dcons, DCONS_VERSION);