Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / arc / dev / pccons.c
blob536a156c59a32d81cc00fd1fb1c692fe48a931f1
1 /* $NetBSD: pccons.c,v 1.56 2008/09/13 17:13:57 tsutsui Exp $ */
2 /* $OpenBSD: pccons.c,v 1.22 1999/01/30 22:39:37 imp Exp $ */
3 /* NetBSD: pccons.c,v 1.89 1995/05/04 19:35:20 cgd Exp */
5 /*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz and Don Ahn.
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
35 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
38 /*-
39 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
41 * This code is derived from software contributed to Berkeley by
42 * William Jolitz and Don Ahn.
44 * Copyright (c) 1994 Charles M. Hannum.
45 * Copyright (c) 1992, 1993 Erik Forsberg.
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. All advertising materials mentioning features or use of this software
56 * must display the following acknowledgement:
57 * This product includes software developed by the University of
58 * California, Berkeley and its contributors.
59 * 4. Neither the name of the University nor the names of its contributors
60 * may be used to endorse or promote products derived from this software
61 * without specific prior written permission.
63 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 * SUCH DAMAGE.
75 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
79 * code to work keyboard & display for PC-style console
82 #include <sys/cdefs.h>
83 __KERNEL_RCSID(0, "$NetBSD: pccons.c,v 1.56 2008/09/13 17:13:57 tsutsui Exp $");
85 #include "opt_ddb.h"
87 #include <sys/param.h>
88 #include <sys/systm.h>
89 #include <sys/tty.h>
90 #include <sys/callout.h>
91 #include <sys/poll.h>
92 #include <sys/conf.h>
93 #include <sys/vnode.h>
94 #include <sys/kernel.h>
95 #include <sys/kcore.h>
96 #include <sys/device.h>
97 #include <sys/proc.h>
98 #include <sys/kauth.h>
100 #include <machine/bus.h>
102 #include <dev/ic/pcdisplay.h>
103 #include <machine/pccons.h>
104 #include <machine/kbdreg.h>
106 #include <dev/cons.h>
107 #include <dev/isa/isavar.h>
109 #include <arc/arc/arcbios.h>
110 #include <arc/dev/pcconsvar.h>
112 #include "ioconf.h"
114 #define XFREE86_BUG_COMPAT
116 #ifndef BEEP_FREQ
117 #define BEEP_FREQ 1600
118 #endif
119 #ifndef BEEP_TIME
120 #define BEEP_TIME (hz/5)
121 #endif
123 #define PCBURST 128
125 static u_short *Crtat; /* pointer to backing store */
126 static u_short *crtat; /* pointer to current char */
127 static u_char async, kernel, polling; /* Really, you don't want to know. */
128 static u_char lock_state = 0x00, /* all off */
129 old_lock_state = 0xff,
130 typematic_rate = 0xff, /* don't update until set by user */
131 old_typematic_rate = 0xff;
132 static u_short cursor_shape = 0xffff, /* don't update until set by user */
133 old_cursor_shape = 0xffff;
134 static pccons_keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */
135 int pc_xmode = 0;
138 * Keyboard output queue.
140 int kb_oq_put = 0;
141 int kb_oq_get = 0;
142 u_char kb_oq[8];
144 #define PCUNIT(x) (minor(x))
146 static struct video_state {
147 int cx, cy; /* escape parameters */
148 int row, col; /* current cursor position */
149 int nrow, ncol, nchr; /* current screen geometry */
150 int offset; /* Saved cursor pos */
151 u_char state; /* parser state */
152 #define VSS_ESCAPE 1
153 #define VSS_EBRACE 2
154 #define VSS_EPARAM 3
155 char so; /* in standout mode? */
156 char color; /* color or mono display */
157 char at; /* normal attributes */
158 char so_at; /* standout attributes */
159 } vs;
161 static callout_t async_update_ch;
163 void pc_xmode_on(void);
164 void pc_xmode_off(void);
165 static u_char kbc_get8042cmd(void);
166 int kbd_cmd(u_char, u_char);
167 static inline int kbd_wait_output(void);
168 static inline int kbd_wait_input(void);
169 void kbd_flush_input(void);
170 void set_cursor_shape(void);
171 void get_cursor_shape(void);
172 void async_update(void);
173 void do_async_update(u_char);
175 void pccnputc(dev_t, int c);
176 int pccngetc(dev_t);
177 void pccnpollc(dev_t, int);
179 dev_type_open(pcopen);
180 dev_type_close(pcclose);
181 dev_type_read(pcread);
182 dev_type_write(pcwrite);
183 dev_type_ioctl(pcioctl);
184 dev_type_tty(pctty);
185 dev_type_poll(pcpoll);
186 dev_type_mmap(pcmmap);
188 const struct cdevsw pc_cdevsw = {
189 pcopen, pcclose, pcread, pcwrite, pcioctl,
190 nostop, pctty, pcpoll, pcmmap, ttykqfilter, D_TTY
193 #define CHR 2
195 char *sget(void);
196 void sput(const u_char *, int);
198 void pcstart(struct tty *);
199 int pcparam(struct tty *, struct termios *);
200 static inline void wcopy(void *, void *, u_int);
201 void pc_context_init(bus_space_tag_t, bus_space_tag_t, bus_space_tag_t,
202 struct pccons_config *);
204 extern void fillw(int, uint16_t *, int);
206 #define KBD_DELAY \
207 DELAY(10);
209 #define crtc_read_1(reg) \
210 bus_space_read_1(pccons_console_context.pc_crt_iot, \
211 pccons_console_context.pc_6845_ioh, reg)
212 #define crtc_write_1(reg, data) \
213 bus_space_write_1(pccons_console_context.pc_crt_iot, \
214 pccons_console_context.pc_6845_ioh, reg, data)
216 struct pccons_context pccons_console_context;
218 void
219 kbd_context_init(bus_space_tag_t kbd_iot, struct pccons_config *config)
221 struct pccons_kbd_context *pkc = &pccons_console_context.pc_pkc;
223 if (pkc->pkc_initialized)
224 return;
225 pkc->pkc_initialized = 1;
227 pkc->pkc_iot = kbd_iot;
229 bus_space_map(kbd_iot, config->pc_kbd_cmdp, 1, 0,
230 &pkc->pkc_cmd_ioh);
231 bus_space_map(kbd_iot, config->pc_kbd_datap, 1, 0,
232 &pkc->pkc_data_ioh);
235 void
236 pc_context_init(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
237 bus_space_tag_t kbd_iot, struct pccons_config *config)
239 struct pccons_context *pc = &pccons_console_context;
241 if (pc->pc_initialized)
242 return;
243 pc->pc_initialized = 1;
245 kbd_context_init(kbd_iot, config);
247 pc->pc_crt_iot = crt_iot;
248 pc->pc_crt_memt = crt_memt;
250 bus_space_map(crt_iot, config->pc_mono_iobase, 2, 0,
251 &pc->pc_mono_ioh);
252 bus_space_map(crt_memt, config->pc_mono_memaddr, 0x20000, 0,
253 &pc->pc_mono_memh);
254 bus_space_map(crt_iot, config->pc_cga_iobase, 2, 0,
255 &pc->pc_cga_ioh);
256 bus_space_map(crt_memt, config->pc_cga_memaddr, 0x20000, 0,
257 &pc->pc_cga_memh);
260 * pc->pc_6845_ioh and pc->pc_crt_memh will be initialized later,
261 * when `Crtat' is initialized.
264 pc->pc_config = config;
266 (*config->pc_init)();
270 * bcopy variant that only moves word-aligned 16-bit entities,
271 * for stupid VGA cards. cnt is required to be an even value.
273 static inline void
274 wcopy(void *src, void *tgt, u_int cnt)
276 uint16_t *from = src;
277 uint16_t *to = tgt;
279 cnt >>= 1;
280 if (to < from || to >= from + cnt)
281 while (cnt--)
282 *to++ = *from++;
283 else {
284 to += cnt;
285 from += cnt;
286 while (cnt--)
287 *--to = *--from;
291 static inline int
292 kbd_wait_output(void)
294 u_int i;
296 for (i = 100000; i; i--)
297 if ((kbd_cmd_read_1() & KBS_IBF) == 0) {
298 KBD_DELAY;
299 return 1;
301 return 0;
304 static inline int
305 kbd_wait_input(void)
307 u_int i;
309 for (i = 100000; i; i--)
310 if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
311 KBD_DELAY;
312 return 1;
314 return 0;
317 void
318 kbd_flush_input(void)
320 uint8_t c;
322 while ((c = kbd_cmd_read_1()) & 0x03)
323 if ((c & KBS_DIB) == KBS_DIB) {
324 /* XXX - delay is needed to prevent some keyboards from
325 wedging when the system boots */
326 delay(6);
327 (void)kbd_data_read_1();
331 #if 1
333 * Get the current command byte.
335 static u_char
336 kbc_get8042cmd(void)
339 if (!kbd_wait_output())
340 return -1;
341 kbd_cmd_write_1(K_RDCMDBYTE);
342 if (!kbd_wait_input())
343 return -1;
344 return kbd_data_read_1();
346 #endif
349 * Pass command byte to keyboard controller (8042).
352 kbc_put8042cmd(uint8_t val)
355 if (!kbd_wait_output())
356 return 0;
357 kbd_cmd_write_1(K_LDCMDBYTE);
358 if (!kbd_wait_output())
359 return 0;
360 kbd_data_write_1(val);
361 return 1;
365 * Pass command to keyboard itself
368 kbd_cmd(uint8_t val, uint8_t polled)
370 u_int retries = 3;
371 u_int i;
373 if (!polled) {
374 i = spltty();
375 if (kb_oq_get == kb_oq_put) {
376 kbd_data_write_1(val);
378 kb_oq[kb_oq_put] = val;
379 kb_oq_put = (kb_oq_put + 1) & 7;
380 splx(i);
381 return 1;
384 do {
385 if (!kbd_wait_output())
386 return 0;
387 kbd_data_write_1(val);
388 for (i = 100000; i; i--) {
389 if (kbd_cmd_read_1() & KBS_DIB) {
390 uint8_t c;
392 KBD_DELAY;
393 c = kbd_data_read_1();
394 if (c == KBR_ACK || c == KBR_ECHO) {
395 return 1;
397 if (c == KBR_RESEND) {
398 break;
400 #ifdef DIAGNOSTIC
401 printf("kbd_cmd: input char %x lost\n", c);
402 #endif
405 } while (--retries);
406 return 0;
409 void
410 set_cursor_shape(void)
413 crtc_write_1(0, 10);
414 crtc_write_1(1, cursor_shape >> 8);
415 crtc_write_1(0, 11);
416 crtc_write_1(1, cursor_shape);
417 old_cursor_shape = cursor_shape;
420 void
421 get_cursor_shape(void)
424 crtc_write_1(0, 10);
425 cursor_shape = crtc_read_1(1) << 8;
426 crtc_write_1(0, 11);
427 cursor_shape |= crtc_read_1(1);
430 * real 6845's, as found on, MDA, Hercules or CGA cards, do
431 * not support reading the cursor shape registers. the 6845
432 * tri-states it's data bus. This is _normally_ read by the
433 * CPU as either 0x00 or 0xff.. in which case we just use
434 * a line cursor.
436 if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
437 cursor_shape = 0x0b10;
438 else
439 cursor_shape &= 0x1f1f;
442 void
443 do_async_update(uint8_t poll)
445 int pos;
446 static int old_pos = -1;
448 async = 0;
450 if (lock_state != old_lock_state) {
451 old_lock_state = lock_state;
452 if (!kbd_cmd(KBC_MODEIND, poll) ||
453 !kbd_cmd(lock_state, poll)) {
454 printf("pc: timeout updating leds\n");
455 (void) kbd_cmd(KBC_ENABLE, poll);
458 if (typematic_rate != old_typematic_rate) {
459 old_typematic_rate = typematic_rate;
460 if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
461 !kbd_cmd(typematic_rate, poll)) {
462 printf("pc: timeout updating typematic rate\n");
463 (void) kbd_cmd(KBC_ENABLE, poll);
467 if (pc_xmode > 0)
468 return;
470 pos = crtat - Crtat;
471 if (pos != old_pos) {
472 crtc_write_1(0, 14);
473 crtc_write_1(1, pos >> 8);
474 crtc_write_1(0, 15);
475 crtc_write_1(1, pos);
476 old_pos = pos;
478 if (cursor_shape != old_cursor_shape)
479 set_cursor_shape();
482 void
483 async_update(void)
486 if (kernel || polling) {
487 if (async)
488 callout_stop(&async_update_ch);
489 do_async_update(1);
490 } else {
491 if (async)
492 return;
493 async = 1;
494 callout_reset(&async_update_ch, 1,
495 (void(*)(void *))do_async_update, NULL);
500 * these are both bad jokes
503 pccons_common_match(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
504 bus_space_tag_t kbd_iot, struct pccons_config *config)
506 int i;
508 pc_context_init(crt_iot, crt_memt, kbd_iot, config);
510 /* Enable interrupts and keyboard, etc. */
511 if (!kbc_put8042cmd(CMDBYTE)) {
512 printf("pcprobe: command error\n");
513 return 0;
516 #if 1
517 /* Flush any garbage. */
518 kbd_flush_input();
519 /* Reset the keyboard. */
520 if (!kbd_cmd(KBC_RESET, 1)) {
521 printf("pcprobe: reset error %d\n", 1);
522 goto lose;
524 for (i = 600000; i; i--)
525 if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
526 KBD_DELAY;
527 break;
529 if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) {
530 printf("pcprobe: reset error %d\n", 2);
531 goto lose;
534 * Some keyboards seem to leave a second ack byte after the reset.
535 * This is kind of stupid, but we account for them anyway by just
536 * flushing the buffer.
538 kbd_flush_input();
539 /* Just to be sure. */
540 if (!kbd_cmd(KBC_ENABLE, 1)) {
541 printf("pcprobe: reset error %d\n", 3);
542 goto lose;
546 * Some keyboard/8042 combinations do not seem to work if the keyboard
547 * is set to table 1; in fact, it would appear that some keyboards just
548 * ignore the command altogether. So by default, we use the AT scan
549 * codes and have the 8042 translate them. Unfortunately, this is
550 * known to not work on some PS/2 machines. We try desparately to deal
551 * with this by checking the (lack of a) translate bit in the 8042 and
552 * attempting to set the keyboard to XT mode. If this all fails, well,
553 * tough luck.
555 * XXX It would perhaps be a better choice to just use AT scan codes
556 * and not bother with this.
558 if (kbc_get8042cmd() & KC8_TRANS) {
559 /* The 8042 is translating for us; use AT codes. */
560 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
561 printf("pcprobe: reset error %d\n", 4);
562 goto lose;
564 } else {
565 /* Stupid 8042; set keyboard to XT codes. */
566 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
567 printf("pcprobe: reset error %d\n", 5);
568 goto lose;
572 lose:
574 * Technically, we should probably fail the probe. But we'll be nice
575 * and allow keyboard-less machines to boot with the console.
577 #endif
579 return 1;
582 void pccons_common_attach(struct pc_softc *sc, bus_space_tag_t crt_iot,
583 bus_space_tag_t crt_memt, bus_space_tag_t kbd_iot,
584 struct pccons_config *config)
587 printf(": %s\n", vs.color ? "color" : "mono");
588 callout_init(&async_update_ch, 0);
589 do_async_update(1);
593 pcopen(dev_t dev, int flag, int mode, struct lwp *l)
595 struct pc_softc *sc;
596 struct tty *tp;
598 sc = device_lookup_private(&pc_cd, PCUNIT(dev));
599 if (sc == NULL)
600 return ENXIO;
602 if (!sc->sc_tty) {
603 tp = sc->sc_tty = ttymalloc();
605 else {
606 tp = sc->sc_tty;
609 tp->t_oproc = pcstart;
610 tp->t_param = pcparam;
611 tp->t_dev = dev;
613 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
614 return (EBUSY);
616 if ((tp->t_state & TS_ISOPEN) == 0) {
617 ttychars(tp);
618 tp->t_iflag = TTYDEF_IFLAG;
619 tp->t_oflag = TTYDEF_OFLAG;
620 tp->t_cflag = TTYDEF_CFLAG;
621 tp->t_lflag = TTYDEF_LFLAG;
622 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
623 pcparam(tp, &tp->t_termios);
624 ttsetwater(tp);
627 tp->t_state |= TS_CARR_ON;
629 return (*tp->t_linesw->l_open)(dev, tp);
633 pcclose(dev_t dev, int flag, int mode, struct lwp *l)
635 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
636 struct tty *tp = sc->sc_tty;
638 (*tp->t_linesw->l_close)(tp, flag);
639 ttyclose(tp);
640 #ifdef notyet /* XXX */
641 ttyfree(tp);
642 #endif
643 return 0;
647 pcread(dev_t dev, struct uio *uio, int flag)
649 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
650 struct tty *tp = sc->sc_tty;
652 return (*tp->t_linesw->l_read)(tp, uio, flag);
656 pcwrite(dev_t dev, struct uio *uio, int flag)
658 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
659 struct tty *tp = sc->sc_tty;
661 return (*tp->t_linesw->l_write)(tp, uio, flag);
665 pcpoll(dev_t dev, int events, struct lwp *l)
667 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
668 struct tty *tp = sc->sc_tty;
670 return (*tp->t_linesw->l_poll)(tp, events, l);
673 struct tty *
674 pctty(dev_t dev)
676 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
677 struct tty *tp = sc->sc_tty;
679 return tp;
683 * Got a console receive interrupt -
684 * the console processor wants to give us a character.
685 * Catch the character, and see who it goes to.
688 pcintr(void *arg)
690 struct pc_softc *sc = arg;
691 struct tty *tp = sc->sc_tty;
692 uint8_t *cp;
694 if ((kbd_cmd_read_1() & KBS_DIB) == 0)
695 return 0;
696 if (polling)
697 return 1;
698 do {
699 cp = sget();
700 if (!tp || (tp->t_state & TS_ISOPEN) == 0)
701 return 1;
702 if (cp)
704 (*tp->t_linesw->l_rint)(*cp++, tp);
705 while (*cp);
706 } while (kbd_cmd_read_1() & KBS_DIB);
707 return 1;
711 pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
713 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
714 struct tty *tp = sc->sc_tty;
715 int error;
717 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
718 if (error != EPASSTHROUGH)
719 return error;
720 error = ttioctl(tp, cmd, data, flag, l);
721 if (error != EPASSTHROUGH)
722 return error;
724 switch (cmd) {
725 case CONSOLE_X_MODE_ON:
726 pc_xmode_on();
727 return 0;
728 case CONSOLE_X_MODE_OFF:
729 pc_xmode_off();
730 return 0;
731 case CONSOLE_X_BELL:
733 * If set, data is a pointer to a length 2 array of
734 * integers. data[0] is the pitch in Hz and data[1]
735 * is the duration in msec.
737 if (data)
738 sysbeep(((int*)data)[0],
739 (((int*)data)[1] * hz) / 1000);
740 else
741 sysbeep(BEEP_FREQ, BEEP_TIME);
742 return 0;
743 case CONSOLE_SET_TYPEMATIC_RATE: {
744 u_char rate;
746 if (!data)
747 return EINVAL;
748 rate = *((u_char *)data);
750 * Check that it isn't too big (which would cause it to be
751 * confused with a command).
753 if (rate & 0x80)
754 return EINVAL;
755 typematic_rate = rate;
756 async_update();
757 return 0;
759 case CONSOLE_SET_KEYMAP: {
760 pccons_keymap_t *map = (pccons_keymap_t *) data;
761 int i;
763 if (!data)
764 return EINVAL;
765 for (i = 0; i < KB_NUM_KEYS; i++)
766 if (map[i].unshift[KB_CODE_SIZE-1] ||
767 map[i].shift[KB_CODE_SIZE-1] ||
768 map[i].ctl[KB_CODE_SIZE-1] ||
769 map[i].altgr[KB_CODE_SIZE-1] ||
770 map[i].shift_altgr[KB_CODE_SIZE-1])
771 return EINVAL;
773 memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
774 return 0;
776 case CONSOLE_GET_KEYMAP:
777 if (!data)
778 return EINVAL;
779 memcpy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
780 return 0;
782 default:
783 return EPASSTHROUGH;
786 #ifdef DIAGNOSTIC
787 panic("pcioctl: impossible");
788 #endif
791 void
792 pcstart(struct tty *tp)
794 struct clist *cl;
795 int s, len;
796 u_char buf[PCBURST];
798 s = spltty();
799 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
800 goto out;
801 tp->t_state |= TS_BUSY;
802 splx(s);
804 * We need to do this outside spl since it could be fairly
805 * expensive and we don't want our serial ports to overflow.
807 cl = &tp->t_outq;
808 len = q_to_b(cl, buf, PCBURST);
809 sput(buf, len);
810 s = spltty();
811 tp->t_state &= ~TS_BUSY;
812 if (ttypull(tp)) {
813 tp->t_state |= TS_TIMEOUT;
814 callout_schedule(&tp->t_rstrt_ch, 1);
816 out:
817 splx(s);
820 /* ARGSUSED */
821 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
822 bus_space_tag_t kbd_iot, struct pccons_config *config)
824 int maj;
825 static struct consdev pccons = {
826 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
827 NULL, NODEV, CN_NORMAL
831 * For now, don't screw with it.
833 /* crtat = 0; */
835 pc_context_init(crt_iot, crt_memt, kbd_iot, config);
837 /* locate the major number */
838 maj = cdevsw_lookup_major(&pc_cdevsw);
839 pccons.cn_dev = makedev(maj, 0);
841 cn_tab = &pccons;
844 /* ARGSUSED */
845 void
846 pccnputc(dev_t dev, int c)
848 u_char cc, oldkernel = kernel;
850 kernel = 1;
851 if (c == '\n') {
852 sput("\r\n", 2);
853 } else {
854 cc = c;
855 sput(&cc, 1);
857 kernel = oldkernel;
860 /* ARGSUSED */
862 pccngetc(dev_t dev)
864 char *cp;
866 if (pc_xmode > 0)
867 return 0;
869 do {
870 /* wait for byte */
871 while ((kbd_cmd_read_1() & KBS_DIB) == 0);
872 /* see if it's worthwhile */
873 cp = sget();
874 } while (!cp);
875 if (*cp == '\r')
876 return '\n';
877 return *cp;
880 void
881 pccnpollc(dev_t dev, int on)
884 polling = on;
885 if (!on) {
886 int unit;
887 struct pc_softc *sc;
888 int s;
891 * If disabling polling on a device that's been configured,
892 * make sure there are no bytes left in the FIFO, holding up
893 * the interrupt line. Otherwise we won't get any further
894 * interrupts.
896 unit = PCUNIT(dev);
897 if (pc_cd.cd_ndevs > unit) {
898 sc = device_lookup_private(&pc_cd, unit);
899 if (sc != NULL) {
900 s = spltty();
901 pcintr(sc);
902 splx(s);
909 * Set line parameters.
912 pcparam(struct tty *tp, struct termios *t)
915 tp->t_ispeed = t->c_ispeed;
916 tp->t_ospeed = t->c_ospeed;
917 tp->t_cflag = t->c_cflag;
918 return 0;
921 #define wrtchar(c, at) do {\
922 char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
923 } while (0)
925 /* translate ANSI color codes to standard pc ones */
926 static char fgansitopc[] = {
927 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
928 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
931 static char bgansitopc[] = {
932 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
933 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
936 static u_char iso2ibm437[] =
938 0, 0, 0, 0, 0, 0, 0, 0,
939 0, 0, 0, 0, 0, 0, 0, 0,
940 0, 0, 0, 0, 0, 0, 0, 0,
941 0, 0, 0, 0, 0, 0, 0, 0,
942 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
943 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
944 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
945 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
946 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
947 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
948 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
949 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
950 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
951 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
952 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
953 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
957 * `pc3' termcap emulation.
959 void
960 sput(const u_char *cp, int n)
962 struct pccons_context *pc = &pccons_console_context;
963 u_char c, scroll = 0;
965 if (pc_xmode > 0)
966 return;
968 if (crtat == 0) {
969 volatile u_short *dp;
970 u_short was;
971 unsigned cursorat;
973 dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
974 was = *dp;
975 *dp = 0xA55A;
976 if (*dp != 0xA55A) {
977 dp = bus_space_vaddr(pc->pc_crt_memt,
978 pc->pc_mono_memh);
979 pc->pc_6845_ioh = pc->pc_mono_ioh;
980 pc->pc_crt_memh = pc->pc_mono_memh;
981 vs.color = 0;
982 } else {
983 *dp = was;
984 pc->pc_6845_ioh = pc->pc_cga_ioh;
985 pc->pc_crt_memh = pc->pc_cga_memh;
986 vs.color = 1;
989 #ifdef FAT_CURSOR
990 cursor_shape = 0x0012;
991 #else
992 get_cursor_shape();
993 #endif
995 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
996 vs.nchr = vs.ncol * vs.nrow;
997 vs.col--;
998 vs.row--;
999 cursorat = vs.ncol * vs.row + vs.col;
1000 vs.at = FG_LIGHTGREY | BG_BLACK;
1002 Crtat = (u_short *)__UNVOLATILE(dp);
1003 crtat = Crtat + cursorat;
1005 if (vs.color == 0)
1006 vs.so_at = FG_BLACK | BG_LIGHTGREY;
1007 else
1008 vs.so_at = FG_YELLOW | BG_BLACK;
1010 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1013 while (n--) {
1014 if (!(c = *cp++))
1015 continue;
1017 switch (c) {
1018 case 0x1B:
1019 if (vs.state >= VSS_ESCAPE) {
1020 wrtchar(c, vs.so_at);
1021 vs.state = 0;
1022 goto maybe_scroll;
1023 } else
1024 vs.state = VSS_ESCAPE;
1025 break;
1027 case 0x9B: /* CSI */
1028 vs.cx = vs.cy = 0;
1029 vs.state = VSS_EBRACE;
1030 break;
1032 case '\t': {
1033 int inccol = 8 - (vs.col & 7);
1034 crtat += inccol;
1035 vs.col += inccol;
1037 maybe_scroll:
1038 if (vs.col >= vs.ncol) {
1039 vs.col -= vs.ncol;
1040 scroll = 1;
1042 break;
1044 case '\b':
1045 if (crtat <= Crtat)
1046 break;
1047 --crtat;
1048 if (--vs.col < 0)
1049 vs.col += vs.ncol; /* non-destructive backspace */
1050 break;
1052 case '\r':
1053 crtat -= vs.col;
1054 vs.col = 0;
1055 break;
1057 case '\n':
1058 crtat += vs.ncol;
1059 scroll = 1;
1060 break;
1062 default:
1063 switch (vs.state) {
1064 case 0:
1065 if (c == '\a')
1066 sysbeep(BEEP_FREQ, BEEP_TIME);
1067 else {
1069 * If we're outputting multiple printed
1070 * characters, just blast them to the
1071 * screen until we reach the end of the
1072 * buffer or a control character. This
1073 * saves time by short-circuiting the
1074 * switch.
1075 * If we reach the end of the line, we
1076 * break to do a scroll check.
1078 for (;;) {
1079 if (c & 0x80)
1080 c = iso2ibm437[c&0x7f];
1082 if (vs.so)
1083 wrtchar(c, vs.so_at);
1084 else
1085 wrtchar(c, vs.at);
1086 if (vs.col >= vs.ncol) {
1087 vs.col = 0;
1088 scroll = 1;
1089 break;
1091 if (!n || (c = *cp) < ' ')
1092 break;
1093 n--, cp++;
1096 break;
1097 case VSS_ESCAPE:
1098 switch (c) {
1099 case '[': /* Start ESC [ sequence */
1100 vs.cx = vs.cy = 0;
1101 vs.state = VSS_EBRACE;
1102 break;
1103 case 'c': /* Create screen & home */
1104 fillw((vs.at << 8) | ' ',
1105 Crtat, vs.nchr);
1106 crtat = Crtat;
1107 vs.col = 0;
1108 vs.state = 0;
1109 break;
1110 case '7': /* save cursor pos */
1111 vs.offset = crtat - Crtat;
1112 vs.state = 0;
1113 break;
1114 case '8': /* restore cursor pos */
1115 crtat = Crtat + vs.offset;
1116 vs.row = vs.offset / vs.ncol;
1117 vs.col = vs.offset % vs.ncol;
1118 vs.state = 0;
1119 break;
1120 default: /* Invalid, clear state */
1121 wrtchar(c, vs.so_at);
1122 vs.state = 0;
1123 goto maybe_scroll;
1125 break;
1127 default: /* VSS_EBRACE or VSS_EPARAM */
1128 switch (c) {
1129 int pos;
1130 case 'm':
1131 if (!vs.cx)
1132 vs.so = 0;
1133 else
1134 vs.so = 1;
1135 vs.state = 0;
1136 break;
1137 case 'A': { /* back cx rows */
1138 int cx = vs.cx;
1139 if (cx <= 0)
1140 cx = 1;
1141 else
1142 cx %= vs.nrow;
1143 pos = crtat - Crtat;
1144 pos -= vs.ncol * cx;
1145 if (pos < 0)
1146 pos += vs.nchr;
1147 crtat = Crtat + pos;
1148 vs.state = 0;
1149 break;
1151 case 'B': { /* down cx rows */
1152 int cx = vs.cx;
1153 if (cx <= 0)
1154 cx = 1;
1155 else
1156 cx %= vs.nrow;
1157 pos = crtat - Crtat;
1158 pos += vs.ncol * cx;
1159 if (pos >= vs.nchr)
1160 pos -= vs.nchr;
1161 crtat = Crtat + pos;
1162 vs.state = 0;
1163 break;
1165 case 'C': { /* right cursor */
1166 int cx = vs.cx,
1167 col = vs.col;
1168 if (cx <= 0)
1169 cx = 1;
1170 else
1171 cx %= vs.ncol;
1172 pos = crtat - Crtat;
1173 pos += cx;
1174 col += cx;
1175 if (col >= vs.ncol) {
1176 pos -= vs.ncol;
1177 col -= vs.ncol;
1179 vs.col = col;
1180 crtat = Crtat + pos;
1181 vs.state = 0;
1182 break;
1184 case 'D': { /* left cursor */
1185 int cx = vs.cx,
1186 col = vs.col;
1187 if (cx <= 0)
1188 cx = 1;
1189 else
1190 cx %= vs.ncol;
1191 pos = crtat - Crtat;
1192 pos -= cx;
1193 col -= cx;
1194 if (col < 0) {
1195 pos += vs.ncol;
1196 col += vs.ncol;
1198 vs.col = col;
1199 crtat = Crtat + pos;
1200 vs.state = 0;
1201 break;
1203 case 'J': /* Clear ... */
1204 switch (vs.cx) {
1205 case 0:
1206 /* ... to end of display */
1207 fillw((vs.at << 8) | ' ',
1208 crtat,
1209 Crtat + vs.nchr - crtat);
1210 break;
1211 case 1:
1212 /* ... to next location */
1213 fillw((vs.at << 8) | ' ',
1214 Crtat,
1215 crtat - Crtat + 1);
1216 break;
1217 case 2:
1218 /* ... whole display */
1219 fillw((vs.at << 8) | ' ',
1220 Crtat,
1221 vs.nchr);
1222 break;
1224 vs.state = 0;
1225 break;
1226 case 'K': /* Clear line ... */
1227 switch (vs.cx) {
1228 case 0:
1229 /* ... current to EOL */
1230 fillw((vs.at << 8) | ' ',
1231 crtat,
1232 vs.ncol - vs.col);
1233 break;
1234 case 1:
1235 /* ... beginning to next */
1236 fillw((vs.at << 8) | ' ',
1237 crtat - vs.col,
1238 vs.col + 1);
1239 break;
1240 case 2:
1241 /* ... entire line */
1242 fillw((vs.at << 8) | ' ',
1243 crtat - vs.col, vs.ncol);
1244 break;
1246 vs.state = 0;
1247 break;
1248 case 'f': /* in system V consoles */
1249 case 'H': { /* Cursor move */
1250 int cx = vs.cx,
1251 cy = vs.cy;
1252 if (!cx || !cy) {
1253 crtat = Crtat;
1254 vs.col = 0;
1255 } else {
1256 if (cx > vs.nrow)
1257 cx = vs.nrow;
1258 if (cy > vs.ncol)
1259 cy = vs.ncol;
1260 crtat = Crtat +
1261 (cx - 1) * vs.ncol + cy - 1;
1262 vs.col = cy - 1;
1264 vs.state = 0;
1265 break;
1267 case 'M': { /* delete cx rows */
1268 u_short *crtAt = crtat - vs.col;
1269 int cx = vs.cx,
1270 row = (crtAt - Crtat) / vs.ncol,
1271 nrow = vs.nrow - row;
1272 if (cx <= 0)
1273 cx = 1;
1274 else if (cx > nrow)
1275 cx = nrow;
1276 if (cx < nrow)
1277 #ifdef PCCONS_FORCE_WORD
1278 wcopy(crtAt + vs.ncol * cx,
1279 crtAt, vs.ncol * (nrow -
1280 cx) * CHR);
1281 #else
1282 memmove(crtAt,
1283 crtAt + vs.ncol * cx,
1284 vs.ncol * (nrow - cx) *
1285 CHR);
1286 #endif
1287 fillw((vs.at << 8) | ' ',
1288 crtAt + vs.ncol * (nrow - cx),
1289 vs.ncol * cx);
1290 vs.state = 0;
1291 break;
1293 case 'S': { /* scroll up cx lines */
1294 int cx = vs.cx;
1295 if (cx <= 0)
1296 cx = 1;
1297 else if (cx > vs.nrow)
1298 cx = vs.nrow;
1299 if (cx < vs.nrow)
1300 #ifdef PCCONS_FORCE_WORD
1301 wcopy(Crtat + vs.ncol * cx,
1302 Crtat, vs.ncol * (vs.nrow -
1303 cx) * CHR);
1304 #else
1305 memmove(Crtat,
1306 Crtat + vs.ncol * cx,
1307 vs.ncol * (vs.nrow - cx) *
1308 CHR);
1309 #endif
1310 fillw((vs.at << 8) | ' ',
1311 Crtat + vs.ncol * (vs.nrow - cx),
1312 vs.ncol * cx);
1313 /* crtat -= vs.ncol * cx; XXX */
1314 vs.state = 0;
1315 break;
1317 case 'L': { /* insert cx rows */
1318 u_short *crtAt = crtat - vs.col;
1319 int cx = vs.cx,
1320 row = (crtAt - Crtat) / vs.ncol,
1321 nrow = vs.nrow - row;
1322 if (cx <= 0)
1323 cx = 1;
1324 else if (cx > nrow)
1325 cx = nrow;
1326 if (cx < nrow)
1327 #ifdef PCCONS_FORCE_WORD
1328 wcopy(crtAt,
1329 crtAt + vs.ncol * cx,
1330 vs.ncol * (nrow - cx) *
1331 CHR);
1332 #else
1333 memmove(crtAt + vs.ncol * cx,
1334 crtAt,
1335 vs.ncol * (nrow - cx) *
1336 CHR);
1337 #endif
1338 fillw((vs.at << 8) | ' ', crtAt,
1339 vs.ncol * cx);
1340 vs.state = 0;
1341 break;
1343 case 'T': { /* scroll down cx lines */
1344 int cx = vs.cx;
1345 if (cx <= 0)
1346 cx = 1;
1347 else if (cx > vs.nrow)
1348 cx = vs.nrow;
1349 if (cx < vs.nrow)
1350 #ifdef PCCONS_FORCE_WORD
1351 wcopy(Crtat,
1352 Crtat + vs.ncol * cx,
1353 vs.ncol * (vs.nrow - cx) *
1354 CHR);
1355 #else
1356 memmove(Crtat + vs.ncol * cx,
1357 Crtat,
1358 vs.ncol * (vs.nrow - cx) *
1359 CHR);
1360 #endif
1361 fillw((vs.at << 8) | ' ', Crtat,
1362 vs.ncol * cx);
1363 /* crtat += vs.ncol * cx; XXX */
1364 vs.state = 0;
1365 break;
1367 case ';': /* Switch params in cursor def */
1368 vs.state = VSS_EPARAM;
1369 break;
1370 case 'r':
1371 vs.so_at = (vs.cx & FG_MASK) |
1372 ((vs.cy << 4) & BG_MASK);
1373 vs.state = 0;
1374 break;
1375 case 's': /* save cursor pos */
1376 vs.offset = crtat - Crtat;
1377 vs.state = 0;
1378 break;
1379 case 'u': /* restore cursor pos */
1380 crtat = Crtat + vs.offset;
1381 vs.row = vs.offset / vs.ncol;
1382 vs.col = vs.offset % vs.ncol;
1383 vs.state = 0;
1384 break;
1385 case 'x': /* set attributes */
1386 switch (vs.cx) {
1387 case 0:
1388 vs.at = FG_LIGHTGREY | BG_BLACK;
1389 break;
1390 case 1:
1391 /* ansi background */
1392 if (!vs.color)
1393 break;
1394 vs.at &= FG_MASK;
1395 vs.at |= bgansitopc[vs.cy & 7];
1396 break;
1397 case 2:
1398 /* ansi foreground */
1399 if (!vs.color)
1400 break;
1401 vs.at &= BG_MASK;
1402 vs.at |= fgansitopc[vs.cy & 7];
1403 break;
1404 case 3:
1405 /* pc text attribute */
1406 if (vs.state >= VSS_EPARAM)
1407 vs.at = vs.cy;
1408 break;
1410 vs.state = 0;
1411 break;
1413 default: /* Only numbers valid here */
1414 if ((c >= '0') && (c <= '9')) {
1415 if (vs.state >= VSS_EPARAM) {
1416 vs.cy *= 10;
1417 vs.cy += c - '0';
1418 } else {
1419 vs.cx *= 10;
1420 vs.cx += c - '0';
1422 } else
1423 vs.state = 0;
1424 break;
1426 break;
1429 if (scroll) {
1430 scroll = 0;
1431 /* scroll check */
1432 if (crtat >= Crtat + vs.nchr) {
1433 if (!kernel) {
1434 int s = spltty();
1435 if (lock_state & KB_SCROLL)
1436 tsleep(&lock_state,
1437 PUSER, "pcputc", 0);
1438 splx(s);
1440 #if PCCONS_FORCE_WORD
1441 wcopy(Crtat + vs.ncol, Crtat,
1442 (vs.nchr - vs.ncol) * CHR);
1443 #else
1444 memmove(Crtat, Crtat + vs.ncol,
1445 (vs.nchr - vs.ncol) * CHR);
1446 #endif
1447 fillw((vs.at << 8) | ' ',
1448 Crtat + vs.nchr - vs.ncol,
1449 vs.ncol);
1450 crtat -= vs.ncol;
1454 async_update();
1457 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1458 left and right shift when reading the keyboard map */
1459 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = {
1460 /* type unshift shift control altgr shift_altgr scancode */
1461 { KB_NONE, "", "", "", "", ""}, /* 0 unused */
1462 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */
1463 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */
1464 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */
1465 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */
1466 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */
1467 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */
1468 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */
1469 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */
1470 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */
1471 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */
1472 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */
1473 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */
1474 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */
1475 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */
1476 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */
1477 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */
1478 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */
1479 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */
1480 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */
1481 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */
1482 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */
1483 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */
1484 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */
1485 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */
1486 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */
1487 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */
1488 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */
1489 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */
1490 { KB_CTL, "", "", "", "", ""}, /* 29 control */
1491 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */
1492 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */
1493 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */
1494 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */
1495 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */
1496 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */
1497 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */
1498 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */
1499 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */
1500 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */
1501 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */
1502 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */
1503 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */
1504 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */
1505 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */
1506 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */
1507 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */
1508 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */
1509 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */
1510 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */
1511 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */
1512 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */
1513 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */
1514 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */
1515 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */
1516 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */
1517 { KB_ALT, "", "", "", "", ""}, /* 56 alt */
1518 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */
1519 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */
1520 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */
1521 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */
1522 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */
1523 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */
1524 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */
1525 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */
1526 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */
1527 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */
1528 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */
1529 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */
1530 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */
1531 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */
1532 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */
1533 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */
1534 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */
1535 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */
1536 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */
1537 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */
1538 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */
1539 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */
1540 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */
1541 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */
1542 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */
1543 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */
1544 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */
1545 { KB_NONE, "", "", "", "", ""}, /* 84 0 */
1546 { KB_NONE, "", "", "", "", ""}, /* 85 0 */
1547 { KB_NONE, "", "", "", "", ""}, /* 86 0 */
1548 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */
1549 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */
1550 { KB_NONE, "", "", "", "", ""}, /* 89 0 */
1551 { KB_NONE, "", "", "", "", ""}, /* 90 0 */
1552 { KB_NONE, "", "", "", "", ""}, /* 91 0 */
1553 { KB_NONE, "", "", "", "", ""}, /* 92 0 */
1554 { KB_NONE, "", "", "", "", ""}, /* 93 0 */
1555 { KB_NONE, "", "", "", "", ""}, /* 94 0 */
1556 { KB_NONE, "", "", "", "", ""}, /* 95 0 */
1557 { KB_NONE, "", "", "", "", ""}, /* 96 0 */
1558 { KB_NONE, "", "", "", "", ""}, /* 97 0 */
1559 { KB_NONE, "", "", "", "", ""}, /* 98 0 */
1560 { KB_NONE, "", "", "", "", ""}, /* 99 0 */
1561 { KB_NONE, "", "", "", "", ""}, /* 100 */
1562 { KB_NONE, "", "", "", "", ""}, /* 101 */
1563 { KB_NONE, "", "", "", "", ""}, /* 102 */
1564 { KB_NONE, "", "", "", "", ""}, /* 103 */
1565 { KB_NONE, "", "", "", "", ""}, /* 104 */
1566 { KB_NONE, "", "", "", "", ""}, /* 105 */
1567 { KB_NONE, "", "", "", "", ""}, /* 106 */
1568 { KB_NONE, "", "", "", "", ""}, /* 107 */
1569 { KB_NONE, "", "", "", "", ""}, /* 108 */
1570 { KB_NONE, "", "", "", "", ""}, /* 109 */
1571 { KB_NONE, "", "", "", "", ""}, /* 110 */
1572 { KB_NONE, "", "", "", "", ""}, /* 111 */
1573 { KB_NONE, "", "", "", "", ""}, /* 112 */
1574 { KB_NONE, "", "", "", "", ""}, /* 113 */
1575 { KB_NONE, "", "", "", "", ""}, /* 114 */
1576 { KB_NONE, "", "", "", "", ""}, /* 115 */
1577 { KB_NONE, "", "", "", "", ""}, /* 116 */
1578 { KB_NONE, "", "", "", "", ""}, /* 117 */
1579 { KB_NONE, "", "", "", "", ""}, /* 118 */
1580 { KB_NONE, "", "", "", "", ""}, /* 119 */
1581 { KB_NONE, "", "", "", "", ""}, /* 120 */
1582 { KB_NONE, "", "", "", "", ""}, /* 121 */
1583 { KB_NONE, "", "", "", "", ""}, /* 122 */
1584 { KB_NONE, "", "", "", "", ""}, /* 123 */
1585 { KB_NONE, "", "", "", "", ""}, /* 124 */
1586 { KB_NONE, "", "", "", "", ""}, /* 125 */
1587 { KB_NONE, "", "", "", "", ""}, /* 126 */
1588 { KB_NONE, "", "", "", "", ""} /* 127 */
1592 * Get characters from the keyboard. If none are present, return NULL.
1594 char *
1595 sget(void)
1597 u_char dt;
1598 static u_char extended = 0, shift_state = 0;
1599 static u_char capchar[2];
1601 top:
1602 KBD_DELAY;
1603 dt = kbd_data_read_1();
1605 switch (dt) {
1606 case KBR_ACK: case KBR_ECHO:
1607 kb_oq_get = (kb_oq_get + 1) & 7;
1608 if(kb_oq_get != kb_oq_put) {
1609 kbd_data_write_1(kb_oq[kb_oq_get]);
1611 goto loop;
1612 case KBR_RESEND:
1613 kbd_data_write_1(kb_oq[kb_oq_get]);
1614 goto loop;
1617 if (pc_xmode > 0) {
1618 #if defined(DDB) && defined(XSERVER_DDB)
1619 /* F12 enters the debugger while in X mode */
1620 if (dt == 88)
1621 Debugger();
1622 #endif
1623 capchar[0] = dt;
1624 capchar[1] = 0;
1626 * Check for locking keys.
1628 * XXX Setting the LEDs this way is a bit bogus. What if the
1629 * keyboard has been remapped in X?
1631 switch (scan_codes[dt & 0x7f].type) {
1632 case KB_NUM:
1633 if (dt & 0x80) {
1634 shift_state &= ~KB_NUM;
1635 break;
1637 if (shift_state & KB_NUM)
1638 break;
1639 shift_state |= KB_NUM;
1640 lock_state ^= KB_NUM;
1641 async_update();
1642 break;
1643 case KB_CAPS:
1644 if (dt & 0x80) {
1645 shift_state &= ~KB_CAPS;
1646 break;
1648 if (shift_state & KB_CAPS)
1649 break;
1650 shift_state |= KB_CAPS;
1651 lock_state ^= KB_CAPS;
1652 async_update();
1653 break;
1654 case KB_SCROLL:
1655 if (dt & 0x80) {
1656 shift_state &= ~KB_SCROLL;
1657 break;
1659 if (shift_state & KB_SCROLL)
1660 break;
1661 shift_state |= KB_SCROLL;
1662 lock_state ^= KB_SCROLL;
1663 if ((lock_state & KB_SCROLL) == 0)
1664 wakeup((void *)&lock_state);
1665 async_update();
1666 break;
1668 return capchar;
1671 switch (dt) {
1672 case KBR_EXTENDED:
1673 extended = 1;
1674 goto loop;
1677 #ifdef DDB
1679 * Check for cntl-alt-esc.
1681 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1682 /* XXX - check pccons_is_console */
1683 Debugger();
1684 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
1686 #endif
1689 * Check for make/break.
1691 if (dt & 0x80) {
1693 * break
1695 dt &= 0x7f;
1696 switch (scan_codes[dt].type) {
1697 case KB_NUM:
1698 shift_state &= ~KB_NUM;
1699 break;
1700 case KB_CAPS:
1701 shift_state &= ~KB_CAPS;
1702 break;
1703 case KB_SCROLL:
1704 shift_state &= ~KB_SCROLL;
1705 break;
1706 case KB_SHIFT:
1707 shift_state &= ~KB_SHIFT;
1708 break;
1709 case KB_ALT:
1710 if (extended)
1711 shift_state &= ~KB_ALTGR;
1712 else
1713 shift_state &= ~KB_ALT;
1714 break;
1715 case KB_CTL:
1716 shift_state &= ~KB_CTL;
1717 break;
1719 } else {
1721 * make
1723 switch (scan_codes[dt].type) {
1725 * locking keys
1727 case KB_NUM:
1728 if (shift_state & KB_NUM)
1729 break;
1730 shift_state |= KB_NUM;
1731 lock_state ^= KB_NUM;
1732 async_update();
1733 break;
1734 case KB_CAPS:
1735 if (shift_state & KB_CAPS)
1736 break;
1737 shift_state |= KB_CAPS;
1738 lock_state ^= KB_CAPS;
1739 async_update();
1740 break;
1741 case KB_SCROLL:
1742 if (shift_state & KB_SCROLL)
1743 break;
1744 shift_state |= KB_SCROLL;
1745 lock_state ^= KB_SCROLL;
1746 if ((lock_state & KB_SCROLL) == 0)
1747 wakeup((void *)&lock_state);
1748 async_update();
1749 break;
1751 * non-locking keys
1753 case KB_SHIFT:
1754 shift_state |= KB_SHIFT;
1755 break;
1756 case KB_ALT:
1757 if (extended)
1758 shift_state |= KB_ALTGR;
1759 else
1760 shift_state |= KB_ALT;
1761 break;
1762 case KB_CTL:
1763 shift_state |= KB_CTL;
1764 break;
1765 case KB_ASCII:
1766 /* control has highest priority */
1767 if (shift_state & KB_CTL)
1768 capchar[0] = scan_codes[dt].ctl[0];
1769 else if (shift_state & KB_ALTGR) {
1770 if (shift_state & KB_SHIFT)
1771 capchar[0] = scan_codes[dt].shift_altgr[0];
1772 else
1773 capchar[0] = scan_codes[dt].altgr[0];
1775 else {
1776 if (shift_state & KB_SHIFT)
1777 capchar[0] = scan_codes[dt].shift[0];
1778 else
1779 capchar[0] = scan_codes[dt].unshift[0];
1781 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1782 capchar[0] <= 'z') {
1783 capchar[0] -= ('a' - 'A');
1785 capchar[0] |= (shift_state & KB_ALT);
1786 extended = 0;
1787 return capchar;
1788 case KB_NONE:
1789 printf("keycode %d\n",dt);
1790 break;
1791 case KB_FUNC: {
1792 char *more_chars;
1793 if (shift_state & KB_SHIFT)
1794 more_chars = scan_codes[dt].shift;
1795 else if (shift_state & KB_CTL)
1796 more_chars = scan_codes[dt].ctl;
1797 else
1798 more_chars = scan_codes[dt].unshift;
1799 extended = 0;
1800 return more_chars;
1802 case KB_KP: {
1803 char *more_chars;
1804 if (shift_state & (KB_SHIFT | KB_CTL) ||
1805 (lock_state & KB_NUM) == 0 || extended)
1806 more_chars = scan_codes[dt].shift;
1807 else
1808 more_chars = scan_codes[dt].unshift;
1809 extended = 0;
1810 return more_chars;
1815 extended = 0;
1816 loop:
1817 if ((kbd_cmd_read_1() & KBS_DIB) == 0)
1818 return 0;
1819 goto top;
1822 paddr_t
1823 pcmmap(dev_t dev, off_t offset, int nprot)
1825 struct pccons_context *pc = &pccons_console_context;
1826 paddr_t pa;
1828 if (offset >= 0xa0000 && offset < 0xc0000) {
1829 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1830 return -1;
1831 pa += offset - pc->pc_config->pc_mono_memaddr;
1832 return mips_btop(pa);
1834 if (offset >= 0x0000 && offset < 0x10000) {
1835 if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
1836 return -1;
1837 pa += offset - pc->pc_config->pc_mono_iobase;
1838 return mips_btop(pa);
1840 if (offset >= 0x40000000 && offset < 0x40800000) {
1841 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1842 return (-1);
1843 pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
1844 return mips_btop(pa);
1846 return -1;
1849 void
1850 pc_xmode_on(void)
1852 if (pc_xmode)
1853 return;
1854 pc_xmode = 1;
1856 #ifdef XFREE86_BUG_COMPAT
1857 /* If still unchanged, get current shape. */
1858 if (cursor_shape == 0xffff)
1859 get_cursor_shape();
1860 #endif
1863 void
1864 pc_xmode_off(void)
1866 if (pc_xmode == 0)
1867 return;
1868 pc_xmode = 0;
1870 #ifdef XFREE86_BUG_COMPAT
1871 /* XXX It would be hard to justify why the X server doesn't do this. */
1872 set_cursor_shape();
1873 #endif
1874 async_update();