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