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: stable/11/sys/dev/mse/mse_isa.c 331722 2018-03-29 02:50:57Z eadler $ 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); 94138755Simp 95138755Simpstatic device_method_t mse_methods[] = { 96144783Simp DEVMETHOD(device_probe, mse_isa_probe), 97144783Simp DEVMETHOD(device_attach, mse_isa_attach), 98272956Sjhb DEVMETHOD(device_detach, mse_detach), 99138755Simp { 0, 0 } 100138755Simp}; 101138755Simp 102138755Simpstatic driver_t mse_driver = { 103138755Simp "mse", 104138755Simp mse_methods, 105138755Simp sizeof(mse_softc_t), 106138755Simp}; 107138755Simp 108138755SimpDRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 109138755Simp 110138755Simpstatic struct isa_pnp_id mse_ids[] = { 111138755Simp { 0x000fd041, "Bus mouse" }, /* PNP0F00 */ 112138755Simp { 0x020fd041, "InPort mouse" }, /* PNP0F02 */ 113138755Simp { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */ 114138755Simp { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */ 115138755Simp { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */ 116138755Simp { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */ 117138755Simp { 0 } 118138755Simp}; 119138755Simp 120138755Simp/* 121138755Simp * Logitech bus mouse definitions 122138755Simp */ 123138755Simp#define MSE_SETUP 0x91 /* What does this mean? */ 124138755Simp /* The definition for the control port */ 125138755Simp /* is as follows: */ 126138755Simp 127138755Simp /* D7 = Mode set flag (1 = active) */ 128138755Simp /* D6,D5 = Mode selection (port A) */ 129138755Simp /* 00 = Mode 0 = Basic I/O */ 130138755Simp /* 01 = Mode 1 = Strobed I/O */ 131138755Simp /* 10 = Mode 2 = Bi-dir bus */ 132138755Simp /* D4 = Port A direction (1 = input)*/ 133138755Simp /* D3 = Port C (upper 4 bits) */ 134138755Simp /* direction. (1 = input) */ 135138755Simp /* D2 = Mode selection (port B & C) */ 136138755Simp /* 0 = Mode 0 = Basic I/O */ 137138755Simp /* 1 = Mode 1 = Strobed I/O */ 138138755Simp /* D1 = Port B direction (1 = input)*/ 139138755Simp /* D0 = Port C (lower 4 bits) */ 140138755Simp /* direction. (1 = input) */ 141138755Simp 142138755Simp /* So 91 means Basic I/O on all 3 ports,*/ 143138755Simp /* Port A is an input port, B is an */ 144138755Simp /* output port, C is split with upper */ 145138755Simp /* 4 bits being an output port and lower*/ 146138755Simp /* 4 bits an input port, and enable the */ 147138755Simp /* sucker. */ 148138755Simp /* Courtesy Intel 8255 databook. Lars */ 149138755Simp#define MSE_HOLD 0x80 150138755Simp#define MSE_RXLOW 0x00 151138755Simp#define MSE_RXHIGH 0x20 152138755Simp#define MSE_RYLOW 0x40 153138755Simp#define MSE_RYHIGH 0x60 154138755Simp#define MSE_DISINTR 0x10 155138755Simp#define MSE_INTREN 0x00 156138755Simp 157138755Simpstatic int mse_probelogi(device_t dev, mse_softc_t *sc); 158272956Sjhbstatic void mse_disablelogi(struct resource *port); 159272956Sjhbstatic void mse_getlogi(struct resource *port, int *dx, int *dy, 160272956Sjhb int *but); 161272956Sjhbstatic void mse_enablelogi(struct resource *port); 162138755Simp 163138755Simp/* 164138755Simp * ATI Inport mouse definitions 165138755Simp */ 166138755Simp#define MSE_INPORT_RESET 0x80 167138755Simp#define MSE_INPORT_STATUS 0x00 168138755Simp#define MSE_INPORT_DX 0x01 169138755Simp#define MSE_INPORT_DY 0x02 170138755Simp#define MSE_INPORT_MODE 0x07 171138755Simp#define MSE_INPORT_HOLD 0x20 172138755Simp#define MSE_INPORT_INTREN 0x09 173138755Simp 174138755Simpstatic int mse_probeati(device_t dev, mse_softc_t *sc); 175272956Sjhbstatic void mse_enableati(struct resource *port); 176272956Sjhbstatic void mse_disableati(struct resource *port); 177272956Sjhbstatic void mse_getati(struct resource *port, int *dx, int *dy, 178272956Sjhb int *but); 179138755Simp 180138755Simpstatic struct mse_types mse_types[] = { 181138755Simp { MSE_ATIINPORT, 182138755Simp mse_probeati, mse_enableati, mse_disableati, mse_getati, 183138755Simp { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 184138755Simp { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 185138755Simp { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 186138755Simp { MSE_LOGITECH, 187138755Simp mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 188138755Simp { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 189138755Simp { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 190138755Simp { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 191138755Simp { 0, }, 192138755Simp}; 193138755Simp 194138755Simpstatic int 195144783Simpmse_isa_probe(device_t dev) 196138755Simp{ 197138755Simp mse_softc_t *sc; 198138755Simp int error; 199138755Simp int rid; 200138755Simp int i; 201138755Simp 202138755Simp /* check PnP IDs */ 203138755Simp error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 204138755Simp if (error == ENXIO) 205138755Simp return error; 206138755Simp 207138755Simp sc = device_get_softc(dev); 208138755Simp rid = 0; 209296137Sjhibbits sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid, 210296137Sjhibbits MSE_IOSIZE, RF_ACTIVE); 211138755Simp if (sc->sc_port == NULL) 212138755Simp return ENXIO; 213138755Simp 214138755Simp /* 215138755Simp * Check for each mouse type in the table. 216138755Simp */ 217138755Simp i = 0; 218138755Simp while (mse_types[i].m_type) { 219138755Simp if ((*mse_types[i].m_probe)(dev, sc)) { 220138755Simp sc->sc_mousetype = mse_types[i].m_type; 221138755Simp sc->sc_enablemouse = mse_types[i].m_enable; 222138755Simp sc->sc_disablemouse = mse_types[i].m_disable; 223138755Simp sc->sc_getmouse = mse_types[i].m_get; 224138755Simp sc->hw = mse_types[i].m_hw; 225138755Simp sc->mode = mse_types[i].m_mode; 226138755Simp bus_release_resource(dev, SYS_RES_IOPORT, rid, 227138755Simp sc->sc_port); 228138755Simp device_set_desc(dev, "Bus/InPort Mouse"); 229138755Simp return 0; 230138755Simp } 231138755Simp i++; 232138755Simp } 233138755Simp bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 234138755Simp return ENXIO; 235138755Simp} 236138755Simp 237138755Simpstatic int 238144783Simpmse_isa_attach(device_t dev) 239138755Simp{ 240138755Simp mse_softc_t *sc; 241138755Simp int rid; 242138755Simp 243138755Simp sc = device_get_softc(dev); 244138755Simp 245138755Simp rid = 0; 246296137Sjhibbits sc->sc_port = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &rid, 247296137Sjhibbits MSE_IOSIZE, RF_ACTIVE); 248138755Simp if (sc->sc_port == NULL) 249138755Simp return ENXIO; 250138755Simp 251138755Simp return (mse_common_attach(dev)); 252138755Simp} 253138755Simp 254138755Simp/* 255138755Simp * Routines for the Logitech mouse. 256138755Simp */ 257138755Simp/* 258138755Simp * Test for a Logitech bus mouse and return 1 if it is. 259138755Simp * (until I know how to use the signature port properly, just disable 260138755Simp * interrupts and return 1) 261138755Simp */ 262138755Simpstatic int 263144783Simpmse_probelogi(device_t dev, mse_softc_t *sc) 264138755Simp{ 265138755Simp 266138755Simp int sig; 267138755Simp 268272956Sjhb bus_write_1(sc->sc_port, MSE_PORTD, MSE_SETUP); 269138755Simp /* set the signature port */ 270272956Sjhb bus_write_1(sc->sc_port, MSE_PORTB, MSE_LOGI_SIG); 271138755Simp 272138755Simp DELAY(30000); /* 30 ms delay */ 273272956Sjhb sig = bus_read_1(sc->sc_port, MSE_PORTB) & 0xFF; 274138755Simp if (sig == MSE_LOGI_SIG) { 275272956Sjhb bus_write_1(sc->sc_port, MSE_PORTC, MSE_DISINTR); 276138755Simp return(1); 277138755Simp } else { 278138755Simp if (bootverbose) 279138755Simp device_printf(dev, "wrong signature %x\n", sig); 280138755Simp return(0); 281138755Simp } 282138755Simp} 283138755Simp 284138755Simp/* 285138755Simp * Initialize Logitech mouse and enable interrupts. 286138755Simp */ 287138755Simpstatic void 288272956Sjhbmse_enablelogi(struct resource *port) 289138755Simp{ 290138755Simp int dx, dy, but; 291138755Simp 292272956Sjhb bus_write_1(port, MSE_PORTD, MSE_SETUP); 293272956Sjhb mse_getlogi(port, &dx, &dy, &but); 294138755Simp} 295138755Simp 296138755Simp/* 297138755Simp * Disable interrupts for Logitech mouse. 298138755Simp */ 299138755Simpstatic void 300272956Sjhbmse_disablelogi(struct resource *port) 301138755Simp{ 302138755Simp 303272956Sjhb bus_write_1(port, MSE_PORTC, MSE_DISINTR); 304138755Simp} 305138755Simp 306138755Simp/* 307138755Simp * Get the current dx, dy and button up/down state. 308138755Simp */ 309138755Simpstatic void 310272956Sjhbmse_getlogi(struct resource *port, int *dx, int *dy, int *but) 311138755Simp{ 312331643Sdim char x, y; 313138755Simp 314272956Sjhb bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 315272956Sjhb x = bus_read_1(port, MSE_PORTA); 316138755Simp *but = (x >> 5) & MOUSE_MSC_BUTTONS; 317138755Simp x &= 0xf; 318272956Sjhb bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 319272956Sjhb x |= (bus_read_1(port, MSE_PORTA) << 4); 320272956Sjhb bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 321272956Sjhb y = (bus_read_1(port, MSE_PORTA) & 0xf); 322272956Sjhb bus_write_1(port, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 323272956Sjhb y |= (bus_read_1(port, MSE_PORTA) << 4); 324138755Simp *dx = x; 325138755Simp *dy = y; 326272956Sjhb bus_write_1(port, MSE_PORTC, MSE_INTREN); 327138755Simp} 328138755Simp 329138755Simp/* 330138755Simp * Routines for the ATI Inport bus mouse. 331138755Simp */ 332138755Simp/* 333138755Simp * Test for an ATI Inport bus mouse and return 1 if it is. 334138755Simp * (do not enable interrupts) 335138755Simp */ 336138755Simpstatic int 337144783Simpmse_probeati(device_t dev, mse_softc_t *sc) 338138755Simp{ 339138755Simp int i; 340138755Simp 341138755Simp for (i = 0; i < 2; i++) 342272956Sjhb if (bus_read_1(sc->sc_port, MSE_PORTC) == 0xde) 343138755Simp return (1); 344138755Simp return (0); 345138755Simp} 346138755Simp 347138755Simp/* 348138755Simp * Initialize ATI Inport mouse and enable interrupts. 349138755Simp */ 350138755Simpstatic void 351272956Sjhbmse_enableati(struct resource *port) 352138755Simp{ 353138755Simp 354272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_RESET); 355272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE); 356272956Sjhb bus_write_1(port, MSE_PORTB, MSE_INPORT_INTREN); 357138755Simp} 358138755Simp 359138755Simp/* 360138755Simp * Disable interrupts for ATI Inport mouse. 361138755Simp */ 362138755Simpstatic void 363272956Sjhbmse_disableati(struct resource *port) 364138755Simp{ 365138755Simp 366272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE); 367272956Sjhb bus_write_1(port, MSE_PORTB, 0); 368138755Simp} 369138755Simp 370138755Simp/* 371138755Simp * Get current dx, dy and up/down button state. 372138755Simp */ 373138755Simpstatic void 374272956Sjhbmse_getati(struct resource *port, int *dx, int *dy, int *but) 375138755Simp{ 376144783Simp char byte; 377138755Simp 378272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE); 379272956Sjhb bus_write_1(port, MSE_PORTB, MSE_INPORT_HOLD); 380272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_STATUS); 381272956Sjhb *but = ~bus_read_1(port, MSE_PORTB) & MOUSE_MSC_BUTTONS; 382272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_DX); 383272956Sjhb byte = bus_read_1(port, MSE_PORTB); 384138755Simp *dx = byte; 385272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_DY); 386272956Sjhb byte = bus_read_1(port, MSE_PORTB); 387138755Simp *dy = byte; 388272956Sjhb bus_write_1(port, MSE_PORTA, MSE_INPORT_MODE); 389272956Sjhb bus_write_1(port, MSE_PORTB, MSE_INPORT_INTREN); 390138755Simp} 391