1 1.28 tsutsui /* $NetBSD: ms.c,v 1.28 2022/06/26 06:25:09 tsutsui Exp $ */ 2 1.1 leo 3 1.1 leo /* 4 1.1 leo * Copyright (c) 1995 Leo Weppelman. 5 1.1 leo * All rights reserved. 6 1.1 leo * 7 1.1 leo * based on: 8 1.1 leo * 9 1.1 leo * Copyright (c) 1992, 1993 10 1.1 leo * The Regents of the University of California. All rights reserved. 11 1.1 leo * 12 1.1 leo * This software was developed by the Computer Systems Engineering group 13 1.1 leo * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 14 1.1 leo * contributed to Berkeley. 15 1.1 leo * 16 1.1 leo * All advertising materials mentioning features or use of this software 17 1.1 leo * must display the following acknowledgement: 18 1.1 leo * This product includes software developed by the University of 19 1.1 leo * California, Lawrence Berkeley Laboratory. 20 1.1 leo * 21 1.1 leo * Redistribution and use in source and binary forms, with or without 22 1.1 leo * modification, are permitted provided that the following conditions 23 1.1 leo * are met: 24 1.1 leo * 1. Redistributions of source code must retain the above copyright 25 1.1 leo * notice, this list of conditions and the following disclaimer. 26 1.1 leo * 2. Redistributions in binary form must reproduce the above copyright 27 1.1 leo * notice, this list of conditions and the following disclaimer in the 28 1.1 leo * documentation and/or other materials provided with the distribution. 29 1.14 agc * 3. Neither the name of the University nor the names of its contributors 30 1.1 leo * may be used to endorse or promote products derived from this software 31 1.1 leo * without specific prior written permission. 32 1.1 leo * 33 1.1 leo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 34 1.1 leo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 35 1.1 leo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 36 1.1 leo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 37 1.1 leo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 38 1.1 leo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 39 1.1 leo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40 1.1 leo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 41 1.1 leo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 42 1.1 leo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 43 1.1 leo * SUCH DAMAGE. 44 1.1 leo * 45 1.1 leo * @(#)ms.c 8.1 (Berkeley) 6/11/93 46 1.1 leo * 47 1.1 leo * Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp (LBL) 48 1.1 leo */ 49 1.1 leo 50 1.1 leo /* 51 1.1 leo * Mouse driver. 52 1.1 leo */ 53 1.13 lukem 54 1.13 lukem #include <sys/cdefs.h> 55 1.28 tsutsui __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.28 2022/06/26 06:25:09 tsutsui Exp $"); 56 1.1 leo 57 1.1 leo #include <sys/param.h> 58 1.1 leo #include <sys/conf.h> 59 1.1 leo #include <sys/ioctl.h> 60 1.1 leo #include <sys/kernel.h> 61 1.1 leo #include <sys/proc.h> 62 1.1 leo #include <sys/systm.h> 63 1.10 thorpej #include <sys/callout.h> 64 1.1 leo #include <sys/tty.h> 65 1.4 leo #include <sys/signalvar.h> 66 1.1 leo 67 1.4 leo #include <machine/msioctl.h> 68 1.1 leo #include <atari/dev/event_var.h> 69 1.1 leo #include <atari/dev/vuid_event.h> 70 1.4 leo #include <atari/dev/kbdvar.h> 71 1.4 leo #include <atari/dev/msvar.h> 72 1.1 leo 73 1.1 leo #include "mouse.h" 74 1.1 leo #if NMOUSE > 0 75 1.1 leo 76 1.1 leo /* there's really no more physical ports on an atari. */ 77 1.1 leo #if NMOUSE > 1 78 1.1 leo #undef NMOUSE 79 1.1 leo #define NMOUSE 1 80 1.1 leo #endif 81 1.1 leo 82 1.27 tsutsui typedef void (*FPV)(void *); 83 1.1 leo 84 1.27 tsutsui static struct ms_softc ms_softc[NMOUSE]; 85 1.4 leo 86 1.28 tsutsui static dev_type_open(msopen); 87 1.28 tsutsui static dev_type_close(msclose); 88 1.28 tsutsui static dev_type_read(msread); 89 1.28 tsutsui static dev_type_ioctl(msioctl); 90 1.28 tsutsui static dev_type_poll(mspoll); 91 1.28 tsutsui static dev_type_kqfilter(mskqfilter); 92 1.11 gehenna 93 1.11 gehenna const struct cdevsw ms_cdevsw = { 94 1.25 dholland .d_open = msopen, 95 1.25 dholland .d_close = msclose, 96 1.25 dholland .d_read = msread, 97 1.25 dholland .d_write = nowrite, 98 1.25 dholland .d_ioctl = msioctl, 99 1.25 dholland .d_stop = nostop, 100 1.25 dholland .d_tty = notty, 101 1.25 dholland .d_poll = mspoll, 102 1.25 dholland .d_mmap = nommap, 103 1.25 dholland .d_kqfilter = mskqfilter, 104 1.26 dholland .d_discard = nodiscard, 105 1.25 dholland .d_flag = 0 106 1.11 gehenna }; 107 1.1 leo 108 1.27 tsutsui static void ms_3b_delay(struct ms_softc *); 109 1.3 leo 110 1.3 leo int 111 1.23 dsl mouseattach(int cnt) 112 1.3 leo { 113 1.27 tsutsui 114 1.9 christos printf("1 mouse configured\n"); 115 1.5 leo ms_softc[0].ms_emul3b = 1; 116 1.18 he callout_init(&ms_softc[0].ms_delay_ch, 0); 117 1.27 tsutsui 118 1.27 tsutsui return NMOUSE; 119 1.3 leo } 120 1.3 leo 121 1.3 leo static void 122 1.23 dsl ms_3b_delay(struct ms_softc *ms) 123 1.3 leo { 124 1.27 tsutsui REL_MOUSE rel_ms; 125 1.3 leo 126 1.3 leo rel_ms.id = TIMEOUT_ID; 127 1.3 leo rel_ms.dx = rel_ms.dy = 0; 128 1.4 leo mouse_soft(&rel_ms, sizeof(rel_ms), KBD_TIMEO_PKG); 129 1.3 leo } 130 1.27 tsutsui /* 131 1.1 leo * Note that we are called from the keyboard software interrupt! 132 1.1 leo */ 133 1.1 leo void 134 1.24 dsl mouse_soft(REL_MOUSE *rel_ms, int size, int type) 135 1.1 leo { 136 1.27 tsutsui struct ms_softc *ms = &ms_softc[0]; 137 1.27 tsutsui struct firm_event *fe, *fe2; 138 1.27 tsutsui REL_MOUSE fake_mouse; 139 1.27 tsutsui int get, put; 140 1.27 tsutsui int s; 141 1.27 tsutsui uint8_t mbut, bmask; 142 1.27 tsutsui int flush_buttons; 143 1.1 leo 144 1.1 leo if (ms->ms_events.ev_io == NULL) 145 1.1 leo return; 146 1.1 leo 147 1.4 leo switch (type) { 148 1.27 tsutsui case KBD_JOY1_PKG: 149 1.6 leo /* 150 1.6 leo * Ignore if in emulation mode 151 1.6 leo */ 152 1.6 leo if (ms->ms_emul3b) 153 1.6 leo return; 154 1.6 leo 155 1.4 leo /* 156 1.4 leo * There are some mice that have their middle button 157 1.4 leo * wired to the 'up' bit of joystick 1.... 158 1.4 leo * Simulate a mouse packet with dx = dy = 0, the middle 159 1.4 leo * button state set by UP and the other buttons unchanged. 160 1.4 leo * Flush all button changes. 161 1.4 leo */ 162 1.4 leo flush_buttons = 1; 163 1.27 tsutsui fake_mouse.id = ((rel_ms->dx & 0x01) != 0 ? 0x04 : 0x00) | 164 1.27 tsutsui (ms->ms_buttons & 0x03); 165 1.4 leo fake_mouse.dx = fake_mouse.dy = 0; 166 1.4 leo rel_ms = &fake_mouse; 167 1.4 leo break; 168 1.27 tsutsui case KBD_TIMEO_PKG: 169 1.4 leo /* 170 1.4 leo * Timeout package. No button changes and no movement. 171 1.4 leo * Flush all button changes. 172 1.4 leo */ 173 1.4 leo flush_buttons = 1; 174 1.4 leo fake_mouse.id = ms->ms_buttons; 175 1.4 leo fake_mouse.dx = fake_mouse.dy = 0; 176 1.4 leo rel_ms = &fake_mouse; 177 1.4 leo break; 178 1.27 tsutsui case KBD_RMS_PKG: 179 1.4 leo /* 180 1.4 leo * Normal mouse package. Always copy the middle button 181 1.4 leo * status. The emulation code decides if button changes 182 1.4 leo * must be flushed. 183 1.4 leo */ 184 1.27 tsutsui rel_ms->id = (ms->ms_buttons & 0x04) | (rel_ms->id & 0x03); 185 1.27 tsutsui flush_buttons = ms->ms_emul3b ? 0 : 1; 186 1.4 leo break; 187 1.27 tsutsui default: 188 1.4 leo return; 189 1.4 leo } 190 1.4 leo 191 1.27 tsutsui s = splev(); 192 1.1 leo get = ms->ms_events.ev_get; 193 1.1 leo put = ms->ms_events.ev_put; 194 1.1 leo fe = &ms->ms_events.ev_q[put]; 195 1.1 leo 196 1.27 tsutsui if ((type != KBD_TIMEO_PKG) && ms->ms_emul3b && ms->ms_bq_idx != 0) 197 1.10 thorpej callout_stop(&ms->ms_delay_ch); 198 1.3 leo 199 1.1 leo /* 200 1.4 leo * Button states are encoded in the lower 3 bits of 'id' 201 1.1 leo */ 202 1.27 tsutsui if ((mbut = (rel_ms->id ^ ms->ms_buttons)) == 0 && (put != get)) { 203 1.1 leo /* 204 1.1 leo * Compact dx/dy messages. Always generate an event when 205 1.1 leo * a button is pressed or the event queue is empty. 206 1.1 leo */ 207 1.1 leo ms->ms_dx += rel_ms->dx; 208 1.1 leo ms->ms_dy += rel_ms->dy; 209 1.1 leo goto out; 210 1.1 leo } 211 1.1 leo rel_ms->dx += ms->ms_dx; 212 1.1 leo rel_ms->dy += ms->ms_dy; 213 1.1 leo ms->ms_dx = ms->ms_dy = 0; 214 1.1 leo 215 1.1 leo /* 216 1.1 leo * Output location events _before_ button events ie. make sure 217 1.1 leo * the button is pressed at the correct location. 218 1.1 leo */ 219 1.27 tsutsui if (rel_ms->dx != 0) { 220 1.1 leo if ((++put) % EV_QSIZE == get) { 221 1.1 leo put--; 222 1.1 leo goto out; 223 1.1 leo } 224 1.1 leo fe->id = LOC_X_DELTA; 225 1.1 leo fe->value = rel_ms->dx; 226 1.21 tsutsui firm_gettime(fe); 227 1.1 leo if (put >= EV_QSIZE) { 228 1.1 leo put = 0; 229 1.1 leo fe = &ms->ms_events.ev_q[0]; 230 1.27 tsutsui } else { 231 1.27 tsutsui fe++; 232 1.1 leo } 233 1.1 leo } 234 1.27 tsutsui if (rel_ms->dy != 0) { 235 1.1 leo if ((++put) % EV_QSIZE == get) { 236 1.1 leo put--; 237 1.1 leo goto out; 238 1.1 leo } 239 1.1 leo fe->id = LOC_Y_DELTA; 240 1.1 leo fe->value = rel_ms->dy; 241 1.21 tsutsui firm_gettime(fe); 242 1.1 leo if (put >= EV_QSIZE) { 243 1.1 leo put = 0; 244 1.1 leo fe = &ms->ms_events.ev_q[0]; 245 1.27 tsutsui } else { 246 1.27 tsutsui fe++; 247 1.1 leo } 248 1.1 leo } 249 1.27 tsutsui if (mbut != 0 && (type != KBD_TIMEO_PKG)) { 250 1.27 tsutsui for (bmask = 0x01; bmask < 0x08; bmask <<= 1) { 251 1.27 tsutsui if ((mbut & bmask) == 0) 252 1.1 leo continue; 253 1.3 leo fe2 = &ms->ms_bq[ms->ms_bq_idx++]; 254 1.27 tsutsui if (bmask == 0x01) 255 1.4 leo fe2->id = MS_RIGHT; 256 1.27 tsutsui else if (bmask == 0x02) 257 1.4 leo fe2->id = MS_LEFT; 258 1.27 tsutsui else 259 1.27 tsutsui fe2->id = MS_MIDDLE; 260 1.27 tsutsui fe2->value = 261 1.27 tsutsui (rel_ms->id & bmask) != 0 ? VKEY_DOWN : VKEY_UP; 262 1.21 tsutsui firm_gettime(fe2); 263 1.3 leo } 264 1.3 leo } 265 1.4 leo 266 1.4 leo /* 267 1.4 leo * Handle 3rd button emulation. 268 1.4 leo */ 269 1.27 tsutsui if (ms->ms_emul3b && ms->ms_bq_idx != 0 && (type != KBD_TIMEO_PKG)) { 270 1.3 leo /* 271 1.4 leo * If the middle button is pressed, any change to 272 1.4 leo * one of the other buttons releases all. 273 1.3 leo */ 274 1.27 tsutsui if ((ms->ms_buttons & 0x04) != 0 && (mbut & 0x03) != 0) { 275 1.4 leo ms->ms_bq[0].id = MS_MIDDLE; 276 1.4 leo ms->ms_bq_idx = 1; 277 1.4 leo rel_ms->id = 0; 278 1.4 leo flush_buttons = 1; 279 1.4 leo goto out; 280 1.4 leo } 281 1.27 tsutsui if (ms->ms_bq_idx == 2) { 282 1.3 leo if (ms->ms_bq[0].value == ms->ms_bq[1].value) { 283 1.3 leo /* Must be 2 button presses! */ 284 1.4 leo ms->ms_bq[0].id = MS_MIDDLE; 285 1.4 leo ms->ms_bq_idx = 1; 286 1.4 leo rel_ms->id = 7; 287 1.3 leo } 288 1.3 leo } 289 1.4 leo else if (ms->ms_bq[0].value == VKEY_DOWN) { 290 1.10 thorpej callout_reset(&ms->ms_delay_ch, 10, 291 1.10 thorpej (FPV)ms_3b_delay, (void *)ms); 292 1.4 leo goto out; 293 1.4 leo } 294 1.4 leo flush_buttons = 1; 295 1.4 leo } 296 1.27 tsutsui out: 297 1.4 leo if (flush_buttons) { 298 1.27 tsutsui int i; 299 1.4 leo 300 1.4 leo for (i = 0; i < ms->ms_bq_idx; i++) { 301 1.4 leo if ((++put) % EV_QSIZE == get) { 302 1.4 leo ms->ms_bq_idx = 0; 303 1.4 leo put--; 304 1.1 leo goto out; 305 1.1 leo } 306 1.4 leo *fe = ms->ms_bq[i]; 307 1.4 leo if (put >= EV_QSIZE) { 308 1.4 leo put = 0; 309 1.4 leo fe = &ms->ms_events.ev_q[0]; 310 1.27 tsutsui } else { 311 1.27 tsutsui fe++; 312 1.1 leo } 313 1.1 leo } 314 1.4 leo ms->ms_bq_idx = 0; 315 1.1 leo } 316 1.1 leo ms->ms_events.ev_put = put; 317 1.4 leo ms->ms_buttons = rel_ms->id; 318 1.27 tsutsui splx(s); 319 1.1 leo EV_WAKEUP(&ms->ms_events); 320 1.1 leo } 321 1.1 leo 322 1.28 tsutsui static int 323 1.24 dsl msopen(dev_t dev, int flags, int mode, struct lwp *l) 324 1.1 leo { 325 1.27 tsutsui uint8_t report_ms_joy[] = { 0x14, 0x08 }; 326 1.27 tsutsui struct ms_softc *ms; 327 1.27 tsutsui int unit; 328 1.1 leo 329 1.1 leo unit = minor(dev); 330 1.1 leo ms = &ms_softc[unit]; 331 1.1 leo 332 1.1 leo if (unit >= NMOUSE) 333 1.27 tsutsui return EXDEV; 334 1.1 leo 335 1.1 leo if (ms->ms_events.ev_io) 336 1.27 tsutsui return EBUSY; 337 1.1 leo 338 1.16 christos ms->ms_events.ev_io = l->l_proc; 339 1.1 leo ms->ms_dx = ms->ms_dy = 0; 340 1.3 leo ms->ms_buttons = 0; 341 1.3 leo ms->ms_bq[0].id = ms->ms_bq[1].id = 0; 342 1.3 leo ms->ms_bq_idx = 0; 343 1.1 leo ev_init(&ms->ms_events); /* may cause sleep */ 344 1.1 leo 345 1.1 leo /* 346 1.1 leo * Enable mouse reporting. 347 1.1 leo */ 348 1.4 leo kbd_write(report_ms_joy, sizeof(report_ms_joy)); 349 1.27 tsutsui return 0; 350 1.1 leo } 351 1.1 leo 352 1.28 tsutsui static int 353 1.24 dsl msclose(dev_t dev, int flags, int mode, struct lwp *l) 354 1.1 leo { 355 1.27 tsutsui uint8_t disable_ms_joy[] = { 0x12, 0x1a }; 356 1.27 tsutsui int unit; 357 1.27 tsutsui struct ms_softc *ms; 358 1.1 leo 359 1.27 tsutsui unit = minor(dev); 360 1.1 leo ms = &ms_softc[unit]; 361 1.1 leo 362 1.1 leo /* 363 1.1 leo * Turn off mouse interrogation. 364 1.1 leo */ 365 1.4 leo kbd_write(disable_ms_joy, sizeof(disable_ms_joy)); 366 1.1 leo ev_fini(&ms->ms_events); 367 1.1 leo ms->ms_events.ev_io = NULL; 368 1.27 tsutsui return 0; 369 1.1 leo } 370 1.1 leo 371 1.28 tsutsui static int 372 1.23 dsl msread(dev_t dev, struct uio *uio, int flags) 373 1.1 leo { 374 1.1 leo struct ms_softc *ms; 375 1.1 leo 376 1.1 leo ms = &ms_softc[minor(dev)]; 377 1.27 tsutsui return ev_read(&ms->ms_events, uio, flags); 378 1.1 leo } 379 1.1 leo 380 1.28 tsutsui static int 381 1.23 dsl msioctl(dev_t dev, u_long cmd, register void * data, int flag, struct lwp *l) 382 1.1 leo { 383 1.1 leo struct ms_softc *ms; 384 1.27 tsutsui int unit; 385 1.1 leo 386 1.1 leo unit = minor(dev); 387 1.1 leo ms = &ms_softc[unit]; 388 1.1 leo 389 1.1 leo switch (cmd) { 390 1.27 tsutsui case MIOCS3B_EMUL: 391 1.4 leo ms->ms_emul3b = (*(int *)data != 0) ? 1 : 0; 392 1.27 tsutsui return 0; 393 1.27 tsutsui case MIOCG3B_EMUL: 394 1.4 leo *(int *)data = ms->ms_emul3b; 395 1.27 tsutsui return 0; 396 1.1 leo case FIONBIO: /* we will remove this someday (soon???) */ 397 1.27 tsutsui return 0; 398 1.1 leo case FIOASYNC: 399 1.1 leo ms->ms_events.ev_async = *(int *)data != 0; 400 1.27 tsutsui return 0; 401 1.15 jdolecek case FIOSETOWN: 402 1.27 tsutsui if (-*(int *)data != ms->ms_events.ev_io->p_pgid && 403 1.27 tsutsui *(int *)data != ms->ms_events.ev_io->p_pid) 404 1.27 tsutsui return EPERM; 405 1.27 tsutsui return 0; 406 1.1 leo case TIOCSPGRP: 407 1.1 leo if (*(int *)data != ms->ms_events.ev_io->p_pgid) 408 1.27 tsutsui return EPERM; 409 1.27 tsutsui return 0; 410 1.1 leo case VUIDGFORMAT: /* we only do firm_events */ 411 1.1 leo *(int *)data = VUID_FIRM_EVENT; 412 1.27 tsutsui return 0; 413 1.1 leo case VUIDSFORMAT: 414 1.1 leo if (*(int *)data != VUID_FIRM_EVENT) 415 1.27 tsutsui return EINVAL; 416 1.27 tsutsui return 0; 417 1.1 leo } 418 1.27 tsutsui return ENOTTY; 419 1.1 leo } 420 1.1 leo 421 1.28 tsutsui static int 422 1.23 dsl mspoll(dev_t dev, int events, struct lwp *l) 423 1.1 leo { 424 1.1 leo struct ms_softc *ms; 425 1.1 leo 426 1.1 leo ms = &ms_softc[minor(dev)]; 427 1.27 tsutsui return ev_poll(&ms->ms_events, events, l); 428 1.12 jdolecek } 429 1.12 jdolecek 430 1.28 tsutsui static int 431 1.12 jdolecek mskqfilter(dev_t dev, struct knote *kn) 432 1.12 jdolecek { 433 1.12 jdolecek struct ms_softc *ms; 434 1.12 jdolecek 435 1.12 jdolecek ms = &ms_softc[minor(dev)]; 436 1.27 tsutsui return ev_kqfilter(&ms->ms_events, kn); 437 1.1 leo } 438 1.1 leo #endif /* NMOUSE > 0 */ 439