removed clang-format and clang_complete files from the repo
[dosdemo] / src / dos / pci.c
1 /*
2 S3 Virge driver hack
3 Copyright (C) 2021 John Tsiombikas <nuclear@member.fsf.org>
4
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.
9
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.
14
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/>.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <conio.h>
22 #include "dosutil.h"
23 #include "inttypes.h"
24 #include "pci.h"
25 #include "cdpmi.h"
26
27 #define CONFIG_ADDR_PORT        0xcf8
28 #define CONFIG_DATA_PORT        0xcfc
29
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)
34
35 /* signature returned in edx by the PCI BIOS present function: FOURCC "PCI " */
36 #define PCI_SIG         0x20494350
37
38 #define TYPE_MULTIFUNC  0x80
39
40
41 static struct pci_device *pcidev;
42 static int num_pcidevs, max_pcidevs;
43
44
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);
49
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);
54
55 static uint32_t (*cfg_read32)(int, int, int, int);
56
57 static void clear_devices(void);
58 static void add_device(struct pci_device *dev);
59
60 int init_pci(void)
61 {
62         int i, count = 0;
63         struct dpmi_regs regs = {0};
64
65         clear_devices();
66
67         regs.eax = 0xb101;
68         dpmi_int(0x1a, &regs);
69
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");
73                 return -1;
74         }
75
76         printf("PCI BIOS v%x.%x found\n", (regs.ebx & 0xff00) >> 8, regs.ebx & 0xff);
77         if(regs.eax & 1) {
78                 cfg_read32 = cfg_read32_m1;
79         } else {
80                 if(!(regs.eax & 2)) {
81                         fprintf(stderr, "Failed to find supported PCI mess mechanism\n");
82                         return -1;
83                 }
84                 printf("PCI mess mechanism #1 unsupported, falling back to mechanism #2\n");
85                 cfg_read32 = cfg_read32_m2;
86         }
87
88         for(i=0; i<256; i++) {
89                 count += enum_bus(i);
90         }
91         printf("found %d PCI devices\n\n", count);
92         return 0;
93 }
94
95 static int enum_bus(int busid)
96 {
97         int i, count = 0;
98
99         for(i=0; i<32; i++) {
100                 count += enum_dev(busid, i);
101         }
102
103         return count;
104 }
105
106 static int enum_dev(int busid, int devid)
107 {
108         int i, count;
109         struct pci_device dev;
110
111         dev.bus = busid;
112         dev.dev = devid;
113         dev.func = 0;
114
115         /* vendor id ffff is invalid */
116         if((cfg_read32(busid, devid, 0, 0) & 0xffff) == 0xffff) {
117                 return 0;
118         }
119         if(read_dev_info(&dev.cfg, busid, devid, 0) == -1) {
120                 return 0;
121         }
122         print_dev_info(&dev.cfg, busid, devid, 0);
123         add_device(&dev);
124
125         count = 1;
126
127         if(dev.cfg.hdr_type & TYPE_MULTIFUNC) {
128                 for(i=1; i<8; i++) {
129                         if(read_dev_info(&dev.cfg, busid, devid, i) == -1) {
130                                 continue;
131                         }
132                         print_dev_info(&dev.cfg, busid, devid, i);
133                         dev.func = i;
134                         add_device(&dev);
135                         count++;
136                 }
137         }
138         return count;
139 }
140
141 static int read_dev_info(struct pci_config_data *res, int bus, int dev, int func)
142 {
143         int i;
144         uint32_t *ptr = (uint32_t*)res;
145
146         *ptr++ = cfg_read32(bus, dev, func, 0);
147         if(res->vendor == 0xffff) {
148                 return -1;
149         }
150
151         for(i=1; i<16; i++) {
152                 *ptr++ = cfg_read32(bus, dev, func, i * 4);
153         }
154         return 0;
155 }
156
157 static void print_dev_info(struct pci_config_data *info, int bus, int dev, int func)
158 {
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);
164 }
165
166 static uint32_t cfg_read32_m1(int bus, int dev, int func, int reg)
167 {
168         uint32_t addr = ADDR_ENABLE | ADDR_BUSID(bus) | ADDR_DEVID(dev) |
169                 ADDR_FUNC(func) | reg;
170
171         outpd(CONFIG_ADDR_PORT, addr);
172         return inpd(CONFIG_DATA_PORT);
173 }
174
175 static uint32_t cfg_read32_m2(int bus, int dev, int func, int reg)
176 {
177         fprintf(stderr, "BUG: PCI mess mechanism #2 not implemented yet!");
178         demo_abort();
179         return 0;
180 }
181
182 static const char *class_names[] = {
183         "unknown",
184         "mass storage controller",
185         "network controller",
186         "display controller",
187         "multimedia device",
188         "memory controller",
189         "bridge device",
190         "simple communication controller",
191         "base system peripheral",
192         "input device",
193         "docking station",
194         "processor",
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"
201 };
202
203 static const char *class_mass_names[] = {
204         "SCSI bus controller",
205         "IDE controller",
206         "floppy disk controller",
207         "IPI bus controller",
208         "RAID controller"
209 };
210
211 static const char *class_net_names[] = {
212         "ethernet controller",
213         "token ring controller",
214         "FDDI controller",
215         "ATM controller",
216         "ISDN controller"
217 };
218
219 static const char *class_disp_names[] = {
220         "VGA-compatible controller",
221         "XGA controller",
222         "3D controller"
223 };
224
225 static const char *class_mm_names[] = {
226         "video device",
227         "audio device",
228         "telephony device"
229 };
230
231 static const char *class_bridge_names[] = {
232         "host bridge",
233         "ISA bridge",
234         "EISA bridge",
235         "MCA bridge",
236         "PCI-to-PCI bridge",
237         "Subtractive decode PCI-to-PCI bridge",
238         "PCMCIA bridge",
239         "NuBus bridge",
240         "CardBus bridge",
241         "RACEway bridge"
242 };
243
244 static const char *class_comm_names[] = {
245         "serial controller",
246         "parallel/IEEE1284",
247         "multiport serial controller",
248         "modem"
249 };
250
251 static const char *class_base_names[] = {
252         "interrupt controller",
253         "DMA controller",
254         "timer",
255         "RTC",
256         "PCI hot-plug controller"
257 };
258
259 static const char *class_input_names[] = {
260         "keyboard controller",
261         "digitizer",
262         "mouse controller",
263         "scanner controller",
264         "gameport controller"
265 };
266
267 static const char *class_ser_names[] = {
268         "firewire",
269         "ACCESS.bus",
270         "SSA",
271         "USB",
272         "Fibre Channel",
273         "SMBus"
274 };
275
276 static const char *class_sat_names[] = {
277         "TV",
278         "audio",
279         "voice",
280         "data"
281 };
282
283
284 static const char *class_str(int cc)
285 {
286         if(cc == 0xff) {
287                 return "other";
288         }
289         if(cc >= 0x12) {
290                 return "unknown";
291         }
292         return class_names[cc];
293 }
294
295 static const char *subclass_str(int cc, int sub)
296 {
297         if(sub == 0x80) return "other";
298
299         switch(cc) {
300         case 0:
301                 if(sub == 1) return "VGA-compatible device";
302                 return "unknown";
303
304         case 1:
305                 if(sub > 4) return "unknown";
306                 return class_mass_names[sub];
307
308         case 2:
309                 if(sub > 4) return "unknown";
310                 return class_net_names[sub];
311
312         case 3:
313                 if(sub > 2) return "unknown";
314                 return class_disp_names[sub];
315
316         case 4:
317                 if(sub > 2) return "unknown";
318                 return class_mm_names[sub];
319
320         case 5:
321                 if(sub == 0) return "RAM";
322                 if(sub == 1) return "flash";
323                 return "unknown";
324
325         case 6:
326                 if(sub > 8) return "unknown";
327                 return class_bridge_names[sub];
328
329         case 7:
330                 if(sub > 3) return "unknown";
331                 return class_comm_names[sub];
332
333         case 8:
334                 if(sub > 4) return "unknown";
335                 return class_base_names[sub];
336
337         case 9:
338                 if(sub > 4) return "unknown";
339                 return class_input_names[sub];
340
341         case 10:
342                 if(sub == 0) return "generic docking station";
343                 return "unknown";
344
345         case 11:
346                 switch(sub) {
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";
354                 default:
355                         break;
356                 }
357                 return "unknown";
358
359         case 12:
360                 if(sub > 5) return "unknown";
361                 return class_ser_names[sub];
362
363         case 13:
364                 if(sub == 0) return "irda controller";
365                 if(sub == 1) return "IR controller";
366                 if(sub == 0x10) return "RF controller";
367                 return "unknonw";
368
369         case 15:
370                 if(sub > 4) return "unknown";
371                 return class_sat_names[sub];
372
373         case 16:
374                 if(sub == 0) return "network & computing crypto";
375                 if(sub == 1) return "entertainment crypto";
376                 return "unknown";
377
378         case 17:
379                 if(sub == 0) return "DPIO module";
380                 return "unknown";
381
382         default:
383                 break;
384         }
385         return "unknown";
386 }
387
388 static void clear_devices(void)
389 {
390         free(pcidev);
391         pcidev = 0;
392         num_pcidevs = max_pcidevs = 0;
393 }
394
395 static void add_device(struct pci_device *dev)
396 {
397         if(num_pcidevs >= max_pcidevs) {
398                 void *newarr;
399                 int newsz = max_pcidevs ? max_pcidevs << 1 : 8;
400
401                 if(!(newarr = realloc(pcidev, newsz * sizeof *pcidev))) {
402                         fprintf(stderr, "failed to resize PCI device array (%d)\n", newsz);
403                         return;
404                 }
405                 pcidev = newarr;
406                 max_pcidevs = newsz;
407         }
408
409         pcidev[num_pcidevs++] = *dev;
410 }
411
412 struct pci_device *find_pci_dev(uint16_t vendorid, uint16_t devid)
413 {
414         int i;
415         for(i=0; i<num_pcidevs; i++) {
416                 if(pcidev[i].cfg.vendor == vendorid && pcidev[i].cfg.device == devid) {
417                         return pcidev + i;
418                 }
419         }
420         return 0;
421 }