/* 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.
*
*/
/* 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;
}
/* 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 ) {
/* 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.
*/
/* 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;
}
/* 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;
/* 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;
/* 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;
/* 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;
/* 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;
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");
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 (*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) {
if (ioctl (fd, TIOCGSERIAL, &si) >= 0) {
if (si.line > 0) {
console = 1 << si.line;
} else {
console = 0;
}
} else console = 0;
}
}
close(fd);
}
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
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;
}