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: 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 $ 37 */ 38 39 #include <sys/param.h> 40 #if __FreeBSD_version >= 502122 41 #include <sys/kdb.h> 42 #include <gdb/gdb.h> 43 #endif 44 #include <sys/kernel.h> 45 #include <sys/module.h> 46 #include <sys/systm.h> 47 #include <sys/types.h> 48 #include <sys/conf.h> 49 #include <sys/cons.h> 50 #include <sys/consio.h> 51 #include <sys/tty.h> 52 #include <sys/malloc.h> 53 #include <sys/proc.h> 54 #include <sys/ucred.h> 55 56 #include <machine/bus.h> 57 58 #ifdef __DragonFly__ 59 #include "dcons.h" 60 #else 61 #include <dev/dcons/dcons.h> 62 #endif 63 64 #include <ddb/ddb.h> 65 #include <sys/reboot.h> 66 67 #include <sys/sysctl.h> 68 69 #include "opt_ddb.h" 70 #include "opt_comconsole.h" 71 #include "opt_dcons.h" 72 73 #ifndef DCONS_POLL_HZ 74 #define DCONS_POLL_HZ 100 75 #endif 76 77 #ifndef DCONS_BUF_SIZE 78 #define DCONS_BUF_SIZE (16*1024) 79 #endif 80 81 #ifndef DCONS_FORCE_CONSOLE 82 #define DCONS_FORCE_CONSOLE 0 /* Mostly for FreeBSD-4/DragonFly */ 83 #endif 84 85 #ifndef DCONS_FORCE_GDB 86 #define DCONS_FORCE_GDB 1 87 #endif 88 89 #if __FreeBSD_version >= 500101 90 #define CONS_NODEV 1 91 #if __FreeBSD_version < 502122 92 static struct consdev gdbconsdev; 93 #endif 94 #endif 95 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; 100 #endif 101 102 static struct cdevsw dcons_cdevsw = { 103 #ifdef __DragonFly__ 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, 112 .d_name = "dcons", 113 .d_flags = D_TTY | D_NEEDGIANT, 114 #else 115 #define CDEV_MAJOR 184 116 /* open */ dcons_open, 117 /* close */ dcons_close, 118 /* read */ ttyread, 119 /* write */ ttywrite, 120 /* ioctl */ dcons_ioctl, 121 /* poll */ ttypoll, 122 /* mmap */ nommap, 123 /* strategy */ nostrategy, 124 /* name */ "dcons", 125 /* major */ CDEV_MAJOR, 126 /* dump */ nodump, 127 /* psize */ nopsize, 128 /* flags */ D_TTY, 129 #endif 130 }; 131 132 #ifndef KLD_MODULE 133 static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */ 134 #endif 135 136 /* global data */ 137 static struct dcons_global dg; 138 struct dcons_global *dcons_conf; 139 static int poll_hz = DCONS_POLL_HZ; 140 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"); 144 145 static int drv_init = 0; 146 static struct callout dcons_callout; 147 struct dcons_buf *dcons_buf; /* for local dconschat */ 148 149 #ifdef __DragonFly__ 150 #define DEV dev_t 151 #define THREAD d_thread_t 152 #elif __FreeBSD_version < 500000 153 #define DEV dev_t 154 #define THREAD struct proc 155 #else 156 #define DEV struct cdev * 157 #define THREAD struct thread 158 #endif 159 160 /* per device data */ 161 static struct dcons_softc { 162 DEV dev; 163 struct dcons_ch o, i; 164 int brk_state; 165 #define DC_GDB 1 166 int flags; 167 } sc[DCONS_NPORT]; 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); 175 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; 181 182 CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc, 183 dcons_cncheckc, dcons_cnputc, NULL); 184 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; 192 193 GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term, 194 dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc); 195 196 extern struct gdb_dbgport *gdb_cur; 197 #endif 198 199 static int 200 dcons_open(DEV dev, int flag, int mode, THREAD *td) 201 { 202 struct tty *tp; 203 int unit, error, s; 204 205 unit = minor(dev); 206 if (unit != 0) 207 return (ENXIO); 208 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; 213 tp->t_dev = dev; 214 215 error = 0; 216 217 s = spltty(); 218 if ((tp->t_state & TS_ISOPEN) == 0) { 219 tp->t_state |= TS_CARR_ON; 220 ttychars(tp); 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; 226 ttsetwater(tp); 227 } else if ((tp->t_state & TS_XCLUDE) && suser(td)) { 228 splx(s); 229 return (EBUSY); 230 } 231 splx(s); 232 233 #if __FreeBSD_version < 502113 234 error = (*linesw[tp->t_line].l_open)(dev, tp); 235 #else 236 error = ttyld_open(tp, dev); 237 #endif 238 239 return (error); 240 } 241 242 static int 243 dcons_close(DEV dev, int flag, int mode, THREAD *td) 244 { 245 int unit; 246 struct tty *tp; 247 248 unit = minor(dev); 249 if (unit != 0) 250 return (ENXIO); 251 252 tp = dev->si_tty; 253 if (tp->t_state & TS_ISOPEN) { 254 #if __FreeBSD_version < 502113 255 (*linesw[tp->t_line].l_close)(tp, flag); 256 ttyclose(tp); 257 #else 258 ttyld_close(tp, flag); 259 tty_close(tp); 260 #endif 261 262 } 263 264 return (0); 265 } 266 267 #if defined(__DragonFly__) || __FreeBSD_version < 500104 268 static int 269 dcons_ioctl(DEV dev, u_long cmd, caddr_t data, int flag, THREAD *td) 270 { 271 int unit; 272 struct tty *tp; 273 int error; 274 275 unit = minor(dev); 276 if (unit != 0) 277 return (ENXIO); 278 279 tp = dev->si_tty; 280 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td); 281 if (error != ENOIOCTL) 282 return (error); 283 284 error = ttioctl(tp, cmd, data, flag); 285 if (error != ENOIOCTL) 286 return (error); 287 288 return (ENOTTY); 289 } 290 #endif 291 292 static int 293 dcons_tty_param(struct tty *tp, struct termios *t) 294 { 295 tp->t_ispeed = t->c_ispeed; 296 tp->t_ospeed = t->c_ospeed; 297 tp->t_cflag = t->c_cflag; 298 return 0; 299 } 300 301 static void 302 dcons_tty_start(struct tty *tp) 303 { 304 struct dcons_softc *dc; 305 int s; 306 307 dc = (struct dcons_softc *)tp->t_dev->si_drv1; 308 s = spltty(); 309 if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 310 ttwwakeup(tp); 311 return; 312 } 313 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; 318 319 ttwwakeup(tp); 320 splx(s); 321 } 322 323 static void 324 dcons_timeout(void *v) 325 { 326 struct tty *tp; 327 struct dcons_softc *dc; 328 int i, c, polltime; 329 330 for (i = 0; i < DCONS_NPORT; i ++) { 331 dc = &sc[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); 337 #else 338 ttyld_rint(tp, c); 339 #endif 340 } 341 polltime = hz / poll_hz; 342 if (polltime < 1) 343 polltime = 1; 344 callout_reset(&dcons_callout, polltime, dcons_timeout, tp); 345 } 346 347 static void 348 dcons_cnprobe(struct consdev *cp) 349 { 350 #ifdef __DragonFly__ 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"); 355 #else 356 cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON); 357 #endif 358 #if DCONS_FORCE_CONSOLE 359 cp->cn_pri = CN_REMOTE; 360 #else 361 cp->cn_pri = CN_NORMAL; 362 #endif 363 } 364 365 static void 366 dcons_cninit(struct consdev *cp) 367 { 368 dcons_drv_init(0); 369 #if CONS_NODEV 370 cp->cn_arg 371 #else 372 cp->cn_dev->si_drv1 373 #endif 374 = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */ 375 } 376 377 #if CONS_NODEV 378 static int 379 dcons_cngetc(struct consdev *cp) 380 { 381 return(dcons_getc((struct dcons_softc *)cp->cn_arg)); 382 } 383 static int 384 dcons_cncheckc(struct consdev *cp) 385 { 386 return(dcons_checkc((struct dcons_softc *)cp->cn_arg)); 387 } 388 static void 389 dcons_cnputc(struct consdev *cp, int c) 390 { 391 dcons_putc((struct dcons_softc *)cp->cn_arg, c); 392 } 393 #else 394 static int 395 dcons_cngetc(DEV dev) 396 { 397 return(dcons_getc((struct dcons_softc *)dev->si_drv1)); 398 } 399 static int 400 dcons_cncheckc(DEV dev) 401 { 402 return(dcons_checkc((struct dcons_softc *)dev->si_drv1)); 403 } 404 static void 405 dcons_cnputc(DEV dev, int c) 406 { 407 dcons_putc((struct dcons_softc *)dev->si_drv1, c); 408 } 409 #endif 410 411 static int 412 dcons_getc(struct dcons_softc *dc) 413 { 414 int c; 415 416 while ((c = dcons_checkc(dc)) == -1); 417 418 return (c & 0xff); 419 } 420 421 static int 422 dcons_checkc(struct dcons_softc *dc) 423 { 424 unsigned char c; 425 u_int32_t ptr, pos, gen, next_gen; 426 struct dcons_ch *ch; 427 428 ch = &dc->i; 429 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) 436 return (-1); 437 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 !! */ 443 /* XXX discard */ 444 ch->gen = gen; 445 ch->pos = pos; 446 return (-1); 447 } 448 449 c = ch->buf[ch->pos]; 450 ch->pos ++; 451 if (ch->pos >= ch->size) { 452 ch->gen = next_gen; 453 ch->pos = 0; 454 } 455 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"); 462 breakpoint(); 463 } 464 } else 465 breakpoint(); 466 } 467 #endif 468 #else 469 #if DDB && ALT_BREAK_TO_DEBUGGER 470 switch (dc->brk_state) { 471 case STATE1: 472 if (c == KEY_TILDE) 473 dc->brk_state = STATE2; 474 else 475 dc->brk_state = STATE0; 476 break; 477 case STATE2: 478 dc->brk_state = STATE0; 479 if (c == KEY_CTRLB) { 480 #if DCONS_FORCE_GDB 481 if (dc->flags & DC_GDB) 482 boothowto |= RB_GDB; 483 #endif 484 breakpoint(); 485 } 486 } 487 if (c == KEY_CR) 488 dc->brk_state = STATE1; 489 #endif 490 #endif 491 return (c); 492 } 493 494 static void 495 dcons_putc(struct dcons_softc *dc, int c) 496 { 497 struct dcons_ch *ch; 498 499 ch = &dc->o; 500 501 ch->buf[ch->pos] = c; 502 ch->pos ++; 503 if (ch->pos >= ch->size) { 504 ch->gen = DCONS_NEXT_GEN(ch->gen); 505 ch->pos = 0; 506 } 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); 510 } 511 512 static int 513 dcons_init_port(int port, int offset, int size) 514 { 515 int osize; 516 struct dcons_softc *dc; 517 518 dc = &sc[port]; 519 520 osize = size * 3 / 4; 521 522 dc->o.size = osize; 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); 537 538 return(0); 539 } 540 541 static int 542 dcons_drv_init(int stage) 543 { 544 int size, size0, offset; 545 546 if (drv_init) 547 return(drv_init); 548 549 drv_init = -1; 550 551 bzero(&dg, sizeof(dg)); 552 dcons_conf = &dg; 553 dg.cdev = &dcons_consdev; 554 dg.size = DCONS_BUF_SIZE; 555 556 #ifndef KLD_MODULE 557 if (stage == 0) /* XXX or cold */ 558 /* 559 * DCONS_FORCE_CONSOLE == 1 and statically linked. 560 * called from cninit(). can't use contigmalloc yet . 561 */ 562 dg.buf = (struct dcons_buf *) bssbuf; 563 else 564 #endif 565 /* 566 * DCONS_FORCE_CONSOLE == 0 or kernel module case. 567 * if the module is loaded after boot, 568 * bssbuf could be non-continuous. 569 */ 570 dg.buf = (struct dcons_buf *) contigmalloc(dg.size, 571 M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); 572 573 dcons_buf = dg.buf; 574 offset = DCONS_HEADER_SIZE; 575 size = (dg.size - offset); 576 size0 = size * 3 / 4; 577 578 dcons_init_port(0, offset, size0); 579 offset += size0; 580 dcons_init_port(1, offset, size - size0); 581 dg.buf->version = htonl(DCONS_VERSION); 582 dg.buf->magic = ntohl(DCONS_MAGIC); 583 584 #if __FreeBSD_version < 502122 585 #if DDB && DCONS_FORCE_GDB 586 #if CONS_NODEV 587 gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB]; 588 #if __FreeBSD_version >= 501109 589 sprintf(gdbconsdev.cn_name, "dgdb"); 590 #endif 591 gdb_arg = &gdbconsdev; 592 #elif defined(__DragonFly__) 593 gdbdev = make_dev(&dcons_cdevsw, DCONS_GDB, 594 UID_ROOT, GID_WHEEL, 0600, "dgdb"); 595 #else 596 gdbdev = makedev(CDEV_MAJOR, DCONS_GDB); 597 #endif 598 gdb_getc = dcons_cngetc; 599 gdb_putc = dcons_cnputc; 600 #endif 601 #endif 602 drv_init = 1; 603 604 return 0; 605 } 606 607 608 static int 609 dcons_attach_port(int port, char *name, int flags) 610 { 611 struct dcons_softc *dc; 612 struct tty *tp; 613 614 dc = &sc[port]; 615 dc->flags = flags; 616 dc->dev = make_dev(&dcons_cdevsw, port, 617 UID_ROOT, GID_WHEEL, 0600, name); 618 tp = ttymalloc(NULL); 619 620 dc->dev->si_drv1 = (void *)dc; 621 dc->dev->si_tty = tp; 622 623 tp->t_oproc = dcons_tty_start; 624 tp->t_param = dcons_tty_param; 625 tp->t_stop = nottystop; 626 tp->t_dev = dc->dev; 627 628 return(0); 629 } 630 631 static int 632 dcons_attach(void) 633 { 634 int polltime; 635 636 #ifdef __DragonFly__ 637 cdevsw_add(&dcons_cdevsw, -1, 0); 638 #endif 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); 643 #else 644 callout_init(&dcons_callout, 0); 645 #endif 646 polltime = hz / poll_hz; 647 if (polltime < 1) 648 polltime = 1; 649 callout_reset(&dcons_callout, polltime, dcons_timeout, NULL); 650 return(0); 651 } 652 653 static int 654 dcons_detach(int port) 655 { 656 struct tty *tp; 657 struct dcons_softc *dc; 658 659 dc = &sc[port]; 660 661 tp = dc->dev->si_tty; 662 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); 667 tp->t_gen++; 668 ttyclose(tp); 669 ttwakeup(tp); 670 ttwwakeup(tp); 671 #else 672 ttyld_close(tp, 0); 673 tty_close(tp); 674 #endif 675 } 676 /* XXX 677 * must wait until all device are closed. 678 */ 679 #ifdef __DragonFly__ 680 tsleep((void *)dc, 0, "dcodtc", hz/4); 681 #else 682 tsleep((void *)dc, PWAIT, "dcodtc", hz/4); 683 #endif 684 destroy_dev(dc->dev); 685 686 return(0); 687 } 688 689 690 /* cnXXX works only for FreeBSD-5 */ 691 static int 692 dcons_modevent(module_t mode, int type, void *data) 693 { 694 int err = 0, ret; 695 696 switch (type) { 697 case MOD_LOAD: 698 ret = dcons_drv_init(1); 699 dcons_attach(); 700 #if __FreeBSD_version >= 500000 701 if (ret == 0) { 702 dcons_cnprobe(&dcons_consdev); 703 dcons_cninit(&dcons_consdev); 704 cnadd(&dcons_consdev); 705 } 706 #endif 707 break; 708 case MOD_UNLOAD: 709 printf("dcons: unload\n"); 710 callout_stop(&dcons_callout); 711 #if __FreeBSD_version < 502122 712 #if DDB && DCONS_FORCE_GDB 713 #if CONS_NODEV 714 gdb_arg = NULL; 715 #else 716 gdbdev = NULL; 717 #endif 718 #endif 719 #endif 720 #if __FreeBSD_version >= 500000 721 cnremove(&dcons_consdev); 722 #endif 723 dcons_detach(DCONS_CON); 724 dcons_detach(DCONS_GDB); 725 dg.buf->magic = 0; 726 727 contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF); 728 729 break; 730 case MOD_SHUTDOWN: 731 break; 732 default: 733 err = EOPNOTSUPP; 734 break; 735 } 736 return(err); 737 } 738 739 #if __FreeBSD_version >= 502122 740 /* Debugger interface */ 741 742 static int 743 dcons_dbg_probe(void) 744 { 745 return(DCONS_FORCE_GDB); 746 } 747 748 static void 749 dcons_dbg_init(void) 750 { 751 } 752 753 static void 754 dcons_dbg_term(void) 755 { 756 } 757 758 static void 759 dcons_dbg_putc(int c) 760 { 761 dcons_putc(&sc[DCONS_GDB], c); 762 } 763 764 static int 765 dcons_dbg_checkc(void) 766 { 767 return (dcons_checkc(&sc[DCONS_GDB])); 768 } 769 770 static int 771 dcons_dbg_getc(void) 772 { 773 return (dcons_getc(&sc[DCONS_GDB])); 774 } 775 #endif 776 777 DEV_MODULE(dcons, dcons_modevent, NULL); 778 MODULE_VERSION(dcons, DCONS_VERSION); 779