add SMACK manifest file
[framework/system/pciutils.git] / pcimodules.c
1 /*
2  *      pcimodules:  Load all kernel modules for PCI device currently
3  *      plugged into any PCI slot.
4  *
5  *      Copyright 2000 Yggdrasil Computing, Incorporated
6  *      This file may be copied under the terms and conditions of version 
7  *      two of the GNU General Public License, as published by the Free
8  *      Software Foundation (Cambridge, Massachusetts, USA).
9  *
10  *      This file is based on pciutils/lib/example.c, which has the following
11  *      authorship and copyright statement:
12  *
13  *              Written by Martin Mares and put to public domain. You can do
14  *              with it anything you want, but I don't give you any warranty.
15  */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <malloc.h>
20 #include <string.h>
21 #include <unistd.h>
22 #include <sys/utsname.h>
23 #include <sys/param.h>
24 #include <sys/types.h>
25
26 #define _GNU_SOURCE
27 #include <getopt.h>
28
29 #include "pciutils.h"
30
31 const char program_name[] = "pcimodules";
32
33 #define MODDIR  "/lib/modules"
34 #define PCIMAP  "modules.pcimap"
35
36 #define LINELENGTH      8000 
37
38 #define DEVICE_ANY      0xffffffff
39 #define VENDOR_ANY      0xffffffff
40
41 #include "lib/pci.h"
42
43 struct pcimap_entry {
44         unsigned int vendor, subsys_vendor, dev, subsys_dev, class, class_mask;
45         char *module;
46         struct pcimap_entry *next;
47 };
48
49 static struct pcimap_entry *pcimap_list = NULL;
50
51 #define OPT_STRING "h"
52 static struct option long_options[] = {
53         {"class",       required_argument,      NULL, 'c'},
54         {"classmask",   required_argument,      NULL, 'm'},
55         {"help",        no_argument,            NULL, 'h'},
56         { 0,            0,                      0,      0}
57 };
58
59 static unsigned long desired_class;
60 static unsigned long desired_classmask; /* Default is 0: accept all classes.*/
61
62 void
63 read_pcimap(void)
64 {
65         struct utsname utsname;
66         char filename[MAXPATHLEN];
67         FILE *pcimap_file;
68         char line[LINELENGTH];
69         struct pcimap_entry *entry;
70         unsigned int driver_data;
71         char *prevmodule = "";
72         char module[LINELENGTH];
73
74         if (uname(&utsname) < 0) {
75                 perror("uname");
76                 exit(1);
77         }
78         sprintf(filename, "%s/%s/%s", MODDIR, utsname.release, PCIMAP);
79         if ((pcimap_file = fopen(filename, "r")) == NULL) {
80                 perror(filename);
81                 exit(1);
82         }
83
84         while(fgets(line, LINELENGTH, pcimap_file) != NULL) {
85                 if (line[0] == '#')
86                         continue;
87
88                 entry = xmalloc(sizeof(struct pcimap_entry));
89
90                 if (sscanf(line, "%s 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x",
91                            module,
92                            &entry->vendor, &entry->dev,
93                            &entry->subsys_vendor, &entry->subsys_dev,
94                            &entry->class, &entry->class_mask,
95                            &driver_data) != 8) {
96                         fprintf (stderr,
97                                 "modules.pcimap unparsable line: %s.\n", line);
98                         free(entry);
99                         continue;
100                 }
101
102                 /* Optimize memory allocation a bit, in case someday we
103                    have Linux systems with ~100,000 modules.  It also
104                    allows us to just compare pointers to avoid trying
105                    to load a module twice. */
106                 if (strcmp(module, prevmodule) != 0) {
107                         prevmodule = xmalloc(strlen(module)+1);
108                         strcpy(prevmodule, module);
109                 }
110                 entry->module = prevmodule;
111                 entry->next = pcimap_list;
112                 pcimap_list = entry;
113         }
114         fclose(pcimap_file);
115 }
116
117 /* Return a filled in pci_access->dev tree, with the device classes
118    stored in dev->aux.
119 */
120 static void
121 match_pci_modules(void)
122 {
123         struct pci_access *pacc;
124         struct pci_dev *dev;
125         unsigned int class, subsys_dev, subsys_vendor;
126         struct pcimap_entry *map;
127         const char *prevmodule = "";
128
129         pacc = pci_alloc();             /* Get the pci_access structure */
130         /* Set all options you want -- here we stick with the defaults */
131         pci_init(pacc);         /* Initialize the PCI library */
132         pci_scan_bus(pacc);     /* We want to get the list of devices */
133         for(dev=pacc->devices; dev; dev=dev->next) {
134                 pci_fill_info(dev, PCI_FILL_IDENT | PCI_FILL_BASES);
135                 class = (pci_read_word(dev, PCI_CLASS_DEVICE) << 8)
136                         | pci_read_byte(dev, PCI_CLASS_PROG);
137                 subsys_dev = pci_read_word(dev, PCI_SUBSYSTEM_ID);
138                 subsys_vendor = pci_read_word(dev,PCI_SUBSYSTEM_VENDOR_ID);
139                 for(map = pcimap_list; map != NULL; map = map->next) {
140                         if (((map->class ^ class) & map->class_mask) == 0 &&
141                             ((desired_class ^ class) & desired_classmask)==0 &&
142                             (map->dev == DEVICE_ANY ||
143                              map->dev == dev->device_id) &&
144                             (map->vendor == VENDOR_ANY ||
145                              map->vendor == dev->vendor_id) &&
146                             (map->subsys_dev == DEVICE_ANY ||
147                              map->subsys_dev == subsys_dev) &&
148                             (map->subsys_vendor == VENDOR_ANY ||
149                              map->subsys_vendor == subsys_vendor) &&
150                             prevmodule != map->module) {
151                                 printf("%s\n", map->module);
152                                 prevmodule = map->module;
153                         }
154                 }
155
156         }
157         pci_cleanup(pacc);
158 }
159
160 int
161 main (int argc, char **argv)
162 {
163         int opt_index = 0;
164         int opt;
165
166         while ((opt = getopt_long(argc, argv, OPT_STRING, long_options,
167                            &opt_index)) != -1) {
168                 switch(opt) {
169                         case 'c':
170                                 desired_class = strtol(optarg, NULL, 0);
171                                 break;
172                         case 'm':
173                                 desired_classmask = strtol(optarg, NULL, 0);
174                                 break;
175                         case 'h':
176                                 printf ("Usage: pcimodules [--help]\n"
177                                         "  Lists kernel modules corresponding to PCI devices currently plugged"
178                                         "  into the computer.\n");
179                 }
180         }       
181
182         read_pcimap();
183         match_pci_modules();
184         return 0;
185 }