xref: /haiku/src/add-ons/kernel/bus_managers/pci/pci_info.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 /*
2 ** Copyright 2003-2005, Marcus Overhagen. All rights reserved.
3 ** Distributed under the terms of the MIT License.
4 */
5 
6 
7 #include <KernelExport.h>
8 #include <PCI.h>
9 #include <string.h>
10 #include "pci_info.h"
11 #include "pci_priv.h"
12 #include "pci.h"
13 
14 #define PCI_VERBOSE	1
15 #define USE_PCI_HEADER 1
16 
17 #if USE_PCI_HEADER
18 #	include "pcihdr.h"
19 #endif
20 
21 
22 void print_bridge_info(const pci_info *info, bool verbose);
23 void print_generic_info(const pci_info *info, bool verbose);
24 void print_capabilities(const pci_info *info);
25 void print_info_basic(const pci_info *info, bool verbose);
26 void get_vendor_info(uint16 vendorID, const char **venShort, const char **venFull);
27 void get_device_info(uint16 vendorID, uint16 deviceID, const char **devShort, const char **devFull);
28 const char *get_class_info(uint8 class_base, uint8 class_sub, uint8 class_api);
29 const char *get_capability_name(uint8 cap_id);
30 
31 
32 void
33 print_bridge_info(const pci_info *info, bool verbose)
34 {
35 	TRACE(("PCI:   primary_bus %02x, secondary_bus %02x, subordinate_bus %02x, secondary_latency %02x\n",
36 			info->u.h1.primary_bus, info->u.h1.secondary_bus, info->u.h1.subordinate_bus, info->u.h1.secondary_latency));
37 	TRACE(("PCI:   io_base %04x%02x, io_limit %04x%02x\n",
38 			info->u.h1.io_base_upper16, info->u.h1.io_base, info->u.h1.io_limit_upper16, info->u.h1.io_limit));
39 	TRACE(("PCI:   memory_base %04x, memory_limit %04x\n",
40 			info->u.h1.memory_base, info->u.h1.memory_limit));
41 	TRACE(("PCI:   prefetchable memory base %08lx%04x, limit %08lx%04x\n",
42 		info->u.h1.prefetchable_memory_base_upper32, info->u.h1.prefetchable_memory_base,
43 		info->u.h1.prefetchable_memory_limit_upper32, info->u.h1.prefetchable_memory_limit));
44 	TRACE(("PCI:   bridge_control %04x, secondary_status %04x\n",
45 			info->u.h1.bridge_control, info->u.h1.secondary_status));
46 	TRACE(("PCI:   interrupt_line %02x, interrupt_pin %02x\n",
47 			info->u.h1.interrupt_line, info->u.h1.interrupt_pin));
48 	TRACE(("PCI:   ROM base host %08lx, pci %08lx, size ??\n",
49 			info->u.h1.rom_base, info->u.h1.rom_base_pci));
50 	for (int i = 0; i < 2; i++)
51 		TRACE(("PCI:   base reg %d: host %08lx, pci %08lx, size %08lx, flags %02x\n",
52 			i, info->u.h1.base_registers[i], info->u.h1.base_registers_pci[i],
53 			info->u.h1.base_register_sizes[i], info->u.h1.base_register_flags[i]));
54 }
55 
56 
57 void
58 print_generic_info(const pci_info *info, bool verbose)
59 {
60 	TRACE(("PCI:   ROM base host %08lx, pci %08lx, size %08lx\n",
61 			info->u.h0.rom_base, info->u.h0.rom_base_pci, info->u.h0.rom_size));
62 	TRACE(("PCI:   cardbus_CIS %08lx, subsystem_id %04x, subsystem_vendor_id %04x\n",
63 			info->u.h0.cardbus_cis, info->u.h0.subsystem_id, info->u.h0.subsystem_vendor_id));
64 	TRACE(("PCI:   interrupt_line %02x, interrupt_pin %02x, min_grant %02x, max_latency %02x\n",
65 			info->u.h0.interrupt_line, info->u.h0.interrupt_pin, info->u.h0.min_grant, info->u.h0.max_latency));
66 	for (int i = 0; i < 6; i++)
67 		TRACE(("PCI:   base reg %d: host %08lx, pci %08lx, size %08lx, flags %02x\n",
68 			i, info->u.h0.base_registers[i], info->u.h0.base_registers_pci[i],
69 			info->u.h0.base_register_sizes[i], info->u.h0.base_register_flags[i]));
70 }
71 
72 
73 void
74 print_capabilities(const pci_info *info)
75 {
76 	uint16	status;
77 	uint8	cap_ptr;
78 	uint8	cap_id;
79 	int		i;
80 
81 	TRACE(("PCI:   Capabilities: "));
82 
83 	status = pci_read_config(info->bus, info->device, info->function, PCI_status, 2);
84 	if (!(status & PCI_status_capabilities)) {
85 		TRACE(("(not supported)\n"));
86 		return;
87 	}
88 
89 	cap_ptr = pci_read_config(info->bus, info->device, info->function, PCI_capabilities_ptr, 1);
90 	cap_ptr &= ~3;
91 	if (!cap_ptr) {
92 		TRACE(("(empty list)\n"));
93 		return;
94 	}
95 
96 	for (i = 0; i < 48; i++) {
97 		const char *name;
98 		cap_id  = pci_read_config(info->bus, info->device, info->function, cap_ptr, 1);
99 		cap_ptr = pci_read_config(info->bus, info->device, info->function, cap_ptr + 1, 1);
100 		cap_ptr &= ~3;
101 		if (i) {
102 			TRACE((", "));
103 		}
104 		name = get_capability_name(cap_id);
105 		if (name) {
106 			TRACE(("%s", name));
107 		} else {
108 			TRACE(("0x%02x", cap_id));
109 		}
110 		if (!cap_ptr)
111 			break;
112 	}
113 	TRACE(("\n"));
114 }
115 
116 
117 void
118 print_info_basic(const pci_info *info, bool verbose)
119 {
120 	TRACE(("PCI: bus %2d, device %2d, function %2d: vendor %04x, device %04x, revision %02x\n",
121 			info->bus, info->device, info->function, info->vendor_id, info->device_id, info->revision));
122 	TRACE(("PCI:   class_base %02x, class_function %02x, class_api %02x\n",
123 			info->class_base, info->class_sub, info->class_api));
124 
125 	if (verbose) {
126 #if USE_PCI_HEADER
127 		const char *venShort;
128 		const char *venFull;
129 		get_vendor_info(info->vendor_id, &venShort, &venFull);
130 		if (!venShort && !venFull) {
131 			TRACE(("PCI:   vendor %04x: Unknown\n", info->vendor_id));
132 		} else if (venShort && venFull) {
133 			TRACE(("PCI:   vendor %04x: %s - %s\n", info->vendor_id, venShort, venFull));
134 		} else {
135 			TRACE(("PCI:   vendor %04x: %s\n", info->vendor_id, venShort ? venShort : venFull));
136 		}
137 		const char *devShort;
138 		const char *devFull;
139 		get_device_info(info->vendor_id, info->device_id, &devShort, &devFull);
140 		if (!devShort && !devFull) {
141 			TRACE(("PCI:   device %04x: Unknown\n", info->device_id));
142 		} else if (devShort && devFull) {
143 			TRACE(("PCI:   device %04x: %s - %s\n", info->device_id, devShort, devFull));
144 		} else {
145 			TRACE(("PCI:   device %04x: %s\n", info->device_id, devShort ? devShort : devFull));
146 		}
147 #endif
148 		TRACE(("PCI:   info: %s\n", get_class_info(info->class_base, info->class_sub, info->class_api)));
149 	}
150 	TRACE(("PCI:   line_size %02x, latency %02x, header_type %02x, BIST %02x\n",
151 			info->line_size, info->latency, info->header_type, info->bist));
152 
153 	switch (info->header_type & PCI_header_type_mask) {
154 		case 0:
155 			print_generic_info(info, verbose);
156 			break;
157 		case 1:
158 			print_bridge_info(info, verbose);
159 			break;
160 		default:
161 			TRACE(("PCI:   unknown header type\n"));
162 	}
163 
164 	print_capabilities(info);
165 }
166 
167 
168 void
169 pci_print_info()
170 {
171 	pci_info info;
172 	for (long index = 0; B_OK == pci_get_nth_pci_info(index, &info); index++) {
173 		print_info_basic(&info, PCI_VERBOSE);
174 	}
175 }
176 
177 
178 const char *
179 get_class_info(uint8 class_base, uint8 class_sub, uint8 class_api)
180 {
181 	switch (class_base) {
182 		case PCI_early:
183 			switch (class_sub) {
184 				case PCI_early_not_vga:
185 					return "Not VGA-compatible pre-2.0 PCI specification device";
186 				case PCI_early_vga:
187 					return "VGA-compatible pre-2.0 PCI specification device";
188 				default:
189 					return "Unknown pre-2.0 PCI specification device";
190 			}
191 
192 		case PCI_mass_storage:
193 			switch (class_sub) {
194 				case PCI_scsi:
195 					return "SCSI mass storage controller";
196 				case PCI_ide:
197 					return "IDE mass storage controller";
198 				case PCI_floppy:
199 					return "Floppy disk controller";
200 				case PCI_ipi:
201 					return "IPI mass storage controller";
202 				case PCI_raid:
203 					return "RAID mass storage controller";
204 				case PCI_mass_storage_other:
205 					return "Other mass storage controller";
206 				default:
207 					return "Unknown mass storage controller";
208 			}
209 
210 		case PCI_network:
211 			switch (class_sub) {
212 				case PCI_ethernet:
213 					return "Ethernet network controller";
214 				case PCI_token_ring:
215 					return "Token ring network controller";
216 				case PCI_fddi:
217 					return "FDDI network controller";
218 				case PCI_atm:
219 					return "ATM network controller";
220 				case PCI_isdn:
221 					return "ISDN network controller";
222 				case PCI_network_other:
223 					return "Other network controller";
224 				default:
225 					return "Unknown network controller";
226 			}
227 
228 		case PCI_display:
229 			switch (class_sub) {
230 				case PCI_vga:
231 					switch (class_api) {
232 						case 0x00:
233 							return "VGA-compatible display controller";
234 						case 0x01:
235 							return "8514-compatible display controller";
236 						default:
237 							return "Unknown VGA display controller";
238 					}
239 				case PCI_xga:
240 					return "XGA display controller";
241 				case PCI_3d:
242 					return "3D display controller";
243 				case PCI_display_other:
244 					return "Other display controller";
245 				default:
246 					return "Unknown display controller";
247 			}
248 
249 		case PCI_multimedia:
250 			switch (class_sub) {
251 				case PCI_video:
252 					return "Video multimedia device";
253 				case PCI_audio:
254 					return "Audio multimedia device";
255 				case PCI_telephony:
256 					return "Computer telephony multimedia device";
257 				case PCI_multimedia_other:
258 					return "Other multimedia device";
259 				default:
260 					return "Unknown multimedia device";
261 			}
262 
263 		case PCI_memory:
264 			switch (class_sub) {
265 				case PCI_ram:
266 					return "RAM memory controller";
267 				case PCI_flash:
268 					return "Flash memory controller";
269 				case PCI_memory_other:
270 					return "Other memory controller";
271 				default:
272 					return "Unknown memory controller";
273 			}
274 
275 		case PCI_bridge:
276 			switch (class_sub) {
277 				case PCI_host:
278 					return "Host/PCI bridge device";
279 				case PCI_isa:
280 					return "PCI/ISA bridge device";
281 				case PCI_eisa:
282 					return "PCI/EISA bridge device";
283 				case PCI_microchannel:
284 					return "PCI/Micro Channel bridge device";
285 				case PCI_pci:
286 					switch (class_api) {
287 						case 0x00:
288 							return "PCI/PCI bridge device";
289 						case 0x01:
290 							return "Transparent PCI/PCI bridge device";
291 						default:
292 							return "Unknown PCI/PCI bridge device";
293 					}
294 				case PCI_pcmcia:
295 					return "PCI/PCMCIA bridge device";
296 				case PCI_nubus:
297 					return "PCI/NuBus bridge device";
298 				case PCI_cardbus:
299 					return "PCI/CardBus bridge device";
300 				case PCI_raceway:
301 					if (class_api & 1)
302 						return "PCI/RACEway bridge device, end-point mode";
303 					else
304 						return "PCI/RACEway bridge device, transparent mode";
305 				case PCI_bridge_other:
306 					return "Other bridge device";
307 				default:
308 					return "Unknown bridge device";
309 			}
310 
311 		case PCI_simple_communications:
312 			switch (class_sub) {
313 				case PCI_serial:
314 					switch (class_api) {
315 						case PCI_serial_xt:
316 							return "Generic XT-compatible serial communications controller";
317 						case PCI_serial_16450:
318 							return "16450-compatible serial communications controller";
319 						case PCI_serial_16550:
320 							return "16550-compatible serial communications controller";
321 						case 0x03:
322 							return "16650-compatible serial communications controller";
323 						case 0x04:
324 							return "16750-compatible serial communications controller";
325 						case 0x05:
326 							return "16850-compatible serial communications controller";
327 						case 0x06:
328 							return "16950-compatible serial communications controller";
329 						default:
330 							return "Unknown serial communications controller";
331 					}
332 				case PCI_parallel:
333 					switch (class_api) {
334 						case PCI_parallel_simple:
335 							return "Simple parallel port communications controller";
336 						case PCI_parallel_bidirectional:
337 							return "Bi-directional parallel port communications controller";
338 						case PCI_parallel_ecp:
339 							return "ECP 1.x compliant parallel port communications controller";
340 						case 0x03:
341 							return "IEEE 1284 parallel communications controller";
342 						case 0xfe:
343 							return "IEEE 1284 parallel communications target device";
344 						default:
345 							return "Unknown parallel communications controller";
346 					}
347 				case PCI_multiport_serial:
348 					return "Multiport serial communications controller";
349 				case PCI_modem:
350 					switch (class_api) {
351 						case 0x00:
352 							return "Generic modem";
353 						case 0x01:
354 							return "Hayes-compatible modem, 16450-compatible interface";
355 						case 0x02:
356 							return "Hayes-compatible modem, 16550-compatible interface";
357 						case 0x03:
358 							return "Hayes-compatible modem, 16650-compatible interface";
359 						case 0x04:
360 							return "Hayes-compatible modem, 16750-compatible interface";
361 						default:
362 							return "Unknown modem communications controller";
363 					}
364 				case PCI_simple_communications_other:
365 					return "Other simple communications controller";
366 				default:
367 					return "Unknown simple communications controller";
368 			}
369 
370 		case PCI_base_peripheral:
371 			switch (class_sub) {
372 				case PCI_pic:
373 					switch (class_api) {
374 						case PCI_pic_8259:
375 							return "Generic 8259 programmable interrupt controller (PIC)";
376 						case PCI_pic_isa:
377 							return "ISA programmable interrupt controller (PIC)";
378 						case PCI_pic_eisa:
379 							return "EISA programmable interrupt controller (PIC)";
380 						case 0x10:
381 							return "IO advanced programmable interrupt controller (APIC)";
382 						case 0x20:
383 							return "IO(x) advanced programmable interrupt controller (APIC)";
384 						default:
385 							return "Unknown programmable interrupt controller (PIC)";
386 					}
387 				case PCI_dma:
388 					switch (class_api) {
389 						case PCI_dma_8237:
390 							return "Generic 8237 DMA controller";
391 						case PCI_dma_isa:
392 							return "ISA DMA controller";
393 						case PCI_dma_eisa:
394 							return "EISA DMA controller";
395 						default:
396 							return "Unknown DMA controller";
397 					}
398 				case PCI_timer:
399 					switch (class_api) {
400 						case PCI_timer_8254:
401 							return "Generic 8254 timer";
402 						case PCI_timer_isa:
403 							return "ISA system timers";
404 						case PCI_timer_eisa:
405 							return "EISA system timers";
406 						default:
407 							return "Unknown timer";
408 					}
409 				case PCI_rtc:
410 					switch (class_api) {
411 						case PCI_rtc_generic:
412 							return "Generic real time clock (RTC) controller";
413 						case PCI_rtc_isa:
414 							return "ISA real time clock (RTC) controller";
415 						default:
416 							return "Unknown real time clock (RTC) controller";
417 					}
418 				case PCI_generic_hot_plug:
419 					return "Generic PCI Hot-Plug controller";
420 				case PCI_system_peripheral_other:
421 					return "Other base system peripheral";
422 				default:
423 					return "Unknown base system peripheral";
424 			}
425 
426 		case PCI_input:
427 			switch (class_sub) {
428 				case PCI_keyboard:
429 					return "Keyboard controller";
430 				case PCI_pen:
431 					return "Digitizer (pen) input device";
432 				case PCI_mouse:
433 					return "Mouse controller";
434 				case PCI_scanner:
435 					return "Scanner controller";
436 				case PCI_gameport:
437 					switch (class_api) {
438 						case 0x00:
439 							return "Generic gameport controller";
440 						case 0x10:
441 							return "Gameport controller";
442 						default:
443 							return "Unknown gameport controller";
444 					}
445 				case PCI_input_other:
446 					return "Other input controller";
447 				default:
448 					return "Unknown input controller";
449 			}
450 
451 		case PCI_docking_station:
452 			switch (class_sub) {
453 				case PCI_docking_generic:
454 					return "Generic docking station";
455 				case 0x80:
456 					return "Other type of docking station";
457 				default:
458 					return "Unknown docking station";
459 			}
460 
461 		case PCI_processor:
462 			switch (class_sub) {
463 				case PCI_386:
464 					return "386 processor";
465 				case PCI_486:
466 					return "486 processor";
467 				case PCI_pentium:
468 					return "Pentium processor";
469 				case PCI_alpha:
470 					return "Alpha processor";
471 				case PCI_PowerPC:
472 					return "PowerPC processor";
473 				case PCI_mips:
474 					return "MIPS processor";
475 				case PCI_coprocessor:
476 					return "Co-processor";
477 				default:
478 					return "Unknown processor";
479 			}
480 
481 		case PCI_serial_bus:
482 			switch (class_sub) {
483 				case PCI_firewire:
484 					switch (class_api) {
485 						case 0x00:
486 							return "Firewire (IEEE 1394) serial bus controller";
487 						case 0x10:
488 							return "Firewire (IEEE 1394) OpenHCI serial bus controller";
489 						default:
490 							return "Unknown Firewire (IEEE 1394) serial bus controller";
491 					}
492 				case PCI_access:
493 					return "ACCESS serial bus controller";
494 				case PCI_ssa:
495 					return "Serial Storage Architecture (SSA) controller";
496 				case PCI_usb:
497 					switch (class_api) {
498 						case PCI_usb_uhci:
499 							return "USB UHCI controller";
500 						case PCI_usb_ohci:
501 							return "USB OHCI controller";
502 						case 0x80:
503 							return "Other USB controller";
504 						case 0xfe:
505 							return "USB device";
506 						default:
507 							return "Unknown USB serial bus controller";
508 					}
509 				case PCI_fibre_channel:
510 					return "Fibre Channel serial bus controller";
511 				case 0x05:
512 					return "System Management Bus (SMBus) controller";
513 				default:
514 					return "Unknown serial bus controller";
515 			}
516 
517 		case PCI_wireless:
518 			switch (class_sub) {
519 				case 0x00:
520 					return "iRDA compatible wireless controller";
521 				case 0x01:
522 					return "Consumer IR wireless controller";
523 				case 0x10:
524 					return "RF wireless controller";
525 				case 0x80:
526 					return "Other wireless controller";
527 				default:
528 					return "Unknown wireless controller";
529 			}
530 
531 		case PCI_intelligent_io:
532 			switch (class_sub) {
533 				case 0x00:
534 					return "Intelligent IO controller";
535 				default:
536 					return "Unknown intelligent IO controller";
537 			}
538 
539 		case PCI_satellite_communications:
540 			switch (class_sub) {
541 				case 0x01:
542 					return "TV satellite communications controller";
543 				case 0x02:
544 					return "Audio satellite communications controller";
545 				case 0x03:
546 					return "Voice satellite communications controller";
547 				case 0x04:
548 					return "Data satellite communications controller";
549 				default:
550 					return "Unknown satellite communications controller";
551 			}
552 
553 		case PCI_encryption_decryption:
554 			switch (class_sub) {
555 				case 0x00:
556 					return "Network and computing encryption/decryption controller";
557 				case 0x10:
558 					return "Entertainment encryption/decryption controller";
559 				case 0x80:
560 					return "Other encryption/decryption controller";
561 				default:
562 					return "Unknown encryption/decryption controller";
563 			}
564 
565 		case PCI_data_acquisition:
566 			switch (class_sub) {
567 				case 0x00:
568 					return "DPIO modules (data acquisition and signal processing controller)";
569 				case 0x80:
570 					return " Other data acquisition and signal processing controller";
571 				default:
572 					return "Unknown data acquisition and signal processing controller";
573 			}
574 
575 		case PCI_undefined:
576 			return "Does not fit any defined class";
577 
578 		default:
579 			return "Unknown device class base";
580 	}
581 }
582 
583 
584 const char *
585 get_capability_name(uint8 cap_id)
586 {
587 	switch (cap_id) {
588 		case PCI_cap_id_reserved:
589 			return "reserved";
590 		case PCI_cap_id_pm:
591 			return "PM";
592 		case PCI_cap_id_agp:
593 			return "AGP";
594 		case PCI_cap_id_vpd:
595 			return "VPD";
596 		case PCI_cap_id_slotid:
597 			return "SlotID";
598 		case PCI_cap_id_msi:
599 			return "MSI";
600 		case PCI_cap_id_chswp:
601 			return "chswp";
602 		case PCI_cap_id_pcix:
603 			return "PCI-X";
604 		case PCI_cap_id_ldt:
605 			return "ldt";
606 		case PCI_cap_id_vendspec:
607 			return "vendspec";
608 		case PCI_cap_id_debugport:
609 			return "DebugPort";
610 		case PCI_cap_id_cpci_rsrcctl:
611 			return "cpci_rsrcctl";
612 		case PCI_cap_id_hotplug:
613 			return "HotPlug";
614 		default:
615 			return NULL;
616 	}
617 }
618 
619 
620 #if USE_PCI_HEADER
621 void
622 get_vendor_info(uint16 vendorID, const char **venShort, const char **venFull)
623 {
624 	for (int i = 0; i < (int)PCI_VENTABLE_LEN; i++) {
625 		if (PciVenTable[i].VenId == vendorID) {
626 			if (0 == strcmp(PciVenTable[i].VenShort, PciVenTable[i].VenFull)) {
627 				*venShort = PciVenTable[i].VenShort[0] ? PciVenTable[i].VenShort : NULL;
628 				*venFull = NULL;
629 			} else {
630 				*venShort = PciVenTable[i].VenShort[0] ? PciVenTable[i].VenShort : NULL;
631 				*venFull = PciVenTable[i].VenFull[0] ? PciVenTable[i].VenFull : NULL;
632 			}
633 			return;
634 		}
635 	}
636 	*venShort = NULL;
637 	*venFull = NULL;
638 }
639 
640 
641 void
642 get_device_info(uint16 vendorID, uint16 deviceID, const char **devShort, const char **devFull)
643 {
644 	for (int i = 0; i < (int)PCI_DEVTABLE_LEN; i++) {
645 		if (PciDevTable[i].VenId == vendorID && PciDevTable[i].DevId == deviceID ) {
646 			*devShort = PciDevTable[i].Chip[0] ? PciDevTable[i].Chip : NULL;
647 			*devFull = PciDevTable[i].ChipDesc[0] ? PciDevTable[i].ChipDesc : NULL;
648 			return;
649 		}
650 	}
651 	*devShort = NULL;
652 	*devFull = NULL;
653 }
654 #endif	/* USE_PCI_HEADER */
655