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