3 Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
27 #define CONFIG_ADDR_PORT 0xcf8
28 #define CONFIG_DATA_PORT 0xcfc
30 #define ADDR_ENABLE 0x80000000
31 #define ADDR_BUSID(x) (((uint32_t)(x) & 0xff) << 16)
32 #define ADDR_DEVID(x) (((uint32_t)(x) & 0x1f) << 11)
33 #define ADDR_FUNC(x) (((uint32_t)(x) & 3) << 8)
35 /* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */
36 #define PCI_SIG 0x20494350
38 #define TYPE_MULTIFUNC 0x80
41 static struct pci_device *pcidev;
42 static int num_pcidevs, max_pcidevs;
45 static int enum_bus(int busid);
46 static int enum_dev(int busid, int dev);
47 static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func);
48 static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func);
50 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg);
51 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg);
52 static const char *class_str(int cc);
53 static const char *subclass_str(int cc, int sub);
55 static uint32_t (*cfg_read32)(int, int, int, int);
57 static void clear_devices(void);
58 static void add_device(struct pci_device *dev);
63 struct dpmi_regs regs = {0};
68 dpmi_int(0x1a, ®s);
70 /* PCI BIOS present if CF=0, AH=0, and EDX has the "PCI " sig FOURCC */
71 if((regs.flags & FLAGS_CF) || (regs.eax & 0xff00) || regs.edx != PCI_SIG) {
72 fprintf(stderr, "No PCI BIOS present\n");
76 printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff);
78 cfg_read32 = cfg_read32_m1;
81 fprintf(stderr, "Failed to find supported PCI mess mechanism\n");
84 printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n");
85 cfg_read32 = cfg_read32_m2;
88 for(i=0; i<256; i++) {
91 printf("found %d PCI devices\n\n", count);
95 static int enum_bus(int busid)
100 count += enum_dev(busid, i);
106 static int enum_dev(int busid, int devid)
109 struct pci_device dev;
115 /* vendor id ffff is invalid */
116 if((cfg_read32(busid, devid, 0, 0) & 0xffff) == 0xffff) {
119 if(read_dev_info(&dev.cfg, busid, devid, 0) == -1) {
122 print_dev_info(&dev.cfg, busid, devid, 0);
127 if(dev.cfg.hdr_type & TYPE_MULTIFUNC) {
129 if(read_dev_info(&dev.cfg, busid, devid, i) == -1) {
132 print_dev_info(&dev.cfg, busid, devid, i);
141 static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func)
144 uint32_t *ptr = (uint32_t*)res;
146 *ptr++ = cfg_read32(bus, dev, func, 0);
147 if(res->vendor == 0xffff) {
151 for(i=1; i<16; i++) {
152 *ptr++ = cfg_read32(bus, dev, func, i * 4);
157 static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func)
159 printf("- (%d:%d,%d) Device %04x:%04x: ", bus, dev, func, info->vendor, info->device);
160 printf("\"%s\" (%d) - %s-func\n", class_str(info->class), info->class,
161 info->hdr_type & TYPE_MULTIFUNC ? "multi" : "single");
162 printf(" subclass: \"%s\" (%d), iface: %d\n", subclass_str(info->class, info->subclass),
163 info->subclass, info->iface);
166 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg)
168 uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) |
169 ADDR_FUNC(func) | reg;
171 outpd(CONFIG_ADDR_PORT, addr);
172 return inpd(CONFIG_DATA_PORT);
175 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg)
177 fprintf(stderr, "BUG: PCI mess mechanism #2 not implemented yet!");
182 static const char *class_names[] = {
184 "mass storage controller",
185 "network controller",
186 "display controller",
190 "simple communication controller",
191 "base system peripheral",
195 "serial bus controller",
196 "wireless controller",
197 "intelligent I/O controller",
198 "satellite communication controller",
199 "encryption/decryption controller",
200 "data acquisition & signal processing controller"
203 static const char *class_mass_names[] = {
204 "SCSI bus controller",
206 "floppy disk controller",
207 "IPI bus controller",
211 static const char *class_net_names[] = {
212 "ethernet controller",
213 "token ring controller",
219 static const char *class_disp_names[] = {
220 "VGA-compatible controller",
225 static const char *class_mm_names[] = {
231 static const char *class_bridge_names[] = {
237 "Subtractive decode PCI-to-PCI bridge",
244 static const char *class_comm_names[] = {
247 "multiport serial controller",
251 static const char *class_base_names[] = {
252 "interrupt controller",
256 "PCI hot-plug controller"
259 static const char *class_input_names[] = {
260 "keyboard controller",
263 "scanner controller",
264 "gameport controller"
267 static const char *class_ser_names[] = {
276 static const char *class_sat_names[] = {
284 static const char *class_str(int cc)
292 return class_names[cc];
295 static const char *subclass_str(int cc, int sub)
297 if(sub == 0x80) return "other";
301 if(sub == 1) return "VGA-compatible device";
305 if(sub > 4) return "unknown";
306 return class_mass_names[sub];
309 if(sub > 4) return "unknown";
310 return class_net_names[sub];
313 if(sub > 2) return "unknown";
314 return class_disp_names[sub];
317 if(sub > 2) return "unknown";
318 return class_mm_names[sub];
321 if(sub == 0) return "RAM";
322 if(sub == 1) return "flash";
326 if(sub > 8) return "unknown";
327 return class_bridge_names[sub];
330 if(sub > 3) return "unknown";
331 return class_comm_names[sub];
334 if(sub > 4) return "unknown";
335 return class_base_names[sub];
338 if(sub > 4) return "unknown";
339 return class_input_names[sub];
342 if(sub == 0) return "generic docking station";
347 case 0: return "386";
348 case 1: return "486";
349 case 2: return "pentium";
350 case 0x10: return "alpha";
351 case 0x20: return "powerpc";
352 case 0x30: return "mips";
353 case 0x40: return "co-processor";
360 if(sub > 5) return "unknown";
361 return class_ser_names[sub];
364 if(sub == 0) return "irda controller";
365 if(sub == 1) return "IR controller";
366 if(sub == 0x10) return "RF controller";
370 if(sub > 4) return "unknown";
371 return class_sat_names[sub];
374 if(sub == 0) return "network & computing crypto";
375 if(sub == 1) return "entertainment crypto";
379 if(sub == 0) return "DPIO module";
388 static void clear_devices(void)
392 num_pcidevs = max_pcidevs = 0;
395 static void add_device(struct pci_device *dev)
397 if(num_pcidevs >= max_pcidevs) {
399 int newsz = max_pcidevs ? max_pcidevs << 1 : 8;
401 if(!(newarr = realloc(pcidev, newsz * sizeof *pcidev))) {
402 fprintf(stderr, "failed to resize PCI device array (%d)\n", newsz);
409 pcidev[num_pcidevs++] = *dev;
412 struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid)
415 for(i=0; i<num_pcidevs; i++) {
416 if(pcidev[i].cfg.vendor == vendorid && pcidev[i].cfg.device == devid) {