mse.c revision 58229
1637Snate/* 2637Snate * Copyright 1992 by the University of Guelph 3637Snate * 4637Snate * Permission to use, copy and modify this 5637Snate * software and its documentation for any purpose and without 6637Snate * fee is hereby granted, provided that the above copyright 7637Snate * notice appear in all copies and that both that copyright 8637Snate * notice and this permission notice appear in supporting 9637Snate * documentation. 10637Snate * University of Guelph makes no representations about the suitability of 11637Snate * this software for any purpose. It is provided "as is" 12637Snate * without express or implied warranty. 131817Sdg * 1450477Speter * $FreeBSD: head/sys/dev/mse/mse.c 58229 2000-03-18 15:13:30Z yokota $ 15637Snate */ 16637Snate/* 17637Snate * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 18637Snate * the X386 port, courtesy of 19637Snate * Rick Macklem, rick@snowhite.cis.uoguelph.ca 20637Snate * Caveats: The driver currently uses spltty(), but doesn't use any 21637Snate * generic tty code. It could use splmse() (that only masks off the 22637Snate * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 23637Snate * (This may be worth the effort, since the Logitech generates 30/60 24637Snate * interrupts/sec continuously while it is open.) 25637Snate * NB: The ATI has NOT been tested yet! 26637Snate */ 27637Snate 28637Snate/* 29637Snate * Modification history: 304259Sjkh * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 314259Sjkh * improved probe based on input from Logitech. 32637Snate * 33637Snate * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 34637Snate * fixes to make it work with Microsoft InPort busmouse 35637Snate * 36637Snate * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 37637Snate * added patches for new "select" interface 38637Snate * 39637Snate * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 40637Snate * changed position of some spl()'s in mseread 41637Snate * 42637Snate * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 43637Snate * limit maximum negative x/y value to -127 to work around XFree problem 44637Snate * that causes spurious button pushes. 45637Snate */ 46637Snate 472056Swollman#include <sys/param.h> 483745Swollman#include <sys/systm.h> 4912658Sbde#include <sys/conf.h> 502056Swollman#include <sys/kernel.h> 5158229Syokota#include <sys/bus.h> 5229368Speter#include <sys/poll.h> 5331254Sbde#include <sys/select.h> 542056Swollman#include <sys/uio.h> 55637Snate 5658229Syokota#include <machine/bus_pio.h> 5758229Syokota#include <machine/bus.h> 587430Sbde#include <machine/clock.h> 5931603Syokota#include <machine/mouse.h> 6058229Syokota#include <machine/resource.h> 6158229Syokota#include <sys/rman.h> 627430Sbde 6358229Syokota#include <isa/isavar.h> 64637Snate 6531603Syokota/* driver configuration flags (config) */ 6631603Syokota#define MSE_CONFIG_ACCEL 0x00f0 /* acceleration factor */ 6731603Syokota#define MSE_CONFIG_FLAGS (MSE_CONFIG_ACCEL) 6831603Syokota 6958229Syokota/* 7058229Syokota * Software control structure for mouse. The sc_enablemouse(), 7158229Syokota * sc_disablemouse() and sc_getmouse() routines must be called spl'd(). 7258229Syokota */ 7358229Syokotatypedef struct mse_softc { 7458229Syokota int sc_flags; 7558229Syokota int sc_mousetype; 7658229Syokota struct selinfo sc_selp; 7758229Syokota struct resource *sc_port; 7858229Syokota struct resource *sc_intr; 7958229Syokota bus_space_tag_t sc_iot; 8058229Syokota bus_space_handle_t sc_ioh; 8158229Syokota void *sc_ih; 8258229Syokota void (*sc_enablemouse) __P((bus_space_tag_t t, 8358229Syokota bus_space_handle_t h)); 8458229Syokota void (*sc_disablemouse) __P((bus_space_tag_t t, 8558229Syokota bus_space_handle_t h)); 8658229Syokota void (*sc_getmouse) __P((bus_space_tag_t t, 8758229Syokota bus_space_handle_t h, 8858229Syokota int *dx, int *dy, int *but)); 8958229Syokota int sc_deltax; 9058229Syokota int sc_deltay; 9158229Syokota int sc_obuttons; 9258229Syokota int sc_buttons; 9358229Syokota int sc_bytesread; 9458229Syokota u_char sc_bytes[MOUSE_SYS_PACKETSIZE]; 9558229Syokota struct callout_handle sc_callout; 9658229Syokota int sc_watchdog; 9758229Syokota dev_t sc_dev; 9858229Syokota dev_t sc_ndev; 9958229Syokota mousehw_t hw; 10058229Syokota mousemode_t mode; 10158229Syokota mousestatus_t status; 10258229Syokota} mse_softc_t; 103637Snate 10458229Syokotastatic devclass_t mse_devclass; 10558229Syokota 10658229Syokotastatic int mse_probe __P((device_t dev)); 10758229Syokotastatic int mse_attach __P((device_t dev)); 10858229Syokotastatic int mse_detach __P((device_t dev)); 10958229Syokota 11058229Syokotastatic device_method_t mse_methods[] = { 11158229Syokota DEVMETHOD(device_probe, mse_probe), 11258229Syokota DEVMETHOD(device_attach, mse_attach), 11358229Syokota DEVMETHOD(device_detach, mse_detach), 11458229Syokota { 0, 0 } 115637Snate}; 116637Snate 11758229Syokotastatic driver_t mse_driver = { 11858229Syokota "mse", 11958229Syokota mse_methods, 12058229Syokota sizeof(mse_softc_t), 12158229Syokota}; 12258229Syokota 12358229SyokotaDRIVER_MODULE(mse, isa, mse_driver, mse_devclass, 0, 0); 12458229Syokota 12558229Syokotastatic struct isa_pnp_id mse_ids[] = { 12658229Syokota { 0x000fd041, "Bus mouse" }, /* PNP0F00 */ 12758229Syokota { 0x020fd041, "InPort mouse" }, /* PNP0F02 */ 12858229Syokota { 0x0d0fd041, "InPort mouse compatible" }, /* PNP0F0D */ 12958229Syokota { 0x110fd041, "Bus mouse compatible" }, /* PNP0F11 */ 13058229Syokota { 0x150fd041, "Logitech bus mouse" }, /* PNP0F15 */ 13158229Syokota { 0x180fd041, "Logitech bus mouse compatible" },/* PNP0F18 */ 13258229Syokota { 0 } 13358229Syokota}; 13458229Syokota 13512675Sjulianstatic d_open_t mseopen; 13612675Sjulianstatic d_close_t mseclose; 13712675Sjulianstatic d_read_t mseread; 13831603Syokotastatic d_ioctl_t mseioctl; 13929368Speterstatic d_poll_t msepoll; 14012675Sjulian 14112675Sjulian#define CDEV_MAJOR 27 14247625Sphkstatic struct cdevsw mse_cdevsw = { 14347625Sphk /* open */ mseopen, 14447625Sphk /* close */ mseclose, 14547625Sphk /* read */ mseread, 14647625Sphk /* write */ nowrite, 14747625Sphk /* ioctl */ mseioctl, 14847625Sphk /* poll */ msepoll, 14947625Sphk /* mmap */ nommap, 15047625Sphk /* strategy */ nostrategy, 15147625Sphk /* name */ "mse", 15247625Sphk /* maj */ CDEV_MAJOR, 15347625Sphk /* dump */ nodump, 15447625Sphk /* psize */ nopsize, 15547625Sphk /* flags */ 0, 15647625Sphk /* bmaj */ -1 15747625Sphk}; 15812675Sjulian 15958229Syokotastatic void mseintr __P((void *)); 16058229Syokotastatic timeout_t msetimeout; 16112675Sjulian 162637Snate/* Flags */ 163637Snate#define MSESC_OPEN 0x1 164637Snate#define MSESC_WANT 0x2 165637Snate 166637Snate/* and Mouse Types */ 16720688Sjoerg#define MSE_NONE 0 /* don't move this! */ 168637Snate#define MSE_LOGITECH 0x1 169637Snate#define MSE_ATIINPORT 0x2 1704259Sjkh#define MSE_LOGI_SIG 0xA5 171637Snate 172637Snate#define MSE_PORTA 0 173637Snate#define MSE_PORTB 1 174637Snate#define MSE_PORTC 2 175637Snate#define MSE_PORTD 3 17658229Syokota#define MSE_IOSIZE 4 177637Snate 178637Snate#define MSE_UNIT(dev) (minor(dev) >> 1) 179637Snate#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 180637Snate 181637Snate/* 182637Snate * Logitech bus mouse definitions 183637Snate */ 184637Snate#define MSE_SETUP 0x91 /* What does this mean? */ 1854259Sjkh /* The definition for the control port */ 1864259Sjkh /* is as follows: */ 1878876Srgrimes 1884259Sjkh /* D7 = Mode set flag (1 = active) */ 1898876Srgrimes /* D6,D5 = Mode selection (port A) */ 1904259Sjkh /* 00 = Mode 0 = Basic I/O */ 1914259Sjkh /* 01 = Mode 1 = Strobed I/O */ 1924259Sjkh /* 10 = Mode 2 = Bi-dir bus */ 1934259Sjkh /* D4 = Port A direction (1 = input)*/ 1944259Sjkh /* D3 = Port C (upper 4 bits) */ 1954259Sjkh /* direction. (1 = input) */ 1964259Sjkh /* D2 = Mode selection (port B & C) */ 1974259Sjkh /* 0 = Mode 0 = Basic I/O */ 1984259Sjkh /* 1 = Mode 1 = Strobed I/O */ 1994259Sjkh /* D1 = Port B direction (1 = input)*/ 2004259Sjkh /* D0 = Port C (lower 4 bits) */ 2014259Sjkh /* direction. (1 = input) */ 2028876Srgrimes 2034259Sjkh /* So 91 means Basic I/O on all 3 ports,*/ 2044259Sjkh /* Port A is an input port, B is an */ 2054259Sjkh /* output port, C is split with upper */ 2064259Sjkh /* 4 bits being an output port and lower*/ 2074259Sjkh /* 4 bits an input port, and enable the */ 2084259Sjkh /* sucker. */ 2094259Sjkh /* Courtesy Intel 8255 databook. Lars */ 210637Snate#define MSE_HOLD 0x80 211637Snate#define MSE_RXLOW 0x00 212637Snate#define MSE_RXHIGH 0x20 213637Snate#define MSE_RYLOW 0x40 214637Snate#define MSE_RYHIGH 0x60 215637Snate#define MSE_DISINTR 0x10 216637Snate#define MSE_INTREN 0x00 217637Snate 21858229Syokotastatic int mse_probelogi __P((device_t dev, mse_softc_t *sc)); 21958229Syokotastatic void mse_disablelogi __P((bus_space_tag_t t, 22058229Syokota bus_space_handle_t h)); 22158229Syokotastatic void mse_getlogi __P((bus_space_tag_t t, 22258229Syokota bus_space_handle_t h, 22358229Syokota int *dx, int *dy, int *but)); 22458229Syokotastatic void mse_enablelogi __P((bus_space_tag_t t, 22558229Syokota bus_space_handle_t h)); 226637Snate 227637Snate/* 228637Snate * ATI Inport mouse definitions 229637Snate */ 230637Snate#define MSE_INPORT_RESET 0x80 231637Snate#define MSE_INPORT_STATUS 0x00 232637Snate#define MSE_INPORT_DX 0x01 233637Snate#define MSE_INPORT_DY 0x02 234637Snate#define MSE_INPORT_MODE 0x07 235637Snate#define MSE_INPORT_HOLD 0x20 236637Snate#define MSE_INPORT_INTREN 0x09 237637Snate 23858229Syokotastatic int mse_probeati __P((device_t dev, mse_softc_t *sc)); 23958229Syokotastatic void mse_enableati __P((bus_space_tag_t t, 24058229Syokota bus_space_handle_t h)); 24158229Syokotastatic void mse_disableati __P((bus_space_tag_t t, 24258229Syokota bus_space_handle_t h)); 24358229Syokotastatic void mse_getati __P((bus_space_tag_t t, 24458229Syokota bus_space_handle_t h, 24558229Syokota int *dx, int *dy, int *but)); 246637Snate 247637Snate#define MSEPRI (PZERO + 3) 248637Snate 249637Snate/* 250637Snate * Table of mouse types. 251637Snate * Keep the Logitech last, since I haven't figured out how to probe it 252637Snate * properly yet. (Someday I'll have the documentation.) 253637Snate */ 25412724Sphkstatic struct mse_types { 255637Snate int m_type; /* Type of bus mouse */ 25658229Syokota int (*m_probe) __P((device_t dev, mse_softc_t *sc)); 25712854Sbde /* Probe routine to test for it */ 25858229Syokota void (*m_enable) __P((bus_space_tag_t t, bus_space_handle_t h)); 25912854Sbde /* Start routine */ 26058229Syokota void (*m_disable) __P((bus_space_tag_t t, bus_space_handle_t h)); 26112854Sbde /* Disable interrupts routine */ 26258229Syokota void (*m_get) __P((bus_space_tag_t t, bus_space_handle_t h, 26358229Syokota int *dx, int *dy, int *but)); 26412854Sbde /* and get mouse status */ 26531603Syokota mousehw_t m_hw; /* buttons iftype type model hwid */ 26631603Syokota mousemode_t m_mode; /* proto rate res accel level size mask */ 267637Snate} mse_types[] = { 26831603Syokota { MSE_ATIINPORT, 26931603Syokota mse_probeati, mse_enableati, mse_disableati, mse_getati, 27031603Syokota { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 27131603Syokota { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 27231603Syokota { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 27331603Syokota { MSE_LOGITECH, 27431603Syokota mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 27531603Syokota { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 27631603Syokota { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 27731603Syokota { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 278637Snate { 0, }, 279637Snate}; 280637Snate 28158229Syokotastatic int 28258229Syokotamse_probe(dev) 28358229Syokota device_t dev; 284637Snate{ 28558229Syokota mse_softc_t *sc; 28658229Syokota int error; 28758229Syokota int rid; 28858229Syokota int i; 289637Snate 29058229Syokota /* check PnP IDs */ 29158229Syokota error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 29258229Syokota if (error == ENXIO) 29358229Syokota return ENXIO; 29458229Syokota 29558229Syokota sc = device_get_softc(dev); 29658229Syokota rid = 0; 29758229Syokota sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 29858229Syokota MSE_IOSIZE, RF_ACTIVE); 29958229Syokota if (sc->sc_port == NULL) 30058229Syokota return ENXIO; 30158229Syokota sc->sc_iot = rman_get_bustag(sc->sc_port); 30258229Syokota sc->sc_ioh = rman_get_bushandle(sc->sc_port); 30358229Syokota 304637Snate /* 305637Snate * Check for each mouse type in the table. 306637Snate */ 307637Snate i = 0; 308637Snate while (mse_types[i].m_type) { 30958229Syokota if ((*mse_types[i].m_probe)(dev, sc)) { 310637Snate sc->sc_mousetype = mse_types[i].m_type; 311637Snate sc->sc_enablemouse = mse_types[i].m_enable; 312637Snate sc->sc_disablemouse = mse_types[i].m_disable; 313637Snate sc->sc_getmouse = mse_types[i].m_get; 31431603Syokota sc->hw = mse_types[i].m_hw; 31531603Syokota sc->mode = mse_types[i].m_mode; 31658229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, 31758229Syokota sc->sc_port); 31858229Syokota device_set_desc(dev, "Bus/InPort Mouse"); 31958229Syokota return 0; 320637Snate } 321637Snate i++; 322637Snate } 32358229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 32458229Syokota return ENXIO; 325637Snate} 326637Snate 32758229Syokotastatic int 32858229Syokotamse_attach(dev) 32958229Syokota device_t dev; 330637Snate{ 33158229Syokota mse_softc_t *sc; 33258229Syokota int flags; 33358229Syokota int unit; 33458229Syokota int rid; 335637Snate 33658229Syokota sc = device_get_softc(dev); 33758229Syokota unit = device_get_unit(dev); 33858229Syokota 33958229Syokota rid = 0; 34058229Syokota sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 34158229Syokota MSE_IOSIZE, RF_ACTIVE); 34258229Syokota if (sc->sc_port == NULL) 34358229Syokota return ENXIO; 34458229Syokota sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 34558229Syokota RF_ACTIVE); 34658229Syokota if (sc->sc_intr == NULL) { 34758229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 34858229Syokota return ENXIO; 34958229Syokota } 35058229Syokota sc->sc_iot = rman_get_bustag(sc->sc_port); 35158229Syokota sc->sc_ioh = rman_get_bushandle(sc->sc_port); 35258229Syokota 35358229Syokota if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr, 35458229Syokota INTR_TYPE_TTY, mseintr, sc, &sc->sc_ih)) { 35558229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 35658229Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 35758229Syokota return ENXIO; 35858229Syokota } 35958229Syokota 36058229Syokota flags = device_get_flags(dev); 36158229Syokota sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4; 36258229Syokota callout_handle_init(&sc->sc_callout); 36358229Syokota 36458229Syokota sc->sc_dev = make_dev(&mse_cdevsw, unit << 1, 0, 0, 0600, 36558229Syokota "mse%d", unit); 36658229Syokota sc->sc_ndev = make_dev(&mse_cdevsw, (unit<<1)+1, 0, 0, 0600, 36758229Syokota "nmse%d", unit); 36858229Syokota 36958229Syokota return 0; 370637Snate} 371637Snate 37258229Syokotastatic int 37358229Syokotamse_detach(dev) 37458229Syokota device_t dev; 37558229Syokota{ 37658229Syokota mse_softc_t *sc; 37758229Syokota int rid; 37858229Syokota 37958229Syokota sc = device_get_softc(dev); 38058229Syokota if (sc->sc_flags & MSESC_OPEN) 38158229Syokota return EBUSY; 38258229Syokota 38358229Syokota rid = 0; 38458229Syokota BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 38558229Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 38658229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 38758229Syokota 38858229Syokota destroy_dev(sc->sc_dev); 38958229Syokota destroy_dev(sc->sc_ndev); 39058229Syokota 39158229Syokota return 0; 39258229Syokota} 39358229Syokota 394637Snate/* 395637Snate * Exclusive open the mouse, initialize it and enable interrupts. 396637Snate */ 39712675Sjulianstatic int 39810624Sbdemseopen(dev, flags, fmt, p) 399637Snate dev_t dev; 40010624Sbde int flags; 40110624Sbde int fmt; 40210624Sbde struct proc *p; 403637Snate{ 40458229Syokota mse_softc_t *sc; 405637Snate int s; 406637Snate 40758229Syokota sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 40858229Syokota if (sc == NULL) 409637Snate return (ENXIO); 41020688Sjoerg if (sc->sc_mousetype == MSE_NONE) 41120688Sjoerg return (ENXIO); 412637Snate if (sc->sc_flags & MSESC_OPEN) 413637Snate return (EBUSY); 414637Snate sc->sc_flags |= MSESC_OPEN; 41531603Syokota sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS; 416637Snate sc->sc_deltax = sc->sc_deltay = 0; 41731603Syokota sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE; 41858229Syokota sc->sc_watchdog = FALSE; 41958229Syokota sc->sc_callout = timeout(msetimeout, dev, hz*2); 42031603Syokota sc->mode.level = 0; 42131603Syokota sc->status.flags = 0; 42231603Syokota sc->status.button = sc->status.obutton = 0; 42331603Syokota sc->status.dx = sc->status.dy = sc->status.dz = 0; 424637Snate 425637Snate /* 426637Snate * Initialize mouse interface and enable interrupts. 427637Snate */ 428637Snate s = spltty(); 42958229Syokota (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh); 430637Snate splx(s); 431637Snate return (0); 432637Snate} 433637Snate 434637Snate/* 435637Snate * mseclose: just turn off mouse innterrupts. 436637Snate */ 43712675Sjulianstatic int 43810624Sbdemseclose(dev, flags, fmt, p) 439798Swollman dev_t dev; 44010624Sbde int flags; 44110624Sbde int fmt; 44210624Sbde struct proc *p; 443637Snate{ 44458229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 445637Snate int s; 446637Snate 44758229Syokota untimeout(msetimeout, dev, sc->sc_callout); 44858229Syokota callout_handle_init(&sc->sc_callout); 449637Snate s = spltty(); 45058229Syokota (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh); 451637Snate sc->sc_flags &= ~MSESC_OPEN; 452637Snate splx(s); 453637Snate return(0); 454637Snate} 455637Snate 4568876Srgrimes/* 457637Snate * mseread: return mouse info using the MSC serial protocol, but without 458637Snate * using bytes 4 and 5. 459637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...) 460637Snate */ 46112675Sjulianstatic int 46210624Sbdemseread(dev, uio, ioflag) 463637Snate dev_t dev; 464637Snate struct uio *uio; 46510624Sbde int ioflag; 466637Snate{ 46758229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 468637Snate int xfer, s, error; 469637Snate 470637Snate /* 471637Snate * If there are no protocol bytes to be read, set up a new protocol 472637Snate * packet. 473637Snate */ 474637Snate s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 47531603Syokota if (sc->sc_bytesread >= sc->mode.packetsize) { 476637Snate while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 477637Snate (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 478637Snate if (MSE_NBLOCKIO(dev)) { 479637Snate splx(s); 480637Snate return (0); 481637Snate } 482637Snate sc->sc_flags |= MSESC_WANT; 48346571Speter error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 48446571Speter "mseread", 0); 48546571Speter if (error) { 486637Snate splx(s); 487637Snate return (error); 488637Snate } 489637Snate } 490637Snate 491637Snate /* 492637Snate * Generate protocol bytes. 493637Snate * For some reason X386 expects 5 bytes but never uses 494637Snate * the fourth or fifth? 495637Snate */ 49631603Syokota sc->sc_bytes[0] = sc->mode.syncmask[1] 49731603Syokota | (sc->sc_buttons & ~sc->mode.syncmask[0]); 498637Snate if (sc->sc_deltax > 127) 499637Snate sc->sc_deltax = 127; 500637Snate if (sc->sc_deltax < -127) 501637Snate sc->sc_deltax = -127; 502637Snate sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 503637Snate if (sc->sc_deltay > 127) 504637Snate sc->sc_deltay = 127; 505637Snate if (sc->sc_deltay < -127) 506637Snate sc->sc_deltay = -127; 507637Snate sc->sc_bytes[1] = sc->sc_deltax; 508637Snate sc->sc_bytes[2] = sc->sc_deltay; 509637Snate sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 51031603Syokota sc->sc_bytes[5] = sc->sc_bytes[6] = 0; 51131603Syokota sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS; 512637Snate sc->sc_obuttons = sc->sc_buttons; 513637Snate sc->sc_deltax = sc->sc_deltay = 0; 514637Snate sc->sc_bytesread = 0; 515637Snate } 516637Snate splx(s); 51731603Syokota xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread); 51846571Speter error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio); 51946571Speter if (error) 520637Snate return (error); 521637Snate sc->sc_bytesread += xfer; 522637Snate return(0); 523637Snate} 524637Snate 525637Snate/* 52631603Syokota * mseioctl: process ioctl commands. 52731603Syokota */ 52831603Syokotastatic int 52931603Syokotamseioctl(dev, cmd, addr, flag, p) 53031603Syokota dev_t dev; 53136735Sdfr u_long cmd; 53231603Syokota caddr_t addr; 53331603Syokota int flag; 53431603Syokota struct proc *p; 53531603Syokota{ 53658229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 53731603Syokota mousestatus_t status; 53831603Syokota int err = 0; 53931603Syokota int s; 54031603Syokota 54131603Syokota switch (cmd) { 54231603Syokota 54331603Syokota case MOUSE_GETHWINFO: 54431603Syokota s = spltty(); 54531603Syokota *(mousehw_t *)addr = sc->hw; 54631603Syokota if (sc->mode.level == 0) 54731603Syokota ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 54831603Syokota splx(s); 54931603Syokota break; 55031603Syokota 55131603Syokota case MOUSE_GETMODE: 55231603Syokota s = spltty(); 55331603Syokota *(mousemode_t *)addr = sc->mode; 55431603Syokota switch (sc->mode.level) { 55531603Syokota case 0: 55631603Syokota break; 55731603Syokota case 1: 55831603Syokota ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 55931603Syokota ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 56031603Syokota ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 56131603Syokota break; 56231603Syokota } 56331603Syokota splx(s); 56431603Syokota break; 56531603Syokota 56631603Syokota case MOUSE_SETMODE: 56731603Syokota switch (((mousemode_t *)addr)->level) { 56831603Syokota case 0: 56931603Syokota case 1: 57031603Syokota break; 57131603Syokota default: 57231603Syokota return (EINVAL); 57331603Syokota } 57431603Syokota if (((mousemode_t *)addr)->accelfactor < -1) 57531603Syokota return (EINVAL); 57631603Syokota else if (((mousemode_t *)addr)->accelfactor >= 0) 57731603Syokota sc->mode.accelfactor = 57831603Syokota ((mousemode_t *)addr)->accelfactor; 57931603Syokota sc->mode.level = ((mousemode_t *)addr)->level; 58031603Syokota switch (sc->mode.level) { 58131603Syokota case 0: 58231603Syokota sc->sc_bytesread = sc->mode.packetsize 58331603Syokota = MOUSE_MSC_PACKETSIZE; 58431603Syokota break; 58531603Syokota case 1: 58631603Syokota sc->sc_bytesread = sc->mode.packetsize 58731603Syokota = MOUSE_SYS_PACKETSIZE; 58831603Syokota break; 58931603Syokota } 59031603Syokota break; 59131603Syokota 59231603Syokota case MOUSE_GETLEVEL: 59331603Syokota *(int *)addr = sc->mode.level; 59431603Syokota break; 59531603Syokota 59631603Syokota case MOUSE_SETLEVEL: 59731603Syokota switch (*(int *)addr) { 59831603Syokota case 0: 59931603Syokota sc->mode.level = *(int *)addr; 60031603Syokota sc->sc_bytesread = sc->mode.packetsize 60131603Syokota = MOUSE_MSC_PACKETSIZE; 60231603Syokota break; 60331603Syokota case 1: 60431603Syokota sc->mode.level = *(int *)addr; 60531603Syokota sc->sc_bytesread = sc->mode.packetsize 60631603Syokota = MOUSE_SYS_PACKETSIZE; 60731603Syokota break; 60831603Syokota default: 60931603Syokota return (EINVAL); 61031603Syokota } 61131603Syokota break; 61231603Syokota 61331603Syokota case MOUSE_GETSTATUS: 61431603Syokota s = spltty(); 61531603Syokota status = sc->status; 61631603Syokota sc->status.flags = 0; 61731603Syokota sc->status.obutton = sc->status.button; 61831603Syokota sc->status.button = 0; 61931603Syokota sc->status.dx = 0; 62031603Syokota sc->status.dy = 0; 62131603Syokota sc->status.dz = 0; 62231603Syokota splx(s); 62331603Syokota *(mousestatus_t *)addr = status; 62431603Syokota break; 62531603Syokota 62631603Syokota case MOUSE_READSTATE: 62731603Syokota case MOUSE_READDATA: 62831603Syokota return (ENODEV); 62931603Syokota 63031603Syokota#if (defined(MOUSE_GETVARS)) 63131603Syokota case MOUSE_GETVARS: 63231603Syokota case MOUSE_SETVARS: 63331603Syokota return (ENODEV); 63431603Syokota#endif 63531603Syokota 63631603Syokota default: 63731603Syokota return (ENOTTY); 63831603Syokota } 63931603Syokota return (err); 64031603Syokota} 64131603Syokota 64231603Syokota/* 64329368Speter * msepoll: check for mouse input to be processed. 644637Snate */ 64512675Sjulianstatic int 64629368Spetermsepoll(dev, events, p) 647637Snate dev_t dev; 64829368Speter int events; 649637Snate struct proc *p; 650637Snate{ 65158229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 652637Snate int s; 65329368Speter int revents = 0; 654637Snate 655637Snate s = spltty(); 65646568Speter if (events & (POLLIN | POLLRDNORM)) { 65731603Syokota if (sc->sc_bytesread != sc->mode.packetsize || 65831603Syokota sc->sc_deltax != 0 || sc->sc_deltay != 0 || 65929368Speter (sc->sc_obuttons ^ sc->sc_buttons) != 0) 66029368Speter revents |= events & (POLLIN | POLLRDNORM); 66129368Speter else { 66229368Speter /* 66329368Speter * Since this is an exclusive open device, any previous 66429368Speter * proc pointer is trash now, so we can just assign it. 66529368Speter */ 66629368Speter selrecord(p, &sc->sc_selp); 66729368Speter } 66846568Speter } 669637Snate splx(s); 67029368Speter return (revents); 671637Snate} 672637Snate 673637Snate/* 67458229Syokota * msetimeout: watchdog timer routine. 67558229Syokota */ 67658229Syokotastatic void 67758229Syokotamsetimeout(arg) 67858229Syokota void *arg; 67958229Syokota{ 68058229Syokota dev_t dev; 68158229Syokota mse_softc_t *sc; 68258229Syokota 68358229Syokota dev = (dev_t)arg; 68458229Syokota sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 68558229Syokota if (sc->sc_watchdog) { 68658229Syokota if (bootverbose) 68758229Syokota printf("mse%d: lost interrupt?\n", MSE_UNIT(dev)); 68858229Syokota mseintr(sc); 68958229Syokota } 69058229Syokota sc->sc_watchdog = TRUE; 69158229Syokota sc->sc_callout = timeout(msetimeout, dev, hz); 69258229Syokota} 69358229Syokota 69458229Syokota/* 695637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 696637Snate */ 69740565Sbdestatic void 69858229Syokotamseintr(arg) 69958229Syokota void *arg; 700637Snate{ 70131603Syokota /* 70231603Syokota * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP) 70331603Syokota * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 70431603Syokota */ 70531603Syokota static int butmap[8] = { 70631603Syokota 0, 70731603Syokota MOUSE_BUTTON3DOWN, 70831603Syokota MOUSE_BUTTON2DOWN, 70931603Syokota MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 71031603Syokota MOUSE_BUTTON1DOWN, 71131603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 71231603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 71331603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 71431603Syokota }; 71558229Syokota mse_softc_t *sc = arg; 71631603Syokota int dx, dy, but; 71731603Syokota int sign; 718637Snate 719637Snate#ifdef DEBUG 720637Snate static int mse_intrcnt = 0; 721637Snate if((mse_intrcnt++ % 10000) == 0) 722637Snate printf("mseintr\n"); 723637Snate#endif /* DEBUG */ 724637Snate if ((sc->sc_flags & MSESC_OPEN) == 0) 725637Snate return; 726637Snate 72758229Syokota (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but); 72831603Syokota if (sc->mode.accelfactor > 0) { 72931603Syokota sign = (dx < 0); 73031603Syokota dx = dx * dx / sc->mode.accelfactor; 73131603Syokota if (dx == 0) 73231603Syokota dx = 1; 73331603Syokota if (sign) 73431603Syokota dx = -dx; 73531603Syokota sign = (dy < 0); 73631603Syokota dy = dy * dy / sc->mode.accelfactor; 73731603Syokota if (dy == 0) 73831603Syokota dy = 1; 73931603Syokota if (sign) 74031603Syokota dy = -dy; 74131603Syokota } 74231603Syokota sc->sc_deltax += dx; 74331603Syokota sc->sc_deltay += dy; 74431603Syokota sc->sc_buttons = but; 745637Snate 74631603Syokota but = butmap[~but & MOUSE_MSC_BUTTONS]; 74731603Syokota sc->status.dx += dx; 74831603Syokota sc->status.dy += dy; 74931603Syokota sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0) 75031603Syokota | (sc->status.button ^ but); 75131603Syokota sc->status.button = but; 75231603Syokota 75358229Syokota sc->sc_watchdog = FALSE; 75458229Syokota 755637Snate /* 756637Snate * If mouse state has changed, wake up anyone wanting to know. 757637Snate */ 758637Snate if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 759637Snate (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 7608876Srgrimes if (sc->sc_flags & MSESC_WANT) { 7618876Srgrimes sc->sc_flags &= ~MSESC_WANT; 7628876Srgrimes wakeup((caddr_t)sc); 7638876Srgrimes } 7641549Srgrimes selwakeup(&sc->sc_selp); 765637Snate } 766637Snate} 767637Snate 768637Snate/* 769637Snate * Routines for the Logitech mouse. 770637Snate */ 771637Snate/* 772637Snate * Test for a Logitech bus mouse and return 1 if it is. 773637Snate * (until I know how to use the signature port properly, just disable 774637Snate * interrupts and return 1) 775637Snate */ 776637Snatestatic int 77758229Syokotamse_probelogi(dev, sc) 77858229Syokota device_t dev; 77958229Syokota mse_softc_t *sc; 780637Snate{ 781637Snate 7824259Sjkh int sig; 7834259Sjkh 78458229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP); 7854259Sjkh /* set the signature port */ 78658229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG); 7874259Sjkh 7884259Sjkh DELAY(30000); /* 30 ms delay */ 78958229Syokota sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF; 7904259Sjkh if (sig == MSE_LOGI_SIG) { 79158229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC, 79258229Syokota MSE_DISINTR); 7934259Sjkh return(1); 7944259Sjkh } else { 79516074Sjoerg if (bootverbose) 79658229Syokota device_printf(dev, "wrong signature %x\n", sig); 7974259Sjkh return(0); 798637Snate } 799637Snate} 800637Snate 801637Snate/* 802637Snate * Initialize Logitech mouse and enable interrupts. 803637Snate */ 804637Snatestatic void 80558229Syokotamse_enablelogi(tag, handle) 80658229Syokota bus_space_tag_t tag; 80758229Syokota bus_space_handle_t handle; 808637Snate{ 809637Snate int dx, dy, but; 810637Snate 81158229Syokota bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP); 81258229Syokota mse_getlogi(tag, handle, &dx, &dy, &but); 813637Snate} 814637Snate 815637Snate/* 816637Snate * Disable interrupts for Logitech mouse. 817637Snate */ 818637Snatestatic void 81958229Syokotamse_disablelogi(tag, handle) 82058229Syokota bus_space_tag_t tag; 82158229Syokota bus_space_handle_t handle; 822637Snate{ 823637Snate 82458229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR); 825637Snate} 826637Snate 827637Snate/* 828637Snate * Get the current dx, dy and button up/down state. 829637Snate */ 830637Snatestatic void 83158229Syokotamse_getlogi(tag, handle, dx, dy, but) 83258229Syokota bus_space_tag_t tag; 83358229Syokota bus_space_handle_t handle; 834637Snate int *dx; 835637Snate int *dy; 836637Snate int *but; 837637Snate{ 838637Snate register char x, y; 839637Snate 84058229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 84158229Syokota x = bus_space_read_1(tag, handle, MSE_PORTA); 84231603Syokota *but = (x >> 5) & MOUSE_MSC_BUTTONS; 843637Snate x &= 0xf; 84458229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 84558229Syokota x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 84658229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 84758229Syokota y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf); 84858229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 84958229Syokota y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 85031603Syokota *dx = x; 85131603Syokota *dy = y; 85258229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN); 853637Snate} 854637Snate 855637Snate/* 856637Snate * Routines for the ATI Inport bus mouse. 857637Snate */ 858637Snate/* 859637Snate * Test for a ATI Inport bus mouse and return 1 if it is. 860637Snate * (do not enable interrupts) 861637Snate */ 862637Snatestatic int 86358229Syokotamse_probeati(dev, sc) 86458229Syokota device_t dev; 86558229Syokota mse_softc_t *sc; 866637Snate{ 867637Snate int i; 868637Snate 869637Snate for (i = 0; i < 2; i++) 87058229Syokota if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde) 871637Snate return (1); 872637Snate return (0); 873637Snate} 874637Snate 875637Snate/* 876637Snate * Initialize ATI Inport mouse and enable interrupts. 877637Snate */ 878637Snatestatic void 87958229Syokotamse_enableati(tag, handle) 88058229Syokota bus_space_tag_t tag; 88158229Syokota bus_space_handle_t handle; 882637Snate{ 883637Snate 88458229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET); 88558229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 88658229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 887637Snate} 888637Snate 889637Snate/* 890637Snate * Disable interrupts for ATI Inport mouse. 891637Snate */ 892637Snatestatic void 89358229Syokotamse_disableati(tag, handle) 89458229Syokota bus_space_tag_t tag; 89558229Syokota bus_space_handle_t handle; 896637Snate{ 897637Snate 89858229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 89958229Syokota bus_space_write_1(tag, handle, MSE_PORTB, 0); 900637Snate} 901637Snate 902637Snate/* 903637Snate * Get current dx, dy and up/down button state. 904637Snate */ 905637Snatestatic void 90658229Syokotamse_getati(tag, handle, dx, dy, but) 90758229Syokota bus_space_tag_t tag; 90858229Syokota bus_space_handle_t handle; 909637Snate int *dx; 910637Snate int *dy; 911637Snate int *but; 912637Snate{ 913637Snate register char byte; 914637Snate 91558229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 91658229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD); 91758229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS); 91858229Syokota *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS; 91958229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX); 92058229Syokota byte = bus_space_read_1(tag, handle, MSE_PORTB); 92131603Syokota *dx = byte; 92258229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY); 92358229Syokota byte = bus_space_read_1(tag, handle, MSE_PORTB); 92431603Syokota *dy = byte; 92558229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 92658229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 927637Snate} 928