Dash:
[t2-trunk.git] / package / base / serpnp / serpnp.c
blob655e1f6a1bf2a46f68c102f5401dca27a678c43a
1 /*
2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * This copyright note is auto-generated by ./scripts/Create-CopyPatch.
4 *
5 * T2 SDE: package/.../serpnp/serpnp.c
6 * Copyright (C) 2004 - 2005 The T2 SDE Project
7 *
8 * More information can be found in the files COPYING and README.
9 *
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>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
33 #include <unistd.h>
35 #include <termios.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <fcntl.h>
40 #include <sys/ioctl.h>
42 struct symtab_t {
43 char* name;
44 char* drv;
48 /* PnP EISA/product IDs */
49 static symtab_t pnpsymtab[] = {
50 #ifdef notyet
51 { "KML0001", PROT_THINKING }, /* Kensignton ThinkingMouse */
52 #endif
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 */
68 #ifdef notyet
69 { "PNP0F00", PROT_BM }, /* MS bus */
70 #endif
71 { "PNP0F01", "-ms" }, /* MS serial */
72 #ifdef notyet
73 { "PNP0F02", PROT_BM }, /* MS InPort */
74 #endif
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 */
81 #ifdef notyet
82 { "PNP0F06", PROT_??? }, /* Genius Mouse */
83 { "PNP0F07", PROT_??? }, /* Genius Mouse */
84 #endif
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 */
90 #ifdef notyet
91 { "PNP0F0D", PROT_BM }, /* MS InPort comatible */
92 #endif
93 { "PNP0F0F", "-ms" }, /* MS BallPoint comatible */
94 #ifdef notyet
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 */
100 #endif
101 { "PNP0F17", "-mman" }, /* Logitech serial compat */
102 #ifdef notyet
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 */
109 #endif
110 { NULL, NULL },
113 /* serial PnP ID string */
114 struct pnpid_t {
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... */
122 int nserial;
123 int ndevclass;
124 int ncompat;
125 int ndescription;
128 bool pnpparse (pnpid_t* id, char* buf, int len)
130 char s[3];
131 int offset;
132 int sum = 0;
133 int i, j;
135 id->revision = 0;
136 id->eisaid = NULL;
137 id->serial = NULL;
138 id->devclass = NULL;
139 id->compat = NULL;
140 id->description = NULL;
141 id->neisaid = 0;
142 id->nserial = 0;
143 id->ndevclass = 0;
144 id->ncompat = 0;
145 id->ndescription = 0;
147 offset = 0x28 - buf[0];
149 /* calculate checksum */
150 for (i = 0; i < len - 3; ++i) {
151 sum += buf[i];
152 buf[i] += offset;
154 sum += buf[len - 1];
155 for (; i < len; ++i)
156 buf[i] += offset;
157 //printf ("PnP ID string: `%*.*s'\n", len, len, buf);
159 /* revision */
160 buf[1] -= offset;
161 buf[2] -= offset;
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];
167 id->neisaid = 7;
169 // workaround for my Logitech mice? only has 6 ... -ReneR
170 if (id->eisaid [id->neisaid-1] == ')')
171 id->neisaid--;
173 /* option strings */
174 i = 10;
175 if (buf[i] == '\\') {
176 /* device serial # */
177 for (j = ++i; i < len; ++i) {
178 if (buf[i] == '\\')
179 break;
181 if (i >= len)
182 i -= 3;
183 if (i - j == 8) {
184 id->serial = &buf[j];
185 id->nserial = 8;
188 if (buf[i] == '\\') {
189 /* PnP class */
190 for (j = ++i; i < len; ++i) {
191 if (buf[i] == '\\')
192 break;
194 if (i >= len)
195 i -= 3;
196 if (i > j + 1) {
197 id->devclass = &buf[j];
198 id->ndevclass = i - j;
201 if (buf[i] == '\\') {
202 /* compatible driver */
203 for (j = ++i; i < len; ++i) {
204 if (buf[i] == '\\')
205 break;
208 * PnP COM spec prior to v0.96 allowed '*' in this field,
209 * it's not allowed now; just ignore it.
211 if (buf[j] == '*')
212 ++j;
213 if (i >= len)
214 i -= 3;
215 if (i > j + 1) {
216 id->compat = &buf[j];
217 id->ncompat = i - j;
220 if (buf[i] == '\\') {
221 /* product description */
222 for (j = ++i; i < len; ++i) {
223 if (buf[i] == ';')
224 break;
226 if (i >= len)
227 i -= 3;
228 if (i > j + 1) {
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!");
241 #if 0
243 * Checksum error!!
244 * I found some mice do not comply with the PnP COM device
245 * spec regarding checksum... XXX
247 return false;
248 #endif
252 return true;
255 int tty = 0;
256 struct termios oldserial_io;
258 void tty_cleanup()
260 printf ("Resetting port ...\n");
261 tcsetattr(tty, TCSANOW, &oldserial_io);
264 int main (int argc, char* argv[])
266 struct termios newserial_io;
268 if (argc <= 1) {
269 printf("Usage: %s devname\n", argv[0]);
270 return -1;
273 //open Serialport for reading and writing
274 tty = open (argv[1], O_RDWR | O_NOCTTY);
276 if (tty < 0) {
277 perror("serial port");
278 return 0;
281 // save current serial port settings
282 tcgetattr(tty, &oldserial_io);
283 tcgetattr(tty, &newserial_io);
285 // control
286 // raw mode
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.
303 unsigned int i;
304 ioctl(tty, TIOCMGET, &i);
305 i |= TIOCM_DTR; // DTR = 1
306 i &= ~TIOCM_RTS; // RTS = 0
307 ioctl(tty, TIOCMSET, &i);
309 usleep(200000);
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;
317 bool pnp = true;
318 unsigned char c;
320 char buf [256];
321 i = 0;
323 while (read (tty, &c, 1) == 1) {
324 if (c == 'M')
325 non_pnp_mice = true;
328 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
329 buf[0] = c;
330 i = 1;
331 break;
335 if (i <= 0) {
336 /* we haven't seen `Begin ID' in time... */
337 return 0;
340 ++c; /* make it `End ID' */
341 while (read (tty, &buf[i], 1) == 1) {
342 if (buf[i++] == c) /* End ID */
343 break;
344 if (i >= sizeof(buf))
345 return 1;
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]);
353 pnpid_t id;
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);
361 else {
362 symtab_t* it = pnpsymtab;
363 while (it->name != 0 && strncmp(it->name, id.eisaid, id.neisaid) != 0)
364 ++it;
365 if (it->name != 0)
366 printf ("CLASS: MOUSE %s\n", it->drv);
368 if (id.ndescription > 9) {
369 printf ("DESCRIPTION: %.*s\n", id.ndescription, id.description);
372 return 0;