* updated tzdata (2024a -> 2024b)
[t2sde.git] / package / base / serpnp / serpnp.c
blob6f87c6ad66fe39876a08fe6db4d3928d27790416
1 /*
2 * --- T2-COPYRIGHT-NOTE-BEGIN ---
3 * T2 SDE: package/.../serpnp/serpnp.c
4 * Copyright (C) 2004 - 2022 The T2 SDE Project
5 *
6 * This Copyright note is generated by scripts/Create-CopyPatch,
7 * more information can be found in the files COPYING and README.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2.
11 * --- T2-COPYRIGHT-NOTE-END ---
15 * Serial / COM PnP evaluation as defined in:
16 * "Plug and Play External COM Device Specification"
17 * by Microsoft Corporation & Hayes Microcomputer Products, Inc.
18 * http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pnpcom.rtf
20 * Copyright 2005 by René Rebe
22 * inspired partly by the X.org mouse/pnp code:
23 * Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include <unistd.h>
32 #include <termios.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
37 #include <sys/ioctl.h>
39 struct symtab_t {
40 char* name;
41 char* drv;
45 /* PnP EISA/product IDs */
46 static symtab_t pnpsymtab[] = {
47 #ifdef notyet
48 { "KML0001", PROT_THINKING }, /* Kensignton ThinkingMouse */
49 #endif
50 { "MSH0001", "-ms3" }, /* MS IntelliMouse */
51 { "MSH0004", "-ms3" }, /* MS IntelliMouse TrackBall */
52 { "KYEEZ00", "-ms" }, /* Genius EZScroll */
53 { "KYE0001", "-ms" }, /* Genius PnP Mouse */
54 { "KYE0002", "-ms" }, /* MouseSystem (Genius?) SmartScroll */
55 { "KYE0003", "-ms3" }, /* Genius NetMouse */
56 { "LGI800", "-ms" }, /* Logitech FirstMouse+ on ReneR's desk */
57 { "LGI800C", "-ms3" }, /* Logitech MouseMan (4 button model) */
58 { "LGI8033", "-ms3" }, /* Logitech Cordless MouseMan Wheel */
59 { "LGI8050", "-ms3" }, /* Logitech MouseMan+ */
60 { "LGI8051", "-ms3" }, /* Logitech FirstMouse+ */
61 { "LGI8001", "-ms" }, /* Logitech serial */ // was -mman -ReneR
62 { "A4W0005", "-ms3" }, /* A4 Tech 4D/4D+ Mouse */
63 { "PEC9802", "-ms3" }, /* 8D Scroll Mouse */
65 #ifdef notyet
66 { "PNP0F00", PROT_BM }, /* MS bus */
67 #endif
68 { "PNP0F01", "-ms" }, /* MS serial */
69 #ifdef notyet
70 { "PNP0F02", PROT_BM }, /* MS InPort */
71 #endif
73 * EzScroll returns PNP0F04 in the compatible device field; but it
74 * doesn't look compatible... XXX
76 { "PNP0F04", "-msc" }, /* MouseSystems */
77 { "PNP0F05", "-msc" }, /* MouseSystems */
78 #ifdef notyet
79 { "PNP0F06", PROT_??? }, /* Genius Mouse */
80 { "PNP0F07", PROT_??? }, /* Genius Mouse */
81 #endif
82 { "PNP0F08", "-mman" }, /* Logitech serial */
83 { "PNP0F09", "-ms" }, /* MS BallPoint serial */
84 { "PNP0F0A", "-ms" }, /* MS PnP serial */
85 { "PNP0F0B", "-ms" }, /* MS PnP BallPoint serial */
86 { "PNP0F0C", "-ms" }, /* MS serial comatible */
87 #ifdef notyet
88 { "PNP0F0D", PROT_BM }, /* MS InPort comatible */
89 #endif
90 { "PNP0F0F", "-ms" }, /* MS BallPoint comatible */
91 #ifdef notyet
92 { "PNP0F10", PROT_??? }, /* TI QuickPort */
93 { "PNP0F11", PROT_BM }, /* MS bus comatible */
94 { "PNP0F14", PROT_??? }, /* MS Kids Mouse */
95 { "PNP0F15", PROT_BM }, /* Logitech bus */
96 { "PNP0F16", PROT_??? }, /* Logitech SWIFT */
97 #endif
98 { "PNP0F17", "-mman" }, /* Logitech serial compat */
99 #ifdef notyet
100 { "PNP0F18", PROT_BM }, /* Logitech bus compatible */
101 { "PNP0F1A", PROT_??? }, /* Logitech SWIFT compatible */
102 { "PNP0F1B", PROT_??? }, /* HP Omnibook */
103 { "PNP0F1C", PROT_??? }, /* Compaq LTE TrackBall PS/2 */
104 { "PNP0F1D", PROT_??? }, /* Compaq LTE TrackBall serial */
105 { "PNP0F1E", PROT_??? }, /* MS Kids Trackball */
106 #endif
107 { NULL, NULL },
110 /* serial PnP ID string */
111 struct pnpid_t {
112 int revision; /* PnP revision, 100 for 1.00 */
113 char* eisaid; /* EISA ID including mfr ID and product ID */
114 char* serial; /* serial No, optional */
115 char* devclass; /* device class, optional */
116 char* compat; /* list of compatible drivers, optional */
117 char* description; /* product description, optional */
118 int neisaid; /* length of the above fields... */
119 int nserial;
120 int ndevclass;
121 int ncompat;
122 int ndescription;
125 bool pnpparse (pnpid_t* id, char* buf, int len)
127 char s[3];
128 int offset;
129 int sum = 0;
130 int i, j;
132 id->revision = 0;
133 id->eisaid = NULL;
134 id->serial = NULL;
135 id->devclass = NULL;
136 id->compat = NULL;
137 id->description = NULL;
138 id->neisaid = 0;
139 id->nserial = 0;
140 id->ndevclass = 0;
141 id->ncompat = 0;
142 id->ndescription = 0;
144 offset = 0x28 - buf[0];
146 /* calculate checksum */
147 for (i = 0; i < len - 3; ++i) {
148 sum += buf[i];
149 buf[i] += offset;
151 sum += buf[len - 1];
152 for (; i < len; ++i)
153 buf[i] += offset;
154 //printf ("PnP ID string: `%*.*s'\n", len, len, buf);
156 /* revision */
157 buf[1] -= offset;
158 buf[2] -= offset;
159 id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
160 //printf ("PnP rev %d.%02d\n", id->revision / 100, id->revision % 100);
162 /* EISA vender and product ID */
163 id->eisaid = &buf[3];
164 id->neisaid = 7;
166 // workaround for my Logitech mice? only has 6 ... -ReneR
167 if (id->eisaid [id->neisaid-1] == ')')
168 id->neisaid--;
170 /* option strings */
171 i = 10;
172 if (buf[i] == '\\') {
173 /* device serial # */
174 for (j = ++i; i < len; ++i) {
175 if (buf[i] == '\\')
176 break;
178 if (i >= len)
179 i -= 3;
180 if (i - j == 8) {
181 id->serial = &buf[j];
182 id->nserial = 8;
185 if (buf[i] == '\\') {
186 /* PnP class */
187 for (j = ++i; i < len; ++i) {
188 if (buf[i] == '\\')
189 break;
191 if (i >= len)
192 i -= 3;
193 if (i > j + 1) {
194 id->devclass = &buf[j];
195 id->ndevclass = i - j;
198 if (buf[i] == '\\') {
199 /* compatible driver */
200 for (j = ++i; i < len; ++i) {
201 if (buf[i] == '\\')
202 break;
205 * PnP COM spec prior to v0.96 allowed '*' in this field,
206 * it's not allowed now; just ignore it.
208 if (buf[j] == '*')
209 ++j;
210 if (i >= len)
211 i -= 3;
212 if (i > j + 1) {
213 id->compat = &buf[j];
214 id->ncompat = i - j;
217 if (buf[i] == '\\') {
218 /* product description */
219 for (j = ++i; i < len; ++i) {
220 if (buf[i] == ';')
221 break;
223 if (i >= len)
224 i -= 3;
225 if (i > j + 1) {
226 id->description = &buf[j];
227 id->ndescription = i - j;
231 /* checksum exists if there are any optional fields */
232 if ((id->nserial > 0) || (id->ndevclass > 0)
233 || (id->ncompat > 0) || (id->ndescription > 0)) {
234 printf ("PnP checksum: 0x%02X\n", sum);
235 sprintf(s, "%02X", sum & 0x0ff);
236 if (strncmp(s, &buf[len - 3], 2) != 0) {
237 printf ("checksum error!");
238 #if 0
240 * Checksum error!!
241 * I found some mice do not comply with the PnP COM device
242 * spec regarding checksum... XXX
244 return false;
245 #endif
249 return true;
252 int tty = 0;
253 struct termios oldserial_io;
255 void tty_cleanup()
257 printf ("Resetting port ...\n");
258 tcsetattr(tty, TCSANOW, &oldserial_io);
261 int main (int argc, char* argv[])
263 struct termios newserial_io;
265 if (argc <= 1) {
266 printf("Usage: %s devname\n", argv[0]);
267 return -1;
270 //open Serialport for reading and writing
271 tty = open (argv[1], O_RDWR | O_NOCTTY);
273 if (tty < 0) {
274 perror("serial port");
275 return 0;
278 // save current serial port settings
279 tcgetattr(tty, &oldserial_io);
280 tcgetattr(tty, &newserial_io);
282 // control
283 // raw mode
284 newserial_io.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
285 newserial_io.c_cc[VTIME] = 2;
286 newserial_io.c_cc[VMIN] = 0;
288 cfsetispeed(&newserial_io, B1200);
289 newserial_io.c_cflag &= ~CSIZE;
290 newserial_io.c_cflag |= CS7;
292 atexit (tty_cleanup);
294 tcflush(tty, TCIFLUSH);
296 tcsetattr(tty,TCSANOW,&newserial_io);
298 // This is a simplified procedure; it simply toggles RTS.
300 unsigned int i;
301 ioctl(tty, TIOCMGET, &i);
302 i |= TIOCM_DTR; // DTR = 1
303 i &= ~TIOCM_RTS; // RTS = 0
304 ioctl(tty, TIOCMSET, &i);
306 usleep(200000);
308 /* wait for respose */
309 tcflush(tty, TCIFLUSH);
310 i |= TIOCM_DTR | TIOCM_RTS; // DTR = 1, RTS = 1
311 ioctl(tty, TIOCMSET, &i);
313 bool non_pnp_mice = false;
314 bool pnp = true;
315 unsigned char c;
317 char buf [256];
318 i = 0;
320 while (read (tty, &c, 1) == 1) {
321 if (c == 'M')
322 non_pnp_mice = true;
325 if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
326 buf[0] = c;
327 i = 1;
328 break;
332 if (i <= 0) {
333 /* we haven't seen `Begin ID' in time... */
334 return 0;
337 ++c; /* make it `End ID' */
338 while (read (tty, &buf[i], 1) == 1) {
339 if (buf[i++] == c) /* End ID */
340 break;
341 if (i >= sizeof(buf))
342 return 1;
345 printf ("God PnP fields - %d bytes:\n", i);
347 for (unsigned int j = 0; j < i; ++j)
348 printf ("%d %x\n", buf[j], buf[j]);
350 pnpid_t id;
351 pnpparse (&id, buf, i);
353 printf ("%.*s\n", id.neisaid, id.eisaid);
355 if (id.ndevclass > 0) {
356 printf ("CLASS: %.*s\n", id.ndevclass, id.devclass);
358 else {
359 symtab_t* it = pnpsymtab;
360 while (it->name != 0 && strncmp(it->name, id.eisaid, id.neisaid) != 0)
361 ++it;
362 if (it->name != 0)
363 printf ("CLASS: MOUSE %s\n", it->drv);
365 if (id.ndescription > 9) {
366 printf ("DESCRIPTION: %.*s\n", id.ndescription, id.description);
369 return 0;