1 /* $NetBSD: aed.c,v 1.28 2008/06/11 23:54:45 cegger Exp $ */
4 * Copyright (C) 1994 Bradley A. Grantham
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include <sys/cdefs.h>
29 __KERNEL_RCSID(0, "$NetBSD: aed.c,v 1.28 2008/06/11 23:54:45 cegger Exp $");
33 #include <sys/param.h>
34 #include <sys/device.h>
35 #include <sys/fcntl.h>
37 #include <sys/select.h>
39 #include <sys/signalvar.h>
40 #include <sys/systm.h>
43 #include <machine/autoconf.h>
44 #include <machine/cpu.h>
45 #include <machine/keyboard.h>
47 #include <mac68k/mac68k/macrom.h>
48 #include <mac68k/dev/adbvar.h>
49 #include <mac68k/dev/aedvar.h>
50 #include <mac68k/dev/akbdvar.h>
53 * Function declarations.
55 static int aedmatch(struct device
*, struct cfdata
*, void *);
56 static void aedattach(struct device
*, struct device
*, void *);
57 static void aed_emulate_mouse(adb_event_t
*);
58 static void aed_kbdrpt(void *);
59 static void aed_dokeyupdown(adb_event_t
*);
60 static void aed_handoff(adb_event_t
*);
61 static void aed_enqevent(adb_event_t
*);
66 static struct aed_softc
*aed_sc
;
67 static int aed_options
= 0 | AED_MSEMUL
;
69 /* Driver definition */
70 CFATTACH_DECL(aed
, sizeof(struct aed_softc
),
71 aedmatch
, aedattach
, NULL
, NULL
);
73 extern struct cfdriver aed_cd
;
75 dev_type_open(aedopen
);
76 dev_type_close(aedclose
);
77 dev_type_read(aedread
);
78 dev_type_ioctl(aedioctl
);
79 dev_type_poll(aedpoll
);
80 dev_type_kqfilter(aedkqfilter
);
82 const struct cdevsw aed_cdevsw
= {
83 aedopen
, aedclose
, aedread
, nullwrite
, aedioctl
,
84 nostop
, notty
, aedpoll
, nommap
, aedkqfilter
,
88 aedmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
90 struct adb_attach_args
*aa_args
= (struct adb_attach_args
*)aux
;
91 static int aed_matched
;
93 /* Allow only one instance. */
94 if ((aa_args
->origaddr
== 0) && (!aed_matched
)) {
102 aedattach(struct device
*parent
, struct device
*self
, void *aux
)
104 struct adb_attach_args
*aa_args
= (struct adb_attach_args
*)aux
;
105 struct aed_softc
*sc
= (struct aed_softc
*)self
;
107 callout_init(&sc
->sc_repeat_ch
, 0);
108 selinit(&sc
->sc_selinfo
);
110 sc
->origaddr
= aa_args
->origaddr
;
111 sc
->adbaddr
= aa_args
->adbaddr
;
112 sc
->handler_id
= aa_args
->handler_id
;
117 sc
->sc_rptdelay
= 20;
118 sc
->sc_rptinterval
= 6;
119 sc
->sc_repeating
= -1; /* not repeating */
121 /* Pull in the options flags. */
122 sc
->sc_options
= (device_cfdata(&sc
->sc_dev
)->cf_flags
| aed_options
);
124 sc
->sc_ioproc
= NULL
;
132 printf("ADB Event device\n");
138 * Given a keyboard ADB event, record the keycode and call the key
139 * repeat handler, optionally passing the event through the mouse
140 * button emulation handler first. Pass mouse events directly to
141 * the handoff function.
144 aed_input(adb_event_t
*event
)
146 adb_event_t new_event
= *event
;
147 int rv
= aed_sc
->sc_open
;
149 switch (event
->def_addr
) {
151 if (aed_sc
->sc_options
& AED_MSEMUL
)
152 aed_emulate_mouse(&new_event
);
154 aed_dokeyupdown(&new_event
);
157 new_event
.u
.m
.buttons
|= aed_sc
->sc_buttons
;
158 aed_handoff(&new_event
);
160 default: /* God only knows. */
162 panic("aed: received event from unsupported device!");
172 * Handles mouse button emulation via the keyboard. If the emulation
173 * modifier key is down, left and right arrows will generate 2nd and
174 * 3rd mouse button events while the 1, 2, and 3 keys will generate
175 * the corresponding mouse button event.
178 aed_emulate_mouse(adb_event_t
*event
)
180 static int emulmodkey_down
;
181 adb_event_t new_event
;
183 if (event
->u
.k
.key
== ADBK_KEYDOWN(ADBK_OPTION
)) {
185 } else if (event
->u
.k
.key
== ADBK_KEYUP(ADBK_OPTION
)) {
188 if (aed_sc
->sc_buttons
& 0xfe) {
189 aed_sc
->sc_buttons
&= 1;
190 new_event
.def_addr
= ADBADDR_MS
;
191 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
192 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
193 microtime(&new_event
.timestamp
);
194 aed_handoff(&new_event
);
196 } else if (emulmodkey_down
) {
197 switch(event
->u
.k
.key
) {
199 case ADBK_KEYDOWN(ADBK_1
):
200 aed_sc
->sc_buttons
|= 1; /* left down */
201 new_event
.def_addr
= ADBADDR_MS
;
202 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
203 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
204 microtime(&new_event
.timestamp
);
205 aed_handoff(&new_event
);
207 case ADBK_KEYUP(ADBK_1
):
208 aed_sc
->sc_buttons
&= ~1; /* left up */
209 new_event
.def_addr
= ADBADDR_MS
;
210 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
211 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
212 microtime(&new_event
.timestamp
);
213 aed_handoff(&new_event
);
216 case ADBK_KEYDOWN(ADBK_LEFT
):
218 case ADBK_KEYDOWN(ADBK_2
):
220 aed_sc
->sc_buttons
|= 2; /* middle down */
221 new_event
.def_addr
= ADBADDR_MS
;
222 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
223 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
224 microtime(&new_event
.timestamp
);
225 aed_handoff(&new_event
);
227 case ADBK_KEYUP(ADBK_LEFT
):
229 case ADBK_KEYUP(ADBK_2
):
231 aed_sc
->sc_buttons
&= ~2; /* middle up */
232 new_event
.def_addr
= ADBADDR_MS
;
233 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
234 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
235 microtime(&new_event
.timestamp
);
236 aed_handoff(&new_event
);
238 case ADBK_KEYDOWN(ADBK_RIGHT
):
240 case ADBK_KEYDOWN(ADBK_3
):
242 aed_sc
->sc_buttons
|= 4; /* right down */
243 new_event
.def_addr
= ADBADDR_MS
;
244 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
245 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
246 microtime(&new_event
.timestamp
);
247 aed_handoff(&new_event
);
249 case ADBK_KEYUP(ADBK_RIGHT
):
251 case ADBK_KEYUP(ADBK_3
):
253 aed_sc
->sc_buttons
&= ~4; /* right up */
254 new_event
.def_addr
= ADBADDR_MS
;
255 new_event
.u
.m
.buttons
= aed_sc
->sc_buttons
;
256 new_event
.u
.m
.dx
= new_event
.u
.m
.dy
= 0;
257 microtime(&new_event
.timestamp
);
258 aed_handoff(&new_event
);
260 case ADBK_KEYUP(ADBK_SHIFT
):
261 case ADBK_KEYDOWN(ADBK_SHIFT
):
262 case ADBK_KEYUP(ADBK_CONTROL
):
263 case ADBK_KEYDOWN(ADBK_CONTROL
):
264 case ADBK_KEYUP(ADBK_FLOWER
):
265 case ADBK_KEYDOWN(ADBK_FLOWER
):
266 /* ctrl, shift, cmd */
267 aed_dokeyupdown(event
);
270 if (event
->u
.k
.key
& 0x80)
277 /* send option-down */
278 new_event
.u
.k
.key
= ADBK_KEYDOWN(ADBK_OPTION
);
279 new_event
.bytes
[0] = new_event
.u
.k
.key
;
280 microtime(&new_event
.timestamp
);
281 aed_dokeyupdown(&new_event
);
284 new_event
.u
.k
.key
= event
->bytes
[0];
285 new_event
.bytes
[0] = new_event
.u
.k
.key
;
286 microtime(&new_event
.timestamp
);
287 aed_dokeyupdown(&new_event
);
291 ADBK_KEYUP(ADBK_KEYVAL(event
->bytes
[0]));
292 microtime(&new_event
.timestamp
);
293 new_event
.bytes
[0] = new_event
.u
.k
.key
;
294 aed_dokeyupdown(&new_event
);
297 new_event
.u
.k
.key
= ADBK_KEYUP(ADBK_OPTION
);
298 new_event
.bytes
[0] = new_event
.u
.k
.key
;
299 microtime(&new_event
.timestamp
);
300 aed_dokeyupdown(&new_event
);
304 aed_dokeyupdown(event
);
309 * Keyboard autorepeat timeout function. Sends key up/down events
310 * for the repeating key and schedules the next call at sc_rptinterval
311 * ticks in the future.
314 aed_kbdrpt(void *kstate
)
316 struct aed_softc
*sc
= (struct aed_softc
*)kstate
;
318 sc
->sc_rptevent
.bytes
[0] |= 0x80;
319 microtime(&sc
->sc_rptevent
.timestamp
);
320 aed_handoff(&sc
->sc_rptevent
); /* do key up */
322 sc
->sc_rptevent
.bytes
[0] &= 0x7f;
323 microtime(&sc
->sc_rptevent
.timestamp
);
324 aed_handoff(&sc
->sc_rptevent
); /* do key down */
326 if (sc
->sc_repeating
== sc
->sc_rptevent
.u
.k
.key
) {
327 callout_reset(&sc
->sc_repeat_ch
, sc
->sc_rptinterval
,
334 * Cancels the currently repeating key event if there is one, schedules
335 * a new repeating key event if needed, and hands the event off to the
336 * appropriate subsystem.
339 aed_dokeyupdown(adb_event_t
*event
)
343 kbd_key
= ADBK_KEYVAL(event
->u
.k
.key
);
344 if (ADBK_PRESS(event
->u
.k
.key
) && keyboard
[kbd_key
][0] != 0) {
345 /* ignore shift & control */
346 if (aed_sc
->sc_repeating
!= -1) {
347 callout_stop(&aed_sc
->sc_repeat_ch
);
349 aed_sc
->sc_rptevent
= *event
;
350 aed_sc
->sc_repeating
= kbd_key
;
351 callout_reset(&aed_sc
->sc_repeat_ch
, aed_sc
->sc_rptdelay
,
352 aed_kbdrpt
, (void *)aed_sc
);
354 if (aed_sc
->sc_repeating
!= -1) {
355 aed_sc
->sc_repeating
= -1;
356 callout_stop(&aed_sc
->sc_repeat_ch
);
358 aed_sc
->sc_rptevent
= *event
;
364 * Place the event in the event queue if a requesting device is open
365 * and we are not polling, otherwise, pass it up to the console driver.
368 aed_handoff(adb_event_t
*event
)
370 if (aed_sc
->sc_open
&& !adb_polling
)
375 * Place the event in the event queue and wakeup any waiting processes.
378 aed_enqevent(adb_event_t
*event
)
385 if (aed_sc
->sc_evq_tail
< 0 || aed_sc
->sc_evq_tail
>= AED_MAX_EVENTS
)
386 panic("adb: event queue tail is out of bounds");
388 if (aed_sc
->sc_evq_len
< 0 || aed_sc
->sc_evq_len
> AED_MAX_EVENTS
)
389 panic("adb: event queue len is out of bounds");
392 if (aed_sc
->sc_evq_len
== AED_MAX_EVENTS
) {
394 return; /* Oh, well... */
396 aed_sc
->sc_evq
[(aed_sc
->sc_evq_len
+ aed_sc
->sc_evq_tail
) %
397 AED_MAX_EVENTS
] = *event
;
398 aed_sc
->sc_evq_len
++;
400 selnotify(&aed_sc
->sc_selinfo
, 0, 0);
401 if (aed_sc
->sc_ioproc
)
402 psignal(aed_sc
->sc_ioproc
, SIGIO
);
408 aedopen(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
410 struct aed_softc
*sc
;
413 sc
= device_lookup_private(&aed_cd
, minor(dev
));
422 aed_sc
->sc_evq_tail
= 0;
423 aed_sc
->sc_evq_len
= 0;
425 aed_sc
->sc_ioproc
= l
->l_proc
;
433 aedclose(dev_t dev
, int flag
, int mode
, struct lwp
*l
)
439 aed_sc
->sc_ioproc
= NULL
;
447 aedread(dev_t dev
, struct uio
*uio
, int flag
)
455 if (uio
->uio_resid
< sizeof(adb_event_t
))
456 return (EMSGSIZE
); /* close enough. */
459 if (aed_sc
->sc_evq_len
== 0) {
463 willfit
= howmany(uio
->uio_resid
, sizeof(adb_event_t
));
464 total
= (aed_sc
->sc_evq_len
< willfit
) ? aed_sc
->sc_evq_len
: willfit
;
466 firstmove
= (aed_sc
->sc_evq_tail
+ total
> AED_MAX_EVENTS
)
467 ? (AED_MAX_EVENTS
- aed_sc
->sc_evq_tail
) : total
;
469 error
= uiomove((void *) & aed_sc
->sc_evq
[aed_sc
->sc_evq_tail
],
470 firstmove
* sizeof(adb_event_t
), uio
);
475 moremove
= total
- firstmove
;
478 error
= uiomove((void *) & aed_sc
->sc_evq
[0],
479 moremove
* sizeof(adb_event_t
), uio
);
485 aed_sc
->sc_evq_tail
= (aed_sc
->sc_evq_tail
+ total
) % AED_MAX_EVENTS
;
486 aed_sc
->sc_evq_len
-= total
;
492 aedioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
495 case ADBIOC_DEVSINFO
: {
497 ADBDataBlock adbdata
;
504 /* Initialize to no devices */
505 for (i
= 0; i
< 16; i
++)
506 di
->dev
[i
].addr
= -1;
508 totaldevs
= CountADBs();
509 for (i
= 1; i
<= totaldevs
; i
++) {
510 adbaddr
= GetIndADB(&adbdata
, i
);
511 di
->dev
[adbaddr
].addr
= adbaddr
;
512 di
->dev
[adbaddr
].default_addr
= (int)(adbdata
.origADBAddr
);
513 di
->dev
[adbaddr
].handler_id
= (int)(adbdata
.devType
);
516 /* Must call ADB Manager to get devices now */
520 case ADBIOC_GETREPEAT
:{
524 ri
->delay_ticks
= aed_sc
->sc_rptdelay
;
525 ri
->interval_ticks
= aed_sc
->sc_rptinterval
;
529 case ADBIOC_SETREPEAT
:{
533 aed_sc
->sc_rptdelay
= ri
->delay_ticks
;
534 aed_sc
->sc_rptinterval
= ri
->interval_ticks
;
539 /* Do nothing for now */
542 case ADBIOC_LISTENCMD
:{
556 aedpoll(dev_t dev
, int events
, struct lwp
*l
)
560 revents
= events
& (POLLOUT
| POLLWRNORM
);
562 if ((events
& (POLLIN
| POLLRDNORM
)) == 0)
566 if (aed_sc
->sc_evq_len
> 0)
567 revents
|= events
& (POLLIN
| POLLRDNORM
);
569 selrecord(l
, &aed_sc
->sc_selinfo
);
576 filt_aedrdetach(struct knote
*kn
)
581 SLIST_REMOVE(&aed_sc
->sc_selinfo
.sel_klist
, kn
, knote
, kn_selnext
);
586 filt_aedread(struct knote
*kn
, long hint
)
589 kn
->kn_data
= aed_sc
->sc_evq_len
* sizeof(adb_event_t
);
590 return (kn
->kn_data
> 0);
593 static const struct filterops aedread_filtops
=
594 { 1, NULL
, filt_aedrdetach
, filt_aedread
};
596 static const struct filterops aed_seltrue_filtops
=
597 { 1, NULL
, filt_aedrdetach
, filt_seltrue
};
600 aedkqfilter(dev_t dev
, struct knote
*kn
)
605 switch (kn
->kn_filter
) {
607 klist
= &aed_sc
->sc_selinfo
.sel_klist
;
608 kn
->kn_fop
= &aedread_filtops
;
612 klist
= &aed_sc
->sc_selinfo
.sel_klist
;
613 kn
->kn_fop
= &aed_seltrue_filtops
;
623 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);