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