diff options
Diffstat (limited to 'tools/serial_probe/serial.c')
-rw-r--r-- | tools/serial_probe/serial.c | 1136 |
1 files changed, 0 insertions, 1136 deletions
diff --git a/tools/serial_probe/serial.c b/tools/serial_probe/serial.c deleted file mode 100644 index c84cbcff5..000000000 --- a/tools/serial_probe/serial.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* Copyright 1999-2003 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. - * - * probe serial port for PnP/Legacy devices - */ - - -#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 <sys/sysmacros.h> - -#include <asm/types.h> -#include <linux/serial.h> - -#include "serial.h" -#include "kudzu.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 */ - -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; -} - -/* - * wait_input - wait until there is data available on fd, - * for the length of time specified by *timo (indefinite - * if timo is NULL). - */ - -static 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; -} - -static int open_serial_port( char *port ) { - int fd; - - DEBUG("opening serial port %s...", port); - - fd = open( port, O_RDWR | O_NONBLOCK); - if (fd < 0) { - DEBUG("failed.\n"); - return -1; - } else { - DEBUG("successful.\n"); - } - - /* reset file so it is no longer in non-blocking mode */ - if (fcntl(fd, F_SETFL, 0) < 0) { - close(fd); - DEBUG("Failed to set port to non-blocking mode\n"); - return -1; - } - - return fd; -} - -/* <0 means ioctl error occurred */ -static int get_serial_lines( int fd ) { - int modem_lines; - - ioctl(fd, TIOCMGET, &modem_lines); - return modem_lines; -} - -/* <0 means ioctl error occurred */ -static 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 */ -static int setup_serial_port( int fd, int nbits, struct termios *attr ) { - - DEBUG("setting up serial port\n"); - - 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; - - if (cfsetospeed( attr, B1200)) - return -1; - if (cfsetispeed( attr, B1200)) - return -1; - 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. - */ - -static 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 */ -static int init_pnp_com_seq1( int fd ) { - int modem_lines; - int temp; - int dsr_status; - int rc = PNP_COM_OK; - struct termios portattr; - - DEBUG("initializing 1st PNP sequence\n"); - if (init_port(fd)) - return PNP_COM_FATAL; - - modem_lines = get_serial_lines(fd); - - /* COM port initialization, check for device enumerate */ - - /* turn on DTR, turn off RTS */ - modem_lines |= TIOCM_DTR; - 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) { - DEBUG("Device did not set DSR\n"); - } - - /* COM port Setup, 1st phase */ - temp = tcgetattr(fd, &portattr); - if (temp < 0) - return PNP_COM_FATAL; - - /* now we set port to be 1200 baud, 7 bits, no parity, 1 stop bit */ - 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); - - /* Wait for response, 1st phase */ - modem_lines |= TIOCM_RTS; - set_serial_lines(fd, modem_lines); - /* usleep(200000); => AQ: not valid as we should look to receive data during this time!! */ - - return rc; -} - - -/* Request for PnP info from serial device */ -/* See page 6 of the pnpcom doc from Microsoft */ -/* Always returns PNP_COM_OK */ -static int init_pnp_com_seq2( int fd ) { - int modem_lines; - int rc = PNP_COM_OK; - - DEBUG("initializing 2nd PNP sequence\n"); - - modem_lines = get_serial_lines(fd); - - /* COM port setup, 2nd phase */ - /* turn off DTR and RTS */ - modem_lines &= ~(TIOCM_DTR | TIOCM_RTS); - set_serial_lines(fd, modem_lines); - usleep(200000); - - /* wait for response, 2nd phase */ - /* turn on DTR and RTS */ - modem_lines |= (TIOCM_DTR | TIOCM_RTS); - set_serial_lines(fd, modem_lines); - /* usleep(200000); => AQ: not valid as we should look to receive data during this time!! */ - - return rc; -} - - -/* Request for PnP info from serial modem 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 */ -static 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; - - DEBUG("Querying ATI9 info from modem\n"); - 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 */ - DEBUG("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; - - DEBUG("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 */ - -static 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; - - DEBUG("looking for a legacy mouse\n"); - - /* 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') { - DEBUG("Found legacy mouse\n"); - 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 */ -static 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; - - DEBUG("looking for a legacy modem\n"); - - /* 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 */ - DEBUG("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 */ -static 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; - - DEBUG("Attempting to read PNP ID string\n"); - - /* 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_FAIL; - } 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 3 seconds */ - if (time(NULL)-starttime > 3 ) - done = 1; - - if (pnp_index >= pnp_stringbuf_size) - done = 1; - } - pnp_string[pnp_index] = 0; - *pnp_len=pnp_index; - if(*pnp_len > 0) - return PNP_COM_OK; - else /* allows to call seq2 to be conformant */ - return PNP_COM_FAIL; -} - -/* parse the PnP ID string into components */ -static 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}; - unsigned char* p1end = NULL; - unsigned char* p2end = NULL; - - /* 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 ); - - - if (p1) { - int p_len = pnp_len - (p1 - pnp_string); - p1end = memchr(p1, EndPnP1, p_len); - } - if (p2) { - int p_len = pnp_len - (p2 - pnp_string); - p2end = memchr(p2, EndPnP2, p_len); - } - - /* use the one which points nearest to start of the string */ - /* and is actually defined */ - if ( p1 && p1end && p2 && p2end ) { - start = (p1 < p2) ? p1 : p2; - } else if ( p1 && p1end ) - start = p1; - else if ( p2 && p2end ) - 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; -} - -static int attempt_pnp_retrieve(int fd, char *pnp_string, int *pnp_strlen, int pnp_stringbuf_size) { - int pnp_probe_status; - struct pnp_com_id pnp_id; - int tried_at_prodding=0, give_up=0; - - DEBUG("Attempting PNP information retrieval\n"); - - while (!give_up) { - pnp_probe_status = init_pnp_com_seq1(fd); - if (pnp_probe_status == PNP_COM_FATAL) - return PNP_COM_FATAL; - pnp_probe_status = read_pnp_string(fd, pnp_string, pnp_strlen, - pnp_stringbuf_size); - if (pnp_probe_status == PNP_COM_FAIL) { - init_pnp_com_seq2(fd); /* always succeeds */ - - pnp_probe_status = read_pnp_string(fd, pnp_string, pnp_strlen, - pnp_stringbuf_size); - } - - 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) { - DEBUG("That failed.\n"); - if (!tried_at_prodding) { - DEBUG("Prod modem with AT command.\n"); - write(fd, "AT\r", 3); - tried_at_prodding=1; - } else - give_up = 1; - } else - return PNP_COM_OK; - } - - /* normal PNP detection has failed. */ - /* 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; - - DEBUG("Probing for serial ports\n"); - - 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; - #ifdef __powerpc__ - } - #endif - } - } else console = 0; - } - } - 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)) { - DEBUG("Port %s in use, skipping probe.\n", - port); - 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)) { - DEBUG("Port %s in use, skipping probe.\n", - port); - continue; - } - } - } - - if ((fd=open_serial_port(port)) < 0) { - continue; - } - /* save the current state of the port */ - temp = tcgetattr(fd, &origattr); - if (temp < 0) { - DEBUG("unable to retrieve port attributes...no port present?\n"); - close(fd); - continue; - } - - - /* try twiddling RS232 control lines and see if it talks to us */ - devicetype=-1; - pnp_strlen = 0; - if (attempt_pnp_retrieve( fd, pnp_string, &pnp_strlen, - sizeof(pnp_string) - 1 ) == PNP_COM_FATAL) - goto endprobe; - - /* see if we found any PnP signature */ - if (pnp_strlen != 0 && (pnp_strlen != 1 || pnp_string[0] != 'M')) { - - /* fill in the PnP com structure */ - if (parse_pnp_string( pnp_string, pnp_strlen, &pnp_id )<0) { - DEBUG("Got PNP data back, but failed to parse. Aborting\n"); - goto endprobe; - } else { - char *foo; - int len; - - DEBUG("PNP data parsed.\n"); - 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); - } - if (serdev->desc) free(serdev->desc); - serdev->desc=strdup(foo); - serdev->device=strdup(port+5); - if (serdev->driver) free(serdev->driver); - 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 (*pnp_id.other_id == 'M' || - !strncmp(pnp_id.class_name, "MOUSE", 5) || - !strncmp(foo, "0F", 2)) { - serdev->type = CLASS_MOUSE; - if (!strncmp(serdev->desc, "|", 1)) { - free(serdev->desc); - serdev->desc=strdup("Generic Serial Mouse"); - } - if (serdev->driver) free(serdev->driver); - serdev->driver = strdup("generic"); - } - else if (!strncmp(pnp_id.class_name, "MODEM", 5) || - !strncmp(foo, "C", 1)) - serdev->type = CLASS_MODEM; - else if (!strncmp(pnp_id.class_name, "PRINTER", 7)) - serdev->type = CLASS_PRINTER; - else - serdev->type = CLASS_OTHER; - if (serdev->type & probeClass) { - 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 { - DEBUG("No PNP data received.\n"); - /* 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_MOUSE) { - serdev=serialNewDevice(NULL); - serdev->type = 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 { - DEBUG("Didn't see a legacy mouse.\n"); - - temp = find_legacy_modem(fd); - if (temp == PNP_COM_FATAL) { - goto endprobe; - } else if (temp == PNP_COM_OK) { - DEBUG("Legacy modem signature seen.\n"); - if (probeClass & CLASS_MODEM) { - serdev=serialNewDevice(NULL); - serdev->type = 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 { - DEBUG("Didnt see a legacy modem, game over.\n"); - } - } - } - endprobe: - DEBUG("Restoring original port attributes\n"); - tcsetattr(fd, TCSANOW, &origattr); - tcflush(fd, TCIOFLUSH); - close(fd); - } - } - return devlist; -} |