mse_cbus.c revision 139749
1/*- 2 * Copyright (c) 2004 M. Warner Losh 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification, immediately at the beginning of the file. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in 13 * the documentation and/or other materials provided with the 14 * distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 20 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD: head/sys/dev/mse/mse_cbus.c 139749 2005-01-06 01:43:34Z imp $ 29 */ 30 31/* 32 * Copyright 1992 by the University of Guelph 33 * 34 * Permission to use, copy and modify this 35 * software and its documentation for any purpose and without 36 * fee is hereby granted, provided that the above copyright 37 * notice appear in all copies and that both that copyright 38 * notice and this permission notice appear in supporting 39 * documentation. 40 * University of Guelph makes no representations about the suitability of 41 * this software for any purpose. It is provided "as is" 42 * without express or implied warranty. 43 */ 44/* 45 * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 46 * the X386 port, courtesy of 47 * Rick Macklem, rick@snowhite.cis.uoguelph.ca 48 * Caveats: The driver currently uses spltty(), but doesn't use any 49 * generic tty code. It could use splmse() (that only masks off the 50 * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 51 * (This may be worth the effort, since the Logitech generates 30/60 52 * interrupts/sec continuously while it is open.) 53 * NB: The ATI has NOT been tested yet! 54 */ 55 56/* 57 * Modification history: 58 * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 59 * improved probe based on input from Logitech. 60 * 61 * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 62 * fixes to make it work with Microsoft InPort busmouse 63 * 64 * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 65 * added patches for new "select" interface 66 * 67 * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 68 * changed position of some spl()'s in mseread 69 * 70 * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 71 * limit maximum negative x/y value to -127 to work around XFree problem 72 * that causes spurious button pushes. 73 */ 74 75#include <sys/param.h> 76#include <sys/systm.h> 77#include <sys/conf.h> 78#include <sys/kernel.h> 79#include <sys/module.h> 80#include <sys/bus.h> 81#include <sys/poll.h> 82#include <sys/selinfo.h> 83#include <sys/uio.h> 84#include <sys/mouse.h> 85 86#include <machine/bus.h> 87#include <machine/clock.h> 88#include <machine/resource.h> 89#include <sys/rman.h> 90 91#include <isa/isavar.h> 92 93#include <dev/mse/msevar.h> 94 95static int mse_probe(device_t dev); 96static int mse_attach(device_t dev); 97static int mse_detach(device_t dev); 98 99static device_method_t mse_methods[] = { 100 DEVMETHOD(device_probe, mse_probe), 101 DEVMETHOD(device_attach, mse_attach), 102 DEVMETHOD(device_detach, mse_detach), 103 { 0, 0 } 104}; 105 106static driver_t mse_driver = { 107 "mse", 108 mse_methods, 109 sizeof(mse_softc_t), 110}; 111 112DRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 113 114static struct isa_pnp_id mse_ids[] = { 115#if 0 116 { 0x001fa3b8, "PC-98 bus mouse" }, /* NEC1F00 */ 117#endif 118 { 0 } 119}; 120 121/* 122 * PC-9801 Bus mouse definitions 123 */ 124 125#define MODE MSE_PORTD 126#define HC MSE_PORTD 127#define INT MSE_PORTD 128 129#define XL 0x00 130#define XH 0x20 131#define YL 0x40 132#define YH 0x60 133 134#define INT_ENABLE 0x8 135#define INT_DISABLE 0x9 136#define HC_NO_CLEAR 0xe 137#define HC_CLEAR 0xf 138 139static bus_addr_t mse_port[] = {0, 2, 4, 6}; 140 141static int mse_probe98m(device_t dev, mse_softc_t *sc); 142static void mse_disable98m(bus_space_tag_t t, bus_space_handle_t h); 143static void mse_get98m(bus_space_tag_t t, bus_space_handle_t h, 144 int *dx, int *dy, int *but); 145static void mse_enable98m(bus_space_tag_t t, bus_space_handle_t h); 146 147static struct mse_types mse_types[] = { 148 { MSE_98BUSMOUSE, 149 mse_probe98m, mse_enable98m, mse_disable98m, mse_get98m, 150 { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 151 { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 152 { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 153 { 0, }, 154}; 155 156static int 157mse_probe(dev) 158 device_t dev; 159{ 160 mse_softc_t *sc; 161 int error; 162 int rid; 163 int i; 164 165 /* check PnP IDs */ 166 error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 167 if (error == ENXIO) 168 return error; 169 170 sc = device_get_softc(dev); 171 rid = 0; 172 sc->sc_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, mse_port, 173 MSE_IOSIZE, RF_ACTIVE); 174 if (sc->sc_port == NULL) 175 return ENXIO; 176 if (isa_load_resourcev(sc->sc_port, mse_port, MSE_IOSIZE)) { 177 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 178 return ENXIO; 179 } 180 sc->sc_iot = rman_get_bustag(sc->sc_port); 181 sc->sc_ioh = rman_get_bushandle(sc->sc_port); 182 183 /* 184 * Check for each mouse type in the table. 185 */ 186 i = 0; 187 while (mse_types[i].m_type) { 188 if ((*mse_types[i].m_probe)(dev, sc)) { 189 sc->sc_mousetype = mse_types[i].m_type; 190 sc->sc_enablemouse = mse_types[i].m_enable; 191 sc->sc_disablemouse = mse_types[i].m_disable; 192 sc->sc_getmouse = mse_types[i].m_get; 193 sc->hw = mse_types[i].m_hw; 194 sc->mode = mse_types[i].m_mode; 195 bus_release_resource(dev, SYS_RES_IOPORT, rid, 196 sc->sc_port); 197 device_set_desc(dev, "Bus/InPort Mouse"); 198 return 0; 199 } 200 i++; 201 } 202 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 203 return ENXIO; 204} 205 206static int 207mse_attach(dev) 208 device_t dev; 209{ 210 mse_softc_t *sc; 211 int rid; 212 213 sc = device_get_softc(dev); 214 215 rid = 0; 216 sc->sc_port = isa_alloc_resourcev(dev, SYS_RES_IOPORT, &rid, mse_port, 217 MSE_IOSIZE, RF_ACTIVE); 218 if (sc->sc_port == NULL) 219 return ENXIO; 220 if (isa_load_resourcev(sc->sc_port, mse_port, MSE_IOSIZE)) { 221 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 222 return ENXIO; 223 } 224 sc->sc_iot = rman_get_bustag(sc->sc_port); 225 sc->sc_ioh = rman_get_bushandle(sc->sc_port); 226 227 return (mse_common_attach(dev)); 228} 229 230static int 231mse_detach(dev) 232 device_t dev; 233{ 234 mse_softc_t *sc; 235 int rid; 236 237 sc = device_get_softc(dev); 238 if (sc->sc_flags & MSESC_OPEN) 239 return EBUSY; 240 241 rid = 0; 242 BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 243 bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 244 bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 245 246 destroy_dev(sc->sc_dev); 247 destroy_dev(sc->sc_ndev); 248 249 return 0; 250} 251 252/* 253 * Routines for the PC98 bus mouse. 254 */ 255 256/* 257 * Test for a PC98 bus mouse and return 1 if it is. 258 * (do not enable interrupts) 259 */ 260static int 261mse_probe98m(dev, sc) 262 device_t dev; 263 mse_softc_t *sc; 264{ 265 /* mode set */ 266 bus_space_write_1(sc->sc_iot, sc->sc_ioh, MODE, 0x93); 267 268 /* initialize */ 269 /* INT disable */ 270 bus_space_write_1(sc->sc_iot, sc->sc_ioh, INT, INT_DISABLE); 271 /* HC = 0 */ 272 bus_space_write_1(sc->sc_iot, sc->sc_ioh, HC, HC_NO_CLEAR); 273 /* HC = 1 */ 274 bus_space_write_1(sc->sc_iot, sc->sc_ioh, HC, HC_CLEAR); 275 276 return (1); 277} 278 279/* 280 * Initialize PC98 bus mouse and enable interrupts. 281 */ 282static void 283mse_enable98m(tag, handle) 284 bus_space_tag_t tag; 285 bus_space_handle_t handle; 286{ 287 bus_space_write_1(tag, handle, INT, INT_ENABLE); /* INT enable */ 288 bus_space_write_1(tag, handle, HC, HC_NO_CLEAR); /* HC = 0 */ 289 bus_space_write_1(tag, handle, HC, HC_CLEAR); /* HC = 1 */ 290} 291 292/* 293 * Disable interrupts for PC98 Bus mouse. 294 */ 295static void 296mse_disable98m(tag, handle) 297 bus_space_tag_t tag; 298 bus_space_handle_t handle; 299{ 300 bus_space_write_1(tag, handle, INT, INT_DISABLE); /* INT disable */ 301 bus_space_write_1(tag, handle, HC, HC_NO_CLEAR); /* HC = 0 */ 302 bus_space_write_1(tag, handle, HC, HC_CLEAR); /* HC = 1 */ 303} 304 305/* 306 * Get current dx, dy and up/down button state. 307 */ 308static void 309mse_get98m(tag, handle, dx, dy, but) 310 bus_space_tag_t tag; 311 bus_space_handle_t handle; 312 int *dx; 313 int *dy; 314 int *but; 315{ 316 register char x, y; 317 318 bus_space_write_1(tag, handle, INT, INT_DISABLE); /* INT disable */ 319 320 bus_space_write_1(tag, handle, HC, HC_CLEAR); /* HC = 1 */ 321 322 /* X low */ 323 bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | XL); 324 x = bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f; 325 /* X high */ 326 bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | XH); 327 x |= ((bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f) << 4); 328 329 /* Y low */ 330 bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | YL); 331 y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f); 332 /* Y high */ 333 bus_space_write_1(tag, handle, MSE_PORTC, 0x90 | YH); 334 y |= ((bus_space_read_1(tag, handle, MSE_PORTA) & 0x0f) << 4); 335 336 *but = (bus_space_read_1(tag, handle, MSE_PORTA) >> 5) & 7; 337 338 *dx = x; 339 *dy = y; 340 341 bus_space_write_1(tag, handle, HC, HC_NO_CLEAR); /* HC = 0 */ 342 343 bus_space_write_1(tag, handle, INT, INT_ENABLE); /* INT enable */ 344} 345