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