/* * \brief Demo device-driver manager (d3m) * \author Christian Helmuth * \author Norman Feske * \date 2010-09-21 * * D3m is a simple device-driver manager for demo purposes. Currently, it copes * with the following tasks: * * - Merge events of input drivers for PS/2 and USB HID * - Probe boot device using the ATAPI and USB storage drivers */ /* * Copyright (C) 2012 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. */ /* Genode includes */ #include #include #include #include #include #include #include /* local includes */ #include #include #include class Ipxe_policy : public Genode::Slave_policy, public Nic::Provider { Genode::Root_capability _cap; bool _announced; Genode::Lock _lock; protected: char const **_permitted_services() const { static char const *permitted_services[] = { "CAP", "RM", "LOG", "SIGNAL", "Timer", "PCI", "IO_MEM", "IO_PORT", "IRQ", 0 }; return permitted_services; }; public: Ipxe_policy(Genode::Rpc_entrypoint &entrypoint) : Slave_policy("nic_drv", entrypoint), _announced(false), _lock(Genode::Lock::LOCKED) { } bool announce_service(const char *service_name, Genode::Root_capability root, Genode::Allocator *alloc) { if (Genode::strcmp(service_name, "Nic")) return false; _cap = root; return true; } /** * Nic::Provider interface */ Genode::Root_capability root() { return _cap; } }; struct Ps2_policy : public Genode::Slave_policy { private: Input::Source_registry &_input_source_registry; Input::Source _input_source_registry_entry; protected: char const **_permitted_services() const { static char const *allowed_services[] = { "CAP", "RM", "IO_PORT", "IRQ", "LOG", 0 }; return allowed_services; }; public: Ps2_policy(Genode::Rpc_entrypoint &entrypoint, Input::Source_registry &input_source_registry) : Genode::Slave_policy("ps2_drv", entrypoint), _input_source_registry(input_source_registry) { } bool announce_service(const char *service_name, Genode::Root_capability root, Genode::Allocator *alloc) { if (Genode::strcmp(service_name, "Input")) return false; _input_source_registry_entry.connect(root); _input_source_registry.add_source(&_input_source_registry_entry); return true; } }; struct Usb_policy : public Genode::Slave_policy { private: Input::Source_registry &_input_source_registry; Input::Source _input_source_registry_entry; Block::Driver_registry &_block_driver_registry; Block::Driver _block_driver; protected: const char **_permitted_services() const { static const char *permitted_services[] = { "CAP", "RM", "IO_PORT", "IO_MEM", "IRQ", "LOG", "PCI", "Timer", "SIGNAL", 0 }; return permitted_services; }; public: Usb_policy(Genode::Rpc_entrypoint &entrypoint, Input::Source_registry &input_source_registry, Block::Driver_registry &block_driver_registry, Genode::Dataspace_capability config) : Genode::Slave_policy("usb_drv", entrypoint, config), _input_source_registry(input_source_registry), _block_driver_registry(block_driver_registry) { } bool announce_service(const char *service_name, Genode::Root_capability root, Genode::Allocator *alloc) { if (Genode::strcmp(service_name, "Input") == 0) { _input_source_registry_entry.connect(root); _input_source_registry.add_source(&_input_source_registry_entry); return true; } if (Genode::strcmp(service_name, "Block") == 0) { _block_driver.init("usb_drv", root); _block_driver_registry.add_driver(&_block_driver); return true; } return false; } }; class Atapi_policy : public Genode::Slave_policy { private: Block::Driver_registry &_block_driver_registry; Block::Driver _block_driver; protected: const char **_permitted_services() const { static const char *permitted_services[] = { "CAP", "RM", "LOG", "SIGNAL", "Timer", "PCI", "IO_MEM", "IO_PORT", "IRQ", 0 }; return permitted_services; }; public: Atapi_policy(Genode::Rpc_entrypoint &entrypoint, Block::Driver_registry &block_driver_registry) : Genode::Slave_policy("atapi_drv", entrypoint), _block_driver_registry(block_driver_registry) { } bool announce_service(char const *service_name, Genode::Root_capability root, Genode::Allocator *alloc) { if (Genode::strcmp(service_name, "Block")) return false; _block_driver.init(name(), root); _block_driver_registry.add_driver(&_block_driver); return true; } }; int main(int argc, char **argv) { using namespace Genode; enum { STACK_SIZE = 2*4096 }; static Cap_connection cap; static Rpc_entrypoint ep(&cap, STACK_SIZE, "d3m_ep"); /* * Registry of input-event sources * * Upon startup of the USB HID and PS/2 drivers, this registry gets * populated when each of the drivers announces its respective 'Input' * service. */ static Input::Source_registry input_source_registry; /* * Registry for boot block device */ static Block::Driver_registry block_driver_registry; /* create PS/2 driver */ static Rpc_entrypoint ps2_ep(&cap, STACK_SIZE, "ps2_slave"); static Ps2_policy ps2_policy(ps2_ep, input_source_registry); static Genode::Slave ps2_slave(ps2_ep, ps2_policy, 512*1024); /* * Create config dataspace for USB driver */ enum { USB_CONFIG_MAX_LEN = 4096 }; Genode::Attached_ram_dataspace usb_config_ds(Genode::env()->ram_session(), USB_CONFIG_MAX_LEN); char const *config = ""; Genode::strncpy(usb_config_ds.local_addr(), config, USB_CONFIG_MAX_LEN); /* create USB driver */ static Rpc_entrypoint usb_ep(&cap, STACK_SIZE, "usb_slave"); static Usb_policy usb_policy(usb_ep, input_source_registry, block_driver_registry, usb_config_ds.cap()); static Genode::Slave usb_slave(usb_ep, usb_policy, 1024*1024); /* create ATAPI driver */ static Rpc_entrypoint atapi_ep(&cap, STACK_SIZE, "atapi_slave"); static Atapi_policy atapi_policy(atapi_ep, block_driver_registry); static Genode::Slave atapi_slave(atapi_ep, atapi_policy, 1024*1024); /* initialize input service */ static Input::Root input_root(&ep, env()->heap(), input_source_registry); env()->parent()->announce(ep.manage(&input_root)); /* * Always announce 'Nic' service, throw 'Unavailable' during session * request if no appropriate driver could be found. */ static Rpc_entrypoint nic_ep(&cap, STACK_SIZE, "nic_slave"); static Ipxe_policy nic_policy(nic_ep); static Genode::Slave nic_slave(nic_ep, nic_policy, 2048 * 1024); static Nic::Root nic_root(nic_policy); env()->parent()->announce(ep.manage(&nic_root)); /* * Announce 'Block' service * * We use a distinct entrypoint for the block driver because otherwise, a * long-taking block session request may defer other session requests * (i.e., input session). By using a different entrypoint, the GUI can * start even if the boot-device probing failed completely. */ { static Rpc_entrypoint ep(&cap, STACK_SIZE, "d3m_block_ep"); static Block::Root block_root(block_driver_registry); env()->parent()->announce(ep.manage(&block_root)); } Genode::sleep_forever(); return 0; }