pccons.c revision 1.21 1 /* $NetBSD: pccons.c,v 1.21 2000/06/26 04:55:25 simonb 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 /* NetBSD: pms.c,v 1.21 1995/04/18 02:25:18 mycroft Exp */
5
6 /*-
7 * Copyright (c) 1993, 1994, 1995 Charles M. Hannum. All rights reserved.
8 * Copyright (c) 1990 The Regents of the University of California.
9 * All rights reserved.
10 *
11 * This code is derived from software contributed to Berkeley by
12 * William Jolitz and Don Ahn.
13 *
14 * Copyright (c) 1994 Charles M. Hannum.
15 * Copyright (c) 1992, 1993 Erik Forsberg.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
19 * are met:
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 * 3. All advertising materials mentioning features or use of this software
26 * must display the following acknowledgement:
27 * This product includes software developed by the University of
28 * California, Berkeley and its contributors.
29 * 4. Neither the name of the University nor the names of its contributors
30 * may be used to endorse or promote products derived from this software
31 * without specific prior written permission.
32 *
33 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43 * SUCH DAMAGE.
44 *
45 * @(#)pccons.c 5.11 (Berkeley) 5/21/91
46 */
47
48 /*
49 * code to work keyboard & display for PC-style console
50 */
51
52 #include "opt_ddb.h"
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/ioctl.h>
57 #include <sys/proc.h>
58 #include <sys/user.h>
59 #include <sys/select.h>
60 #include <sys/tty.h>
61 #include <sys/uio.h>
62 #include <sys/callout.h>
63 #include <sys/syslog.h>
64 #include <sys/device.h>
65 #include <sys/poll.h>
66 #include <sys/conf.h>
67 #include <sys/vnode.h>
68 #include <sys/fcntl.h>
69 #include <sys/kernel.h>
70 #include <sys/kcore.h>
71
72 #include <dev/cons.h>
73
74 #include <machine/cpu.h>
75 #include <machine/pio.h>
76 #include <machine/autoconf.h>
77 #include <machine/bus.h>
78 #include <machine/display.h>
79 #include <machine/pccons.h>
80 #include <arc/arc/arctype.h>
81 #include <arc/arc/arcbios.h>
82 #include <arc/pica/pica.h>
83 #include <arc/dti/desktech.h>
84
85 #include <dev/isa/isavar.h>
86 #include <machine/isa_machdep.h>
87 #include <machine/kbdreg.h>
88
89 #include <dev/cons.h>
90
91 #include "pc.h"
92
93 #define XFREE86_BUG_COMPAT
94
95 #ifndef BEEP_FREQ
96 #define BEEP_FREQ 1600
97 #endif
98 #ifndef BEEP_TIME
99 #define BEEP_TIME (hz/5)
100 #endif
101
102 #define PCBURST 128
103
104 static u_short *Crtat; /* pointer to backing store */
105 static u_short *crtat; /* pointer to current char */
106 static u_char async, kernel, polling; /* Really, you don't want to know. */
107 static u_char lock_state = 0x00, /* all off */
108 old_lock_state = 0xff,
109 typematic_rate = 0xff, /* don't update until set by user */
110 old_typematic_rate = 0xff;
111 static u_short cursor_shape = 0xffff, /* don't update until set by user */
112 old_cursor_shape = 0xffff;
113 static pccons_keymap_t scan_codes[KB_NUM_KEYS];/* keyboard translation table */
114 int pc_xmode = 0;
115
116 cdev_decl(pc);
117
118 /*
119 * Keyboard output queue.
120 */
121 int kb_oq_put = 0;
122 int kb_oq_get = 0;
123 u_char kb_oq[8];
124
125 #define PCUNIT(x) (minor(x))
126
127 static struct video_state {
128 int cx, cy; /* escape parameters */
129 int row, col; /* current cursor position */
130 int nrow, ncol, nchr; /* current screen geometry */
131 int offset; /* Saved cursor pos */
132 u_char state; /* parser state */
133 #define VSS_ESCAPE 1
134 #define VSS_EBRACE 2
135 #define VSS_EPARAM 3
136 char so; /* in standout mode? */
137 char color; /* color or mono display */
138 char at; /* normal attributes */
139 char so_at; /* standout attributes */
140 } vs;
141
142 struct pc_softc {
143 struct device sc_dev;
144 struct tty *sc_tty;
145 };
146
147 struct opms_softc { /* driver status information */
148 struct device sc_dev;
149
150 struct clist sc_q;
151 struct selinfo sc_rsel;
152 u_char sc_state; /* mouse driver state */
153 #define PMS_OPEN 0x01 /* device is open */
154 #define PMS_ASLP 0x02 /* waiting for mouse data */
155 u_char sc_status; /* mouse button status */
156 int sc_x, sc_y; /* accumulated motion in the X,Y axis */
157 };
158
159 static struct callout async_update_ch = CALLOUT_INITIALIZER;
160
161 int pcprobe __P((struct device *, struct cfdata *, void *));
162 void pcattach __P((struct device *, struct device *, void *));
163 int pcintr __P((void *));
164 void pc_xmode_on __P((void));
165 void pc_xmode_off __P((void));
166 static u_char kbc_get8042cmd __P((void));
167 static int kbc_put8042cmd __P((u_char));
168 int kbc_8042sysreset __P((void));
169 int kbd_cmd __P((u_char, u_char));
170 static __inline int kbd_wait_output __P((void));
171 static __inline int kbd_wait_input __P((void));
172 static __inline void kbd_flush_input __P((void));
173 void set_cursor_shape __P((void));
174 void get_cursor_shape __P((void));
175 void async_update __P((void));
176 void do_async_update __P((u_char));;
177
178 void pccnattach __P((void));
179 void pccnputc __P((dev_t, int c));
180 int pccngetc __P((dev_t));
181 void pccnpollc __P((dev_t, int));
182
183 extern struct cfdriver pc_cd;
184
185 struct cfattach pc_pica_ca = {
186 sizeof(struct pc_softc), pcprobe, pcattach
187 };
188
189 struct cfattach pc_isa_ca = {
190 sizeof(struct pc_softc), pcprobe, pcattach
191 };
192
193 int opmsprobe __P((struct device *, struct cfdata *, void *));
194 void opmsattach __P((struct device *, struct device *, void *));
195 int opmsintr __P((void *));
196
197 #if NOPMS > 0
198 struct cfattach opms_ca = {
199 sizeof(struct opms_softc), opmsprobe, opmsattach
200 };
201 #endif
202
203 extern struct cfdriver opms_cd;
204
205 #define PMSUNIT(dev) (minor(dev))
206
207 #define CHR 2
208
209 static unsigned int addr_6845;
210 static unsigned int mono_base = 0x3b4;
211 static unsigned int mono_buf = 0xb0000;
212 static unsigned int cga_base = 0x3d4;
213 static unsigned int cga_buf = 0xb8000;
214 static unsigned int kbd_cmdp = 0x64;
215 static unsigned int kbd_datap = 0x60;
216
217 char *sget __P((void));
218 void sput __P((u_char *, int));
219
220 void pcstart __P((struct tty *));
221 int pcparam __P((struct tty *, struct termios *));
222 static __inline void wcopy __P((void *, void *, u_int));
223 void pcinithandle __P((void));
224
225 extern void fillw __P((int, u_int16_t *, int));
226
227 #define KBD_DELAY \
228 DELAY(10);
229
230 void
231 pcinithandle()
232 {
233 static int initialized = 0;
234
235 if (initialized)
236 return;
237 initialized = 1;
238
239 switch (cputype) {
240
241 case ACER_PICA_61:
242 case NEC_R96: /* XXX - not really confirmed */
243 mono_base += PICA_V_LOCAL_VIDEO_CTRL;
244 mono_buf += PICA_V_LOCAL_VIDEO;
245 cga_base += PICA_V_LOCAL_VIDEO_CTRL;
246 cga_buf += PICA_V_LOCAL_VIDEO;
247 case MAGNUM:
248 case NEC_R94:
249 case NEC_RAx94:
250 case NEC_RD94:
251 kbd_cmdp = PICA_SYS_KBD + 0x61;
252 kbd_datap = PICA_SYS_KBD + 0x60;
253 break;
254
255 case DESKSTATION_TYNE:
256 bus_space_map(&arc_bus_io, mono_base, 2, 0, &mono_base);
257 bus_space_map(&arc_bus_mem, mono_buf, 0x20000, 0, &mono_buf);
258 bus_space_map(&arc_bus_io, cga_base, 2, 0, &cga_base);
259 bus_space_map(&arc_bus_mem, cga_buf, 0x20000, 0, &cga_buf);
260 bus_space_map(&arc_bus_io, 0x64, 1, 0, &kbd_cmdp);
261 bus_space_map(&arc_bus_io, 0x60, 1, 0, &kbd_datap);
262 break;
263
264 case DESKSTATION_RPC44:
265 bus_space_map(&arc_bus_io, mono_base, 2, 0, &mono_base);
266 bus_space_map(&arc_bus_mem, mono_buf, 0x20000, 0, &mono_buf);
267 bus_space_map(&arc_bus_io, cga_base, 2, 0, &cga_base);
268 bus_space_map(&arc_bus_mem, 0xa0000, 0x20000, 0, &cga_buf);
269 bus_space_map(&arc_bus_io, 0x64, 1, 0, &kbd_cmdp);
270 bus_space_map(&arc_bus_io, 0x60, 1, 0, &kbd_datap);
271 break;
272
273 case SNI_RM200:
274 bus_space_map(&arc_bus_io, mono_base, 2, 0, &mono_base);
275 bus_space_map(&arc_bus_mem, mono_buf, 0x20000, 0, &mono_buf);
276 bus_space_map(&arc_bus_io, cga_base, 2, 0, &cga_base);
277 bus_space_map(&arc_bus_mem, cga_buf, 0x20000, 0, &cga_buf);
278 bus_space_map(&arc_bus_io, 0x64, 1, 0, &kbd_cmdp);
279 bus_space_map(&arc_bus_io, 0x60, 1, 0, &kbd_datap);
280 break;
281 }
282 }
283
284 /*
285 * bcopy variant that only moves word-aligned 16-bit entities,
286 * for stupid VGA cards. cnt is required to be an even vale.
287 */
288 static __inline void
289 wcopy(src, tgt, cnt)
290 void *src, *tgt;
291 u_int cnt;
292 {
293 u_int16_t *from = src;
294 u_int16_t *to = tgt;
295
296 cnt >>= 1;
297 if (to < from || to >= from + cnt)
298 while(cnt--)
299 *to++ = *from++;
300 else {
301 to += cnt;
302 from += cnt;
303 while(cnt--)
304 *--to = *--from;
305 }
306 }
307
308 static __inline int
309 kbd_wait_output()
310 {
311 u_int i;
312
313 for (i = 100000; i; i--)
314 if ((inb(kbd_cmdp) & KBS_IBF) == 0) {
315 KBD_DELAY;
316 return 1;
317 }
318 return 0;
319 }
320
321 static __inline int
322 kbd_wait_input()
323 {
324 u_int i;
325
326 for (i = 100000; i; i--)
327 if ((inb(kbd_cmdp) & KBS_DIB) != 0) {
328 KBD_DELAY;
329 return 1;
330 }
331 return 0;
332 }
333
334 static __inline void
335 kbd_flush_input()
336 {
337 u_char c;
338
339 while ((c = inb(kbd_cmdp)) & 0x03)
340 if ((c & KBS_DIB) == KBS_DIB) {
341 /* XXX - delay is needed to prevent some keyboards from
342 wedging when the system boots */
343 delay(6);
344 (void) inb(kbd_datap);
345 }
346 }
347
348
349
350 /*
351 * Pass system reset command to keyboard controller (8042).
352 */
353 int
354 kbc_8042sysreset()
355 {
356
357 pcinithandle();
358
359 if (!kbd_wait_output())
360 return 0;
361 outb(kbd_cmdp, 0xd1);
362 if (!kbd_wait_output())
363 return 0;
364 outb(kbd_datap, 0); /* ZAP */
365 return 1;
366 }
367
368 #if 1
369 /*
370 * Get the current command byte.
371 */
372 static u_char
373 kbc_get8042cmd()
374 {
375
376 if (!kbd_wait_output())
377 return -1;
378 outb(kbd_cmdp, K_RDCMDBYTE);
379 if (!kbd_wait_input())
380 return -1;
381 return inb(kbd_datap);
382 }
383 #endif
384
385 /*
386 * Pass command byte to keyboard controller (8042).
387 */
388 static int
389 kbc_put8042cmd(val)
390 u_char val;
391 {
392
393 if (!kbd_wait_output())
394 return 0;
395 outb(kbd_cmdp, K_LDCMDBYTE);
396 if (!kbd_wait_output())
397 return 0;
398 outb(kbd_datap, val);
399 return 1;
400 }
401
402 /*
403 * Pass command to keyboard itself
404 */
405 int
406 kbd_cmd(val, polling)
407 u_char val;
408 u_char polling;
409 {
410 u_int retries = 3;
411 register u_int i;
412
413 if(!polling) {
414 i = spltty();
415 if(kb_oq_get == kb_oq_put) {
416 outb(kbd_datap, val);
417 }
418 kb_oq[kb_oq_put] = val;
419 kb_oq_put = (kb_oq_put + 1) & 7;
420 splx(i);
421 return(1);
422 }
423 else do {
424 if (!kbd_wait_output())
425 return 0;
426 outb(kbd_datap, val);
427 for (i = 100000; i; i--) {
428 if (inb(kbd_cmdp) & KBS_DIB) {
429 register u_char c;
430
431 KBD_DELAY;
432 c = inb(kbd_datap);
433 if (c == KBR_ACK || c == KBR_ECHO) {
434 return 1;
435 }
436 if (c == KBR_RESEND) {
437 break;
438 }
439 #ifdef DIAGNOSTIC
440 printf("kbd_cmd: input char %x lost\n", c);
441 #endif
442 }
443 }
444 } while (--retries);
445 return 0;
446 }
447
448 void
449 set_cursor_shape()
450 {
451 register int iobase = addr_6845;
452
453 outb(iobase, 10);
454 outb(iobase+1, cursor_shape >> 8);
455 outb(iobase, 11);
456 outb(iobase+1, cursor_shape);
457 old_cursor_shape = cursor_shape;
458 }
459
460 void
461 get_cursor_shape()
462 {
463 register int iobase = addr_6845;
464
465 outb(iobase, 10);
466 cursor_shape = inb(iobase+1) << 8;
467 outb(iobase, 11);
468 cursor_shape |= inb(iobase+1);
469
470 /*
471 * real 6845's, as found on, MDA, Hercules or CGA cards, do
472 * not support reading the cursor shape registers. the 6845
473 * tri-states it's data bus. This is _normally_ read by the
474 * cpu as either 0x00 or 0xff.. in which case we just use
475 * a line cursor.
476 */
477 if (cursor_shape == 0x0000 || cursor_shape == 0xffff)
478 cursor_shape = 0x0b10;
479 else
480 cursor_shape &= 0x1f1f;
481 }
482
483 void
484 do_async_update(poll)
485 u_char poll;
486 {
487 int pos;
488 static int old_pos = -1;
489
490 async = 0;
491
492 if (lock_state != old_lock_state) {
493 old_lock_state = lock_state;
494 if (!kbd_cmd(KBC_MODEIND, poll) ||
495 !kbd_cmd(lock_state, poll)) {
496 printf("pc: timeout updating leds\n");
497 (void) kbd_cmd(KBC_ENABLE, poll);
498 }
499 }
500 if (typematic_rate != old_typematic_rate) {
501 old_typematic_rate = typematic_rate;
502 if (!kbd_cmd(KBC_TYPEMATIC, poll) ||
503 !kbd_cmd(typematic_rate, poll)) {
504 printf("pc: timeout updating typematic rate\n");
505 (void) kbd_cmd(KBC_ENABLE, poll);
506 }
507 }
508
509 if (pc_xmode > 0)
510 return;
511
512 pos = crtat - Crtat;
513 if (pos != old_pos) {
514 register int iobase = addr_6845;
515 outb(iobase, 14);
516 outb(iobase+1, pos >> 8);
517 outb(iobase, 15);
518 outb(iobase+1, pos);
519 old_pos = pos;
520 }
521 if (cursor_shape != old_cursor_shape)
522 set_cursor_shape();
523 }
524
525 void
526 async_update()
527 {
528
529 if (kernel || polling) {
530 if (async)
531 callout_stop(&async_update_ch);
532 do_async_update(1);
533 } else {
534 if (async)
535 return;
536 async = 1;
537 callout_reset(&async_update_ch, 1,
538 (void(*)(void *))do_async_update, NULL);
539 }
540 }
541
542 /*
543 * these are both bad jokes
544 */
545 int
546 pcprobe(parent, match, aux)
547 struct device *parent;
548 struct cfdata *match;
549 void *aux;
550 {
551 struct confargs *ca = aux;
552 u_int i;
553
554 /* Make shure we're looking for this type of device */
555 if(!strcmp((parent)->dv_cfdata->cf_driver->cd_name, "pica")) {
556 if(!BUS_MATCHNAME(ca, "pckbd"))
557 return(0);
558
559 switch (cputype) { /* XXX ick */
560 case ACER_PICA_61:
561 case NEC_R96: /* XXX - not really confirmed */
562 break;
563 default:
564 return (0);
565 }
566 } else { /* ISA */
567 switch (cputype) { /* XXX ick */
568 case DESKSTATION_RPC44:
569 case DESKSTATION_TYNE:
570 break;
571 default:
572 return (0);
573 }
574 }
575
576 pcinithandle();
577
578 /* Enable interrupts and keyboard, etc. */
579 if (!kbc_put8042cmd(CMDBYTE)) {
580 printf("pcprobe: command error\n");
581 return 0;
582 }
583
584 #if 1
585 /* Flush any garbage. */
586 kbd_flush_input();
587 /* Reset the keyboard. */
588 if (!kbd_cmd(KBC_RESET, 1)) {
589 printf("pcprobe: reset error %d\n", 1);
590 goto lose;
591 }
592 for (i = 600000; i; i--)
593 if ((inb(kbd_cmdp) & KBS_DIB) != 0) {
594 KBD_DELAY;
595 break;
596 }
597 if (i == 0 || inb(kbd_datap) != KBR_RSTDONE) {
598 printf("pcprobe: reset error %d\n", 2);
599 goto lose;
600 }
601 /*
602 * Some keyboards seem to leave a second ack byte after the reset.
603 * This is kind of stupid, but we account for them anyway by just
604 * flushing the buffer.
605 */
606 kbd_flush_input();
607 /* Just to be sure. */
608 if (!kbd_cmd(KBC_ENABLE, 1)) {
609 printf("pcprobe: reset error %d\n", 3);
610 goto lose;
611 }
612
613 /*
614 * Some keyboard/8042 combinations do not seem to work if the keyboard
615 * is set to table 1; in fact, it would appear that some keyboards just
616 * ignore the command altogether. So by default, we use the AT scan
617 * codes and have the 8042 translate them. Unfortunately, this is
618 * known to not work on some PS/2 machines. We try desparately to deal
619 * with this by checking the (lack of a) translate bit in the 8042 and
620 * attempting to set the keyboard to XT mode. If this all fails, well,
621 * tough luck.
622 *
623 * XXX It would perhaps be a better choice to just use AT scan codes
624 * and not bother with this.
625 */
626 if (kbc_get8042cmd() & KC8_TRANS) {
627 /* The 8042 is translating for us; use AT codes. */
628 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(2, 1)) {
629 printf("pcprobe: reset error %d\n", 4);
630 goto lose;
631 }
632 } else {
633 /* Stupid 8042; set keyboard to XT codes. */
634 if (!kbd_cmd(KBC_SETTABLE, 1) || !kbd_cmd(1, 1)) {
635 printf("pcprobe: reset error %d\n", 5);
636 goto lose;
637 }
638 }
639
640 lose:
641 /*
642 * Technically, we should probably fail the probe. But we'll be nice
643 * and allow keyboard-less machines to boot with the console.
644 */
645 #endif
646
647 return 1;
648 }
649
650 void
651 pcattach(parent, self, aux)
652 struct device *parent, *self;
653 void *aux;
654 {
655 struct confargs *ca = aux;
656 struct isa_attach_args *ia = aux;
657 struct pc_softc *sc = (void *)self;
658
659 printf(": %s\n", vs.color ? "color" : "mono");
660 do_async_update(1);
661
662 switch (cputype) {
663 case ACER_PICA_61:
664 case NEC_R96:
665 BUS_INTR_ESTABLISH(ca, pcintr, (void *)(long)sc);
666 break;
667 case DESKSTATION_RPC44: /* XXX ick */
668 case DESKSTATION_TYNE:
669 isa_intr_establish(ia->ia_ic, ia->ia_irq, 1,
670 2, pcintr, sc); /*XXX ick */
671 break;
672 }
673 }
674
675 int
676 pcopen(dev, flag, mode, p)
677 dev_t dev;
678 int flag, mode;
679 struct proc *p;
680 {
681 struct pc_softc *sc;
682 int unit = PCUNIT(dev);
683 struct tty *tp;
684
685 if (unit >= pc_cd.cd_ndevs)
686 return ENXIO;
687 sc = pc_cd.cd_devs[unit];
688 if (sc == 0)
689 return ENXIO;
690
691 if (!sc->sc_tty) {
692 tp = sc->sc_tty = ttymalloc();
693 }
694 else {
695 tp = sc->sc_tty;
696 }
697
698 tp->t_oproc = pcstart;
699 tp->t_param = pcparam;
700 tp->t_dev = dev;
701 if ((tp->t_state & TS_ISOPEN) == 0) {
702 ttychars(tp);
703 tp->t_iflag = TTYDEF_IFLAG;
704 tp->t_oflag = TTYDEF_OFLAG;
705 tp->t_cflag = TTYDEF_CFLAG;
706 tp->t_lflag = TTYDEF_LFLAG;
707 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
708 pcparam(tp, &tp->t_termios);
709 ttsetwater(tp);
710 } else if (tp->t_state&TS_XCLUDE && p->p_ucred->cr_uid != 0)
711 return EBUSY;
712 tp->t_state |= TS_CARR_ON;
713
714 return ((*linesw[tp->t_line].l_open)(dev, tp));
715 }
716
717 int
718 pcclose(dev, flag, mode, p)
719 dev_t dev;
720 int flag, mode;
721 struct proc *p;
722 {
723 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
724 struct tty *tp = sc->sc_tty;
725
726 (*linesw[tp->t_line].l_close)(tp, flag);
727 ttyclose(tp);
728 #ifdef notyet /* XXX */
729 ttyfree(tp);
730 #endif
731 return(0);
732 }
733
734 int
735 pcread(dev, uio, flag)
736 dev_t dev;
737 struct uio *uio;
738 int flag;
739 {
740 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
741 struct tty *tp = sc->sc_tty;
742
743 return ((*linesw[tp->t_line].l_read)(tp, uio, flag));
744 }
745
746 int
747 pcwrite(dev, uio, flag)
748 dev_t dev;
749 struct uio *uio;
750 int flag;
751 {
752 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
753 struct tty *tp = sc->sc_tty;
754
755 return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
756 }
757
758 struct tty *
759 pctty(dev)
760 dev_t dev;
761 {
762 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
763 struct tty *tp = sc->sc_tty;
764
765 return (tp);
766 }
767
768 /*
769 * Got a console receive interrupt -
770 * the console processor wants to give us a character.
771 * Catch the character, and see who it goes to.
772 */
773 int
774 pcintr(arg)
775 void *arg;
776 {
777 struct pc_softc *sc = arg;
778 register struct tty *tp = sc->sc_tty;
779 u_char *cp;
780
781 if ((inb(kbd_cmdp) & KBS_DIB) == 0)
782 return 0;
783 if (polling)
784 return 1;
785 do {
786 cp = sget();
787 if (!tp || (tp->t_state & TS_ISOPEN) == 0)
788 return 1;
789 if (cp)
790 do
791 (*linesw[tp->t_line].l_rint)(*cp++, tp);
792 while (*cp);
793 } while (inb(kbd_cmdp) & KBS_DIB);
794 return 1;
795 }
796
797 int
798 pcioctl(dev, cmd, data, flag, p)
799 dev_t dev;
800 u_long cmd;
801 caddr_t data;
802 int flag;
803 struct proc *p;
804 {
805 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
806 struct tty *tp = sc->sc_tty;
807 int error;
808
809 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
810 if (error >= 0)
811 return error;
812 error = ttioctl(tp, cmd, data, flag, p);
813 if (error >= 0)
814 return error;
815
816 switch (cmd) {
817 case CONSOLE_X_MODE_ON:
818 pc_xmode_on();
819 return 0;
820 case CONSOLE_X_MODE_OFF:
821 pc_xmode_off();
822 return 0;
823 case CONSOLE_X_BELL:
824 /*
825 * If set, data is a pointer to a length 2 array of
826 * integers. data[0] is the pitch in Hz and data[1]
827 * is the duration in msec.
828 */
829 if (data)
830 sysbeep(((int*)data)[0],
831 (((int*)data)[1] * hz) / 1000);
832 else
833 sysbeep(BEEP_FREQ, BEEP_TIME);
834 return 0;
835 case CONSOLE_SET_TYPEMATIC_RATE: {
836 u_char rate;
837
838 if (!data)
839 return EINVAL;
840 rate = *((u_char *)data);
841 /*
842 * Check that it isn't too big (which would cause it to be
843 * confused with a command).
844 */
845 if (rate & 0x80)
846 return EINVAL;
847 typematic_rate = rate;
848 async_update();
849 return 0;
850 }
851 case CONSOLE_SET_KEYMAP: {
852 pccons_keymap_t *map = (pccons_keymap_t *) data;
853 int i;
854
855 if (!data)
856 return EINVAL;
857 for (i = 0; i < KB_NUM_KEYS; i++)
858 if (map[i].unshift[KB_CODE_SIZE-1] ||
859 map[i].shift[KB_CODE_SIZE-1] ||
860 map[i].ctl[KB_CODE_SIZE-1] ||
861 map[i].altgr[KB_CODE_SIZE-1] ||
862 map[i].shift_altgr[KB_CODE_SIZE-1])
863 return EINVAL;
864
865 bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
866 return 0;
867 }
868 case CONSOLE_GET_KEYMAP:
869 if (!data)
870 return EINVAL;
871 bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
872 return 0;
873
874 default:
875 return ENOTTY;
876 }
877
878 #ifdef DIAGNOSTIC
879 panic("pcioctl: impossible");
880 #endif
881 }
882
883 void
884 pcstart(tp)
885 struct tty *tp;
886 {
887 struct clist *cl;
888 int s, len;
889 u_char buf[PCBURST];
890
891 s = spltty();
892 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
893 goto out;
894 tp->t_state |= TS_BUSY;
895 splx(s);
896 /*
897 * We need to do this outside spl since it could be fairly
898 * expensive and we don't want our serial ports to overflow.
899 */
900 cl = &tp->t_outq;
901 len = q_to_b(cl, buf, PCBURST);
902 sput(buf, len);
903 s = spltty();
904 tp->t_state &= ~TS_BUSY;
905 if (cl->c_cc) {
906 tp->t_state |= TS_TIMEOUT;
907 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
908 }
909 if (cl->c_cc <= tp->t_lowat) {
910 if (tp->t_state & TS_ASLEEP) {
911 tp->t_state &= ~TS_ASLEEP;
912 wakeup(cl);
913 }
914 selwakeup(&tp->t_wsel);
915 }
916 out:
917 splx(s);
918 }
919
920 void
921 pcstop(tp, flag)
922 struct tty *tp;
923 int flag;
924 {
925 }
926
927 /* ARGSUSED */
928 void
929 pccnattach()
930 {
931 int maj;
932 static struct consdev pccons = {
933 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL,
934 NODEV, CN_NORMAL
935 };
936
937 /*
938 * For now, don't screw with it.
939 */
940 /* crtat = 0; */
941 pcinithandle();
942
943 switch (cputype) {
944
945 case ACER_PICA_61:
946 case NEC_R96: /* XXX - not really confirmed */
947 break;
948
949 case DESKSTATION_TYNE:
950 outb(arc_bus_io.bs_vbase + 0x3ce, 6); /* Correct video mode */
951 outb(arc_bus_io.bs_vbase + 0x3cf,
952 inb(arc_bus_io.bs_vbase + 0x3cf) | 0xc);
953 kbc_put8042cmd(CMDBYTE); /* Want XT codes.. */
954 break;
955
956 case DESKSTATION_RPC44:
957 kbc_put8042cmd(CMDBYTE); /* Want XT codes.. */
958 break;
959
960 case SNI_RM200:
961 break;
962 }
963
964 /* locate the major number */
965 for (maj = 0; maj < nchrdev; maj++)
966 if (cdevsw[maj].d_open == pcopen)
967 break;
968 pccons.cn_dev = makedev(maj, 0);
969
970 cn_tab = &pccons;
971 }
972
973 /* ARGSUSED */
974 void
975 pccnputc(dev, c)
976 dev_t dev;
977 int c;
978 {
979 u_char cc, oldkernel = kernel;
980
981 kernel = 1;
982 if (c == '\n') {
983 sput("\r\n", 2);
984 } else {
985 cc = c;
986 sput(&cc, 1);
987 }
988 kernel = oldkernel;
989 }
990
991 /* ARGSUSED */
992 int
993 pccngetc(dev)
994 dev_t dev;
995 {
996 register char *cp;
997
998 if (pc_xmode > 0)
999 return 0;
1000
1001 do {
1002 /* wait for byte */
1003 while ((inb(kbd_cmdp) & KBS_DIB) == 0);
1004 /* see if it's worthwhile */
1005 cp = sget();
1006 } while (!cp);
1007 if (*cp == '\r')
1008 return '\n';
1009 return *cp;
1010 }
1011
1012 void
1013 pccnpollc(dev, on)
1014 dev_t dev;
1015 int on;
1016 {
1017
1018 polling = on;
1019 if (!on) {
1020 int unit;
1021 struct pc_softc *sc;
1022 int s;
1023
1024 /*
1025 * If disabling polling on a device that's been configured,
1026 * make sure there are no bytes left in the FIFO, holding up
1027 * the interrupt line. Otherwise we won't get any further
1028 * interrupts.
1029 */
1030 unit = PCUNIT(dev);
1031 if (pc_cd.cd_ndevs > unit) {
1032 sc = pc_cd.cd_devs[unit];
1033 if (sc != 0) {
1034 s = spltty();
1035 pcintr(sc);
1036 splx(s);
1037 }
1038 }
1039 }
1040 }
1041
1042 /*
1043 * Set line parameters.
1044 */
1045 int
1046 pcparam(tp, t)
1047 struct tty *tp;
1048 struct termios *t;
1049 {
1050
1051 tp->t_ispeed = t->c_ispeed;
1052 tp->t_ospeed = t->c_ospeed;
1053 tp->t_cflag = t->c_cflag;
1054 return 0;
1055 }
1056
1057 #define wrtchar(c, at) do {\
1058 char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \
1059 } while (0)
1060
1061 /* translate ANSI color codes to standard pc ones */
1062 static char fgansitopc[] = {
1063 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
1064 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
1065 };
1066
1067 static char bgansitopc[] = {
1068 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
1069 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
1070 };
1071
1072 static u_char iso2ibm437[] =
1073 {
1074 0, 0, 0, 0, 0, 0, 0, 0,
1075 0, 0, 0, 0, 0, 0, 0, 0,
1076 0, 0, 0, 0, 0, 0, 0, 0,
1077 0, 0, 0, 0, 0, 0, 0, 0,
1078 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
1079 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
1080 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
1081 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
1082 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
1083 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
1084 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
1085 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
1086 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
1087 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
1088 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
1089 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
1090 };
1091
1092 /*
1093 * `pc3' termcap emulation.
1094 */
1095 void
1096 sput(cp, n)
1097 u_char *cp;
1098 int n;
1099 {
1100 u_char c, scroll = 0;
1101
1102 if (pc_xmode > 0)
1103 return;
1104
1105 if (crtat == 0) {
1106 volatile u_short *cp;
1107 u_short was;
1108 unsigned cursorat;
1109
1110 cp = (volatile u_short *)cga_buf;
1111 was = *cp;
1112 *cp = (volatile u_short) 0xA55A;
1113 if (*cp != 0xA55A) {
1114 cp = (volatile u_short *)mono_buf;
1115 addr_6845 = mono_base;
1116 vs.color = 0;
1117 } else {
1118 *cp = was;
1119 addr_6845 = cga_base;
1120 vs.color = 1;
1121 }
1122
1123 #ifdef FAT_CURSOR
1124 cursor_shape = 0x0012;
1125 #else
1126 get_cursor_shape();
1127 #endif
1128
1129 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
1130 vs.nchr = vs.ncol * vs.nrow;
1131 vs.col--;
1132 vs.row--;
1133 cursorat = vs.ncol * vs.row + vs.col;
1134 vs.at = FG_LIGHTGREY | BG_BLACK;
1135
1136 Crtat = (u_short *)cp;
1137 crtat = Crtat + cursorat;
1138
1139 if (vs.color == 0)
1140 vs.so_at = FG_BLACK | BG_LIGHTGREY;
1141 else
1142 vs.so_at = FG_YELLOW | BG_BLACK;
1143
1144 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1145 }
1146
1147 while (n--) {
1148 if (!(c = *cp++))
1149 continue;
1150
1151 switch (c) {
1152 case 0x1B:
1153 if (vs.state >= VSS_ESCAPE) {
1154 wrtchar(c, vs.so_at);
1155 vs.state = 0;
1156 goto maybe_scroll;
1157 } else
1158 vs.state = VSS_ESCAPE;
1159 break;
1160
1161 case 0x9B: /* CSI */
1162 vs.cx = vs.cy = 0;
1163 vs.state = VSS_EBRACE;
1164 break;
1165
1166 case '\t': {
1167 int inccol = 8 - (vs.col & 7);
1168 crtat += inccol;
1169 vs.col += inccol;
1170 }
1171 maybe_scroll:
1172 if (vs.col >= vs.ncol) {
1173 vs.col -= vs.ncol;
1174 scroll = 1;
1175 }
1176 break;
1177
1178 case '\b':
1179 if (crtat <= Crtat)
1180 break;
1181 --crtat;
1182 if (--vs.col < 0)
1183 vs.col += vs.ncol; /* non-destructive backspace */
1184 break;
1185
1186 case '\r':
1187 crtat -= vs.col;
1188 vs.col = 0;
1189 break;
1190
1191 case '\n':
1192 crtat += vs.ncol;
1193 scroll = 1;
1194 break;
1195
1196 default:
1197 switch (vs.state) {
1198 case 0:
1199 if (c == '\a')
1200 sysbeep(BEEP_FREQ, BEEP_TIME);
1201 else {
1202 /*
1203 * If we're outputting multiple printed
1204 * characters, just blast them to the
1205 * screen until we reach the end of the
1206 * buffer or a control character. This
1207 * saves time by short-circuiting the
1208 * switch.
1209 * If we reach the end of the line, we
1210 * break to do a scroll check.
1211 */
1212 for (;;) {
1213 if (c & 0x80)
1214 c = iso2ibm437[c&0x7f];
1215
1216 if (vs.so)
1217 wrtchar(c, vs.so_at);
1218 else
1219 wrtchar(c, vs.at);
1220 if (vs.col >= vs.ncol) {
1221 vs.col = 0;
1222 scroll = 1;
1223 break;
1224 }
1225 if (!n || (c = *cp) < ' ')
1226 break;
1227 n--, cp++;
1228 }
1229 }
1230 break;
1231 case VSS_ESCAPE:
1232 switch (c) {
1233 case '[': /* Start ESC [ sequence */
1234 vs.cx = vs.cy = 0;
1235 vs.state = VSS_EBRACE;
1236 break;
1237 case 'c': /* Create screen & home */
1238 fillw((vs.at << 8) | ' ',
1239 Crtat, vs.nchr);
1240 crtat = Crtat;
1241 vs.col = 0;
1242 vs.state = 0;
1243 break;
1244 case '7': /* save cursor pos */
1245 vs.offset = crtat - Crtat;
1246 vs.state = 0;
1247 break;
1248 case '8': /* restore cursor pos */
1249 crtat = Crtat + vs.offset;
1250 vs.row = vs.offset / vs.ncol;
1251 vs.col = vs.offset % vs.ncol;
1252 vs.state = 0;
1253 break;
1254 default: /* Invalid, clear state */
1255 wrtchar(c, vs.so_at);
1256 vs.state = 0;
1257 goto maybe_scroll;
1258 }
1259 break;
1260
1261 default: /* VSS_EBRACE or VSS_EPARAM */
1262 switch (c) {
1263 int pos;
1264 case 'm':
1265 if (!vs.cx)
1266 vs.so = 0;
1267 else
1268 vs.so = 1;
1269 vs.state = 0;
1270 break;
1271 case 'A': { /* back cx rows */
1272 int cx = vs.cx;
1273 if (cx <= 0)
1274 cx = 1;
1275 else
1276 cx %= vs.nrow;
1277 pos = crtat - Crtat;
1278 pos -= vs.ncol * cx;
1279 if (pos < 0)
1280 pos += vs.nchr;
1281 crtat = Crtat + pos;
1282 vs.state = 0;
1283 break;
1284 }
1285 case 'B': { /* down cx rows */
1286 int cx = vs.cx;
1287 if (cx <= 0)
1288 cx = 1;
1289 else
1290 cx %= vs.nrow;
1291 pos = crtat - Crtat;
1292 pos += vs.ncol * cx;
1293 if (pos >= vs.nchr)
1294 pos -= vs.nchr;
1295 crtat = Crtat + pos;
1296 vs.state = 0;
1297 break;
1298 }
1299 case 'C': { /* right cursor */
1300 int cx = vs.cx,
1301 col = vs.col;
1302 if (cx <= 0)
1303 cx = 1;
1304 else
1305 cx %= vs.ncol;
1306 pos = crtat - Crtat;
1307 pos += cx;
1308 col += cx;
1309 if (col >= vs.ncol) {
1310 pos -= vs.ncol;
1311 col -= vs.ncol;
1312 }
1313 vs.col = col;
1314 crtat = Crtat + pos;
1315 vs.state = 0;
1316 break;
1317 }
1318 case 'D': { /* left cursor */
1319 int cx = vs.cx,
1320 col = vs.col;
1321 if (cx <= 0)
1322 cx = 1;
1323 else
1324 cx %= vs.ncol;
1325 pos = crtat - Crtat;
1326 pos -= cx;
1327 col -= cx;
1328 if (col < 0) {
1329 pos += vs.ncol;
1330 col += vs.ncol;
1331 }
1332 vs.col = col;
1333 crtat = Crtat + pos;
1334 vs.state = 0;
1335 break;
1336 }
1337 case 'J': /* Clear ... */
1338 switch (vs.cx) {
1339 case 0:
1340 /* ... to end of display */
1341 fillw((vs.at << 8) | ' ',
1342 crtat,
1343 Crtat + vs.nchr - crtat);
1344 break;
1345 case 1:
1346 /* ... to next location */
1347 fillw((vs.at << 8) | ' ',
1348 Crtat,
1349 crtat - Crtat + 1);
1350 break;
1351 case 2:
1352 /* ... whole display */
1353 fillw((vs.at << 8) | ' ',
1354 Crtat,
1355 vs.nchr);
1356 break;
1357 }
1358 vs.state = 0;
1359 break;
1360 case 'K': /* Clear line ... */
1361 switch (vs.cx) {
1362 case 0:
1363 /* ... current to EOL */
1364 fillw((vs.at << 8) | ' ',
1365 crtat,
1366 vs.ncol - vs.col);
1367 break;
1368 case 1:
1369 /* ... beginning to next */
1370 fillw((vs.at << 8) | ' ',
1371 crtat - vs.col,
1372 vs.col + 1);
1373 break;
1374 case 2:
1375 /* ... entire line */
1376 fillw((vs.at << 8) | ' ',
1377 crtat - vs.col, vs.ncol);
1378 break;
1379 }
1380 vs.state = 0;
1381 break;
1382 case 'f': /* in system V consoles */
1383 case 'H': { /* Cursor move */
1384 int cx = vs.cx,
1385 cy = vs.cy;
1386 if (!cx || !cy) {
1387 crtat = Crtat;
1388 vs.col = 0;
1389 } else {
1390 if (cx > vs.nrow)
1391 cx = vs.nrow;
1392 if (cy > vs.ncol)
1393 cy = vs.ncol;
1394 crtat = Crtat +
1395 (cx - 1) * vs.ncol + cy - 1;
1396 vs.col = cy - 1;
1397 }
1398 vs.state = 0;
1399 break;
1400 }
1401 case 'M': { /* delete cx rows */
1402 u_short *crtAt = crtat - vs.col;
1403 int cx = vs.cx,
1404 row = (crtAt - Crtat) / vs.ncol,
1405 nrow = vs.nrow - row;
1406 if (cx <= 0)
1407 cx = 1;
1408 else if (cx > nrow)
1409 cx = nrow;
1410 if (cx < nrow)
1411 #ifdef PCCONS_FORCE_WORD
1412 wcopy(crtAt + vs.ncol * cx,
1413 crtAt, vs.ncol * (nrow -
1414 cx) * CHR);
1415 #else
1416 bcopy(crtAt + vs.ncol * cx,
1417 crtAt, vs.ncol * (nrow -
1418 cx) * CHR);
1419 #endif
1420 fillw((vs.at << 8) | ' ',
1421 crtAt + vs.ncol * (nrow - cx),
1422 vs.ncol * cx);
1423 vs.state = 0;
1424 break;
1425 }
1426 case 'S': { /* scroll up cx lines */
1427 int cx = vs.cx;
1428 if (cx <= 0)
1429 cx = 1;
1430 else if (cx > vs.nrow)
1431 cx = vs.nrow;
1432 if (cx < vs.nrow)
1433 #ifdef PCCONS_FORCE_WORD
1434 wcopy(Crtat + vs.ncol * cx,
1435 Crtat, vs.ncol * (vs.nrow -
1436 cx) * CHR);
1437 #else
1438 bcopy(Crtat + vs.ncol * cx,
1439 Crtat, vs.ncol * (vs.nrow -
1440 cx) * CHR);
1441 #endif
1442 fillw((vs.at << 8) | ' ',
1443 Crtat + vs.ncol * (vs.nrow - cx),
1444 vs.ncol * cx);
1445 /* crtat -= vs.ncol * cx; XXX */
1446 vs.state = 0;
1447 break;
1448 }
1449 case 'L': { /* insert cx rows */
1450 u_short *crtAt = crtat - vs.col;
1451 int cx = vs.cx,
1452 row = (crtAt - Crtat) / vs.ncol,
1453 nrow = vs.nrow - row;
1454 if (cx <= 0)
1455 cx = 1;
1456 else if (cx > nrow)
1457 cx = nrow;
1458 if (cx < nrow)
1459 #ifdef PCCONS_FORCE_WORD
1460 wcopy(crtAt,
1461 crtAt + vs.ncol * cx,
1462 vs.ncol * (nrow - cx) *
1463 CHR);
1464 #else
1465 bcopy(crtAt,
1466 crtAt + vs.ncol * cx,
1467 vs.ncol * (nrow - cx) *
1468 CHR);
1469 #endif
1470 fillw((vs.at << 8) | ' ', crtAt,
1471 vs.ncol * cx);
1472 vs.state = 0;
1473 break;
1474 }
1475 case 'T': { /* scroll down cx lines */
1476 int cx = vs.cx;
1477 if (cx <= 0)
1478 cx = 1;
1479 else if (cx > vs.nrow)
1480 cx = vs.nrow;
1481 if (cx < vs.nrow)
1482 #ifdef PCCONS_FORCE_WORD
1483 wcopy(Crtat,
1484 Crtat + vs.ncol * cx,
1485 vs.ncol * (vs.nrow - cx) *
1486 CHR);
1487 #else
1488 bcopy(Crtat,
1489 Crtat + vs.ncol * cx,
1490 vs.ncol * (vs.nrow - cx) *
1491 CHR);
1492 #endif
1493 fillw((vs.at << 8) | ' ', Crtat,
1494 vs.ncol * cx);
1495 /* crtat += vs.ncol * cx; XXX */
1496 vs.state = 0;
1497 break;
1498 }
1499 case ';': /* Switch params in cursor def */
1500 vs.state = VSS_EPARAM;
1501 break;
1502 case 'r':
1503 vs.so_at = (vs.cx & FG_MASK) |
1504 ((vs.cy << 4) & BG_MASK);
1505 vs.state = 0;
1506 break;
1507 case 's': /* save cursor pos */
1508 vs.offset = crtat - Crtat;
1509 vs.state = 0;
1510 break;
1511 case 'u': /* restore cursor pos */
1512 crtat = Crtat + vs.offset;
1513 vs.row = vs.offset / vs.ncol;
1514 vs.col = vs.offset % vs.ncol;
1515 vs.state = 0;
1516 break;
1517 case 'x': /* set attributes */
1518 switch (vs.cx) {
1519 case 0:
1520 vs.at = FG_LIGHTGREY | BG_BLACK;
1521 break;
1522 case 1:
1523 /* ansi background */
1524 if (!vs.color)
1525 break;
1526 vs.at &= FG_MASK;
1527 vs.at |= bgansitopc[vs.cy & 7];
1528 break;
1529 case 2:
1530 /* ansi foreground */
1531 if (!vs.color)
1532 break;
1533 vs.at &= BG_MASK;
1534 vs.at |= fgansitopc[vs.cy & 7];
1535 break;
1536 case 3:
1537 /* pc text attribute */
1538 if (vs.state >= VSS_EPARAM)
1539 vs.at = vs.cy;
1540 break;
1541 }
1542 vs.state = 0;
1543 break;
1544
1545 default: /* Only numbers valid here */
1546 if ((c >= '0') && (c <= '9')) {
1547 if (vs.state >= VSS_EPARAM) {
1548 vs.cy *= 10;
1549 vs.cy += c - '0';
1550 } else {
1551 vs.cx *= 10;
1552 vs.cx += c - '0';
1553 }
1554 } else
1555 vs.state = 0;
1556 break;
1557 }
1558 break;
1559 }
1560 }
1561 if (scroll) {
1562 scroll = 0;
1563 /* scroll check */
1564 if (crtat >= Crtat + vs.nchr) {
1565 if (!kernel) {
1566 int s = spltty();
1567 if (lock_state & KB_SCROLL)
1568 tsleep(&lock_state,
1569 PUSER, "pcputc", 0);
1570 splx(s);
1571 }
1572 #if PCCONS_FORCE_WORD
1573 wcopy(Crtat + vs.ncol, Crtat,
1574 (vs.nchr - vs.ncol) * CHR);
1575 #else
1576 bcopy(Crtat + vs.ncol, Crtat,
1577 (vs.nchr - vs.ncol) * CHR);
1578 #endif
1579 fillw((vs.at << 8) | ' ',
1580 Crtat + vs.nchr - vs.ncol,
1581 vs.ncol);
1582 crtat -= vs.ncol;
1583 }
1584 }
1585 }
1586 async_update();
1587 }
1588
1589 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1590 left and right shift when reading the keyboard map */
1591 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = {
1592 /* type unshift shift control altgr shift_altgr scancode */
1593 { KB_NONE, "", "", "", "", ""}, /* 0 unused */
1594 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */
1595 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */
1596 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */
1597 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */
1598 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */
1599 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */
1600 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */
1601 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */
1602 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */
1603 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */
1604 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */
1605 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */
1606 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */
1607 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */
1608 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */
1609 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */
1610 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */
1611 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */
1612 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */
1613 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */
1614 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */
1615 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */
1616 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */
1617 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */
1618 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */
1619 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */
1620 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */
1621 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */
1622 { KB_CTL, "", "", "", "", ""}, /* 29 control */
1623 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */
1624 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */
1625 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */
1626 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */
1627 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */
1628 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */
1629 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */
1630 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */
1631 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */
1632 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */
1633 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */
1634 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */
1635 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */
1636 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */
1637 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */
1638 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */
1639 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */
1640 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */
1641 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */
1642 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */
1643 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */
1644 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */
1645 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */
1646 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */
1647 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */
1648 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */
1649 { KB_ALT, "", "", "", "", ""}, /* 56 alt */
1650 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */
1651 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */
1652 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */
1653 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */
1654 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */
1655 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */
1656 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */
1657 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */
1658 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */
1659 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */
1660 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */
1661 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */
1662 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */
1663 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */
1664 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */
1665 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */
1666 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */
1667 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */
1668 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */
1669 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */
1670 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */
1671 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */
1672 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */
1673 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */
1674 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */
1675 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */
1676 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */
1677 { KB_NONE, "", "", "", "", ""}, /* 84 0 */
1678 { KB_NONE, "", "", "", "", ""}, /* 85 0 */
1679 { KB_NONE, "", "", "", "", ""}, /* 86 0 */
1680 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */
1681 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */
1682 { KB_NONE, "", "", "", "", ""}, /* 89 0 */
1683 { KB_NONE, "", "", "", "", ""}, /* 90 0 */
1684 { KB_NONE, "", "", "", "", ""}, /* 91 0 */
1685 { KB_NONE, "", "", "", "", ""}, /* 92 0 */
1686 { KB_NONE, "", "", "", "", ""}, /* 93 0 */
1687 { KB_NONE, "", "", "", "", ""}, /* 94 0 */
1688 { KB_NONE, "", "", "", "", ""}, /* 95 0 */
1689 { KB_NONE, "", "", "", "", ""}, /* 96 0 */
1690 { KB_NONE, "", "", "", "", ""}, /* 97 0 */
1691 { KB_NONE, "", "", "", "", ""}, /* 98 0 */
1692 { KB_NONE, "", "", "", "", ""}, /* 99 0 */
1693 { KB_NONE, "", "", "", "", ""}, /* 100 */
1694 { KB_NONE, "", "", "", "", ""}, /* 101 */
1695 { KB_NONE, "", "", "", "", ""}, /* 102 */
1696 { KB_NONE, "", "", "", "", ""}, /* 103 */
1697 { KB_NONE, "", "", "", "", ""}, /* 104 */
1698 { KB_NONE, "", "", "", "", ""}, /* 105 */
1699 { KB_NONE, "", "", "", "", ""}, /* 106 */
1700 { KB_NONE, "", "", "", "", ""}, /* 107 */
1701 { KB_NONE, "", "", "", "", ""}, /* 108 */
1702 { KB_NONE, "", "", "", "", ""}, /* 109 */
1703 { KB_NONE, "", "", "", "", ""}, /* 110 */
1704 { KB_NONE, "", "", "", "", ""}, /* 111 */
1705 { KB_NONE, "", "", "", "", ""}, /* 112 */
1706 { KB_NONE, "", "", "", "", ""}, /* 113 */
1707 { KB_NONE, "", "", "", "", ""}, /* 114 */
1708 { KB_NONE, "", "", "", "", ""}, /* 115 */
1709 { KB_NONE, "", "", "", "", ""}, /* 116 */
1710 { KB_NONE, "", "", "", "", ""}, /* 117 */
1711 { KB_NONE, "", "", "", "", ""}, /* 118 */
1712 { KB_NONE, "", "", "", "", ""}, /* 119 */
1713 { KB_NONE, "", "", "", "", ""}, /* 120 */
1714 { KB_NONE, "", "", "", "", ""}, /* 121 */
1715 { KB_NONE, "", "", "", "", ""}, /* 122 */
1716 { KB_NONE, "", "", "", "", ""}, /* 123 */
1717 { KB_NONE, "", "", "", "", ""}, /* 124 */
1718 { KB_NONE, "", "", "", "", ""}, /* 125 */
1719 { KB_NONE, "", "", "", "", ""}, /* 126 */
1720 { KB_NONE, "", "", "", "", ""} /* 127 */
1721 };
1722
1723 /*
1724 * Get characters from the keyboard. If none are present, return NULL.
1725 */
1726 char *
1727 sget()
1728 {
1729 u_char dt;
1730 static u_char extended = 0, shift_state = 0;
1731 static u_char capchar[2];
1732
1733 top:
1734 KBD_DELAY;
1735 dt = inb(kbd_datap);
1736
1737 switch (dt) {
1738 case KBR_ACK: case KBR_ECHO:
1739 kb_oq_get = (kb_oq_get + 1) & 7;
1740 if(kb_oq_get != kb_oq_put) {
1741 outb(kbd_datap, kb_oq[kb_oq_get]);
1742 }
1743 goto loop;
1744 case KBR_RESEND:
1745 outb(kbd_datap, kb_oq[kb_oq_get]);
1746 goto loop;
1747 }
1748
1749 if (pc_xmode > 0) {
1750 #if defined(DDB) && defined(XSERVER_DDB)
1751 /* F12 enters the debugger while in X mode */
1752 if (dt == 88)
1753 Debugger();
1754 #endif
1755 capchar[0] = dt;
1756 capchar[1] = 0;
1757 /*
1758 * Check for locking keys.
1759 *
1760 * XXX Setting the LEDs this way is a bit bogus. What if the
1761 * keyboard has been remapped in X?
1762 */
1763 switch (scan_codes[dt & 0x7f].type) {
1764 case KB_NUM:
1765 if (dt & 0x80) {
1766 shift_state &= ~KB_NUM;
1767 break;
1768 }
1769 if (shift_state & KB_NUM)
1770 break;
1771 shift_state |= KB_NUM;
1772 lock_state ^= KB_NUM;
1773 async_update();
1774 break;
1775 case KB_CAPS:
1776 if (dt & 0x80) {
1777 shift_state &= ~KB_CAPS;
1778 break;
1779 }
1780 if (shift_state & KB_CAPS)
1781 break;
1782 shift_state |= KB_CAPS;
1783 lock_state ^= KB_CAPS;
1784 async_update();
1785 break;
1786 case KB_SCROLL:
1787 if (dt & 0x80) {
1788 shift_state &= ~KB_SCROLL;
1789 break;
1790 }
1791 if (shift_state & KB_SCROLL)
1792 break;
1793 shift_state |= KB_SCROLL;
1794 lock_state ^= KB_SCROLL;
1795 if ((lock_state & KB_SCROLL) == 0)
1796 wakeup((caddr_t)&lock_state);
1797 async_update();
1798 break;
1799 }
1800 return capchar;
1801 }
1802
1803 switch (dt) {
1804 case KBR_EXTENDED:
1805 extended = 1;
1806 goto loop;
1807 }
1808
1809 #ifdef DDB
1810 /*
1811 * Check for cntl-alt-esc.
1812 */
1813 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1814 /* XXX - check pccons_is_console */
1815 Debugger();
1816 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
1817 }
1818 #endif
1819
1820 /*
1821 * Check for make/break.
1822 */
1823 if (dt & 0x80) {
1824 /*
1825 * break
1826 */
1827 dt &= 0x7f;
1828 switch (scan_codes[dt].type) {
1829 case KB_NUM:
1830 shift_state &= ~KB_NUM;
1831 break;
1832 case KB_CAPS:
1833 shift_state &= ~KB_CAPS;
1834 break;
1835 case KB_SCROLL:
1836 shift_state &= ~KB_SCROLL;
1837 break;
1838 case KB_SHIFT:
1839 shift_state &= ~KB_SHIFT;
1840 break;
1841 case KB_ALT:
1842 if (extended)
1843 shift_state &= ~KB_ALTGR;
1844 else
1845 shift_state &= ~KB_ALT;
1846 break;
1847 case KB_CTL:
1848 shift_state &= ~KB_CTL;
1849 break;
1850 }
1851 } else {
1852 /*
1853 * make
1854 */
1855 switch (scan_codes[dt].type) {
1856 /*
1857 * locking keys
1858 */
1859 case KB_NUM:
1860 if (shift_state & KB_NUM)
1861 break;
1862 shift_state |= KB_NUM;
1863 lock_state ^= KB_NUM;
1864 async_update();
1865 break;
1866 case KB_CAPS:
1867 if (shift_state & KB_CAPS)
1868 break;
1869 shift_state |= KB_CAPS;
1870 lock_state ^= KB_CAPS;
1871 async_update();
1872 break;
1873 case KB_SCROLL:
1874 if (shift_state & KB_SCROLL)
1875 break;
1876 shift_state |= KB_SCROLL;
1877 lock_state ^= KB_SCROLL;
1878 if ((lock_state & KB_SCROLL) == 0)
1879 wakeup((caddr_t)&lock_state);
1880 async_update();
1881 break;
1882 /*
1883 * non-locking keys
1884 */
1885 case KB_SHIFT:
1886 shift_state |= KB_SHIFT;
1887 break;
1888 case KB_ALT:
1889 if (extended)
1890 shift_state |= KB_ALTGR;
1891 else
1892 shift_state |= KB_ALT;
1893 break;
1894 case KB_CTL:
1895 shift_state |= KB_CTL;
1896 break;
1897 case KB_ASCII:
1898 /* control has highest priority */
1899 if (shift_state & KB_CTL)
1900 capchar[0] = scan_codes[dt].ctl[0];
1901 else if (shift_state & KB_ALTGR) {
1902 if (shift_state & KB_SHIFT)
1903 capchar[0] = scan_codes[dt].shift_altgr[0];
1904 else
1905 capchar[0] = scan_codes[dt].altgr[0];
1906 }
1907 else {
1908 if (shift_state & KB_SHIFT)
1909 capchar[0] = scan_codes[dt].shift[0];
1910 else
1911 capchar[0] = scan_codes[dt].unshift[0];
1912 }
1913 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1914 capchar[0] <= 'z') {
1915 capchar[0] -= ('a' - 'A');
1916 }
1917 capchar[0] |= (shift_state & KB_ALT);
1918 extended = 0;
1919 return capchar;
1920 case KB_NONE:
1921 printf("keycode %d\n",dt);
1922 break;
1923 case KB_FUNC: {
1924 char *more_chars;
1925 if (shift_state & KB_SHIFT)
1926 more_chars = scan_codes[dt].shift;
1927 else if (shift_state & KB_CTL)
1928 more_chars = scan_codes[dt].ctl;
1929 else
1930 more_chars = scan_codes[dt].unshift;
1931 extended = 0;
1932 return more_chars;
1933 }
1934 case KB_KP: {
1935 char *more_chars;
1936 if (shift_state & (KB_SHIFT | KB_CTL) ||
1937 (lock_state & KB_NUM) == 0 || extended)
1938 more_chars = scan_codes[dt].shift;
1939 else
1940 more_chars = scan_codes[dt].unshift;
1941 extended = 0;
1942 return more_chars;
1943 }
1944 }
1945 }
1946
1947 extended = 0;
1948 loop:
1949 if ((inb(kbd_cmdp) & KBS_DIB) == 0)
1950 return 0;
1951 goto top;
1952 }
1953
1954 paddr_t
1955 pcmmap(dev, offset, nprot)
1956 dev_t dev;
1957 off_t offset;
1958 int nprot;
1959 {
1960
1961 switch(cputype) {
1962
1963 case ACER_PICA_61:
1964 case NEC_R96:
1965 if (offset >= 0xa0000 && offset < 0xc0000)
1966 return mips_btop(PICA_P_LOCAL_VIDEO + offset);
1967 if (offset >= 0x0000 && offset < 0x10000)
1968 return mips_btop(PICA_P_LOCAL_VIDEO_CTRL + offset);
1969 if (offset >= 0x40000000 && offset < 0x40800000)
1970 return mips_btop(PICA_P_LOCAL_VIDEO + offset - 0x40000000);
1971 return -1;
1972
1973 case DESKSTATION_RPC44:
1974 if (offset >= 0xa0000 && offset < 0xc0000)
1975 return mips_btop(RPC44_P_ISA_MEM + offset);
1976 if (offset >= 0x0000 && offset < 0x10000)
1977 return mips_btop(RPC44_P_ISA_IO + offset);
1978 if (offset >= 0x40000000 && offset < 0x40800000)
1979 return mips_btop(RPC44_P_ISA_MEM + offset - 0x40000000);
1980 return -1;
1981
1982 case DESKSTATION_TYNE:
1983 if (offset >= 0xa0000 && offset < 0xc0000)
1984 return mips_btop(TYNE_P_ISA_MEM + offset);
1985 if (offset >= 0x0000 && offset < 0x10000)
1986 return mips_btop(TYNE_P_ISA_IO + offset);
1987 if (offset >= 0x40000000 && offset < 0x40800000)
1988 return mips_btop(TYNE_P_ISA_MEM + offset - 0x40000000);
1989 return -1;
1990 }
1991 return -1;
1992 }
1993
1994 void
1995 pc_xmode_on()
1996 {
1997 if (pc_xmode)
1998 return;
1999 pc_xmode = 1;
2000
2001 #ifdef XFREE86_BUG_COMPAT
2002 /* If still unchanged, get current shape. */
2003 if (cursor_shape == 0xffff)
2004 get_cursor_shape();
2005 #endif
2006 }
2007
2008 void
2009 pc_xmode_off()
2010 {
2011 if (pc_xmode == 0)
2012 return;
2013 pc_xmode = 0;
2014
2015 #ifdef XFREE86_BUG_COMPAT
2016 /* XXX It would be hard to justify why the X server doesn't do this. */
2017 set_cursor_shape();
2018 #endif
2019 async_update();
2020 }
2021
2022 #include <machine/mouse.h>
2023
2024 /* status bits */
2025 #define PMS_OBUF_FULL 0x01
2026 #define PMS_IBUF_FULL 0x02
2027
2028 /* controller commands */
2029 #define PMS_INT_ENABLE 0x47 /* enable controller interrupts */
2030 #define PMS_INT_DISABLE 0x65 /* disable controller interrupts */
2031 #define PMS_AUX_ENABLE 0xa7 /* enable auxiliary port */
2032 #define PMS_AUX_DISABLE 0xa8 /* disable auxiliary port */
2033 #define PMS_MAGIC_1 0xa9 /* XXX */
2034
2035 #define PMS_8042_CMD 0x65
2036
2037 /* mouse commands */
2038 #define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */
2039 #define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */
2040 #define PMS_SET_RES 0xe8 /* set resolution */
2041 #define PMS_GET_SCALE 0xe9 /* get scaling factor */
2042 #define PMS_SET_STREAM 0xea /* set streaming mode */
2043 #define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
2044 #define PMS_DEV_ENABLE 0xf4 /* mouse on */
2045 #define PMS_DEV_DISABLE 0xf5 /* mouse off */
2046 #define PMS_RESET 0xff /* reset */
2047
2048 #define PMS_CHUNK 128 /* chunk size for read */
2049 #define PMS_BSIZE 1020 /* buffer size */
2050
2051 #define FLUSHQ(q) { if((q)->c_cc) ndflush(q, (q)->c_cc); }
2052
2053 #if NOPMS > 0
2054
2055 int opmsopen __P((dev_t, int));
2056 int opmsclose __P((dev_t, int));
2057 int opmsread __P((dev_t, struct uio *, int));
2058 int opmsioctl __P((dev_t, u_long, caddr_t, int));
2059 int opmsselect __P((dev_t, int, struct proc *));
2060 int opmspoll __P((dev_t, int, struct proc *));
2061 static __inline void pms_dev_cmd __P((u_char));
2062 static __inline void pms_aux_cmd __P((u_char));
2063 static __inline void pms_pit_cmd __P((u_char));
2064
2065 static __inline void
2066 pms_dev_cmd(value)
2067 u_char value;
2068 {
2069 kbd_flush_input();
2070 outb(kbd_cmdp, 0xd4);
2071 kbd_flush_input();
2072 outb(kbd_datap, value);
2073 }
2074
2075 static __inline void
2076 pms_aux_cmd(value)
2077 u_char value;
2078 {
2079 kbd_flush_input();
2080 outb(kbd_cmdp, value);
2081 }
2082
2083 static __inline void
2084 pms_pit_cmd(value)
2085 u_char value;
2086 {
2087 kbd_flush_input();
2088 outb(kbd_cmdp, 0x60);
2089 kbd_flush_input();
2090 outb(kbd_datap, value);
2091 }
2092
2093 int
2094 opmsprobe(parent, match, aux)
2095 struct device *parent;
2096 struct cfdata *match;
2097 void *aux;
2098 {
2099 struct confargs *ca = aux;
2100 u_char x;
2101
2102 /* Make shure we're looking for this type of device */
2103 if(!BUS_MATCHNAME(ca, "pms"))
2104 return(0);
2105
2106 pcinithandle();
2107 pms_dev_cmd(KBC_RESET);
2108 pms_aux_cmd(PMS_MAGIC_1);
2109 delay(10000);
2110 x = inb(kbd_datap);
2111 pms_pit_cmd(PMS_INT_DISABLE);
2112 if (x & 0x04)
2113 return 0;
2114
2115 return 1;
2116 }
2117
2118 void
2119 opmsattach(parent, self, aux)
2120 struct device *parent, *self;
2121 void *aux;
2122 {
2123 struct opms_softc *sc = (void *)self;
2124 struct confargs *ca = aux;
2125
2126 printf("\n");
2127
2128 /* Other initialization was done by opmsprobe. */
2129 sc->sc_state = 0;
2130
2131 BUS_INTR_ESTABLISH(ca, opmsintr, (void *)(long)sc);
2132 }
2133
2134 int
2135 opmsopen(dev, flag)
2136 dev_t dev;
2137 int flag;
2138 {
2139 int unit = PMSUNIT(dev);
2140 struct opms_softc *sc;
2141
2142 if (unit >= opms_cd.cd_ndevs)
2143 return ENXIO;
2144 sc = opms_cd.cd_devs[unit];
2145 if (!sc)
2146 return ENXIO;
2147
2148 if (sc->sc_state & PMS_OPEN)
2149 return EBUSY;
2150
2151 if (clalloc(&sc->sc_q, PMS_BSIZE, 0) == -1)
2152 return ENOMEM;
2153
2154 sc->sc_state |= PMS_OPEN;
2155 sc->sc_status = 0;
2156 sc->sc_x = sc->sc_y = 0;
2157
2158 /* Enable interrupts. */
2159 pms_dev_cmd(PMS_DEV_ENABLE);
2160 pms_aux_cmd(PMS_AUX_ENABLE);
2161 pms_dev_cmd(PMS_SET_RES);
2162 pms_dev_cmd(3); /* 8 counts/mm */
2163 pms_dev_cmd(PMS_SET_SCALE21);
2164 #if 0
2165 pms_dev_cmd(PMS_SET_SAMPLE);
2166 pms_dev_cmd(100); /* 100 samples/sec */
2167 pms_dev_cmd(PMS_SET_STREAM);
2168 #endif
2169 pms_pit_cmd(PMS_INT_ENABLE);
2170
2171 return 0;
2172 }
2173
2174 int
2175 opmsclose(dev, flag)
2176 dev_t dev;
2177 int flag;
2178 {
2179 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2180
2181 /* Disable interrupts. */
2182 pms_dev_cmd(PMS_DEV_DISABLE);
2183 pms_pit_cmd(PMS_INT_DISABLE);
2184 pms_aux_cmd(PMS_AUX_DISABLE);
2185
2186 sc->sc_state &= ~PMS_OPEN;
2187
2188 clfree(&sc->sc_q);
2189
2190 return 0;
2191 }
2192
2193 int
2194 opmsread(dev, uio, flag)
2195 dev_t dev;
2196 struct uio *uio;
2197 int flag;
2198 {
2199 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2200 int s;
2201 int error = 0;
2202 size_t length;
2203 u_char buffer[PMS_CHUNK];
2204
2205 /* Block until mouse activity occured. */
2206
2207 s = spltty();
2208 while (sc->sc_q.c_cc == 0) {
2209 if (flag & IO_NDELAY) {
2210 splx(s);
2211 return EWOULDBLOCK;
2212 }
2213 sc->sc_state |= PMS_ASLP;
2214 error = tsleep((caddr_t)sc, PZERO | PCATCH, "pmsrea", 0);
2215 if (error) {
2216 sc->sc_state &= ~PMS_ASLP;
2217 splx(s);
2218 return error;
2219 }
2220 }
2221 splx(s);
2222
2223 /* Transfer as many chunks as possible. */
2224
2225 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
2226 length = min(sc->sc_q.c_cc, uio->uio_resid);
2227 if (length > sizeof(buffer))
2228 length = sizeof(buffer);
2229
2230 /* Remove a small chunk from the input queue. */
2231 (void) q_to_b(&sc->sc_q, buffer, length);
2232
2233 /* Copy the data to the user process. */
2234 error = uiomove(buffer, length, uio);
2235 if (error)
2236 break;
2237 }
2238
2239 return error;
2240 }
2241
2242 int
2243 opmsioctl(dev, cmd, addr, flag)
2244 dev_t dev;
2245 u_long cmd;
2246 caddr_t addr;
2247 int flag;
2248 {
2249 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2250 struct mouseinfo info;
2251 int s;
2252 int error;
2253
2254 switch (cmd) {
2255 case MOUSEIOCREAD:
2256 s = spltty();
2257
2258 info.status = sc->sc_status;
2259 if (sc->sc_x || sc->sc_y)
2260 info.status |= MOVEMENT;
2261
2262 if (sc->sc_x > 127)
2263 info.xmotion = 127;
2264 else if (sc->sc_x < -127)
2265 /* Bounding at -127 avoids a bug in XFree86. */
2266 info.xmotion = -127;
2267 else
2268 info.xmotion = sc->sc_x;
2269
2270 if (sc->sc_y > 127)
2271 info.ymotion = 127;
2272 else if (sc->sc_y < -127)
2273 info.ymotion = -127;
2274 else
2275 info.ymotion = sc->sc_y;
2276
2277 /* Reset historical information. */
2278 sc->sc_x = sc->sc_y = 0;
2279 sc->sc_status &= ~BUTCHNGMASK;
2280 ndflush(&sc->sc_q, sc->sc_q.c_cc);
2281
2282 splx(s);
2283 error = copyout(&info, addr, sizeof(struct mouseinfo));
2284 break;
2285 default:
2286 error = EINVAL;
2287 break;
2288 }
2289
2290 return error;
2291 }
2292
2293 /* Masks for the first byte of a packet */
2294 #define PS2LBUTMASK 0x01
2295 #define PS2RBUTMASK 0x02
2296 #define PS2MBUTMASK 0x04
2297
2298 int
2299 opmsintr(arg)
2300 void *arg;
2301 {
2302 struct opms_softc *sc = arg;
2303 static int state = 0;
2304 static u_char buttons;
2305 u_char changed;
2306 static char dx, dy;
2307 u_char buffer[5];
2308
2309 if ((sc->sc_state & PMS_OPEN) == 0) {
2310 /* Interrupts are not expected. Discard the byte. */
2311 kbd_flush_input();
2312 return 0;
2313 }
2314
2315 switch (state) {
2316
2317 case 0:
2318 buttons = inb(kbd_datap);
2319 if ((buttons & 0xc0) == 0)
2320 ++state;
2321 break;
2322
2323 case 1:
2324 dx = inb(kbd_datap);
2325 /* Bounding at -127 avoids a bug in XFree86. */
2326 dx = (dx == -128) ? -127 : dx;
2327 ++state;
2328 break;
2329
2330 case 2:
2331 dy = inb(kbd_datap);
2332 dy = (dy == -128) ? -127 : dy;
2333 state = 0;
2334
2335 buttons = ((buttons & PS2LBUTMASK) << 2) |
2336 ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1);
2337 changed = ((buttons ^ sc->sc_status) & BUTSTATMASK) << 3;
2338 sc->sc_status = buttons | (sc->sc_status & ~BUTSTATMASK) | changed;
2339
2340 if (dx || dy || changed) {
2341 /* Update accumulated movements. */
2342 sc->sc_x += dx;
2343 sc->sc_y += dy;
2344
2345 /* Add this event to the queue. */
2346 buffer[0] = 0x80 | (buttons & BUTSTATMASK);
2347 if(dx < 0)
2348 buffer[0] |= 0x10;
2349 buffer[1] = dx & 0x7f;
2350 if(dy < 0)
2351 buffer[0] |= 0x20;
2352 buffer[2] = dy & 0x7f;
2353 buffer[3] = buffer[4] = 0;
2354 (void) b_to_q(buffer, sizeof buffer, &sc->sc_q);
2355
2356 if (sc->sc_state & PMS_ASLP) {
2357 sc->sc_state &= ~PMS_ASLP;
2358 wakeup((caddr_t)sc);
2359 }
2360 selwakeup(&sc->sc_rsel);
2361 }
2362
2363 break;
2364 }
2365 return -1;
2366 }
2367
2368 int
2369 opmspoll(dev, events, p)
2370 dev_t dev;
2371 int events;
2372 struct proc *p;
2373 {
2374 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2375 int revents = 0;
2376 int s = spltty();
2377
2378 if (events & (POLLIN | POLLRDNORM)) {
2379 if (sc->sc_q.c_cc > 0)
2380 revents |= events & (POLLIN | POLLRDNORM);
2381 else
2382 selrecord(p, &sc->sc_rsel);
2383 }
2384
2385 splx(s);
2386 return (revents);
2387 }
2388
2389 #endif /* NOPMS > 0 */
2390