pccons.c revision 1.54 1 /* $NetBSD: pccons.c,v 1.54 2008/06/13 08:27:38 cegger 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 */
4
5 /*-
6 * Copyright (c) 1990 The Regents of the University of California.
7 * All rights reserved.
8 *
9 * This code is derived from software contributed to Berkeley by
10 * William Jolitz and Don Ahn.
11 *
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.
22 *
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.
34 *
35 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
36 */
37
38 /*-
39 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
40 *
41 * This code is derived from software contributed to Berkeley by
42 * William Jolitz and Don Ahn.
43 *
44 * Copyright (c) 1994 Charles M. Hannum.
45 * Copyright (c) 1992, 1993 Erik Forsberg.
46 *
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.
62 *
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.
74 *
75 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
76 */
77
78 /*
79 * code to work keyboard & display for PC-style console
80 */
81
82 #include <sys/cdefs.h>
83 __KERNEL_RCSID(0, "$NetBSD: pccons.c,v 1.54 2008/06/13 08:27:38 cegger Exp $");
84
85 #include "opt_ddb.h"
86
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>
99
100 #include <machine/bus.h>
101
102 #include <dev/ic/pcdisplay.h>
103 #include <machine/pccons.h>
104 #include <machine/kbdreg.h>
105
106 #include <dev/cons.h>
107 #include <dev/isa/isavar.h>
108
109 #include <arc/arc/arcbios.h>
110 #include <arc/dev/pcconsvar.h>
111
112 #include "ioconf.h"
113
114 #define XFREE86_BUG_COMPAT
115
116 #ifndef BEEP_FREQ
117 #define BEEP_FREQ 1600
118 #endif
119 #ifndef BEEP_TIME
120 #define BEEP_TIME (hz/5)
121 #endif
122
123 #define PCBURST 128
124
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;
136
137 /*
138 * Keyboard output queue.
139 */
140 int kb_oq_put = 0;
141 int kb_oq_get = 0;
142 u_char kb_oq[8];
143
144 #define PCUNIT(x) (minor(x))
145
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;
160
161 static callout_t async_update_ch;
162
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);
174
175 void pccnputc(dev_t, int c);
176 int pccngetc(dev_t);
177 void pccnpollc(dev_t, int);
178
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);
187
188 const struct cdevsw pc_cdevsw = {
189 pcopen, pcclose, pcread, pcwrite, pcioctl,
190 nostop, pctty, pcpoll, pcmmap, ttykqfilter, D_TTY
191 };
192
193 #define CHR 2
194
195 char *sget(void);
196 void sput(const u_char *, int);
197
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 *);
203
204 extern void fillw(int, uint16_t *, int);
205
206 #define KBD_DELAY \
207 DELAY(10);
208
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)
215
216 struct pccons_context pccons_console_context;
217
218 void
219 kbd_context_init(bus_space_tag_t kbd_iot, struct pccons_config *config)
220 {
221 struct pccons_kbd_context *pkc = &pccons_console_context.pc_pkc;
222
223 if (pkc->pkc_initialized)
224 return;
225 pkc->pkc_initialized = 1;
226
227 pkc->pkc_iot = kbd_iot;
228
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);
233 }
234
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)
238 {
239 struct pccons_context *pc = &pccons_console_context;
240
241 if (pc->pc_initialized)
242 return;
243 pc->pc_initialized = 1;
244
245 kbd_context_init(kbd_iot, config);
246
247 pc->pc_crt_iot = crt_iot;
248 pc->pc_crt_memt = crt_memt;
249
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);
258
259 /*
260 * pc->pc_6845_ioh and pc->pc_crt_memh will be initialized later,
261 * when `Crtat' is initialized.
262 */
263
264 pc->pc_config = config;
265
266 (*config->pc_init)();
267 }
268
269 /*
270 * bcopy variant that only moves word-aligned 16-bit entities,
271 * for stupid VGA cards. cnt is required to be an even vale.
272 */
273 static inline void
274 wcopy(void *src, void *tgt, u_int cnt)
275 {
276 uint16_t *from = src;
277 uint16_t *to = tgt;
278
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;
288 }
289 }
290
291 static inline int
292 kbd_wait_output(void)
293 {
294 u_int i;
295
296 for (i = 100000; i; i--)
297 if ((kbd_cmd_read_1() & KBS_IBF) == 0) {
298 KBD_DELAY;
299 return 1;
300 }
301 return 0;
302 }
303
304 static inline int
305 kbd_wait_input(void)
306 {
307 u_int i;
308
309 for (i = 100000; i; i--)
310 if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
311 KBD_DELAY;
312 return 1;
313 }
314 return 0;
315 }
316
317 void
318 kbd_flush_input(void)
319 {
320 uint8_t c;
321
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();
328 }
329 }
330
331 #if 1
332 /*
333 * Get the current command byte.
334 */
335 static u_char
336 kbc_get8042cmd(void)
337 {
338
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();
345 }
346 #endif
347
348 /*
349 * Pass command byte to keyboard controller (8042).
350 */
351 int
352 kbc_put8042cmd(val)
353 uint8_t val;
354 {
355
356 if (!kbd_wait_output())
357 return 0;
358 kbd_cmd_write_1(K_LDCMDBYTE);
359 if (!kbd_wait_output())
360 return 0;
361 kbd_data_write_1(val);
362 return 1;
363 }
364
365 /*
366 * Pass command to keyboard itself
367 */
368 int
369 kbd_cmd(uint8_t val, uint8_t polled)
370 {
371 u_int retries = 3;
372 u_int i;
373
374 if (!polled) {
375 i = spltty();
376 if (kb_oq_get == kb_oq_put) {
377 kbd_data_write_1(val);
378 }
379 kb_oq[kb_oq_put] = val;
380 kb_oq_put = (kb_oq_put + 1) & 7;
381 splx(i);
382 return 1;
383 }
384
385 do {
386 if (!kbd_wait_output())
387 return 0;
388 kbd_data_write_1(val);
389 for (i = 100000; i; i--) {
390 if (kbd_cmd_read_1() & KBS_DIB) {
391 uint8_t c;
392
393 KBD_DELAY;
394 c = kbd_data_read_1();
395 if (c == KBR_ACK || c == KBR_ECHO) {
396 return 1;
397 }
398 if (c == KBR_RESEND) {
399 break;
400 }
401 #ifdef DIAGNOSTIC
402 printf("kbd_cmd: input char %x lost\n", c);
403 #endif
404 }
405 }
406 } while (--retries);
407 return 0;
408 }
409
410 void
411 set_cursor_shape(void)
412 {
413
414 crtc_write_1(0, 10);
415 crtc_write_1(1, cursor_shape >> 8);
416 crtc_write_1(0, 11);
417 crtc_write_1(1, cursor_shape);
418 old_cursor_shape = cursor_shape;
419 }
420
421 void
422 get_cursor_shape(void)
423 {
424
425 crtc_write_1(0, 10);
426 cursor_shape = crtc_read_1(1) << 8;
427 crtc_write_1(0, 11);
428 cursor_shape |= crtc_read_1(1);
429
430 /*
431 * real 6845's, as found on, MDA, Hercules or CGA cards, do
432 * not support reading the cursor shape registers. the 6845
433 * tri-states it's data bus. This is _normally_ read by the
434 * CPU as either 0x00 or 0xff.. in which case we just use
435 * a line cursor.
436 */
437 if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
438 cursor_shape = 0x0b10;
439 else
440 cursor_shape &= 0x1f1f;
441 }
442
443 void
444 do_async_update(uint8_t poll)
445 {
446 int pos;
447 static int old_pos = -1;
448
449 async = 0;
450
451 if (lock_state != old_lock_state) {
452 old_lock_state = lock_state;
453 if (!kbd_cmd(KBC_MODEIND, poll) ||
454 !kbd_cmd(lock_state, poll)) {
455 printf("pc: timeout updating leds\n");
456 (void) kbd_cmd(KBC_ENABLE, poll);
457 }
458 }
459 if (typematic_rate != old_typematic_rate) {
460 old_typematic_rate = typematic_rate;
461 if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
462 !kbd_cmd(typematic_rate, poll)) {
463 printf("pc: timeout updating typematic rate\n");
464 (void) kbd_cmd(KBC_ENABLE, poll);
465 }
466 }
467
468 if (pc_xmode > 0)
469 return;
470
471 pos = crtat - Crtat;
472 if (pos != old_pos) {
473 crtc_write_1(0, 14);
474 crtc_write_1(1, pos >> 8);
475 crtc_write_1(0, 15);
476 crtc_write_1(1, pos);
477 old_pos = pos;
478 }
479 if (cursor_shape != old_cursor_shape)
480 set_cursor_shape();
481 }
482
483 void
484 async_update(void)
485 {
486
487 if (kernel || polling) {
488 if (async)
489 callout_stop(&async_update_ch);
490 do_async_update(1);
491 } else {
492 if (async)
493 return;
494 async = 1;
495 callout_reset(&async_update_ch, 1,
496 (void(*)(void *))do_async_update, NULL);
497 }
498 }
499
500 /*
501 * these are both bad jokes
502 */
503 int
504 pccons_common_match(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
505 bus_space_tag_t kbd_iot, struct pccons_config *config)
506 {
507 int i;
508
509 pc_context_init(crt_iot, crt_memt, kbd_iot, config);
510
511 /* Enable interrupts and keyboard, etc. */
512 if (!kbc_put8042cmd(CMDBYTE)) {
513 printf("pcprobe: command error\n");
514 return 0;
515 }
516
517 #if 1
518 /* Flush any garbage. */
519 kbd_flush_input();
520 /* Reset the keyboard. */
521 if (!kbd_cmd(KBC_RESET, 1)) {
522 printf("pcprobe: reset error %d\n", 1);
523 goto lose;
524 }
525 for (i = 600000; i; i--)
526 if ((kbd_cmd_read_1() & KBS_DIB) != 0) {
527 KBD_DELAY;
528 break;
529 }
530 if (i == 0 || kbd_data_read_1() != KBR_RSTDONE) {
531 printf("pcprobe: reset error %d\n", 2);
532 goto lose;
533 }
534 /*
535 * Some keyboards seem to leave a second ack byte after the reset.
536 * This is kind of stupid, but we account for them anyway by just
537 * flushing the buffer.
538 */
539 kbd_flush_input();
540 /* Just to be sure. */
541 if (!kbd_cmd(KBC_ENABLE, 1)) {
542 printf("pcprobe: reset error %d\n", 3);
543 goto lose;
544 }
545
546 /*
547 * Some keyboard/8042 combinations do not seem to work if the keyboard
548 * is set to table 1; in fact, it would appear that some keyboards just
549 * ignore the command altogether. So by default, we use the AT scan
550 * codes and have the 8042 translate them. Unfortunately, this is
551 * known to not work on some PS/2 machines. We try desparately to deal
552 * with this by checking the (lack of a) translate bit in the 8042 and
553 * attempting to set the keyboard to XT mode. If this all fails, well,
554 * tough luck.
555 *
556 * XXX It would perhaps be a better choice to just use AT scan codes
557 * and not bother with this.
558 */
559 if (kbc_get8042cmd() & KC8_TRANS) {
560 /* The 8042 is translating for us; use AT codes. */
561 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
562 printf("pcprobe: reset error %d\n", 4);
563 goto lose;
564 }
565 } else {
566 /* Stupid 8042; set keyboard to XT codes. */
567 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
568 printf("pcprobe: reset error %d\n", 5);
569 goto lose;
570 }
571 }
572
573 lose:
574 /*
575 * Technically, we should probably fail the probe. But we'll be nice
576 * and allow keyboard-less machines to boot with the console.
577 */
578 #endif
579
580 return 1;
581 }
582
583 void pccons_common_attach(struct pc_softc *sc, bus_space_tag_t crt_iot,
584 bus_space_tag_t crt_memt, bus_space_tag_t kbd_iot,
585 struct pccons_config *config)
586 {
587
588 printf(": %s\n", vs.color ? "color" : "mono");
589 callout_init(&async_update_ch, 0);
590 do_async_update(1);
591 }
592
593 int
594 pcopen(dev_t dev, int flag, int mode, struct lwp *l)
595 {
596 struct pc_softc *sc;
597 struct tty *tp;
598
599 sc = device_lookup_private(&pc_cd, PCUNIT(dev));
600 if (sc == NULL)
601 return ENXIO;
602
603 if (!sc->sc_tty) {
604 tp = sc->sc_tty = ttymalloc();
605 }
606 else {
607 tp = sc->sc_tty;
608 }
609
610 tp->t_oproc = pcstart;
611 tp->t_param = pcparam;
612 tp->t_dev = dev;
613
614 if (kauth_authorize_device_tty(l->l_cred, KAUTH_DEVICE_TTY_OPEN, tp))
615 return (EBUSY);
616
617 if ((tp->t_state & TS_ISOPEN) == 0) {
618 ttychars(tp);
619 tp->t_iflag = TTYDEF_IFLAG;
620 tp->t_oflag = TTYDEF_OFLAG;
621 tp->t_cflag = TTYDEF_CFLAG;
622 tp->t_lflag = TTYDEF_LFLAG;
623 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
624 pcparam(tp, &tp->t_termios);
625 ttsetwater(tp);
626 }
627
628 tp->t_state |= TS_CARR_ON;
629
630 return (*tp->t_linesw->l_open)(dev, tp);
631 }
632
633 int
634 pcclose(dev_t dev, int flag, int mode, struct lwp *l)
635 {
636 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
637 struct tty *tp = sc->sc_tty;
638
639 (*tp->t_linesw->l_close)(tp, flag);
640 ttyclose(tp);
641 #ifdef notyet /* XXX */
642 ttyfree(tp);
643 #endif
644 return 0;
645 }
646
647 int
648 pcread(dev_t dev, struct uio *uio, int flag)
649 {
650 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
651 struct tty *tp = sc->sc_tty;
652
653 return (*tp->t_linesw->l_read)(tp, uio, flag);
654 }
655
656 int
657 pcwrite(dev_t dev, struct uio *uio, int flag)
658 {
659 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
660 struct tty *tp = sc->sc_tty;
661
662 return (*tp->t_linesw->l_write)(tp, uio, flag);
663 }
664
665 int
666 pcpoll(dev_t dev, int events, struct lwp *l)
667 {
668 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
669 struct tty *tp = sc->sc_tty;
670
671 return (*tp->t_linesw->l_poll)(tp, events, l);
672 }
673
674 struct tty *
675 pctty(dev_t dev)
676 {
677 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
678 struct tty *tp = sc->sc_tty;
679
680 return tp;
681 }
682
683 /*
684 * Got a console receive interrupt -
685 * the console processor wants to give us a character.
686 * Catch the character, and see who it goes to.
687 */
688 int
689 pcintr(void *arg)
690 {
691 struct pc_softc *sc = arg;
692 struct tty *tp = sc->sc_tty;
693 uint8_t *cp;
694
695 if ((kbd_cmd_read_1() & KBS_DIB) == 0)
696 return 0;
697 if (polling)
698 return 1;
699 do {
700 cp = sget();
701 if (!tp || (tp->t_state & TS_ISOPEN) == 0)
702 return 1;
703 if (cp)
704 do
705 (*tp->t_linesw->l_rint)(*cp++, tp);
706 while (*cp);
707 } while (kbd_cmd_read_1() & KBS_DIB);
708 return 1;
709 }
710
711 int
712 pcioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
713 {
714 struct pc_softc *sc = device_lookup_private(&pc_cd, PCUNIT(dev));
715 struct tty *tp = sc->sc_tty;
716 int error;
717
718 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, l);
719 if (error != EPASSTHROUGH)
720 return error;
721 error = ttioctl(tp, cmd, data, flag, l);
722 if (error != EPASSTHROUGH)
723 return error;
724
725 switch (cmd) {
726 case CONSOLE_X_MODE_ON:
727 pc_xmode_on();
728 return 0;
729 case CONSOLE_X_MODE_OFF:
730 pc_xmode_off();
731 return 0;
732 case CONSOLE_X_BELL:
733 /*
734 * If set, data is a pointer to a length 2 array of
735 * integers. data[0] is the pitch in Hz and data[1]
736 * is the duration in msec.
737 */
738 if (data)
739 sysbeep(((int*)data)[0],
740 (((int*)data)[1] * hz) / 1000);
741 else
742 sysbeep(BEEP_FREQ, BEEP_TIME);
743 return 0;
744 case CONSOLE_SET_TYPEMATIC_RATE: {
745 u_char rate;
746
747 if (!data)
748 return EINVAL;
749 rate = *((u_char *)data);
750 /*
751 * Check that it isn't too big (which would cause it to be
752 * confused with a command).
753 */
754 if (rate & 0x80)
755 return EINVAL;
756 typematic_rate = rate;
757 async_update();
758 return 0;
759 }
760 case CONSOLE_SET_KEYMAP: {
761 pccons_keymap_t *map = (pccons_keymap_t *) data;
762 int i;
763
764 if (!data)
765 return EINVAL;
766 for (i = 0; i < KB_NUM_KEYS; i++)
767 if (map[i].unshift[KB_CODE_SIZE-1] ||
768 map[i].shift[KB_CODE_SIZE-1] ||
769 map[i].ctl[KB_CODE_SIZE-1] ||
770 map[i].altgr[KB_CODE_SIZE-1] ||
771 map[i].shift_altgr[KB_CODE_SIZE-1])
772 return EINVAL;
773
774 bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
775 return 0;
776 }
777 case CONSOLE_GET_KEYMAP:
778 if (!data)
779 return EINVAL;
780 bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
781 return 0;
782
783 default:
784 return EPASSTHROUGH;
785 }
786
787 #ifdef DIAGNOSTIC
788 panic("pcioctl: impossible");
789 #endif
790 }
791
792 void
793 pcstart(struct tty *tp)
794 {
795 int s, len;
796 u_char buf[PCBURST];
797
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);
803 /*
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.
806 */
807 len = q_to_b(cl, buf, PCBURST);
808 sput(buf, len);
809 s = spltty();
810 tp->t_state &= ~TS_BUSY;
811 if (ttypull(tp)) {
812 tp->t_state |= TS_TIMEOUT;
813 callout_schedule(&tp->t_rstrt_ch, 1);
814 }
815 out:
816 splx(s);
817 }
818
819 /* ARGSUSED */
820 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
821 bus_space_tag_t kbd_iot, struct pccons_config *config)
822 {
823 int maj;
824 static struct consdev pccons = {
825 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
826 NULL, NODEV, CN_NORMAL
827 };
828
829 /*
830 * For now, don't screw with it.
831 */
832 /* crtat = 0; */
833
834 pc_context_init(crt_iot, crt_memt, kbd_iot, config);
835
836 /* locate the major number */
837 maj = cdevsw_lookup_major(&pc_cdevsw);
838 pccons.cn_dev = makedev(maj, 0);
839
840 cn_tab = &pccons;
841 }
842
843 /* ARGSUSED */
844 void
845 pccnputc(dev_t dev, int c)
846 {
847 u_char cc, oldkernel = kernel;
848
849 kernel = 1;
850 if (c == '\n') {
851 sput("\r\n", 2);
852 } else {
853 cc = c;
854 sput(&cc, 1);
855 }
856 kernel = oldkernel;
857 }
858
859 /* ARGSUSED */
860 int
861 pccngetc(dev_t dev)
862 {
863 char *cp;
864
865 if (pc_xmode > 0)
866 return 0;
867
868 do {
869 /* wait for byte */
870 while ((kbd_cmd_read_1() & KBS_DIB) == 0);
871 /* see if it's worthwhile */
872 cp = sget();
873 } while (!cp);
874 if (*cp == '\r')
875 return '\n';
876 return *cp;
877 }
878
879 void
880 pccnpollc(dev_t dev, int on)
881 {
882
883 polling = on;
884 if (!on) {
885 int unit;
886 struct pc_softc *sc;
887 int s;
888
889 /*
890 * If disabling polling on a device that's been configured,
891 * make sure there are no bytes left in the FIFO, holding up
892 * the interrupt line. Otherwise we won't get any further
893 * interrupts.
894 */
895 unit = PCUNIT(dev);
896 if (pc_cd.cd_ndevs > unit) {
897 sc = device_lookup_private(&pc_cd, unit);
898 if (sc != NULL) {
899 s = spltty();
900 pcintr(sc);
901 splx(s);
902 }
903 }
904 }
905 }
906
907 /*
908 * Set line parameters.
909 */
910 int
911 pcparam(struct tty *tp, struct termios *t)
912 {
913
914 tp->t_ispeed = t->c_ispeed;
915 tp->t_ospeed = t->c_ospeed;
916 tp->t_cflag = t->c_cflag;
917 return 0;
918 }
919
920 #define wrtchar(c, at) do {\
921 char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
922 } while (0)
923
924 /* translate ANSI color codes to standard pc ones */
925 static char fgansitopc[] = {
926 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
927 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
928 };
929
930 static char bgansitopc[] = {
931 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
932 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
933 };
934
935 static u_char iso2ibm437[] =
936 {
937 0, 0, 0, 0, 0, 0, 0, 0,
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 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
942 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
943 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
944 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
945 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
946 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
947 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
948 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
949 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
950 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
951 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
952 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
953 };
954
955 /*
956 * `pc3' termcap emulation.
957 */
958 void
959 sput(const u_char *cp, int n)
960 {
961 struct pccons_context *pc = &pccons_console_context;
962 u_char c, scroll = 0;
963
964 if (pc_xmode > 0)
965 return;
966
967 if (crtat == 0) {
968 volatile u_short *dp;
969 u_short was;
970 unsigned cursorat;
971
972 dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
973 was = *dp;
974 *dp = 0xA55A;
975 if (*dp != 0xA55A) {
976 dp = bus_space_vaddr(pc->pc_crt_memt,
977 pc->pc_mono_memh);
978 pc->pc_6845_ioh = pc->pc_mono_ioh;
979 pc->pc_crt_memh = pc->pc_mono_memh;
980 vs.color = 0;
981 } else {
982 *dp = was;
983 pc->pc_6845_ioh = pc->pc_cga_ioh;
984 pc->pc_crt_memh = pc->pc_cga_memh;
985 vs.color = 1;
986 }
987
988 #ifdef FAT_CURSOR
989 cursor_shape = 0x0012;
990 #else
991 get_cursor_shape();
992 #endif
993
994 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
995 vs.nchr = vs.ncol * vs.nrow;
996 vs.col--;
997 vs.row--;
998 cursorat = vs.ncol * vs.row + vs.col;
999 vs.at = FG_LIGHTGREY | BG_BLACK;
1000
1001 Crtat = (u_short *)__UNVOLATILE(dp);
1002 crtat = Crtat + cursorat;
1003
1004 if (vs.color == 0)
1005 vs.so_at = FG_BLACK | BG_LIGHTGREY;
1006 else
1007 vs.so_at = FG_YELLOW | BG_BLACK;
1008
1009 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1010 }
1011
1012 while (n--) {
1013 if (!(c = *cp++))
1014 continue;
1015
1016 switch (c) {
1017 case 0x1B:
1018 if (vs.state >= VSS_ESCAPE) {
1019 wrtchar(c, vs.so_at);
1020 vs.state = 0;
1021 goto maybe_scroll;
1022 } else
1023 vs.state = VSS_ESCAPE;
1024 break;
1025
1026 case 0x9B: /* CSI */
1027 vs.cx = vs.cy = 0;
1028 vs.state = VSS_EBRACE;
1029 break;
1030
1031 case '\t': {
1032 int inccol = 8 - (vs.col & 7);
1033 crtat += inccol;
1034 vs.col += inccol;
1035 }
1036 maybe_scroll:
1037 if (vs.col >= vs.ncol) {
1038 vs.col -= vs.ncol;
1039 scroll = 1;
1040 }
1041 break;
1042
1043 case '\b':
1044 if (crtat <= Crtat)
1045 break;
1046 --crtat;
1047 if (--vs.col < 0)
1048 vs.col += vs.ncol; /* non-destructive backspace */
1049 break;
1050
1051 case '\r':
1052 crtat -= vs.col;
1053 vs.col = 0;
1054 break;
1055
1056 case '\n':
1057 crtat += vs.ncol;
1058 scroll = 1;
1059 break;
1060
1061 default:
1062 switch (vs.state) {
1063 case 0:
1064 if (c == '\a')
1065 sysbeep(BEEP_FREQ, BEEP_TIME);
1066 else {
1067 /*
1068 * If we're outputting multiple printed
1069 * characters, just blast them to the
1070 * screen until we reach the end of the
1071 * buffer or a control character. This
1072 * saves time by short-circuiting the
1073 * switch.
1074 * If we reach the end of the line, we
1075 * break to do a scroll check.
1076 */
1077 for (;;) {
1078 if (c & 0x80)
1079 c = iso2ibm437[c&0x7f];
1080
1081 if (vs.so)
1082 wrtchar(c, vs.so_at);
1083 else
1084 wrtchar(c, vs.at);
1085 if (vs.col >= vs.ncol) {
1086 vs.col = 0;
1087 scroll = 1;
1088 break;
1089 }
1090 if (!n || (c = *cp) < ' ')
1091 break;
1092 n--, cp++;
1093 }
1094 }
1095 break;
1096 case VSS_ESCAPE:
1097 switch (c) {
1098 case '[': /* Start ESC [ sequence */
1099 vs.cx = vs.cy = 0;
1100 vs.state = VSS_EBRACE;
1101 break;
1102 case 'c': /* Create screen & home */
1103 fillw((vs.at << 8) | ' ',
1104 Crtat, vs.nchr);
1105 crtat = Crtat;
1106 vs.col = 0;
1107 vs.state = 0;
1108 break;
1109 case '7': /* save cursor pos */
1110 vs.offset = crtat - Crtat;
1111 vs.state = 0;
1112 break;
1113 case '8': /* restore cursor pos */
1114 crtat = Crtat + vs.offset;
1115 vs.row = vs.offset / vs.ncol;
1116 vs.col = vs.offset % vs.ncol;
1117 vs.state = 0;
1118 break;
1119 default: /* Invalid, clear state */
1120 wrtchar(c, vs.so_at);
1121 vs.state = 0;
1122 goto maybe_scroll;
1123 }
1124 break;
1125
1126 default: /* VSS_EBRACE or VSS_EPARAM */
1127 switch (c) {
1128 int pos;
1129 case 'm':
1130 if (!vs.cx)
1131 vs.so = 0;
1132 else
1133 vs.so = 1;
1134 vs.state = 0;
1135 break;
1136 case 'A': { /* back cx rows */
1137 int cx = vs.cx;
1138 if (cx <= 0)
1139 cx = 1;
1140 else
1141 cx %= vs.nrow;
1142 pos = crtat - Crtat;
1143 pos -= vs.ncol * cx;
1144 if (pos < 0)
1145 pos += vs.nchr;
1146 crtat = Crtat + pos;
1147 vs.state = 0;
1148 break;
1149 }
1150 case 'B': { /* down cx rows */
1151 int cx = vs.cx;
1152 if (cx <= 0)
1153 cx = 1;
1154 else
1155 cx %= vs.nrow;
1156 pos = crtat - Crtat;
1157 pos += vs.ncol * cx;
1158 if (pos >= vs.nchr)
1159 pos -= vs.nchr;
1160 crtat = Crtat + pos;
1161 vs.state = 0;
1162 break;
1163 }
1164 case 'C': { /* right cursor */
1165 int cx = vs.cx,
1166 col = vs.col;
1167 if (cx <= 0)
1168 cx = 1;
1169 else
1170 cx %= vs.ncol;
1171 pos = crtat - Crtat;
1172 pos += cx;
1173 col += cx;
1174 if (col >= vs.ncol) {
1175 pos -= vs.ncol;
1176 col -= vs.ncol;
1177 }
1178 vs.col = col;
1179 crtat = Crtat + pos;
1180 vs.state = 0;
1181 break;
1182 }
1183 case 'D': { /* left cursor */
1184 int cx = vs.cx,
1185 col = vs.col;
1186 if (cx <= 0)
1187 cx = 1;
1188 else
1189 cx %= vs.ncol;
1190 pos = crtat - Crtat;
1191 pos -= cx;
1192 col -= cx;
1193 if (col < 0) {
1194 pos += vs.ncol;
1195 col += vs.ncol;
1196 }
1197 vs.col = col;
1198 crtat = Crtat + pos;
1199 vs.state = 0;
1200 break;
1201 }
1202 case 'J': /* Clear ... */
1203 switch (vs.cx) {
1204 case 0:
1205 /* ... to end of display */
1206 fillw((vs.at << 8) | ' ',
1207 crtat,
1208 Crtat + vs.nchr - crtat);
1209 break;
1210 case 1:
1211 /* ... to next location */
1212 fillw((vs.at << 8) | ' ',
1213 Crtat,
1214 crtat - Crtat + 1);
1215 break;
1216 case 2:
1217 /* ... whole display */
1218 fillw((vs.at << 8) | ' ',
1219 Crtat,
1220 vs.nchr);
1221 break;
1222 }
1223 vs.state = 0;
1224 break;
1225 case 'K': /* Clear line ... */
1226 switch (vs.cx) {
1227 case 0:
1228 /* ... current to EOL */
1229 fillw((vs.at << 8) | ' ',
1230 crtat,
1231 vs.ncol - vs.col);
1232 break;
1233 case 1:
1234 /* ... beginning to next */
1235 fillw((vs.at << 8) | ' ',
1236 crtat - vs.col,
1237 vs.col + 1);
1238 break;
1239 case 2:
1240 /* ... entire line */
1241 fillw((vs.at << 8) | ' ',
1242 crtat - vs.col, vs.ncol);
1243 break;
1244 }
1245 vs.state = 0;
1246 break;
1247 case 'f': /* in system V consoles */
1248 case 'H': { /* Cursor move */
1249 int cx = vs.cx,
1250 cy = vs.cy;
1251 if (!cx || !cy) {
1252 crtat = Crtat;
1253 vs.col = 0;
1254 } else {
1255 if (cx > vs.nrow)
1256 cx = vs.nrow;
1257 if (cy > vs.ncol)
1258 cy = vs.ncol;
1259 crtat = Crtat +
1260 (cx - 1) * vs.ncol + cy - 1;
1261 vs.col = cy - 1;
1262 }
1263 vs.state = 0;
1264 break;
1265 }
1266 case 'M': { /* delete cx rows */
1267 u_short *crtAt = crtat - vs.col;
1268 int cx = vs.cx,
1269 row = (crtAt - Crtat) / vs.ncol,
1270 nrow = vs.nrow - row;
1271 if (cx <= 0)
1272 cx = 1;
1273 else if (cx > nrow)
1274 cx = nrow;
1275 if (cx < nrow)
1276 #ifdef PCCONS_FORCE_WORD
1277 wcopy(crtAt + vs.ncol * cx,
1278 crtAt, vs.ncol * (nrow -
1279 cx) * CHR);
1280 #else
1281 bcopy(crtAt + vs.ncol * cx,
1282 crtAt, vs.ncol * (nrow -
1283 cx) * CHR);
1284 #endif
1285 fillw((vs.at << 8) | ' ',
1286 crtAt + vs.ncol * (nrow - cx),
1287 vs.ncol * cx);
1288 vs.state = 0;
1289 break;
1290 }
1291 case 'S': { /* scroll up cx lines */
1292 int cx = vs.cx;
1293 if (cx <= 0)
1294 cx = 1;
1295 else if (cx > vs.nrow)
1296 cx = vs.nrow;
1297 if (cx < vs.nrow)
1298 #ifdef PCCONS_FORCE_WORD
1299 wcopy(Crtat + vs.ncol * cx,
1300 Crtat, vs.ncol * (vs.nrow -
1301 cx) * CHR);
1302 #else
1303 bcopy(Crtat + vs.ncol * cx,
1304 Crtat, vs.ncol * (vs.nrow -
1305 cx) * CHR);
1306 #endif
1307 fillw((vs.at << 8) | ' ',
1308 Crtat + vs.ncol * (vs.nrow - cx),
1309 vs.ncol * cx);
1310 /* crtat -= vs.ncol * cx; XXX */
1311 vs.state = 0;
1312 break;
1313 }
1314 case 'L': { /* insert cx rows */
1315 u_short *crtAt = crtat - vs.col;
1316 int cx = vs.cx,
1317 row = (crtAt - Crtat) / vs.ncol,
1318 nrow = vs.nrow - row;
1319 if (cx <= 0)
1320 cx = 1;
1321 else if (cx > nrow)
1322 cx = nrow;
1323 if (cx < nrow)
1324 #ifdef PCCONS_FORCE_WORD
1325 wcopy(crtAt,
1326 crtAt + vs.ncol * cx,
1327 vs.ncol * (nrow - cx) *
1328 CHR);
1329 #else
1330 bcopy(crtAt,
1331 crtAt + vs.ncol * cx,
1332 vs.ncol * (nrow - cx) *
1333 CHR);
1334 #endif
1335 fillw((vs.at << 8) | ' ', crtAt,
1336 vs.ncol * cx);
1337 vs.state = 0;
1338 break;
1339 }
1340 case 'T': { /* scroll down cx lines */
1341 int cx = vs.cx;
1342 if (cx <= 0)
1343 cx = 1;
1344 else if (cx > vs.nrow)
1345 cx = vs.nrow;
1346 if (cx < vs.nrow)
1347 #ifdef PCCONS_FORCE_WORD
1348 wcopy(Crtat,
1349 Crtat + vs.ncol * cx,
1350 vs.ncol * (vs.nrow - cx) *
1351 CHR);
1352 #else
1353 bcopy(Crtat,
1354 Crtat + vs.ncol * cx,
1355 vs.ncol * (vs.nrow - cx) *
1356 CHR);
1357 #endif
1358 fillw((vs.at << 8) | ' ', Crtat,
1359 vs.ncol * cx);
1360 /* crtat += vs.ncol * cx; XXX */
1361 vs.state = 0;
1362 break;
1363 }
1364 case ';': /* Switch params in cursor def */
1365 vs.state = VSS_EPARAM;
1366 break;
1367 case 'r':
1368 vs.so_at = (vs.cx & FG_MASK) |
1369 ((vs.cy << 4) & BG_MASK);
1370 vs.state = 0;
1371 break;
1372 case 's': /* save cursor pos */
1373 vs.offset = crtat - Crtat;
1374 vs.state = 0;
1375 break;
1376 case 'u': /* restore cursor pos */
1377 crtat = Crtat + vs.offset;
1378 vs.row = vs.offset / vs.ncol;
1379 vs.col = vs.offset % vs.ncol;
1380 vs.state = 0;
1381 break;
1382 case 'x': /* set attributes */
1383 switch (vs.cx) {
1384 case 0:
1385 vs.at = FG_LIGHTGREY | BG_BLACK;
1386 break;
1387 case 1:
1388 /* ansi background */
1389 if (!vs.color)
1390 break;
1391 vs.at &= FG_MASK;
1392 vs.at |= bgansitopc[vs.cy & 7];
1393 break;
1394 case 2:
1395 /* ansi foreground */
1396 if (!vs.color)
1397 break;
1398 vs.at &= BG_MASK;
1399 vs.at |= fgansitopc[vs.cy & 7];
1400 break;
1401 case 3:
1402 /* pc text attribute */
1403 if (vs.state >= VSS_EPARAM)
1404 vs.at = vs.cy;
1405 break;
1406 }
1407 vs.state = 0;
1408 break;
1409
1410 default: /* Only numbers valid here */
1411 if ((c >= '0') && (c <= '9')) {
1412 if (vs.state >= VSS_EPARAM) {
1413 vs.cy *= 10;
1414 vs.cy += c - '0';
1415 } else {
1416 vs.cx *= 10;
1417 vs.cx += c - '0';
1418 }
1419 } else
1420 vs.state = 0;
1421 break;
1422 }
1423 break;
1424 }
1425 }
1426 if (scroll) {
1427 scroll = 0;
1428 /* scroll check */
1429 if (crtat >= Crtat + vs.nchr) {
1430 if (!kernel) {
1431 int s = spltty();
1432 if (lock_state & KB_SCROLL)
1433 tsleep(&lock_state,
1434 PUSER, "pcputc", 0);
1435 splx(s);
1436 }
1437 #if PCCONS_FORCE_WORD
1438 wcopy(Crtat + vs.ncol, Crtat,
1439 (vs.nchr - vs.ncol) * CHR);
1440 #else
1441 bcopy(Crtat + vs.ncol, Crtat,
1442 (vs.nchr - vs.ncol) * CHR);
1443 #endif
1444 fillw((vs.at << 8) | ' ',
1445 Crtat + vs.nchr - vs.ncol,
1446 vs.ncol);
1447 crtat -= vs.ncol;
1448 }
1449 }
1450 }
1451 async_update();
1452 }
1453
1454 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1455 left and right shift when reading the keyboard map */
1456 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = {
1457 /* type unshift shift control altgr shift_altgr scancode */
1458 { KB_NONE, "", "", "", "", ""}, /* 0 unused */
1459 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */
1460 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */
1461 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */
1462 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */
1463 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */
1464 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */
1465 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */
1466 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */
1467 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */
1468 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */
1469 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */
1470 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */
1471 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */
1472 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */
1473 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */
1474 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */
1475 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */
1476 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */
1477 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */
1478 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */
1479 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */
1480 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */
1481 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */
1482 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */
1483 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */
1484 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */
1485 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */
1486 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */
1487 { KB_CTL, "", "", "", "", ""}, /* 29 control */
1488 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */
1489 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */
1490 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */
1491 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */
1492 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */
1493 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */
1494 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */
1495 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */
1496 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */
1497 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */
1498 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */
1499 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */
1500 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */
1501 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */
1502 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */
1503 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */
1504 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */
1505 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */
1506 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */
1507 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */
1508 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */
1509 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */
1510 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */
1511 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */
1512 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */
1513 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */
1514 { KB_ALT, "", "", "", "", ""}, /* 56 alt */
1515 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */
1516 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */
1517 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */
1518 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */
1519 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */
1520 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */
1521 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */
1522 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */
1523 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */
1524 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */
1525 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */
1526 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */
1527 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */
1528 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */
1529 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */
1530 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */
1531 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */
1532 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */
1533 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */
1534 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */
1535 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */
1536 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */
1537 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */
1538 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */
1539 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */
1540 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */
1541 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */
1542 { KB_NONE, "", "", "", "", ""}, /* 84 0 */
1543 { KB_NONE, "", "", "", "", ""}, /* 85 0 */
1544 { KB_NONE, "", "", "", "", ""}, /* 86 0 */
1545 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */
1546 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */
1547 { KB_NONE, "", "", "", "", ""}, /* 89 0 */
1548 { KB_NONE, "", "", "", "", ""}, /* 90 0 */
1549 { KB_NONE, "", "", "", "", ""}, /* 91 0 */
1550 { KB_NONE, "", "", "", "", ""}, /* 92 0 */
1551 { KB_NONE, "", "", "", "", ""}, /* 93 0 */
1552 { KB_NONE, "", "", "", "", ""}, /* 94 0 */
1553 { KB_NONE, "", "", "", "", ""}, /* 95 0 */
1554 { KB_NONE, "", "", "", "", ""}, /* 96 0 */
1555 { KB_NONE, "", "", "", "", ""}, /* 97 0 */
1556 { KB_NONE, "", "", "", "", ""}, /* 98 0 */
1557 { KB_NONE, "", "", "", "", ""}, /* 99 0 */
1558 { KB_NONE, "", "", "", "", ""}, /* 100 */
1559 { KB_NONE, "", "", "", "", ""}, /* 101 */
1560 { KB_NONE, "", "", "", "", ""}, /* 102 */
1561 { KB_NONE, "", "", "", "", ""}, /* 103 */
1562 { KB_NONE, "", "", "", "", ""}, /* 104 */
1563 { KB_NONE, "", "", "", "", ""}, /* 105 */
1564 { KB_NONE, "", "", "", "", ""}, /* 106 */
1565 { KB_NONE, "", "", "", "", ""}, /* 107 */
1566 { KB_NONE, "", "", "", "", ""}, /* 108 */
1567 { KB_NONE, "", "", "", "", ""}, /* 109 */
1568 { KB_NONE, "", "", "", "", ""}, /* 110 */
1569 { KB_NONE, "", "", "", "", ""}, /* 111 */
1570 { KB_NONE, "", "", "", "", ""}, /* 112 */
1571 { KB_NONE, "", "", "", "", ""}, /* 113 */
1572 { KB_NONE, "", "", "", "", ""}, /* 114 */
1573 { KB_NONE, "", "", "", "", ""}, /* 115 */
1574 { KB_NONE, "", "", "", "", ""}, /* 116 */
1575 { KB_NONE, "", "", "", "", ""}, /* 117 */
1576 { KB_NONE, "", "", "", "", ""}, /* 118 */
1577 { KB_NONE, "", "", "", "", ""}, /* 119 */
1578 { KB_NONE, "", "", "", "", ""}, /* 120 */
1579 { KB_NONE, "", "", "", "", ""}, /* 121 */
1580 { KB_NONE, "", "", "", "", ""}, /* 122 */
1581 { KB_NONE, "", "", "", "", ""}, /* 123 */
1582 { KB_NONE, "", "", "", "", ""}, /* 124 */
1583 { KB_NONE, "", "", "", "", ""}, /* 125 */
1584 { KB_NONE, "", "", "", "", ""}, /* 126 */
1585 { KB_NONE, "", "", "", "", ""} /* 127 */
1586 };
1587
1588 /*
1589 * Get characters from the keyboard. If none are present, return NULL.
1590 */
1591 char *
1592 sget(void)
1593 {
1594 u_char dt;
1595 static u_char extended = 0, shift_state = 0;
1596 static u_char capchar[2];
1597
1598 top:
1599 KBD_DELAY;
1600 dt = kbd_data_read_1();
1601
1602 switch (dt) {
1603 case KBR_ACK: case KBR_ECHO:
1604 kb_oq_get = (kb_oq_get + 1) & 7;
1605 if(kb_oq_get != kb_oq_put) {
1606 kbd_data_write_1(kb_oq[kb_oq_get]);
1607 }
1608 goto loop;
1609 case KBR_RESEND:
1610 kbd_data_write_1(kb_oq[kb_oq_get]);
1611 goto loop;
1612 }
1613
1614 if (pc_xmode > 0) {
1615 #if defined(DDB) && defined(XSERVER_DDB)
1616 /* F12 enters the debugger while in X mode */
1617 if (dt == 88)
1618 Debugger();
1619 #endif
1620 capchar[0] = dt;
1621 capchar[1] = 0;
1622 /*
1623 * Check for locking keys.
1624 *
1625 * XXX Setting the LEDs this way is a bit bogus. What if the
1626 * keyboard has been remapped in X?
1627 */
1628 switch (scan_codes[dt & 0x7f].type) {
1629 case KB_NUM:
1630 if (dt & 0x80) {
1631 shift_state &= ~KB_NUM;
1632 break;
1633 }
1634 if (shift_state & KB_NUM)
1635 break;
1636 shift_state |= KB_NUM;
1637 lock_state ^= KB_NUM;
1638 async_update();
1639 break;
1640 case KB_CAPS:
1641 if (dt & 0x80) {
1642 shift_state &= ~KB_CAPS;
1643 break;
1644 }
1645 if (shift_state & KB_CAPS)
1646 break;
1647 shift_state |= KB_CAPS;
1648 lock_state ^= KB_CAPS;
1649 async_update();
1650 break;
1651 case KB_SCROLL:
1652 if (dt & 0x80) {
1653 shift_state &= ~KB_SCROLL;
1654 break;
1655 }
1656 if (shift_state & KB_SCROLL)
1657 break;
1658 shift_state |= KB_SCROLL;
1659 lock_state ^= KB_SCROLL;
1660 if ((lock_state & KB_SCROLL) == 0)
1661 wakeup((void *)&lock_state);
1662 async_update();
1663 break;
1664 }
1665 return capchar;
1666 }
1667
1668 switch (dt) {
1669 case KBR_EXTENDED:
1670 extended = 1;
1671 goto loop;
1672 }
1673
1674 #ifdef DDB
1675 /*
1676 * Check for cntl-alt-esc.
1677 */
1678 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1679 /* XXX - check pccons_is_console */
1680 Debugger();
1681 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
1682 }
1683 #endif
1684
1685 /*
1686 * Check for make/break.
1687 */
1688 if (dt & 0x80) {
1689 /*
1690 * break
1691 */
1692 dt &= 0x7f;
1693 switch (scan_codes[dt].type) {
1694 case KB_NUM:
1695 shift_state &= ~KB_NUM;
1696 break;
1697 case KB_CAPS:
1698 shift_state &= ~KB_CAPS;
1699 break;
1700 case KB_SCROLL:
1701 shift_state &= ~KB_SCROLL;
1702 break;
1703 case KB_SHIFT:
1704 shift_state &= ~KB_SHIFT;
1705 break;
1706 case KB_ALT:
1707 if (extended)
1708 shift_state &= ~KB_ALTGR;
1709 else
1710 shift_state &= ~KB_ALT;
1711 break;
1712 case KB_CTL:
1713 shift_state &= ~KB_CTL;
1714 break;
1715 }
1716 } else {
1717 /*
1718 * make
1719 */
1720 switch (scan_codes[dt].type) {
1721 /*
1722 * locking keys
1723 */
1724 case KB_NUM:
1725 if (shift_state & KB_NUM)
1726 break;
1727 shift_state |= KB_NUM;
1728 lock_state ^= KB_NUM;
1729 async_update();
1730 break;
1731 case KB_CAPS:
1732 if (shift_state & KB_CAPS)
1733 break;
1734 shift_state |= KB_CAPS;
1735 lock_state ^= KB_CAPS;
1736 async_update();
1737 break;
1738 case KB_SCROLL:
1739 if (shift_state & KB_SCROLL)
1740 break;
1741 shift_state |= KB_SCROLL;
1742 lock_state ^= KB_SCROLL;
1743 if ((lock_state & KB_SCROLL) == 0)
1744 wakeup((void *)&lock_state);
1745 async_update();
1746 break;
1747 /*
1748 * non-locking keys
1749 */
1750 case KB_SHIFT:
1751 shift_state |= KB_SHIFT;
1752 break;
1753 case KB_ALT:
1754 if (extended)
1755 shift_state |= KB_ALTGR;
1756 else
1757 shift_state |= KB_ALT;
1758 break;
1759 case KB_CTL:
1760 shift_state |= KB_CTL;
1761 break;
1762 case KB_ASCII:
1763 /* control has highest priority */
1764 if (shift_state & KB_CTL)
1765 capchar[0] = scan_codes[dt].ctl[0];
1766 else if (shift_state & KB_ALTGR) {
1767 if (shift_state & KB_SHIFT)
1768 capchar[0] = scan_codes[dt].shift_altgr[0];
1769 else
1770 capchar[0] = scan_codes[dt].altgr[0];
1771 }
1772 else {
1773 if (shift_state & KB_SHIFT)
1774 capchar[0] = scan_codes[dt].shift[0];
1775 else
1776 capchar[0] = scan_codes[dt].unshift[0];
1777 }
1778 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1779 capchar[0] <= 'z') {
1780 capchar[0] -= ('a' - 'A');
1781 }
1782 capchar[0] |= (shift_state & KB_ALT);
1783 extended = 0;
1784 return capchar;
1785 case KB_NONE:
1786 printf("keycode %d\n",dt);
1787 break;
1788 case KB_FUNC: {
1789 char *more_chars;
1790 if (shift_state & KB_SHIFT)
1791 more_chars = scan_codes[dt].shift;
1792 else if (shift_state & KB_CTL)
1793 more_chars = scan_codes[dt].ctl;
1794 else
1795 more_chars = scan_codes[dt].unshift;
1796 extended = 0;
1797 return more_chars;
1798 }
1799 case KB_KP: {
1800 char *more_chars;
1801 if (shift_state & (KB_SHIFT | KB_CTL) ||
1802 (lock_state & KB_NUM) == 0 || extended)
1803 more_chars = scan_codes[dt].shift;
1804 else
1805 more_chars = scan_codes[dt].unshift;
1806 extended = 0;
1807 return more_chars;
1808 }
1809 }
1810 }
1811
1812 extended = 0;
1813 loop:
1814 if ((kbd_cmd_read_1() & KBS_DIB) == 0)
1815 return 0;
1816 goto top;
1817 }
1818
1819 paddr_t
1820 pcmmap(dev_t dev, off_t offset, int nprot)
1821 {
1822 struct pccons_context *pc = &pccons_console_context;
1823 paddr_t pa;
1824
1825 if (offset >= 0xa0000 && offset < 0xc0000) {
1826 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1827 return -1;
1828 pa += offset - pc->pc_config->pc_mono_memaddr;
1829 return mips_btop(pa);
1830 }
1831 if (offset >= 0x0000 && offset < 0x10000) {
1832 if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
1833 return -1;
1834 pa += offset - pc->pc_config->pc_mono_iobase;
1835 return mips_btop(pa);
1836 }
1837 if (offset >= 0x40000000 && offset < 0x40800000) {
1838 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1839 return (-1);
1840 pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
1841 return mips_btop(pa);
1842 }
1843 return -1;
1844 }
1845
1846 void
1847 pc_xmode_on(void)
1848 {
1849 if (pc_xmode)
1850 return;
1851 pc_xmode = 1;
1852
1853 #ifdef XFREE86_BUG_COMPAT
1854 /* If still unchanged, get current shape. */
1855 if (cursor_shape == 0xffff)
1856 get_cursor_shape();
1857 #endif
1858 }
1859
1860 void
1861 pc_xmode_off(void)
1862 {
1863 if (pc_xmode == 0)
1864 return;
1865 pc_xmode = 0;
1866
1867 #ifdef XFREE86_BUG_COMPAT
1868 /* XXX It would be hard to justify why the X server doesn't do this. */
1869 set_cursor_shape();
1870 #endif
1871 async_update();
1872 }
1873