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