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