VirtualBox

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

Last change on this file since 34575 was 33540, checked in by vboxsync, 14 years ago

*: spelling fixes, thanks Timeless!

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/*
2 * Copyright 1998 by Kazutaka YOKOTA <[email protected]>
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#define NEED_EVENTS
24#include "X.h"
25#include "Xproto.h"
26#include "inputstr.h"
27#include "scrnintstr.h"
28
29#include "xf86.h"
30#include "xf86Priv.h"
31#include "xf86Xinput.h"
32#include "xf86_OSproc.h"
33#include "xf86OSmouse.h"
34#include "xf86_ansic.h"
35#include "mouse.h"
36#include "mousePriv.h"
37
38/* serial PnP ID string */
39typedef struct {
40 int revision; /* PnP revision, 100 for 1.00 */
41 char *eisaid; /* EISA ID including mfr ID and product ID */
42 char *serial; /* serial No, optional */
43 char *class; /* device class, optional */
44 char *compat; /* list of compatible drivers, optional */
45 char *description; /* product description, optional */
46 int neisaid; /* length of the above fields... */
47 int nserial;
48 int nclass;
49 int ncompat;
50 int ndescription;
51} pnpid_t;
52
53/* symbol table entry */
54typedef struct {
55 char *name;
56 int val;
57} symtab_t;
58
59/* PnP EISA/product IDs */
60static symtab_t pnpprod[] = {
61 { "KML0001", PROT_THINKING }, /* Kensington ThinkingMouse */
62 { "MSH0001", PROT_IMSERIAL }, /* MS IntelliMouse */
63 { "MSH0004", PROT_IMSERIAL }, /* MS IntelliMouse TrackBall */
64 { "KYEEZ00", PROT_MS }, /* Genius EZScroll */
65 { "KYE0001", PROT_MS }, /* Genius PnP Mouse */
66 { "KYE0002", PROT_MS }, /* MouseSystem (Genius?) SmartScroll */
67 { "KYE0003", PROT_IMSERIAL }, /* Genius NetMouse */
68 { "LGI800C", PROT_IMSERIAL }, /* Logitech MouseMan (4 button model) */
69 { "LGI8033", PROT_IMSERIAL }, /* Logitech Cordless MouseMan Wheel */
70 { "LGI8050", PROT_IMSERIAL }, /* Logitech MouseMan+ */
71 { "LGI8051", PROT_IMSERIAL }, /* Logitech FirstMouse+ */
72 { "LGI8001", PROT_LOGIMAN }, /* Logitech serial */
73 { "A4W0005", PROT_IMSERIAL }, /* A4 Tech 4D/4D+ Mouse */
74 { "PEC9802", PROT_IMSERIAL }, /* 8D Scroll Mouse */
75
76 { "PNP0F00", PROT_BM }, /* MS bus */
77 { "PNP0F01", PROT_MS }, /* MS serial */
78 { "PNP0F02", PROT_BM }, /* MS InPort */
79 { "PNP0F03", PROT_PS2 }, /* MS PS/2 */
80 /*
81 * EzScroll returns PNP0F04 in the compatible device field; but it
82 * doesn't look compatible... XXX
83 */
84 { "PNP0F04", PROT_MSC }, /* MouseSystems */
85 { "PNP0F05", PROT_MSC }, /* MouseSystems */
86#ifdef notyet
87 { "PNP0F06", PROT_??? }, /* Genius Mouse */
88 { "PNP0F07", PROT_??? }, /* Genius Mouse */
89#endif
90 { "PNP0F08", PROT_LOGIMAN }, /* Logitech serial */
91 { "PNP0F09", PROT_MS }, /* MS BallPoint serial */
92 { "PNP0F0A", PROT_MS }, /* MS PnP serial */
93 { "PNP0F0B", PROT_MS }, /* MS PnP BallPoint serial */
94 { "PNP0F0C", PROT_MS }, /* MS serial compatible */
95 { "PNP0F0D", PROT_BM }, /* MS InPort compatible */
96 { "PNP0F0E", PROT_PS2 }, /* MS PS/2 compatible */
97 { "PNP0F0F", PROT_MS }, /* MS BallPoint compatible */
98#ifdef notyet
99 { "PNP0F10", PROT_??? }, /* TI QuickPort */
100#endif
101 { "PNP0F11", PROT_BM }, /* MS bus compatible */
102 { "PNP0F12", PROT_PS2 }, /* Logitech PS/2 */
103 { "PNP0F13", PROT_PS2 }, /* PS/2 */
104#ifdef notyet
105 { "PNP0F14", PROT_??? }, /* MS Kids Mouse */
106#endif
107 { "PNP0F15", PROT_BM }, /* Logitech bus */
108#ifdef notyet
109 { "PNP0F16", PROT_??? }, /* Logitech SWIFT */
110#endif
111 { "PNP0F17", PROT_LOGIMAN }, /* Logitech serial compat */
112 { "PNP0F18", PROT_BM }, /* Logitech bus compatible */
113 { "PNP0F19", PROT_PS2 }, /* Logitech PS/2 compatible */
114#ifdef notyet
115 { "PNP0F1A", PROT_??? }, /* Logitech SWIFT compatible */
116 { "PNP0F1B", PROT_??? }, /* HP Omnibook */
117 { "PNP0F1C", PROT_??? }, /* Compaq LTE TrackBall PS/2 */
118 { "PNP0F1D", PROT_??? }, /* Compaq LTE TrackBall serial */
119 { "PNP0F1E", PROT_??? }, /* MS Kids Trackball */
120#endif
121 { NULL, -1 },
122};
123
124static const char *pnpSerial[] = {
125 "BaudRate", "1200",
126 "DataBits", "7",
127 "StopBits", "1",
128 "Parity", "None",
129 "FlowControl", "None",
130 "VTime", "0",
131 "VMin", "1",
132 NULL
133};
134
135static int pnpgets(InputInfoPtr, char *);
136static int pnpparse(InputInfoPtr, pnpid_t *, char *, int);
137static symtab_t *pnpproto(pnpid_t *);
138static symtab_t *gettoken(symtab_t *, char *, int);
139
140int
141MouseGetPnpProtocol(InputInfoPtr pInfo)
142{
143 char buf[256]; /* PnP ID string may be up to 256 bytes long */
144 pnpid_t pnpid;
145 symtab_t *t;
146 int len;
147
148 if (((len = pnpgets(pInfo, buf)) <= 0) ||
149 !pnpparse(pInfo, &pnpid, buf, len))
150 return PROT_UNKNOWN;
151 if ((t = pnpproto(&pnpid)) == NULL)
152 return PROT_UNKNOWN;
153 xf86MsgVerb(X_INFO, 2, "%s: PnP-detected protocol ID: %d\n",
154 pInfo->name, t->val);
155 return (t->val);
156}
157
158/*
159 * Try to elicit a PnP ID as described in
160 * Microsoft, Hayes: "Plug and Play External COM Device Specification,
161 * rev 1.00", 1995.
162 *
163 * The routine does not fully implement the COM Enumerator as per Section
164 * 2.1 of the document. In particular, we don't have idle state in which
165 * the driver software monitors the com port for dynamic connection or
166 * removal of a device at the port, because `moused' simply quits if no
167 * device is found.
168 *
169 * In addition, as PnP COM device enumeration procedure slightly has
170 * changed since its first publication, devices which follow earlier
171 * revisions of the above spec. may fail to respond if the rev 1.0
172 * procedure is used. XXX
173 */
174static int
175pnpgets(InputInfoPtr pInfo, char *buf)
176{
177 int i;
178 char c;
179 pointer pnpOpts;
180
181#if 0
182 /*
183 * This is the procedure described in rev 1.0 of PnP COM device spec.
184 * Unfortunately, some devices which comform to earlier revisions of
185 * the spec gets confused and do not return the ID string...
186 */
187
188 /* port initialization (2.1.2) */
189 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1)
190 return 0;
191 i |= XF86_M_DTR; /* DTR = 1 */
192 i &= ~XF86_M_RTS; /* RTS = 0 */
193 if (xf86SetSerialModemState(pInfo->fd, i) == -1)
194 goto disconnect_idle;
195 usleep(200000);
196 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1 ||
197 (i & XF86_M_DSR) == 0)
198 goto disconnect_idle;
199
200 /* port setup, 1st phase (2.1.3) */
201 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1);
202 xf86SetSerial(pInfo->fd, pnpOpts);
203 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
204 xf86SerialModemClearBits(pInfo->fd, i);
205 usleep(200000);
206 i = TIOCM_DTR; /* DTR = 1, RTS = 0 */
207 xf86SerialModemSetBits(pInfo->fd, i);
208 usleep(200000);
209
210 /* wait for response, 1st phase (2.1.4) */
211 xf86FlushInput(pInfo->fd);
212 i = TIOCM_RTS; /* DTR = 1, RTS = 1 */
213 xf86SerialModemSetBits(pInfo->fd, i);
214
215 /* try to read something */
216 if (xf86WaitForInput(pInfo->fd, 200000) <= 0) {
217
218 /* port setup, 2nd phase (2.1.5) */
219 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 0, RTS = 0 */
220 xf86SerialModemClearBits(pInfo->fd, i);
221 usleep(200000);
222
223 /* wait for response, 2nd phase (2.1.6) */
224 xf86FlushInput(pInfo->fd);
225 i = TIOCM_DTR | TIOCM_RTS; /* DTR = 1, RTS = 1 */
226 xf86SerialModemSetBits(pInfo->fd, i);
227
228 /* try to read something */
229 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
230 goto connect_idle;
231 }
232#else
233 /*
234 * This is a simplified procedure; it simply toggles RTS.
235 */
236
237 if ((i = xf86GetSerialModemState(pInfo->fd)) == -1)
238 return 0;
239 i |= XF86_M_DTR; /* DTR = 1 */
240 i &= ~XF86_M_RTS; /* RTS = 0 */
241 if (xf86SetSerialModemState(pInfo->fd, i) == -1)
242 goto disconnect_idle;
243 usleep(200000);
244
245 pnpOpts = xf86OptionListCreate(pnpSerial, -1, 1);
246 xf86SetSerial(pInfo->fd, pnpOpts);
247
248 /* wait for response */
249 xf86FlushInput(pInfo->fd);
250 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */
251 xf86SerialModemSetBits(pInfo->fd, i);
252
253 /* try to read something */
254 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
255 goto connect_idle;
256#endif
257
258 /* collect PnP COM device ID (2.1.7) */
259 i = 0;
260 usleep(200000); /* the mouse must send `Begin ID' within 200msec */
261 while (xf86ReadSerial(pInfo->fd, &c, 1) == 1) {
262 /* we may see "M", or "M3..." before `Begin ID' */
263 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
264 buf[i++] = c;
265 break;
266 }
267 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
268 break;
269 }
270 if (i <= 0) {
271 /* we haven't seen `Begin ID' in time... */
272 goto connect_idle;
273 }
274
275 ++c; /* make it `End ID' */
276 for (;;) {
277 if (xf86WaitForInput(pInfo->fd, 200000) <= 0)
278 break;
279
280 xf86ReadSerial(pInfo->fd, &buf[i], 1);
281 if (buf[i++] == c) /* End ID */
282 break;
283 if (i >= 256)
284 break;
285 }
286 if (buf[i - 1] != c)
287 goto connect_idle;
288 return i;
289
290 /*
291 * According to PnP spec, we should set DTR = 1 and RTS = 0 while
292 * in idle state. But, `moused' shall set DTR = RTS = 1 and proceed,
293 * assuming there is something at the port even if it didn't
294 * respond to the PnP enumeration procedure.
295 */
296disconnect_idle:
297 i = XF86_M_DTR | XF86_M_RTS; /* DTR = 1, RTS = 1 */
298 xf86SerialModemSetBits(pInfo->fd, i);
299connect_idle:
300 return 0;
301}
302
303static int
304pnpparse(InputInfoPtr pInfo, pnpid_t *id, char *buf, int len)
305{
306 char s[3];
307 int offset;
308 int sum = 0;
309 int i, j;
310
311 id->revision = 0;
312 id->eisaid = NULL;
313 id->serial = NULL;
314 id->class = NULL;
315 id->compat = NULL;
316 id->description = NULL;
317 id->neisaid = 0;
318 id->nserial = 0;
319 id->nclass = 0;
320 id->ncompat = 0;
321 id->ndescription = 0;
322
323 offset = 0x28 - buf[0];
324
325 /* calculate checksum */
326 for (i = 0; i < len - 3; ++i) {
327 sum += buf[i];
328 buf[i] += offset;
329 }
330 sum += buf[len - 1];
331 for (; i < len; ++i)
332 buf[i] += offset;
333 xf86MsgVerb(X_INFO, 2, "%s: PnP ID string: `%*.*s'\n", pInfo->name,
334 len, len, buf);
335
336 /* revision */
337 buf[1] -= offset;
338 buf[2] -= offset;
339 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
340 xf86MsgVerb(X_INFO, 2, "%s: PnP rev %d.%02d\n", pInfo->name,
341 id->revision / 100, id->revision % 100);
342
343 /* EISA vender and product ID */
344 id->eisaid = &buf[3];
345 id->neisaid = 7;
346
347 /* option strings */
348 i = 10;
349 if (buf[i] == '\\') {
350 /* device serial # */
351 for (j = ++i; i < len; ++i) {
352 if (buf[i] == '\\')
353 break;
354 }
355 if (i >= len)
356 i -= 3;
357 if (i - j == 8) {
358 id->serial = &buf[j];
359 id->nserial = 8;
360 }
361 }
362 if (buf[i] == '\\') {
363 /* PnP class */
364 for (j = ++i; i < len; ++i) {
365 if (buf[i] == '\\')
366 break;
367 }
368 if (i >= len)
369 i -= 3;
370 if (i > j + 1) {
371 id->class = &buf[j];
372 id->nclass = i - j;
373 }
374 }
375 if (buf[i] == '\\') {
376 /* compatible driver */
377 for (j = ++i; i < len; ++i) {
378 if (buf[i] == '\\')
379 break;
380 }
381 /*
382 * PnP COM spec prior to v0.96 allowed '*' in this field,
383 * it's not allowed now; just ignore it.
384 */
385 if (buf[j] == '*')
386 ++j;
387 if (i >= len)
388 i -= 3;
389 if (i > j + 1) {
390 id->compat = &buf[j];
391 id->ncompat = i - j;
392 }
393 }
394 if (buf[i] == '\\') {
395 /* product description */
396 for (j = ++i; i < len; ++i) {
397 if (buf[i] == ';')
398 break;
399 }
400 if (i >= len)
401 i -= 3;
402 if (i > j + 1) {
403 id->description = &buf[j];
404 id->ndescription = i - j;
405 }
406 }
407
408 /* checksum exists if there are any optional fields */
409 if ((id->nserial > 0) || (id->nclass > 0)
410 || (id->ncompat > 0) || (id->ndescription > 0)) {
411 xf86MsgVerb(X_INFO, 4, "PnP checksum: 0x%02X\n", pInfo->name, sum);
412 sprintf(s, "%02X", sum & 0x0ff);
413 if (strncmp(s, &buf[len - 3], 2) != 0) {
414#if 0
415 /*
416 * Checksum error!!
417 * I found some mice do not comply with the PnP COM device
418 * spec regarding checksum... XXX
419 */
420 return FALSE;
421#endif
422 }
423 }
424
425 return TRUE;
426}
427
428static symtab_t *
429pnpproto(pnpid_t *id)
430{
431 symtab_t *t;
432 int i, j;
433
434 if (id->nclass > 0)
435 if (strncmp(id->class, "MOUSE", id->nclass) != 0)
436 /* this is not a mouse! */
437 return NULL;
438
439 if (id->neisaid > 0) {
440 t = gettoken(pnpprod, id->eisaid, id->neisaid);
441 if (t->val != -1)
442 return t;
443 }
444
445 /*
446 * The 'Compatible drivers' field may contain more than one
447 * ID separated by ','.
448 */
449 if (id->ncompat <= 0)
450 return NULL;
451 for (i = 0; i < id->ncompat; ++i) {
452 for (j = i; id->compat[i] != ','; ++i)
453 if (i >= id->ncompat)
454 break;
455 if (i > j) {
456 t = gettoken(pnpprod, id->compat + j, i - j);
457 if (t->val != -1)
458 return t;
459 }
460 }
461
462 return NULL;
463}
464
465/* name/val mapping */
466
467static symtab_t *
468gettoken(tab, s, len)
469symtab_t *tab;
470char *s;
471int len;
472{
473 int i;
474
475 for (i = 0; tab[i].name != NULL; ++i) {
476 if (strncmp(tab[i].name, s, len) == 0)
477 break;
478 }
479 return &tab[i];
480}
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