mse_isa.c revision 158651
150826Smdodd/*- 250826Smdodd * Copyright (c) 2004 M. Warner Losh 350826Smdodd * All rights reserved. 450826Smdodd * 550826Smdodd * Redistribution and use in source and binary forms, with or without 650826Smdodd * modification, are permitted provided that the following conditions 750826Smdodd * are met: 850826Smdodd * 1. Redistributions of source code must retain the above copyright 950826Smdodd * notice, this list of conditions and the following disclaimer. 1050826Smdodd * 2. Redistributions in binary form must reproduce the above copyright 1150826Smdodd * notice, this list of conditions and the following disclaimer in the 1250826Smdodd * documentation and/or other materials provided with the distribution. 1350826Smdodd * 1450826Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1550826Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1650826Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1750826Smdodd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1850826Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1950826Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2050826Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2150826Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2250826Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2350826Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2450826Smdodd * SUCH DAMAGE. 2550826Smdodd * 2650826Smdodd * $FreeBSD: head/sys/dev/mse/mse_isa.c 158651 2006-05-16 14:37:58Z phk $ 2750826Smdodd */ 2850826Smdodd 2950826Smdodd/*- 3050826Smdodd * Copyright 1992 by the University of Guelph 3150826Smdodd * 3250826Smdodd * Permission to use, copy and modify this 3350826Smdodd * software and its documentation for any purpose and without 3450826Smdodd * fee is hereby granted, provided that the above copyright 3550826Smdodd * notice appear in all copies and that both that copyright 3650826Smdodd * notice and this permission notice appear in supporting 3750826Smdodd * documentation. 3850826Smdodd * University of Guelph makes no representations about the suitability of 3950826Smdodd * this software for any purpose. It is provided "as is" 4050826Smdodd * without express or implied warranty. 4150826Smdodd */ 4250826Smdodd/* 4350826Smdodd * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 4450826Smdodd * the X386 port, courtesy of 4550826Smdodd * Rick Macklem, rick@snowhite.cis.uoguelph.ca 4650826Smdodd * Caveats: The driver currently uses spltty(), but doesn't use any 4750826Smdodd * generic tty code. It could use splmse() (that only masks off the 4850826Smdodd * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 4950826Smdodd * (This may be worth the effort, since the Logitech generates 30/60 5050826Smdodd * interrupts/sec continuously while it is open.) 5150826Smdodd * NB: The ATI has NOT been tested yet! 5250826Smdodd */ 5350826Smdodd 5450826Smdodd/* 5550826Smdodd * Modification history: 5650826Smdodd * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 5750826Smdodd * improved probe based on input from Logitech. 5850826Smdodd * 5950826Smdodd * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 6050826Smdodd * fixes to make it work with Microsoft InPort busmouse 6150826Smdodd * 6250826Smdodd * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 6350826Smdodd * added patches for new "select" interface 6450826Smdodd * 6550826Smdodd * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 6650826Smdodd * changed position of some spl()'s in mseread 6750826Smdodd * 6850826Smdodd * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 6950826Smdodd * limit maximum negative x/y value to -127 to work around XFree problem 7050826Smdodd * that causes spurious button pushes. 7150826Smdodd */ 7250826Smdodd 7350826Smdodd#include <sys/param.h> 7450826Smdodd#include <sys/systm.h> 7550826Smdodd#include <sys/conf.h> 7650826Smdodd#include <sys/kernel.h> 7750826Smdodd#include <sys/module.h> 7850826Smdodd#include <sys/bus.h> 7950826Smdodd#include <sys/poll.h> 8050826Smdodd#include <sys/selinfo.h> 8150826Smdodd#include <sys/uio.h> 8250826Smdodd#include <sys/mouse.h> 8350826Smdodd 8450826Smdodd#include <machine/bus.h> 8550826Smdodd#include <machine/resource.h> 8650826Smdodd#include <sys/rman.h> 8750826Smdodd 8850826Smdodd#include <isa/isavar.h> 8950826Smdodd 9050826Smdodd#include <dev/mse/msevar.h> 9150826Smdodd 9250826Smdoddstatic int mse_isa_probe(device_t dev); 9350826Smdoddstatic int mse_isa_attach(device_t dev); 9450826Smdoddstatic int mse_isa_detach(device_t dev); 9550826Smdodd 9650826Smdoddstatic device_method_t mse_methods[] = { 9750826Smdodd DEVMETHOD(device_probe, mse_isa_probe), 9850826Smdodd DEVMETHOD(device_attach, mse_isa_attach), 9950826Smdodd DEVMETHOD(device_detach, mse_isa_detach), 10050826Smdodd { 0, 0 } 10150826Smdodd}; 10250826Smdodd 10350826Smdoddstatic driver_t mse_driver = { 10450826Smdodd "mse", 10550826Smdodd mse_methods, 10650826Smdodd sizeof(mse_softc_t), 10750826Smdodd}; 10850826Smdodd 10950826SmdoddDRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 11050826Smdodd 11150826Smdoddstatic struct isa_pnp_id mse_ids[] = { 11250826Smdodd { 0x000fd041, "Bus mouse" }, /* PNP0F00 */ 11350826Smdodd { 0x020fd041, "InPort mouse" }, /* PNP0F02 */ 11450826Smdodd { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */ 11550826Smdodd { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */ 11650826Smdodd { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */ 11750826Smdodd { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */ 11850826Smdodd { 0 } 11950826Smdodd}; 12050826Smdodd 12150826Smdodd/* 12250826Smdodd * Logitech bus mouse definitions 12350826Smdodd */ 12450826Smdodd#define MSE_SETUP 0x91 /* What does this mean? */ 12550826Smdodd /* The definition for the control port */ 12650826Smdodd /* is as follows: */ 12750826Smdodd 12850826Smdodd /* D7 = Mode set flag (1 = active) */ 12950826Smdodd /* D6,D5 = Mode selection (port A) */ 13050826Smdodd /* 00 = Mode 0 = Basic I/O */ 13150826Smdodd /* 01 = Mode 1 = Strobed I/O */ 13250826Smdodd /* 10 = Mode 2 = Bi-dir bus */ 13350826Smdodd /* D4 = Port A direction (1 = input)*/ 13450826Smdodd /* D3 = Port C (upper 4 bits) */ 13550826Smdodd /* direction. (1 = input) */ 13650826Smdodd /* D2 = Mode selection (port B & C) */ 13750826Smdodd /* 0 = Mode 0 = Basic I/O */ 13850826Smdodd /* 1 = Mode 1 = Strobed I/O */ 13950826Smdodd /* D1 = Port B direction (1 = input)*/ 14050826Smdodd /* D0 = Port C (lower 4 bits) */ 14150826Smdodd /* direction. (1 = input) */ 14250826Smdodd 14350826Smdodd /* So 91 means Basic I/O on all 3 ports,*/ 14450826Smdodd /* Port A is an input port, B is an */ 14550826Smdodd /* output port, C is split with upper */ 14650826Smdodd /* 4 bits being an output port and lower*/ 14750826Smdodd /* 4 bits an input port, and enable the */ 14850826Smdodd /* sucker. */ 14950826Smdodd /* Courtesy Intel 8255 databook. Lars */ 15050826Smdodd#define MSE_HOLD 0x80 15150826Smdodd#define MSE_RXLOW 0x00 15250826Smdodd#define MSE_RXHIGH 0x20 15350826Smdodd#define MSE_RYLOW 0x40 15450826Smdodd#define MSE_RYHIGH 0x60 15550826Smdodd#define MSE_DISINTR 0x10 15650826Smdodd#define MSE_INTREN 0x00 15750826Smdodd 15850826Smdoddstatic int mse_probelogi(device_t dev, mse_softc_t *sc); 15950826Smdoddstatic void mse_disablelogi(bus_space_tag_t t, 16050826Smdodd bus_space_handle_t h); 16150826Smdoddstatic void mse_getlogi(bus_space_tag_t t, bus_space_handle_t h, 16250826Smdodd int *dx, int *dy, int *but); 16350826Smdoddstatic void mse_enablelogi(bus_space_tag_t t, 16450826Smdodd bus_space_handle_t h); 16550826Smdodd 16650826Smdodd/* 16750826Smdodd * ATI Inport mouse definitions 16850826Smdodd */ 16950826Smdodd#define MSE_INPORT_RESET 0x80 17050826Smdodd#define MSE_INPORT_STATUS 0x00 17150826Smdodd#define MSE_INPORT_DX 0x01 17250826Smdodd#define MSE_INPORT_DY 0x02 17350826Smdodd#define MSE_INPORT_MODE 0x07 17450826Smdodd#define MSE_INPORT_HOLD 0x20 17550826Smdodd#define MSE_INPORT_INTREN 0x09 17650826Smdodd 17750826Smdoddstatic int mse_probeati(device_t dev, mse_softc_t *sc); 17850826Smdoddstatic void mse_enableati(bus_space_tag_t t, bus_space_handle_t h); 17950826Smdoddstatic void mse_disableati(bus_space_tag_t t, bus_space_handle_t h); 18050826Smdoddstatic void mse_getati(bus_space_tag_t t, bus_space_handle_t h, 18150826Smdodd int *dx, int *dy, int *but); 18250826Smdodd 18350826Smdoddstatic struct mse_types mse_types[] = { 18450826Smdodd { MSE_ATIINPORT, 18550826Smdodd mse_probeati, mse_enableati, mse_disableati, mse_getati, 18650826Smdodd { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 18750826Smdodd { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 18850826Smdodd { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 18950826Smdodd { MSE_LOGITECH, 19050826Smdodd mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 19150826Smdodd { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 19250826Smdodd { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 19350826Smdodd { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 19450826Smdodd { 0, }, 19550826Smdodd}; 19650826Smdodd 19750826Smdoddstatic int 19850826Smdoddmse_isa_probe(device_t dev) 19950826Smdodd{ 20050826Smdodd mse_softc_t *sc; 20150826Smdodd int error; 20250826Smdodd int rid; 20350826Smdodd int i; 20450826Smdodd 20550826Smdodd /* check PnP IDs */ 20650826Smdodd error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 20750826Smdodd if (error == ENXIO) 20850826Smdodd return error; 20950826Smdodd 21050826Smdodd sc = device_get_softc(dev); 21150826Smdodd rid = 0; 21250826Smdodd sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 21350826Smdodd MSE_IOSIZE, RF_ACTIVE); 21450826Smdodd if (sc->sc_port == NULL) 21550826Smdodd return ENXIO; 21650826Smdodd sc->sc_iot = rman_get_bustag(sc->sc_port); 21750826Smdodd sc->sc_ioh = rman_get_bushandle(sc->sc_port); 21850826Smdodd 21950826Smdodd /* 22050826Smdodd * Check for each mouse type in the table. 22150826Smdodd */ 22250826Smdodd i = 0; 22350826Smdodd while (mse_types[i].m_type) { 22450826Smdodd if ((*mse_types[i].m_probe)(dev, sc)) { 22550826Smdodd sc->sc_mousetype = mse_types[i].m_type; 22650826Smdodd sc->sc_enablemouse = mse_types[i].m_enable; 22750826Smdodd sc->sc_disablemouse = mse_types[i].m_disable; 22850826Smdodd sc->sc_getmouse = mse_types[i].m_get; 22950826Smdodd sc->hw = mse_types[i].m_hw; 23050826Smdodd sc->mode = mse_types[i].m_mode; 23150826Smdodd bus_release_resource(dev, SYS_RES_IOPORT, rid, 23250826Smdodd sc->sc_port); 23350826Smdodd device_set_desc(dev, "Bus/InPort Mouse"); 23450826Smdodd return 0; 23550826Smdodd } 23650826Smdodd i++; 23750826Smdodd } 23850826Smdodd bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 23950826Smdodd return ENXIO; 24050826Smdodd} 24150826Smdodd 24250826Smdoddstatic int 24350826Smdoddmse_isa_attach(device_t dev) 24450826Smdodd{ 24550826Smdodd mse_softc_t *sc; 24650826Smdodd int rid; 24750826Smdodd 24850826Smdodd sc = device_get_softc(dev); 24950826Smdodd 25050826Smdodd rid = 0; 25150826Smdodd sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 25250826Smdodd MSE_IOSIZE, RF_ACTIVE); 25350826Smdodd if (sc->sc_port == NULL) 25450826Smdodd return ENXIO; 25550826Smdodd sc->sc_iot = rman_get_bustag(sc->sc_port); 25650826Smdodd sc->sc_ioh = rman_get_bushandle(sc->sc_port); 25750826Smdodd 25850826Smdodd return (mse_common_attach(dev)); 25950826Smdodd} 26050826Smdodd 26150826Smdoddstatic int 26250826Smdoddmse_isa_detach(device_t dev) 26350826Smdodd{ 26450826Smdodd mse_softc_t *sc; 26550826Smdodd int rid; 26650826Smdodd 26750826Smdodd sc = device_get_softc(dev); 26850826Smdodd if (sc->sc_flags & MSESC_OPEN) 26950826Smdodd return EBUSY; 27050826Smdodd 27150826Smdodd rid = 0; 27250826Smdodd BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 27350826Smdodd bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 27450826Smdodd bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 27550826Smdodd 27650826Smdodd destroy_dev(sc->sc_dev); 27750826Smdodd destroy_dev(sc->sc_ndev); 27850826Smdodd 27950826Smdodd return 0; 28050826Smdodd} 28150826Smdodd 28250826Smdodd/* 28350826Smdodd * Routines for the Logitech mouse. 28450826Smdodd */ 28550826Smdodd/* 28650826Smdodd * Test for a Logitech bus mouse and return 1 if it is. 28750826Smdodd * (until I know how to use the signature port properly, just disable 28850826Smdodd * interrupts and return 1) 28950826Smdodd */ 29050826Smdoddstatic int 29150826Smdoddmse_probelogi(device_t dev, mse_softc_t *sc) 29250826Smdodd{ 29350826Smdodd 29450826Smdodd int sig; 29550826Smdodd 29650826Smdodd bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP); 29750826Smdodd /* set the signature port */ 29850826Smdodd bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG); 29950826Smdodd 30050826Smdodd DELAY(30000); /* 30 ms delay */ 30150826Smdodd sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF; 30250826Smdodd if (sig == MSE_LOGI_SIG) { 30350826Smdodd bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC, 30450826Smdodd MSE_DISINTR); 30550826Smdodd return(1); 30650826Smdodd } else { 30750826Smdodd if (bootverbose) 30850826Smdodd device_printf(dev, "wrong signature %x\n", sig); 30950826Smdodd return(0); 31050826Smdodd } 31150826Smdodd} 31250826Smdodd 31350826Smdodd/* 31450826Smdodd * Initialize Logitech mouse and enable interrupts. 31550826Smdodd */ 31650826Smdoddstatic void 31750826Smdoddmse_enablelogi(bus_space_tag_t tag, bus_space_handle_t handle) 31850826Smdodd{ 31950826Smdodd int dx, dy, but; 32050826Smdodd 32150826Smdodd bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP); 32250826Smdodd mse_getlogi(tag, handle, &dx, &dy, &but); 32350826Smdodd} 32450826Smdodd 325/* 326 * Disable interrupts for Logitech mouse. 327 */ 328static void 329mse_disablelogi(bus_space_tag_t tag, bus_space_handle_t handle) 330{ 331 332 bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR); 333} 334 335/* 336 * Get the current dx, dy and button up/down state. 337 */ 338static void 339mse_getlogi(bus_space_tag_t tag, bus_space_handle_t handle, int *dx, int *dy, 340 int *but) 341{ 342 register char x, y; 343 344 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 345 x = bus_space_read_1(tag, handle, MSE_PORTA); 346 *but = (x >> 5) & MOUSE_MSC_BUTTONS; 347 x &= 0xf; 348 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 349 x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 350 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 351 y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf); 352 bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 353 y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 354 *dx = x; 355 *dy = y; 356 bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN); 357} 358 359/* 360 * Routines for the ATI Inport bus mouse. 361 */ 362/* 363 * Test for an ATI Inport bus mouse and return 1 if it is. 364 * (do not enable interrupts) 365 */ 366static int 367mse_probeati(device_t dev, mse_softc_t *sc) 368{ 369 int i; 370 371 for (i = 0; i < 2; i++) 372 if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde) 373 return (1); 374 return (0); 375} 376 377/* 378 * Initialize ATI Inport mouse and enable interrupts. 379 */ 380static void 381mse_enableati(bus_space_tag_t tag, bus_space_handle_t handle) 382{ 383 384 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET); 385 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 386 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 387} 388 389/* 390 * Disable interrupts for ATI Inport mouse. 391 */ 392static void 393mse_disableati(bus_space_tag_t tag, bus_space_handle_t handle) 394{ 395 396 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 397 bus_space_write_1(tag, handle, MSE_PORTB, 0); 398} 399 400/* 401 * Get current dx, dy and up/down button state. 402 */ 403static void 404mse_getati(bus_space_tag_t tag, bus_space_handle_t handle, int *dx, int *dy, 405 int *but) 406{ 407 char byte; 408 409 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 410 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD); 411 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS); 412 *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS; 413 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX); 414 byte = bus_space_read_1(tag, handle, MSE_PORTB); 415 *dx = byte; 416 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY); 417 byte = bus_space_read_1(tag, handle, MSE_PORTB); 418 *dy = byte; 419 bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 420 bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 421} 422