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