mse.c revision 66860
1/* 2 * Copyright 1992 by the University of Guelph 3 * 4 * Permission to use, copy and modify this 5 * software and its documentation for any purpose and without 6 * fee is hereby granted, provided that the above copyright 7 * notice appear in all copies and that both that copyright 8 * notice and this permission notice appear in supporting 9 * documentation. 10 * University of Guelph makes no representations about the suitability of 11 * this software for any purpose. It is provided "as is" 12 * without express or implied warranty. 13 * 14 * $FreeBSD: head/sys/dev/mse/mse.c 66860 2000-10-09 08:08:36Z phk $ 15 */ 16/* 17 * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 18 * the X386 port, courtesy of 19 * Rick Macklem, rick@snowhite.cis.uoguelph.ca 20 * Caveats: The driver currently uses spltty(), but doesn't use any 21 * generic tty code. It could use splmse() (that only masks off the 22 * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 23 * (This may be worth the effort, since the Logitech generates 30/60 24 * interrupts/sec continuously while it is open.) 25 * NB: The ATI has NOT been tested yet! 26 */ 27 28/* 29 * Modification history: 30 * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 31 * improved probe based on input from Logitech. 32 * 33 * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 34 * fixes to make it work with Microsoft InPort busmouse 35 * 36 * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 37 * added patches for new "select" interface 38 * 39 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 40 * changed position of some spl()'s in mseread 41 * 42 * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 43 * limit maximum negative x/y value to -127 to work around XFree problem 44 * that causes spurious button pushes. 45 */ 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/conf.h> 50#include <sys/kernel.h> 51#include <sys/bus.h> 52#include <sys/poll.h> 53#include <sys/select.h> 54#include <sys/uio.h> 55#include <sys/mouse.h> 56 57#include <machine/bus_pio.h> 58#include <machine/bus.h> 59#include <machine/clock.h> 60#include <machine/resource.h> 61#include <sys/rman.h> 62 63#include <isa/isavar.h> 64 65/* driver configuration flags (config) */ 66#define MSE_CONFIG_ACCEL 0x00f0 /* acceleration factor */ 67#define MSE_CONFIG_FLAGS (MSE_CONFIG_ACCEL) 68 69/* 70 * Software control structure for mouse. The sc_enablemouse(), 71 * sc_disablemouse() and sc_getmouse() routines must be called spl'd(). 72 */ 73typedef struct mse_softc { 74 int sc_flags; 75 int sc_mousetype; 76 struct selinfo sc_selp; 77 struct resource *sc_port; 78 struct resource *sc_intr; 79 bus_space_tag_t sc_iot; 80 bus_space_handle_t sc_ioh; 81 void *sc_ih; 82 void (*sc_enablemouse) __P((bus_space_tag_t t, 83 bus_space_handle_t h)); 84 void (*sc_disablemouse) __P((bus_space_tag_t t, 85 bus_space_handle_t h)); 86 void (*sc_getmouse) __P((bus_space_tag_t t, 87 bus_space_handle_t h, 88 int *dx, int *dy, int *but)); 89 int sc_deltax; 90 int sc_deltay; 91 int sc_obuttons; 92 int sc_buttons; 93 int sc_bytesread; 94 u_char sc_bytes[MOUSE_SYS_PACKETSIZE]; 95 struct callout_handle sc_callout; 96 int sc_watchdog; 97 dev_t sc_dev; 98 dev_t sc_ndev; 99 mousehw_t hw; 100 mousemode_t mode; 101 mousestatus_t status; 102} mse_softc_t; 103 104static devclass_t mse_devclass; 105 106static int mse_probe __P((device_t dev)); 107static int mse_attach __P((device_t dev)); 108static int mse_detach __P((device_t dev)); 109 110static device_method_t mse_methods[] = { 111 DEVMETHOD(device_probe, mse_probe), 112 DEVMETHOD(device_attach, mse_attach), 113 DEVMETHOD(device_detach, mse_detach), 114 { 0, 0 } 115}; 116 117static driver_t mse_driver = { 118 "mse", 119 mse_methods, 120 sizeof(mse_softc_t), 121}; 122 123DRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 124 125static struct isa_pnp_id mse_ids[] = { 126 { 0x000fd041, "Bus mouse" }, /* PNP0F00 */ 127 { 0x020fd041, "InPort mouse" }, /* PNP0F02 */ 128 { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */ 129 { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */ 130 { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */ 131 { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */ 132 { 0 } 133}; 134 135static d_open_t mseopen; 136static d_close_t mseclose; 137static d_read_t mseread; 138static d_ioctl_t mseioctl; 139static d_poll_t msepoll; 140 141#define CDEV_MAJOR 27 142static struct cdevsw mse_cdevsw = { 143 /* open */ mseopen, 144 /* close */ mseclose, 145 /* read */ mseread, 146 /* write */ nowrite, 147 /* ioctl */ mseioctl, 148 /* poll */ msepoll, 149 /* mmap */ nommap, 150 /* strategy */ nostrategy, 151 /* name */ "mse", 152 /* maj */ CDEV_MAJOR, 153 /* dump */ nodump, 154 /* psize */ nopsize, 155 /* flags */ 0, 156 /* bmaj */ -1 157}; 158 159static void mseintr __P((void *)); 160static timeout_t msetimeout; 161 162/* Flags */ 163#define MSESC_OPEN 0x1 164#define MSESC_WANT 0x2 165 166/* and Mouse Types */ 167#define MSE_NONE 0 /* don't move this! */ 168#define MSE_LOGITECH 0x1 169#define MSE_ATIINPORT 0x2 170#define MSE_LOGI_SIG 0xA5 171 172#define MSE_PORTA 0 173#define MSE_PORTB 1 174#define MSE_PORTC 2 175#define MSE_PORTD 3 176#define MSE_IOSIZE 4 177 178#define MSE_UNIT(dev) (minor(dev) >> 1) 179#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 180 181/* 182 * Logitech bus mouse definitions 183 */ 184#define MSE_SETUP 0x91 /* What does this mean? */ 185 /* The definition for the control port */ 186 /* is as follows: */ 187 188 /* D7 = Mode set flag (1 = active) */ 189 /* D6,D5 = Mode selection (port A) */ 190 /* 00 = Mode 0 = Basic I/O */ 191 /* 01 = Mode 1 = Strobed I/O */ 192 /* 10 = Mode 2 = Bi-dir bus */ 193 /* D4 = Port A direction (1 = input)*/ 194 /* D3 = Port C (upper 4 bits) */ 195 /* direction. (1 = input) */ 196 /* D2 = Mode selection (port B & C) */ 197 /* 0 = Mode 0 = Basic I/O */ 198 /* 1 = Mode 1 = Strobed I/O */ 199 /* D1 = Port B direction (1 = input)*/ 200 /* D0 = Port C (lower 4 bits) */ 201 /* direction. (1 = input) */ 202 203 /* So 91 means Basic I/O on all 3 ports,*/ 204 /* Port A is an input port, B is an */ 205 /* output port, C is split with upper */ 206 /* 4 bits being an output port and lower*/ 207 /* 4 bits an input port, and enable the */ 208 /* sucker. */ 209 /* Courtesy Intel 8255 databook. Lars */ 210#define MSE_HOLD 0x80 211#define MSE_RXLOW 0x00 212#define MSE_RXHIGH 0x20 213#define MSE_RYLOW 0x40 214#define MSE_RYHIGH 0x60 215#define MSE_DISINTR 0x10 216#define MSE_INTREN 0x00 217 218static int mse_probelogi __P((device_t dev, mse_softc_t *sc)); 219static void mse_disablelogi __P((bus_space_tag_t t, 220 bus_space_handle_t h)); 221static void mse_getlogi __P((bus_space_tag_t t, 222 bus_space_handle_t h, 223 int *dx, int *dy, int *but)); 224static void mse_enablelogi __P((bus_space_tag_t t, 225 bus_space_handle_t h)); 226 227/* 228 * ATI Inport mouse definitions 229 */ 230#define MSE_INPORT_RESET 0x80 231#define MSE_INPORT_STATUS 0x00 232#define MSE_INPORT_DX 0x01 233#define MSE_INPORT_DY 0x02 234#define MSE_INPORT_MODE 0x07 235#define MSE_INPORT_HOLD 0x20 236#define MSE_INPORT_INTREN 0x09 237 238static int mse_probeati __P((device_t dev, mse_softc_t *sc)); 239static void mse_enableati __P((bus_space_tag_t t, 240 bus_space_handle_t h)); 241static void mse_disableati __P((bus_space_tag_t t, 242 bus_space_handle_t h)); 243static void mse_getati __P((bus_space_tag_t t, 244 bus_space_handle_t h, 245 int *dx, int *dy, int *but)); 246 247#define MSEPRI (PZERO + 3) 248 249/* 250 * Table of mouse types. 251 * Keep the Logitech last, since I haven't figured out how to probe it 252 * properly yet. (Someday I'll have the documentation.) 253 */ 254static struct mse_types { 255 int m_type; /* Type of bus mouse */ 256 int (*m_probe) __P((device_t dev, mse_softc_t *sc)); 257 /* Probe routine to test for it */ 258 void (*m_enable) __P((bus_space_tag_t t, bus_space_handle_t h)); 259 /* Start routine */ 260 void (*m_disable) __P((bus_space_tag_t t, bus_space_handle_t h)); 261 /* Disable interrupts routine */ 262 void (*m_get) __P((bus_space_tag_t t, bus_space_handle_t h, 263 int *dx, int *dy, int *but)); 264 /* and get mouse status */ 265 mousehw_t m_hw; /* buttons iftype type model hwid */ 266 mousemode_t m_mode; /* proto rate res accel level size mask */ 267} mse_types[] = { 268 { MSE_ATIINPORT, 269 mse_probeati, mse_enableati, mse_disableati, mse_getati, 270 { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 271 { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 272 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 273 { MSE_LOGITECH, 274 mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 275 { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 276 { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 277 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 278 { 0, }, 279}; 280 281static int 282mse_probe(dev) 283 device_t dev; 284{ 285 mse_softc_t *sc; 286 int error; 287 int rid; 288 int i; 289 290 /* check PnP IDs */ 291 error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 292 if (error == ENXIO) 293 return ENXIO; 294 295 sc = device_get_softc(dev); 296 rid = 0; 297 sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 298 MSE_IOSIZE, RF_ACTIVE); 299 if (sc->sc_port == NULL) 300 return ENXIO; 301 sc->sc_iot = rman_get_bustag(sc->sc_port); 302 sc->sc_ioh = rman_get_bushandle(sc->sc_port); 303 304 /* 305 * Check for each mouse type in the table. 306 */ 307 i = 0; 308 while (mse_types[i].m_type) { 309 if ((*mse_types[i].m_probe)(dev, sc)) { 310 sc->sc_mousetype = mse_types[i].m_type; 311 sc->sc_enablemouse = mse_types[i].m_enable; 312 sc->sc_disablemouse = mse_types[i].m_disable; 313 sc->sc_getmouse = mse_types[i].m_get; 314 sc->hw = mse_types[i].m_hw; 315 sc->mode = mse_types[i].m_mode; 316 bus_release_resource(dev, SYS_RES_IOPORT, rid, 317 sc->sc_port); 318 device_set_desc(dev, "Bus/InPort Mouse"); 319 return 0; 320 } 321 i++; 322 } 323 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 324 return ENXIO; 325} 326 327static int 328mse_attach(dev) 329 device_t dev; 330{ 331 mse_softc_t *sc; 332 int flags; 333 int unit; 334 int rid; 335 336 sc = device_get_softc(dev); 337 unit = device_get_unit(dev); 338 339 rid = 0; 340 sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 341 MSE_IOSIZE, RF_ACTIVE); 342 if (sc->sc_port == NULL) 343 return ENXIO; 344 sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 345 RF_ACTIVE); 346 if (sc->sc_intr == NULL) { 347 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 348 return ENXIO; 349 } 350 sc->sc_iot = rman_get_bustag(sc->sc_port); 351 sc->sc_ioh = rman_get_bushandle(sc->sc_port); 352 353 if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr, 354 INTR_TYPE_TTY, mseintr, sc, &sc->sc_ih)) { 355 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 356 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 357 return ENXIO; 358 } 359 360 flags = device_get_flags(dev); 361 sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4; 362 callout_handle_init(&sc->sc_callout); 363 364 sc->sc_dev = make_dev(&mse_cdevsw, unit << 1, 0, 0, 0600, 365 "mse%d", unit); 366 sc->sc_ndev = make_dev(&mse_cdevsw, (unit<<1)+1, 0, 0, 0600, 367 "nmse%d", unit); 368 369 return 0; 370} 371 372static int 373mse_detach(dev) 374 device_t dev; 375{ 376 mse_softc_t *sc; 377 int rid; 378 379 sc = device_get_softc(dev); 380 if (sc->sc_flags & MSESC_OPEN) 381 return EBUSY; 382 383 rid = 0; 384 BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 385 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 386 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 387 388 destroy_dev(sc->sc_dev); 389 destroy_dev(sc->sc_ndev); 390 391 return 0; 392} 393 394/* 395 * Exclusive open the mouse, initialize it and enable interrupts. 396 */ 397static int 398mseopen(dev, flags, fmt, p) 399 dev_t dev; 400 int flags; 401 int fmt; 402 struct proc *p; 403{ 404 mse_softc_t *sc; 405 int s; 406 407 sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 408 if (sc == NULL) 409 return (ENXIO); 410 if (sc->sc_mousetype == MSE_NONE) 411 return (ENXIO); 412 if (sc->sc_flags & MSESC_OPEN) 413 return (EBUSY); 414 sc->sc_flags |= MSESC_OPEN; 415 sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS; 416 sc->sc_deltax = sc->sc_deltay = 0; 417 sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE; 418 sc->sc_watchdog = FALSE; 419 sc->sc_callout = timeout(msetimeout, dev, hz*2); 420 sc->mode.level = 0; 421 sc->status.flags = 0; 422 sc->status.button = sc->status.obutton = 0; 423 sc->status.dx = sc->status.dy = sc->status.dz = 0; 424 425 /* 426 * Initialize mouse interface and enable interrupts. 427 */ 428 s = spltty(); 429 (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh); 430 splx(s); 431 return (0); 432} 433 434/* 435 * mseclose: just turn off mouse innterrupts. 436 */ 437static int 438mseclose(dev, flags, fmt, p) 439 dev_t dev; 440 int flags; 441 int fmt; 442 struct proc *p; 443{ 444 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 445 int s; 446 447 untimeout(msetimeout, dev, sc->sc_callout); 448 callout_handle_init(&sc->sc_callout); 449 s = spltty(); 450 (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh); 451 sc->sc_flags &= ~MSESC_OPEN; 452 splx(s); 453 return(0); 454} 455 456/* 457 * mseread: return mouse info using the MSC serial protocol, but without 458 * using bytes 4 and 5. 459 * (Yes this is cheesy, but it makes the X386 server happy, so...) 460 */ 461static int 462mseread(dev, uio, ioflag) 463 dev_t dev; 464 struct uio *uio; 465 int ioflag; 466{ 467 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 468 int xfer, s, error; 469 470 /* 471 * If there are no protocol bytes to be read, set up a new protocol 472 * packet. 473 */ 474 s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 475 if (sc->sc_bytesread >= sc->mode.packetsize) { 476 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 477 (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 478 if (MSE_NBLOCKIO(dev)) { 479 splx(s); 480 return (0); 481 } 482 sc->sc_flags |= MSESC_WANT; 483 error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 484 "mseread", 0); 485 if (error) { 486 splx(s); 487 return (error); 488 } 489 } 490 491 /* 492 * Generate protocol bytes. 493 * For some reason X386 expects 5 bytes but never uses 494 * the fourth or fifth? 495 */ 496 sc->sc_bytes[0] = sc->mode.syncmask[1] 497 | (sc->sc_buttons & ~sc->mode.syncmask[0]); 498 if (sc->sc_deltax > 127) 499 sc->sc_deltax = 127; 500 if (sc->sc_deltax < -127) 501 sc->sc_deltax = -127; 502 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 503 if (sc->sc_deltay > 127) 504 sc->sc_deltay = 127; 505 if (sc->sc_deltay < -127) 506 sc->sc_deltay = -127; 507 sc->sc_bytes[1] = sc->sc_deltax; 508 sc->sc_bytes[2] = sc->sc_deltay; 509 sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 510 sc->sc_bytes[5] = sc->sc_bytes[6] = 0; 511 sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS; 512 sc->sc_obuttons = sc->sc_buttons; 513 sc->sc_deltax = sc->sc_deltay = 0; 514 sc->sc_bytesread = 0; 515 } 516 splx(s); 517 xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread); 518 error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio); 519 if (error) 520 return (error); 521 sc->sc_bytesread += xfer; 522 return(0); 523} 524 525/* 526 * mseioctl: process ioctl commands. 527 */ 528static int 529mseioctl(dev, cmd, addr, flag, p) 530 dev_t dev; 531 u_long cmd; 532 caddr_t addr; 533 int flag; 534 struct proc *p; 535{ 536 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 537 mousestatus_t status; 538 int err = 0; 539 int s; 540 541 switch (cmd) { 542 543 case MOUSE_GETHWINFO: 544 s = spltty(); 545 *(mousehw_t *)addr = sc->hw; 546 if (sc->mode.level == 0) 547 ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 548 splx(s); 549 break; 550 551 case MOUSE_GETMODE: 552 s = spltty(); 553 *(mousemode_t *)addr = sc->mode; 554 switch (sc->mode.level) { 555 case 0: 556 break; 557 case 1: 558 ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 559 ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 560 ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 561 break; 562 } 563 splx(s); 564 break; 565 566 case MOUSE_SETMODE: 567 switch (((mousemode_t *)addr)->level) { 568 case 0: 569 case 1: 570 break; 571 default: 572 return (EINVAL); 573 } 574 if (((mousemode_t *)addr)->accelfactor < -1) 575 return (EINVAL); 576 else if (((mousemode_t *)addr)->accelfactor >= 0) 577 sc->mode.accelfactor = 578 ((mousemode_t *)addr)->accelfactor; 579 sc->mode.level = ((mousemode_t *)addr)->level; 580 switch (sc->mode.level) { 581 case 0: 582 sc->sc_bytesread = sc->mode.packetsize 583 = MOUSE_MSC_PACKETSIZE; 584 break; 585 case 1: 586 sc->sc_bytesread = sc->mode.packetsize 587 = MOUSE_SYS_PACKETSIZE; 588 break; 589 } 590 break; 591 592 case MOUSE_GETLEVEL: 593 *(int *)addr = sc->mode.level; 594 break; 595 596 case MOUSE_SETLEVEL: 597 switch (*(int *)addr) { 598 case 0: 599 sc->mode.level = *(int *)addr; 600 sc->sc_bytesread = sc->mode.packetsize 601 = MOUSE_MSC_PACKETSIZE; 602 break; 603 case 1: 604 sc->mode.level = *(int *)addr; 605 sc->sc_bytesread = sc->mode.packetsize 606 = MOUSE_SYS_PACKETSIZE; 607 break; 608 default: 609 return (EINVAL); 610 } 611 break; 612 613 case MOUSE_GETSTATUS: 614 s = spltty(); 615 status = sc->status; 616 sc->status.flags = 0; 617 sc->status.obutton = sc->status.button; 618 sc->status.button = 0; 619 sc->status.dx = 0; 620 sc->status.dy = 0; 621 sc->status.dz = 0; 622 splx(s); 623 *(mousestatus_t *)addr = status; 624 break; 625 626 case MOUSE_READSTATE: 627 case MOUSE_READDATA: 628 return (ENODEV); 629 630#if (defined(MOUSE_GETVARS)) 631 case MOUSE_GETVARS: 632 case MOUSE_SETVARS: 633 return (ENODEV); 634#endif 635 636 default: 637 return (ENOTTY); 638 } 639 return (err); 640} 641 642/* 643 * msepoll: check for mouse input to be processed. 644 */ 645static int 646msepoll(dev, events, p) 647 dev_t dev; 648 int events; 649 struct proc *p; 650{ 651 mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 652 int s; 653 int revents = 0; 654 655 s = spltty(); 656 if (events & (POLLIN | POLLRDNORM)) { 657 if (sc->sc_bytesread != sc->mode.packetsize || 658 sc->sc_deltax != 0 || sc->sc_deltay != 0 || 659 (sc->sc_obuttons ^ sc->sc_buttons) != 0) 660 revents |= events & (POLLIN | POLLRDNORM); 661 else { 662 /* 663 * Since this is an exclusive open device, any previous 664 * proc pointer is trash now, so we can just assign it. 665 */ 666 selrecord(p, &sc->sc_selp); 667 } 668 } 669 splx(s); 670 return (revents); 671} 672 673/* 674 * msetimeout: watchdog timer routine. 675 */ 676static void 677msetimeout(arg) 678 void *arg; 679{ 680 dev_t dev; 681 mse_softc_t *sc; 682 683 dev = (dev_t)arg; 684 sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 685 if (sc->sc_watchdog) { 686 if (bootverbose) 687 printf("mse%d: lost interrupt?\n", MSE_UNIT(dev)); 688 mseintr(sc); 689 } 690 sc->sc_watchdog = TRUE; 691 sc->sc_callout = timeout(msetimeout, dev, hz); 692} 693 694/* 695 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 696 */ 697static void 698mseintr(arg) 699 void *arg; 700{ 701 /* 702 * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP) 703 * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 704 */ 705 static int butmap[8] = { 706 0, 707 MOUSE_BUTTON3DOWN, 708 MOUSE_BUTTON2DOWN, 709 MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 710 MOUSE_BUTTON1DOWN, 711 MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 712 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 713 MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 714 }; 715 mse_softc_t *sc = arg; 716 int dx, dy, but; 717 int sign; 718 719#ifdef DEBUG 720 static int mse_intrcnt = 0; 721 if((mse_intrcnt++ % 10000) == 0) 722 printf("mseintr\n"); 723#endif /* DEBUG */ 724 if ((sc->sc_flags & MSESC_OPEN) == 0) 725 return; 726 727 (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but); 728 if (sc->mode.accelfactor > 0) { 729 sign = (dx < 0); 730 dx = dx * dx / sc->mode.accelfactor; 731 if (dx == 0) 732 dx = 1; 733 if (sign) 734 dx = -dx; 735 sign = (dy < 0); 736 dy = dy * dy / sc->mode.accelfactor; 737 if (dy == 0) 738 dy = 1; 739 if (sign) 740 dy = -dy; 741 } 742 sc->sc_deltax += dx; 743 sc->sc_deltay += dy; 744 sc->sc_buttons = but; 745 746 but = butmap[~but & MOUSE_MSC_BUTTONS]; 747 sc->status.dx += dx; 748 sc->status.dy += dy; 749 sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0) 750 | (sc->status.button ^ but); 751 sc->status.button = but; 752 753 sc->sc_watchdog = FALSE; 754 755 /* 756 * If mouse state has changed, wake up anyone wanting to know. 757 */ 758 if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 759 (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 760 if (sc->sc_flags & MSESC_WANT) { 761 sc->sc_flags &= ~MSESC_WANT; 762 wakeup((caddr_t)sc); 763 } 764 selwakeup(&sc->sc_selp); 765 } 766} 767 768/* 769 * Routines for the Logitech mouse. 770 */ 771/* 772 * Test for a Logitech bus mouse and return 1 if it is. 773 * (until I know how to use the signature port properly, just disable 774 * interrupts and return 1) 775 */ 776static int 777mse_probelogi(dev, sc) 778 device_t dev; 779 mse_softc_t *sc; 780{ 781 782 int sig; 783 784 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP); 785 /* set the signature port */ 786 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG); 787 788 DELAY(30000); /* 30 ms delay */ 789 sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF; 790 if (sig == MSE_LOGI_SIG) { 791 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC, 792 MSE_DISINTR); 793 return(1); 794 } else { 795 if (bootverbose) 796 device_printf(dev, "wrong signature %x\n", sig); 797 return(0); 798 } 799} 800 801/* 802 * Initialize Logitech mouse and enable interrupts. 803 */ 804static void 805mse_enablelogi(tag, handle) 806 bus_space_tag_t tag; 807 bus_space_handle_t handle; 808{ 809 int dx, dy, but; 810 811 bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP); 812 mse_getlogi(tag, handle, &dx, &dy, &but); 813} 814 815/* 816 * Disable interrupts for Logitech mouse. 817 */ 818static void 819mse_disablelogi(tag, handle) 820 bus_space_tag_t tag; 821 bus_space_handle_t handle; 822{ 823 824 bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR); 825} 826 827/* 828 * Get the current dx, dy and button up/down state. 829 */ 830static void 831mse_getlogi(tag, handle, dx, dy, but) 832 bus_space_tag_t tag; 833 bus_space_handle_t handle; 834 int *dx; 835 int *dy; 836 int *but; 837{ 838 register char x, y; 839 840 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 841 x = bus_space_read_1(tag, handle, MSE_PORTA); 842 *but = (x >> 5) & MOUSE_MSC_BUTTONS; 843 x &= 0xf; 844 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 845 x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 846 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 847 y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf); 848 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 849 y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 850 *dx = x; 851 *dy = y; 852 bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN); 853} 854 855/* 856 * Routines for the ATI Inport bus mouse. 857 */ 858/* 859 * Test for a ATI Inport bus mouse and return 1 if it is. 860 * (do not enable interrupts) 861 */ 862static int 863mse_probeati(dev, sc) 864 device_t dev; 865 mse_softc_t *sc; 866{ 867 int i; 868 869 for (i = 0; i < 2; i++) 870 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde) 871 return (1); 872 return (0); 873} 874 875/* 876 * Initialize ATI Inport mouse and enable interrupts. 877 */ 878static void 879mse_enableati(tag, handle) 880 bus_space_tag_t tag; 881 bus_space_handle_t handle; 882{ 883 884 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET); 885 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 886 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 887} 888 889/* 890 * Disable interrupts for ATI Inport mouse. 891 */ 892static void 893mse_disableati(tag, handle) 894 bus_space_tag_t tag; 895 bus_space_handle_t handle; 896{ 897 898 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 899 bus_space_write_1(tag, handle, MSE_PORTB, 0); 900} 901 902/* 903 * Get current dx, dy and up/down button state. 904 */ 905static void 906mse_getati(tag, handle, dx, dy, but) 907 bus_space_tag_t tag; 908 bus_space_handle_t handle; 909 int *dx; 910 int *dy; 911 int *but; 912{ 913 register char byte; 914 915 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 916 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD); 917 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS); 918 *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS; 919 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX); 920 byte = bus_space_read_1(tag, handle, MSE_PORTB); 921 *dx = byte; 922 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY); 923 byte = bus_space_read_1(tag, handle, MSE_PORTB); 924 *dy = byte; 925 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 926 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 927} 928