mse.c revision 798
178977Sroam/* 278977Sroam * Copyright 1992 by the University of Guelph 378977Sroam * 478977Sroam * Permission to use, copy and modify this 578977Sroam * software and its documentation for any purpose and without 678977Sroam * fee is hereby granted, provided that the above copyright 778977Sroam * notice appear in all copies and that both that copyright 878977Sroam * notice and this permission notice appear in supporting 978977Sroam * documentation. 1078977Sroam * University of Guelph makes no representations about the suitability of 1178977Sroam * this software for any purpose. It is provided "as is" 1278977Sroam * without express or implied warranty. 1378977Sroam */ 1478977Sroam/* 1578977Sroam * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 1678977Sroam * the X386 port, courtesy of 1778977Sroam * Rick Macklem, rick@snowhite.cis.uoguelph.ca 1878977Sroam * Caveats: The driver currently uses spltty(), but doesn't use any 1978977Sroam * generic tty code. It could use splmse() (that only masks off the 2078977Sroam * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 2178977Sroam * (This may be worth the effort, since the Logitech generates 30/60 2278977Sroam * interrupts/sec continuously while it is open.) 2378977Sroam * NB: The ATI has NOT been tested yet! 2478977Sroam */ 2578977Sroam 2678977Sroam/* 2778977Sroam * Modification history: 2878977Sroam * 2978977Sroam * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 3078977Sroam * fixes to make it work with Microsoft InPort busmouse 3178977Sroam * 3278977Sroam * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 33 * added patches for new "select" interface 34 * 35 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 36 * changed position of some spl()'s in mseread 37 * 38 * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 39 * limit maximum negative x/y value to -127 to work around XFree problem 40 * that causes spurious button pushes. 41 */ 42 43#include "mse.h" 44#if NMSE > 0 45#include "param.h" 46#include "proc.h" 47#include "user.h" 48#include "buf.h" 49#include "systm.h" 50#include "kernel.h" 51#include "ioctl.h" 52#include "tty.h" 53#include "uio.h" 54 55#include "i386/isa/isa_device.h" 56#include "i386/isa/icu.h" 57 58static int mseprobe(struct isa_device *); 59static int mseattach(struct isa_device *); 60void mseintr(int); 61 62struct isa_driver msedriver = { 63 mseprobe, mseattach, "mse" 64}; 65 66/* 67 * Software control structure for mouse. The sc_enablemouse(), 68 * sc_disablemouse() and sc_getmouse() routines must be called spl'd(). 69 */ 70#define PROTOBYTES 5 71struct mse_softc { 72 int sc_flags; 73 int sc_mousetype; 74 pid_t sc_selp; 75 u_int sc_port; 76 void (*sc_enablemouse)(); 77 void (*sc_disablemouse)(); 78 void (*sc_getmouse)(); 79 int sc_deltax; 80 int sc_deltay; 81 int sc_obuttons; 82 int sc_buttons; 83 int sc_bytesread; 84 u_char sc_bytes[PROTOBYTES]; 85} mse_sc[NMSE]; 86 87/* Flags */ 88#define MSESC_OPEN 0x1 89#define MSESC_WANT 0x2 90 91/* and Mouse Types */ 92#define MSE_LOGITECH 0x1 93#define MSE_ATIINPORT 0x2 94 95#define MSE_PORTA 0 96#define MSE_PORTB 1 97#define MSE_PORTC 2 98#define MSE_PORTD 3 99 100#define MSE_UNIT(dev) (minor(dev) >> 1) 101#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 102 103/* 104 * Logitech bus mouse definitions 105 */ 106#define MSE_SETUP 0x91 /* What does this mean? */ 107#define MSE_HOLD 0x80 108#define MSE_RXLOW 0x00 109#define MSE_RXHIGH 0x20 110#define MSE_RYLOW 0x40 111#define MSE_RYHIGH 0x60 112#define MSE_DISINTR 0x10 113#define MSE_INTREN 0x00 114 115static int mse_probelogi(); 116static void mse_enablelogi(), mse_disablelogi(), mse_getlogi(); 117 118/* 119 * ATI Inport mouse definitions 120 */ 121#define MSE_INPORT_RESET 0x80 122#define MSE_INPORT_STATUS 0x00 123#define MSE_INPORT_DX 0x01 124#define MSE_INPORT_DY 0x02 125#define MSE_INPORT_MODE 0x07 126#define MSE_INPORT_HOLD 0x20 127#define MSE_INPORT_INTREN 0x09 128 129static int mse_probeati(); 130static void mse_enableati(), mse_disableati(), mse_getati(); 131 132#define MSEPRI (PZERO + 3) 133 134/* 135 * Table of mouse types. 136 * Keep the Logitech last, since I haven't figured out how to probe it 137 * properly yet. (Someday I'll have the documentation.) 138 */ 139struct mse_types { 140 int m_type; /* Type of bus mouse */ 141 int (*m_probe)(); /* Probe routine to test for it */ 142 void (*m_enable)(); /* Start routine */ 143 void (*m_disable)(); /* Disable interrupts routine */ 144 void (*m_get)(); /* and get mouse status */ 145} mse_types[] = { 146 { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati }, 147 { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi }, 148 { 0, }, 149}; 150 151int 152mseprobe(idp) 153 register struct isa_device *idp; 154{ 155 register struct mse_softc *sc = &mse_sc[idp->id_unit]; 156 register int i; 157 158 /* 159 * Check for each mouse type in the table. 160 */ 161 i = 0; 162 while (mse_types[i].m_type) { 163 if ((*mse_types[i].m_probe)(idp)) { 164 sc->sc_mousetype = mse_types[i].m_type; 165 sc->sc_enablemouse = mse_types[i].m_enable; 166 sc->sc_disablemouse = mse_types[i].m_disable; 167 sc->sc_getmouse = mse_types[i].m_get; 168 return (1); 169 } 170 i++; 171 } 172 return (0); 173} 174 175int 176mseattach(idp) 177 struct isa_device *idp; 178{ 179 struct mse_softc *sc = &mse_sc[idp->id_unit]; 180 181 sc->sc_port = idp->id_iobase; 182 return (1); 183} 184 185/* 186 * Exclusive open the mouse, initialize it and enable interrupts. 187 */ 188int 189mseopen(dev, flag) 190 dev_t dev; 191 int flag; 192{ 193 register struct mse_softc *sc; 194 int s; 195 196 if (MSE_UNIT(dev) >= NMSE) 197 return (ENXIO); 198 sc = &mse_sc[MSE_UNIT(dev)]; 199 if (sc->sc_flags & MSESC_OPEN) 200 return (EBUSY); 201 sc->sc_flags |= MSESC_OPEN; 202 sc->sc_obuttons = sc->sc_buttons = 0x7; 203 sc->sc_deltax = sc->sc_deltay = 0; 204 sc->sc_bytesread = PROTOBYTES; 205 206 /* 207 * Initialize mouse interface and enable interrupts. 208 */ 209 s = spltty(); 210 (*sc->sc_enablemouse)(sc->sc_port); 211 splx(s); 212 return (0); 213} 214 215/* 216 * mseclose: just turn off mouse innterrupts. 217 */ 218int 219mseclose(dev, flag) 220 dev_t dev; 221 int flag; 222{ 223 struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 224 int s; 225 226 s = spltty(); 227 (*sc->sc_disablemouse)(sc->sc_port); 228 sc->sc_flags &= ~MSESC_OPEN; 229 splx(s); 230 return(0); 231} 232 233/* 234 * mseread: return mouse info using the MSC serial protocol, but without 235 * using bytes 4 and 5. 236 * (Yes this is cheesy, but it makes the X386 server happy, so...) 237 */ 238int 239mseread(dev, uio) 240 dev_t dev; 241 struct uio *uio; 242{ 243 register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 244 int xfer, s, error; 245 246 /* 247 * If there are no protocol bytes to be read, set up a new protocol 248 * packet. 249 */ 250 s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 251 if (sc->sc_bytesread >= PROTOBYTES) { 252 while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 253 (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 254 if (MSE_NBLOCKIO(dev)) { 255 splx(s); 256 return (0); 257 } 258 sc->sc_flags |= MSESC_WANT; 259 if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 260 "mseread", 0)) { 261 splx(s); 262 return (error); 263 } 264 } 265 266 /* 267 * Generate protocol bytes. 268 * For some reason X386 expects 5 bytes but never uses 269 * the fourth or fifth? 270 */ 271 sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8); 272 if (sc->sc_deltax > 127) 273 sc->sc_deltax = 127; 274 if (sc->sc_deltax < -127) 275 sc->sc_deltax = -127; 276 sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 277 if (sc->sc_deltay > 127) 278 sc->sc_deltay = 127; 279 if (sc->sc_deltay < -127) 280 sc->sc_deltay = -127; 281 sc->sc_bytes[1] = sc->sc_deltax; 282 sc->sc_bytes[2] = sc->sc_deltay; 283 sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 284 sc->sc_obuttons = sc->sc_buttons; 285 sc->sc_deltax = sc->sc_deltay = 0; 286 sc->sc_bytesread = 0; 287 } 288 splx(s); 289 xfer = MIN(uio->uio_resid, PROTOBYTES - sc->sc_bytesread); 290 if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio)) 291 return (error); 292 sc->sc_bytesread += xfer; 293 return(0); 294} 295 296/* 297 * mseselect: check for mouse input to be processed. 298 */ 299int 300mseselect(dev, rw, p) 301 dev_t dev; 302 int rw; 303 struct proc *p; 304{ 305 register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 306 int s; 307 308 s = spltty(); 309 if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 || 310 sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 311 splx(s); 312 return (1); 313 } 314 315 /* 316 * Since this is an exclusive open device, any previous proc. 317 * pointer is trash now, so we can just assign it. 318 */ 319 sc->sc_selp = p->p_pid; 320 splx(s); 321 return (0); 322} 323 324/* 325 * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 326 */ 327void 328mseintr(unit) 329 int unit; 330{ 331 register struct mse_softc *sc = &mse_sc[unit]; 332 pid_t p; 333 334#ifdef DEBUG 335 static int mse_intrcnt = 0; 336 if((mse_intrcnt++ % 10000) == 0) 337 printf("mseintr\n"); 338#endif /* DEBUG */ 339 if ((sc->sc_flags & MSESC_OPEN) == 0) 340 return; 341 342 (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons); 343 344 /* 345 * If mouse state has changed, wake up anyone wanting to know. 346 */ 347 if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 348 (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 349 if (sc->sc_flags & MSESC_WANT) { 350 sc->sc_flags &= ~MSESC_WANT; 351 wakeup((caddr_t)sc); 352 } 353 if (sc->sc_selp) { 354 p = sc->sc_selp; 355 sc->sc_selp = (pid_t)0; 356 selwakeup(p, 0); 357 } 358 } 359} 360 361/* 362 * Routines for the Logitech mouse. 363 */ 364/* 365 * Test for a Logitech bus mouse and return 1 if it is. 366 * (until I know how to use the signature port properly, just disable 367 * interrupts and return 1) 368 */ 369static int 370mse_probelogi(idp) 371 register struct isa_device *idp; 372{ 373 374 outb(idp->id_iobase + MSE_PORTB, 0x55); 375 if (inb(idp->id_iobase + MSE_PORTB) == 0x55) { 376 outb(idp->id_iobase + MSE_PORTB, 0xaa); 377 if (inb(idp->id_iobase + MSE_PORTB) == 0xaa) 378 return (1); 379 } 380 return (0); 381} 382 383/* 384 * Initialize Logitech mouse and enable interrupts. 385 */ 386static void 387mse_enablelogi(port) 388 register u_int port; 389{ 390 int dx, dy, but; 391 392 outb(port + MSE_PORTD, MSE_SETUP); 393 mse_getlogi(port, &dx, &dy, &but); 394} 395 396/* 397 * Disable interrupts for Logitech mouse. 398 */ 399static void 400mse_disablelogi(port) 401 register u_int port; 402{ 403 404 outb(port + MSE_PORTC, MSE_DISINTR); 405} 406 407/* 408 * Get the current dx, dy and button up/down state. 409 */ 410static void 411mse_getlogi(port, dx, dy, but) 412 register u_int port; 413 int *dx; 414 int *dy; 415 int *but; 416{ 417 register char x, y; 418 419 outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW); 420 x = inb(port + MSE_PORTA); 421 *but = (x >> 5) & 0x7; 422 x &= 0xf; 423 outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 424 x |= (inb(port + MSE_PORTA) << 4); 425 outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW); 426 y = (inb(port + MSE_PORTA) & 0xf); 427 outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 428 y |= (inb(port + MSE_PORTA) << 4); 429 *dx += x; 430 *dy += y; 431 outb(port + MSE_PORTC, MSE_INTREN); 432} 433 434/* 435 * Routines for the ATI Inport bus mouse. 436 */ 437/* 438 * Test for a ATI Inport bus mouse and return 1 if it is. 439 * (do not enable interrupts) 440 */ 441static int 442mse_probeati(idp) 443 register struct isa_device *idp; 444{ 445 int i; 446 447 for (i = 0; i < 2; i++) 448 if (inb(idp->id_iobase + MSE_PORTC) == 0xde) 449 return (1); 450 return (0); 451} 452 453/* 454 * Initialize ATI Inport mouse and enable interrupts. 455 */ 456static void 457mse_enableati(port) 458 register u_int port; 459{ 460 461 outb(port + MSE_PORTA, MSE_INPORT_RESET); 462 outb(port + MSE_PORTA, MSE_INPORT_MODE); 463 outb(port + MSE_PORTB, MSE_INPORT_INTREN); 464} 465 466/* 467 * Disable interrupts for ATI Inport mouse. 468 */ 469static void 470mse_disableati(port) 471 register u_int port; 472{ 473 474 outb(port + MSE_PORTA, MSE_INPORT_MODE); 475 outb(port + MSE_PORTB, 0); 476} 477 478/* 479 * Get current dx, dy and up/down button state. 480 */ 481static void 482mse_getati(port, dx, dy, but) 483 register u_int port; 484 int *dx; 485 int *dy; 486 int *but; 487{ 488 register char byte; 489 490 outb(port + MSE_PORTA, MSE_INPORT_MODE); 491 outb(port + MSE_PORTB, MSE_INPORT_HOLD); 492 outb(port + MSE_PORTA, MSE_INPORT_STATUS); 493 *but = ~(inb(port + MSE_PORTB) & 0x7); 494 outb(port + MSE_PORTA, MSE_INPORT_DX); 495 byte = inb(port + MSE_PORTB); 496 *dx += byte; 497 outb(port + MSE_PORTA, MSE_INPORT_DY); 498 byte = inb(port + MSE_PORTB); 499 *dy += byte; 500 outb(port + MSE_PORTA, MSE_INPORT_MODE); 501 outb(port + MSE_PORTB, MSE_INPORT_INTREN); 502} 503#endif /* NMSE */ 504