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