pccons.c revision 1.24 1 /* $NetBSD: pccons.c,v 1.24 2001/02/17 04:27:54 tsutsui 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 struct tty *
761 pctty(dev)
762 dev_t dev;
763 {
764 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
765 struct tty *tp = sc->sc_tty;
766
767 return (tp);
768 }
769
770 /*
771 * Got a console receive interrupt -
772 * the console processor wants to give us a character.
773 * Catch the character, and see who it goes to.
774 */
775 int
776 pcintr(arg)
777 void *arg;
778 {
779 struct pc_softc *sc = arg;
780 register struct tty *tp = sc->sc_tty;
781 u_char *cp;
782
783 if ((inb(kbd_cmdp) & KBS_DIB) == 0)
784 return 0;
785 if (polling)
786 return 1;
787 do {
788 cp = sget();
789 if (!tp || (tp->t_state & TS_ISOPEN) == 0)
790 return 1;
791 if (cp)
792 do
793 (*tp->t_linesw->l_rint)(*cp++, tp);
794 while (*cp);
795 } while (inb(kbd_cmdp) & KBS_DIB);
796 return 1;
797 }
798
799 int
800 pcioctl(dev, cmd, data, flag, p)
801 dev_t dev;
802 u_long cmd;
803 caddr_t data;
804 int flag;
805 struct proc *p;
806 {
807 struct pc_softc *sc = pc_cd.cd_devs[PCUNIT(dev)];
808 struct tty *tp = sc->sc_tty;
809 int error;
810
811 error = (*tp->t_linesw->l_ioctl)(tp, cmd, data, flag, p);
812 if (error >= 0)
813 return error;
814 error = ttioctl(tp, cmd, data, flag, p);
815 if (error >= 0)
816 return error;
817
818 switch (cmd) {
819 case CONSOLE_X_MODE_ON:
820 pc_xmode_on();
821 return 0;
822 case CONSOLE_X_MODE_OFF:
823 pc_xmode_off();
824 return 0;
825 case CONSOLE_X_BELL:
826 /*
827 * If set, data is a pointer to a length 2 array of
828 * integers. data[0] is the pitch in Hz and data[1]
829 * is the duration in msec.
830 */
831 if (data)
832 sysbeep(((int*)data)[0],
833 (((int*)data)[1] * hz) / 1000);
834 else
835 sysbeep(BEEP_FREQ, BEEP_TIME);
836 return 0;
837 case CONSOLE_SET_TYPEMATIC_RATE: {
838 u_char rate;
839
840 if (!data)
841 return EINVAL;
842 rate = *((u_char *)data);
843 /*
844 * Check that it isn't too big (which would cause it to be
845 * confused with a command).
846 */
847 if (rate & 0x80)
848 return EINVAL;
849 typematic_rate = rate;
850 async_update();
851 return 0;
852 }
853 case CONSOLE_SET_KEYMAP: {
854 pccons_keymap_t *map = (pccons_keymap_t *) data;
855 int i;
856
857 if (!data)
858 return EINVAL;
859 for (i = 0; i < KB_NUM_KEYS; i++)
860 if (map[i].unshift[KB_CODE_SIZE-1] ||
861 map[i].shift[KB_CODE_SIZE-1] ||
862 map[i].ctl[KB_CODE_SIZE-1] ||
863 map[i].altgr[KB_CODE_SIZE-1] ||
864 map[i].shift_altgr[KB_CODE_SIZE-1])
865 return EINVAL;
866
867 bcopy(data, scan_codes, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
868 return 0;
869 }
870 case CONSOLE_GET_KEYMAP:
871 if (!data)
872 return EINVAL;
873 bcopy(scan_codes, data, sizeof(pccons_keymap_t[KB_NUM_KEYS]));
874 return 0;
875
876 default:
877 return ENOTTY;
878 }
879
880 #ifdef DIAGNOSTIC
881 panic("pcioctl: impossible");
882 #endif
883 }
884
885 void
886 pcstart(tp)
887 struct tty *tp;
888 {
889 struct clist *cl;
890 int s, len;
891 u_char buf[PCBURST];
892
893 s = spltty();
894 if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP))
895 goto out;
896 tp->t_state |= TS_BUSY;
897 splx(s);
898 /*
899 * We need to do this outside spl since it could be fairly
900 * expensive and we don't want our serial ports to overflow.
901 */
902 cl = &tp->t_outq;
903 len = q_to_b(cl, buf, PCBURST);
904 sput(buf, len);
905 s = spltty();
906 tp->t_state &= ~TS_BUSY;
907 if (cl->c_cc) {
908 tp->t_state |= TS_TIMEOUT;
909 callout_reset(&tp->t_rstrt_ch, 1, ttrstrt, tp);
910 }
911 if (cl->c_cc <= tp->t_lowat) {
912 if (tp->t_state & TS_ASLEEP) {
913 tp->t_state &= ~TS_ASLEEP;
914 wakeup(cl);
915 }
916 selwakeup(&tp->t_wsel);
917 }
918 out:
919 splx(s);
920 }
921
922 void
923 pcstop(tp, flag)
924 struct tty *tp;
925 int flag;
926 {
927 }
928
929 /* ARGSUSED */
930 void
931 pccnattach()
932 {
933 int maj;
934 static struct consdev pccons = {
935 NULL, NULL, pccngetc, pccnputc, pccnpollc, NULL,
936 NODEV, CN_NORMAL
937 };
938
939 /*
940 * For now, don't screw with it.
941 */
942 /* crtat = 0; */
943 pcinithandle();
944
945 switch (cputype) {
946
947 case ACER_PICA_61:
948 case NEC_R96: /* XXX - not really confirmed */
949 break;
950
951 case DESKSTATION_TYNE:
952 outb(arc_bus_io.bs_vbase + 0x3ce, 6); /* Correct video mode */
953 outb(arc_bus_io.bs_vbase + 0x3cf,
954 inb(arc_bus_io.bs_vbase + 0x3cf) | 0xc);
955 kbc_put8042cmd(CMDBYTE); /* Want XT codes.. */
956 break;
957
958 case DESKSTATION_RPC44:
959 kbc_put8042cmd(CMDBYTE); /* Want XT codes.. */
960 break;
961
962 case SNI_RM200:
963 break;
964 }
965
966 /* locate the major number */
967 for (maj = 0; maj < nchrdev; maj++)
968 if (cdevsw[maj].d_open == pcopen)
969 break;
970 pccons.cn_dev = makedev(maj, 0);
971
972 cn_tab = &pccons;
973 }
974
975 /* ARGSUSED */
976 void
977 pccnputc(dev, c)
978 dev_t dev;
979 int c;
980 {
981 u_char cc, oldkernel = kernel;
982
983 kernel = 1;
984 if (c == '\n') {
985 sput("\r\n", 2);
986 } else {
987 cc = c;
988 sput(&cc, 1);
989 }
990 kernel = oldkernel;
991 }
992
993 /* ARGSUSED */
994 int
995 pccngetc(dev)
996 dev_t dev;
997 {
998 register char *cp;
999
1000 if (pc_xmode > 0)
1001 return 0;
1002
1003 do {
1004 /* wait for byte */
1005 while ((inb(kbd_cmdp) & KBS_DIB) == 0);
1006 /* see if it's worthwhile */
1007 cp = sget();
1008 } while (!cp);
1009 if (*cp == '\r')
1010 return '\n';
1011 return *cp;
1012 }
1013
1014 void
1015 pccnpollc(dev, on)
1016 dev_t dev;
1017 int on;
1018 {
1019
1020 polling = on;
1021 if (!on) {
1022 int unit;
1023 struct pc_softc *sc;
1024 int s;
1025
1026 /*
1027 * If disabling polling on a device that's been configured,
1028 * make sure there are no bytes left in the FIFO, holding up
1029 * the interrupt line. Otherwise we won't get any further
1030 * interrupts.
1031 */
1032 unit = PCUNIT(dev);
1033 if (pc_cd.cd_ndevs > unit) {
1034 sc = pc_cd.cd_devs[unit];
1035 if (sc != 0) {
1036 s = spltty();
1037 pcintr(sc);
1038 splx(s);
1039 }
1040 }
1041 }
1042 }
1043
1044 /*
1045 * Set line parameters.
1046 */
1047 int
1048 pcparam(tp, t)
1049 struct tty *tp;
1050 struct termios *t;
1051 {
1052
1053 tp->t_ispeed = t->c_ispeed;
1054 tp->t_ospeed = t->c_ospeed;
1055 tp->t_cflag = t->c_cflag;
1056 return 0;
1057 }
1058
1059 #define wrtchar(c, at) do {\
1060 char *cp = (char *)crtat; *cp++ = (c); *cp = (at); crtat++; vs.col++; \
1061 } while (0)
1062
1063 /* translate ANSI color codes to standard pc ones */
1064 static char fgansitopc[] = {
1065 FG_BLACK, FG_RED, FG_GREEN, FG_BROWN, FG_BLUE,
1066 FG_MAGENTA, FG_CYAN, FG_LIGHTGREY
1067 };
1068
1069 static char bgansitopc[] = {
1070 BG_BLACK, BG_RED, BG_GREEN, BG_BROWN, BG_BLUE,
1071 BG_MAGENTA, BG_CYAN, BG_LIGHTGREY
1072 };
1073
1074 static u_char iso2ibm437[] =
1075 {
1076 0, 0, 0, 0, 0, 0, 0, 0,
1077 0, 0, 0, 0, 0, 0, 0, 0,
1078 0, 0, 0, 0, 0, 0, 0, 0,
1079 0, 0, 0, 0, 0, 0, 0, 0,
1080 0xff, 0xad, 0x9b, 0x9c, 0, 0x9d, 0, 0x40,
1081 0x6f, 0x63, 0x61, 0xae, 0, 0, 0, 0,
1082 0xf8, 0xf1, 0xfd, 0x33, 0, 0xe6, 0, 0xfa,
1083 0, 0x31, 0x6f, 0xaf, 0xac, 0xab, 0, 0xa8,
1084 0x41, 0x41, 0x41, 0x41, 0x8e, 0x8f, 0x92, 0x80,
1085 0x45, 0x90, 0x45, 0x45, 0x49, 0x49, 0x49, 0x49,
1086 0x81, 0xa5, 0x4f, 0x4f, 0x4f, 0x4f, 0x99, 0x4f,
1087 0x4f, 0x55, 0x55, 0x55, 0x9a, 0x59, 0, 0xe1,
1088 0x85, 0xa0, 0x83, 0x61, 0x84, 0x86, 0x91, 0x87,
1089 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b,
1090 0, 0xa4, 0x95, 0xa2, 0x93, 0x6f, 0x94, 0x6f,
1091 0x6f, 0x97, 0xa3, 0x96, 0x81, 0x98, 0, 0
1092 };
1093
1094 /*
1095 * `pc3' termcap emulation.
1096 */
1097 void
1098 sput(cp, n)
1099 u_char *cp;
1100 int n;
1101 {
1102 u_char c, scroll = 0;
1103
1104 if (pc_xmode > 0)
1105 return;
1106
1107 if (crtat == 0) {
1108 volatile u_short *cp;
1109 u_short was;
1110 unsigned cursorat;
1111
1112 cp = (volatile u_short *)cga_buf;
1113 was = *cp;
1114 *cp = (volatile u_short) 0xA55A;
1115 if (*cp != 0xA55A) {
1116 cp = (volatile u_short *)mono_buf;
1117 addr_6845 = mono_base;
1118 vs.color = 0;
1119 } else {
1120 *cp = was;
1121 addr_6845 = cga_base;
1122 vs.color = 1;
1123 }
1124
1125 #ifdef FAT_CURSOR
1126 cursor_shape = 0x0012;
1127 #else
1128 get_cursor_shape();
1129 #endif
1130
1131 bios_display_info(&vs.col, &vs.row, &vs.ncol, &vs.nrow);
1132 vs.nchr = vs.ncol * vs.nrow;
1133 vs.col--;
1134 vs.row--;
1135 cursorat = vs.ncol * vs.row + vs.col;
1136 vs.at = FG_LIGHTGREY | BG_BLACK;
1137
1138 Crtat = (u_short *)cp;
1139 crtat = Crtat + cursorat;
1140
1141 if (vs.color == 0)
1142 vs.so_at = FG_BLACK | BG_LIGHTGREY;
1143 else
1144 vs.so_at = FG_YELLOW | BG_BLACK;
1145
1146 fillw((vs.at << 8) | ' ', crtat, vs.nchr - cursorat);
1147 }
1148
1149 while (n--) {
1150 if (!(c = *cp++))
1151 continue;
1152
1153 switch (c) {
1154 case 0x1B:
1155 if (vs.state >= VSS_ESCAPE) {
1156 wrtchar(c, vs.so_at);
1157 vs.state = 0;
1158 goto maybe_scroll;
1159 } else
1160 vs.state = VSS_ESCAPE;
1161 break;
1162
1163 case 0x9B: /* CSI */
1164 vs.cx = vs.cy = 0;
1165 vs.state = VSS_EBRACE;
1166 break;
1167
1168 case '\t': {
1169 int inccol = 8 - (vs.col & 7);
1170 crtat += inccol;
1171 vs.col += inccol;
1172 }
1173 maybe_scroll:
1174 if (vs.col >= vs.ncol) {
1175 vs.col -= vs.ncol;
1176 scroll = 1;
1177 }
1178 break;
1179
1180 case '\b':
1181 if (crtat <= Crtat)
1182 break;
1183 --crtat;
1184 if (--vs.col < 0)
1185 vs.col += vs.ncol; /* non-destructive backspace */
1186 break;
1187
1188 case '\r':
1189 crtat -= vs.col;
1190 vs.col = 0;
1191 break;
1192
1193 case '\n':
1194 crtat += vs.ncol;
1195 scroll = 1;
1196 break;
1197
1198 default:
1199 switch (vs.state) {
1200 case 0:
1201 if (c == '\a')
1202 sysbeep(BEEP_FREQ, BEEP_TIME);
1203 else {
1204 /*
1205 * If we're outputting multiple printed
1206 * characters, just blast them to the
1207 * screen until we reach the end of the
1208 * buffer or a control character. This
1209 * saves time by short-circuiting the
1210 * switch.
1211 * If we reach the end of the line, we
1212 * break to do a scroll check.
1213 */
1214 for (;;) {
1215 if (c & 0x80)
1216 c = iso2ibm437[c&0x7f];
1217
1218 if (vs.so)
1219 wrtchar(c, vs.so_at);
1220 else
1221 wrtchar(c, vs.at);
1222 if (vs.col >= vs.ncol) {
1223 vs.col = 0;
1224 scroll = 1;
1225 break;
1226 }
1227 if (!n || (c = *cp) < ' ')
1228 break;
1229 n--, cp++;
1230 }
1231 }
1232 break;
1233 case VSS_ESCAPE:
1234 switch (c) {
1235 case '[': /* Start ESC [ sequence */
1236 vs.cx = vs.cy = 0;
1237 vs.state = VSS_EBRACE;
1238 break;
1239 case 'c': /* Create screen & home */
1240 fillw((vs.at << 8) | ' ',
1241 Crtat, vs.nchr);
1242 crtat = Crtat;
1243 vs.col = 0;
1244 vs.state = 0;
1245 break;
1246 case '7': /* save cursor pos */
1247 vs.offset = crtat - Crtat;
1248 vs.state = 0;
1249 break;
1250 case '8': /* restore cursor pos */
1251 crtat = Crtat + vs.offset;
1252 vs.row = vs.offset / vs.ncol;
1253 vs.col = vs.offset % vs.ncol;
1254 vs.state = 0;
1255 break;
1256 default: /* Invalid, clear state */
1257 wrtchar(c, vs.so_at);
1258 vs.state = 0;
1259 goto maybe_scroll;
1260 }
1261 break;
1262
1263 default: /* VSS_EBRACE or VSS_EPARAM */
1264 switch (c) {
1265 int pos;
1266 case 'm':
1267 if (!vs.cx)
1268 vs.so = 0;
1269 else
1270 vs.so = 1;
1271 vs.state = 0;
1272 break;
1273 case 'A': { /* back cx rows */
1274 int cx = vs.cx;
1275 if (cx <= 0)
1276 cx = 1;
1277 else
1278 cx %= vs.nrow;
1279 pos = crtat - Crtat;
1280 pos -= vs.ncol * cx;
1281 if (pos < 0)
1282 pos += vs.nchr;
1283 crtat = Crtat + pos;
1284 vs.state = 0;
1285 break;
1286 }
1287 case 'B': { /* down cx rows */
1288 int cx = vs.cx;
1289 if (cx <= 0)
1290 cx = 1;
1291 else
1292 cx %= vs.nrow;
1293 pos = crtat - Crtat;
1294 pos += vs.ncol * cx;
1295 if (pos >= vs.nchr)
1296 pos -= vs.nchr;
1297 crtat = Crtat + pos;
1298 vs.state = 0;
1299 break;
1300 }
1301 case 'C': { /* right cursor */
1302 int cx = vs.cx,
1303 col = vs.col;
1304 if (cx <= 0)
1305 cx = 1;
1306 else
1307 cx %= vs.ncol;
1308 pos = crtat - Crtat;
1309 pos += cx;
1310 col += cx;
1311 if (col >= vs.ncol) {
1312 pos -= vs.ncol;
1313 col -= vs.ncol;
1314 }
1315 vs.col = col;
1316 crtat = Crtat + pos;
1317 vs.state = 0;
1318 break;
1319 }
1320 case 'D': { /* left cursor */
1321 int cx = vs.cx,
1322 col = vs.col;
1323 if (cx <= 0)
1324 cx = 1;
1325 else
1326 cx %= vs.ncol;
1327 pos = crtat - Crtat;
1328 pos -= cx;
1329 col -= cx;
1330 if (col < 0) {
1331 pos += vs.ncol;
1332 col += vs.ncol;
1333 }
1334 vs.col = col;
1335 crtat = Crtat + pos;
1336 vs.state = 0;
1337 break;
1338 }
1339 case 'J': /* Clear ... */
1340 switch (vs.cx) {
1341 case 0:
1342 /* ... to end of display */
1343 fillw((vs.at << 8) | ' ',
1344 crtat,
1345 Crtat + vs.nchr - crtat);
1346 break;
1347 case 1:
1348 /* ... to next location */
1349 fillw((vs.at << 8) | ' ',
1350 Crtat,
1351 crtat - Crtat + 1);
1352 break;
1353 case 2:
1354 /* ... whole display */
1355 fillw((vs.at << 8) | ' ',
1356 Crtat,
1357 vs.nchr);
1358 break;
1359 }
1360 vs.state = 0;
1361 break;
1362 case 'K': /* Clear line ... */
1363 switch (vs.cx) {
1364 case 0:
1365 /* ... current to EOL */
1366 fillw((vs.at << 8) | ' ',
1367 crtat,
1368 vs.ncol - vs.col);
1369 break;
1370 case 1:
1371 /* ... beginning to next */
1372 fillw((vs.at << 8) | ' ',
1373 crtat - vs.col,
1374 vs.col + 1);
1375 break;
1376 case 2:
1377 /* ... entire line */
1378 fillw((vs.at << 8) | ' ',
1379 crtat - vs.col, vs.ncol);
1380 break;
1381 }
1382 vs.state = 0;
1383 break;
1384 case 'f': /* in system V consoles */
1385 case 'H': { /* Cursor move */
1386 int cx = vs.cx,
1387 cy = vs.cy;
1388 if (!cx || !cy) {
1389 crtat = Crtat;
1390 vs.col = 0;
1391 } else {
1392 if (cx > vs.nrow)
1393 cx = vs.nrow;
1394 if (cy > vs.ncol)
1395 cy = vs.ncol;
1396 crtat = Crtat +
1397 (cx - 1) * vs.ncol + cy - 1;
1398 vs.col = cy - 1;
1399 }
1400 vs.state = 0;
1401 break;
1402 }
1403 case 'M': { /* delete cx rows */
1404 u_short *crtAt = crtat - vs.col;
1405 int cx = vs.cx,
1406 row = (crtAt - Crtat) / vs.ncol,
1407 nrow = vs.nrow - row;
1408 if (cx <= 0)
1409 cx = 1;
1410 else if (cx > nrow)
1411 cx = nrow;
1412 if (cx < nrow)
1413 #ifdef PCCONS_FORCE_WORD
1414 wcopy(crtAt + vs.ncol * cx,
1415 crtAt, vs.ncol * (nrow -
1416 cx) * CHR);
1417 #else
1418 bcopy(crtAt + vs.ncol * cx,
1419 crtAt, vs.ncol * (nrow -
1420 cx) * CHR);
1421 #endif
1422 fillw((vs.at << 8) | ' ',
1423 crtAt + vs.ncol * (nrow - cx),
1424 vs.ncol * cx);
1425 vs.state = 0;
1426 break;
1427 }
1428 case 'S': { /* scroll up cx lines */
1429 int cx = vs.cx;
1430 if (cx <= 0)
1431 cx = 1;
1432 else if (cx > vs.nrow)
1433 cx = vs.nrow;
1434 if (cx < vs.nrow)
1435 #ifdef PCCONS_FORCE_WORD
1436 wcopy(Crtat + vs.ncol * cx,
1437 Crtat, vs.ncol * (vs.nrow -
1438 cx) * CHR);
1439 #else
1440 bcopy(Crtat + vs.ncol * cx,
1441 Crtat, vs.ncol * (vs.nrow -
1442 cx) * CHR);
1443 #endif
1444 fillw((vs.at << 8) | ' ',
1445 Crtat + vs.ncol * (vs.nrow - cx),
1446 vs.ncol * cx);
1447 /* crtat -= vs.ncol * cx; XXX */
1448 vs.state = 0;
1449 break;
1450 }
1451 case 'L': { /* insert cx rows */
1452 u_short *crtAt = crtat - vs.col;
1453 int cx = vs.cx,
1454 row = (crtAt - Crtat) / vs.ncol,
1455 nrow = vs.nrow - row;
1456 if (cx <= 0)
1457 cx = 1;
1458 else if (cx > nrow)
1459 cx = nrow;
1460 if (cx < nrow)
1461 #ifdef PCCONS_FORCE_WORD
1462 wcopy(crtAt,
1463 crtAt + vs.ncol * cx,
1464 vs.ncol * (nrow - cx) *
1465 CHR);
1466 #else
1467 bcopy(crtAt,
1468 crtAt + vs.ncol * cx,
1469 vs.ncol * (nrow - cx) *
1470 CHR);
1471 #endif
1472 fillw((vs.at << 8) | ' ', crtAt,
1473 vs.ncol * cx);
1474 vs.state = 0;
1475 break;
1476 }
1477 case 'T': { /* scroll down cx lines */
1478 int cx = vs.cx;
1479 if (cx <= 0)
1480 cx = 1;
1481 else if (cx > vs.nrow)
1482 cx = vs.nrow;
1483 if (cx < vs.nrow)
1484 #ifdef PCCONS_FORCE_WORD
1485 wcopy(Crtat,
1486 Crtat + vs.ncol * cx,
1487 vs.ncol * (vs.nrow - cx) *
1488 CHR);
1489 #else
1490 bcopy(Crtat,
1491 Crtat + vs.ncol * cx,
1492 vs.ncol * (vs.nrow - cx) *
1493 CHR);
1494 #endif
1495 fillw((vs.at << 8) | ' ', Crtat,
1496 vs.ncol * cx);
1497 /* crtat += vs.ncol * cx; XXX */
1498 vs.state = 0;
1499 break;
1500 }
1501 case ';': /* Switch params in cursor def */
1502 vs.state = VSS_EPARAM;
1503 break;
1504 case 'r':
1505 vs.so_at = (vs.cx & FG_MASK) |
1506 ((vs.cy << 4) & BG_MASK);
1507 vs.state = 0;
1508 break;
1509 case 's': /* save cursor pos */
1510 vs.offset = crtat - Crtat;
1511 vs.state = 0;
1512 break;
1513 case 'u': /* restore cursor pos */
1514 crtat = Crtat + vs.offset;
1515 vs.row = vs.offset / vs.ncol;
1516 vs.col = vs.offset % vs.ncol;
1517 vs.state = 0;
1518 break;
1519 case 'x': /* set attributes */
1520 switch (vs.cx) {
1521 case 0:
1522 vs.at = FG_LIGHTGREY | BG_BLACK;
1523 break;
1524 case 1:
1525 /* ansi background */
1526 if (!vs.color)
1527 break;
1528 vs.at &= FG_MASK;
1529 vs.at |= bgansitopc[vs.cy & 7];
1530 break;
1531 case 2:
1532 /* ansi foreground */
1533 if (!vs.color)
1534 break;
1535 vs.at &= BG_MASK;
1536 vs.at |= fgansitopc[vs.cy & 7];
1537 break;
1538 case 3:
1539 /* pc text attribute */
1540 if (vs.state >= VSS_EPARAM)
1541 vs.at = vs.cy;
1542 break;
1543 }
1544 vs.state = 0;
1545 break;
1546
1547 default: /* Only numbers valid here */
1548 if ((c >= '0') && (c <= '9')) {
1549 if (vs.state >= VSS_EPARAM) {
1550 vs.cy *= 10;
1551 vs.cy += c - '0';
1552 } else {
1553 vs.cx *= 10;
1554 vs.cx += c - '0';
1555 }
1556 } else
1557 vs.state = 0;
1558 break;
1559 }
1560 break;
1561 }
1562 }
1563 if (scroll) {
1564 scroll = 0;
1565 /* scroll check */
1566 if (crtat >= Crtat + vs.nchr) {
1567 if (!kernel) {
1568 int s = spltty();
1569 if (lock_state & KB_SCROLL)
1570 tsleep(&lock_state,
1571 PUSER, "pcputc", 0);
1572 splx(s);
1573 }
1574 #if PCCONS_FORCE_WORD
1575 wcopy(Crtat + vs.ncol, Crtat,
1576 (vs.nchr - vs.ncol) * CHR);
1577 #else
1578 bcopy(Crtat + vs.ncol, Crtat,
1579 (vs.nchr - vs.ncol) * CHR);
1580 #endif
1581 fillw((vs.at << 8) | ' ',
1582 Crtat + vs.nchr - vs.ncol,
1583 vs.ncol);
1584 crtat -= vs.ncol;
1585 }
1586 }
1587 }
1588 async_update();
1589 }
1590
1591 /* the unshifted code for KB_SHIFT keys is used by X to distinguish between
1592 left and right shift when reading the keyboard map */
1593 static pccons_keymap_t scan_codes[KB_NUM_KEYS] = {
1594 /* type unshift shift control altgr shift_altgr scancode */
1595 { KB_NONE, "", "", "", "", ""}, /* 0 unused */
1596 { KB_ASCII, "\033", "\033", "\033", "", ""}, /* 1 ESCape */
1597 { KB_ASCII, "1", "!", "!", "", ""}, /* 2 1 */
1598 { KB_ASCII, "2", "@", "\000", "", ""}, /* 3 2 */
1599 { KB_ASCII, "3", "#", "#", "", ""}, /* 4 3 */
1600 { KB_ASCII, "4", "$", "$", "", ""}, /* 5 4 */
1601 { KB_ASCII, "5", "%", "%", "", ""}, /* 6 5 */
1602 { KB_ASCII, "6", "^", "\036", "", ""}, /* 7 6 */
1603 { KB_ASCII, "7", "&", "&", "", ""}, /* 8 7 */
1604 { KB_ASCII, "8", "*", "\010", "", ""}, /* 9 8 */
1605 { KB_ASCII, "9", "(", "(", "", ""}, /* 10 9 */
1606 { KB_ASCII, "0", ")", ")", "", ""}, /* 11 0 */
1607 { KB_ASCII, "-", "_", "\037", "", ""}, /* 12 - */
1608 { KB_ASCII, "=", "+", "+", "", ""}, /* 13 = */
1609 { KB_ASCII, "\177", "\177", "\010", "", ""}, /* 14 backspace */
1610 { KB_ASCII, "\t", "\t", "\t", "", ""}, /* 15 tab */
1611 { KB_ASCII, "q", "Q", "\021", "", ""}, /* 16 q */
1612 { KB_ASCII, "w", "W", "\027", "", ""}, /* 17 w */
1613 { KB_ASCII, "e", "E", "\005", "", ""}, /* 18 e */
1614 { KB_ASCII, "r", "R", "\022", "", ""}, /* 19 r */
1615 { KB_ASCII, "t", "T", "\024", "", ""}, /* 20 t */
1616 { KB_ASCII, "y", "Y", "\031", "", ""}, /* 21 y */
1617 { KB_ASCII, "u", "U", "\025", "", ""}, /* 22 u */
1618 { KB_ASCII, "i", "I", "\011", "", ""}, /* 23 i */
1619 { KB_ASCII, "o", "O", "\017", "", ""}, /* 24 o */
1620 { KB_ASCII, "p", "P", "\020", "", ""}, /* 25 p */
1621 { KB_ASCII, "[", "{", "\033", "", ""}, /* 26 [ */
1622 { KB_ASCII, "]", "}", "\035", "", ""}, /* 27 ] */
1623 { KB_ASCII, "\r", "\r", "\n", "", ""}, /* 28 return */
1624 { KB_CTL, "", "", "", "", ""}, /* 29 control */
1625 { KB_ASCII, "a", "A", "\001", "", ""}, /* 30 a */
1626 { KB_ASCII, "s", "S", "\023", "", ""}, /* 31 s */
1627 { KB_ASCII, "d", "D", "\004", "", ""}, /* 32 d */
1628 { KB_ASCII, "f", "F", "\006", "", ""}, /* 33 f */
1629 { KB_ASCII, "g", "G", "\007", "", ""}, /* 34 g */
1630 { KB_ASCII, "h", "H", "\010", "", ""}, /* 35 h */
1631 { KB_ASCII, "j", "J", "\n", "", ""}, /* 36 j */
1632 { KB_ASCII, "k", "K", "\013", "", ""}, /* 37 k */
1633 { KB_ASCII, "l", "L", "\014", "", ""}, /* 38 l */
1634 { KB_ASCII, ";", ":", ";", "", ""}, /* 39 ; */
1635 { KB_ASCII, "'", "\"", "'", "", ""}, /* 40 ' */
1636 { KB_ASCII, "`", "~", "`", "", ""}, /* 41 ` */
1637 { KB_SHIFT, "\001", "", "", "", ""}, /* 42 shift */
1638 { KB_ASCII, "\\", "|", "\034", "", ""}, /* 43 \ */
1639 { KB_ASCII, "z", "Z", "\032", "", ""}, /* 44 z */
1640 { KB_ASCII, "x", "X", "\030", "", ""}, /* 45 x */
1641 { KB_ASCII, "c", "C", "\003", "", ""}, /* 46 c */
1642 { KB_ASCII, "v", "V", "\026", "", ""}, /* 47 v */
1643 { KB_ASCII, "b", "B", "\002", "", ""}, /* 48 b */
1644 { KB_ASCII, "n", "N", "\016", "", ""}, /* 49 n */
1645 { KB_ASCII, "m", "M", "\r", "", ""}, /* 50 m */
1646 { KB_ASCII, ",", "<", "<", "", ""}, /* 51 , */
1647 { KB_ASCII, ".", ">", ">", "", ""}, /* 52 . */
1648 { KB_ASCII, "/", "?", "\037", "", ""}, /* 53 / */
1649 { KB_SHIFT, "\002", "", "", "", ""}, /* 54 shift */
1650 { KB_KP, "*", "*", "*", "", ""}, /* 55 kp * */
1651 { KB_ALT, "", "", "", "", ""}, /* 56 alt */
1652 { KB_ASCII, " ", " ", "\000", "", ""}, /* 57 space */
1653 { KB_CAPS, "", "", "", "", ""}, /* 58 caps */
1654 { KB_FUNC, "\033[M", "\033[Y", "\033[k", "", ""}, /* 59 f1 */
1655 { KB_FUNC, "\033[N", "\033[Z", "\033[l", "", ""}, /* 60 f2 */
1656 { KB_FUNC, "\033[O", "\033[a", "\033[m", "", ""}, /* 61 f3 */
1657 { KB_FUNC, "\033[P", "\033[b", "\033[n", "", ""}, /* 62 f4 */
1658 { KB_FUNC, "\033[Q", "\033[c", "\033[o", "", ""}, /* 63 f5 */
1659 { KB_FUNC, "\033[R", "\033[d", "\033[p", "", ""}, /* 64 f6 */
1660 { KB_FUNC, "\033[S", "\033[e", "\033[q", "", ""}, /* 65 f7 */
1661 { KB_FUNC, "\033[T", "\033[f", "\033[r", "", ""}, /* 66 f8 */
1662 { KB_FUNC, "\033[U", "\033[g", "\033[s", "", ""}, /* 67 f9 */
1663 { KB_FUNC, "\033[V", "\033[h", "\033[t", "", ""}, /* 68 f10 */
1664 { KB_NUM, "", "", "", "", ""}, /* 69 num lock */
1665 { KB_SCROLL, "", "", "", "", ""}, /* 70 scroll lock */
1666 { KB_KP, "7", "\033[H", "7", "", ""}, /* 71 kp 7 */
1667 { KB_KP, "8", "\033[A", "8", "", ""}, /* 72 kp 8 */
1668 { KB_KP, "9", "\033[I", "9", "", ""}, /* 73 kp 9 */
1669 { KB_KP, "-", "-", "-", "", ""}, /* 74 kp - */
1670 { KB_KP, "4", "\033[D", "4", "", ""}, /* 75 kp 4 */
1671 { KB_KP, "5", "\033[E", "5", "", ""}, /* 76 kp 5 */
1672 { KB_KP, "6", "\033[C", "6", "", ""}, /* 77 kp 6 */
1673 { KB_KP, "+", "+", "+", "", ""}, /* 78 kp + */
1674 { KB_KP, "1", "\033[F", "1", "", ""}, /* 79 kp 1 */
1675 { KB_KP, "2", "\033[B", "2", "", ""}, /* 80 kp 2 */
1676 { KB_KP, "3", "\033[G", "3", "", ""}, /* 81 kp 3 */
1677 { KB_KP, "0", "\033[L", "0", "", ""}, /* 82 kp 0 */
1678 { KB_KP, ",", "\177", ",", "", ""}, /* 83 kp , */
1679 { KB_NONE, "", "", "", "", ""}, /* 84 0 */
1680 { KB_NONE, "", "", "", "", ""}, /* 85 0 */
1681 { KB_NONE, "", "", "", "", ""}, /* 86 0 */
1682 { KB_FUNC, "\033[W", "\033[i", "\033[u", "", ""}, /* 87 f11 */
1683 { KB_FUNC, "\033[X", "\033[j", "\033[v", "", ""}, /* 88 f12 */
1684 { KB_NONE, "", "", "", "", ""}, /* 89 0 */
1685 { KB_NONE, "", "", "", "", ""}, /* 90 0 */
1686 { KB_NONE, "", "", "", "", ""}, /* 91 0 */
1687 { KB_NONE, "", "", "", "", ""}, /* 92 0 */
1688 { KB_NONE, "", "", "", "", ""}, /* 93 0 */
1689 { KB_NONE, "", "", "", "", ""}, /* 94 0 */
1690 { KB_NONE, "", "", "", "", ""}, /* 95 0 */
1691 { KB_NONE, "", "", "", "", ""}, /* 96 0 */
1692 { KB_NONE, "", "", "", "", ""}, /* 97 0 */
1693 { KB_NONE, "", "", "", "", ""}, /* 98 0 */
1694 { KB_NONE, "", "", "", "", ""}, /* 99 0 */
1695 { KB_NONE, "", "", "", "", ""}, /* 100 */
1696 { KB_NONE, "", "", "", "", ""}, /* 101 */
1697 { KB_NONE, "", "", "", "", ""}, /* 102 */
1698 { KB_NONE, "", "", "", "", ""}, /* 103 */
1699 { KB_NONE, "", "", "", "", ""}, /* 104 */
1700 { KB_NONE, "", "", "", "", ""}, /* 105 */
1701 { KB_NONE, "", "", "", "", ""}, /* 106 */
1702 { KB_NONE, "", "", "", "", ""}, /* 107 */
1703 { KB_NONE, "", "", "", "", ""}, /* 108 */
1704 { KB_NONE, "", "", "", "", ""}, /* 109 */
1705 { KB_NONE, "", "", "", "", ""}, /* 110 */
1706 { KB_NONE, "", "", "", "", ""}, /* 111 */
1707 { KB_NONE, "", "", "", "", ""}, /* 112 */
1708 { KB_NONE, "", "", "", "", ""}, /* 113 */
1709 { KB_NONE, "", "", "", "", ""}, /* 114 */
1710 { KB_NONE, "", "", "", "", ""}, /* 115 */
1711 { KB_NONE, "", "", "", "", ""}, /* 116 */
1712 { KB_NONE, "", "", "", "", ""}, /* 117 */
1713 { KB_NONE, "", "", "", "", ""}, /* 118 */
1714 { KB_NONE, "", "", "", "", ""}, /* 119 */
1715 { KB_NONE, "", "", "", "", ""}, /* 120 */
1716 { KB_NONE, "", "", "", "", ""}, /* 121 */
1717 { KB_NONE, "", "", "", "", ""}, /* 122 */
1718 { KB_NONE, "", "", "", "", ""}, /* 123 */
1719 { KB_NONE, "", "", "", "", ""}, /* 124 */
1720 { KB_NONE, "", "", "", "", ""}, /* 125 */
1721 { KB_NONE, "", "", "", "", ""}, /* 126 */
1722 { KB_NONE, "", "", "", "", ""} /* 127 */
1723 };
1724
1725 /*
1726 * Get characters from the keyboard. If none are present, return NULL.
1727 */
1728 char *
1729 sget()
1730 {
1731 u_char dt;
1732 static u_char extended = 0, shift_state = 0;
1733 static u_char capchar[2];
1734
1735 top:
1736 KBD_DELAY;
1737 dt = inb(kbd_datap);
1738
1739 switch (dt) {
1740 case KBR_ACK: case KBR_ECHO:
1741 kb_oq_get = (kb_oq_get + 1) & 7;
1742 if(kb_oq_get != kb_oq_put) {
1743 outb(kbd_datap, kb_oq[kb_oq_get]);
1744 }
1745 goto loop;
1746 case KBR_RESEND:
1747 outb(kbd_datap, kb_oq[kb_oq_get]);
1748 goto loop;
1749 }
1750
1751 if (pc_xmode > 0) {
1752 #if defined(DDB) && defined(XSERVER_DDB)
1753 /* F12 enters the debugger while in X mode */
1754 if (dt == 88)
1755 Debugger();
1756 #endif
1757 capchar[0] = dt;
1758 capchar[1] = 0;
1759 /*
1760 * Check for locking keys.
1761 *
1762 * XXX Setting the LEDs this way is a bit bogus. What if the
1763 * keyboard has been remapped in X?
1764 */
1765 switch (scan_codes[dt & 0x7f].type) {
1766 case KB_NUM:
1767 if (dt & 0x80) {
1768 shift_state &= ~KB_NUM;
1769 break;
1770 }
1771 if (shift_state & KB_NUM)
1772 break;
1773 shift_state |= KB_NUM;
1774 lock_state ^= KB_NUM;
1775 async_update();
1776 break;
1777 case KB_CAPS:
1778 if (dt & 0x80) {
1779 shift_state &= ~KB_CAPS;
1780 break;
1781 }
1782 if (shift_state & KB_CAPS)
1783 break;
1784 shift_state |= KB_CAPS;
1785 lock_state ^= KB_CAPS;
1786 async_update();
1787 break;
1788 case KB_SCROLL:
1789 if (dt & 0x80) {
1790 shift_state &= ~KB_SCROLL;
1791 break;
1792 }
1793 if (shift_state & KB_SCROLL)
1794 break;
1795 shift_state |= KB_SCROLL;
1796 lock_state ^= KB_SCROLL;
1797 if ((lock_state & KB_SCROLL) == 0)
1798 wakeup((caddr_t)&lock_state);
1799 async_update();
1800 break;
1801 }
1802 return capchar;
1803 }
1804
1805 switch (dt) {
1806 case KBR_EXTENDED:
1807 extended = 1;
1808 goto loop;
1809 }
1810
1811 #ifdef DDB
1812 /*
1813 * Check for cntl-alt-esc.
1814 */
1815 if ((dt == 1) && (shift_state & (KB_CTL | KB_ALT)) == (KB_CTL | KB_ALT)) {
1816 /* XXX - check pccons_is_console */
1817 Debugger();
1818 dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
1819 }
1820 #endif
1821
1822 /*
1823 * Check for make/break.
1824 */
1825 if (dt & 0x80) {
1826 /*
1827 * break
1828 */
1829 dt &= 0x7f;
1830 switch (scan_codes[dt].type) {
1831 case KB_NUM:
1832 shift_state &= ~KB_NUM;
1833 break;
1834 case KB_CAPS:
1835 shift_state &= ~KB_CAPS;
1836 break;
1837 case KB_SCROLL:
1838 shift_state &= ~KB_SCROLL;
1839 break;
1840 case KB_SHIFT:
1841 shift_state &= ~KB_SHIFT;
1842 break;
1843 case KB_ALT:
1844 if (extended)
1845 shift_state &= ~KB_ALTGR;
1846 else
1847 shift_state &= ~KB_ALT;
1848 break;
1849 case KB_CTL:
1850 shift_state &= ~KB_CTL;
1851 break;
1852 }
1853 } else {
1854 /*
1855 * make
1856 */
1857 switch (scan_codes[dt].type) {
1858 /*
1859 * locking keys
1860 */
1861 case KB_NUM:
1862 if (shift_state & KB_NUM)
1863 break;
1864 shift_state |= KB_NUM;
1865 lock_state ^= KB_NUM;
1866 async_update();
1867 break;
1868 case KB_CAPS:
1869 if (shift_state & KB_CAPS)
1870 break;
1871 shift_state |= KB_CAPS;
1872 lock_state ^= KB_CAPS;
1873 async_update();
1874 break;
1875 case KB_SCROLL:
1876 if (shift_state & KB_SCROLL)
1877 break;
1878 shift_state |= KB_SCROLL;
1879 lock_state ^= KB_SCROLL;
1880 if ((lock_state & KB_SCROLL) == 0)
1881 wakeup((caddr_t)&lock_state);
1882 async_update();
1883 break;
1884 /*
1885 * non-locking keys
1886 */
1887 case KB_SHIFT:
1888 shift_state |= KB_SHIFT;
1889 break;
1890 case KB_ALT:
1891 if (extended)
1892 shift_state |= KB_ALTGR;
1893 else
1894 shift_state |= KB_ALT;
1895 break;
1896 case KB_CTL:
1897 shift_state |= KB_CTL;
1898 break;
1899 case KB_ASCII:
1900 /* control has highest priority */
1901 if (shift_state & KB_CTL)
1902 capchar[0] = scan_codes[dt].ctl[0];
1903 else if (shift_state & KB_ALTGR) {
1904 if (shift_state & KB_SHIFT)
1905 capchar[0] = scan_codes[dt].shift_altgr[0];
1906 else
1907 capchar[0] = scan_codes[dt].altgr[0];
1908 }
1909 else {
1910 if (shift_state & KB_SHIFT)
1911 capchar[0] = scan_codes[dt].shift[0];
1912 else
1913 capchar[0] = scan_codes[dt].unshift[0];
1914 }
1915 if ((lock_state & KB_CAPS) && capchar[0] >= 'a' &&
1916 capchar[0] <= 'z') {
1917 capchar[0] -= ('a' - 'A');
1918 }
1919 capchar[0] |= (shift_state & KB_ALT);
1920 extended = 0;
1921 return capchar;
1922 case KB_NONE:
1923 printf("keycode %d\n",dt);
1924 break;
1925 case KB_FUNC: {
1926 char *more_chars;
1927 if (shift_state & KB_SHIFT)
1928 more_chars = scan_codes[dt].shift;
1929 else if (shift_state & KB_CTL)
1930 more_chars = scan_codes[dt].ctl;
1931 else
1932 more_chars = scan_codes[dt].unshift;
1933 extended = 0;
1934 return more_chars;
1935 }
1936 case KB_KP: {
1937 char *more_chars;
1938 if (shift_state & (KB_SHIFT | KB_CTL) ||
1939 (lock_state & KB_NUM) == 0 || extended)
1940 more_chars = scan_codes[dt].shift;
1941 else
1942 more_chars = scan_codes[dt].unshift;
1943 extended = 0;
1944 return more_chars;
1945 }
1946 }
1947 }
1948
1949 extended = 0;
1950 loop:
1951 if ((inb(kbd_cmdp) & KBS_DIB) == 0)
1952 return 0;
1953 goto top;
1954 }
1955
1956 paddr_t
1957 pcmmap(dev, offset, nprot)
1958 dev_t dev;
1959 off_t offset;
1960 int nprot;
1961 {
1962
1963 switch(cputype) {
1964
1965 case ACER_PICA_61:
1966 case NEC_R96:
1967 if (offset >= 0xa0000 && offset < 0xc0000)
1968 return mips_btop(PICA_P_LOCAL_VIDEO + offset);
1969 if (offset >= 0x0000 && offset < 0x10000)
1970 return mips_btop(PICA_P_LOCAL_VIDEO_CTRL + offset);
1971 if (offset >= 0x40000000 && offset < 0x40800000)
1972 return mips_btop(PICA_P_LOCAL_VIDEO + offset - 0x40000000);
1973 return -1;
1974
1975 case DESKSTATION_RPC44:
1976 if (offset >= 0xa0000 && offset < 0xc0000)
1977 return mips_btop(RPC44_P_ISA_MEM + offset);
1978 if (offset >= 0x0000 && offset < 0x10000)
1979 return mips_btop(RPC44_P_ISA_IO + offset);
1980 if (offset >= 0x40000000 && offset < 0x40800000)
1981 return mips_btop(RPC44_P_ISA_MEM + offset - 0x40000000);
1982 return -1;
1983
1984 case DESKSTATION_TYNE:
1985 if (offset >= 0xa0000 && offset < 0xc0000)
1986 return mips_btop(TYNE_P_ISA_MEM + offset);
1987 if (offset >= 0x0000 && offset < 0x10000)
1988 return mips_btop(TYNE_P_ISA_IO + offset);
1989 if (offset >= 0x40000000 && offset < 0x40800000)
1990 return mips_btop(TYNE_P_ISA_MEM + offset - 0x40000000);
1991 return -1;
1992 }
1993 return -1;
1994 }
1995
1996 void
1997 pc_xmode_on()
1998 {
1999 if (pc_xmode)
2000 return;
2001 pc_xmode = 1;
2002
2003 #ifdef XFREE86_BUG_COMPAT
2004 /* If still unchanged, get current shape. */
2005 if (cursor_shape == 0xffff)
2006 get_cursor_shape();
2007 #endif
2008 }
2009
2010 void
2011 pc_xmode_off()
2012 {
2013 if (pc_xmode == 0)
2014 return;
2015 pc_xmode = 0;
2016
2017 #ifdef XFREE86_BUG_COMPAT
2018 /* XXX It would be hard to justify why the X server doesn't do this. */
2019 set_cursor_shape();
2020 #endif
2021 async_update();
2022 }
2023
2024 #include <machine/mouse.h>
2025
2026 /* status bits */
2027 #define PMS_OBUF_FULL 0x01
2028 #define PMS_IBUF_FULL 0x02
2029
2030 /* controller commands */
2031 #define PMS_INT_ENABLE 0x47 /* enable controller interrupts */
2032 #define PMS_INT_DISABLE 0x65 /* disable controller interrupts */
2033 #define PMS_AUX_ENABLE 0xa7 /* enable auxiliary port */
2034 #define PMS_AUX_DISABLE 0xa8 /* disable auxiliary port */
2035 #define PMS_MAGIC_1 0xa9 /* XXX */
2036
2037 #define PMS_8042_CMD 0x65
2038
2039 /* mouse commands */
2040 #define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */
2041 #define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */
2042 #define PMS_SET_RES 0xe8 /* set resolution */
2043 #define PMS_GET_SCALE 0xe9 /* get scaling factor */
2044 #define PMS_SET_STREAM 0xea /* set streaming mode */
2045 #define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
2046 #define PMS_DEV_ENABLE 0xf4 /* mouse on */
2047 #define PMS_DEV_DISABLE 0xf5 /* mouse off */
2048 #define PMS_RESET 0xff /* reset */
2049
2050 #define PMS_CHUNK 128 /* chunk size for read */
2051 #define PMS_BSIZE 1020 /* buffer size */
2052
2053 #define FLUSHQ(q) { if((q)->c_cc) ndflush(q, (q)->c_cc); }
2054
2055 #if NOPMS > 0
2056
2057 int opmsopen __P((dev_t, int));
2058 int opmsclose __P((dev_t, int));
2059 int opmsread __P((dev_t, struct uio *, int));
2060 int opmsioctl __P((dev_t, u_long, caddr_t, int));
2061 int opmsselect __P((dev_t, int, struct proc *));
2062 int opmspoll __P((dev_t, int, struct proc *));
2063 static __inline void pms_dev_cmd __P((u_char));
2064 static __inline void pms_aux_cmd __P((u_char));
2065 static __inline void pms_pit_cmd __P((u_char));
2066
2067 static __inline void
2068 pms_dev_cmd(value)
2069 u_char value;
2070 {
2071 kbd_flush_input();
2072 outb(kbd_cmdp, 0xd4);
2073 kbd_flush_input();
2074 outb(kbd_datap, value);
2075 }
2076
2077 static __inline void
2078 pms_aux_cmd(value)
2079 u_char value;
2080 {
2081 kbd_flush_input();
2082 outb(kbd_cmdp, value);
2083 }
2084
2085 static __inline void
2086 pms_pit_cmd(value)
2087 u_char value;
2088 {
2089 kbd_flush_input();
2090 outb(kbd_cmdp, 0x60);
2091 kbd_flush_input();
2092 outb(kbd_datap, value);
2093 }
2094
2095 int
2096 opmsprobe(parent, match, aux)
2097 struct device *parent;
2098 struct cfdata *match;
2099 void *aux;
2100 {
2101 struct confargs *ca = aux;
2102 u_char x;
2103
2104 /* Make shure we're looking for this type of device */
2105 if(!BUS_MATCHNAME(ca, "pms"))
2106 return(0);
2107
2108 pcinithandle();
2109 pms_dev_cmd(KBC_RESET);
2110 pms_aux_cmd(PMS_MAGIC_1);
2111 delay(10000);
2112 x = inb(kbd_datap);
2113 pms_pit_cmd(PMS_INT_DISABLE);
2114 if (x & 0x04)
2115 return 0;
2116
2117 return 1;
2118 }
2119
2120 void
2121 opmsattach(parent, self, aux)
2122 struct device *parent, *self;
2123 void *aux;
2124 {
2125 struct opms_softc *sc = (void *)self;
2126 struct confargs *ca = aux;
2127
2128 printf("\n");
2129
2130 /* Other initialization was done by opmsprobe. */
2131 sc->sc_state = 0;
2132
2133 BUS_INTR_ESTABLISH(ca, opmsintr, (void *)(long)sc);
2134 }
2135
2136 int
2137 opmsopen(dev, flag)
2138 dev_t dev;
2139 int flag;
2140 {
2141 int unit = PMSUNIT(dev);
2142 struct opms_softc *sc;
2143
2144 if (unit >= opms_cd.cd_ndevs)
2145 return ENXIO;
2146 sc = opms_cd.cd_devs[unit];
2147 if (!sc)
2148 return ENXIO;
2149
2150 if (sc->sc_state & PMS_OPEN)
2151 return EBUSY;
2152
2153 if (clalloc(&sc->sc_q, PMS_BSIZE, 0) == -1)
2154 return ENOMEM;
2155
2156 sc->sc_state |= PMS_OPEN;
2157 sc->sc_status = 0;
2158 sc->sc_x = sc->sc_y = 0;
2159
2160 /* Enable interrupts. */
2161 pms_dev_cmd(PMS_DEV_ENABLE);
2162 pms_aux_cmd(PMS_AUX_ENABLE);
2163 pms_dev_cmd(PMS_SET_RES);
2164 pms_dev_cmd(3); /* 8 counts/mm */
2165 pms_dev_cmd(PMS_SET_SCALE21);
2166 #if 0
2167 pms_dev_cmd(PMS_SET_SAMPLE);
2168 pms_dev_cmd(100); /* 100 samples/sec */
2169 pms_dev_cmd(PMS_SET_STREAM);
2170 #endif
2171 pms_pit_cmd(PMS_INT_ENABLE);
2172
2173 return 0;
2174 }
2175
2176 int
2177 opmsclose(dev, flag)
2178 dev_t dev;
2179 int flag;
2180 {
2181 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2182
2183 /* Disable interrupts. */
2184 pms_dev_cmd(PMS_DEV_DISABLE);
2185 pms_pit_cmd(PMS_INT_DISABLE);
2186 pms_aux_cmd(PMS_AUX_DISABLE);
2187
2188 sc->sc_state &= ~PMS_OPEN;
2189
2190 clfree(&sc->sc_q);
2191
2192 return 0;
2193 }
2194
2195 int
2196 opmsread(dev, uio, flag)
2197 dev_t dev;
2198 struct uio *uio;
2199 int flag;
2200 {
2201 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2202 int s;
2203 int error = 0;
2204 size_t length;
2205 u_char buffer[PMS_CHUNK];
2206
2207 /* Block until mouse activity occured. */
2208
2209 s = spltty();
2210 while (sc->sc_q.c_cc == 0) {
2211 if (flag & IO_NDELAY) {
2212 splx(s);
2213 return EWOULDBLOCK;
2214 }
2215 sc->sc_state |= PMS_ASLP;
2216 error = tsleep((caddr_t)sc, PZERO | PCATCH, "pmsrea", 0);
2217 if (error) {
2218 sc->sc_state &= ~PMS_ASLP;
2219 splx(s);
2220 return error;
2221 }
2222 }
2223 splx(s);
2224
2225 /* Transfer as many chunks as possible. */
2226
2227 while (sc->sc_q.c_cc > 0 && uio->uio_resid > 0) {
2228 length = min(sc->sc_q.c_cc, uio->uio_resid);
2229 if (length > sizeof(buffer))
2230 length = sizeof(buffer);
2231
2232 /* Remove a small chunk from the input queue. */
2233 (void) q_to_b(&sc->sc_q, buffer, length);
2234
2235 /* Copy the data to the user process. */
2236 error = uiomove(buffer, length, uio);
2237 if (error)
2238 break;
2239 }
2240
2241 return error;
2242 }
2243
2244 int
2245 opmsioctl(dev, cmd, addr, flag)
2246 dev_t dev;
2247 u_long cmd;
2248 caddr_t addr;
2249 int flag;
2250 {
2251 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2252 struct mouseinfo info;
2253 int s;
2254 int error;
2255
2256 switch (cmd) {
2257 case MOUSEIOCREAD:
2258 s = spltty();
2259
2260 info.status = sc->sc_status;
2261 if (sc->sc_x || sc->sc_y)
2262 info.status |= MOVEMENT;
2263
2264 if (sc->sc_x > 127)
2265 info.xmotion = 127;
2266 else if (sc->sc_x < -127)
2267 /* Bounding at -127 avoids a bug in XFree86. */
2268 info.xmotion = -127;
2269 else
2270 info.xmotion = sc->sc_x;
2271
2272 if (sc->sc_y > 127)
2273 info.ymotion = 127;
2274 else if (sc->sc_y < -127)
2275 info.ymotion = -127;
2276 else
2277 info.ymotion = sc->sc_y;
2278
2279 /* Reset historical information. */
2280 sc->sc_x = sc->sc_y = 0;
2281 sc->sc_status &= ~BUTCHNGMASK;
2282 ndflush(&sc->sc_q, sc->sc_q.c_cc);
2283
2284 splx(s);
2285 error = copyout(&info, addr, sizeof(struct mouseinfo));
2286 break;
2287 default:
2288 error = EINVAL;
2289 break;
2290 }
2291
2292 return error;
2293 }
2294
2295 /* Masks for the first byte of a packet */
2296 #define PS2LBUTMASK 0x01
2297 #define PS2RBUTMASK 0x02
2298 #define PS2MBUTMASK 0x04
2299
2300 int
2301 opmsintr(arg)
2302 void *arg;
2303 {
2304 struct opms_softc *sc = arg;
2305 static int state = 0;
2306 static u_char buttons;
2307 u_char changed;
2308 static char dx, dy;
2309 u_char buffer[5];
2310
2311 if ((sc->sc_state & PMS_OPEN) == 0) {
2312 /* Interrupts are not expected. Discard the byte. */
2313 kbd_flush_input();
2314 return 0;
2315 }
2316
2317 switch (state) {
2318
2319 case 0:
2320 buttons = inb(kbd_datap);
2321 if ((buttons & 0xc0) == 0)
2322 ++state;
2323 break;
2324
2325 case 1:
2326 dx = inb(kbd_datap);
2327 /* Bounding at -127 avoids a bug in XFree86. */
2328 dx = (dx == -128) ? -127 : dx;
2329 ++state;
2330 break;
2331
2332 case 2:
2333 dy = inb(kbd_datap);
2334 dy = (dy == -128) ? -127 : dy;
2335 state = 0;
2336
2337 buttons = ((buttons & PS2LBUTMASK) << 2) |
2338 ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1);
2339 changed = ((buttons ^ sc->sc_status) & BUTSTATMASK) << 3;
2340 sc->sc_status = buttons | (sc->sc_status & ~BUTSTATMASK) | changed;
2341
2342 if (dx || dy || changed) {
2343 /* Update accumulated movements. */
2344 sc->sc_x += dx;
2345 sc->sc_y += dy;
2346
2347 /* Add this event to the queue. */
2348 buffer[0] = 0x80 | (buttons & BUTSTATMASK);
2349 if(dx < 0)
2350 buffer[0] |= 0x10;
2351 buffer[1] = dx & 0x7f;
2352 if(dy < 0)
2353 buffer[0] |= 0x20;
2354 buffer[2] = dy & 0x7f;
2355 buffer[3] = buffer[4] = 0;
2356 (void) b_to_q(buffer, sizeof buffer, &sc->sc_q);
2357
2358 if (sc->sc_state & PMS_ASLP) {
2359 sc->sc_state &= ~PMS_ASLP;
2360 wakeup((caddr_t)sc);
2361 }
2362 selwakeup(&sc->sc_rsel);
2363 }
2364
2365 break;
2366 }
2367 return -1;
2368 }
2369
2370 int
2371 opmspoll(dev, events, p)
2372 dev_t dev;
2373 int events;
2374 struct proc *p;
2375 {
2376 struct opms_softc *sc = opms_cd.cd_devs[PMSUNIT(dev)];
2377 int revents = 0;
2378 int s = spltty();
2379
2380 if (events & (POLLIN | POLLRDNORM)) {
2381 if (sc->sc_q.c_cc > 0)
2382 revents |= events & (POLLIN | POLLRDNORM);
2383 else
2384 selrecord(p, &sc->sc_rsel);
2385 }
2386
2387 splx(s);
2388 return (revents);
2389 }
2390
2391 #endif /* NOPMS > 0 */
2392