OpenSDE Packages Database (without history before r20070)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

373 lines
9.4 KiB

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