lspci.c 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2018 K. Lange
  5. *
  6. * lspci - Print information about connected PCI devices.
  7. *
  8. */
  9. #include <stdio.h>
  10. #include <unistd.h>
  11. #include <errno.h>
  12. #include <string.h>
  13. struct device_class {
  14. uint16_t id;
  15. char * name;
  16. } _pci_classes[] = {
  17. {0x0101, "IDE interface"},
  18. {0x0102, "Floppy disk controller"},
  19. {0x0105, "ATA controller"},
  20. {0x0106, "SATA controller"},
  21. {0x0200, "Ethernet controller"},
  22. {0x0280, "Network controller"},
  23. {0x0300, "VGA compatible controller"},
  24. {0x0380, "Display controller"},
  25. {0x0401, "Multimedia audio controller"},
  26. {0x0403, "Audio device"},
  27. {0x0480, "Multimedia controller"},
  28. {0x0600, "Host bridge"},
  29. {0x0601, "ISA bridge"},
  30. {0x0604, "PCI bridge"},
  31. {0x0680, "Bridge"},
  32. {0x0880, "System peripheral"},
  33. };
  34. struct {
  35. uint16_t id;
  36. const char * name;
  37. } _pci_vendors[] = {
  38. {0x1013, "Cirrus Logic"},
  39. {0x1022, "AMD"},
  40. {0x106b, "Apple, Inc."},
  41. {0x1234, "Bochs/QEMU"},
  42. {0x1274, "Ensoniq"},
  43. {0x15ad, "VMWare"},
  44. {0x8086, "Intel Corporation"},
  45. {0x80EE, "VirtualBox"},
  46. };
  47. struct {
  48. uint16_t ven_id;
  49. uint16_t dev_id;
  50. const char * name;
  51. } _pci_devices[] = {
  52. {0x1013, 0x00b8, "CLGD 54xx VGA Adapter"},
  53. {0x1022, 0x2000, "PCNet Ethernet Controller (pcnet)"},
  54. {0x106b, 0x003f, "OHCI Controller"},
  55. {0x1234, 0x1111, "VGA BIOS Graphics Extensions"},
  56. {0x1274, 0x1371, "Creative Labs CT2518 (ensoniq audio)"},
  57. {0x15ad, 0x0740, "VM Communication Interface"},
  58. {0x15ad, 0x0405, "SVGA II Adapter"},
  59. {0x15ad, 0x0790, "PCI bridge"},
  60. {0x15ad, 0x07a0, "PCI Express Root Port"},
  61. {0x8086, 0x100e, "Gigabit Ethernet Controller (e1000)"},
  62. {0x8086, 0x100f, "Gigabit Ethernet Controller (e1000)"},
  63. {0x8086, 0x1237, "PCI & Memory"},
  64. {0x8086, 0x2415, "AC'97 Audio Chipset"},
  65. {0x8086, 0x7000, "PCI-to-ISA Bridge"},
  66. {0x8086, 0x7010, "IDE Interface"},
  67. {0x8086, 0x7110, "PIIX4 ISA"},
  68. {0x8086, 0x7111, "PIIX4 IDE"},
  69. {0x8086, 0x7113, "Power Management Controller"},
  70. {0x8086, 0x7190, "Host Bridge"},
  71. {0x8086, 0x7191, "AGP Bridge"},
  72. {0x80EE, 0xBEEF, "Bochs/QEMU-compatible Graphics Adapter"},
  73. {0x80EE, 0xCAFE, "Guest Additions Device"},
  74. };
  75. const char * pci_class_lookup(unsigned short class_id) {
  76. for (unsigned int i = 0; i < sizeof(_pci_classes)/sizeof(_pci_classes[0]); ++i) {
  77. if (_pci_classes[i].id == class_id) {
  78. return _pci_classes[i].name;
  79. }
  80. }
  81. return "(unknown)";
  82. }
  83. const char * pci_vendor_lookup(unsigned short vendor_id) {
  84. for (unsigned int i = 0; i < sizeof(_pci_vendors)/sizeof(_pci_vendors[0]); ++i) {
  85. if (_pci_vendors[i].id == vendor_id) {
  86. return _pci_vendors[i].name;
  87. }
  88. }
  89. return NULL;
  90. }
  91. const char * pci_device_lookup(unsigned short vendor_id, unsigned short device_id) {
  92. for (unsigned int i = 0; i < sizeof(_pci_devices)/sizeof(_pci_devices[0]); ++i) {
  93. if (_pci_devices[i].ven_id == vendor_id && _pci_devices[i].dev_id == device_id) {
  94. return _pci_devices[i].name;
  95. }
  96. }
  97. return NULL;
  98. }
  99. static void show_usage(char * argv[]) {
  100. fprintf(stderr,
  101. "lspci - show information about PCI devices\n"
  102. "\n"
  103. "usage: %s [-n]\n"
  104. "\n"
  105. " -n \033[3mshow numeric device codes\033[0m\n"
  106. " -? \033[3mshow this help text\033[0m\n"
  107. "\n", argv[0]);
  108. }
  109. int main(int argc, char * argv[]) {
  110. int numeric = 0;
  111. int opt;
  112. while ((opt = getopt(argc, argv, "n?")) != -1) {
  113. switch (opt) {
  114. case '?':
  115. show_usage(argv);
  116. return 0;
  117. case 'n':
  118. numeric = 1;
  119. break;
  120. }
  121. }
  122. FILE * f = fopen("/proc/pci","r");
  123. if (!f) {
  124. fprintf(stderr, "%s: %s: %s\n", argv[0], "/proc/pci", strerror(errno));
  125. return 1;
  126. }
  127. while (!feof(f)) {
  128. char line[1024];
  129. fgets(line, 1024, f);
  130. if (line[0] == ' ' || line[0] == '\n') {
  131. /* Skip; don't care about this information */
  132. continue;
  133. }
  134. /* Read bus, etc. verbatim */
  135. char * device_bus = line;
  136. /* Read device class */
  137. char * device_class = strstr(line," (");
  138. if (!device_class) {
  139. fprintf(stderr, "%s: parse error - expected (\n", argv[0]);
  140. return 1;
  141. }
  142. *device_class = '\0';
  143. device_class++; /* space */
  144. device_class++; /* ( */
  145. char * device_vendor = strstr(device_class, ", ");
  146. if (!device_vendor) {
  147. fprintf(stderr, "%s: parse error - expected ,\n", argv[0]);
  148. return 1;
  149. }
  150. *device_vendor = '\0';
  151. device_vendor++; /* comma */
  152. device_vendor++; /* space */
  153. char * device_code = strstr(device_vendor, ":");
  154. if (!device_code) {
  155. fprintf(stderr, "%s: parse error - expected :\n", argv[0]);
  156. return 1;
  157. }
  158. *device_code = '\0';
  159. device_code++; /* colon */
  160. char * last_paren = strstr(device_code, ")");
  161. if (!last_paren) {
  162. fprintf(stderr, "%s: parse error - expected )\n", argv[0]);
  163. return 1;
  164. }
  165. *last_paren = '\0';
  166. if (numeric) {
  167. fprintf(stdout, "%s %s: %s:%s\n", device_bus, device_class, device_vendor, device_code);
  168. } else {
  169. unsigned short class_id = strtoul(device_class, NULL, 16);
  170. unsigned short vendor_id = strtoul(device_vendor, NULL, 16);
  171. unsigned short device_id = strtoul(device_code, NULL, 16);
  172. const char * class_name = pci_class_lookup(class_id);
  173. const char * vendor_name = pci_vendor_lookup(vendor_id);
  174. const char * device_name = pci_device_lookup(vendor_id, device_id);
  175. if (!vendor_name && !device_name) {
  176. fprintf(stdout, "%s %s: %s:%s\n", device_bus, class_name, device_vendor, device_code);
  177. } else if (!vendor_name) {
  178. fprintf(stdout, "%s %s: %s %s\n", device_bus, class_name, device_vendor, device_name);
  179. } else if (!device_name) {
  180. fprintf(stdout, "%s %s: %s %s\n", device_bus, class_name, vendor_name, device_code);
  181. } else {
  182. fprintf(stdout, "%s %s: %s %s\n", device_bus, class_name, vendor_name, device_name);
  183. }
  184. }
  185. }
  186. return 0;
  187. }