1/* 2 * Copyright (C) 2003 3 * Hidetoshi Shimokawa. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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: 15 * 16 * This product includes software developed by Hidetoshi Shimokawa. 17 * 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. 21 * 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 32 * SUCH DAMAGE. 33 * 34 * $Id: dcons.c,v 1.65 2003/10/24 03:24:55 simokawa Exp $
| 1/* 2 * Copyright (C) 2003 3 * Hidetoshi Shimokawa. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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: 15 * 16 * This product includes software developed by Hidetoshi Shimokawa. 17 * 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. 21 * 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 32 * SUCH DAMAGE. 33 * 34 * $Id: dcons.c,v 1.65 2003/10/24 03:24:55 simokawa Exp $
|
35 * $FreeBSD: head/sys/dev/dcons/dcons.c 132199 2004-07-15 08:26:07Z phk $
| 35 * $FreeBSD: head/sys/dev/dcons/dcons.c 132226 2004-07-15 20:47:41Z phk $
|
36 */ 37 38#include <sys/param.h> 39#if __FreeBSD_version >= 502122 40#include <sys/kdb.h> 41#include <gdb/gdb.h> 42#endif 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/systm.h> 46#include <sys/types.h> 47#include <sys/conf.h> 48#include <sys/cons.h> 49#include <sys/consio.h> 50#include <sys/tty.h> 51#include <sys/malloc.h> 52#include <sys/proc.h> 53#include <sys/ucred.h> 54 55#include <machine/bus.h> 56 57#include <dev/dcons/dcons.h> 58 59#include <ddb/ddb.h> 60#include <sys/reboot.h> 61 62#include <sys/sysctl.h> 63 64#include "opt_ddb.h" 65#include "opt_comconsole.h" 66#include "opt_dcons.h" 67 68#ifndef DCONS_POLL_HZ 69#define DCONS_POLL_HZ 100 70#endif 71 72#ifndef DCONS_BUF_SIZE 73#define DCONS_BUF_SIZE (16*1024) 74#endif 75 76#ifndef DCONS_FORCE_CONSOLE 77#define DCONS_FORCE_CONSOLE 0 /* mostly for FreeBSD-4 */ 78#endif 79 80#ifndef DCONS_FORCE_GDB 81#define DCONS_FORCE_GDB 1 82#endif 83 84#if __FreeBSD_version >= 500101 85#define CONS_NODEV 1 86#if __FreeBSD_version < 502122 87static struct consdev gdbconsdev; 88#endif 89#endif 90 91 92static d_open_t dcons_open; 93static d_close_t dcons_close; 94 95static struct cdevsw dcons_cdevsw = { 96#if __FreeBSD_version >= 500104 97 .d_version = D_VERSION, 98 .d_open = dcons_open, 99 .d_close = dcons_close, 100 .d_name = "dcons", 101 .d_flags = D_TTY | D_NEEDGIANT, 102#else 103 /* open */ dcons_open, 104 /* close */ dcons_close, 105 /* read */ ttyread, 106 /* write */ ttywrite, 107 /* ioctl */ dcons_ioctl, 108 /* poll */ ttypoll, 109 /* mmap */ nommap, 110 /* strategy */ nostrategy, 111 /* name */ "dcons", 112 /* major */ CDEV_MAJOR, 113 /* dump */ nodump, 114 /* psize */ nopsize, 115 /* flags */ 0, 116#endif 117}; 118 119#ifndef KLD_MODULE 120static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */ 121#endif 122 123/* global data */ 124static struct dcons_global dg; 125struct dcons_global *dcons_conf; 126static int poll_hz = DCONS_POLL_HZ; 127 128SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console"); 129SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0, 130 "dcons polling rate"); 131 132static int drv_init = 0; 133static struct callout dcons_callout; 134struct dcons_buf *dcons_buf; /* for local dconschat */ 135 136/* per device data */ 137static struct dcons_softc { 138 struct cdev *dev; 139 struct dcons_ch o, i; 140 int brk_state; 141#define DC_GDB 1 142 int flags; 143} sc[DCONS_NPORT]; 144static void dcons_tty_start(struct tty *); 145static int dcons_tty_param(struct tty *, struct termios *); 146static void dcons_timeout(void *); 147static int dcons_drv_init(int); 148static int dcons_getc(struct dcons_softc *); 149static int dcons_checkc(struct dcons_softc *); 150static void dcons_putc(struct dcons_softc *, int); 151 152static cn_probe_t dcons_cnprobe; 153static cn_init_t dcons_cninit; 154static cn_getc_t dcons_cngetc; 155static cn_checkc_t dcons_cncheckc; 156static cn_putc_t dcons_cnputc; 157 158CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc, 159 dcons_cncheckc, dcons_cnputc, NULL); 160 161#if __FreeBSD_version >= 502122 162static gdb_probe_f dcons_dbg_probe; 163static gdb_init_f dcons_dbg_init; 164static gdb_term_f dcons_dbg_term; 165static gdb_getc_f dcons_dbg_getc; 166static gdb_checkc_f dcons_dbg_checkc; 167static gdb_putc_f dcons_dbg_putc; 168 169GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term, 170 dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc); 171 172extern struct gdb_dbgport *gdb_cur; 173#endif 174 175#if __FreeBSD_version < 500000 176#define THREAD proc 177#else 178#define THREAD thread 179#endif 180 181static int 182dcons_open(struct cdev *dev, int flag, int mode, struct THREAD *td) 183{ 184 struct tty *tp; 185 int unit, error, s; 186 187 unit = minor(dev); 188 if (unit != 0) 189 return (ENXIO); 190 191 tp = dev->si_tty = ttymalloc(dev->si_tty); 192 tp->t_oproc = dcons_tty_start; 193 tp->t_param = dcons_tty_param; 194 tp->t_stop = nottystop; 195 tp->t_dev = dev; 196 197 error = 0; 198 199 s = spltty(); 200 if ((tp->t_state & TS_ISOPEN) == 0) { 201 tp->t_state |= TS_CARR_ON; 202 ttychars(tp); 203 tp->t_iflag = TTYDEF_IFLAG; 204 tp->t_oflag = TTYDEF_OFLAG; 205 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 206 tp->t_lflag = TTYDEF_LFLAG; 207 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 208 ttsetwater(tp); 209 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 210 splx(s); 211 return (EBUSY); 212 } 213 splx(s); 214 215 error = ttyld_open(tp, dev); 216 217 return (error); 218} 219 220static int 221dcons_close(struct cdev *dev, int flag, int mode, struct THREAD *td) 222{ 223 int unit; 224 struct tty *tp; 225 226 unit = minor(dev); 227 if (unit != 0) 228 return (ENXIO); 229 230 tp = dev->si_tty; 231 if (tp->t_state & TS_ISOPEN) { 232 ttyld_close(tp, flag);
| 36 */ 37 38#include <sys/param.h> 39#if __FreeBSD_version >= 502122 40#include <sys/kdb.h> 41#include <gdb/gdb.h> 42#endif 43#include <sys/kernel.h> 44#include <sys/module.h> 45#include <sys/systm.h> 46#include <sys/types.h> 47#include <sys/conf.h> 48#include <sys/cons.h> 49#include <sys/consio.h> 50#include <sys/tty.h> 51#include <sys/malloc.h> 52#include <sys/proc.h> 53#include <sys/ucred.h> 54 55#include <machine/bus.h> 56 57#include <dev/dcons/dcons.h> 58 59#include <ddb/ddb.h> 60#include <sys/reboot.h> 61 62#include <sys/sysctl.h> 63 64#include "opt_ddb.h" 65#include "opt_comconsole.h" 66#include "opt_dcons.h" 67 68#ifndef DCONS_POLL_HZ 69#define DCONS_POLL_HZ 100 70#endif 71 72#ifndef DCONS_BUF_SIZE 73#define DCONS_BUF_SIZE (16*1024) 74#endif 75 76#ifndef DCONS_FORCE_CONSOLE 77#define DCONS_FORCE_CONSOLE 0 /* mostly for FreeBSD-4 */ 78#endif 79 80#ifndef DCONS_FORCE_GDB 81#define DCONS_FORCE_GDB 1 82#endif 83 84#if __FreeBSD_version >= 500101 85#define CONS_NODEV 1 86#if __FreeBSD_version < 502122 87static struct consdev gdbconsdev; 88#endif 89#endif 90 91 92static d_open_t dcons_open; 93static d_close_t dcons_close; 94 95static struct cdevsw dcons_cdevsw = { 96#if __FreeBSD_version >= 500104 97 .d_version = D_VERSION, 98 .d_open = dcons_open, 99 .d_close = dcons_close, 100 .d_name = "dcons", 101 .d_flags = D_TTY | D_NEEDGIANT, 102#else 103 /* open */ dcons_open, 104 /* close */ dcons_close, 105 /* read */ ttyread, 106 /* write */ ttywrite, 107 /* ioctl */ dcons_ioctl, 108 /* poll */ ttypoll, 109 /* mmap */ nommap, 110 /* strategy */ nostrategy, 111 /* name */ "dcons", 112 /* major */ CDEV_MAJOR, 113 /* dump */ nodump, 114 /* psize */ nopsize, 115 /* flags */ 0, 116#endif 117}; 118 119#ifndef KLD_MODULE 120static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */ 121#endif 122 123/* global data */ 124static struct dcons_global dg; 125struct dcons_global *dcons_conf; 126static int poll_hz = DCONS_POLL_HZ; 127 128SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console"); 129SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0, 130 "dcons polling rate"); 131 132static int drv_init = 0; 133static struct callout dcons_callout; 134struct dcons_buf *dcons_buf; /* for local dconschat */ 135 136/* per device data */ 137static struct dcons_softc { 138 struct cdev *dev; 139 struct dcons_ch o, i; 140 int brk_state; 141#define DC_GDB 1 142 int flags; 143} sc[DCONS_NPORT]; 144static void dcons_tty_start(struct tty *); 145static int dcons_tty_param(struct tty *, struct termios *); 146static void dcons_timeout(void *); 147static int dcons_drv_init(int); 148static int dcons_getc(struct dcons_softc *); 149static int dcons_checkc(struct dcons_softc *); 150static void dcons_putc(struct dcons_softc *, int); 151 152static cn_probe_t dcons_cnprobe; 153static cn_init_t dcons_cninit; 154static cn_getc_t dcons_cngetc; 155static cn_checkc_t dcons_cncheckc; 156static cn_putc_t dcons_cnputc; 157 158CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc, 159 dcons_cncheckc, dcons_cnputc, NULL); 160 161#if __FreeBSD_version >= 502122 162static gdb_probe_f dcons_dbg_probe; 163static gdb_init_f dcons_dbg_init; 164static gdb_term_f dcons_dbg_term; 165static gdb_getc_f dcons_dbg_getc; 166static gdb_checkc_f dcons_dbg_checkc; 167static gdb_putc_f dcons_dbg_putc; 168 169GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term, 170 dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc); 171 172extern struct gdb_dbgport *gdb_cur; 173#endif 174 175#if __FreeBSD_version < 500000 176#define THREAD proc 177#else 178#define THREAD thread 179#endif 180 181static int 182dcons_open(struct cdev *dev, int flag, int mode, struct THREAD *td) 183{ 184 struct tty *tp; 185 int unit, error, s; 186 187 unit = minor(dev); 188 if (unit != 0) 189 return (ENXIO); 190 191 tp = dev->si_tty = ttymalloc(dev->si_tty); 192 tp->t_oproc = dcons_tty_start; 193 tp->t_param = dcons_tty_param; 194 tp->t_stop = nottystop; 195 tp->t_dev = dev; 196 197 error = 0; 198 199 s = spltty(); 200 if ((tp->t_state & TS_ISOPEN) == 0) { 201 tp->t_state |= TS_CARR_ON; 202 ttychars(tp); 203 tp->t_iflag = TTYDEF_IFLAG; 204 tp->t_oflag = TTYDEF_OFLAG; 205 tp->t_cflag = TTYDEF_CFLAG|CLOCAL; 206 tp->t_lflag = TTYDEF_LFLAG; 207 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 208 ttsetwater(tp); 209 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 210 splx(s); 211 return (EBUSY); 212 } 213 splx(s); 214 215 error = ttyld_open(tp, dev); 216 217 return (error); 218} 219 220static int 221dcons_close(struct cdev *dev, int flag, int mode, struct THREAD *td) 222{ 223 int unit; 224 struct tty *tp; 225 226 unit = minor(dev); 227 if (unit != 0) 228 return (ENXIO); 229 230 tp = dev->si_tty; 231 if (tp->t_state & TS_ISOPEN) { 232 ttyld_close(tp, flag);
|
233 ttyclose(tp);
| 233 tty_close(tp);
|
234 } 235 236 return (0); 237} 238 239static int 240dcons_tty_param(struct tty *tp, struct termios *t) 241{ 242 tp->t_ispeed = t->c_ispeed; 243 tp->t_ospeed = t->c_ospeed; 244 tp->t_cflag = t->c_cflag; 245 return 0; 246} 247 248static void 249dcons_tty_start(struct tty *tp) 250{ 251 struct dcons_softc *dc; 252 int s; 253 254 dc = (struct dcons_softc *)tp->t_dev->si_drv1; 255 s = spltty(); 256 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 257 ttwwakeup(tp); 258 return; 259 } 260 261 tp->t_state |= TS_BUSY; 262 while (tp->t_outq.c_cc != 0) 263 dcons_putc(dc, getc(&tp->t_outq)); 264 tp->t_state &= ~TS_BUSY; 265 266 ttwwakeup(tp); 267 splx(s); 268} 269 270static void 271dcons_timeout(void *v) 272{ 273 struct tty *tp; 274 struct dcons_softc *dc; 275 int i, c, polltime; 276 277 for (i = 0; i < DCONS_NPORT; i ++) { 278 dc = &sc[i]; 279 tp = dc->dev->si_tty; 280 while ((c = dcons_checkc(dc)) != -1) 281 if (tp->t_state & TS_ISOPEN) 282 ttyld_rint(tp, c); 283 } 284 polltime = hz / poll_hz; 285 if (polltime < 1) 286 polltime = 1; 287 callout_reset(&dcons_callout, polltime, dcons_timeout, tp); 288} 289 290static void 291dcons_cnprobe(struct consdev *cp) 292{ 293#if __FreeBSD_version >= 501109 294 sprintf(cp->cn_name, "dcons"); 295#else 296 cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON); 297#endif 298#if DCONS_FORCE_CONSOLE 299 cp->cn_pri = CN_REMOTE; 300#else 301 cp->cn_pri = CN_NORMAL; 302#endif 303} 304 305static void 306dcons_cninit(struct consdev *cp) 307{ 308 dcons_drv_init(0); 309#if CONS_NODEV 310 cp->cn_arg 311#else 312 cp->cn_dev->si_drv1 313#endif 314 = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */ 315} 316 317#if CONS_NODEV 318static int 319dcons_cngetc(struct consdev *cp) 320{ 321 return(dcons_getc((struct dcons_softc *)cp->cn_arg)); 322} 323static int 324dcons_cncheckc(struct consdev *cp) 325{ 326 return(dcons_checkc((struct dcons_softc *)cp->cn_arg)); 327} 328static void 329dcons_cnputc(struct consdev *cp, int c) 330{ 331 dcons_putc((struct dcons_softc *)cp->cn_arg, c); 332} 333#else 334static int 335dcons_cngetc(struct cdev *dev) 336{ 337 return(dcons_getc((struct dcons_softc *)dev->si_drv1)); 338} 339static int 340dcons_cncheckc(struct cdev *dev) 341{ 342 return(dcons_checkc((struct dcons_softc *)dev->si_drv1)); 343} 344static void 345dcons_cnputc(struct cdev *dev, int c) 346{ 347 dcons_putc((struct dcons_softc *)dev->si_drv1, c); 348} 349#endif 350 351static int 352dcons_getc(struct dcons_softc *dc) 353{ 354 int c; 355 356 while ((c = dcons_checkc(dc)) == -1); 357 358 return (c & 0xff); 359} 360 361static int 362dcons_checkc(struct dcons_softc *dc) 363{ 364 unsigned char c; 365 u_int32_t ptr, pos, gen, next_gen; 366 struct dcons_ch *ch; 367 368 ch = &dc->i; 369 370 if (dg.dma_tag != NULL) 371 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD); 372 ptr = ntohl(*ch->ptr); 373 gen = ptr >> DCONS_GEN_SHIFT; 374 pos = ptr & DCONS_POS_MASK; 375 if (gen == ch->gen && pos == ch->pos) 376 return (-1); 377 378 next_gen = DCONS_NEXT_GEN(ch->gen); 379 /* XXX sanity check */ 380 if ((gen != ch->gen && gen != next_gen) 381 || (gen == ch->gen && pos < ch->pos)) { 382 /* generation skipped !! */ 383 /* XXX discard */ 384 ch->gen = gen; 385 ch->pos = pos; 386 return (-1); 387 } 388 389 c = ch->buf[ch->pos]; 390 ch->pos ++; 391 if (ch->pos >= ch->size) { 392 ch->gen = next_gen; 393 ch->pos = 0; 394 } 395 396#if __FreeBSD_version >= 502122 397#if KDB && ALT_BREAK_TO_DEBUGGER 398 if (kdb_alt_break(c, &dc->brk_state)) { 399 if ((dc->flags & DC_GDB) != 0) { 400 if (gdb_cur == &dcons_gdb_dbgport) { 401 kdb_dbbe_select("gdb"); 402 breakpoint(); 403 } 404 } else 405 breakpoint(); 406 } 407#endif 408#else 409#if DDB && ALT_BREAK_TO_DEBUGGER 410 switch (dc->brk_state) { 411 case STATE1: 412 if (c == KEY_TILDE) 413 dc->brk_state = STATE2; 414 else 415 dc->brk_state = STATE0; 416 break; 417 case STATE2: 418 dc->brk_state = STATE0; 419 if (c == KEY_CTRLB) { 420#if DCONS_FORCE_GDB 421 if (dc->flags & DC_GDB) 422 boothowto |= RB_GDB; 423#endif 424 breakpoint(); 425 } 426 } 427 if (c == KEY_CR) 428 dc->brk_state = STATE1; 429#endif 430#endif 431 return (c); 432} 433 434static void 435dcons_putc(struct dcons_softc *dc, int c) 436{ 437 struct dcons_ch *ch; 438 439 ch = &dc->o; 440 441 ch->buf[ch->pos] = c; 442 ch->pos ++; 443 if (ch->pos >= ch->size) { 444 ch->gen = DCONS_NEXT_GEN(ch->gen); 445 ch->pos = 0; 446 } 447 *ch->ptr = DCONS_MAKE_PTR(ch); 448 if (dg.dma_tag != NULL) 449 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE); 450} 451 452static int 453dcons_init_port(int port, int offset, int size) 454{ 455 int osize; 456 struct dcons_softc *dc; 457 458 dc = &sc[port]; 459 460 osize = size * 3 / 4; 461 462 dc->o.size = osize; 463 dc->i.size = size - osize; 464 dc->o.buf = (char *)dg.buf + offset; 465 dc->i.buf = dc->o.buf + osize; 466 dc->o.gen = dc->i.gen = 0; 467 dc->o.pos = dc->i.pos = 0; 468 dc->o.ptr = &dg.buf->optr[port]; 469 dc->i.ptr = &dg.buf->iptr[port]; 470 dc->brk_state = STATE0; 471 dg.buf->osize[port] = htonl(osize); 472 dg.buf->isize[port] = htonl(size - osize); 473 dg.buf->ooffset[port] = htonl(offset); 474 dg.buf->ioffset[port] = htonl(offset + osize); 475 dg.buf->optr[port] = DCONS_MAKE_PTR(&dc->o); 476 dg.buf->iptr[port] = DCONS_MAKE_PTR(&dc->i); 477 478 return(0); 479} 480 481static int 482dcons_drv_init(int stage) 483{ 484 int size, size0, offset; 485 486 if (drv_init) 487 return(drv_init); 488 489 drv_init = -1; 490 491 bzero(&dg, sizeof(dg)); 492 dcons_conf = &dg; 493 dg.cdev = &dcons_consdev; 494 dg.size = DCONS_BUF_SIZE; 495 496#ifndef KLD_MODULE 497 if (stage == 0) /* XXX or cold */ 498 /* 499 * DCONS_FORCE_CONSOLE == 1 and statically linked. 500 * called from cninit(). can't use contigmalloc yet . 501 */ 502 dg.buf = (struct dcons_buf *) bssbuf; 503 else 504#endif 505 /* 506 * DCONS_FORCE_CONSOLE == 0 or kernel module case. 507 * if the module is loaded after boot, 508 * bssbuf could be non-continuous. 509 */ 510 dg.buf = (struct dcons_buf *) contigmalloc(dg.size, 511 M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); 512 513 dcons_buf = dg.buf; 514 offset = DCONS_HEADER_SIZE; 515 size = (dg.size - offset); 516 size0 = size * 3 / 4; 517 518 dcons_init_port(0, offset, size0); 519 offset += size0; 520 dcons_init_port(1, offset, size - size0); 521 dg.buf->version = htonl(DCONS_VERSION); 522 dg.buf->magic = ntohl(DCONS_MAGIC); 523 524#if __FreeBSD_version < 502122 525#if DDB && DCONS_FORCE_GDB 526#if CONS_NODEV 527 gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB]; 528#if __FreeBSD_version >= 501109 529 sprintf(gdbconsdev.cn_name, "dgdb"); 530#endif 531 gdb_arg = &gdbconsdev; 532#else 533 gdbdev = makedev(CDEV_MAJOR, DCONS_GDB); 534#endif 535 gdb_getc = dcons_cngetc; 536 gdb_putc = dcons_cnputc; 537#endif 538#endif 539 drv_init = 1; 540 541 return 0; 542} 543 544 545static int 546dcons_attach_port(int port, char *name, int flags) 547{ 548 struct dcons_softc *dc; 549 struct tty *tp; 550 551 dc = &sc[port]; 552 dc->flags = flags; 553 dc->dev = make_dev(&dcons_cdevsw, port, 554 UID_ROOT, GID_WHEEL, 0600, name); 555 tp = ttymalloc(NULL); 556 557 dc->dev->si_drv1 = (void *)dc; 558 dc->dev->si_tty = tp; 559 560 tp->t_oproc = dcons_tty_start; 561 tp->t_param = dcons_tty_param; 562 tp->t_stop = nottystop; 563 tp->t_dev = dc->dev; 564 565 return(0); 566} 567 568static int 569dcons_attach(void) 570{ 571 int polltime; 572 573 dcons_attach_port(DCONS_CON, "dcons", 0); 574 dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB); 575#if __FreeBSD_version < 500000 576 callout_init(&dcons_callout); 577#else 578 callout_init(&dcons_callout, 0); 579#endif 580 polltime = hz / poll_hz; 581 if (polltime < 1) 582 polltime = 1; 583 callout_reset(&dcons_callout, polltime, dcons_timeout, NULL); 584 return(0); 585} 586 587static int 588dcons_detach(int port) 589{ 590 struct tty *tp; 591 struct dcons_softc *dc; 592 593 dc = &sc[port]; 594 595 tp = dc->dev->si_tty; 596 597 if (tp->t_state & TS_ISOPEN) { 598 printf("dcons: still opened\n"); 599 ttyld_close(tp, 0);
| 234 } 235 236 return (0); 237} 238 239static int 240dcons_tty_param(struct tty *tp, struct termios *t) 241{ 242 tp->t_ispeed = t->c_ispeed; 243 tp->t_ospeed = t->c_ospeed; 244 tp->t_cflag = t->c_cflag; 245 return 0; 246} 247 248static void 249dcons_tty_start(struct tty *tp) 250{ 251 struct dcons_softc *dc; 252 int s; 253 254 dc = (struct dcons_softc *)tp->t_dev->si_drv1; 255 s = spltty(); 256 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 257 ttwwakeup(tp); 258 return; 259 } 260 261 tp->t_state |= TS_BUSY; 262 while (tp->t_outq.c_cc != 0) 263 dcons_putc(dc, getc(&tp->t_outq)); 264 tp->t_state &= ~TS_BUSY; 265 266 ttwwakeup(tp); 267 splx(s); 268} 269 270static void 271dcons_timeout(void *v) 272{ 273 struct tty *tp; 274 struct dcons_softc *dc; 275 int i, c, polltime; 276 277 for (i = 0; i < DCONS_NPORT; i ++) { 278 dc = &sc[i]; 279 tp = dc->dev->si_tty; 280 while ((c = dcons_checkc(dc)) != -1) 281 if (tp->t_state & TS_ISOPEN) 282 ttyld_rint(tp, c); 283 } 284 polltime = hz / poll_hz; 285 if (polltime < 1) 286 polltime = 1; 287 callout_reset(&dcons_callout, polltime, dcons_timeout, tp); 288} 289 290static void 291dcons_cnprobe(struct consdev *cp) 292{ 293#if __FreeBSD_version >= 501109 294 sprintf(cp->cn_name, "dcons"); 295#else 296 cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON); 297#endif 298#if DCONS_FORCE_CONSOLE 299 cp->cn_pri = CN_REMOTE; 300#else 301 cp->cn_pri = CN_NORMAL; 302#endif 303} 304 305static void 306dcons_cninit(struct consdev *cp) 307{ 308 dcons_drv_init(0); 309#if CONS_NODEV 310 cp->cn_arg 311#else 312 cp->cn_dev->si_drv1 313#endif 314 = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */ 315} 316 317#if CONS_NODEV 318static int 319dcons_cngetc(struct consdev *cp) 320{ 321 return(dcons_getc((struct dcons_softc *)cp->cn_arg)); 322} 323static int 324dcons_cncheckc(struct consdev *cp) 325{ 326 return(dcons_checkc((struct dcons_softc *)cp->cn_arg)); 327} 328static void 329dcons_cnputc(struct consdev *cp, int c) 330{ 331 dcons_putc((struct dcons_softc *)cp->cn_arg, c); 332} 333#else 334static int 335dcons_cngetc(struct cdev *dev) 336{ 337 return(dcons_getc((struct dcons_softc *)dev->si_drv1)); 338} 339static int 340dcons_cncheckc(struct cdev *dev) 341{ 342 return(dcons_checkc((struct dcons_softc *)dev->si_drv1)); 343} 344static void 345dcons_cnputc(struct cdev *dev, int c) 346{ 347 dcons_putc((struct dcons_softc *)dev->si_drv1, c); 348} 349#endif 350 351static int 352dcons_getc(struct dcons_softc *dc) 353{ 354 int c; 355 356 while ((c = dcons_checkc(dc)) == -1); 357 358 return (c & 0xff); 359} 360 361static int 362dcons_checkc(struct dcons_softc *dc) 363{ 364 unsigned char c; 365 u_int32_t ptr, pos, gen, next_gen; 366 struct dcons_ch *ch; 367 368 ch = &dc->i; 369 370 if (dg.dma_tag != NULL) 371 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD); 372 ptr = ntohl(*ch->ptr); 373 gen = ptr >> DCONS_GEN_SHIFT; 374 pos = ptr & DCONS_POS_MASK; 375 if (gen == ch->gen && pos == ch->pos) 376 return (-1); 377 378 next_gen = DCONS_NEXT_GEN(ch->gen); 379 /* XXX sanity check */ 380 if ((gen != ch->gen && gen != next_gen) 381 || (gen == ch->gen && pos < ch->pos)) { 382 /* generation skipped !! */ 383 /* XXX discard */ 384 ch->gen = gen; 385 ch->pos = pos; 386 return (-1); 387 } 388 389 c = ch->buf[ch->pos]; 390 ch->pos ++; 391 if (ch->pos >= ch->size) { 392 ch->gen = next_gen; 393 ch->pos = 0; 394 } 395 396#if __FreeBSD_version >= 502122 397#if KDB && ALT_BREAK_TO_DEBUGGER 398 if (kdb_alt_break(c, &dc->brk_state)) { 399 if ((dc->flags & DC_GDB) != 0) { 400 if (gdb_cur == &dcons_gdb_dbgport) { 401 kdb_dbbe_select("gdb"); 402 breakpoint(); 403 } 404 } else 405 breakpoint(); 406 } 407#endif 408#else 409#if DDB && ALT_BREAK_TO_DEBUGGER 410 switch (dc->brk_state) { 411 case STATE1: 412 if (c == KEY_TILDE) 413 dc->brk_state = STATE2; 414 else 415 dc->brk_state = STATE0; 416 break; 417 case STATE2: 418 dc->brk_state = STATE0; 419 if (c == KEY_CTRLB) { 420#if DCONS_FORCE_GDB 421 if (dc->flags & DC_GDB) 422 boothowto |= RB_GDB; 423#endif 424 breakpoint(); 425 } 426 } 427 if (c == KEY_CR) 428 dc->brk_state = STATE1; 429#endif 430#endif 431 return (c); 432} 433 434static void 435dcons_putc(struct dcons_softc *dc, int c) 436{ 437 struct dcons_ch *ch; 438 439 ch = &dc->o; 440 441 ch->buf[ch->pos] = c; 442 ch->pos ++; 443 if (ch->pos >= ch->size) { 444 ch->gen = DCONS_NEXT_GEN(ch->gen); 445 ch->pos = 0; 446 } 447 *ch->ptr = DCONS_MAKE_PTR(ch); 448 if (dg.dma_tag != NULL) 449 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE); 450} 451 452static int 453dcons_init_port(int port, int offset, int size) 454{ 455 int osize; 456 struct dcons_softc *dc; 457 458 dc = &sc[port]; 459 460 osize = size * 3 / 4; 461 462 dc->o.size = osize; 463 dc->i.size = size - osize; 464 dc->o.buf = (char *)dg.buf + offset; 465 dc->i.buf = dc->o.buf + osize; 466 dc->o.gen = dc->i.gen = 0; 467 dc->o.pos = dc->i.pos = 0; 468 dc->o.ptr = &dg.buf->optr[port]; 469 dc->i.ptr = &dg.buf->iptr[port]; 470 dc->brk_state = STATE0; 471 dg.buf->osize[port] = htonl(osize); 472 dg.buf->isize[port] = htonl(size - osize); 473 dg.buf->ooffset[port] = htonl(offset); 474 dg.buf->ioffset[port] = htonl(offset + osize); 475 dg.buf->optr[port] = DCONS_MAKE_PTR(&dc->o); 476 dg.buf->iptr[port] = DCONS_MAKE_PTR(&dc->i); 477 478 return(0); 479} 480 481static int 482dcons_drv_init(int stage) 483{ 484 int size, size0, offset; 485 486 if (drv_init) 487 return(drv_init); 488 489 drv_init = -1; 490 491 bzero(&dg, sizeof(dg)); 492 dcons_conf = &dg; 493 dg.cdev = &dcons_consdev; 494 dg.size = DCONS_BUF_SIZE; 495 496#ifndef KLD_MODULE 497 if (stage == 0) /* XXX or cold */ 498 /* 499 * DCONS_FORCE_CONSOLE == 1 and statically linked. 500 * called from cninit(). can't use contigmalloc yet . 501 */ 502 dg.buf = (struct dcons_buf *) bssbuf; 503 else 504#endif 505 /* 506 * DCONS_FORCE_CONSOLE == 0 or kernel module case. 507 * if the module is loaded after boot, 508 * bssbuf could be non-continuous. 509 */ 510 dg.buf = (struct dcons_buf *) contigmalloc(dg.size, 511 M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); 512 513 dcons_buf = dg.buf; 514 offset = DCONS_HEADER_SIZE; 515 size = (dg.size - offset); 516 size0 = size * 3 / 4; 517 518 dcons_init_port(0, offset, size0); 519 offset += size0; 520 dcons_init_port(1, offset, size - size0); 521 dg.buf->version = htonl(DCONS_VERSION); 522 dg.buf->magic = ntohl(DCONS_MAGIC); 523 524#if __FreeBSD_version < 502122 525#if DDB && DCONS_FORCE_GDB 526#if CONS_NODEV 527 gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB]; 528#if __FreeBSD_version >= 501109 529 sprintf(gdbconsdev.cn_name, "dgdb"); 530#endif 531 gdb_arg = &gdbconsdev; 532#else 533 gdbdev = makedev(CDEV_MAJOR, DCONS_GDB); 534#endif 535 gdb_getc = dcons_cngetc; 536 gdb_putc = dcons_cnputc; 537#endif 538#endif 539 drv_init = 1; 540 541 return 0; 542} 543 544 545static int 546dcons_attach_port(int port, char *name, int flags) 547{ 548 struct dcons_softc *dc; 549 struct tty *tp; 550 551 dc = &sc[port]; 552 dc->flags = flags; 553 dc->dev = make_dev(&dcons_cdevsw, port, 554 UID_ROOT, GID_WHEEL, 0600, name); 555 tp = ttymalloc(NULL); 556 557 dc->dev->si_drv1 = (void *)dc; 558 dc->dev->si_tty = tp; 559 560 tp->t_oproc = dcons_tty_start; 561 tp->t_param = dcons_tty_param; 562 tp->t_stop = nottystop; 563 tp->t_dev = dc->dev; 564 565 return(0); 566} 567 568static int 569dcons_attach(void) 570{ 571 int polltime; 572 573 dcons_attach_port(DCONS_CON, "dcons", 0); 574 dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB); 575#if __FreeBSD_version < 500000 576 callout_init(&dcons_callout); 577#else 578 callout_init(&dcons_callout, 0); 579#endif 580 polltime = hz / poll_hz; 581 if (polltime < 1) 582 polltime = 1; 583 callout_reset(&dcons_callout, polltime, dcons_timeout, NULL); 584 return(0); 585} 586 587static int 588dcons_detach(int port) 589{ 590 struct tty *tp; 591 struct dcons_softc *dc; 592 593 dc = &sc[port]; 594 595 tp = dc->dev->si_tty; 596 597 if (tp->t_state & TS_ISOPEN) { 598 printf("dcons: still opened\n"); 599 ttyld_close(tp, 0);
|
600 ttyclose(tp);
| 600 tty_close(tp);
|
601 } 602 /* XXX 603 * must wait until all device are closed. 604 */ 605 tsleep((void *)dc, PWAIT, "dcodtc", hz/4); 606 destroy_dev(dc->dev); 607 608 return(0); 609} 610 611 612/* cnXXX works only for FreeBSD-5 */ 613static int 614dcons_modevent(module_t mode, int type, void *data) 615{ 616 int err = 0, ret; 617 618 switch (type) { 619 case MOD_LOAD: 620 ret = dcons_drv_init(1); 621 dcons_attach(); 622#if __FreeBSD_version >= 500000 623 if (ret == 0) { 624 dcons_cnprobe(&dcons_consdev); 625 dcons_cninit(&dcons_consdev); 626 cnadd(&dcons_consdev); 627 } 628#endif 629 break; 630 case MOD_UNLOAD: 631 printf("dcons: unload\n"); 632 callout_stop(&dcons_callout); 633#if __FreeBSD_version < 502122 634#if DDB && DCONS_FORCE_GDB 635#if CONS_NODEV 636 gdb_arg = NULL; 637#else 638 gdbdev = NULL; 639#endif 640#endif 641#endif 642#if __FreeBSD_version >= 500000 643 cnremove(&dcons_consdev); 644#endif 645 dcons_detach(DCONS_CON); 646 dcons_detach(DCONS_GDB); 647 dg.buf->magic = 0; 648 649 contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF); 650 651 break; 652 case MOD_SHUTDOWN: 653 break; 654 default: 655 err = EOPNOTSUPP; 656 break; 657 } 658 return(err); 659} 660 661#if __FreeBSD_version >= 502122 662/* Debugger interface */ 663 664static int 665dcons_dbg_probe(void) 666{ 667 return(DCONS_FORCE_GDB); 668} 669 670static void 671dcons_dbg_init(void) 672{ 673} 674 675static void 676dcons_dbg_term(void) 677{ 678} 679 680static void 681dcons_dbg_putc(int c) 682{ 683 dcons_putc(&sc[DCONS_GDB], c); 684} 685 686static int 687dcons_dbg_checkc(void) 688{ 689 return (dcons_checkc(&sc[DCONS_GDB])); 690} 691 692static int 693dcons_dbg_getc(void) 694{ 695 return (dcons_getc(&sc[DCONS_GDB])); 696} 697#endif 698 699DEV_MODULE(dcons, dcons_modevent, NULL); 700MODULE_VERSION(dcons, DCONS_VERSION);
| 601 } 602 /* XXX 603 * must wait until all device are closed. 604 */ 605 tsleep((void *)dc, PWAIT, "dcodtc", hz/4); 606 destroy_dev(dc->dev); 607 608 return(0); 609} 610 611 612/* cnXXX works only for FreeBSD-5 */ 613static int 614dcons_modevent(module_t mode, int type, void *data) 615{ 616 int err = 0, ret; 617 618 switch (type) { 619 case MOD_LOAD: 620 ret = dcons_drv_init(1); 621 dcons_attach(); 622#if __FreeBSD_version >= 500000 623 if (ret == 0) { 624 dcons_cnprobe(&dcons_consdev); 625 dcons_cninit(&dcons_consdev); 626 cnadd(&dcons_consdev); 627 } 628#endif 629 break; 630 case MOD_UNLOAD: 631 printf("dcons: unload\n"); 632 callout_stop(&dcons_callout); 633#if __FreeBSD_version < 502122 634#if DDB && DCONS_FORCE_GDB 635#if CONS_NODEV 636 gdb_arg = NULL; 637#else 638 gdbdev = NULL; 639#endif 640#endif 641#endif 642#if __FreeBSD_version >= 500000 643 cnremove(&dcons_consdev); 644#endif 645 dcons_detach(DCONS_CON); 646 dcons_detach(DCONS_GDB); 647 dg.buf->magic = 0; 648 649 contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF); 650 651 break; 652 case MOD_SHUTDOWN: 653 break; 654 default: 655 err = EOPNOTSUPP; 656 break; 657 } 658 return(err); 659} 660 661#if __FreeBSD_version >= 502122 662/* Debugger interface */ 663 664static int 665dcons_dbg_probe(void) 666{ 667 return(DCONS_FORCE_GDB); 668} 669 670static void 671dcons_dbg_init(void) 672{ 673} 674 675static void 676dcons_dbg_term(void) 677{ 678} 679 680static void 681dcons_dbg_putc(int c) 682{ 683 dcons_putc(&sc[DCONS_GDB], c); 684} 685 686static int 687dcons_dbg_checkc(void) 688{ 689 return (dcons_checkc(&sc[DCONS_GDB])); 690} 691 692static int 693dcons_dbg_getc(void) 694{ 695 return (dcons_getc(&sc[DCONS_GDB])); 696} 697#endif 698 699DEV_MODULE(dcons, dcons_modevent, NULL); 700MODULE_VERSION(dcons, DCONS_VERSION);
|