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