1 1.37 riastrad /* $NetBSD: aed.c,v 1.37 2025/01/13 16:17:36 riastradh Exp $ */ 2 1.1 tsubai 3 1.1 tsubai /* 4 1.1 tsubai * Copyright (C) 1994 Bradley A. Grantham 5 1.1 tsubai * All rights reserved. 6 1.1 tsubai * 7 1.1 tsubai * Redistribution and use in source and binary forms, with or without 8 1.1 tsubai * modification, are permitted provided that the following conditions 9 1.1 tsubai * are met: 10 1.1 tsubai * 1. Redistributions of source code must retain the above copyright 11 1.1 tsubai * notice, this list of conditions and the following disclaimer. 12 1.1 tsubai * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 tsubai * notice, this list of conditions and the following disclaimer in the 14 1.1 tsubai * documentation and/or other materials provided with the distribution. 15 1.1 tsubai * 16 1.1 tsubai * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 tsubai * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 tsubai * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 tsubai * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 tsubai * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 1.1 tsubai * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 1.1 tsubai * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 1.1 tsubai * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 1.1 tsubai * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 1.1 tsubai * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 1.1 tsubai */ 27 1.14 lukem 28 1.14 lukem #include <sys/cdefs.h> 29 1.37 riastrad __KERNEL_RCSID(0, "$NetBSD: aed.c,v 1.37 2025/01/13 16:17:36 riastradh Exp $"); 30 1.1 tsubai 31 1.1 tsubai #include <sys/param.h> 32 1.1 tsubai #include <sys/device.h> 33 1.1 tsubai #include <sys/fcntl.h> 34 1.1 tsubai #include <sys/poll.h> 35 1.1 tsubai #include <sys/select.h> 36 1.1 tsubai #include <sys/proc.h> 37 1.1 tsubai #include <sys/signalvar.h> 38 1.1 tsubai #include <sys/systm.h> 39 1.6 gehenna #include <sys/conf.h> 40 1.1 tsubai 41 1.1 tsubai #include <machine/autoconf.h> 42 1.1 tsubai #include <machine/cpu.h> 43 1.1 tsubai #include <machine/keyboard.h> 44 1.1 tsubai 45 1.1 tsubai #include <macppc/dev/adbvar.h> 46 1.1 tsubai #include <macppc/dev/aedvar.h> 47 1.1 tsubai #include <macppc/dev/akbdvar.h> 48 1.1 tsubai 49 1.1 tsubai #define spladb splhigh 50 1.1 tsubai 51 1.1 tsubai /* 52 1.1 tsubai * Function declarations. 53 1.1 tsubai */ 54 1.26 matt static int aedmatch(device_t, cfdata_t, void *); 55 1.26 matt static void aedattach(device_t, device_t, void *); 56 1.36 nat static int aed_emulate_mouse(adb_event_t *event); 57 1.22 dsl static void aed_kbdrpt(void *kstate); 58 1.22 dsl static void aed_dokeyupdown(adb_event_t *event); 59 1.22 dsl static void aed_handoff(adb_event_t *event); 60 1.22 dsl static void aed_enqevent(adb_event_t *event); 61 1.1 tsubai 62 1.1 tsubai /* 63 1.1 tsubai * Global variables. 64 1.1 tsubai */ 65 1.1 tsubai extern int adb_polling; /* Are we polling? (Debugger mode) */ 66 1.1 tsubai 67 1.1 tsubai /* 68 1.1 tsubai * Local variables. 69 1.1 tsubai */ 70 1.4 tsubai static struct aed_softc *aed_sc = NULL; 71 1.3 tsubai static int aed_options = 0; /* | AED_MSEMUL; */ 72 1.1 tsubai 73 1.1 tsubai /* Driver definition */ 74 1.27 chs CFATTACH_DECL_NEW(aed, sizeof(struct aed_softc), 75 1.9 thorpej aedmatch, aedattach, NULL, NULL); 76 1.1 tsubai 77 1.1 tsubai extern struct cfdriver aed_cd; 78 1.1 tsubai 79 1.6 gehenna dev_type_open(aedopen); 80 1.6 gehenna dev_type_close(aedclose); 81 1.6 gehenna dev_type_read(aedread); 82 1.6 gehenna dev_type_ioctl(aedioctl); 83 1.6 gehenna dev_type_poll(aedpoll); 84 1.10 jdolecek dev_type_kqfilter(aedkqfilter); 85 1.6 gehenna 86 1.6 gehenna const struct cdevsw aed_cdevsw = { 87 1.28 dholland .d_open = aedopen, 88 1.28 dholland .d_close = aedclose, 89 1.28 dholland .d_read = aedread, 90 1.28 dholland .d_write = nullwrite, 91 1.28 dholland .d_ioctl = aedioctl, 92 1.28 dholland .d_stop = nostop, 93 1.28 dholland .d_tty = notty, 94 1.28 dholland .d_poll = aedpoll, 95 1.28 dholland .d_mmap = nommap, 96 1.28 dholland .d_kqfilter = aedkqfilter, 97 1.29 dholland .d_discard = nodiscard, 98 1.28 dholland .d_flag = 0 99 1.6 gehenna }; 100 1.6 gehenna 101 1.1 tsubai static int 102 1.26 matt aedmatch(device_t parent, cfdata_t cf, void *aux) 103 1.1 tsubai { 104 1.4 tsubai struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 105 1.1 tsubai static int aed_matched = 0; 106 1.1 tsubai 107 1.1 tsubai /* Allow only one instance. */ 108 1.1 tsubai if ((aa_args->origaddr == 0) && (!aed_matched)) { 109 1.1 tsubai aed_matched = 1; 110 1.1 tsubai return (1); 111 1.1 tsubai } else 112 1.1 tsubai return (0); 113 1.1 tsubai } 114 1.1 tsubai 115 1.1 tsubai static void 116 1.26 matt aedattach(device_t parent, device_t self, void *aux) 117 1.1 tsubai { 118 1.4 tsubai struct adb_attach_args *aa_args = (struct adb_attach_args *)aux; 119 1.26 matt struct aed_softc *sc = device_private(self); 120 1.1 tsubai 121 1.19 ad callout_init(&sc->sc_repeat_ch, 0); 122 1.21 rmind selinit(&sc->sc_selinfo); 123 1.5 thorpej 124 1.1 tsubai sc->origaddr = aa_args->origaddr; 125 1.1 tsubai sc->adbaddr = aa_args->adbaddr; 126 1.1 tsubai sc->handler_id = aa_args->handler_id; 127 1.1 tsubai 128 1.1 tsubai sc->sc_evq_tail = 0; 129 1.1 tsubai sc->sc_evq_len = 0; 130 1.1 tsubai 131 1.1 tsubai sc->sc_rptdelay = 20; 132 1.1 tsubai sc->sc_rptinterval = 6; 133 1.1 tsubai sc->sc_repeating = -1; /* not repeating */ 134 1.1 tsubai 135 1.37 riastrad /* Pull in the options flags. */ 136 1.27 chs sc->sc_options = (device_cfdata(self)->cf_flags | aed_options); 137 1.1 tsubai 138 1.1 tsubai sc->sc_ioproc = NULL; 139 1.37 riastrad 140 1.1 tsubai sc->sc_buttons = 0; 141 1.1 tsubai 142 1.1 tsubai sc->sc_open = 0; 143 1.1 tsubai 144 1.1 tsubai aed_sc = sc; 145 1.1 tsubai 146 1.1 tsubai printf("ADB Event device\n"); 147 1.1 tsubai 148 1.1 tsubai return; 149 1.1 tsubai } 150 1.1 tsubai 151 1.1 tsubai /* 152 1.37 riastrad * Given a keyboard ADB event, record the keycode and call the key 153 1.1 tsubai * repeat handler, optionally passing the event through the mouse 154 1.1 tsubai * button emulation handler first. Pass mouse events directly to 155 1.1 tsubai * the handoff function. 156 1.1 tsubai */ 157 1.1 tsubai void 158 1.23 dsl aed_input(adb_event_t *event) 159 1.1 tsubai { 160 1.1 tsubai adb_event_t new_event = *event; 161 1.1 tsubai 162 1.1 tsubai switch (event->def_addr) { 163 1.1 tsubai case ADBADDR_KBD: 164 1.36 nat if (aed_sc->sc_options & AED_MSEMUL) { 165 1.36 nat rv = aed_emulate_mouse(&new_event); 166 1.36 nat } else 167 1.1 tsubai aed_dokeyupdown(&new_event); 168 1.1 tsubai break; 169 1.1 tsubai case ADBADDR_MS: 170 1.35 nat event->u.m.buttons |= aed_sc->sc_buttons; 171 1.4 tsubai new_event.u.m.buttons |= aed_sc->sc_buttons; 172 1.1 tsubai aed_handoff(&new_event); 173 1.1 tsubai break; 174 1.1 tsubai default: /* God only knows. */ 175 1.1 tsubai #ifdef DIAGNOSTIC 176 1.7 provos panic("aed: received event from unsupported device!"); 177 1.1 tsubai #endif 178 1.1 tsubai break; 179 1.1 tsubai } 180 1.1 tsubai 181 1.1 tsubai } 182 1.1 tsubai 183 1.1 tsubai /* 184 1.1 tsubai * Handles mouse button emulation via the keyboard. If the emulation 185 1.1 tsubai * modifier key is down, left and right arrows will generate 2nd and 186 1.1 tsubai * 3rd mouse button events while the 1, 2, and 3 keys will generate 187 1.1 tsubai * the corresponding mouse button event. 188 1.1 tsubai */ 189 1.37 riastrad static int 190 1.23 dsl aed_emulate_mouse(adb_event_t *event) 191 1.1 tsubai { 192 1.1 tsubai static int emulmodkey_down = 0; 193 1.1 tsubai adb_event_t new_event; 194 1.36 nat int result = 0; 195 1.1 tsubai 196 1.1 tsubai if (event->u.k.key == ADBK_KEYDOWN(ADBK_OPTION)) { 197 1.1 tsubai emulmodkey_down = 1; 198 1.1 tsubai } else if (event->u.k.key == ADBK_KEYUP(ADBK_OPTION)) { 199 1.1 tsubai /* key up */ 200 1.1 tsubai emulmodkey_down = 0; 201 1.1 tsubai if (aed_sc->sc_buttons & 0xfe) { 202 1.1 tsubai aed_sc->sc_buttons &= 1; 203 1.1 tsubai new_event.def_addr = ADBADDR_MS; 204 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 205 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 206 1.1 tsubai microtime(&new_event.timestamp); 207 1.1 tsubai aed_handoff(&new_event); 208 1.1 tsubai } 209 1.1 tsubai } else if (emulmodkey_down) { 210 1.1 tsubai switch(event->u.k.key) { 211 1.1 tsubai #ifdef ALTXBUTTONS 212 1.1 tsubai case ADBK_KEYDOWN(ADBK_1): 213 1.36 nat result = 1; 214 1.1 tsubai aed_sc->sc_buttons |= 1; /* left down */ 215 1.1 tsubai new_event.def_addr = ADBADDR_MS; 216 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 217 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 218 1.1 tsubai microtime(&new_event.timestamp); 219 1.1 tsubai aed_handoff(&new_event); 220 1.1 tsubai break; 221 1.1 tsubai case ADBK_KEYUP(ADBK_1): 222 1.36 nat result = 1; 223 1.4 tsubai aed_sc->sc_buttons &= ~1; /* left up */ 224 1.1 tsubai new_event.def_addr = ADBADDR_MS; 225 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 226 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 227 1.1 tsubai microtime(&new_event.timestamp); 228 1.1 tsubai aed_handoff(&new_event); 229 1.1 tsubai break; 230 1.1 tsubai #endif 231 1.1 tsubai case ADBK_KEYDOWN(ADBK_LEFT): 232 1.1 tsubai #ifdef ALTXBUTTONS 233 1.1 tsubai case ADBK_KEYDOWN(ADBK_2): 234 1.1 tsubai #endif 235 1.36 nat result = 1; 236 1.1 tsubai aed_sc->sc_buttons |= 2; /* middle down */ 237 1.1 tsubai new_event.def_addr = ADBADDR_MS; 238 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 239 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 240 1.1 tsubai microtime(&new_event.timestamp); 241 1.1 tsubai aed_handoff(&new_event); 242 1.1 tsubai break; 243 1.1 tsubai case ADBK_KEYUP(ADBK_LEFT): 244 1.1 tsubai #ifdef ALTXBUTTONS 245 1.1 tsubai case ADBK_KEYUP(ADBK_2): 246 1.1 tsubai #endif 247 1.36 nat result = 1; 248 1.1 tsubai aed_sc->sc_buttons &= ~2; /* middle up */ 249 1.1 tsubai new_event.def_addr = ADBADDR_MS; 250 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 251 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 252 1.1 tsubai microtime(&new_event.timestamp); 253 1.1 tsubai aed_handoff(&new_event); 254 1.1 tsubai break; 255 1.1 tsubai case ADBK_KEYDOWN(ADBK_RIGHT): 256 1.1 tsubai #ifdef ALTXBUTTONS 257 1.1 tsubai case ADBK_KEYDOWN(ADBK_3): 258 1.1 tsubai #endif 259 1.36 nat result = 1; 260 1.1 tsubai aed_sc->sc_buttons |= 4; /* right down */ 261 1.1 tsubai new_event.def_addr = ADBADDR_MS; 262 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 263 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 264 1.1 tsubai microtime(&new_event.timestamp); 265 1.1 tsubai aed_handoff(&new_event); 266 1.1 tsubai break; 267 1.1 tsubai case ADBK_KEYUP(ADBK_RIGHT): 268 1.4 tsubai #ifdef ALTXBUTTONS 269 1.1 tsubai case ADBK_KEYUP(ADBK_3): 270 1.4 tsubai #endif 271 1.36 nat result = 1; 272 1.1 tsubai aed_sc->sc_buttons &= ~4; /* right up */ 273 1.1 tsubai new_event.def_addr = ADBADDR_MS; 274 1.1 tsubai new_event.u.m.buttons = aed_sc->sc_buttons; 275 1.1 tsubai new_event.u.m.dx = new_event.u.m.dy = 0; 276 1.1 tsubai microtime(&new_event.timestamp); 277 1.1 tsubai aed_handoff(&new_event); 278 1.1 tsubai break; 279 1.4 tsubai case ADBK_KEYUP(ADBK_SHIFT): 280 1.4 tsubai case ADBK_KEYDOWN(ADBK_SHIFT): 281 1.4 tsubai case ADBK_KEYUP(ADBK_CONTROL): 282 1.4 tsubai case ADBK_KEYDOWN(ADBK_CONTROL): 283 1.4 tsubai case ADBK_KEYUP(ADBK_FLOWER): 284 1.4 tsubai case ADBK_KEYDOWN(ADBK_FLOWER): 285 1.1 tsubai /* ctrl, shift, cmd */ 286 1.1 tsubai aed_dokeyupdown(event); 287 1.1 tsubai break; 288 1.1 tsubai default: 289 1.1 tsubai if (event->u.k.key & 0x80) 290 1.1 tsubai /* ignore keyup */ 291 1.1 tsubai break; 292 1.1 tsubai 293 1.1 tsubai /* key down */ 294 1.1 tsubai new_event = *event; 295 1.1 tsubai 296 1.1 tsubai /* send option-down */ 297 1.1 tsubai new_event.u.k.key = ADBK_KEYDOWN(ADBK_OPTION); 298 1.1 tsubai new_event.bytes[0] = new_event.u.k.key; 299 1.1 tsubai microtime(&new_event.timestamp); 300 1.1 tsubai aed_dokeyupdown(&new_event); 301 1.1 tsubai 302 1.1 tsubai /* send key-down */ 303 1.1 tsubai new_event.u.k.key = event->bytes[0]; 304 1.1 tsubai new_event.bytes[0] = new_event.u.k.key; 305 1.1 tsubai microtime(&new_event.timestamp); 306 1.1 tsubai aed_dokeyupdown(&new_event); 307 1.1 tsubai 308 1.1 tsubai /* send key-up */ 309 1.1 tsubai new_event.u.k.key = 310 1.1 tsubai ADBK_KEYUP(ADBK_KEYVAL(event->bytes[0])); 311 1.1 tsubai microtime(&new_event.timestamp); 312 1.1 tsubai new_event.bytes[0] = new_event.u.k.key; 313 1.1 tsubai aed_dokeyupdown(&new_event); 314 1.1 tsubai 315 1.1 tsubai /* send option-up */ 316 1.1 tsubai new_event.u.k.key = ADBK_KEYUP(ADBK_OPTION); 317 1.1 tsubai new_event.bytes[0] = new_event.u.k.key; 318 1.1 tsubai microtime(&new_event.timestamp); 319 1.1 tsubai aed_dokeyupdown(&new_event); 320 1.1 tsubai break; 321 1.1 tsubai } 322 1.1 tsubai } else { 323 1.1 tsubai aed_dokeyupdown(event); 324 1.1 tsubai } 325 1.36 nat 326 1.36 nat return result; 327 1.1 tsubai } 328 1.1 tsubai 329 1.1 tsubai /* 330 1.1 tsubai * Keyboard autorepeat timeout function. Sends key up/down events 331 1.1 tsubai * for the repeating key and schedules the next call at sc_rptinterval 332 1.1 tsubai * ticks in the future. 333 1.1 tsubai */ 334 1.37 riastrad static void 335 1.23 dsl aed_kbdrpt(void *kstate) 336 1.1 tsubai { 337 1.15 nathanw struct aed_softc *sc = (struct aed_softc *)kstate; 338 1.1 tsubai 339 1.15 nathanw sc->sc_rptevent.bytes[0] |= 0x80; 340 1.15 nathanw microtime(&sc->sc_rptevent.timestamp); 341 1.15 nathanw aed_handoff(&sc->sc_rptevent); /* do key up */ 342 1.15 nathanw 343 1.15 nathanw sc->sc_rptevent.bytes[0] &= 0x7f; 344 1.15 nathanw microtime(&sc->sc_rptevent.timestamp); 345 1.15 nathanw aed_handoff(&sc->sc_rptevent); /* do key down */ 346 1.1 tsubai 347 1.15 nathanw if (sc->sc_repeating == sc->sc_rptevent.u.k.key) { 348 1.15 nathanw callout_reset(&sc->sc_repeat_ch, sc->sc_rptinterval, 349 1.5 thorpej aed_kbdrpt, kstate); 350 1.1 tsubai } 351 1.1 tsubai } 352 1.1 tsubai 353 1.1 tsubai /* 354 1.1 tsubai * Cancels the currently repeating key event if there is one, schedules 355 1.1 tsubai * a new repeating key event if needed, and hands the event off to the 356 1.1 tsubai * appropriate subsystem. 357 1.1 tsubai */ 358 1.37 riastrad static void 359 1.23 dsl aed_dokeyupdown(adb_event_t *event) 360 1.1 tsubai { 361 1.1 tsubai int kbd_key; 362 1.1 tsubai 363 1.1 tsubai kbd_key = ADBK_KEYVAL(event->u.k.key); 364 1.1 tsubai if (ADBK_PRESS(event->u.k.key) && keyboard[kbd_key][0] != 0) { 365 1.1 tsubai /* ignore shift & control */ 366 1.1 tsubai if (aed_sc->sc_repeating != -1) { 367 1.5 thorpej callout_stop(&aed_sc->sc_repeat_ch); 368 1.1 tsubai } 369 1.1 tsubai aed_sc->sc_rptevent = *event; 370 1.1 tsubai aed_sc->sc_repeating = kbd_key; 371 1.5 thorpej callout_reset(&aed_sc->sc_repeat_ch, aed_sc->sc_rptdelay, 372 1.5 thorpej aed_kbdrpt, (void *)aed_sc); 373 1.1 tsubai } else { 374 1.1 tsubai if (aed_sc->sc_repeating != -1) { 375 1.1 tsubai aed_sc->sc_repeating = -1; 376 1.5 thorpej callout_stop(&aed_sc->sc_repeat_ch); 377 1.1 tsubai } 378 1.1 tsubai aed_sc->sc_rptevent = *event; 379 1.1 tsubai } 380 1.1 tsubai aed_handoff(event); 381 1.1 tsubai } 382 1.1 tsubai 383 1.1 tsubai /* 384 1.1 tsubai * Place the event in the event queue if a requesting device is open 385 1.3 tsubai * and we are not polling. 386 1.1 tsubai */ 387 1.1 tsubai static void 388 1.23 dsl aed_handoff(adb_event_t *event) 389 1.1 tsubai { 390 1.1 tsubai if (aed_sc->sc_open && !adb_polling) 391 1.1 tsubai aed_enqevent(event); 392 1.1 tsubai } 393 1.1 tsubai 394 1.1 tsubai /* 395 1.1 tsubai * Place the event in the event queue and wakeup any waiting processes. 396 1.1 tsubai */ 397 1.37 riastrad static void 398 1.23 dsl aed_enqevent(adb_event_t *event) 399 1.1 tsubai { 400 1.1 tsubai int s; 401 1.1 tsubai 402 1.1 tsubai s = spladb(); 403 1.1 tsubai 404 1.1 tsubai #ifdef DIAGNOSTIC 405 1.1 tsubai if (aed_sc->sc_evq_tail < 0 || aed_sc->sc_evq_tail >= AED_MAX_EVENTS) 406 1.1 tsubai panic("adb: event queue tail is out of bounds"); 407 1.1 tsubai 408 1.1 tsubai if (aed_sc->sc_evq_len < 0 || aed_sc->sc_evq_len > AED_MAX_EVENTS) 409 1.1 tsubai panic("adb: event queue len is out of bounds"); 410 1.1 tsubai #endif 411 1.1 tsubai 412 1.1 tsubai if (aed_sc->sc_evq_len == AED_MAX_EVENTS) { 413 1.1 tsubai splx(s); 414 1.1 tsubai return; /* Oh, well... */ 415 1.1 tsubai } 416 1.1 tsubai aed_sc->sc_evq[(aed_sc->sc_evq_len + aed_sc->sc_evq_tail) % 417 1.1 tsubai AED_MAX_EVENTS] = *event; 418 1.1 tsubai aed_sc->sc_evq_len++; 419 1.1 tsubai 420 1.21 rmind selnotify(&aed_sc->sc_selinfo, 0, 0); 421 1.1 tsubai if (aed_sc->sc_ioproc) 422 1.1 tsubai psignal(aed_sc->sc_ioproc, SIGIO); 423 1.1 tsubai 424 1.1 tsubai splx(s); 425 1.1 tsubai } 426 1.1 tsubai 427 1.37 riastrad int 428 1.24 dsl aedopen(dev_t dev, int flag, int mode, struct lwp *l) 429 1.1 tsubai { 430 1.1 tsubai int unit; 431 1.1 tsubai int error = 0; 432 1.1 tsubai int s; 433 1.1 tsubai 434 1.1 tsubai unit = minor(dev); 435 1.1 tsubai 436 1.1 tsubai if (unit != 0) 437 1.1 tsubai return (ENXIO); 438 1.1 tsubai 439 1.1 tsubai s = spladb(); 440 1.1 tsubai if (aed_sc->sc_open) { 441 1.1 tsubai splx(s); 442 1.1 tsubai return (EBUSY); 443 1.1 tsubai } 444 1.1 tsubai aed_sc->sc_evq_tail = 0; 445 1.1 tsubai aed_sc->sc_evq_len = 0; 446 1.1 tsubai aed_sc->sc_open = 1; 447 1.16 christos aed_sc->sc_ioproc = l->l_proc; 448 1.1 tsubai splx(s); 449 1.1 tsubai 450 1.1 tsubai return (error); 451 1.1 tsubai } 452 1.1 tsubai 453 1.37 riastrad int 454 1.24 dsl aedclose(dev_t dev, int flag, int mode, struct lwp *l) 455 1.1 tsubai { 456 1.1 tsubai int s = spladb(); 457 1.1 tsubai 458 1.1 tsubai aed_sc->sc_open = 0; 459 1.1 tsubai aed_sc->sc_ioproc = NULL; 460 1.1 tsubai splx(s); 461 1.1 tsubai 462 1.1 tsubai return (0); 463 1.1 tsubai } 464 1.1 tsubai 465 1.37 riastrad int 466 1.23 dsl aedread(dev_t dev, struct uio *uio, int flag) 467 1.1 tsubai { 468 1.1 tsubai int s, error; 469 1.1 tsubai int willfit; 470 1.1 tsubai int total; 471 1.1 tsubai int firstmove; 472 1.1 tsubai int moremove; 473 1.1 tsubai 474 1.1 tsubai if (uio->uio_resid < sizeof(adb_event_t)) 475 1.1 tsubai return (EMSGSIZE); /* close enough. */ 476 1.1 tsubai 477 1.1 tsubai s = spladb(); 478 1.1 tsubai if (aed_sc->sc_evq_len == 0) { 479 1.1 tsubai splx(s); 480 1.1 tsubai return (0); 481 1.1 tsubai } 482 1.1 tsubai willfit = howmany(uio->uio_resid, sizeof(adb_event_t)); 483 1.1 tsubai total = (aed_sc->sc_evq_len < willfit) ? aed_sc->sc_evq_len : willfit; 484 1.1 tsubai 485 1.1 tsubai firstmove = (aed_sc->sc_evq_tail + total > AED_MAX_EVENTS) 486 1.1 tsubai ? (AED_MAX_EVENTS - aed_sc->sc_evq_tail) : total; 487 1.1 tsubai 488 1.18 christos error = uiomove((void *) & aed_sc->sc_evq[aed_sc->sc_evq_tail], 489 1.1 tsubai firstmove * sizeof(adb_event_t), uio); 490 1.1 tsubai if (error) { 491 1.1 tsubai splx(s); 492 1.1 tsubai return (error); 493 1.1 tsubai } 494 1.1 tsubai moremove = total - firstmove; 495 1.1 tsubai 496 1.1 tsubai if (moremove > 0) { 497 1.18 christos error = uiomove((void *) & aed_sc->sc_evq[0], 498 1.1 tsubai moremove * sizeof(adb_event_t), uio); 499 1.1 tsubai if (error) { 500 1.1 tsubai splx(s); 501 1.1 tsubai return (error); 502 1.1 tsubai } 503 1.1 tsubai } 504 1.1 tsubai aed_sc->sc_evq_tail = (aed_sc->sc_evq_tail + total) % AED_MAX_EVENTS; 505 1.1 tsubai aed_sc->sc_evq_len -= total; 506 1.1 tsubai splx(s); 507 1.1 tsubai return (0); 508 1.1 tsubai } 509 1.1 tsubai 510 1.37 riastrad int 511 1.23 dsl aedioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 512 1.1 tsubai { 513 1.1 tsubai switch (cmd) { 514 1.1 tsubai case ADBIOCDEVSINFO: { 515 1.1 tsubai adb_devinfo_t *di; 516 1.1 tsubai ADBDataBlock adbdata; 517 1.1 tsubai int totaldevs; 518 1.1 tsubai int adbaddr; 519 1.1 tsubai int i; 520 1.1 tsubai 521 1.1 tsubai di = (void *)data; 522 1.1 tsubai 523 1.1 tsubai /* Initialize to no devices */ 524 1.1 tsubai for (i = 0; i < 16; i++) 525 1.1 tsubai di->dev[i].addr = -1; 526 1.1 tsubai 527 1.1 tsubai totaldevs = CountADBs(); 528 1.1 tsubai for (i = 1; i <= totaldevs; i++) { 529 1.1 tsubai adbaddr = GetIndADB(&adbdata, i); 530 1.1 tsubai di->dev[adbaddr].addr = adbaddr; 531 1.4 tsubai di->dev[adbaddr].default_addr = (int)(adbdata.origADBAddr); 532 1.4 tsubai di->dev[adbaddr].handler_id = (int)(adbdata.devType); 533 1.1 tsubai } 534 1.1 tsubai 535 1.1 tsubai /* Must call ADB Manager to get devices now */ 536 1.1 tsubai break; 537 1.1 tsubai } 538 1.1 tsubai 539 1.1 tsubai case ADBIOCGETREPEAT:{ 540 1.1 tsubai adb_rptinfo_t *ri; 541 1.1 tsubai 542 1.1 tsubai ri = (void *)data; 543 1.1 tsubai ri->delay_ticks = aed_sc->sc_rptdelay; 544 1.1 tsubai ri->interval_ticks = aed_sc->sc_rptinterval; 545 1.1 tsubai break; 546 1.1 tsubai } 547 1.1 tsubai 548 1.1 tsubai case ADBIOCSETREPEAT:{ 549 1.1 tsubai adb_rptinfo_t *ri; 550 1.1 tsubai 551 1.1 tsubai ri = (void *) data; 552 1.1 tsubai aed_sc->sc_rptdelay = ri->delay_ticks; 553 1.1 tsubai aed_sc->sc_rptinterval = ri->interval_ticks; 554 1.1 tsubai break; 555 1.1 tsubai } 556 1.1 tsubai 557 1.1 tsubai case ADBIOCRESET: 558 1.1 tsubai /* Do nothing for now */ 559 1.1 tsubai break; 560 1.1 tsubai 561 1.1 tsubai case ADBIOCLISTENCMD:{ 562 1.1 tsubai adb_listencmd_t *lc; 563 1.1 tsubai 564 1.1 tsubai lc = (void *)data; 565 1.1 tsubai } 566 1.1 tsubai 567 1.1 tsubai default: 568 1.1 tsubai return (EINVAL); 569 1.1 tsubai } 570 1.1 tsubai return (0); 571 1.1 tsubai } 572 1.1 tsubai 573 1.37 riastrad int 574 1.23 dsl aedpoll(dev_t dev, int events, struct lwp *l) 575 1.1 tsubai { 576 1.1 tsubai int s, revents; 577 1.1 tsubai 578 1.1 tsubai revents = events & (POLLOUT | POLLWRNORM); 579 1.37 riastrad 580 1.1 tsubai if ((events & (POLLIN | POLLRDNORM)) == 0) 581 1.1 tsubai return (revents); 582 1.1 tsubai 583 1.1 tsubai s = spladb(); 584 1.1 tsubai if (aed_sc->sc_evq_len > 0) 585 1.1 tsubai revents |= events & (POLLIN | POLLRDNORM); 586 1.1 tsubai else 587 1.16 christos selrecord(l, &aed_sc->sc_selinfo); 588 1.1 tsubai splx(s); 589 1.1 tsubai 590 1.1 tsubai return (revents); 591 1.10 jdolecek } 592 1.10 jdolecek 593 1.10 jdolecek static void 594 1.10 jdolecek filt_aedrdetach(struct knote *kn) 595 1.10 jdolecek { 596 1.10 jdolecek int s; 597 1.10 jdolecek 598 1.10 jdolecek s = spladb(); 599 1.31 thorpej selremove_knote(&aed_sc->sc_selinfo, kn); 600 1.10 jdolecek splx(s); 601 1.10 jdolecek } 602 1.10 jdolecek 603 1.10 jdolecek static int 604 1.10 jdolecek filt_aedread(struct knote *kn, long hint) 605 1.10 jdolecek { 606 1.10 jdolecek 607 1.10 jdolecek kn->kn_data = aed_sc->sc_evq_len * sizeof(adb_event_t); 608 1.10 jdolecek return (kn->kn_data > 0); 609 1.10 jdolecek } 610 1.10 jdolecek 611 1.30 maya static const struct filterops aedread_filtops = { 612 1.32 thorpej .f_flags = FILTEROP_ISFD, 613 1.30 maya .f_attach = NULL, 614 1.30 maya .f_detach = filt_aedrdetach, 615 1.30 maya .f_event = filt_aedread 616 1.30 maya }; 617 1.10 jdolecek 618 1.10 jdolecek int 619 1.10 jdolecek aedkqfilter(dev_t dev, struct knote *kn) 620 1.10 jdolecek { 621 1.10 jdolecek int s; 622 1.10 jdolecek 623 1.10 jdolecek switch (kn->kn_filter) { 624 1.10 jdolecek case EVFILT_READ: 625 1.10 jdolecek kn->kn_fop = &aedread_filtops; 626 1.33 thorpej s = spladb(); 627 1.33 thorpej selrecord_knote(&aed_sc->sc_selinfo, kn); 628 1.33 thorpej splx(s); 629 1.10 jdolecek break; 630 1.10 jdolecek 631 1.10 jdolecek case EVFILT_WRITE: 632 1.33 thorpej kn->kn_fop = &seltrue_filtops; 633 1.10 jdolecek break; 634 1.10 jdolecek 635 1.10 jdolecek default: 636 1.34 thorpej return (EINVAL); 637 1.10 jdolecek } 638 1.10 jdolecek 639 1.10 jdolecek return (0); 640 1.1 tsubai } 641