mse.c revision 92765
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 92765 2002-03-20 07:51:46Z alfred $ 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> 5371286Swollman#include <sys/selinfo.h> 542056Swollman#include <sys/uio.h> 5566860Sphk#include <sys/mouse.h> 56637Snate 5758229Syokota#include <machine/bus_pio.h> 5858229Syokota#include <machine/bus.h> 597430Sbde#include <machine/clock.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; 8292765Salfred void (*sc_enablemouse)(bus_space_tag_t t, 8392765Salfred bus_space_handle_t h); 8492765Salfred void (*sc_disablemouse)(bus_space_tag_t t, 8592765Salfred bus_space_handle_t h); 8692765Salfred void (*sc_getmouse)(bus_space_tag_t t, 8758229Syokota bus_space_handle_t h, 8892765Salfred 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 10692765Salfredstatic int mse_probe(device_t dev); 10792765Salfredstatic int mse_attach(device_t dev); 10892765Salfredstatic int mse_detach(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}; 15712675Sjulian 15892765Salfredstatic void mseintr(void *); 15958229Syokotastatic timeout_t msetimeout; 16012675Sjulian 161637Snate/* Flags */ 162637Snate#define MSESC_OPEN 0x1 163637Snate#define MSESC_WANT 0x2 164637Snate 165637Snate/* and Mouse Types */ 16620688Sjoerg#define MSE_NONE 0 /* don't move this! */ 167637Snate#define MSE_LOGITECH 0x1 168637Snate#define MSE_ATIINPORT 0x2 1694259Sjkh#define MSE_LOGI_SIG 0xA5 170637Snate 171637Snate#define MSE_PORTA 0 172637Snate#define MSE_PORTB 1 173637Snate#define MSE_PORTC 2 174637Snate#define MSE_PORTD 3 17558229Syokota#define MSE_IOSIZE 4 176637Snate 177637Snate#define MSE_UNIT(dev) (minor(dev) >> 1) 178637Snate#define MSE_NBLOCKIO(dev) (minor(dev) & 0x1) 179637Snate 180637Snate/* 181637Snate * Logitech bus mouse definitions 182637Snate */ 183637Snate#define MSE_SETUP 0x91 /* What does this mean? */ 1844259Sjkh /* The definition for the control port */ 1854259Sjkh /* is as follows: */ 1868876Srgrimes 1874259Sjkh /* D7 = Mode set flag (1 = active) */ 1888876Srgrimes /* D6,D5 = Mode selection (port A) */ 1894259Sjkh /* 00 = Mode 0 = Basic I/O */ 1904259Sjkh /* 01 = Mode 1 = Strobed I/O */ 1914259Sjkh /* 10 = Mode 2 = Bi-dir bus */ 1924259Sjkh /* D4 = Port A direction (1 = input)*/ 1934259Sjkh /* D3 = Port C (upper 4 bits) */ 1944259Sjkh /* direction. (1 = input) */ 1954259Sjkh /* D2 = Mode selection (port B & C) */ 1964259Sjkh /* 0 = Mode 0 = Basic I/O */ 1974259Sjkh /* 1 = Mode 1 = Strobed I/O */ 1984259Sjkh /* D1 = Port B direction (1 = input)*/ 1994259Sjkh /* D0 = Port C (lower 4 bits) */ 2004259Sjkh /* direction. (1 = input) */ 2018876Srgrimes 2024259Sjkh /* So 91 means Basic I/O on all 3 ports,*/ 2034259Sjkh /* Port A is an input port, B is an */ 2044259Sjkh /* output port, C is split with upper */ 2054259Sjkh /* 4 bits being an output port and lower*/ 2064259Sjkh /* 4 bits an input port, and enable the */ 2074259Sjkh /* sucker. */ 2084259Sjkh /* Courtesy Intel 8255 databook. Lars */ 209637Snate#define MSE_HOLD 0x80 210637Snate#define MSE_RXLOW 0x00 211637Snate#define MSE_RXHIGH 0x20 212637Snate#define MSE_RYLOW 0x40 213637Snate#define MSE_RYHIGH 0x60 214637Snate#define MSE_DISINTR 0x10 215637Snate#define MSE_INTREN 0x00 216637Snate 21792765Salfredstatic int mse_probelogi(device_t dev, mse_softc_t *sc); 21892765Salfredstatic void mse_disablelogi(bus_space_tag_t t, 21992765Salfred bus_space_handle_t h); 22092765Salfredstatic void mse_getlogi(bus_space_tag_t t, 22158229Syokota bus_space_handle_t h, 22292765Salfred int *dx, int *dy, int *but); 22392765Salfredstatic void mse_enablelogi(bus_space_tag_t t, 22492765Salfred bus_space_handle_t h); 225637Snate 226637Snate/* 227637Snate * ATI Inport mouse definitions 228637Snate */ 229637Snate#define MSE_INPORT_RESET 0x80 230637Snate#define MSE_INPORT_STATUS 0x00 231637Snate#define MSE_INPORT_DX 0x01 232637Snate#define MSE_INPORT_DY 0x02 233637Snate#define MSE_INPORT_MODE 0x07 234637Snate#define MSE_INPORT_HOLD 0x20 235637Snate#define MSE_INPORT_INTREN 0x09 236637Snate 23792765Salfredstatic int mse_probeati(device_t dev, mse_softc_t *sc); 23892765Salfredstatic void mse_enableati(bus_space_tag_t t, 23992765Salfred bus_space_handle_t h); 24092765Salfredstatic void mse_disableati(bus_space_tag_t t, 24192765Salfred bus_space_handle_t h); 24292765Salfredstatic void mse_getati(bus_space_tag_t t, 24358229Syokota bus_space_handle_t h, 24492765Salfred int *dx, int *dy, int *but); 245637Snate 246637Snate#define MSEPRI (PZERO + 3) 247637Snate 248637Snate/* 249637Snate * Table of mouse types. 250637Snate * Keep the Logitech last, since I haven't figured out how to probe it 251637Snate * properly yet. (Someday I'll have the documentation.) 252637Snate */ 25312724Sphkstatic struct mse_types { 254637Snate int m_type; /* Type of bus mouse */ 25592765Salfred int (*m_probe)(device_t dev, mse_softc_t *sc); 25612854Sbde /* Probe routine to test for it */ 25792765Salfred void (*m_enable)(bus_space_tag_t t, bus_space_handle_t h); 25812854Sbde /* Start routine */ 25992765Salfred void (*m_disable)(bus_space_tag_t t, bus_space_handle_t h); 26012854Sbde /* Disable interrupts routine */ 26192765Salfred void (*m_get)(bus_space_tag_t t, bus_space_handle_t h, 26292765Salfred int *dx, int *dy, int *but); 26312854Sbde /* and get mouse status */ 26431603Syokota mousehw_t m_hw; /* buttons iftype type model hwid */ 26531603Syokota mousemode_t m_mode; /* proto rate res accel level size mask */ 266637Snate} mse_types[] = { 26731603Syokota { MSE_ATIINPORT, 26831603Syokota mse_probeati, mse_enableati, mse_disableati, mse_getati, 26931603Syokota { 2, MOUSE_IF_INPORT, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 27031603Syokota { MOUSE_PROTO_INPORT, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 27131603Syokota { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 27231603Syokota { MSE_LOGITECH, 27331603Syokota mse_probelogi, mse_enablelogi, mse_disablelogi, mse_getlogi, 27431603Syokota { 2, MOUSE_IF_BUS, MOUSE_MOUSE, MOUSE_MODEL_GENERIC, 0, }, 27531603Syokota { MOUSE_PROTO_BUS, -1, -1, 0, 0, MOUSE_MSC_PACKETSIZE, 27631603Syokota { MOUSE_MSC_SYNCMASK, MOUSE_MSC_SYNC, }, }, }, 277637Snate { 0, }, 278637Snate}; 279637Snate 28058229Syokotastatic int 28158229Syokotamse_probe(dev) 28258229Syokota device_t dev; 283637Snate{ 28458229Syokota mse_softc_t *sc; 28558229Syokota int error; 28658229Syokota int rid; 28758229Syokota int i; 288637Snate 28958229Syokota /* check PnP IDs */ 29058229Syokota error = ISA_PNP_PROBE(device_get_parent(dev), dev, mse_ids); 29182618Smsmith if (error == ENXIO) 29282554Smsmith return error; 29358229Syokota 29458229Syokota sc = device_get_softc(dev); 29558229Syokota rid = 0; 29658229Syokota sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 29758229Syokota MSE_IOSIZE, RF_ACTIVE); 29858229Syokota if (sc->sc_port == NULL) 29958229Syokota return ENXIO; 30058229Syokota sc->sc_iot = rman_get_bustag(sc->sc_port); 30158229Syokota sc->sc_ioh = rman_get_bushandle(sc->sc_port); 30258229Syokota 303637Snate /* 304637Snate * Check for each mouse type in the table. 305637Snate */ 306637Snate i = 0; 307637Snate while (mse_types[i].m_type) { 30858229Syokota if ((*mse_types[i].m_probe)(dev, sc)) { 309637Snate sc->sc_mousetype = mse_types[i].m_type; 310637Snate sc->sc_enablemouse = mse_types[i].m_enable; 311637Snate sc->sc_disablemouse = mse_types[i].m_disable; 312637Snate sc->sc_getmouse = mse_types[i].m_get; 31331603Syokota sc->hw = mse_types[i].m_hw; 31431603Syokota sc->mode = mse_types[i].m_mode; 31558229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, 31658229Syokota sc->sc_port); 31758229Syokota device_set_desc(dev, "Bus/InPort Mouse"); 31858229Syokota return 0; 319637Snate } 320637Snate i++; 321637Snate } 32258229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 32358229Syokota return ENXIO; 324637Snate} 325637Snate 32658229Syokotastatic int 32758229Syokotamse_attach(dev) 32858229Syokota device_t dev; 329637Snate{ 33058229Syokota mse_softc_t *sc; 33158229Syokota int flags; 33258229Syokota int unit; 33358229Syokota int rid; 334637Snate 33558229Syokota sc = device_get_softc(dev); 33658229Syokota unit = device_get_unit(dev); 33758229Syokota 33858229Syokota rid = 0; 33958229Syokota sc->sc_port = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0, ~0, 34058229Syokota MSE_IOSIZE, RF_ACTIVE); 34158229Syokota if (sc->sc_port == NULL) 34258229Syokota return ENXIO; 34358229Syokota sc->sc_intr = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1, 34458229Syokota RF_ACTIVE); 34558229Syokota if (sc->sc_intr == NULL) { 34658229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 34758229Syokota return ENXIO; 34858229Syokota } 34958229Syokota sc->sc_iot = rman_get_bustag(sc->sc_port); 35058229Syokota sc->sc_ioh = rman_get_bushandle(sc->sc_port); 35158229Syokota 35258229Syokota if (BUS_SETUP_INTR(device_get_parent(dev), dev, sc->sc_intr, 35358229Syokota INTR_TYPE_TTY, mseintr, sc, &sc->sc_ih)) { 35458229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 35558229Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 35658229Syokota return ENXIO; 35758229Syokota } 35858229Syokota 35958229Syokota flags = device_get_flags(dev); 36058229Syokota sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4; 36158229Syokota callout_handle_init(&sc->sc_callout); 36258229Syokota 36358229Syokota sc->sc_dev = make_dev(&mse_cdevsw, unit << 1, 0, 0, 0600, 36458229Syokota "mse%d", unit); 36558229Syokota sc->sc_ndev = make_dev(&mse_cdevsw, (unit<<1)+1, 0, 0, 0600, 36658229Syokota "nmse%d", unit); 36758229Syokota 36858229Syokota return 0; 369637Snate} 370637Snate 37158229Syokotastatic int 37258229Syokotamse_detach(dev) 37358229Syokota device_t dev; 37458229Syokota{ 37558229Syokota mse_softc_t *sc; 37658229Syokota int rid; 37758229Syokota 37858229Syokota sc = device_get_softc(dev); 37958229Syokota if (sc->sc_flags & MSESC_OPEN) 38058229Syokota return EBUSY; 38158229Syokota 38258229Syokota rid = 0; 38358229Syokota BUS_TEARDOWN_INTR(device_get_parent(dev), dev, sc->sc_intr, sc->sc_ih); 38458229Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 38558229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 38658229Syokota 38758229Syokota destroy_dev(sc->sc_dev); 38858229Syokota destroy_dev(sc->sc_ndev); 38958229Syokota 39058229Syokota return 0; 39158229Syokota} 39258229Syokota 393637Snate/* 394637Snate * Exclusive open the mouse, initialize it and enable interrupts. 395637Snate */ 39612675Sjulianstatic int 39783366Sjulianmseopen(dev, flags, fmt, td) 398637Snate dev_t dev; 39910624Sbde int flags; 40010624Sbde int fmt; 40183366Sjulian struct thread *td; 402637Snate{ 40358229Syokota mse_softc_t *sc; 404637Snate int s; 405637Snate 40658229Syokota sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 40758229Syokota if (sc == NULL) 408637Snate return (ENXIO); 40920688Sjoerg if (sc->sc_mousetype == MSE_NONE) 41020688Sjoerg return (ENXIO); 411637Snate if (sc->sc_flags & MSESC_OPEN) 412637Snate return (EBUSY); 413637Snate sc->sc_flags |= MSESC_OPEN; 41431603Syokota sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS; 415637Snate sc->sc_deltax = sc->sc_deltay = 0; 41631603Syokota sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE; 41758229Syokota sc->sc_watchdog = FALSE; 41858229Syokota sc->sc_callout = timeout(msetimeout, dev, hz*2); 41931603Syokota sc->mode.level = 0; 42031603Syokota sc->status.flags = 0; 42131603Syokota sc->status.button = sc->status.obutton = 0; 42231603Syokota sc->status.dx = sc->status.dy = sc->status.dz = 0; 423637Snate 424637Snate /* 425637Snate * Initialize mouse interface and enable interrupts. 426637Snate */ 427637Snate s = spltty(); 42858229Syokota (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh); 429637Snate splx(s); 430637Snate return (0); 431637Snate} 432637Snate 433637Snate/* 434637Snate * mseclose: just turn off mouse innterrupts. 435637Snate */ 43612675Sjulianstatic int 43783366Sjulianmseclose(dev, flags, fmt, td) 438798Swollman dev_t dev; 43910624Sbde int flags; 44010624Sbde int fmt; 44183366Sjulian struct thread *td; 442637Snate{ 44358229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 444637Snate int s; 445637Snate 44658229Syokota untimeout(msetimeout, dev, sc->sc_callout); 44758229Syokota callout_handle_init(&sc->sc_callout); 448637Snate s = spltty(); 44958229Syokota (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh); 450637Snate sc->sc_flags &= ~MSESC_OPEN; 451637Snate splx(s); 452637Snate return(0); 453637Snate} 454637Snate 4558876Srgrimes/* 456637Snate * mseread: return mouse info using the MSC serial protocol, but without 457637Snate * using bytes 4 and 5. 458637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...) 459637Snate */ 46012675Sjulianstatic int 46110624Sbdemseread(dev, uio, ioflag) 462637Snate dev_t dev; 463637Snate struct uio *uio; 46410624Sbde int ioflag; 465637Snate{ 46658229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 467637Snate int xfer, s, error; 468637Snate 469637Snate /* 470637Snate * If there are no protocol bytes to be read, set up a new protocol 471637Snate * packet. 472637Snate */ 473637Snate s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 47431603Syokota if (sc->sc_bytesread >= sc->mode.packetsize) { 475637Snate while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 476637Snate (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 477637Snate if (MSE_NBLOCKIO(dev)) { 478637Snate splx(s); 479637Snate return (0); 480637Snate } 481637Snate sc->sc_flags |= MSESC_WANT; 48246571Speter error = tsleep((caddr_t)sc, MSEPRI | PCATCH, 48346571Speter "mseread", 0); 48446571Speter if (error) { 485637Snate splx(s); 486637Snate return (error); 487637Snate } 488637Snate } 489637Snate 490637Snate /* 491637Snate * Generate protocol bytes. 492637Snate * For some reason X386 expects 5 bytes but never uses 493637Snate * the fourth or fifth? 494637Snate */ 49531603Syokota sc->sc_bytes[0] = sc->mode.syncmask[1] 49631603Syokota | (sc->sc_buttons & ~sc->mode.syncmask[0]); 497637Snate if (sc->sc_deltax > 127) 498637Snate sc->sc_deltax = 127; 499637Snate if (sc->sc_deltax < -127) 500637Snate sc->sc_deltax = -127; 501637Snate sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 502637Snate if (sc->sc_deltay > 127) 503637Snate sc->sc_deltay = 127; 504637Snate if (sc->sc_deltay < -127) 505637Snate sc->sc_deltay = -127; 506637Snate sc->sc_bytes[1] = sc->sc_deltax; 507637Snate sc->sc_bytes[2] = sc->sc_deltay; 508637Snate sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 50931603Syokota sc->sc_bytes[5] = sc->sc_bytes[6] = 0; 51031603Syokota sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS; 511637Snate sc->sc_obuttons = sc->sc_buttons; 512637Snate sc->sc_deltax = sc->sc_deltay = 0; 513637Snate sc->sc_bytesread = 0; 514637Snate } 515637Snate splx(s); 51631603Syokota xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread); 51746571Speter error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio); 51846571Speter if (error) 519637Snate return (error); 520637Snate sc->sc_bytesread += xfer; 521637Snate return(0); 522637Snate} 523637Snate 524637Snate/* 52531603Syokota * mseioctl: process ioctl commands. 52631603Syokota */ 52731603Syokotastatic int 52883366Sjulianmseioctl(dev, cmd, addr, flag, td) 52931603Syokota dev_t dev; 53036735Sdfr u_long cmd; 53131603Syokota caddr_t addr; 53231603Syokota int flag; 53383366Sjulian struct thread *td; 53431603Syokota{ 53558229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 53631603Syokota mousestatus_t status; 53731603Syokota int err = 0; 53831603Syokota int s; 53931603Syokota 54031603Syokota switch (cmd) { 54131603Syokota 54231603Syokota case MOUSE_GETHWINFO: 54331603Syokota s = spltty(); 54431603Syokota *(mousehw_t *)addr = sc->hw; 54531603Syokota if (sc->mode.level == 0) 54631603Syokota ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 54731603Syokota splx(s); 54831603Syokota break; 54931603Syokota 55031603Syokota case MOUSE_GETMODE: 55131603Syokota s = spltty(); 55231603Syokota *(mousemode_t *)addr = sc->mode; 55331603Syokota switch (sc->mode.level) { 55431603Syokota case 0: 55531603Syokota break; 55631603Syokota case 1: 55731603Syokota ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 55831603Syokota ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 55931603Syokota ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 56031603Syokota break; 56131603Syokota } 56231603Syokota splx(s); 56331603Syokota break; 56431603Syokota 56531603Syokota case MOUSE_SETMODE: 56631603Syokota switch (((mousemode_t *)addr)->level) { 56731603Syokota case 0: 56831603Syokota case 1: 56931603Syokota break; 57031603Syokota default: 57131603Syokota return (EINVAL); 57231603Syokota } 57331603Syokota if (((mousemode_t *)addr)->accelfactor < -1) 57431603Syokota return (EINVAL); 57531603Syokota else if (((mousemode_t *)addr)->accelfactor >= 0) 57631603Syokota sc->mode.accelfactor = 57731603Syokota ((mousemode_t *)addr)->accelfactor; 57831603Syokota sc->mode.level = ((mousemode_t *)addr)->level; 57931603Syokota switch (sc->mode.level) { 58031603Syokota case 0: 58131603Syokota sc->sc_bytesread = sc->mode.packetsize 58231603Syokota = MOUSE_MSC_PACKETSIZE; 58331603Syokota break; 58431603Syokota case 1: 58531603Syokota sc->sc_bytesread = sc->mode.packetsize 58631603Syokota = MOUSE_SYS_PACKETSIZE; 58731603Syokota break; 58831603Syokota } 58931603Syokota break; 59031603Syokota 59131603Syokota case MOUSE_GETLEVEL: 59231603Syokota *(int *)addr = sc->mode.level; 59331603Syokota break; 59431603Syokota 59531603Syokota case MOUSE_SETLEVEL: 59631603Syokota switch (*(int *)addr) { 59731603Syokota case 0: 59831603Syokota sc->mode.level = *(int *)addr; 59931603Syokota sc->sc_bytesread = sc->mode.packetsize 60031603Syokota = MOUSE_MSC_PACKETSIZE; 60131603Syokota break; 60231603Syokota case 1: 60331603Syokota sc->mode.level = *(int *)addr; 60431603Syokota sc->sc_bytesread = sc->mode.packetsize 60531603Syokota = MOUSE_SYS_PACKETSIZE; 60631603Syokota break; 60731603Syokota default: 60831603Syokota return (EINVAL); 60931603Syokota } 61031603Syokota break; 61131603Syokota 61231603Syokota case MOUSE_GETSTATUS: 61331603Syokota s = spltty(); 61431603Syokota status = sc->status; 61531603Syokota sc->status.flags = 0; 61631603Syokota sc->status.obutton = sc->status.button; 61731603Syokota sc->status.button = 0; 61831603Syokota sc->status.dx = 0; 61931603Syokota sc->status.dy = 0; 62031603Syokota sc->status.dz = 0; 62131603Syokota splx(s); 62231603Syokota *(mousestatus_t *)addr = status; 62331603Syokota break; 62431603Syokota 62531603Syokota case MOUSE_READSTATE: 62631603Syokota case MOUSE_READDATA: 62731603Syokota return (ENODEV); 62831603Syokota 62931603Syokota#if (defined(MOUSE_GETVARS)) 63031603Syokota case MOUSE_GETVARS: 63131603Syokota case MOUSE_SETVARS: 63231603Syokota return (ENODEV); 63331603Syokota#endif 63431603Syokota 63531603Syokota default: 63631603Syokota return (ENOTTY); 63731603Syokota } 63831603Syokota return (err); 63931603Syokota} 64031603Syokota 64131603Syokota/* 64229368Speter * msepoll: check for mouse input to be processed. 643637Snate */ 64412675Sjulianstatic int 64583366Sjulianmsepoll(dev, events, td) 646637Snate dev_t dev; 64729368Speter int events; 64883366Sjulian struct thread *td; 649637Snate{ 65058229Syokota mse_softc_t *sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 651637Snate int s; 65229368Speter int revents = 0; 653637Snate 654637Snate s = spltty(); 65546568Speter if (events & (POLLIN | POLLRDNORM)) { 65631603Syokota if (sc->sc_bytesread != sc->mode.packetsize || 65731603Syokota sc->sc_deltax != 0 || sc->sc_deltay != 0 || 65829368Speter (sc->sc_obuttons ^ sc->sc_buttons) != 0) 65929368Speter revents |= events & (POLLIN | POLLRDNORM); 66029368Speter else { 66129368Speter /* 66229368Speter * Since this is an exclusive open device, any previous 66329368Speter * proc pointer is trash now, so we can just assign it. 66429368Speter */ 66583366Sjulian selrecord(td, &sc->sc_selp); 66629368Speter } 66746568Speter } 668637Snate splx(s); 66929368Speter return (revents); 670637Snate} 671637Snate 672637Snate/* 67358229Syokota * msetimeout: watchdog timer routine. 67458229Syokota */ 67558229Syokotastatic void 67658229Syokotamsetimeout(arg) 67758229Syokota void *arg; 67858229Syokota{ 67958229Syokota dev_t dev; 68058229Syokota mse_softc_t *sc; 68158229Syokota 68258229Syokota dev = (dev_t)arg; 68358229Syokota sc = devclass_get_softc(mse_devclass, MSE_UNIT(dev)); 68458229Syokota if (sc->sc_watchdog) { 68558229Syokota if (bootverbose) 68658229Syokota printf("mse%d: lost interrupt?\n", MSE_UNIT(dev)); 68758229Syokota mseintr(sc); 68858229Syokota } 68958229Syokota sc->sc_watchdog = TRUE; 69058229Syokota sc->sc_callout = timeout(msetimeout, dev, hz); 69158229Syokota} 69258229Syokota 69358229Syokota/* 694637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 695637Snate */ 69640565Sbdestatic void 69758229Syokotamseintr(arg) 69858229Syokota void *arg; 699637Snate{ 70031603Syokota /* 70131603Syokota * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP) 70231603Syokota * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 70331603Syokota */ 70431603Syokota static int butmap[8] = { 70531603Syokota 0, 70631603Syokota MOUSE_BUTTON3DOWN, 70731603Syokota MOUSE_BUTTON2DOWN, 70831603Syokota MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 70931603Syokota MOUSE_BUTTON1DOWN, 71031603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 71131603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 71231603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 71331603Syokota }; 71458229Syokota mse_softc_t *sc = arg; 71531603Syokota int dx, dy, but; 71631603Syokota int sign; 717637Snate 718637Snate#ifdef DEBUG 719637Snate static int mse_intrcnt = 0; 720637Snate if((mse_intrcnt++ % 10000) == 0) 721637Snate printf("mseintr\n"); 722637Snate#endif /* DEBUG */ 723637Snate if ((sc->sc_flags & MSESC_OPEN) == 0) 724637Snate return; 725637Snate 72658229Syokota (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but); 72731603Syokota if (sc->mode.accelfactor > 0) { 72831603Syokota sign = (dx < 0); 72931603Syokota dx = dx * dx / sc->mode.accelfactor; 73031603Syokota if (dx == 0) 73131603Syokota dx = 1; 73231603Syokota if (sign) 73331603Syokota dx = -dx; 73431603Syokota sign = (dy < 0); 73531603Syokota dy = dy * dy / sc->mode.accelfactor; 73631603Syokota if (dy == 0) 73731603Syokota dy = 1; 73831603Syokota if (sign) 73931603Syokota dy = -dy; 74031603Syokota } 74131603Syokota sc->sc_deltax += dx; 74231603Syokota sc->sc_deltay += dy; 74331603Syokota sc->sc_buttons = but; 744637Snate 74531603Syokota but = butmap[~but & MOUSE_MSC_BUTTONS]; 74631603Syokota sc->status.dx += dx; 74731603Syokota sc->status.dy += dy; 74831603Syokota sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0) 74931603Syokota | (sc->status.button ^ but); 75031603Syokota sc->status.button = but; 75131603Syokota 75258229Syokota sc->sc_watchdog = FALSE; 75358229Syokota 754637Snate /* 755637Snate * If mouse state has changed, wake up anyone wanting to know. 756637Snate */ 757637Snate if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 758637Snate (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 7598876Srgrimes if (sc->sc_flags & MSESC_WANT) { 7608876Srgrimes sc->sc_flags &= ~MSESC_WANT; 7618876Srgrimes wakeup((caddr_t)sc); 7628876Srgrimes } 7631549Srgrimes selwakeup(&sc->sc_selp); 764637Snate } 765637Snate} 766637Snate 767637Snate/* 768637Snate * Routines for the Logitech mouse. 769637Snate */ 770637Snate/* 771637Snate * Test for a Logitech bus mouse and return 1 if it is. 772637Snate * (until I know how to use the signature port properly, just disable 773637Snate * interrupts and return 1) 774637Snate */ 775637Snatestatic int 77658229Syokotamse_probelogi(dev, sc) 77758229Syokota device_t dev; 77858229Syokota mse_softc_t *sc; 779637Snate{ 780637Snate 7814259Sjkh int sig; 7824259Sjkh 78358229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTD, MSE_SETUP); 7844259Sjkh /* set the signature port */ 78558229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB, MSE_LOGI_SIG); 7864259Sjkh 7874259Sjkh DELAY(30000); /* 30 ms delay */ 78858229Syokota sig = bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTB) & 0xFF; 7894259Sjkh if (sig == MSE_LOGI_SIG) { 79058229Syokota bus_space_write_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC, 79158229Syokota MSE_DISINTR); 7924259Sjkh return(1); 7934259Sjkh } else { 79416074Sjoerg if (bootverbose) 79558229Syokota device_printf(dev, "wrong signature %x\n", sig); 7964259Sjkh return(0); 797637Snate } 798637Snate} 799637Snate 800637Snate/* 801637Snate * Initialize Logitech mouse and enable interrupts. 802637Snate */ 803637Snatestatic void 80458229Syokotamse_enablelogi(tag, handle) 80558229Syokota bus_space_tag_t tag; 80658229Syokota bus_space_handle_t handle; 807637Snate{ 808637Snate int dx, dy, but; 809637Snate 81058229Syokota bus_space_write_1(tag, handle, MSE_PORTD, MSE_SETUP); 81158229Syokota mse_getlogi(tag, handle, &dx, &dy, &but); 812637Snate} 813637Snate 814637Snate/* 815637Snate * Disable interrupts for Logitech mouse. 816637Snate */ 817637Snatestatic void 81858229Syokotamse_disablelogi(tag, handle) 81958229Syokota bus_space_tag_t tag; 82058229Syokota bus_space_handle_t handle; 821637Snate{ 822637Snate 82358229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_DISINTR); 824637Snate} 825637Snate 826637Snate/* 827637Snate * Get the current dx, dy and button up/down state. 828637Snate */ 829637Snatestatic void 83058229Syokotamse_getlogi(tag, handle, dx, dy, but) 83158229Syokota bus_space_tag_t tag; 83258229Syokota bus_space_handle_t handle; 833637Snate int *dx; 834637Snate int *dy; 835637Snate int *but; 836637Snate{ 837637Snate register char x, y; 838637Snate 83958229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXLOW); 84058229Syokota x = bus_space_read_1(tag, handle, MSE_PORTA); 84131603Syokota *but = (x >> 5) & MOUSE_MSC_BUTTONS; 842637Snate x &= 0xf; 84358229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RXHIGH); 84458229Syokota x |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 84558229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYLOW); 84658229Syokota y = (bus_space_read_1(tag, handle, MSE_PORTA) & 0xf); 84758229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_HOLD | MSE_RYHIGH); 84858229Syokota y |= (bus_space_read_1(tag, handle, MSE_PORTA) << 4); 84931603Syokota *dx = x; 85031603Syokota *dy = y; 85158229Syokota bus_space_write_1(tag, handle, MSE_PORTC, MSE_INTREN); 852637Snate} 853637Snate 854637Snate/* 855637Snate * Routines for the ATI Inport bus mouse. 856637Snate */ 857637Snate/* 858637Snate * Test for a ATI Inport bus mouse and return 1 if it is. 859637Snate * (do not enable interrupts) 860637Snate */ 861637Snatestatic int 86258229Syokotamse_probeati(dev, sc) 86358229Syokota device_t dev; 86458229Syokota mse_softc_t *sc; 865637Snate{ 866637Snate int i; 867637Snate 868637Snate for (i = 0; i < 2; i++) 86958229Syokota if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, MSE_PORTC) == 0xde) 870637Snate return (1); 871637Snate return (0); 872637Snate} 873637Snate 874637Snate/* 875637Snate * Initialize ATI Inport mouse and enable interrupts. 876637Snate */ 877637Snatestatic void 87858229Syokotamse_enableati(tag, handle) 87958229Syokota bus_space_tag_t tag; 88058229Syokota bus_space_handle_t handle; 881637Snate{ 882637Snate 88358229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_RESET); 88458229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 88558229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 886637Snate} 887637Snate 888637Snate/* 889637Snate * Disable interrupts for ATI Inport mouse. 890637Snate */ 891637Snatestatic void 89258229Syokotamse_disableati(tag, handle) 89358229Syokota bus_space_tag_t tag; 89458229Syokota bus_space_handle_t handle; 895637Snate{ 896637Snate 89758229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 89858229Syokota bus_space_write_1(tag, handle, MSE_PORTB, 0); 899637Snate} 900637Snate 901637Snate/* 902637Snate * Get current dx, dy and up/down button state. 903637Snate */ 904637Snatestatic void 90558229Syokotamse_getati(tag, handle, dx, dy, but) 90658229Syokota bus_space_tag_t tag; 90758229Syokota bus_space_handle_t handle; 908637Snate int *dx; 909637Snate int *dy; 910637Snate int *but; 911637Snate{ 912637Snate register char byte; 913637Snate 91458229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 91558229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_HOLD); 91658229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_STATUS); 91758229Syokota *but = ~bus_space_read_1(tag, handle, MSE_PORTB) & MOUSE_MSC_BUTTONS; 91858229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DX); 91958229Syokota byte = bus_space_read_1(tag, handle, MSE_PORTB); 92031603Syokota *dx = byte; 92158229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_DY); 92258229Syokota byte = bus_space_read_1(tag, handle, MSE_PORTB); 92331603Syokota *dy = byte; 92458229Syokota bus_space_write_1(tag, handle, MSE_PORTA, MSE_INPORT_MODE); 92558229Syokota bus_space_write_1(tag, handle, MSE_PORTB, MSE_INPORT_INTREN); 926637Snate} 927