home *** CD-ROM | disk | FTP | other *** search
- /* very simple set of routines to get back what is stored in /proc/pci in */
- /* a programmer friendly fashion. Also tries to map a pci entry into a */
- /* kernel module name to aid autoloading modules during an install */
- /* Michael Fulbright Sept 1997 */
-
- #include <stdio.h>
- #include <strings.h>
- #include <malloc.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <ctype.h>
-
- #include "pciprobe.h"
- #include "pci-ids.h"
-
-
- /* clean up that string */
- static void TrimWhitespace( char *s ) {
- char *f, *l, *p, *q;
-
- if (!(*s))
- return;
-
- for (f=s; *f && isspace(*f); f++) ;
-
- if (!*f) {
- *s = '\0';
- return;
- }
-
- for (l=f+strlen(f)-1; isspace(*l) ; l--)
- *l = '\0';
-
- q = s, p = f;
- while (*p)
- *q++ = *p++;
-
- *q = '\0';
- }
-
-
- /* create a new clean pciDevice entry */
- struct pciDevice *pciNewDevice( void ) {
- struct pciDevice *p;
-
- p = (struct pciDevice *) malloc( sizeof(struct pciDevice) );
- p->nhits = 0;
- p->name=NULL;
- p->module=NULL;
- p->class=PCI_UNSET;
- return p;
- }
-
- /* remove a pciDevice */
- void pciFreeDevice( struct pciDevice *p ) {
- int i;
-
- if (p->name) {
- for (i=0; i<p->nhits; i++)
- free(p->name[i]);
- free(p->name);
- }
-
- if (p->module) {
- for (i=0; i<p->nhits; i++)
- free(p->module[i]);
- free(p->module);
- }
-
- free(p);
- }
-
-
- /* given a class to probe, returns an array of devices found which match */
- /* all entries are malloc'd, so caller must free when done. Use */
- /* pciDeviceFree() to free individual pciDevice's, since they have */
- /* internal elements which are malloc'd */
- /* returns number cards found. If nothing found returns 0 and */
- /* setsdevs is set to NULL */
- /* if system error occurs (like no /proc/pci!) returns -1 */
- int pciProbeDevice( enum pciClass type, struct pciDevice ***devs ) {
- int done;
- int found, maxlen, maxidx;
- int ok, first;
- int ndevs, nmatches;
- int bus, device, function;
- int nonvgadev, madeentry;
- int i, len;
- char *devtype, *devmodel, *vendorid, *deviceid, *mapped, *mapname, *eptr;
- int stage;
- unsigned int devnumid, vennumid;
- FILE *f;
- char buf[100];
-
- struct pci_module_map *pcidb;
-
- /* open /proc/pci and parse output */
- f=fopen("/proc/pci", "r");
- if (!f) {
- return -1;
- }
-
- done = 0;
- stage = 0;
- ndevs = 0;
- *devs = NULL;
- while (!done) {
- if (!fgets(buf,100,f))
- break;
-
- madeentry = 0; /* havent made nothin yet */
-
- /* see what we're looking for */
- if (stage == 0) {
- /* need to find start of list of PCI devices */
- if (!strncmp(buf, "PCI devices found:", 18))
- stage++;
- continue;
- } else if (stage == 1) {
- /* looking for a line starting with 'Bus' */
- if (strstr(buf, "Bus") && strstr(buf, "device")) {
- /* found it, now parse out stuff we care about */
- sscanf(buf, " Bus %d, device %d, function %d:\n",
- &bus, &device, &function);
-
- /* read the next line for other goodies */
- if (!fgets(buf,100,f))
- break;
-
- /* strip out devtype and model of card */
- devmodel = strchr(buf, ':');
- if (!devmodel)
- continue;
- *devmodel++ = 0;
-
- /* blow revision number off end of devmodel */
- if ((eptr=strrchr(devmodel, '(')))
- *eptr = 0;
- devtype=strdup(buf);
- devmodel=strdup(devmodel);
- TrimWhitespace(devtype);
- TrimWhitespace(devmodel);
-
- /* see if its the class we're looking for */
- /* nonvgadev tells use card didnt set a class */
- /* so we have to see if it happens to match a */
- /* entry in the class db we have */
- ok = 1;
- nonvgadev = strstr(devtype, CLASS_NONE) != NULL;
-
- switch (type) {
- case PCI_ETHERNET:
- ok = strstr(devtype, CLASS_ETHERNET) != NULL || nonvgadev;
- break;
- case PCI_SCSI:
- ok = strstr(devtype, CLASS_SCSI) != NULL || nonvgadev;
- break;
- case PCI_VIDEO:
- ok = strstr(devtype, CLASS_VIDEO) != NULL ||
- strstr(devtype, CLASS_VIDEO_OTHER) != NULL ||
- nonvgadev;
- break;
- default:
- ok = 0;
- break;
- }
-
- if (!ok) {
- free(devtype);
- free(devmodel);
- continue;
- }
-
- /* see if its an unknown model */
- deviceid = vendorid = NULL;
- if (strstr(devmodel, "Unknown")) {
- if (!fgets(buf,100,f))
- break;
- if (strstr(buf, "Vendor id")) {
- char *s, *t, *v;
- s = strchr(buf, '=');
- if (s) {
- s++;
- t = strchr(s, '.');
- if (t) {
- *t = 0;
- t = strchr(t+1, '=');
- if (t) {
- t++;
- v = strchr(t, '.');
- if (v) {
- *v = 0;
- vendorid = strdup(s);
- deviceid = strdup(t);
- TrimWhitespace(vendorid);
- TrimWhitespace(deviceid);
- devnumid=strtol(deviceid, &eptr, 16);
- vennumid=strtol(vendorid, &eptr, 16);
- }
- }
- }
- }
- }
- }
-
- /* now find all matches and stick into entry */
- switch (type) {
- case PCI_ETHERNET:
- pcidb = eth_pci_ids;
- len = eth_num_ids;
- break;
- case PCI_SCSI:
- pcidb = scsi_pci_ids;
- len = scsi_num_ids;
- break;
- case PCI_VIDEO:
- pcidb = video_pci_ids;
- len = video_num_ids;
- break;
- default:
- pcidb = NULL;
- len = 0;
- }
-
- /* gotta find the maximally matching entry(s) */
- maxlen = -1;
- if (!strstr(devmodel,"Unknown")) {
- for (i=0; i<len; i++) {
- if (strstr(devmodel, pcidb[i].name)) {
- int l=strlen(pcidb[i].name);
- if (l > maxlen) {
- maxlen = l;
- }
- }
- }
- }
-
- first = 1;
- nmatches = 0;
- i = 0;
- while ( 1 ) {
- found = 0;
- if (strstr(devmodel, "Unknown")) {
- for (; i<len &&
- (vennumid != pcidb[i].vendor ||
- devnumid != pcidb[i].device); i++);
- found = (i < len);
- if (found)
- maxidx = i;
- } else {
- for (; i<len; i++){
- if (strstr(devmodel, pcidb[i].name)) {
- int l=strlen(pcidb[i].name);
- if (l >= maxlen) {
- maxidx = i;
- found = 1;
- break;
- }
- }
- }
- }
-
- if (!found) {
- if (!first || nonvgadev)
- break;
- else {
- mapped = "UNKNOWN";
- mapname = "UNKNOWN";
- }
- } else {
- mapped = (char *) pcidb[maxidx].module;
- mapname = (char *) pcidb[maxidx].name;
- }
-
- first = 0;
-
- /* insert into current pciDevice */
- /* we got enough info, let make a device entry */
- if (!madeentry) {
- if ((ndevs % 4) == 0)
- *devs=(struct pciDevice **)
- realloc(*devs,(ndevs+4)*sizeof(struct pciDevice *));
- (*devs)[ndevs]=pciNewDevice();
- }
-
- madeentry = 1;
-
- (*devs)[ndevs]->name=realloc((*devs)[ndevs]->name,
- (nmatches+1)*sizeof(char *));
- (*devs)[ndevs]->module=realloc((*devs)[ndevs]->module,
- (nmatches+1)*sizeof(char *));
- (*devs)[ndevs]->name[nmatches]=strdup(mapname);
- (*devs)[ndevs]->module[nmatches]=strdup(mapped);
- i++;
- nmatches++;
- }
-
- if (vendorid)
- free(vendorid);
- if (deviceid)
- free(deviceid);
- free(devtype);
- free(devmodel);
- if (madeentry) {
- (*devs)[ndevs]->nhits=nmatches;
- (*devs)[ndevs]->class=type;
- ndevs++;
- }
- }
- }
- }
-
- fclose(f);
- return ndevs;
- }
-
-