home *** CD-ROM | disk | FTP | other *** search
/ Chip 1998 February / CHIP_2_98.iso / misc / src / install / pci-probing / pciprobe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-10-14  |  7.1 KB  |  317 lines

  1. /* very simple set of routines to get back what is stored in /proc/pci in */
  2. /* a programmer friendly fashion. Also tries to map a pci entry into a    */
  3. /* kernel module name to aid autoloading modules during an install        */
  4. /* Michael Fulbright Sept 1997                                            */
  5.  
  6. #include <stdio.h>
  7. #include <strings.h>
  8. #include <malloc.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <ctype.h>
  12.  
  13. #include "pciprobe.h"
  14. #include "pci-ids.h"
  15.  
  16.  
  17. /* clean up that string */
  18. static void TrimWhitespace( char *s ) {
  19.     char *f, *l, *p, *q;
  20.  
  21.     if (!(*s))
  22.         return;
  23.     
  24.     for (f=s; *f && isspace(*f); f++) ;
  25.  
  26.     if (!*f) {
  27.         *s = '\0';
  28.         return;
  29.     }
  30.     
  31.     for (l=f+strlen(f)-1; isspace(*l) ; l--)
  32.     *l = '\0';
  33.         
  34.     q = s, p = f;
  35.     while (*p)
  36.         *q++ = *p++;
  37.     
  38.     *q = '\0';
  39. }
  40.  
  41.  
  42. /* create a new clean pciDevice entry */
  43. struct pciDevice *pciNewDevice( void ) {
  44.     struct pciDevice *p;
  45.  
  46.     p = (struct pciDevice *) malloc( sizeof(struct pciDevice) );
  47.     p->nhits = 0;
  48.     p->name=NULL;
  49.     p->module=NULL;
  50.     p->class=PCI_UNSET;
  51.     return p;
  52. }
  53.  
  54. /* remove a pciDevice */
  55. void pciFreeDevice( struct pciDevice *p ) {
  56.     int i;
  57.  
  58.     if (p->name) {
  59.     for (i=0; i<p->nhits; i++)
  60.         free(p->name[i]);
  61.     free(p->name);
  62.     }
  63.  
  64.     if (p->module) {
  65.     for (i=0; i<p->nhits; i++)
  66.         free(p->module[i]);
  67.     free(p->module);
  68.     }
  69.  
  70.     free(p);
  71. }
  72.  
  73.     
  74. /* given a class to probe, returns an array of devices found which match */
  75. /* all entries are malloc'd, so caller must free when done. Use          */
  76. /* pciDeviceFree() to free individual pciDevice's, since they have       */
  77. /* internal elements which are malloc'd                                  */
  78. /* returns number cards found. If nothing found returns 0 and            */
  79. /* setsdevs is set to NULL                                               */
  80. /* if system error occurs (like no /proc/pci!) returns -1                */
  81. int pciProbeDevice( enum pciClass type, struct pciDevice ***devs ) {
  82.     int done;
  83.     int found, maxlen, maxidx;
  84.     int ok, first;
  85.     int ndevs, nmatches;
  86.     int bus, device, function;
  87.     int nonvgadev, madeentry;
  88.     int i, len;
  89.     char *devtype, *devmodel, *vendorid, *deviceid, *mapped, *mapname, *eptr;
  90.     int stage;
  91.     unsigned int devnumid, vennumid;
  92.     FILE *f;
  93.     char buf[100];
  94.  
  95.     struct pci_module_map *pcidb;
  96.  
  97.     /* open /proc/pci and parse output */
  98.     f=fopen("/proc/pci", "r");
  99.     if (!f) {
  100.     return -1;
  101.     }
  102.  
  103.     done = 0;
  104.     stage = 0;
  105.     ndevs = 0;
  106.     *devs = NULL;
  107.     while (!done) {
  108.     if (!fgets(buf,100,f))
  109.         break;
  110.  
  111.     madeentry = 0; /* havent made nothin yet */
  112.  
  113.     /* see what we're looking for */
  114.     if (stage == 0) {
  115.         /* need to find start of list of PCI devices */
  116.         if (!strncmp(buf, "PCI devices found:", 18))
  117.         stage++;
  118.         continue;
  119.     } else if (stage == 1) {
  120.         /* looking for a line starting with 'Bus' */
  121.         if (strstr(buf, "Bus") && strstr(buf, "device")) {
  122.         /* found it, now parse out stuff we care about */
  123.         sscanf(buf, "  Bus %d, device %d, function %d:\n",
  124.                &bus, &device, &function);
  125.  
  126.         /* read the next line for other goodies */
  127.         if (!fgets(buf,100,f))
  128.             break;
  129.  
  130.         /* strip out devtype and model of card */
  131.         devmodel = strchr(buf, ':');
  132.         if (!devmodel)
  133.             continue;
  134.         *devmodel++ = 0;
  135.  
  136.         /* blow revision number off end of devmodel */
  137.         if ((eptr=strrchr(devmodel, '(')))
  138.             *eptr = 0;
  139.         devtype=strdup(buf);
  140.         devmodel=strdup(devmodel);
  141.         TrimWhitespace(devtype);
  142.         TrimWhitespace(devmodel);
  143.  
  144.         /* see if its the class we're looking for */
  145.         /* nonvgadev tells use card didnt set a class */
  146.         /* so we have to see if it happens to match a */
  147.         /* entry in the class db we have              */
  148.         ok = 1;
  149.         nonvgadev = strstr(devtype, CLASS_NONE) != NULL;
  150.  
  151.         switch (type) {
  152.           case PCI_ETHERNET:
  153.             ok = strstr(devtype, CLASS_ETHERNET) != NULL || nonvgadev;
  154.             break;
  155.           case PCI_SCSI:
  156.             ok = strstr(devtype, CLASS_SCSI) != NULL || nonvgadev;
  157.             break;
  158.           case PCI_VIDEO:
  159.             ok = strstr(devtype, CLASS_VIDEO) != NULL ||
  160.              strstr(devtype, CLASS_VIDEO_OTHER) != NULL ||
  161.              nonvgadev;
  162.             break;
  163.           default:
  164.             ok = 0;
  165.             break;
  166.         }
  167.  
  168.         if (!ok) {
  169.             free(devtype);
  170.             free(devmodel);
  171.             continue;
  172.         }
  173.         
  174.         /* see if its an unknown model */
  175.         deviceid = vendorid = NULL;
  176.         if (strstr(devmodel, "Unknown")) {
  177.             if (!fgets(buf,100,f))
  178.             break;
  179.             if (strstr(buf, "Vendor id")) {
  180.             char *s, *t, *v;
  181.             s = strchr(buf, '=');
  182.             if (s) {
  183.                 s++;
  184.                 t = strchr(s, '.');
  185.                 if (t) {
  186.                 *t = 0;
  187.                 t = strchr(t+1, '=');
  188.                 if (t) {
  189.                     t++;
  190.                     v = strchr(t, '.');
  191.                     if (v) {
  192.                     *v = 0;
  193.                     vendorid = strdup(s);
  194.                     deviceid = strdup(t);
  195.                     TrimWhitespace(vendorid);
  196.                     TrimWhitespace(deviceid);
  197.                     devnumid=strtol(deviceid, &eptr, 16);
  198.                     vennumid=strtol(vendorid, &eptr, 16);
  199.                     }
  200.                 }
  201.                 }
  202.             }
  203.             }
  204.         }
  205.             
  206.         /* now find all matches and stick into entry */
  207.         switch (type) {
  208.           case PCI_ETHERNET:
  209.             pcidb = eth_pci_ids;
  210.             len   = eth_num_ids;
  211.             break;
  212.           case PCI_SCSI:
  213.             pcidb = scsi_pci_ids;
  214.             len   = scsi_num_ids;
  215.             break;
  216.           case PCI_VIDEO:
  217.             pcidb = video_pci_ids;
  218.             len   = video_num_ids;
  219.             break;
  220.           default:
  221.             pcidb = NULL;
  222.             len = 0;
  223.         }
  224.  
  225.         /* gotta find the maximally matching entry(s) */
  226.         maxlen = -1;
  227.         if (!strstr(devmodel,"Unknown")) {
  228.             for (i=0; i<len; i++) {
  229.             if (strstr(devmodel, pcidb[i].name)) {
  230.                 int l=strlen(pcidb[i].name);
  231.                 if (l > maxlen) {
  232.                 maxlen = l;
  233.                 }
  234.             }
  235.             }
  236.         }
  237.         
  238.         first = 1;
  239.         nmatches = 0;
  240.         i = 0;
  241.         while ( 1 ) {
  242.             found = 0;
  243.             if (strstr(devmodel, "Unknown")) {
  244.             for (; i<len && 
  245.                  (vennumid != pcidb[i].vendor ||
  246.                  devnumid != pcidb[i].device); i++);
  247.             found = (i < len);
  248.             if (found)
  249.                 maxidx = i;
  250.             } else {
  251.             for (; i<len; i++){
  252.                 if (strstr(devmodel, pcidb[i].name)) {
  253.                 int l=strlen(pcidb[i].name);
  254.                 if (l >= maxlen) {
  255.                     maxidx = i;
  256.                     found = 1;
  257.                     break;
  258.                 }
  259.                 }
  260.             }
  261.             }
  262.             
  263.             if (!found) {
  264.             if (!first || nonvgadev) 
  265.                 break;
  266.             else {
  267.                 mapped  = "UNKNOWN";
  268.                 mapname = "UNKNOWN";
  269.             }
  270.             } else {
  271.             mapped = (char *) pcidb[maxidx].module;
  272.             mapname = (char *) pcidb[maxidx].name;
  273.             }
  274.             
  275.             first = 0;
  276.             
  277.             /* insert into current pciDevice */
  278.             /* we got enough info, let make a device entry */
  279.             if (!madeentry) {
  280.               if ((ndevs % 4) == 0) 
  281.             *devs=(struct pciDevice **)
  282.               realloc(*devs,(ndevs+4)*sizeof(struct pciDevice *));
  283.               (*devs)[ndevs]=pciNewDevice();
  284.             }
  285.  
  286.             madeentry = 1;
  287.  
  288.             (*devs)[ndevs]->name=realloc((*devs)[ndevs]->name,
  289.                        (nmatches+1)*sizeof(char *));
  290.             (*devs)[ndevs]->module=realloc((*devs)[ndevs]->module,
  291.                      (nmatches+1)*sizeof(char *));
  292.             (*devs)[ndevs]->name[nmatches]=strdup(mapname);
  293.             (*devs)[ndevs]->module[nmatches]=strdup(mapped);
  294.             i++;
  295.             nmatches++;
  296.         }            
  297.  
  298.         if (vendorid)
  299.             free(vendorid);
  300.         if (deviceid)
  301.             free(deviceid);
  302.         free(devtype);
  303.         free(devmodel);
  304.         if (madeentry) {
  305.           (*devs)[ndevs]->nhits=nmatches;
  306.           (*devs)[ndevs]->class=type;
  307.           ndevs++;
  308.         }
  309.         }
  310.     }
  311.     }
  312.     
  313.     fclose(f);
  314.     return ndevs;
  315. }
  316.  
  317.