55304c9ddda379b8f27e2b53ac9705250471b3d8
[dragonfly.git] / sys / dev / misc / dcons / dcons_os.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (C) 2003,2004
5  *      Hidetoshi Shimokawa. All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *
18  *      This product includes software developed by Hidetoshi Shimokawa.
19  *
20  * 4. Neither the name of the author nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  * 
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  * 
36  * $FreeBSD: src/sys/dev/dcons/dcons_os.c,v 1.4 2004/10/24 12:41:04 simokawa Exp $
37  * $DragonFly: src/sys/dev/misc/dcons/dcons_os.c,v 1.13 2007/08/07 13:14:11 hasso Exp $
38  */
39
40 #include <sys/param.h>
41 #if __FreeBSD_version >= 502122
42 #include <sys/kdb.h>
43 #include <gdb/gdb.h>
44 #endif
45 #include <sys/kernel.h>
46 #include <sys/module.h>
47 #include <sys/systm.h>
48 #include <sys/types.h>
49 #include <sys/conf.h>
50 #include <sys/cons.h>
51 #include <sys/consio.h>
52 #include <sys/tty.h>
53 #include <sys/malloc.h>
54 #include <sys/proc.h>
55 #include <sys/priv.h>
56 #include <sys/thread2.h>
57 #include <sys/ucred.h>
58 #include <sys/bus.h>
59
60 #include "dcons.h"
61 #include "dcons_os.h"
62
63 #include <ddb/ddb.h>
64 #include <sys/reboot.h>
65
66 #include <sys/sysctl.h>
67
68 #include <vm/vm.h>
69 #include <vm/vm_param.h>
70 #include <vm/pmap.h>
71
72 #include "opt_ddb.h"
73 #include "opt_comconsole.h"
74 #include "opt_dcons.h"
75
76 #ifndef DCONS_POLL_HZ
77 #define DCONS_POLL_HZ   100
78 #endif
79
80 #ifndef DCONS_BUF_SIZE
81 #define DCONS_BUF_SIZE (16*1024)
82 #endif
83
84 #ifndef DCONS_FORCE_CONSOLE
85 #define DCONS_FORCE_CONSOLE     0       /* Mostly for FreeBSD-4/DragonFly */
86 #endif
87
88 #ifndef DCONS_FORCE_GDB
89 #define DCONS_FORCE_GDB 1
90 #endif
91
92 #define CDEV_MAJOR      184
93
94 static d_open_t         dcons_open;
95 static d_close_t        dcons_close;
96 static d_ioctl_t        dcons_ioctl;
97
98 static struct dev_ops dcons_ops = {
99         { "dcons", CDEV_MAJOR, D_TTY },
100         .d_open =       dcons_open,
101         .d_close =      dcons_close,
102         .d_read =       ttyread,
103         .d_write =      ttywrite,
104         .d_ioctl =      dcons_ioctl,
105         .d_kqfilter =   ttykqfilter,
106         .d_revoke =     ttyrevoke
107 };
108
109 #ifndef KLD_MODULE
110 static char bssbuf[DCONS_BUF_SIZE];     /* buf in bss */
111 #endif
112
113 /* global data */
114 static struct dcons_global dg;
115 struct dcons_global *dcons_conf;
116 static int poll_hz = DCONS_POLL_HZ;
117
118 static struct dcons_softc sc[DCONS_NPORT];
119
120 SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console");
121 SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0,
122                                 "dcons polling rate");
123
124 static int drv_init = 0;
125 static struct callout dcons_callout;
126 struct dcons_buf *dcons_buf;            /* for local dconschat */
127
128 #ifdef __DragonFly__
129 #define DEV     cdev_t
130 #define THREAD  d_thread_t
131 #elif __FreeBSD_version < 500000
132 #define DEV     cdev_t
133 #define THREAD  struct proc
134 #else
135 #define DEV     struct cdev *
136 #define THREAD  struct thread
137 #endif
138
139
140 static void     dcons_tty_start(struct tty *);
141 static int      dcons_tty_param(struct tty *, struct termios *);
142 static void     dcons_timeout(void *);
143 static int      dcons_drv_init(int);
144
145 static cn_probe_t       dcons_cnprobe;
146 static cn_init_t        dcons_cninit;
147 static cn_init_fini_t   dcons_cninit_fini;
148 static cn_getc_t        dcons_cngetc;
149 static cn_checkc_t      dcons_cncheckc;
150 static cn_putc_t        dcons_cnputc;
151
152 CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, dcons_cninit_fini,
153             NULL, dcons_cngetc, dcons_cncheckc, dcons_cnputc, NULL);
154
155 #if __FreeBSD_version >= 502122
156 static gdb_probe_f dcons_dbg_probe;
157 static gdb_init_f dcons_dbg_init;
158 static gdb_term_f dcons_dbg_term;
159 static gdb_getc_f dcons_dbg_getc;
160 static gdb_checkc_f dcons_dbg_checkc;
161 static gdb_putc_f dcons_dbg_putc;
162
163 GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term,
164     dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc);
165
166 extern struct gdb_dbgport *gdb_cur;
167 #endif
168
169 #if (KDB || DDB) && ALT_BREAK_TO_DEBUGGER
170 static int
171 dcons_check_break(struct dcons_softc *dc, int c)
172 {
173         if (c < 0)
174                 return (c);
175
176         lwkt_gettoken(&tty_token);
177 #if __FreeBSD_version >= 502122
178         if (kdb_alt_break(c, &dc->brk_state)) {
179                 if ((dc->flags & DC_GDB) != 0) {
180                         if (gdb_cur == &dcons_gdb_dbgport) {
181                                 kdb_dbbe_select("gdb");
182                                 breakpoint();
183                         }
184                 } else
185                         breakpoint();
186         }
187 #else
188         switch (dc->brk_state) {
189         case STATE1:
190                 if (c == KEY_TILDE)
191                         dc->brk_state = STATE2;
192                 else
193                         dc->brk_state = STATE0;
194                 break;
195         case STATE2:
196                 dc->brk_state = STATE0;
197                 if (c == KEY_CTRLB) {
198 #if DCONS_FORCE_GDB
199                         if (dc->flags & DC_GDB)
200                                 boothowto |= RB_GDB;
201 #endif
202                         breakpoint();
203                 }
204         }
205         if (c == KEY_CR)
206                 dc->brk_state = STATE1;
207 #endif
208         lwkt_reltoken(&tty_token);
209         return (c);
210 }
211 #else
212 #define dcons_check_break(dc, c)        (c)
213 #endif
214
215 static int
216 dcons_os_checkc(struct dcons_softc *dc)
217 {
218         int c;
219
220         lwkt_gettoken(&tty_token);
221         if (dg.dma_tag != NULL)
222                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD);
223   
224         c = dcons_check_break(dc, dcons_checkc(dc));
225
226         if (dg.dma_tag != NULL)
227                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREREAD);
228
229         lwkt_reltoken(&tty_token);
230         return (c);
231 }
232
233 static int
234 dcons_os_getc(struct dcons_softc *dc)
235 {
236         int c;
237
238         while ((c = dcons_os_checkc(dc)) == -1);
239
240         return (c & 0xff);
241
242
243 static void
244 dcons_os_putc(struct dcons_softc *dc, int c)
245 {
246         if (dg.dma_tag != NULL)
247                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTWRITE);
248
249         dcons_putc(dc, c);
250
251         if (dg.dma_tag != NULL)
252                 bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE);
253 }
254 static int
255 dcons_open(struct dev_open_args *ap)
256 {
257         cdev_t dev = ap->a_head.a_dev;
258         struct tty *tp;
259         int unit, error;
260
261         unit = minor(dev);
262         if (unit != 0)
263                 return (ENXIO);
264
265         lwkt_gettoken(&tty_token);
266         tp = dev->si_tty = ttymalloc(dev->si_tty);
267         tp->t_oproc = dcons_tty_start;
268         tp->t_param = dcons_tty_param;
269         tp->t_stop = nottystop;
270         tp->t_dev = dev;
271
272         error = 0;
273
274         crit_enter();
275         if ((tp->t_state & TS_ISOPEN) == 0) {
276                 tp->t_state |= TS_CARR_ON;
277                 ttychars(tp);
278                 tp->t_iflag = TTYDEF_IFLAG;
279                 tp->t_oflag = TTYDEF_OFLAG;
280                 tp->t_cflag = TTYDEF_CFLAG|CLOCAL;
281                 tp->t_lflag = TTYDEF_LFLAG;
282                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
283                 ttsetwater(tp);
284         } else if ((tp->t_state & TS_XCLUDE) && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
285                 crit_exit();
286                 lwkt_reltoken(&tty_token);
287                 return (EBUSY);
288         }
289         crit_exit();
290
291 #if __FreeBSD_version < 502113
292         error = (*linesw[tp->t_line].l_open)(dev, tp);
293 #else
294         error = ttyld_open(tp, dev);
295 #endif
296         lwkt_reltoken(&tty_token);
297         return (error);
298 }
299
300 static int
301 dcons_close(struct dev_close_args *ap)
302 {
303         cdev_t dev = ap->a_head.a_dev;
304         int     unit;
305         struct  tty *tp;
306
307         unit = minor(dev);
308         if (unit != 0)
309                 return (ENXIO);
310
311         lwkt_gettoken(&tty_token);
312         tp = dev->si_tty;
313         if (tp->t_state & TS_ISOPEN) {
314                 (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
315                 ttyclose(tp);
316         }
317         lwkt_reltoken(&tty_token);
318
319         return (0);
320 }
321
322 static int
323 dcons_ioctl(struct dev_ioctl_args *ap)
324 {
325         cdev_t dev = ap->a_head.a_dev;
326         int     unit;
327         struct  tty *tp;
328         int     error;
329
330         unit = minor(dev);
331         if (unit != 0)
332                 return (ENXIO);
333
334         lwkt_gettoken(&tty_token);
335         tp = dev->si_tty;
336         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred);
337         if (error != ENOIOCTL) {
338                 lwkt_reltoken(&tty_token);
339                 return (error);
340         }
341
342         error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
343         if (error != ENOIOCTL) {
344                 lwkt_reltoken(&tty_token);
345                 return (error);
346         }
347
348         lwkt_reltoken(&tty_token);
349         return (ENOTTY);
350 }
351
352 static int
353 dcons_tty_param(struct tty *tp, struct termios *t)
354 {
355         lwkt_gettoken(&tty_token);
356         tp->t_ispeed = t->c_ispeed;
357         tp->t_ospeed = t->c_ospeed;
358         tp->t_cflag = t->c_cflag;
359         lwkt_reltoken(&tty_token);
360         return 0;
361 }
362
363 static void
364 dcons_tty_start(struct tty *tp)
365 {
366         struct dcons_softc *dc;
367
368         lwkt_gettoken(&tty_token);
369         dc = (struct dcons_softc *)tp->t_dev->si_drv1;
370         crit_enter();
371         if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
372                 ttwwakeup(tp);
373                 lwkt_reltoken(&tty_token);
374                 return;
375         }
376
377         tp->t_state |= TS_BUSY;
378         while (tp->t_outq.c_cc != 0)
379                 dcons_os_putc(dc, clist_getc(&tp->t_outq));
380         tp->t_state &= ~TS_BUSY;
381
382         ttwwakeup(tp);
383         crit_exit();
384         lwkt_reltoken(&tty_token);
385 }
386
387 static void
388 dcons_timeout(void *v)
389 {
390         struct  tty *tp;
391         struct dcons_softc *dc;
392         int i, c, polltime;
393
394         lwkt_gettoken(&tty_token);
395         for (i = 0; i < DCONS_NPORT; i ++) {
396                 dc = &sc[i];
397                 tp = ((DEV)dc->dev)->si_tty;
398                 while ((c = dcons_os_checkc(dc)) != -1)
399                         if (tp->t_state & TS_ISOPEN)
400 #if __FreeBSD_version < 502113
401                                 (*linesw[tp->t_line].l_rint)(c, tp);
402 #else
403                                 ttyld_rint(tp, c);
404 #endif
405         }
406         polltime = hz / poll_hz;
407         if (polltime < 1)
408                 polltime = 1;
409         callout_reset(&dcons_callout, polltime, dcons_timeout, tp);
410         lwkt_reltoken(&tty_token);
411 }
412
413 static void
414 dcons_cnprobe(struct consdev *cp)
415 {
416 #ifdef __DragonFly__
417         cp->cn_probegood = 1;
418 #elif __FreeBSD_version >= 501109
419         ksprintf(cp->cn_name, "dcons");
420 #else
421         cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON);
422 #endif
423 #if DCONS_FORCE_CONSOLE
424         cp->cn_pri = CN_REMOTE;
425 #else
426         cp->cn_pri = CN_NORMAL;
427 #endif
428 }
429
430 static void
431 dcons_cninit(struct consdev *cp)
432 {
433         dcons_drv_init(0);
434 #if CONS_NODEV
435         cp->cn_arg
436 #else
437         cp->cn_private
438 #endif
439                 = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */
440 }
441
442 static void
443 dcons_cninit_fini(struct consdev *cp)
444 {
445         cp->cn_dev = make_dev(&dcons_ops, DCONS_CON,
446                               UID_ROOT, GID_WHEEL, 0600, "dcons");
447 }
448
449 #if CONS_NODEV
450 static int
451 dcons_cngetc(struct consdev *cp)
452 {
453         struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
454         return (dcons_os_getc(dc));
455 }
456 static int
457 dcons_cncheckc(struct consdev *cp)
458 {
459         struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
460         return (dcons_os_checkc(dc));
461 }
462 static void
463 dcons_cnputc(struct consdev *cp, int c)
464 {
465         struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg;
466         dcons_os_putc(dc, c);
467 }
468 #else
469 static int
470 dcons_cngetc(void *private)
471 {
472         struct dcons_softc *dc = (struct dcons_softc *)private;
473         return (dcons_os_getc(dc));
474 }
475 static int
476 dcons_cncheckc(void *private)
477 {
478         struct dcons_softc *dc = (struct dcons_softc *)private;
479         return (dcons_os_checkc(dc));
480 }
481 static void
482 dcons_cnputc(void *private, int c)
483 {
484         struct dcons_softc *dc = (struct dcons_softc *)private;
485         dcons_os_putc(dc, c);
486 }
487 #endif
488
489 static int
490 dcons_drv_init(int stage)
491 {
492 #ifdef __i386__
493         quad_t addr, size;
494 #endif
495
496         if (drv_init)
497                 return(drv_init);
498
499         drv_init = -1;
500
501         bzero(&dg, sizeof(dg));
502         dcons_conf = &dg;
503         dg.cdev = &dcons_consdev;
504         dg.buf = NULL;
505         dg.size = DCONS_BUF_SIZE;
506
507 #ifdef __i386__
508         if (kgetenv_quad("dcons.addr", &addr) > 0 &&
509             kgetenv_quad("dcons.size", &size) > 0) {
510                 vm_paddr_t pa;
511                 /*
512                  * Allow read/write access to dcons buffer.
513                  */
514                 for (pa = trunc_page(addr); pa < addr + size; pa += PAGE_SIZE)
515                         pmap_kmodify_rw((vm_offset_t)(KERNBASE + pa));
516                 cpu_invltlb();
517                 /* XXX P to V */
518                 dg.buf = (struct dcons_buf *)(vm_offset_t)(KERNBASE + addr);
519                 dg.size = size;
520                 if (dcons_load_buffer(dg.buf, dg.size, sc) < 0)
521                         dg.buf = NULL;
522         }
523 #endif
524         if (dg.buf != NULL)
525                 goto ok;
526
527 #ifndef KLD_MODULE
528         if (stage == 0) { /* XXX or cold */
529                 /*
530                  * DCONS_FORCE_CONSOLE == 1 and statically linked.
531                  * called from cninit(). can't use contigmalloc yet .
532                  */
533                 dg.buf = (struct dcons_buf *) bssbuf;
534                 dcons_init(dg.buf, dg.size, sc);
535         } else
536 #endif
537         {
538                 /*
539                  * DCONS_FORCE_CONSOLE == 0 or kernel module case.
540                  * if the module is loaded after boot,
541                  * bssbuf could be non-continuous.
542                  */ 
543                 dg.buf = (struct dcons_buf *) contigmalloc(dg.size,
544                         M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul);
545                 dcons_init(dg.buf, dg.size, sc);
546         }
547
548 ok:
549         dcons_buf = dg.buf;
550
551 #if DDB && DCONS_FORCE_GDB
552         if (gdb_tab == NULL) {
553                 gdb_tab = &dcons_consdev;
554                 dcons_consdev.cn_gdbprivate = &sc[DCONS_GDB];
555         }
556 #endif
557         drv_init = 1;
558
559         return 0;
560 }
561
562 /*
563  * NOTE: Must be called with tty_token held
564  */
565 static int
566 dcons_attach_port(int port, char *name, int flags)
567 {
568         struct dcons_softc *dc;
569         struct tty *tp;
570         DEV dev;
571
572         ASSERT_LWKT_TOKEN_HELD(&tty_token);
573         dc = &sc[port];
574         dc->flags = flags;
575         dev = make_dev(&dcons_ops, port,
576                         UID_ROOT, GID_WHEEL, 0600, name);
577         dc->dev = (void *)dev;
578         tp = ttymalloc(NULL);
579
580         dev->si_drv1 = (void *)dc;
581         dev->si_tty = tp;
582
583         tp->t_oproc = dcons_tty_start;
584         tp->t_param = dcons_tty_param;
585         tp->t_stop = nottystop;
586         tp->t_dev = dc->dev;
587
588         return(0);
589 }
590
591 /*
592  * NOTE: Must be called with tty_token held
593  */
594 static int
595 dcons_attach(void)
596 {
597         int polltime;
598
599         ASSERT_LWKT_TOKEN_HELD(&tty_token);
600         dcons_attach_port(DCONS_CON, "dcons", 0);
601         dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB);
602 #if __FreeBSD_version < 500000
603         callout_init_mp(&dcons_callout);
604 #else
605         callout_init(&dcons_callout, 0);
606 #endif
607         polltime = hz / poll_hz;
608         if (polltime < 1)
609                 polltime = 1;
610         callout_reset(&dcons_callout, polltime, dcons_timeout, NULL);
611         return(0);
612 }
613
614 /*
615  * NOTE: Must be called with tty_token held
616  */
617 static int
618 dcons_detach(int port)
619 {
620         struct  tty *tp;
621         struct dcons_softc *dc;
622
623         ASSERT_LWKT_TOKEN_HELD(&tty_token);
624         dc = &sc[port];
625
626         tp = ((DEV)dc->dev)->si_tty;
627
628         if (tp->t_state & TS_ISOPEN) {
629                 kprintf("dcons: still opened\n");
630 #if __FreeBSD_version < 502113
631                 (*linesw[tp->t_line].l_close)(tp, 0);
632                 ttyclose(tp);
633 #else
634                 ttyld_close(tp, 0);
635                 tty_close(tp);
636 #endif
637         }
638         /* XXX
639          * must wait until all device are closed.
640          */
641 #ifdef __DragonFly__
642         tsleep((void *)dc, 0, "dcodtc", hz/4);
643 #else
644         tsleep((void *)dc, PWAIT, "dcodtc", hz/4);
645 #endif
646         destroy_dev(dc->dev);
647
648         return(0);
649 }
650
651
652 /* cnXXX works only for FreeBSD-5 */
653 static int
654 dcons_modevent(module_t mode, int type, void *data)
655 {
656         int err = 0, ret;
657
658         lwkt_gettoken(&tty_token);
659         switch (type) {
660         case MOD_LOAD:
661                 ret = dcons_drv_init(1);
662                 dcons_attach();
663 #if __FreeBSD_version >= 500000
664                 if (ret == 0) {
665                         dcons_cnprobe(&dcons_consdev);
666                         dcons_cninit(&dcons_consdev);
667                         cnadd(&dcons_consdev);
668                 }
669 #endif
670                 break;
671         case MOD_UNLOAD:
672                 kprintf("dcons: unload\n");
673                 callout_stop(&dcons_callout);
674 #if __FreeBSD_version < 502122
675 #if DDB && DCONS_FORCE_GDB
676 #if CONS_NODEV
677                 gdb_arg = NULL;
678 #else
679                 if (gdb_tab == &dcons_consdev)
680                         gdb_tab = NULL;
681 #endif
682 #endif
683 #endif
684 #if __FreeBSD_version >= 500000
685                 cnremove(&dcons_consdev);
686 #endif
687                 dcons_detach(DCONS_CON);
688                 dcons_detach(DCONS_GDB);
689                 dg.buf->magic = 0;
690
691                 contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF);
692
693                 break;
694         case MOD_SHUTDOWN:
695                 dg.buf->magic = 0;
696                 break;
697         default:
698                 err = EOPNOTSUPP;
699                 break;
700         }
701         lwkt_reltoken(&tty_token);
702         return(err);
703 }
704
705 #if __FreeBSD_version >= 502122
706 /* Debugger interface */
707
708 static int
709 dcons_dbg_probe(void)
710 {
711         return(DCONS_FORCE_GDB);
712 }
713
714 static void
715 dcons_dbg_init(void)
716 {
717 }
718
719 static void
720 dcons_dbg_term(void)
721 {
722 }
723
724 static void
725 dcons_dbg_putc(int c)
726 {
727         struct dcons_softc *dc = &sc[DCONS_GDB];
728         dcons_os_putc(dc, c);
729 }
730
731 static int
732 dcons_dbg_checkc(void)
733 {
734         struct dcons_softc *dc = &sc[DCONS_GDB];
735         return (dcons_os_checkc(dc));
736 }
737
738 static int
739 dcons_dbg_getc(void)
740 {
741         struct dcons_softc *dc = &sc[DCONS_GDB];
742         return (dcons_os_getc(dc));
743 }
744 #endif
745
746 DEV_MODULE(dcons, dcons_modevent, NULL);
747 MODULE_VERSION(dcons, DCONS_VERSION);