xref: /netbsd-src/sys/dev/sun/kbd.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /*	$NetBSD: kbd.c,v 1.56 2006/06/07 22:33:38 kardel Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This software was developed by the Computer Systems Engineering group
8  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
9  * contributed to Berkeley.
10  *
11  * All advertising materials mentioning features or use of this software
12  * must display the following acknowledgement:
13  *	This product includes software developed by the University of
14  *	California, Lawrence Berkeley Laboratory.
15  *
16  * Redistribution and use in source and binary forms, with or without
17  * modification, are permitted provided that the following conditions
18  * are met:
19  * 1. Redistributions of source code must retain the above copyright
20  *    notice, this list of conditions and the following disclaimer.
21  * 2. Redistributions in binary form must reproduce the above copyright
22  *    notice, this list of conditions and the following disclaimer in the
23  *    documentation and/or other materials provided with the distribution.
24  * 3. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)kbd.c	8.2 (Berkeley) 10/30/93
41  */
42 
43 /*
44  * Keyboard driver (/dev/kbd -- note that we do not have minor numbers
45  * [yet?]).  Translates incoming bytes to ASCII or to `firm_events' and
46  * passes them up to the appropriate reader.
47  */
48 
49 #include <sys/cdefs.h>
50 __KERNEL_RCSID(0, "$NetBSD: kbd.c,v 1.56 2006/06/07 22:33:38 kardel Exp $");
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/conf.h>
55 #include <sys/device.h>
56 #include <sys/ioctl.h>
57 #include <sys/kernel.h>
58 #include <sys/proc.h>
59 #include <sys/malloc.h>
60 #include <sys/signal.h>
61 #include <sys/signalvar.h>
62 #include <sys/time.h>
63 #include <sys/syslog.h>
64 #include <sys/select.h>
65 #include <sys/poll.h>
66 #include <sys/file.h>
67 
68 #include <dev/wscons/wsksymdef.h>
69 
70 #include <dev/sun/kbd_reg.h>
71 #include <dev/sun/kbio.h>
72 #include <dev/sun/vuid_event.h>
73 #include <dev/sun/event_var.h>
74 #include <dev/sun/kbd_xlate.h>
75 #include <dev/sun/kbdvar.h>
76 
77 #include "locators.h"
78 
79 extern struct cfdriver kbd_cd;
80 
81 dev_type_open(kbdopen);
82 dev_type_close(kbdclose);
83 dev_type_read(kbdread);
84 dev_type_ioctl(kbdioctl);
85 dev_type_poll(kbdpoll);
86 dev_type_kqfilter(kbdkqfilter);
87 
88 const struct cdevsw kbd_cdevsw = {
89 	kbdopen, kbdclose, kbdread, nowrite, kbdioctl,
90 	nostop, notty, kbdpoll, nommap, kbdkqfilter
91 };
92 
93 #if NWSKBD > 0
94 static int	wssunkbd_enable(void *, int);
95 static void	wssunkbd_set_leds(void *, int);
96 static int	wssunkbd_ioctl(void *, u_long, caddr_t, int, struct lwp *);
97 static void	sunkbd_wskbd_cngetc(void *, u_int *, int *);
98 static void	sunkbd_wskbd_cnpollc(void *, int);
99 static void	sunkbd_wskbd_cnbell(void *, u_int, u_int, u_int);
100 static void	sunkbd_bell_off(void *v);
101 static void	kbd_enable(struct device *); /* deferred keyboard init */
102 
103 const struct wskbd_accessops sunkbd_wskbd_accessops = {
104 	wssunkbd_enable,
105 	wssunkbd_set_leds,
106 	wssunkbd_ioctl,
107 };
108 
109 extern const struct wscons_keydesc wssun_keydesctab[];
110 const struct wskbd_mapdata sunkbd_wskbd_keymapdata = {
111 	wssun_keydesctab,
112 #ifdef SUNKBD_LAYOUT
113 	SUNKBD_LAYOUT,
114 #else
115 	KB_US,
116 #endif
117 };
118 
119 const struct wskbd_consops sunkbd_wskbd_consops = {
120         sunkbd_wskbd_cngetc,
121         sunkbd_wskbd_cnpollc,
122         sunkbd_wskbd_cnbell,
123 };
124 
125 void kbd_wskbd_attach(struct kbd_softc *, int);
126 #endif
127 
128 /* ioctl helpers */
129 static int kbd_iockeymap(struct kbd_state *, u_long, struct kiockeymap *);
130 #ifdef KIOCGETKEY
131 static int kbd_oldkeymap(struct kbd_state *, u_long, struct okiockey *);
132 #endif
133 
134 
135 /* callbacks for console driver */
136 static int kbd_cc_open(struct cons_channel *);
137 static int kbd_cc_close(struct cons_channel *);
138 
139 /* console input */
140 static void	kbd_input_console(struct kbd_softc *, int);
141 static void	kbd_repeat(void *);
142 static int	kbd_input_keysym(struct kbd_softc *, int);
143 static void	kbd_input_string(struct kbd_softc *, char *);
144 static void	kbd_input_funckey(struct kbd_softc *, int);
145 static void	kbd_update_leds(struct kbd_softc *);
146 
147 #if NWSKBD > 0
148 static void	kbd_input_wskbd(struct kbd_softc *, int);
149 #endif
150 
151 /* firm events input */
152 static void	kbd_input_event(struct kbd_softc *, int);
153 
154 
155 
156 /****************************************************************
157  *  Entry points for /dev/kbd
158  *  (open,close,read,write,...)
159  ****************************************************************/
160 
161 /*
162  * Open:
163  * Check exclusion, open actual device (_iopen),
164  * setup event channel, clear ASCII repeat stuff.
165  */
166 int
167 kbdopen(dev_t dev, int flags, int mode, struct lwp *l)
168 {
169 	struct kbd_softc *k;
170 	int error, unit;
171 
172 	/* locate device */
173 	unit = minor(dev);
174 	if (unit >= kbd_cd.cd_ndevs)
175 		return (ENXIO);
176 	k = kbd_cd.cd_devs[unit];
177 	if (k == NULL)
178 		return (ENXIO);
179 
180 #if NWSKBD > 0
181 	/*
182 	 * NB: wscons support: while we can track if wskbd has called
183 	 * enable(), we can't tell if that's for console input or for
184 	 * events input, so we should probably just let the open to
185 	 * always succeed regardless (e.g. Xsun opening /dev/kbd).
186 	 */
187 	if (!k->k_wsenabled)
188 		wssunkbd_enable(k, 1);
189 #endif
190 
191 	/* exclusive open required for /dev/kbd */
192 	if (k->k_events.ev_io)
193 		return (EBUSY);
194 	k->k_events.ev_io = l->l_proc;
195 
196 	/* stop pending autorepeat of console input */
197 	if (k->k_repeating) {
198 		k->k_repeating = 0;
199 		callout_stop(&k->k_repeat_ch);
200 	}
201 
202 	/* open actual underlying device */
203 	if (k->k_ops != NULL && k->k_ops->open != NULL)
204 		if ((error = (*k->k_ops->open)(k)) != 0) {
205 			k->k_events.ev_io = NULL;
206 			return (error);
207 		}
208 
209 	ev_init(&k->k_events);
210 	k->k_evmode = 0;	/* XXX: OK? */
211 
212 	return (0);
213 }
214 
215 
216 /*
217  * Close:
218  * Turn off event mode, dump the queue, and close the keyboard
219  * unless it is supplying console input.
220  */
221 int
222 kbdclose(dev_t dev, int flags, int mode, struct lwp *l)
223 {
224 	struct kbd_softc *k;
225 
226 	k = kbd_cd.cd_devs[minor(dev)];
227 	k->k_evmode = 0;
228 	ev_fini(&k->k_events);
229 	k->k_events.ev_io = NULL;
230 
231 	if (k->k_ops != NULL && k->k_ops->close != NULL) {
232 		int error;
233 		if ((error = (*k->k_ops->close)(k)) != 0)
234 			return (error);
235 	}
236 	return (0);
237 }
238 
239 
240 int
241 kbdread(dev_t dev, struct uio *uio, int flags)
242 {
243 	struct kbd_softc *k;
244 
245 	k = kbd_cd.cd_devs[minor(dev)];
246 	return (ev_read(&k->k_events, uio, flags));
247 }
248 
249 
250 int
251 kbdpoll(dev_t dev, int events, struct lwp *l)
252 {
253 	struct kbd_softc *k;
254 
255 	k = kbd_cd.cd_devs[minor(dev)];
256 	return (ev_poll(&k->k_events, events, l));
257 }
258 
259 int
260 kbdkqfilter(dev_t dev, struct knote *kn)
261 {
262 	struct kbd_softc *k;
263 
264 	k = kbd_cd.cd_devs[minor(dev)];
265 	return (ev_kqfilter(&k->k_events, kn));
266 }
267 
268 int
269 kbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct lwp *l)
270 {
271 	struct kbd_softc *k;
272 	struct kbd_state *ks;
273 	int error = 0;
274 
275 	k = kbd_cd.cd_devs[minor(dev)];
276 	ks = &k->k_state;
277 
278 	switch (cmd) {
279 
280 	case KIOCTRANS: 	/* Set translation mode */
281 		/* We only support "raw" mode on /dev/kbd */
282 		if (*(int *)data != TR_UNTRANS_EVENT)
283 			error = EINVAL;
284 		break;
285 
286 	case KIOCGTRANS:	/* Get translation mode */
287 		/* We only support "raw" mode on /dev/kbd */
288 		*(int *)data = TR_UNTRANS_EVENT;
289 		break;
290 
291 #ifdef KIOCGETKEY
292 	case KIOCGETKEY:	/* Get keymap entry (old format) */
293 		error = kbd_oldkeymap(ks, cmd, (struct okiockey *)data);
294 		break;
295 #endif /* KIOCGETKEY */
296 
297 	case KIOCSKEY:  	/* Set keymap entry */
298 		/* FALLTHROUGH */
299 	case KIOCGKEY:  	/* Get keymap entry */
300 		error = kbd_iockeymap(ks, cmd, (struct kiockeymap *)data);
301 		break;
302 
303 	case KIOCCMD:		/* Send a command to the keyboard */
304 		/* pass it to the middle layer */
305 		if (k->k_ops != NULL && k->k_ops->docmd != NULL)
306 			error = (*k->k_ops->docmd)(k, *(int *)data, 1);
307 		break;
308 
309 	case KIOCTYPE:		/* Get keyboard type */
310 		*(int *)data = ks->kbd_id;
311 		break;
312 
313 	case KIOCSDIRECT:	/* Where to send input */
314 		k->k_evmode = *(int *)data;
315 		break;
316 
317 	case KIOCLAYOUT:	/* Get keyboard layout */
318 		*(int *)data = ks->kbd_layout;
319 		break;
320 
321 	case KIOCSLED:		/* Set keyboard LEDs */
322 		/* pass the request to the middle layer */
323 		if (k->k_ops != NULL && k->k_ops->setleds != NULL)
324 			error = (*k->k_ops->setleds)(k, *(char *)data, 1);
325 		break;
326 
327 	case KIOCGLED:		/* Get keyboard LEDs */
328 		*(char *)data = ks->kbd_leds;
329 		break;
330 
331 	case FIONBIO:		/* we will remove this someday (soon???) */
332 		break;
333 
334 	case FIOASYNC:
335 		k->k_events.ev_async = (*(int *)data != 0);
336 		break;
337 
338 	case FIOSETOWN:
339 		if (-*(int *)data != k->k_events.ev_io->p_pgid
340 		    && *(int *)data != k->k_events.ev_io->p_pid)
341 			error = EPERM;
342 		break;
343 
344 	case TIOCSPGRP:
345 		if (*(int *)data != k->k_events.ev_io->p_pgid)
346 			error = EPERM;
347 		break;
348 
349 	default:
350 		error = ENOTTY;
351 		break;
352 	}
353 
354 	return (error);
355 }
356 
357 
358 /****************************************************************
359  * ioctl helpers
360  ****************************************************************/
361 
362 /*
363  * Get/Set keymap entry
364  */
365 static int
366 kbd_iockeymap(struct kbd_state *ks, u_long cmd, struct kiockeymap *kio)
367 {
368 	u_short *km;
369 	u_int station;
370 
371 	switch (kio->kio_tablemask) {
372 	case KIOC_NOMASK:
373 		km = ks->kbd_k.k_normal;
374 		break;
375 	case KIOC_SHIFTMASK:
376 		km = ks->kbd_k.k_shifted;
377 		break;
378 	case KIOC_CTRLMASK:
379 		km = ks->kbd_k.k_control;
380 		break;
381 	case KIOC_UPMASK:
382 		km = ks->kbd_k.k_release;
383 		break;
384 	default:
385 		/* Silently ignore unsupported masks */
386 		return (0);
387 	}
388 
389 	/* Range-check the table position. */
390 	station = kio->kio_station;
391 	if (station >= KEYMAP_SIZE)
392 		return (EINVAL);
393 
394 	switch (cmd) {
395 
396 	case KIOCGKEY:	/* Get keymap entry */
397 		kio->kio_entry = km[station];
398 		break;
399 
400 	case KIOCSKEY:	/* Set keymap entry */
401 		km[station] = kio->kio_entry;
402 		break;
403 
404 	default:
405 		return(ENOTTY);
406 	}
407 	return (0);
408 }
409 
410 
411 #ifdef KIOCGETKEY
412 /*
413  * Get/Set keymap entry,
414  * old format (compatibility)
415  */
416 int
417 kbd_oldkeymap(struct kbd_state *ks, u_long cmd, struct okiockey *kio)
418 {
419 	int error = 0;
420 
421 	switch (cmd) {
422 
423 	case KIOCGETKEY:
424 		if (kio->kio_station == 118) {
425 			/*
426 			 * This is X11 asking if a type 3 keyboard is
427 			 * really a type 3 keyboard.  Say yes, it is,
428 			 * by reporting key station 118 as a "hole".
429 			 * Note old (SunOS 3.5) definition of HOLE!
430 			 */
431 			kio->kio_entry = 0xA2;
432 			break;
433 		}
434 		/* fall through */
435 
436 	default:
437 		error = ENOTTY;
438 		break;
439 	}
440 
441 	return (error);
442 }
443 #endif /* KIOCGETKEY */
444 
445 
446 
447 /****************************************************************
448  *  Keyboard input - called by middle layer at spltty().
449  ****************************************************************/
450 
451 void
452 kbd_input(struct kbd_softc *k, int code)
453 {
454 	if (k->k_evmode) {
455 		/*
456 		 * XXX: is this still true?
457 		 * IDLEs confuse the MIT X11R4 server badly, so we must drop them.
458 		 * This is bad as it means the server will not automatically resync
459 		 * on all-up IDLEs, but I did not drop them before, and the server
460 		 * goes crazy when it comes time to blank the screen....
461 		 */
462 		if (code == KBD_IDLE)
463 			return;
464 
465 		/*
466 		 * Keyboard is generating firm events.  Turn this keystroke
467 		 * into an event and put it in the queue.
468 		 */
469 		kbd_input_event(k, code);
470 		return;
471 	}
472 
473 #if NWSKBD > 0
474 	if (k->k_wskbd != NULL && k->k_wsenabled) {
475 		/*
476 		 * We are using wskbd input mode, pass the event up.
477 		 */
478 		if (code == KBD_IDLE)
479 			return;	/* this key is not in the mapped */
480 		kbd_input_wskbd(k, code);
481 		return;
482 	}
483 #endif
484 
485 	/*
486 	 * If /dev/kbd is not connected in event mode, or wskbd mode,
487 	 * translate and send upstream (to console).
488 	 */
489 	kbd_input_console(k, code);
490 }
491 
492 
493 
494 /****************************************************************
495  *  Open/close routines called upon opening /dev/console
496  *  if we serve console input.
497  ****************************************************************/
498 
499 struct cons_channel *
500 kbd_cc_alloc(struct kbd_softc *k)
501 {
502 	struct cons_channel *cc;
503 
504 	if ((cc = malloc(sizeof *cc, M_DEVBUF, M_NOWAIT)) == NULL)
505 		return (NULL);
506 
507 	/* our callbacks for the console driver */
508 	cc->cc_dev = k;
509 	cc->cc_iopen = kbd_cc_open;
510 	cc->cc_iclose = kbd_cc_close;
511 
512 	/* will be provided by the console driver so that we can feed input */
513 	cc->cc_upstream = NULL;
514 
515 	/*
516 	 * TODO: clean up cons_attach_input() vs kd_attach_input() in
517 	 * lower layers and move that code here.
518 	 */
519 
520 	k->k_cc = cc;
521 	return (cc);
522 }
523 
524 
525 static int
526 kbd_cc_open(struct cons_channel *cc)
527 {
528 	struct kbd_softc *k;
529 	int ret;
530 
531 	if (cc == NULL)
532 		return (0);
533 
534 	k = (struct kbd_softc *)cc->cc_dev;
535 	if (k == NULL)
536 		return (0);
537 
538 	if (k->k_ops != NULL && k->k_ops->open != NULL)
539 		ret = (*k->k_ops->open)(k);
540 	else
541 		ret = 0;
542 
543 	/* XXX: verify that callout is not active? */
544 	k->k_repeat_start = hz/2;
545 	k->k_repeat_step = hz/20;
546 	callout_init(&k->k_repeat_ch);
547 
548 	return (ret);
549 }
550 
551 
552 static int
553 kbd_cc_close(struct cons_channel *cc)
554 {
555 	struct kbd_softc *k;
556 	int ret;
557 
558 	if (cc == NULL)
559 		return (0);
560 
561 	k = (struct kbd_softc *)cc->cc_dev;
562 	if (k == NULL)
563 		return (0);
564 
565 	if (k->k_ops != NULL && k->k_ops->close != NULL)
566 		ret = (*k->k_ops->close)(k);
567 	else
568 		ret = 0;
569 
570 	/* stop any pending auto-repeat */
571 	if (k->k_repeating) {
572 		k->k_repeating = 0;
573 		callout_stop(&k->k_repeat_ch);
574 	}
575 
576 	return (ret);
577 }
578 
579 
580 
581 /****************************************************************
582  *  Console input - called by middle layer at spltty().
583  ****************************************************************/
584 
585 static void
586 kbd_input_console(struct kbd_softc *k, int code)
587 {
588 	struct kbd_state *ks= &k->k_state;
589 	int keysym;
590 
591 	/* any input stops auto-repeat (i.e. key release) */
592 	if (k->k_repeating) {
593 		k->k_repeating = 0;
594 		callout_stop(&k->k_repeat_ch);
595 	}
596 
597 	keysym = kbd_code_to_keysym(ks, code);
598 
599 	/* pass to console */
600 	if (kbd_input_keysym(k, keysym)) {
601 		log(LOG_WARNING, "%s: code=0x%x with mod=0x%x"
602 		    " produced unexpected keysym 0x%x\n",
603 		    k->k_dev.dv_xname,
604 		    code, ks->kbd_modbits, keysym);
605 		return;		/* no point in auto-repeat here */
606 	}
607 
608 	if (KEYSYM_NOREPEAT(keysym))
609 		return;
610 
611 	/* setup for auto-repeat after initial delay */
612 	k->k_repeating = 1;
613 	k->k_repeatsym = keysym;
614 	callout_reset(&k->k_repeat_ch, k->k_repeat_start,
615 		      kbd_repeat, k);
616 }
617 
618 
619 /*
620  * This is the autorepeat callout function scheduled by kbd_input() above.
621  * Called at splsoftclock().
622  */
623 static void
624 kbd_repeat(void *arg)
625 {
626 	struct kbd_softc *k = (struct kbd_softc *)arg;
627 	int s;
628 
629 	s = spltty();
630 	if (k->k_repeating && k->k_repeatsym >= 0) {
631 		/* feed typematic keysym to the console */
632 		(void)kbd_input_keysym(k, k->k_repeatsym);
633 
634 		/* reschedule next repeat */
635 		callout_reset(&k->k_repeat_ch, k->k_repeat_step,
636 			      kbd_repeat, k);
637 	}
638 	splx(s);
639 }
640 
641 
642 
643 /*
644  * Supply keysym as console input.  Convert keysym to character(s) and
645  * pass them up to cons_channel's upstream hook.
646  *
647  * Return zero on success, else the keysym that we could not handle
648  * (so that the caller may complain).
649  */
650 static int
651 kbd_input_keysym(struct kbd_softc *k, int keysym)
652 {
653 	struct kbd_state *ks = &k->k_state;
654 	int data;
655 	/* Check if a recipient has been configured */
656 	if (k->k_cc == NULL || k->k_cc->cc_upstream == NULL)
657 		return (0);
658 
659 	switch (KEYSYM_CLASS(keysym)) {
660 
661 	case KEYSYM_ASCII:
662 		data = KEYSYM_DATA(keysym);
663 		if (ks->kbd_modbits & KBMOD_META_MASK)
664 			data |= 0x80;
665 		(*k->k_cc->cc_upstream)(data);
666 		break;
667 
668 	case KEYSYM_STRING:
669 		data = keysym & 0xF;
670 		kbd_input_string(k, kbd_stringtab[data]);
671 		break;
672 
673 	case KEYSYM_FUNC:
674 		kbd_input_funckey(k, keysym);
675 		break;
676 
677 	case KEYSYM_CLRMOD:
678 		data = 1 << (keysym & 0x1F);
679 		ks->kbd_modbits &= ~data;
680 		break;
681 
682 	case KEYSYM_SETMOD:
683 		data = 1 << (keysym & 0x1F);
684 		ks->kbd_modbits |= data;
685 		break;
686 
687 	case KEYSYM_INVMOD:
688 		data = 1 << (keysym & 0x1F);
689 		ks->kbd_modbits ^= data;
690 		kbd_update_leds(k);
691 		break;
692 
693 	case KEYSYM_ALL_UP:
694 		ks->kbd_modbits &= ~0xFFFF;
695 		break;
696 
697 	case KEYSYM_SPECIAL:
698 		if (keysym == KEYSYM_NOP)
699 			break;
700 		/* FALLTHROUGH */
701 	default:
702 		/* We could not handle it. */
703 		return (keysym);
704 	}
705 
706 	return (0);
707 }
708 
709 
710 /*
711  * Send string upstream.
712  */
713 static void
714 kbd_input_string(struct kbd_softc *k, char *str)
715 {
716 
717 	while (*str) {
718 		(*k->k_cc->cc_upstream)(*str);
719 		++str;
720 	}
721 }
722 
723 
724 /*
725  * Format the F-key sequence and send as a string.
726  * XXX: Ugly compatibility mappings.
727  */
728 static void
729 kbd_input_funckey(struct kbd_softc *k, int keysym)
730 {
731 	int n;
732 	char str[12];
733 
734 	n = 0xC0 + (keysym & 0x3F);
735 	snprintf(str, sizeof(str), "\033[%dz", n);
736 	kbd_input_string(k, str);
737 }
738 
739 
740 /*
741  * Update LEDs to reflect console input state.
742  */
743 static void
744 kbd_update_leds(struct kbd_softc *k)
745 {
746 	struct kbd_state *ks = &k->k_state;
747 	char leds;
748 
749 	leds = ks->kbd_leds;
750 	leds &= ~(LED_CAPS_LOCK|LED_NUM_LOCK);
751 
752 	if (ks->kbd_modbits & (1 << KBMOD_CAPSLOCK))
753 		leds |= LED_CAPS_LOCK;
754 	if (ks->kbd_modbits & (1 << KBMOD_NUMLOCK))
755 		leds |= LED_NUM_LOCK;
756 
757 	if (k->k_ops != NULL && k->k_ops->setleds != NULL)
758 		(void)(*k->k_ops->setleds)(k, leds, 0);
759 }
760 
761 
762 
763 /****************************************************************
764  *  Events input - called by middle layer at spltty().
765  ****************************************************************/
766 
767 /*
768  * Supply raw keystrokes when keyboard is open in firm event mode.
769  *
770  * Turn the keystroke into an event and put it in the queue.
771  * If the queue is full, the keystroke is lost (sorry!).
772  */
773 static void
774 kbd_input_event(struct kbd_softc *k, int code)
775 {
776 	struct firm_event *fe;
777 	int put;
778 
779 #ifdef DIAGNOSTIC
780 	if (!k->k_evmode) {
781 		printf("%s: kbd_input_event called when not in event mode\n",
782 		       k->k_dev.dv_xname);
783 		return;
784 	}
785 #endif
786 	put = k->k_events.ev_put;
787 	fe = &k->k_events.ev_q[put];
788 	put = (put + 1) % EV_QSIZE;
789 	if (put == k->k_events.ev_get) {
790 		log(LOG_WARNING, "%s: event queue overflow\n",
791 		    k->k_dev.dv_xname);
792 		return;
793 	}
794 
795 	fe->id = KEY_CODE(code);
796 	fe->value = KEY_UP(code) ? VKEY_UP : VKEY_DOWN;
797 	getmicrotime(&fe->time);
798 	k->k_events.ev_put = put;
799 	EV_WAKEUP(&k->k_events);
800 }
801 
802 
803 
804 /****************************************************************
805  *  Translation stuff declared in kbd_xlate.h
806  ****************************************************************/
807 
808 /*
809  * Initialization - called by either lower layer attach or by kdcninit.
810  */
811 void
812 kbd_xlate_init(struct kbd_state *ks)
813 {
814 	struct keyboard *ktbls;
815 	int id;
816 
817 	id = ks->kbd_id;
818 	if (id < KBD_MIN_TYPE)
819 		id = KBD_MIN_TYPE;
820 	if (id > kbd_max_type)
821 		id = kbd_max_type;
822 	ktbls = keyboards[id];
823 
824 	ks->kbd_k = *ktbls; 	/* struct assignment */
825 	ks->kbd_modbits = 0;
826 }
827 
828 /*
829  * Turn keyboard up/down codes into a KEYSYM.
830  * Note that the "kd" driver (on sun3 and sparc64) uses this too!
831  */
832 int
833 kbd_code_to_keysym(struct kbd_state *ks, int c)
834 {
835 	u_short *km;
836 	int keysym;
837 
838 	/*
839 	 * Get keymap pointer.  One of these:
840 	 * release, control, shifted, normal, ...
841 	 */
842 	if (KEY_UP(c))
843 		km = ks->kbd_k.k_release;
844 	else if (ks->kbd_modbits & KBMOD_CTRL_MASK)
845 		km = ks->kbd_k.k_control;
846 	else if (ks->kbd_modbits & KBMOD_SHIFT_MASK)
847 		km = ks->kbd_k.k_shifted;
848 	else
849 		km = ks->kbd_k.k_normal;
850 
851 	if (km == NULL) {
852 		/*
853 		 * Do not know how to translate yet.
854 		 * We will find out when a RESET comes along.
855 		 */
856 		return (KEYSYM_NOP);
857 	}
858 	keysym = km[KEY_CODE(c)];
859 
860 	/*
861 	 * Post-processing for Caps-lock
862 	 */
863 	if ((ks->kbd_modbits & (1 << KBMOD_CAPSLOCK)) &&
864 		(KEYSYM_CLASS(keysym) == KEYSYM_ASCII) )
865 	{
866 		if (('a' <= keysym) && (keysym <= 'z'))
867 			keysym -= ('a' - 'A');
868 	}
869 
870 	/*
871 	 * Post-processing for Num-lock.  All "function"
872 	 * keysyms get indirected through another table.
873 	 * (XXX: Only if numlock on.  Want off also!)
874 	 */
875 	if ((ks->kbd_modbits & (1 << KBMOD_NUMLOCK)) &&
876 		(KEYSYM_CLASS(keysym) == KEYSYM_FUNC) )
877 	{
878 		keysym = kbd_numlock_map[keysym & 0x3F];
879 	}
880 
881 	return (keysym);
882 }
883 
884 
885 /*
886  * Back door for rcons (fb.c)
887  */
888 void
889 kbd_bell(int on)
890 {
891 	struct kbd_softc *k = kbd_cd.cd_devs[0]; /* XXX: hardcoded minor */
892 
893 	if (k == NULL || k->k_ops == NULL || k->k_ops->docmd == NULL)
894 		return;
895 
896 	(void)(*k->k_ops->docmd)(k, on ? KBD_CMD_BELL : KBD_CMD_NOBELL, 0);
897 }
898 
899 #if NWSKBD > 0
900 static void
901 kbd_input_wskbd(struct kbd_softc *k, int code)
902 {
903 	int type, key;
904 
905 #ifdef WSDISPLAY_COMPAT_RAWKBD
906 	if (k->k_wsraw) {
907 		u_char buf;
908 
909 		buf = code;
910 		wskbd_rawinput(k->k_wskbd, &buf, 1);
911 		return;
912 	}
913 #endif
914 
915 	type = KEY_UP(code) ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
916 	key = KEY_CODE(code);
917 	wskbd_input(k->k_wskbd, type, key);
918 }
919 
920 int
921 wssunkbd_enable(void *v, int on)
922 {
923 	struct kbd_softc *k = v;
924 	if (k->k_wsenabled != on) {
925 		k->k_wsenabled = on;
926 		if (on) {
927 			/* open actual underlying device */
928 			if (k->k_ops != NULL && k->k_ops->open != NULL)
929 				(*k->k_ops->open)(k);
930 			ev_init(&k->k_events);
931 			k->k_evmode = 0;	/* XXX: OK? */
932 		} else {
933 			/* close underlying device */
934 			if (k->k_ops != NULL && k->k_ops->close != NULL)
935 				(*k->k_ops->close)(k);
936 		}
937 	}
938 	return 0;
939 }
940 
941 void
942 wssunkbd_set_leds(void *v, int leds)
943 {
944 	struct kbd_softc *k = v;
945 	int l = 0;
946 
947 	if (leds & WSKBD_LED_CAPS)
948 		l |= LED_CAPS_LOCK;
949 	if (leds & WSKBD_LED_NUM)
950 		l |= LED_NUM_LOCK;
951 	if (leds & WSKBD_LED_SCROLL)
952 		l |= LED_SCROLL_LOCK;
953 	if (leds & WSKBD_LED_COMPOSE)
954 		l |= LED_COMPOSE;
955 	if (k->k_ops != NULL && k->k_ops->setleds != NULL)
956 		(*k->k_ops->setleds)(k, l, 0);
957 	k->k_leds=l;
958 }
959 
960 static int
961 wssunkbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct lwp *l)
962 {
963 	struct kbd_softc *k = v;
964 
965 	switch (cmd) {
966 		case WSKBDIO_GTYPE:
967 			/* we can't tell  4 from  5 or 6 */
968 			*(int *)data = k->k_state.kbd_id < KB_SUN4 ?
969 			    WSKBD_TYPE_SUN : WSKBD_TYPE_SUN5;
970 			return (0);
971 		case WSKBDIO_SETLEDS:
972 			wssunkbd_set_leds(v, *(int *)data);
973 			return (0);
974 		case WSKBDIO_GETLEDS:
975 			*(int *)data = k->k_leds;
976 			return (0);
977 #ifdef WSDISPLAY_COMPAT_RAWKBD
978 		case WSKBDIO_SETMODE:
979 			k->k_wsraw = *(int *)data == WSKBD_RAW;
980 			return (0);
981 #endif
982 	}
983 	return EPASSTHROUGH;
984 }
985 
986 extern int	prom_cngetc(dev_t);
987 
988 static void
989 sunkbd_wskbd_cngetc(void *v, u_int *type, int *data)
990 {
991 	/* struct kbd_sun_softc *k = v; */
992 	*data = prom_cngetc(0);
993 	*type = WSCONS_EVENT_ASCII;
994 }
995 
996 void
997 sunkbd_wskbd_cnpollc(void *v, int on)
998 {
999 }
1000 
1001 static void
1002 sunkbd_bell_off(void *v)
1003 {
1004 	struct kbd_softc *k = v;
1005 	k->k_ops->docmd(k, KBD_CMD_NOBELL, 0);
1006 }
1007 
1008 void
1009 sunkbd_wskbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
1010 {
1011 	struct kbd_softc *k = v;
1012 
1013 	callout_reset(&k->k_wsbell, period*1000/hz, sunkbd_bell_off, v);
1014 	k->k_ops->docmd(k, KBD_CMD_BELL, 0);
1015 }
1016 
1017 void
1018 kbd_enable(struct device *dev)
1019 {
1020 	struct kbd_softc *k = (struct kbd_softc *)(void *)dev;
1021 	struct wskbddev_attach_args a;
1022 
1023 	if (k->k_isconsole)
1024 		wskbd_cnattach(&sunkbd_wskbd_consops, k,
1025 		    &sunkbd_wskbd_keymapdata);
1026 
1027 	a.console = k->k_isconsole;
1028 	a.keymap = &sunkbd_wskbd_keymapdata;
1029 	a.accessops = &sunkbd_wskbd_accessops;
1030 	a.accesscookie = k;
1031 
1032 	/* XXX why? */
1033 	k->k_wsenabled = 0;
1034 
1035 	/* Attach the wskbd */
1036 	k->k_wskbd = config_found(&k->k_dev, &a, wskbddevprint);
1037 
1038 	callout_init(&k->k_wsbell);
1039 
1040 	wssunkbd_enable(k,1);
1041 
1042 	wssunkbd_set_leds(k, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
1043 	delay(100000);
1044 	wssunkbd_set_leds(k, 0);
1045 }
1046 
1047 void
1048 kbd_wskbd_attach(struct kbd_softc *k, int isconsole)
1049 {
1050 	k->k_isconsole = isconsole;
1051 
1052 	config_interrupts(&k->k_dev, kbd_enable);
1053 }
1054 #endif
1055