diff options
Diffstat (limited to 'tools/serial_probe/serial.c')
-rw-r--r-- | tools/serial_probe/serial.c | 1209 |
1 files changed, 0 insertions, 1209 deletions
diff --git a/tools/serial_probe/serial.c b/tools/serial_probe/serial.c deleted file mode 100644 index 14b315817..000000000 --- a/tools/serial_probe/serial.c +++ /dev/null @@ -1,1209 +0,0 @@ -/* probe serial port for PnP/Legacy devices - * - * Copyright 1999 Red Hat, Inc. - * - * This software may be freely redistributed under the terms of the GNU - * public license. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - - -#include <stdio.h> -#include <stdlib.h> -#include <fcntl.h> -#include <unistd.h> -#include <termios.h> -#include <errno.h> -#include <string.h> -#include <signal.h> -#include <time.h> -#include <libgen.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/ioctl.h> - -#include <linux/serial.h> -#include "serial.h" - -/* character strings ARE null-terminated in the following structure */ -/* these elements are marked with a (string) in the comment */ -/* If PnP device sent 6 bit data stream, we've xlated by a 0x20 offset */ -/* When computing checksum, must remove this offset */ -struct pnp_com_id { - unsigned char xlate_6bit; /* does this contain xlated data */ - unsigned char other_id[17]; /* backward compatibility with pre-PNP */ - unsigned char other_len; /* length of the other_id */ - unsigned char pnp_rev[2]; /* PnP revision bytes */ - unsigned char pnp_rev_str[8]; /* PnP revision (string version) */ - unsigned char eisa_id[4]; /* EISA Mfr identifier (string) */ - unsigned char product_id[5]; /* Mfr determined product ID (string) */ - unsigned char serial_number[9];/* Optional dev serial number (string) */ - unsigned char class_name[33]; /* Optional PnP Class name (string) */ - unsigned char driver_id[42]; /* Optional compat device IDs (string) */ - unsigned char user_name[42]; /* Optional verbose product descr (string)*/ - unsigned char checksum[2]; /* Optional checksum */ -}; - -/* there are two possible bytes to signify the start of a PnP ID string */ -#define BeginPnP1 0x28 -#define BeginPnP2 0x08 - -/* Likewise, two possible stop bytes */ -#define EndPnP1 0x29 -#define EndPnP2 0x09 - -/* these chars indicate extensions to the base dev id exist */ -#define ExtendPnP1 0x5c -#define ExtendPnP2 0x3c - -#define PNP_COM_MAXLEN 256 - -/* results from initiating hardware probe of a hardware device */ -#define PNP_COM_FATAL 1 /* system error, check errno */ -#define PNP_COM_FAIL 2 /* probe ok, but found nothing */ -#define PNP_COM_OK 3 /* probe ok, we found it */ - -/* types of devices we might find */ -/* if PNP_COM_PNPDEV is NOT set, its a legacy device */ -#define PNP_COM_MOUSE 1 /* its a mouse */ -#define PNP_COM_MODEM 2 /* its a modem */ -#define PNP_COM_OTHER 4 /* device is there, cant tell what kind */ -#define PNP_COM_NOEXIST 8 /* no device seen */ -#define PNP_COM_PNPDEV 512 /* its a PNP device */ - -/* level of debugging output */ -/* current any value > 0 dumps all available debugging output */ -static int debug_level=0; - -static void serialFreeDevice(struct serialDevice *dev) { - if (dev->pnpmfr) free(dev->pnpmfr); - if (dev->pnpmodel) free(dev->pnpmodel); - if (dev->pnpcompat) free(dev->pnpcompat); - if (dev->pnpdesc) free(dev->pnpdesc); - freeDevice((struct device *)dev); -} - -static void serialWriteDevice(FILE *file, struct serialDevice *dev) -{ - writeDevice(file, (struct device *) dev); - if (dev->pnpmfr) - fprintf(file,"pnpmfr: %s\n",dev->pnpmfr); - if (dev->pnpmodel) - fprintf(file,"pnpmodel: %s\n",dev->pnpmodel); - if (dev->pnpcompat) - fprintf(file,"pnpcompat: %s\n",dev->pnpcompat); - if (dev->pnpdesc) - fprintf(file,"pnpdesc: %s\n",dev->pnpdesc); -} - -static int serialCompareDevice( struct serialDevice *dev1, struct serialDevice *dev2) -{ - int x; - - x = compareDevice((struct device *)dev1, (struct device *)dev2); - if (x && x!=2) return x; - if (dev1->pnpmfr && dev2->pnpmfr && strcmp(dev1->pnpmfr,dev2->pnpmfr)) - return 1; - if ((!dev1->pnpmfr || !dev2->pnpmfr) && (dev1->pnpmfr != dev2->pnpmfr)) - return 1; - if (dev1->pnpmodel && dev2->pnpmodel && strcmp(dev1->pnpmodel,dev2->pnpmodel)) - return 1; - if ((!dev1->pnpmodel || !dev2->pnpmodel) && (dev1->pnpmodel != dev2->pnpmodel)) - return 1; - if (dev1->pnpcompat && dev2->pnpcompat && strcmp(dev1->pnpcompat,dev2->pnpcompat)) - return 1; - if ((!dev1->pnpcompat || !dev2->pnpcompat) && (dev1->pnpcompat != dev2->pnpcompat)) - return 1; - if (dev1->pnpdesc && dev2->pnpdesc && strcmp(dev1->pnpdesc,dev2->pnpdesc)) - return 1; - if ((!dev1->pnpdesc || !dev2->pnpdesc) && (dev1->pnpdesc != dev2->pnpdesc)) - return 1; - return x; -} - - -struct serialDevice * serialNewDevice(struct serialDevice *dev) { - struct serialDevice *ret; - - ret = malloc(sizeof(struct serialDevice)); - memset(ret,'\0',sizeof(struct serialDevice)); - ret=(struct serialDevice *)newDevice((struct device *)dev,(struct device *)ret); - ret->bus = BUS_SERIAL; - ret->newDevice = serialNewDevice; - ret->freeDevice = serialFreeDevice; - ret->writeDevice = serialWriteDevice; - ret->compareDevice = serialCompareDevice; - if (dev && dev->bus == BUS_SERIAL) { - if (dev->pnpmfr) - ret->pnpmfr=strdup(dev->pnpmfr); - if (dev->pnpmodel) - ret->pnpmodel=strdup(dev->pnpmodel); - if (dev->pnpcompat) - ret->pnpcompat=strdup(dev->pnpcompat); - if (dev->pnpdesc) - ret->pnpdesc=strdup(dev->pnpdesc); - } - return ret; -} - -/* UNUSED */ -void print_status_lines( int fd ) { - int modem_lines; - - ioctl(fd, TIOCMGET, &modem_lines); - - printf("DTR : %s\n",(modem_lines & TIOCM_DTR ? "On" : "Off")); - printf("RTS : %s\n",(modem_lines & TIOCM_RTS ? "On" : "Off")); - printf("CTS : %s\n",(modem_lines & TIOCM_CTS ? "On" : "Off")); - printf("DSR : %s\n",(modem_lines & TIOCM_DSR ? "On" : "Off")); - printf("CD : %s\n",(modem_lines & TIOCM_CD ? "On" : "Off")); - printf("RI : %s\n",(modem_lines & TIOCM_RI ? "On" : "Off")); - -} - - -/* UNUSED except in debug */ -/* outputs data in a hex table, 8 values per row */ -void print_hex_data( unsigned char *data, int len ) { - int i, j, pos; - - if (len == 0) { - printf("No data to print.\n"); - return; - } - - pos = 0; - for (i=0; i< len; i+=8) { - printf("0x%.4x ", i); - for (j=i; j < len && j < i+8; j++) { - printf("0x%.2x ",data[pos++]); - } - printf("\n"); - } -} - - -/* - * wait_input - wait until there is data available on fd, - * for the length of time specified by *timo (indefinite - * if timo is NULL). - */ - -int wait_for_input (int fd, struct timeval *timo) { - fd_set ready; - int n; - - FD_ZERO(&ready); - FD_SET(fd, &ready); - - n = select(fd+1, &ready, NULL, &ready, timo); - return n; -} - -/* UNUSED */ -/* read characters into the buffer buf, until one of: */ -/* char_timeout expired before next character arrives */ -/* total_timeout expires */ -/* maxlen characters are retrieved */ -/* */ -/* returns < 0 if it fails */ -/* otherwise the # of characters received is returned */ -/* char_timeout is in microseconds (millionths of a sec) */ -/* total_timeout is in seconds */ -int timed_serial_read(int fd, int char_timeout, int total_timeout, - unsigned char *buf, int maxlen ) { - - int done, pos, starttime, temp; - struct timeval timo; - unsigned char intbuf[2]; - - /* start reading */ - done = 0; - pos = 0; - starttime=time(NULL); - memset(buf, 0, maxlen); - while (!done) { - timo.tv_sec=0; - timo.tv_usec=char_timeout; - if (wait_for_input(fd, &timo) > 0) { - temp = read( fd, intbuf, 1 ); - if (temp < 0) { - if (errno != EAGAIN) - return -1; - } else { - buf[pos++] = intbuf[0]; - buf[pos] = 0; - } - } else - done = 1; - - /* shouldnt run more than 5 seconds */ - if (time(NULL)-starttime > total_timeout ) - done = 1; - - if (pos > maxlen) - done = 1; - } - return pos; -} - - -int open_serial_port( char *port ) { - int fd; - - fd = open( port, O_RDWR | O_NONBLOCK); - if (fd < 0) - return -1; - - /* reset file so it is no longer in non-blocking mode */ - if (fcntl(fd, F_SETFL, 0) < 0) { - close(fd); - return -1; - } - - return fd; -} - -/* <0 means ioctl error occurred */ -int get_serial_lines( int fd ) { - int modem_lines; - - ioctl(fd, TIOCMGET, &modem_lines); - return modem_lines; -} - -/* <0 means ioctl error occurred */ -int set_serial_lines( int fd, int modem_lines ) { - return ioctl(fd, TIOCMSET, &modem_lines); -} - -/* set serial port to 1200 baud, 'nbits' bits, 1 stop, no parity */ -int setup_serial_port( int fd, int nbits, struct termios *attr ) { - - attr->c_iflag = IGNBRK | IGNPAR; - attr->c_cflag = 0; - attr->c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | PARENB); - attr->c_cflag |= CREAD | CLOCAL; /*| CRTSCTS ; */ - if (nbits == 7) - attr->c_cflag |= CS7 | CSTOPB; - else - attr->c_cflag |= CS8; - attr->c_oflag = 0; - attr->c_lflag = 0; - - attr->c_cc[VMIN] = 1; - attr->c_cc[VTIME] = 5; - - cfsetospeed( attr, B1200); - cfsetispeed( attr, B1200); - return tcsetattr(fd, TCSANOW, attr); -} - -/* Initialize the serial port to a known state *before* probing. This is - * apparently required for some Logitech mice, who will stubbornly refuse - * to respond to PnP probes after they've been opened by gpm or XFree. - */ - -int init_port(int fd) { - struct termios attr; - - if (tcgetattr(fd,&attr)) - return 1; - - cfsetospeed(&attr, B2400); - cfsetispeed(&attr, B2400); - attr.c_iflag = IXON | ICRNL; - attr.c_cflag = CLOCAL | HUPCL | CREAD | B9600 | CS8; - attr.c_oflag = 0; - attr.c_lflag = 0; - return tcsetattr(fd, TCSANOW, &attr); -} - - -/* Request for PnP info from serial device */ -/* See page 6 of the pnpcom doc from Microsoft */ -/* Return code tells us what happened */ -/* */ -/* PNP_COM_FATAL - error, errno has reason */ -/* PNP_COM_OK - probe initiated successfully */ -/* PNP_COM_FAIL - DSR never came on - try alterntives */ -/* means (ATI9?) to get PnP string */ -int init_pnp_com_seq1( int fd ) { - int modem_lines; - int temp; - int dsr_status; - int rc = PNP_COM_OK; - struct termios portattr; - - if (init_port(fd)) - return PNP_COM_FATAL; - - modem_lines = get_serial_lines(fd); - - /* turn off RTS */ - modem_lines &= ~TIOCM_RTS; - set_serial_lines(fd, modem_lines); - - /* wait 200ms for DSR=1 */ - usleep(200000); - - dsr_status = get_serial_lines(fd) & TIOCM_DSR; - /* see if we got DSR coming up */ - - if (!dsr_status) { - /* turn DTR and RTS back on and try alternative methods */ - modem_lines |= TIOCM_DTR | TIOCM_RTS; - set_serial_lines(fd, modem_lines); - rc = PNP_COM_OK; - } - - /* COM port Setup, 1st phase */ - /* now we set port to be 1200 baud, 7 bits, no parity, 1 stop bit */ - temp = tcgetattr(fd, &portattr); - if (temp < 0) - return PNP_COM_FATAL; - /* goto 1200 baud, etc etc as PnP requires */ - temp = setup_serial_port( fd, 7, &portattr ); - if (temp < 0) - return PNP_COM_FATAL; - - /* we drop DTR and RTS */ - modem_lines &= ~( TIOCM_RTS | TIOCM_DTR); - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* bring DTR back up */ - modem_lines |= TIOCM_DTR; - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* now entering next phase */ - modem_lines |= TIOCM_RTS; - set_serial_lines(fd, modem_lines); - usleep(200000); - - return rc; -} - - -/* Request for PnP info from serial device */ -/* Uses ATI9 code, may not do anything but return 'ERROR' */ -/* Return code tells us what happened */ -/* */ -/* PNP_COM_FATAL - error, errno has reason */ -/* PNP_COM_OK - probe initiated successfully */ -/* PNP_COM_FAIL - DSR never came on - try alterntives */ -/* means (ATI9?) to get PnP string */ -int init_pnp_com_ati9( int fd ) { - int modem_lines; - int temp; - int done; - int respindex; - int starttime; - unsigned char resp[100], buf[2]; - struct timeval timo; - struct termios portattr; - - modem_lines = get_serial_lines(fd); - - /* turn off RTS */ - modem_lines &= ~TIOCM_RTS; - set_serial_lines(fd, modem_lines); - - /* wait 200ms for DSR=1 */ - usleep(200000); - - /* now we set port to be 1200 baud, 8 bits, no parity, 1 stop bit */ - temp = tcgetattr(fd, &portattr); - if (temp < 0) { - modem_lines |= TIOCM_DTR | TIOCM_RTS; - set_serial_lines(fd, modem_lines); - return PNP_COM_FATAL; - } - - /* goto 1200 baud, 8 bits */ - temp = setup_serial_port( fd, 8, &portattr ); - if (temp < 0) { - modem_lines |= TIOCM_DTR | TIOCM_RTS; - set_serial_lines(fd, modem_lines); - return PNP_COM_FATAL; - } - - /* turn on DTR and RTS */ - modem_lines = get_serial_lines(fd); - modem_lines |= TIOCM_RTS | TIOCM_DTR; - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* send the 'AT' command */ - if (debug_level > 0) - printf("Sending ATI9 command to modem\n"); - - write(fd, "ATI9\r", 5); - - /* start reading - read the AT command back */ - done = 0; - respindex= 0; - starttime=time(NULL); - memset(resp, 0, sizeof(resp)); - while (!done) { - timo.tv_sec=0; - timo.tv_usec=250000; - if (wait_for_input(fd, &timo) > 0) { - temp = read( fd, buf, 1 ); - if (temp < 0) { - if (errno != EAGAIN) - return PNP_COM_FATAL; - } else { - resp[respindex++] = buf[0]; - resp[respindex] = 0; - } - } else - done = 1; - - /* shouldnt run more than 5 seconds */ - if (time(NULL)-starttime > 5 ) - done = 1; - - if (respindex > 6) - done = 1; - - if (strstr(resp, "ATI9\r")) - done = 1; - - if (debug_level > 0) - printf("ATI9 probe ->%d \"%s\"\n",respindex, resp); - } - - /* see if we saw the 'OK' response */ - if (strstr(resp, "(")) - return PNP_COM_OK; - else - return PNP_COM_FAIL; - - return PNP_COM_OK; -} - -/* See if this is a legacy mouse device */ -/* Only called if the PnP probe above failed */ -/* We turn off the mouse via RS232 lines, then turn it on */ -/* If it spits out an 'M' character (at 1200 baud, 7N1) */ -/* it could be a mouse. */ -/* */ -/* Return code tells us what happened */ -/* */ -/* PNP_COM_FATAL - error, errno has reason */ -/* PNP_COM_OK - probe saw 'M' */ -/* PNP_COM_FAIL - Never saw the 'M' response */ - -int find_legacy_mouse( int fd ) { - int modem_lines; - int temp; - int done; - int starttime; - unsigned char resp[2]; - struct timeval timo; - struct termios portattr; - - /* now we set port to be 1200 baud, 7 bits, no parity, 1 stop bit */ - temp = tcgetattr(fd, &portattr); - if (temp < 0) - return PNP_COM_FATAL; - - /* goto 1200 baud, etc etc*/ - temp = setup_serial_port( fd, 7, &portattr ); - if (temp < 0) - return PNP_COM_FATAL; - - /* we drop DTR and RTS */ - modem_lines = get_serial_lines(fd); - modem_lines &= ~( TIOCM_RTS | TIOCM_DTR); - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* bring them DTR back up */ - modem_lines |= TIOCM_DTR | TIOCM_RTS; - set_serial_lines(fd, modem_lines); - - /* start reading - after first character we quit */ - done = 0; - starttime=time(NULL); - while (!done) { - timo.tv_sec=0; - timo.tv_usec=250000; - if (wait_for_input(fd, &timo) > 0) { - temp = read( fd, resp, 1 ); - if (temp < 0) { - if (errno != EAGAIN) - return PNP_COM_FATAL; - } else { - done = 1; - } - } else - done = 1; - - - /* shouldnt run more than 2 seconds */ - if (time(NULL)-starttime > 2 ) - done = 1; - } - if (*resp == 'M') - return PNP_COM_OK; - else - return PNP_COM_FAIL; -} - -/* See if this is a legacy modem device */ -/* Only called if the PnP probe above failed */ -/* We send a '!AT' and see if we get an 'OK' back */ -/* */ -/* Return code tells us what happened */ -/* */ -/* PNP_COM_FATAL - error, errno has reason */ -/* PNP_COM_OK - probe saw 'OK' */ -/* PNP_COM_FAIL - Never saw the 'OK' response */ -int find_legacy_modem( int fd ) { - int modem_lines; - int temp; - int done; - int respindex; - int starttime; - unsigned char resp[10], buf[2]; - struct timeval timo; - struct termios portattr; - - /* now we set port to be 1200 baud, 8 bits, no parity, 1 stop bit */ - temp = tcgetattr(fd, &portattr); - if (temp < 0) - return PNP_COM_FATAL; - - /* goto 1200 baud, 8 bits */ - temp = setup_serial_port( fd, 8, &portattr ); - if (temp < 0) - return PNP_COM_FATAL; - - /* turn on DTR and RTS */ - modem_lines = get_serial_lines(fd); - modem_lines |= TIOCM_RTS | TIOCM_DTR; - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* send the 'AT' command */ - if (debug_level > 0) - printf("Sending AT command to modem\n"); - - write(fd, "AT\r", 3); - - /* start reading - we'll get AT command back first, then modem response */ - done = 0; - respindex= 0; - starttime=time(NULL); - memset(resp, 0, sizeof(resp)); - while (!done) { - timo.tv_sec=0; - timo.tv_usec=250000; - if (wait_for_input(fd, &timo) > 0) { - temp = read( fd, buf, 1 ); - if (temp < 0) { - if (errno != EAGAIN) - return PNP_COM_FATAL; - } else { - resp[respindex++] = buf[0]; - } - } else - done = 1; - - /* shouldnt run more than 5 seconds */ - if (time(NULL)-starttime > 5 ) - done = 1; - - if (respindex > 9) - done = 1; - } - - /* see if we saw the 'OK' response */ - if (strstr(resp, "OK")) - return PNP_COM_OK; - else - return PNP_COM_FAIL; -} - -/* retrieve the PnP ID string */ -/* timeout after 3 seconds */ -/* should probably set a 200 msec timeout per char, as spec says */ -/* if no char received, we're done */ -int read_pnp_string( int fd, unsigned char *pnp_string, int *pnp_len, int pnp_stringbuf_size ) { - int pnp_index; - int temp, done, counter; - int seen_start; - time_t starttime; - struct timeval timo; - unsigned char buf[80]; - unsigned char end_char; - - /* see if we have any input waiting */ - pnp_index =0; - seen_start = 0; - done = 0; - end_char = 0; - starttime=time(NULL); - while (!done) { - timo.tv_sec=0; - timo.tv_usec=250000; - if (wait_for_input(fd, &timo) > 0) { - temp = read( fd, buf, 1 ); - if (temp < 0) { - if (errno != EAGAIN) - return PNP_COM_FATAL; - } else { - for (counter=0; counter < temp; counter++) { - pnp_string[pnp_index++] = buf[counter]; - if (seen_start) { - if (buf[counter] == end_char) { - done=1; - break; - } - } else { - if (buf[counter] == BeginPnP1) { - seen_start = 1; - end_char = EndPnP1; - } else if (buf[counter] == BeginPnP2) { - seen_start = 1; - end_char = EndPnP2; - } - } - } - } - } else - done = 1; - - /* shouldnt run more than 4 seconds */ - if (time(NULL)-starttime > 4 ) - done = 1; - - if (pnp_index >= pnp_stringbuf_size) - done = 1; - } - pnp_string[pnp_index] = 0; - *pnp_len=pnp_index; - return 0; -} - -/* UNUSED */ -/* simple little helper function */ -void xlate_memcpy( void *dest, void *src, int len, int xlate_flag ) { - unsigned char *d, *s; - int i; - - for (i=0,d=dest,s=src; i<len; i++, d++, s++) - *d = (*s) + ((xlate_flag) ? 0x20 : 0 ); -} - -/* parse the PnP ID string into components */ -int parse_pnp_string( unsigned char *pnp_id_string, int pnp_len, - struct pnp_com_id *pnp_id ) { - unsigned char *p1, *p2; - unsigned char *start; - unsigned char *end; - unsigned char *curpos; - unsigned char *endfield; - unsigned char *temppos; - unsigned char *pnp_string; - unsigned char end_char; - - int no_more_extensions=0; - int stage; - int len; - unsigned short int checksum; - char hex_checksum[5]; - - char extension_delims[] = {EndPnP1, EndPnP2, ExtendPnP1, ExtendPnP2, 0}; - char end_delims[] = {EndPnP1, EndPnP2, 0}; - - /* clear out pnp_id */ - memset(pnp_id, 0, sizeof(*pnp_id)); - - /* copy pnp_string to temp space */ - pnp_string = alloca(pnp_len+1); - memcpy(pnp_string, pnp_id_string, pnp_len+1); - - /* first find the start of the PnP part of string */ - p1 = memchr( pnp_string, BeginPnP1, pnp_len ); - p2 = memchr( pnp_string, BeginPnP2, pnp_len ); - - /* use the one which points nearest to start of the string */ - /* and is actually defined */ - if ( p1 && p2 ) { - start = (p1 < p2) ? p1 : p2; - } else if (p1) - start = p1; - else if (p2) - start = p2; - else - start = NULL; - - /* if no start then we're done */ - if (!start) - return -1; - - /* the length of the initial part cannot be more than 17 bytes */ - if ((start - pnp_string) > 17) - return -1; - - /* setup end character we are looking for based on the start character */ - if (start == p2) { - pnp_id->xlate_6bit = 1; - end_char = EndPnP2; - /* we need to xlate data in PnP fields */ - /* remember to skip the revision fields (bytes 1 and 2 after start) */ - temppos=start; - while (1) { - if (*temppos == EndPnP2) { - *temppos += 0x20; - break; - } else if (temppos != start+1 && temppos != start+2 ) - *temppos += 0x20; - - temppos++; - } - } else { - pnp_id->xlate_6bit = 0; - end_char = EndPnP1; - } - - /* move everything before the start of the PnP block */ - memcpy(pnp_id->other_id, pnp_string, start-pnp_string); - pnp_id->other_len = start - pnp_string; - - /* now we get the PnP fields - all were zero'd out above */ - curpos = start+1; - memcpy(pnp_id->pnp_rev,curpos,2); curpos += 2; - memcpy(pnp_id->eisa_id,curpos,3); curpos += 3; - memcpy(pnp_id->product_id,curpos,4); curpos += 4; - /* now we see if have extension fields */ - no_more_extensions = 0; - stage = 0; - while (!no_more_extensions) { - if (*curpos == ExtendPnP1 || *curpos == ExtendPnP2) { - curpos++; - endfield = strpbrk(curpos, extension_delims); - if (!endfield) - return -1; - /* if we reached the end of all PnP data, back off */ - /* cause there is a checksum at the end of extension data */ - if (*endfield == EndPnP1 || *endfield == EndPnP2) - endfield -= 2; - } else - break; - - len = endfield - curpos; - switch (stage) { - case 0: - if (len != 8 && len != 0 ) - return -1; - - memcpy(pnp_id->serial_number,curpos,len); - curpos += len; - break; - - case 1: - if (len > 33) - return -1; - memcpy(pnp_id->class_name, curpos, len); - curpos = endfield; - break; - - case 2: - if (len > 41) - return -1; - memcpy(pnp_id->driver_id, curpos, len); - curpos = endfield; - break; - - case 3: - if (len > 41) - return -1; - memcpy(pnp_id->user_name, curpos, len); - curpos = endfield; - break; - } - stage++; - } - - /* now find the end of all PnP data */ - end = strpbrk(curpos, end_delims); - if (!end) - return -1; - - /* if we had any extensions, we expect an checksum */ - if (stage != 0) { - /* copy checksum into struct */ - memcpy(pnp_id->checksum, curpos, 2); - - /* compute the checksum as the sum of all PnP bytes, excluding */ - /* the two byte checksum. */ - checksum = 0; - for (temppos=start; temppos <= end; temppos++) { - /* skip checksum in calculation */ - if (temppos == (end-2) || temppos == (end-1)) - continue; - /* dont xlate the revision at start */ - if (temppos != (start+1) && temppos != (start+2)) - checksum += *temppos - ((pnp_id->xlate_6bit) ? 0x20 : 0); - else - checksum += *temppos; - } - sprintf(hex_checksum, "%.2X", checksum & 0xff); - if (strncmp(hex_checksum, pnp_id->checksum, 2)) - return -1; - } - - /* checksum was ok, so we're done */ - return 0; -} - -/* UNUSED except for debugging */ -void print_pnp_id( struct pnp_com_id id ) { - int i; - int extensions_exist; - int revision_temp; - - if (id.other_len != 0) { - printf("Detected non-PnP data stream at start.\n"); - printf(" Length = 0x%x\n",id.other_len); - printf(" Contents ="); - for (i=0; i<id.other_len; i++) - printf(" 0x%x",id.other_id[i]); - printf("\n"); - } else - printf("Non-PnP data stream not detected at start.\n"); - - - /* parse PnP revision bytes into a string values (eg. "1.00") */ - revision_temp = ((id.pnp_rev[0]&0x3f) << 6)+(id.pnp_rev[1]&0x3f); - sprintf(id.pnp_rev_str, "%d.%d",revision_temp/100,revision_temp % 100); - - printf("\nPnP Required fields:\n"); - printf(" Revision = %s\n",id.pnp_rev_str); - printf(" Manufacturer = %s\n",id.eisa_id); - printf(" Product ID = %s\n",id.product_id); - - extensions_exist = id.serial_number[0] || id.class_name[0] || - id.driver_id[0] || id.user_name[0]; - - if (extensions_exist) { - printf("\nPnP extension field(s) exist:\n"); - if (id.serial_number[0]) - printf(" Serial Number = %s\n",id.serial_number); - if (id.class_name[0]) - printf(" PnP class name = %s\n",id.class_name); - if (id.driver_id[0]) - printf(" PnP Compatible = %s\n",id.driver_id); - if (id.user_name[0]) - printf(" PnP Description = %s\n",id.user_name); - } -} - -int attempt_pnp_retrieve(int fd, char *pnp_string, int *pnp_strlen, int pnp_stringbuf_size) { - int pnp_probe_status; - int tried_at_prodding; - int give_up; - struct pnp_com_id pnp_id; - - tried_at_prodding=0; - give_up=0; - - while (!give_up) { - pnp_probe_status = init_pnp_com_seq1(fd); - if (pnp_probe_status == PNP_COM_FATAL) { - return(PNP_COM_FATAL); - } else if (pnp_probe_status == PNP_COM_OK) { - read_pnp_string(fd, pnp_string, pnp_strlen, pnp_stringbuf_size ); - - if (debug_level > 0) { - printf("\nPNP string = |%s|\n\n",pnp_string); - print_hex_data(pnp_string, *pnp_strlen); - } - - if (*pnp_strlen == 1 && pnp_string[0] == 'M') /* legacy mouse */ - return PNP_COM_OK; - /* see if we got anything useful, if not try at command */ - /* to prod device into correct serial params */ - if (parse_pnp_string( pnp_string, *pnp_strlen, &pnp_id )<0) - if (!tried_at_prodding) { - write(fd, "AT\r", 3); - tried_at_prodding=1; - } else - give_up = 1; - else - return PNP_COM_OK; - } else - give_up = 1; - } - - /* try sending a ATI9 code to the modem to see if we get PnP id back */ - init_pnp_com_ati9(fd); - read_pnp_string(fd, pnp_string, pnp_strlen, pnp_stringbuf_size ); - if (parse_pnp_string( pnp_string, *pnp_strlen, &pnp_id )<0) { - *pnp_strlen = 0; - pnp_string[0] = 0; - return PNP_COM_FAIL; - } else - return PNP_COM_OK; -} - -struct device *serialProbe(enum deviceClass probeClass, int probeFlags, - struct device *devlist) { - int fd; - int temp; - int pnp_strlen; - int devicetype=-1; - unsigned char pnp_string[100]; - char port[20]; - struct termios origattr; - struct pnp_com_id pnp_id; - struct serialDevice *serdev; - struct stat sb; - int maj, twelve=12; - int console=-1; - int stdin_line=-1; - struct serial_struct si; - - if (probeFlags & PROBE_SAFE) return devlist; - - /* Are we on a serial console? */ - fstat(0,&sb); - maj = major(sb.st_rdev); - if (maj != 4 && (maj < 136 || maj > 143)) { - if (ioctl (0, TIOCLINUX, &twelve) < 0) { - if (ioctl (0, TIOCGSERIAL, &si) >= 0) { - if (si.line > 0) { - stdin_line = 1 << si.line; - } else { - stdin_line = 0; - } - } else stdin_line = 0; - } - } - - fd=open("/dev/console",O_RDWR); - if (fd != -1) { - fstat(fd,&sb); - maj = major(sb.st_rdev); - if (maj != 4 && (maj < 136 || maj > 143)) { - if (ioctl (fd, TIOCLINUX, &twelve) < 0) { - #ifdef __powerpc__ - // we could have gotten an error for another reason - like EINVAL - // skipping ttyS0 on PPC - which is where most modems reside - if (errno == ENOTTY) { - #endif - if (ioctl (fd, TIOCGSERIAL, &si) >= 0) { - if (si.line > 0) { - console = 1 << si.line; - } else { - console = 0; - } - } else console = 0; - #ifdef __powerpc__ - } - #endif - } - } - close(fd); - } - - - if ( - (probeClass == CLASS_UNSPEC) || - (probeClass == CLASS_OTHER) || - (probeClass == CLASS_MOUSE) || - (probeClass == CLASS_MODEM) || - (probeClass == CLASS_PRINTER) - ) { - int x; - - for (x=0; x<=3 ; x++) { - struct stat sbuf; - char lockfile[32]; - if (x==console || x==stdin_line) continue; - snprintf(port,20,"/dev/ttyS%d",x); - - /* Make sure it's not in use */ - snprintf(lockfile,32,"/var/lock/LCK..ttyS%d",x); - if (!stat(lockfile,&sbuf)) - continue; - memset(lockfile,'\0',32); - if (readlink("/dev/modem",lockfile,32)>0) { - if (!strcmp(basename(port),basename(lockfile))) { - snprintf(lockfile,32,"/var/lock/LCK..modem"); - if (!stat(lockfile,&sbuf)) - continue; - } - } - - if ((fd=open_serial_port(port)) < 0) { - continue; - } - /* save the current state of the port */ - temp = tcgetattr(fd, &origattr); - if (temp < 0) { - close(fd); - continue; - } - - /* try twiddling RS232 control lines and see if it talks to us */ - devicetype=-1; - pnp_strlen = 0; - attempt_pnp_retrieve( fd, pnp_string, &pnp_strlen, sizeof(pnp_string) - 1 ); - - /* see if we found any PnP signature */ - if (pnp_strlen != 0) { - if (*pnp_string == 'M') { /* Legacy mouse */ - if (probeClass == CLASS_MOUSE || probeClass == CLASS_UNSPEC) { - serdev = serialNewDevice(NULL); - serdev->class=CLASS_MOUSE; - serdev->device=strdup(port+5); - serdev->desc=strdup("Generic Serial Mouse"); - serdev->driver=strdup("generic"); - if (devlist) - serdev->next = devlist; - devlist = (struct device *)serdev; - if (probeFlags & PROBE_ONE) { - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - return devlist; - } - } - tcsetattr(fd, TCSANOW, &origattr); - close(fd); - continue; - } - /* fill in the PnP com structure */ - if (parse_pnp_string( pnp_string, pnp_strlen, &pnp_id )<0) { - goto endprobe; - } else { - char *foo; - int len; - - if (debug_level > 0) { - printf("PnP ID string for serial device on port %s\n",port); - print_pnp_id( pnp_id ); - } - serdev = serialNewDevice(NULL); - if (pnp_id.user_name[0]) { - serdev->pnpdesc = strdup(pnp_id.user_name); - len = strlen(pnp_id.eisa_id)+strlen(pnp_id.product_id)+strlen(pnp_id.user_name)+3; - foo = malloc(len); - snprintf(foo,len,"%s|%s %s",pnp_id.eisa_id,pnp_id.product_id,pnp_id.user_name); - } else { - len = strlen(pnp_id.eisa_id)+strlen(pnp_id.product_id)+3; - foo = malloc(len); - snprintf(foo,len,"%s|%s",pnp_id.eisa_id,pnp_id.product_id); - } - serdev->desc=strdup(foo); - serdev->device=strdup(port+5); - serdev->driver=strdup("ignore"); - serdev->pnpmfr = strdup(pnp_id.eisa_id); - serdev->pnpmodel = strdup(pnp_id.product_id); - - free(foo); - foo=pnp_id.product_id; - if (pnp_id.driver_id) { - if (strstr(pnp_id.driver_id,"PNP")) - foo = strstr(pnp_id.driver_id,"PNP")+3; - serdev->pnpcompat = strdup(pnp_id.driver_id); - } - if (!strncmp(foo, "0F", 2)) - serdev->class = CLASS_MOUSE; - else if (!strncmp(foo, "C", 1)) - serdev->class = CLASS_MODEM; - else if (!strncmp(pnp_id.class_name, "Modem", 5)) - serdev->class = CLASS_MODEM; - else - serdev->class = CLASS_OTHER; - if (serdev->class == probeClass || probeClass == CLASS_UNSPEC) { - if (devlist) - serdev->next = devlist; - devlist = (struct device *)serdev; - if (probeFlags & PROBE_ONE) { - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - return devlist; - } - } else { - serdev->freeDevice(serdev); - } - goto endprobe; - } - } else { - /* try to find a legacy device */ - - temp = find_legacy_mouse(fd); - if (temp == PNP_COM_FATAL) { - goto endprobe; - } else if (temp == PNP_COM_OK) { - if (probeClass == CLASS_UNSPEC || probeClass == CLASS_MOUSE) { - serdev=serialNewDevice(NULL); - serdev->class = CLASS_MOUSE; - serdev->device = strdup(port+5); - serdev->driver= strdup("generic"); - serdev->desc = strdup("Generic Serial Mouse"); - if (devlist) - serdev->next = devlist; - devlist = (struct device *)serdev; - if (probeFlags & PROBE_ONE) { - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - return devlist; - } - } - goto endprobe; - } else { - if (debug_level > 0) - printf("Didnt see a legacy mouse, need to ATI it now.\n"); - - temp = find_legacy_modem(fd); - if (temp == PNP_COM_FATAL) { - goto endprobe; - } else if (temp == PNP_COM_OK) { - if (debug_level > 0) - printf("\nLegacy modem signature seen.\n\n"); - if (probeClass == CLASS_UNSPEC || probeClass == CLASS_MODEM) { - serdev=serialNewDevice(NULL); - serdev->class = CLASS_MODEM; - serdev->device = strdup(port+5); - serdev->driver= strdup("ignore"); - serdev->desc = strdup("Generic Serial Modem"); - if (devlist) - serdev->next = devlist; - devlist = (struct device *)serdev; - if (probeFlags & PROBE_ONE) { - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - return devlist; - } - } - goto endprobe; - } else { - if (debug_level > 0) - printf("Didnt see a legacy modem, game over.\n"); - } - } - } -endprobe: - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - } - } - return devlist; -} |