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
						
					
					
				
			
		
		
	
	
							373 lines
						
					
					
						
							9.4 KiB
						
					
					
				/* | 
						|
 * --- SDE-COPYRIGHT-NOTE-BEGIN --- | 
						|
 * This copyright note is auto-generated by ./scripts/Create-CopyPatch. | 
						|
 * | 
						|
 * Filename: 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. | 
						|
 * --- SDE-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 <[email protected]> | 
						|
 */ | 
						|
 | 
						|
#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; | 
						|
}
 | 
						|
 |