Commit | Line | Data |
---|---|---|
d8d65eca HS |
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: src/sys/dev/dcons/dcons_os.c,v 1.4 2004/10/24 12:41:04 simokawa Exp $ | |
1f7ab7c9 | 35 | * $DragonFly: src/sys/dev/misc/dcons/dcons_os.c,v 1.7 2006/10/25 20:55:54 dillon Exp $ |
d8d65eca HS |
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> | |
6434890e | 53 | #include <sys/thread2.h> |
d8d65eca | 54 | #include <sys/ucred.h> |
1f7ab7c9 | 55 | #include <sys/bus.h> |
d8d65eca | 56 | |
d8d65eca HS |
57 | #include "dcons.h" |
58 | #include "dcons_os.h" | |
d8d65eca HS |
59 | |
60 | #include <ddb/ddb.h> | |
61 | #include <sys/reboot.h> | |
62 | ||
63 | #include <sys/sysctl.h> | |
64 | ||
65 | #include <vm/vm.h> | |
66 | #include <vm/vm_param.h> | |
67 | #include <vm/pmap.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 | ||
fef8985e MD |
96 | #define CDEV_MAJOR 184 |
97 | ||
d8d65eca HS |
98 | static d_open_t dcons_open; |
99 | static d_close_t dcons_close; | |
d8d65eca | 100 | static d_ioctl_t dcons_ioctl; |
d8d65eca | 101 | |
fef8985e MD |
102 | static struct dev_ops dcons_ops = { |
103 | { "dcons", CDEV_MAJOR, D_TTY }, | |
d8d65eca HS |
104 | .d_open = dcons_open, |
105 | .d_close = dcons_close, | |
fef8985e MD |
106 | .d_read = ttyread, |
107 | .d_write = ttywrite, | |
108 | .d_ioctl = dcons_ioctl, | |
109 | .d_poll = ttypoll, | |
d8d65eca HS |
110 | }; |
111 | ||
112 | #ifndef KLD_MODULE | |
113 | static char bssbuf[DCONS_BUF_SIZE]; /* buf in bss */ | |
114 | #endif | |
115 | ||
116 | /* global data */ | |
117 | static struct dcons_global dg; | |
118 | struct dcons_global *dcons_conf; | |
119 | static int poll_hz = DCONS_POLL_HZ; | |
120 | ||
121 | static struct dcons_softc sc[DCONS_NPORT]; | |
122 | ||
123 | SYSCTL_NODE(_kern, OID_AUTO, dcons, CTLFLAG_RD, 0, "Dumb Console"); | |
124 | SYSCTL_INT(_kern_dcons, OID_AUTO, poll_hz, CTLFLAG_RW, &poll_hz, 0, | |
125 | "dcons polling rate"); | |
126 | ||
127 | static int drv_init = 0; | |
128 | static struct callout dcons_callout; | |
129 | struct dcons_buf *dcons_buf; /* for local dconschat */ | |
130 | ||
131 | #ifdef __DragonFly__ | |
b13267a5 | 132 | #define DEV cdev_t |
d8d65eca HS |
133 | #define THREAD d_thread_t |
134 | #elif __FreeBSD_version < 500000 | |
b13267a5 | 135 | #define DEV cdev_t |
d8d65eca HS |
136 | #define THREAD struct proc |
137 | #else | |
138 | #define DEV struct cdev * | |
139 | #define THREAD struct thread | |
140 | #endif | |
141 | ||
142 | ||
143 | static void dcons_tty_start(struct tty *); | |
144 | static int dcons_tty_param(struct tty *, struct termios *); | |
145 | static void dcons_timeout(void *); | |
146 | static int dcons_drv_init(int); | |
147 | ||
148 | static cn_probe_t dcons_cnprobe; | |
149 | static cn_init_t dcons_cninit; | |
150 | static cn_getc_t dcons_cngetc; | |
151 | static cn_checkc_t dcons_cncheckc; | |
152 | static cn_putc_t dcons_cnputc; | |
153 | ||
154 | CONS_DRIVER(dcons, dcons_cnprobe, dcons_cninit, NULL, dcons_cngetc, | |
155 | dcons_cncheckc, dcons_cnputc, NULL); | |
156 | ||
157 | #if __FreeBSD_version >= 502122 | |
158 | static gdb_probe_f dcons_dbg_probe; | |
159 | static gdb_init_f dcons_dbg_init; | |
160 | static gdb_term_f dcons_dbg_term; | |
161 | static gdb_getc_f dcons_dbg_getc; | |
162 | static gdb_checkc_f dcons_dbg_checkc; | |
163 | static gdb_putc_f dcons_dbg_putc; | |
164 | ||
165 | GDB_DBGPORT(dcons, dcons_dbg_probe, dcons_dbg_init, dcons_dbg_term, | |
166 | dcons_dbg_checkc, dcons_dbg_getc, dcons_dbg_putc); | |
167 | ||
168 | extern struct gdb_dbgport *gdb_cur; | |
169 | #endif | |
170 | ||
171 | #if (KDB || DDB) && ALT_BREAK_TO_DEBUGGER | |
172 | static int | |
173 | dcons_check_break(struct dcons_softc *dc, int c) | |
174 | { | |
175 | if (c < 0) | |
176 | return (c); | |
177 | ||
178 | #if __FreeBSD_version >= 502122 | |
179 | if (kdb_alt_break(c, &dc->brk_state)) { | |
180 | if ((dc->flags & DC_GDB) != 0) { | |
181 | if (gdb_cur == &dcons_gdb_dbgport) { | |
182 | kdb_dbbe_select("gdb"); | |
183 | breakpoint(); | |
184 | } | |
185 | } else | |
186 | breakpoint(); | |
187 | } | |
188 | #else | |
189 | switch (dc->brk_state) { | |
190 | case STATE1: | |
191 | if (c == KEY_TILDE) | |
192 | dc->brk_state = STATE2; | |
193 | else | |
194 | dc->brk_state = STATE0; | |
195 | break; | |
196 | case STATE2: | |
197 | dc->brk_state = STATE0; | |
198 | if (c == KEY_CTRLB) { | |
199 | #if DCONS_FORCE_GDB | |
200 | if (dc->flags & DC_GDB) | |
201 | boothowto |= RB_GDB; | |
202 | #endif | |
203 | breakpoint(); | |
204 | } | |
205 | } | |
206 | if (c == KEY_CR) | |
207 | dc->brk_state = STATE1; | |
208 | #endif | |
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 | if (dg.dma_tag != NULL) | |
221 | bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTREAD); | |
222 | ||
223 | c = dcons_check_break(dc, dcons_checkc(dc)); | |
224 | ||
225 | if (dg.dma_tag != NULL) | |
226 | bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREREAD); | |
227 | ||
228 | return (c); | |
229 | } | |
230 | ||
231 | static int | |
232 | dcons_os_getc(struct dcons_softc *dc) | |
233 | { | |
234 | int c; | |
235 | ||
236 | while ((c = dcons_os_checkc(dc)) == -1); | |
237 | ||
238 | return (c & 0xff); | |
239 | } | |
240 | ||
241 | static void | |
242 | dcons_os_putc(struct dcons_softc *dc, int c) | |
243 | { | |
244 | if (dg.dma_tag != NULL) | |
245 | bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_POSTWRITE); | |
246 | ||
247 | dcons_putc(dc, c); | |
248 | ||
249 | if (dg.dma_tag != NULL) | |
250 | bus_dmamap_sync(dg.dma_tag, dg.dma_map, BUS_DMASYNC_PREWRITE); | |
251 | } | |
252 | static int | |
fef8985e | 253 | dcons_open(struct dev_open_args *ap) |
d8d65eca | 254 | { |
b13267a5 | 255 | cdev_t dev = ap->a_head.a_dev; |
d8d65eca | 256 | struct tty *tp; |
6434890e | 257 | int unit, error; |
d8d65eca HS |
258 | |
259 | unit = minor(dev); | |
260 | if (unit != 0) | |
261 | return (ENXIO); | |
262 | ||
263 | tp = dev->si_tty = ttymalloc(dev->si_tty); | |
264 | tp->t_oproc = dcons_tty_start; | |
265 | tp->t_param = dcons_tty_param; | |
266 | tp->t_stop = nottystop; | |
267 | tp->t_dev = dev; | |
268 | ||
269 | error = 0; | |
270 | ||
6434890e | 271 | crit_enter(); |
d8d65eca HS |
272 | if ((tp->t_state & TS_ISOPEN) == 0) { |
273 | tp->t_state |= TS_CARR_ON; | |
274 | ttychars(tp); | |
275 | tp->t_iflag = TTYDEF_IFLAG; | |
276 | tp->t_oflag = TTYDEF_OFLAG; | |
277 | tp->t_cflag = TTYDEF_CFLAG|CLOCAL; | |
278 | tp->t_lflag = TTYDEF_LFLAG; | |
279 | tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; | |
280 | ttsetwater(tp); | |
fef8985e | 281 | } else if ((tp->t_state & TS_XCLUDE) && suser_cred(ap->a_cred, 0)) { |
6434890e | 282 | crit_exit(); |
d8d65eca HS |
283 | return (EBUSY); |
284 | } | |
6434890e | 285 | crit_exit(); |
d8d65eca HS |
286 | |
287 | #if __FreeBSD_version < 502113 | |
288 | error = (*linesw[tp->t_line].l_open)(dev, tp); | |
289 | #else | |
290 | error = ttyld_open(tp, dev); | |
291 | #endif | |
292 | ||
293 | return (error); | |
294 | } | |
295 | ||
296 | static int | |
fef8985e | 297 | dcons_close(struct dev_close_args *ap) |
d8d65eca | 298 | { |
b13267a5 | 299 | cdev_t dev = ap->a_head.a_dev; |
d8d65eca HS |
300 | int unit; |
301 | struct tty *tp; | |
302 | ||
303 | unit = minor(dev); | |
304 | if (unit != 0) | |
305 | return (ENXIO); | |
306 | ||
307 | tp = dev->si_tty; | |
308 | if (tp->t_state & TS_ISOPEN) { | |
fef8985e | 309 | (*linesw[tp->t_line].l_close)(tp, ap->a_fflag); |
d8d65eca | 310 | ttyclose(tp); |
d8d65eca HS |
311 | } |
312 | ||
313 | return (0); | |
314 | } | |
315 | ||
d8d65eca | 316 | static int |
fef8985e | 317 | dcons_ioctl(struct dev_ioctl_args *ap) |
d8d65eca | 318 | { |
b13267a5 | 319 | cdev_t dev = ap->a_head.a_dev; |
d8d65eca HS |
320 | int unit; |
321 | struct tty *tp; | |
322 | int error; | |
323 | ||
324 | unit = minor(dev); | |
325 | if (unit != 0) | |
326 | return (ENXIO); | |
327 | ||
328 | tp = dev->si_tty; | |
fef8985e | 329 | error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data, ap->a_fflag, ap->a_cred); |
d8d65eca HS |
330 | if (error != ENOIOCTL) |
331 | return (error); | |
332 | ||
fef8985e | 333 | error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag); |
d8d65eca HS |
334 | if (error != ENOIOCTL) |
335 | return (error); | |
336 | ||
337 | return (ENOTTY); | |
338 | } | |
d8d65eca HS |
339 | |
340 | static int | |
341 | dcons_tty_param(struct tty *tp, struct termios *t) | |
342 | { | |
343 | tp->t_ispeed = t->c_ispeed; | |
344 | tp->t_ospeed = t->c_ospeed; | |
345 | tp->t_cflag = t->c_cflag; | |
346 | return 0; | |
347 | } | |
348 | ||
349 | static void | |
350 | dcons_tty_start(struct tty *tp) | |
351 | { | |
352 | struct dcons_softc *dc; | |
d8d65eca HS |
353 | |
354 | dc = (struct dcons_softc *)tp->t_dev->si_drv1; | |
6434890e | 355 | crit_enter(); |
d8d65eca HS |
356 | if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { |
357 | ttwwakeup(tp); | |
358 | return; | |
359 | } | |
360 | ||
361 | tp->t_state |= TS_BUSY; | |
362 | while (tp->t_outq.c_cc != 0) | |
0ced1954 | 363 | dcons_os_putc(dc, clist_getc(&tp->t_outq)); |
d8d65eca HS |
364 | tp->t_state &= ~TS_BUSY; |
365 | ||
366 | ttwwakeup(tp); | |
6434890e | 367 | crit_exit(); |
d8d65eca HS |
368 | } |
369 | ||
370 | static void | |
371 | dcons_timeout(void *v) | |
372 | { | |
373 | struct tty *tp; | |
374 | struct dcons_softc *dc; | |
375 | int i, c, polltime; | |
376 | ||
377 | for (i = 0; i < DCONS_NPORT; i ++) { | |
378 | dc = &sc[i]; | |
379 | tp = ((DEV)dc->dev)->si_tty; | |
380 | while ((c = dcons_os_checkc(dc)) != -1) | |
381 | if (tp->t_state & TS_ISOPEN) | |
382 | #if __FreeBSD_version < 502113 | |
383 | (*linesw[tp->t_line].l_rint)(c, tp); | |
384 | #else | |
385 | ttyld_rint(tp, c); | |
386 | #endif | |
387 | } | |
388 | polltime = hz / poll_hz; | |
389 | if (polltime < 1) | |
390 | polltime = 1; | |
391 | callout_reset(&dcons_callout, polltime, dcons_timeout, tp); | |
392 | } | |
393 | ||
394 | static void | |
395 | dcons_cnprobe(struct consdev *cp) | |
396 | { | |
397 | #ifdef __DragonFly__ | |
fef8985e | 398 | cp->cn_dev = make_dev(&dcons_ops, DCONS_CON, |
d8d65eca HS |
399 | UID_ROOT, GID_WHEEL, 0600, "dcons"); |
400 | #elif __FreeBSD_version >= 501109 | |
401 | sprintf(cp->cn_name, "dcons"); | |
402 | #else | |
403 | cp->cn_dev = makedev(CDEV_MAJOR, DCONS_CON); | |
404 | #endif | |
405 | #if DCONS_FORCE_CONSOLE | |
406 | cp->cn_pri = CN_REMOTE; | |
407 | #else | |
408 | cp->cn_pri = CN_NORMAL; | |
409 | #endif | |
410 | } | |
411 | ||
412 | static void | |
413 | dcons_cninit(struct consdev *cp) | |
414 | { | |
415 | dcons_drv_init(0); | |
416 | #if CONS_NODEV | |
417 | cp->cn_arg | |
418 | #else | |
419 | cp->cn_dev->si_drv1 | |
420 | #endif | |
421 | = (void *)&sc[DCONS_CON]; /* share port0 with unit0 */ | |
422 | } | |
423 | ||
424 | #if CONS_NODEV | |
425 | static int | |
426 | dcons_cngetc(struct consdev *cp) | |
427 | { | |
428 | struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg; | |
429 | return (dcons_os_getc(dc)); | |
430 | } | |
431 | static int | |
432 | dcons_cncheckc(struct consdev *cp) | |
433 | { | |
434 | struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg; | |
435 | return (dcons_os_checkc(dc)); | |
436 | } | |
437 | static void | |
438 | dcons_cnputc(struct consdev *cp, int c) | |
439 | { | |
440 | struct dcons_softc *dc = (struct dcons_softc *)cp->cn_arg; | |
441 | dcons_os_putc(dc, c); | |
442 | } | |
443 | #else | |
444 | static int | |
445 | dcons_cngetc(DEV dev) | |
446 | { | |
447 | struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1; | |
448 | return (dcons_os_getc(dc)); | |
449 | } | |
450 | static int | |
451 | dcons_cncheckc(DEV dev) | |
452 | { | |
453 | struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1; | |
454 | return (dcons_os_checkc(dc)); | |
455 | } | |
456 | static void | |
457 | dcons_cnputc(DEV dev, int c) | |
458 | { | |
459 | struct dcons_softc *dc = (struct dcons_softc *)dev->si_drv1; | |
460 | dcons_os_putc(dc, c); | |
461 | } | |
462 | #endif | |
463 | ||
464 | static int | |
465 | dcons_drv_init(int stage) | |
466 | { | |
467 | #ifdef __i386__ | |
468 | quad_t addr, size; | |
469 | #endif | |
470 | ||
471 | if (drv_init) | |
472 | return(drv_init); | |
473 | ||
474 | drv_init = -1; | |
475 | ||
476 | bzero(&dg, sizeof(dg)); | |
477 | dcons_conf = &dg; | |
478 | dg.cdev = &dcons_consdev; | |
479 | dg.buf = NULL; | |
480 | dg.size = DCONS_BUF_SIZE; | |
481 | ||
482 | #ifdef __i386__ | |
bc01a404 MD |
483 | if (kgetenv_quad("dcons.addr", &addr) > 0 && |
484 | kgetenv_quad("dcons.size", &size) > 0) { | |
d8d65eca HS |
485 | vm_paddr_t pa; |
486 | /* | |
487 | * Allow read/write access to dcons buffer. | |
488 | */ | |
489 | for (pa = trunc_page(addr); pa < addr + size; pa += PAGE_SIZE) | |
490 | *vtopte(KERNBASE + pa) |= PG_RW; | |
491 | cpu_invltlb(); | |
492 | /* XXX P to V */ | |
493 | dg.buf = (struct dcons_buf *)(vm_offset_t)(KERNBASE + addr); | |
494 | dg.size = size; | |
495 | if (dcons_load_buffer(dg.buf, dg.size, sc) < 0) | |
496 | dg.buf = NULL; | |
497 | } | |
498 | #endif | |
499 | if (dg.buf != NULL) | |
500 | goto ok; | |
501 | ||
502 | #ifndef KLD_MODULE | |
503 | if (stage == 0) { /* XXX or cold */ | |
504 | /* | |
505 | * DCONS_FORCE_CONSOLE == 1 and statically linked. | |
506 | * called from cninit(). can't use contigmalloc yet . | |
507 | */ | |
508 | dg.buf = (struct dcons_buf *) bssbuf; | |
509 | dcons_init(dg.buf, dg.size, sc); | |
510 | } else | |
511 | #endif | |
512 | { | |
513 | /* | |
514 | * DCONS_FORCE_CONSOLE == 0 or kernel module case. | |
515 | * if the module is loaded after boot, | |
516 | * bssbuf could be non-continuous. | |
517 | */ | |
518 | dg.buf = (struct dcons_buf *) contigmalloc(dg.size, | |
519 | M_DEVBUF, 0, 0x10000, 0xffffffff, PAGE_SIZE, 0ul); | |
520 | dcons_init(dg.buf, dg.size, sc); | |
521 | } | |
522 | ||
523 | ok: | |
524 | dcons_buf = dg.buf; | |
525 | ||
526 | #if __FreeBSD_version < 502122 | |
527 | #if DDB && DCONS_FORCE_GDB | |
528 | #if CONS_NODEV | |
529 | gdbconsdev.cn_arg = (void *)&sc[DCONS_GDB]; | |
530 | #if __FreeBSD_version >= 501109 | |
531 | sprintf(gdbconsdev.cn_name, "dgdb"); | |
532 | #endif | |
533 | gdb_arg = &gdbconsdev; | |
534 | #elif defined(__DragonFly__) | |
fef8985e | 535 | gdbdev = make_dev(&dcons_ops, DCONS_GDB, |
d8d65eca HS |
536 | UID_ROOT, GID_WHEEL, 0600, "dgdb"); |
537 | #else | |
538 | gdbdev = makedev(CDEV_MAJOR, DCONS_GDB); | |
539 | #endif | |
540 | gdb_getc = dcons_cngetc; | |
541 | gdb_putc = dcons_cnputc; | |
542 | #endif | |
543 | #endif | |
544 | drv_init = 1; | |
545 | ||
546 | return 0; | |
547 | } | |
548 | ||
549 | ||
550 | static int | |
551 | dcons_attach_port(int port, char *name, int flags) | |
552 | { | |
553 | struct dcons_softc *dc; | |
554 | struct tty *tp; | |
555 | DEV dev; | |
556 | ||
557 | dc = &sc[port]; | |
558 | dc->flags = flags; | |
fef8985e | 559 | dev = make_dev(&dcons_ops, port, |
d8d65eca HS |
560 | UID_ROOT, GID_WHEEL, 0600, name); |
561 | dc->dev = (void *)dev; | |
562 | tp = ttymalloc(NULL); | |
563 | ||
564 | dev->si_drv1 = (void *)dc; | |
565 | dev->si_tty = tp; | |
566 | ||
567 | tp->t_oproc = dcons_tty_start; | |
568 | tp->t_param = dcons_tty_param; | |
569 | tp->t_stop = nottystop; | |
570 | tp->t_dev = dc->dev; | |
571 | ||
572 | return(0); | |
573 | } | |
574 | ||
575 | static int | |
576 | dcons_attach(void) | |
577 | { | |
578 | int polltime; | |
579 | ||
580 | #ifdef __DragonFly__ | |
fef8985e | 581 | dev_ops_add(&dcons_ops, -1, 0); |
d8d65eca HS |
582 | #endif |
583 | dcons_attach_port(DCONS_CON, "dcons", 0); | |
584 | dcons_attach_port(DCONS_GDB, "dgdb", DC_GDB); | |
585 | #if __FreeBSD_version < 500000 | |
586 | callout_init(&dcons_callout); | |
587 | #else | |
588 | callout_init(&dcons_callout, 0); | |
589 | #endif | |
590 | polltime = hz / poll_hz; | |
591 | if (polltime < 1) | |
592 | polltime = 1; | |
593 | callout_reset(&dcons_callout, polltime, dcons_timeout, NULL); | |
594 | return(0); | |
595 | } | |
596 | ||
597 | static int | |
598 | dcons_detach(int port) | |
599 | { | |
600 | struct tty *tp; | |
601 | struct dcons_softc *dc; | |
602 | ||
603 | dc = &sc[port]; | |
604 | ||
605 | tp = ((DEV)dc->dev)->si_tty; | |
606 | ||
607 | if (tp->t_state & TS_ISOPEN) { | |
608 | printf("dcons: still opened\n"); | |
609 | #if __FreeBSD_version < 502113 | |
610 | (*linesw[tp->t_line].l_close)(tp, 0); | |
611 | tp->t_gen++; | |
612 | ttyclose(tp); | |
613 | ttwakeup(tp); | |
614 | ttwwakeup(tp); | |
615 | #else | |
616 | ttyld_close(tp, 0); | |
617 | tty_close(tp); | |
618 | #endif | |
619 | } | |
620 | /* XXX | |
621 | * must wait until all device are closed. | |
622 | */ | |
623 | #ifdef __DragonFly__ | |
624 | tsleep((void *)dc, 0, "dcodtc", hz/4); | |
625 | #else | |
626 | tsleep((void *)dc, PWAIT, "dcodtc", hz/4); | |
627 | #endif | |
628 | destroy_dev(dc->dev); | |
629 | ||
630 | return(0); | |
631 | } | |
632 | ||
633 | ||
634 | /* cnXXX works only for FreeBSD-5 */ | |
635 | static int | |
636 | dcons_modevent(module_t mode, int type, void *data) | |
637 | { | |
638 | int err = 0, ret; | |
639 | ||
640 | switch (type) { | |
641 | case MOD_LOAD: | |
642 | ret = dcons_drv_init(1); | |
643 | dcons_attach(); | |
644 | #if __FreeBSD_version >= 500000 | |
645 | if (ret == 0) { | |
646 | dcons_cnprobe(&dcons_consdev); | |
647 | dcons_cninit(&dcons_consdev); | |
648 | cnadd(&dcons_consdev); | |
649 | } | |
650 | #endif | |
651 | break; | |
652 | case MOD_UNLOAD: | |
653 | printf("dcons: unload\n"); | |
654 | callout_stop(&dcons_callout); | |
655 | #if __FreeBSD_version < 502122 | |
656 | #if DDB && DCONS_FORCE_GDB | |
657 | #if CONS_NODEV | |
658 | gdb_arg = NULL; | |
659 | #else | |
660 | gdbdev = NULL; | |
661 | #endif | |
662 | #endif | |
663 | #endif | |
664 | #if __FreeBSD_version >= 500000 | |
665 | cnremove(&dcons_consdev); | |
666 | #endif | |
667 | dcons_detach(DCONS_CON); | |
668 | dcons_detach(DCONS_GDB); | |
669 | dg.buf->magic = 0; | |
670 | ||
671 | contigfree(dg.buf, DCONS_BUF_SIZE, M_DEVBUF); | |
672 | ||
673 | break; | |
674 | case MOD_SHUTDOWN: | |
675 | dg.buf->magic = 0; | |
676 | break; | |
677 | default: | |
678 | err = EOPNOTSUPP; | |
679 | break; | |
680 | } | |
681 | return(err); | |
682 | } | |
683 | ||
684 | #if __FreeBSD_version >= 502122 | |
685 | /* Debugger interface */ | |
686 | ||
687 | static int | |
688 | dcons_dbg_probe(void) | |
689 | { | |
690 | return(DCONS_FORCE_GDB); | |
691 | } | |
692 | ||
693 | static void | |
694 | dcons_dbg_init(void) | |
695 | { | |
696 | } | |
697 | ||
698 | static void | |
699 | dcons_dbg_term(void) | |
700 | { | |
701 | } | |
702 | ||
703 | static void | |
704 | dcons_dbg_putc(int c) | |
705 | { | |
706 | struct dcons_softc *dc = &sc[DCONS_GDB]; | |
707 | dcons_os_putc(dc, c); | |
708 | } | |
709 | ||
710 | static int | |
711 | dcons_dbg_checkc(void) | |
712 | { | |
713 | struct dcons_softc *dc = &sc[DCONS_GDB]; | |
714 | return (dcons_os_checkc(dc)); | |
715 | } | |
716 | ||
717 | static int | |
718 | dcons_dbg_getc(void) | |
719 | { | |
720 | struct dcons_softc *dc = &sc[DCONS_GDB]; | |
721 | return (dcons_os_getc(dc)); | |
722 | } | |
723 | #endif | |
724 | ||
725 | DEV_MODULE(dcons, dcons_modevent, NULL); | |
726 | MODULE_VERSION(dcons, DCONS_VERSION); |