1 /* $NetBSD: hpckbd.c,v 1.27 2009/05/12 12:13:49 cegger Exp $ */
4 * Copyright (c) 1999-2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: hpckbd.c,v 1.27 2009/05/12 12:13:49 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/device.h>
44 #include <machine/config_hook.h>
45 #include <machine/platid.h>
46 #include <machine/platid_mask.h>
48 #include "opt_wsdisplay_compat.h"
49 #include "opt_pckbd_layout.h"
50 #include <dev/wscons/wsksymdef.h>
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wskbdvar.h>
53 #include <dev/wscons/wsksymvar.h>
54 #include <dev/pckbport/wskbdmap_mfii.h>
55 #ifdef WSDISPLAY_COMPAT_RAWKBD
56 #include <dev/hpc/pckbd_encode.h>
59 #include <dev/hpc/hpckbdvar.h>
60 #include <dev/hpc/hpckbdkeymap.h>
65 struct hpckbd_eventq
{
71 struct hpckbd_if hc_if
;
72 struct hpckbd_ic_if
*hc_ic
;
73 const uint8_t *hc_keymap
;
74 const int *hc_special
;
78 struct hpckbd_eventq hc_eventq
[NEVENTQ
];
79 struct hpckbd_eventq
*hc_head
, *hc_tail
;
82 struct device
*hc_wskbddev
;
83 struct hpckbd_softc
* hc_sc
; /* back link */
84 #ifdef WSDISPLAY_COMPAT_RAWKBD
91 struct hpckbd_core
*sc_core
;
92 struct hpckbd_core sc_coredata
;
95 int hpckbd_match(device_t
, cfdata_t
, void *);
96 void hpckbd_attach(device_t
, device_t
, void *);
98 void hpckbd_initcore(struct hpckbd_core
*, struct hpckbd_ic_if
*, int);
99 void hpckbd_initif(struct hpckbd_core
*);
100 int hpckbd_getevent(struct hpckbd_core
*, u_int
*, int *);
101 int hpckbd_putevent(struct hpckbd_core
*, u_int
, int);
102 void hpckbd_keymap_lookup(struct hpckbd_core
*);
103 void hpckbd_keymap_setup(struct hpckbd_core
*, const keysym_t
*, int);
104 int __hpckbd_input(void *, int, int);
105 void __hpckbd_input_hook(void *);
107 CFATTACH_DECL(hpckbd
, sizeof(struct hpckbd_softc
),
108 hpckbd_match
, hpckbd_attach
, NULL
, NULL
);
110 /* wskbd accessopts */
111 int hpckbd_enable(void *, int);
112 void hpckbd_set_leds(void *, int);
113 int hpckbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
116 struct hpckbd_core hpckbd_consdata
;
117 void hpckbd_cngetc(void *, u_int
*, int*);
118 void hpckbd_cnpollc(void *, int);
120 const struct wskbd_accessops hpckbd_accessops
= {
126 const struct wskbd_consops hpckbd_consops
= {
132 struct wskbd_mapdata hpckbd_keymapdata
= {
142 hpckbd_match(device_t parent
,
143 cfdata_t cf
, void *aux
)
149 hpckbd_attach(device_t parent
, device_t self
, void *aux
)
151 struct hpckbd_attach_args
*haa
= aux
;
152 struct hpckbd_softc
*sc
= device_private(self
);
153 struct hpckbd_ic_if
*ic
= haa
->haa_ic
;
154 struct wskbddev_attach_args wa
;
157 * Initialize core if it isn't console
159 if (hpckbd_consdata
.hc_ic
== ic
) {
160 sc
->sc_core
= &hpckbd_consdata
;
161 /* The core has been initialized in hpckbd_cnattach. */
163 sc
->sc_core
= &sc
->sc_coredata
;
164 hpckbd_initcore(sc
->sc_core
, ic
, 0 /* not console */);
167 if (sc
->sc_core
->hc_keymap
== default_keymap
)
168 printf(": no keymap.");
173 * setup hpckbd public interface for parent controller.
175 hpckbd_initif(sc
->sc_core
);
180 wa
.console
= sc
->sc_core
->hc_console
;
181 wa
.keymap
= &hpckbd_keymapdata
;
182 wa
.accessops
= &hpckbd_accessops
;
183 wa
.accesscookie
= sc
->sc_core
;
184 sc
->sc_core
->hc_wskbddev
= config_found(self
, &wa
, wskbddevprint
);
186 if (!pmf_device_register(self
, NULL
, NULL
))
187 aprint_error_dev(self
, "unable to establish power handler\n");
191 hpckbd_print(void *aux
, const char *pnp
)
193 return (pnp
? QUIET
: UNCONF
);
197 hpckbd_initcore(struct hpckbd_core
*hc
, struct hpckbd_ic_if
*ic
, int console
)
200 hc
->hc_console
= console
;
203 /* setup event queue */
204 hc
->hc_head
= hc
->hc_tail
= hc
->hc_eventq
;
207 hpckbd_keymap_lookup(hc
);
211 hpckbd_initif(struct hpckbd_core
*hc
)
213 struct hpckbd_if
*kbdif
= &hc
->hc_if
;
216 kbdif
->hi_input
= __hpckbd_input
;
217 kbdif
->hi_input_hook
= __hpckbd_input_hook
;
218 hpckbd_ic_establish(hc
->hc_ic
, &hc
->hc_if
);
222 hpckbd_putevent(struct hpckbd_core
* hc
, u_int type
, int data
)
226 if (hc
->hc_nevents
== NEVENTQ
) {
228 return (0); /* queue is full */
232 hc
->hc_tail
->hq_type
= type
;
233 hc
->hc_tail
->hq_data
= data
;
234 if (&hc
->hc_eventq
[NEVENTQ
] <= ++hc
->hc_tail
)
235 hc
->hc_tail
= hc
->hc_eventq
;
242 hpckbd_getevent(struct hpckbd_core
* hc
, u_int
*type
, int *data
)
246 if (hc
->hc_nevents
== 0) {
248 return (0); /* queue is empty */
251 *type
= hc
->hc_head
->hq_type
;
252 *data
= hc
->hc_head
->hq_data
;
254 if (&hc
->hc_eventq
[NEVENTQ
] <= ++hc
->hc_head
)
255 hc
->hc_head
= hc
->hc_eventq
;
262 hpckbd_keymap_setup(struct hpckbd_core
*hc
,
263 const keysym_t
*map
, int mapsize
)
266 struct wscons_keydesc
*desc
;
268 /* fix keydesc table */
270 * XXX The way this is done is really wrong. The __UNCONST()
271 * is a hint as to what is wrong. This actually ends up modifying
272 * initialized data which is marked "const".
273 * The reason we get away with it here is apparently that text
274 * and read-only data gets mapped read/write on the platforms
277 desc
= (struct wscons_keydesc
*)__UNCONST(hpckbd_keymapdata
.keydesc
);
278 for (i
= 0; desc
[i
].name
!= 0; i
++) {
279 if ((desc
[i
].name
& KB_MACHDEP
) && desc
[i
].map
== NULL
) {
281 desc
[i
].map_size
= mapsize
;
289 hpckbd_keymap_lookup(struct hpckbd_core
*hc
)
291 const struct hpckbd_keymap_table
*tab
;
294 for (tab
= hpckbd_keymap_table
; tab
->ht_platform
!= NULL
; tab
++) {
296 mask
= PLATID_DEREF(tab
->ht_platform
);
298 if (platid_match(&platid
, &mask
)) {
299 hc
->hc_keymap
= tab
->ht_keymap
;
300 hc
->hc_special
= tab
->ht_special
;
301 #if !defined(PCKBD_LAYOUT)
302 hpckbd_keymapdata
.layout
= tab
->ht_layout
;
304 if (tab
->ht_cmdmap
.map
) {
305 hpckbd_keymap_setup(hc
, tab
->ht_cmdmap
.map
,
306 tab
->ht_cmdmap
.size
);
307 #if !defined(PCKBD_LAYOUT)
308 hpckbd_keymapdata
.layout
|= KB_MACHDEP
;
311 hpckbd_keymapdata
.layout
&= ~KB_MACHDEP
;
317 /* no keymap. use default. */
318 hc
->hc_keymap
= default_keymap
;
319 hc
->hc_special
= default_special_keymap
;
320 #if !defined(PCKBD_LAYOUT)
321 hpckbd_keymapdata
.layout
= KB_US
;
326 __hpckbd_input_hook(void *arg
)
329 struct hpckbd_core
*hc
= arg
;
331 if (hc
->hc_polling
) {
332 hc
->hc_type
= WSCONS_EVENT_ALL_KEYS_UP
;
338 __hpckbd_input(void *arg
, int flag
, int scancode
)
340 struct hpckbd_core
*hc
= arg
;
344 type
= WSCONS_EVENT_KEY_DOWN
;
346 type
= WSCONS_EVENT_KEY_UP
;
349 key
= hc
->hc_keymap
[scancode
];
352 printf("hpckbd: unknown scan code %#x (%d, %d)\n",
353 scancode
, scancode
>> 3,
354 scancode
- ((scancode
>> 3) << 3));
367 if (scancode
== hc
->hc_special
[KEY_SPECIAL_OFF
]) {
368 config_hook_call(CONFIG_HOOK_BUTTONEVENT
,
369 CONFIG_HOOK_BUTTONEVENT_POWER
, (void *)1 /* on */);
370 } else if (scancode
== hc
->hc_special
[KEY_SPECIAL_LIGHT
]) {
371 static int onoff
; /* XXX -uch */
372 config_hook_call(CONFIG_HOOK_BUTTONEVENT
,
373 CONFIG_HOOK_BUTTONEVENT_LIGHT
,
374 (void *)(onoff
^= 1));
377 printf("unknown special key %d\n", scancode
);
384 if (hc
->hc_polling
) {
385 if (hpckbd_putevent(hc
, type
, key
) == 0)
386 printf("hpckbd: queue over flow\n");
388 #ifdef WSDISPLAY_COMPAT_RAWKBD
392 n
= pckbd_encode(type
, key
, data
);
393 wskbd_rawinput(hc
->hc_wskbddev
, data
, n
);
396 wskbd_input(hc
->hc_wskbddev
, type
, key
);
403 * console support routines
406 hpckbd_cnattach(struct hpckbd_ic_if
*ic
)
408 struct hpckbd_core
*hc
= &hpckbd_consdata
;
410 hpckbd_initcore(hc
, ic
, 1 /* console */);
412 /* attach controller */
416 wskbd_cnattach(&hpckbd_consops
, hc
, &hpckbd_keymapdata
);
422 hpckbd_cngetc(void *arg
, u_int
*type
, int *data
)
424 struct hpckbd_core
*hc
= arg
;
426 if (!hc
->hc_console
|| !hc
->hc_polling
|| !hc
->hc_ic
)
429 while (hpckbd_getevent(hc
, type
, data
) == 0) /* busy loop */
430 hpckbd_ic_poll(hc
->hc_ic
);
434 hpckbd_cnpollc(void *arg
, int on
)
436 struct hpckbd_core
*hc
= arg
;
442 hpckbd_enable(void *arg
, int on
)
444 struct hpckbd_core
*hc
= arg
;
460 hpckbd_set_leds(void *arg
, int leds
)
462 /* Can you find any LED which tells you about keyboard? */
466 hpckbd_ioctl(void *arg
, u_long cmd
, void *data
, int flag
,
469 #ifdef WSDISPLAY_COMPAT_RAWKBD
470 struct hpckbd_core
*hc
= arg
;
474 *(int *)data
= WSKBD_TYPE_HPC_KBD
;
476 case WSKBDIO_SETLEDS
:
478 case WSKBDIO_GETLEDS
:
479 *(int *)data
= 0; /* dummy for wsconsctl(8) */
481 #ifdef WSDISPLAY_COMPAT_RAWKBD
482 case WSKBDIO_SETMODE
:
483 hc
->hc_rawkbd
= (*(int *)data
== WSKBD_RAW
);
487 return (EPASSTHROUGH
);