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