mse_isa.c revision 139749
1139749Simp/*- 2138755Simp * Copyright (c) 2004 M. Warner Losh 3138755Simp * All rights reserved. 4138755Simp * 5138755Simp * Redistribution and use in source and binary forms, with or without 6138755Simp * modification, are permitted provided that the following conditions 7138755Simp * are met: 8138755Simp * 1. Redistributions of source code must retain the above copyright 9138755Simp * notice, this list of conditions, and the following disclaimer, 10138755Simp * without modification, immediately at the beginning of the file. 11138755Simp * 2. Redistributions in binary form must reproduce the above copyright 12138755Simp * notice, this list of conditions and the following disclaimer in 13138755Simp * the documentation and/or other materials provided with the 14138755Simp * distribution. 15138755Simp * 16138755Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17138755Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18138755Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19138755Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20138755Simp * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21138755Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22138755Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23138755Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24138755Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25138755Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26138755Simp * SUCH DAMAGE. 27138755Simp * 28138755Simp * $FreeBSD: head/sys/dev/mse/mse_isa.c 139749 2005-01-06 01:43:34Z imp $ 29138755Simp */ 30138755Simp 31138755Simp/* 32138755Simp * Copyright 1992 by the University of Guelph 33138755Simp * 34138755Simp * Permission to use, copy and modify this 35138755Simp * software and its documentation for any purpose and without 36138755Simp * fee is hereby granted, provided that the above copyright 37138755Simp * notice appear in all copies and that both that copyright 38138755Simp * notice and this permission notice appear in supporting 39138755Simp * documentation. 40138755Simp * University of Guelph makes no representations about the suitability of 41138755Simp * this software for any purpose. It is provided "as is" 42138755Simp * without express or implied warranty. 43138755Simp */ 44138755Simp/* 45138755Simp * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 46138755Simp * the X386 port, courtesy of 47138755Simp * Rick Macklem, rick@snowhite.cis.uoguelph.ca 48138755Simp * Caveats: The driver currently uses spltty(), but doesn't use any 49138755Simp * generic tty code. It could use splmse() (that only masks off the 50138755Simp * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 51138755Simp * (This may be worth the effort, since the Logitech generates 30/60 52138755Simp * interrupts/sec continuously while it is open.) 53138755Simp * NB: The ATI has NOT been tested yet! 54138755Simp */ 55138755Simp 56138755Simp/* 57138755Simp * Modification history: 58138755Simp * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 59138755Simp * improved probe based on input from Logitech. 60138755Simp * 61138755Simp * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 62138755Simp * fixes to make it work with Microsoft InPort busmouse 63138755Simp * 64138755Simp * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 65138755Simp * added patches for new "select" interface 66138755Simp * 67138755Simp * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 68138755Simp * changed position of some spl()'s in mseread 69138755Simp * 70138755Simp * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 71138755Simp * limit maximum negative x/y value to -127 to work around XFree problem 72138755Simp * that causes spurious button pushes. 73138755Simp */ 74138755Simp 75138755Simp#include <sys/param.h> 76138755Simp#include <sys/systm.h> 77138755Simp#include <sys/conf.h> 78138755Simp#include <sys/kernel.h> 79138755Simp#include <sys/module.h> 80138755Simp#include <sys/bus.h> 81138755Simp#include <sys/poll.h> 82138755Simp#include <sys/selinfo.h> 83138755Simp#include <sys/uio.h> 84138755Simp#include <sys/mouse.h> 85138755Simp 86138755Simp#include <machine/bus.h> 87138755Simp#include <machine/clock.h> 88138755Simp#include <machine/resource.h> 89138755Simp#include <sys/rman.h> 90138755Simp 91138755Simp#include <isa/isavar.h> 92138755Simp 93138755Simp#include <dev/mse/msevar.h> 94138755Simp 95138755Simpstatic int mse_probe(device_t dev); 96138755Simpstatic int mse_attach(device_t dev); 97138755Simpstatic int mse_detach(device_t dev); 98138755Simp 99138755Simpstatic device_method_t mse_methods[] = { 100138755Simp DEVMETHOD(device_probe, mse_probe), 101138755Simp DEVMETHOD(device_attach, mse_attach), 102138755Simp DEVMETHOD(device_detach, mse_detach), 103138755Simp { 0, 0 } 104138755Simp}; 105138755Simp 106138755Simpstatic driver_t mse_driver = { 107138755Simp "mse", 108138755Simp mse_methods, 109138755Simp sizeof(mse_softc_t), 110138755Simp}; 111138755Simp 112138755SimpDRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 113138755Simp 114138755Simpstatic struct isa_pnp_id mse_ids[] = { 115138755Simp { 0x000fd041, "Bus mouse" }, /* PNP0F00 */ 116138755Simp { 0x020fd041, "InPort mouse" }, /* PNP0F02 */ 117138755Simp { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */ 118138755Simp { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */ 119138755Simp { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */ 120138755Simp { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */ 121138755Simp { 0 } 122138755Simp}; 123138755Simp 124138755Simp/* 125138755Simp * Logitech bus mouse definitions 126138755Simp */ 127138755Simp#define MSE_SETUP 0x91 /* What does this mean? */ 128138755Simp /* The definition for the control port */ 129138755Simp /* is as follows: */ 130138755Simp 131138755Simp /* D7 = Mode set flag (1 = active) */ 132138755Simp /* D6,D5 = Mode selection (port A) */ 133138755Simp /* 00 = Mode 0 = Basic I/O */ 134138755Simp /* 01 = Mode 1 = Strobed I/O */ 135138755Simp /* 10 = Mode 2 = Bi-dir bus */ 136138755Simp /* D4 = Port A direction (1 = input)*/ 137138755Simp /* D3 = Port C (upper 4 bits) */ 138138755Simp /* direction. (1 = input) */ 139138755Simp /* D2 = Mode selection (port B & C) */ 140138755Simp /* 0 = Mode 0 = Basic I/O */ 141138755Simp /* 1 = Mode 1 = Strobed I/O */ 142138755Simp /* D1 = Port B direction (1 = input)*/ 143138755Simp /* D0 = Port C (lower 4 bits) */ 144138755Simp /* direction. (1 = input) */ 145138755Simp 146138755Simp /* So 91 means Basic I/O on all 3 ports,*/ 147138755Simp /* Port A is an input port, B is an */ 148138755Simp /* output port, C is split with upper */ 149138755Simp /* 4 bits being an output port and lower*/ 150138755Simp /* 4 bits an input port, and enable the */ 151138755Simp /* sucker. */ 152138755Simp /* Courtesy Intel 8255 databook. Lars */ 153138755Simp#define MSE_HOLD 0x80 154138755Simp#define MSE_RXLOW 0x00 155138755Simp#define MSE_RXHIGH 0x20 156138755Simp#define MSE_RYLOW 0x40 157138755Simp#define MSE_RYHIGH 0x60 158138755Simp#define MSE_DISINTR 0x10 159138755Simp#define MSE_INTREN 0x00 160138755Simp 161138755Simpstatic int mse_probelogi(device_t dev, mse_softc_t *sc); 162138755Simpstatic void mse_disablelogi(bus_space_tag_t t, 163138755Simp bus_space_handle_t h); 164138755Simpstatic void mse_getlogi(bus_space_tag_t t, bus_space_handle_t h, 165138755Simp int *dx, int *dy, int *but); 166138755Simpstatic void mse_enablelogi(bus_space_tag_t t, 167138755Simp bus_space_handle_t h); 168138755Simp 169138755Simp/* 170138755Simp * ATI Inport mouse definitions 171138755Simp */ 172138755Simp#define MSE_INPORT_RESET 0x80 173138755Simp#define MSE_INPORT_STATUS 0x00 174138755Simp#define MSE_INPORT_DX 0x01 175138755Simp#define MSE_INPORT_DY 0x02 176138755Simp#define MSE_INPORT_MODE 0x07 177138755Simp#define MSE_INPORT_HOLD 0x20 178138755Simp#define MSE_INPORT_INTREN 0x09 179138755Simp 180138755Simpstatic int mse_probeati(device_t dev, mse_softc_t *sc); 181138755Simpstatic void mse_enableati(bus_space_tag_t t, bus_space_handle_t h); 182138755Simpstatic void mse_disableati(bus_space_tag_t t, bus_space_handle_t h); 183138755Simpstatic void mse_getati(bus_space_tag_t t, bus_space_handle_t h, 184138755Simp int *dx, int *dy, int *but); 185138755Simp 186138755Simpstatic struct mse_types mse_types[] = { 187138755Simp { MSE_ATIINPORT, 188138755Simp mse_probeati, mse_enableati, mse_disableati, mse_getati, 189138755Simp { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 190138755Simp { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 191138755Simp { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 192138755Simp { MSE_LOGITECH, 193138755Simp mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 194138755Simp { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 195138755Simp { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 196138755Simp { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 197138755Simp { 0, }, 198138755Simp}; 199138755Simp 200138755Simpstatic int 201138755Simpmse_probe(dev) 202138755Simp device_t dev; 203138755Simp{ 204138755Simp mse_softc_t *sc; 205138755Simp int error; 206138755Simp int rid; 207138755Simp int i; 208138755Simp 209138755Simp /* check PnP IDs */ 210138755Simp error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 211138755Simp if (error == ENXIO) 212138755Simp return error; 213138755Simp 214138755Simp sc = device_get_softc(dev); 215138755Simp rid = 0; 216138755Simp sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 217138755Simp MSE_IOSIZE, RF_ACTIVE); 218138755Simp if (sc->sc_port == NULL) 219138755Simp return ENXIO; 220138755Simp sc->sc_iot = rman_get_bustag(sc->sc_port); 221138755Simp sc->sc_ioh = rman_get_bushandle(sc->sc_port); 222138755Simp 223138755Simp /* 224138755Simp * Check for each mouse type in the table. 225138755Simp */ 226138755Simp i = 0; 227138755Simp while (mse_types[i].m_type) { 228138755Simp if ((*mse_types[i].m_probe)(dev, sc)) { 229138755Simp sc->sc_mousetype = mse_types[i].m_type; 230138755Simp sc->sc_enablemouse = mse_types[i].m_enable; 231138755Simp sc->sc_disablemouse = mse_types[i].m_disable; 232138755Simp sc->sc_getmouse = mse_types[i].m_get; 233138755Simp sc->hw = mse_types[i].m_hw; 234138755Simp sc->mode = mse_types[i].m_mode; 235138755Simp bus_release_resource(dev, SYS_RES_IOPORT, rid, 236138755Simp sc->sc_port); 237138755Simp device_set_desc(dev, "Bus/InPort Mouse"); 238138755Simp return 0; 239138755Simp } 240138755Simp i++; 241138755Simp } 242138755Simp bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 243138755Simp return ENXIO; 244138755Simp} 245138755Simp 246138755Simpstatic int 247138755Simpmse_attach(dev) 248138755Simp device_t dev; 249138755Simp{ 250138755Simp mse_softc_t *sc; 251138755Simp int rid; 252138755Simp 253138755Simp sc = device_get_softc(dev); 254138755Simp 255138755Simp rid = 0; 256138755Simp sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 257138755Simp MSE_IOSIZE, RF_ACTIVE); 258138755Simp if (sc->sc_port == NULL) 259138755Simp return ENXIO; 260138755Simp sc->sc_iot = rman_get_bustag(sc->sc_port); 261138755Simp sc->sc_ioh = rman_get_bushandle(sc->sc_port); 262138755Simp 263138755Simp return (mse_common_attach(dev)); 264138755Simp} 265138755Simp 266138755Simpstatic int 267138755Simpmse_detach(dev) 268138755Simp device_t dev; 269138755Simp{ 270138755Simp mse_softc_t *sc; 271138755Simp int rid; 272138755Simp 273138755Simp sc = device_get_softc(dev); 274138755Simp if (sc->sc_flags & MSESC_OPEN) 275138755Simp return EBUSY; 276138755Simp 277138755Simp rid = 0; 278138755Simp BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 279138755Simp bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 280138755Simp bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 281138755Simp 282138755Simp destroy_dev(sc->sc_dev); 283138755Simp destroy_dev(sc->sc_ndev); 284138755Simp 285138755Simp return 0; 286138755Simp} 287138755Simp 288138755Simp/* 289138755Simp * Routines for the Logitech mouse. 290138755Simp */ 291138755Simp/* 292138755Simp * Test for a Logitech bus mouse and return 1 if it is. 293138755Simp * (until I know how to use the signature port properly, just disable 294138755Simp * interrupts and return 1) 295138755Simp */ 296138755Simpstatic int 297138755Simpmse_probelogi(dev, sc) 298138755Simp device_t dev; 299138755Simp mse_softc_t *sc; 300138755Simp{ 301138755Simp 302138755Simp int sig; 303138755Simp 304138755Simp bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP); 305138755Simp /* set the signature port */ 306138755Simp bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG); 307138755Simp 308138755Simp DELAY(30000); /* 30 ms delay */ 309138755Simp sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF; 310138755Simp if (sig == MSE_LOGI_SIG) { 311138755Simp bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC, 312138755Simp MSE_DISINTR); 313138755Simp return(1); 314138755Simp } else { 315138755Simp if (bootverbose) 316138755Simp device_printf(dev, "wrong signature %x\n", sig); 317138755Simp return(0); 318138755Simp } 319138755Simp} 320138755Simp 321138755Simp/* 322138755Simp * Initialize Logitech mouse and enable interrupts. 323138755Simp */ 324138755Simpstatic void 325138755Simpmse_enablelogi(tag, handle) 326138755Simp bus_space_tag_t tag; 327138755Simp bus_space_handle_t handle; 328138755Simp{ 329138755Simp int dx, dy, but; 330138755Simp 331138755Simp bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP); 332138755Simp mse_getlogi(tag, handle, &dx, &dy, &but); 333138755Simp} 334138755Simp 335138755Simp/* 336138755Simp * Disable interrupts for Logitech mouse. 337138755Simp */ 338138755Simpstatic void 339138755Simpmse_disablelogi(tag, handle) 340138755Simp bus_space_tag_t tag; 341138755Simp bus_space_handle_t handle; 342138755Simp{ 343138755Simp 344138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR); 345138755Simp} 346138755Simp 347138755Simp/* 348138755Simp * Get the current dx, dy and button up/down state. 349138755Simp */ 350138755Simpstatic void 351138755Simpmse_getlogi(tag, handle, dx, dy, but) 352138755Simp bus_space_tag_t tag; 353138755Simp bus_space_handle_t handle; 354138755Simp int *dx; 355138755Simp int *dy; 356138755Simp int *but; 357138755Simp{ 358138755Simp register char x, y; 359138755Simp 360138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 361138755Simp x = bus_space_read_1(tag, handle, MSE_PORTA); 362138755Simp *but = (x >> 5) & MOUSE_MSC_BUTTONS; 363138755Simp x &= 0xf; 364138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 365138755Simp x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 366138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 367138755Simp y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf); 368138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 369138755Simp y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 370138755Simp *dx = x; 371138755Simp *dy = y; 372138755Simp bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN); 373138755Simp} 374138755Simp 375138755Simp/* 376138755Simp * Routines for the ATI Inport bus mouse. 377138755Simp */ 378138755Simp/* 379138755Simp * Test for an ATI Inport bus mouse and return 1 if it is. 380138755Simp * (do not enable interrupts) 381138755Simp */ 382138755Simpstatic int 383138755Simpmse_probeati(dev, sc) 384138755Simp device_t dev; 385138755Simp mse_softc_t *sc; 386138755Simp{ 387138755Simp int i; 388138755Simp 389138755Simp for (i = 0; i < 2; i++) 390138755Simp if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde) 391138755Simp return (1); 392138755Simp return (0); 393138755Simp} 394138755Simp 395138755Simp/* 396138755Simp * Initialize ATI Inport mouse and enable interrupts. 397138755Simp */ 398138755Simpstatic void 399138755Simpmse_enableati(tag, handle) 400138755Simp bus_space_tag_t tag; 401138755Simp bus_space_handle_t handle; 402138755Simp{ 403138755Simp 404138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET); 405138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 406138755Simp bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 407138755Simp} 408138755Simp 409138755Simp/* 410138755Simp * Disable interrupts for ATI Inport mouse. 411138755Simp */ 412138755Simpstatic void 413138755Simpmse_disableati(tag, handle) 414138755Simp bus_space_tag_t tag; 415138755Simp bus_space_handle_t handle; 416138755Simp{ 417138755Simp 418138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 419138755Simp bus_space_write_1(tag, handle, MSE_PORTB, 0); 420138755Simp} 421138755Simp 422138755Simp/* 423138755Simp * Get current dx, dy and up/down button state. 424138755Simp */ 425138755Simpstatic void 426138755Simpmse_getati(tag, handle, dx, dy, but) 427138755Simp bus_space_tag_t tag; 428138755Simp bus_space_handle_t handle; 429138755Simp int *dx; 430138755Simp int *dy; 431138755Simp int *but; 432138755Simp{ 433138755Simp register char byte; 434138755Simp 435138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 436138755Simp bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD); 437138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS); 438138755Simp *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS; 439138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX); 440138755Simp byte = bus_space_read_1(tag, handle, MSE_PORTB); 441138755Simp *dx = byte; 442138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY); 443138755Simp byte = bus_space_read_1(tag, handle, MSE_PORTB); 444138755Simp *dy = byte; 445138755Simp bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 446138755Simp bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 447138755Simp} 448