kbd.c revision 1.37 1 /* $NetBSD: kbd.c,v 1.37 2002/01/26 13:40:58 aymeric Exp $ */
2
3 /*
4 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * kbd.c
36 */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/ioctl.h>
41 #include <sys/tty.h>
42 #include <sys/proc.h>
43 #include <sys/file.h>
44 #include <sys/kernel.h>
45 #include <sys/syslog.h>
46 #include <sys/signalvar.h>
47 #include <dev/cons.h>
48 #include <machine/cpu.h>
49 #include <amiga/amiga/device.h>
50 #include <amiga/amiga/custom.h>
51 #ifdef DRACO
52 #include <m68k/asm_single.h>
53 #include <amiga/amiga/drcustom.h>
54 #endif
55 #include <amiga/amiga/cia.h>
56 #include <amiga/dev/itevar.h>
57 #include <amiga/dev/kbdreg.h>
58 #include <amiga/dev/kbdmap.h>
59 #include <amiga/dev/event_var.h>
60 #include <amiga/dev/vuid_event.h>
61
62 #include "kbd.h"
63 #include "ite.h"
64
65 /* WSKBD */
66
67 /*
68 * If NWSKBD>0 we try to attach an wskbd device to us. What follows
69 * is definitions of callback functions and structures that are passed
70 * to wscons when initializing.
71 */
72
73 /*
74 * Now with wscons this driver exhibits some weird behaviour.
75 * It may act both as a driver of its own and the md part of the
76 * wskbd driver. Therefore it can be accessed through /dev/kbd
77 * and /dev/wskbd0 both.
78 *
79 * The data from they keyboard may end up in at least four different
80 * places:
81 * - If this driver has been opened (/dev/kbd) and the
82 * direct mode (TIOCDIRECT) has been set, data goes to
83 * the process who opened the device. Data will transmit itself
84 * as described by the firm_event structure.
85 * - If wskbd support is compiled in and a wskbd driver has been
86 * attached then the data is sent to it. Wskbd in turn may
87 * - Send the data in the wscons_event form to a process that
88 * has opened /dev/wskbd0
89 * - Feed the data to a virtual terminal.
90 * - If an ite is present the data may be fed to it.
91 */
92
93 #include "wskbd.h"
94
95 #if NWSKBD>0
96 #include <dev/wscons/wsconsio.h>
97 #include <dev/wscons/wskbdvar.h>
98 #include <dev/wscons/wsksymdef.h>
99 #include <dev/wscons/wsksymvar.h>
100 #include <amiga/dev/wskbdmap_amiga.h>
101
102 /* accessops */
103 int kbd_enable(void *, int);
104 void kbd_set_leds(void *, int);
105 int kbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
106
107 /* console ops */
108 void kbd_getc(void *, u_int *, int *);
109 void kbd_pollc(void *, int);
110 void kbd_bell(void *, u_int, u_int, u_int);
111
112 static struct wskbd_accessops kbd_accessops = {
113 kbd_enable,
114 kbd_set_leds,
115 kbd_ioctl
116 };
117
118 static struct wskbd_consops kbd_consops = {
119 kbd_getc,
120 kbd_pollc,
121 kbd_bell
122 };
123
124 /*
125 * Pointer to keymaps. They are defined in wskbdmap_amiga.c.
126 */
127 static struct wskbd_mapdata kbd_mapdata = {
128 amigakbd_keydesctab,
129 KB_US
130 };
131
132 #endif /* WSKBD */
133
134
135 #include <sys/conf.h>
136 #include <machine/conf.h>
137
138 struct kbd_softc {
139 int k_event_mode; /* if true, collect events, else pass to ite */
140 struct evvar k_events; /* event queue state */
141 #ifdef DRACO
142 u_char k_rlprfx; /* MF-II rel. prefix has been seen */
143 u_char k_mf2;
144 #endif
145
146 #if NWSKBD>0
147 struct device *k_wskbddev; /* pointer to wskbd for sending strokes */
148 int k_pollingmode; /* polling mode on? whatever it isss... */
149 #endif
150 };
151 struct kbd_softc kbd_softc;
152
153 int kbdmatch(struct device *, struct cfdata *, void *);
154 void kbdattach(struct device *, struct device *, void *);
155 void kbdintr(int);
156 void kbdstuffchar(u_char);
157
158 int drkbdgetc(void);
159 int drkbdrputc(u_int8_t);
160 int drkbdputc(u_int8_t);
161 int drkbdputc2(u_int8_t, u_int8_t);
162 int drkbdwaitfor(int);
163
164 struct cfattach kbd_ca = {
165 sizeof(struct device), kbdmatch, kbdattach
166 };
167
168 /*ARGSUSED*/
169 int
170 kbdmatch(struct device *pdp, struct cfdata *cfp, void *auxp)
171 {
172
173 if (matchname((char *)auxp, "kbd"))
174 return(1);
175 return(0);
176 }
177
178 /*ARGSUSED*/
179 void
180 kbdattach(struct device *pdp, struct device *dp, void *auxp)
181 {
182 #ifdef DRACO
183 kbdenable();
184 if (kbd_softc.k_mf2)
185 printf(": QuickLogic type MF-II\n");
186 else
187 printf(": CIA A type Amiga\n");
188 #else
189 printf(": CIA A type Amiga\n");
190 #endif
191
192 #if NWSKBD>0
193 if (dp != NULL) {
194 /*
195 * Try to attach the wskbd.
196 */
197 struct wskbddev_attach_args waa;
198
199 /* Maybe should be done before this?... */
200 wskbd_cnattach(&kbd_consops, NULL, &kbd_mapdata);
201
202 waa.console = 1;
203 waa.keymap = &kbd_mapdata;
204 waa.accessops = &kbd_accessops;
205 waa.accesscookie = NULL;
206 kbd_softc.k_wskbddev = config_found(dp, &waa, wskbddevprint);
207
208 kbd_softc.k_pollingmode = 0;
209 }
210 kbdenable();
211 #endif /* WSKBD */
212 }
213
214 /* definitions for amiga keyboard encoding. */
215 #define KEY_CODE(c) ((c) & 0x7f)
216 #define KEY_UP(c) ((c) & 0x80)
217
218 #define DATLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
219 #define DATHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDDATOUT)
220
221 #define CLKLO single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
222 #define CLKHI single_inst_bset_b(draco_ioct->io_control, DRCNTRL_KBDCLKOUT)
223
224 void
225 kbdenable(void)
226 {
227 static int kbd_inited = 0;
228
229 int s;
230
231 #ifdef DRACO
232 int id;
233 #endif
234 /*
235 * collides with external ints from SCSI, watch out for this when
236 * enabling/disabling interrupts there !!
237 */
238 s = splhigh(); /* don't lower; might be called from early ddb */
239 if (kbd_inited) {
240 splx(s);
241 return;
242 }
243 kbd_inited = 1;
244 #ifdef DRACO
245 if (is_draco()) {
246
247 CLKLO;
248 delay(5000);
249 draco_ioct->io_kbdrst = 0;
250
251 if (drkbdputc(0xf2))
252 goto LnoMFII;
253
254 id = drkbdgetc() << 8;
255 id |= drkbdgetc();
256
257 if (id != 0xab83)
258 goto LnoMFII;
259
260 if (drkbdputc2(0xf0, 3)) /* mode 3 */
261 goto LnoMFII;
262
263 if (drkbdputc(0xf8)) /* make/break, no typematic */
264 goto LnoMFII;
265
266 if (drkbdputc(0xf4)) /* enable */
267 goto LnoMFII;
268 kbd_softc.k_mf2 = 1;
269 single_inst_bclr_b(draco_ioct->io_control, DRCNTRL_KBDINTENA);
270
271 ciaa.icr = CIA_ICR_SP; /* CIA SP interrupt disable */
272 ciaa.cra &= ~(1<<6); /* serial line == input */
273 splx(s);
274 return;
275
276 LnoMFII:
277 kbd_softc.k_mf2 = 0;
278 single_inst_bset_b(*draco_intena, DRIRQ_INT2);
279 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP;
280 /* SP interrupt enable */
281 ciaa.cra &= ~(1<<6); /* serial line == input */
282 splx(s);
283 return;
284
285 } else {
286 #endif
287 custom.intena = INTF_SETCLR | INTF_PORTS;
288 ciaa.icr = CIA_ICR_IR_SC | CIA_ICR_SP; /* SP interrupt enable */
289 ciaa.cra &= ~(1<<6); /* serial line == input */
290 #ifdef DRACO
291 }
292 #endif
293 kbd_softc.k_event_mode = 0;
294 kbd_softc.k_events.ev_io = 0;
295 splx(s);
296 }
297
298 #ifdef DRACO
299 /*
300 * call this with kbd interupt blocked
301 */
302
303 int
304 drkbdgetc(void)
305 {
306 u_int8_t in;
307
308 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
309 in = draco_ioct->io_kbddata;
310 draco_ioct->io_kbdrst = 0;
311
312 return in;
313 }
314
315 #define WAIT0 if (drkbdwaitfor(0)) goto Ltimeout
316 #define WAIT1 if (drkbdwaitfor(DRSTAT_KBDCLKIN)) goto Ltimeout
317
318 int
319 drkbdwaitfor(int bit)
320 {
321 int i;
322
323
324
325 i = 60000; /* about 50 ms max */
326
327 do {
328 if ((draco_ioct->io_status & DRSTAT_KBDCLKIN) == bit)
329 return 0;
330
331 } while (--i >= 0);
332
333 return 1;
334 }
335
336 /*
337 * Output a raw byte to the keyboard (+ parity and stop bit).
338 * return 0 on success, 1 on timeout.
339 */
340 int
341 drkbdrputc(u_int8_t c)
342 {
343 u_int8_t parity;
344 int bitcnt;
345
346 DATLO; CLKHI; WAIT1;
347 parity = 0;
348
349 for (bitcnt=7; bitcnt >= 0; bitcnt--) {
350 WAIT0;
351 if (c & 1) {
352 DATHI;
353 } else {
354 ++parity;
355 DATLO;
356 }
357 c >>= 1;
358 WAIT1;
359 }
360 WAIT0;
361 /* parity bit */
362 if (parity & 1) {
363 DATLO;
364 } else {
365 DATHI;
366 }
367 WAIT1;
368 /* stop bit */
369 WAIT0; DATHI; WAIT1;
370
371 WAIT0; /* XXX should check the ack bit here... */
372 WAIT1;
373 draco_ioct->io_kbdrst = 0;
374 return 0;
375
376 Ltimeout:
377 DATHI;
378 draco_ioct->io_kbdrst = 0;
379 return 1;
380 }
381
382 /*
383 * Output one cooked byte to the keyboard, with wait for ACK or RESEND,
384 * and retry if necessary. 0 == success, 1 == timeout
385 */
386 int
387 drkbdputc(u_int8_t c)
388 {
389 int rc;
390
391 do {
392 if (drkbdrputc(c))
393 return(-1);
394
395 rc = drkbdgetc();
396 } while (rc == 0xfe);
397 return (!(rc == 0xfa));
398 }
399
400 /*
401 * same for twobyte sequence
402 */
403
404 int
405 drkbdputc2(u_int8_t c1, u_int8_t c2)
406 {
407 int rc;
408
409 do {
410 do {
411 if (drkbdrputc(c1))
412 return(-1);
413
414 rc = drkbdgetc();
415 } while (rc == 0xfe);
416 if (rc != 0xfa)
417 return (-1);
418
419 if (drkbdrputc(c2))
420 return(-1);
421
422 rc = drkbdgetc();
423 } while (rc == 0xfe);
424 return (!(rc == 0xfa));
425 }
426 #endif
427
428 int
429 kbdopen(dev_t dev, int flags, int mode, struct proc *p)
430 {
431
432 kbdenable();
433 if (kbd_softc.k_events.ev_io)
434 return EBUSY;
435
436 kbd_softc.k_events.ev_io = p;
437 ev_init(&kbd_softc.k_events);
438 return (0);
439 }
440
441 int
442 kbdclose(dev_t dev, int flags, int mode, struct proc *p)
443 {
444
445 /* Turn off event mode, dump the queue */
446 kbd_softc.k_event_mode = 0;
447 ev_fini(&kbd_softc.k_events);
448 kbd_softc.k_events.ev_io = NULL;
449 return (0);
450 }
451
452 int
453 kbdread(dev_t dev, struct uio *uio, int flags)
454 {
455 return ev_read (&kbd_softc.k_events, uio, flags);
456 }
457
458 int
459 kbdioctl(dev_t dev, u_long cmd, register caddr_t data, int flag,
460 struct proc *p)
461 {
462 register struct kbd_softc *k = &kbd_softc;
463
464 switch (cmd) {
465 case KIOCTRANS:
466 if (*(int *)data == TR_UNTRANS_EVENT)
467 return 0;
468 break;
469
470 case KIOCGTRANS:
471 /* Get translation mode */
472 *(int *)data = TR_UNTRANS_EVENT;
473 return 0;
474
475 case KIOCSDIRECT:
476 k->k_event_mode = *(int *)data;
477 return 0;
478
479 case FIONBIO: /* we will remove this someday (soon???) */
480 return 0;
481
482 case FIOASYNC:
483 k->k_events.ev_async = *(int *)data != 0;
484 return 0;
485
486 case TIOCSPGRP:
487 if (*(int *)data != k->k_events.ev_io->p_pgid)
488 return EPERM;
489 return 0;
490
491 default:
492 return ENOTTY;
493 }
494
495 /* We identified the ioctl, but we do not handle it. */
496 return EOPNOTSUPP; /* misuse, but what the heck */
497 }
498
499 int
500 kbdpoll(dev_t dev, int events, struct proc *p)
501 {
502 return ev_poll (&kbd_softc.k_events, events, p);
503 }
504
505
506 void
507 kbdintr(int mask)
508 {
509 u_char c;
510 #ifdef KBDRESET
511 static int reset_warn;
512 #endif
513
514 /*
515 * now only invoked from generic CIA interrupt handler if there *is*
516 * a keyboard interrupt pending
517 */
518
519 c = ~ciaa.sdr; /* keyboard data is inverted */
520 /* ack */
521 ciaa.cra |= (1 << 6); /* serial line output */
522 #ifdef KBDRESET
523 if (reset_warn && c == 0xf0) {
524 #ifdef DEBUG
525 printf ("kbdintr: !!!! Reset Warning !!!!\n");
526 #endif
527 bootsync();
528 reset_warn = 0;
529 DELAY(30000000);
530 }
531 #endif
532 /* wait 200 microseconds (for bloody Cherry keyboards..) */
533 DELAY(2000); /* fudge delay a bit for some keyboards */
534 ciaa.cra &= ~(1 << 6);
535
536 /* process the character */
537 c = (c >> 1) | (c << 7); /* rotate right once */
538
539 #ifdef KBDRESET
540 if (c == 0x78) {
541 #ifdef DEBUG
542 printf ("kbdintr: Reset Warning started\n");
543 #endif
544 ++reset_warn;
545 return;
546 }
547 #endif
548 kbdstuffchar(c);
549 }
550
551 #ifdef DRACO
552 /* maps MF-II keycodes to Amiga keycodes */
553
554 const u_char drkbdtab[] = {
555 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x50,
556 0x45, 0xff, 0xff, 0xff, 0xff, 0x42, 0x00, 0x51,
557
558 0xff, 0x64, 0x60, 0x30, 0x63, 0x10, 0x01, 0x52,
559 0xff, 0x66, 0x31, 0x21, 0x20, 0x11, 0x02, 0x53,
560
561 0xff, 0x33, 0x32, 0x22, 0x12, 0x04, 0x03, 0x54,
562 0xff, 0x40, 0x34, 0x23, 0x14, 0x13, 0x05, 0x55,
563
564 0xff, 0x36, 0x35, 0x25, 0x24, 0x15, 0x06, 0x56,
565 0xff, 0x67, 0x37, 0x26, 0x16, 0x07, 0x08, 0x57,
566 /* --- */
567 0xff, 0x38, 0x27, 0x17, 0x18, 0x0a, 0x09, 0x58,
568 0xff, 0x39, 0x3a, 0x28, 0x29, 0x19, 0x0b, 0x59,
569
570 0xff, 0xff, 0x2a, 0x2b, 0x1a, 0x0c, 0x4b, 0xff,
571 0x65, 0x61, 0x44, 0x1b, 0xff, 0xff, 0x6f, 0xff,
572
573 0x4d, 0x4f, 0xff, 0x4c, 0x0d, 0xff, 0x41, 0x46,
574 0xff, 0x1d, 0x4e, 0x2d, 0x3d, 0x4a, 0x5f, 0x62,
575
576 0x0f, 0x3c, 0x1e, 0x2e, 0x2f, 0x3e, 0x5a, 0x5b,
577 0xff, 0x43, 0x1f, 0xff, 0x5e, 0x3f, 0x5c, 0xff,
578 /* --- */
579 0xff, 0xff, 0xff, 0xff, 0x5d
580 };
581 #endif
582
583
584 int
585 kbdgetcn(void)
586 {
587 int s;
588 u_char ints, mask, c, in;
589
590 #ifdef DRACO
591 if (is_draco() && kbd_softc.k_mf2) {
592 do {
593 c = 0;
594 s = spltty ();
595 while ((draco_ioct->io_status & DRSTAT_KBDRECV) == 0);
596 in = draco_ioct->io_kbddata;
597 draco_ioct->io_kbdrst = 0;
598 if (in == 0xF0) { /* release prefix */
599 c = 0x80;
600 while ((draco_ioct->io_status &
601 DRSTAT_KBDRECV) == 0);
602 in = draco_ioct->io_kbddata;
603 draco_ioct->io_kbdrst = 0;
604 }
605 splx(s);
606 #ifdef DRACORAWKEYDEBUG
607 printf("<%02x>", in);
608 #endif
609 c |= in>=sizeof(drkbdtab) ? 0xff : drkbdtab[in];
610 } while (c == 0xff);
611 return (c);
612 }
613 #endif
614 s = spltty();
615 for (ints = 0; ! ((mask = ciaa.icr) & CIA_ICR_SP);
616 ints |= mask) ;
617
618 in = ciaa.sdr;
619 c = ~in;
620
621 /* ack */
622 ciaa.cra |= (1 << 6); /* serial line output */
623 ciaa.sdr = 0xff; /* ack */
624 /* wait 200 microseconds */
625 DELAY(2000); /* XXXX only works as long as DELAY doesn't
626 * use a timer and waits.. */
627 ciaa.cra &= ~(1 << 6);
628 ciaa.sdr = in;
629
630 splx (s);
631 c = (c >> 1) | (c << 7);
632
633 /* take care that no CIA-interrupts are lost */
634 if (ints)
635 dispatch_cia_ints (0, ints);
636
637 return c;
638 }
639
640 void
641 kbdstuffchar(u_char c)
642 {
643 struct firm_event *fe;
644 struct kbd_softc *k = &kbd_softc;
645 int put;
646
647 #if NWSKBD>0
648 /*
649 * If we have attached a wskbd and not in polling mode and
650 * nobody has opened us directly, then send the keystroke
651 * to the wskbd.
652 */
653
654 if (kbd_softc.k_pollingmode == 0
655 && kbd_softc.k_wskbddev != NULL
656 && k->k_event_mode == 0) {
657 wskbd_input(kbd_softc.k_wskbddev,
658 KEY_UP(c) ?
659 WSCONS_EVENT_KEY_UP :
660 WSCONS_EVENT_KEY_DOWN,
661 KEY_CODE(c));
662 return;
663 }
664
665 #endif /* NWSKBD */
666
667 /*
668 * If not in event mode, deliver straight to ite to process
669 * key stroke
670 */
671
672 if (! k->k_event_mode) {
673 #if NITE>0
674 ite_filter (c, ITEFILT_TTY);
675 #endif
676 return;
677 }
678
679 /*
680 * Keyboard is generating events. Turn this keystroke into an
681 * event and put it in the queue. If the queue is full, the
682 * keystroke is lost (sorry!).
683 */
684
685 put = k->k_events.ev_put;
686 fe = &k->k_events.ev_q[put];
687 put = (put + 1) % EV_QSIZE;
688 if (put == k->k_events.ev_get) {
689 log(LOG_WARNING, "keyboard event queue overflow\n");
690 /* ??? */
691 return;
692 }
693 fe->id = KEY_CODE(c);
694 fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN;
695 fe->time = time;
696 k->k_events.ev_put = put;
697 EV_WAKEUP(&k->k_events);
698 }
699
700
701 #ifdef DRACO
702 void
703 drkbdintr(void)
704 {
705 u_char in;
706 struct kbd_softc *k = &kbd_softc;
707
708 in = draco_ioct->io_kbddata;
709 draco_ioct->io_kbdrst = 0;
710
711 if (in == 0xF0)
712 k->k_rlprfx = 0x80;
713 else {
714 kbdstuffchar(in>=sizeof(drkbdtab) ? 0xff :
715 drkbdtab[in] | k->k_rlprfx);
716 k->k_rlprfx = 0;
717 }
718 }
719
720 #endif
721
722
723 #if NWSKBD>0
724 /*
725 * These are the callback functions that are passed to wscons.
726 * They really don't do anything worth noting, just call the
727 * other functions above.
728 */
729
730 int
731 kbd_enable(void *c, int on)
732 {
733 /* Wonder what this is supposed to do... */
734 return (0);
735 }
736
737 void
738 kbd_set_leds(void *c, int leds)
739 {
740 }
741
742 int
743 kbd_ioctl(void *c, u_long cmd, caddr_t data, int flag, struct proc *p)
744 {
745 switch (cmd)
746 {
747 case WSKBDIO_COMPLEXBELL:
748 return 0;
749 case WSKBDIO_SETLEDS:
750 return 0;
751 case WSKBDIO_GETLEDS:
752 *(int*)data = 0;
753 return 0;
754 case WSKBDIO_GTYPE:
755 *(u_int*)data = WSKBD_TYPE_AMIGA;
756 return 0;
757 }
758
759 /* We are supposed to return -1 to wscons if we didn't understand */
760 return (-1);
761 }
762
763 void
764 kbd_getc(void *c, u_int *type, int *data)
765 {
766 int key;
767
768 key = kbdgetcn();
769
770 *data = KEY_CODE(key);
771 *type = KEY_UP(key) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
772 }
773
774 void
775 kbd_pollc(void *c, int on)
776 {
777 kbd_softc.k_pollingmode = on;
778 }
779
780 void
781 kbd_bell(void *c, u_int x, u_int y, u_int z)
782 {
783 }
784 #endif /* WSKBD */
785