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