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