Revision: 322 Author: nieklinnenbank Date: Tue Aug 18 13:59:35 2009Log: Separated traversal of /dev/pci and execution of /etc/pci/$VENDOR:$DEVICE in PCIDetect.
This makes the PCIServer much more simple: it is now only responsible forexporting PCI configuration space as files. Another utility PCIDetect traverses the directories in /dev/pci, corresponding to PCI busses, slots and functions, and
tries to execute /etc/pci/$VENDOR:$DEVICE for each detected device. http://code.google.com/p/freenos/source/detail?r=322 Added: /trunk/srv/pci/PCIDetect.cpp Modified: /trunk/srv/pci/PCIServer.cpp /trunk/srv/pci/PCIServer.h /trunk/srv/pci/SConscript ======================================= --- /dev/null +++ /trunk/srv/pci/PCIDetect.cpp Tue Aug 18 13:59:35 2009 @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2009 Niek Linnenbank + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <dirent.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <syslog.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <sys/stat.h> + +int readint(struct dirent *bus, struct dirent *slot, + struct dirent *func, const char *file) +{ + char path[256]; + int fd, value = 0; + + /* Construct target path. */ + snprintf(path, sizeof(path), "/dev/pci/%s/%s/%s/%s", + bus->d_name, slot->d_name, func->d_name, file); + + /* Open the target file. */ + if ((fd = open(path, O_RDONLY)) < 0) + { + syslog(LOG_ERR, "failed to open() `%s': %s", + path, strerror(errno)); + exit(EXIT_FAILURE); + } + /* Read out the integer. */ + if (read(fd, &value, sizeof(value)) <= 0) + { + syslog(LOG_ERR, "failed to read() `%s': %s", + path, strerror(errno)); + exit(EXIT_FAILURE); + } + /* Done. */ + close(fd); + return value; +} + +int main(int argc, char **argv) +{ + DIR *busDir, *slotDir, *funcDir; + struct dirent *bus, *slot, *func; + struct stat st; + char path[256]; + const char *args[5]; + int vendor, device, revision, status, pid; + + /* Open logs. */ + openlog("PCI", LOG_PID, LOG_USER); + + /* Open the PCI filesystem. */ + if (!(busDir = opendir("/dev/pci"))) + { + syslog(LOG_ERR, "failed to opendir() `%s': %s", + "/dev/pci", strerror(errno)); + return EXIT_FAILURE; + } + /* + * Loop PCI bus(ses). + */ + while ((bus = readdir(busDir))) + { + if (bus->d_name[0] == '.') + { + continue; + } + snprintf(path, sizeof(path), "/dev/pci/%s", + bus->d_name); + + /* Open PCI slot directory. */ + if (!(slotDir = opendir(path))) + { + syslog(LOG_ERR, "failed to opendir() `%s': %s", + path, strerror(errno)); + return EXIT_FAILURE; + } + + /* + * Loop PCI slot(s). + */ + while ((slot = readdir(slotDir))) + { + if (slot->d_name[0] == '.') + { + continue; + } + snprintf(path, sizeof(path), "/dev/pci/%s/%s", + bus->d_name, slot->d_name); + + /* Open PCI function directory. */ + if (!(funcDir = opendir(path))) + { + syslog(LOG_ERR, "failed to opendir() `%s': %s\r\n", + path, strerror(errno)); + return EXIT_FAILURE; + } + + /* + * Loop PCI function(s). + */ + while ((func = readdir(funcDir))) + { + if (func->d_name[0] == '.') + { + continue; + } + /* Read out properties. */ + vendor = readint(bus, slot, func, "vendor"); + device = readint(bus, slot, func, "device"); + revision = readint(bus, slot, func, "revision"); + + /* Log the device. */ + syslog(LOG_INFO, "[%s:%s:%s] %x:%x (rev %d)", + bus->d_name, slot->d_name, func->d_name, + vendor, device, revision); + + /* Construct path to a device driver server. */ + snprintf(path, sizeof(path), "/etc/pci/%x:%x", + vendor, device); + + /* Find device server, if any. */ + if (stat(path, &st) == 0) + { + /* Setup argument list. */ + args[0] = path; + args[1] = bus->d_name; + args[2] = slot->d_name; + args[3] = func->d_name; + args[4] = ZERO; + + /* Execute it! */ + pid = forkexec(path, args); + waitpid(pid, &status, 0); + } + + } + closedir(funcDir); + } + closedir(slotDir); + } + closedir(busDir); +} ======================================= --- /trunk/srv/pci/PCIServer.cpp Sun Aug 16 14:22:16 2009 +++ /trunk/srv/pci/PCIServer.cpp Tue Aug 18 13:59:35 2009 @@ -28,14 +28,16 @@ int main(int argc, char **argv) { - /* (Re)create target directory. */ - mkdir("/dev/pci", S_IWUSR | S_IRUSR); - /* Create instance. */ PCIServer server("/dev/pci"); - /* Start serving requests. */ - if (!fork()) + /* (Re)create target directory. */ + mkdir("/dev/pci", S_IWUSR | S_IRUSR); + + /* + * Mount the filesystem. + */ + if (server.mount()) { /* * TODO: Please see issue 76: @@ -70,12 +72,12 @@ if (PCI_READ_WORD(0, 0, 0, PCI_VID) == 0xffff || PCI_READ_WORD(0, 0, 0, PCI_DID) == 0xffff) { - syslog(LOG_INFO, "No Host Controller found"); + syslog(LOG_INFO, "No Host Controller"); exit(EXIT_FAILURE); } else { - syslog(LOG_INFO, "Host Controller found"); + syslog(LOG_INFO, "Intel Host Controller"); scan(); } } @@ -124,13 +126,6 @@ /* Then make & fill the function directory. */ detect(bus, slot, func); slotDir->insert(DirectoryFile, "%x", func); - - /* Log the device. */ - syslog(LOG_INFO, "[%x:%x:%x] %x:%x (rev %d)", - bus, slot, func, vendorID, deviceID, revisionID); - - /* Execute a device server. */ - runDeviceServer(bus, slot, func, vendorID, deviceID); } slotDir = ZERO; } @@ -192,51 +187,3 @@ insertFileCache(new PCIFile(bus, slot, func, PCI_BAR5, 4), "%x/%x/%x/bar5", bus, slot, func); } - -void PCIServer::runDeviceServer(u16 bus, u16 slot, u16 func, - u16 vendorID, u16 deviceID) -{ - ProcessID pid; - struct stat st; - char path[PATHLEN]; - const char *args[5]; - int status; - - /* - * Attempt to execute an external driver program - * to handle I/O for the PCI device. First we construct - * the full path to the handler, if any. - */ - snprintf(path, sizeof(path), "/etc/pci/%x:%x", - vendorID, deviceID); - - /* If there is no device server, forget it. */ - if (stat(path, &st) == -1) - { - return; - } - - /* - * Construct an argument list. - */ - for (int i = 0; i < 4; i++) - { - args[i] = new char[PATHLEN]; - } - args[4] = ZERO; - snprintf((char*)args[0], PATHLEN, "%s", path); - snprintf((char*)args[1], PATHLEN, "%x", bus); - snprintf((char*)args[2], PATHLEN, "%x", slot); - snprintf((char*)args[3], PATHLEN, "%x", func); - - /* - * Try to fork off a child for the device server. - */ - if ((pid = forkexec(path, args)) == (pid_t) -1) - { - syslog(LOG_ERR, "failed to forkexec() `%s': %s\r\n", - path, strerror(errno)); - } - else - waitpid(pid, &status, 0); -} ======================================= --- /trunk/srv/pci/PCIServer.h Sun Aug 16 14:22:16 2009 +++ /trunk/srv/pci/PCIServer.h Tue Aug 18 13:59:35 2009 @@ -188,17 +188,6 @@ * @param func Device function number in the slot. */ void detect(u16 bus, u16 slot, u16 func); - - /** - * @brief Runs a PCI device server. - * @param bus PCI Bus number on which the device was detected. - * @param slot Slot number in the PCI bus. - * @param func Device function number in the slot. - * @param vendorID Numeric vendor ID read from PCI configuration space. - * @param deviceID Numeric device ID read from PCI configuration space. - */ - void runDeviceServer(u16 bus, u16 slot, u16 func, - u16 vendorID, u16 deviceID); /** @brief Root directory pointer. */ Directory *rootDir; ======================================= --- /trunk/srv/pci/SConscript Sun Aug 16 14:22:16 2009 +++ /trunk/srv/pci/SConscript Tue Aug 18 13:59:35 2009 @@ -22,3 +22,6 @@ env.Program('server', [ 'PCIServer.cpp', 'PCIFile.cpp' ], LIBS = env['LIBS'], LIBPATH = env['LIBPATH']) + +env.Program('detect', [ 'PCIDetect.cpp' ], + LIBS = env['LIBS'], LIBPATH = env['LIBPATH'])