pccons.c revision 1.47 1 /* $NetBSD: pccons.c,v 1.47 2006/09/01 19:15:48 matt 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.47 2006/09/01 19:15:48 matt 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 struct callout async_update_ch = CALLOUT_INITIALIZER;
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 do_async_update(1);
590 }
591
592 int
593 pcopen(dev_t dev, int flag, int mode, struct lwp *l)
594 {
595 struct pc_softc *sc;
596 int unit = PCUNIT(dev);
597 struct tty *tp;
598
599 if (unit >= pc_cd.cd_ndevs)
600 return ENXIO;
601 sc = pc_cd.cd_devs[unit];
602 if (sc == 0)
603 return ENXIO;
604
605 if (!sc->sc_tty) {
606 tp = sc->sc_tty = ttymalloc();
607 }
608 else {
609 tp = sc->sc_tty;
610 }
611
612 tp->t_oproc = pcstart;
613 tp->t_param = pcparam;
614 tp->t_dev = dev;
615 if ((tp->t_state & TS_ISOPEN) == 0) {
616 ttychars(tp);
617 tp->t_iflag = TTYDEF_IFLAG;
618 tp->t_oflag = TTYDEF_OFLAG;
619 tp->t_cflag = TTYDEF_CFLAG;
620 tp->t_lflag = TTYDEF_LFLAG;
621 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
622 pcparam(tp, &tp->t_termios);
623 ttsetwater(tp);
624 } else if (tp->t_state&TS_XCLUDE &&
625 kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER,
626 &l->l_acflag) != 0)
627 return EBUSY;
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 = pc_cd.cd_devs[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 = pc_cd.cd_devs[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 = pc_cd.cd_devs[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 = pc_cd.cd_devs[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 = pc_cd.cd_devs[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, caddr_t data, int flag, struct lwp *l)
713 {
714 struct pc_softc *sc = pc_cd.cd_devs[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 struct clist *cl;
796 int s, len;
797 u_char buf[PCBURST];
798
799 s = spltty();
800 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
801 goto out;
802 tp->t_state |= TS_BUSY;
803 splx(s);
804 /*
805 * We need to do this outside spl since it could be fairly
806 * expensive and we don't want our serial ports to overflow.
807 */
808 cl = &tp->t_outq;
809 len = q_to_b(cl, buf, PCBURST);
810 sput(buf, len);
811 s = spltty();
812 tp->t_state &= ~TS_BUSY;
813 if (cl->c_cc) {
814 tp->t_state |= TS_TIMEOUT;
815 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
816 }
817 if (cl->c_cc <= tp->t_lowat) {
818 if (tp->t_state & TS_ASLEEP) {
819 tp->t_state &= ~TS_ASLEEP;
820 wakeup(cl);
821 }
822 selwakeup(&tp->t_wsel);
823 }
824 out:
825 splx(s);
826 }
827
828 /* ARGSUSED */
829 void pccons_common_cnattach(bus_space_tag_t crt_iot, bus_space_tag_t crt_memt,
830 bus_space_tag_t kbd_iot, struct pccons_config *config)
831 {
832 int maj;
833 static struct consdev pccons = {
834 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL, NULL,
835 NULL, NODEV, CN_NORMAL
836 };
837
838 /*
839 * For now, don't screw with it.
840 */
841 /* crtat = 0; */
842
843 pc_context_init(crt_iot, crt_memt, kbd_iot, config);
844
845 /* locate the major number */
846 maj = cdevsw_lookup_major(&pc_cdevsw);
847 pccons.cn_dev = makedev(maj, 0);
848
849 cn_tab = &pccons;
850 }
851
852 /* ARGSUSED */
853 void
854 pccnputc(dev_t dev, int c)
855 {
856 u_char cc, oldkernel = kernel;
857
858 kernel = 1;
859 if (c == '\n') {
860 sput("\r\n", 2);
861 } else {
862 cc = c;
863 sput(&cc, 1);
864 }
865 kernel = oldkernel;
866 }
867
868 /* ARGSUSED */
869 int
870 pccngetc(dev_t dev)
871 {
872 char *cp;
873
874 if (pc_xmode > 0)
875 return 0;
876
877 do {
878 /* wait for byte */
879 while ((kbd_cmd_read_1() & KBS_DIB) == 0);
880 /* see if it's worthwhile */
881 cp = sget();
882 } while (!cp);
883 if (*cp == '\r')
884 return '\n';
885 return *cp;
886 }
887
888 void
889 pccnpollc(dev_t dev, int on)
890 {
891
892 polling = on;
893 if (!on) {
894 int unit;
895 struct pc_softc *sc;
896 int s;
897
898 /*
899 * If disabling polling on a device that's been configured,
900 * make sure there are no bytes left in the FIFO, holding up
901 * the interrupt line. Otherwise we won't get any further
902 * interrupts.
903 */
904 unit = PCUNIT(dev);
905 if (pc_cd.cd_ndevs > unit) {
906 sc = pc_cd.cd_devs[unit];
907 if (sc != 0) {
908 s = spltty();
909 pcintr(sc);
910 splx(s);
911 }
912 }
913 }
914 }
915
916 /*
917 * Set line parameters.
918 */
919 int
920 pcparam(struct tty *tp, struct termios *t)
921 {
922
923 tp->t_ispeed = t->c_ispeed;
924 tp->t_ospeed = t->c_ospeed;
925 tp->t_cflag = t->c_cflag;
926 return 0;
927 }
928
929 #define wrtchar(c, at) do {\
930 char *cp0 = (char *)crtat; *cp0++ = (c); *cp0 = (at); crtat++; vs.col++; \
931 } while (0)
932
933 /* translate ANSI color codes to standard pc ones */
934 static char fgansitopc[] = {
935 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
936 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
937 };
938
939 static char bgansitopc[] = {
940 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
941 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
942 };
943
944 static u_char iso2ibm437[] =
945 {
946 0, 0, 0, 0, 0, 0, 0, 0,
947 0, 0, 0, 0, 0, 0, 0, 0,
948 0, 0, 0, 0, 0, 0, 0, 0,
949 0, 0, 0, 0, 0, 0, 0, 0,
950 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
951 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
952 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
953 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
954 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
955 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
956 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
957 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
958 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
959 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
960 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
961 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
962 };
963
964 /*
965 * `pc3' termcap emulation.
966 */
967 void
968 sput(const u_char *cp, int n)
969 {
970 struct pccons_context *pc = &pccons_console_context;
971 u_char c, scroll = 0;
972
973 if (pc_xmode > 0)
974 return;
975
976 if (crtat == 0) {
977 volatile u_short *dp;
978 u_short was;
979 unsigned cursorat;
980
981 dp = bus_space_vaddr(pc->pc_crt_memt, pc->pc_cga_memh);
982 was = *dp;
983 *dp = 0xA55A;
984 if (*dp != 0xA55A) {
985 dp = bus_space_vaddr(pc->pc_crt_memt,
986 pc->pc_mono_memh);
987 pc->pc_6845_ioh = pc->pc_mono_ioh;
988 pc->pc_crt_memh = pc->pc_mono_memh;
989 vs.color = 0;
990 } else {
991 *dp = was;
992 pc->pc_6845_ioh = pc->pc_cga_ioh;
993 pc->pc_crt_memh = pc->pc_cga_memh;
994 vs.color = 1;
995 }
996
997 #ifdef FAT_CURSOR
998 cursor_shape = 0x0012;
999 #else
1000 get_cursor_shape();
1001 #endif
1002
1003 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
1004 vs.nchr = vs.ncol * vs.nrow;
1005 vs.col--;
1006 vs.row--;
1007 cursorat = vs.ncol * vs.row + vs.col;
1008 vs.at = FG_LIGHTGREY | BG_BLACK;
1009
1010 Crtat = (u_short *)__UNVOLATILE(dp);
1011 crtat = Crtat + cursorat;
1012
1013 if (vs.color == 0)
1014 vs.so_at = FG_BLACK | BG_LIGHTGREY;
1015 else
1016 vs.so_at = FG_YELLOW | BG_BLACK;
1017
1018 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1019 }
1020
1021 while (n--) {
1022 if (!(c = *cp++))
1023 continue;
1024
1025 switch (c) {
1026 case 0x1B:
1027 if (vs.state >= VSS_ESCAPE) {
1028 wrtchar(c, vs.so_at);
1029 vs.state = 0;
1030 goto maybe_scroll;
1031 } else
1032 vs.state = VSS_ESCAPE;
1033 break;
1034
1035 case 0x9B: /* CSI */
1036 vs.cx = vs.cy = 0;
1037 vs.state = VSS_EBRACE;
1038 break;
1039
1040 case '\t': {
1041 int inccol = 8 - (vs.col & 7);
1042 crtat += inccol;
1043 vs.col += inccol;
1044 }
1045 maybe_scroll:
1046 if (vs.col >= vs.ncol) {
1047 vs.col -= vs.ncol;
1048 scroll = 1;
1049 }
1050 break;
1051
1052 case '\b':
1053 if (crtat <= Crtat)
1054 break;
1055 --crtat;
1056 if (--vs.col < 0)
1057 vs.col += vs.ncol; /* non-destructive backspace */
1058 break;
1059
1060 case '\r':
1061 crtat -= vs.col;
1062 vs.col = 0;
1063 break;
1064
1065 case '\n':
1066 crtat += vs.ncol;
1067 scroll = 1;
1068 break;
1069
1070 default:
1071 switch (vs.state) {
1072 case 0:
1073 if (c == '\a')
1074 sysbeep(BEEP_FREQ, BEEP_TIME);
1075 else {
1076 /*
1077 * If we're outputting multiple printed
1078 * characters, just blast them to the
1079 * screen until we reach the end of the
1080 * buffer or a control character. This
1081 * saves time by short-circuiting the
1082 * switch.
1083 * If we reach the end of the line, we
1084 * break to do a scroll check.
1085 */
1086 for (;;) {
1087 if (c & 0x80)
1088 c = iso2ibm437[c&0x7f];
1089
1090 if (vs.so)
1091 wrtchar(c, vs.so_at);
1092 else
1093 wrtchar(c, vs.at);
1094 if (vs.col >= vs.ncol) {
1095 vs.col = 0;
1096 scroll = 1;
1097 break;
1098 }
1099 if (!n || (c = *cp) < ' ')
1100 break;
1101 n--, cp++;
1102 }
1103 }
1104 break;
1105 case VSS_ESCAPE:
1106 switch (c) {
1107 case '[': /* Start ESC [ sequence */
1108 vs.cx = vs.cy = 0;
1109 vs.state = VSS_EBRACE;
1110 break;
1111 case 'c': /* Create screen & home */
1112 fillw((vs.at << 8) | ' ',
1113 Crtat, vs.nchr);
1114 crtat = Crtat;
1115 vs.col = 0;
1116 vs.state = 0;
1117 break;
1118 case '7': /* save cursor pos */
1119 vs.offset = crtat - Crtat;
1120 vs.state = 0;
1121 break;
1122 case '8': /* restore cursor pos */
1123 crtat = Crtat + vs.offset;
1124 vs.row = vs.offset / vs.ncol;
1125 vs.col = vs.offset % vs.ncol;
1126 vs.state = 0;
1127 break;
1128 default: /* Invalid, clear state */
1129 wrtchar(c, vs.so_at);
1130 vs.state = 0;
1131 goto maybe_scroll;
1132 }
1133 break;
1134
1135 default: /* VSS_EBRACE or VSS_EPARAM */
1136 switch (c) {
1137 int pos;
1138 case 'm':
1139 if (!vs.cx)
1140 vs.so = 0;
1141 else
1142 vs.so = 1;
1143 vs.state = 0;
1144 break;
1145 case 'A': { /* back cx rows */
1146 int cx = vs.cx;
1147 if (cx <= 0)
1148 cx = 1;
1149 else
1150 cx %= vs.nrow;
1151 pos = crtat - Crtat;
1152 pos -= vs.ncol * cx;
1153 if (pos < 0)
1154 pos += vs.nchr;
1155 crtat = Crtat + pos;
1156 vs.state = 0;
1157 break;
1158 }
1159 case 'B': { /* down cx rows */
1160 int cx = vs.cx;
1161 if (cx <= 0)
1162 cx = 1;
1163 else
1164 cx %= vs.nrow;
1165 pos = crtat - Crtat;
1166 pos += vs.ncol * cx;
1167 if (pos >= vs.nchr)
1168 pos -= vs.nchr;
1169 crtat = Crtat + pos;
1170 vs.state = 0;
1171 break;
1172 }
1173 case 'C': { /* right cursor */
1174 int cx = vs.cx,
1175 col = vs.col;
1176 if (cx <= 0)
1177 cx = 1;
1178 else
1179 cx %= vs.ncol;
1180 pos = crtat - Crtat;
1181 pos += cx;
1182 col += cx;
1183 if (col >= vs.ncol) {
1184 pos -= vs.ncol;
1185 col -= vs.ncol;
1186 }
1187 vs.col = col;
1188 crtat = Crtat + pos;
1189 vs.state = 0;
1190 break;
1191 }
1192 case 'D': { /* left cursor */
1193 int cx = vs.cx,
1194 col = vs.col;
1195 if (cx <= 0)
1196 cx = 1;
1197 else
1198 cx %= vs.ncol;
1199 pos = crtat - Crtat;
1200 pos -= cx;
1201 col -= cx;
1202 if (col < 0) {
1203 pos += vs.ncol;
1204 col += vs.ncol;
1205 }
1206 vs.col = col;
1207 crtat = Crtat + pos;
1208 vs.state = 0;
1209 break;
1210 }
1211 case 'J': /* Clear ... */
1212 switch (vs.cx) {
1213 case 0:
1214 /* ... to end of display */
1215 fillw((vs.at << 8) | ' ',
1216 crtat,
1217 Crtat + vs.nchr - crtat);
1218 break;
1219 case 1:
1220 /* ... to next location */
1221 fillw((vs.at << 8) | ' ',
1222 Crtat,
1223 crtat - Crtat + 1);
1224 break;
1225 case 2:
1226 /* ... whole display */
1227 fillw((vs.at << 8) | ' ',
1228 Crtat,
1229 vs.nchr);
1230 break;
1231 }
1232 vs.state = 0;
1233 break;
1234 case 'K': /* Clear line ... */
1235 switch (vs.cx) {
1236 case 0:
1237 /* ... current to EOL */
1238 fillw((vs.at << 8) | ' ',
1239 crtat,
1240 vs.ncol - vs.col);
1241 break;
1242 case 1:
1243 /* ... beginning to next */
1244 fillw((vs.at << 8) | ' ',
1245 crtat - vs.col,
1246 vs.col + 1);
1247 break;
1248 case 2:
1249 /* ... entire line */
1250 fillw((vs.at << 8) | ' ',
1251 crtat - vs.col, vs.ncol);
1252 break;
1253 }
1254 vs.state = 0;
1255 break;
1256 case 'f': /* in system V consoles */
1257 case 'H': { /* Cursor move */
1258 int cx = vs.cx,
1259 cy = vs.cy;
1260 if (!cx || !cy) {
1261 crtat = Crtat;
1262 vs.col = 0;
1263 } else {
1264 if (cx > vs.nrow)
1265 cx = vs.nrow;
1266 if (cy > vs.ncol)
1267 cy = vs.ncol;
1268 crtat = Crtat +
1269 (cx - 1) * vs.ncol + cy - 1;
1270 vs.col = cy - 1;
1271 }
1272 vs.state = 0;
1273 break;
1274 }
1275 case 'M': { /* delete cx rows */
1276 u_short *crtAt = crtat - vs.col;
1277 int cx = vs.cx,
1278 row = (crtAt - Crtat) / vs.ncol,
1279 nrow = vs.nrow - row;
1280 if (cx <= 0)
1281 cx = 1;
1282 else if (cx > nrow)
1283 cx = nrow;
1284 if (cx < nrow)
1285 #ifdef PCCONS_FORCE_WORD
1286 wcopy(crtAt + vs.ncol * cx,
1287 crtAt, vs.ncol * (nrow -
1288 cx) * CHR);
1289 #else
1290 bcopy(crtAt + vs.ncol * cx,
1291 crtAt, vs.ncol * (nrow -
1292 cx) * CHR);
1293 #endif
1294 fillw((vs.at << 8) | ' ',
1295 crtAt + vs.ncol * (nrow - cx),
1296 vs.ncol * cx);
1297 vs.state = 0;
1298 break;
1299 }
1300 case 'S': { /* scroll up cx lines */
1301 int cx = vs.cx;
1302 if (cx <= 0)
1303 cx = 1;
1304 else if (cx > vs.nrow)
1305 cx = vs.nrow;
1306 if (cx < vs.nrow)
1307 #ifdef PCCONS_FORCE_WORD
1308 wcopy(Crtat + vs.ncol * cx,
1309 Crtat, vs.ncol * (vs.nrow -
1310 cx) * CHR);
1311 #else
1312 bcopy(Crtat + vs.ncol * cx,
1313 Crtat, vs.ncol * (vs.nrow -
1314 cx) * CHR);
1315 #endif
1316 fillw((vs.at << 8) | ' ',
1317 Crtat + vs.ncol * (vs.nrow - cx),
1318 vs.ncol * cx);
1319 /* crtat -= vs.ncol * cx; XXX */
1320 vs.state = 0;
1321 break;
1322 }
1323 case 'L': { /* insert cx rows */
1324 u_short *crtAt = crtat - vs.col;
1325 int cx = vs.cx,
1326 row = (crtAt - Crtat) / vs.ncol,
1327 nrow = vs.nrow - row;
1328 if (cx <= 0)
1329 cx = 1;
1330 else if (cx > nrow)
1331 cx = nrow;
1332 if (cx < nrow)
1333 #ifdef PCCONS_FORCE_WORD
1334 wcopy(crtAt,
1335 crtAt + vs.ncol * cx,
1336 vs.ncol * (nrow - cx) *
1337 CHR);
1338 #else
1339 bcopy(crtAt,
1340 crtAt + vs.ncol * cx,
1341 vs.ncol * (nrow - cx) *
1342 CHR);
1343 #endif
1344 fillw((vs.at << 8) | ' ', crtAt,
1345 vs.ncol * cx);
1346 vs.state = 0;
1347 break;
1348 }
1349 case 'T': { /* scroll down cx lines */
1350 int cx = vs.cx;
1351 if (cx <= 0)
1352 cx = 1;
1353 else if (cx > vs.nrow)
1354 cx = vs.nrow;
1355 if (cx < vs.nrow)
1356 #ifdef PCCONS_FORCE_WORD
1357 wcopy(Crtat,
1358 Crtat + vs.ncol * cx,
1359 vs.ncol * (vs.nrow - cx) *
1360 CHR);
1361 #else
1362 bcopy(Crtat,
1363 Crtat + vs.ncol * cx,
1364 vs.ncol * (vs.nrow - cx) *
1365 CHR);
1366 #endif
1367 fillw((vs.at << 8) | ' ', Crtat,
1368 vs.ncol * cx);
1369 /* crtat += vs.ncol * cx; XXX */
1370 vs.state = 0;
1371 break;
1372 }
1373 case ';': /* Switch params in cursor def */
1374 vs.state = VSS_EPARAM;
1375 break;
1376 case 'r':
1377 vs.so_at = (vs.cx & FG_MASK) |
1378 ((vs.cy << 4) & BG_MASK);
1379 vs.state = 0;
1380 break;
1381 case 's': /* save cursor pos */
1382 vs.offset = crtat - Crtat;
1383 vs.state = 0;
1384 break;
1385 case 'u': /* restore cursor pos */
1386 crtat = Crtat + vs.offset;
1387 vs.row = vs.offset / vs.ncol;
1388 vs.col = vs.offset % vs.ncol;
1389 vs.state = 0;
1390 break;
1391 case 'x': /* set attributes */
1392 switch (vs.cx) {
1393 case 0:
1394 vs.at = FG_LIGHTGREY | BG_BLACK;
1395 break;
1396 case 1:
1397 /* ansi background */
1398 if (!vs.color)
1399 break;
1400 vs.at &= FG_MASK;
1401 vs.at |= bgansitopc[vs.cy & 7];
1402 break;
1403 case 2:
1404 /* ansi foreground */
1405 if (!vs.color)
1406 break;
1407 vs.at &= BG_MASK;
1408 vs.at |= fgansitopc[vs.cy & 7];
1409 break;
1410 case 3:
1411 /* pc text attribute */
1412 if (vs.state >= VSS_EPARAM)
1413 vs.at = vs.cy;
1414 break;
1415 }
1416 vs.state = 0;
1417 break;
1418
1419 default: /* Only numbers valid here */
1420 if ((c >= '0') && (c <= '9')) {
1421 if (vs.state >= VSS_EPARAM) {
1422 vs.cy *= 10;
1423 vs.cy += c - '0';
1424 } else {
1425 vs.cx *= 10;
1426 vs.cx += c - '0';
1427 }
1428 } else
1429 vs.state = 0;
1430 break;
1431 }
1432 break;
1433 }
1434 }
1435 if (scroll) {
1436 scroll = 0;
1437 /* scroll check */
1438 if (crtat >= Crtat + vs.nchr) {
1439 if (!kernel) {
1440 int s = spltty();
1441 if (lock_state & KB_SCROLL)
1442 tsleep(&lock_state,
1443 PUSER, "pcputc", 0);
1444 splx(s);
1445 }
1446 #if PCCONS_FORCE_WORD
1447 wcopy(Crtat + vs.ncol, Crtat,
1448 (vs.nchr - vs.ncol) * CHR);
1449 #else
1450 bcopy(Crtat + vs.ncol, Crtat,
1451 (vs.nchr - vs.ncol) * CHR);
1452 #endif
1453 fillw((vs.at << 8) | ' ',
1454 Crtat + vs.nchr - vs.ncol,
1455 vs.ncol);
1456 crtat -= vs.ncol;
1457 }
1458 }
1459 }
1460 async_update();
1461 }
1462
1463 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1464 left and right shift when reading the keyboard map */
1465 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = {
1466 /* type unshift shift control altgr shift_altgr scancode */
1467 { KB_NONE, "", "", "", "", ""}, /* 0 unused */
1468 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */
1469 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */
1470 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */
1471 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */
1472 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */
1473 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */
1474 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */
1475 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */
1476 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */
1477 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */
1478 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */
1479 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */
1480 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */
1481 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */
1482 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */
1483 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */
1484 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */
1485 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */
1486 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */
1487 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */
1488 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */
1489 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */
1490 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */
1491 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */
1492 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */
1493 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */
1494 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */
1495 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */
1496 { KB_CTL, "", "", "", "", ""}, /* 29 control */
1497 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */
1498 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */
1499 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */
1500 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */
1501 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */
1502 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */
1503 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */
1504 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */
1505 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */
1506 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */
1507 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */
1508 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */
1509 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */
1510 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */
1511 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */
1512 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */
1513 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */
1514 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */
1515 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */
1516 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */
1517 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */
1518 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */
1519 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */
1520 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */
1521 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */
1522 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */
1523 { KB_ALT, "", "", "", "", ""}, /* 56 alt */
1524 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */
1525 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */
1526 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */
1527 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */
1528 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */
1529 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */
1530 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */
1531 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */
1532 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */
1533 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */
1534 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */
1535 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */
1536 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */
1537 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */
1538 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */
1539 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */
1540 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */
1541 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */
1542 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */
1543 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */
1544 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */
1545 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */
1546 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */
1547 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */
1548 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */
1549 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */
1550 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */
1551 { KB_NONE, "", "", "", "", ""}, /* 84 0 */
1552 { KB_NONE, "", "", "", "", ""}, /* 85 0 */
1553 { KB_NONE, "", "", "", "", ""}, /* 86 0 */
1554 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */
1555 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */
1556 { KB_NONE, "", "", "", "", ""}, /* 89 0 */
1557 { KB_NONE, "", "", "", "", ""}, /* 90 0 */
1558 { KB_NONE, "", "", "", "", ""}, /* 91 0 */
1559 { KB_NONE, "", "", "", "", ""}, /* 92 0 */
1560 { KB_NONE, "", "", "", "", ""}, /* 93 0 */
1561 { KB_NONE, "", "", "", "", ""}, /* 94 0 */
1562 { KB_NONE, "", "", "", "", ""}, /* 95 0 */
1563 { KB_NONE, "", "", "", "", ""}, /* 96 0 */
1564 { KB_NONE, "", "", "", "", ""}, /* 97 0 */
1565 { KB_NONE, "", "", "", "", ""}, /* 98 0 */
1566 { KB_NONE, "", "", "", "", ""}, /* 99 0 */
1567 { KB_NONE, "", "", "", "", ""}, /* 100 */
1568 { KB_NONE, "", "", "", "", ""}, /* 101 */
1569 { KB_NONE, "", "", "", "", ""}, /* 102 */
1570 { KB_NONE, "", "", "", "", ""}, /* 103 */
1571 { KB_NONE, "", "", "", "", ""}, /* 104 */
1572 { KB_NONE, "", "", "", "", ""}, /* 105 */
1573 { KB_NONE, "", "", "", "", ""}, /* 106 */
1574 { KB_NONE, "", "", "", "", ""}, /* 107 */
1575 { KB_NONE, "", "", "", "", ""}, /* 108 */
1576 { KB_NONE, "", "", "", "", ""}, /* 109 */
1577 { KB_NONE, "", "", "", "", ""}, /* 110 */
1578 { KB_NONE, "", "", "", "", ""}, /* 111 */
1579 { KB_NONE, "", "", "", "", ""}, /* 112 */
1580 { KB_NONE, "", "", "", "", ""}, /* 113 */
1581 { KB_NONE, "", "", "", "", ""}, /* 114 */
1582 { KB_NONE, "", "", "", "", ""}, /* 115 */
1583 { KB_NONE, "", "", "", "", ""}, /* 116 */
1584 { KB_NONE, "", "", "", "", ""}, /* 117 */
1585 { KB_NONE, "", "", "", "", ""}, /* 118 */
1586 { KB_NONE, "", "", "", "", ""}, /* 119 */
1587 { KB_NONE, "", "", "", "", ""}, /* 120 */
1588 { KB_NONE, "", "", "", "", ""}, /* 121 */
1589 { KB_NONE, "", "", "", "", ""}, /* 122 */
1590 { KB_NONE, "", "", "", "", ""}, /* 123 */
1591 { KB_NONE, "", "", "", "", ""}, /* 124 */
1592 { KB_NONE, "", "", "", "", ""}, /* 125 */
1593 { KB_NONE, "", "", "", "", ""}, /* 126 */
1594 { KB_NONE, "", "", "", "", ""} /* 127 */
1595 };
1596
1597 /*
1598 * Get characters from the keyboard. If none are present, return NULL.
1599 */
1600 char *
1601 sget(void)
1602 {
1603 u_char dt;
1604 static u_char extended = 0, shift_state = 0;
1605 static u_char capchar[2];
1606
1607 top:
1608 KBD_DELAY;
1609 dt = kbd_data_read_1();
1610
1611 switch (dt) {
1612 case KBR_ACK: case KBR_ECHO:
1613 kb_oq_get = (kb_oq_get + 1) & 7;
1614 if(kb_oq_get != kb_oq_put) {
1615 kbd_data_write_1(kb_oq[kb_oq_get]);
1616 }
1617 goto loop;
1618 case KBR_RESEND:
1619 kbd_data_write_1(kb_oq[kb_oq_get]);
1620 goto loop;
1621 }
1622
1623 if (pc_xmode > 0) {
1624 #if defined(DDB) && defined(XSERVER_DDB)
1625 /* F12 enters the debugger while in X mode */
1626 if (dt == 88)
1627 Debugger();
1628 #endif
1629 capchar[0] = dt;
1630 capchar[1] = 0;
1631 /*
1632 * Check for locking keys.
1633 *
1634 * XXX Setting the LEDs this way is a bit bogus. What if the
1635 * keyboard has been remapped in X?
1636 */
1637 switch (scan_codes[dt & 0x7f].type) {
1638 case KB_NUM:
1639 if (dt & 0x80) {
1640 shift_state &= ~KB_NUM;
1641 break;
1642 }
1643 if (shift_state & KB_NUM)
1644 break;
1645 shift_state |= KB_NUM;
1646 lock_state ^= KB_NUM;
1647 async_update();
1648 break;
1649 case KB_CAPS:
1650 if (dt & 0x80) {
1651 shift_state &= ~KB_CAPS;
1652 break;
1653 }
1654 if (shift_state & KB_CAPS)
1655 break;
1656 shift_state |= KB_CAPS;
1657 lock_state ^= KB_CAPS;
1658 async_update();
1659 break;
1660 case KB_SCROLL:
1661 if (dt & 0x80) {
1662 shift_state &= ~KB_SCROLL;
1663 break;
1664 }
1665 if (shift_state & KB_SCROLL)
1666 break;
1667 shift_state |= KB_SCROLL;
1668 lock_state ^= KB_SCROLL;
1669 if ((lock_state & KB_SCROLL) == 0)
1670 wakeup((caddr_t)&lock_state);
1671 async_update();
1672 break;
1673 }
1674 return capchar;
1675 }
1676
1677 switch (dt) {
1678 case KBR_EXTENDED:
1679 extended = 1;
1680 goto loop;
1681 }
1682
1683 #ifdef DDB
1684 /*
1685 * Check for cntl-alt-esc.
1686 */
1687 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1688 /* XXX - check pccons_is_console */
1689 Debugger();
1690 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
1691 }
1692 #endif
1693
1694 /*
1695 * Check for make/break.
1696 */
1697 if (dt & 0x80) {
1698 /*
1699 * break
1700 */
1701 dt &= 0x7f;
1702 switch (scan_codes[dt].type) {
1703 case KB_NUM:
1704 shift_state &= ~KB_NUM;
1705 break;
1706 case KB_CAPS:
1707 shift_state &= ~KB_CAPS;
1708 break;
1709 case KB_SCROLL:
1710 shift_state &= ~KB_SCROLL;
1711 break;
1712 case KB_SHIFT:
1713 shift_state &= ~KB_SHIFT;
1714 break;
1715 case KB_ALT:
1716 if (extended)
1717 shift_state &= ~KB_ALTGR;
1718 else
1719 shift_state &= ~KB_ALT;
1720 break;
1721 case KB_CTL:
1722 shift_state &= ~KB_CTL;
1723 break;
1724 }
1725 } else {
1726 /*
1727 * make
1728 */
1729 switch (scan_codes[dt].type) {
1730 /*
1731 * locking keys
1732 */
1733 case KB_NUM:
1734 if (shift_state & KB_NUM)
1735 break;
1736 shift_state |= KB_NUM;
1737 lock_state ^= KB_NUM;
1738 async_update();
1739 break;
1740 case KB_CAPS:
1741 if (shift_state & KB_CAPS)
1742 break;
1743 shift_state |= KB_CAPS;
1744 lock_state ^= KB_CAPS;
1745 async_update();
1746 break;
1747 case KB_SCROLL:
1748 if (shift_state & KB_SCROLL)
1749 break;
1750 shift_state |= KB_SCROLL;
1751 lock_state ^= KB_SCROLL;
1752 if ((lock_state & KB_SCROLL) == 0)
1753 wakeup((caddr_t)&lock_state);
1754 async_update();
1755 break;
1756 /*
1757 * non-locking keys
1758 */
1759 case KB_SHIFT:
1760 shift_state |= KB_SHIFT;
1761 break;
1762 case KB_ALT:
1763 if (extended)
1764 shift_state |= KB_ALTGR;
1765 else
1766 shift_state |= KB_ALT;
1767 break;
1768 case KB_CTL:
1769 shift_state |= KB_CTL;
1770 break;
1771 case KB_ASCII:
1772 /* control has highest priority */
1773 if (shift_state & KB_CTL)
1774 capchar[0] = scan_codes[dt].ctl[0];
1775 else if (shift_state & KB_ALTGR) {
1776 if (shift_state & KB_SHIFT)
1777 capchar[0] = scan_codes[dt].shift_altgr[0];
1778 else
1779 capchar[0] = scan_codes[dt].altgr[0];
1780 }
1781 else {
1782 if (shift_state & KB_SHIFT)
1783 capchar[0] = scan_codes[dt].shift[0];
1784 else
1785 capchar[0] = scan_codes[dt].unshift[0];
1786 }
1787 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1788 capchar[0] <= 'z') {
1789 capchar[0] -= ('a' - 'A');
1790 }
1791 capchar[0] |= (shift_state & KB_ALT);
1792 extended = 0;
1793 return capchar;
1794 case KB_NONE:
1795 printf("keycode %d\n",dt);
1796 break;
1797 case KB_FUNC: {
1798 char *more_chars;
1799 if (shift_state & KB_SHIFT)
1800 more_chars = scan_codes[dt].shift;
1801 else if (shift_state & KB_CTL)
1802 more_chars = scan_codes[dt].ctl;
1803 else
1804 more_chars = scan_codes[dt].unshift;
1805 extended = 0;
1806 return more_chars;
1807 }
1808 case KB_KP: {
1809 char *more_chars;
1810 if (shift_state & (KB_SHIFT | KB_CTL) ||
1811 (lock_state & KB_NUM) == 0 || extended)
1812 more_chars = scan_codes[dt].shift;
1813 else
1814 more_chars = scan_codes[dt].unshift;
1815 extended = 0;
1816 return more_chars;
1817 }
1818 }
1819 }
1820
1821 extended = 0;
1822 loop:
1823 if ((kbd_cmd_read_1() & KBS_DIB) == 0)
1824 return 0;
1825 goto top;
1826 }
1827
1828 paddr_t
1829 pcmmap(dev_t dev, off_t offset, int nprot)
1830 {
1831 struct pccons_context *pc = &pccons_console_context;
1832 paddr_t pa;
1833
1834 if (offset >= 0xa0000 && offset < 0xc0000) {
1835 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1836 return -1;
1837 pa += offset - pc->pc_config->pc_mono_memaddr;
1838 return mips_btop(pa);
1839 }
1840 if (offset >= 0x0000 && offset < 0x10000) {
1841 if (bus_space_paddr(pc->pc_crt_iot, pc->pc_mono_ioh, &pa))
1842 return -1;
1843 pa += offset - pc->pc_config->pc_mono_iobase;
1844 return mips_btop(pa);
1845 }
1846 if (offset >= 0x40000000 && offset < 0x40800000) {
1847 if (bus_space_paddr(pc->pc_crt_memt, pc->pc_mono_memh, &pa))
1848 return (-1);
1849 pa += offset - 0x40000000 - pc->pc_config->pc_mono_memaddr;
1850 return mips_btop(pa);
1851 }
1852 return -1;
1853 }
1854
1855 void
1856 pc_xmode_on(void)
1857 {
1858 if (pc_xmode)
1859 return;
1860 pc_xmode = 1;
1861
1862 #ifdef XFREE86_BUG_COMPAT
1863 /* If still unchanged, get current shape. */
1864 if (cursor_shape == 0xffff)
1865 get_cursor_shape();
1866 #endif
1867 }
1868
1869 void
1870 pc_xmode_off(void)
1871 {
1872 if (pc_xmode == 0)
1873 return;
1874 pc_xmode = 0;
1875
1876 #ifdef XFREE86_BUG_COMPAT
1877 /* XXX It would be hard to justify why the X server doesn't do this. */
1878 set_cursor_shape();
1879 #endif
1880 async_update();
1881 }
1882