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