1139749Simp/*- 2138755Simp * Copyright (c) 2004 M. Warner Losh 3138755Simp * All rights reserved. 4138755Simp * 5138755Simp * Redistribution and use in source and binary forms, with or without 6138755Simp * modification, are permitted provided that the following conditions 7138755Simp * are met: 8138755Simp * 1. Redistributions of source code must retain the above copyright 9140040Simp * notice, this list of conditions and the following disclaimer. 10138755Simp * 2. Redistributions in binary form must reproduce the above copyright 11140040Simp * notice, this list of conditions and the following disclaimer in the 12140040Simp * documentation and/or other materials provided with the distribution. 13138755Simp * 14138755Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15138755Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16138755Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17140040Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18140040Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19138755Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20138755Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21138755Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22138755Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23138755Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24138755Simp * SUCH DAMAGE. 25138755Simp * 26138755Simp * $FreeBSD$ 27138755Simp */ 28138755Simp 29138755Simp/* 30637Snate * Copyright 1992 by the University of Guelph 31637Snate * 32637Snate * Permission to use, copy and modify this 33637Snate * software and its documentation for any purpose and without 34637Snate * fee is hereby granted, provided that the above copyright 35637Snate * notice appear in all copies and that both that copyright 36637Snate * notice and this permission notice appear in supporting 37637Snate * documentation. 38637Snate * University of Guelph makes no representations about the suitability of 39637Snate * this software for any purpose. It is provided "as is" 40637Snate * without express or implied warranty. 41637Snate */ 42637Snate/* 43637Snate * Driver for the Logitech and ATI Inport Bus mice for use with 386bsd and 44637Snate * the X386 port, courtesy of 45637Snate * Rick Macklem, rick@snowhite.cis.uoguelph.ca 46637Snate * Caveats: The driver currently uses spltty(), but doesn't use any 47637Snate * generic tty code. It could use splmse() (that only masks off the 48637Snate * bus mouse interrupt, but that would require hacking in i386/isa/icu.s. 49637Snate * (This may be worth the effort, since the Logitech generates 30/60 50637Snate * interrupts/sec continuously while it is open.) 51637Snate * NB: The ATI has NOT been tested yet! 52637Snate */ 53637Snate 54637Snate/* 55637Snate * Modification history: 564259Sjkh * Sep 6, 1994 -- Lars Fredriksen(fredriks@mcs.com) 574259Sjkh * improved probe based on input from Logitech. 58637Snate * 59637Snate * Oct 19, 1992 -- E. Stark (stark@cs.sunysb.edu) 60637Snate * fixes to make it work with Microsoft InPort busmouse 61637Snate * 62637Snate * Jan, 1993 -- E. Stark (stark@cs.sunysb.edu) 63637Snate * added patches for new "select" interface 64637Snate * 65637Snate * May 4, 1993 -- E. Stark (stark@cs.sunysb.edu) 66637Snate * changed position of some spl()'s in mseread 67637Snate * 68637Snate * October 8, 1993 -- E. Stark (stark@cs.sunysb.edu) 69637Snate * limit maximum negative x/y value to -127 to work around XFree problem 70637Snate * that causes spurious button pushes. 71637Snate */ 72637Snate 732056Swollman#include <sys/param.h> 743745Swollman#include <sys/systm.h> 7512658Sbde#include <sys/conf.h> 762056Swollman#include <sys/kernel.h> 77129882Sphk#include <sys/module.h> 7858229Syokota#include <sys/bus.h> 7929368Speter#include <sys/poll.h> 8071286Swollman#include <sys/selinfo.h> 812056Swollman#include <sys/uio.h> 8266860Sphk#include <sys/mouse.h> 83637Snate 8458229Syokota#include <machine/bus.h> 8558229Syokota#include <machine/resource.h> 8658229Syokota#include <sys/rman.h> 877430Sbde 8858229Syokota#include <isa/isavar.h> 89637Snate 90138755Simp#include <dev/mse/msevar.h> 9131603Syokota 92138755Simpdevclass_t mse_devclass; 93637Snate 9412675Sjulianstatic d_open_t mseopen; 9512675Sjulianstatic d_close_t mseclose; 9612675Sjulianstatic d_read_t mseread; 9731603Syokotastatic d_ioctl_t mseioctl; 9829368Speterstatic d_poll_t msepoll; 9912675Sjulian 10047625Sphkstatic struct cdevsw mse_cdevsw = { 101126080Sphk .d_version = D_VERSION, 102126080Sphk .d_flags = D_NEEDGIANT, 103111815Sphk .d_open = mseopen, 104111815Sphk .d_close = mseclose, 105111815Sphk .d_read = mseread, 106111815Sphk .d_ioctl = mseioctl, 107111815Sphk .d_poll = msepoll, 108111815Sphk .d_name = "mse", 10947625Sphk}; 11012675Sjulian 11192765Salfredstatic void mseintr(void *); 11258229Syokotastatic timeout_t msetimeout; 11312675Sjulian 114191320Sed#define MSE_NBLOCKIO(dev) dev2unit(dev) 115637Snate 116637Snate#define MSEPRI (PZERO + 3) 117637Snate 118138755Simpint 119138755Simpmse_common_attach(device_t dev) 120637Snate{ 12158229Syokota mse_softc_t *sc; 122138755Simp int unit, flags, rid; 123637Snate 12458229Syokota sc = device_get_softc(dev); 12558229Syokota unit = device_get_unit(dev); 12658229Syokota 12758229Syokota rid = 0; 128138755Simp sc->sc_intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 129138755Simp RF_ACTIVE); 13058229Syokota if (sc->sc_intr == NULL) { 13158229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 13258229Syokota return ENXIO; 13358229Syokota } 13458229Syokota 135155921Sjhb if (bus_setup_intr(dev, sc->sc_intr, 136166901Spiso INTR_TYPE_TTY, NULL, mseintr, sc, &sc->sc_ih)) { 13758229Syokota bus_release_resource(dev, SYS_RES_IOPORT, rid, sc->sc_port); 13858229Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->sc_intr); 13958229Syokota return ENXIO; 14058229Syokota } 14158229Syokota flags = device_get_flags(dev); 14258229Syokota sc->mode.accelfactor = (flags & MSE_CONFIG_ACCEL) >> 4; 14358229Syokota callout_handle_init(&sc->sc_callout); 14458229Syokota 145191320Sed sc->sc_dev = make_dev(&mse_cdevsw, 0, 0, 0, 0600, "mse%d", unit); 146191320Sed sc->sc_dev->si_drv1 = sc; 147191320Sed sc->sc_ndev = make_dev(&mse_cdevsw, 1, 0, 0, 0600, "nmse%d", unit); 148191320Sed sc->sc_ndev->si_drv1 = sc; 14958229Syokota return 0; 150637Snate} 151637Snate 152637Snate/* 153637Snate * Exclusive open the mouse, initialize it and enable interrupts. 154637Snate */ 15512675Sjulianstatic int 156144783Simpmseopen(struct cdev *dev, int flags, int fmt, struct thread *td) 157637Snate{ 158191320Sed mse_softc_t *sc = dev->si_drv1; 159637Snate int s; 160637Snate 16120688Sjoerg if (sc->sc_mousetype == MSE_NONE) 16220688Sjoerg return (ENXIO); 163637Snate if (sc->sc_flags & MSESC_OPEN) 164637Snate return (EBUSY); 165637Snate sc->sc_flags |= MSESC_OPEN; 16631603Syokota sc->sc_obuttons = sc->sc_buttons = MOUSE_MSC_BUTTONS; 167637Snate sc->sc_deltax = sc->sc_deltay = 0; 16831603Syokota sc->sc_bytesread = sc->mode.packetsize = MOUSE_MSC_PACKETSIZE; 16958229Syokota sc->sc_watchdog = FALSE; 17058229Syokota sc->sc_callout = timeout(msetimeout, dev, hz*2); 17131603Syokota sc->mode.level = 0; 17231603Syokota sc->status.flags = 0; 17331603Syokota sc->status.button = sc->status.obutton = 0; 17431603Syokota sc->status.dx = sc->status.dy = sc->status.dz = 0; 175637Snate 176637Snate /* 177637Snate * Initialize mouse interface and enable interrupts. 178637Snate */ 179637Snate s = spltty(); 18058229Syokota (*sc->sc_enablemouse)(sc->sc_iot, sc->sc_ioh); 181637Snate splx(s); 182637Snate return (0); 183637Snate} 184637Snate 185637Snate/* 186637Snate * mseclose: just turn off mouse innterrupts. 187637Snate */ 18812675Sjulianstatic int 189144783Simpmseclose(struct cdev *dev, int flags, int fmt, struct thread *td) 190637Snate{ 191191320Sed mse_softc_t *sc = dev->si_drv1; 192637Snate int s; 193637Snate 19458229Syokota untimeout(msetimeout, dev, sc->sc_callout); 19558229Syokota callout_handle_init(&sc->sc_callout); 196637Snate s = spltty(); 19758229Syokota (*sc->sc_disablemouse)(sc->sc_iot, sc->sc_ioh); 198637Snate sc->sc_flags &= ~MSESC_OPEN; 199637Snate splx(s); 200637Snate return(0); 201637Snate} 202637Snate 2038876Srgrimes/* 204637Snate * mseread: return mouse info using the MSC serial protocol, but without 205637Snate * using bytes 4 and 5. 206637Snate * (Yes this is cheesy, but it makes the X386 server happy, so...) 207637Snate */ 20812675Sjulianstatic int 209144783Simpmseread(struct cdev *dev, struct uio *uio, int ioflag) 210637Snate{ 211191320Sed mse_softc_t *sc = dev->si_drv1; 212637Snate int xfer, s, error; 213637Snate 214637Snate /* 215637Snate * If there are no protocol bytes to be read, set up a new protocol 216637Snate * packet. 217637Snate */ 218637Snate s = spltty(); /* XXX Should be its own spl, but where is imlXX() */ 21931603Syokota if (sc->sc_bytesread >= sc->mode.packetsize) { 220637Snate while (sc->sc_deltax == 0 && sc->sc_deltay == 0 && 221637Snate (sc->sc_obuttons ^ sc->sc_buttons) == 0) { 222637Snate if (MSE_NBLOCKIO(dev)) { 223637Snate splx(s); 224637Snate return (0); 225637Snate } 226637Snate sc->sc_flags |= MSESC_WANT; 227111748Sdes error = tsleep(sc, MSEPRI | PCATCH, 22846571Speter "mseread", 0); 22946571Speter if (error) { 230637Snate splx(s); 231637Snate return (error); 232637Snate } 233637Snate } 234637Snate 235637Snate /* 236637Snate * Generate protocol bytes. 237637Snate * For some reason X386 expects 5 bytes but never uses 238637Snate * the fourth or fifth? 239637Snate */ 24031603Syokota sc->sc_bytes[0] = sc->mode.syncmask[1] 24131603Syokota | (sc->sc_buttons & ~sc->mode.syncmask[0]); 242637Snate if (sc->sc_deltax > 127) 243637Snate sc->sc_deltax = 127; 244637Snate if (sc->sc_deltax < -127) 245637Snate sc->sc_deltax = -127; 246637Snate sc->sc_deltay = -sc->sc_deltay; /* Otherwise mousey goes wrong way */ 247637Snate if (sc->sc_deltay > 127) 248637Snate sc->sc_deltay = 127; 249637Snate if (sc->sc_deltay < -127) 250637Snate sc->sc_deltay = -127; 251637Snate sc->sc_bytes[1] = sc->sc_deltax; 252637Snate sc->sc_bytes[2] = sc->sc_deltay; 253637Snate sc->sc_bytes[3] = sc->sc_bytes[4] = 0; 25431603Syokota sc->sc_bytes[5] = sc->sc_bytes[6] = 0; 25531603Syokota sc->sc_bytes[7] = MOUSE_SYS_EXTBUTTONS; 256637Snate sc->sc_obuttons = sc->sc_buttons; 257637Snate sc->sc_deltax = sc->sc_deltay = 0; 258637Snate sc->sc_bytesread = 0; 259637Snate } 260637Snate splx(s); 26131603Syokota xfer = min(uio->uio_resid, sc->mode.packetsize - sc->sc_bytesread); 26246571Speter error = uiomove(&sc->sc_bytes[sc->sc_bytesread], xfer, uio); 26346571Speter if (error) 264637Snate return (error); 265637Snate sc->sc_bytesread += xfer; 266637Snate return(0); 267637Snate} 268637Snate 269637Snate/* 27031603Syokota * mseioctl: process ioctl commands. 27131603Syokota */ 27231603Syokotastatic int 273144783Simpmseioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 27431603Syokota{ 275191320Sed mse_softc_t *sc = dev->si_drv1; 27631603Syokota mousestatus_t status; 27731603Syokota int err = 0; 27831603Syokota int s; 27931603Syokota 28031603Syokota switch (cmd) { 28131603Syokota 28231603Syokota case MOUSE_GETHWINFO: 28331603Syokota s = spltty(); 28431603Syokota *(mousehw_t *)addr = sc->hw; 28531603Syokota if (sc->mode.level == 0) 28631603Syokota ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 28731603Syokota splx(s); 28831603Syokota break; 28931603Syokota 29031603Syokota case MOUSE_GETMODE: 29131603Syokota s = spltty(); 29231603Syokota *(mousemode_t *)addr = sc->mode; 29331603Syokota switch (sc->mode.level) { 29431603Syokota case 0: 29531603Syokota break; 29631603Syokota case 1: 29731603Syokota ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 29831603Syokota ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 29931603Syokota ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 30031603Syokota break; 30131603Syokota } 30231603Syokota splx(s); 30331603Syokota break; 30431603Syokota 30531603Syokota case MOUSE_SETMODE: 30631603Syokota switch (((mousemode_t *)addr)->level) { 30731603Syokota case 0: 30831603Syokota case 1: 30931603Syokota break; 31031603Syokota default: 31131603Syokota return (EINVAL); 31231603Syokota } 31331603Syokota if (((mousemode_t *)addr)->accelfactor < -1) 31431603Syokota return (EINVAL); 31531603Syokota else if (((mousemode_t *)addr)->accelfactor >= 0) 31631603Syokota sc->mode.accelfactor = 31731603Syokota ((mousemode_t *)addr)->accelfactor; 31831603Syokota sc->mode.level = ((mousemode_t *)addr)->level; 31931603Syokota switch (sc->mode.level) { 32031603Syokota case 0: 32131603Syokota sc->sc_bytesread = sc->mode.packetsize 32231603Syokota = MOUSE_MSC_PACKETSIZE; 32331603Syokota break; 32431603Syokota case 1: 32531603Syokota sc->sc_bytesread = sc->mode.packetsize 32631603Syokota = MOUSE_SYS_PACKETSIZE; 32731603Syokota break; 32831603Syokota } 32931603Syokota break; 33031603Syokota 33131603Syokota case MOUSE_GETLEVEL: 33231603Syokota *(int *)addr = sc->mode.level; 33331603Syokota break; 33431603Syokota 33531603Syokota case MOUSE_SETLEVEL: 33631603Syokota switch (*(int *)addr) { 33731603Syokota case 0: 33831603Syokota sc->mode.level = *(int *)addr; 33931603Syokota sc->sc_bytesread = sc->mode.packetsize 34031603Syokota = MOUSE_MSC_PACKETSIZE; 34131603Syokota break; 34231603Syokota case 1: 34331603Syokota sc->mode.level = *(int *)addr; 34431603Syokota sc->sc_bytesread = sc->mode.packetsize 34531603Syokota = MOUSE_SYS_PACKETSIZE; 34631603Syokota break; 34731603Syokota default: 34831603Syokota return (EINVAL); 34931603Syokota } 35031603Syokota break; 35131603Syokota 35231603Syokota case MOUSE_GETSTATUS: 35331603Syokota s = spltty(); 35431603Syokota status = sc->status; 35531603Syokota sc->status.flags = 0; 35631603Syokota sc->status.obutton = sc->status.button; 35731603Syokota sc->status.button = 0; 35831603Syokota sc->status.dx = 0; 35931603Syokota sc->status.dy = 0; 36031603Syokota sc->status.dz = 0; 36131603Syokota splx(s); 36231603Syokota *(mousestatus_t *)addr = status; 36331603Syokota break; 36431603Syokota 36531603Syokota case MOUSE_READSTATE: 36631603Syokota case MOUSE_READDATA: 36731603Syokota return (ENODEV); 36831603Syokota 36931603Syokota#if (defined(MOUSE_GETVARS)) 37031603Syokota case MOUSE_GETVARS: 37131603Syokota case MOUSE_SETVARS: 37231603Syokota return (ENODEV); 37331603Syokota#endif 37431603Syokota 37531603Syokota default: 37631603Syokota return (ENOTTY); 37731603Syokota } 37831603Syokota return (err); 37931603Syokota} 38031603Syokota 38131603Syokota/* 38229368Speter * msepoll: check for mouse input to be processed. 383637Snate */ 38412675Sjulianstatic int 385144783Simpmsepoll(struct cdev *dev, int events, struct thread *td) 386637Snate{ 387191320Sed mse_softc_t *sc = dev->si_drv1; 388637Snate int s; 38929368Speter int revents = 0; 390637Snate 391637Snate s = spltty(); 39246568Speter if (events & (POLLIN | POLLRDNORM)) { 39331603Syokota if (sc->sc_bytesread != sc->mode.packetsize || 39431603Syokota sc->sc_deltax != 0 || sc->sc_deltay != 0 || 39529368Speter (sc->sc_obuttons ^ sc->sc_buttons) != 0) 39629368Speter revents |= events & (POLLIN | POLLRDNORM); 39729368Speter else { 39829368Speter /* 39929368Speter * Since this is an exclusive open device, any previous 40029368Speter * proc pointer is trash now, so we can just assign it. 40129368Speter */ 40283366Sjulian selrecord(td, &sc->sc_selp); 40329368Speter } 40446568Speter } 405637Snate splx(s); 40629368Speter return (revents); 407637Snate} 408637Snate 409637Snate/* 41058229Syokota * msetimeout: watchdog timer routine. 41158229Syokota */ 41258229Syokotastatic void 413144783Simpmsetimeout(void *arg) 41458229Syokota{ 415130585Sphk struct cdev *dev; 41658229Syokota mse_softc_t *sc; 41758229Syokota 418130585Sphk dev = (struct cdev *)arg; 419191320Sed sc = dev->si_drv1; 42058229Syokota if (sc->sc_watchdog) { 42158229Syokota if (bootverbose) 422191320Sed printf("%s: lost interrupt?\n", devtoname(dev)); 42358229Syokota mseintr(sc); 42458229Syokota } 42558229Syokota sc->sc_watchdog = TRUE; 42658229Syokota sc->sc_callout = timeout(msetimeout, dev, hz); 42758229Syokota} 42858229Syokota 42958229Syokota/* 430637Snate * mseintr: update mouse status. sc_deltax and sc_deltay are accumulative. 431637Snate */ 43240565Sbdestatic void 433144783Simpmseintr(void *arg) 434637Snate{ 43531603Syokota /* 43631603Syokota * the table to turn MouseSystem button bits (MOUSE_MSC_BUTTON?UP) 43731603Syokota * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 43831603Syokota */ 43931603Syokota static int butmap[8] = { 44031603Syokota 0, 44131603Syokota MOUSE_BUTTON3DOWN, 44231603Syokota MOUSE_BUTTON2DOWN, 44331603Syokota MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 44431603Syokota MOUSE_BUTTON1DOWN, 44531603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 44631603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 44731603Syokota MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 44831603Syokota }; 44958229Syokota mse_softc_t *sc = arg; 45031603Syokota int dx, dy, but; 45131603Syokota int sign; 452637Snate 453637Snate#ifdef DEBUG 454637Snate static int mse_intrcnt = 0; 455637Snate if((mse_intrcnt++ % 10000) == 0) 456637Snate printf("mseintr\n"); 457637Snate#endif /* DEBUG */ 458637Snate if ((sc->sc_flags & MSESC_OPEN) == 0) 459637Snate return; 460637Snate 46158229Syokota (*sc->sc_getmouse)(sc->sc_iot, sc->sc_ioh, &dx, &dy, &but); 46231603Syokota if (sc->mode.accelfactor > 0) { 46331603Syokota sign = (dx < 0); 46431603Syokota dx = dx * dx / sc->mode.accelfactor; 46531603Syokota if (dx == 0) 46631603Syokota dx = 1; 46731603Syokota if (sign) 46831603Syokota dx = -dx; 46931603Syokota sign = (dy < 0); 47031603Syokota dy = dy * dy / sc->mode.accelfactor; 47131603Syokota if (dy == 0) 47231603Syokota dy = 1; 47331603Syokota if (sign) 47431603Syokota dy = -dy; 47531603Syokota } 47631603Syokota sc->sc_deltax += dx; 47731603Syokota sc->sc_deltay += dy; 47831603Syokota sc->sc_buttons = but; 479637Snate 48031603Syokota but = butmap[~but & MOUSE_MSC_BUTTONS]; 48131603Syokota sc->status.dx += dx; 48231603Syokota sc->status.dy += dy; 48331603Syokota sc->status.flags |= ((dx || dy) ? MOUSE_POSCHANGED : 0) 48431603Syokota | (sc->status.button ^ but); 48531603Syokota sc->status.button = but; 48631603Syokota 48758229Syokota sc->sc_watchdog = FALSE; 48858229Syokota 489637Snate /* 490637Snate * If mouse state has changed, wake up anyone wanting to know. 491637Snate */ 492637Snate if (sc->sc_deltax != 0 || sc->sc_deltay != 0 || 493637Snate (sc->sc_obuttons ^ sc->sc_buttons) != 0) { 4948876Srgrimes if (sc->sc_flags & MSESC_WANT) { 4958876Srgrimes sc->sc_flags &= ~MSESC_WANT; 496111748Sdes wakeup(sc); 4978876Srgrimes } 498122352Stanimura selwakeuppri(&sc->sc_selp, MSEPRI); 499637Snate } 500637Snate} 501