psm.c revision 176554
141016Sdfr/*- 241016Sdfr * Copyright (c) 1992, 1993 Erik Forsberg. 341016Sdfr * Copyright (c) 1996, 1997 Kazutaka YOKOTA. 441016Sdfr * All rights reserved. 541016Sdfr * 641016Sdfr * Redistribution and use in source and binary forms, with or without 741016Sdfr * modification, are permitted provided that the following conditions 841016Sdfr * are met: 941016Sdfr * 1. Redistributions of source code must retain the above copyright 1041016Sdfr * notice, this list of conditions and the following disclaimer. 1141016Sdfr * 1241016Sdfr * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED 1341016Sdfr * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1441016Sdfr * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN 1541016Sdfr * NO EVENT SHALL I BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 1641016Sdfr * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1741016Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 1841016Sdfr * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 1941016Sdfr * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2041016Sdfr * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 2141016Sdfr * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2241016Sdfr */ 2341016Sdfr/* 2441016Sdfr * Ported to 386bsd Oct 17, 1992 2541016Sdfr * Sandi Donno, Computer Science, University of Cape Town, South Africa 2641016Sdfr * Please send bug reports to sandi@cs.uct.ac.za 2741016Sdfr * 2841016Sdfr * Thanks are also due to Rick Macklem, rick@snowhite.cis.uoguelph.ca - 2941016Sdfr * although I was only partially successful in getting the alpha release 3041016Sdfr * of his "driver for the Logitech and ATI Inport Bus mice for use with 3141016Sdfr * 386bsd and the X386 port" to work with my Microsoft mouse, I nevertheless 3241016Sdfr * found his code to be an invaluable reference when porting this driver 3341016Sdfr * to 386bsd. 3441016Sdfr * 3541016Sdfr * Further modifications for latest 386BSD+patchkit and port to NetBSD, 3641016Sdfr * Andrew Herbert <andrew@werple.apana.org.au> - 8 June 1993 3741016Sdfr * 3841016Sdfr * Cloned from the Microsoft Bus Mouse driver, also by Erik Forsberg, by 3941016Sdfr * Andrew Herbert - 12 June 1993 4041016Sdfr * 4141016Sdfr * Modified for PS/2 mouse by Charles Hannum <mycroft@ai.mit.edu> 4241016Sdfr * - 13 June 1993 4341016Sdfr * 4441016Sdfr * Modified for PS/2 AUX mouse by Shoji Yuen <yuen@nuie.nagoya-u.ac.jp> 4541016Sdfr * - 24 October 1993 4641016Sdfr * 4741016Sdfr * Hardware access routines and probe logic rewritten by 4841016Sdfr * Kazutaka Yokota <yokota@zodiac.mech.utsunomiya-u.ac.jp> 4941016Sdfr * - 3, 14, 22 October 1996. 5041016Sdfr * - 12 November 1996. IOCTLs and rearranging `psmread', `psmioctl'... 5141016Sdfr * - 14, 30 November 1996. Uses `kbdio.c'. 5241016Sdfr * - 13 December 1996. Uses queuing version of `kbdio.c'. 5341016Sdfr * - January/February 1997. Tweaked probe logic for 5441016Sdfr * HiNote UltraII/Latitude/Armada laptops. 5541016Sdfr * - 30 July 1997. Added APM support. 5641016Sdfr * - 5 March 1997. Defined driver configuration flags (PSM_CONFIG_XXX). 5741016Sdfr * Improved sync check logic. 5841016Sdfr * Vendor specific support routines. 5941016Sdfr */ 6041016Sdfr 61116181Sobrien#include <sys/cdefs.h> 62116181Sobrien__FBSDID("$FreeBSD: head/sys/dev/atkbdc/psm.c 176554 2008-02-25 13:57:18Z rink $"); 63116181Sobrien 64147271Smarius#include "opt_isa.h" 6541016Sdfr#include "opt_psm.h" 6641016Sdfr 6741016Sdfr#include <sys/param.h> 6841016Sdfr#include <sys/systm.h> 6941016Sdfr#include <sys/kernel.h> 7041016Sdfr#include <sys/module.h> 7141016Sdfr#include <sys/bus.h> 7241016Sdfr#include <sys/conf.h> 7341016Sdfr#include <sys/poll.h> 7441016Sdfr#include <sys/syslog.h> 7545720Speter#include <machine/bus.h> 7641181Sdfr#include <sys/rman.h> 7770834Swollman#include <sys/selinfo.h> 78123442Salfred#include <sys/sysctl.h> 7984880Syokota#include <sys/time.h> 8041016Sdfr#include <sys/uio.h> 8141016Sdfr 82114216Skan#include <sys/limits.h> 8366860Sphk#include <sys/mouse.h> 8441181Sdfr#include <machine/resource.h> 8541016Sdfr 86147271Smarius#ifdef DEV_ISA 8741016Sdfr#include <isa/isavar.h> 88147271Smarius#endif 8941016Sdfr 90147271Smarius#include <dev/atkbdc/atkbdcreg.h> 91147271Smarius#include <dev/atkbdc/psm.h> 92147271Smarius 9341016Sdfr/* 9441016Sdfr * Driver specific options: the following options may be set by 9541016Sdfr * `options' statements in the kernel configuration file. 9641016Sdfr */ 9741016Sdfr 9841016Sdfr/* debugging */ 9941016Sdfr#ifndef PSM_DEBUG 100134405Sgibbs#define PSM_DEBUG 0 /* 101134405Sgibbs * logging: 0: none, 1: brief, 2: verbose 102134405Sgibbs * 3: sync errors, 4: all packets 103134405Sgibbs */ 10441016Sdfr#endif 105134405Sgibbs#define VLOG(level, args) \ 106134405Sgibbsdo { \ 107134405Sgibbs if (verbose >= level) \ 108134405Sgibbs log args; \ 109134405Sgibbs} while (0) 11041016Sdfr 11184880Syokota#ifndef PSM_INPUT_TIMEOUT 11284880Syokota#define PSM_INPUT_TIMEOUT 2000000 /* 2 sec */ 11384880Syokota#endif 11484880Syokota 115133297Sphilip#ifndef PSM_TAP_TIMEOUT 116133297Sphilip#define PSM_TAP_TIMEOUT 125000 117133297Sphilip#endif 118133297Sphilip 119133297Sphilip#ifndef PSM_TAP_THRESHOLD 120133297Sphilip#define PSM_TAP_THRESHOLD 25 121133297Sphilip#endif 122133297Sphilip 12341016Sdfr/* end of driver specific options */ 12441016Sdfr 12583931Syokota#define PSMCPNP_DRIVER_NAME "psmcpnp" 12683492Syokota 12741016Sdfr/* input queue */ 12841016Sdfr#define PSM_BUFSIZE 960 12941016Sdfr#define PSM_SMALLBUFSIZE 240 13041016Sdfr 13141016Sdfr/* operation levels */ 13241016Sdfr#define PSM_LEVEL_BASE 0 13341016Sdfr#define PSM_LEVEL_STANDARD 1 13441016Sdfr#define PSM_LEVEL_NATIVE 2 13541016Sdfr#define PSM_LEVEL_MIN PSM_LEVEL_BASE 13641016Sdfr#define PSM_LEVEL_MAX PSM_LEVEL_NATIVE 13741016Sdfr 13848778Syokota/* Logitech PS2++ protocol */ 13948778Syokota#define MOUSE_PS2PLUS_CHECKBITS(b) \ 14048778Syokota ((((b[2] & 0x03) << 2) | 0x02) == (b[1] & 0x0f)) 14148778Syokota#define MOUSE_PS2PLUS_PACKET_TYPE(b) \ 14248778Syokota (((b[0] & 0x30) >> 2) | ((b[1] & 0x30) >> 4)) 14348778Syokota 14441016Sdfr/* some macros */ 14541016Sdfr#define PSM_UNIT(dev) (minor(dev) >> 1) 14641016Sdfr#define PSM_NBLOCKIO(dev) (minor(dev) & 1) 14741016Sdfr#define PSM_MKMINOR(unit,block) (((unit) << 1) | ((block) ? 0:1)) 14841016Sdfr 14941016Sdfr/* ring buffer */ 15041016Sdfrtypedef struct ringbuf { 15141016Sdfr int count; /* # of valid elements in the buffer */ 15241016Sdfr int head; /* head pointer */ 15341016Sdfr int tail; /* tail poiner */ 15441016Sdfr unsigned char buf[PSM_BUFSIZE]; 15541016Sdfr} ringbuf_t; 15641016Sdfr 157123442Salfred/* data buffer */ 158123442Salfredtypedef struct packetbuf { 159123442Salfred unsigned char ipacket[16]; /* interim input buffer */ 160123442Salfred int inputbytes; /* # of bytes in the input buffer */ 161123442Salfred} packetbuf_t; 162123442Salfred 163123442Salfred#ifndef PSM_PACKETQUEUE 164123442Salfred#define PSM_PACKETQUEUE 128 165123442Salfred#endif 166123442Salfred 167139982Sphiliptypedef struct synapticsinfo { 168139982Sphilip struct sysctl_ctx_list sysctl_ctx; 169139982Sphilip struct sysctl_oid *sysctl_tree; 170139982Sphilip int directional_scrolls; 171139982Sphilip int low_speed_threshold; 172139982Sphilip int min_movement; 173139982Sphilip int squelch_level; 174139982Sphilip} synapticsinfo_t; 175139982Sphilip 17641016Sdfr/* driver control block */ 17741016Sdfrstruct psm_softc { /* Driver status information */ 17884880Syokota int unit; 17941016Sdfr struct selinfo rsel; /* Process selecting for Input */ 18041016Sdfr unsigned char state; /* Mouse driver state */ 18141016Sdfr int config; /* driver configuration flags */ 18241016Sdfr int flags; /* other flags */ 18341016Sdfr KBDC kbdc; /* handle to access the keyboard controller */ 18458230Syokota struct resource *intr; /* IRQ resource */ 18558230Syokota void *ih; /* interrupt handle */ 18641016Sdfr mousehw_t hw; /* hardware information */ 187132865Snjl synapticshw_t synhw; /* Synaptics-specific hardware information */ 188139982Sphilip synapticsinfo_t syninfo; /* Synaptics-specific configuration */ 18941016Sdfr mousemode_t mode; /* operation mode */ 19041016Sdfr mousemode_t dflt_mode; /* default operation mode */ 19141016Sdfr mousestatus_t status; /* accumulated mouse movement */ 19241016Sdfr ringbuf_t queue; /* mouse status queue */ 193123442Salfred packetbuf_t pqueue[PSM_PACKETQUEUE]; /* mouse data queue */ 194123442Salfred int pqueue_start; /* start of data in queue */ 195123442Salfred int pqueue_end; /* end of data in queue */ 19641016Sdfr int button; /* the latest button state */ 197139982Sphilip int xold; /* previous absolute X position */ 198139982Sphilip int yold; /* previous absolute Y position */ 199139982Sphilip int xaverage; /* average X position */ 200139982Sphilip int yaverage; /* average Y position */ 201139982Sphilip int squelch; /* level to filter movement data at low speed */ 202139982Sphilip int zmax; /* maximum pressure value for touchpads */ 203134405Sgibbs int syncerrors; /* # of bytes discarded searching for sync */ 204134405Sgibbs int pkterrors; /* # of packets failed during quaranteen. */ 20584880Syokota struct timeval inputtimeout; 206123442Salfred struct timeval lastsoftintr; /* time of last soft interrupt */ 207123442Salfred struct timeval lastinputerr; /* time last sync error happened */ 208133297Sphilip struct timeval taptimeout; /* tap timeout for touchpads */ 209139982Sphilip int watchdog; /* watchdog timer flag */ 21058230Syokota struct callout_handle callout; /* watchdog timer call out */ 211123442Salfred struct callout_handle softcallout; /* buffer timer call out */ 212130585Sphk struct cdev *dev; 213130585Sphk struct cdev *bdev; 214123442Salfred int lasterr; 215123442Salfred int cmdcount; 21641016Sdfr}; 217114293Smarkmstatic devclass_t psm_devclass; 21841016Sdfr#define PSM_SOFTC(unit) ((struct psm_softc*)devclass_get_softc(psm_devclass, unit)) 21941016Sdfr 22041016Sdfr/* driver state flags (state) */ 22141016Sdfr#define PSM_VALID 0x80 22241016Sdfr#define PSM_OPEN 1 /* Device is open */ 22341016Sdfr#define PSM_ASLP 2 /* Waiting for mouse data */ 224123442Salfred#define PSM_SOFTARMED 4 /* Software interrupt armed */ 225133918Sgibbs#define PSM_NEED_SYNCBITS 8 /* Set syncbits using next data pkt */ 22641016Sdfr 22741016Sdfr/* driver configuration flags (config) */ 22841016Sdfr#define PSM_CONFIG_RESOLUTION 0x000f /* resolution */ 22941016Sdfr#define PSM_CONFIG_ACCEL 0x00f0 /* acceleration factor */ 23041016Sdfr#define PSM_CONFIG_NOCHECKSYNC 0x0100 /* disable sync. test */ 23145789Speter#define PSM_CONFIG_NOIDPROBE 0x0200 /* disable mouse model probe */ 23245789Speter#define PSM_CONFIG_NORESET 0x0400 /* don't reset the mouse */ 23345789Speter#define PSM_CONFIG_FORCETAP 0x0800 /* assume `tap' action exists */ 23445789Speter#define PSM_CONFIG_IGNPORTERROR 0x1000 /* ignore error in aux port test */ 23558230Syokota#define PSM_CONFIG_HOOKRESUME 0x2000 /* hook the system resume event */ 23658230Syokota#define PSM_CONFIG_INITAFTERSUSPEND 0x4000 /* init the device at the resume event */ 23769439Syokota#define PSM_CONFIG_SYNCHACK 0x8000 /* enable `out-of-sync' hack */ 23841016Sdfr 23941016Sdfr#define PSM_CONFIG_FLAGS (PSM_CONFIG_RESOLUTION \ 24041016Sdfr | PSM_CONFIG_ACCEL \ 24145789Speter | PSM_CONFIG_NOCHECKSYNC \ 24269439Syokota | PSM_CONFIG_SYNCHACK \ 24345789Speter | PSM_CONFIG_NOIDPROBE \ 24445789Speter | PSM_CONFIG_NORESET \ 24545789Speter | PSM_CONFIG_FORCETAP \ 24658230Syokota | PSM_CONFIG_IGNPORTERROR \ 24758230Syokota | PSM_CONFIG_HOOKRESUME \ 24858230Syokota | PSM_CONFIG_INITAFTERSUSPEND) 24941016Sdfr 25041016Sdfr/* other flags (flags) */ 25149965Syokota#define PSM_FLAGS_FINGERDOWN 0x0001 /* VersaPad finger down */ 25241016Sdfr 253135945Sphilip/* Tunables */ 254135945Sphilipstatic int synaptics_support = 0; 255135945SphilipTUNABLE_INT("hw.psm.synaptics_support", &synaptics_support); 256135945Sphilip 257139628Sphilipstatic int verbose = PSM_DEBUG; 258139628SphilipTUNABLE_INT("debug.psm.loglevel", &verbose); 259139628Sphilip 26041016Sdfr/* for backward compatibility */ 26141016Sdfr#define OLD_MOUSE_GETHWINFO _IOR('M', 1, old_mousehw_t) 26241016Sdfr#define OLD_MOUSE_GETMODE _IOR('M', 2, old_mousemode_t) 26341016Sdfr#define OLD_MOUSE_SETMODE _IOW('M', 3, old_mousemode_t) 26441016Sdfr 26541016Sdfrtypedef struct old_mousehw { 26641016Sdfr int buttons; 26741016Sdfr int iftype; 26841016Sdfr int type; 26941016Sdfr int hwid; 27041016Sdfr} old_mousehw_t; 27141016Sdfr 27241016Sdfrtypedef struct old_mousemode { 27341016Sdfr int protocol; 27441016Sdfr int rate; 27541016Sdfr int resolution; 27641016Sdfr int accelfactor; 27741016Sdfr} old_mousemode_t; 27841016Sdfr 27941016Sdfr/* packet formatting function */ 28092756Salfredtypedef int packetfunc_t(struct psm_softc *, unsigned char *, 28192756Salfred int *, int, mousestatus_t *); 28241016Sdfr 28341016Sdfr/* function prototypes */ 28492756Salfredstatic void psmidentify(driver_t *, device_t); 28592756Salfredstatic int psmprobe(device_t); 28692756Salfredstatic int psmattach(device_t); 28792756Salfredstatic int psmdetach(device_t); 28892756Salfredstatic int psmresume(device_t); 28941016Sdfr 29041016Sdfrstatic d_open_t psmopen; 29141016Sdfrstatic d_close_t psmclose; 29241016Sdfrstatic d_read_t psmread; 29341016Sdfrstatic d_ioctl_t psmioctl; 29441016Sdfrstatic d_poll_t psmpoll; 29541016Sdfr 29692756Salfredstatic int enable_aux_dev(KBDC); 29792756Salfredstatic int disable_aux_dev(KBDC); 29892756Salfredstatic int get_mouse_status(KBDC, int *, int, int); 29992756Salfredstatic int get_aux_id(KBDC); 30092756Salfredstatic int set_mouse_sampling_rate(KBDC, int); 30192756Salfredstatic int set_mouse_scaling(KBDC, int); 30292756Salfredstatic int set_mouse_resolution(KBDC, int); 30392756Salfredstatic int set_mouse_mode(KBDC); 30492756Salfredstatic int get_mouse_buttons(KBDC); 30592756Salfredstatic int is_a_mouse(int); 30692756Salfredstatic void recover_from_error(KBDC); 30792756Salfredstatic int restore_controller(KBDC, int); 30892756Salfredstatic int doinitialize(struct psm_softc *, mousemode_t *); 30992756Salfredstatic int doopen(struct psm_softc *, int); 31092756Salfredstatic int reinitialize(struct psm_softc *, int); 31192756Salfredstatic char *model_name(int); 312123442Salfredstatic void psmsoftintr(void *); 31392756Salfredstatic void psmintr(void *); 31492756Salfredstatic void psmtimeout(void *); 315123442Salfredstatic int timeelapsed(const struct timeval *, 316123442Salfred int, int, const struct timeval *); 317123442Salfredstatic void dropqueue(struct psm_softc *); 318123442Salfredstatic void flushpackets(struct psm_softc *); 31941016Sdfr 32041016Sdfr/* vendor specific features */ 32192756Salfredtypedef int probefunc_t(struct psm_softc *); 32241016Sdfr 32392756Salfredstatic int mouse_id_proc1(KBDC, int, int, int *); 32492756Salfredstatic int mouse_ext_command(KBDC, int); 32541016Sdfrstatic probefunc_t enable_groller; 32641016Sdfrstatic probefunc_t enable_gmouse; 32741016Sdfrstatic probefunc_t enable_aglide; 32841016Sdfrstatic probefunc_t enable_kmouse; 32958230Syokotastatic probefunc_t enable_msexplorer; 33041016Sdfrstatic probefunc_t enable_msintelli; 33158230Syokotastatic probefunc_t enable_4dmouse; 33258230Syokotastatic probefunc_t enable_4dplus; 33341016Sdfrstatic probefunc_t enable_mmanplus; 334132865Snjlstatic probefunc_t enable_synaptics; 33549965Syokotastatic probefunc_t enable_versapad; 336123442Salfredstatic int tame_mouse(struct psm_softc *, packetbuf_t *, mousestatus_t *, unsigned char *); 33741016Sdfr 33841016Sdfrstatic struct { 33941016Sdfr int model; 34041016Sdfr unsigned char syncmask; 34141016Sdfr int packetsize; 34241016Sdfr probefunc_t *probefunc; 34341016Sdfr} vendortype[] = { 34458230Syokota /* 34558230Syokota * WARNING: the order of probe is very important. Don't mess it 34658230Syokota * unless you know what you are doing. 34758230Syokota */ 34841016Sdfr { MOUSE_MODEL_NET, /* Genius NetMouse */ 34958230Syokota 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_gmouse, }, 35041016Sdfr { MOUSE_MODEL_NETSCROLL, /* Genius NetScroll */ 35141016Sdfr 0xc8, 6, enable_groller, }, 35258230Syokota { MOUSE_MODEL_MOUSEMANPLUS, /* Logitech MouseMan+ */ 35358230Syokota 0x08, MOUSE_PS2_PACKETSIZE, enable_mmanplus, }, 35458230Syokota { MOUSE_MODEL_EXPLORER, /* Microsoft IntelliMouse Explorer */ 35558230Syokota 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msexplorer, }, 35658230Syokota { MOUSE_MODEL_4D, /* A4 Tech 4D Mouse */ 35758230Syokota 0x08, MOUSE_4D_PACKETSIZE, enable_4dmouse, }, 35858230Syokota { MOUSE_MODEL_4DPLUS, /* A4 Tech 4D+ Mouse */ 35958230Syokota 0xc8, MOUSE_4DPLUS_PACKETSIZE, enable_4dplus, }, 36058230Syokota { MOUSE_MODEL_INTELLI, /* Microsoft IntelliMouse */ 36158230Syokota 0x08, MOUSE_PS2INTELLI_PACKETSIZE, enable_msintelli, }, 36241016Sdfr { MOUSE_MODEL_GLIDEPOINT, /* ALPS GlidePoint */ 36341016Sdfr 0xc0, MOUSE_PS2_PACKETSIZE, enable_aglide, }, 364165335Skeramida { MOUSE_MODEL_THINK, /* Kensington ThinkingMouse */ 36541016Sdfr 0x80, MOUSE_PS2_PACKETSIZE, enable_kmouse, }, 36649965Syokota { MOUSE_MODEL_VERSAPAD, /* Interlink electronics VersaPad */ 36749965Syokota 0xe8, MOUSE_PS2VERSA_PACKETSIZE, enable_versapad, }, 368132865Snjl { MOUSE_MODEL_SYNAPTICS, /* Synaptics Touchpad */ 369132865Snjl 0xc0, MOUSE_SYNAPTICS_PACKETSIZE, enable_synaptics, }, 37041016Sdfr { MOUSE_MODEL_GENERIC, 37141016Sdfr 0xc0, MOUSE_PS2_PACKETSIZE, NULL, }, 37241016Sdfr}; 37363951Syokota#define GENERIC_MOUSE_ENTRY ((sizeof(vendortype) / sizeof(*vendortype)) - 1) 37441016Sdfr 37541016Sdfr/* device driver declarateion */ 37641016Sdfrstatic device_method_t psm_methods[] = { 37741016Sdfr /* Device interface */ 37883147Syokota DEVMETHOD(device_identify, psmidentify), 37941016Sdfr DEVMETHOD(device_probe, psmprobe), 38041016Sdfr DEVMETHOD(device_attach, psmattach), 38158230Syokota DEVMETHOD(device_detach, psmdetach), 38254629Syokota DEVMETHOD(device_resume, psmresume), 38341016Sdfr 38441016Sdfr { 0, 0 } 38541016Sdfr}; 38641016Sdfr 38741016Sdfrstatic driver_t psm_driver = { 38883492Syokota PSM_DRIVER_NAME, 38941016Sdfr psm_methods, 39041016Sdfr sizeof(struct psm_softc), 39141016Sdfr}; 39241016Sdfr 39341016Sdfr 39447625Sphkstatic struct cdevsw psm_cdevsw = { 395126080Sphk .d_version = D_VERSION, 396126080Sphk .d_flags = D_NEEDGIANT, 397111815Sphk .d_open = psmopen, 398111815Sphk .d_close = psmclose, 399111815Sphk .d_read = psmread, 400111815Sphk .d_ioctl = psmioctl, 401111815Sphk .d_poll = psmpoll, 402111815Sphk .d_name = PSM_DRIVER_NAME, 40341016Sdfr}; 40441016Sdfr 40541016Sdfr/* device I/O routines */ 40641016Sdfrstatic int 40741016Sdfrenable_aux_dev(KBDC kbdc) 40841016Sdfr{ 40941016Sdfr int res; 41041016Sdfr 41141016Sdfr res = send_aux_command(kbdc, PSMC_ENABLE_DEV); 412134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: ENABLE_DEV return code:%04x\n", res)); 41341016Sdfr 41441016Sdfr return (res == PSM_ACK); 41541016Sdfr} 41641016Sdfr 41741016Sdfrstatic int 41841016Sdfrdisable_aux_dev(KBDC kbdc) 41941016Sdfr{ 42041016Sdfr int res; 42141016Sdfr 42241016Sdfr res = send_aux_command(kbdc, PSMC_DISABLE_DEV); 423134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: DISABLE_DEV return code:%04x\n", res)); 42441016Sdfr 42541016Sdfr return (res == PSM_ACK); 42641016Sdfr} 42741016Sdfr 42841016Sdfrstatic int 42941016Sdfrget_mouse_status(KBDC kbdc, int *status, int flag, int len) 43041016Sdfr{ 43141016Sdfr int cmd; 43241016Sdfr int res; 43341016Sdfr int i; 43441016Sdfr 43541016Sdfr switch (flag) { 43641016Sdfr case 0: 43741016Sdfr default: 43841016Sdfr cmd = PSMC_SEND_DEV_STATUS; 43941016Sdfr break; 44041016Sdfr case 1: 44141016Sdfr cmd = PSMC_SEND_DEV_DATA; 44241016Sdfr break; 44341016Sdfr } 44441016Sdfr empty_aux_buffer(kbdc, 5); 44541016Sdfr res = send_aux_command(kbdc, cmd); 446134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SEND_AUX_DEV_%s return code:%04x\n", 447134405Sgibbs (flag == 1) ? "DATA" : "STATUS", res)); 44841016Sdfr if (res != PSM_ACK) 44941016Sdfr return 0; 45041016Sdfr 45141016Sdfr for (i = 0; i < len; ++i) { 45241016Sdfr status[i] = read_aux_data(kbdc); 45341016Sdfr if (status[i] < 0) 45441016Sdfr break; 45541016Sdfr } 45641016Sdfr 457134405Sgibbs VLOG(1, (LOG_DEBUG, "psm: %s %02x %02x %02x\n", 458134405Sgibbs (flag == 1) ? "data" : "status", status[0], status[1], status[2])); 45941016Sdfr 46041016Sdfr return i; 46141016Sdfr} 46241016Sdfr 46341016Sdfrstatic int 46441016Sdfrget_aux_id(KBDC kbdc) 46541016Sdfr{ 46641016Sdfr int res; 46741016Sdfr int id; 46841016Sdfr 46941016Sdfr empty_aux_buffer(kbdc, 5); 47041016Sdfr res = send_aux_command(kbdc, PSMC_SEND_DEV_ID); 471134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SEND_DEV_ID return code:%04x\n", res)); 47241016Sdfr if (res != PSM_ACK) 47341016Sdfr return (-1); 47441016Sdfr 47541016Sdfr /* 10ms delay */ 47641016Sdfr DELAY(10000); 47741016Sdfr 47841016Sdfr id = read_aux_data(kbdc); 479134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: device ID: %04x\n", id)); 48041016Sdfr 48141016Sdfr return id; 48241016Sdfr} 48341016Sdfr 48441016Sdfrstatic int 48541016Sdfrset_mouse_sampling_rate(KBDC kbdc, int rate) 48641016Sdfr{ 48741016Sdfr int res; 48841016Sdfr 48941016Sdfr res = send_aux_command_and_data(kbdc, PSMC_SET_SAMPLING_RATE, rate); 490134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SET_SAMPLING_RATE (%d) %04x\n", rate, res)); 49141016Sdfr 49241016Sdfr return ((res == PSM_ACK) ? rate : -1); 49341016Sdfr} 49441016Sdfr 49541016Sdfrstatic int 49641016Sdfrset_mouse_scaling(KBDC kbdc, int scale) 49741016Sdfr{ 49841016Sdfr int res; 49941016Sdfr 50041016Sdfr switch (scale) { 50141016Sdfr case 1: 50241016Sdfr default: 50341016Sdfr scale = PSMC_SET_SCALING11; 50441016Sdfr break; 50541016Sdfr case 2: 50641016Sdfr scale = PSMC_SET_SCALING21; 50741016Sdfr break; 50841016Sdfr } 50941016Sdfr res = send_aux_command(kbdc, scale); 510134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SET_SCALING%s return code:%04x\n", 511134405Sgibbs (scale == PSMC_SET_SCALING21) ? "21" : "11", res)); 51241016Sdfr 51341016Sdfr return (res == PSM_ACK); 51441016Sdfr} 51541016Sdfr 51641016Sdfr/* `val' must be 0 through PSMD_MAX_RESOLUTION */ 51741016Sdfrstatic int 51841016Sdfrset_mouse_resolution(KBDC kbdc, int val) 51941016Sdfr{ 52041016Sdfr int res; 52141016Sdfr 52241016Sdfr res = send_aux_command_and_data(kbdc, PSMC_SET_RESOLUTION, val); 523134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SET_RESOLUTION (%d) %04x\n", val, res)); 52441016Sdfr 52541016Sdfr return ((res == PSM_ACK) ? val : -1); 52641016Sdfr} 52741016Sdfr 52841016Sdfr/* 52941016Sdfr * NOTE: once `set_mouse_mode()' is called, the mouse device must be 53041016Sdfr * re-enabled by calling `enable_aux_dev()' 53141016Sdfr */ 53241016Sdfrstatic int 53341016Sdfrset_mouse_mode(KBDC kbdc) 53441016Sdfr{ 53541016Sdfr int res; 53641016Sdfr 53741016Sdfr res = send_aux_command(kbdc, PSMC_SET_STREAM_MODE); 538134405Sgibbs VLOG(2, (LOG_DEBUG, "psm: SET_STREAM_MODE return code:%04x\n", res)); 53941016Sdfr 54041016Sdfr return (res == PSM_ACK); 54141016Sdfr} 54241016Sdfr 54341016Sdfrstatic int 54441016Sdfrget_mouse_buttons(KBDC kbdc) 54541016Sdfr{ 54641016Sdfr int c = 2; /* assume two buttons by default */ 54741016Sdfr int status[3]; 54841016Sdfr 54941016Sdfr /* 55041016Sdfr * NOTE: a special sequence to obtain Logitech Mouse specific 55141016Sdfr * information: set resolution to 25 ppi, set scaling to 1:1, set 55241016Sdfr * scaling to 1:1, set scaling to 1:1. Then the second byte of the 55341016Sdfr * mouse status bytes is the number of available buttons. 55441016Sdfr * Some manufactures also support this sequence. 55541016Sdfr */ 55641016Sdfr if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW) 55741016Sdfr return c; 55841016Sdfr if (set_mouse_scaling(kbdc, 1) && set_mouse_scaling(kbdc, 1) 55941016Sdfr && set_mouse_scaling(kbdc, 1) 56041016Sdfr && (get_mouse_status(kbdc, status, 0, 3) >= 3)) { 56141016Sdfr if (status[1] != 0) 56241016Sdfr return status[1]; 56341016Sdfr } 56441016Sdfr return c; 56541016Sdfr} 56641016Sdfr 56741016Sdfr/* misc subroutines */ 56841016Sdfr/* 56941016Sdfr * Someday, I will get the complete list of valid pointing devices and 57041016Sdfr * their IDs... XXX 57141016Sdfr */ 57241016Sdfrstatic int 57341016Sdfris_a_mouse(int id) 57441016Sdfr{ 57541016Sdfr#if 0 57641016Sdfr static int valid_ids[] = { 57741016Sdfr PSM_MOUSE_ID, /* mouse */ 57841016Sdfr PSM_BALLPOINT_ID, /* ballpoint device */ 57941016Sdfr PSM_INTELLI_ID, /* Intellimouse */ 58058230Syokota PSM_EXPLORER_ID, /* Intellimouse Explorer */ 58141016Sdfr -1 /* end of table */ 58241016Sdfr }; 58341016Sdfr int i; 58441016Sdfr 58541016Sdfr for (i = 0; valid_ids[i] >= 0; ++i) 58641016Sdfr if (valid_ids[i] == id) 58741016Sdfr return TRUE; 58841016Sdfr return FALSE; 58941016Sdfr#else 59041016Sdfr return TRUE; 59141016Sdfr#endif 59241016Sdfr} 59341016Sdfr 59441016Sdfrstatic char * 59541016Sdfrmodel_name(int model) 59641016Sdfr{ 59741016Sdfr static struct { 59841016Sdfr int model_code; 59941016Sdfr char *model_name; 60041016Sdfr } models[] = { 60158230Syokota { MOUSE_MODEL_NETSCROLL, "NetScroll" }, 60258230Syokota { MOUSE_MODEL_NET, "NetMouse/NetScroll Optical" }, 60341016Sdfr { MOUSE_MODEL_GLIDEPOINT, "GlidePoint" }, 60441016Sdfr { MOUSE_MODEL_THINK, "ThinkingMouse" }, 60541016Sdfr { MOUSE_MODEL_INTELLI, "IntelliMouse" }, 60641016Sdfr { MOUSE_MODEL_MOUSEMANPLUS, "MouseMan+" }, 60749965Syokota { MOUSE_MODEL_VERSAPAD, "VersaPad" }, 60858230Syokota { MOUSE_MODEL_EXPLORER, "IntelliMouse Explorer" }, 60958230Syokota { MOUSE_MODEL_4D, "4D Mouse" }, 61058230Syokota { MOUSE_MODEL_4DPLUS, "4D+ Mouse" }, 611132865Snjl { MOUSE_MODEL_SYNAPTICS, "Synaptics Touchpad" }, 61241016Sdfr { MOUSE_MODEL_GENERIC, "Generic PS/2 mouse" }, 61341016Sdfr { MOUSE_MODEL_UNKNOWN, NULL }, 61441016Sdfr }; 61541016Sdfr int i; 61641016Sdfr 61741016Sdfr for (i = 0; models[i].model_code != MOUSE_MODEL_UNKNOWN; ++i) { 61841016Sdfr if (models[i].model_code == model) 61941016Sdfr return models[i].model_name; 62041016Sdfr } 62141016Sdfr return "Unknown"; 62241016Sdfr} 62341016Sdfr 62441016Sdfrstatic void 62541016Sdfrrecover_from_error(KBDC kbdc) 62641016Sdfr{ 62741016Sdfr /* discard anything left in the output buffer */ 62841016Sdfr empty_both_buffers(kbdc, 10); 62941016Sdfr 63041016Sdfr#if 0 63141016Sdfr /* 63241016Sdfr * NOTE: KBDC_RESET_KBD may not restore the communication between the 63341016Sdfr * keyboard and the controller. 63441016Sdfr */ 63541016Sdfr reset_kbd(kbdc); 63641016Sdfr#else 63741016Sdfr /* 63841016Sdfr * NOTE: somehow diagnostic and keyboard port test commands bring the 63941016Sdfr * keyboard back. 64041016Sdfr */ 64141016Sdfr if (!test_controller(kbdc)) 64241016Sdfr log(LOG_ERR, "psm: keyboard controller failed.\n"); 64341016Sdfr /* if there isn't a keyboard in the system, the following error is OK */ 644134405Sgibbs if (test_kbd_port(kbdc) != 0) 645134405Sgibbs VLOG(1, (LOG_ERR, "psm: keyboard port failed.\n")); 64641016Sdfr#endif 64741016Sdfr} 64841016Sdfr 64941016Sdfrstatic int 65041016Sdfrrestore_controller(KBDC kbdc, int command_byte) 65141016Sdfr{ 65241016Sdfr empty_both_buffers(kbdc, 10); 65341016Sdfr 65441016Sdfr if (!set_controller_command_byte(kbdc, 0xff, command_byte)) { 65541016Sdfr log(LOG_ERR, "psm: failed to restore the keyboard controller " 65641016Sdfr "command byte.\n"); 65758230Syokota empty_both_buffers(kbdc, 10); 65841016Sdfr return FALSE; 65941016Sdfr } else { 66058230Syokota empty_both_buffers(kbdc, 10); 66141016Sdfr return TRUE; 66241016Sdfr } 66341016Sdfr} 66441016Sdfr 66541016Sdfr/* 66641016Sdfr * Re-initialize the aux port and device. The aux port must be enabled 66741016Sdfr * and its interrupt must be disabled before calling this routine. 66841016Sdfr * The aux device will be disabled before returning. 66941016Sdfr * The keyboard controller must be locked via `kbdc_lock()' before 67041016Sdfr * calling this routine. 67141016Sdfr */ 67241016Sdfrstatic int 67384880Syokotadoinitialize(struct psm_softc *sc, mousemode_t *mode) 67441016Sdfr{ 67541016Sdfr KBDC kbdc = sc->kbdc; 67641016Sdfr int stat[3]; 67741016Sdfr int i; 67841016Sdfr 67941016Sdfr switch((i = test_aux_port(kbdc))) { 680132270Smux case 1: /* ignore these errors */ 681132270Smux case 2: 682132270Smux case 3: 68341016Sdfr case PSM_ACK: 68441016Sdfr if (verbose) 68541016Sdfr log(LOG_DEBUG, "psm%d: strange result for test aux port (%d).\n", 68684880Syokota sc->unit, i); 687102412Scharnier /* FALLTHROUGH */ 68841016Sdfr case 0: /* no error */ 68941016Sdfr break; 69041016Sdfr case -1: /* time out */ 69141016Sdfr default: /* error */ 69241016Sdfr recover_from_error(kbdc); 69345789Speter if (sc->config & PSM_CONFIG_IGNPORTERROR) 69445789Speter break; 69541016Sdfr log(LOG_ERR, "psm%d: the aux port is not functioning (%d).\n", 69684880Syokota sc->unit, i); 69741016Sdfr return FALSE; 69841016Sdfr } 69941016Sdfr 70045789Speter if (sc->config & PSM_CONFIG_NORESET) { 70145789Speter /* 70245789Speter * Don't try to reset the pointing device. It may possibly be 70345789Speter * left in the unknown state, though... 70445789Speter */ 70545789Speter } else { 70645789Speter /* 70745789Speter * NOTE: some controllers appears to hang the `keyboard' when 70845789Speter * the aux port doesn't exist and `PSMC_RESET_DEV' is issued. 70945789Speter */ 71045789Speter if (!reset_aux_dev(kbdc)) { 71145789Speter recover_from_error(kbdc); 71284880Syokota log(LOG_ERR, "psm%d: failed to reset the aux device.\n", sc->unit); 71345789Speter return FALSE; 71445789Speter } 71541016Sdfr } 71641016Sdfr 71741016Sdfr /* 71841016Sdfr * both the aux port and the aux device is functioning, see 71941016Sdfr * if the device can be enabled. 72041016Sdfr */ 72141016Sdfr if (!enable_aux_dev(kbdc) || !disable_aux_dev(kbdc)) { 72284880Syokota log(LOG_ERR, "psm%d: failed to enable the aux device.\n", sc->unit); 72341016Sdfr return FALSE; 72441016Sdfr } 72541016Sdfr empty_both_buffers(kbdc, 10); /* remove stray data if any */ 72641016Sdfr 72745789Speter if (sc->config & PSM_CONFIG_NOIDPROBE) { 72845789Speter i = GENERIC_MOUSE_ENTRY; 72945789Speter } else { 73045789Speter /* FIXME: hardware ID, mouse buttons? */ 73141016Sdfr 73245789Speter /* other parameters */ 73345789Speter for (i = 0; vendortype[i].probefunc != NULL; ++i) { 73445789Speter if ((*vendortype[i].probefunc)(sc)) { 73545789Speter if (verbose >= 2) 73645789Speter log(LOG_ERR, "psm%d: found %s\n", 73784880Syokota sc->unit, model_name(vendortype[i].model)); 73845789Speter break; 73945789Speter } 74041016Sdfr } 74141016Sdfr } 74241016Sdfr 74341016Sdfr sc->hw.model = vendortype[i].model; 74441016Sdfr sc->mode.packetsize = vendortype[i].packetsize; 74541016Sdfr 74641016Sdfr /* set mouse parameters */ 74741016Sdfr if (mode != (mousemode_t *)NULL) { 74841016Sdfr if (mode->rate > 0) 74941016Sdfr mode->rate = set_mouse_sampling_rate(kbdc, mode->rate); 75041016Sdfr if (mode->resolution >= 0) 75141016Sdfr mode->resolution = set_mouse_resolution(kbdc, mode->resolution); 75241016Sdfr set_mouse_scaling(kbdc, 1); 75341016Sdfr set_mouse_mode(kbdc); 75441016Sdfr } 75541016Sdfr 756133918Sgibbs /* Record sync on the next data packet we see. */ 757133918Sgibbs sc->flags |= PSM_NEED_SYNCBITS; 75841016Sdfr 75941016Sdfr /* just check the status of the mouse */ 76041016Sdfr if (get_mouse_status(kbdc, stat, 0, 3) < 3) 76184880Syokota log(LOG_DEBUG, "psm%d: failed to get status (doinitialize).\n", 76284880Syokota sc->unit); 76341016Sdfr 76441016Sdfr return TRUE; 76541016Sdfr} 76641016Sdfr 76741016Sdfrstatic int 76884880Syokotadoopen(struct psm_softc *sc, int command_byte) 76941016Sdfr{ 77041016Sdfr int stat[3]; 77141016Sdfr 77241016Sdfr /* enable the mouse device */ 77341016Sdfr if (!enable_aux_dev(sc->kbdc)) { 77441016Sdfr /* MOUSE ERROR: failed to enable the mouse because: 77541016Sdfr * 1) the mouse is faulty, 77641016Sdfr * 2) the mouse has been removed(!?) 77741016Sdfr * In the latter case, the keyboard may have hung, and need 77841016Sdfr * recovery procedure... 77941016Sdfr */ 78041016Sdfr recover_from_error(sc->kbdc); 78141016Sdfr#if 0 78241016Sdfr /* FIXME: we could reset the mouse here and try to enable 78341016Sdfr * it again. But it will take long time and it's not a good 78441016Sdfr * idea to disable the keyboard that long... 78541016Sdfr */ 78684880Syokota if (!doinitialize(sc, &sc->mode) || !enable_aux_dev(sc->kbdc)) { 78741016Sdfr recover_from_error(sc->kbdc); 78841016Sdfr#else 78941016Sdfr { 79041016Sdfr#endif 79141016Sdfr restore_controller(sc->kbdc, command_byte); 79241016Sdfr /* mark this device is no longer available */ 79341016Sdfr sc->state &= ~PSM_VALID; 79441016Sdfr log(LOG_ERR, "psm%d: failed to enable the device (doopen).\n", 79584880Syokota sc->unit); 79641016Sdfr return (EIO); 79741016Sdfr } 79841016Sdfr } 79941016Sdfr 80041016Sdfr if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 80184880Syokota log(LOG_DEBUG, "psm%d: failed to get status (doopen).\n", sc->unit); 80241016Sdfr 80341016Sdfr /* enable the aux port and interrupt */ 80441016Sdfr if (!set_controller_command_byte(sc->kbdc, 80541016Sdfr kbdc_get_device_mask(sc->kbdc), 80641016Sdfr (command_byte & KBD_KBD_CONTROL_BITS) 80741016Sdfr | KBD_ENABLE_AUX_PORT | KBD_ENABLE_AUX_INT)) { 80841016Sdfr /* CONTROLLER ERROR */ 80941016Sdfr disable_aux_dev(sc->kbdc); 81041016Sdfr restore_controller(sc->kbdc, command_byte); 81141016Sdfr log(LOG_ERR, "psm%d: failed to enable the aux interrupt (doopen).\n", 81284880Syokota sc->unit); 81341016Sdfr return (EIO); 81441016Sdfr } 81541016Sdfr 81658230Syokota /* start the watchdog timer */ 81758230Syokota sc->watchdog = FALSE; 81884880Syokota sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz*2); 81958230Syokota 82041016Sdfr return (0); 82141016Sdfr} 82241016Sdfr 82384880Syokotastatic int 82484880Syokotareinitialize(struct psm_softc *sc, int doinit) 82584880Syokota{ 82684880Syokota int err; 82784880Syokota int c; 82884880Syokota int s; 82984880Syokota 83084880Syokota /* don't let anybody mess with the aux device */ 83184880Syokota if (!kbdc_lock(sc->kbdc, TRUE)) 83284880Syokota return (EIO); 83384880Syokota s = spltty(); 83484880Syokota 83584880Syokota /* block our watchdog timer */ 83684880Syokota sc->watchdog = FALSE; 83784880Syokota untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout); 83884880Syokota callout_handle_init(&sc->callout); 83984880Syokota 84084880Syokota /* save the current controller command byte */ 84184880Syokota empty_both_buffers(sc->kbdc, 10); 84284880Syokota c = get_controller_command_byte(sc->kbdc); 843134405Sgibbs VLOG(2, (LOG_DEBUG, "psm%d: current command byte: %04x (reinitialize).\n", 844134405Sgibbs sc->unit, c)); 84584880Syokota 84684880Syokota /* enable the aux port but disable the aux interrupt and the keyboard */ 84784880Syokota if ((c == -1) || !set_controller_command_byte(sc->kbdc, 84884880Syokota kbdc_get_device_mask(sc->kbdc), 84984880Syokota KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 85084880Syokota | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 85184880Syokota /* CONTROLLER ERROR */ 85284880Syokota splx(s); 85384880Syokota kbdc_lock(sc->kbdc, FALSE); 85484880Syokota log(LOG_ERR, "psm%d: unable to set the command byte (reinitialize).\n", 85584880Syokota sc->unit); 85684880Syokota return (EIO); 85784880Syokota } 85884880Syokota 85984880Syokota /* flush any data */ 86084880Syokota if (sc->state & PSM_VALID) { 86184880Syokota disable_aux_dev(sc->kbdc); /* this may fail; but never mind... */ 86284880Syokota empty_aux_buffer(sc->kbdc, 10); 86384880Syokota } 864123442Salfred flushpackets(sc); 86584880Syokota sc->syncerrors = 0; 866134405Sgibbs sc->pkterrors = 0; 867134405Sgibbs memset(&sc->lastinputerr, 0, sizeof(sc->lastinputerr)); 86884880Syokota 86984880Syokota /* try to detect the aux device; are you still there? */ 87084880Syokota err = 0; 87184880Syokota if (doinit) { 87284880Syokota if (doinitialize(sc, &sc->mode)) { 87384880Syokota /* yes */ 87484880Syokota sc->state |= PSM_VALID; 87584880Syokota } else { 87684880Syokota /* the device has gone! */ 87784880Syokota restore_controller(sc->kbdc, c); 87884880Syokota sc->state &= ~PSM_VALID; 87984880Syokota log(LOG_ERR, "psm%d: the aux device has gone! (reinitialize).\n", 88084880Syokota sc->unit); 88184880Syokota err = ENXIO; 88284880Syokota } 88384880Syokota } 88484880Syokota splx(s); 88584880Syokota 88684880Syokota /* restore the driver state */ 88784880Syokota if ((sc->state & PSM_OPEN) && (err == 0)) { 88884880Syokota /* enable the aux device and the port again */ 88984880Syokota err = doopen(sc, c); 89084880Syokota if (err != 0) 89184880Syokota log(LOG_ERR, "psm%d: failed to enable the device (reinitialize).\n", 89284880Syokota sc->unit); 89384880Syokota } else { 89484880Syokota /* restore the keyboard port and disable the aux port */ 89584880Syokota if (!set_controller_command_byte(sc->kbdc, 89684880Syokota kbdc_get_device_mask(sc->kbdc), 89784880Syokota (c & KBD_KBD_CONTROL_BITS) 89884880Syokota | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 89984880Syokota /* CONTROLLER ERROR */ 900133918Sgibbs log(LOG_ERR, 901133918Sgibbs "psm%d: failed to disable the aux port (reinitialize).\n", 90284880Syokota sc->unit); 90384880Syokota err = EIO; 90484880Syokota } 90584880Syokota } 90684880Syokota 90784880Syokota kbdc_lock(sc->kbdc, FALSE); 90884880Syokota return (err); 90984880Syokota} 91084880Syokota 91141016Sdfr/* psm driver entry points */ 91241016Sdfr 91383147Syokotastatic void 91483147Syokotapsmidentify(driver_t *driver, device_t parent) 91583147Syokota{ 91683931Syokota device_t psmc; 91783931Syokota device_t psm; 91883931Syokota u_long irq; 91983931Syokota int unit; 92083147Syokota 92183931Syokota unit = device_get_unit(parent); 92283931Syokota 92383147Syokota /* always add at least one child */ 92483931Syokota psm = BUS_ADD_CHILD(parent, KBDC_RID_AUX, driver->name, unit); 92583931Syokota if (psm == NULL) 92683931Syokota return; 92783931Syokota 92883931Syokota irq = bus_get_resource_start(psm, SYS_RES_IRQ, KBDC_RID_AUX); 92983931Syokota if (irq > 0) 93083931Syokota return; 93183931Syokota 93283931Syokota /* 93383931Syokota * If the PS/2 mouse device has already been reported by ACPI or 93483931Syokota * PnP BIOS, obtain the IRQ resource from it. 93583931Syokota * (See psmcpnp_attach() below.) 93683931Syokota */ 93783931Syokota psmc = device_find_child(device_get_parent(parent), 93883931Syokota PSMCPNP_DRIVER_NAME, unit); 93983931Syokota if (psmc == NULL) 94083931Syokota return; 94183931Syokota irq = bus_get_resource_start(psmc, SYS_RES_IRQ, 0); 94283931Syokota if (irq <= 0) 94383931Syokota return; 94483931Syokota bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); 94583147Syokota} 94683147Syokota 947115569Sphk#define endprobe(v) do { if (bootverbose) \ 94841016Sdfr --verbose; \ 94941016Sdfr kbdc_set_device_mask(sc->kbdc, mask); \ 95041016Sdfr kbdc_lock(sc->kbdc, FALSE); \ 95141016Sdfr return (v); \ 952115569Sphk } while (0) 95341016Sdfr 95441016Sdfrstatic int 95541016Sdfrpsmprobe(device_t dev) 95641016Sdfr{ 95741016Sdfr int unit = device_get_unit(dev); 95841016Sdfr struct psm_softc *sc = device_get_softc(dev); 95941016Sdfr int stat[3]; 96041016Sdfr int command_byte; 96141016Sdfr int mask; 96258230Syokota int rid; 96341016Sdfr int i; 96441016Sdfr 96541016Sdfr#if 0 96641016Sdfr kbdc_debug(TRUE); 96741016Sdfr#endif 96858230Syokota 96983147Syokota /* see if IRQ is available */ 97083147Syokota rid = KBDC_RID_AUX; 971127135Snjl sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 972127135Snjl RF_SHAREABLE | RF_ACTIVE); 97383147Syokota if (sc->intr == NULL) { 97483147Syokota if (bootverbose) 97583147Syokota device_printf(dev, "unable to allocate IRQ\n"); 97683147Syokota return (ENXIO); 97783147Syokota } 97883147Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 97958230Syokota 98084880Syokota sc->unit = unit; 98158230Syokota sc->kbdc = atkbdc_open(device_get_unit(device_get_parent(dev))); 98283147Syokota sc->config = device_get_flags(dev) & PSM_CONFIG_FLAGS; 98358230Syokota /* XXX: for backward compatibility */ 98458230Syokota#if defined(PSM_HOOKRESUME) || defined(PSM_HOOKAPM) 98558230Syokota sc->config |= 98658230Syokota#ifdef PSM_RESETAFTERSUSPEND 98758230Syokota PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND; 98858230Syokota#else 98958230Syokota PSM_CONFIG_HOOKRESUME; 99058230Syokota#endif 99158230Syokota#endif /* PSM_HOOKRESUME | PSM_HOOKAPM */ 99241016Sdfr sc->flags = 0; 99341016Sdfr if (bootverbose) 99441016Sdfr ++verbose; 99541016Sdfr 99643105Sdfr device_set_desc(dev, "PS/2 Mouse"); 99743105Sdfr 99841016Sdfr if (!kbdc_lock(sc->kbdc, TRUE)) { 99941016Sdfr printf("psm%d: unable to lock the controller.\n", unit); 100041016Sdfr if (bootverbose) 100141016Sdfr --verbose; 100241016Sdfr return (ENXIO); 100341016Sdfr } 100441016Sdfr 100541016Sdfr /* 100641016Sdfr * NOTE: two bits in the command byte controls the operation of the 100741016Sdfr * aux port (mouse port): the aux port disable bit (bit 5) and the aux 100841016Sdfr * port interrupt (IRQ 12) enable bit (bit 2). 100941016Sdfr */ 101041016Sdfr 101141016Sdfr /* discard anything left after the keyboard initialization */ 101241016Sdfr empty_both_buffers(sc->kbdc, 10); 101341016Sdfr 101441016Sdfr /* save the current command byte; it will be used later */ 101541016Sdfr mask = kbdc_get_device_mask(sc->kbdc) & ~KBD_AUX_CONTROL_BITS; 101641016Sdfr command_byte = get_controller_command_byte(sc->kbdc); 101741016Sdfr if (verbose) 101841016Sdfr printf("psm%d: current command byte:%04x\n", unit, command_byte); 101941016Sdfr if (command_byte == -1) { 102041016Sdfr /* CONTROLLER ERROR */ 102141016Sdfr printf("psm%d: unable to get the current command byte value.\n", 102241016Sdfr unit); 102341016Sdfr endprobe(ENXIO); 102441016Sdfr } 102541016Sdfr 102641016Sdfr /* 102741016Sdfr * disable the keyboard port while probing the aux port, which must be 102841016Sdfr * enabled during this routine 102941016Sdfr */ 103041016Sdfr if (!set_controller_command_byte(sc->kbdc, 103141016Sdfr KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, 103241016Sdfr KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 103341016Sdfr | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 103441016Sdfr /* 103541016Sdfr * this is CONTROLLER ERROR; I don't know how to recover 103641016Sdfr * from this error... 103741016Sdfr */ 103841016Sdfr restore_controller(sc->kbdc, command_byte); 103941016Sdfr printf("psm%d: unable to set the command byte.\n", unit); 104041016Sdfr endprobe(ENXIO); 104141016Sdfr } 104245789Speter write_controller_command(sc->kbdc, KBDC_ENABLE_AUX_PORT); 104341016Sdfr 104441016Sdfr /* 104541016Sdfr * NOTE: `test_aux_port()' is designed to return with zero if the aux 104641016Sdfr * port exists and is functioning. However, some controllers appears 104741016Sdfr * to respond with zero even when the aux port doesn't exist. (It may 104841016Sdfr * be that this is only the case when the controller DOES have the aux 104941016Sdfr * port but the port is not wired on the motherboard.) The keyboard 105041016Sdfr * controllers without the port, such as the original AT, are 105141016Sdfr * supporsed to return with an error code or simply time out. In any 105241016Sdfr * case, we have to continue probing the port even when the controller 105341016Sdfr * passes this test. 105441016Sdfr * 1055132270Smux * XXX: some controllers erroneously return the error code 1, 2 or 3 1056132270Smux * when it has the perfectly functional aux port. We have to ignore 1057132270Smux * this error code. Even if the controller HAS error with the aux 1058132270Smux * port, it will be detected later... 105941016Sdfr * XXX: another incompatible controller returns PSM_ACK (0xfa)... 106041016Sdfr */ 106141016Sdfr switch ((i = test_aux_port(sc->kbdc))) { 1062132270Smux case 1: /* ignore these errors */ 1063132270Smux case 2: 1064132270Smux case 3: 106541016Sdfr case PSM_ACK: 106641016Sdfr if (verbose) 106741016Sdfr printf("psm%d: strange result for test aux port (%d).\n", 106841016Sdfr unit, i); 1069102412Scharnier /* FALLTHROUGH */ 107041016Sdfr case 0: /* no error */ 107141016Sdfr break; 107241016Sdfr case -1: /* time out */ 107341016Sdfr default: /* error */ 107441016Sdfr recover_from_error(sc->kbdc); 107545789Speter if (sc->config & PSM_CONFIG_IGNPORTERROR) 107645789Speter break; 107741016Sdfr restore_controller(sc->kbdc, command_byte); 107841016Sdfr if (verbose) 107941016Sdfr printf("psm%d: the aux port is not functioning (%d).\n", 108041016Sdfr unit, i); 108141016Sdfr endprobe(ENXIO); 108241016Sdfr } 108341016Sdfr 108445789Speter if (sc->config & PSM_CONFIG_NORESET) { 108545789Speter /* 108645789Speter * Don't try to reset the pointing device. It may possibly be 108745789Speter * left in the unknown state, though... 108845789Speter */ 108945789Speter } else { 109045789Speter /* 109145789Speter * NOTE: some controllers appears to hang the `keyboard' when the aux 109245789Speter * port doesn't exist and `PSMC_RESET_DEV' is issued. 1093117302Smikeh * 1094117302Smikeh * Attempt to reset the controller twice -- this helps 1095117302Smikeh * pierce through some KVM switches. The second reset 1096117302Smikeh * is non-fatal. 109745789Speter */ 109845789Speter if (!reset_aux_dev(sc->kbdc)) { 109945789Speter recover_from_error(sc->kbdc); 110045789Speter restore_controller(sc->kbdc, command_byte); 110145789Speter if (verbose) 110245789Speter printf("psm%d: failed to reset the aux device.\n", unit); 110345789Speter endprobe(ENXIO); 1104117302Smikeh } else if (!reset_aux_dev(sc->kbdc)) { 1105117302Smikeh recover_from_error(sc->kbdc); 1106117302Smikeh if (verbose >= 2) 1107117302Smikeh printf("psm%d: failed to reset the aux device (2).\n", 1108117302Smikeh unit); 110945789Speter } 111041016Sdfr } 111145789Speter 111241016Sdfr /* 111341016Sdfr * both the aux port and the aux device is functioning, see if the 111441016Sdfr * device can be enabled. NOTE: when enabled, the device will start 111541016Sdfr * sending data; we shall immediately disable the device once we know 111641016Sdfr * the device can be enabled. 111741016Sdfr */ 111841016Sdfr if (!enable_aux_dev(sc->kbdc) || !disable_aux_dev(sc->kbdc)) { 111945789Speter /* MOUSE ERROR */ 112045789Speter recover_from_error(sc->kbdc); 112145789Speter restore_controller(sc->kbdc, command_byte); 112245789Speter if (verbose) 112345789Speter printf("psm%d: failed to enable the aux device.\n", unit); 112441016Sdfr endprobe(ENXIO); 112541016Sdfr } 112641016Sdfr 112741016Sdfr /* save the default values after reset */ 112841016Sdfr if (get_mouse_status(sc->kbdc, stat, 0, 3) >= 3) { 112941016Sdfr sc->dflt_mode.rate = sc->mode.rate = stat[2]; 113041016Sdfr sc->dflt_mode.resolution = sc->mode.resolution = stat[1]; 113141016Sdfr } else { 113241016Sdfr sc->dflt_mode.rate = sc->mode.rate = -1; 113341016Sdfr sc->dflt_mode.resolution = sc->mode.resolution = -1; 113441016Sdfr } 113541016Sdfr 113641016Sdfr /* hardware information */ 113741016Sdfr sc->hw.iftype = MOUSE_IF_PS2; 113841016Sdfr 113941016Sdfr /* verify the device is a mouse */ 114041016Sdfr sc->hw.hwid = get_aux_id(sc->kbdc); 114141016Sdfr if (!is_a_mouse(sc->hw.hwid)) { 114241016Sdfr restore_controller(sc->kbdc, command_byte); 114341016Sdfr if (verbose) 114441016Sdfr printf("psm%d: unknown device type (%d).\n", unit, sc->hw.hwid); 114541016Sdfr endprobe(ENXIO); 114641016Sdfr } 114741016Sdfr switch (sc->hw.hwid) { 114841016Sdfr case PSM_BALLPOINT_ID: 114941016Sdfr sc->hw.type = MOUSE_TRACKBALL; 115041016Sdfr break; 115141016Sdfr case PSM_MOUSE_ID: 115241016Sdfr case PSM_INTELLI_ID: 115358230Syokota case PSM_EXPLORER_ID: 115458230Syokota case PSM_4DMOUSE_ID: 115558230Syokota case PSM_4DPLUS_ID: 115641016Sdfr sc->hw.type = MOUSE_MOUSE; 115741016Sdfr break; 115841016Sdfr default: 115941016Sdfr sc->hw.type = MOUSE_UNKNOWN; 116041016Sdfr break; 116141016Sdfr } 116241016Sdfr 116345789Speter if (sc->config & PSM_CONFIG_NOIDPROBE) { 116445789Speter sc->hw.buttons = 2; 116545789Speter i = GENERIC_MOUSE_ENTRY; 116645789Speter } else { 116745789Speter /* # of buttons */ 116845789Speter sc->hw.buttons = get_mouse_buttons(sc->kbdc); 116941016Sdfr 117045789Speter /* other parameters */ 117145789Speter for (i = 0; vendortype[i].probefunc != NULL; ++i) { 117245789Speter if ((*vendortype[i].probefunc)(sc)) { 117345789Speter if (verbose >= 2) 117445789Speter printf("psm%d: found %s\n", 117545789Speter unit, model_name(vendortype[i].model)); 117645789Speter break; 117745789Speter } 117841016Sdfr } 117941016Sdfr } 118041016Sdfr 118141016Sdfr sc->hw.model = vendortype[i].model; 118241016Sdfr 118341016Sdfr sc->dflt_mode.level = PSM_LEVEL_BASE; 118441016Sdfr sc->dflt_mode.packetsize = MOUSE_PS2_PACKETSIZE; 118541016Sdfr sc->dflt_mode.accelfactor = (sc->config & PSM_CONFIG_ACCEL) >> 4; 118641016Sdfr if (sc->config & PSM_CONFIG_NOCHECKSYNC) 118741016Sdfr sc->dflt_mode.syncmask[0] = 0; 118841016Sdfr else 118941016Sdfr sc->dflt_mode.syncmask[0] = vendortype[i].syncmask; 119045789Speter if (sc->config & PSM_CONFIG_FORCETAP) 1191134405Sgibbs sc->dflt_mode.syncmask[0] &= ~MOUSE_PS2_TAP; 119241016Sdfr sc->dflt_mode.syncmask[1] = 0; /* syncbits */ 119341016Sdfr sc->mode = sc->dflt_mode; 119441016Sdfr sc->mode.packetsize = vendortype[i].packetsize; 119541016Sdfr 119641016Sdfr /* set mouse parameters */ 119748773Syokota#if 0 119848773Syokota /* 119948773Syokota * A version of Logitech FirstMouse+ won't report wheel movement, 120048773Syokota * if SET_DEFAULTS is sent... Don't use this command. 120148773Syokota * This fix was found by Takashi Nishida. 120248773Syokota */ 120341016Sdfr i = send_aux_command(sc->kbdc, PSMC_SET_DEFAULTS); 120441016Sdfr if (verbose >= 2) 120541016Sdfr printf("psm%d: SET_DEFAULTS return code:%04x\n", unit, i); 120648773Syokota#endif 120741016Sdfr if (sc->config & PSM_CONFIG_RESOLUTION) { 120841016Sdfr sc->mode.resolution 120941016Sdfr = set_mouse_resolution(sc->kbdc, 121048773Syokota (sc->config & PSM_CONFIG_RESOLUTION) - 1); 121148773Syokota } else if (sc->mode.resolution >= 0) { 121248773Syokota sc->mode.resolution 121348773Syokota = set_mouse_resolution(sc->kbdc, sc->dflt_mode.resolution); 121441016Sdfr } 121548773Syokota if (sc->mode.rate > 0) { 121648773Syokota sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, sc->dflt_mode.rate); 121748773Syokota } 121848773Syokota set_mouse_scaling(sc->kbdc, 1); 121941016Sdfr 1220133918Sgibbs /* Record sync on the next data packet we see. */ 1221133918Sgibbs sc->flags |= PSM_NEED_SYNCBITS; 122241016Sdfr 122341016Sdfr /* just check the status of the mouse */ 122441016Sdfr /* 122541016Sdfr * NOTE: XXX there are some arcane controller/mouse combinations out 122641016Sdfr * there, which hung the controller unless there is data transmission 122741016Sdfr * after ACK from the mouse. 122841016Sdfr */ 122941016Sdfr if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) { 123041016Sdfr printf("psm%d: failed to get status.\n", unit); 123141016Sdfr } else { 123241016Sdfr /* 123341016Sdfr * When in its native mode, some mice operate with different 123441016Sdfr * default parameters than in the PS/2 compatible mode. 123541016Sdfr */ 123641016Sdfr sc->dflt_mode.rate = sc->mode.rate = stat[2]; 123741016Sdfr sc->dflt_mode.resolution = sc->mode.resolution = stat[1]; 123841016Sdfr } 123941016Sdfr 124041016Sdfr /* disable the aux port for now... */ 124141016Sdfr if (!set_controller_command_byte(sc->kbdc, 124241016Sdfr KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS, 124341016Sdfr (command_byte & KBD_KBD_CONTROL_BITS) 124441016Sdfr | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 124541016Sdfr /* 124641016Sdfr * this is CONTROLLER ERROR; I don't know the proper way to 124741016Sdfr * recover from this error... 124841016Sdfr */ 124941016Sdfr restore_controller(sc->kbdc, command_byte); 125041016Sdfr printf("psm%d: unable to set the command byte.\n", unit); 125141016Sdfr endprobe(ENXIO); 125241016Sdfr } 125341016Sdfr 1254166492Sdumbbell /* 1255166492Sdumbbell * Synaptics TouchPad seems to go back to Relative Mode after 1256166492Sdumbbell * the previous set_controller_command_byte() call; by issueing 1257166492Sdumbbell * a Read Mode Byte command, the touchpad is in Absolute Mode 1258166492Sdumbbell * again. 1259166492Sdumbbell */ 1260166492Sdumbbell if (sc->hw.model == MOUSE_MODEL_SYNAPTICS) { 1261166492Sdumbbell mouse_ext_command(sc->kbdc, 1); 1262166492Sdumbbell } 1263166492Sdumbbell 126441016Sdfr /* done */ 126541016Sdfr kbdc_set_device_mask(sc->kbdc, mask | KBD_AUX_CONTROL_BITS); 126641016Sdfr kbdc_lock(sc->kbdc, FALSE); 126741016Sdfr return (0); 126841016Sdfr} 126941016Sdfr 127041016Sdfrstatic int 127141016Sdfrpsmattach(device_t dev) 127241016Sdfr{ 127341016Sdfr int unit = device_get_unit(dev); 127441016Sdfr struct psm_softc *sc = device_get_softc(dev); 127558230Syokota int error; 127658230Syokota int rid; 127741016Sdfr 127841016Sdfr /* Setup initial state */ 127941016Sdfr sc->state = PSM_VALID; 128058230Syokota callout_handle_init(&sc->callout); 128141016Sdfr 128258230Syokota /* Setup our interrupt handler */ 128383147Syokota rid = KBDC_RID_AUX; 1284127135Snjl sc->intr = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 1285127135Snjl RF_SHAREABLE | RF_ACTIVE); 128658230Syokota if (sc->intr == NULL) 128758230Syokota return (ENXIO); 1288166901Spiso error = bus_setup_intr(dev, sc->intr, INTR_TYPE_TTY, NULL, psmintr, sc, &sc->ih); 128958230Syokota if (error) { 129058230Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 129158230Syokota return (error); 129258230Syokota } 129358230Syokota 129441016Sdfr /* Done */ 129558230Syokota sc->dev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, FALSE), 0, 0, 0666, 129658230Syokota "psm%d", unit); 129758230Syokota sc->bdev = make_dev(&psm_cdevsw, PSM_MKMINOR(unit, TRUE), 0, 0, 0666, 129858230Syokota "bpsm%d", unit); 129941016Sdfr 130041016Sdfr if (!verbose) { 130141016Sdfr printf("psm%d: model %s, device ID %d\n", 130248778Syokota unit, model_name(sc->hw.model), sc->hw.hwid & 0x00ff); 130341016Sdfr } else { 130448778Syokota printf("psm%d: model %s, device ID %d-%02x, %d buttons\n", 130548778Syokota unit, model_name(sc->hw.model), 130648778Syokota sc->hw.hwid & 0x00ff, sc->hw.hwid >> 8, sc->hw.buttons); 130741016Sdfr printf("psm%d: config:%08x, flags:%08x, packet size:%d\n", 130841016Sdfr unit, sc->config, sc->flags, sc->mode.packetsize); 130941016Sdfr printf("psm%d: syncmask:%02x, syncbits:%02x\n", 131041016Sdfr unit, sc->mode.syncmask[0], sc->mode.syncmask[1]); 131141016Sdfr } 131241016Sdfr 131341016Sdfr if (bootverbose) 131441016Sdfr --verbose; 131541016Sdfr 131641016Sdfr return (0); 131741016Sdfr} 131841016Sdfr 131941016Sdfrstatic int 132058230Syokotapsmdetach(device_t dev) 132158230Syokota{ 132258230Syokota struct psm_softc *sc; 132358230Syokota int rid; 132458230Syokota 132558230Syokota sc = device_get_softc(dev); 132658230Syokota if (sc->state & PSM_OPEN) 132758230Syokota return EBUSY; 132858230Syokota 132983147Syokota rid = KBDC_RID_AUX; 133083147Syokota bus_teardown_intr(dev, sc->intr, sc->ih); 133158230Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, sc->intr); 133258230Syokota 133358230Syokota destroy_dev(sc->dev); 133458230Syokota destroy_dev(sc->bdev); 133558230Syokota 133658230Syokota return 0; 133758230Syokota} 133858230Syokota 133958230Syokotastatic int 1340130585Sphkpsmopen(struct cdev *dev, int flag, int fmt, struct thread *td) 134141016Sdfr{ 134241016Sdfr int unit = PSM_UNIT(dev); 134341016Sdfr struct psm_softc *sc; 134441016Sdfr int command_byte; 134541016Sdfr int err; 134641016Sdfr int s; 134741016Sdfr 134841016Sdfr /* Get device data */ 134941016Sdfr sc = PSM_SOFTC(unit); 135041016Sdfr if ((sc == NULL) || (sc->state & PSM_VALID) == 0) 135141016Sdfr /* the device is no longer valid/functioning */ 135241016Sdfr return (ENXIO); 135341016Sdfr 135441016Sdfr /* Disallow multiple opens */ 135541016Sdfr if (sc->state & PSM_OPEN) 135641016Sdfr return (EBUSY); 135741016Sdfr 135841016Sdfr device_busy(devclass_get_device(psm_devclass, unit)); 135941016Sdfr 136041016Sdfr /* Initialize state */ 136141016Sdfr sc->mode.level = sc->dflt_mode.level; 136241016Sdfr sc->mode.protocol = sc->dflt_mode.protocol; 136358230Syokota sc->watchdog = FALSE; 136441016Sdfr 136541016Sdfr /* flush the event queue */ 136641016Sdfr sc->queue.count = 0; 136741016Sdfr sc->queue.head = 0; 136841016Sdfr sc->queue.tail = 0; 136941016Sdfr sc->status.flags = 0; 137041016Sdfr sc->status.button = 0; 137141016Sdfr sc->status.obutton = 0; 137241016Sdfr sc->status.dx = 0; 137341016Sdfr sc->status.dy = 0; 137441016Sdfr sc->status.dz = 0; 137541016Sdfr sc->button = 0; 1376123442Salfred sc->pqueue_start = 0; 1377123442Salfred sc->pqueue_end = 0; 137841016Sdfr 137941016Sdfr /* empty input buffer */ 1380123442Salfred flushpackets(sc); 138184880Syokota sc->syncerrors = 0; 1382134405Sgibbs sc->pkterrors = 0; 138341016Sdfr 138441016Sdfr /* don't let timeout routines in the keyboard driver to poll the kbdc */ 138541016Sdfr if (!kbdc_lock(sc->kbdc, TRUE)) 138641016Sdfr return (EIO); 138741016Sdfr 138841016Sdfr /* save the current controller command byte */ 138941016Sdfr s = spltty(); 139041016Sdfr command_byte = get_controller_command_byte(sc->kbdc); 139141016Sdfr 139241016Sdfr /* enable the aux port and temporalily disable the keyboard */ 139341016Sdfr if ((command_byte == -1) 139441016Sdfr || !set_controller_command_byte(sc->kbdc, 139541016Sdfr kbdc_get_device_mask(sc->kbdc), 139641016Sdfr KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 139741016Sdfr | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 139841016Sdfr /* CONTROLLER ERROR; do you know how to get out of this? */ 139941016Sdfr kbdc_lock(sc->kbdc, FALSE); 140041016Sdfr splx(s); 140141016Sdfr log(LOG_ERR, "psm%d: unable to set the command byte (psmopen).\n", 140241016Sdfr unit); 140341016Sdfr return (EIO); 140441016Sdfr } 140541016Sdfr /* 140641016Sdfr * Now that the keyboard controller is told not to generate 140741016Sdfr * the keyboard and mouse interrupts, call `splx()' to allow 140841016Sdfr * the other tty interrupts. The clock interrupt may also occur, 140941016Sdfr * but timeout routines will be blocked by the poll flag set 141041016Sdfr * via `kbdc_lock()' 141141016Sdfr */ 141241016Sdfr splx(s); 141341016Sdfr 141441016Sdfr /* enable the mouse device */ 141584880Syokota err = doopen(sc, command_byte); 141641016Sdfr 141741016Sdfr /* done */ 141841016Sdfr if (err == 0) 141941016Sdfr sc->state |= PSM_OPEN; 142041016Sdfr kbdc_lock(sc->kbdc, FALSE); 142141016Sdfr return (err); 142241016Sdfr} 142341016Sdfr 142441016Sdfrstatic int 1425130585Sphkpsmclose(struct cdev *dev, int flag, int fmt, struct thread *td) 142641016Sdfr{ 142741016Sdfr int unit = PSM_UNIT(dev); 142841016Sdfr struct psm_softc *sc = PSM_SOFTC(unit); 142941016Sdfr int stat[3]; 143041016Sdfr int command_byte; 143141016Sdfr int s; 143241016Sdfr 143341016Sdfr /* don't let timeout routines in the keyboard driver to poll the kbdc */ 143441016Sdfr if (!kbdc_lock(sc->kbdc, TRUE)) 143541016Sdfr return (EIO); 143641016Sdfr 143741016Sdfr /* save the current controller command byte */ 143841016Sdfr s = spltty(); 143941016Sdfr command_byte = get_controller_command_byte(sc->kbdc); 144041016Sdfr if (command_byte == -1) { 144141016Sdfr kbdc_lock(sc->kbdc, FALSE); 144241016Sdfr splx(s); 144341016Sdfr return (EIO); 144441016Sdfr } 144541016Sdfr 144641016Sdfr /* disable the aux interrupt and temporalily disable the keyboard */ 144741016Sdfr if (!set_controller_command_byte(sc->kbdc, 144841016Sdfr kbdc_get_device_mask(sc->kbdc), 144941016Sdfr KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 145041016Sdfr | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 145141016Sdfr log(LOG_ERR, "psm%d: failed to disable the aux int (psmclose).\n", 145258230Syokota unit); 145341016Sdfr /* CONTROLLER ERROR; 145441016Sdfr * NOTE: we shall force our way through. Because the only 145541016Sdfr * ill effect we shall see is that we may not be able 145641016Sdfr * to read ACK from the mouse, and it doesn't matter much 145741016Sdfr * so long as the mouse will accept the DISABLE command. 145841016Sdfr */ 145941016Sdfr } 146041016Sdfr splx(s); 146141016Sdfr 146258230Syokota /* stop the watchdog timer */ 146384880Syokota untimeout(psmtimeout, (void *)(uintptr_t)sc, sc->callout); 146458230Syokota callout_handle_init(&sc->callout); 146558230Syokota 146641016Sdfr /* remove anything left in the output buffer */ 146741016Sdfr empty_aux_buffer(sc->kbdc, 10); 146841016Sdfr 146941016Sdfr /* disable the aux device, port and interrupt */ 147041016Sdfr if (sc->state & PSM_VALID) { 147141016Sdfr if (!disable_aux_dev(sc->kbdc)) { 147241016Sdfr /* MOUSE ERROR; 147341016Sdfr * NOTE: we don't return error and continue, pretending 147441016Sdfr * we have successfully disabled the device. It's OK because 147541016Sdfr * the interrupt routine will discard any data from the mouse 147641016Sdfr * hereafter. 147741016Sdfr */ 147841016Sdfr log(LOG_ERR, "psm%d: failed to disable the device (psmclose).\n", 147958230Syokota unit); 148041016Sdfr } 148141016Sdfr 148241016Sdfr if (get_mouse_status(sc->kbdc, stat, 0, 3) < 3) 1483134405Sgibbs log(LOG_DEBUG, "psm%d: failed to get status (psmclose).\n", unit); 148441016Sdfr } 148541016Sdfr 148641016Sdfr if (!set_controller_command_byte(sc->kbdc, 148741016Sdfr kbdc_get_device_mask(sc->kbdc), 148841016Sdfr (command_byte & KBD_KBD_CONTROL_BITS) 148941016Sdfr | KBD_DISABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 149041016Sdfr /* CONTROLLER ERROR; 149141016Sdfr * we shall ignore this error; see the above comment. 149241016Sdfr */ 149341016Sdfr log(LOG_ERR, "psm%d: failed to disable the aux port (psmclose).\n", 149458230Syokota unit); 149541016Sdfr } 149641016Sdfr 149741016Sdfr /* remove anything left in the output buffer */ 149841016Sdfr empty_aux_buffer(sc->kbdc, 10); 149941016Sdfr 150041016Sdfr /* close is almost always successful */ 150141016Sdfr sc->state &= ~PSM_OPEN; 150241016Sdfr kbdc_lock(sc->kbdc, FALSE); 150341016Sdfr device_unbusy(devclass_get_device(psm_devclass, unit)); 150441016Sdfr return (0); 150541016Sdfr} 150641016Sdfr 150741016Sdfrstatic int 1508123442Salfredtame_mouse(struct psm_softc *sc, packetbuf_t *pb, mousestatus_t *status, unsigned char *buf) 150941016Sdfr{ 151041016Sdfr static unsigned char butmapps2[8] = { 151141016Sdfr 0, 151241016Sdfr MOUSE_PS2_BUTTON1DOWN, 151341016Sdfr MOUSE_PS2_BUTTON2DOWN, 151441016Sdfr MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN, 151541016Sdfr MOUSE_PS2_BUTTON3DOWN, 151641016Sdfr MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON3DOWN, 151741016Sdfr MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN, 151841016Sdfr MOUSE_PS2_BUTTON1DOWN | MOUSE_PS2_BUTTON2DOWN | MOUSE_PS2_BUTTON3DOWN, 151941016Sdfr }; 152041016Sdfr static unsigned char butmapmsc[8] = { 152141016Sdfr MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 152241016Sdfr MOUSE_MSC_BUTTON2UP | MOUSE_MSC_BUTTON3UP, 152341016Sdfr MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON3UP, 152441016Sdfr MOUSE_MSC_BUTTON3UP, 152541016Sdfr MOUSE_MSC_BUTTON1UP | MOUSE_MSC_BUTTON2UP, 152641016Sdfr MOUSE_MSC_BUTTON2UP, 152741016Sdfr MOUSE_MSC_BUTTON1UP, 152841016Sdfr 0, 152941016Sdfr }; 153041016Sdfr int mapped; 153141016Sdfr int i; 153241016Sdfr 153341016Sdfr if (sc->mode.level == PSM_LEVEL_BASE) { 153441016Sdfr mapped = status->button & ~MOUSE_BUTTON4DOWN; 153541016Sdfr if (status->button & MOUSE_BUTTON4DOWN) 153641016Sdfr mapped |= MOUSE_BUTTON1DOWN; 153741016Sdfr status->button = mapped; 153841016Sdfr buf[0] = MOUSE_PS2_SYNC | butmapps2[mapped & MOUSE_STDBUTTONS]; 1539109269Smdodd i = imax(imin(status->dx, 255), -256); 154041016Sdfr if (i < 0) 154141016Sdfr buf[0] |= MOUSE_PS2_XNEG; 154241016Sdfr buf[1] = i; 1543109269Smdodd i = imax(imin(status->dy, 255), -256); 154441016Sdfr if (i < 0) 154541016Sdfr buf[0] |= MOUSE_PS2_YNEG; 154641016Sdfr buf[2] = i; 154741016Sdfr return MOUSE_PS2_PACKETSIZE; 154841016Sdfr } else if (sc->mode.level == PSM_LEVEL_STANDARD) { 154941016Sdfr buf[0] = MOUSE_MSC_SYNC | butmapmsc[status->button & MOUSE_STDBUTTONS]; 1550109269Smdodd i = imax(imin(status->dx, 255), -256); 155141016Sdfr buf[1] = i >> 1; 155241016Sdfr buf[3] = i - buf[1]; 1553109269Smdodd i = imax(imin(status->dy, 255), -256); 155441016Sdfr buf[2] = i >> 1; 155541016Sdfr buf[4] = i - buf[2]; 1556109269Smdodd i = imax(imin(status->dz, 127), -128); 155741016Sdfr buf[5] = (i >> 1) & 0x7f; 155841016Sdfr buf[6] = (i - (i >> 1)) & 0x7f; 155941016Sdfr buf[7] = (~status->button >> 3) & 0x7f; 156041016Sdfr return MOUSE_SYS_PACKETSIZE; 156141016Sdfr } 1562123442Salfred return pb->inputbytes; 156341016Sdfr} 156441016Sdfr 156541016Sdfrstatic int 1566130585Sphkpsmread(struct cdev *dev, struct uio *uio, int flag) 156741016Sdfr{ 156841016Sdfr register struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); 156941016Sdfr unsigned char buf[PSM_SMALLBUFSIZE]; 157041016Sdfr int error = 0; 157141016Sdfr int s; 157241016Sdfr int l; 157341016Sdfr 157441016Sdfr if ((sc->state & PSM_VALID) == 0) 157541016Sdfr return EIO; 157641016Sdfr 157741016Sdfr /* block until mouse activity occured */ 157841016Sdfr s = spltty(); 157941016Sdfr while (sc->queue.count <= 0) { 158041016Sdfr if (PSM_NBLOCKIO(dev)) { 158141016Sdfr splx(s); 158241016Sdfr return EWOULDBLOCK; 158341016Sdfr } 158441016Sdfr sc->state |= PSM_ASLP; 1585111748Sdes error = tsleep( sc, PZERO | PCATCH, "psmrea", 0); 158641016Sdfr sc->state &= ~PSM_ASLP; 158741016Sdfr if (error) { 158841016Sdfr splx(s); 158941016Sdfr return error; 159041016Sdfr } else if ((sc->state & PSM_VALID) == 0) { 159141016Sdfr /* the device disappeared! */ 159241016Sdfr splx(s); 159341016Sdfr return EIO; 159441016Sdfr } 159541016Sdfr } 159641016Sdfr splx(s); 159741016Sdfr 159841016Sdfr /* copy data to the user land */ 159941016Sdfr while ((sc->queue.count > 0) && (uio->uio_resid > 0)) { 160041016Sdfr s = spltty(); 1601109269Smdodd l = imin(sc->queue.count, uio->uio_resid); 160241016Sdfr if (l > sizeof(buf)) 160341016Sdfr l = sizeof(buf); 160441016Sdfr if (l > sizeof(sc->queue.buf) - sc->queue.head) { 160541016Sdfr bcopy(&sc->queue.buf[sc->queue.head], &buf[0], 160641016Sdfr sizeof(sc->queue.buf) - sc->queue.head); 160741016Sdfr bcopy(&sc->queue.buf[0], 160841016Sdfr &buf[sizeof(sc->queue.buf) - sc->queue.head], 160941016Sdfr l - (sizeof(sc->queue.buf) - sc->queue.head)); 161041016Sdfr } else { 161141016Sdfr bcopy(&sc->queue.buf[sc->queue.head], &buf[0], l); 161241016Sdfr } 161341016Sdfr sc->queue.count -= l; 161441016Sdfr sc->queue.head = (sc->queue.head + l) % sizeof(sc->queue.buf); 161541016Sdfr splx(s); 161641016Sdfr error = uiomove(buf, l, uio); 161741016Sdfr if (error) 161841016Sdfr break; 161941016Sdfr } 162041016Sdfr 162141016Sdfr return error; 162241016Sdfr} 162341016Sdfr 162441016Sdfrstatic int 162541016Sdfrblock_mouse_data(struct psm_softc *sc, int *c) 162641016Sdfr{ 162741016Sdfr int s; 162841016Sdfr 162941016Sdfr if (!kbdc_lock(sc->kbdc, TRUE)) 163041016Sdfr return EIO; 163141016Sdfr 163241016Sdfr s = spltty(); 163341016Sdfr *c = get_controller_command_byte(sc->kbdc); 163441016Sdfr if ((*c == -1) 163541016Sdfr || !set_controller_command_byte(sc->kbdc, 163641016Sdfr kbdc_get_device_mask(sc->kbdc), 163741016Sdfr KBD_DISABLE_KBD_PORT | KBD_DISABLE_KBD_INT 163841016Sdfr | KBD_ENABLE_AUX_PORT | KBD_DISABLE_AUX_INT)) { 163941016Sdfr /* this is CONTROLLER ERROR */ 164041016Sdfr splx(s); 164141016Sdfr kbdc_lock(sc->kbdc, FALSE); 164241016Sdfr return EIO; 164341016Sdfr } 164441016Sdfr 164541016Sdfr /* 164641016Sdfr * The device may be in the middle of status data transmission. 164741016Sdfr * The transmission will be interrupted, thus, incomplete status 164841016Sdfr * data must be discarded. Although the aux interrupt is disabled 164941016Sdfr * at the keyboard controller level, at most one aux interrupt 165041016Sdfr * may have already been pending and a data byte is in the 165141016Sdfr * output buffer; throw it away. Note that the second argument 165241016Sdfr * to `empty_aux_buffer()' is zero, so that the call will just 165341016Sdfr * flush the internal queue. 165441016Sdfr * `psmintr()' will be invoked after `splx()' if an interrupt is 165541016Sdfr * pending; it will see no data and returns immediately. 165641016Sdfr */ 165741016Sdfr empty_aux_buffer(sc->kbdc, 0); /* flush the queue */ 165841016Sdfr read_aux_data_no_wait(sc->kbdc); /* throw away data if any */ 1659123442Salfred flushpackets(sc); 166041016Sdfr splx(s); 166141016Sdfr 166241016Sdfr return 0; 166341016Sdfr} 166441016Sdfr 1665123442Salfredstatic void 1666123442Salfreddropqueue(struct psm_softc *sc) 1667123442Salfred{ 1668123442Salfred 1669123442Salfred sc->queue.count = 0; 1670123442Salfred sc->queue.head = 0; 1671123442Salfred sc->queue.tail = 0; 1672123442Salfred if ((sc->state & PSM_SOFTARMED) != 0) { 1673123442Salfred sc->state &= ~PSM_SOFTARMED; 1674123442Salfred untimeout(psmsoftintr, (void *)(uintptr_t)sc, sc->softcallout); 1675123442Salfred } 1676123442Salfred sc->pqueue_start = sc->pqueue_end; 1677123442Salfred} 1678123442Salfred 1679123442Salfredstatic void 1680123442Salfredflushpackets(struct psm_softc *sc) 1681123442Salfred{ 1682123442Salfred 1683123442Salfred dropqueue(sc); 1684123442Salfred bzero(&sc->pqueue, sizeof(sc->pqueue)); 1685123442Salfred} 1686123442Salfred 168741016Sdfrstatic int 168841016Sdfrunblock_mouse_data(struct psm_softc *sc, int c) 168941016Sdfr{ 169041016Sdfr int error = 0; 169141016Sdfr 169241016Sdfr /* 169341016Sdfr * We may have seen a part of status data during `set_mouse_XXX()'. 169441016Sdfr * they have been queued; flush it. 169541016Sdfr */ 169641016Sdfr empty_aux_buffer(sc->kbdc, 0); 169741016Sdfr 169841016Sdfr /* restore ports and interrupt */ 169941016Sdfr if (!set_controller_command_byte(sc->kbdc, 170041016Sdfr kbdc_get_device_mask(sc->kbdc), 170141016Sdfr c & (KBD_KBD_CONTROL_BITS | KBD_AUX_CONTROL_BITS))) { 170241016Sdfr /* CONTROLLER ERROR; this is serious, we may have 170341016Sdfr * been left with the inaccessible keyboard and 170441016Sdfr * the disabled mouse interrupt. 170541016Sdfr */ 170641016Sdfr error = EIO; 170741016Sdfr } 170841016Sdfr 170941016Sdfr kbdc_lock(sc->kbdc, FALSE); 171041016Sdfr return error; 171141016Sdfr} 171241016Sdfr 171341016Sdfrstatic int 1714130585Sphkpsmioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) 171541016Sdfr{ 171641016Sdfr struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); 171741016Sdfr mousemode_t mode; 171841016Sdfr mousestatus_t status; 171941016Sdfr#if (defined(MOUSE_GETVARS)) 172041016Sdfr mousevar_t *var; 172141016Sdfr#endif 172241016Sdfr mousedata_t *data; 172341016Sdfr int stat[3]; 172441016Sdfr int command_byte; 172541016Sdfr int error = 0; 172641016Sdfr int s; 172741016Sdfr 172841016Sdfr /* Perform IOCTL command */ 172941016Sdfr switch (cmd) { 173041016Sdfr 173141016Sdfr case OLD_MOUSE_GETHWINFO: 173241016Sdfr s = spltty(); 173341016Sdfr ((old_mousehw_t *)addr)->buttons = sc->hw.buttons; 173441016Sdfr ((old_mousehw_t *)addr)->iftype = sc->hw.iftype; 173541016Sdfr ((old_mousehw_t *)addr)->type = sc->hw.type; 173648778Syokota ((old_mousehw_t *)addr)->hwid = sc->hw.hwid & 0x00ff; 173741016Sdfr splx(s); 173841016Sdfr break; 173941016Sdfr 174041016Sdfr case MOUSE_GETHWINFO: 174141016Sdfr s = spltty(); 174241016Sdfr *(mousehw_t *)addr = sc->hw; 174341016Sdfr if (sc->mode.level == PSM_LEVEL_BASE) 174441016Sdfr ((mousehw_t *)addr)->model = MOUSE_MODEL_GENERIC; 174541016Sdfr splx(s); 174641016Sdfr break; 174741016Sdfr 1748132865Snjl case MOUSE_SYN_GETHWINFO: 1749132865Snjl s = spltty(); 1750135945Sphilip if (synaptics_support && sc->hw.model == MOUSE_MODEL_SYNAPTICS) 1751132865Snjl *(synapticshw_t *)addr = sc->synhw; 1752132865Snjl else 1753132865Snjl error = EINVAL; 1754132865Snjl splx(s); 1755132865Snjl break; 1756132865Snjl 175741016Sdfr case OLD_MOUSE_GETMODE: 175841016Sdfr s = spltty(); 175941016Sdfr switch (sc->mode.level) { 176041016Sdfr case PSM_LEVEL_BASE: 176141016Sdfr ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 176241016Sdfr break; 176341016Sdfr case PSM_LEVEL_STANDARD: 176441016Sdfr ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 176541016Sdfr break; 176641016Sdfr case PSM_LEVEL_NATIVE: 176741016Sdfr ((old_mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 176841016Sdfr break; 176941016Sdfr } 177041016Sdfr ((old_mousemode_t *)addr)->rate = sc->mode.rate; 177141016Sdfr ((old_mousemode_t *)addr)->resolution = sc->mode.resolution; 177241016Sdfr ((old_mousemode_t *)addr)->accelfactor = sc->mode.accelfactor; 177341016Sdfr splx(s); 177441016Sdfr break; 177541016Sdfr 177641016Sdfr case MOUSE_GETMODE: 177741016Sdfr s = spltty(); 177841016Sdfr *(mousemode_t *)addr = sc->mode; 1779134405Sgibbs if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { 1780134405Sgibbs ((mousemode_t *)addr)->syncmask[0] = 0; 1781134405Sgibbs ((mousemode_t *)addr)->syncmask[1] = 0; 1782134405Sgibbs } 178341016Sdfr ((mousemode_t *)addr)->resolution = 178441016Sdfr MOUSE_RES_LOW - sc->mode.resolution; 178541016Sdfr switch (sc->mode.level) { 178641016Sdfr case PSM_LEVEL_BASE: 178741016Sdfr ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 178841016Sdfr ((mousemode_t *)addr)->packetsize = MOUSE_PS2_PACKETSIZE; 178941016Sdfr break; 179041016Sdfr case PSM_LEVEL_STANDARD: 179141016Sdfr ((mousemode_t *)addr)->protocol = MOUSE_PROTO_SYSMOUSE; 179241016Sdfr ((mousemode_t *)addr)->packetsize = MOUSE_SYS_PACKETSIZE; 179341016Sdfr ((mousemode_t *)addr)->syncmask[0] = MOUSE_SYS_SYNCMASK; 179441016Sdfr ((mousemode_t *)addr)->syncmask[1] = MOUSE_SYS_SYNC; 179541016Sdfr break; 179641016Sdfr case PSM_LEVEL_NATIVE: 179741016Sdfr /* FIXME: this isn't quite correct... XXX */ 179841016Sdfr ((mousemode_t *)addr)->protocol = MOUSE_PROTO_PS2; 179941016Sdfr break; 180041016Sdfr } 180141016Sdfr splx(s); 180241016Sdfr break; 180341016Sdfr 180441016Sdfr case OLD_MOUSE_SETMODE: 180541016Sdfr case MOUSE_SETMODE: 180641016Sdfr if (cmd == OLD_MOUSE_SETMODE) { 180741016Sdfr mode.rate = ((old_mousemode_t *)addr)->rate; 180841016Sdfr /* 180941016Sdfr * resolution old I/F new I/F 181041016Sdfr * default 0 0 181141016Sdfr * low 1 -2 181241016Sdfr * medium low 2 -3 181341016Sdfr * medium high 3 -4 181441016Sdfr * high 4 -5 181541016Sdfr */ 181641016Sdfr if (((old_mousemode_t *)addr)->resolution > 0) 181741016Sdfr mode.resolution = -((old_mousemode_t *)addr)->resolution - 1; 1818170868Smjacob else 1819170868Smjacob mode.resolution = 0; 182041016Sdfr mode.accelfactor = ((old_mousemode_t *)addr)->accelfactor; 182141016Sdfr mode.level = -1; 182241016Sdfr } else { 182341016Sdfr mode = *(mousemode_t *)addr; 182441016Sdfr } 182541016Sdfr 182641016Sdfr /* adjust and validate parameters. */ 182741016Sdfr if (mode.rate > UCHAR_MAX) 182841016Sdfr return EINVAL; 182941016Sdfr if (mode.rate == 0) 183041016Sdfr mode.rate = sc->dflt_mode.rate; 183141016Sdfr else if (mode.rate == -1) 183241016Sdfr /* don't change the current setting */ 183341016Sdfr ; 183441016Sdfr else if (mode.rate < 0) 183541016Sdfr return EINVAL; 183641016Sdfr if (mode.resolution >= UCHAR_MAX) 183741016Sdfr return EINVAL; 183841016Sdfr if (mode.resolution >= 200) 183941016Sdfr mode.resolution = MOUSE_RES_HIGH; 184041016Sdfr else if (mode.resolution >= 100) 184141016Sdfr mode.resolution = MOUSE_RES_MEDIUMHIGH; 184241016Sdfr else if (mode.resolution >= 50) 184341016Sdfr mode.resolution = MOUSE_RES_MEDIUMLOW; 184441016Sdfr else if (mode.resolution > 0) 184541016Sdfr mode.resolution = MOUSE_RES_LOW; 184641016Sdfr if (mode.resolution == MOUSE_RES_DEFAULT) 184741016Sdfr mode.resolution = sc->dflt_mode.resolution; 184841016Sdfr else if (mode.resolution == -1) 184941016Sdfr /* don't change the current setting */ 185041016Sdfr ; 185141016Sdfr else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */ 185241016Sdfr mode.resolution = MOUSE_RES_LOW - mode.resolution; 185341016Sdfr if (mode.level == -1) 185441016Sdfr /* don't change the current setting */ 185541016Sdfr mode.level = sc->mode.level; 185641016Sdfr else if ((mode.level < PSM_LEVEL_MIN) || (mode.level > PSM_LEVEL_MAX)) 185741016Sdfr return EINVAL; 185841016Sdfr if (mode.accelfactor == -1) 185941016Sdfr /* don't change the current setting */ 186041016Sdfr mode.accelfactor = sc->mode.accelfactor; 186141016Sdfr else if (mode.accelfactor < 0) 186241016Sdfr return EINVAL; 186341016Sdfr 186441016Sdfr /* don't allow anybody to poll the keyboard controller */ 186541016Sdfr error = block_mouse_data(sc, &command_byte); 186641016Sdfr if (error) 186741016Sdfr return error; 186841016Sdfr 186941016Sdfr /* set mouse parameters */ 187041016Sdfr if (mode.rate > 0) 187141016Sdfr mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate); 187241016Sdfr if (mode.resolution >= 0) 187341016Sdfr mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution); 187441016Sdfr set_mouse_scaling(sc->kbdc, 1); 187541016Sdfr get_mouse_status(sc->kbdc, stat, 0, 3); 187641016Sdfr 187741016Sdfr s = spltty(); 187841016Sdfr sc->mode.rate = mode.rate; 187941016Sdfr sc->mode.resolution = mode.resolution; 188041016Sdfr sc->mode.accelfactor = mode.accelfactor; 188141016Sdfr sc->mode.level = mode.level; 188241016Sdfr splx(s); 188341016Sdfr 188441016Sdfr unblock_mouse_data(sc, command_byte); 188541016Sdfr break; 188641016Sdfr 188741016Sdfr case MOUSE_GETLEVEL: 188841016Sdfr *(int *)addr = sc->mode.level; 188941016Sdfr break; 189041016Sdfr 189141016Sdfr case MOUSE_SETLEVEL: 189241016Sdfr if ((*(int *)addr < PSM_LEVEL_MIN) || (*(int *)addr > PSM_LEVEL_MAX)) 189341016Sdfr return EINVAL; 189441016Sdfr sc->mode.level = *(int *)addr; 189541016Sdfr break; 189641016Sdfr 189741016Sdfr case MOUSE_GETSTATUS: 189841016Sdfr s = spltty(); 189941016Sdfr status = sc->status; 190041016Sdfr sc->status.flags = 0; 190141016Sdfr sc->status.obutton = sc->status.button; 190241016Sdfr sc->status.button = 0; 190341016Sdfr sc->status.dx = 0; 190441016Sdfr sc->status.dy = 0; 190541016Sdfr sc->status.dz = 0; 190641016Sdfr splx(s); 190741016Sdfr *(mousestatus_t *)addr = status; 190841016Sdfr break; 190941016Sdfr 191041016Sdfr#if (defined(MOUSE_GETVARS)) 191141016Sdfr case MOUSE_GETVARS: 191241016Sdfr var = (mousevar_t *)addr; 191341016Sdfr bzero(var, sizeof(*var)); 191441016Sdfr s = spltty(); 191541016Sdfr var->var[0] = MOUSE_VARS_PS2_SIG; 191641016Sdfr var->var[1] = sc->config; 191741016Sdfr var->var[2] = sc->flags; 191841016Sdfr splx(s); 191941016Sdfr break; 192041016Sdfr 192141016Sdfr case MOUSE_SETVARS: 192241016Sdfr return ENODEV; 192341016Sdfr#endif /* MOUSE_GETVARS */ 192441016Sdfr 192541016Sdfr case MOUSE_READSTATE: 192641016Sdfr case MOUSE_READDATA: 192741016Sdfr data = (mousedata_t *)addr; 192841016Sdfr if (data->len > sizeof(data->buf)/sizeof(data->buf[0])) 192941016Sdfr return EINVAL; 193041016Sdfr 193141016Sdfr error = block_mouse_data(sc, &command_byte); 193241016Sdfr if (error) 193341016Sdfr return error; 193441016Sdfr if ((data->len = get_mouse_status(sc->kbdc, data->buf, 193541016Sdfr (cmd == MOUSE_READDATA) ? 1 : 0, data->len)) <= 0) 193641016Sdfr error = EIO; 193741016Sdfr unblock_mouse_data(sc, command_byte); 193841016Sdfr break; 193941016Sdfr 194041016Sdfr#if (defined(MOUSE_SETRESOLUTION)) 194141016Sdfr case MOUSE_SETRESOLUTION: 194241016Sdfr mode.resolution = *(int *)addr; 194341016Sdfr if (mode.resolution >= UCHAR_MAX) 194441016Sdfr return EINVAL; 194541016Sdfr else if (mode.resolution >= 200) 194641016Sdfr mode.resolution = MOUSE_RES_HIGH; 194741016Sdfr else if (mode.resolution >= 100) 194841016Sdfr mode.resolution = MOUSE_RES_MEDIUMHIGH; 194941016Sdfr else if (mode.resolution >= 50) 195041016Sdfr mode.resolution = MOUSE_RES_MEDIUMLOW; 195141016Sdfr else if (mode.resolution > 0) 195241016Sdfr mode.resolution = MOUSE_RES_LOW; 195341016Sdfr if (mode.resolution == MOUSE_RES_DEFAULT) 195441016Sdfr mode.resolution = sc->dflt_mode.resolution; 195541016Sdfr else if (mode.resolution == -1) 195641016Sdfr mode.resolution = sc->mode.resolution; 195741016Sdfr else if (mode.resolution < 0) /* MOUSE_RES_LOW/MEDIUM/HIGH */ 195841016Sdfr mode.resolution = MOUSE_RES_LOW - mode.resolution; 195941016Sdfr 196041016Sdfr error = block_mouse_data(sc, &command_byte); 196141016Sdfr if (error) 196241016Sdfr return error; 196341016Sdfr sc->mode.resolution = set_mouse_resolution(sc->kbdc, mode.resolution); 196441016Sdfr if (sc->mode.resolution != mode.resolution) 196541016Sdfr error = EIO; 196641016Sdfr unblock_mouse_data(sc, command_byte); 196741016Sdfr break; 196841016Sdfr#endif /* MOUSE_SETRESOLUTION */ 196941016Sdfr 197041016Sdfr#if (defined(MOUSE_SETRATE)) 197141016Sdfr case MOUSE_SETRATE: 197241016Sdfr mode.rate = *(int *)addr; 197341016Sdfr if (mode.rate > UCHAR_MAX) 197441016Sdfr return EINVAL; 197541016Sdfr if (mode.rate == 0) 197641016Sdfr mode.rate = sc->dflt_mode.rate; 197741016Sdfr else if (mode.rate < 0) 197841016Sdfr mode.rate = sc->mode.rate; 197941016Sdfr 198041016Sdfr error = block_mouse_data(sc, &command_byte); 198141016Sdfr if (error) 198241016Sdfr return error; 198341016Sdfr sc->mode.rate = set_mouse_sampling_rate(sc->kbdc, mode.rate); 198441016Sdfr if (sc->mode.rate != mode.rate) 198541016Sdfr error = EIO; 198641016Sdfr unblock_mouse_data(sc, command_byte); 198741016Sdfr break; 198841016Sdfr#endif /* MOUSE_SETRATE */ 198941016Sdfr 199041016Sdfr#if (defined(MOUSE_SETSCALING)) 199141016Sdfr case MOUSE_SETSCALING: 199241016Sdfr if ((*(int *)addr <= 0) || (*(int *)addr > 2)) 199341016Sdfr return EINVAL; 199441016Sdfr 199541016Sdfr error = block_mouse_data(sc, &command_byte); 199641016Sdfr if (error) 199741016Sdfr return error; 199841016Sdfr if (!set_mouse_scaling(sc->kbdc, *(int *)addr)) 199941016Sdfr error = EIO; 200041016Sdfr unblock_mouse_data(sc, command_byte); 200141016Sdfr break; 200241016Sdfr#endif /* MOUSE_SETSCALING */ 200341016Sdfr 200441016Sdfr#if (defined(MOUSE_GETHWID)) 200541016Sdfr case MOUSE_GETHWID: 200641016Sdfr error = block_mouse_data(sc, &command_byte); 200741016Sdfr if (error) 200841016Sdfr return error; 200948778Syokota sc->hw.hwid &= ~0x00ff; 201048778Syokota sc->hw.hwid |= get_aux_id(sc->kbdc); 201148778Syokota *(int *)addr = sc->hw.hwid & 0x00ff; 201241016Sdfr unblock_mouse_data(sc, command_byte); 201341016Sdfr break; 201441016Sdfr#endif /* MOUSE_GETHWID */ 201541016Sdfr 201641016Sdfr default: 201741016Sdfr return ENOTTY; 201841016Sdfr } 201941016Sdfr 202041016Sdfr return error; 202141016Sdfr} 202241016Sdfr 202341016Sdfrstatic void 202458230Syokotapsmtimeout(void *arg) 202558230Syokota{ 202658230Syokota struct psm_softc *sc; 202765045Syokota int s; 202858230Syokota 202984880Syokota sc = (struct psm_softc *)arg; 203065045Syokota s = spltty(); 203163746Syokota if (sc->watchdog && kbdc_lock(sc->kbdc, TRUE)) { 2032134405Sgibbs VLOG(4, (LOG_DEBUG, "psm%d: lost interrupt?\n", sc->unit)); 203358230Syokota psmintr(sc); 203463746Syokota kbdc_lock(sc->kbdc, FALSE); 203558230Syokota } 203658230Syokota sc->watchdog = TRUE; 203765045Syokota splx(s); 203884880Syokota sc->callout = timeout(psmtimeout, (void *)(uintptr_t)sc, hz); 203958230Syokota} 204058230Syokota 2041139628Sphilip/* Add all sysctls under the debug.psm and hw.psm nodes */ 2042139628SphilipSYSCTL_NODE(_debug, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); 2043139628SphilipSYSCTL_NODE(_hw, OID_AUTO, psm, CTLFLAG_RD, 0, "ps/2 mouse"); 2044123442Salfred 2045139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, loglevel, CTLFLAG_RW, &verbose, 0, ""); 2046123442Salfred 2047139628Sphilipstatic int psmhz = 20; 2048139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, hz, CTLFLAG_RW, &psmhz, 0, ""); 2049123442Salfredstatic int psmerrsecs = 2; 2050139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, errsecs, CTLFLAG_RW, &psmerrsecs, 0, ""); 2051123442Salfredstatic int psmerrusecs = 0; 2052139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, errusecs, CTLFLAG_RW, &psmerrusecs, 0, ""); 2053123442Salfredstatic int psmsecs = 0; 2054139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, secs, CTLFLAG_RW, &psmsecs, 0, ""); 2055123442Salfredstatic int psmusecs = 500000; 2056139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, usecs, CTLFLAG_RW, &psmusecs, 0, ""); 2057139628Sphilipstatic int pkterrthresh = 2; 2058139628SphilipSYSCTL_INT(_debug_psm, OID_AUTO, pkterrthresh, CTLFLAG_RW, &pkterrthresh, 0, ""); 2059123442Salfred 2060139628Sphilipstatic int tap_threshold = PSM_TAP_THRESHOLD; 2061139628SphilipSYSCTL_INT(_hw_psm, OID_AUTO, tap_threshold, CTLFLAG_RW, &tap_threshold, 0, ""); 2062139628Sphilipstatic int tap_timeout = PSM_TAP_TIMEOUT; 2063139628SphilipSYSCTL_INT(_hw_psm, OID_AUTO, tap_timeout, CTLFLAG_RW, &tap_timeout, 0, ""); 2064134405Sgibbs 206558230Syokotastatic void 206641016Sdfrpsmintr(void *arg) 206741016Sdfr{ 2068123442Salfred struct psm_softc *sc = arg; 2069123442Salfred struct timeval now; 207041016Sdfr int c; 2071123442Salfred packetbuf_t *pb; 207241016Sdfr 2073123442Salfred 207441016Sdfr /* read until there is nothing to read */ 207541016Sdfr while((c = read_aux_data_no_wait(sc->kbdc)) != -1) { 207641016Sdfr 2077123442Salfred pb = &sc->pqueue[sc->pqueue_end]; 207841016Sdfr /* discard the byte if the device is not open */ 207941016Sdfr if ((sc->state & PSM_OPEN) == 0) 208041016Sdfr continue; 208141016Sdfr 2082123442Salfred getmicrouptime(&now); 2083123442Salfred if ((pb->inputbytes > 0) && timevalcmp(&now, &sc->inputtimeout, >)) { 2084134405Sgibbs VLOG(3, (LOG_DEBUG, "psmintr: delay too long; " 2085134405Sgibbs "resetting byte count\n")); 2086123442Salfred pb->inputbytes = 0; 208784880Syokota sc->syncerrors = 0; 2088134405Sgibbs sc->pkterrors = 0; 208984880Syokota } 209084880Syokota sc->inputtimeout.tv_sec = PSM_INPUT_TIMEOUT/1000000; 209184880Syokota sc->inputtimeout.tv_usec = PSM_INPUT_TIMEOUT%1000000; 2092123442Salfred timevaladd(&sc->inputtimeout, &now); 209384880Syokota 2094123442Salfred pb->ipacket[pb->inputbytes++] = c; 2095123442Salfred if (pb->inputbytes < sc->mode.packetsize) 209641016Sdfr continue; 209741016Sdfr 2098134405Sgibbs VLOG(4, (LOG_DEBUG, "psmintr: %02x %02x %02x %02x %02x %02x\n", 2099134405Sgibbs pb->ipacket[0], pb->ipacket[1], pb->ipacket[2], 2100134405Sgibbs pb->ipacket[3], pb->ipacket[4], pb->ipacket[5])); 210141016Sdfr 2102123442Salfred c = pb->ipacket[0]; 210341016Sdfr 2104134405Sgibbs if ((sc->flags & PSM_NEED_SYNCBITS) != 0) { 2105134405Sgibbs sc->mode.syncmask[1] = (c & sc->mode.syncmask[0]); 2106134405Sgibbs sc->flags &= ~PSM_NEED_SYNCBITS; 2107134405Sgibbs VLOG(2, (LOG_DEBUG, "psmintr: Sync bytes now %04x,%04x\n", 2108134405Sgibbs sc->mode.syncmask[0], sc->mode.syncmask[0])); 2109134405Sgibbs } else if ((c & sc->mode.syncmask[0]) != sc->mode.syncmask[1]) { 2110134405Sgibbs VLOG(3, (LOG_DEBUG, "psmintr: out of sync (%04x != %04x) %d" 2111134405Sgibbs " cmds since last error.\n", 2112134405Sgibbs c & sc->mode.syncmask[0], sc->mode.syncmask[1], 2113134405Sgibbs sc->cmdcount - sc->lasterr)); 2114123442Salfred sc->lasterr = sc->cmdcount; 2115134405Sgibbs /* 2116134405Sgibbs * The sync byte test is a weak measure of packet 2117134405Sgibbs * validity. Conservatively discard any input yet 2118134405Sgibbs * to be seen by userland when we detect a sync 2119134405Sgibbs * error since there is a good chance some of 2120134405Sgibbs * the queued packets have undetected errors. 2121134405Sgibbs */ 2122123442Salfred dropqueue(sc); 2123134405Sgibbs if (sc->syncerrors == 0) 2124134405Sgibbs sc->pkterrors++; 212584880Syokota ++sc->syncerrors; 2126123442Salfred sc->lastinputerr = now; 2127134405Sgibbs if (sc->syncerrors >= sc->mode.packetsize * 2 || 2128139628Sphilip sc->pkterrors >= pkterrthresh) { 2129134405Sgibbs 2130134405Sgibbs /* 2131134405Sgibbs * If we've failed to find a single sync byte in 2 2132134405Sgibbs * packets worth of data, or we've seen persistent 2133134405Sgibbs * packet errors during the validation period, 2134134405Sgibbs * reinitialize the mouse in hopes of returning it 2135134405Sgibbs * to the expected mode. 2136134405Sgibbs */ 2137134405Sgibbs VLOG(3, (LOG_DEBUG, "psmintr: reset the mouse.\n")); 2138134405Sgibbs reinitialize(sc, TRUE); 213984880Syokota } else if (sc->syncerrors == sc->mode.packetsize) { 2140134405Sgibbs 2141134405Sgibbs /* 2142134405Sgibbs * Try a soft reset after searching for a sync 2143134405Sgibbs * byte through a packet length of bytes. 2144134405Sgibbs */ 2145134405Sgibbs VLOG(3, (LOG_DEBUG, "psmintr: re-enable the mouse.\n")); 2146123442Salfred pb->inputbytes = 0; 214769439Syokota disable_aux_dev(sc->kbdc); 214869439Syokota enable_aux_dev(sc->kbdc); 2149134405Sgibbs } else { 2150134405Sgibbs VLOG(3, (LOG_DEBUG, "psmintr: discard a byte (%d)\n", 2151134405Sgibbs sc->syncerrors)); 2152134405Sgibbs pb->inputbytes--; 2153123442Salfred bcopy(&pb->ipacket[1], &pb->ipacket[0], pb->inputbytes); 215469439Syokota } 215584880Syokota continue; 215663746Syokota } 2157134405Sgibbs 2158134405Sgibbs /* 2159134405Sgibbs * We have what appears to be a valid packet. 2160134405Sgibbs * Reset the error counters. 2161134405Sgibbs */ 2162134405Sgibbs sc->syncerrors = 0; 2163134405Sgibbs 2164134405Sgibbs /* 2165134405Sgibbs * Drop even good packets if they occur within a timeout 2166134405Sgibbs * period of a sync error. This allows the detection of 2167134405Sgibbs * a change in the mouse's packet mode without exposing 2168134405Sgibbs * erratic mouse behavior to the user. Some KVMs forget 2169134405Sgibbs * enhanced mouse modes during switch events. 2170134405Sgibbs */ 2171134405Sgibbs if (!timeelapsed(&sc->lastinputerr, psmerrsecs, psmerrusecs, &now)) { 2172123442Salfred pb->inputbytes = 0; 2173123442Salfred continue; 2174123442Salfred } 217563746Syokota 2176134405Sgibbs /* 2177134405Sgibbs * Now that we're out of the validation period, reset 2178134405Sgibbs * the packet error count. 2179134405Sgibbs */ 2180134405Sgibbs sc->pkterrors = 0; 2181134405Sgibbs 2182123442Salfred sc->cmdcount++; 2183123442Salfred if (++sc->pqueue_end >= PSM_PACKETQUEUE) 2184123442Salfred sc->pqueue_end = 0; 2185123442Salfred /* 2186123442Salfred * If we've filled the queue then call the softintr ourselves, 2187123442Salfred * otherwise schedule the interrupt for later. 2188123442Salfred */ 2189123442Salfred if (!timeelapsed(&sc->lastsoftintr, psmsecs, psmusecs, &now) || 2190123442Salfred (sc->pqueue_end == sc->pqueue_start)) { 2191123442Salfred if ((sc->state & PSM_SOFTARMED) != 0) { 2192123442Salfred sc->state &= ~PSM_SOFTARMED; 2193123442Salfred untimeout(psmsoftintr, arg, sc->softcallout); 2194123442Salfred } 2195123442Salfred psmsoftintr(arg); 2196123442Salfred } else if ((sc->state & PSM_SOFTARMED) == 0) { 2197123442Salfred sc->state |= PSM_SOFTARMED; 2198123442Salfred sc->softcallout = timeout(psmsoftintr, arg, 2199123442Salfred psmhz < 1 ? 1 : (hz/psmhz)); 2200123442Salfred } 2201123442Salfred } 2202123442Salfred} 2203123442Salfred 2204123442Salfredstatic void 2205123442Salfredpsmsoftintr(void *arg) 2206123442Salfred{ 2207123442Salfred /* 2208123442Salfred * the table to turn PS/2 mouse button bits (MOUSE_PS2_BUTTON?DOWN) 2209123442Salfred * into `mousestatus' button bits (MOUSE_BUTTON?DOWN). 2210123442Salfred */ 2211123442Salfred static int butmap[8] = { 2212123442Salfred 0, 2213123442Salfred MOUSE_BUTTON1DOWN, 2214123442Salfred MOUSE_BUTTON3DOWN, 2215123442Salfred MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 2216123442Salfred MOUSE_BUTTON2DOWN, 2217123442Salfred MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN, 2218123442Salfred MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN, 2219123442Salfred MOUSE_BUTTON1DOWN | MOUSE_BUTTON2DOWN | MOUSE_BUTTON3DOWN 2220123442Salfred }; 2221123442Salfred static int butmap_versapad[8] = { 2222123442Salfred 0, 2223123442Salfred MOUSE_BUTTON3DOWN, 2224123442Salfred 0, 2225123442Salfred MOUSE_BUTTON3DOWN, 2226123442Salfred MOUSE_BUTTON1DOWN, 2227123442Salfred MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN, 2228123442Salfred MOUSE_BUTTON1DOWN, 2229123442Salfred MOUSE_BUTTON1DOWN | MOUSE_BUTTON3DOWN 2230123442Salfred }; 2231133882Sphilip static int touchpad_buttons; 2232133882Sphilip static int guest_buttons; 2233123442Salfred register struct psm_softc *sc = arg; 2234123442Salfred mousestatus_t ms; 2235132865Snjl int w, x, y, z; 2236123442Salfred int c; 2237123442Salfred int l; 2238139982Sphilip int x0, y0, xavg, yavg, xsensitivity, ysensitivity, sensitivity = 0; 2239123442Salfred int s; 2240123442Salfred packetbuf_t *pb; 2241123442Salfred 2242123442Salfred getmicrouptime(&sc->lastsoftintr); 2243123442Salfred 2244123442Salfred s = spltty(); 2245123442Salfred 2246123442Salfred do { 2247123442Salfred 2248123442Salfred pb = &sc->pqueue[sc->pqueue_start]; 2249123442Salfred c = pb->ipacket[0]; 225049965Syokota /* 225141016Sdfr * A kludge for Kensington device! 225241016Sdfr * The MSB of the horizontal count appears to be stored in 225358230Syokota * a strange place. 225441016Sdfr */ 225558230Syokota if (sc->hw.model == MOUSE_MODEL_THINK) 2256123442Salfred pb->ipacket[1] |= (c & MOUSE_PS2_XOVERFLOW) ? 0x80 : 0; 225741016Sdfr 225841016Sdfr /* ignore the overflow bits... */ 2259123442Salfred x = (c & MOUSE_PS2_XNEG) ? pb->ipacket[1] - 256 : pb->ipacket[1]; 2260123442Salfred y = (c & MOUSE_PS2_YNEG) ? pb->ipacket[2] - 256 : pb->ipacket[2]; 226141016Sdfr z = 0; 226241016Sdfr ms.obutton = sc->button; /* previous button state */ 226341016Sdfr ms.button = butmap[c & MOUSE_PS2_BUTTONS]; 226445789Speter /* `tapping' action */ 226545789Speter if (sc->config & PSM_CONFIG_FORCETAP) 226645789Speter ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; 226741016Sdfr 226841016Sdfr switch (sc->hw.model) { 226941016Sdfr 227058230Syokota case MOUSE_MODEL_EXPLORER: 227158230Syokota /* 227258230Syokota * b7 b6 b5 b4 b3 b2 b1 b0 227358230Syokota * byte 1: oy ox sy sx 1 M R L 227458230Syokota * byte 2: x x x x x x x x 227558230Syokota * byte 3: y y y y y y y y 227658230Syokota * byte 4: * * S2 S1 s d2 d1 d0 227758230Syokota * 227858230Syokota * L, M, R, S1, S2: left, middle, right and side buttons 227958230Syokota * s: wheel data sign bit 228058230Syokota * d2-d0: wheel data 228158230Syokota */ 2282123442Salfred z = (pb->ipacket[3] & MOUSE_EXPLORER_ZNEG) 2283123442Salfred ? (pb->ipacket[3] & 0x0f) - 16 : (pb->ipacket[3] & 0x0f); 2284123442Salfred ms.button |= (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON4DOWN) 228558230Syokota ? MOUSE_BUTTON4DOWN : 0; 2286123442Salfred ms.button |= (pb->ipacket[3] & MOUSE_EXPLORER_BUTTON5DOWN) 228758230Syokota ? MOUSE_BUTTON5DOWN : 0; 228858230Syokota break; 228958230Syokota 229041016Sdfr case MOUSE_MODEL_INTELLI: 229141016Sdfr case MOUSE_MODEL_NET: 229241016Sdfr /* wheel data is in the fourth byte */ 2293123442Salfred z = (char)pb->ipacket[3]; 229458230Syokota /* some mice may send 7 when there is no Z movement?! XXX */ 229558230Syokota if ((z >= 7) || (z <= -7)) 229658230Syokota z = 0; 229758230Syokota /* some compatible mice have additional buttons */ 229858230Syokota ms.button |= (c & MOUSE_PS2INTELLI_BUTTON4DOWN) 229958230Syokota ? MOUSE_BUTTON4DOWN : 0; 230058230Syokota ms.button |= (c & MOUSE_PS2INTELLI_BUTTON5DOWN) 230158230Syokota ? MOUSE_BUTTON5DOWN : 0; 230241016Sdfr break; 230341016Sdfr 230441016Sdfr case MOUSE_MODEL_MOUSEMANPLUS: 230548778Syokota /* 230648778Syokota * PS2++ protocl packet 230748778Syokota * 230848778Syokota * b7 b6 b5 b4 b3 b2 b1 b0 230948778Syokota * byte 1: * 1 p3 p2 1 * * * 231048778Syokota * byte 2: c1 c2 p1 p0 d1 d0 1 0 231148778Syokota * 231248778Syokota * p3-p0: packet type 231348778Syokota * c1, c2: c1 & c2 == 1, if p2 == 0 231448778Syokota * c1 & c2 == 0, if p2 == 1 231548778Syokota * 231648778Syokota * packet type: 0 (device type) 231748778Syokota * See comments in enable_mmanplus() below. 231848778Syokota * 231948778Syokota * packet type: 1 (wheel data) 232048778Syokota * 232148778Syokota * b7 b6 b5 b4 b3 b2 b1 b0 232248778Syokota * byte 3: h * B5 B4 s d2 d1 d0 232348778Syokota * 232448778Syokota * h: 1, if horizontal roller data 232548778Syokota * 0, if vertical roller data 232648778Syokota * B4, B5: button 4 and 5 232748778Syokota * s: sign bit 232848778Syokota * d2-d0: roller data 232948778Syokota * 233048778Syokota * packet type: 2 (reserved) 233148778Syokota */ 233248778Syokota if (((c & MOUSE_PS2PLUS_SYNCMASK) == MOUSE_PS2PLUS_SYNC) 233348778Syokota && (abs(x) > 191) 2334123442Salfred && MOUSE_PS2PLUS_CHECKBITS(pb->ipacket)) { 233541016Sdfr /* the extended data packet encodes button and wheel events */ 2336123442Salfred switch (MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket)) { 233748778Syokota case 1: 233848778Syokota /* wheel data packet */ 233948778Syokota x = y = 0; 2340123442Salfred if (pb->ipacket[2] & 0x80) { 234148778Syokota /* horizontal roller count - ignore it XXX*/ 234248778Syokota } else { 234348778Syokota /* vertical roller count */ 2344123442Salfred z = (pb->ipacket[2] & MOUSE_PS2PLUS_ZNEG) 2345123442Salfred ? (pb->ipacket[2] & 0x0f) - 16 2346123442Salfred : (pb->ipacket[2] & 0x0f); 234748778Syokota } 2348123442Salfred ms.button |= (pb->ipacket[2] & MOUSE_PS2PLUS_BUTTON4DOWN) 234948778Syokota ? MOUSE_BUTTON4DOWN : 0; 2350123442Salfred ms.button |= (pb->ipacket[2] & MOUSE_PS2PLUS_BUTTON5DOWN) 235148778Syokota ? MOUSE_BUTTON5DOWN : 0; 235248778Syokota break; 235348778Syokota case 2: 235458230Syokota /* this packet type is reserved by Logitech... */ 235558230Syokota /* 235658230Syokota * IBM ScrollPoint Mouse uses this packet type to 235758230Syokota * encode both vertical and horizontal scroll movement. 235858230Syokota */ 235958230Syokota x = y = 0; 236058230Syokota /* horizontal count */ 2361123442Salfred if (pb->ipacket[2] & 0x0f) 2362123442Salfred z = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) ? -2 : 2; 236358230Syokota /* vertical count */ 2364123442Salfred if (pb->ipacket[2] & 0xf0) 2365123442Salfred z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) ? -1 : 1; 236658230Syokota#if 0 236758230Syokota /* vertical count */ 2368123442Salfred z = (pb->ipacket[2] & MOUSE_SPOINT_ZNEG) 2369123442Salfred ? ((pb->ipacket[2] >> 4) & 0x0f) - 16 2370123442Salfred : ((pb->ipacket[2] >> 4) & 0x0f); 237158230Syokota /* horizontal count */ 2372123442Salfred w = (pb->ipacket[2] & MOUSE_SPOINT_WNEG) 2373123442Salfred ? (pb->ipacket[2] & 0x0f) - 16 2374123442Salfred : (pb->ipacket[2] & 0x0f); 237558230Syokota#endif 237658230Syokota break; 237748778Syokota case 0: 237848778Syokota /* device type packet - shouldn't happen */ 2379102412Scharnier /* FALLTHROUGH */ 238048778Syokota default: 238148778Syokota x = y = 0; 238248778Syokota ms.button = ms.obutton; 2383134405Sgibbs VLOG(1, (LOG_DEBUG, "psmintr: unknown PS2++ packet type %d:" 2384134405Sgibbs " 0x%02x 0x%02x 0x%02x\n", 2385134405Sgibbs MOUSE_PS2PLUS_PACKET_TYPE(pb->ipacket), 2386134405Sgibbs pb->ipacket[0], pb->ipacket[1], pb->ipacket[2])); 238748778Syokota break; 238848778Syokota } 238941016Sdfr } else { 239041016Sdfr /* preserve button states */ 239141016Sdfr ms.button |= ms.obutton & MOUSE_EXTBUTTONS; 239241016Sdfr } 239341016Sdfr break; 239441016Sdfr 239541016Sdfr case MOUSE_MODEL_GLIDEPOINT: 239641016Sdfr /* `tapping' action */ 239741016Sdfr ms.button |= ((c & MOUSE_PS2_TAP)) ? 0 : MOUSE_BUTTON4DOWN; 239841016Sdfr break; 239941016Sdfr 240041016Sdfr case MOUSE_MODEL_NETSCROLL: 240158230Syokota /* three addtional bytes encode buttons and wheel events */ 2402123442Salfred ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON3DOWN) 240341016Sdfr ? MOUSE_BUTTON4DOWN : 0; 2404123442Salfred ms.button |= (pb->ipacket[3] & MOUSE_PS2_BUTTON1DOWN) 240558230Syokota ? MOUSE_BUTTON5DOWN : 0; 2406123442Salfred z = (pb->ipacket[3] & MOUSE_PS2_XNEG) 2407123442Salfred ? pb->ipacket[4] - 256 : pb->ipacket[4]; 240841016Sdfr break; 240941016Sdfr 241041016Sdfr case MOUSE_MODEL_THINK: 241141016Sdfr /* the fourth button state in the first byte */ 241241016Sdfr ms.button |= (c & MOUSE_PS2_TAP) ? MOUSE_BUTTON4DOWN : 0; 241341016Sdfr break; 241441016Sdfr 241549965Syokota case MOUSE_MODEL_VERSAPAD: 241649965Syokota /* VersaPad PS/2 absolute mode message format 241749965Syokota * 241849965Syokota * [packet1] 7 6 5 4 3 2 1 0(LSB) 241949965Syokota * ipacket[0]: 1 1 0 A 1 L T R 242049965Syokota * ipacket[1]: H7 H6 H5 H4 H3 H2 H1 H0 242149965Syokota * ipacket[2]: V7 V6 V5 V4 V3 V2 V1 V0 242249965Syokota * ipacket[3]: 1 1 1 A 1 L T R 242349965Syokota * ipacket[4]:V11 V10 V9 V8 H11 H10 H9 H8 242449965Syokota * ipacket[5]: 0 P6 P5 P4 P3 P2 P1 P0 242549965Syokota * 242649965Syokota * [note] 242749965Syokota * R: right physical mouse button (1=on) 242849965Syokota * T: touch pad virtual button (1=tapping) 242949965Syokota * L: left physical mouse button (1=on) 243049965Syokota * A: position data is valid (1=valid) 243149965Syokota * H: horizontal data (12bit signed integer. H11 is sign bit.) 243249965Syokota * V: vertical data (12bit signed integer. V11 is sign bit.) 243349965Syokota * P: pressure data 243449965Syokota * 243549965Syokota * Tapping is mapped to MOUSE_BUTTON4. 243649965Syokota */ 243749965Syokota ms.button = butmap_versapad[c & MOUSE_PS2VERSA_BUTTONS]; 243849965Syokota ms.button |= (c & MOUSE_PS2VERSA_TAP) ? MOUSE_BUTTON4DOWN : 0; 243949965Syokota x = y = 0; 244049965Syokota if (c & MOUSE_PS2VERSA_IN_USE) { 2441123442Salfred x0 = pb->ipacket[1] | (((pb->ipacket[4]) & 0x0f) << 8); 2442123442Salfred y0 = pb->ipacket[2] | (((pb->ipacket[4]) & 0xf0) << 4); 244349965Syokota if (x0 & 0x800) 244449965Syokota x0 -= 0x1000; 244549965Syokota if (y0 & 0x800) 244649965Syokota y0 -= 0x1000; 244749965Syokota if (sc->flags & PSM_FLAGS_FINGERDOWN) { 244849965Syokota x = sc->xold - x0; 244949965Syokota y = y0 - sc->yold; 245049965Syokota if (x < 0) /* XXX */ 245149965Syokota x++; 245249965Syokota else if (x) 245349965Syokota x--; 245449965Syokota if (y < 0) 245549965Syokota y++; 245649965Syokota else if (y) 245749965Syokota y--; 245849965Syokota } else { 245949965Syokota sc->flags |= PSM_FLAGS_FINGERDOWN; 246049965Syokota } 246149965Syokota sc->xold = x0; 246249965Syokota sc->yold = y0; 246349965Syokota } else { 246449965Syokota sc->flags &= ~PSM_FLAGS_FINGERDOWN; 246549965Syokota } 246649965Syokota c = ((x < 0) ? MOUSE_PS2_XNEG : 0) 246749965Syokota | ((y < 0) ? MOUSE_PS2_YNEG : 0); 246849965Syokota break; 246949965Syokota 247058230Syokota case MOUSE_MODEL_4D: 247158230Syokota /* 247258230Syokota * b7 b6 b5 b4 b3 b2 b1 b0 247358230Syokota * byte 1: s2 d2 s1 d1 1 M R L 247458230Syokota * byte 2: sx x x x x x x x 247558230Syokota * byte 3: sy y y y y y y y 247658230Syokota * 247758230Syokota * s1: wheel 1 direction 247858230Syokota * d1: wheel 1 data 247958230Syokota * s2: wheel 2 direction 248058230Syokota * d2: wheel 2 data 248158230Syokota */ 2482123442Salfred x = (pb->ipacket[1] & 0x80) ? pb->ipacket[1] - 256 : pb->ipacket[1]; 2483123442Salfred y = (pb->ipacket[2] & 0x80) ? pb->ipacket[2] - 256 : pb->ipacket[2]; 248458230Syokota switch (c & MOUSE_4D_WHEELBITS) { 248558230Syokota case 0x10: 248658230Syokota z = 1; 248758230Syokota break; 248858230Syokota case 0x30: 248958230Syokota z = -1; 249058230Syokota break; 249158230Syokota case 0x40: /* 2nd wheel turning right XXX */ 249258230Syokota z = 2; 249358230Syokota break; 249458230Syokota case 0xc0: /* 2nd wheel turning left XXX */ 249558230Syokota z = -2; 249658230Syokota break; 249758230Syokota } 249858230Syokota break; 249958230Syokota 250058230Syokota case MOUSE_MODEL_4DPLUS: 250158230Syokota if ((x < 16 - 256) && (y < 16 - 256)) { 250258230Syokota /* 250358230Syokota * b7 b6 b5 b4 b3 b2 b1 b0 250458230Syokota * byte 1: 0 0 1 1 1 M R L 250558230Syokota * byte 2: 0 0 0 0 1 0 0 0 250658230Syokota * byte 3: 0 0 0 0 S s d1 d0 250758230Syokota * 250858230Syokota * L, M, R, S: left, middle, right and side buttons 250958230Syokota * s: wheel data sign bit 251058230Syokota * d1-d0: wheel data 251158230Syokota */ 251258230Syokota x = y = 0; 2513123442Salfred if (pb->ipacket[2] & MOUSE_4DPLUS_BUTTON4DOWN) 251458230Syokota ms.button |= MOUSE_BUTTON4DOWN; 2515123442Salfred z = (pb->ipacket[2] & MOUSE_4DPLUS_ZNEG) 2516123442Salfred ? ((pb->ipacket[2] & 0x07) - 8) 2517123442Salfred : (pb->ipacket[2] & 0x07) ; 251858230Syokota } else { 251958230Syokota /* preserve previous button states */ 252058230Syokota ms.button |= ms.obutton & MOUSE_EXTBUTTONS; 252158230Syokota } 252258230Syokota break; 252358230Syokota 2524132865Snjl case MOUSE_MODEL_SYNAPTICS: 2525132865Snjl /* TouchPad PS/2 absolute mode message format 2526132865Snjl * 2527132865Snjl * Bits: 7 6 5 4 3 2 1 0 (LSB) 2528132865Snjl * ------------------------------------------------ 2529132865Snjl * ipacket[0]: 1 0 W3 W2 0 W1 R L 2530132865Snjl * ipacket[1]: Yb Ya Y9 Y8 Xb Xa X9 X8 2531132865Snjl * ipacket[2]: Z7 Z6 Z5 Z4 Z3 Z2 Z1 Z0 2532132865Snjl * ipacket[3]: 1 1 Yc Xc 0 W0 D U 2533132865Snjl * ipacket[4]: X7 X6 X5 X4 X3 X2 X1 X0 2534132865Snjl * ipacket[5]: Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 2535132865Snjl * 2536132865Snjl * Legend: 2537132865Snjl * L: left physical mouse button 2538132865Snjl * R: right physical mouse button 2539132865Snjl * D: down button 2540132865Snjl * U: up button 2541132865Snjl * W: "wrist" value 2542132865Snjl * X: x position 2543132865Snjl * Y: x position 2544132865Snjl * Z: pressure 2545132865Snjl * 2546132865Snjl * Absolute reportable limits: 0 - 6143. 2547132865Snjl * Typical bezel limits: 1472 - 5472. 2548132865Snjl * Typical edge marings: 1632 - 5312. 2549132865Snjl * 2550132865Snjl * w = 3 Passthrough Packet 2551132865Snjl * 2552132865Snjl * Byte 2,5,6 == Byte 1,2,3 of "Guest" 2553132865Snjl */ 2554132865Snjl 2555135945Sphilip if (!synaptics_support) 2556135945Sphilip break; 2557135945Sphilip 2558132865Snjl /* Sanity check for out of sync packets. */ 2559132865Snjl if ((pb->ipacket[0] & 0xc8) != 0x80 || 2560132865Snjl (pb->ipacket[3] & 0xc8) != 0xc0) 2561154059Sdumbbell goto NEXT; 2562132865Snjl 2563132865Snjl x = y = x0 = y0 = 0; 2564132865Snjl 2565132865Snjl /* Pressure value. */ 2566132865Snjl z = pb->ipacket[2]; 2567132865Snjl 2568133301Sphilip /* Finger width value */ 2569133301Sphilip if (sc->synhw.capExtended) { 2570133301Sphilip w = ((pb->ipacket[0] & 0x30) >> 2) | 2571133301Sphilip ((pb->ipacket[0] & 0x04) >> 1) | 2572133301Sphilip ((pb->ipacket[3] & 0x04) >> 2); 2573133301Sphilip } else { 2574133301Sphilip /* Assume a finger of regular width */ 2575133301Sphilip w = 4; 2576133301Sphilip } 2577133301Sphilip 2578133868Sphilip /* Handle packets from the guest device */ 2579133868Sphilip if (w == 3 && sc->synhw.capPassthrough) { 2580133868Sphilip x = ((pb->ipacket[1] & 0x10) ? 2581133868Sphilip pb->ipacket[4] - 256 : pb->ipacket[4]); 2582133868Sphilip y = ((pb->ipacket[1] & 0x20) ? 2583133868Sphilip pb->ipacket[5] - 256 : pb->ipacket[5]); 2584133868Sphilip z = 0; 2585133868Sphilip 2586133868Sphilip guest_buttons = 0; 2587133868Sphilip if (pb->ipacket[1] & 0x01) 2588133868Sphilip guest_buttons |= MOUSE_BUTTON1DOWN; 2589133868Sphilip if (pb->ipacket[1] & 0x04) 2590133868Sphilip guest_buttons |= MOUSE_BUTTON2DOWN; 2591133868Sphilip if (pb->ipacket[1] & 0x02) 2592133868Sphilip guest_buttons |= MOUSE_BUTTON3DOWN; 2593133868Sphilip 2594133868Sphilip ms.button = touchpad_buttons | guest_buttons; 2595133868Sphilip break; 2596133868Sphilip } 2597133868Sphilip 2598133296Sphilip /* Button presses */ 2599133868Sphilip touchpad_buttons = 0; 2600132865Snjl if (pb->ipacket[0] & 0x01) 2601133868Sphilip touchpad_buttons |= MOUSE_BUTTON1DOWN; 2602132865Snjl if (pb->ipacket[0] & 0x02) 2603133868Sphilip touchpad_buttons |= MOUSE_BUTTON3DOWN; 2604132865Snjl 2605133296Sphilip if (sc->synhw.capExtended && sc->synhw.capFourButtons) { 2606133296Sphilip if ((pb->ipacket[3] & 0x01) && (pb->ipacket[0] & 0x01) == 0) 2607133868Sphilip touchpad_buttons |= MOUSE_BUTTON4DOWN; 2608133296Sphilip if ((pb->ipacket[3] & 0x02) && (pb->ipacket[0] & 0x02) == 0) 2609133868Sphilip touchpad_buttons |= MOUSE_BUTTON5DOWN; 2610133296Sphilip } 2611132865Snjl 2612139982Sphilip /* 2613139982Sphilip * In newer pads - bit 0x02 in the third byte of 2614139982Sphilip * the packet indicates that we have an extended 2615139982Sphilip * button press. 2616139982Sphilip */ 2617139982Sphilip if (pb->ipacket[3] & 0x02) { 2618139982Sphilip /* 2619139982Sphilip * if directional_scrolls is not 1, we treat 2620139982Sphilip * any of the scrolling directions as middle-click. 2621139982Sphilip */ 2622139982Sphilip if (sc->syninfo.directional_scrolls) { 2623139982Sphilip if (pb->ipacket[4] & 0x01) 2624139982Sphilip touchpad_buttons |= MOUSE_BUTTON4DOWN; 2625139982Sphilip if (pb->ipacket[5] & 0x01) 2626139982Sphilip touchpad_buttons |= MOUSE_BUTTON5DOWN; 2627139982Sphilip if (pb->ipacket[4] & 0x02) 2628139982Sphilip touchpad_buttons |= MOUSE_BUTTON6DOWN; 2629139982Sphilip if (pb->ipacket[5] & 0x02) 2630139982Sphilip touchpad_buttons |= MOUSE_BUTTON7DOWN; 2631139982Sphilip } else { 2632139982Sphilip if ((pb->ipacket[4] & 0x0F) || (pb->ipacket[5] & 0x0F)) 2633139982Sphilip touchpad_buttons |= MOUSE_BUTTON2DOWN; 2634139982Sphilip } 2635139982Sphilip 2636139982Sphilip } 2637139982Sphilip 2638133868Sphilip ms.button = touchpad_buttons | guest_buttons; 2639133868Sphilip 2640132865Snjl /* There is a finger on the pad. */ 2641132865Snjl if ((w >= 4 && w <= 7) && (z >= 16 && z < 200)) { 2642132865Snjl x0 = ((pb->ipacket[3] & 0x10) << 8) | 2643132865Snjl ((pb->ipacket[1] & 0x0f) << 8) | 2644132865Snjl pb->ipacket[4]; 2645132865Snjl y0 = ((pb->ipacket[3] & 0x20) << 7) | 2646132865Snjl ((pb->ipacket[1] & 0xf0) << 4) | 2647132865Snjl pb->ipacket[5]; 2648132865Snjl 2649132865Snjl if (sc->flags & PSM_FLAGS_FINGERDOWN) { 2650139982Sphilip x = x0 - sc->xold; 2651139982Sphilip y = y0 - sc->yold; 2652139982Sphilip 2653139982Sphilip /* we compute averages of x and y movement */ 2654139982Sphilip if (sc->xaverage == 0) 2655139982Sphilip sc->xaverage=x; 2656139982Sphilip 2657139982Sphilip if (sc->yaverage == 0) 2658139982Sphilip sc->yaverage=y; 2659139982Sphilip 2660139982Sphilip xavg = sc->xaverage; 2661139982Sphilip yavg = sc->yaverage; 2662139982Sphilip 2663139982Sphilip sc->xaverage = (xavg + x) >> 1; 2664139982Sphilip sc->yaverage = (yavg + y) >> 1; 2665139982Sphilip 2666139982Sphilip /* 2667139982Sphilip * then use the averages to compute a sensitivity level 2668139982Sphilip * in each dimension 2669139982Sphilip */ 2670139982Sphilip xsensitivity = (sc->xaverage - xavg); 2671139982Sphilip if (xsensitivity < 0) 2672139982Sphilip xsensitivity = -xsensitivity; 2673139982Sphilip 2674139982Sphilip ysensitivity = (sc->yaverage - yavg); 2675139982Sphilip if (ysensitivity < 0) 2676139982Sphilip ysensitivity = -ysensitivity; 2677139982Sphilip 2678139982Sphilip /* 2679139982Sphilip * The sensitivity level is higher the faster the finger 2680139982Sphilip * is moving. It also tends to be higher in the middle 2681139982Sphilip * of a touchpad motion than on either end 2682139982Sphilip * 2683139982Sphilip * Note - sensitivity gets to 0 when moving slowly - so 2684139982Sphilip * we add 1 to it to give it a meaningful value in that case. 2685139982Sphilip */ 2686139982Sphilip sensitivity = (xsensitivity & ysensitivity)+1; 2687139982Sphilip 2688139982Sphilip /* 2689139982Sphilip * If either our x or y change is greater than our 2690139982Sphilip * hi/low speed threshold - we do the high-speed 2691139982Sphilip * absolute to relative calculation otherwise we 2692139982Sphilip * do the low-speed calculation. 2693139982Sphilip */ 2694139982Sphilip if ((x>sc->syninfo.low_speed_threshold || 2695139982Sphilip x<-sc->syninfo.low_speed_threshold) || 2696139982Sphilip (y>sc->syninfo.low_speed_threshold || 2697139982Sphilip y<-sc->syninfo.low_speed_threshold)) { 2698132865Snjl x0 = (x0 + sc->xold * 3) / 4; 2699132865Snjl y0 = (y0 + sc->yold * 3) / 4; 2700133298Sphilip x = (x0 - sc->xold) * 10 / 85; 2701133298Sphilip y = (y0 - sc->yold) * 10 / 85; 2702132865Snjl } else { 2703139982Sphilip /* 2704139982Sphilip * This is the low speed calculation. 2705139982Sphilip * We simply check to see if our movement 2706139982Sphilip * is more than our minimum movement threshold 2707139982Sphilip * and if it is - set the movement to 1 in the 2708139982Sphilip * correct direction. 2709139982Sphilip * NOTE - Normally this would result in pointer 2710139982Sphilip * movement that was WAY too fast. This works 2711139982Sphilip * due to the movement squelch we do later. 2712139982Sphilip */ 2713139982Sphilip if (x < -sc->syninfo.min_movement) 2714139982Sphilip x = -1; 2715139982Sphilip else if (x > sc->syninfo.min_movement) 2716139982Sphilip x = 1; 2717139982Sphilip else 2718139982Sphilip x = 0; 2719139982Sphilip if (y < -sc->syninfo.min_movement) 2720139982Sphilip y = -1; 2721139982Sphilip else if (y > sc->syninfo.min_movement) 2722139982Sphilip y = 1; 2723139982Sphilip else 2724139982Sphilip y = 0; 2725139982Sphilip 2726139982Sphilip } 2727139982Sphilip } else { 2728132865Snjl sc->flags |= PSM_FLAGS_FINGERDOWN; 2729132865Snjl } 2730132865Snjl 2731139982Sphilip /* 2732139982Sphilip * ok - the squelch process. Take our sensitivity value 2733139982Sphilip * and add it to the current squelch value - if squelch 2734139982Sphilip * is less than our squelch threshold we kill the movement, 2735139982Sphilip * otherwise we reset squelch and pass the movement through. 2736139982Sphilip * Since squelch is cumulative - when mouse movement is slow 2737139982Sphilip * (around sensitivity 1) the net result is that only 2738139982Sphilip * 1 out of every squelch_level packets is 2739139982Sphilip * delivered, effectively slowing down the movement. 2740139982Sphilip */ 2741139982Sphilip sc->squelch += sensitivity; 2742139982Sphilip if (sc->squelch < sc->syninfo.squelch_level) { 2743139982Sphilip x = 0; 2744139982Sphilip y = 0; 2745139982Sphilip } else 2746139982Sphilip sc->squelch = 0; 2747139982Sphilip 2748132865Snjl sc->xold = x0; 2749132865Snjl sc->yold = y0; 2750133297Sphilip sc->zmax = imax(z, sc->zmax); 2751132865Snjl } else { 2752132865Snjl sc->flags &= ~PSM_FLAGS_FINGERDOWN; 2753133297Sphilip 2754139982Sphilip if (sc->zmax > tap_threshold && 2755133297Sphilip timevalcmp(&sc->lastsoftintr, &sc->taptimeout, <=)) { 2756133297Sphilip if (w == 0) 2757133297Sphilip ms.button |= MOUSE_BUTTON3DOWN; 2758133297Sphilip else if (w == 1) 2759133297Sphilip ms.button |= MOUSE_BUTTON2DOWN; 2760133297Sphilip else 2761133297Sphilip ms.button |= MOUSE_BUTTON1DOWN; 2762133297Sphilip } 2763133297Sphilip 2764133297Sphilip sc->zmax = 0; 2765139982Sphilip sc->taptimeout.tv_sec = tap_timeout / 1000000; 2766139982Sphilip sc->taptimeout.tv_usec = tap_timeout % 1000000; 2767133297Sphilip timevaladd(&sc->taptimeout, &sc->lastsoftintr); 2768132865Snjl } 2769133296Sphilip 2770133296Sphilip /* Use the extra buttons as a scrollwheel */ 2771133296Sphilip if (ms.button & MOUSE_BUTTON4DOWN) 2772133296Sphilip z = -1; 2773133296Sphilip else if (ms.button & MOUSE_BUTTON5DOWN) 2774133296Sphilip z = 1; 2775133296Sphilip else 2776133296Sphilip z = 0; 2777133296Sphilip 2778132865Snjl break; 2779132865Snjl 278041016Sdfr case MOUSE_MODEL_GENERIC: 278141016Sdfr default: 278241016Sdfr break; 278341016Sdfr } 278441016Sdfr 278541016Sdfr /* scale values */ 278641016Sdfr if (sc->mode.accelfactor >= 1) { 278741016Sdfr if (x != 0) { 278841016Sdfr x = x * x / sc->mode.accelfactor; 278941016Sdfr if (x == 0) 279041016Sdfr x = 1; 279141016Sdfr if (c & MOUSE_PS2_XNEG) 279241016Sdfr x = -x; 279341016Sdfr } 279441016Sdfr if (y != 0) { 279541016Sdfr y = y * y / sc->mode.accelfactor; 279641016Sdfr if (y == 0) 279741016Sdfr y = 1; 279841016Sdfr if (c & MOUSE_PS2_YNEG) 279941016Sdfr y = -y; 280041016Sdfr } 280141016Sdfr } 280241016Sdfr 280341016Sdfr ms.dx = x; 280441016Sdfr ms.dy = y; 280541016Sdfr ms.dz = z; 280641016Sdfr ms.flags = ((x || y || z) ? MOUSE_POSCHANGED : 0) 280741016Sdfr | (ms.obutton ^ ms.button); 280841016Sdfr 280941016Sdfr if (sc->mode.level < PSM_LEVEL_NATIVE) 2810123442Salfred pb->inputbytes = tame_mouse(sc, pb, &ms, pb->ipacket); 281141016Sdfr 281241016Sdfr sc->status.flags |= ms.flags; 281341016Sdfr sc->status.dx += ms.dx; 281441016Sdfr sc->status.dy += ms.dy; 281541016Sdfr sc->status.dz += ms.dz; 281641016Sdfr sc->status.button = ms.button; 281741016Sdfr sc->button = ms.button; 281841016Sdfr 281958230Syokota sc->watchdog = FALSE; 282058230Syokota 282141016Sdfr /* queue data */ 2822123442Salfred if (sc->queue.count + pb->inputbytes < sizeof(sc->queue.buf)) { 2823123442Salfred l = imin(pb->inputbytes, sizeof(sc->queue.buf) - sc->queue.tail); 2824123442Salfred bcopy(&pb->ipacket[0], &sc->queue.buf[sc->queue.tail], l); 2825123442Salfred if (pb->inputbytes > l) 2826123442Salfred bcopy(&pb->ipacket[l], &sc->queue.buf[0], pb->inputbytes - l); 282741016Sdfr sc->queue.tail = 2828123442Salfred (sc->queue.tail + pb->inputbytes) % sizeof(sc->queue.buf); 2829123442Salfred sc->queue.count += pb->inputbytes; 283041016Sdfr } 2831123442Salfred pb->inputbytes = 0; 283241016Sdfr 2833154059SdumbbellNEXT: 2834123442Salfred if (++sc->pqueue_start >= PSM_PACKETQUEUE) 2835123442Salfred sc->pqueue_start = 0; 2836123442Salfred } while (sc->pqueue_start != sc->pqueue_end); 2837123442Salfred if (sc->state & PSM_ASLP) { 2838123442Salfred sc->state &= ~PSM_ASLP; 2839123442Salfred wakeup( sc); 284041016Sdfr } 2841123442Salfred selwakeuppri(&sc->rsel, PZERO); 2842123442Salfred sc->state &= ~PSM_SOFTARMED; 2843123442Salfred splx(s); 284441016Sdfr} 284541016Sdfr 284641016Sdfrstatic int 2847130585Sphkpsmpoll(struct cdev *dev, int events, struct thread *td) 284841016Sdfr{ 284941016Sdfr struct psm_softc *sc = PSM_SOFTC(PSM_UNIT(dev)); 285041016Sdfr int s; 285141016Sdfr int revents = 0; 285241016Sdfr 285341016Sdfr /* Return true if a mouse event available */ 285441016Sdfr s = spltty(); 285545789Speter if (events & (POLLIN | POLLRDNORM)) { 285641016Sdfr if (sc->queue.count > 0) 285741016Sdfr revents |= events & (POLLIN | POLLRDNORM); 285841016Sdfr else 285983366Sjulian selrecord(td, &sc->rsel); 286045789Speter } 286141016Sdfr splx(s); 286241016Sdfr 286341016Sdfr return (revents); 286441016Sdfr} 286541016Sdfr 286641016Sdfr/* vendor/model specific routines */ 286741016Sdfr 286841016Sdfrstatic int mouse_id_proc1(KBDC kbdc, int res, int scale, int *status) 286941016Sdfr{ 287041016Sdfr if (set_mouse_resolution(kbdc, res) != res) 287141016Sdfr return FALSE; 287241016Sdfr if (set_mouse_scaling(kbdc, scale) 287341016Sdfr && set_mouse_scaling(kbdc, scale) 287441016Sdfr && set_mouse_scaling(kbdc, scale) 287541016Sdfr && (get_mouse_status(kbdc, status, 0, 3) >= 3)) 287641016Sdfr return TRUE; 287741016Sdfr return FALSE; 287841016Sdfr} 287941016Sdfr 288069438Syokotastatic int 288169438Syokotamouse_ext_command(KBDC kbdc, int command) 288269438Syokota{ 288369438Syokota int c; 288469438Syokota 288569438Syokota c = (command >> 6) & 0x03; 288669438Syokota if (set_mouse_resolution(kbdc, c) != c) 288769438Syokota return FALSE; 288869438Syokota c = (command >> 4) & 0x03; 288969438Syokota if (set_mouse_resolution(kbdc, c) != c) 289069438Syokota return FALSE; 289169438Syokota c = (command >> 2) & 0x03; 289269438Syokota if (set_mouse_resolution(kbdc, c) != c) 289369438Syokota return FALSE; 289469438Syokota c = (command >> 0) & 0x03; 289569438Syokota if (set_mouse_resolution(kbdc, c) != c) 289669438Syokota return FALSE; 289769438Syokota return TRUE; 289869438Syokota} 289969438Syokota 2900153072Sru#ifdef notyet 290141016Sdfr/* Logitech MouseMan Cordless II */ 290241016Sdfrstatic int 290341016Sdfrenable_lcordless(struct psm_softc *sc) 290441016Sdfr{ 290541016Sdfr int status[3]; 290641016Sdfr int ch; 290741016Sdfr 290841016Sdfr if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 2, status)) 290941016Sdfr return FALSE; 291041016Sdfr if (status[1] == PSMD_RES_HIGH) 291141016Sdfr return FALSE; 291241016Sdfr ch = (status[0] & 0x07) - 1; /* channel # */ 291341016Sdfr if ((ch <= 0) || (ch > 4)) 291441016Sdfr return FALSE; 291541016Sdfr /* 291641016Sdfr * status[1]: always one? 291741016Sdfr * status[2]: battery status? (0-100) 291841016Sdfr */ 291941016Sdfr return TRUE; 292041016Sdfr} 292141016Sdfr#endif /* notyet */ 292241016Sdfr 292358230Syokota/* Genius NetScroll Mouse, MouseSystems SmartScroll Mouse */ 292441016Sdfrstatic int 292541016Sdfrenable_groller(struct psm_softc *sc) 292641016Sdfr{ 292741016Sdfr int status[3]; 292841016Sdfr 292941016Sdfr /* 293041016Sdfr * The special sequence to enable the fourth button and the 293141016Sdfr * roller. Immediately after this sequence check status bytes. 293241016Sdfr * if the mouse is NetScroll, the second and the third bytes are 293341016Sdfr * '3' and 'D'. 293441016Sdfr */ 293541016Sdfr 293641016Sdfr /* 293741016Sdfr * If the mouse is an ordinary PS/2 mouse, the status bytes should 293841016Sdfr * look like the following. 293941016Sdfr * 294041016Sdfr * byte 1 bit 7 always 0 294141016Sdfr * bit 6 stream mode (0) 294241016Sdfr * bit 5 disabled (0) 294341016Sdfr * bit 4 1:1 scaling (0) 294441016Sdfr * bit 3 always 0 294541016Sdfr * bit 0-2 button status 294641016Sdfr * byte 2 resolution (PSMD_RES_HIGH) 294741016Sdfr * byte 3 report rate (?) 294841016Sdfr */ 294941016Sdfr 295041016Sdfr if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status)) 295141016Sdfr return FALSE; 295241016Sdfr if ((status[1] != '3') || (status[2] != 'D')) 295341016Sdfr return FALSE; 295458230Syokota /* FIXME: SmartScroll Mouse has 5 buttons! XXX */ 295541016Sdfr sc->hw.buttons = 4; 295641016Sdfr return TRUE; 295741016Sdfr} 295841016Sdfr 295958230Syokota/* Genius NetMouse/NetMouse Pro, ASCII Mie Mouse, NetScroll Optical */ 296041016Sdfrstatic int 296141016Sdfrenable_gmouse(struct psm_softc *sc) 296241016Sdfr{ 296341016Sdfr int status[3]; 296441016Sdfr 296541016Sdfr /* 296641016Sdfr * The special sequence to enable the middle, "rubber" button. 296741016Sdfr * Immediately after this sequence check status bytes. 296841016Sdfr * if the mouse is NetMouse, NetMouse Pro, or ASCII MIE Mouse, 296941016Sdfr * the second and the third bytes are '3' and 'U'. 297041016Sdfr * NOTE: NetMouse reports that it has three buttons although it has 297141016Sdfr * two buttons and a rubber button. NetMouse Pro and MIE Mouse 297241016Sdfr * say they have three buttons too and they do have a button on the 297341016Sdfr * side... 297441016Sdfr */ 297541016Sdfr if (!mouse_id_proc1(sc->kbdc, PSMD_RES_HIGH, 1, status)) 297641016Sdfr return FALSE; 297741016Sdfr if ((status[1] != '3') || (status[2] != 'U')) 297841016Sdfr return FALSE; 297941016Sdfr return TRUE; 298041016Sdfr} 298141016Sdfr 298241016Sdfr/* ALPS GlidePoint */ 298341016Sdfrstatic int 298441016Sdfrenable_aglide(struct psm_softc *sc) 298541016Sdfr{ 298641016Sdfr int status[3]; 298741016Sdfr 298841016Sdfr /* 298941016Sdfr * The special sequence to obtain ALPS GlidePoint specific 299041016Sdfr * information. Immediately after this sequence, status bytes will 299141016Sdfr * contain something interesting. 299241016Sdfr * NOTE: ALPS produces several models of GlidePoint. Some of those 299341016Sdfr * do not respond to this sequence, thus, cannot be detected this way. 299441016Sdfr */ 299550149Syokota if (set_mouse_sampling_rate(sc->kbdc, 100) != 100) 299650149Syokota return FALSE; 299741016Sdfr if (!mouse_id_proc1(sc->kbdc, PSMD_RES_LOW, 2, status)) 299841016Sdfr return FALSE; 299950149Syokota if ((status[1] == PSMD_RES_LOW) || (status[2] == 100)) 300041016Sdfr return FALSE; 300141016Sdfr return TRUE; 300241016Sdfr} 300341016Sdfr 300441016Sdfr/* Kensington ThinkingMouse/Trackball */ 300541016Sdfrstatic int 300641016Sdfrenable_kmouse(struct psm_softc *sc) 300741016Sdfr{ 300841016Sdfr static unsigned char rate[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; 300941016Sdfr KBDC kbdc = sc->kbdc; 301041016Sdfr int status[3]; 301141016Sdfr int id1; 301241016Sdfr int id2; 301341016Sdfr int i; 301441016Sdfr 301541016Sdfr id1 = get_aux_id(kbdc); 301641016Sdfr if (set_mouse_sampling_rate(kbdc, 10) != 10) 301741016Sdfr return FALSE; 301841016Sdfr /* 301941016Sdfr * The device is now in the native mode? It returns a different 302041016Sdfr * ID value... 302141016Sdfr */ 302241016Sdfr id2 = get_aux_id(kbdc); 302341016Sdfr if ((id1 == id2) || (id2 != 2)) 302441016Sdfr return FALSE; 302541016Sdfr 302641016Sdfr if (set_mouse_resolution(kbdc, PSMD_RES_LOW) != PSMD_RES_LOW) 302741016Sdfr return FALSE; 302841016Sdfr#if PSM_DEBUG >= 2 302941016Sdfr /* at this point, resolution is LOW, sampling rate is 10/sec */ 303041016Sdfr if (get_mouse_status(kbdc, status, 0, 3) < 3) 303141016Sdfr return FALSE; 303241016Sdfr#endif 303341016Sdfr 303441016Sdfr /* 303541016Sdfr * The special sequence to enable the third and fourth buttons. 303641016Sdfr * Otherwise they behave like the first and second buttons. 303741016Sdfr */ 303841016Sdfr for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) { 303941016Sdfr if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 304041016Sdfr return FALSE; 304141016Sdfr } 304241016Sdfr 304341016Sdfr /* 304441016Sdfr * At this point, the device is using default resolution and 304541016Sdfr * sampling rate for the native mode. 304641016Sdfr */ 304741016Sdfr if (get_mouse_status(kbdc, status, 0, 3) < 3) 304841016Sdfr return FALSE; 304941016Sdfr if ((status[1] == PSMD_RES_LOW) || (status[2] == rate[i - 1])) 305041016Sdfr return FALSE; 305141016Sdfr 305241016Sdfr /* the device appears be enabled by this sequence, diable it for now */ 305341016Sdfr disable_aux_dev(kbdc); 305441016Sdfr empty_aux_buffer(kbdc, 5); 305541016Sdfr 305641016Sdfr return TRUE; 305741016Sdfr} 305841016Sdfr 305958230Syokota/* Logitech MouseMan+/FirstMouse+, IBM ScrollPoint Mouse */ 306041016Sdfrstatic int 306141016Sdfrenable_mmanplus(struct psm_softc *sc) 306241016Sdfr{ 306341016Sdfr KBDC kbdc = sc->kbdc; 306441016Sdfr int data[3]; 306541016Sdfr 306641016Sdfr /* the special sequence to enable the fourth button and the roller. */ 306758230Syokota /* 306858230Syokota * NOTE: for ScrollPoint to respond correctly, the SET_RESOLUTION 306958230Syokota * must be called exactly three times since the last RESET command 307058230Syokota * before this sequence. XXX 307158230Syokota */ 307269438Syokota if (!set_mouse_scaling(kbdc, 1)) 307369438Syokota return FALSE; 307469438Syokota if (!mouse_ext_command(kbdc, 0x39) || !mouse_ext_command(kbdc, 0xdb)) 307569438Syokota return FALSE; 307641016Sdfr if (get_mouse_status(kbdc, data, 1, 3) < 3) 307741016Sdfr return FALSE; 307841016Sdfr 307948778Syokota /* 308048778Syokota * PS2++ protocl, packet type 0 308141016Sdfr * 308248778Syokota * b7 b6 b5 b4 b3 b2 b1 b0 308348778Syokota * byte 1: * 1 p3 p2 1 * * * 308448778Syokota * byte 2: 1 1 p1 p0 m1 m0 1 0 308548778Syokota * byte 3: m7 m6 m5 m4 m3 m2 m1 m0 308648778Syokota * 308748778Syokota * p3-p0: packet type: 0 308858230Syokota * m7-m0: model ID: MouseMan+:0x50, FirstMouse+:0x51, ScrollPoint:0x58... 308941016Sdfr */ 309048778Syokota /* check constant bits */ 309148778Syokota if ((data[0] & MOUSE_PS2PLUS_SYNCMASK) != MOUSE_PS2PLUS_SYNC) 309241016Sdfr return FALSE; 309348778Syokota if ((data[1] & 0xc3) != 0xc2) 309448778Syokota return FALSE; 309548778Syokota /* check d3-d0 in byte 2 */ 309648778Syokota if (!MOUSE_PS2PLUS_CHECKBITS(data)) 309748778Syokota return FALSE; 309848778Syokota /* check p3-p0 */ 309948778Syokota if (MOUSE_PS2PLUS_PACKET_TYPE(data) != 0) 310048778Syokota return FALSE; 310141016Sdfr 310248778Syokota sc->hw.hwid &= 0x00ff; 310348778Syokota sc->hw.hwid |= data[2] << 8; /* save model ID */ 310448778Syokota 310541016Sdfr /* 310641016Sdfr * MouseMan+ (or FirstMouse+) is now in its native mode, in which 310741016Sdfr * the wheel and the fourth button events are encoded in the 310841016Sdfr * special data packet. The mouse may be put in the IntelliMouse mode 310941016Sdfr * if it is initialized by the IntelliMouse's method. 311041016Sdfr */ 311141016Sdfr return TRUE; 311241016Sdfr} 311341016Sdfr 311458230Syokota/* MS IntelliMouse Explorer */ 311558230Syokotastatic int 311658230Syokotaenable_msexplorer(struct psm_softc *sc) 311758230Syokota{ 311858923Syokota static unsigned char rate0[] = { 200, 100, 80, }; 311958923Syokota static unsigned char rate1[] = { 200, 200, 80, }; 312058230Syokota KBDC kbdc = sc->kbdc; 312158230Syokota int id; 312258230Syokota int i; 312358230Syokota 3124176554Srink /* 3125176554Srink * This is needed for at least A4Tech X-7xx mice - they do not go 3126176554Srink * straight to Explorer mode, but need to be set to Intelli mode 3127176554Srink * first. 3128176554Srink */ 3129176554Srink enable_msintelli(sc); 3130176554Srink 313169438Syokota /* the special sequence to enable the extra buttons and the roller. */ 313269438Syokota for (i = 0; i < sizeof(rate1)/sizeof(rate1[0]); ++i) { 313369438Syokota if (set_mouse_sampling_rate(kbdc, rate1[i]) != rate1[i]) 313469438Syokota return FALSE; 313569438Syokota } 313669438Syokota /* the device will give the genuine ID only after the above sequence */ 313769438Syokota id = get_aux_id(kbdc); 313869438Syokota if (id != PSM_EXPLORER_ID) 313969438Syokota return FALSE; 314069438Syokota 314169438Syokota sc->hw.hwid = id; 314269438Syokota sc->hw.buttons = 5; /* IntelliMouse Explorer XXX */ 314369438Syokota 314458923Syokota /* 314558923Syokota * XXX: this is a kludge to fool some KVM switch products 314658923Syokota * which think they are clever enough to know the 4-byte IntelliMouse 314758923Syokota * protocol, and assume any other protocols use 3-byte packets. 314858923Syokota * They don't convey 4-byte data packets from the IntelliMouse Explorer 314958923Syokota * correctly to the host computer because of this! 315058923Syokota * The following sequence is actually IntelliMouse's "wake up" 315158923Syokota * sequence; it will make the KVM think the mouse is IntelliMouse 315258923Syokota * when it is in fact IntelliMouse Explorer. 315358923Syokota */ 315458923Syokota for (i = 0; i < sizeof(rate0)/sizeof(rate0[0]); ++i) { 315558923Syokota if (set_mouse_sampling_rate(kbdc, rate0[i]) != rate0[i]) 315669438Syokota break; 315758923Syokota } 315858923Syokota id = get_aux_id(kbdc); 315958923Syokota 316058230Syokota return TRUE; 316158230Syokota} 316258230Syokota 316341016Sdfr/* MS IntelliMouse */ 316441016Sdfrstatic int 316541016Sdfrenable_msintelli(struct psm_softc *sc) 316641016Sdfr{ 316741016Sdfr /* 316841016Sdfr * Logitech MouseMan+ and FirstMouse+ will also respond to this 316941016Sdfr * probe routine and act like IntelliMouse. 317041016Sdfr */ 317141016Sdfr 317241016Sdfr static unsigned char rate[] = { 200, 100, 80, }; 317341016Sdfr KBDC kbdc = sc->kbdc; 317441016Sdfr int id; 317541016Sdfr int i; 317641016Sdfr 317741016Sdfr /* the special sequence to enable the third button and the roller. */ 317841016Sdfr for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) { 317941016Sdfr if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 318041016Sdfr return FALSE; 318141016Sdfr } 318241016Sdfr /* the device will give the genuine ID only after the above sequence */ 318341016Sdfr id = get_aux_id(kbdc); 318441016Sdfr if (id != PSM_INTELLI_ID) 318541016Sdfr return FALSE; 318641016Sdfr 318741016Sdfr sc->hw.hwid = id; 318841016Sdfr sc->hw.buttons = 3; 318941016Sdfr 319041016Sdfr return TRUE; 319141016Sdfr} 319241016Sdfr 319358230Syokota/* A4 Tech 4D Mouse */ 319458230Syokotastatic int 319558230Syokotaenable_4dmouse(struct psm_softc *sc) 319658230Syokota{ 319758230Syokota /* 319858230Syokota * Newer wheel mice from A4 Tech may use the 4D+ protocol. 319958230Syokota */ 320058230Syokota 320158230Syokota static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 }; 320258230Syokota KBDC kbdc = sc->kbdc; 320358230Syokota int id; 320458230Syokota int i; 320558230Syokota 320658230Syokota for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) { 320758230Syokota if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 320858230Syokota return FALSE; 320958230Syokota } 321058230Syokota id = get_aux_id(kbdc); 321158230Syokota /* 321258923Syokota * WinEasy 4D, 4 Way Scroll 4D: 6 321358230Syokota * Cable-Free 4D: 8 (4DPLUS) 321458923Syokota * WinBest 4D+, 4 Way Scroll 4D+: 8 (4DPLUS) 321558230Syokota */ 321658230Syokota if (id != PSM_4DMOUSE_ID) 321758230Syokota return FALSE; 321858230Syokota 321958230Syokota sc->hw.hwid = id; 322058230Syokota sc->hw.buttons = 3; /* XXX some 4D mice have 4? */ 322158230Syokota 322258230Syokota return TRUE; 322358230Syokota} 322458230Syokota 322558230Syokota/* A4 Tech 4D+ Mouse */ 322658230Syokotastatic int 322758230Syokotaenable_4dplus(struct psm_softc *sc) 322858230Syokota{ 322958230Syokota /* 323058230Syokota * Newer wheel mice from A4 Tech seem to use this protocol. 323158230Syokota * Older models are recognized as either 4D Mouse or IntelliMouse. 323258230Syokota */ 323358230Syokota KBDC kbdc = sc->kbdc; 323458230Syokota int id; 323558230Syokota 323658230Syokota /* 323758230Syokota * enable_4dmouse() already issued the following ID sequence... 323858230Syokota static unsigned char rate[] = { 200, 100, 80, 60, 40, 20 }; 323958230Syokota int i; 324058230Syokota 324158230Syokota for (i = 0; i < sizeof(rate)/sizeof(rate[0]); ++i) { 324258230Syokota if (set_mouse_sampling_rate(kbdc, rate[i]) != rate[i]) 324358230Syokota return FALSE; 324458230Syokota } 324558230Syokota */ 324658230Syokota 324758230Syokota id = get_aux_id(kbdc); 3248117478Smikeh switch (id) { 3249117478Smikeh case PSM_4DPLUS_ID: 3250117478Smikeh sc->hw.buttons = 4; 3251117478Smikeh break; 3252117478Smikeh case PSM_4DPLUS_RFSW35_ID: 3253117478Smikeh sc->hw.buttons = 3; 3254117478Smikeh break; 3255117478Smikeh default: 3256117478Smikeh return FALSE; 3257117478Smikeh } 325858230Syokota 325958230Syokota sc->hw.hwid = id; 326058230Syokota 326158230Syokota return TRUE; 326258230Syokota} 326358230Syokota 3264132865Snjl/* Synaptics Touchpad */ 3265132865Snjlstatic int 3266132865Snjlenable_synaptics(struct psm_softc *sc) 3267132865Snjl{ 3268132865Snjl int status[3]; 3269132865Snjl KBDC kbdc; 3270132865Snjl 3271135945Sphilip if (!synaptics_support) 3272135945Sphilip return (FALSE); 3273135945Sphilip 3274139982Sphilip /* Attach extra synaptics sysctl nodes under hw.psm.synaptics */ 3275139982Sphilip sysctl_ctx_init(&sc->syninfo.sysctl_ctx); 3276139982Sphilip sc->syninfo.sysctl_tree = SYSCTL_ADD_NODE(&sc->syninfo.sysctl_ctx, 3277139982Sphilip SYSCTL_STATIC_CHILDREN(_hw_psm), OID_AUTO, "synaptics", 3278139982Sphilip CTLFLAG_RD, 0, "Synaptics TouchPad"); 3279139982Sphilip 3280139982Sphilip /* 3281139982Sphilip * synaptics_directional_scrolls - if non-zero, the directional 3282139982Sphilip * pad scrolls, otherwise it registers as a middle-click. 3283139982Sphilip */ 3284139982Sphilip sc->syninfo.directional_scrolls = 1; 3285139982Sphilip SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 3286139982Sphilip SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), 3287139982Sphilip OID_AUTO, "directional_scrolls", CTLFLAG_RW, 3288139982Sphilip &sc->syninfo.directional_scrolls, 0, 3289139982Sphilip "directional pad scrolls (1=yes 0=3rd button)"); 3290139982Sphilip 3291139982Sphilip /* 3292139982Sphilip * Synaptics_low_speed_threshold - the number of touchpad units 3293139982Sphilip * below-which we go into low-speed tracking mode. 3294139982Sphilip */ 3295139982Sphilip sc->syninfo.low_speed_threshold = 20; 3296139982Sphilip SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 3297139982Sphilip SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), 3298139982Sphilip OID_AUTO, "low_speed_threshold", CTLFLAG_RW, 3299139982Sphilip &sc->syninfo.low_speed_threshold, 0, 3300139982Sphilip "threshold between low and hi speed positioning"); 3301139982Sphilip 3302139982Sphilip /* 3303139982Sphilip * Synaptics_min_movement - the number of touchpad units below 3304139982Sphilip * which we ignore altogether. 3305139982Sphilip */ 3306139982Sphilip sc->syninfo.min_movement = 2; 3307139982Sphilip SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 3308139982Sphilip SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), 3309139982Sphilip OID_AUTO, "min_movement", CTLFLAG_RW, 3310139982Sphilip &sc->syninfo.min_movement, 0, 3311139982Sphilip "ignore touchpad movements less than this"); 3312139982Sphilip 3313139982Sphilip /* 3314139982Sphilip * Synaptics_squelch_level - level at which we squelch movement 3315139982Sphilip * packets. 3316139982Sphilip * 3317139982Sphilip * This effectively sends 1 out of every synaptics_squelch_level 3318139982Sphilip * packets when * running in low-speed mode. 3319139982Sphilip */ 3320139982Sphilip sc->syninfo.squelch_level=3; 3321139982Sphilip SYSCTL_ADD_INT(&sc->syninfo.sysctl_ctx, 3322139982Sphilip SYSCTL_CHILDREN(sc->syninfo.sysctl_tree), 3323139982Sphilip OID_AUTO, "squelch_level", CTLFLAG_RW, 3324139982Sphilip &sc->syninfo.squelch_level, 0, 3325139982Sphilip "squelch level for synaptics touchpads"); 3326139982Sphilip 3327132865Snjl kbdc = sc->kbdc; 3328132865Snjl disable_aux_dev(kbdc); 3329139982Sphilip sc->hw.buttons = 3; 3330139982Sphilip sc->squelch = 0; 3331132865Snjl 3332132865Snjl /* Just to be on the safe side */ 3333132865Snjl set_mouse_scaling(kbdc, 1); 3334132865Snjl 3335133295Sphilip /* Identify the Touchpad version */ 3336132865Snjl if (mouse_ext_command(kbdc, 0) == 0) 3337132865Snjl return (FALSE); 3338132865Snjl if (get_mouse_status(kbdc, status, 0, 3) != 3) 3339132865Snjl return (FALSE); 3340132865Snjl if (status[1] != 0x47) 3341132865Snjl return (FALSE); 3342132865Snjl 3343132865Snjl sc->synhw.infoMinor = status[0]; 3344132865Snjl sc->synhw.infoMajor = status[2] & 0x0f; 3345133295Sphilip 3346133295Sphilip if (verbose >= 2) 3347133295Sphilip printf("Synaptics Touchpad v%d.%d\n", 3348133295Sphilip sc->synhw.infoMajor, sc->synhw.infoMinor); 3349133295Sphilip 3350132865Snjl if (sc->synhw.infoMajor < 4) { 3351133295Sphilip printf(" Unsupported (pre-v4) Touchpad detected\n"); 3352132865Snjl return (FALSE); 3353132865Snjl } 3354132865Snjl 3355133295Sphilip /* Get the Touchpad model information */ 3356132865Snjl if (mouse_ext_command(kbdc, 3) == 0) 3357132865Snjl return (FALSE); 3358132865Snjl if (get_mouse_status(kbdc, status, 0, 3) != 3) 3359132865Snjl return (FALSE); 3360132865Snjl if ((status[1] & 0x01) != 0) { 3361133295Sphilip printf(" Failed to read model information\n"); 3362132865Snjl return (FALSE); 3363132865Snjl } 3364132865Snjl 3365132865Snjl sc->synhw.infoRot180 = (status[0] & 0x80) >> 7; 3366132865Snjl sc->synhw.infoPortrait = (status[0] & 0x40) >> 6; 3367132865Snjl sc->synhw.infoSensor = status[0] & 0x3f; 3368132865Snjl sc->synhw.infoHardware = (status[1] & 0xfe) >> 1; 3369132865Snjl sc->synhw.infoNewAbs = (status[2] & 0x80) >> 7; 3370132865Snjl sc->synhw.capPen = (status[2] & 0x40) >> 6; 3371132865Snjl sc->synhw.infoSimplC = (status[2] & 0x20) >> 5; 3372132865Snjl sc->synhw.infoGeometry = status[2] & 0x0f; 3373133295Sphilip 3374132865Snjl if (verbose >= 2) { 3375133295Sphilip printf(" Model information:\n"); 3376133295Sphilip printf(" infoRot180: %d\n", sc->synhw.infoRot180); 3377133295Sphilip printf(" infoPortrait: %d\n", sc->synhw.infoPortrait); 3378133295Sphilip printf(" infoSensor: %d\n", sc->synhw.infoSensor); 3379133295Sphilip printf(" infoHardware: %d\n", sc->synhw.infoHardware); 3380133295Sphilip printf(" infoNewAbs: %d\n", sc->synhw.infoNewAbs); 3381133295Sphilip printf(" capPen: %d\n", sc->synhw.capPen); 3382133295Sphilip printf(" infoSimplC: %d\n", sc->synhw.infoSimplC); 3383133295Sphilip printf(" infoGeometry: %d\n", sc->synhw.infoGeometry); 3384132865Snjl } 3385132865Snjl 3386133295Sphilip /* Read the extended capability bits */ 3387132865Snjl if (mouse_ext_command(kbdc, 2) == 0) 3388132865Snjl return (FALSE); 3389132865Snjl if (get_mouse_status(kbdc, status, 0, 3) != 3) 3390132865Snjl return (FALSE); 3391132865Snjl if (status[1] != 0x47) { 3392133295Sphilip printf(" Failed to read extended capability bits\n"); 3393132865Snjl return (FALSE); 3394132865Snjl } 3395132865Snjl 3396133295Sphilip /* Set the different capabilities when they exist */ 3397133295Sphilip if ((status[0] & 0x80) >> 7) { 3398133295Sphilip sc->synhw.capExtended = (status[0] & 0x80) >> 7; 3399133295Sphilip sc->synhw.capPassthrough = (status[2] & 0x80) >> 7; 3400133295Sphilip sc->synhw.capSleep = (status[2] & 0x10) >> 4; 3401133295Sphilip sc->synhw.capFourButtons = (status[2] & 0x08) >> 3; 3402133295Sphilip sc->synhw.capMultiFinger = (status[2] & 0x02) >> 1; 3403133295Sphilip sc->synhw.capPalmDetect = (status[2] & 0x01); 3404133295Sphilip 3405133295Sphilip if (verbose >= 2) { 3406133295Sphilip printf(" Extended capabilities:\n"); 3407133295Sphilip printf(" capExtended: %d\n", sc->synhw.capExtended); 3408133295Sphilip printf(" capPassthrough: %d\n", sc->synhw.capPassthrough); 3409133295Sphilip printf(" capSleep: %d\n", sc->synhw.capSleep); 3410133295Sphilip printf(" capFourButtons: %d\n", sc->synhw.capFourButtons); 3411133295Sphilip printf(" capMultiFinger: %d\n", sc->synhw.capMultiFinger); 3412133295Sphilip printf(" capPalmDetect: %d\n", sc->synhw.capPalmDetect); 3413133295Sphilip } 3414139982Sphilip 3415139982Sphilip /* 3416139982Sphilip * if we have bits set in status[0] & 0x70 - then we can load 3417139982Sphilip * more information about buttons using query 0x09 3418139982Sphilip */ 3419139982Sphilip if (status[0] & 0x70) { 3420139982Sphilip if (mouse_ext_command(kbdc, 0x09) == 0) 3421139982Sphilip return (FALSE); 3422139982Sphilip if (get_mouse_status(kbdc, status, 0, 3) != 3) 3423139982Sphilip return (FALSE); 3424139982Sphilip sc->hw.buttons = ((status[1] & 0xf0) >> 4) + 3; 3425139982Sphilip if (verbose >= 2) 3426139982Sphilip printf(" Additional Buttons: %d\n", sc->hw.buttons -3); 3427139982Sphilip } 3428139982Sphilip 3429133295Sphilip } else { 3430133295Sphilip sc->synhw.capExtended = 0; 3431133295Sphilip 3432133295Sphilip if (verbose >= 2) 3433133295Sphilip printf(" No extended capabilities\n"); 3434133295Sphilip } 3435133295Sphilip 3436133295Sphilip /* 3437133295Sphilip * Read the mode byte 3438133295Sphilip * 3439133295Sphilip * XXX: Note the Synaptics documentation also defines the first 3440133295Sphilip * byte of the response to this query to be a constant 0x3b, this 3441133295Sphilip * does not appear to be true for Touchpads with guest devices. 3442133295Sphilip */ 3443132865Snjl if (mouse_ext_command(kbdc, 1) == 0) 3444132865Snjl return (FALSE); 3445132865Snjl if (get_mouse_status(kbdc, status, 0, 3) != 3) 3446132865Snjl return (FALSE); 3447133295Sphilip if (status[1] != 0x47) { 3448133295Sphilip printf(" Failed to read mode byte\n"); 3449132865Snjl return (FALSE); 3450132865Snjl } 3451132865Snjl 3452133295Sphilip /* Set the mode byte -- request wmode where available */ 3453133295Sphilip if (sc->synhw.capExtended) 3454133295Sphilip mouse_ext_command(kbdc, 0xc1); 3455133295Sphilip else 3456133295Sphilip mouse_ext_command(kbdc, 0xc0); 3457132865Snjl 3458133295Sphilip /* Reset the sampling rate */ 3459132865Snjl set_mouse_sampling_rate(kbdc, 20); 3460132865Snjl 3461133296Sphilip /* 3462133296Sphilip * Report the correct number of buttons 3463133296Sphilip * 3464133296Sphilip * XXX: I'm not sure this is used anywhere. 3465133296Sphilip */ 3466133296Sphilip if (sc->synhw.capExtended && sc->synhw.capFourButtons) 3467133296Sphilip sc->hw.buttons = 4; 3468133296Sphilip 3469132865Snjl return (TRUE); 3470132865Snjl} 3471133295Sphilip 347249965Syokota/* Interlink electronics VersaPad */ 347349965Syokotastatic int 347449965Syokotaenable_versapad(struct psm_softc *sc) 347549965Syokota{ 347649965Syokota KBDC kbdc = sc->kbdc; 347749965Syokota int data[3]; 347849965Syokota 347949965Syokota set_mouse_resolution(kbdc, PSMD_RES_MEDIUM_HIGH); /* set res. 2 */ 348049965Syokota set_mouse_sampling_rate(kbdc, 100); /* set rate 100 */ 348149965Syokota set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 348249965Syokota set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 348349965Syokota set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 348449965Syokota set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 348549965Syokota if (get_mouse_status(kbdc, data, 0, 3) < 3) /* get status */ 348649965Syokota return FALSE; 348749965Syokota if (data[2] != 0xa || data[1] != 0 ) /* rate == 0xa && res. == 0 */ 348849965Syokota return FALSE; 348949965Syokota set_mouse_scaling(kbdc, 1); /* set scale 1:1 */ 349049965Syokota 349158230Syokota sc->config |= PSM_CONFIG_HOOKRESUME | PSM_CONFIG_INITAFTERSUSPEND; 349258230Syokota 349349965Syokota return TRUE; /* PS/2 absolute mode */ 349449965Syokota} 349549965Syokota 3496147271Smarius/* 3497147271Smarius * Return true if 'now' is earlier than (start + (secs.usecs)). 3498147271Smarius * Now may be NULL and the function will fetch the current time from 3499147271Smarius * getmicrouptime(), or a cached 'now' can be passed in. 3500147271Smarius * All values should be numbers derived from getmicrouptime(). 3501147271Smarius */ 350241016Sdfrstatic int 3503147271Smariustimeelapsed(start, secs, usecs, now) 3504147271Smarius const struct timeval *start, *now; 3505147271Smarius int secs, usecs; 3506147271Smarius{ 3507147271Smarius struct timeval snow, tv; 3508147271Smarius 3509147271Smarius /* if there is no 'now' passed in, the get it as a convience. */ 3510147271Smarius if (now == NULL) { 3511147271Smarius getmicrouptime(&snow); 3512147271Smarius now = &snow; 3513147271Smarius } 3514147271Smarius 3515147271Smarius tv.tv_sec = secs; 3516147271Smarius tv.tv_usec = usecs; 3517147271Smarius timevaladd(&tv, start); 3518147271Smarius return (timevalcmp(&tv, now, <)); 3519147271Smarius} 3520147271Smarius 3521147271Smariusstatic int 352254629Syokotapsmresume(device_t dev) 352341016Sdfr{ 352454629Syokota struct psm_softc *sc = device_get_softc(dev); 352554629Syokota int unit = device_get_unit(dev); 352684880Syokota int err; 352741016Sdfr 3528134405Sgibbs VLOG(2, (LOG_NOTICE, "psm%d: system resume hook called.\n", unit)); 352941016Sdfr 353058230Syokota if (!(sc->config & PSM_CONFIG_HOOKRESUME)) 353158230Syokota return (0); 353258230Syokota 353384880Syokota err = reinitialize(sc, sc->config & PSM_CONFIG_INITAFTERSUSPEND); 353441016Sdfr 353541016Sdfr if ((sc->state & PSM_ASLP) && !(sc->state & PSM_VALID)) { 353641016Sdfr /* 353741016Sdfr * Release the blocked process; it must be notified that the device 353841016Sdfr * cannot be accessed anymore. 353941016Sdfr */ 354041016Sdfr sc->state &= ~PSM_ASLP; 3541111748Sdes wakeup(sc); 354241016Sdfr } 354341016Sdfr 3544134405Sgibbs VLOG(2, (LOG_DEBUG, "psm%d: system resume hook exiting.\n", unit)); 354541016Sdfr 354641016Sdfr return (err); 354741016Sdfr} 354841016Sdfr 354952997SpeterDRIVER_MODULE(psm, atkbdc, psm_driver, psm_devclass, 0, 0); 355083147Syokota 3551147271Smarius#ifdef DEV_ISA 3552147271Smarius 355383147Syokota/* 355483147Syokota * This sucks up assignments from PNPBIOS and ACPI. 355583147Syokota */ 355683147Syokota 355783931Syokota/* 355883931Syokota * When the PS/2 mouse device is reported by ACPI or PnP BIOS, it may 355983931Syokota * appear BEFORE the AT keyboard controller. As the PS/2 mouse device 356083931Syokota * can be probed and attached only after the AT keyboard controller is 356183931Syokota * attached, we shall quietly reserve the IRQ resource for later use. 356283931Syokota * If the PS/2 mouse device is reported to us AFTER the keyboard controller, 356383931Syokota * copy the IRQ resource to the PS/2 mouse device instance hanging 356483931Syokota * under the keyboard controller, then probe and attach it. 356583931Syokota */ 356683147Syokota 356783147Syokotastatic devclass_t psmcpnp_devclass; 356883147Syokota 356983147Syokotastatic device_probe_t psmcpnp_probe; 357083147Syokotastatic device_attach_t psmcpnp_attach; 357183147Syokota 357283147Syokotastatic device_method_t psmcpnp_methods[] = { 357383147Syokota DEVMETHOD(device_probe, psmcpnp_probe), 357483147Syokota DEVMETHOD(device_attach, psmcpnp_attach), 357583147Syokota 357683147Syokota { 0, 0 } 357783147Syokota}; 357883147Syokota 357983147Syokotastatic driver_t psmcpnp_driver = { 358083147Syokota PSMCPNP_DRIVER_NAME, 358183147Syokota psmcpnp_methods, 358283147Syokota 1, /* no softc */ 358383147Syokota}; 358483147Syokota 358583147Syokotastatic struct isa_pnp_id psmcpnp_ids[] = { 358688188Ssheldonh { 0x030fd041, "PS/2 mouse port" }, /* PNP0F03 */ 3587156730Stakawata { 0x0e0fd041, "PS/2 mouse port" }, /* PNP0F0E */ 3588156730Stakawata { 0x120fd041, "PS/2 mouse port" }, /* PNP0F12 */ 358983147Syokota { 0x130fd041, "PS/2 mouse port" }, /* PNP0F13 */ 359083147Syokota { 0x1303d041, "PS/2 port" }, /* PNP0313, XXX */ 3591117117Smikeh { 0x02002e4f, "Dell PS/2 mouse port" }, /* Lat. X200, Dell */ 3592156730Stakawata { 0x0002a906, "ALPS Glide Point" }, /* ALPS Glide Point */ 359383492Syokota { 0x80374d24, "IBM PS/2 mouse port" }, /* IBM3780, ThinkPad */ 359484407Stakawata { 0x81374d24, "IBM PS/2 mouse port" }, /* IBM3781, ThinkPad */ 3595109679Shsu { 0x0190d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9001, Vaio */ 3596109679Shsu { 0x0290d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9002, Vaio */ 3597109710Smarcel { 0x0390d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9003, Vaio */ 3598109679Shsu { 0x0490d94d, "SONY VAIO PS/2 mouse port"}, /* SNY9004, Vaio */ 359983147Syokota { 0 } 360083147Syokota}; 360183147Syokota 360283147Syokotastatic int 360383147Syokotacreate_a_copy(device_t atkbdc, device_t me) 360483147Syokota{ 360583147Syokota device_t psm; 360683147Syokota u_long irq; 360783147Syokota 360883931Syokota /* find the PS/2 mouse device instance under the keyboard controller */ 360983931Syokota psm = device_find_child(atkbdc, PSM_DRIVER_NAME, 361083931Syokota device_get_unit(atkbdc)); 361183147Syokota if (psm == NULL) 361283147Syokota return ENXIO; 361383931Syokota if (device_get_state(psm) != DS_NOTPRESENT) 361483931Syokota return 0; 361583147Syokota 361683931Syokota /* move our resource to the found device */ 361783931Syokota irq = bus_get_resource_start(me, SYS_RES_IRQ, 0); 361883147Syokota bus_set_resource(psm, SYS_RES_IRQ, KBDC_RID_AUX, irq, 1); 361983147Syokota 362083147Syokota /* ...then probe and attach it */ 362183147Syokota return device_probe_and_attach(psm); 362283147Syokota} 362383147Syokota 362483147Syokotastatic int 362583147Syokotapsmcpnp_probe(device_t dev) 362683147Syokota{ 362783931Syokota struct resource *res; 362883931Syokota u_long irq; 362983931Syokota int rid; 363083147Syokota 363183147Syokota if (ISA_PNP_PROBE(device_get_parent(dev), dev, psmcpnp_ids)) 363283147Syokota return ENXIO; 363383147Syokota 363483931Syokota /* 363583931Syokota * The PnP BIOS and ACPI are supposed to assign an IRQ (12) 363683931Syokota * to the PS/2 mouse device node. But, some buggy PnP BIOS 363783931Syokota * declares the PS/2 mouse device node without an IRQ resource! 363883931Syokota * If this happens, we shall refer to device hints. 363983931Syokota * If we still don't find it there, use a hardcoded value... XXX 364083931Syokota */ 364183931Syokota rid = 0; 364283931Syokota irq = bus_get_resource_start(dev, SYS_RES_IRQ, rid); 364383931Syokota if (irq <= 0) { 364483931Syokota if (resource_long_value(PSM_DRIVER_NAME, 364583931Syokota device_get_unit(dev), "irq", &irq) != 0) 364683931Syokota irq = 12; /* XXX */ 364783931Syokota device_printf(dev, "irq resource info is missing; " 364883931Syokota "assuming irq %ld\n", irq); 364983931Syokota bus_set_resource(dev, SYS_RES_IRQ, rid, irq, 1); 365083931Syokota } 3651127135Snjl res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 3652127135Snjl RF_SHAREABLE); 365383931Syokota bus_release_resource(dev, SYS_RES_IRQ, rid, res); 365483147Syokota 365583147Syokota /* keep quiet */ 365683147Syokota if (!bootverbose) 365783147Syokota device_quiet(dev); 365883492Syokota 365983931Syokota return ((res == NULL) ? ENXIO : 0); 366083147Syokota} 366183147Syokota 366283147Syokotastatic int 366383147Syokotapsmcpnp_attach(device_t dev) 366483147Syokota{ 366583492Syokota device_t atkbdc; 366683931Syokota int rid; 366783147Syokota 366883931Syokota /* find the keyboard controller, which may be on acpi* or isa* bus */ 366983931Syokota atkbdc = devclass_get_device(devclass_find(ATKBDC_DRIVER_NAME), 367083931Syokota device_get_unit(dev)); 367183931Syokota if ((atkbdc != NULL) && (device_get_state(atkbdc) == DS_ATTACHED)) { 367283492Syokota create_a_copy(atkbdc, dev); 367383931Syokota } else { 367483931Syokota /* 367583931Syokota * If we don't have the AT keyboard controller yet, 367683931Syokota * just reserve the IRQ for later use... 367783931Syokota * (See psmidentify() above.) 367883931Syokota */ 367983931Syokota rid = 0; 3680127135Snjl bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, RF_SHAREABLE); 368183931Syokota } 368283492Syokota 368383147Syokota return 0; 368483147Syokota} 368583147Syokota 368683147SyokotaDRIVER_MODULE(psmcpnp, isa, psmcpnp_driver, psmcpnp_devclass, 0, 0); 368783147SyokotaDRIVER_MODULE(psmcpnp, acpi, psmcpnp_driver, psmcpnp_devclass, 0, 0); 3688147271Smarius 3689147271Smarius#endif /* DEV_ISA */ 3690