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