2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
5 * T2 SDE: package/.../serpnp/serpnp.c
6 * Copyright (C) 2004 - 2005 The T2 SDE Project
8 * More information can be found in the files COPYING and README.
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2 of the License. A copy of the
13 * GNU General Public License can be found in the file COPYING.
14 * --- T2-COPYRIGHT-NOTE-END ---
18 * Serial / COM PnP evaluation as defined in:
19 * "Plug and Play External COM Device Specification"
20 * by Microsoft Corporation & Hayes Microcomputer Products, Inc.
21 * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pnpcom.rtf
23 * Copyright 2005 by René Rebe
25 * inspired partly by the X.org mouse/pnp code:
26 * Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
36 #include <sys/types.h>
40 #include <sys/ioctl.h>
48 /* PnP EISA/product IDs */
49 static symtab_t pnpsymtab
[] = {
51 { "KML0001", PROT_THINKING
}, /* Kensignton ThinkingMouse */
53 { "MSH0001", "-ms3" }, /* MS IntelliMouse */
54 { "MSH0004", "-ms3" }, /* MS IntelliMouse TrackBall */
55 { "KYEEZ00", "-ms" }, /* Genius EZScroll */
56 { "KYE0001", "-ms" }, /* Genius PnP Mouse */
57 { "KYE0002", "-ms" }, /* MouseSystem (Genius?) SmartScroll */
58 { "KYE0003", "-ms3" }, /* Genius NetMouse */
59 { "LGI800", "-ms" }, /* Logitech FirstMouse+ on ReneR's desk */
60 { "LGI800C", "-ms3" }, /* Logitech MouseMan (4 button model) */
61 { "LGI8033", "-ms3" }, /* Logitech Cordless MouseMan Wheel */
62 { "LGI8050", "-ms3" }, /* Logitech MouseMan+ */
63 { "LGI8051", "-ms3" }, /* Logitech FirstMouse+ */
64 { "LGI8001", "-ms" }, /* Logitech serial */ // was -mman -ReneR
65 { "A4W0005", "-ms3" }, /* A4 Tech 4D/4D+ Mouse */
66 { "PEC9802", "-ms3" }, /* 8D Scroll Mouse */
69 { "PNP0F00", PROT_BM
}, /* MS bus */
71 { "PNP0F01", "-ms" }, /* MS serial */
73 { "PNP0F02", PROT_BM
}, /* MS InPort */
76 * EzScroll returns PNP0F04 in the compatible device field; but it
77 * doesn't look compatible... XXX
79 { "PNP0F04", "-msc" }, /* MouseSystems */
80 { "PNP0F05", "-msc" }, /* MouseSystems */
82 { "PNP0F06", PROT_
??? }, /* Genius Mouse */
83 { "PNP0F07", PROT_
??? }, /* Genius Mouse */
85 { "PNP0F08", "-mman" }, /* Logitech serial */
86 { "PNP0F09", "-ms" }, /* MS BallPoint serial */
87 { "PNP0F0A", "-ms" }, /* MS PnP serial */
88 { "PNP0F0B", "-ms" }, /* MS PnP BallPoint serial */
89 { "PNP0F0C", "-ms" }, /* MS serial comatible */
91 { "PNP0F0D", PROT_BM
}, /* MS InPort comatible */
93 { "PNP0F0F", "-ms" }, /* MS BallPoint comatible */
95 { "PNP0F10", PROT_
??? }, /* TI QuickPort */
96 { "PNP0F11", PROT_BM
}, /* MS bus comatible */
97 { "PNP0F14", PROT_
??? }, /* MS Kids Mouse */
98 { "PNP0F15", PROT_BM
}, /* Logitech bus */
99 { "PNP0F16", PROT_
??? }, /* Logitech SWIFT */
101 { "PNP0F17", "-mman" }, /* Logitech serial compat */
103 { "PNP0F18", PROT_BM
}, /* Logitech bus compatible */
104 { "PNP0F1A", PROT_
??? }, /* Logitech SWIFT compatible */
105 { "PNP0F1B", PROT_
??? }, /* HP Omnibook */
106 { "PNP0F1C", PROT_
??? }, /* Compaq LTE TrackBall PS/2 */
107 { "PNP0F1D", PROT_
??? }, /* Compaq LTE TrackBall serial */
108 { "PNP0F1E", PROT_
??? }, /* MS Kids Trackball */
113 /* serial PnP ID string */
115 int revision
; /* PnP revision, 100 for 1.00 */
116 char* eisaid
; /* EISA ID including mfr ID and product ID */
117 char* serial
; /* serial No, optional */
118 char* devclass
; /* device class, optional */
119 char* compat
; /* list of compatible drivers, optional */
120 char* description
; /* product description, optional */
121 int neisaid
; /* length of the above fields... */
128 bool pnpparse (pnpid_t
* id
, char* buf
, int len
)
140 id
->description
= NULL
;
145 id
->ndescription
= 0;
147 offset
= 0x28 - buf
[0];
149 /* calculate checksum */
150 for (i
= 0; i
< len
- 3; ++i
) {
157 //printf ("PnP ID string: `%*.*s'\n", len, len, buf);
162 id
->revision
= ((buf
[1] & 0x3f) << 6) | (buf
[2] & 0x3f);
163 //printf ("PnP rev %d.%02d\n", id->revision / 100, id->revision % 100);
165 /* EISA vender and product ID */
166 id
->eisaid
= &buf
[3];
169 // workaround for my Logitech mice? only has 6 ... -ReneR
170 if (id
->eisaid
[id
->neisaid
-1] == ')')
175 if (buf
[i
] == '\\') {
176 /* device serial # */
177 for (j
= ++i
; i
< len
; ++i
) {
184 id
->serial
= &buf
[j
];
188 if (buf
[i
] == '\\') {
190 for (j
= ++i
; i
< len
; ++i
) {
197 id
->devclass
= &buf
[j
];
198 id
->ndevclass
= i
- j
;
201 if (buf
[i
] == '\\') {
202 /* compatible driver */
203 for (j
= ++i
; i
< len
; ++i
) {
208 * PnP COM spec prior to v0.96 allowed '*' in this field,
209 * it's not allowed now; just ignore it.
216 id
->compat
= &buf
[j
];
220 if (buf
[i
] == '\\') {
221 /* product description */
222 for (j
= ++i
; i
< len
; ++i
) {
229 id
->description
= &buf
[j
];
230 id
->ndescription
= i
- j
;
234 /* checksum exists if there are any optional fields */
235 if ((id
->nserial
> 0) || (id
->ndevclass
> 0)
236 || (id
->ncompat
> 0) || (id
->ndescription
> 0)) {
237 printf ("PnP checksum: 0x%02X\n", sum
);
238 sprintf(s
, "%02X", sum
& 0x0ff);
239 if (strncmp(s
, &buf
[len
- 3], 2) != 0) {
240 printf ("checksum error!");
244 * I found some mice do not comply with the PnP COM device
245 * spec regarding checksum... XXX
256 struct termios oldserial_io
;
260 printf ("Resetting port ...\n");
261 tcsetattr(tty
, TCSANOW
, &oldserial_io
);
264 int main (int argc
, char* argv
[])
266 struct termios newserial_io
;
269 printf("Usage: %s devname\n", argv
[0]);
273 //open Serialport for reading and writing
274 tty
= open (argv
[1], O_RDWR
| O_NOCTTY
);
277 perror("serial port");
281 // save current serial port settings
282 tcgetattr(tty
, &oldserial_io
);
283 tcgetattr(tty
, &newserial_io
);
287 newserial_io
.c_lflag
&= ~(ICANON
| ECHO
| ECHOE
| ISIG
);
288 newserial_io
.c_cc
[VTIME
] = 2;
289 newserial_io
.c_cc
[VMIN
] = 0;
291 cfsetispeed(&newserial_io
, B1200
);
292 newserial_io
.c_cflag
&= ~CSIZE
;
293 newserial_io
.c_cflag
|= CS7
;
295 atexit (tty_cleanup
);
297 tcflush(tty
, TCIFLUSH
);
299 tcsetattr(tty
,TCSANOW
,&newserial_io
);
301 // This is a simplified procedure; it simply toggles RTS.
304 ioctl(tty
, TIOCMGET
, &i
);
305 i
|= TIOCM_DTR
; // DTR = 1
306 i
&= ~TIOCM_RTS
; // RTS = 0
307 ioctl(tty
, TIOCMSET
, &i
);
311 /* wait for respose */
312 tcflush(tty
, TCIFLUSH
);
313 i
|= TIOCM_DTR
| TIOCM_RTS
; // DTR = 1, RTS = 1
314 ioctl(tty
, TIOCMSET
, &i
);
316 bool non_pnp_mice
= false;
323 while (read (tty
, &c
, 1) == 1) {
328 if ((c
== 0x08) || (c
== 0x28)) { /* Begin ID */
336 /* we haven't seen `Begin ID' in time... */
340 ++c
; /* make it `End ID' */
341 while (read (tty
, &buf
[i
], 1) == 1) {
342 if (buf
[i
++] == c
) /* End ID */
344 if (i
>= sizeof(buf
))
348 printf ("God PnP fields - %d bytes:\n", i
);
350 for (unsigned int j
= 0; j
< i
; ++j
)
351 printf ("%d %x\n", buf
[j
], buf
[j
]);
354 pnpparse (&id
, buf
, i
);
356 printf ("%.*s\n", id
.neisaid
, id
.eisaid
);
358 if (id
.ndevclass
> 0) {
359 printf ("CLASS: %.*s\n", id
.ndevclass
, id
.devclass
);
362 symtab_t
* it
= pnpsymtab
;
363 while (it
->name
!= 0 && strncmp(it
->name
, id
.eisaid
, id
.neisaid
) != 0)
366 printf ("CLASS: MOUSE %s\n", it
->drv
);
368 if (id
.ndescription
> 9) {
369 printf ("DESCRIPTION: %.*s\n", id
.ndescription
, id
.description
);