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