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.5 KiB

/*
* --- T2-COPYRIGHT-NOTE-BEGIN ---
* This copyright note is auto-generated by ./scripts/Create-CopyPatch.
*
* T2 SDE: package/.../serpnp/serpnp.c
* Copyright (C) 2004 - 2006 The T2 SDE Project
*
* More information can be found in the files COPYING and README.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License. A copy of the
* GNU General Public License can be found in the file COPYING.
* --- T2-COPYRIGHT-NOTE-END ---
*/
/*
* Serial / COM PnP evaluation as defined in:
* "Plug and Play External COM Device Specification"
* by Microsoft Corporation & Hayes Microcomputer Products, Inc.
* http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pnpcom.rtf
*
* Copyright 2005 by René Rebe
*
* inspired partly by the X.org mouse/pnp code:
* Copyright 1998 by Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <termios.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
struct symtab_t {
char* name;
char* drv;
};
/* PnP EISA/product IDs */
static symtab_t pnpsymtab[] = {
#ifdef notyet
{ "KML0001", PROT_THINKING }, /* Kensignton ThinkingMouse */
#endif
{ "MSH0001", "-ms3" }, /* MS IntelliMouse */
{ "MSH0004", "-ms3" }, /* MS IntelliMouse TrackBall */
{ "KYEEZ00", "-ms" }, /* Genius EZScroll */
{ "KYE0001", "-ms" }, /* Genius PnP Mouse */
{ "KYE0002", "-ms" }, /* MouseSystem (Genius?) SmartScroll */
{ "KYE0003", "-ms3" }, /* Genius NetMouse */
{ "LGI800", "-ms" }, /* Logitech FirstMouse+ on ReneR's desk */
{ "LGI800C", "-ms3" }, /* Logitech MouseMan (4 button model) */
{ "LGI8033", "-ms3" }, /* Logitech Cordless MouseMan Wheel */
{ "LGI8050", "-ms3" }, /* Logitech MouseMan+ */
{ "LGI8051", "-ms3" }, /* Logitech FirstMouse+ */
{ "LGI8001", "-ms" }, /* Logitech serial */ // was -mman -ReneR
{ "A4W0005", "-ms3" }, /* A4 Tech 4D/4D+ Mouse */
{ "PEC9802", "-ms3" }, /* 8D Scroll Mouse */
#ifdef notyet
{ "PNP0F00", PROT_BM }, /* MS bus */
#endif
{ "PNP0F01", "-ms" }, /* MS serial */
#ifdef notyet
{ "PNP0F02", PROT_BM }, /* MS InPort */
#endif
/*
* EzScroll returns PNP0F04 in the compatible device field; but it
* doesn't look compatible... XXX
*/
{ "PNP0F04", "-msc" }, /* MouseSystems */
{ "PNP0F05", "-msc" }, /* MouseSystems */
#ifdef notyet
{ "PNP0F06", PROT_??? }, /* Genius Mouse */
{ "PNP0F07", PROT_??? }, /* Genius Mouse */
#endif
{ "PNP0F08", "-mman" }, /* Logitech serial */
{ "PNP0F09", "-ms" }, /* MS BallPoint serial */
{ "PNP0F0A", "-ms" }, /* MS PnP serial */
{ "PNP0F0B", "-ms" }, /* MS PnP BallPoint serial */
{ "PNP0F0C", "-ms" }, /* MS serial comatible */
#ifdef notyet
{ "PNP0F0D", PROT_BM }, /* MS InPort comatible */
#endif
{ "PNP0F0F", "-ms" }, /* MS BallPoint comatible */
#ifdef notyet
{ "PNP0F10", PROT_??? }, /* TI QuickPort */
{ "PNP0F11", PROT_BM }, /* MS bus comatible */
{ "PNP0F14", PROT_??? }, /* MS Kids Mouse */
{ "PNP0F15", PROT_BM }, /* Logitech bus */
{ "PNP0F16", PROT_??? }, /* Logitech SWIFT */
#endif
{ "PNP0F17", "-mman" }, /* Logitech serial compat */
#ifdef notyet
{ "PNP0F18", PROT_BM }, /* Logitech bus compatible */
{ "PNP0F1A", PROT_??? }, /* Logitech SWIFT compatible */
{ "PNP0F1B", PROT_??? }, /* HP Omnibook */
{ "PNP0F1C", PROT_??? }, /* Compaq LTE TrackBall PS/2 */
{ "PNP0F1D", PROT_??? }, /* Compaq LTE TrackBall serial */
{ "PNP0F1E", PROT_??? }, /* MS Kids Trackball */
#endif
{ NULL, NULL },
};
/* serial PnP ID string */
struct pnpid_t {
int revision; /* PnP revision, 100 for 1.00 */
char* eisaid; /* EISA ID including mfr ID and product ID */
char* serial; /* serial No, optional */
char* devclass; /* device class, optional */
char* compat; /* list of compatible drivers, optional */
char* description; /* product description, optional */
int neisaid; /* length of the above fields... */
int nserial;
int ndevclass;
int ncompat;
int ndescription;
};
bool pnpparse (pnpid_t* id, char* buf, int len)
{
char s[3];
int offset;
int sum = 0;
int i, j;
id->revision = 0;
id->eisaid = NULL;
id->serial = NULL;
id->devclass = NULL;
id->compat = NULL;
id->description = NULL;
id->neisaid = 0;
id->nserial = 0;
id->ndevclass = 0;
id->ncompat = 0;
id->ndescription = 0;
offset = 0x28 - buf[0];
/* calculate checksum */
for (i = 0; i < len - 3; ++i) {
sum += buf[i];
buf[i] += offset;
}
sum += buf[len - 1];
for (; i < len; ++i)
buf[i] += offset;
//printf ("PnP ID string: `%*.*s'\n", len, len, buf);
/* revision */
buf[1] -= offset;
buf[2] -= offset;
id->revision = ((buf[1] & 0x3f) << 6) | (buf[2] & 0x3f);
//printf ("PnP rev %d.%02d\n", id->revision / 100, id->revision % 100);
/* EISA vender and product ID */
id->eisaid = &buf[3];
id->neisaid = 7;
// workaround for my Logitech mice? only has 6 ... -ReneR
if (id->eisaid [id->neisaid-1] == ')')
id->neisaid--;
/* option strings */
i = 10;
if (buf[i] == '\\') {
/* device serial # */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
if (i >= len)
i -= 3;
if (i - j == 8) {
id->serial = &buf[j];
id->nserial = 8;
}
}
if (buf[i] == '\\') {
/* PnP class */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
if (i >= len)
i -= 3;
if (i > j + 1) {
id->devclass = &buf[j];
id->ndevclass = i - j;
}
}
if (buf[i] == '\\') {
/* compatible driver */
for (j = ++i; i < len; ++i) {
if (buf[i] == '\\')
break;
}
/*
* PnP COM spec prior to v0.96 allowed '*' in this field,
* it's not allowed now; just ignore it.
*/
if (buf[j] == '*')
++j;
if (i >= len)
i -= 3;
if (i > j + 1) {
id->compat = &buf[j];
id->ncompat = i - j;
}
}
if (buf[i] == '\\') {
/* product description */
for (j = ++i; i < len; ++i) {
if (buf[i] == ';')
break;
}
if (i >= len)
i -= 3;
if (i > j + 1) {
id->description = &buf[j];
id->ndescription = i - j;
}
}
/* checksum exists if there are any optional fields */
if ((id->nserial > 0) || (id->ndevclass > 0)
|| (id->ncompat > 0) || (id->ndescription > 0)) {
printf ("PnP checksum: 0x%02X\n", sum);
sprintf(s, "%02X", sum & 0x0ff);
if (strncmp(s, &buf[len - 3], 2) != 0) {
printf ("checksum error!");
#if 0
/*
* Checksum error!!
* I found some mice do not comply with the PnP COM device
* spec regarding checksum... XXX
*/
return false;
#endif
}
}
return true;
}
int tty = 0;
struct termios oldserial_io;
void tty_cleanup()
{
printf ("Resetting port ...\n");
tcsetattr(tty, TCSANOW, &oldserial_io);
}
int main (int argc, char* argv[])
{
struct termios newserial_io;
if (argc <= 1) {
printf("Usage: %s devname\n", argv[0]);
return -1;
}
//open Serialport for reading and writing
tty = open (argv[1], O_RDWR | O_NOCTTY);
if (tty < 0) {
perror("serial port");
return 0;
}
// save current serial port settings
tcgetattr(tty, &oldserial_io);
tcgetattr(tty, &newserial_io);
// control
// raw mode
newserial_io.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
newserial_io.c_cc[VTIME] = 2;
newserial_io.c_cc[VMIN] = 0;
cfsetispeed(&newserial_io, B1200);
newserial_io.c_cflag &= ~CSIZE;
newserial_io.c_cflag |= CS7;
atexit (tty_cleanup);
tcflush(tty, TCIFLUSH);
tcsetattr(tty,TCSANOW,&newserial_io);
// This is a simplified procedure; it simply toggles RTS.
unsigned int i;
ioctl(tty, TIOCMGET, &i);
i |= TIOCM_DTR; // DTR = 1
i &= ~TIOCM_RTS; // RTS = 0
ioctl(tty, TIOCMSET, &i);
usleep(200000);
/* wait for respose */
tcflush(tty, TCIFLUSH);
i |= TIOCM_DTR | TIOCM_RTS; // DTR = 1, RTS = 1
ioctl(tty, TIOCMSET, &i);
bool non_pnp_mice = false;
bool pnp = true;
unsigned char c;
char buf [256];
i = 0;
while (read (tty, &c, 1) == 1) {
if (c == 'M')
non_pnp_mice = true;
if ((c == 0x08) || (c == 0x28)) { /* Begin ID */
buf[0] = c;
i = 1;
break;
}
}
if (i <= 0) {
/* we haven't seen `Begin ID' in time... */
return 0;
}
++c; /* make it `End ID' */
while (read (tty, &buf[i], 1) == 1) {
if (buf[i++] == c) /* End ID */
break;
if (i >= sizeof(buf))
return 1;
}
printf ("God PnP fields - %d bytes:\n", i);
for (unsigned int j = 0; j < i; ++j)
printf ("%d %x\n", buf[j], buf[j]);
pnpid_t id;
pnpparse (&id, buf, i);
printf ("%.*s\n", id.neisaid, id.eisaid);
if (id.ndevclass > 0) {
printf ("CLASS: %.*s\n", id.ndevclass, id.devclass);
}
else {
symtab_t* it = pnpsymtab;
while (it->name != 0 && strncmp(it->name, id.eisaid, id.neisaid) != 0)
++it;
if (it->name != 0)
printf ("CLASS: MOUSE %s\n", it->drv);
}
if (id.ndescription > 9) {
printf ("DESCRIPTION: %.*s\n", id.ndescription, id.description);
}
return 0;
}