From 8743575dcf773bae0326186fd0e2b3b9aaf781f1 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Fri, 17 Apr 2015 14:12:30 +0200 Subject: [PATCH] pci: support discovery of non pci devices Issue #1486 --- repos/os/include/pci_device/pci_device.h | 11 +++ repos/os/include/pci_session/client.h | 7 +- repos/os/include/pci_session/pci_session.h | 23 ++++- repos/os/src/drivers/pci/nonpci_devices.cc | 93 +++++++++++++++++++ .../os/src/drivers/pci/pci_device_component.h | 10 ++ .../src/drivers/pci/pci_session_component.h | 57 ++---------- repos/os/src/drivers/pci/session.cc | 60 ++++++++++++ repos/os/src/drivers/pci/x86/target.mk | 2 +- 8 files changed, 210 insertions(+), 53 deletions(-) create mode 100644 repos/os/src/drivers/pci/nonpci_devices.cc create mode 100644 repos/os/src/drivers/pci/session.cc diff --git a/repos/os/include/pci_device/pci_device.h b/repos/os/include/pci_device/pci_device.h index 3d7637662..db3f9ee1f 100644 --- a/repos/os/include/pci_device/pci_device.h +++ b/repos/os/include/pci_device/pci_device.h @@ -16,17 +16,28 @@ #include #include +#include #include #include +#include /* os includes */ #include + namespace Pci { struct Device; } struct Pci::Device : Platform::Device { + /********************* + ** Exception types ** + *********************/ + + class Alloc_failed : public Genode::Exception { }; + class Quota_exceeded : public Alloc_failed { }; + + class Resource { private: diff --git a/repos/os/include/pci_session/client.h b/repos/os/include/pci_session/client.h index cfa45ecdf..d0117fd5b 100644 --- a/repos/os/include/pci_session/client.h +++ b/repos/os/include/pci_session/client.h @@ -14,9 +14,11 @@ #ifndef _INCLUDE__PCI_SESSION__CLIENT_H_ #define _INCLUDE__PCI_SESSION__CLIENT_H_ -#include #include +#include +#include + namespace Pci { struct Session_client; } @@ -45,6 +47,9 @@ struct Pci::Session_client : public Genode::Rpc_client void free_dma_buffer(Genode::Ram_dataspace_capability cap) override { call(cap); } + + Device_capability device(String const &device) override { + return call(device); } }; #endif /* _INCLUDE__PCI_SESSION__CLIENT_H_ */ diff --git a/repos/os/include/pci_session/pci_session.h b/repos/os/include/pci_session/pci_session.h index b6937514d..3625f1c8a 100644 --- a/repos/os/include/pci_session/pci_session.h +++ b/repos/os/include/pci_session/pci_session.h @@ -14,13 +14,16 @@ #ifndef _INCLUDE__PCI_SESSION__PCI_SESSION_H_ #define _INCLUDE__PCI_SESSION__PCI_SESSION_H_ -#include +/* base */ #include #include +/* os */ +#include + namespace Pci { - typedef Genode::Capability Device_capability; + typedef Genode::Capability Device_capability; struct Session; } @@ -61,9 +64,16 @@ struct Pci::Session : Genode::Session */ virtual Genode::Io_mem_dataspace_capability config_extended(Device_capability) = 0; + typedef Genode::Rpc_in_buffer<8> String; + /** - * Allocate memory suitable for DMA. + * Provide non-PCI device known by unique name. */ + virtual Device_capability device(String const &string) = 0; + + /** + * Allocate memory suitable for DMA. + */ virtual Genode::Ram_dataspace_capability alloc_dma_buffer(Genode::size_t) = 0; /** @@ -71,6 +81,7 @@ struct Pci::Session : Genode::Session */ virtual void free_dma_buffer(Genode::Ram_dataspace_capability) = 0; + /********************* ** RPC declaration ** *********************/ @@ -88,10 +99,14 @@ struct Pci::Session : Genode::Session Genode::size_t); GENODE_RPC(Rpc_free_dma_buffer, void, free_dma_buffer, Genode::Ram_dataspace_capability); + GENODE_RPC_THROW(Rpc_device, Device_capability, device, + GENODE_TYPE_LIST(Pci::Device::Quota_exceeded), + String const &); GENODE_RPC_INTERFACE(Rpc_first_device, Rpc_next_device, Rpc_release_device, Rpc_config_extended, - Rpc_alloc_dma_buffer, Rpc_free_dma_buffer); + Rpc_alloc_dma_buffer, Rpc_free_dma_buffer, + Rpc_device); }; #endif /* _INCLUDE__PCI_SESSION__PCI_SESSION_H_ */ diff --git a/repos/os/src/drivers/pci/nonpci_devices.cc b/repos/os/src/drivers/pci/nonpci_devices.cc new file mode 100644 index 000000000..938caa285 --- /dev/null +++ b/repos/os/src/drivers/pci/nonpci_devices.cc @@ -0,0 +1,93 @@ +/* + * \brief Non PCI devices, e.g. PS2 + * \author Alexander Boettcher + */ + +/* + * Copyright (C) 2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include +#include "pci_session_component.h" + + +namespace Nonpci { class Ps2; } + +class Nonpci::Ps2 : public Pci::Device_component +{ + private: + + enum { + IRQ_KEYBOARD = 1, + IRQ_MOUSE = 12, + }; + + Genode::Irq_connection _irq_mouse; + + public: + + Ps2(Genode::Rpc_entrypoint * ep, Pci::Session_component * session) + : + Pci::Device_component(ep, IRQ_KEYBOARD), + _irq_mouse(IRQ_MOUSE) + { } + + Genode::Irq_session_capability irq(Genode::uint8_t virt_irq) override + { + switch (virt_irq) { + case 0: + return Device_component::irq(virt_irq); + case 1: + return _irq_mouse.cap(); + default: + return Genode::Irq_session_capability(); + } + } +}; + + +/** + * PCI session component devices which are non PCI devices, e.g. PS2 + */ +Pci::Device_capability Pci::Session_component::device(String const &name) { + + if (!name.is_valid_string()) + return Device_capability(); + + using namespace Genode; + + char const * device_name = name.string(); + const char * devices [] = { "PS2" }; + unsigned devices_i = 0; + + for (; devices_i < sizeof(devices) / sizeof(devices[0]); devices_i++) + if (!strcmp(device_name, devices[devices_i])) + break; + + if (devices_i >= sizeof(devices) / sizeof(devices[0])) { + PERR("unknown '%s' device name", device_name); + return Device_capability(); + } + + try { + Device_component * dev = nullptr; + + switch(devices_i) { + case 0: + dev = new (_md_alloc) Nonpci::Ps2(_ep, this); + break; + default: + return Device_capability(); + } + + _device_list.insert(dev); + return _ep->manage(dev); + } catch (Genode::Allocator::Out_of_memory) { + throw Pci::Device::Quota_exceeded(); + } catch (Genode::Parent::Service_denied) { + return Device_capability(); + } +} diff --git a/repos/os/src/drivers/pci/pci_device_component.h b/repos/os/src/drivers/pci/pci_device_component.h index 23f15fdd9..a7b6a62cb 100644 --- a/repos/os/src/drivers/pci/pci_device_component.h +++ b/repos/os/src/drivers/pci/pci_device_component.h @@ -57,6 +57,16 @@ class Pci::Device_component : public Genode::Rpc_object, _ep->manage(&_irq_session); } + /** + * Constructor for non PCI devices + */ + Device_component(Genode::Rpc_entrypoint *ep, unsigned irq) + : + _config_space(~0UL), _io_mem(0), _ep(ep), _irq_session(irq) + { + _ep->manage(&_irq_session); + } + /** * De-constructor */ diff --git a/repos/os/src/drivers/pci/pci_session_component.h b/repos/os/src/drivers/pci/pci_session_component.h index 9db1e4084..75a788f88 100644 --- a/repos/os/src/drivers/pci/pci_session_component.h +++ b/repos/os/src/drivers/pci/pci_session_component.h @@ -14,65 +14,26 @@ #ifndef _PCI_SESSION_COMPONENT_H_ #define _PCI_SESSION_COMPONENT_H_ +/* base */ #include -#include +#include #include +/* os */ #include - #include +#include +/* local */ #include "pci_device_component.h" #include "pci_config_access.h" #include "pci_device_pd_ipc.h" namespace Pci { + bool bus_valid(int bus = 0); +} - /** - * Check if given PCI bus was found on initial scan - * - * This tremendously speeds up further scans by other drivers. - */ - bool bus_valid(int bus = 0) - { - struct Valid_buses - { - bool valid[Device_config::MAX_BUSES]; - - void scan_bus(Config_access &config_access, int bus = 0) - { - for (int dev = 0; dev < Device_config::MAX_DEVICES; ++dev) { - for (int fun = 0; fun < Device_config::MAX_FUNCTIONS; ++fun) { - - /* read config space */ - Device_config config(bus, dev, fun, &config_access); - - if (!config.valid()) - continue; - - /* - * There is at least one device on the current bus, so - * we mark it as valid. - */ - valid[bus] = true; - - /* scan behind bridge */ - if (config.is_pci_bridge()) { - int sub_bus = config.read(&config_access, - 0x19, Device::ACCESS_8BIT); - scan_bus(config_access, sub_bus); - } - } - } - } - - Valid_buses() { Config_access c; scan_bus(c); } - }; - - static Valid_buses buses; - - return buses.valid[bus]; - } +namespace Pci { class Session_component : public Genode::Rpc_object { @@ -335,6 +296,8 @@ namespace Pci { if (ram.valid()) _ram->free(ram); } + + Device_capability device(String const &name) override; }; diff --git a/repos/os/src/drivers/pci/session.cc b/repos/os/src/drivers/pci/session.cc new file mode 100644 index 000000000..c2e7951c6 --- /dev/null +++ b/repos/os/src/drivers/pci/session.cc @@ -0,0 +1,60 @@ +/* + * \brief PCI-session component + * \author Norman Feske + * \date 2008-01-28 + */ + +/* + * Copyright (C) 2008-2015 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#include "pci_session_component.h" + +/** + * Check if given PCI bus was found on initial scan + * + * This tremendously speeds up further scans by other drivers. + */ +bool Pci::bus_valid(int bus) +{ + struct Valid_buses + { + bool valid[Device_config::MAX_BUSES]; + + void scan_bus(Config_access &config_access, int bus = 0) + { + for (int dev = 0; dev < Device_config::MAX_DEVICES; ++dev) { + for (int fun = 0; fun < Device_config::MAX_FUNCTIONS; ++fun) { + + /* read config space */ + Device_config config(bus, dev, fun, &config_access); + + if (!config.valid()) + continue; + + /* + * There is at least one device on the current bus, so + * we mark it as valid. + */ + valid[bus] = true; + + /* scan behind bridge */ + if (config.is_pci_bridge()) { + int sub_bus = config.read(&config_access, + 0x19, Device::ACCESS_8BIT); + scan_bus(config_access, sub_bus); + } + } + } + } + + Valid_buses() { Config_access c; scan_bus(c); } + }; + + static Valid_buses buses; + + return buses.valid[bus]; +} diff --git a/repos/os/src/drivers/pci/x86/target.mk b/repos/os/src/drivers/pci/x86/target.mk index b3c3c97e2..3988fe787 100644 --- a/repos/os/src/drivers/pci/x86/target.mk +++ b/repos/os/src/drivers/pci/x86/target.mk @@ -1,6 +1,6 @@ TARGET = pci_drv REQUIRES = x86 -SRC_CC = main.cc irq.cc +SRC_CC = main.cc irq.cc nonpci_devices.cc session.cc LIBS = base config INC_DIR = $(PRG_DIR)/..