pci: support discovery of non pci devices

Issue #1486
This commit is contained in:
Alexander Boettcher 2015-04-17 14:12:30 +02:00 committed by Christian Helmuth
parent e4d663cf41
commit 8743575dcf
8 changed files with 210 additions and 53 deletions

View File

@ -16,17 +16,28 @@
#include <base/rpc.h>
#include <base/signal.h>
#include <base/exception.h>
#include <io_mem_session/io_mem_session.h>
#include <irq_session/capability.h>
#include <ram_session/ram_session.h>
/* os includes */
#include <platform/device.h>
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:

View File

@ -14,9 +14,11 @@
#ifndef _INCLUDE__PCI_SESSION__CLIENT_H_
#define _INCLUDE__PCI_SESSION__CLIENT_H_
#include <pci_session/capability.h>
#include <base/rpc_client.h>
#include <pci_device/client.h>
#include <pci_session/capability.h>
namespace Pci { struct Session_client; }
@ -45,6 +47,9 @@ struct Pci::Session_client : public Genode::Rpc_client<Session>
void free_dma_buffer(Genode::Ram_dataspace_capability cap) override {
call<Rpc_free_dma_buffer>(cap); }
Device_capability device(String const &device) override {
return call<Rpc_device>(device); }
};
#endif /* _INCLUDE__PCI_SESSION__CLIENT_H_ */

View File

@ -14,13 +14,16 @@
#ifndef _INCLUDE__PCI_SESSION__PCI_SESSION_H_
#define _INCLUDE__PCI_SESSION__PCI_SESSION_H_
#include <pci_device/pci_device.h>
/* base */
#include <session/session.h>
#include <ram_session/ram_session.h>
/* os */
#include <pci_device/pci_device.h>
namespace Pci {
typedef Genode::Capability<Device> Device_capability;
typedef Genode::Capability<Pci::Device> 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_ */

View File

@ -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 <irq_session/connection.h>
#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();
}
}

View File

@ -57,6 +57,16 @@ class Pci::Device_component : public Genode::Rpc_object<Pci::Device>,
_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
*/

View File

@ -14,65 +14,26 @@
#ifndef _PCI_SESSION_COMPONENT_H_
#define _PCI_SESSION_COMPONENT_H_
/* base */
#include <base/rpc_server.h>
#include <pci_session/pci_session.h>
#include <ram_session/connection.h>
#include <root/component.h>
/* os */
#include <io_mem_session/connection.h>
#include <os/config.h>
#include <pci_session/pci_session.h>
/* 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<Session>
{
@ -335,6 +296,8 @@ namespace Pci {
if (ram.valid())
_ram->free(ram);
}
Device_capability device(String const &name) override;
};

View File

@ -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];
}

View File

@ -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)/..