1 /* $NetBSD: nextkbd.c,v 1.12 2007/03/04 06:00:27 christos Exp $ */
3 * Copyright (c) 1998 Matt DeBergalis
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Matt DeBergalis
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: nextkbd.c,v 1.12 2007/03/04 06:00:27 christos Exp $");
35 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
41 #include <sys/device.h>
42 #include <sys/malloc.h>
43 #include <sys/errno.h>
44 #include <sys/queue.h>
49 #include <machine/autoconf.h>
51 #include <dev/wscons/wsconsio.h>
52 #include <dev/wscons/wskbdvar.h>
53 #include <dev/wscons/wsksymdef.h>
54 #include <dev/wscons/wsksymvar.h>
56 #include <next68k/dev/nextkbdvar.h>
57 #include <next68k/dev/wskbdmap_next.h>
59 #include <next68k/next68k/isr.h>
61 #include <next68k/dev/intiovar.h>
63 struct nextkbd_internal
{
64 int num_ints
; /* interrupt total */
69 bus_space_handle_t ioh
;
70 struct nextkbd_softc
*t_sc
; /* back pointer */
80 static int attached
= 0;
82 int nextkbd_match(struct device
*, struct cfdata
*, void *);
83 void nextkbd_attach(struct device
*, struct device
*, void *);
85 int nextkbc_cnattach(bus_space_tag_t
);
87 CFATTACH_DECL(nextkbd
, sizeof(struct nextkbd_softc
),
88 nextkbd_match
, nextkbd_attach
, NULL
, NULL
);
90 int nextkbd_enable(void *, int);
91 void nextkbd_set_leds(void *, int);
92 int nextkbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
94 const struct wskbd_accessops nextkbd_accessops
= {
100 void nextkbd_cngetc(void *, u_int
*, int *);
101 void nextkbd_cnpollc(void *, int);
103 const struct wskbd_consops nextkbd_consops
= {
108 const struct wskbd_mapdata nextkbd_keymapdata
= {
113 static int nextkbd_read_data(struct nextkbd_internal
*);
114 static int nextkbd_decode(struct nextkbd_internal
*, int, u_int
*, int *);
116 static struct nextkbd_internal nextkbd_consdata
;
117 static int nextkbd_is_console(bus_space_tag_t
);
119 int nextkbdhard(void *);
122 nextkbd_is_console(bus_space_tag_t bst
)
124 return (nextkbd_consdata
.isconsole
&& (bst
== nextkbd_consdata
.iot
));
128 nextkbd_match(struct device
*parent
, struct cfdata
*match
, void *aux
)
130 struct intio_attach_args
*ia
= (struct intio_attach_args
*)aux
;
135 ia
->ia_addr
= (void *)NEXT_P_MON
;
141 nextkbd_attach(struct device
*parent
, struct device
*self
, void *aux
)
143 struct nextkbd_softc
*sc
= (struct nextkbd_softc
*)self
;
144 struct intio_attach_args
*ia
= (struct intio_attach_args
*)aux
;
146 struct wskbddev_attach_args a
;
150 isconsole
= nextkbd_is_console(ia
->ia_bst
); /* XXX */
153 sc
->id
= &nextkbd_consdata
;
155 sc
->id
= malloc(sizeof(struct nextkbd_internal
),
158 memset(sc
->id
, 0, sizeof(struct nextkbd_internal
));
159 sc
->id
->iot
= ia
->ia_bst
;
160 if (bus_space_map(sc
->id
->iot
, NEXT_P_MON
,
161 sizeof(struct mon_regs
),
163 printf("%s: can't map mon status control register\n",
164 sc
->sc_dev
.dv_xname
);
169 sc
->id
->t_sc
= sc
; /* set back pointer */
171 isrlink_autovec(nextkbdhard
, sc
, NEXT_I_IPL(NEXT_I_KYBD_MOUSE
), 0, NULL
);
173 INTR_ENABLE(NEXT_I_KYBD_MOUSE
);
175 a
.console
= isconsole
;
176 a
.keymap
= &nextkbd_keymapdata
;
177 a
.accessops
= &nextkbd_accessops
;
181 * Attach the wskbd, saving a handle to it.
184 sc
->sc_wskbddev
= config_found(self
, &a
, wskbddevprint
);
190 nextkbd_enable(void *v
, int on
)
192 /* XXX not sure if this should do anything */
193 /* printf("nextkbd_enable %d\n", on); */
198 nextkbd_set_leds(void *v
, int leds
)
200 struct nextkbd_softc
*sc
= v
;
201 uint32_t hw_leds
= 0;
204 sc
->sc_leds
&= ~ NEXT_WSKBD_LEDS
;
205 sc
->sc_leds
|= (leds
& NEXT_WSKBD_LEDS
);
207 if (sc
->sc_leds
& WSKBD_LED_CAPS
) {
212 bus_space_write_1(sc
->id
->iot
, sc
->id
->ioh
, 3, 0xc5);
214 if bit 7 of @ioh+0 set:
216 wait until bit 6 of @ioh+2 clears
218 bus_space_write_4(sc
->id
->iot
, sc
->id
->ioh
, 4, hw_leds
);
220 wait until bit 4 of @ioh+0 (@ioh+2 if bit 7 was set above)
229 nextkbd_ioctl(void *v
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
231 struct nextkbd_softc
*sc
= v
;
236 *(int *)data
= WSKBD_TYPE_NEXT
;
238 case WSKBDIO_SETLEDS
:
239 nextkbd_set_leds (sc
, *(int *)data
);
241 case WSKBDIO_GETLEDS
:
242 *(int *)data
= sc
->sc_leds
& NEXT_WSKBD_LEDS
;
244 case WSKBDIO_COMPLEXBELL
:
251 nextkbdhard(void *arg
)
253 struct nextkbd_softc
*sc
= arg
;
256 if (!INTR_OCCURRED(NEXT_I_KYBD_MOUSE
)) return 0;
258 #define CSR_INT 0x00800000
259 #define CSR_DATA 0x00400000
261 #define KD_KEYMASK 0x007f
262 #define KD_DIRECTION 0x0080 /* pressed or released */
263 #define KD_CNTL 0x0100
264 #define KD_LSHIFT 0x0200
265 #define KD_RSHIFT 0x0400
266 #define KD_LCOMM 0x0800
267 #define KD_RCOMM 0x1000
268 #define KD_LALT 0x2000
269 #define KD_RALT 0x4000
270 #define KD_VALID 0x8000 /* only set for scancode keys ? */
271 #define KD_MODS 0x4f00
273 val
= nextkbd_read_data(sc
->id
);
274 if ((val
!= -1) && nextkbd_decode(sc
->id
, val
, &type
, &key
)) {
275 wskbd_input(sc
->sc_wskbddev
, type
, key
);
281 nextkbd_cnattach(bus_space_tag_t bst
)
283 bus_space_handle_t bsh
;
285 if (bus_space_map(bst
, NEXT_P_MON
, sizeof(struct mon_regs
),
289 memset(&nextkbd_consdata
, 0, sizeof(nextkbd_consdata
));
291 nextkbd_consdata
.iot
= bst
;
292 nextkbd_consdata
.ioh
= bsh
;
293 nextkbd_consdata
.isconsole
= 1;
295 wskbd_cnattach(&nextkbd_consops
, &nextkbd_consdata
,
296 &nextkbd_keymapdata
);
302 nextkbd_cngetc(void *v
, u_int
*type
, int *data
)
304 struct nextkbd_internal
*t
= v
;
308 if (INTR_OCCURRED(NEXT_I_KYBD_MOUSE
)) {
309 val
= nextkbd_read_data(t
);
310 if ((val
!= -1) && nextkbd_decode(t
, val
, type
, data
))
317 nextkbd_cnpollc(void *v
, int on
)
319 struct nextkbd_internal
*t
= v
;
323 INTR_DISABLE(NEXT_I_KYBD_MOUSE
);
325 INTR_ENABLE(NEXT_I_KYBD_MOUSE
);
331 nextkbd_read_data(struct nextkbd_internal
*id
)
333 unsigned char device
;
334 struct mon_regs stat
;
336 bus_space_read_region_4(id
->iot
, id
->ioh
, 0, &stat
, 3);
337 if ((stat
.mon_csr
& CSR_INT
) && (stat
.mon_csr
& CSR_DATA
)) {
338 stat
.mon_csr
&= ~CSR_INT
;
340 bus_space_write_4(id
->iot
, id
->ioh
, 0, stat
.mon_csr
);
341 device
= stat
.mon_data
>> 28;
342 if (device
!= 1) return (-1); /* XXX: mouse */
343 return (stat
.mon_data
& 0xffff);
349 nextkbd_decode(struct nextkbd_internal
*id
, int datain
, u_int
*type
,
352 /* printf("datain %08x mods %08x\n", datain, id->mods); */
354 if ((datain
^ id
->mods
) & KD_LSHIFT
) {
355 id
->mods
^= KD_LSHIFT
;
357 if (datain
& KD_LSHIFT
)
358 *type
= WSCONS_EVENT_KEY_DOWN
;
360 *type
= WSCONS_EVENT_KEY_UP
;
361 } else if ((datain
^ id
->mods
) & KD_RSHIFT
) {
362 id
->mods
^= KD_RSHIFT
;
364 if (datain
& KD_RSHIFT
)
365 *type
= WSCONS_EVENT_KEY_DOWN
;
367 *type
= WSCONS_EVENT_KEY_UP
;
368 } else if ((datain
^ id
->mods
) & KD_LALT
) {
371 if (datain
& KD_LALT
)
372 *type
= WSCONS_EVENT_KEY_DOWN
;
374 *type
= WSCONS_EVENT_KEY_UP
;
375 } else if ((datain
^ id
->mods
) & KD_RALT
) {
378 if (datain
& KD_RALT
)
379 *type
= WSCONS_EVENT_KEY_DOWN
;
381 *type
= WSCONS_EVENT_KEY_UP
;
382 } else if ((datain
^ id
->mods
) & KD_CNTL
) {
385 if (datain
& KD_CNTL
)
386 *type
= WSCONS_EVENT_KEY_DOWN
;
388 *type
= WSCONS_EVENT_KEY_UP
;
389 } else if ((datain
^ id
->mods
) & KD_LCOMM
) {
390 id
->mods
^= KD_LCOMM
;
392 if (datain
& KD_LCOMM
)
393 *type
= WSCONS_EVENT_KEY_DOWN
;
395 *type
= WSCONS_EVENT_KEY_UP
;
396 } else if ((datain
^ id
->mods
) & KD_RCOMM
) {
397 id
->mods
^= KD_RCOMM
;
399 if (datain
& KD_RCOMM
)
400 *type
= WSCONS_EVENT_KEY_DOWN
;
402 *type
= WSCONS_EVENT_KEY_UP
;
403 } else if (datain
& KD_KEYMASK
) {
404 if (datain
& KD_DIRECTION
)
405 *type
= WSCONS_EVENT_KEY_UP
;
407 *type
= WSCONS_EVENT_KEY_DOWN
;
409 *dataout
= (datain
& KD_KEYMASK
);