mse.c revision 1549
1637Snate/* 2637Snate * Copyright 1992 by the University of Guelph 3637Snate * 4637Snate * Permission to use, copy and modify this 5637Snate * software and its documentation for any purpose and without 6637Snate * fee is hereby granted, provided that the above copyright 7637Snate * notice appear in all copies and that both that copyright 8637Snate * notice and this permission notice appear in supporting 9637Snate * documentation. 10637Snate * University of Guelph makes no representations about the suitability of 11637Snate * this software for any purpose. It is provided "as is" 12637Snate * without express or implied warranty. 13637Snate */ 14637Snate/* 15637Snate * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 16637Snate * the X386 port, courtesy of 17637Snate * Rick Macklem, rick@snowhite.cis.uoguelph.ca 18637Snate * Caveats: The driver currently uses spltty(), but doesn't use any 19637Snate * generic tty code. It could use splmse() (that only masks off the 20637Snate * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 21637Snate * (This may be worth the effort, since the Logitech generates 30/60 22637Snate * interrupts/sec continuously while it is open.) 23637Snate * NB: The ATI has NOT been tested yet! 24637Snate */ 25637Snate 26637Snate/* 27637Snate * Modification history: 28637Snate * 29637Snate * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 30637Snate * fixes to make it work with Microsoft InPort busmouse 31637Snate * 32637Snate * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 33637Snate * added patches for new "select" interface 34637Snate * 35637Snate * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 36637Snate * changed position of some spl()'s in mseread 37637Snate * 38637Snate * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 39637Snate * limit maximum negative x/y value to -127 to work around XFree problem 40637Snate * that causes spurious button pushes. 41637Snate */ 42637Snate 43637Snate#include "mse.h" 44637Snate#if NMSE > 0 45637Snate#include "param.h" 46637Snate#include "proc.h" 47637Snate#include "user.h" 48637Snate#include "buf.h" 49637Snate#include "systm.h" 50637Snate#include "kernel.h" 51637Snate#include "ioctl.h" 52637Snate#include "tty.h" 53637Snate#include "uio.h" 54637Snate 55637Snate#include "i386/isa/isa_device.h" 56637Snate#include "i386/isa/icu.h" 57637Snate 58798Swollmanstatic int mseprobe(struct isa_device *); 59798Swollmanstatic int mseattach(struct isa_device *); 60798Swollmanvoid mseintr(int); 61637Snate 62637Snatestruct isa_driver msedriver = { 63637Snate mseprobe, mseattach, "mse" 64637Snate}; 65637Snate 66637Snate/* 67637Snate * Software control structure for mouse. The sc_enablemouse(), 68637Snate * sc_disablemouse() and sc_getmouse() routines must be called spl'd(). 69637Snate */ 70637Snate#define PROTOBYTES 5 71637Snatestruct mse_softc { 72637Snate int sc_flags; 73637Snate int sc_mousetype; 741549Srgrimes struct selinfo sc_selp; 75637Snate u_int sc_port; 76637Snate void (*sc_enablemouse)(); 77637Snate void (*sc_disablemouse)(); 78637Snate void (*sc_getmouse)(); 79637Snate int sc_deltax; 80637Snate int sc_deltay; 81637Snate int sc_obuttons; 82637Snate int sc_buttons; 83637Snate int sc_bytesread; 84637Snate u_char sc_bytes[PROTOBYTES]; 85637Snate} mse_sc[NMSE]; 86637Snate 87637Snate/* Flags */ 88637Snate#define MSESC_OPEN 0x1 89637Snate#define MSESC_WANT 0x2 90637Snate 91637Snate/* and Mouse Types */ 92637Snate#define MSE_LOGITECH 0x1 93637Snate#define MSE_ATIINPORT 0x2 94637Snate 95637Snate#define MSE_PORTA 0 96637Snate#define MSE_PORTB 1 97637Snate#define MSE_PORTC 2 98637Snate#define MSE_PORTD 3 99637Snate 100637Snate#define MSE_UNIT(dev) (minor(dev) >> 1) 101637Snate#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 102637Snate 103637Snate/* 104637Snate * Logitech bus mouse definitions 105637Snate */ 106637Snate#define MSE_SETUP 0x91 /* What does this mean? */ 107637Snate#define MSE_HOLD 0x80 108637Snate#define MSE_RXLOW 0x00 109637Snate#define MSE_RXHIGH 0x20 110637Snate#define MSE_RYLOW 0x40 111637Snate#define MSE_RYHIGH 0x60 112637Snate#define MSE_DISINTR 0x10 113637Snate#define MSE_INTREN 0x00 114637Snate 115637Snatestatic int mse_probelogi(); 116637Snatestatic void mse_enablelogi(), mse_disablelogi(), mse_getlogi(); 117637Snate 118637Snate/* 119637Snate * ATI Inport mouse definitions 120637Snate */ 121637Snate#define MSE_INPORT_RESET 0x80 122637Snate#define MSE_INPORT_STATUS 0x00 123637Snate#define MSE_INPORT_DX 0x01 124637Snate#define MSE_INPORT_DY 0x02 125637Snate#define MSE_INPORT_MODE 0x07 126637Snate#define MSE_INPORT_HOLD 0x20 127637Snate#define MSE_INPORT_INTREN 0x09 128637Snate 129637Snatestatic int mse_probeati(); 130637Snatestatic void mse_enableati(), mse_disableati(), mse_getati(); 131637Snate 132637Snate#define MSEPRI (PZERO + 3) 133637Snate 134637Snate/* 135637Snate * Table of mouse types. 136637Snate * Keep the Logitech last, since I haven't figured out how to probe it 137637Snate * properly yet. (Someday I'll have the documentation.) 138637Snate */ 139637Snatestruct mse_types { 140637Snate int m_type; /* Type of bus mouse */ 141637Snate int (*m_probe)(); /* Probe routine to test for it */ 142637Snate void (*m_enable)(); /* Start routine */ 143637Snate void (*m_disable)(); /* Disable interrupts routine */ 144637Snate void (*m_get)(); /* and get mouse status */ 145637Snate} mse_types[] = { 146637Snate { MSE_ATIINPORT, mse_probeati, mse_enableati, mse_disableati, mse_getati }, 147637Snate { MSE_LOGITECH, mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi }, 148637Snate { 0, }, 149637Snate}; 150637Snate 151798Swollmanint 152637Snatemseprobe(idp) 153637Snate register struct isa_device *idp; 154637Snate{ 155637Snate register struct mse_softc *sc = &mse_sc[idp->id_unit]; 156637Snate register int i; 157637Snate 158637Snate /* 159637Snate * Check for each mouse type in the table. 160637Snate */ 161637Snate i = 0; 162637Snate while (mse_types[i].m_type) { 163637Snate if ((*mse_types[i].m_probe)(idp)) { 164637Snate sc->sc_mousetype = mse_types[i].m_type; 165637Snate sc->sc_enablemouse = mse_types[i].m_enable; 166637Snate sc->sc_disablemouse = mse_types[i].m_disable; 167637Snate sc->sc_getmouse = mse_types[i].m_get; 168637Snate return (1); 169637Snate } 170637Snate i++; 171637Snate } 172637Snate return (0); 173637Snate} 174637Snate 175798Swollmanint 176637Snatemseattach(idp) 177637Snate struct isa_device *idp; 178637Snate{ 179637Snate struct mse_softc *sc = &mse_sc[idp->id_unit]; 180637Snate 181637Snate sc->sc_port = idp->id_iobase; 182637Snate return (1); 183637Snate} 184637Snate 185637Snate/* 186637Snate * Exclusive open the mouse, initialize it and enable interrupts. 187637Snate */ 188798Swollmanint 189637Snatemseopen(dev, flag) 190637Snate dev_t dev; 191637Snate int flag; 192637Snate{ 193637Snate register struct mse_softc *sc; 194637Snate int s; 195637Snate 196637Snate if (MSE_UNIT(dev) >= NMSE) 197637Snate return (ENXIO); 198637Snate sc = &mse_sc[MSE_UNIT(dev)]; 199637Snate if (sc->sc_flags & MSESC_OPEN) 200637Snate return (EBUSY); 201637Snate sc->sc_flags |= MSESC_OPEN; 202637Snate sc->sc_obuttons = sc->sc_buttons = 0x7; 203637Snate sc->sc_deltax = sc->sc_deltay = 0; 204637Snate sc->sc_bytesread = PROTOBYTES; 205637Snate 206637Snate /* 207637Snate * Initialize mouse interface and enable interrupts. 208637Snate */ 209637Snate s = spltty(); 210637Snate (*sc->sc_enablemouse)(sc->sc_port); 211637Snate splx(s); 212637Snate return (0); 213637Snate} 214637Snate 215637Snate/* 216637Snate * mseclose: just turn off mouse innterrupts. 217637Snate */ 218798Swollmanint 219637Snatemseclose(dev, flag) 220798Swollman dev_t dev; 221637Snate int flag; 222637Snate{ 223637Snate struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 224637Snate int s; 225637Snate 226637Snate s = spltty(); 227637Snate (*sc->sc_disablemouse)(sc->sc_port); 228637Snate sc->sc_flags &= ~MSESC_OPEN; 229637Snate splx(s); 230637Snate return(0); 231637Snate} 232637Snate 233637Snate/* 234637Snate * mseread: return mouse info using the MSC serial protocol, but without 235637Snate * using bytes 4 and 5. 236637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...) 237637Snate */ 238798Swollmanint 239637Snatemseread(dev, uio) 240637Snate dev_t dev; 241637Snate struct uio *uio; 242637Snate{ 243637Snate register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 244637Snate int xfer, s, error; 245637Snate 246637Snate /* 247637Snate * If there are no protocol bytes to be read, set up a new protocol 248637Snate * packet. 249637Snate */ 250637Snate s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 251637Snate if (sc->sc_bytesread >= PROTOBYTES) { 252637Snate while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 253637Snate (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 254637Snate if (MSE_NBLOCKIO(dev)) { 255637Snate splx(s); 256637Snate return (0); 257637Snate } 258637Snate sc->sc_flags |= MSESC_WANT; 259637Snate if (error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 260637Snate "mseread", 0)) { 261637Snate splx(s); 262637Snate return (error); 263637Snate } 264637Snate } 265637Snate 266637Snate /* 267637Snate * Generate protocol bytes. 268637Snate * For some reason X386 expects 5 bytes but never uses 269637Snate * the fourth or fifth? 270637Snate */ 271637Snate sc->sc_bytes[0] = 0x80 | (sc->sc_buttons & ~0xf8); 272637Snate if (sc->sc_deltax > 127) 273637Snate sc->sc_deltax = 127; 274637Snate if (sc->sc_deltax < -127) 275637Snate sc->sc_deltax = -127; 276637Snate sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 277637Snate if (sc->sc_deltay > 127) 278637Snate sc->sc_deltay = 127; 279637Snate if (sc->sc_deltay < -127) 280637Snate sc->sc_deltay = -127; 281637Snate sc->sc_bytes[1] = sc->sc_deltax; 282637Snate sc->sc_bytes[2] = sc->sc_deltay; 283637Snate sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 284637Snate sc->sc_obuttons = sc->sc_buttons; 285637Snate sc->sc_deltax = sc->sc_deltay = 0; 286637Snate sc->sc_bytesread = 0; 287637Snate } 288637Snate splx(s); 289637Snate xfer = MIN(uio->uio_resid, PROTOBYTES - sc->sc_bytesread); 290637Snate if (error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio)) 291637Snate return (error); 292637Snate sc->sc_bytesread += xfer; 293637Snate return(0); 294637Snate} 295637Snate 296637Snate/* 297637Snate * mseselect: check for mouse input to be processed. 298637Snate */ 299798Swollmanint 300637Snatemseselect(dev, rw, p) 301637Snate dev_t dev; 302637Snate int rw; 303637Snate struct proc *p; 304637Snate{ 305637Snate register struct mse_softc *sc = &mse_sc[MSE_UNIT(dev)]; 306637Snate int s; 307637Snate 308637Snate s = spltty(); 309637Snate if (sc->sc_bytesread != PROTOBYTES || sc->sc_deltax != 0 || 310637Snate sc->sc_deltay != 0 || (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 311637Snate splx(s); 312637Snate return (1); 313637Snate } 314637Snate 315637Snate /* 316637Snate * Since this is an exclusive open device, any previous proc. 317637Snate * pointer is trash now, so we can just assign it. 318637Snate */ 3191549Srgrimes selrecord(p, &sc->sc_selp); 320637Snate splx(s); 321637Snate return (0); 322637Snate} 323637Snate 324637Snate/* 325637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 326637Snate */ 327798Swollmanvoid 328637Snatemseintr(unit) 329637Snate int unit; 330637Snate{ 331637Snate register struct mse_softc *sc = &mse_sc[unit]; 332637Snate pid_t p; 333637Snate 334637Snate#ifdef DEBUG 335637Snate static int mse_intrcnt = 0; 336637Snate if((mse_intrcnt++ % 10000) == 0) 337637Snate printf("mseintr\n"); 338637Snate#endif /* DEBUG */ 339637Snate if ((sc->sc_flags & MSESC_OPEN) == 0) 340637Snate return; 341637Snate 342637Snate (*sc->sc_getmouse)(sc->sc_port, &sc->sc_deltax, &sc->sc_deltay, &sc->sc_buttons); 343637Snate 344637Snate /* 345637Snate * If mouse state has changed, wake up anyone wanting to know. 346637Snate */ 347637Snate if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 348637Snate (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 349637Snate if (sc->sc_flags & MSESC_WANT) { 350637Snate sc->sc_flags &= ~MSESC_WANT; 351637Snate wakeup((caddr_t)sc); 352637Snate } 3531549Srgrimes selwakeup(&sc->sc_selp); 354637Snate } 355637Snate} 356637Snate 357637Snate/* 358637Snate * Routines for the Logitech mouse. 359637Snate */ 360637Snate/* 361637Snate * Test for a Logitech bus mouse and return 1 if it is. 362637Snate * (until I know how to use the signature port properly, just disable 363637Snate * interrupts and return 1) 364637Snate */ 365637Snatestatic int 366637Snatemse_probelogi(idp) 367637Snate register struct isa_device *idp; 368637Snate{ 369637Snate 370637Snate outb(idp->id_iobase + MSE_PORTB, 0x55); 371637Snate if (inb(idp->id_iobase + MSE_PORTB) == 0x55) { 372637Snate outb(idp->id_iobase + MSE_PORTB, 0xaa); 373637Snate if (inb(idp->id_iobase + MSE_PORTB) == 0xaa) 374637Snate return (1); 375637Snate } 376637Snate return (0); 377637Snate} 378637Snate 379637Snate/* 380637Snate * Initialize Logitech mouse and enable interrupts. 381637Snate */ 382637Snatestatic void 383637Snatemse_enablelogi(port) 384637Snate register u_int port; 385637Snate{ 386637Snate int dx, dy, but; 387637Snate 388637Snate outb(port + MSE_PORTD, MSE_SETUP); 389637Snate mse_getlogi(port, &dx, &dy, &but); 390637Snate} 391637Snate 392637Snate/* 393637Snate * Disable interrupts for Logitech mouse. 394637Snate */ 395637Snatestatic void 396637Snatemse_disablelogi(port) 397637Snate register u_int port; 398637Snate{ 399637Snate 400637Snate outb(port + MSE_PORTC, MSE_DISINTR); 401637Snate} 402637Snate 403637Snate/* 404637Snate * Get the current dx, dy and button up/down state. 405637Snate */ 406637Snatestatic void 407637Snatemse_getlogi(port, dx, dy, but) 408637Snate register u_int port; 409637Snate int *dx; 410637Snate int *dy; 411637Snate int *but; 412637Snate{ 413637Snate register char x, y; 414637Snate 415637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RXLOW); 416637Snate x = inb(port + MSE_PORTA); 417637Snate *but = (x >> 5) & 0x7; 418637Snate x &= 0xf; 419637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 420637Snate x |= (inb(port + MSE_PORTA) << 4); 421637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RYLOW); 422637Snate y = (inb(port + MSE_PORTA) & 0xf); 423637Snate outb(port + MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 424637Snate y |= (inb(port + MSE_PORTA) << 4); 425637Snate *dx += x; 426637Snate *dy += y; 427637Snate outb(port + MSE_PORTC, MSE_INTREN); 428637Snate} 429637Snate 430637Snate/* 431637Snate * Routines for the ATI Inport bus mouse. 432637Snate */ 433637Snate/* 434637Snate * Test for a ATI Inport bus mouse and return 1 if it is. 435637Snate * (do not enable interrupts) 436637Snate */ 437637Snatestatic int 438637Snatemse_probeati(idp) 439637Snate register struct isa_device *idp; 440637Snate{ 441637Snate int i; 442637Snate 443637Snate for (i = 0; i < 2; i++) 444637Snate if (inb(idp->id_iobase + MSE_PORTC) == 0xde) 445637Snate return (1); 446637Snate return (0); 447637Snate} 448637Snate 449637Snate/* 450637Snate * Initialize ATI Inport mouse and enable interrupts. 451637Snate */ 452637Snatestatic void 453637Snatemse_enableati(port) 454637Snate register u_int port; 455637Snate{ 456637Snate 457637Snate outb(port + MSE_PORTA, MSE_INPORT_RESET); 458637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 459637Snate outb(port + MSE_PORTB, MSE_INPORT_INTREN); 460637Snate} 461637Snate 462637Snate/* 463637Snate * Disable interrupts for ATI Inport mouse. 464637Snate */ 465637Snatestatic void 466637Snatemse_disableati(port) 467637Snate register u_int port; 468637Snate{ 469637Snate 470637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 471637Snate outb(port + MSE_PORTB, 0); 472637Snate} 473637Snate 474637Snate/* 475637Snate * Get current dx, dy and up/down button state. 476637Snate */ 477637Snatestatic void 478637Snatemse_getati(port, dx, dy, but) 479637Snate register u_int port; 480637Snate int *dx; 481637Snate int *dy; 482637Snate int *but; 483637Snate{ 484637Snate register char byte; 485637Snate 486637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 487637Snate outb(port + MSE_PORTB, MSE_INPORT_HOLD); 488637Snate outb(port + MSE_PORTA, MSE_INPORT_STATUS); 489637Snate *but = ~(inb(port + MSE_PORTB) & 0x7); 490637Snate outb(port + MSE_PORTA, MSE_INPORT_DX); 491637Snate byte = inb(port + MSE_PORTB); 492637Snate *dx += byte; 493637Snate outb(port + MSE_PORTA, MSE_INPORT_DY); 494637Snate byte = inb(port + MSE_PORTB); 495637Snate *dy += byte; 496637Snate outb(port + MSE_PORTA, MSE_INPORT_MODE); 497637Snate outb(port + MSE_PORTB, MSE_INPORT_INTREN); 498637Snate} 499637Snate#endif /* NMSE */ 500