add /proc/pci, lspci

This commit is contained in:
K. Lange 2018-09-12 11:45:52 +09:00
parent d5f6170991
commit 5a6cc6868a
2 changed files with 194 additions and 0 deletions

131
apps/lspci.c Normal file
View File

@ -0,0 +1,131 @@
/* vim: tabstop=4 shiftwidth=4 noexpandtab
* This file is part of ToaruOS and is released under the terms
* of the NCSA / University of Illinois License - see LICENSE.md
* Copyright (C) 2018 K. Lange
*
* lspci - Print information about connected PCI devices.
*
*/
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
struct device_class {
char * code;
char * name;
} device_classes[] = {
{"0101", "IDE interface"},
{"0102", "Floppy disk controller"},
{"0105", "ATA controller"},
{"0106", "SATA controller"},
{"0200", "Ethernet controller"},
{"0280", "Network controller"},
{"0300", "VGA compatible controller"},
{"0380", "Display controller"},
{"0401", "Multimedia audio controller"},
{"0403", "Audio device"},
{"0480", "Multimedia controller"},
{"0600", "Host bridge"},
{"0601", "ISA bridge"},
{"0680", "Bridge"},
{"0880", "System peripheral"},
{NULL, NULL},
};
static void show_usage(char * argv[]) {
fprintf(stderr,
"lspci - show information about PCI devices\n"
"\n"
"usage: %s [-n]\n"
"\n"
" -n \033[3mshow numeric device codes\033[0m\n"
" -? \033[3mshow this help text\033[0m\n"
"\n", argv[0]);
}
int main(int argc, char * argv[]) {
int numeric = 0;
int opt;
while ((opt = getopt(argc, argv, "n?")) != -1) {
switch (opt) {
case '?':
show_usage(argv);
return 0;
case 'n':
numeric = 1;
break;
}
}
FILE * f = fopen("/proc/pci","r");
if (!f) {
fprintf(stderr, "%s: %s: %s\n", argv[0], "/proc/pci", strerror(errno));
return 1;
}
while (!feof(f)) {
char line[1024];
fgets(line, 1024, f);
if (line[0] == ' ') {
/* Skip; don't care about this information */
continue;
}
/* Read bus, etc. verbatim */
char * device_bus = line;
/* Read device class */
char * device_class = strstr(line," (");
if (!device_class) {
fprintf(stderr, "%s: parse error\n", argv[0]);
return 1;
}
*device_class = '\0';
device_class++; /* space */
device_class++; /* ( */
char * device_vendor = strstr(device_class, ", ");
if (!device_vendor) {
fprintf(stderr, "%s: parse error\n", argv[0]);
return 1;
}
*device_vendor = '\0';
device_vendor++; /* comma */
device_vendor++; /* space */
char * device_code = strstr(device_vendor, ":");
if (!device_code) {
fprintf(stderr, "%s: parse error\n", argv[0]);
return 1;
}
*device_code = '\0';
device_code++; /* colon */
char * device_name = strstr(device_code, ") ");
if (!device_name) {
fprintf(stderr, "%s: parse error\n", argv[0]);
return 1;
}
*device_name = '\0';
device_name++; /* ) */
device_name++; /* space */
char * linefeed = strstr(device_name, "\n");
if (linefeed) *linefeed = '\0';
if (numeric) {
fprintf(stdout, "%s %s: %s:%s\n", device_bus, device_class, device_vendor, device_code);
} else {
for (struct device_class * c = device_classes; c->code; ++c) {
if (!strcmp(device_class, c->code)) {
device_class = c->name;
break;
}
}
/* TODO: We should also look up vendor + device names ourselves and possibly remove them from the kernel */
fprintf(stdout, "%s %s: %s\n", device_bus, device_class, device_name);
}
}
return 0;
}

View File

@ -12,6 +12,7 @@
#include <kernel/module.h>
#include <kernel/mod/net.h>
#include <kernel/multiboot.h>
#include <kernel/pci.h>
#define PROCFS_STANDARD_ENTRIES (sizeof(std_entries) / sizeof(struct procfs_entry))
#define PROCFS_PROCDIR_ENTRIES (sizeof(procdir_entries) / sizeof(struct procfs_entry))
@ -620,6 +621,67 @@ static uint32_t irq_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_
return size;
}
/**
* Basically the same as the kdebug `pci` command.
*/
struct _pci_buf {
size_t offset;
char *buffer;
};
static void scan_hit_list(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
struct _pci_buf * b = extra;
b->offset += sprintf(b->buffer + b->offset, "%2x:%2x.%d (%4x, %4x:%4x) %s %s\n",
(int)pci_extract_bus(device),
(int)pci_extract_slot(device),
(int)pci_extract_func(device),
(int)pci_find_type(device),
vendorid,
deviceid,
pci_vendor_lookup(vendorid),
pci_device_lookup(vendorid,deviceid));
b->offset += sprintf(b->buffer + b->offset, " BAR0: 0x%8x", pci_read_field(device, PCI_BAR0, 4));
b->offset += sprintf(b->buffer + b->offset, " BAR1: 0x%8x", pci_read_field(device, PCI_BAR1, 4));
b->offset += sprintf(b->buffer + b->offset, " BAR2: 0x%8x", pci_read_field(device, PCI_BAR2, 4));
b->offset += sprintf(b->buffer + b->offset, " BAR3: 0x%8x", pci_read_field(device, PCI_BAR3, 4));
b->offset += sprintf(b->buffer + b->offset, " BAR4: 0x%8x", pci_read_field(device, PCI_BAR4, 4));
b->offset += sprintf(b->buffer + b->offset, " BAR6: 0x%8x\n", pci_read_field(device, PCI_BAR5, 4));
b->offset += sprintf(b->buffer + b->offset, " IRQ Line: %d", pci_read_field(device, 0x3C, 1));
b->offset += sprintf(b->buffer + b->offset, " IRQ Pin: %d", pci_read_field(device, 0x3D, 1));
b->offset += sprintf(b->buffer + b->offset, " Interrupt: %d", pci_get_interrupt(device));
b->offset += sprintf(b->buffer + b->offset, " Status: 0x%4x\n", pci_read_field(device, PCI_STATUS, 2));
}
static void scan_count(uint32_t device, uint16_t vendorid, uint16_t deviceid, void * extra) {
size_t * count = extra;
(*count)++;
}
static uint32_t pci_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
size_t count = 0;
pci_scan(&scan_count, -1, &count);
struct _pci_buf b = {0,NULL};
b.buffer = malloc(count * 512);
pci_scan(&scan_hit_list, -1, &b);
size_t _bsize = b.offset;
if (offset > _bsize) {
free(b.buffer);
return 0;
}
if (size > _bsize - offset) size = _bsize - offset;
memcpy(buffer, b.buffer, size);
free(b.buffer);
return size;
}
static struct procfs_entry std_entries[] = {
{-1, "cpuinfo", cpuinfo_func},
{-2, "meminfo", meminfo_func},
@ -634,6 +696,7 @@ static struct procfs_entry std_entries[] = {
{-11,"loader", loader_func},
{-12,"irq", irq_func},
{-13,"pat", pat_func},
{-14,"pci", pci_func},
};
static struct dirent * readdir_procfs_root(fs_node_t *node, uint32_t index) {