VirtualBox

source: vbox/trunk/src/VBox/Additions/x11/vboxmouse/xorg71/pnp.c@ 20488

Last change on this file since 20488 was 7261, checked in by vboxsync, 17 years ago

Additions/x11: ifdef-ed some unnecessary debug logging in the mouse drivers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 20.0 KB
Line 
1/*
2 * Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Kazutaka YOKOTA not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission. Kazutaka YOKOTA makes no representations
11 * about the suitability of this software for any purpose. It is provided
12 * "as is" without express or implied warranty.
13 *
14 * KAZUTAKA YOKOTA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KAZUTAKA YOKOTA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_CONFIG_H
24#include "config.h"
25#endif
26
27#define NEED_EVENTS
28#include <stdio.h>
29#include <X11/X.h>
30#include <X11/Xproto.h>
31#include "inputstr.h"
32#include "scrnintstr.h"
33#include "xf86.h"
34#include "xf86Priv.h"
35#include "xf86Xinput.h"
36#include "xf86_OSproc.h"
37#include "xf86OSmouse.h"
38#include "mouse.h"
39#include "mousePriv.h"
40
41#ifdef MOUSEINITDEBUG
42# define DEBUG
43# define EXTMOUSEDEBUG
44#endif
45
46#ifdef VBOX
47/* Xorg 7.1 does not include xf86_ansic.h anymore. Don't reinclude this
48 * file as it renamed ANSI C functions to xf86*. */
49extern void usleep(unsigned long);
50extern int strncmp(const char*,const char*,size_t);
51#endif
52
53/* serial PnP ID string */
54typedef struct {
55 int revision; /* PnP revision, 100 for 1.00 */
56 char *eisaid; /* EISA ID including mfr ID and product ID */
57 char *serial; /* serial No, optional */
58 char *class; /* device class, optional */
59 char *compat; /* list of compatible drivers, optional */
60 char *description; /* product description, optional */
61 int neisaid; /* length of the above fields... */
62 int nserial;
63 int nclass;
64 int ncompat;
65 int ndescription;
66} pnpid_t;
67
68/* symbol table entry */
69typedef struct {
70 char *name;
71 MouseProtocolID val;
72} symtab_t;
73
74/* PnP EISA/product IDs */
75static symtab_t pnpprod[] = {
76 { "KML0001", PROT_THINKING }, /* Kensignton ThinkingMouse */
77 { "MSH0001", PROT_IMSERIAL }, /* MS IntelliMouse */
78 { "MSH0004", PROT_IMSERIAL }, /* MS IntelliMouse TrackBall */
79 { "KYEEZ00", PROT_MS }, /* Genius EZScroll */
80 { "KYE0001", PROT_MS }, /* Genius PnP Mouse */
81 { "KYE0002", PROT_MS }, /* MouseSystem (Genius?) SmartScroll */
82 { "KYE0003", PROT_IMSERIAL }, /* Genius NetMouse */
83 { "LGI800C", PROT_IMSERIAL }, /* Logitech MouseMan (4 button model) */
84 { "LGI8033", PROT_IMSERIAL }, /* Logitech Cordless MouseMan Wheel */
85 { "LGI8050", PROT_IMSERIAL }, /* Logitech MouseMan+ */
86 { "LGI8051", PROT_IMSERIAL }, /* Logitech FirstMouse+ */
87 { "LGI8001", PROT_LOGIMAN }, /* Logitech serial */
88 { "A4W0005", PROT_IMSERIAL }, /* A4 Tech 4D/4D+ Mouse */
89 { "PEC9802", PROT_IMSERIAL }, /* 8D Scroll Mouse */
90
91 { "PNP0F00", PROT_BM }, /* MS bus */
92 { "PNP0F01", PROT_MS }, /* MS serial */
93 { "PNP0F02", PROT_BM }, /* MS InPort */
94 { "PNP0F03", PROT_PS2 }, /* MS PS/2 */
95 /*
96 * EzScroll returns PNP0F04 in the compatible device field; but it
97 * doesn't look compatible... XXX
98 */
99 { "PNP0F04", PROT_MSC }, /* MouseSystems */
100 { "PNP0F05", PROT_MSC }, /* MouseSystems */
101#ifdef notyet
102 { "PNP0F06", PROT_??? }, /* Genius Mouse */
103 { "PNP0F07", PROT_??? }, /* Genius Mouse */
104#endif
105 { "PNP0F08", PROT_LOGIMAN }, /* Logitech serial */
106 { "PNP0F09", PROT_MS }, /* MS BallPoint serial */
107 { "PNP0F0A", PROT_MS }, /* MS PnP serial */
108 { "PNP0F0B", PROT_MS }, /* MS PnP BallPoint serial */
109 { "PNP0F0C", PROT_MS }, /* MS serial comatible */
110 { "PNP0F0D", PROT_BM }, /* MS InPort comatible */
111 { "PNP0F0E", PROT_PS2 }, /* MS PS/2 comatible */
112 { "PNP0F0F", PROT_MS }, /* MS BallPoint comatible */
113#ifdef notyet
114 { "PNP0F10", PROT_??? }, /* TI QuickPort */
115#endif
116 { "PNP0F11", PROT_BM }, /* MS bus comatible */
117 { "PNP0F12", PROT_PS2 }, /* Logitech PS/2 */
118 { "PNP0F13", PROT_PS2 }, /* PS/2 */
119#ifdef notyet
120 { "PNP0F14", PROT_??? }, /* MS Kids Mouse */
121#endif
122 { "PNP0F15", PROT_BM }, /* Logitech bus */
123#ifdef notyet
124 { "PNP0F16", PROT_??? }, /* Logitech SWIFT */
125#endif
126 { "PNP0F17", PROT_LOGIMAN }, /* Logitech serial compat */
127 { "PNP0F18", PROT_BM }, /* Logitech bus compatible */
128 { "PNP0F19", PROT_PS2 }, /* Logitech PS/2 compatible */
129#ifdef notyet
130 { "PNP0F1A", PROT_??? }, /* Logitech SWIFT compatible */
131 { "PNP0F1B", PROT_??? }, /* HP Omnibook */
132 { "PNP0F1C", PROT_??? }, /* Compaq LTE TrackBall PS/2 */
133 { "PNP0F1D", PROT_??? }, /* Compaq LTE TrackBall serial */
134 { "PNP0F1E", PROT_??? }, /* MS Kids Trackball */
135#endif
136 { NULL, PROT_UNKNOWN },
137};
138
139static const char *pnpSerial[] = {
140 "BaudRate", "1200",
141 "DataBits", "7",
142 "StopBits", "1",
143 "Parity", "None",
144 "FlowControl", "None",
145 "VTime", "0",
146 "VMin", "1",
147 NULL
148};
149
150static int pnpgets(InputInfoPtr, char *, Bool *prePNP);
151static int pnpparse(InputInfoPtr, pnpid_t *, char *, int);
152static MouseProtocolID prepnpparse(InputInfoPtr pInfo, char *buf);
153static symtab_t *pnpproto(pnpid_t *);
154static symtab_t *gettoken(symtab_t *, char *, int);
155static MouseProtocolID getPs2ProtocolPnP(InputInfoPtr pInfo);
156static MouseProtocolID probePs2ProtocolPnP(InputInfoPtr pInfo);
157
158static MouseProtocolID
159MouseGetSerialPnpProtocol(InputInfoPtr pInfo)
160{
161 char buf[256]; /* PnP ID string may be up to 256 bytes long */
162 pnpid_t pnpid;
163 symtab_t *t;
164 int len;
165 Bool prePNP;
166
167 if ((len = pnpgets(pInfo, buf, &prePNP)) > 0)
168 {
169 if (!prePNP) {
170 if (pnpparse(pInfo, &pnpid, buf, len) &&
171 (t = pnpproto(&pnpid)) != NULL) {
172 xf86MsgVerb(X_INFO, 2, "%s: PnP-detected protocol ID: %d\n",
173 pInfo->name, t->val);
174 return (t->val);
175 }
176 } else
177 return prepnpparse(pInfo,buf);
178 }
179 return PROT_UNKNOWN;
180}
181
182MouseProtocolID
183MouseGetPnpProtocol(InputInfoPtr pInfo)
184{
185 MouseDevPtr pMse = pInfo->private;
186 mousePrivPtr mPriv = (mousePrivPtr)pMse->mousePriv;
187 MouseProtocolID val;
188 CARD32 last;
189
190 if ((val = MouseGetSerialPnpProtocol(pInfo)) != PROT_UNKNOWN) {
191 if (val == MouseGetSerialPnpProtocol(pInfo))
192 return val;
193 }
194
195#if 1
196 last = mPriv->pnpLast;
197 mPriv->pnpLast = currentTime.milliseconds;
198
199 if (last) {
200 if (last - currentTime.milliseconds < 100
201 || (mPriv->disablePnPauto
202 && (last - currentTime.milliseconds < 10000))) {
203#ifdef EXTMOUSEDEBUG
204 xf86ErrorF("Mouse: Disabling PnP\n");
205#endif
206 mPriv->disablePnPauto = TRUE;
207 return PROT_UNKNOWN;
208 }
209 }
210
211#ifdef EXTMOUSEDEBUG
212 if (mPriv->disablePnPauto)
213 xf86ErrorF("Mouse: Enabling PnP\n");
214#endif
215 mPriv->disablePnPauto = FALSE;
216
217 if (mPriv->soft)
218 return getPs2ProtocolPnP(pInfo);
219 else
220 return probePs2ProtocolPnP(pInfo);
221#else
222 return PROT_UNKNOWN;
223#endif
224}
225
226/*
227 * Try to elicit a PnP ID as described in
228 * Microsoft, Hayes: "Plug and Play External COM Device Specification,
229 * rev 1.00", 1995.
230 *
231 * The routine does not fully implement the COM Enumerator as per Section
232 * 2.1 of the document. In particular, we don't have idle state in which
233 * the driver software monitors the com port for dynamic connection or
234 * removal of a device at the port, because `moused' simply quits if no
235 * device is found.
236 *
237 * In addition, as PnP COM device enumeration procedure slightly has
238 * changed since its first publication, devices which follow earlier
239 * revisions of the above spec. may fail to respond if the rev 1.0
240 * procedure is used. XXX
241 */
242static int
243pnpgets(InputInfoPtr pInfo, char *buf, Bool *prePNP)
244{
245 int i;
246 char c;
247 pointer pnpOpts;
248
249#if 0
250 /*
251 * This is the procedure described in rev 1.0 of PnP COM device spec.
252 * Unfortunately, some devices which comform to earlier revisions of
253 * the spec gets confused and do not return the ID string...
254 */
255
256 /* port initialization (2.1.2) */
257 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1)
258 return 0;
259 i |= XF86_M_DTR; /* DTR = 1 */
260 i &= ~XF86_M_RTS; /* RTS = 0 */
261 if (xf86SetSerialModemState(pInfo->fd, i) == -1)
262 goto disconnect_idle;
263 usleep(200000);
264 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1 ||
265 (i & XF86_M_DSR) == 0)
266 goto disconnect_idle;
267
268 /* port setup, 1st phase (2.1.3) */
269 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1);
270 xf86SetSerial(pInfo->fd, pnpOpts);
271 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
272 xf86SerialModemClearBits(pInfo->fd, i);
273 usleep(200000);
274 i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
275 xf86SerialModemSetBits(pInfo->fd, i);
276 usleep(200000);
277
278 /* wait for response, 1st phase (2.1.4) */
279 xf86FlushInput(pInfo->fd);
280 i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
281 xf86SerialModemSetBits(pInfo->fd, i);
282
283 /* try to read something */
284 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) {
285
286 /* port setup, 2nd phase (2.1.5) */
287 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
288 xf86SerialModemClearBits(pInfo->fd, i);
289 usleep(200000);
290
291 /* wait for respose, 2nd phase (2.1.6) */
292 xf86FlushInput(pInfo->fd);
293 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
294 xf86SerialModemSetBits(pInfo->fd, i);
295
296 /* try to read something */
297 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
298 goto connect_idle;
299 }
300#else
301 /*
302 * This is a simplified procedure; it simply toggles RTS.
303 */
304
305 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1)
306 return 0;
307 i |= XF86_M_DTR; /* DTR = 1 */
308 i &= ~XF86_M_RTS; /* RTS = 0 */
309 if (xf86SetSerialModemState(pInfo->fd, i) == -1)
310 goto disconnect_idle;
311 usleep(200000);
312
313 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1);
314 xf86SetSerial(pInfo->fd, pnpOpts);
315
316 /* wait for respose */
317 xf86FlushInput(pInfo->fd);
318 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */
319 xf86SerialModemSetBits(pInfo->fd, i);
320
321 /* try to read something */
322 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
323 goto connect_idle;
324#endif
325
326 /* collect PnP COM device ID (2.1.7) */
327 i = 0;
328 *prePNP = FALSE;
329
330 usleep(200000); /* the mouse must send `Begin ID' within 200msec */
331 while (xf86ReadSerial(pInfo->fd, &c, 1) == 1) {
332 /* we may see "M", or "M3..." before `Begin ID' */
333 if (c == 'M')
334 *prePNP = TRUE;
335
336 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
337 *prePNP = FALSE;
338 buf[0] = c;
339 i = 1;
340 break;
341 }
342 if (*prePNP)
343 buf[i++] = c;
344
345 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
346 break;
347 }
348 if (i <= 0) {
349 /* we haven't seen `Begin ID' in time... */
350 goto connect_idle;
351 }
352 if (*prePNP)
353 return i;
354
355 ++c; /* make it `End ID' */
356 for (;;) {
357 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
358 break;
359
360 xf86ReadSerial(pInfo->fd, &buf[i], 1);
361 if (buf[i++] == c) /* End ID */
362 break;
363 if (i >= 256)
364 break;
365 }
366 if (buf[i - 1] != c)
367 goto connect_idle;
368 return i;
369
370 /*
371 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
372 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
373 * assuming there is something at the port even if it didn't
374 * respond to the PnP enumeration procedure.
375 */
376disconnect_idle:
377 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */
378 xf86SerialModemSetBits(pInfo->fd, i);
379connect_idle:
380 return 0;
381}
382
383static int
384pnpparse(InputInfoPtr pInfo, pnpid_t *id, char *buf, int len)
385{
386 char s[3];
387 int offset;
388 int sum = 0;
389 int i, j;
390
391 id->revision = 0;
392 id->eisaid = NULL;
393 id->serial = NULL;
394 id->class = NULL;
395 id->compat = NULL;
396 id->description = NULL;
397 id->neisaid = 0;
398 id->nserial = 0;
399 id->nclass = 0;
400 id->ncompat = 0;
401 id->ndescription = 0;
402
403 offset = 0x28 - buf[0];
404
405 /* calculate checksum */
406 for (i = 0; i < len - 3; ++i) {
407 sum += buf[i];
408 buf[i] += offset;
409 }
410 sum += buf[len - 1];
411 for (; i < len; ++i)
412 buf[i] += offset;
413 xf86MsgVerb(X_INFO, 2, "%s: PnP ID string: `%*.*s'\n", pInfo->name,
414 len, len, buf);
415
416 /* revision */
417 buf[1] -= offset;
418 buf[2] -= offset;
419 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
420 xf86MsgVerb(X_INFO, 2, "%s: PnP rev %d.%02d\n", pInfo->name,
421 id->revision / 100, id->revision % 100);
422
423 /* EISA vender and product ID */
424 id->eisaid = &buf[3];
425 id->neisaid = 7;
426
427 /* option strings */
428 i = 10;
429 if (buf[i] == '\\') {
430 /* device serial # */
431 for (j = ++i; i < len; ++i) {
432 if (buf[i] == '\\')
433 break;
434 }
435 if (i >= len)
436 i -= 3;
437 if (i - j == 8) {
438 id->serial = &buf[j];
439 id->nserial = 8;
440 }
441 }
442 if (buf[i] == '\\') {
443 /* PnP class */
444 for (j = ++i; i < len; ++i) {
445 if (buf[i] == '\\')
446 break;
447 }
448 if (i >= len)
449 i -= 3;
450 if (i > j + 1) {
451 id->class = &buf[j];
452 id->nclass = i - j;
453 }
454 }
455 if (buf[i] == '\\') {
456 /* compatible driver */
457 for (j = ++i; i < len; ++i) {
458 if (buf[i] == '\\')
459 break;
460 }
461 /*
462 * PnP COM spec prior to v0.96 allowed '*' in this field,
463 * it's not allowed now; just ignore it.
464 */
465 if (buf[j] == '*')
466 ++j;
467 if (i >= len)
468 i -= 3;
469 if (i > j + 1) {
470 id->compat = &buf[j];
471 id->ncompat = i - j;
472 }
473 }
474 if (buf[i] == '\\') {
475 /* product description */
476 for (j = ++i; i < len; ++i) {
477 if (buf[i] == ';')
478 break;
479 }
480 if (i >= len)
481 i -= 3;
482 if (i > j + 1) {
483 id->description = &buf[j];
484 id->ndescription = i - j;
485 }
486 }
487
488 /* checksum exists if there are any optional fields */
489 if ((id->nserial > 0) || (id->nclass > 0)
490 || (id->ncompat > 0) || (id->ndescription > 0)) {
491 xf86MsgVerb(X_INFO, 4, "%s: PnP checksum: 0x%02X\n", pInfo->name, sum);
492 sprintf(s, "%02X", sum & 0x0ff);
493 if (strncmp(s, &buf[len - 3], 2) != 0) {
494#if 0
495 /*
496 * Checksum error!!
497 * I found some mice do not comply with the PnP COM device
498 * spec regarding checksum... XXX
499 */
500 return FALSE;
501#endif
502 }
503 }
504
505 return TRUE;
506}
507
508/* We can only identify MS at the moment */
509static MouseProtocolID
510prepnpparse(InputInfoPtr pInfo, char *buf)
511{
512 if (buf[0] == 'M' && buf[1] == '3')
513 return PROT_MS;
514 return PROT_UNKNOWN;
515}
516
517
518static symtab_t *
519pnpproto(pnpid_t *id)
520{
521 symtab_t *t;
522 int i, j;
523
524 if (id->nclass > 0)
525 if (strncmp(id->class, "MOUSE", id->nclass) != 0)
526 /* this is not a mouse! */
527 return NULL;
528
529 if (id->neisaid > 0) {
530 t = gettoken(pnpprod, id->eisaid, id->neisaid);
531 if (t->val != -1)
532 return t;
533 }
534
535 /*
536 * The 'Compatible drivers' field may contain more than one
537 * ID separated by ','.
538 */
539 if (id->ncompat <= 0)
540 return NULL;
541 for (i = 0; i < id->ncompat; ++i) {
542 for (j = i; id->compat[i] != ','; ++i)
543 if (i >= id->ncompat)
544 break;
545 if (i > j) {
546 t = gettoken(pnpprod, id->compat + j, i - j);
547 if (t->val != -1)
548 return t;
549 }
550 }
551
552 return NULL;
553}
554
555/* name/val mapping */
556
557static symtab_t *
558gettoken(tab, s, len)
559symtab_t *tab;
560char *s;
561int len;
562{
563 int i;
564
565 for (i = 0; tab[i].name != NULL; ++i) {
566 if (strncmp(tab[i].name, s, len) == 0)
567 break;
568 }
569 return &tab[i];
570}
571
572/******************* PS/2 PnP probing ****************/
573
574static int
575readMouse(InputInfoPtr pInfo, unsigned char *u)
576{
577
578 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
579 return FALSE;
580
581 xf86ReadSerial(pInfo->fd, u, 1);
582 return TRUE;
583}
584
585static void
586ps2DisableWrapMode(InputInfoPtr pInfo)
587{
588 unsigned char reset_wrap_mode[] = { 0xEC };
589 ps2SendPacket(pInfo, reset_wrap_mode, sizeof(reset_wrap_mode));
590}
591
592Bool
593ps2SendPacket(InputInfoPtr pInfo, unsigned char *bytes, int len)
594{
595 unsigned char c;
596 int i,j;
597
598#ifdef MOUSE_DEBUG
599 xf86ErrorF("Ps/2 data package:");
600 for (i = 0; i < len; i++)
601 xf86ErrorF(" %x", *(bytes + i));
602 xf86ErrorF("\n");
603#endif
604
605 for (i = 0; i < len; i++) {
606 for (j = 0; j < 10; j++) {
607 xf86WriteSerial(pInfo->fd, bytes + i, 1);
608 usleep(10000);
609 if (!readMouse(pInfo,&c)) {
610#ifdef MOUSE_DEBUG
611 xf86ErrorF("sending 0x%x to PS/2 unsuccessful\n",*(bytes + i));
612#endif
613 return FALSE;
614 }
615#ifdef MOUSE_DEBUG
616 xf86ErrorF("Recieved: 0x%x\n",c);
617#endif
618 if (c == 0xFA) /* ACK */
619 break;
620
621 if (c == 0xFE) /* resend */
622 continue;
623
624
625 if (c == 0xFC) /* error */
626 return FALSE;
627
628 /* Some mice accidently enter wrap mode during init */
629 if (c == *(bytes + i) /* wrap mode */
630 && (*(bytes + i) != 0xEC)) /* avoid recursion */
631 ps2DisableWrapMode(pInfo);
632
633 return FALSE;
634 }
635 if (j == 10)
636 return FALSE;
637 }
638
639 return TRUE;
640}
641
642static Bool
643ps2DisableDataReporting(InputInfoPtr pInfo)
644{
645 unsigned char packet[] = { 0xF5 };
646 return ps2SendPacket(pInfo, packet, sizeof(packet));
647}
648
649Bool
650ps2EnableDataReporting(InputInfoPtr pInfo)
651{
652 unsigned char packet[] = { 0xF4 };
653 return ps2SendPacket(pInfo, packet, sizeof(packet));
654}
655
656int
657ps2GetDeviceID(InputInfoPtr pInfo)
658{
659 unsigned char u;
660 unsigned char packet[] = { 0xf2 };
661
662 usleep(30000);
663 xf86FlushInput(pInfo->fd);
664 if (!ps2SendPacket(pInfo, packet, sizeof(packet)))
665 return -1;
666 while (1) {
667 if (!readMouse(pInfo,&u))
668 return -1;
669 if (u != 0xFA)
670 break;
671 }
672#ifdef MOUSE_DEBUG
673 xf86ErrorF("Obtained Mouse Type: %x\n",u);
674#endif
675 return (int) u;
676}
677
678Bool
679ps2Reset(InputInfoPtr pInfo)
680{
681 unsigned char u;
682 unsigned char packet[] = { 0xff };
683 unsigned char reply[] = { 0xaa, 0x00 };
684 unsigned int i;
685#ifdef MOUSE_DEBUG
686 xf86ErrorF("PS/2 Mouse reset\n");
687#endif
688 if (!ps2SendPacket(pInfo, packet, sizeof(packet)))
689 return FALSE;
690 /* we need a little delay here */
691 xf86WaitForInput(pInfo->fd, 500000);
692 for (i = 0; i < sizeof(reply) ; i++) {
693 if (!readMouse(pInfo,&u)) {
694 goto EXIT;
695 }
696 if (u != reply[i])
697 goto EXIT;
698 }
699 return TRUE;
700
701 EXIT:
702 xf86FlushInput(pInfo->fd);
703 return FALSE;
704}
705
706static MouseProtocolID
707probePs2ProtocolPnP(InputInfoPtr pInfo)
708{
709 unsigned char u;
710 MouseProtocolID ret = PROT_UNKNOWN;
711
712 xf86FlushInput(pInfo->fd);
713
714 ps2DisableDataReporting(pInfo);
715
716 if (ps2Reset(pInfo)) { /* Reset PS2 device */
717 unsigned char seq[] = { 243, 200, 243, 100, 243, 80 };
718 /* Try to identify Intelli Mouse */
719 if (ps2SendPacket(pInfo, seq, sizeof(seq))) {
720 u = ps2GetDeviceID(pInfo);
721 if (u == 0x03) {
722 /* found IntelliMouse now try IntelliExplorer */
723 unsigned char seq[] = { 243, 200, 243, 200, 243, 80 };
724 if (ps2SendPacket(pInfo,seq,sizeof(seq))) {
725 u = ps2GetDeviceID(pInfo);
726 if (u == 0x04)
727 ret = PROT_EXPPS2;
728 else
729 ret = PROT_IMPS2;
730 }
731 } else if (ps2Reset(pInfo)) /* reset again to find sane state */
732 ret = PROT_PS2;
733 }
734
735 if (ret != PROT_UNKNOWN)
736 ps2EnableDataReporting(pInfo);
737 }
738 return ret;
739}
740
741static struct ps2protos {
742 int Id;
743 MouseProtocolID protoID;
744} ps2 [] = {
745 { 0x0, PROT_PS2 },
746 { 0x3, PROT_IMPS2 },
747 { 0x4, PROT_EXPPS2 },
748 { -1 , PROT_UNKNOWN }
749};
750
751
752static MouseProtocolID
753getPs2ProtocolPnP(InputInfoPtr pInfo)
754{
755 int Id;
756 int i;
757 MouseProtocolID proto;
758 int count = 4;
759
760 xf86FlushInput(pInfo->fd);
761
762 while (--count)
763 if (ps2DisableDataReporting(pInfo))
764 break;
765
766 if (!count) {
767 proto = PROT_UNKNOWN;
768 goto EXIT;
769 }
770
771 if ((Id = ps2GetDeviceID(pInfo)) == -1) {
772 proto = PROT_UNKNOWN;
773 goto EXIT;
774 }
775
776 if (-1 == ps2EnableDataReporting(pInfo)) {
777 proto = PROT_UNKNOWN;
778 goto EXIT;
779 }
780
781 for (i = 0; ps2[i].protoID != PROT_UNKNOWN; i++) {
782 if (ps2[i].Id == Id) {
783 xf86MsgVerb(X_PROBED,2,"Found PS/2 proto ID %x\n",Id);
784 proto = ps2[i].protoID;
785 goto EXIT;
786 }
787 }
788
789 proto = PROT_UNKNOWN;
790 xf86Msg(X_ERROR,"Found unknown PS/2 proto ID %x\n",Id);
791
792 EXIT:
793 xf86FlushInput(pInfo->fd);
794 return proto;
795}
796
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette