1706f2543Smrg/* 2706f2543Smrg * Copyright � 2001 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 6706f2543Smrg * the above copyright notice appear in all copies and that both that 7706f2543Smrg * copyright notice and this permission notice appear in supporting 8706f2543Smrg * documentation, and that the name of Keith Packard not be used in 9706f2543Smrg * advertising or publicity pertaining to distribution of the software without 10706f2543Smrg * specific, written prior permission. Keith Packard makes no 11706f2543Smrg * representations about the suitability of this software for any purpose. It 12706f2543Smrg * is provided "as is" without express or implied warranty. 13706f2543Smrg * 14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 21706f2543Smrg */ 22706f2543Smrg 23706f2543Smrg#ifdef HAVE_CONFIG_H 24706f2543Smrg#include <kdrive-config.h> 25706f2543Smrg#endif 26706f2543Smrg#include <errno.h> 27706f2543Smrg#include <termios.h> 28706f2543Smrg#include <X11/X.h> 29706f2543Smrg#include <X11/Xproto.h> 30706f2543Smrg#include <X11/Xpoll.h> 31706f2543Smrg#include "inputstr.h" 32706f2543Smrg#include "scrnintstr.h" 33706f2543Smrg#include "kdrive.h" 34706f2543Smrg 35706f2543Smrg#undef DEBUG 36706f2543Smrg#undef DEBUG_BYTES 37706f2543Smrg#define KBUFIO_SIZE 256 38706f2543Smrg#define MOUSE_TIMEOUT 100 39706f2543Smrg 40706f2543Smrgtypedef struct _kbufio { 41706f2543Smrg int fd; 42706f2543Smrg unsigned char buf[KBUFIO_SIZE]; 43706f2543Smrg int avail; 44706f2543Smrg int used; 45706f2543Smrg} Kbufio; 46706f2543Smrg 47706f2543Smrgstatic Bool 48706f2543SmrgMouseWaitForReadable (int fd, int timeout) 49706f2543Smrg{ 50706f2543Smrg fd_set set; 51706f2543Smrg struct timeval tv, *tp; 52706f2543Smrg int n; 53706f2543Smrg CARD32 done; 54706f2543Smrg 55706f2543Smrg done = GetTimeInMillis () + timeout; 56706f2543Smrg for (;;) 57706f2543Smrg { 58706f2543Smrg FD_ZERO (&set); 59706f2543Smrg FD_SET (fd, &set); 60706f2543Smrg if (timeout == -1) 61706f2543Smrg tp = 0; 62706f2543Smrg else 63706f2543Smrg { 64706f2543Smrg tv.tv_sec = timeout / 1000; 65706f2543Smrg tv.tv_usec = (timeout % 1000) * 1000; 66706f2543Smrg tp = &tv; 67706f2543Smrg } 68706f2543Smrg n = select (fd + 1, &set, 0, 0, tp); 69706f2543Smrg if (n > 0) 70706f2543Smrg return TRUE; 71706f2543Smrg if (n < 0 && (errno == EAGAIN || errno == EINTR)) 72706f2543Smrg { 73706f2543Smrg timeout = (int) (done - GetTimeInMillis ()); 74706f2543Smrg if (timeout > 0) 75706f2543Smrg continue; 76706f2543Smrg } 77706f2543Smrg break; 78706f2543Smrg } 79706f2543Smrg return FALSE; 80706f2543Smrg} 81706f2543Smrg 82706f2543Smrgstatic int 83706f2543SmrgMouseReadByte (Kbufio *b, int timeout) 84706f2543Smrg{ 85706f2543Smrg int n; 86706f2543Smrg if (b->avail <= b->used) 87706f2543Smrg { 88706f2543Smrg if (timeout && !MouseWaitForReadable (b->fd, timeout)) 89706f2543Smrg { 90706f2543Smrg#ifdef DEBUG_BYTES 91706f2543Smrg ErrorF ("\tTimeout %d\n", timeout); 92706f2543Smrg#endif 93706f2543Smrg return -1; 94706f2543Smrg } 95706f2543Smrg n = read (b->fd, b->buf, KBUFIO_SIZE); 96706f2543Smrg if (n <= 0) 97706f2543Smrg return -1; 98706f2543Smrg b->avail = n; 99706f2543Smrg b->used = 0; 100706f2543Smrg } 101706f2543Smrg#ifdef DEBUG_BYTES 102706f2543Smrg ErrorF ("\tget %02x\n", b->buf[b->used]); 103706f2543Smrg#endif 104706f2543Smrg return b->buf[b->used++]; 105706f2543Smrg} 106706f2543Smrg 107706f2543Smrg#if NOTUSED 108706f2543Smrgstatic int 109706f2543SmrgMouseFlush (Kbufio *b, char *buf, int size) 110706f2543Smrg{ 111706f2543Smrg CARD32 now = GetTimeInMillis (); 112706f2543Smrg CARD32 done = now + 100; 113706f2543Smrg int c; 114706f2543Smrg int n = 0; 115706f2543Smrg 116706f2543Smrg while ((c = MouseReadByte (b, done - now)) != -1) 117706f2543Smrg { 118706f2543Smrg if (buf) 119706f2543Smrg { 120706f2543Smrg if (n == size) 121706f2543Smrg { 122706f2543Smrg memmove (buf, buf + 1, size - 1); 123706f2543Smrg n--; 124706f2543Smrg } 125706f2543Smrg buf[n++] = c; 126706f2543Smrg } 127706f2543Smrg now = GetTimeInMillis (); 128706f2543Smrg if ((INT32) (now - done) >= 0) 129706f2543Smrg break; 130706f2543Smrg } 131706f2543Smrg return n; 132706f2543Smrg} 133706f2543Smrg 134706f2543Smrgstatic int 135706f2543SmrgMousePeekByte (Kbufio *b, int timeout) 136706f2543Smrg{ 137706f2543Smrg int c; 138706f2543Smrg 139706f2543Smrg c = MouseReadByte (b, timeout); 140706f2543Smrg if (c != -1) 141706f2543Smrg --b->used; 142706f2543Smrg return c; 143706f2543Smrg} 144706f2543Smrg#endif /* NOTUSED */ 145706f2543Smrg 146706f2543Smrgstatic Bool 147706f2543SmrgMouseWaitForWritable (int fd, int timeout) 148706f2543Smrg{ 149706f2543Smrg fd_set set; 150706f2543Smrg struct timeval tv, *tp; 151706f2543Smrg int n; 152706f2543Smrg 153706f2543Smrg FD_ZERO (&set); 154706f2543Smrg FD_SET (fd, &set); 155706f2543Smrg if (timeout == -1) 156706f2543Smrg tp = 0; 157706f2543Smrg else 158706f2543Smrg { 159706f2543Smrg tv.tv_sec = timeout / 1000; 160706f2543Smrg tv.tv_usec = (timeout % 1000) * 1000; 161706f2543Smrg tp = &tv; 162706f2543Smrg } 163706f2543Smrg n = select (fd + 1, 0, &set, 0, tp); 164706f2543Smrg if (n > 0) 165706f2543Smrg return TRUE; 166706f2543Smrg return FALSE; 167706f2543Smrg} 168706f2543Smrg 169706f2543Smrgstatic Bool 170706f2543SmrgMouseWriteByte (int fd, unsigned char c, int timeout) 171706f2543Smrg{ 172706f2543Smrg int ret; 173706f2543Smrg 174706f2543Smrg#ifdef DEBUG_BYTES 175706f2543Smrg ErrorF ("\tput %02x\n", c); 176706f2543Smrg#endif 177706f2543Smrg for (;;) 178706f2543Smrg { 179706f2543Smrg ret = write (fd, &c, 1); 180706f2543Smrg if (ret == 1) 181706f2543Smrg return TRUE; 182706f2543Smrg if (ret == 0) 183706f2543Smrg return FALSE; 184706f2543Smrg if (errno != EWOULDBLOCK) 185706f2543Smrg return FALSE; 186706f2543Smrg if (!MouseWaitForWritable (fd, timeout)) 187706f2543Smrg return FALSE; 188706f2543Smrg } 189706f2543Smrg} 190706f2543Smrg 191706f2543Smrgstatic Bool 192706f2543SmrgMouseWriteBytes (int fd, unsigned char *c, int n, int timeout) 193706f2543Smrg{ 194706f2543Smrg while (n--) 195706f2543Smrg if (!MouseWriteByte (fd, *c++, timeout)) 196706f2543Smrg return FALSE; 197706f2543Smrg return TRUE; 198706f2543Smrg} 199706f2543Smrg 200706f2543Smrg#define MAX_MOUSE 10 /* maximum length of mouse protocol */ 201706f2543Smrg#define MAX_SKIP 16 /* number of error bytes before switching */ 202706f2543Smrg#define MAX_VALID 4 /* number of valid packets before accepting */ 203706f2543Smrg 204706f2543Smrgtypedef struct _kmouseProt { 205706f2543Smrg char *name; 206706f2543Smrg Bool (*Complete) (KdPointerInfo *pi, unsigned char *ev, int ne); 207706f2543Smrg int (*Valid) (KdPointerInfo *pi, unsigned char *ev, int ne); 208706f2543Smrg Bool (*Parse) (KdPointerInfo *pi, unsigned char *ev, int ne); 209706f2543Smrg Bool (*Init) (KdPointerInfo *pi); 210706f2543Smrg unsigned char headerMask, headerValid; 211706f2543Smrg unsigned char dataMask, dataValid; 212706f2543Smrg Bool tty; 213706f2543Smrg unsigned int c_iflag; 214706f2543Smrg unsigned int c_oflag; 215706f2543Smrg unsigned int c_lflag; 216706f2543Smrg unsigned int c_cflag; 217706f2543Smrg unsigned int speed; 218706f2543Smrg unsigned char *init; 219706f2543Smrg unsigned long state; 220706f2543Smrg} KmouseProt; 221706f2543Smrg 222706f2543Smrgtypedef enum _kmouseStage { 223706f2543Smrg MouseBroken, MouseTesting, MouseWorking 224706f2543Smrg} KmouseStage; 225706f2543Smrg 226706f2543Smrgtypedef struct _kmouse { 227706f2543Smrg Kbufio iob; 228706f2543Smrg const KmouseProt *prot; 229706f2543Smrg int i_prot; 230706f2543Smrg KmouseStage stage; /* protocol verification stage */ 231706f2543Smrg Bool tty; /* mouse device is a tty */ 232706f2543Smrg int valid; /* sequential valid events */ 233706f2543Smrg int tested; /* bytes scanned during Testing phase */ 234706f2543Smrg int invalid;/* total invalid bytes for this protocol */ 235706f2543Smrg unsigned long state; /* private per protocol, init to prot->state */ 236706f2543Smrg} Kmouse; 237706f2543Smrg 238706f2543Smrgstatic int mouseValid (KdPointerInfo *pi, unsigned char *ev, int ne) 239706f2543Smrg{ 240706f2543Smrg Kmouse *km = pi->driverPrivate; 241706f2543Smrg const KmouseProt *prot = km->prot; 242706f2543Smrg int i; 243706f2543Smrg 244706f2543Smrg for (i = 0; i < ne; i++) 245706f2543Smrg if ((ev[i] & prot->headerMask) == prot->headerValid) 246706f2543Smrg break; 247706f2543Smrg if (i != 0) 248706f2543Smrg return i; 249706f2543Smrg for (i = 1; i < ne; i++) 250706f2543Smrg if ((ev[i] & prot->dataMask) != prot->dataValid) 251706f2543Smrg return -1; 252706f2543Smrg return 0; 253706f2543Smrg} 254706f2543Smrg 255706f2543Smrgstatic Bool threeComplete (KdPointerInfo *pi, unsigned char *ev, int ne) 256706f2543Smrg{ 257706f2543Smrg return ne == 3; 258706f2543Smrg} 259706f2543Smrg 260706f2543Smrgstatic Bool fourComplete (KdPointerInfo *pi, unsigned char *ev, int ne) 261706f2543Smrg{ 262706f2543Smrg return ne == 4; 263706f2543Smrg} 264706f2543Smrg 265706f2543Smrgstatic Bool fiveComplete (KdPointerInfo *pi, unsigned char *ev, int ne) 266706f2543Smrg{ 267706f2543Smrg return ne == 5; 268706f2543Smrg} 269706f2543Smrg 270706f2543Smrgstatic Bool MouseReasonable (KdPointerInfo *pi, unsigned long flags, int dx, int dy) 271706f2543Smrg{ 272706f2543Smrg Kmouse *km = pi->driverPrivate; 273706f2543Smrg 274706f2543Smrg if (km->stage == MouseWorking) 275706f2543Smrg return TRUE; 276706f2543Smrg if (dx < -50 || dx > 50) 277706f2543Smrg { 278706f2543Smrg#ifdef DEBUG 279706f2543Smrg ErrorF ("Large X %d\n", dx); 280706f2543Smrg#endif 281706f2543Smrg return FALSE; 282706f2543Smrg } 283706f2543Smrg if (dy < -50 || dy > 50) 284706f2543Smrg { 285706f2543Smrg#ifdef DEBUG 286706f2543Smrg ErrorF ("Large Y %d\n", dy); 287706f2543Smrg#endif 288706f2543Smrg return FALSE; 289706f2543Smrg } 290706f2543Smrg return TRUE; 291706f2543Smrg} 292706f2543Smrg 293706f2543Smrg/* 294706f2543Smrg * Standard PS/2 mouse protocol 295706f2543Smrg */ 296706f2543Smrgstatic Bool ps2Parse (KdPointerInfo *pi, unsigned char *ev, int ne) 297706f2543Smrg{ 298706f2543Smrg Kmouse *km = pi->driverPrivate; 299706f2543Smrg int dx, dy, dz; 300706f2543Smrg unsigned long flags; 301706f2543Smrg unsigned long flagsrelease = 0; 302706f2543Smrg 303706f2543Smrg flags = KD_MOUSE_DELTA; 304706f2543Smrg if (ev[0] & 4) 305706f2543Smrg flags |= KD_BUTTON_2; 306706f2543Smrg if (ev[0] & 2) 307706f2543Smrg flags |= KD_BUTTON_3; 308706f2543Smrg if (ev[0] & 1) 309706f2543Smrg flags |= KD_BUTTON_1; 310706f2543Smrg 311706f2543Smrg if (ne > 3) 312706f2543Smrg { 313706f2543Smrg dz = (int) (signed char) ev[3]; 314706f2543Smrg if (dz < 0) 315706f2543Smrg { 316706f2543Smrg flags |= KD_BUTTON_4; 317706f2543Smrg flagsrelease = KD_BUTTON_4; 318706f2543Smrg } 319706f2543Smrg else if (dz > 0) 320706f2543Smrg { 321706f2543Smrg flags |= KD_BUTTON_5; 322706f2543Smrg flagsrelease = KD_BUTTON_5; 323706f2543Smrg } 324706f2543Smrg } 325706f2543Smrg 326706f2543Smrg dx = ev[1]; 327706f2543Smrg if (ev[0] & 0x10) 328706f2543Smrg dx -= 256; 329706f2543Smrg dy = ev[2]; 330706f2543Smrg if (ev[0] & 0x20) 331706f2543Smrg dy -= 256; 332706f2543Smrg dy = -dy; 333706f2543Smrg if (!MouseReasonable (pi, flags, dx, dy)) 334706f2543Smrg return FALSE; 335706f2543Smrg if (km->stage == MouseWorking) 336706f2543Smrg { 337706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 338706f2543Smrg if (flagsrelease) 339706f2543Smrg { 340706f2543Smrg flags &= ~flagsrelease; 341706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 342706f2543Smrg } 343706f2543Smrg } 344706f2543Smrg return TRUE; 345706f2543Smrg} 346706f2543Smrg 347706f2543Smrgstatic Bool ps2Init (KdPointerInfo *pi); 348706f2543Smrg 349706f2543Smrgstatic const KmouseProt ps2Prot = { 350706f2543Smrg "ps/2", 351706f2543Smrg threeComplete, mouseValid, ps2Parse, ps2Init, 352706f2543Smrg 0x08, 0x08, 0x00, 0x00, 353706f2543Smrg FALSE 354706f2543Smrg}; 355706f2543Smrg 356706f2543Smrgstatic const KmouseProt imps2Prot = { 357706f2543Smrg "imps/2", 358706f2543Smrg fourComplete, mouseValid, ps2Parse, ps2Init, 359706f2543Smrg 0x08, 0x08, 0x00, 0x00, 360706f2543Smrg FALSE 361706f2543Smrg}; 362706f2543Smrg 363706f2543Smrgstatic const KmouseProt exps2Prot = { 364706f2543Smrg "exps/2", 365706f2543Smrg fourComplete, mouseValid, ps2Parse, ps2Init, 366706f2543Smrg 0x08, 0x08, 0x00, 0x00, 367706f2543Smrg FALSE 368706f2543Smrg}; 369706f2543Smrg 370706f2543Smrg/* 371706f2543Smrg * Once the mouse is known to speak ps/2 protocol, go and find out 372706f2543Smrg * what advanced capabilities it has and turn them on 373706f2543Smrg */ 374706f2543Smrg 375706f2543Smrg/* these extracted from FreeBSD 4.3 sys/dev/kbd/atkbdcreg.h */ 376706f2543Smrg 377706f2543Smrg/* aux device commands (sent to KBD_DATA_PORT) */ 378706f2543Smrg#define PSMC_SET_SCALING11 0x00e6 379706f2543Smrg#define PSMC_SET_SCALING21 0x00e7 380706f2543Smrg#define PSMC_SET_RESOLUTION 0x00e8 381706f2543Smrg#define PSMC_SEND_DEV_STATUS 0x00e9 382706f2543Smrg#define PSMC_SET_STREAM_MODE 0x00ea 383706f2543Smrg#define PSMC_SEND_DEV_DATA 0x00eb 384706f2543Smrg#define PSMC_SET_REMOTE_MODE 0x00f0 385706f2543Smrg#define PSMC_SEND_DEV_ID 0x00f2 386706f2543Smrg#define PSMC_SET_SAMPLING_RATE 0x00f3 387706f2543Smrg#define PSMC_ENABLE_DEV 0x00f4 388706f2543Smrg#define PSMC_DISABLE_DEV 0x00f5 389706f2543Smrg#define PSMC_SET_DEFAULTS 0x00f6 390706f2543Smrg#define PSMC_RESET_DEV 0x00ff 391706f2543Smrg 392706f2543Smrg/* PSMC_SET_RESOLUTION argument */ 393706f2543Smrg#define PSMD_RES_LOW 0 /* typically 25ppi */ 394706f2543Smrg#define PSMD_RES_MEDIUM_LOW 1 /* typically 50ppi */ 395706f2543Smrg#define PSMD_RES_MEDIUM_HIGH 2 /* typically 100ppi (default) */ 396706f2543Smrg#define PSMD_RES_HIGH 3 /* typically 200ppi */ 397706f2543Smrg#define PSMD_MAX_RESOLUTION PSMD_RES_HIGH 398706f2543Smrg 399706f2543Smrg/* PSMC_SET_SAMPLING_RATE */ 400706f2543Smrg#define PSMD_MAX_RATE 255 /* FIXME: not sure if it's possible */ 401706f2543Smrg 402706f2543Smrg/* aux device ID */ 403706f2543Smrg#define PSM_MOUSE_ID 0 404706f2543Smrg#define PSM_BALLPOINT_ID 2 405706f2543Smrg#define PSM_INTELLI_ID 3 406706f2543Smrg#define PSM_EXPLORER_ID 4 407706f2543Smrg#define PSM_4DMOUSE_ID 6 408706f2543Smrg#define PSM_4DPLUS_ID 8 409706f2543Smrg 410706f2543Smrgstatic unsigned char ps2_init[] = { 411706f2543Smrg PSMC_ENABLE_DEV, 412706f2543Smrg 0, 413706f2543Smrg}; 414706f2543Smrg 415706f2543Smrg#define NINIT_PS2 1 416706f2543Smrg 417706f2543Smrgstatic unsigned char wheel_3button_init[] = { 418706f2543Smrg PSMC_SET_SAMPLING_RATE, 200, 419706f2543Smrg PSMC_SET_SAMPLING_RATE, 100, 420706f2543Smrg PSMC_SET_SAMPLING_RATE, 80, 421706f2543Smrg PSMC_SEND_DEV_ID, 422706f2543Smrg 0, 423706f2543Smrg}; 424706f2543Smrg 425706f2543Smrg#define NINIT_IMPS2 4 426706f2543Smrg 427706f2543Smrgstatic unsigned char wheel_5button_init[] = { 428706f2543Smrg PSMC_SET_SAMPLING_RATE, 200, 429706f2543Smrg PSMC_SET_SAMPLING_RATE, 100, 430706f2543Smrg PSMC_SET_SAMPLING_RATE, 80, 431706f2543Smrg PSMC_SET_SAMPLING_RATE, 200, 432706f2543Smrg PSMC_SET_SAMPLING_RATE, 200, 433706f2543Smrg PSMC_SET_SAMPLING_RATE, 80, 434706f2543Smrg PSMC_SEND_DEV_ID, 435706f2543Smrg 0 436706f2543Smrg}; 437706f2543Smrg 438706f2543Smrg#define NINIT_EXPS2 7 439706f2543Smrg 440706f2543Smrgstatic unsigned char intelli_init[] = { 441706f2543Smrg PSMC_SET_SAMPLING_RATE, 200, 442706f2543Smrg PSMC_SET_SAMPLING_RATE, 100, 443706f2543Smrg PSMC_SET_SAMPLING_RATE, 80, 444706f2543Smrg 0 445706f2543Smrg}; 446706f2543Smrg 447706f2543Smrg#define NINIT_INTELLI 3 448706f2543Smrg 449706f2543Smrgstatic int 450706f2543Smrgps2SkipInit (KdPointerInfo *pi, int ninit, Bool ret_next) 451706f2543Smrg{ 452706f2543Smrg Kmouse *km = pi->driverPrivate; 453706f2543Smrg int c = -1; 454706f2543Smrg int skipping; 455706f2543Smrg Bool waiting; 456706f2543Smrg 457706f2543Smrg skipping = 0; 458706f2543Smrg waiting = FALSE; 459706f2543Smrg while (ninit || ret_next) 460706f2543Smrg { 461706f2543Smrg c = MouseReadByte (&km->iob, MOUSE_TIMEOUT); 462706f2543Smrg if (c == -1) 463706f2543Smrg break; 464706f2543Smrg /* look for ACK */ 465706f2543Smrg if (c == 0xfa) 466706f2543Smrg { 467706f2543Smrg ninit--; 468706f2543Smrg if (ret_next) 469706f2543Smrg waiting = TRUE; 470706f2543Smrg } 471706f2543Smrg /* look for packet start -- not the response */ 472706f2543Smrg else if ((c & 0x08) == 0x08) 473706f2543Smrg waiting = FALSE; 474706f2543Smrg else if (waiting) 475706f2543Smrg break; 476706f2543Smrg } 477706f2543Smrg return c; 478706f2543Smrg} 479706f2543Smrg 480706f2543Smrgstatic Bool 481706f2543Smrgps2Init (KdPointerInfo *pi) 482706f2543Smrg{ 483706f2543Smrg Kmouse *km = pi->driverPrivate; 484706f2543Smrg int skipping; 485706f2543Smrg Bool waiting; 486706f2543Smrg int id; 487706f2543Smrg unsigned char *init; 488706f2543Smrg int ninit; 489706f2543Smrg 490706f2543Smrg /* Send Intellimouse initialization sequence */ 491706f2543Smrg MouseWriteBytes (km->iob.fd, intelli_init, strlen ((char *) intelli_init), 100); 492706f2543Smrg /* 493706f2543Smrg * Send ID command 494706f2543Smrg */ 495706f2543Smrg if (!MouseWriteByte (km->iob.fd, PSMC_SEND_DEV_ID, 100)) 496706f2543Smrg return FALSE; 497706f2543Smrg skipping = 0; 498706f2543Smrg waiting = FALSE; 499706f2543Smrg id = ps2SkipInit (pi, 0, TRUE); 500706f2543Smrg switch (id) { 501706f2543Smrg case 3: 502706f2543Smrg init = wheel_3button_init; 503706f2543Smrg ninit = NINIT_IMPS2; 504706f2543Smrg km->prot = &imps2Prot; 505706f2543Smrg break; 506706f2543Smrg case 4: 507706f2543Smrg init = wheel_5button_init; 508706f2543Smrg ninit = NINIT_EXPS2; 509706f2543Smrg km->prot = &exps2Prot; 510706f2543Smrg break; 511706f2543Smrg default: 512706f2543Smrg init = ps2_init; 513706f2543Smrg ninit = NINIT_PS2; 514706f2543Smrg km->prot = &ps2Prot; 515706f2543Smrg break; 516706f2543Smrg } 517706f2543Smrg if (init) 518706f2543Smrg MouseWriteBytes (km->iob.fd, init, strlen ((char *) init), 100); 519706f2543Smrg /* 520706f2543Smrg * Flush out the available data to eliminate responses to the 521706f2543Smrg * initialization string. Make sure any partial event is 522706f2543Smrg * skipped 523706f2543Smrg */ 524706f2543Smrg (void) ps2SkipInit (pi, ninit, FALSE); 525706f2543Smrg return TRUE; 526706f2543Smrg} 527706f2543Smrg 528706f2543Smrgstatic Bool busParse (KdPointerInfo *pi, unsigned char *ev, int ne) 529706f2543Smrg{ 530706f2543Smrg Kmouse *km = pi->driverPrivate; 531706f2543Smrg int dx, dy; 532706f2543Smrg unsigned long flags; 533706f2543Smrg 534706f2543Smrg flags = KD_MOUSE_DELTA; 535706f2543Smrg dx = (signed char) ev[1]; 536706f2543Smrg dy = -(signed char) ev[2]; 537706f2543Smrg if ((ev[0] & 4) == 0) 538706f2543Smrg flags |= KD_BUTTON_1; 539706f2543Smrg if ((ev[0] & 2) == 0) 540706f2543Smrg flags |= KD_BUTTON_2; 541706f2543Smrg if ((ev[0] & 1) == 0) 542706f2543Smrg flags |= KD_BUTTON_3; 543706f2543Smrg if (!MouseReasonable (pi, flags, dx, dy)) 544706f2543Smrg return FALSE; 545706f2543Smrg if (km->stage == MouseWorking) 546706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 547706f2543Smrg return TRUE; 548706f2543Smrg} 549706f2543Smrg 550706f2543Smrgstatic const KmouseProt busProt = { 551706f2543Smrg "bus", 552706f2543Smrg threeComplete, mouseValid, busParse, 0, 553706f2543Smrg 0xf8, 0x00, 0x00, 0x00, 554706f2543Smrg FALSE 555706f2543Smrg}; 556706f2543Smrg 557706f2543Smrg/* 558706f2543Smrg * Standard MS serial protocol, three bytes 559706f2543Smrg */ 560706f2543Smrg 561706f2543Smrgstatic Bool msParse (KdPointerInfo *pi, unsigned char *ev, int ne) 562706f2543Smrg{ 563706f2543Smrg Kmouse *km = pi->driverPrivate; 564706f2543Smrg int dx, dy; 565706f2543Smrg unsigned long flags; 566706f2543Smrg 567706f2543Smrg flags = KD_MOUSE_DELTA; 568706f2543Smrg 569706f2543Smrg if (ev[0] & 0x20) 570706f2543Smrg flags |= KD_BUTTON_1; 571706f2543Smrg if (ev[0] & 0x10) 572706f2543Smrg flags |= KD_BUTTON_3; 573706f2543Smrg 574706f2543Smrg dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); 575706f2543Smrg dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); 576706f2543Smrg if (!MouseReasonable (pi, flags, dx, dy)) 577706f2543Smrg return FALSE; 578706f2543Smrg if (km->stage == MouseWorking) 579706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 580706f2543Smrg return TRUE; 581706f2543Smrg} 582706f2543Smrg 583706f2543Smrgstatic const KmouseProt msProt = { 584706f2543Smrg "ms", 585706f2543Smrg threeComplete, mouseValid, msParse, 0, 586706f2543Smrg 0xc0, 0x40, 0xc0, 0x00, 587706f2543Smrg TRUE, 588706f2543Smrg IGNPAR, 589706f2543Smrg 0, 590706f2543Smrg 0, 591706f2543Smrg CS7 | CSTOPB | CREAD | CLOCAL, 592706f2543Smrg B1200, 593706f2543Smrg}; 594706f2543Smrg 595706f2543Smrg/* 596706f2543Smrg * Logitech mice send 3 or 4 bytes, the only way to tell is to look at the 597706f2543Smrg * first byte of a synchronized protocol stream and see if it's got 598706f2543Smrg * any bits turned on that can't occur in that fourth byte 599706f2543Smrg */ 600706f2543Smrgstatic Bool logiComplete (KdPointerInfo *pi, unsigned char *ev, int ne) 601706f2543Smrg{ 602706f2543Smrg Kmouse *km = pi->driverPrivate; 603706f2543Smrg 604706f2543Smrg if ((ev[0] & 0x40) == 0x40) 605706f2543Smrg return ne == 3; 606706f2543Smrg if (km->stage != MouseBroken && (ev[0] & ~0x23) == 0) 607706f2543Smrg return ne == 1; 608706f2543Smrg return FALSE; 609706f2543Smrg} 610706f2543Smrg 611706f2543Smrgstatic int logiValid (KdPointerInfo *pi, unsigned char *ev, int ne) 612706f2543Smrg{ 613706f2543Smrg Kmouse *km = pi->driverPrivate; 614706f2543Smrg const KmouseProt *prot = km->prot; 615706f2543Smrg int i; 616706f2543Smrg 617706f2543Smrg for (i = 0; i < ne; i++) 618706f2543Smrg { 619706f2543Smrg if ((ev[i] & 0x40) == 0x40) 620706f2543Smrg break; 621706f2543Smrg if (km->stage != MouseBroken && (ev[i] & ~0x23) == 0) 622706f2543Smrg break; 623706f2543Smrg } 624706f2543Smrg if (i != 0) 625706f2543Smrg return i; 626706f2543Smrg for (i = 1; i < ne; i++) 627706f2543Smrg if ((ev[i] & prot->dataMask) != prot->dataValid) 628706f2543Smrg return -1; 629706f2543Smrg return 0; 630706f2543Smrg} 631706f2543Smrg 632706f2543Smrgstatic Bool logiParse (KdPointerInfo *pi, unsigned char *ev, int ne) 633706f2543Smrg{ 634706f2543Smrg Kmouse *km = pi->driverPrivate; 635706f2543Smrg int dx, dy; 636706f2543Smrg unsigned long flags; 637706f2543Smrg 638706f2543Smrg flags = KD_MOUSE_DELTA; 639706f2543Smrg 640706f2543Smrg if (ne == 3) 641706f2543Smrg { 642706f2543Smrg if (ev[0] & 0x20) 643706f2543Smrg flags |= KD_BUTTON_1; 644706f2543Smrg if (ev[0] & 0x10) 645706f2543Smrg flags |= KD_BUTTON_3; 646706f2543Smrg 647706f2543Smrg dx = (signed char)(((ev[0] & 0x03) << 6) | (ev[1] & 0x3F)); 648706f2543Smrg dy = (signed char)(((ev[0] & 0x0C) << 4) | (ev[2] & 0x3F)); 649706f2543Smrg flags |= km->state & KD_BUTTON_2; 650706f2543Smrg } 651706f2543Smrg else 652706f2543Smrg { 653706f2543Smrg if (ev[0] & 0x20) 654706f2543Smrg flags |= KD_BUTTON_2; 655706f2543Smrg dx = 0; 656706f2543Smrg dy = 0; 657706f2543Smrg flags |= km->state & (KD_BUTTON_1|KD_BUTTON_3); 658706f2543Smrg } 659706f2543Smrg 660706f2543Smrg if (!MouseReasonable (pi, flags, dx, dy)) 661706f2543Smrg return FALSE; 662706f2543Smrg if (km->stage == MouseWorking) 663706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 664706f2543Smrg return TRUE; 665706f2543Smrg} 666706f2543Smrg 667706f2543Smrgstatic const KmouseProt logiProt = { 668706f2543Smrg "logitech", 669706f2543Smrg logiComplete, logiValid, logiParse, 0, 670706f2543Smrg 0xc0, 0x40, 0xc0, 0x00, 671706f2543Smrg TRUE, 672706f2543Smrg IGNPAR, 673706f2543Smrg 0, 674706f2543Smrg 0, 675706f2543Smrg CS7 | CSTOPB | CREAD | CLOCAL, 676706f2543Smrg B1200, 677706f2543Smrg}; 678706f2543Smrg 679706f2543Smrg/* 680706f2543Smrg * Mouse systems protocol, 5 bytes 681706f2543Smrg */ 682706f2543Smrgstatic Bool mscParse (KdPointerInfo *pi, unsigned char *ev, int ne) 683706f2543Smrg{ 684706f2543Smrg Kmouse *km = pi->driverPrivate; 685706f2543Smrg int dx, dy; 686706f2543Smrg unsigned long flags; 687706f2543Smrg 688706f2543Smrg flags = KD_MOUSE_DELTA; 689706f2543Smrg 690706f2543Smrg if (!(ev[0] & 0x4)) 691706f2543Smrg flags |= KD_BUTTON_1; 692706f2543Smrg if (!(ev[0] & 0x2)) 693706f2543Smrg flags |= KD_BUTTON_2; 694706f2543Smrg if (!(ev[0] & 0x1)) 695706f2543Smrg flags |= KD_BUTTON_3; 696706f2543Smrg dx = (signed char)(ev[1]) + (signed char)(ev[3]); 697706f2543Smrg dy = - ((signed char)(ev[2]) + (signed char)(ev[4])); 698706f2543Smrg 699706f2543Smrg if (!MouseReasonable (pi, flags, dx, dy)) 700706f2543Smrg return FALSE; 701706f2543Smrg if (km->stage == MouseWorking) 702706f2543Smrg KdEnqueuePointerEvent (pi, flags, dx, dy, 0); 703706f2543Smrg return TRUE; 704706f2543Smrg} 705706f2543Smrg 706706f2543Smrgstatic const KmouseProt mscProt = { 707706f2543Smrg "msc", 708706f2543Smrg fiveComplete, mouseValid, mscParse, 0, 709706f2543Smrg 0xf8, 0x80, 0x00, 0x00, 710706f2543Smrg TRUE, 711706f2543Smrg IGNPAR, 712706f2543Smrg 0, 713706f2543Smrg 0, 714706f2543Smrg CS8 | CSTOPB | CREAD | CLOCAL, 715706f2543Smrg B1200, 716706f2543Smrg}; 717706f2543Smrg 718706f2543Smrg/* 719706f2543Smrg * Use logitech before ms -- they're the same except that 720706f2543Smrg * logitech sometimes has a fourth byte 721706f2543Smrg */ 722706f2543Smrgstatic const KmouseProt *kmouseProts[] = { 723706f2543Smrg &ps2Prot, &imps2Prot, &exps2Prot, &busProt, &logiProt, &msProt, &mscProt, 724706f2543Smrg}; 725706f2543Smrg 726706f2543Smrg#define NUM_PROT (sizeof (kmouseProts) / sizeof (kmouseProts[0])) 727706f2543Smrg 728706f2543Smrgstatic void 729706f2543SmrgMouseInitProtocol (Kmouse *km) 730706f2543Smrg{ 731706f2543Smrg int ret; 732706f2543Smrg struct termios t; 733706f2543Smrg 734706f2543Smrg if (km->prot->tty) 735706f2543Smrg { 736706f2543Smrg ret = tcgetattr (km->iob.fd, &t); 737706f2543Smrg 738706f2543Smrg if (ret >= 0) 739706f2543Smrg { 740706f2543Smrg t.c_iflag = km->prot->c_iflag; 741706f2543Smrg t.c_oflag = km->prot->c_oflag; 742706f2543Smrg t.c_lflag = km->prot->c_lflag; 743706f2543Smrg t.c_cflag = km->prot->c_cflag; 744706f2543Smrg cfsetispeed (&t, km->prot->speed); 745706f2543Smrg cfsetospeed (&t, km->prot->speed); 746706f2543Smrg ret = tcsetattr (km->iob.fd, TCSANOW, &t); 747706f2543Smrg } 748706f2543Smrg } 749706f2543Smrg km->stage = MouseBroken; 750706f2543Smrg km->valid = 0; 751706f2543Smrg km->tested = 0; 752706f2543Smrg km->invalid = 0; 753706f2543Smrg km->state = km->prot->state; 754706f2543Smrg} 755706f2543Smrg 756706f2543Smrgstatic void 757706f2543SmrgMouseFirstProtocol (Kmouse *km, char *prot) 758706f2543Smrg{ 759706f2543Smrg if (prot) 760706f2543Smrg { 761706f2543Smrg for (km->i_prot = 0; km->i_prot < NUM_PROT; km->i_prot++) 762706f2543Smrg if (!strcmp (prot, kmouseProts[km->i_prot]->name)) 763706f2543Smrg break; 764706f2543Smrg if (km->i_prot == NUM_PROT) 765706f2543Smrg { 766706f2543Smrg int i; 767706f2543Smrg ErrorF ("Unknown mouse protocol \"%s\". Pick one of:", prot); 768706f2543Smrg for (i = 0; i < NUM_PROT; i++) 769706f2543Smrg ErrorF (" %s", kmouseProts[i]->name); 770706f2543Smrg ErrorF ("\n"); 771706f2543Smrg } 772706f2543Smrg else 773706f2543Smrg { 774706f2543Smrg km->prot = kmouseProts[km->i_prot]; 775706f2543Smrg if (km->tty && !km->prot->tty) 776706f2543Smrg ErrorF ("Mouse device is serial port, protocol %s is not serial protocol\n", 777706f2543Smrg prot); 778706f2543Smrg else if (!km->tty && km->prot->tty) 779706f2543Smrg ErrorF ("Mouse device is not serial port, protocol %s is serial protocol\n", 780706f2543Smrg prot); 781706f2543Smrg } 782706f2543Smrg } 783706f2543Smrg if (!km->prot) 784706f2543Smrg { 785706f2543Smrg for (km->i_prot = 0; kmouseProts[km->i_prot]->tty != km->tty; km->i_prot++) 786706f2543Smrg ; 787706f2543Smrg km->prot = kmouseProts[km->i_prot]; 788706f2543Smrg } 789706f2543Smrg MouseInitProtocol (km); 790706f2543Smrg} 791706f2543Smrg 792706f2543Smrgstatic void 793706f2543SmrgMouseNextProtocol (Kmouse *km) 794706f2543Smrg{ 795706f2543Smrg do 796706f2543Smrg { 797706f2543Smrg if (!km->prot) 798706f2543Smrg km->i_prot = 0; 799706f2543Smrg else 800706f2543Smrg if (++km->i_prot == NUM_PROT) km->i_prot = 0; 801706f2543Smrg km->prot = kmouseProts[km->i_prot]; 802706f2543Smrg } while (km->prot->tty != km->tty); 803706f2543Smrg MouseInitProtocol (km); 804706f2543Smrg ErrorF ("Switching to mouse protocol \"%s\"\n", km->prot->name); 805706f2543Smrg} 806706f2543Smrg 807706f2543Smrgstatic void 808706f2543SmrgMouseRead (int mousePort, void *closure) 809706f2543Smrg{ 810706f2543Smrg KdPointerInfo *pi = closure; 811706f2543Smrg Kmouse *km = pi->driverPrivate; 812706f2543Smrg unsigned char event[MAX_MOUSE]; 813706f2543Smrg int ne; 814706f2543Smrg int c; 815706f2543Smrg int i; 816706f2543Smrg int timeout; 817706f2543Smrg 818706f2543Smrg timeout = 0; 819706f2543Smrg ne = 0; 820706f2543Smrg for(;;) 821706f2543Smrg { 822706f2543Smrg c = MouseReadByte (&km->iob, timeout); 823706f2543Smrg if (c == -1) 824706f2543Smrg { 825706f2543Smrg if (ne) 826706f2543Smrg { 827706f2543Smrg km->invalid += ne + km->tested; 828706f2543Smrg km->valid = 0; 829706f2543Smrg km->tested = 0; 830706f2543Smrg km->stage = MouseBroken; 831706f2543Smrg } 832706f2543Smrg break; 833706f2543Smrg } 834706f2543Smrg event[ne++] = c; 835706f2543Smrg i = (*km->prot->Valid) (pi, event, ne); 836706f2543Smrg if (i != 0) 837706f2543Smrg { 838706f2543Smrg#ifdef DEBUG 839706f2543Smrg ErrorF ("Mouse protocol %s broken %d of %d bytes bad\n", 840706f2543Smrg km->prot->name, i > 0 ? i : ne, ne); 841706f2543Smrg#endif 842706f2543Smrg if (i > 0 && i < ne) 843706f2543Smrg { 844706f2543Smrg ne -= i; 845706f2543Smrg memmove (event, event + i, ne); 846706f2543Smrg } 847706f2543Smrg else 848706f2543Smrg { 849706f2543Smrg i = ne; 850706f2543Smrg ne = 0; 851706f2543Smrg } 852706f2543Smrg km->invalid += i + km->tested; 853706f2543Smrg km->valid = 0; 854706f2543Smrg km->tested = 0; 855706f2543Smrg if (km->stage == MouseWorking) 856706f2543Smrg km->i_prot--; 857706f2543Smrg km->stage = MouseBroken; 858706f2543Smrg if (km->invalid > MAX_SKIP) 859706f2543Smrg { 860706f2543Smrg MouseNextProtocol (km); 861706f2543Smrg ne = 0; 862706f2543Smrg } 863706f2543Smrg timeout = 0; 864706f2543Smrg } 865706f2543Smrg else 866706f2543Smrg { 867706f2543Smrg if ((*km->prot->Complete) (pi, event, ne)) 868706f2543Smrg { 869706f2543Smrg if ((*km->prot->Parse) (pi, event, ne)) 870706f2543Smrg { 871706f2543Smrg switch (km->stage) 872706f2543Smrg { 873706f2543Smrg case MouseBroken: 874706f2543Smrg#ifdef DEBUG 875706f2543Smrg ErrorF ("Mouse protocol %s seems OK\n", 876706f2543Smrg km->prot->name); 877706f2543Smrg#endif 878706f2543Smrg /* do not zero invalid to accumulate invalid bytes */ 879706f2543Smrg km->valid = 0; 880706f2543Smrg km->tested = 0; 881706f2543Smrg km->stage = MouseTesting; 882706f2543Smrg /* fall through ... */ 883706f2543Smrg case MouseTesting: 884706f2543Smrg km->valid++; 885706f2543Smrg km->tested += ne; 886706f2543Smrg if (km->valid > MAX_VALID) 887706f2543Smrg { 888706f2543Smrg#ifdef DEBUG 889706f2543Smrg ErrorF ("Mouse protocol %s working\n", 890706f2543Smrg km->prot->name); 891706f2543Smrg#endif 892706f2543Smrg km->stage = MouseWorking; 893706f2543Smrg km->invalid = 0; 894706f2543Smrg km->tested = 0; 895706f2543Smrg km->valid = 0; 896706f2543Smrg if (km->prot->Init && !(*km->prot->Init) (pi)) 897706f2543Smrg km->stage = MouseBroken; 898706f2543Smrg } 899706f2543Smrg break; 900706f2543Smrg case MouseWorking: 901706f2543Smrg break; 902706f2543Smrg } 903706f2543Smrg } 904706f2543Smrg else 905706f2543Smrg { 906706f2543Smrg km->invalid += ne + km->tested; 907706f2543Smrg km->valid = 0; 908706f2543Smrg km->tested = 0; 909706f2543Smrg km->stage = MouseBroken; 910706f2543Smrg } 911706f2543Smrg ne = 0; 912706f2543Smrg timeout = 0; 913706f2543Smrg } 914706f2543Smrg else 915706f2543Smrg timeout = MOUSE_TIMEOUT; 916706f2543Smrg } 917706f2543Smrg } 918706f2543Smrg} 919706f2543Smrg 920706f2543Smrgint MouseInputType; 921706f2543Smrg 922706f2543Smrgchar *kdefaultMouse[] = { 923706f2543Smrg "/dev/input/mice", 924706f2543Smrg "/dev/mouse", 925706f2543Smrg "/dev/psaux", 926706f2543Smrg "/dev/adbmouse", 927706f2543Smrg "/dev/ttyS0", 928706f2543Smrg "/dev/ttyS1", 929706f2543Smrg}; 930706f2543Smrg 931706f2543Smrg#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0])) 932706f2543Smrg 933706f2543Smrgstatic Status 934706f2543SmrgMouseInit (KdPointerInfo *pi) 935706f2543Smrg{ 936706f2543Smrg int i; 937706f2543Smrg int fd; 938706f2543Smrg Kmouse *km; 939706f2543Smrg 940706f2543Smrg if (!pi) 941706f2543Smrg return BadImplementation; 942706f2543Smrg 943706f2543Smrg if (!pi->path || strcmp(pi->path, "auto") == 0) { 944706f2543Smrg for (i = 0; i < NUM_DEFAULT_MOUSE; i++) { 945706f2543Smrg fd = open (kdefaultMouse[i], 2); 946706f2543Smrg if (fd >= 0) { 947706f2543Smrg pi->path = strdup (kdefaultMouse[i]); 948706f2543Smrg break; 949706f2543Smrg } 950706f2543Smrg } 951706f2543Smrg } 952706f2543Smrg else { 953706f2543Smrg fd = open (pi->path, 2); 954706f2543Smrg } 955706f2543Smrg 956706f2543Smrg if (fd < 0) 957706f2543Smrg return BadMatch; 958706f2543Smrg 959706f2543Smrg close(fd); 960706f2543Smrg 961706f2543Smrg km = (Kmouse *) malloc(sizeof (Kmouse)); 962706f2543Smrg if (km) { 963706f2543Smrg km->iob.avail = km->iob.used = 0; 964706f2543Smrg MouseFirstProtocol(km, pi->protocol ? pi->protocol : "exps/2"); 965706f2543Smrg /* MouseFirstProtocol sets state to MouseBroken for later protocol 966706f2543Smrg * checks. Skip these checks if a protocol was supplied */ 967706f2543Smrg if (pi->protocol) 968706f2543Smrg km->state = MouseWorking; 969706f2543Smrg km->i_prot = 0; 970706f2543Smrg km->tty = isatty (fd); 971706f2543Smrg km->iob.fd = -1; 972706f2543Smrg pi->driverPrivate = km; 973706f2543Smrg } 974706f2543Smrg else { 975706f2543Smrg close (fd); 976706f2543Smrg return BadAlloc; 977706f2543Smrg } 978706f2543Smrg 979706f2543Smrg return Success; 980706f2543Smrg} 981706f2543Smrg 982706f2543Smrgstatic Status 983706f2543SmrgMouseEnable (KdPointerInfo *pi) 984706f2543Smrg{ 985706f2543Smrg Kmouse *km; 986706f2543Smrg 987706f2543Smrg if (!pi || !pi->driverPrivate || !pi->path) 988706f2543Smrg return BadImplementation; 989706f2543Smrg 990706f2543Smrg km = pi->driverPrivate; 991706f2543Smrg 992706f2543Smrg km->iob.fd = open(pi->path, 2); 993706f2543Smrg if (km->iob.fd < 0) 994706f2543Smrg return BadMatch; 995706f2543Smrg 996706f2543Smrg if (!KdRegisterFd (km->iob.fd, MouseRead, pi)) 997706f2543Smrg { 998706f2543Smrg close(km->iob.fd); 999706f2543Smrg return BadAlloc; 1000706f2543Smrg } 1001706f2543Smrg 1002706f2543Smrg return Success; 1003706f2543Smrg} 1004706f2543Smrg 1005706f2543Smrgstatic void 1006706f2543SmrgMouseDisable (KdPointerInfo *pi) 1007706f2543Smrg{ 1008706f2543Smrg Kmouse *km; 1009706f2543Smrg if (!pi || !pi->driverPrivate) 1010706f2543Smrg return; 1011706f2543Smrg 1012706f2543Smrg km = pi->driverPrivate; 1013706f2543Smrg KdUnregisterFd (pi, km->iob.fd, TRUE); 1014706f2543Smrg} 1015706f2543Smrg 1016706f2543Smrgstatic void 1017706f2543SmrgMouseFini (KdPointerInfo *pi) 1018706f2543Smrg{ 1019706f2543Smrg free(pi->driverPrivate); 1020706f2543Smrg pi->driverPrivate = NULL; 1021706f2543Smrg} 1022706f2543Smrg 1023706f2543SmrgKdPointerDriver LinuxMouseDriver = { 1024706f2543Smrg "mouse", 1025706f2543Smrg MouseInit, 1026706f2543Smrg MouseEnable, 1027706f2543Smrg MouseDisable, 1028706f2543Smrg MouseFini, 1029706f2543Smrg NULL, 1030706f2543Smrg}; 1031