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