mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-17 22:58:26 +00:00
usb: Move driver into library
This raised the opportunity to structure the library more cleanly for each supported platform.
This commit is contained in:
committed by
Norman Feske
parent
ebc76fc13b
commit
6ef3f0f153
18
dde_linux/src/lib/usb/arm/mem.cc
Normal file
18
dde_linux/src/lib/usb/arm/mem.cc
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* \brief Backend for allocating DMA memory on ARM
|
||||
* \author Alexander Boettcher
|
||||
* \date 2013-02-19
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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 <base/env.h>
|
||||
#include "mem.h"
|
||||
|
||||
Genode::Ram_dataspace_capability Genode::Mem::alloc_dma_buffer(size_t size) {
|
||||
return Genode::env()->ram_session()->alloc(size, false); }
|
162
dde_linux/src/lib/usb/arm/platform_arndale/platform.cc
Normal file
162
dde_linux/src/lib/usb/arm/platform_arndale/platform.cc
Normal file
@ -0,0 +1,162 @@
|
||||
/*
|
||||
* \brief EHCI for Arndale initializaion code
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2013-02-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013 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 */
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
/* Emulation */
|
||||
#include <platform/platform.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
/* Linux */
|
||||
#include <plat/ehci.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
enum {
|
||||
EHCI_BASE = 0x12110000,
|
||||
GPIO_BASE = 0x11400000,
|
||||
EHCI_IRQ = 103,
|
||||
};
|
||||
|
||||
static resource _ehci[] =
|
||||
{
|
||||
{ EHCI_BASE, EHCI_BASE + 0xfff, "ehci", IORESOURCE_MEM },
|
||||
{ EHCI_IRQ, EHCI_IRQ, "ehci-irq", IORESOURCE_IRQ },
|
||||
};
|
||||
|
||||
static struct s5p_ehci_platdata _ehci_data;
|
||||
|
||||
|
||||
/**
|
||||
* EHCI controller
|
||||
*/
|
||||
struct Ehci : Genode::Mmio
|
||||
{
|
||||
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
write<Cmd>(0);
|
||||
|
||||
/* reset */
|
||||
write<Cmd::Reset>(1);
|
||||
|
||||
while(read<Cmd::Reset>())
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
struct Cmd : Register<0x10, 32>
|
||||
{
|
||||
struct Reset : Bitfield<1, 1> { };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Gpio handling
|
||||
*/
|
||||
struct Gpio_bank {
|
||||
unsigned con;
|
||||
unsigned dat;
|
||||
};
|
||||
|
||||
|
||||
static inline
|
||||
unsigned con_mask(unsigned val) { return 0xf << ((val) << 2); }
|
||||
|
||||
|
||||
static inline
|
||||
unsigned con_sfr(unsigned x, unsigned v) { return (v) << ((x) << 2); }
|
||||
|
||||
|
||||
static void gpio_cfg_pin(Gpio_bank *bank, int gpio, int cfg)
|
||||
{
|
||||
unsigned int value;
|
||||
|
||||
value = readl(&bank->con);
|
||||
value &= ~con_mask(gpio);
|
||||
value |= con_sfr(gpio, cfg);
|
||||
writel(value, &bank->con);
|
||||
}
|
||||
|
||||
|
||||
static void gpio_direction_output(Gpio_bank *bank, int gpio, int en)
|
||||
{
|
||||
unsigned int value;
|
||||
enum { GPIO_OUTPUT = 0x1 };
|
||||
|
||||
gpio_cfg_pin(bank, gpio, GPIO_OUTPUT);
|
||||
|
||||
value = readl(&bank->dat);
|
||||
value &= ~(0x1 << gpio);
|
||||
if (en)
|
||||
value |= 0x1 << gpio;
|
||||
writel(value, &bank->dat);
|
||||
}
|
||||
|
||||
|
||||
static void arndale_ehci_init()
|
||||
{
|
||||
enum Gpio_offset { D1 = 0x180, X3 = 0xc60 };
|
||||
|
||||
/* reset hub via GPIO */
|
||||
Io_mem_connection io_gpio(GPIO_BASE, 0x1000);
|
||||
addr_t gpio_base = (addr_t)env()->rm_session()->attach(io_gpio.dataspace());
|
||||
|
||||
Gpio_bank *d1 = reinterpret_cast<Gpio_bank *>(gpio_base + D1);
|
||||
Gpio_bank *x3 = reinterpret_cast<Gpio_bank *>(gpio_base + X3);
|
||||
|
||||
/* hub reset */
|
||||
gpio_direction_output(x3, 5, 0);
|
||||
/* hub connect */
|
||||
gpio_direction_output(d1, 7, 0);
|
||||
|
||||
gpio_direction_output(x3, 5, 1);
|
||||
gpio_direction_output(d1, 7, 1);
|
||||
|
||||
env()->rm_session()->detach(gpio_base);
|
||||
|
||||
/* reset ehci controller */
|
||||
Io_mem_connection io_ehci(EHCI_BASE, 0x1000);
|
||||
addr_t ehci_base = (addr_t)env()->rm_session()->attach(io_ehci.dataspace());
|
||||
|
||||
Ehci ehci(ehci_base);
|
||||
env()->rm_session()->detach(ehci_base);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void module_ehci_hcd_init();
|
||||
|
||||
void platform_hcd_init(Services *services)
|
||||
{
|
||||
/* register EHCI controller */
|
||||
module_ehci_hcd_init();
|
||||
|
||||
/* setup controller */
|
||||
arndale_ehci_init();
|
||||
|
||||
/* setup EHCI-controller platform device */
|
||||
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
|
||||
pdev->name = "s5p-ehci";
|
||||
pdev->id = 0;
|
||||
pdev->num_resources = 2;
|
||||
pdev->resource = _ehci;
|
||||
pdev->dev.platform_data = &_ehci_data;
|
||||
|
||||
/*needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c' */
|
||||
static u64 dma_mask = ~(u64)0;
|
||||
pdev->dev.dma_mask = &dma_mask;
|
||||
pdev->dev.coherent_dma_mask = ~0;
|
||||
|
||||
platform_device_register(pdev);
|
||||
}
|
108
dde_linux/src/lib/usb/arm/platform_device.c
Normal file
108
dde_linux/src/lib/usb/arm/platform_device.c
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* \brief Linux platform_device emulation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <lx_emul.h>
|
||||
|
||||
#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \
|
||||
driver))
|
||||
#define to_platform_device(x) container_of((x), struct platform_device, dev)
|
||||
|
||||
|
||||
static int platform_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
if (!dev->name)
|
||||
return 0;
|
||||
|
||||
return (strcmp(dev->name, drv->name) == 0);
|
||||
}
|
||||
|
||||
|
||||
static int platform_drv_probe(struct device *_dev)
|
||||
{
|
||||
struct platform_driver *drv = to_platform_driver(_dev->driver);
|
||||
struct platform_device *dev = to_platform_device(_dev);
|
||||
|
||||
return drv->probe(dev);
|
||||
}
|
||||
|
||||
|
||||
struct bus_type platform_bus_type = {
|
||||
.name = "platform",
|
||||
.match = platform_match,
|
||||
.probe = platform_drv_probe
|
||||
};
|
||||
|
||||
|
||||
int platform_driver_register(struct platform_driver *drv)
|
||||
{
|
||||
drv->driver.bus = &platform_bus_type;
|
||||
if (drv->probe)
|
||||
drv->driver.probe = platform_drv_probe;
|
||||
|
||||
return driver_register(&drv->driver);
|
||||
}
|
||||
|
||||
struct resource *platform_get_resource(struct platform_device *dev,
|
||||
unsigned int type, unsigned int num)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->num_resources; i++) {
|
||||
struct resource *r = &dev->resource[i];
|
||||
|
||||
if ((type & r->flags) && num-- == 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct resource *platform_get_resource_byname(struct platform_device *dev,
|
||||
unsigned int type,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < dev->num_resources; i++) {
|
||||
struct resource *r = &dev->resource[i];
|
||||
|
||||
if (type == r->flags && !strcmp(r->name, name))
|
||||
return r;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int platform_get_irq_byname(struct platform_device *dev, const char *name)
|
||||
{
|
||||
struct resource *r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name);
|
||||
return r ? r->start : -1;
|
||||
}
|
||||
|
||||
|
||||
int platform_get_irq(struct platform_device *dev, unsigned int num)
|
||||
{
|
||||
struct resource *r = platform_get_resource(dev, IORESOURCE_IRQ, 0);
|
||||
return r ? r->start : -1;
|
||||
}
|
||||
|
||||
int platform_device_register(struct platform_device *pdev)
|
||||
{
|
||||
pdev->dev.bus = &platform_bus_type;
|
||||
pdev->dev.name = pdev->name;
|
||||
/* XXX: Fill with magic value to see page fault */
|
||||
pdev->dev.parent = (struct device *)0xaaaaaaaa;
|
||||
device_add(&pdev->dev);
|
||||
return 0;
|
||||
}
|
402
dde_linux/src/lib/usb/arm/platform_panda/platform.cc
Normal file
402
dde_linux/src/lib/usb/arm/platform_panda/platform.cc
Normal file
@ -0,0 +1,402 @@
|
||||
/**
|
||||
* \brief EHCI for OMAP4
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-06-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <platform/platform.h>
|
||||
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/**
|
||||
* Base addresses
|
||||
*/
|
||||
enum {
|
||||
EHCI_BASE = 0x4a064c00,
|
||||
UHH_BASE = 0x4a064000,
|
||||
TLL_BASE = 0x4a062000,
|
||||
SCRM_BASE = 0x4a30a000,
|
||||
CAM_BASE = 0x4a009000, /* used for L3INIT_CM2 */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Inerrupt numbers
|
||||
*/
|
||||
enum {
|
||||
IRQ_GIC_START = 32,
|
||||
IRQ_EHCI = IRQ_GIC_START + 77,
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Resources for platform device
|
||||
*/
|
||||
static resource _ehci[] =
|
||||
{
|
||||
{ EHCI_BASE, EHCI_BASE + 0x400 - 1, "ehci", IORESOURCE_MEM },
|
||||
{ IRQ_EHCI, IRQ_EHCI, "ehci-irq", IORESOURCE_IRQ },
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Port informations for platform device
|
||||
*/
|
||||
static struct ehci_hcd_omap_platform_data _ehci_data
|
||||
{
|
||||
{ OMAP_EHCI_PORT_MODE_PHY, OMAP_EHCI_PORT_MODE_NONE },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Enables USB clocks
|
||||
*/
|
||||
struct Clocks : Genode::Mmio
|
||||
{
|
||||
Clocks(Genode::addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
write<Usb_phy_clk>(0x101);
|
||||
write<Usb_host_clk>(0x1008002);
|
||||
write<Usb_tll_clk>(0x1);
|
||||
}
|
||||
|
||||
struct Usb_host_clk : Register<0x358, 32> { };
|
||||
struct Usb_tll_clk : Register<0x368, 32> { };
|
||||
struct Usb_phy_clk : Register<0x3e0, 32> { };
|
||||
|
||||
template <typename T> void update(unsigned val)
|
||||
{
|
||||
typename T::access_t access = read<T>();
|
||||
access |= val;
|
||||
write<T>(access);
|
||||
};
|
||||
|
||||
void dump()
|
||||
{
|
||||
Usb_host_clk::access_t a1 = read<Usb_host_clk>();
|
||||
Usb_tll_clk::access_t a3 = read<Usb_tll_clk>();
|
||||
Usb_phy_clk::access_t a4 = read<Usb_phy_clk>();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Panda board reference USB clock
|
||||
*/
|
||||
struct Aux3 : Genode::Mmio
|
||||
{
|
||||
Aux3(addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
enable();
|
||||
}
|
||||
|
||||
/* the clock register */
|
||||
struct Aux3_clk : Register<0x31c, 32>
|
||||
{
|
||||
struct Src_select : Bitfield<1, 2> { };
|
||||
struct Div : Bitfield<16, 4> { enum { DIV_2 = 1 }; };
|
||||
struct Enable : Bitfield<8, 1> { enum { ON = 1 }; };
|
||||
};
|
||||
|
||||
/* clock source register */
|
||||
struct Aux_src : Register<0x110, 32, true> { };
|
||||
|
||||
void enable()
|
||||
{
|
||||
/* select system clock */
|
||||
write<Aux3_clk::Src_select>(0);
|
||||
|
||||
/* set to 19.2 Mhz */
|
||||
write<Aux3_clk::Div>(Aux3_clk::Div::DIV_2);
|
||||
|
||||
/* enable clock */
|
||||
write<Aux3_clk::Enable>(Aux3_clk::Enable::ON);
|
||||
|
||||
/* enable_ext = 1 | enable_int = 1| mode = 0x01 */
|
||||
write<Aux_src>(0xd);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* ULPI transceiverless link
|
||||
*/
|
||||
struct Tll : Genode::Mmio
|
||||
{
|
||||
Tll(addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
struct Sys_config : Register<0x10, 32>
|
||||
{
|
||||
struct Soft_reset : Bitfield<1, 1> { };
|
||||
struct Cactivity : Bitfield<8, 1> { };
|
||||
struct Sidle_mode : Bitfield<3, 2> { };
|
||||
struct Ena_wakeup : Bitfield<2, 1> { };
|
||||
};
|
||||
|
||||
struct Sys_status : Register<0x14, 32> { };
|
||||
|
||||
void reset()
|
||||
{
|
||||
write<Sys_config>(0x0);
|
||||
|
||||
/* reset */
|
||||
write<Sys_config::Soft_reset>(0x1);
|
||||
|
||||
while(!read<Sys_status>())
|
||||
msleep(1);
|
||||
|
||||
/* disable IDLE, enable wake up, enable auto gating */
|
||||
write<Sys_config::Cactivity>(1);
|
||||
write<Sys_config::Sidle_mode>(1);
|
||||
write<Sys_config::Ena_wakeup>(1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* USB high-speed host
|
||||
*/
|
||||
struct Uhh : Genode::Mmio
|
||||
{
|
||||
Uhh(addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
/* diable idle and standby */
|
||||
write<Sys_config::Idle>(1);
|
||||
write<Sys_config::Standby>(1);
|
||||
|
||||
/* set ports to external phy */
|
||||
write<Host_config::P1_mode>(0);
|
||||
write<Host_config::P2_mode>(0);
|
||||
}
|
||||
|
||||
struct Sys_config : Register<0x10, 32>
|
||||
{
|
||||
struct Idle : Bitfield<2, 2> { };
|
||||
struct Standby : Bitfield<4, 2> { };
|
||||
};
|
||||
|
||||
struct Host_config : Register<0x40, 32>
|
||||
{
|
||||
struct P1_mode : Bitfield<16, 2> { };
|
||||
struct P2_mode : Bitfield<18, 2> { };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* EHCI controller
|
||||
*/
|
||||
struct Ehci : Genode::Mmio
|
||||
{
|
||||
Ehci(addr_t const mmio_base) : Mmio(mmio_base)
|
||||
{
|
||||
write<Cmd>(0);
|
||||
|
||||
/* reset */
|
||||
write<Cmd::Reset>(1);
|
||||
|
||||
while(read<Cmd::Reset>())
|
||||
msleep(1);
|
||||
}
|
||||
|
||||
struct Cmd : Register<0x10, 32>
|
||||
{
|
||||
struct Reset : Bitfield<1, 1> { };
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Panda board GPIO bases 1 - 6
|
||||
*/
|
||||
static addr_t omap44xx_gpio_base[] =
|
||||
{
|
||||
0x4A310000, 0x48055000, 0x48057000, 0x48059000, 0x4805B000, 0x4805D000
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* General purpose I/O
|
||||
*/
|
||||
struct Gpio
|
||||
{
|
||||
enum { GPIO = 6 };
|
||||
|
||||
addr_t _io[GPIO];
|
||||
Io_mem_session_capability _cap[GPIO];
|
||||
|
||||
void map()
|
||||
{
|
||||
for (int i = 0; i < GPIO; i++) {
|
||||
Io_mem_connection io(omap44xx_gpio_base[i], 0x1000);
|
||||
io.on_destruction(Io_mem_connection::KEEP_OPEN);
|
||||
_io[i] = (addr_t)env()->rm_session()->attach(io.dataspace());
|
||||
_cap[i] = io.cap();
|
||||
}
|
||||
}
|
||||
|
||||
Gpio()
|
||||
{
|
||||
map();
|
||||
}
|
||||
|
||||
~Gpio()
|
||||
{
|
||||
for (int i = 0; i < GPIO; i++) {
|
||||
env()->rm_session()->detach(_io[i]);
|
||||
env()->parent()->close(_cap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
addr_t base(unsigned gpio) { return _io[gpio >> 5]; }
|
||||
int index(unsigned gpio) { return gpio & 0x1f; }
|
||||
|
||||
void _set_data_out(addr_t base, unsigned gpio, bool enable)
|
||||
{
|
||||
enum { SETDATAOUT = 0x194, CLEARDATAOUT = 0x190 };
|
||||
writel(1U << gpio, base + (enable ? SETDATAOUT : CLEARDATAOUT));
|
||||
}
|
||||
|
||||
void _set_gpio_direction(addr_t base, unsigned gpio, bool input)
|
||||
{
|
||||
enum { OE = 0x134 };
|
||||
base += OE;
|
||||
|
||||
u32 val = readl(base);
|
||||
|
||||
if (input)
|
||||
val |= 1U << gpio;
|
||||
else
|
||||
val &= ~(1U << gpio);
|
||||
|
||||
writel(val, base);
|
||||
}
|
||||
|
||||
void direction_output(unsigned gpio, bool enable)
|
||||
{
|
||||
_set_data_out(base(gpio), index(gpio), enable);
|
||||
_set_gpio_direction(base(gpio), index(gpio), false);
|
||||
}
|
||||
|
||||
void direction_input(unsigned gpio)
|
||||
{
|
||||
_set_gpio_direction(base(gpio), index(gpio), true);
|
||||
}
|
||||
|
||||
void set_value(unsigned gpio, int val)
|
||||
{
|
||||
_set_data_out(base(gpio), index(gpio), val);
|
||||
}
|
||||
|
||||
unsigned get_value(int gpio)
|
||||
{
|
||||
enum { DATAIN = 0x138 };
|
||||
return (readl(base(gpio) + DATAIN) & (1 << index(gpio))) != 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the USB controller from scratch, since the boot loader might not
|
||||
* do it or even disable USB.
|
||||
*/
|
||||
static void omap_ehci_init()
|
||||
{
|
||||
/* taken from the Panda board manual */
|
||||
enum { HUB_POWER = 1, HUB_NRESET = 62, ULPI_PHY_TYPE = 182 };
|
||||
|
||||
/* SCRM */
|
||||
Io_mem_connection io_scrm(SCRM_BASE, 0x1000);
|
||||
addr_t scrm_base = (addr_t)env()->rm_session()->attach(io_scrm.dataspace());
|
||||
|
||||
/* enable reference clock */
|
||||
Aux3 aux3(scrm_base);
|
||||
|
||||
/* init GPIO */
|
||||
Gpio gpio;
|
||||
/* disable the hub power and reset before init */
|
||||
gpio.direction_output(HUB_POWER, false);
|
||||
gpio.direction_output(HUB_NRESET, false);
|
||||
gpio.set_value(HUB_POWER, 0);
|
||||
gpio.set_value(HUB_NRESET, 1);
|
||||
|
||||
/* enable clocks */
|
||||
Io_mem_connection io_clock(CAM_BASE, 0x1000);
|
||||
addr_t clock_base = (addr_t)env()->rm_session()->attach(io_clock.dataspace());
|
||||
Clocks c(clock_base);
|
||||
|
||||
/* reset TLL */
|
||||
Io_mem_connection io_tll(TLL_BASE, 0x1000);
|
||||
addr_t tll_base = (addr_t)env()->rm_session()->attach(io_tll.dataspace());
|
||||
Tll t(tll_base);
|
||||
|
||||
/* reset host */
|
||||
Io_mem_connection io_uhh(UHH_BASE, 0x1000);
|
||||
addr_t uhh_base = (addr_t)env()->rm_session()->attach(io_uhh.dataspace());
|
||||
Uhh uhh(uhh_base);
|
||||
|
||||
/* enable hub power */
|
||||
gpio.set_value(HUB_POWER, 1);
|
||||
|
||||
/* reset EHCI */
|
||||
addr_t ehci_base = uhh_base + 0xc00;
|
||||
Ehci ehci(ehci_base);
|
||||
|
||||
addr_t base[] = { scrm_base, clock_base, tll_base, uhh_base, 0 };
|
||||
for (int i = 0; base[i]; i++)
|
||||
env()->rm_session()->detach(base[i]);
|
||||
}
|
||||
|
||||
|
||||
extern "C" void module_ehci_hcd_init();
|
||||
extern "C" int module_usbnet_init();
|
||||
extern "C" int module_smsc95xx_init();
|
||||
|
||||
void platform_hcd_init(Services *services)
|
||||
{
|
||||
/* register netowrk */
|
||||
if (services->nic) {
|
||||
module_usbnet_init();
|
||||
module_smsc95xx_init();
|
||||
}
|
||||
|
||||
/* register EHCI controller */
|
||||
module_ehci_hcd_init();
|
||||
|
||||
/* initialize EHCI */
|
||||
omap_ehci_init();
|
||||
|
||||
/* setup EHCI-controller platform device */
|
||||
platform_device *pdev = (platform_device *)kzalloc(sizeof(platform_device), 0);
|
||||
pdev->name = "ehci-omap";
|
||||
pdev->id = 0;
|
||||
pdev->num_resources = 2;
|
||||
pdev->resource = _ehci;
|
||||
pdev->dev.platform_data = &_ehci_data;
|
||||
|
||||
/*
|
||||
* Needed for DMA buffer allocation. See 'hcd_buffer_alloc' in 'buffer.c'
|
||||
*/
|
||||
static u64 dma_mask = ~(u64)0;
|
||||
pdev->dev.dma_mask = &dma_mask;
|
||||
pdev->dev.coherent_dma_mask = ~0;
|
||||
|
||||
platform_device_register(pdev);
|
||||
}
|
||||
|
897
dde_linux/src/lib/usb/dummies.c
Normal file
897
dde_linux/src/lib/usb/dummies.c
Normal file
@ -0,0 +1,897 @@
|
||||
/*
|
||||
* \brief Dummy functions
|
||||
* \author Norman Feske
|
||||
* \author Sebastian sumpf
|
||||
* \date 2011-01-29
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 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.
|
||||
*/
|
||||
|
||||
/* Linux kernel API */
|
||||
#include <lx_emul.h>
|
||||
|
||||
/* DDE-Kit includes */
|
||||
#include <dde_kit/printf.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <linux/input.h>
|
||||
|
||||
#define SKIP_VERBOSE 0
|
||||
|
||||
#if VERBOSE_LX_EMUL
|
||||
#define TRACE dde_kit_printf("\033[32m%s\033[0m called, not implemented\n", __PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define TRACE
|
||||
#endif
|
||||
#if SKIP_VERBOSE
|
||||
#define SKIP dde_kit_printf("\033[34m%s\033[0m: skipped\n", __PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define SKIP
|
||||
#endif
|
||||
|
||||
|
||||
/******************
|
||||
** asm/atomic.h **
|
||||
******************/
|
||||
|
||||
int atomic_inc_return(atomic_t *v) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************************
|
||||
** linux/byteorder/generic.h **
|
||||
*******************************/
|
||||
|
||||
u16 get_unaligned_le16(const void *p) { TRACE; return 0; }
|
||||
u32 get_unaligned_le32(const void *p) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************************
|
||||
** linux/errno.h and friends **
|
||||
*******************************/
|
||||
|
||||
long PTR_ERR(const void *ptr) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/kernel.h **
|
||||
********************/
|
||||
|
||||
void might_sleep() { SKIP; }
|
||||
char *kasprintf(gfp_t gfp, const char *fmt, ...) { TRACE; return NULL; }
|
||||
int kstrtouint(const char *s, unsigned int base, unsigned int *res) { TRACE; return 0; }
|
||||
int sprintf(char *buf, const char *fmt, ...) { TRACE; return 0; }
|
||||
int sscanf(const char *b, const char *s, ...) { TRACE; return 0; }
|
||||
int scnprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
int strict_strtoul(const char *s, unsigned int base, unsigned long *res) { TRACE; return 0; }
|
||||
long simple_strtoul(const char *cp, char **endp, unsigned int base) { TRACE; return 0; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/log2.h **
|
||||
******************/
|
||||
|
||||
int roundup_pow_of_two(u32 n) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/printk.h **
|
||||
********************/
|
||||
|
||||
void print_hex_dump(const char *level, const char *prefix_str,
|
||||
int prefix_type, int rowsize, int groupsize,
|
||||
const void *buf, size_t len, bool ascii) { TRACE; }
|
||||
|
||||
|
||||
/**********************************
|
||||
** linux/bitops.h, asm/bitops.h **
|
||||
**********************************/
|
||||
|
||||
int ffs(int x) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/string.h **
|
||||
********************/
|
||||
|
||||
int memcmp(const void *dst, const void *src, size_t s) { TRACE; return 0; }
|
||||
char *strcat(char *dest, const char *src) { TRACE; return 0; }
|
||||
int strncmp(const char *cs, const char *ct, size_t count) { TRACE; return 0; }
|
||||
char *strncpy(char *dst, const char *src, size_t s) { TRACE; return NULL; }
|
||||
char *strchr(const char *s, int n) { TRACE; return NULL; }
|
||||
char *strrchr(const char *s, int n) { TRACE; return NULL; }
|
||||
size_t strlcpy(char *dest, const char *src, size_t size) { TRACE; return 0; }
|
||||
char *strsep(char **s,const char *d) { TRACE; return NULL; }
|
||||
char *kstrdup(const char *s, gfp_t gfp) { TRACE; return 0; }
|
||||
char *strstr(const char *h, const char *n) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/nls.h **
|
||||
*****************/
|
||||
|
||||
int utf16s_to_utf8s(const wchar_t *pwcs, int len,
|
||||
enum utf16_endian endian, u8 *s, int maxlen) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/ctype.h **
|
||||
*******************/
|
||||
|
||||
int isprint(int v) { TRACE; return 0; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/spinlock.h **
|
||||
**********************/
|
||||
|
||||
void spin_lock(spinlock_t *lock) { SKIP; }
|
||||
void spin_lock_nested(spinlock_t *lock, int subclass) { TRACE; }
|
||||
void spin_unlock(spinlock_t *lock) { SKIP; }
|
||||
void spin_lock_init(spinlock_t *lock) { SKIP; }
|
||||
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags) { SKIP; }
|
||||
void spin_lock_irqrestore(spinlock_t *lock, unsigned long flags) { SKIP; }
|
||||
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) { SKIP; }
|
||||
void spin_lock_irq(spinlock_t *lock) { SKIP; }
|
||||
void spin_unlock_irq(spinlock_t *lock) { SKIP; }
|
||||
void assert_spin_locked(spinlock_t *lock) { TRACE;}
|
||||
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/mutex.h **
|
||||
*******************/
|
||||
|
||||
void mutex_lock_nested(struct mutex *lock, unsigned int subclass) { TRACE; }
|
||||
int mutex_lock_interruptible(struct mutex *m) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/rwsem.h **
|
||||
*******************/
|
||||
|
||||
void down_read(struct rw_semaphore *sem) { TRACE; }
|
||||
void up_read(struct rw_semaphore *sem) { TRACE; }
|
||||
void down_write(struct rw_semaphore *sem) { TRACE; }
|
||||
void up_write(struct rw_semaphore *sem) { TRACE; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/ktime.h **
|
||||
*******************/
|
||||
|
||||
ktime_t ktime_add_ns(const ktime_t kt, u64 nsec) { TRACE; ktime_t ret = { 0 }; return ret; }
|
||||
|
||||
s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) { TRACE; return 0; };
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/timer.h **
|
||||
*******************/
|
||||
|
||||
int del_timer_sync(struct timer_list *timer) { TRACE; return 0; }
|
||||
unsigned long round_jiffies(unsigned long j) { TRACE; return 1; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/hrtimer.h **
|
||||
*********************/
|
||||
|
||||
ktime_t ktime_get_real(void) { TRACE; ktime_t ret; return ret; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/delay.h **
|
||||
*******************/
|
||||
|
||||
void mdelay(unsigned long msecs) { TRACE; }
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/workquque.h **
|
||||
***********************/
|
||||
|
||||
bool cancel_work_sync(struct work_struct *work) { TRACE; return 0; }
|
||||
int cancel_delayed_work_sync(struct delayed_work *work) { TRACE; return 0; }
|
||||
bool flush_work_sync(struct work_struct *work) { TRACE; return 0; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/wait.h **
|
||||
******************/
|
||||
|
||||
void init_waitqueue_head(wait_queue_head_t *q) { TRACE; }
|
||||
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { TRACE; }
|
||||
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) { TRACE; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/time.h **
|
||||
******************/
|
||||
|
||||
struct timespec current_kernel_time(void)
|
||||
{
|
||||
struct timespec t = { 0, 0 };
|
||||
return t;
|
||||
}
|
||||
|
||||
void do_gettimeofday(struct timeval *tv) { TRACE; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/sched.h **
|
||||
*******************/
|
||||
|
||||
int kill_pid_info_as_cred(int i, struct siginfo *s, struct pid *p,
|
||||
const struct cred *c, u32 v) { TRACE; return 0; }
|
||||
pid_t task_pid_nr(struct task_struct *tsk) { TRACE; return 0; }
|
||||
struct pid *task_pid(struct task_struct *task) { TRACE; return NULL; }
|
||||
void __set_current_state(int state) { TRACE; }
|
||||
int signal_pending(struct task_struct *p) { TRACE; return 0; }
|
||||
void schedule(void) { TRACE; }
|
||||
void yield(void) { TRACE; }
|
||||
void cpu_relax(void) { TRACE; udelay(1); }
|
||||
signed long schedule_timeout(signed long timeout) { TRACE; return 0; }
|
||||
|
||||
struct task_struct *current;
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/kthread.h **
|
||||
*********************/
|
||||
|
||||
int kthread_should_stop(void) { SKIP; return 0; }
|
||||
int kthread_stop(struct task_struct *k) { TRACE; return 0; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/notifier.h **
|
||||
**********************/
|
||||
|
||||
int blocking_notifier_chain_register(struct blocking_notifier_head *nh,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
|
||||
unsigned long val, void *v) { TRACE; return 0; }
|
||||
int atomic_notifier_chain_register(struct atomic_notifier_head *nh,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/kobject.h **
|
||||
*********************/
|
||||
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) { TRACE; return 0; }
|
||||
char *kobject_name(const struct kobject *kobj) { TRACE; return 0; }
|
||||
char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/sysfs.h **
|
||||
*******************/
|
||||
|
||||
int sysfs_create_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp) { TRACE; return 0; }
|
||||
void sysfs_remove_group(struct kobject *kobj,
|
||||
const struct attribute_group *grp) { TRACE; }
|
||||
|
||||
int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) { TRACE; return 0; }
|
||||
|
||||
ssize_t simple_read_from_buffer(void __user *to, size_t count,
|
||||
loff_t *ppos, const void *from, size_t available) { TRACE; return 0; }
|
||||
|
||||
/************************
|
||||
** linux/pm_runtime.h **
|
||||
************************/
|
||||
|
||||
int pm_runtime_set_active(struct device *dev) { TRACE; return 0; }
|
||||
void pm_suspend_ignore_children(struct device *dev, bool enable) { TRACE; }
|
||||
void pm_runtime_enable(struct device *dev) { TRACE; }
|
||||
void pm_runtime_disable(struct device *dev) { TRACE; }
|
||||
void pm_runtime_set_suspended(struct device *dev) { TRACE; }
|
||||
void pm_runtime_get_noresume(struct device *dev) { TRACE; }
|
||||
void pm_runtime_put_noidle(struct device *dev) { TRACE; }
|
||||
void pm_runtime_use_autosuspend(struct device *dev) { TRACE; }
|
||||
int pm_runtime_put_sync_autosuspend(struct device *dev) { TRACE; return 0; }
|
||||
void pm_runtime_no_callbacks(struct device *dev) { TRACE; }
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/pm_wakeup.h **
|
||||
***********************/
|
||||
|
||||
int device_init_wakeup(struct device *dev, bool val) { TRACE; return 0; }
|
||||
int device_wakeup_enable(struct device *dev) { TRACE; return 0; }
|
||||
bool device_may_wakeup(struct device *dev) { TRACE; return 1; }
|
||||
int device_set_wakeup_enable(struct device *dev, bool enable) { TRACE; return 0; }
|
||||
bool device_can_wakeup(struct device *dev) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/device.h **
|
||||
********************/
|
||||
|
||||
int dev_set_name(struct device *dev, const char *name, ...) { TRACE; return 0; }
|
||||
int dev_to_node(struct device *dev) { TRACE; return 0; }
|
||||
void set_dev_node(struct device *dev, int node) { TRACE; }
|
||||
|
||||
struct device *device_create(struct class *cls, struct device *parent,
|
||||
dev_t devt, void *drvdata,
|
||||
const char *fmt, ...) { TRACE; return NULL; }
|
||||
void device_destroy(struct class *cls, dev_t devt) { TRACE; }
|
||||
void device_unregister(struct device *dev) { TRACE; }
|
||||
void device_lock(struct device *dev) { TRACE; }
|
||||
int device_trylock(struct device *dev) { TRACE; return 0; }
|
||||
void device_unlock(struct device *dev) { TRACE; }
|
||||
void device_del(struct device *dev) { TRACE; }
|
||||
void device_initialize(struct device *dev) { TRACE; }
|
||||
int device_attach(struct device *dev) { TRACE; return 0; }
|
||||
int device_is_registered(struct device *dev) { TRACE; return 0; }
|
||||
int device_bind_driver(struct device *dev) { TRACE; return 0; }
|
||||
void device_release_driver(struct device *dev) { TRACE; }
|
||||
void device_enable_async_suspend(struct device *dev) { TRACE; }
|
||||
void device_set_wakeup_capable(struct device *dev, bool capable) { TRACE; }
|
||||
int device_create_bin_file(struct device *dev,
|
||||
const struct bin_attribute *attr) { TRACE; return 0; }
|
||||
void device_remove_bin_file(struct device *dev,
|
||||
const struct bin_attribute *attr) { TRACE; }
|
||||
int device_create_file(struct device *device,
|
||||
const struct device_attribute *entry) { TRACE; return 0; }
|
||||
void device_remove_file(struct device *dev,
|
||||
const struct device_attribute *attr) { TRACE; }
|
||||
|
||||
void put_device(struct device *dev) { TRACE; }
|
||||
|
||||
void driver_unregister(struct device_driver *drv) { TRACE; }
|
||||
int driver_attach(struct device_driver *drv) { TRACE; return 0; }
|
||||
int driver_create_file(struct device_driver *driver,
|
||||
const struct driver_attribute *attr) { TRACE; return 0; }
|
||||
void driver_remove_file(struct device_driver *driver,
|
||||
const struct driver_attribute *attr) { TRACE; }
|
||||
|
||||
struct device_driver *get_driver(struct device_driver *drv) { TRACE; return NULL; }
|
||||
void put_driver(struct device_driver *drv) { TRACE; }
|
||||
|
||||
struct device *bus_find_device(struct bus_type *bus, struct device *start,
|
||||
void *data,
|
||||
int (*match)(struct device *dev, void *data)) { TRACE; return NULL; }
|
||||
int bus_register(struct bus_type *bus) { TRACE; return 0; }
|
||||
void bus_unregister(struct bus_type *bus) { TRACE; }
|
||||
int bus_register_notifier(struct bus_type *bus,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
int bus_unregister_notifier(struct bus_type *bus,
|
||||
struct notifier_block *nb) { TRACE; return 0; }
|
||||
|
||||
struct class *__class_create(struct module *owner,
|
||||
const char *name,
|
||||
struct lock_class_key *key) { TRACE; return NULL; }
|
||||
int class_register(struct class *cls) { TRACE; return 0; }
|
||||
void class_unregister(struct class *cls) { TRACE; }
|
||||
void class_destroy(struct class *cls) { TRACE; }
|
||||
|
||||
|
||||
/*****************************
|
||||
** linux/platform_device.h **
|
||||
*****************************/
|
||||
|
||||
void *platform_get_drvdata(const struct platform_device *pdev) { TRACE; return NULL; }
|
||||
void platform_set_drvdata(struct platform_device *pdev, void *data) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/dcache.h **
|
||||
********************/
|
||||
|
||||
void d_instantiate(struct dentry *dentry, struct inode *i) { TRACE; }
|
||||
int d_unhashed(struct dentry *dentry) { TRACE; return 0; }
|
||||
void d_delete(struct dentry *d) { TRACE; }
|
||||
struct dentry *d_alloc_root(struct inode *i) { TRACE; return NULL; }
|
||||
struct dentry *dget(struct dentry *dentry) { TRACE; return NULL; }
|
||||
void dput(struct dentry *dentry) { TRACE; }
|
||||
|
||||
void dont_mount(struct dentry *dentry) { TRACE; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/poll.h **
|
||||
******************/
|
||||
|
||||
void poll_wait(struct file *f, wait_queue_head_t *w, poll_table *p) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/statfs.h **
|
||||
********************/
|
||||
|
||||
loff_t default_llseek(struct file *file, loff_t offset, int origin) { TRACE; return 0; }
|
||||
|
||||
|
||||
/****************
|
||||
** linux/fs.h **
|
||||
****************/
|
||||
|
||||
unsigned iminor(const struct inode *inode) { TRACE; return 0; }
|
||||
unsigned imajor(const struct inode *inode) { TRACE; return 0; }
|
||||
|
||||
int register_chrdev_region(dev_t d, unsigned v, const char *s) { TRACE; return 0; }
|
||||
void unregister_chrdev_region(dev_t d, unsigned v) { TRACE; }
|
||||
void fops_put(struct file_operations const *fops) { TRACE; }
|
||||
loff_t noop_llseek(struct file *file, loff_t offset, int origin) { TRACE; return 0; }
|
||||
int register_chrdev(unsigned int major, const char *name,
|
||||
const struct file_operations *fops) { TRACE; return 0; }
|
||||
void unregister_chrdev(unsigned int major, const char *name) { TRACE; }
|
||||
struct inode *new_inode(struct super_block *sb) { TRACE; return NULL; }
|
||||
unsigned int get_next_ino(void) { TRACE; return 0; }
|
||||
void init_special_inode(struct inode *i, umode_t m, dev_t d) { TRACE; }
|
||||
int generic_delete_inode(struct inode *inode) { TRACE; return 0; }
|
||||
void drop_nlink(struct inode *inode) { TRACE; }
|
||||
void inc_nlink(struct inode *inode) { TRACE; }
|
||||
void dentry_unhash(struct dentry *dentry) { TRACE; }
|
||||
void iput(struct inode *i) { TRACE; }
|
||||
struct dentry *mount_single(struct file_system_type *fs_type,
|
||||
int flags, void *data,
|
||||
int (*fill_super)(struct super_block *,
|
||||
void *, int)) { TRACE; return NULL; }
|
||||
int nonseekable_open(struct inode *inode, struct file *filp) { TRACE; return 0; }
|
||||
int simple_statfs(struct dentry *d, struct kstatfs *k) { TRACE; return 0; }
|
||||
int simple_pin_fs(struct file_system_type *t, struct vfsmount **mount, int *count) { TRACE; return 0; }
|
||||
void simple_release_fs(struct vfsmount **mount, int *count) { TRACE; }
|
||||
void kill_litter_super(struct super_block *sb) { TRACE; }
|
||||
int register_filesystem(struct file_system_type *t) { TRACE; return 0; }
|
||||
int unregister_filesystem(struct file_system_type *t) { TRACE; return 0; }
|
||||
|
||||
void kill_fasync(struct fasync_struct **fp, int sig, int band) { TRACE; }
|
||||
int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) { TRACE; return 0; }
|
||||
const struct file_operations simple_dir_operations;
|
||||
const struct inode_operations simple_dir_inode_operations;
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/namei.h **
|
||||
*******************/
|
||||
|
||||
struct dentry *lookup_one_len(const char *c, struct dentry *e, int v) { TRACE; return NULL; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/seq_file.h **
|
||||
**********************/
|
||||
|
||||
int seq_printf(struct seq_file *f, const char *fmt, ...) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/gfp.h **
|
||||
*****************/
|
||||
|
||||
unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) { TRACE; return 0; }
|
||||
void __free_pages(struct page *p, unsigned int order) { TRACE; }
|
||||
void free_pages(unsigned long addr, unsigned int order) { TRACE; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/proc_fs.h **
|
||||
*********************/
|
||||
|
||||
struct proc_dir_entry *proc_mkdir(const char *s,struct proc_dir_entry *e) { TRACE; return NULL; }
|
||||
void remove_proc_entry(const char *name, struct proc_dir_entry *parent) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
* linux/debugfs.h **
|
||||
********************/
|
||||
|
||||
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) { TRACE; return (struct dentry *)1; }
|
||||
struct dentry *debugfs_create_file(const char *name, mode_t mode,
|
||||
struct dentry *parent, void *data,
|
||||
const struct file_operations *fops) { TRACE; return (struct dentry *)1; }
|
||||
void debugfs_remove(struct dentry *dentry) { TRACE; }
|
||||
|
||||
|
||||
/************************
|
||||
** linux/page-flags.h **
|
||||
************************/
|
||||
|
||||
bool is_highmem(void *ptr) { TRACE; return 0; }
|
||||
|
||||
|
||||
/****************
|
||||
** linux/mm.h **
|
||||
****************/
|
||||
|
||||
struct zone *page_zone(const struct page *page) { TRACE; return NULL; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/highmem.h **
|
||||
**********************/
|
||||
|
||||
void *kmap(struct page *page) { TRACE; return 0; }
|
||||
void kunmap(struct page *page) { TRACE; }
|
||||
|
||||
|
||||
/**********************
|
||||
** asm-generic/io.h **
|
||||
**********************/
|
||||
|
||||
void iounmap(volatile void *addr) { TRACE; }
|
||||
void native_io_delay(void) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/ioport.h **
|
||||
********************/
|
||||
|
||||
void release_region(resource_size_t start, resource_size_t n) { TRACE; }
|
||||
void release_mem_region(resource_size_t start, resource_size_t n) { TRACE; }
|
||||
|
||||
/**
|
||||
* SKIP
|
||||
*/
|
||||
|
||||
/* implemented in Pci_driver */
|
||||
struct resource *request_region(resource_size_t start, resource_size_t n,
|
||||
const char *name) { SKIP; return (struct resource *)1; }
|
||||
/* implemented in Pci_driver */
|
||||
struct resource *request_mem_region(resource_size_t start, resource_size_t n,
|
||||
const char *name) { SKIP; return (struct resource *)1; }
|
||||
|
||||
/***********************
|
||||
** linux/interrupt.h **
|
||||
***********************/
|
||||
|
||||
void local_irq_enable(void) { TRACE; }
|
||||
void local_irq_disable(void) { TRACE; }
|
||||
void free_irq(unsigned int i, void *p) { TRACE; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/hardirq.h **
|
||||
*********************/
|
||||
|
||||
void synchronize_irq(unsigned int irq) { TRACE; }
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/pci.h **
|
||||
*****************/
|
||||
int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 *val) { TRACE; return 0; }
|
||||
int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, int where, u32 val) { TRACE; return 0; }
|
||||
|
||||
void *pci_get_drvdata(struct pci_dev *pdev) { TRACE; return NULL; }
|
||||
void pci_dev_put(struct pci_dev *dev) { TRACE; }
|
||||
struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device,
|
||||
struct pci_dev *from) { TRACE; return NULL; }
|
||||
|
||||
|
||||
void pci_disable_device(struct pci_dev *dev) { TRACE; }
|
||||
int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) { TRACE; return 0; }
|
||||
|
||||
void pci_unregister_driver(struct pci_driver *drv) { TRACE; }
|
||||
|
||||
bool pci_dev_run_wake(struct pci_dev *dev) { TRACE; return 0; }
|
||||
int pci_set_mwi(struct pci_dev *dev) { TRACE; return 0; }
|
||||
int pci_find_capability(struct pci_dev *dev, int cap) { TRACE; return 0; }
|
||||
struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn) { TRACE; return NULL; }
|
||||
const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
|
||||
struct pci_dev *dev) { TRACE; return 0; }
|
||||
void *pci_ioremap_bar(struct pci_dev *pdev, int bar);
|
||||
|
||||
/**
|
||||
* Omitted PCI functions
|
||||
*/
|
||||
/* scans resources, this is already implemented in 'pci_driver.cc' */
|
||||
int pci_enable_device(struct pci_dev *dev) { SKIP; return 0; }
|
||||
|
||||
/* implemented in Pci_driver::_setup_pci_device */
|
||||
void pci_set_master(struct pci_dev *dev) { SKIP; }
|
||||
|
||||
/**********************
|
||||
** linux/irqflags.h **
|
||||
**********************/
|
||||
|
||||
unsigned long local_irq_save(unsigned long flags) { SKIP; return 0; }
|
||||
unsigned long local_irq_restore(unsigned long flags) { SKIP; return 0; }
|
||||
|
||||
|
||||
/*************************
|
||||
** linux/dma-mapping.h **
|
||||
*************************/
|
||||
|
||||
void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr,
|
||||
size_t size,
|
||||
enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs) { SKIP; }
|
||||
|
||||
void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg,
|
||||
int nents, enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs) { SKIP; }
|
||||
|
||||
|
||||
void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
|
||||
enum dma_data_direction direction) { SKIP;; }
|
||||
|
||||
int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { SKIP; return 0; }
|
||||
|
||||
/*****************
|
||||
** linux/pid.h **
|
||||
*****************/
|
||||
|
||||
void put_pid(struct pid *pid) { TRACE; }
|
||||
struct pid *get_pid(struct pid *pid) { TRACE; return NULL; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/cred.h **
|
||||
******************/
|
||||
|
||||
void put_cred(struct cred const *c) { TRACE; }
|
||||
const struct cred *get_cred(const struct cred *cred) { TRACE; return NULL; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/security.h **
|
||||
**********************/
|
||||
|
||||
void security_task_getsecid(struct task_struct *p, u32 *secid) { TRACE; }
|
||||
|
||||
|
||||
/******************
|
||||
** linux/cdev.h **
|
||||
******************/
|
||||
|
||||
void cdev_init(struct cdev *c, const struct file_operations *fops) { TRACE; }
|
||||
int cdev_add(struct cdev *c, dev_t d, unsigned v) { TRACE; return 0; }
|
||||
void cdev_del(struct cdev *c) { TRACE; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/utsname.h **
|
||||
*********************/
|
||||
|
||||
struct new_utsname *init_utsname(void)
|
||||
{
|
||||
static struct new_utsname uts = { .sysname = "Genode.UTS", .release = "1.0" };
|
||||
return &uts;
|
||||
}
|
||||
struct new_utsname *utsname(void) { TRACE; return NULL; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/freezer.h **
|
||||
*********************/
|
||||
|
||||
void set_freezable(void) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/parser.h **
|
||||
********************/
|
||||
|
||||
int match_token(char *s, const match_table_t table, substring_t args[]) { TRACE; return 0; }
|
||||
int match_int(substring_t *s, int *result) { TRACE; return 0; }
|
||||
int match_octal(substring_t *s, int *result) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/semaphore **
|
||||
*********************/
|
||||
void sema_init(struct semaphore *sem, int val) { TRACE; }
|
||||
int down_trylock(struct semaphore *sem) { TRACE; return 0; }
|
||||
int down_interruptible(struct semaphore *sem) { TRACE; return 0; }
|
||||
void up(struct semaphore *sem) { TRACE; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/input.h **
|
||||
*******************/
|
||||
|
||||
void input_ff_destroy(struct input_dev *dev) { TRACE; }
|
||||
int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { TRACE; return 0; }
|
||||
int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file) { TRACE; return 0; }
|
||||
int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) { TRACE; return 0; }
|
||||
|
||||
/*********************
|
||||
** input-compat.h" **
|
||||
*********************/
|
||||
|
||||
int input_event_from_user(const char __user *buffer, struct input_event *event) { TRACE; return 0; }
|
||||
int input_event_to_user(char __user *buffer, const struct input_event *event) { TRACE; return 0; }
|
||||
int input_ff_effect_from_user(const char __user *buffer, size_t size, struct ff_effect *effect) { TRACE; return 0;}
|
||||
|
||||
/****************
|
||||
** linux/mt.h **
|
||||
****************/
|
||||
|
||||
void input_mt_destroy_slots(struct input_dev *dev) { TRACE; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/vmalloc.h **
|
||||
*********************/
|
||||
|
||||
void *vmalloc(unsigned long size) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/blkdev.h **
|
||||
********************/
|
||||
|
||||
void blk_queue_bounce_limit(struct request_queue *q, u64 dma_mask) { TRACE; }
|
||||
void blk_queue_update_dma_alignment(struct request_queue *q, int mask) { TRACE; }
|
||||
void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) { TRACE; }
|
||||
unsigned int queue_max_hw_sectors(struct request_queue *q) { TRACE; return 0; }
|
||||
|
||||
|
||||
/**********************
|
||||
** scsi/scsi_cmnd.h **
|
||||
**********************/
|
||||
|
||||
void scsi_set_resid(struct scsi_cmnd *cmd, int resid) { TRACE; }
|
||||
int scsi_get_resid(struct scsi_cmnd *cmd) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************
|
||||
** scsi/scsi_eh.h **
|
||||
*******************/
|
||||
|
||||
void scsi_report_bus_reset(struct Scsi_Host *shost, int channel) { TRACE; }
|
||||
void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target) { TRACE; }
|
||||
|
||||
void scsi_eh_prep_cmnd(struct scsi_cmnd *scmd,
|
||||
struct scsi_eh_save *ses, unsigned char *cmnd,
|
||||
int cmnd_size, unsigned sense_bytes) { TRACE; }
|
||||
|
||||
void scsi_eh_restore_cmnd(struct scsi_cmnd* scmd,
|
||||
struct scsi_eh_save *ses) { TRACE; }
|
||||
|
||||
|
||||
int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
|
||||
struct scsi_sense_hdr *sshdr) { TRACE; return 0; }
|
||||
|
||||
const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
|
||||
int desc_type) { TRACE; return 0; }
|
||||
|
||||
|
||||
/***********************
|
||||
** drivers/scsi/sd.h **
|
||||
**********************/
|
||||
|
||||
struct scsi_disk *scsi_disk(struct gendisk *disk) { TRACE; return 0; }
|
||||
|
||||
|
||||
/**********************
|
||||
** scsi/scsi_host.h **
|
||||
**********************/
|
||||
int scsi_add_host_with_dma(struct Scsi_Host *shost, struct device *dev,
|
||||
struct device *dma_dev) { TRACE; return 0; }
|
||||
void scsi_remove_host(struct Scsi_Host *shost) { TRACE; }
|
||||
void scsi_host_put(struct Scsi_Host *shost) { TRACE; }
|
||||
struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost) { TRACE; return 0; }
|
||||
|
||||
|
||||
/********************************
|
||||
** linux/regulator/consumer.h **
|
||||
********************************/
|
||||
struct regulator;
|
||||
int regulator_enable(struct regulator *r) { TRACE; return 0; }
|
||||
int regulator_disable(struct regulator *r) { TRACE; return 0; }
|
||||
void regulator_put(struct regulator *r) { TRACE; }
|
||||
struct regulator *regulator_get(struct device *dev, const char *id) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************************************
|
||||
** arch/arm/plat-omap/include/plat/usb.h **
|
||||
*******************************************/
|
||||
|
||||
int omap_usbhs_enable(struct device *dev) { TRACE; return 0; }
|
||||
void omap_usbhs_disable(struct device *dev) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** linux/skbuff.h **
|
||||
********************/
|
||||
|
||||
unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) { TRACE; return 0; }
|
||||
int skb_checksum_start_offset(const struct sk_buff *skb) { TRACE; return 0; }
|
||||
struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
|
||||
int newheadroom, int newtailroom,
|
||||
gfp_t gfp_mask) { TRACE; return 0; }
|
||||
int skb_tailroom(const struct sk_buff *skb) { TRACE; return 0; }
|
||||
|
||||
int skb_queue_empty(const struct sk_buff_head *list) { TRACE; return 1; }
|
||||
void skb_queue_purge(struct sk_buff_head *list) { TRACE; }
|
||||
|
||||
void skb_tx_timestamp(struct sk_buff *skb) { TRACE; }
|
||||
bool skb_defer_rx_timestamp(struct sk_buff *skb) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/ethtool.h **
|
||||
*********************/
|
||||
|
||||
__u32 ethtool_cmd_speed(const struct ethtool_cmd *ep) { TRACE; return 0; }
|
||||
u32 ethtool_op_get_link(struct net_device *dev) { TRACE; return 0; }
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/netdevice.h **
|
||||
***********************/
|
||||
|
||||
u32 netif_msg_init(int debug_value, int default_msg_enable_bits) { TRACE; return 0; }
|
||||
|
||||
void netif_start_queue(struct net_device *dev) { TRACE; }
|
||||
void netif_device_detach(struct net_device *dev) { TRACE; }
|
||||
void netif_stop_queue(struct net_device *dev) { TRACE; }
|
||||
void netif_wake_queue(struct net_device *dev) { TRACE; }
|
||||
void netif_device_attach(struct net_device *dev) { TRACE; }
|
||||
void unregister_netdev(struct net_device *dev) { TRACE; }
|
||||
void free_netdev(struct net_device *dev) { TRACE; }
|
||||
void netif_carrier_off(struct net_device *dev) { TRACE; }
|
||||
|
||||
int netdev_mc_empty(struct net_device *dev) { TRACE; return 1; }
|
||||
|
||||
/*****************
|
||||
** linux/mii.h **
|
||||
*****************/
|
||||
|
||||
unsigned int mii_check_media (struct mii_if_info *mii,
|
||||
unsigned int ok_to_print,
|
||||
unsigned int init_media) { TRACE; return 0; }
|
||||
int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd) { TRACE; return 0; }
|
||||
int mii_link_ok (struct mii_if_info *mii) { TRACE; return 0; }
|
||||
|
||||
int generic_mii_ioctl(struct mii_if_info *mii_if,
|
||||
struct mii_ioctl_data *mii_data, int cmd,
|
||||
unsigned int *duplex_changed) { TRACE; return 0; }
|
||||
struct mii_ioctl_data *if_mii(struct ifreq *rq) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*************************
|
||||
** linux/etherdevice.h **
|
||||
*************************/
|
||||
|
||||
__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) { TRACE; return 0; }
|
||||
int eth_mac_addr(struct net_device *dev, void *p) { TRACE; return 0; }
|
||||
int eth_validate_addr(struct net_device *dev) { TRACE; return 0; }
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/inerrupt.h **
|
||||
**********************/
|
||||
|
||||
void tasklet_kill(struct tasklet_struct *t) { TRACE; }
|
||||
|
||||
|
||||
/********************
|
||||
** asm/checksum.h **
|
||||
********************/
|
||||
|
||||
__wsum csum_partial(const void *buff, int len, __wsum wsum) { TRACE; return 0; }
|
||||
__sum16 csum_fold(__wsum sum) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/clk.h **
|
||||
*****************/
|
||||
|
||||
struct clk { };
|
||||
|
||||
struct clk *clk_get(struct device *dev, const char *id)
|
||||
{
|
||||
static struct clk _c;
|
||||
TRACE;
|
||||
return &_c;
|
||||
}
|
||||
|
||||
int clk_enable(struct clk *clk) { TRACE; return 0; }
|
||||
void clk_disable(struct clk *clk) { TRACE; }
|
||||
void clk_put(struct clk *clk) { TRACE; }
|
160
dde_linux/src/lib/usb/include/arm/platform/lx_emul.h
Normal file
160
dde_linux/src/lib/usb/include/arm/platform/lx_emul.h
Normal file
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* \brief Platform specific part of the Linux API emulation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
#ifndef _ARM__PLATFORM__LX_EMUL_H_
|
||||
#define _ARM__PLATFORM__LX_EMUL_H_
|
||||
|
||||
/*************************
|
||||
** asm-generic/sizes.h **
|
||||
*************************/
|
||||
|
||||
enum {
|
||||
SZ_1K = 0x00000400,
|
||||
SZ_4K = 0x00001000,
|
||||
};
|
||||
|
||||
struct platform_device
|
||||
{
|
||||
const char *name;
|
||||
int id;
|
||||
struct device dev;
|
||||
u32 num_resources;
|
||||
struct resource *resource;
|
||||
};
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/usb/ulpi.h **
|
||||
**********************/
|
||||
|
||||
enum {
|
||||
ULPI_FUNC_CTRL_RESET = (1 << 5),
|
||||
ULPI_FUNC_CTRL = (1 << 2),
|
||||
};
|
||||
|
||||
/*
|
||||
* Macros for Set and Clear
|
||||
* See ULPI 1.1 specification to find the registers with Set and Clear offsets
|
||||
*/
|
||||
|
||||
#define ULPI_SET(a) (a + 1)
|
||||
|
||||
/*******************************************
|
||||
** arch/arm/plat-omap/include/plat/usb.h **
|
||||
*******************************************/
|
||||
|
||||
enum { OMAP3_HS_USB_PORTS = 2 };
|
||||
|
||||
enum usbhs_omap_port_mode
|
||||
{
|
||||
OMAP_EHCI_PORT_MODE_NONE,
|
||||
OMAP_EHCI_PORT_MODE_PHY,
|
||||
};
|
||||
|
||||
|
||||
struct ehci_hcd_omap_platform_data
|
||||
{
|
||||
enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS];
|
||||
struct regulator *regulator[OMAP3_HS_USB_PORTS];
|
||||
};
|
||||
|
||||
struct regulator;
|
||||
|
||||
|
||||
/*****************************
|
||||
** linux/platform_device.h **
|
||||
*****************************/
|
||||
|
||||
struct platform_driver {
|
||||
int (*probe)(struct platform_device *);
|
||||
int (*remove)(struct platform_device *);
|
||||
void (*shutdown)(struct platform_device *);
|
||||
int (*suspend)(struct platform_device *, pm_message_t state);
|
||||
int (*resume)(struct platform_device *);
|
||||
struct device_driver driver;
|
||||
const struct platform_device_id *id_table;
|
||||
};
|
||||
|
||||
struct resource *platform_get_resource(struct platform_device *, unsigned, unsigned);
|
||||
struct resource *platform_get_resource_byname(struct platform_device *, unsigned int, const char *);
|
||||
|
||||
int platform_get_irq(struct platform_device *, unsigned int);
|
||||
int platform_get_irq_byname(struct platform_device *, const char *);
|
||||
|
||||
int platform_driver_register(struct platform_driver *);
|
||||
int platform_device_register(struct platform_device *);
|
||||
|
||||
|
||||
/**********************
|
||||
** asm/generic/io.h **
|
||||
**********************/
|
||||
|
||||
static inline u32 __raw_readl(const volatile void __iomem *addr)
|
||||
{
|
||||
return *(const volatile u32 __force *) addr;
|
||||
}
|
||||
|
||||
static inline void __raw_writel(u32 b, volatile void __iomem *addr)
|
||||
{
|
||||
*(volatile u32 __force *) addr = b;
|
||||
}
|
||||
|
||||
|
||||
static inline u8 __raw_readb(const volatile void __iomem *addr)
|
||||
{
|
||||
return *(const volatile u8 __force *) addr;
|
||||
}
|
||||
|
||||
static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
|
||||
{
|
||||
*(volatile u8 __force *) addr = b;
|
||||
}
|
||||
|
||||
|
||||
/********************************
|
||||
** linux/regulator/consumer.h **
|
||||
********************************/
|
||||
|
||||
int regulator_enable(struct regulator *);
|
||||
int regulator_disable(struct regulator *);
|
||||
void regulator_put(struct regulator *regulator);
|
||||
struct regulator *regulator_get(struct device *dev, const char *id);
|
||||
|
||||
|
||||
/*******************************************
|
||||
** arch/arm/plat-omap/include/plat/usb.h **
|
||||
*******************************************/
|
||||
|
||||
int omap_usbhs_enable(struct device *dev);
|
||||
void omap_usbhs_disable(struct device *dev);
|
||||
|
||||
|
||||
/****************
|
||||
** linux/pm.h **
|
||||
****************/
|
||||
|
||||
struct dev_pm_ops {
|
||||
int (*suspend)(struct device *dev);
|
||||
int (*resume)(struct device *dev);
|
||||
};
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/clk.h **
|
||||
*****************/
|
||||
|
||||
struct clk *clk_get(struct device *, const char *);
|
||||
int clk_enable(struct clk *);
|
||||
void clk_disable(struct clk *);
|
||||
void clk_put(struct clk *);
|
||||
|
||||
#endif /* _ARM__PLATFORM__LX_EMUL_H_ */
|
37
dde_linux/src/lib/usb/include/arm/platform/platform.h
Normal file
37
dde_linux/src/lib/usb/include/arm/platform/platform.h
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* \brief Platform specific code
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _ARM__PLATFORM_H_
|
||||
#define _ARM__PLATFORM_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
static inline
|
||||
void platform_execute(void *sp, void *func, void *arg)
|
||||
{
|
||||
asm volatile ("mov r0, %2;" /* set arg */
|
||||
"mov sp, %0;" /* set stack */
|
||||
"mov pc, %1;" /* call func */
|
||||
""
|
||||
: : "r"(sp), "r"(func), "r"(arg) : "r0");
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ARM__PLATFORM_H_ */
|
3084
dde_linux/src/lib/usb/include/lx_emul.h
Normal file
3084
dde_linux/src/lib/usb/include/lx_emul.h
Normal file
File diff suppressed because it is too large
Load Diff
251
dde_linux/src/lib/usb/include/mem.h
Normal file
251
dde_linux/src/lib/usb/include/mem.h
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* \brief Memory pool
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _MEM_H_
|
||||
#define _MEM_H_
|
||||
|
||||
#include <base/allocator_avl.h>
|
||||
#include <dataspace/client.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
/*********************
|
||||
** linux/dmapool.h **
|
||||
*********************/
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Memory back-end
|
||||
*/
|
||||
class Mem
|
||||
{
|
||||
/* configurable sizes of memory pools */
|
||||
enum
|
||||
{
|
||||
MEM_POOL_SHARE = 3
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
addr_t _base; /* virt base of pool */
|
||||
addr_t _base_phys; /* phys base of pool */
|
||||
size_t _size; /* size of backng store */
|
||||
Allocator_avl _range; /* range allocator for pool */
|
||||
addr_t *_zones; /* bases of zones */
|
||||
int _zone_count; /* number of zones */
|
||||
int _zone_alloc; /* currently allocated zones */
|
||||
|
||||
Ram_dataspace_capability _ds_cap; /* backing store */
|
||||
|
||||
/**
|
||||
* Allocates memory which can be used for DMA.
|
||||
*/
|
||||
Genode::Ram_dataspace_capability alloc_dma_buffer(size_t size);
|
||||
|
||||
/**
|
||||
* Private constructor
|
||||
*/
|
||||
Mem(size_t size, bool cached = true)
|
||||
: _size(size), _range(env()->heap()),_zone_count(0), _zone_alloc(0)
|
||||
{
|
||||
if (cached)
|
||||
_ds_cap = env()->ram_session()->alloc(_size, cached);
|
||||
else
|
||||
_ds_cap = alloc_dma_buffer(_size);
|
||||
|
||||
_base_phys = Dataspace_client(_ds_cap).phys_addr();
|
||||
_base = (addr_t)env()->rm_session()->attach(_ds_cap);
|
||||
|
||||
dde_kit_log(DEBUG_DMA, "New DMA range [%lx-%lx)", _base, _base + _size);
|
||||
_range.add_range(_base, _size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert 'Mem' addres to zone address
|
||||
*/
|
||||
void *_to_zone(void const *addr, int i)
|
||||
{
|
||||
if (i < 0)
|
||||
return (void *)addr;
|
||||
|
||||
addr_t zone_base = _zones[i];
|
||||
addr_t offset = (addr_t)addr - _base;
|
||||
return (void *)(zone_base + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert zone addres to 'Mem' address
|
||||
*/
|
||||
void *_from_zone(void const *addr, int i)
|
||||
{
|
||||
if (i < 0)
|
||||
return (void *)addr;
|
||||
|
||||
addr_t zone_base = _zones[i];
|
||||
addr_t offset = (addr_t)addr - zone_base;
|
||||
return (void *)(_base + offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memory usable by back-end allocators
|
||||
*/
|
||||
static size_t _mem_avail() {
|
||||
return env()->ram_session()->avail() - (1024 * 1024); }
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Memory zone within Mem allocator
|
||||
*/
|
||||
class Zone_alloc : public Allocator
|
||||
{
|
||||
private:
|
||||
|
||||
Mem *_pool; /* pool of zone */
|
||||
int _zone; /* zone number */
|
||||
addr_t _base; /* base address of zone */
|
||||
size_t _size; /* size of zone */
|
||||
|
||||
public:
|
||||
|
||||
Zone_alloc(Mem *pool, int zone, addr_t base, size_t size)
|
||||
: _pool(pool), _zone(zone), _base(base), _size(size) { }
|
||||
|
||||
|
||||
/*************************
|
||||
** Alocator interface **
|
||||
*************************/
|
||||
|
||||
bool alloc(size_t size, void **out_addr)
|
||||
{
|
||||
*out_addr = _pool->alloc(size, _zone);
|
||||
if (!*out_addr) {
|
||||
PERR("Zone of %zu bytes allocation failed", size);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void free(void *addr, size_t /* size */) { _pool->free(addr, _zone); }
|
||||
size_t overhead(size_t size) { return 0; }
|
||||
|
||||
/**
|
||||
* Check if address matches zone
|
||||
*/
|
||||
bool match(void const *addr)
|
||||
{
|
||||
addr_t a = (addr_t)addr;
|
||||
bool ret = ((a >= _base) && (a < (_base + _size)));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve virt to phys mapping
|
||||
*/
|
||||
addr_t phys_addr(void const *addr) { return _pool->phys_addr(addr, _zone); }
|
||||
};
|
||||
|
||||
/**
|
||||
* Gernal purpose memory pool
|
||||
*/
|
||||
static Mem* pool()
|
||||
{
|
||||
static Mem _p(_mem_avail() / MEM_POOL_SHARE);
|
||||
return &_p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* DMA memory pool
|
||||
*/
|
||||
static Mem* dma()
|
||||
{
|
||||
static Mem _p(_mem_avail() - (_mem_avail() / MEM_POOL_SHARE), false);
|
||||
return &_p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allocator interface
|
||||
*/
|
||||
void *alloc(size_t size, int zone = -1, int align = 2)
|
||||
{
|
||||
void *addr;
|
||||
if (_range.alloc_aligned(size, &addr, align).is_error()) {
|
||||
PERR("Memory allocation of %zu bytes failed", size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return _to_zone(addr, zone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Free addr in zone
|
||||
*/
|
||||
void free(void *addr, int zone = -1) { _range.free(_from_zone(addr, zone)); }
|
||||
|
||||
/**
|
||||
* Get phys for virt address
|
||||
*/
|
||||
addr_t phys_addr(void const *addr, int zone = - 1)
|
||||
{
|
||||
addr_t a = (addr_t)_from_zone(addr, zone);
|
||||
if (a < _base || a >= _base + _size) {
|
||||
PERR("No DMA phys addr for %lx zone: %d", a, zone);
|
||||
return 0;
|
||||
}
|
||||
return (a - _base) + _base_phys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iinit allocator with count zones
|
||||
*/
|
||||
void init_zones(int count)
|
||||
{
|
||||
if (_zone_count)
|
||||
return;
|
||||
|
||||
_zones = (addr_t *)env()->heap()->alloc(count * sizeof(addr_t));
|
||||
_zone_count = count;
|
||||
|
||||
for (int i = 0; i < _zone_count; i++) {
|
||||
_zones[i] = (addr_t)env()->rm_session()->attach(_ds_cap);
|
||||
dde_kit_log(DEBUG_DMA, "Zone %d: base: %lx end %lx", i, _zones[i], _zones[i] + _size);
|
||||
}
|
||||
|
||||
PINF("Registered %d zone allocators", count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new zone allocator
|
||||
*
|
||||
* 'init_zones' must have been called beforehand
|
||||
*/
|
||||
Zone_alloc *new_zone_allocator()
|
||||
{
|
||||
if(_zone_alloc >= _zone_count) {
|
||||
PERR("Zone allocators exhausted");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Zone_alloc *zone = new(env()->heap()) Zone_alloc(this,
|
||||
_zone_alloc,
|
||||
_zones[_zone_alloc],
|
||||
_size);
|
||||
_zone_alloc++;
|
||||
return zone;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif /* _MEM_H_ */
|
283
dde_linux/src/lib/usb/include/nic/component.h
Normal file
283
dde_linux/src/lib/usb/include/nic/component.h
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
* \brief Block-session implementation for network devices
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _NIC__COMPONENT_H_
|
||||
#define _NIC__COMPONENT_H_
|
||||
|
||||
#include <root/component.h>
|
||||
#include <nic/packet_allocator.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
#include <timer_session/connection.h>
|
||||
#include <signal/dispatch.h>
|
||||
|
||||
#define BENCH 0
|
||||
|
||||
namespace Nic {
|
||||
|
||||
using namespace Genode;
|
||||
class Session_component;
|
||||
|
||||
#if BENCH
|
||||
struct Counter : public Genode::Thread<8192>
|
||||
{
|
||||
char const *prefix;
|
||||
int cnt;
|
||||
int burst;
|
||||
size_t size;
|
||||
|
||||
void entry()
|
||||
{
|
||||
Timer::Connection _timer;
|
||||
int interval = 5;
|
||||
while(1) {
|
||||
_timer.msleep(interval * 1000);
|
||||
PDBG("%s: Packets %d/s (in %d burst packets) bytes/s: %d",
|
||||
prefix, cnt / interval, burst / interval, size / interval);
|
||||
cnt = 0;
|
||||
size = 0;
|
||||
burst = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void inc(size_t s) { cnt++; size += s; }
|
||||
void inc_burst() { burst++; }
|
||||
|
||||
Counter(char const *prefix) : prefix(prefix), cnt(0), burst(0), size(0) { start(); }
|
||||
};
|
||||
#else
|
||||
struct Counter
|
||||
{
|
||||
Counter(char const *) { };
|
||||
void inc(size_t) { }
|
||||
void inc_burst() { }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct Device : ::Device
|
||||
{
|
||||
Session_component *_session;
|
||||
|
||||
/**
|
||||
* Transmit data to driver
|
||||
*/
|
||||
virtual void tx(addr_t virt, size_t size) = 0;
|
||||
|
||||
/**
|
||||
* Return mac address of device
|
||||
*/
|
||||
virtual Mac_address mac_address() = 0;
|
||||
|
||||
/**
|
||||
* Set session belonging to this driver
|
||||
*/
|
||||
void session(Session_component *s) { _session = s; }
|
||||
|
||||
/**
|
||||
* Check for session
|
||||
*/
|
||||
bool session() { return _session != 0; }
|
||||
|
||||
/**
|
||||
* Alloc an SKB
|
||||
*/
|
||||
virtual sk_buff *alloc_skb() = 0;
|
||||
|
||||
/**
|
||||
* Submit SKB to device
|
||||
*/
|
||||
virtual void tx_skb(sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Setup SKB with 'data' of 'size', return 'false' if SKB is longer than
|
||||
* 'end'.
|
||||
*/
|
||||
virtual bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end) = 0;
|
||||
|
||||
/**
|
||||
* Call driver fixup function on SKB
|
||||
*/
|
||||
virtual void tx_fixup(struct sk_buff *skb) = 0;
|
||||
|
||||
/**
|
||||
* Return true if device supports burst operations
|
||||
*/
|
||||
virtual bool burst() = 0;
|
||||
|
||||
Device() : _session(0) { }
|
||||
};
|
||||
|
||||
|
||||
class Session_component : public Nic::Packet_allocator,
|
||||
public Packet_session_component<Session_rpc_object>
|
||||
{
|
||||
private:
|
||||
|
||||
Device *_device; /* device this session is using */
|
||||
Tx::Sink *_tx_sink; /* client packet sink */
|
||||
|
||||
protected:
|
||||
|
||||
void _process_packets(unsigned)
|
||||
{
|
||||
static sk_buff work_skb; /* dummy skb for fixup calls */
|
||||
static Counter counter("TX");
|
||||
|
||||
int tx_cnt = 0;
|
||||
unsigned size = 0;
|
||||
sk_buff *skb = 0;
|
||||
unsigned char *ptr = 0;
|
||||
|
||||
/* submit received packets to lower layer */
|
||||
while (_tx_sink->packet_avail())
|
||||
{
|
||||
Packet_descriptor packet = _tx_sink->get_packet();
|
||||
addr_t virt = (addr_t)_tx_sink->packet_content(packet);
|
||||
|
||||
if (_device->burst()) {
|
||||
if (!ptr || !_device->skb_fill(&work_skb, ptr, packet.size(), skb->end)) {
|
||||
|
||||
/* submit batch to device */
|
||||
if (ptr) {
|
||||
_device->tx_skb(skb);
|
||||
tx_cnt++;
|
||||
counter.inc_burst();
|
||||
}
|
||||
|
||||
/* alloc new SKB */
|
||||
skb = _device->alloc_skb();
|
||||
ptr = skb->data;
|
||||
work_skb.data = 0;
|
||||
_device->skb_fill(&work_skb, ptr, packet.size(), skb->end);
|
||||
}
|
||||
|
||||
/* copy packet to current data pos */
|
||||
Genode::memcpy(work_skb.data, (void *)virt, packet.size());
|
||||
/* call fixup on dummy SKB */
|
||||
_device->tx_fixup(&work_skb);
|
||||
/* advance to next slot */
|
||||
ptr = work_skb.end;
|
||||
skb->len += work_skb.truesize;
|
||||
} else {
|
||||
/* send to driver */
|
||||
_device->tx(virt, packet.size());
|
||||
}
|
||||
|
||||
counter.inc(packet.size());
|
||||
|
||||
if (!_tx_sink->ready_to_ack()) {
|
||||
_wait_event(_tx_sink->ready_to_ack());
|
||||
}
|
||||
|
||||
/* acknowledge to client */
|
||||
_tx_sink->acknowledge_packet(packet);
|
||||
|
||||
/* it's cooperative scheduling - be nice */
|
||||
if (tx_cnt == 20)
|
||||
break;
|
||||
}
|
||||
|
||||
/* sumbit last skb */
|
||||
if (skb) {
|
||||
_device->tx_skb(skb);
|
||||
counter.inc_burst();
|
||||
}
|
||||
|
||||
/* for large TCP/s check RX immediately */
|
||||
Irq::check_irq();
|
||||
|
||||
/* release acknowledged packets */
|
||||
_rx_ack(false);
|
||||
|
||||
if (_tx_sink->packet_avail())
|
||||
Signal_transmitter(_tx.sigh_packet_avail()).submit();
|
||||
}
|
||||
|
||||
void _rx_ack(bool block = true)
|
||||
{
|
||||
while (_rx.source()->ack_avail() || block)
|
||||
{
|
||||
|
||||
Packet_descriptor packet = _rx.source()->get_acked_packet();
|
||||
|
||||
/* free packet buffer */
|
||||
_rx.source()->release_packet(packet);
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Dataspace_capability rx_ds,
|
||||
Rpc_entrypoint &ep,
|
||||
Signal_receiver *sig_rec,
|
||||
::Device *device)
|
||||
:
|
||||
Nic::Packet_allocator(Genode::env()->heap()),
|
||||
Packet_session_component(tx_ds, rx_ds, this, ep, sig_rec),
|
||||
_device(static_cast<Device *>(device)),
|
||||
_tx_sink(Session_rpc_object::_tx.sink())
|
||||
{ _device->session(this); }
|
||||
|
||||
Mac_address mac_address() { return _device->mac_address(); }
|
||||
|
||||
/**
|
||||
* Send packet to client (called form driver)
|
||||
*/
|
||||
void rx(addr_t virt, size_t size)
|
||||
{
|
||||
static Counter counter("RX");
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Packet_descriptor p =_rx.source()->alloc_packet(size);
|
||||
Genode::memcpy(_rx.source()->packet_content(p), (void*)virt, size);
|
||||
_rx.source()->submit_packet(p);
|
||||
counter.inc(size);
|
||||
} catch (...) {
|
||||
/* ack or block */
|
||||
_rx_ack();
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
_rx_ack(false);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Shortcut for single-client root component
|
||||
*/
|
||||
typedef Root_component<Session_component, Single_client> Root_component;
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Packet_root<Root_component, Session_component>
|
||||
{
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Signal_receiver *sig_rec, Device *device)
|
||||
:
|
||||
Packet_root(session_ep, md_alloc, sig_rec, device) { }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif /* _NIC__COMPONENT_H_ */
|
30
dde_linux/src/lib/usb/include/platform.h
Normal file
30
dde_linux/src/lib/usb/include/platform.h
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* \brief Platform specific definitions
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-06
|
||||
*
|
||||
* These functions have to be implemented on all supported platforms.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#define _PLATFORM_H_
|
||||
|
||||
struct Services
|
||||
{
|
||||
bool hid;
|
||||
bool stor;
|
||||
bool nic;
|
||||
|
||||
Services() : hid(false), stor(false), nic(false) { }
|
||||
};
|
||||
|
||||
void platform_hcd_init(Services *services);
|
||||
|
||||
#endif /* _PLATFORM_H_ */
|
194
dde_linux/src/lib/usb/include/routine.h
Normal file
194
dde_linux/src/lib/usb/include/routine.h
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
* \brief Pseudo-thread implementation using setjmp/longjmp
|
||||
* \author Sebastian Sumpf <Sebastian.Sumpf@genode-labs.com>
|
||||
* \date 2012-04-25
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _ROUTINE_H_
|
||||
#define _ROUTINE_H_
|
||||
|
||||
#include <base/env.h>
|
||||
#include <util/list.h>
|
||||
#include <libc/setjmp.h>
|
||||
|
||||
extern "C" {
|
||||
#include <dde_kit/memory.h>
|
||||
}
|
||||
|
||||
#include <platform/platform.h>
|
||||
|
||||
static const bool verbose = false;
|
||||
|
||||
|
||||
/**
|
||||
* Allows pseudo-parallel execution of functions
|
||||
*/
|
||||
class Routine : public Genode::List<Routine>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
enum { STACK_SIZE = 0x2000 };
|
||||
bool _started; /* true if already started */
|
||||
jmp_buf _env; /* state */
|
||||
int (*_func)(void *); /* function to call*/
|
||||
void *_arg; /* argument for function */
|
||||
char const *_name; /* name of this object */
|
||||
char *_stack; /* stack pointer */
|
||||
static Routine *_current; /* currently scheduled object */
|
||||
static Routine *_dead; /* object to remove */
|
||||
static bool _all; /* true when all objects must be scheduled */
|
||||
|
||||
|
||||
/**
|
||||
* List containing all registered objects
|
||||
*/
|
||||
static Genode::List<Routine> *_list()
|
||||
{
|
||||
static Genode::List<Routine> _l;
|
||||
return &_l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start/restore
|
||||
*/
|
||||
void _run()
|
||||
{
|
||||
/* will never return */
|
||||
if (!_started) {
|
||||
_started = true;
|
||||
_stack = (char *)dde_kit_simple_malloc(STACK_SIZE);
|
||||
|
||||
if (verbose)
|
||||
PDBG("Start func %s (%p) sp: %p", _name, _func, (_stack + STACK_SIZE));
|
||||
|
||||
/* XXX move to platform code */
|
||||
|
||||
/* switch stack and call '_func(_arg)' */
|
||||
platform_execute((void *)(_stack + STACK_SIZE), (void *)_func, _arg);
|
||||
}
|
||||
|
||||
/* restore old state */
|
||||
if (verbose)
|
||||
PDBG("Schedule %s (%p)", _name, _func);
|
||||
|
||||
_longjmp(_env, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for and remove dead objects
|
||||
*/
|
||||
static void _check_dead()
|
||||
{
|
||||
if (!_dead)
|
||||
return;
|
||||
|
||||
_list()->remove(_dead);
|
||||
destroy(Genode::env()->heap(), _dead);
|
||||
_dead = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get next object to schedule
|
||||
*/
|
||||
static Routine *_next(bool all)
|
||||
{
|
||||
/* on schedule all start at first element */
|
||||
if (all) {
|
||||
_all = true;
|
||||
return _list()->first();
|
||||
}
|
||||
|
||||
/* disable all at last element */
|
||||
if (_all && _current && !_current->next())
|
||||
_all = false;
|
||||
|
||||
/* return next element (wrap at the end) */
|
||||
return _current && _current->next() ? _current->next() : _list()->first();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Routine(int (*func)(void*), void *arg, char const *name, bool started)
|
||||
: _started(started), _func(func), _arg(arg), _name(name), _stack(0) { }
|
||||
|
||||
~Routine()
|
||||
{
|
||||
if (_stack)
|
||||
dde_kit_simple_free(_stack);
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule next object
|
||||
*
|
||||
* If all is true, each object will be scheduled once.
|
||||
*/
|
||||
static void schedule(bool all = false) __attribute__((noinline))
|
||||
{
|
||||
if (!_list()->first())
|
||||
return;
|
||||
|
||||
Routine *next = _next(all);
|
||||
|
||||
if (next == _current) {
|
||||
_check_dead();
|
||||
return;
|
||||
}
|
||||
|
||||
/* return when restored */
|
||||
if (_current && _setjmp(_current->_env)) {
|
||||
_check_dead();
|
||||
return;
|
||||
}
|
||||
|
||||
_current = next;
|
||||
_current->_run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Schedule each object once
|
||||
*/
|
||||
static void schedule_all() { schedule(true); }
|
||||
|
||||
/**
|
||||
* Set current to first object
|
||||
*/
|
||||
static void current_use_first() { _current = _list()->first(); }
|
||||
|
||||
/**
|
||||
* Add an object
|
||||
*/
|
||||
static void add(int (*func)(void *), void *arg, char const *name,
|
||||
bool started = false)
|
||||
{
|
||||
_list()->insert(new (Genode::env()->heap())
|
||||
Routine(func, arg, name, started));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this object
|
||||
*/
|
||||
static void remove()
|
||||
{
|
||||
if (!_current)
|
||||
return;
|
||||
|
||||
_dead = _current;
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
* True when 'schedule_all' has been called and is still in progress
|
||||
*/
|
||||
static bool all() { return _all; }
|
||||
};
|
||||
|
||||
#endif /* _ROUTINE_H_ */
|
||||
|
136
dde_linux/src/lib/usb/include/signal.h
Normal file
136
dde_linux/src/lib/usb/include/signal.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* \brief Main-signal receiver and signal-helper functions
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _SIGNAL_H_
|
||||
#define _SIGNAL_H_
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/signal.h>
|
||||
|
||||
#include "routine.h"
|
||||
|
||||
/**
|
||||
* Context base for IRQ, Timer, etc.
|
||||
*/
|
||||
class Driver_context : public Genode::Signal_context
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Perform context operation
|
||||
*/
|
||||
virtual void handle() = 0;
|
||||
|
||||
virtual char const *debug() = 0;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This singelton currently received all signals
|
||||
*/
|
||||
class Service_handler
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
Genode::Signal_receiver *_receiver;
|
||||
|
||||
Service_handler() { }
|
||||
|
||||
public:
|
||||
|
||||
static Service_handler * s()
|
||||
{
|
||||
static Service_handler _s;
|
||||
return &_s;
|
||||
}
|
||||
|
||||
void receiver(Genode::Signal_receiver *recv) { _receiver = recv; }
|
||||
|
||||
/**
|
||||
* Dispatch for wait for signal
|
||||
*/
|
||||
void process()
|
||||
{
|
||||
if (Routine::all()) {
|
||||
Routine::schedule();
|
||||
return;
|
||||
}
|
||||
|
||||
check_signal();
|
||||
}
|
||||
|
||||
void check_signal(bool block = true)
|
||||
{
|
||||
while (_receiver->pending() || block) {
|
||||
|
||||
Genode::Signal s = _receiver->wait_for_signal();
|
||||
|
||||
/* handle signal IRQ, timer, or event signals */
|
||||
Driver_context *ctx = static_cast<Driver_context *>(s.context());
|
||||
ctx->handle();
|
||||
block = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Helper that holds sender and receiver
|
||||
*/
|
||||
class Signal_helper
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_receiver *_receiver;
|
||||
Genode::Signal_transmitter *_sender;
|
||||
|
||||
public:
|
||||
|
||||
Signal_helper(Genode::Signal_receiver *recv)
|
||||
: _receiver(recv),
|
||||
_sender(new (Genode::env()->heap()) Genode::Signal_transmitter()) { }
|
||||
|
||||
Genode::Signal_receiver *receiver() const { return _receiver; }
|
||||
Genode::Signal_transmitter *sender() const { return _sender; }
|
||||
};
|
||||
|
||||
|
||||
namespace Timer
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
namespace Irq
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
void check_irq();
|
||||
}
|
||||
|
||||
namespace Event
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
namespace Storage
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
namespace Nic
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
140
dde_linux/src/lib/usb/include/signal/dispatch.h
Normal file
140
dde_linux/src/lib/usb/include/signal/dispatch.h
Normal file
@ -0,0 +1,140 @@
|
||||
/**
|
||||
* \brief Packet-stream-session components
|
||||
* \author Sebastian Sumpf
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _SIGNAL__DISPATCHER_H_
|
||||
#define _SIGNAL__DISPATCHER_H_
|
||||
|
||||
#include "signal.h"
|
||||
|
||||
|
||||
/**
|
||||
* Session components that overrides signal handlers
|
||||
*/
|
||||
template <typename RPC>
|
||||
class Packet_session_component : public RPC
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_dispatcher<Packet_session_component> _process_packet_dispatcher;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void _process_packets(unsigned) = 0;
|
||||
|
||||
public:
|
||||
|
||||
Packet_session_component(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Rpc_entrypoint &ep,
|
||||
Genode::Signal_receiver *sig_rec)
|
||||
:
|
||||
RPC(tx_ds, ep),
|
||||
_process_packet_dispatcher(*sig_rec, *this,
|
||||
&Packet_session_component::_process_packets)
|
||||
{
|
||||
/*
|
||||
* Register '_process_packets' dispatch function as signal
|
||||
* handler for packet-avail and ready-to-ack signals.
|
||||
*/
|
||||
RPC::_tx.sigh_packet_avail(_process_packet_dispatcher);
|
||||
RPC::_tx.sigh_ready_to_ack(_process_packet_dispatcher);
|
||||
}
|
||||
|
||||
Packet_session_component(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Dataspace_capability rx_ds,
|
||||
Genode::Range_allocator *rx_buffer_alloc,
|
||||
Genode::Rpc_entrypoint &ep,
|
||||
Genode::Signal_receiver *sig_rec)
|
||||
:
|
||||
RPC(tx_ds, rx_ds, rx_buffer_alloc, ep),
|
||||
_process_packet_dispatcher(*sig_rec, *this,
|
||||
&Packet_session_component::_process_packets)
|
||||
{
|
||||
/*
|
||||
* Register '_process_packets' dispatch function as signal
|
||||
* handler for packet-avail and ready-to-ack signals.
|
||||
*/
|
||||
RPC::_tx.sigh_packet_avail(_process_packet_dispatcher);
|
||||
RPC::_tx.sigh_ready_to_ack(_process_packet_dispatcher);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Abstract device
|
||||
*/
|
||||
struct Device { };
|
||||
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
template <typename ROOT_COMPONENT, typename SESSION_COMPONENT>
|
||||
class Packet_root : public ROOT_COMPONENT
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Rpc_entrypoint &_ep;
|
||||
Genode::Signal_receiver *_sig_rec;
|
||||
Device *_device;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
SESSION_COMPONENT *_create_session(const char *args)
|
||||
{
|
||||
using namespace Genode;
|
||||
size_t ram_quota =
|
||||
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
|
||||
size_t tx_buf_size =
|
||||
Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
|
||||
size_t rx_buf_size =
|
||||
Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
|
||||
|
||||
/* delete ram quota by the memory needed for the session */
|
||||
size_t session_size = max((size_t)4096,
|
||||
sizeof(SESSION_COMPONENT)
|
||||
+ sizeof(Allocator_avl));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
/*
|
||||
* Check if donated ram quota suffices for both communication
|
||||
* buffers. Also check both sizes separately to handle a
|
||||
* possible overflow of the sum of both sizes.
|
||||
*/
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("insufficient 'ram_quota', got %zd, need %zd",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
return new (ROOT_COMPONENT::md_alloc())
|
||||
SESSION_COMPONENT(env()->ram_session()->alloc(tx_buf_size),
|
||||
env()->ram_session()->alloc(rx_buf_size),
|
||||
_ep, _sig_rec, _device);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Packet_root(Genode::Rpc_entrypoint *session_ep, Genode::Allocator *md_alloc,
|
||||
Genode::Signal_receiver *sig_rec, Device *device)
|
||||
:
|
||||
ROOT_COMPONENT(session_ep, md_alloc),
|
||||
_ep(*session_ep), _sig_rec(sig_rec), _device(device)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _SIGNAL__DISPATCHER_H_ */
|
121
dde_linux/src/lib/usb/include/storage/component.h
Normal file
121
dde_linux/src/lib/usb/include/storage/component.h
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* \brief Block-session implementation for USB storage
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _STORAGE__COMPONENT_H_
|
||||
#define _STORAGE__COMPONENT_H_
|
||||
|
||||
#include <root/component.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
#include <signal/dispatch.h>
|
||||
|
||||
namespace Block {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
class Session_component;
|
||||
|
||||
struct Device : ::Device
|
||||
{
|
||||
/**
|
||||
* Request block size for driver and medium
|
||||
*/
|
||||
virtual Genode::size_t block_size() = 0;
|
||||
|
||||
/**
|
||||
* Request capacity of medium in blocks
|
||||
*/
|
||||
virtual Genode::size_t block_count() = 0;
|
||||
|
||||
virtual void io(Session_component *session, Packet_descriptor &packet,
|
||||
addr_t virt, addr_t phys) = 0;
|
||||
};
|
||||
|
||||
|
||||
class Session_component : public Packet_session_component<Session_rpc_object>
|
||||
{
|
||||
private:
|
||||
|
||||
addr_t _rq_phys ; /* physical addr. of rq_ds */
|
||||
Device *_device; /* device this session is using */
|
||||
|
||||
protected:
|
||||
|
||||
void _process_packets(unsigned)
|
||||
{
|
||||
while (tx_sink()->packet_avail())
|
||||
{
|
||||
Packet_descriptor packet = tx_sink()->get_packet();
|
||||
addr_t virt = (addr_t)tx_sink()->packet_content(packet);
|
||||
addr_t phys = _rq_phys + packet.offset();
|
||||
|
||||
try {
|
||||
_device->io(this, packet, virt, phys);
|
||||
} catch (...) { PERR("Failed to queue packet"); }
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Ram_dataspace_capability rx_ds,
|
||||
Rpc_entrypoint &ep,
|
||||
Signal_receiver *sig_rec,
|
||||
::Device *device)
|
||||
:
|
||||
Packet_session_component(tx_ds, ep, sig_rec),
|
||||
_rq_phys(Dataspace_client(tx_ds).phys_addr()),
|
||||
_device(static_cast<Device *>(device))
|
||||
{
|
||||
env()->ram_session()->free(rx_ds);
|
||||
}
|
||||
|
||||
void info(size_t *blk_count, size_t *blk_size,
|
||||
Operations *ops)
|
||||
{
|
||||
*blk_count = _device->block_count();
|
||||
*blk_size = _device->block_size();
|
||||
ops->set_operation(Packet_descriptor::READ);
|
||||
ops->set_operation(Packet_descriptor::WRITE);
|
||||
}
|
||||
|
||||
void complete(Packet_descriptor &packet, bool success)
|
||||
{
|
||||
packet.succeeded(success);
|
||||
tx_sink()->acknowledge_packet(packet);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Shortcut for single-client root component
|
||||
*/
|
||||
typedef Root_component<Session_component, Single_client> Root_component;
|
||||
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Packet_root<Root_component, Session_component>
|
||||
{
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Signal_receiver *sig_rec, Device *device)
|
||||
:
|
||||
Packet_root(session_ep, md_alloc, sig_rec, device) { }
|
||||
};
|
||||
|
||||
}
|
||||
#endif /* _STORAGE__COMPONENT_H_ */
|
88
dde_linux/src/lib/usb/include/storage/scsi.h
Normal file
88
dde_linux/src/lib/usb/include/storage/scsi.h
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* \brief SCSI helpers
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-05-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _SCSI_H_
|
||||
#define _SCSI_H_
|
||||
|
||||
struct scsi_cmnd;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Add a SCSI device
|
||||
*
|
||||
* \param sdev Device to add
|
||||
*/
|
||||
void scsi_add_device(struct scsi_device *sdev);
|
||||
|
||||
|
||||
/**
|
||||
* Alloc data buffer for command
|
||||
*
|
||||
* \param size Size of buffer
|
||||
* \param cmnd Command to assciate buffer
|
||||
*/
|
||||
void scsi_alloc_buffer(size_t size, struct scsi_cmnd *cmnd);
|
||||
|
||||
|
||||
/**
|
||||
* Fill command
|
||||
*
|
||||
* \param cmnd Command buffer to setup
|
||||
* \param size Data size
|
||||
* \param virt Virtual address of buffer
|
||||
* \param addr DMA address of buffer
|
||||
*/
|
||||
void scsi_setup_buffer(struct scsi_cmnd *cmnd, size_t size, void *virt, dma_addr_t addr);
|
||||
|
||||
|
||||
/**
|
||||
* Free data buffer of command
|
||||
*
|
||||
* \param cmnd Command
|
||||
*/
|
||||
void scsi_free_buffer(struct scsi_cmnd *cmnd);
|
||||
|
||||
|
||||
/**
|
||||
* Get buffer data for command
|
||||
*
|
||||
* \param cmnd Command to retrieve buffer pointer
|
||||
*
|
||||
* \return Buffer pointer
|
||||
*/
|
||||
void *scsi_buffer_data(struct scsi_cmnd *cmnd);
|
||||
|
||||
|
||||
/**
|
||||
* Allocate a SCSI command
|
||||
*
|
||||
* \return Allocated command or zero on failure
|
||||
*/
|
||||
struct scsi_cmnd *_scsi_alloc_command();
|
||||
|
||||
|
||||
/**
|
||||
* Free a SCSI command
|
||||
*
|
||||
* \param cmnd Command
|
||||
*/
|
||||
void _scsi_free_command(struct scsi_cmnd *cmnd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _SCSI_H_ */
|
18
dde_linux/src/lib/usb/include/x86/platform/lx_emul.h
Normal file
18
dde_linux/src/lib/usb/include/x86/platform/lx_emul.h
Normal file
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* \brief Platform specific part of the Linux API emulation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-18
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _X86_32__PLATFORM__LX_EMUL_
|
||||
#define _X86_32__PLATFORM__LX_EMUL_
|
||||
|
||||
|
||||
#endif /* _X86_32__PLATFORM__LX_EMUL_ */
|
40
dde_linux/src/lib/usb/include/x86/platform/platform.h
Normal file
40
dde_linux/src/lib/usb/include/x86/platform/platform.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* \brief Platform specific code
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-06-10
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#ifndef _X86_32__PLATFORM_H_
|
||||
#define _X86_32__PLATFORM_H_
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
static inline
|
||||
void platform_execute(void *sp, void *func, void *arg)
|
||||
{
|
||||
asm volatile ("movl %2, 0(%0);"
|
||||
"movl %1, -0x4(%0);"
|
||||
"movl %0, %%esp;"
|
||||
"call *-4(%%esp);"
|
||||
: : "r" (sp), "r" (func), "r" (arg));
|
||||
}
|
||||
|
||||
extern "C" void module_ehci_hcd_init();
|
||||
extern "C" void module_uhci_hcd_init();
|
||||
|
||||
inline void platform_hcd_init(Services *s)
|
||||
{
|
||||
|
||||
/* ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after */
|
||||
module_ehci_hcd_init();
|
||||
module_uhci_hcd_init();
|
||||
}
|
||||
|
||||
#endif /* _X86_32__PLATFORM_H_ */
|
143
dde_linux/src/lib/usb/input/evdev.c
Normal file
143
dde_linux/src/lib/usb/input/evdev.c
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* \brief Input service and event handler
|
||||
* \author Christian Helmuth
|
||||
* \author Dirk Vogt <dvogt@os.inf.tu-dresden.de>
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2009-04-20
|
||||
*
|
||||
* The original implementation was in the L4Env from the TUD:OS group
|
||||
* (l4/pkg/input/lib/src/l4evdev.c). This file was released under the terms of
|
||||
* the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 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.
|
||||
*/
|
||||
|
||||
/* Linux */
|
||||
#include <linux/input.h>
|
||||
|
||||
/* Local */
|
||||
#include <lx_emul.h>
|
||||
|
||||
/* Callback function to Genode subsystem */
|
||||
static genode_input_event_cb handler;;
|
||||
|
||||
void genode_evdev_event(struct input_handle *handle, unsigned int type,
|
||||
unsigned int code, int value)
|
||||
{
|
||||
#if DEBUG_EVDEV
|
||||
static unsigned long count = 0;
|
||||
#endif
|
||||
|
||||
/* filter sound events */
|
||||
if (test_bit(EV_SND, handle->dev->evbit)) return;
|
||||
|
||||
/* filter input_repeat_key() */
|
||||
if ((type == EV_KEY) && (value == 2)) return;
|
||||
|
||||
/* filter EV_SYN */
|
||||
if (type == EV_SYN) return;
|
||||
|
||||
/* generate arguments and call back */
|
||||
enum input_event_type arg_type;
|
||||
unsigned arg_keycode = KEY_UNKNOWN;
|
||||
int arg_ax = 0, arg_ay = 0, arg_rx = 0, arg_ry = 0;
|
||||
|
||||
switch (type) {
|
||||
|
||||
case EV_KEY:
|
||||
arg_keycode = code;
|
||||
switch (value) {
|
||||
|
||||
case 0:
|
||||
arg_type = EVENT_TYPE_RELEASE;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
arg_type = EVENT_TYPE_PRESS;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("Unknown key event value %d - not handled\n", value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_ABS:
|
||||
switch (code) {
|
||||
|
||||
case ABS_X:
|
||||
arg_type = EVENT_TYPE_MOTION;
|
||||
arg_ax = value;
|
||||
break;
|
||||
|
||||
case ABS_Y:
|
||||
arg_type = EVENT_TYPE_MOTION;
|
||||
arg_ay = value;
|
||||
break;
|
||||
|
||||
case ABS_WHEEL:
|
||||
/*
|
||||
* XXX I do not know, how to handle this correctly. At least, this
|
||||
* scheme works on Qemu.
|
||||
*/
|
||||
arg_type = EVENT_TYPE_WHEEL;
|
||||
arg_ry = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("Unknown absolute event code %d - not handled\n", code);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case EV_REL:
|
||||
switch (code) {
|
||||
|
||||
case REL_X:
|
||||
arg_type = EVENT_TYPE_MOTION;
|
||||
arg_rx = value;
|
||||
break;
|
||||
|
||||
case REL_Y:
|
||||
arg_type = EVENT_TYPE_MOTION;
|
||||
arg_ry = value;
|
||||
break;
|
||||
|
||||
case REL_HWHEEL:
|
||||
arg_type = EVENT_TYPE_WHEEL;
|
||||
arg_rx = value;
|
||||
break;
|
||||
|
||||
case REL_WHEEL:
|
||||
arg_type = EVENT_TYPE_WHEEL;
|
||||
arg_ry = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("Unknown relative event code %d - not handled\n", code);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
printk("Unknown event type %d - not handled\n", type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler)
|
||||
handler(arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry);
|
||||
printk("EVENT: t: %x c: %x ax: %d ay %d rx: %d ry %d\n",
|
||||
arg_type, arg_keycode, arg_ax, arg_ay, arg_rx, arg_ry);
|
||||
#if DEBUG_EVDEV
|
||||
printk("event[%ld]. dev: %s, type: %d, code: %d, value: %d\n",
|
||||
count++, handle->dev->name, type, code, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
void genode_input_register(genode_input_event_cb h) { handler = h; }
|
||||
|
77
dde_linux/src/lib/usb/input/input_component.cc
Normal file
77
dde_linux/src/lib/usb/input/input_component.cc
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* \brief Linux 2.6 Input driver for USB HID
|
||||
* \author Christian Helmuth
|
||||
* \author Christian Prochaska
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2011-07-15
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2011-2013 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 <base/printf.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <input/component.h>
|
||||
#include <os/ring_buffer.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
|
||||
#undef RELEASE
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
/*********************
|
||||
** Input component **
|
||||
*********************/
|
||||
|
||||
typedef Ring_buffer<Input::Event, 512> Input_ring_buffer;
|
||||
|
||||
static Input_ring_buffer ev_queue;
|
||||
|
||||
namespace Input {
|
||||
|
||||
void event_handling(bool enable) { }
|
||||
bool event_pending() { return !ev_queue.empty(); }
|
||||
Event get_event() { return ev_queue.get(); }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Input event call-back function
|
||||
*/
|
||||
static void input_callback(enum input_event_type type,
|
||||
unsigned code,
|
||||
int absolute_x, int absolute_y,
|
||||
int relative_x, int relative_y)
|
||||
{
|
||||
Input::Event::Type t = Input::Event::INVALID;
|
||||
switch (type) {
|
||||
case EVENT_TYPE_PRESS: t = Input::Event::PRESS; break;
|
||||
case EVENT_TYPE_RELEASE: t = Input::Event::RELEASE; break;
|
||||
case EVENT_TYPE_MOTION: t = Input::Event::MOTION; break;
|
||||
case EVENT_TYPE_WHEEL: t = Input::Event::WHEEL; break;
|
||||
}
|
||||
|
||||
try {
|
||||
ev_queue.add(Input::Event(t, code,
|
||||
absolute_x, absolute_y,
|
||||
relative_x, relative_y));
|
||||
} catch (Input_ring_buffer::Overflow) {
|
||||
PWRN("input ring buffer overflow");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void start_input_service(void *ep)
|
||||
{
|
||||
Rpc_entrypoint *e = static_cast<Rpc_entrypoint *>(ep);
|
||||
static Input::Root input_root(e, env()->heap());
|
||||
env()->parent()->announce(e->manage(&input_root));
|
||||
|
||||
genode_input_register(input_callback);
|
||||
}
|
1033
dde_linux/src/lib/usb/lx_emul.cc
Normal file
1033
dde_linux/src/lib/usb/lx_emul.cc
Normal file
File diff suppressed because it is too large
Load Diff
130
dde_linux/src/lib/usb/main.cc
Normal file
130
dde_linux/src/lib/usb/main.cc
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* \brief USB driver main program
|
||||
* \author Norman Feske
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-01-29
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 */
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/printf.h>
|
||||
#include <base/sleep.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <nic_session/nic_session.h>
|
||||
/* Local */
|
||||
#include "storage/component.h"
|
||||
#include "routine.h"
|
||||
#include "signal.h"
|
||||
|
||||
extern "C" {
|
||||
#include <dde_kit/timer.h>
|
||||
}
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern "C" int subsys_usb_init();
|
||||
extern "C" void subsys_input_init();
|
||||
extern "C" void module_evdev_init();
|
||||
extern "C" void module_hid_init();
|
||||
extern "C" void module_hid_init_core();
|
||||
extern "C" void module_usb_stor_init();
|
||||
|
||||
extern "C" void start_input_service(void *ep);
|
||||
|
||||
Routine *Routine::_current = 0;
|
||||
Routine *Routine::_dead = 0;
|
||||
bool Routine::_all = false;
|
||||
|
||||
void breakpoint() { PDBG("BREAK"); }
|
||||
|
||||
|
||||
static void init(Services *services)
|
||||
{
|
||||
/* start jiffies */
|
||||
dde_kit_timer_init(0, 0);
|
||||
|
||||
/* USB */
|
||||
subsys_usb_init();
|
||||
|
||||
/* input + HID */
|
||||
if (services->hid) {
|
||||
subsys_input_init();
|
||||
module_evdev_init();
|
||||
|
||||
/* HID */
|
||||
module_hid_init();
|
||||
}
|
||||
|
||||
/* host controller */
|
||||
platform_hcd_init(services);
|
||||
|
||||
/* storage */
|
||||
if (services->stor)
|
||||
module_usb_stor_init();
|
||||
}
|
||||
|
||||
|
||||
void start_usb_driver()
|
||||
{
|
||||
/*
|
||||
* Initialize server entry point
|
||||
*/
|
||||
enum { STACK_SIZE = 4096 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep_hid(&cap, STACK_SIZE, "usb_hid_ep");
|
||||
static Signal_receiver recv;
|
||||
|
||||
Services services;
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("hid");
|
||||
start_input_service(&ep_hid);
|
||||
services.hid = true;
|
||||
} catch (Config::Invalid) {
|
||||
PDBG("No <config> node found - not starting any USB services");
|
||||
return;
|
||||
} catch (Xml_node::Nonexistent_sub_node) {
|
||||
PDBG("No <hid> config node found - not starting the USB HID (Input) service");
|
||||
}
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("storage");
|
||||
services.stor = true;
|
||||
} catch (Xml_node::Nonexistent_sub_node) {
|
||||
PDBG("No <storage> config node found - not starting the USB Storage (Block) service");
|
||||
}
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("nic");
|
||||
services.nic = true;
|
||||
} catch (Xml_node::Nonexistent_sub_node) {
|
||||
PDBG("No <nic> config node found - not starting the USB Nic (Network) service");
|
||||
}
|
||||
|
||||
Timer::init(&recv);
|
||||
Irq::init(&recv);
|
||||
Event::init(&recv);
|
||||
Service_handler::s()->receiver(&recv);
|
||||
Storage::init(&recv);
|
||||
Nic::init(&recv);
|
||||
|
||||
Routine::add(0, 0, "Main", true);
|
||||
Routine::current_use_first();
|
||||
init(&services);
|
||||
|
||||
Routine::remove();
|
||||
|
||||
/* will never be reached */
|
||||
sleep_forever();
|
||||
}
|
611
dde_linux/src/lib/usb/nic/nic.cc
Normal file
611
dde_linux/src/lib/usb/nic/nic.cc
Normal file
@ -0,0 +1,611 @@
|
||||
/*
|
||||
* \brief Glue code for Linux network drivers
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <base/rpc_server.h>
|
||||
#include <base/snprintf.h>
|
||||
#include <nic_session/nic_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <os/config.h>
|
||||
#include <nic/xml_node.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <mem.h>
|
||||
|
||||
#include <nic/component.h>
|
||||
#include "signal.h"
|
||||
|
||||
extern "C" {
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/usbnet.h>
|
||||
}
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
enum {
|
||||
START = 0x1, /* device flag */
|
||||
HEAD_ROOM = 8, /* head room in skb in bytes */
|
||||
MAC_LEN = 17, /* 12 number and 6 colons */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Internal alloc function
|
||||
*/
|
||||
struct sk_buff *_alloc_skb(unsigned int size, bool tx = true);
|
||||
|
||||
|
||||
/**
|
||||
* Skb-bitmap allocator
|
||||
*/
|
||||
template <unsigned ENTRIES, unsigned BUFFER>
|
||||
class Skb
|
||||
{
|
||||
private:
|
||||
|
||||
enum {
|
||||
IDX = ENTRIES / 32,
|
||||
};
|
||||
|
||||
sk_buff _buf[ENTRIES];
|
||||
unsigned _free[ENTRIES / sizeof(unsigned)];
|
||||
unsigned _idx;
|
||||
bool _wait_free;
|
||||
|
||||
public:
|
||||
|
||||
Skb() : _idx(0)
|
||||
{
|
||||
Genode::memset(_free, 0xff, sizeof(_free));
|
||||
|
||||
for (unsigned i = 0; i < ENTRIES; i++)
|
||||
_buf[i].start = (unsigned char *)Genode::Mem::dma()->alloc(BUFFER);;
|
||||
}
|
||||
|
||||
sk_buff *alloc()
|
||||
{
|
||||
for (register int i = 0; i < IDX; i++) {
|
||||
if (_free[_idx] != 0) {
|
||||
unsigned msb = Genode::log2(_free[_idx]);
|
||||
_free[_idx] ^= (1 << msb);
|
||||
|
||||
sk_buff *r = &_buf[(_idx * 32) + msb];
|
||||
r->data = r->start;
|
||||
r->phys = 0;
|
||||
r->cloned = 0;
|
||||
r->clone = 0;
|
||||
r->len = 0;
|
||||
return r;
|
||||
}
|
||||
_idx = (_idx + 1) % IDX;
|
||||
}
|
||||
|
||||
|
||||
/* wait until some SKBs are fred */
|
||||
_wait_free = false;
|
||||
_wait_event(_wait_free);
|
||||
|
||||
return alloc();
|
||||
}
|
||||
|
||||
void free(sk_buff *buf)
|
||||
{
|
||||
unsigned entry = buf - &_buf[0];
|
||||
if (&_buf[0] > buf || entry > ENTRIES)
|
||||
return;
|
||||
|
||||
/* unblock waiting skb allocs */
|
||||
_wait_free = true;
|
||||
_idx = entry / 32;
|
||||
_free[_idx] |= (1 << (entry % 32));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* smsc95xx.c */
|
||||
enum { DEFAULT_HS_BURST_CAP_SIZE = 18944 };
|
||||
|
||||
/* send/receive skb type */
|
||||
typedef Skb<50,DEFAULT_HS_BURST_CAP_SIZE> Tx_skb;
|
||||
typedef Skb<32, DEFAULT_HS_BURST_CAP_SIZE> Rx_skb;
|
||||
|
||||
|
||||
/* send/receive skb allocators */
|
||||
static Tx_skb *skb_tx()
|
||||
{
|
||||
static Tx_skb _skb;
|
||||
return &_skb;
|
||||
}
|
||||
|
||||
|
||||
static Rx_skb *skb_rx()
|
||||
{
|
||||
static Rx_skb _skb;
|
||||
return &_skb;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prototype of fixup function
|
||||
*/
|
||||
extern "C" {
|
||||
typedef struct sk_buff* (*fixup_t)(struct usbnet *, struct sk_buff *, gfp_t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Net_device to session glue code
|
||||
*/
|
||||
class Nic_device : public Nic::Device
|
||||
{
|
||||
public:
|
||||
|
||||
struct net_device *_ndev; /* Linux-net device */
|
||||
fixup_t _tx_fixup;
|
||||
|
||||
public:
|
||||
|
||||
Nic_device(struct net_device *ndev) : _ndev(ndev)
|
||||
{
|
||||
/*
|
||||
* Retrieve 'tx_fixup' funcion from driver and set it to zero, so it
|
||||
* cannot be called by the actual driver.
|
||||
*/
|
||||
struct usbnet *dev = (usbnet *)netdev_priv(ndev);
|
||||
_tx_fixup = dev->driver_info->tx_fixup;
|
||||
dev->driver_info->tx_fixup = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add device
|
||||
*/
|
||||
static Nic_device *add(struct net_device *ndev) {
|
||||
return new (Genode::env()->heap()) Nic_device(ndev); }
|
||||
|
||||
|
||||
/**********************
|
||||
** Device interface **
|
||||
**********************/
|
||||
|
||||
/**
|
||||
* Submit packet to driver
|
||||
*/
|
||||
void tx(Genode::addr_t virt, Genode::size_t size)
|
||||
{
|
||||
sk_buff *skb = _alloc_skb(size + HEAD_ROOM);
|
||||
skb->len = size;
|
||||
skb->data += HEAD_ROOM;
|
||||
Genode::memcpy(skb->data, (void *)virt, skb->len);
|
||||
|
||||
tx_skb(skb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Alloc an SKB
|
||||
*/
|
||||
sk_buff *alloc_skb()
|
||||
{
|
||||
sk_buff *skb = _alloc_skb(18944);
|
||||
skb->len = 0;
|
||||
return skb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit SKB to the driver
|
||||
*/
|
||||
void tx_skb(sk_buff *skb)
|
||||
{
|
||||
struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
|
||||
unsigned long dropped = dev->net->stats.tx_dropped;
|
||||
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
|
||||
|
||||
if (dropped < dev->net->stats.tx_dropped)
|
||||
PWRN("Dropped SKB");
|
||||
}
|
||||
|
||||
/**
|
||||
* Call tx_fixup function of driver
|
||||
*/
|
||||
void tx_fixup(struct sk_buff *skb)
|
||||
{
|
||||
struct usbnet *dev = (usbnet *)netdev_priv(_ndev);
|
||||
if(!_tx_fixup || !_tx_fixup(dev, skb, 0))
|
||||
PERR("Tx fixup error");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fill an SKB with 'data' if 'size', return false if SKB is greater than
|
||||
* 'end'
|
||||
*/
|
||||
bool skb_fill(struct sk_buff *skb, unsigned char *data, Genode::size_t size, unsigned char *end)
|
||||
{
|
||||
Genode::addr_t align = ((Genode::addr_t)(data + 3) & ~3);
|
||||
skb->truesize = skb->data == 0 ? 0 : (unsigned char*)align - data;
|
||||
data = skb->data == 0 ? data : (unsigned char*)align;
|
||||
|
||||
skb->start = data;
|
||||
data += HEAD_ROOM;
|
||||
skb->len = size;
|
||||
skb->data = data;
|
||||
skb->end = skb->tail = data + size;
|
||||
skb->truesize += (skb->end - skb->start);
|
||||
|
||||
|
||||
return skb->end >= end ? false : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit packet for session
|
||||
*/
|
||||
inline void rx(sk_buff *skb) { _session->rx((Genode::addr_t)skb->data, skb->len); }
|
||||
|
||||
/**
|
||||
* Return mac address
|
||||
*/
|
||||
Nic::Mac_address mac_address()
|
||||
{
|
||||
Nic::Mac_address m;
|
||||
Genode::memcpy(&m, _ndev->_dev_addr, ETH_ALEN);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool burst() { return true; }
|
||||
};
|
||||
|
||||
|
||||
/* XXX support multiple devices */
|
||||
static Nic_device *_nic = 0;
|
||||
|
||||
|
||||
void Nic::init(Genode::Signal_receiver *recv) {
|
||||
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/netdevice.h **
|
||||
***********************/
|
||||
|
||||
int register_netdev(struct net_device *ndev)
|
||||
{
|
||||
using namespace Genode;
|
||||
static bool announce = false;
|
||||
|
||||
Nic_device *nic = Nic_device::add(ndev);
|
||||
|
||||
/* XXX: move to 'main' */
|
||||
if (!announce) {
|
||||
static Cap_connection cap_nic;
|
||||
static Rpc_entrypoint ep_nic(&cap_nic, 4096, "usb_nic_ep");
|
||||
static Nic::Root root(&ep_nic, env()->heap(), _signal->receiver(), nic);
|
||||
|
||||
announce = true;
|
||||
|
||||
ndev->state |= START;
|
||||
int err = ndev->netdev_ops->ndo_open(ndev);
|
||||
_nic = nic;
|
||||
env()->parent()->announce(ep_nic.manage(&root));
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
int netif_running(const struct net_device *dev) { return dev->state & START; }
|
||||
int netif_device_present(struct net_device *dev) { return 1; }
|
||||
|
||||
|
||||
int netif_rx(struct sk_buff *skb)
|
||||
{
|
||||
if (_nic && _nic->session()) {
|
||||
_nic->rx(skb);
|
||||
}
|
||||
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** linux/skbuff.h **
|
||||
********************/
|
||||
|
||||
struct sk_buff *_alloc_skb(unsigned int size, bool tx)
|
||||
{
|
||||
sk_buff *skb = tx ? skb_tx()->alloc() : skb_rx()->alloc();
|
||||
|
||||
size = (size + 3) & ~(0x3);
|
||||
|
||||
skb->tail = skb->end = skb->start + size;
|
||||
skb->truesize = size;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
|
||||
{
|
||||
/*
|
||||
* Note: This is only called for RX skb's by the driver
|
||||
*/
|
||||
struct sk_buff *skb = _alloc_skb(size, false);
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
void dev_kfree_skb(struct sk_buff *skb)
|
||||
{
|
||||
dde_kit_log(DEBUG_SKB, "free skb: %p start: %p cloned: %d",
|
||||
skb, skb->start, skb->cloned);
|
||||
|
||||
if (skb->cloned) {
|
||||
skb->start = skb->clone;
|
||||
skb->cloned = false;
|
||||
skb_rx()->free(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
skb_tx()->free(skb);
|
||||
skb_rx()->free(skb);
|
||||
}
|
||||
|
||||
|
||||
void dev_kfree_skb_any(struct sk_buff *skb) { dev_kfree_skb(skb); }
|
||||
|
||||
|
||||
/**
|
||||
* Reserve 'len'
|
||||
*/
|
||||
void skb_reserve(struct sk_buff *skb, int len)
|
||||
{
|
||||
if ((skb->data + len) > skb->end) {
|
||||
PERR("Error resevring SKB data: skb: %p data: %p end: %p len: %d",
|
||||
skb, skb->data, skb->end, skb->len);
|
||||
return;
|
||||
}
|
||||
skb->data += len;
|
||||
dde_kit_log(DEBUG_SKB, "skb: %p slen: %u len: %d", skb, skb->len, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepend 'len'
|
||||
*/
|
||||
unsigned char *skb_push(struct sk_buff *skb, unsigned int len)
|
||||
{
|
||||
if((skb->data - len) < skb->start) {
|
||||
PERR("Error SKB head room too small: %p data: %p start: %p len: %u",
|
||||
skb, skb->data, skb->start, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skb->len += len;
|
||||
skb->data -= len;
|
||||
|
||||
dde_kit_log(DEBUG_SKB, "skb: %p slen: %u len: %u", skb, skb->len, len);
|
||||
return skb->data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append 'len'
|
||||
*/
|
||||
unsigned char *skb_put(struct sk_buff *skb, unsigned int len)
|
||||
{
|
||||
if ((skb->data + len > skb->end)) {
|
||||
PERR("Error increasing SKB length: skb: %p data: %p end: %p len: %u",
|
||||
skb, skb->data, skb->end, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char *old = skb_tail_pointer(skb);
|
||||
skb->len += len;
|
||||
skb->tail += len;
|
||||
dde_kit_log(DEBUG_SKB, "skb: %p slen: %u len: %u", skb, skb->len, len);
|
||||
return old;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return current head room
|
||||
*/
|
||||
unsigned int skb_headroom(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->data - skb->start;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Take 'len' from front
|
||||
*/
|
||||
unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)
|
||||
{
|
||||
if (len > skb->len) {
|
||||
PERR("Error try to pull too much: skb: %p len: %u pull len: %u",
|
||||
skb, skb->len, len);
|
||||
return 0;
|
||||
}
|
||||
skb->len -= len;
|
||||
dde_kit_log(DEBUG_SKB, "skb: %p slen: %u len: %u", skb, skb->len, len);
|
||||
return skb->data += len;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set 'len' and 'tail'
|
||||
*/
|
||||
void skb_trim(struct sk_buff *skb, unsigned int len)
|
||||
{
|
||||
if (skb->len <= len) {
|
||||
PERR("Error trimming to %u bytes skb: %p data: %p start: %p len %u ret: %p",
|
||||
len, skb, skb->data, skb->start, skb->len, __builtin_return_address((0)));
|
||||
return;
|
||||
}
|
||||
|
||||
skb->len = len;
|
||||
skb_set_tail_pointer(skb, len);
|
||||
|
||||
dde_kit_log(DEBUG_SKB, "skb: %p slen: %u len: %u", skb, skb->len, len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clone skb
|
||||
*/
|
||||
struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
|
||||
{
|
||||
sk_buff *c = alloc_skb(0, 0);
|
||||
unsigned char *start = c->start;
|
||||
*c = *skb;
|
||||
|
||||
/* save old start pointer */
|
||||
c->cloned = 1;
|
||||
c->clone = start;
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
void skb_set_tail_pointer(struct sk_buff *skb, const int offset)
|
||||
{
|
||||
skb->tail = skb->data + offset;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *skb_tail_pointer(const struct sk_buff *skb)
|
||||
{
|
||||
return skb->tail;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dummy for shared info
|
||||
*/
|
||||
struct skb_shared_info *skb_shinfo(struct sk_buff * /* skb */)
|
||||
{
|
||||
static skb_shared_info _s = { 0 };
|
||||
return &_s;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init list head
|
||||
*/
|
||||
void skb_queue_head_init(struct sk_buff_head *list)
|
||||
{
|
||||
list->prev = list->next = (sk_buff *)list;
|
||||
list->qlen = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add to tail of queue
|
||||
*/
|
||||
void __skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
|
||||
{
|
||||
newsk->next = (sk_buff *)list;
|
||||
newsk->prev = list->prev;
|
||||
list->prev->next = newsk;
|
||||
list->prev = newsk;
|
||||
list->qlen++;
|
||||
}
|
||||
|
||||
|
||||
void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) {
|
||||
__skb_queue_tail(list, newsk); }
|
||||
|
||||
|
||||
/**
|
||||
* Remove skb from queue
|
||||
*/
|
||||
void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
|
||||
{
|
||||
sk_buff *l = (sk_buff *)list;
|
||||
while (l->next != l) {
|
||||
l = l->next;
|
||||
|
||||
if (l == skb) {
|
||||
l->prev->next = l->next;
|
||||
l->next->prev = l->prev;
|
||||
list->qlen--;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PERR("SKB not found in __skb_unlink");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove from head of queue
|
||||
*/
|
||||
struct sk_buff *skb_dequeue(struct sk_buff_head *list)
|
||||
{
|
||||
if (list->next == (sk_buff *)list)
|
||||
return 0;
|
||||
|
||||
sk_buff *skb = list->next;
|
||||
list->next = skb->next;
|
||||
list->next->prev = (sk_buff *)list;
|
||||
list->qlen--;
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/inerrupt.h **
|
||||
**********************/
|
||||
|
||||
static void snprint_mac(char *buf, char *mac)
|
||||
{
|
||||
for (int i = 0; i < ETH_ALEN; i++)
|
||||
{
|
||||
Genode::snprintf(&buf[i * 3], 3, "%02x", mac[i]);
|
||||
if ((i * 3) < MAC_LEN)
|
||||
buf[(i * 3) + 2] = ':';
|
||||
}
|
||||
|
||||
buf[MAC_LEN] = 0;
|
||||
}
|
||||
|
||||
|
||||
void random_ether_addr(u8 *addr)
|
||||
{
|
||||
using namespace Genode;
|
||||
char str[MAC_LEN + 1];
|
||||
char fallback[] = { 0x2e, 0x60, 0x90, 0x0c, 0x4e, 0x01 };
|
||||
Nic::Mac_address mac;
|
||||
|
||||
/* try using configured mac */
|
||||
try {
|
||||
Xml_node nic_config = config()->xml_node().sub_node("nic");
|
||||
Xml_node::Attribute mac_node = nic_config.attribute("mac");
|
||||
mac_node.value(&mac);
|
||||
} catch (...) {
|
||||
/* use fallback mac */
|
||||
snprint_mac(str, fallback);
|
||||
PWRN("No mac address or wrong format attribute in <nic> - using fallback (%s)",
|
||||
str);
|
||||
|
||||
Genode::memcpy(addr, fallback, ETH_ALEN);
|
||||
return;
|
||||
}
|
||||
|
||||
/* use configured mac*/
|
||||
Genode::memcpy(addr, mac.addr, ETH_ALEN);
|
||||
snprint_mac(str, mac.addr);
|
||||
PINF("Using configured mac: %s", str);
|
||||
}
|
||||
|
320
dde_linux/src/lib/usb/pci_driver.cc
Normal file
320
dde_linux/src/lib/usb/pci_driver.cc
Normal file
@ -0,0 +1,320 @@
|
||||
/*
|
||||
* \brief Emulate 'pci_dev' structure
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-04-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 inludes */
|
||||
#include <pci_session/connection.h>
|
||||
#include <pci_device/client.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include "mem.h"
|
||||
|
||||
struct bus_type pci_bus_type;
|
||||
|
||||
|
||||
/**
|
||||
* Scan PCI bus and probe for HCDs
|
||||
*/
|
||||
class Pci_driver
|
||||
{
|
||||
private:
|
||||
|
||||
pci_driver *_drv; /* Linux PCI driver */
|
||||
Pci::Device_capability _cap; /* PCI cap */
|
||||
pci_device_id const *_id; /* matched id for this driver */
|
||||
|
||||
public:
|
||||
|
||||
pci_dev *_dev; /* Linux PCI device */
|
||||
|
||||
private:
|
||||
|
||||
/* offset used in PCI config space */
|
||||
enum Pci_config { IRQ = 0x3c, REV = 0x8, CMD = 0x4 };
|
||||
|
||||
/**
|
||||
* Fill Linux device informations
|
||||
*/
|
||||
void _setup_pci_device()
|
||||
{
|
||||
using namespace Pci;
|
||||
|
||||
_dev = new (Genode::env()->heap()) pci_dev;
|
||||
Device_client client(_cap);
|
||||
|
||||
_dev->vendor = client.vendor_id();
|
||||
_dev->device = client.device_id();
|
||||
_dev->device_class = client.class_code();
|
||||
_dev->revision = client.config_read(REV, Device::ACCESS_8BIT);
|
||||
_dev->dev.driver = &_drv->driver;
|
||||
|
||||
/* dummy dma mask used to mark device as DMA capable */
|
||||
static u64 dma_mask = ~(u64)0;
|
||||
_dev->dev.dma_mask = &dma_mask;
|
||||
_dev->dev.coherent_dma_mask = ~0;
|
||||
|
||||
/* read interrupt line */
|
||||
_dev->irq = client.config_read(IRQ, Device::ACCESS_8BIT);
|
||||
|
||||
/* hide ourselfs in bus structure */
|
||||
_dev->bus = (struct pci_bus *)this;
|
||||
|
||||
/* setup resources */
|
||||
bool io = false;
|
||||
for (int i = 0; i < Device::NUM_RESOURCES; i++) {
|
||||
Device::Resource res = client.resource(i);
|
||||
_dev->resource[i].start = res.base();
|
||||
_dev->resource[i].end = res.base() + res.size() - 1;
|
||||
_dev->resource[i].flags = res.type() == Device::Resource::IO
|
||||
? IORESOURCE_IO : 0;
|
||||
|
||||
/* request port I/O session */
|
||||
if (res.type() == Device::Resource::IO) {
|
||||
if (dde_kit_request_io(res.base(), res.size()))
|
||||
PERR("Failed to request I/O: [%u,%u)",
|
||||
res.base(), res.base() + res.size());
|
||||
io = true;
|
||||
dde_kit_log(DEBUG_PCI, "I/O [%u-%u)",
|
||||
res.base(), res.base() + res.size());
|
||||
}
|
||||
|
||||
/* request I/O memory (write combined) */
|
||||
if (res.type() == Device::Resource::MEMORY)
|
||||
dde_kit_log(DEBUG_PCI, "I/O memory [%x-%x)", res.base(),
|
||||
res.base() + res.size());
|
||||
}
|
||||
|
||||
/* enable bus master and io bits */
|
||||
uint16_t cmd = client.config_read(CMD, Device::ACCESS_16BIT);
|
||||
cmd |= io ? 0x1 : 0;
|
||||
|
||||
/* enable bus master */
|
||||
cmd |= 0x4;
|
||||
client.config_write(CMD, cmd, Device::ACCESS_16BIT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe device with driver
|
||||
*/
|
||||
bool _probe()
|
||||
{
|
||||
_setup_pci_device();
|
||||
|
||||
if (!_drv->probe(_dev, _id))
|
||||
return true;
|
||||
|
||||
PERR("Probe failed\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Pci::Device::Access_size _access_size(T t)
|
||||
{
|
||||
switch (sizeof(T))
|
||||
{
|
||||
case 1:
|
||||
return Pci::Device::ACCESS_8BIT;
|
||||
case 2:
|
||||
return Pci::Device::ACCESS_16BIT;
|
||||
default:
|
||||
return Pci::Device::ACCESS_32BIT;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Pci_driver(pci_driver *drv, Pci::Device_capability cap,
|
||||
pci_device_id const * id)
|
||||
: _drv(drv), _cap(cap), _id(id), _dev(0)
|
||||
{
|
||||
if (!_probe())
|
||||
throw -1;
|
||||
}
|
||||
|
||||
~Pci_driver()
|
||||
{
|
||||
if (!_dev)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < Pci::Device::NUM_RESOURCES; i++) {
|
||||
resource *r = &_dev->resource[i];
|
||||
|
||||
if (r->flags & IORESOURCE_IO)
|
||||
dde_kit_release_io(r->start, (r->end - r->start) + 1);
|
||||
}
|
||||
|
||||
destroy(Genode::env()->heap(), _dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read/write data from/to config space
|
||||
*/
|
||||
template <typename T>
|
||||
void config_read(unsigned int devfn, T *val)
|
||||
{
|
||||
Pci::Device_client client(_cap);
|
||||
*val = client.config_read(devfn, _access_size(*val));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void config_write(unsigned int devfn, T val)
|
||||
{
|
||||
Pci::Device_client client(_cap);
|
||||
client.config_write(devfn, val, _access_size(val));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*********************
|
||||
** Linux interface **
|
||||
*********************/
|
||||
|
||||
static Pci::Device_capability pci_device_cap;
|
||||
static Pci::Connection pci;
|
||||
|
||||
int pci_register_driver(struct pci_driver *drv)
|
||||
{
|
||||
dde_kit_log(DEBUG_PCI, "DRIVER name: %s", drv->name);
|
||||
drv->driver.name = drv->name;
|
||||
|
||||
pci_device_id const *id = drv->id_table;
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
bool found = false;
|
||||
|
||||
while (id->vendor || id->subvendor || id->class_mask) {
|
||||
|
||||
Pci::Device_capability cap = pci.first_device(id->device_class,
|
||||
id->class_mask);
|
||||
Pci::Device_capability old;
|
||||
while (cap.valid()) {
|
||||
|
||||
uint8_t bus, dev, func;
|
||||
Pci::Device_client client(cap);
|
||||
client.bus_address(&bus, &dev, &func);
|
||||
dde_kit_log(DEBUG_PCI, "bus: %x dev: %x func: %x", bus, dev, func);
|
||||
|
||||
Pci_driver *pci_drv = 0;
|
||||
try {
|
||||
/*
|
||||
* Assign cap already here, since for probing already DMA
|
||||
* buffer is required and allocated by
|
||||
* Genode::Mem::alloc_dma_buffer(size_t size)
|
||||
*/
|
||||
pci_device_cap = cap;
|
||||
|
||||
/* probe device */
|
||||
pci_drv = new (env()->heap()) Pci_driver(drv, cap, id);
|
||||
pci.on_destruction(Pci::Connection::KEEP_OPEN);
|
||||
found = true;
|
||||
|
||||
/* trigger that the device get be assigned to the usb driver */
|
||||
pci.config_extended(cap);
|
||||
} catch (...) {
|
||||
destroy(env()->heap(), pci_drv);
|
||||
pci_drv = 0;
|
||||
}
|
||||
|
||||
old = cap;
|
||||
cap = pci.next_device(cap, id->device_class, id->class_mask);
|
||||
pci.release_device(old);
|
||||
}
|
||||
id++;
|
||||
}
|
||||
|
||||
return found ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
|
||||
size_t pci_resource_start(struct pci_dev *dev, unsigned bar)
|
||||
{
|
||||
if (bar >= DEVICE_COUNT_RESOURCE)
|
||||
return 0;
|
||||
|
||||
return dev->resource[bar].start;
|
||||
}
|
||||
|
||||
|
||||
size_t pci_resource_len(struct pci_dev *dev, unsigned bar)
|
||||
{
|
||||
size_t start = pci_resource_start(dev, bar);
|
||||
|
||||
if (!start)
|
||||
return 0;
|
||||
|
||||
return (dev->resource[bar].end - start) + 1;
|
||||
}
|
||||
|
||||
|
||||
unsigned int pci_resource_flags(struct pci_dev *dev, unsigned bar)
|
||||
{
|
||||
if (bar >= DEVICE_COUNT_RESOURCE)
|
||||
return 0;
|
||||
|
||||
return dev->resource[bar].flags;
|
||||
}
|
||||
|
||||
|
||||
int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int, int where, u8 *val)
|
||||
{
|
||||
Pci_driver *drv = (Pci_driver *)bus;
|
||||
drv->config_read(where, val);
|
||||
dde_kit_log(DEBUG_PCI, "READ %p: where: %x val: %x", drv, where, *val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pci_bus_read_config_word(struct pci_bus *bus, unsigned int, int where, u16 *val)
|
||||
{
|
||||
Pci_driver *drv = (Pci_driver *)bus;
|
||||
drv->config_read(where, val);
|
||||
dde_kit_log(DEBUG_PCI, "READ %p: where: %x val: %x", drv, where, *val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pci_bus_write_config_word(struct pci_bus *bus, unsigned int, int where, u16 val)
|
||||
{
|
||||
Pci_driver *drv = (Pci_driver *)bus;
|
||||
dde_kit_log(DEBUG_PCI, "WRITE %p: where: %x val: %x", drv, where, val);
|
||||
drv->config_write(where, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int, int where, u8 val)
|
||||
{
|
||||
Pci_driver *drv = (Pci_driver *)bus;
|
||||
dde_kit_log(DEBUG_PCI, "WRITE %p: where: %x val: %x", drv, where, val);
|
||||
drv->config_write(where, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char *pci_name(const struct pci_dev *pdev)
|
||||
{
|
||||
/* simply return driver name */
|
||||
return "dummy";
|
||||
}
|
||||
|
||||
Genode::Ram_dataspace_capability Genode::Mem::alloc_dma_buffer(size_t size)
|
||||
{
|
||||
using namespace Genode;
|
||||
Ram_dataspace_capability ram_cap = pci.alloc_dma_buffer(pci_device_cap,
|
||||
size);
|
||||
return ram_cap;
|
||||
}
|
240
dde_linux/src/lib/usb/signal/event.cc
Normal file
240
dde_linux/src/lib/usb/signal/event.cc
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* \brief Signal context for completions and events
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <signal.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
/**
|
||||
* Context for events
|
||||
*/
|
||||
class Event_context : public Driver_context
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Signal_context_capability _ctx_cap;
|
||||
|
||||
Event_context()
|
||||
: _ctx_cap(_signal->receiver()->manage(this)) {
|
||||
_signal->sender()->context(_ctx_cap); }
|
||||
|
||||
public:
|
||||
|
||||
static Event_context *e()
|
||||
{
|
||||
static Event_context _e;
|
||||
return &_e;
|
||||
}
|
||||
|
||||
void submit() {
|
||||
_signal->sender()->submit(); }
|
||||
|
||||
void handle() {
|
||||
Routine::schedule_all(); }
|
||||
|
||||
char const *debug() { return "Event_context"; }
|
||||
};
|
||||
|
||||
|
||||
void Event::init(Genode::Signal_receiver *recv) {
|
||||
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||
|
||||
|
||||
/**
|
||||
* Delayed work
|
||||
*/
|
||||
class Work : public Genode::List<Work>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
void *_work;
|
||||
bool _delayed;
|
||||
|
||||
static Genode::List<Work> *_list()
|
||||
{
|
||||
static Genode::List<Work> _l;
|
||||
return &_l;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Work(void *work, bool delayed) : _work(work), _delayed(delayed) { }
|
||||
|
||||
static void schedule(void *work, bool delayed)
|
||||
{
|
||||
Work *w = new (Genode::env()->heap()) Work(work, delayed);
|
||||
_list()->insert(w);
|
||||
}
|
||||
|
||||
static void exec()
|
||||
{
|
||||
while (_list()->first()) {
|
||||
Work *w = _list()->first();
|
||||
_list()->remove(w);
|
||||
|
||||
if (w->_delayed) {
|
||||
delayed_work *work = static_cast<delayed_work *>(w->_work);
|
||||
work->work.func(&(work)->work);
|
||||
}
|
||||
else {
|
||||
work_struct *work = static_cast<work_struct *>(w->_work);
|
||||
work->func(work);
|
||||
}
|
||||
destroy(Genode::env()->heap(), w);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************
|
||||
** linux/completion.h **
|
||||
************************/
|
||||
|
||||
void __wake_up() { Routine::schedule_all(); }
|
||||
|
||||
|
||||
void __wait_event()
|
||||
{
|
||||
/* schedule work first */
|
||||
Work::exec();
|
||||
|
||||
/* schedule other routines or wait for signals */
|
||||
Service_handler::s()->process();
|
||||
}
|
||||
|
||||
|
||||
void init_completion(struct completion *work)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "New completion %p", work);
|
||||
work->done = 0;
|
||||
}
|
||||
|
||||
|
||||
void complete(struct completion *work)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p", work);
|
||||
work->done = 1;
|
||||
|
||||
/* send signal */
|
||||
Event_context::e()->submit();
|
||||
}
|
||||
|
||||
|
||||
void complete_and_exit(struct completion *work, long code)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p", work);
|
||||
complete(work);
|
||||
Routine::remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __wait_completion(struct completion *work)
|
||||
{
|
||||
while (!work->done)
|
||||
__wait_event();
|
||||
|
||||
work->done = 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned long
|
||||
__wait_completion_timeout(struct completion *work, unsigned long timeout)
|
||||
{
|
||||
unsigned long _j = jiffies + (timeout / HZ);
|
||||
while (!work->done) {
|
||||
__wait_event();
|
||||
|
||||
if (_j >= jiffies)
|
||||
return 0;
|
||||
}
|
||||
|
||||
work->done = 0;
|
||||
|
||||
return _j - jiffies;
|
||||
}
|
||||
|
||||
|
||||
unsigned long wait_for_completion_timeout(struct completion *work,
|
||||
unsigned long timeout)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done);
|
||||
__wait_completion(work);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int wait_for_completion_interruptible(struct completion *work)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done);
|
||||
|
||||
__wait_completion(work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
long wait_for_completion_interruptible_timeout(struct completion *work,
|
||||
unsigned long timeout)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done);
|
||||
__wait_completion(work);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void wait_for_completion(struct completion *work)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%p state: %u", work, work->done);
|
||||
__wait_completion(work);
|
||||
}
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/timer.h **
|
||||
*******************/
|
||||
|
||||
signed long schedule_timeout_uninterruptible(signed long timeout)
|
||||
{
|
||||
dde_kit_log(DEBUG_COMPLETION, "%ld\n", timeout);
|
||||
__wait_event();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wake_up_process(struct task_struct *tsk)
|
||||
{
|
||||
Routine::schedule_all();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/workquque.h **
|
||||
***********************/
|
||||
|
||||
int schedule_delayed_work(struct delayed_work *work, unsigned long delay)
|
||||
{
|
||||
Work::schedule((void *)work, true);
|
||||
//work->work.func(&(work)->work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int schedule_work(struct work_struct *work)
|
||||
{
|
||||
Work::schedule((void *)work, false);
|
||||
return 1;
|
||||
}
|
214
dde_linux/src/lib/usb/signal/irq.cc
Normal file
214
dde_linux/src/lib/usb/signal/irq.cc
Normal file
@ -0,0 +1,214 @@
|
||||
/*
|
||||
* \brief Signal context for IRQ's
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <signal.h>
|
||||
#include <lx_emul.h>
|
||||
|
||||
extern "C" {
|
||||
#include <dde_kit/interrupt.h>
|
||||
}
|
||||
|
||||
/* our local incarnation of sender and receiver */
|
||||
static Signal_helper *_signal = 0;
|
||||
static Genode::Lock _irq_sync(Genode::Lock::LOCKED);
|
||||
static Genode::Lock _irq_wait(Genode::Lock::LOCKED);
|
||||
|
||||
|
||||
/**
|
||||
* This contains the Linux-driver handlers
|
||||
*/
|
||||
struct Irq_handler : Genode::List<Irq_handler>::Element
|
||||
{
|
||||
void *dev; /* Linux device */
|
||||
irq_handler_t handler; /* Linux handler */
|
||||
|
||||
Irq_handler(void *dev, irq_handler_t handler)
|
||||
: dev(dev), handler(handler) { }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Signal context for IRQs
|
||||
*/
|
||||
class Irq_context : public Driver_context,
|
||||
public Genode::List<Irq_context>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
typedef Genode::List<Irq_context>::Element LE;
|
||||
|
||||
unsigned int _irq; /* IRQ number */
|
||||
Genode::List<Irq_handler> _handler_list; /* List of registered handlers */
|
||||
Genode::Signal_context_capability _ctx_cap; /* capability for this context */
|
||||
|
||||
static Genode::List<Irq_context> *_list()
|
||||
{
|
||||
static Genode::List<Irq_context> _l;
|
||||
return &_l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find context for given IRQ number
|
||||
*/
|
||||
static Irq_context *_find_ctx(unsigned int irq)
|
||||
{
|
||||
|
||||
for (Irq_context *i = _list()->first(); i; i = i->LE::next())
|
||||
if (i->_irq == irq)
|
||||
return i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called by the DDE kit upon IRQ */
|
||||
static void _dde_handler(void *irq)
|
||||
{
|
||||
/*
|
||||
* Make sure there is only one interrupt handled at a time, since dde_kit
|
||||
* will use one thread per IRQ
|
||||
*/
|
||||
static Genode::Lock handler_lock;
|
||||
Genode::Lock::Guard guard(handler_lock);
|
||||
|
||||
/* unlock if main thread is waiting */
|
||||
_irq_wait.unlock();
|
||||
|
||||
Irq_context *ctx = static_cast<Irq_context *>(irq);
|
||||
|
||||
/* set context & submit signal */
|
||||
_signal->sender()->context(ctx->_ctx_cap);
|
||||
_signal->sender()->submit();
|
||||
|
||||
/* wait for interrupt to get acked at device side */
|
||||
_irq_sync.lock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Call one IRQ handler
|
||||
*/
|
||||
inline bool _handle_one(Irq_handler *h)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
/*
|
||||
* It might be that the next interrupt triggers right after the device has
|
||||
* acknowledged the IRQ
|
||||
*/
|
||||
do {
|
||||
if (h->handler(_irq, h->dev) != IRQ_HANDLED)
|
||||
return handled;
|
||||
|
||||
handled = true;
|
||||
|
||||
} while (true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call all handlers registered for this context
|
||||
*/
|
||||
bool _handle()
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
/* report IRQ to all clients */
|
||||
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
|
||||
|
||||
handled |= _handle_one(h);
|
||||
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u h: %p dev: %p", _irq, handled, h->handler, h->dev);
|
||||
}
|
||||
|
||||
/* interrupt should be acked at device now */
|
||||
_irq_sync.unlock();
|
||||
|
||||
if (handled)
|
||||
Routine::schedule_all();
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Irq_context(unsigned int irq)
|
||||
: _irq(irq),
|
||||
_ctx_cap(_signal->receiver()->manage(this))
|
||||
{
|
||||
/* register at DDE (shared) */
|
||||
int ret = dde_kit_interrupt_attach(_irq, 0, 0, _dde_handler, this);
|
||||
if (ret)
|
||||
PERR("Interrupt attach return %d for IRQ %u", ret, irq);
|
||||
|
||||
dde_kit_interrupt_enable(_irq);
|
||||
_list()->insert(this);
|
||||
}
|
||||
|
||||
|
||||
inline void handle() { _handle(); }
|
||||
const char *debug() { return "Irq_context"; }
|
||||
|
||||
/**
|
||||
* Request an IRQ
|
||||
*/
|
||||
static void request_irq(unsigned int irq, irq_handler_t handler, void *dev)
|
||||
{
|
||||
Irq_handler *h = new(Genode::env()->heap()) Irq_handler(dev, handler);
|
||||
Irq_context *ctx = _find_ctx(irq);
|
||||
|
||||
/* if this IRQ is not registered */
|
||||
if (!ctx)
|
||||
ctx = new (Genode::env()->heap()) Irq_context(irq);
|
||||
|
||||
/* register Linux handler */
|
||||
ctx->_handler_list.insert(h);
|
||||
}
|
||||
|
||||
static bool check_irq()
|
||||
{
|
||||
bool handled = false;
|
||||
for (Irq_context *i = _list()->first(); i; i = i->LE::next())
|
||||
handled |= i->_handle();
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
static void wait()
|
||||
{
|
||||
_irq_wait.lock();
|
||||
check_irq();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Irq::init(Genode::Signal_receiver *recv) {
|
||||
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||
|
||||
|
||||
void Irq::check_irq()
|
||||
{
|
||||
if (!Irq_context::check_irq())
|
||||
Irq_context::wait();
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/interrupt.h **
|
||||
***********************/
|
||||
|
||||
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,
|
||||
const char *name, void *dev)
|
||||
{
|
||||
dde_kit_log(DEBUG_IRQ, "Request irq %u handler %p", irq, handler);
|
||||
Irq_context::request_irq(irq, handler, dev);
|
||||
return 0;
|
||||
}
|
||||
|
151
dde_linux/src/lib/usb/signal/timer.cc
Normal file
151
dde_linux/src/lib/usb/signal/timer.cc
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* \brief Signal context for timer events
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-23
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <base/env.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include "signal.h"
|
||||
|
||||
static void handler(void *timer);
|
||||
|
||||
|
||||
/* our local incarnation of sender and receiver */
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Signal context for time-outs
|
||||
*/
|
||||
class Timer_context : public Driver_context
|
||||
{
|
||||
private:
|
||||
|
||||
timer_list *_timer; /* Linux timer */
|
||||
dde_kit_timer *_dde_timer; /* DDE kit timer */
|
||||
Genode::Signal_context_capability _ctx_cap; /* Signal-context cap
|
||||
for this timer */
|
||||
|
||||
public:
|
||||
|
||||
Timer_context(timer_list *timer)
|
||||
: _timer(timer), _dde_timer(0),
|
||||
_ctx_cap(_signal->receiver()->manage(this)) { }
|
||||
|
||||
~Timer_context()
|
||||
{
|
||||
_signal->receiver()->dissolve(this);
|
||||
}
|
||||
|
||||
/* call timer function */
|
||||
void handle() { _timer->function(_timer->data); }
|
||||
|
||||
/* schedule next timeout */
|
||||
void schedule(unsigned long expires)
|
||||
{
|
||||
if (!_dde_timer)
|
||||
_dde_timer = dde_kit_timer_add(handler, this, expires);
|
||||
else
|
||||
dde_kit_timer_schedule_absolute(_dde_timer, expires);
|
||||
}
|
||||
|
||||
char const *debug() { return "Timer_context"; }
|
||||
/**
|
||||
* Return true if timer is pending
|
||||
*/
|
||||
bool pending() const
|
||||
{
|
||||
return _dde_timer ? dde_kit_timer_pending(_dde_timer) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return internal signal cap
|
||||
*/
|
||||
Genode::Signal_context_capability cap() const { return _ctx_cap; }
|
||||
|
||||
/**
|
||||
* Convert 'timer_list' to 'Timer_conext'
|
||||
*/
|
||||
static Timer_context *to_ctx(timer_list const *timer) {
|
||||
return static_cast<Timer_context *>(timer->timer); }
|
||||
|
||||
void remove()
|
||||
{
|
||||
if (_dde_timer)
|
||||
dde_kit_timer_del(_dde_timer);
|
||||
|
||||
_dde_timer = 0;
|
||||
}
|
||||
|
||||
timer_list *l() { return _timer; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* C handler for DDE timer interface
|
||||
*/
|
||||
static void handler(void *timer)
|
||||
{
|
||||
Timer_context *t = static_cast<Timer_context *>(timer);
|
||||
|
||||
/* set context and submit */
|
||||
_signal->sender()->context(t->cap());
|
||||
_signal->sender()->submit();
|
||||
}
|
||||
|
||||
|
||||
void Timer::init(Genode::Signal_receiver *recv) {
|
||||
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/timer.h **
|
||||
*******************/
|
||||
|
||||
void init_timer(struct timer_list *timer) {
|
||||
timer->timer = (void *) new (Genode::env()->heap()) Timer_context(timer); }
|
||||
|
||||
|
||||
int mod_timer(struct timer_list *timer, unsigned long expires)
|
||||
{
|
||||
dde_kit_log(DEBUG_TIMER, "Timer: %p j: %lu ex: %lu func %p",
|
||||
timer, jiffies, expires, timer->function);
|
||||
Timer_context::to_ctx(timer)->schedule(expires);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void setup_timer(struct timer_list *timer,void (*function)(unsigned long),
|
||||
unsigned long data)
|
||||
{
|
||||
timer->function = function;
|
||||
timer->data = data;
|
||||
init_timer(timer);
|
||||
}
|
||||
|
||||
|
||||
int timer_pending(const struct timer_list * timer)
|
||||
{
|
||||
bool pending = Timer_context::to_ctx(timer)->pending();
|
||||
dde_kit_log(DEBUG_TIMER, "Pending %p %u", timer, pending);
|
||||
return pending;
|
||||
}
|
||||
|
||||
|
||||
int del_timer(struct timer_list *timer)
|
||||
{
|
||||
dde_kit_log(DEBUG_TIMER, "Delete timer %p", timer);
|
||||
Timer_context::to_ctx(timer)->remove();
|
||||
return 0;
|
||||
}
|
||||
|
225
dde_linux/src/lib/usb/storage/scsi.c
Normal file
225
dde_linux/src/lib/usb/storage/scsi.c
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* \brief SCSI support emulation
|
||||
* \author Christian Helmuth
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2009-10-29
|
||||
*
|
||||
* XXX NOTES XXX
|
||||
*
|
||||
* struct scsi_host_template
|
||||
*
|
||||
* struct scsi_host
|
||||
*
|
||||
* host_lock used by scsi_unlock, scsi_lock
|
||||
* max_id used by usb_stor_report_device_reset
|
||||
*
|
||||
* struct scsi_cmnd
|
||||
*
|
||||
* functions
|
||||
*
|
||||
* scsi_add_host
|
||||
* scsi_host_alloc
|
||||
* scsi_host_get
|
||||
* scsi_host_put
|
||||
* scsi_remove_host
|
||||
* scsi_report_bus_reset
|
||||
* scsi_report_device_reset
|
||||
* scsi_scan_host
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2009-2013 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 <lx_emul.h>
|
||||
|
||||
#include <storage/scsi.h>
|
||||
|
||||
#define DEBUG_SCSI 0
|
||||
|
||||
/***************
|
||||
** SCSI host **
|
||||
***************/
|
||||
|
||||
struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *t, int priv_size)
|
||||
{
|
||||
dde_kit_log(DEBUG_SCSI, "t=%p, priv_size=%d", t, priv_size);
|
||||
|
||||
static int free = 1;
|
||||
|
||||
/* XXX we not some extra space for hostdata[] */
|
||||
static char buffer[4096] __attribute__((aligned(4096)));
|
||||
static struct Scsi_Host *host = (struct Scsi_Host *)buffer;
|
||||
|
||||
/* FIXME we support only one host for now */
|
||||
if (!free) return 0;
|
||||
free = 0;
|
||||
|
||||
host->host_lock = &host->default_lock;
|
||||
spin_lock_init(host->host_lock);
|
||||
|
||||
host->host_no = 13;
|
||||
host->max_id = 8;
|
||||
host->hostt = t;
|
||||
|
||||
// rval = scsi_setup_command_freelist(shost);
|
||||
// if (rval)
|
||||
// goto fail_kfree;
|
||||
|
||||
// shost->ehandler = kthread_run(scsi_error_handler, shost,
|
||||
// "scsi_eh_%d", shost->host_no);
|
||||
// if (IS_ERR(shost->ehandler)) {
|
||||
// rval = PTR_ERR(shost->ehandler);
|
||||
// goto fail_destroy_freelist;
|
||||
// }
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
static struct page *_page(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
return (struct page *)cmnd->sdb.table.sgl->page_link;
|
||||
}
|
||||
|
||||
|
||||
void scsi_alloc_buffer(size_t size, struct scsi_cmnd *cmnd)
|
||||
{
|
||||
scsi_setup_buffer(cmnd, size, 0, 0);
|
||||
struct scatterlist *sgl = cmnd->sdb.table.sgl;
|
||||
struct page *page = _page(cmnd);
|
||||
page->virt = kmalloc(size, GFP_NOIO);
|
||||
page->phys = dma_map_single_attrs(0, page->virt, 0, 0, 0);
|
||||
sgl->dma_address = page->phys;
|
||||
}
|
||||
|
||||
|
||||
void scsi_setup_buffer(struct scsi_cmnd *cmnd, size_t size, void *virt, dma_addr_t addr)
|
||||
{
|
||||
cmnd->sdb.table.nents = 1;
|
||||
cmnd->sdb.length = size;
|
||||
|
||||
struct scatterlist *sgl = cmnd->sdb.table.sgl;
|
||||
|
||||
struct page *page = _page(cmnd);
|
||||
page->virt = virt;
|
||||
page->phys = addr;
|
||||
|
||||
sgl->page_link = (unsigned long)page;
|
||||
sgl->offset = 0;
|
||||
sgl->length = size;
|
||||
sgl->dma_address = addr;
|
||||
sgl->last = 1;
|
||||
}
|
||||
|
||||
|
||||
void scsi_free_buffer(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
struct page *page = _page(cmnd);
|
||||
if (page)
|
||||
kfree(page->virt);
|
||||
}
|
||||
|
||||
|
||||
void *scsi_buffer_data(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
return _page(cmnd)->virt;
|
||||
}
|
||||
|
||||
|
||||
struct scsi_cmnd *_scsi_alloc_command()
|
||||
{
|
||||
struct scsi_cmnd *cmnd = (struct scsi_cmnd *)kmalloc(sizeof(struct scsi_cmnd), GFP_KERNEL);
|
||||
cmnd->sdb.table.sgl = (struct scatterlist *)kmalloc(sizeof(struct scatterlist), GFP_KERNEL);
|
||||
cmnd->cmnd = kzalloc(MAX_COMMAND_SIZE, 0);
|
||||
cmnd->sdb.table.sgl->page_link = (unsigned long) kzalloc(sizeof(struct page), 0);
|
||||
return cmnd;
|
||||
}
|
||||
|
||||
|
||||
void _scsi_free_command(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
kfree((void *)cmnd->sdb.table.sgl->page_link);
|
||||
kfree(cmnd->sdb.table.sgl);
|
||||
kfree(cmnd->cmnd);
|
||||
kfree(cmnd);
|
||||
}
|
||||
|
||||
|
||||
static void inquiry_done(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
char *data = (char *)scsi_buffer_data(cmnd);
|
||||
dde_kit_printf("Vendor id: %c%c%c%c%c%c%c%c Product id: %s\n",
|
||||
data[8], data[9], data[10], data[11], data[12],
|
||||
data[13], data[14], data[15], &data[16]);
|
||||
complete(cmnd->back);
|
||||
}
|
||||
|
||||
|
||||
static void scsi_done(struct scsi_cmnd *cmd)
|
||||
{
|
||||
complete(cmd->back);
|
||||
}
|
||||
|
||||
|
||||
void scsi_scan_host(struct Scsi_Host *host)
|
||||
{
|
||||
struct scsi_cmnd *cmnd;
|
||||
struct scsi_device *sdev;
|
||||
struct scsi_target *target;
|
||||
struct completion compl;
|
||||
void *result;
|
||||
|
||||
init_completion(&compl);
|
||||
|
||||
sdev = (struct scsi_device *)kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
|
||||
target = (struct scsi_target *)kmalloc(sizeof(struct scsi_target), GFP_KERNEL);
|
||||
|
||||
cmnd = _scsi_alloc_command();
|
||||
|
||||
/* init device */
|
||||
sdev->sdev_target = target;
|
||||
sdev->host = host;
|
||||
sdev->id = 0;
|
||||
sdev->lun = 0;
|
||||
host->hostt->slave_alloc(sdev);
|
||||
host->hostt->slave_configure(sdev);
|
||||
|
||||
/* inquiry (36 bytes for usb) */
|
||||
scsi_alloc_buffer(sdev->inquiry_len, cmnd);
|
||||
cmnd->cmnd[0] = INQUIRY;
|
||||
cmnd->cmnd[4] = sdev->inquiry_len;
|
||||
cmnd->device = sdev;
|
||||
cmnd->cmd_len = 6;
|
||||
cmnd->sc_data_direction = DMA_FROM_DEVICE;
|
||||
|
||||
cmnd->back = &compl;
|
||||
cmnd->scsi_done = inquiry_done;
|
||||
|
||||
host->hostt->queuecommand(host, cmnd);
|
||||
wait_for_completion(&compl);
|
||||
|
||||
/* if PQ and PDT are zero we have a direct access block device conntected */
|
||||
result = scsi_buffer_data(cmnd);
|
||||
if (!((char*)result)[0])
|
||||
scsi_add_device(sdev);
|
||||
else {
|
||||
kfree(sdev);
|
||||
kfree(target);
|
||||
}
|
||||
|
||||
scsi_free_buffer(cmnd);
|
||||
_scsi_free_command(cmnd);
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
** scsi/scsi_cmnd.h **
|
||||
**********************/
|
||||
|
||||
unsigned scsi_bufflen(struct scsi_cmnd *cmnd) { return cmnd->sdb.length; }
|
||||
struct scatterlist *scsi_sglist(struct scsi_cmnd *cmnd) { return cmnd->sdb.table.sgl; }
|
||||
unsigned scsi_sg_count(struct scsi_cmnd *cmnd) { return cmnd->sdb.table.nents; }
|
177
dde_linux/src/lib/usb/storage/storage.cc
Normal file
177
dde_linux/src/lib/usb/storage/storage.cc
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* \brief USB storage glue
|
||||
* \author Sebastian Sumpf <sebastian.sumpf@genode-labs.com>
|
||||
* \date 2012-05-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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 <base/rpc_server.h>
|
||||
#include <block_session/block_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
#include <util/endian.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include <storage/component.h>
|
||||
#include <storage/scsi.h>
|
||||
#include "signal.h"
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
class Storage_device : public Genode::List<Storage_device>::Element,
|
||||
public Block::Device
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::size_t _block_size;
|
||||
Block::sector_t _block_count;
|
||||
struct scsi_device *_sdev;
|
||||
|
||||
static void _sync_done(struct scsi_cmnd *cmnd) {
|
||||
complete((struct completion *)cmnd->back); }
|
||||
|
||||
static void _async_done(struct scsi_cmnd *cmnd)
|
||||
{
|
||||
Block::Session_component *session = static_cast<Block::Session_component *>(cmnd->session);
|
||||
Block::Packet_descriptor *packet = static_cast<Block::Packet_descriptor *>(cmnd->packet);
|
||||
|
||||
if (verbose)
|
||||
PDBG("ACK packet for block: %zu status: %d", packet->block_number(), cmnd->result);
|
||||
|
||||
session->complete(*packet, true);
|
||||
_scsi_free_command(cmnd);
|
||||
}
|
||||
|
||||
void _capacity()
|
||||
{
|
||||
struct completion comp;
|
||||
|
||||
struct scsi_cmnd *cmnd = _scsi_alloc_command();
|
||||
|
||||
/* alloc data for command */
|
||||
scsi_alloc_buffer(8, cmnd);
|
||||
|
||||
cmnd->cmnd[0] = READ_CAPACITY;
|
||||
cmnd->cmd_len = 10;
|
||||
cmnd->device = _sdev;
|
||||
cmnd->sc_data_direction = DMA_FROM_DEVICE;
|
||||
|
||||
init_completion(&comp);
|
||||
cmnd->back = ∁
|
||||
cmnd->scsi_done = _sync_done;
|
||||
|
||||
_sdev->host->hostt->queuecommand(_sdev->host, cmnd);
|
||||
wait_for_completion(&comp);
|
||||
|
||||
Genode::uint32_t *data = (Genode::uint32_t *)scsi_buffer_data(cmnd);
|
||||
_block_count = bswap(data[0]);
|
||||
_block_size = bswap(data[1]);
|
||||
|
||||
/* if device returns the highest block number */
|
||||
if (!_sdev->fix_capacity)
|
||||
_block_count++;
|
||||
|
||||
if (verbose)
|
||||
PDBG("block size: %zu block count: %llu", _block_size, _block_count);
|
||||
|
||||
scsi_free_buffer(cmnd);
|
||||
_scsi_free_command(cmnd);
|
||||
}
|
||||
|
||||
|
||||
Storage_device(struct scsi_device *sdev) : _sdev(sdev)
|
||||
{
|
||||
/* read device capacity */
|
||||
_capacity();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static Storage_device *add(struct scsi_device *sdev) {
|
||||
return new (Genode::env()->heap()) Storage_device(sdev); }
|
||||
|
||||
Genode::size_t block_size() { return _block_size; }
|
||||
Genode::size_t block_count() { return _block_count; }
|
||||
|
||||
void io(Block::Session_component *session, Block::Packet_descriptor &packet,
|
||||
Genode::addr_t virt, Genode::addr_t phys)
|
||||
{
|
||||
Block::sector_t block_nr = packet.block_number();
|
||||
Genode::uint16_t block_count = packet.block_count() & 0xffff;
|
||||
bool read = packet.operation() == Block::Packet_descriptor::WRITE ? false : true;
|
||||
|
||||
if (block_nr > _block_count)
|
||||
throw -1;
|
||||
|
||||
if (verbose)
|
||||
PDBG("PACKET: phys: %lx block: %llu count: %u %s",
|
||||
phys, block_nr, block_count, read ? "read" : "write");
|
||||
|
||||
struct scsi_cmnd *cmnd = _scsi_alloc_command();
|
||||
|
||||
cmnd->cmnd[0] = read ? READ_10 : WRITE_10;
|
||||
cmnd->cmd_len = 10;
|
||||
cmnd->device = _sdev;
|
||||
cmnd->sc_data_direction = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
||||
cmnd->scsi_done = _async_done;
|
||||
|
||||
Block::Packet_descriptor *p = new (Genode::env()->heap()) Block::Packet_descriptor();
|
||||
*p = packet;
|
||||
cmnd->packet = (void *)p;
|
||||
cmnd->session = (void *)session;
|
||||
|
||||
Genode::uint32_t be_block_nr = bswap<Genode::uint32_t>(block_nr);
|
||||
memcpy(&cmnd->cmnd[2], &be_block_nr, 4);
|
||||
|
||||
/* transfer one block */
|
||||
Genode::uint16_t be_block_count = bswap(block_count);
|
||||
memcpy(&cmnd->cmnd[7], &be_block_count, 2);
|
||||
|
||||
/* setup command */
|
||||
scsi_setup_buffer(cmnd, block_count * _block_size, (void *)virt, phys);
|
||||
|
||||
/*
|
||||
* Required by 'last_sector_hacks' in 'drivers/usb/storage/transprot.c
|
||||
*/
|
||||
struct request req;
|
||||
req.rq_disk = 0;
|
||||
cmnd->request = &req;
|
||||
|
||||
/* send command to host driver */
|
||||
if (_sdev->host->hostt->queuecommand(_sdev->host, cmnd)) {
|
||||
throw -2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Storage::init(Genode::Signal_receiver *recv) {
|
||||
_signal = new (Genode::env()->heap()) Signal_helper(recv); }
|
||||
|
||||
|
||||
void scsi_add_device(struct scsi_device *sdev)
|
||||
{
|
||||
using namespace Genode;
|
||||
static bool announce = false;
|
||||
|
||||
Storage_device *device = Storage_device::add(sdev);
|
||||
|
||||
/*
|
||||
* XXX move to 'main'
|
||||
*/
|
||||
if (!announce) {
|
||||
static Cap_connection cap_stor;
|
||||
static Rpc_entrypoint ep_stor(&cap_stor, 4096, "usb_stor_ep");
|
||||
static Block::Root root(&ep_stor, env()->heap(), _signal->receiver(), device);
|
||||
env()->parent()->announce(ep_stor.manage(&root));
|
||||
announce = true;
|
||||
}
|
||||
}
|
||||
|
44
dde_linux/src/lib/usb/test.cc
Normal file
44
dde_linux/src/lib/usb/test.cc
Normal file
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* \brief Test functions
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-08-02
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012-2013 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.
|
||||
*/
|
||||
|
||||
#if 0
|
||||
|
||||
void tx_test() {
|
||||
char *data = (char *)skb->data;
|
||||
if (data[0x2a] == (char)0xaa && data[0x2b] == (char)0xbb) {
|
||||
PDBG("Got server signal");
|
||||
static char data[1066];
|
||||
static char header[] = {
|
||||
0x00, 0x1c, 0x25, 0x9e, 0x92, 0x4a, 0x2e, 0x60, 0x90, 0x0c, 0x4e, 0x01, 0x08, 0x00, 0x45, 0x00,
|
||||
0x04, 0x1c, 0x00, 0x00, 0x40, 0x00, 0x40, 0x11, 0x22, 0x88, 0x0a, 0x00, 0x00, 0x3b, 0x0a, 0x00,
|
||||
0x00, 0x0f, 0x89, 0xc5, 0x04, 0xd2, 0x04, 0x08, 0x54, 0xfd};
|
||||
Genode::memset(data, 0, 1065);
|
||||
memcpy(data, header, sizeof(header));
|
||||
while (1) {
|
||||
sk_buff *skb = alloc_skb(1066 + HEAD_ROOM, 0);
|
||||
if (!skb) {
|
||||
Service_handler::s()->check_signal(true);
|
||||
continue;
|
||||
}
|
||||
skb->len = 1066;
|
||||
skb->data += HEAD_ROOM;
|
||||
|
||||
memcpy(skb->data, data, 1066);
|
||||
|
||||
_nic->_ndev->netdev_ops->ndo_start_xmit(skb, _nic->_ndev);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user