1 /* $NetBSD: kd.c,v 1.47 2007/11/19 18:51:42 ad Exp $ */
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Console driver based on PROM primitives.
35 * This driver exists to provide a tty device that the indirect
36 * console driver can point to. It also provides a hook that
37 * allows another device to serve console input. This will normally
38 * be a keyboard driver (see sys/dev/sun/kbd.c)
41 #include <sys/cdefs.h>
42 __KERNEL_RCSID(0, "$NetBSD: kd.c,v 1.47 2007/11/19 18:51:42 ad Exp $");
47 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/kernel.h>
51 #include <sys/ioctl.h>
55 #include <sys/device.h>
56 #include <sys/kauth.h>
58 #include <machine/bsd_openprom.h>
59 #include <machine/promlib.h>
60 #include <machine/eeprom.h>
61 #include <machine/psl.h>
62 #include <machine/cpu.h>
63 #include <machine/kbd.h>
64 #include <machine/autoconf.h>
66 #if defined(RASTERCONSOLE) && NFB > 0
67 #include <dev/sun/fbio.h>
68 #include <dev/sun/fbvar.h>
72 #include <sparc/dev/cons.h>
74 #include <dev/sun/event_var.h>
75 #include <dev/sun/kbd_xlate.h>
76 #include <dev/sun/kbdvar.h>
81 struct device kd_dev
; /* required first: base device */
85 /* Console input hook */
86 struct cons_channel
*kd_in
;
90 * There is no point in pretending there might be
91 * more than one keyboard/display device.
93 static struct kd_softc kd_softc
;
95 /* For keyboard driver to register itself as console input */
96 void kd_attach_input(struct cons_channel
*);
98 static void kd_init(struct kd_softc
*);
99 static void kdstart(struct tty
*);
100 static void kd_later(void *);
101 static void kd_putfb(struct tty
*);
102 static int kdparam(struct tty
*, struct termios
*);
103 static void kd_cons_input(int);
105 dev_type_open(kdopen
);
106 dev_type_close(kdclose
);
107 dev_type_read(kdread
);
108 dev_type_write(kdwrite
);
109 dev_type_ioctl(kdioctl
);
111 dev_type_poll(kdpoll
);
113 const struct cdevsw kd_cdevsw
= {
114 kdopen
, kdclose
, kdread
, kdwrite
, kdioctl
,
115 nostop
, kdtty
, kdpoll
, nommap
, ttykqfilter
, D_TTY
119 * Prepare the console tty; called on first open of /dev/console
122 kd_init(struct kd_softc
*kd
)
127 callout_setfunc(&tp
->t_rstrt_ch
, kd_later
, tp
);
128 tp
->t_oproc
= kdstart
;
129 tp
->t_param
= kdparam
;
130 tp
->t_dev
= makedev(cdevsw_lookup_major(&kd_cdevsw
), 0);
136 * Get the console struct winsize.
138 #if defined(RASTERCONSOLE) && NFB > 0
139 /* If the raster console driver is attached, copy its size */
140 kd
->rows
= fbrcons_rows();
141 kd
->cols
= fbrcons_cols();
145 /* else, consult the PROM */
146 switch (prom_version()) {
147 char prop
[6+1]; /* Enough for six digits */
150 if ((ep
= (struct eeprom
*)eeprom_va
) == NULL
)
153 kd
->rows
= (u_short
)ep
->eeTtyRows
;
155 kd
->cols
= (u_short
)ep
->eeTtyCols
;
163 prom_getoption("screen-#rows", prop
, sizeof prop
) == 0)
164 kd
->rows
= strtoul(prop
, NULL
, 10);
167 prom_getoption("screen-#columns", prop
, sizeof prop
) == 0)
168 kd
->cols
= strtoul(prop
, NULL
, 10);
181 kd
= &kd_softc
; /* XXX */
186 kdopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
191 static int firstopen
= 1;
197 kd
= &kd_softc
; /* XXX */
205 /* It's simpler to do this up here. */
206 if (kauth_authorize_device_tty(l
->l_cred
, KAUTH_DEVICE_TTY_OPEN
, tp
))
210 if ((tp
->t_state
& TS_ISOPEN
) == 0) {
213 /* Notify the input device that serves us */
214 struct cons_channel
*cc
= kd
->kd_in
;
216 (error
= (*cc
->cc_iopen
)(cc
)) != 0) {
221 tp
->t_iflag
= TTYDEF_IFLAG
;
222 tp
->t_oflag
= TTYDEF_OFLAG
;
223 tp
->t_cflag
= TTYDEF_CFLAG
;
224 tp
->t_lflag
= TTYDEF_LFLAG
;
225 tp
->t_ispeed
= tp
->t_ospeed
= TTYDEF_SPEED
;
226 (void) kdparam(tp
, &tp
->t_termios
);
228 tp
->t_winsize
.ws_row
= kd
->rows
;
229 tp
->t_winsize
.ws_col
= kd
->cols
;
230 /* Flush pending input? Clear translator? */
231 /* This (pseudo)device always has SOFTCAR */
232 tp
->t_state
|= TS_CARR_ON
;
237 return ((*tp
->t_linesw
->l_open
)(dev
, tp
));
241 kdclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
245 struct cons_channel
*cc
;
247 kd
= &kd_softc
; /* XXX */
250 /* XXX This is for cons.c. */
251 if ((tp
->t_state
& TS_ISOPEN
) == 0)
254 (*tp
->t_linesw
->l_close
)(tp
, flag
);
257 if ((cc
= kd
->kd_in
) != NULL
)
258 (void)(*cc
->cc_iclose
)(cc
);
264 kdread(dev_t dev
, struct uio
*uio
, int flag
)
269 kd
= &kd_softc
; /* XXX */
272 return ((*tp
->t_linesw
->l_read
)(tp
, uio
, flag
));
276 kdwrite(dev_t dev
, struct uio
*uio
, int flag
)
281 kd
= &kd_softc
; /* XXX */
284 return ((*tp
->t_linesw
->l_write
)(tp
, uio
, flag
));
288 kdpoll(dev_t dev
, int events
, struct lwp
*l
)
293 kd
= &kd_softc
; /* XXX */
296 return ((*tp
->t_linesw
->l_poll
)(tp
, events
, l
));
300 kdioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
306 kd
= &kd_softc
; /* XXX */
309 error
= (*tp
->t_linesw
->l_ioctl
)(tp
, cmd
, data
, flag
, l
);
310 if (error
!= EPASSTHROUGH
)
313 error
= ttioctl(tp
, cmd
, data
, flag
, l
);
314 if (error
!= EPASSTHROUGH
)
317 /* Handle any ioctl commands specific to kbd/display. */
318 /* XXX - Send KB* ioctls to kbd module? */
319 /* XXX - Send FB* ioctls to fb module? */
325 kdparam(struct tty
*tp
, struct termios
*t
)
328 /* XXX - These are ignored... */
329 tp
->t_ispeed
= t
->c_ispeed
;
330 tp
->t_ospeed
= t
->c_ospeed
;
331 tp
->t_cflag
= t
->c_cflag
;
336 kdstart(struct tty
*tp
)
343 if (tp
->t_state
& (TS_BUSY
|TS_TTSTOP
|TS_TIMEOUT
))
348 tp
->t_state
|= TS_BUSY
;
349 if ((s1
& PSR_PIL
) == 0) {
350 /* called at level zero - update screen now. */
354 tp
->t_state
&= ~TS_BUSY
;
356 /* called at interrupt level - do it later */
357 callout_schedule(&tp
->t_rstrt_ch
, 0);
366 * Timeout function to do delayed writes to the screen.
367 * Called at splsoftclock when requested by kdstart.
372 struct tty
*tp
= arg
;
378 tp
->t_state
&= ~TS_BUSY
;
379 (*tp
->t_linesw
->l_start
)(tp
);
384 * Put text on the screen using the PROM monitor.
385 * This can take a while, so to avoid missing
386 * interrupts, this is called at splsoftclock.
389 kd_putfb(struct tty
*tp
)
392 struct clist
*cl
= &tp
->t_outq
;
396 while ((len
= q_to_b(cl
, buf
, PUT_WSIZE
-1)) > 0) {
397 /* PROM will barf if high bits are set. */
403 /* Now let the PROM print it. */
404 prom_putstr(buf
, len
);
409 * Our "interrupt" routine for input. This is called by
410 * the keyboard driver (dev/sun/kbd.c) at spltty.
415 struct kd_softc
*kd
= &kd_softc
;
418 /* XXX: Make sure the device is open. */
422 if ((tp
->t_state
& TS_ISOPEN
) == 0)
425 (*tp
->t_linesw
->l_rint
)(c
, tp
);
429 cons_attach_input(struct cons_channel
*cc
, struct consdev
*cn
)
431 struct kd_softc
*kd
= &kd_softc
;
434 cc
->cc_upstream
= kd_cons_input
;
438 kd_attach_input(struct cons_channel
*cc
)
440 struct kd_softc
*kd
= &kd_softc
;
443 cc
->cc_upstream
= kd_cons_input
;
447 * Default PROM-based console input stream
448 * Since the PROM does not notify us when data is available on the
449 * input channel these functions periodically poll the PROM.
451 static int kd_rom_iopen(struct cons_channel
*);
452 static int kd_rom_iclose(struct cons_channel
*);
453 static void kd_rom_intr(void *);
455 static struct cons_channel prom_cons_channel
= {
456 NULL
, /* no private data */
459 NULL
/* will be set by kd driver */
462 static struct callout prom_cons_callout
;
465 kd_rom_iopen(struct cons_channel
*cc
)
470 callout_init(&prom_cons_callout
, 0);
474 /* Poll for ROM input 4 times per second */
475 callout_reset(&prom_cons_callout
, hz
/ 4, kd_rom_intr
, cc
);
480 kd_rom_iclose(struct cons_channel
*cc
)
483 callout_stop(&prom_cons_callout
);
488 * "Interrupt" routine for input through ROM vectors
491 kd_rom_intr(void *arg
)
493 struct cons_channel
*cc
= arg
;
496 callout_schedule(&prom_cons_callout
, hz
/ 4);
500 while ((c
= prom_peekchar()) >= 0)
501 (*cc
->cc_upstream
)(c
);
506 /*****************************************************************/
509 int prom_stdout_node
;
510 char prom_stdin_args
[16];
511 char prom_stdout_args
[16];
513 static void prom_cnprobe(struct consdev
*);
514 static void prom_cninit(struct consdev
*);
515 int prom_cngetc(dev_t
); /* XXX: for sunkbd_wskbd_cngetc */
516 static void prom_cnputc(dev_t
, int);
517 static void prom_cnpollc(dev_t
, int);
520 * The console is set to this one initially,
521 * which lets us use the PROM until consinit()
522 * is called to select a real console.
524 struct consdev consdev_prom
= {
534 * The console table pointer is statically initialized
535 * to point to the PROM table, so that early calls to printf will work.
537 struct consdev
*cn_tab
= &consdev_prom
;
540 prom_cnprobe(struct consdev
*cn
)
545 prom_cninit(struct consdev
*cn
)
550 prom_cnpollc(dev_t dev
, int on
)
554 /* Entering debugger. */
559 /* Resuming kernel. */
565 * PROM console input putchar.
568 prom_cngetc(dev_t dev
)
579 * PROM console output putchar.
582 prom_cnputc(dev_t dev
, int c
)
589 /*****************************************************************/
591 static void prom_get_device_args(const char *, char *, unsigned int);
594 prom_get_device_args(const char *prop
, char *args
, unsigned int sz
)
599 cp
= prom_getpropstringA(findroot(), prop
, buffer
, sizeof buffer
);
602 * Extract device-specific arguments from a PROM device path (if any)
604 cp
= buffer
+ strlen(buffer
);
605 while (cp
>= buffer
) {
607 strncpy(args
, cp
+1, sz
);
620 int inSource
, outSink
;
622 switch (prom_version()) {
625 /* The stdio handles identify the device type */
626 inSource
= prom_stdin();
627 outSink
= prom_stdout();
634 /* Save PROM arguments for device matching */
635 prom_get_device_args("stdin-path", prom_stdin_args
,
636 sizeof(prom_stdin_args
));
637 prom_get_device_args("stdout-path", prom_stdout_args
,
638 sizeof(prom_stdout_args
));
641 * Translate the STDIO package instance (`ihandle') -- that
642 * the PROM has already opened for us -- to a device tree
643 * node (i.e. a `phandle').
646 prom_stdin_node
= prom_instance_to_package(prom_stdin());
647 if (prom_stdin_node
== 0)
648 printf("consinit: cannot convert stdin ihandle\n");
650 prom_stdout_node
= prom_instance_to_package(prom_stdout());
651 if (prom_stdout_node
== 0) {
652 printf("consinit: cannot convert stdout ihandle\n");
662 /* Wire up /dev/console */
663 cn_tab
->cn_dev
= makedev(cdevsw_lookup_major(&kd_cdevsw
), 0);
664 cn_tab
->cn_pri
= CN_INTERNAL
;
666 /* Set up initial PROM input channel for /dev/console */
667 cons_attach_input(&prom_cons_channel
, cn_tab
);
670 zs_kgdb_init(); /* XXX */