mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-21 03:55:04 +00:00
USB: Support usbnet and smsc95xx for omap4
This commit is contained in:
parent
b2a62b4b2d
commit
70b8fc2832
@ -56,13 +56,11 @@ CONTENT_INPUT := input.c evdev.c input-compat.h
|
||||
CONTENT += $(addprefix drivers/input/,$(CONTENT_INPUT))
|
||||
CONTENT += include/linux/input/mt.h
|
||||
|
||||
# Panda board usb network driver
|
||||
CONTENT_NET = usbnet.c smsc95xx.c smsc95xx.h
|
||||
CONTENT += $(addprefix drivers/net/usb/,$(CONTENT_NET))
|
||||
CONTENT += include/linux/usb/usbnet.h
|
||||
|
||||
# Panda board
|
||||
#CONTENT += drivers/mfd/omap-usb-host.c
|
||||
#CONTENT += arch/arm/plat-omap/include/plat/usb.h
|
||||
#CONTENT_ARCH = usb-host.c mux.h mux2420.h mux2430.h mux34xx.h mux44xx.h
|
||||
#CONTENT += $(addprefix arch/arm/mach-omap2/,$(CONTENT_ARCH))
|
||||
#CONTRIB_CONTENT := $(addprefix $(CONTRIB_DIR)/,$(CONTENT))
|
||||
#
|
||||
#
|
||||
# Utility to check if a tool is installed
|
||||
|
@ -22,7 +22,7 @@ Note: It has been observed that certain 1.0 versions of Qemu do not generate
|
||||
mouse interrupts. The mouse driver should work correctly on Qemu 1.0.93 and
|
||||
above.
|
||||
|
||||
STORAGE
|
||||
Storage
|
||||
~~~~~~~
|
||||
|
||||
Currently supports one USB storage device. Hot plugging has not been tested. A
|
||||
@ -35,3 +35,31 @@ Configuration snippet:
|
||||
! <provides> <service name="Block"/> </provides>
|
||||
! <config><storage /></config>
|
||||
!</start>
|
||||
|
||||
|
||||
Network (Nic)
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Supported on PandaBoard only using the 'smsc95xx' driver.
|
||||
|
||||
Configuration snippet:
|
||||
|
||||
!<start name="usb_drv">
|
||||
! <resource name="RAM" quantum="3M"/>
|
||||
! <provides>
|
||||
! <service name="Nic"/>
|
||||
! <service name="Input"/>
|
||||
! </provides>
|
||||
! <config>
|
||||
! <nic mac="2e:60:90:0c:4e:01" />
|
||||
! <hid/>
|
||||
! </config>
|
||||
!</start>
|
||||
|
||||
Please observe that this setup starts the HID and Nic service at the same time.
|
||||
Also there is the 'mac' attribute where one can specify the hardware address of
|
||||
the network interface. This is necessary in case the EEPROM of the network card
|
||||
cannot be accessed via the host controller making it impossible to retrieve the
|
||||
devices hardware address. If this is the case and no 'mac' attribute is given a
|
||||
fallback address will be assigned to the network device. Note that the fallback
|
||||
address will always be the same.
|
||||
|
17
dde_linux/patches/csum.patch
Normal file
17
dde_linux/patches/csum.patch
Normal file
@ -0,0 +1,17 @@
|
||||
diff -r 4d66ab105ff0 drivers/net/usb/smsc95xx.c
|
||||
--- a/drivers/net/usb/smsc95xx.c Fri Jul 06 17:50:36 2012 +0200
|
||||
+++ b/drivers/net/usb/smsc95xx.c Fri Jul 06 17:55:13 2012 +0200
|
||||
@@ -1032,7 +1032,12 @@
|
||||
|
||||
static void smsc95xx_rx_csum_offload(struct sk_buff *skb)
|
||||
{
|
||||
- skb->csum = *(u16 *)(skb_tail_pointer(skb) - 2);
|
||||
+ /*
|
||||
+ * Use bytewise access to avoid alignment issues on packets that have none
|
||||
+ * aligned sizes
|
||||
+ */
|
||||
+ char *tail = skb_tail_pointer(skb);
|
||||
+ skb->csum = (*(tail - 2) << 8) | *(tail - 1);
|
||||
skb->ip_summed = CHECKSUM_COMPLETE;
|
||||
skb_trim(skb, skb->len - 2);
|
||||
}
|
80
dde_linux/run/usb_net.run
Normal file
80
dde_linux/run/usb_net.run
Normal file
@ -0,0 +1,80 @@
|
||||
#
|
||||
# \brief Test for using the lwIP TCP/IP stack over USB
|
||||
# \author Sebastian Sumpf
|
||||
# \date 2012-07-06
|
||||
#
|
||||
# This test case executes a small HTTP server, it has been used on PandaBoard
|
||||
# hardware only, though it should execute but not do anything on other hardware
|
||||
#
|
||||
|
||||
#
|
||||
# Build
|
||||
#
|
||||
|
||||
build {
|
||||
core init
|
||||
drivers/pci drivers/timer drivers/usb
|
||||
test/lwip/http_srv
|
||||
}
|
||||
|
||||
create_boot_directory
|
||||
|
||||
#
|
||||
# Generate config
|
||||
#
|
||||
|
||||
set config {
|
||||
<config verbose="yes">
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
<service name="RAM"/>
|
||||
<service name="IRQ"/>
|
||||
<service name="IO_MEM"/>
|
||||
<service name="IO_PORT"/>
|
||||
<service name="CAP"/>
|
||||
<service name="PD"/>
|
||||
<service name="RM"/>
|
||||
<service name="CPU"/>
|
||||
<service name="LOG"/>
|
||||
<service name="SIGNAL"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> <any-child/> </any-service>
|
||||
</default-route>
|
||||
<start name="timer">
|
||||
<resource name="RAM" quantum="512K"/>
|
||||
<provides> <service name="Timer"/> </provides>
|
||||
</start>
|
||||
<start name="usb_drv">
|
||||
<resource name="RAM" quantum="3M"/>
|
||||
<provides>
|
||||
<service name="Nic"/>
|
||||
<service name="Input"/>
|
||||
</provides>
|
||||
<config>
|
||||
<nic mac="2e:60:90:0c:4e:01" />
|
||||
<hid/>
|
||||
</config>
|
||||
</start>
|
||||
<start name="test-lwip_httpsrv">
|
||||
<resource name="RAM" quantum="2M"/>
|
||||
</start>
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
#
|
||||
# Boot modules
|
||||
#
|
||||
|
||||
# generic modules
|
||||
set boot_modules {
|
||||
core init timer
|
||||
usb_drv
|
||||
ld.lib.so libc.lib.so libc_log.lib.so lwip.lib.so test-lwip_httpsrv
|
||||
}
|
||||
|
||||
build_boot_image $boot_modules
|
||||
|
||||
# vi: set ft=tcl :
|
@ -61,7 +61,6 @@ static struct ehci_hcd_omap_platform_data _ehci_data
|
||||
};
|
||||
|
||||
|
||||
extern "C" void module_ehci_hcd_init();
|
||||
|
||||
|
||||
/**
|
||||
@ -370,9 +369,22 @@ static void omap_ehci_init()
|
||||
}
|
||||
|
||||
|
||||
void platform_hcd_init(void)
|
||||
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 */
|
||||
|
@ -18,6 +18,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
static inline
|
||||
void platform_execute(void *sp, void *func, void *arg)
|
||||
{
|
||||
@ -28,9 +30,6 @@ void platform_execute(void *sp, void *func, void *arg)
|
||||
: : "r"(sp), "r"(func), "r"(arg) : "r0");
|
||||
}
|
||||
|
||||
|
||||
void platform_hcd_init(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -197,7 +197,6 @@ void mdelay(unsigned long msecs) { TRACE; }
|
||||
|
||||
bool cancel_work_sync(struct work_struct *work) { TRACE; return 0; }
|
||||
int cancel_delayed_work_sync(struct delayed_work *work) { TRACE; return 0; }
|
||||
int schedule_work(struct work_struct *work) { TRACE; return 0; }
|
||||
bool flush_work_sync(struct work_struct *work) { TRACE; return 0; }
|
||||
|
||||
|
||||
@ -236,6 +235,7 @@ 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;
|
||||
|
||||
@ -793,3 +793,90 @@ struct regulator *regulator_get(struct device *dev, const char *id) { TRACE; ret
|
||||
|
||||
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; }
|
||||
|
||||
void dev_kfree_skb_any(struct sk_buff *skb) { TRACE; }
|
||||
|
||||
|
||||
/*********************
|
||||
** 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; }
|
||||
|
||||
|
||||
|
@ -77,13 +77,15 @@ void mutex_unlock(struct mutex *m) { if (m->lock) dde_kit_lock_unlock( m->lock);
|
||||
|
||||
void *kmalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
return dde_kit_large_malloc(size);
|
||||
/* align at least four byte alignment */
|
||||
void *addr = Genode::Dma::pool()->alloc(size, 2);
|
||||
return addr;
|
||||
}
|
||||
|
||||
|
||||
void *kzalloc(size_t size, gfp_t flags)
|
||||
{
|
||||
void *addr = dde_kit_large_malloc(size);
|
||||
void *addr = kmalloc(size, flags);
|
||||
if (addr)
|
||||
Genode::memset(addr, 0, size);
|
||||
return addr;
|
||||
@ -100,7 +102,8 @@ void *kcalloc(size_t n, size_t size, gfp_t flags)
|
||||
|
||||
void kfree(const void *p)
|
||||
{
|
||||
dde_kit_large_free((void *)p);
|
||||
//dde_kit_large_free((void *)p);
|
||||
Genode::Dma::pool()->free((void *)p);
|
||||
}
|
||||
|
||||
|
||||
@ -396,6 +399,13 @@ class Driver : public Genode::List<Driver>::Element
|
||||
*/
|
||||
bool match(struct device *dev)
|
||||
{
|
||||
/*
|
||||
* Don't try if buses don't match, since drivers often use 'container_of'
|
||||
* which might cast the device to non-matching type
|
||||
*/
|
||||
if (_drv->bus != dev->bus)
|
||||
return false;
|
||||
|
||||
bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
|
||||
dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p",
|
||||
_drv->name, ret, _drv->bus->match);
|
||||
@ -594,7 +604,7 @@ void dma_pool_destroy(struct dma_pool *d)
|
||||
|
||||
static void* _alloc(size_t size, int align, dma_addr_t *dma)
|
||||
{
|
||||
void *addr = Genode::Dma::pool()->alloc(size, align);
|
||||
void *addr = Genode::Dma::pool()->alloc(size, align < 2 ? 2 : align);
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
@ -609,8 +619,6 @@ static void* _alloc(size_t size, int align, dma_addr_t *dma)
|
||||
void *dma_pool_alloc(struct dma_pool *d, gfp_t f, dma_addr_t *dma)
|
||||
{
|
||||
return _alloc(d->size, d->align, dma);
|
||||
// return _alloc(0x1000, 12, dma);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -646,7 +654,7 @@ dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr,
|
||||
enum dma_data_direction dir,
|
||||
struct dma_attrs *attrs)
|
||||
{
|
||||
dma_addr_t phys = (dma_addr_t)dde_kit_pgtab_get_physaddr(ptr);
|
||||
dma_addr_t phys = (dma_addr_t)Genode::Dma::pool()->phys_addr(ptr);
|
||||
dde_kit_log(DEBUG_DMA, "virt: %p phys: %lx", ptr, phys);
|
||||
return phys;
|
||||
}
|
||||
@ -666,17 +674,6 @@ int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg,
|
||||
struct dma_attrs *attrs) { return nents; }
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/workquque.h **
|
||||
***********************/
|
||||
|
||||
int schedule_delayed_work(struct delayed_work *work, unsigned long delay)
|
||||
{
|
||||
work->work.func(&(work)->work);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/kthread.h **
|
||||
*********************/
|
||||
@ -743,3 +740,115 @@ resource_size_t resource_size(const struct resource *res)
|
||||
{
|
||||
return res->end - res->start + 1;
|
||||
}
|
||||
|
||||
|
||||
/****************
|
||||
** Networking **
|
||||
****************/
|
||||
|
||||
|
||||
/*************************
|
||||
** linux/etherdevice.h **
|
||||
*************************/
|
||||
|
||||
struct net_device *alloc_etherdev(int sizeof_priv)
|
||||
{
|
||||
net_device *dev = (net_device *)kzalloc(sizeof(net_device), 0);
|
||||
|
||||
dev->mtu = 1500;
|
||||
dev->hard_header_len = 0;
|
||||
dev->priv = kzalloc(sizeof_priv, 0);
|
||||
dev->dev_addr = dev->_dev_addr;
|
||||
memset(dev->_dev_addr, 0, sizeof(dev->_dev_addr));
|
||||
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
int is_valid_ether_addr(const u8 *addr)
|
||||
{
|
||||
/* is multicast */
|
||||
if (!(addr[0] & 0x1))
|
||||
return 0;
|
||||
|
||||
/* zero */
|
||||
if (!(addr[0] | addr[1] | addr[2] | addr[3] | addr[4] | addr[5]))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/mii.h **
|
||||
*****************/
|
||||
|
||||
|
||||
/**
|
||||
* Restart NWay (autonegotiation) for this interface
|
||||
*/
|
||||
int mii_nway_restart (struct mii_if_info *mii)
|
||||
{
|
||||
int bmcr;
|
||||
int r = -EINVAL;
|
||||
enum {
|
||||
BMCR_ANENABLE = 0x1000, /* enable auto negotiation */
|
||||
BMCR_ANRESTART = 0x200, /* auto negotation restart */
|
||||
};
|
||||
|
||||
/* if autoneg is off, it's an error */
|
||||
bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
|
||||
|
||||
if (bmcr & BMCR_ANENABLE) {
|
||||
printk("Reanable\n");
|
||||
bmcr |= BMCR_ANRESTART;
|
||||
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
|
||||
r = 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
|
||||
{
|
||||
ecmd->duplex = DUPLEX_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv)
|
||||
{
|
||||
u8 cap = 0;
|
||||
|
||||
if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) {
|
||||
cap = FLOW_CTRL_TX | FLOW_CTRL_RX;
|
||||
} else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) {
|
||||
if (lcladv & ADVERTISE_PAUSE_CAP)
|
||||
cap = FLOW_CTRL_RX;
|
||||
else if (rmtadv & ADVERTISE_PAUSE_CAP)
|
||||
cap = FLOW_CTRL_TX;
|
||||
}
|
||||
|
||||
return cap;
|
||||
}
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/netdevice.h **
|
||||
***********************/
|
||||
|
||||
void *netdev_priv(const struct net_device *dev)
|
||||
{
|
||||
return dev->priv;
|
||||
}
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/inerrupt.h **
|
||||
**********************/
|
||||
|
||||
void tasklet_schedule(struct tasklet_struct *t)
|
||||
{
|
||||
t->func(t->data);
|
||||
}
|
||||
|
@ -39,10 +39,11 @@ extern "C" {
|
||||
#if VERBOSE_LX_EMUL
|
||||
#define DEBUG_COMPLETION 0
|
||||
#define DEBUG_DMA 0
|
||||
#define DEBUG_DRIVER 0
|
||||
#define DEBUG_DRIVER 1
|
||||
#define DEBUG_IRQ 0
|
||||
#define DEBUG_KREF 0
|
||||
#define DEBUG_PCI 0
|
||||
#define DEBUG_SKB 0
|
||||
#define DEBUG_SLAB 0
|
||||
#define DEBUG_TIMER 0
|
||||
#define DEBUG_THREAD 0
|
||||
@ -52,8 +53,9 @@ extern "C" {
|
||||
#define DEBUG_DMA 0
|
||||
#define DEBUG_IRQ 0
|
||||
#define DEBUG_KREF 0
|
||||
#define DEBUG_SLAB 0
|
||||
#define DEBUG_PCI 0
|
||||
#define DEBUG_SKB 0
|
||||
#define DEBUG_SLAB 0
|
||||
#define DEBUG_TIMER 0
|
||||
#define DEBUG_THREAD 0
|
||||
#endif
|
||||
@ -136,6 +138,7 @@ typedef dde_kit_int64_t int64_t;
|
||||
typedef dde_kit_uint64_t uint64_t;
|
||||
|
||||
typedef uint32_t uint;
|
||||
typedef unsigned long ulong;
|
||||
|
||||
typedef int8_t s8;
|
||||
typedef uint8_t u8;
|
||||
@ -162,6 +165,9 @@ typedef __u16 __be16;
|
||||
typedef __u32 __be32;
|
||||
typedef __u64 __be64;
|
||||
|
||||
typedef __u16 __sum16;
|
||||
typedef __u32 __wsum;
|
||||
|
||||
typedef u64 sector_t;
|
||||
|
||||
struct list_head {
|
||||
@ -229,6 +235,7 @@ typedef unsigned short mode_t;
|
||||
#define rmb() mb()
|
||||
#define wmb() asm volatile ("": : :"memory")
|
||||
#define smp_wmb() wmb()
|
||||
#define smp_mb() mb()
|
||||
|
||||
static inline void barrier() { mb(); }
|
||||
|
||||
@ -417,6 +424,8 @@ enum {
|
||||
ETIME = 46,
|
||||
EALREADY = 47,
|
||||
EOPNOTSUPP = 48,
|
||||
EDOM = 49,
|
||||
ENOLINK = 50,
|
||||
};
|
||||
|
||||
static inline bool IS_ERR(void *ptr) {
|
||||
@ -505,6 +514,8 @@ static inline size_t min(size_t a, size_t b) {
|
||||
|
||||
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||
|
||||
#define BUILD_BUG_ON(condition)
|
||||
|
||||
void might_sleep();
|
||||
|
||||
#define INT_MAX ((int)(~0U>>1))
|
||||
@ -627,6 +638,7 @@ void *memscan(void *addr, int c, size_t size);
|
||||
char *strcat(char *dest, const char *src);
|
||||
int strcmp(const char *s1, const char *s2);
|
||||
int strncmp(const char *cs, const char *ct, size_t count);
|
||||
char *strcpy(char *to, const char *from);
|
||||
char *strncpy(char *, const char *, size_t);
|
||||
char *strchr(const char *, int);
|
||||
char *strrchr(const char *,int);
|
||||
@ -931,6 +943,8 @@ typedef struct wait_queue { int dummy; } wait_queue_t;
|
||||
#define DECLARE_WAIT_QUEUE_HEAD(name) \
|
||||
wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name)
|
||||
|
||||
#define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name)
|
||||
|
||||
void __wake_up();
|
||||
void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
|
||||
void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait);
|
||||
@ -1005,7 +1019,7 @@ void do_gettimeofday(struct timeval *tv);
|
||||
** linux/sched.h **
|
||||
*******************/
|
||||
|
||||
enum { TASK_RUNNING = 0, TASK_INTERRUPTIBLE = 1, TASK_NORMAL = 3 };
|
||||
enum { TASK_RUNNING = 0, TASK_INTERRUPTIBLE = 1, TASK_UNINTERRUPTIBLE = 2, TASK_NORMAL = 3 };
|
||||
|
||||
enum { MAX_SCHEDULE_TIMEOUT = (~0U >> 1) };
|
||||
|
||||
@ -1027,6 +1041,7 @@ void __set_current_state(int state);
|
||||
#define set_current_state(state) __set_current_state(state)
|
||||
int signal_pending(struct task_struct *p);
|
||||
void schedule(void);
|
||||
signed long schedule_timeout(signed long);
|
||||
signed long schedule_timeout_uninterruptible(signed long timeout);
|
||||
void yield(void);
|
||||
int wake_up_process(struct task_struct *tsk);
|
||||
@ -1200,6 +1215,7 @@ typedef struct pm_message { int event; } pm_message_t;
|
||||
|
||||
struct dev_pm_info { bool is_prepared; };
|
||||
|
||||
#define PMSG_IS_AUTO(msg) 0
|
||||
|
||||
/************************
|
||||
** linux/pm_runtime.h **
|
||||
@ -2595,6 +2611,396 @@ struct scsi_driver
|
||||
};
|
||||
|
||||
|
||||
/************************
|
||||
** Networking support **
|
||||
************************/
|
||||
|
||||
|
||||
/********************
|
||||
** linux/skbuff.h **
|
||||
********************/
|
||||
|
||||
enum {
|
||||
NET_IP_ALIGN = 2,
|
||||
CHECKSUM_COMPLETE = 2,
|
||||
CHECKSUM_PARTIAL = 3,
|
||||
};
|
||||
|
||||
struct skb_shared_info
|
||||
{
|
||||
unsigned short nr_frags;
|
||||
};
|
||||
|
||||
struct sk_buff
|
||||
{
|
||||
struct sk_buff *next;
|
||||
struct sk_buff *prev;
|
||||
|
||||
/*
|
||||
* This is the control buffer. It is free to use for every
|
||||
* layer. Please put your private variables there. If you
|
||||
* want to keep them across layers you have to do a skb_clone()
|
||||
* first. This is owned by whoever has the skb queued ATM.
|
||||
*/
|
||||
char cb[48] __attribute__((aligned(8)));
|
||||
|
||||
unsigned int len;
|
||||
union
|
||||
{
|
||||
__wsum csum;
|
||||
struct
|
||||
{
|
||||
u16 csum_start;
|
||||
u16 csum_offset;
|
||||
};
|
||||
};
|
||||
u8 local_df:1,
|
||||
cloned:1,
|
||||
ip_summed:2,
|
||||
nohdr:1,
|
||||
nfctinfo:3;
|
||||
__be16 protocol;
|
||||
unsigned char *start;
|
||||
unsigned char *end;
|
||||
unsigned char *data;
|
||||
unsigned char *tail;
|
||||
unsigned int truesize;
|
||||
};
|
||||
|
||||
struct sk_buff_head
|
||||
{
|
||||
struct sk_buff *next;
|
||||
struct sk_buff *prev;
|
||||
u32 qlen;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
#define skb_queue_walk_safe(queue, skb, tmp) \
|
||||
for (skb = (queue)->next, tmp = skb->next; \
|
||||
skb != (struct sk_buff *)(queue); \
|
||||
skb = tmp, tmp = skb->next)
|
||||
|
||||
struct skb_shared_info *skb_shinfo(struct sk_buff *);
|
||||
|
||||
struct sk_buff *alloc_skb(unsigned int, gfp_t);
|
||||
unsigned char *skb_push(struct sk_buff *, unsigned int);
|
||||
unsigned char *skb_pull(struct sk_buff *, unsigned int);
|
||||
unsigned char *skb_put(struct sk_buff *, unsigned int);
|
||||
unsigned char *__skb_put(struct sk_buff *, unsigned int);
|
||||
void skb_trim(struct sk_buff *, unsigned int);
|
||||
unsigned int skb_headroom(const struct sk_buff *);
|
||||
int skb_checksum_start_offset(const struct sk_buff *);
|
||||
struct sk_buff *skb_copy_expand(const struct sk_buff *, int, int, gfp_t);
|
||||
unsigned char *skb_tail_pointer(const struct sk_buff *);
|
||||
int skb_tailroom(const struct sk_buff *);
|
||||
void skb_set_tail_pointer(struct sk_buff *, const int);
|
||||
struct sk_buff *skb_clone(struct sk_buff *, gfp_t);
|
||||
void skb_reserve(struct sk_buff *, int);
|
||||
|
||||
struct sk_buff *skb_dequeue(struct sk_buff_head *);
|
||||
void skb_queue_head_init(struct sk_buff_head *);
|
||||
void skb_queue_tail(struct sk_buff_head *, struct sk_buff *);
|
||||
void __skb_queue_tail(struct sk_buff_head *, struct sk_buff *);
|
||||
int skb_queue_empty(const struct sk_buff_head *);
|
||||
void skb_queue_purge(struct sk_buff_head *);
|
||||
void __skb_unlink(struct sk_buff *, struct sk_buff_head *);
|
||||
|
||||
void skb_tx_timestamp(struct sk_buff *);
|
||||
bool skb_defer_rx_timestamp(struct sk_buff *);
|
||||
|
||||
void dev_kfree_skb(struct sk_buff *);
|
||||
void dev_kfree_skb_any(struct sk_buff *);
|
||||
|
||||
|
||||
/****************
|
||||
** linux/if.h **
|
||||
****************/
|
||||
|
||||
enum {
|
||||
IFF_PROMISC = 0x100, /* receive all packets */
|
||||
IFF_ALLMULTI = 0x200, /* receive all multicast packets */
|
||||
IFF_MULTICAST = 0x1000, /* supports multicast */
|
||||
IFNAMSIZ = 16,
|
||||
};
|
||||
|
||||
struct ifreq { };
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/if_ether.h **
|
||||
**********************/
|
||||
|
||||
enum {
|
||||
ETH_ALEN = 6, /* octets in one ethernet addr */
|
||||
ETH_P_8021Q = 0x8100, /* 802.1Q VLAN Extended Header */
|
||||
|
||||
ETH_FRAME_LEN = 1514,
|
||||
};
|
||||
|
||||
|
||||
/*********************
|
||||
** linux/ethtool.h **
|
||||
*********************/
|
||||
|
||||
enum {
|
||||
DUPLEX_FULL = 0x1,
|
||||
ETHTOOL_GSET = 0x1,
|
||||
ETHTOOL_FWVERS_LEN = 32,
|
||||
ETHTOOL_BUSINFO_LEN = 32,
|
||||
};
|
||||
|
||||
|
||||
struct ethtool_cmd
|
||||
{
|
||||
u32 cmd;
|
||||
u8 duplex;
|
||||
};
|
||||
|
||||
struct ethtool_eeprom
|
||||
{
|
||||
u32 magic;
|
||||
u32 offset;
|
||||
u32 len;
|
||||
};
|
||||
|
||||
struct ethtool_drvinfo
|
||||
{
|
||||
char driver[32]; /* driver short name, "tulip", "eepro100" */
|
||||
char version[32]; /* driver version string */
|
||||
char fw_version[ETHTOOL_FWVERS_LEN]; /* firmware version string */
|
||||
char bus_info[ETHTOOL_BUSINFO_LEN]; /* Bus info for this IF. */
|
||||
/* For PCI devices, use pci_name(pci_dev). */
|
||||
};
|
||||
|
||||
struct ethhdr { };
|
||||
|
||||
struct net_device;
|
||||
|
||||
struct ethtool_ops
|
||||
{
|
||||
int (*get_settings)(struct net_device *, struct ethtool_cmd *);
|
||||
int (*set_settings)(struct net_device *, struct ethtool_cmd *);
|
||||
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
|
||||
int (*nway_reset)(struct net_device *);
|
||||
u32 (*get_link)(struct net_device *);
|
||||
int (*get_eeprom_len)(struct net_device *);
|
||||
int (*get_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
|
||||
int (*set_eeprom)(struct net_device *, struct ethtool_eeprom *, u8 *);
|
||||
u32 (*get_msglevel)(struct net_device *);
|
||||
void (*set_msglevel)(struct net_device *, u32);
|
||||
};
|
||||
|
||||
__u32 ethtool_cmd_speed(const struct ethtool_cmd *ep);
|
||||
u32 ethtool_op_get_link(struct net_device *);
|
||||
|
||||
|
||||
/***********************
|
||||
** linux/netdevice.h **
|
||||
***********************/
|
||||
|
||||
#define netif_err(priv, type, dev, fmt, args...) dde_kit_printf("netif_err: " fmt, ## args);
|
||||
#define netif_info(priv, type, dev, fmt, args...) dde_kit_printf("netif_info: " fmt, ## args);
|
||||
|
||||
#define netdev_err(dev, fmt, args...) dde_kit_printf("nedev_err: " fmt, ##args)
|
||||
#define netdev_warn(dev, fmt, args...) dde_kit_printf("nedev_warn: " fmt, ##args)
|
||||
#define netdev_info(dev, fmt, args...) dde_kit_printf("nedev_info: " fmt, ##args)
|
||||
|
||||
#define netdev_for_each_mc_addr(a, b) if (0)
|
||||
|
||||
#if VERBOSE_LX_EMUL
|
||||
#define netif_dbg(priv, type, dev, fmt, args...) dde_kit_printf("netif_dbg: " fmt, ## args)
|
||||
#define netdev_dbg(dev, fmt, args...) dde_kit_printf("nedev_dbg: " fmt, ##args)
|
||||
#else
|
||||
#define netif_dbg(priv, type, dev, fmt, args...)
|
||||
#define netdev_dbg(dev, fmt, args...)
|
||||
#endif
|
||||
|
||||
#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev))
|
||||
#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype))
|
||||
|
||||
enum netdev_tx { NETDEV_TX_OK = 0 };
|
||||
typedef enum netdev_tx netdev_tx_t;
|
||||
|
||||
enum {
|
||||
MAX_ADDR_LEN = 32,
|
||||
|
||||
NETIF_F_HW_CSUM = 8,
|
||||
NETIF_F_RXCSUM = (1 << 29),
|
||||
|
||||
NET_RX_SUCCESS = 0,
|
||||
|
||||
NETIF_MSG_DRV = 0x1,
|
||||
NETIF_MSG_PROBE = 0x2,
|
||||
NETIF_MSG_LINK = 0x4,
|
||||
};
|
||||
|
||||
struct net_device_ops
|
||||
{
|
||||
int (*ndo_open)(struct net_device *dev);
|
||||
int (*ndo_stop)(struct net_device *dev);
|
||||
netdev_tx_t (*ndo_start_xmit) (struct sk_buff *skb, struct net_device *dev);
|
||||
void (*ndo_set_rx_mode)(struct net_device *dev);
|
||||
int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
|
||||
int (*ndo_validate_addr)(struct net_device *dev);
|
||||
int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
void (*ndo_tx_timeout) (struct net_device *dev);
|
||||
int (*ndo_change_mtu)(struct net_device *dev, int new_mtu);
|
||||
int (*ndo_set_features)(struct net_device *dev, u32 features);
|
||||
};
|
||||
|
||||
struct net_device_stats
|
||||
{
|
||||
unsigned long rx_packets;
|
||||
unsigned long tx_packets;
|
||||
unsigned long rx_bytes;
|
||||
unsigned long tx_bytes;
|
||||
unsigned long rx_errors;
|
||||
unsigned long tx_errors;
|
||||
unsigned long rx_dropped;
|
||||
unsigned long tx_dropped;
|
||||
unsigned long rx_length_errors;
|
||||
unsigned long rx_over_errors;
|
||||
unsigned long rx_crc_errors;
|
||||
unsigned long rx_frame_errors;
|
||||
};
|
||||
|
||||
/* NET_DEVICE */
|
||||
struct net_device
|
||||
{
|
||||
char name[IFNAMSIZ];
|
||||
u32 features;
|
||||
u32 hw_features;
|
||||
|
||||
struct net_device_stats stats;
|
||||
const struct net_device_ops *netdev_ops;
|
||||
const struct ethtool_ops *ethtool_ops;
|
||||
|
||||
unsigned long state;
|
||||
|
||||
unsigned int flags;
|
||||
unsigned short hard_header_len; /* hardware hdr length */
|
||||
unsigned int mtu;
|
||||
unsigned char *dev_addr;
|
||||
unsigned char _dev_addr[ETH_ALEN];
|
||||
unsigned long trans_start; /* Time (in jiffies) of last Tx */
|
||||
int watchdog_timeo; /* used by dev_watchdog() */
|
||||
struct device dev;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
|
||||
struct netdev_hw_addr
|
||||
{
|
||||
unsigned char addr[MAX_ADDR_LEN];
|
||||
};
|
||||
|
||||
#define netif_msg_tx_err(p) ({ printk("netif_msg_tx_err called not implemented\n"); 0; })
|
||||
#define netif_msg_rx_err(p) ({ printk("netif_msg_rx_err called not implemented\n"); 0; })
|
||||
#define netif_msg_tx_queued(p) ({ printk("netif_msg_tx_queued called not implemented\n"); 0; })
|
||||
|
||||
u32 netif_msg_init(int, int);
|
||||
|
||||
void *netdev_priv(const struct net_device *);
|
||||
int netif_running(const struct net_device *);
|
||||
int netif_device_present(struct net_device *);
|
||||
void netif_device_detach(struct net_device *);
|
||||
void netif_start_queue(struct net_device *);
|
||||
void netif_stop_queue(struct net_device *);
|
||||
void netif_wake_queue(struct net_device *);
|
||||
void netif_device_attach(struct net_device *);
|
||||
void unregister_netdev(struct net_device *);
|
||||
void free_netdev(struct net_device *);
|
||||
int netif_rx(struct sk_buff *);
|
||||
void netif_carrier_off(struct net_device *);
|
||||
|
||||
int netdev_mc_empty(struct net_device *);
|
||||
int register_netdev(struct net_device *);
|
||||
|
||||
/*****************
|
||||
** linux/mii.h **
|
||||
*****************/
|
||||
|
||||
enum {
|
||||
FLOW_CTRL_TX = 0x1,
|
||||
FLOW_CTRL_RX = 0x2,
|
||||
|
||||
MII_BMCR = 0x0,
|
||||
MII_ADVERTISE = 0x4,
|
||||
MII_LPA = 0x5,
|
||||
|
||||
BMCR_RESET = 0x8000, /* reset to default state */
|
||||
|
||||
ADVERTISE_PAUSE_CAP = 0x0400, /* try for pause */
|
||||
ADVERTISE_CSMA = 0x0001, /* only selector supported */
|
||||
ADVERTISE_PAUSE_ASYM = 0x0800, /* try for asymetric pause */
|
||||
ADVERTISE_10HALF = 0x0020,
|
||||
ADVERTISE_10FULL = 0x0040,
|
||||
ADVERTISE_100HALF = 0x0080,
|
||||
ADVERTISE_100FULL = 0x0100,
|
||||
ADVERTISE_ALL = ADVERTISE_10HALF | ADVERTISE_10FULL |
|
||||
ADVERTISE_100HALF | ADVERTISE_100FULL
|
||||
};
|
||||
|
||||
struct mii_if_info
|
||||
{
|
||||
int phy_id;
|
||||
int phy_id_mask;
|
||||
int reg_num_mask;
|
||||
struct net_device *dev;
|
||||
int (*mdio_read) (struct net_device *dev, int phy_id, int location);
|
||||
void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val);
|
||||
};
|
||||
|
||||
|
||||
unsigned int mii_check_media (struct mii_if_info *, unsigned int,
|
||||
unsigned int);
|
||||
int mii_ethtool_gset(struct mii_if_info *, struct ethtool_cmd *);
|
||||
int mii_ethtool_sset(struct mii_if_info *, struct ethtool_cmd *);
|
||||
u8 mii_resolve_flowctrl_fdx(u16, u16);
|
||||
int mii_nway_restart (struct mii_if_info *);
|
||||
int mii_link_ok (struct mii_if_info *);
|
||||
|
||||
struct mii_ioctl_data { };
|
||||
int generic_mii_ioctl(struct mii_if_info *,
|
||||
struct mii_ioctl_data *, int,
|
||||
unsigned int *);
|
||||
struct mii_ioctl_data *if_mii(struct ifreq *);
|
||||
|
||||
|
||||
/**********************
|
||||
** linux/inerrupt.h **
|
||||
**********************/
|
||||
|
||||
struct tasklet_struct
|
||||
{
|
||||
void (*func)(unsigned long);
|
||||
unsigned long data;
|
||||
};
|
||||
|
||||
void tasklet_schedule(struct tasklet_struct *);
|
||||
void tasklet_kill(struct tasklet_struct *);
|
||||
|
||||
/*************************
|
||||
** linux/etherdevice.h **
|
||||
*************************/
|
||||
|
||||
int eth_mac_addr(struct net_device *, void *);
|
||||
int eth_validate_addr(struct net_device *);
|
||||
__be16 eth_type_trans(struct sk_buff *, struct net_device *);
|
||||
int is_valid_ether_addr(const u8 *);
|
||||
|
||||
void random_ether_addr(u8 *addr);
|
||||
|
||||
struct net_device *alloc_etherdev(int);
|
||||
|
||||
/********************
|
||||
** asm/checksum.h **
|
||||
********************/
|
||||
|
||||
__wsum csum_partial(const void *, int, __wsum);
|
||||
__sum16 csum_fold(__wsum);
|
||||
|
||||
/**********************************
|
||||
** Platform specific defintions **
|
||||
*********************************/
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <os/config.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <nic_session/nic_session.h>
|
||||
/* Local */
|
||||
#include "storage/component.h"
|
||||
#include "routine.h"
|
||||
@ -50,7 +51,7 @@ bool Routine::_all = false;
|
||||
void breakpoint() { PDBG("BREAK"); }
|
||||
|
||||
|
||||
static void init(bool hid, bool stor)
|
||||
static void init(Services *services)
|
||||
{
|
||||
/* start jiffies */
|
||||
dde_kit_timer_init(0, 0);
|
||||
@ -59,7 +60,7 @@ static void init(bool hid, bool stor)
|
||||
subsys_usb_init();
|
||||
|
||||
/* input + HID */
|
||||
if (hid) {
|
||||
if (services->hid) {
|
||||
subsys_input_init();
|
||||
module_evdev_init();
|
||||
|
||||
@ -73,10 +74,10 @@ static void init(bool hid, bool stor)
|
||||
* Host controller.
|
||||
*
|
||||
*/
|
||||
platform_hcd_init();
|
||||
platform_hcd_init(services);
|
||||
|
||||
/* storage */
|
||||
if (stor)
|
||||
if (services->stor)
|
||||
module_usb_stor_init();
|
||||
}
|
||||
|
||||
@ -91,13 +92,12 @@ int main(int, char **)
|
||||
static Rpc_entrypoint ep_hid(&cap, STACK_SIZE, "usb_hid_ep");
|
||||
static Signal_receiver recv;
|
||||
|
||||
bool hid = false;
|
||||
bool stor = false;
|
||||
Services services;
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("hid");
|
||||
start_input_service(&ep_hid);
|
||||
hid = true;
|
||||
services.hid = true;
|
||||
} catch (Config::Invalid) {
|
||||
PDBG("No <config> node found - not starting any USB services");
|
||||
return 0;
|
||||
@ -107,20 +107,28 @@ int main(int, char **)
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("storage");
|
||||
stor = true;
|
||||
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(hid, stor);
|
||||
init(&services);
|
||||
|
||||
Routine::remove();
|
||||
|
||||
|
136
dde_linux/src/drivers/usb/nic/component.h
Normal file
136
dde_linux/src/drivers/usb/nic/component.h
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* \brief Block-session implementation for network devices
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _NIC__COMPONENT_H_
|
||||
#define _NIC__COMPONENT_H_
|
||||
|
||||
#include <root/component.h>
|
||||
#include <nic_session/rpc_object.h>
|
||||
|
||||
#include <signal/dispatch.h>
|
||||
|
||||
namespace Nic {
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
class Session_component;
|
||||
|
||||
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; }
|
||||
};
|
||||
|
||||
class Session_component : public Genode::Allocator_avl,
|
||||
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()
|
||||
{
|
||||
/* 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);
|
||||
/* send to driver */
|
||||
_device->tx(virt, packet.size());
|
||||
|
||||
if (!_tx_sink->ready_to_ack())
|
||||
PWRN("Wait for TX packet ack");
|
||||
|
||||
/* acknowledge to client */
|
||||
_tx_sink->acknowledge_packet(packet);
|
||||
}
|
||||
|
||||
/* release acknowledged packets */
|
||||
while (_rx.source()->ack_avail())
|
||||
{
|
||||
|
||||
Packet_descriptor packet = _rx.source()->get_acked_packet();
|
||||
|
||||
/* free packet buffer */
|
||||
_rx.source()->release_packet(packet);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Dataspace_capability rx_ds,
|
||||
Rpc_entrypoint &ep,
|
||||
Signal_receiver *sig_rec,
|
||||
::Device *device)
|
||||
:
|
||||
Genode::Allocator_avl(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)
|
||||
{
|
||||
Packet_descriptor p =_rx.source()->alloc_packet(size);
|
||||
memcpy(_rx.source()->packet_content(p), (void*)virt, size);
|
||||
_rx.source()->submit_packet(p);
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* 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_ */
|
441
dde_linux/src/drivers/usb/nic/nic.cc
Normal file
441
dde_linux/src/drivers/usb/nic/nic.cc
Normal file
@ -0,0 +1,441 @@
|
||||
/*
|
||||
* \brief Glue code for Linux network drivers
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2012-07-05
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#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 <util/xml_node.h>
|
||||
|
||||
#include <lx_emul.h>
|
||||
#include <dma.h>
|
||||
|
||||
#include <nic/component.h>
|
||||
#include "signal.h"
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
enum {
|
||||
START = 0x1, /* device flag */
|
||||
HEAD_ROOM = 32, /* head room in skb in bytes */
|
||||
MAC_LEN = 17, /* 12 number and 6 colons */
|
||||
};
|
||||
|
||||
class Nic_device : public Nic::Device
|
||||
{
|
||||
private:
|
||||
|
||||
struct net_device *_ndev; /* Linux-net device */
|
||||
|
||||
public:
|
||||
|
||||
Nic_device(struct net_device *ndev) : _ndev(ndev) { }
|
||||
|
||||
/**
|
||||
* 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, 0);
|
||||
skb->len = size;
|
||||
skb->data += HEAD_ROOM;
|
||||
|
||||
Genode::memcpy(skb->data, (void *)virt, skb->len);
|
||||
|
||||
_ndev->netdev_ops->ndo_start_xmit(skb, _ndev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit packet for session
|
||||
*/
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
/* 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->rx(skb);
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** linux/skbuff.h **
|
||||
********************/
|
||||
|
||||
struct sk_buff *alloc_skb(unsigned int size, gfp_t priority)
|
||||
{
|
||||
sk_buff *skb = new (Genode::env()->heap()) sk_buff;
|
||||
Genode::memset(skb, 0, sizeof(sk_buff));
|
||||
|
||||
size = (size + 3) & ~(0x3);
|
||||
|
||||
skb->start = skb->data = size ? (unsigned char*)kzalloc(size, 0) : 0;
|
||||
skb->tail = skb->end = skb->start + size;
|
||||
skb->truesize = size;
|
||||
|
||||
dde_kit_log(DEBUG_SKB, "alloc sbk: %p start: %p size: %u", skb, skb->start, size);
|
||||
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)
|
||||
kfree(skb->start);
|
||||
|
||||
destroy(Genode::env()->heap(), 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 skb: %p data: %p start: %p len %u ret: %p",
|
||||
skb, skb->data, skb->start, 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);
|
||||
Genode::memcpy(c, skb, sizeof(sk_buff));
|
||||
c->cloned = 1;
|
||||
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 **
|
||||
**********************/
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
* Convert ASCII string to mac address
|
||||
*/
|
||||
template <>
|
||||
inline size_t ascii_to<Nic::Mac_address>(char const *s, Nic::Mac_address* mac, unsigned)
|
||||
{
|
||||
enum {
|
||||
HEX = true,
|
||||
};
|
||||
|
||||
if(strlen(s) < MAC_LEN)
|
||||
throw -1;
|
||||
|
||||
char mac_str[6];
|
||||
for (int i = 0; i < ETH_ALEN; i++) {
|
||||
int hi = i * 3;
|
||||
int lo = hi + 1;
|
||||
|
||||
if (!is_digit(s[hi], HEX) || !is_digit(s[lo], HEX))
|
||||
throw -1;
|
||||
|
||||
mac_str[i] = (digit(s[hi], HEX) << 4) | digit(s[lo], HEX);
|
||||
}
|
||||
|
||||
memcpy(mac->addr, mac_str, ETH_ALEN);
|
||||
|
||||
return MAC_LEN;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
30
dde_linux/src/drivers/usb/platform.h
Normal file
30
dde_linux/src/drivers/usb/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 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_ */
|
@ -136,8 +136,10 @@ class Routine : public Genode::List<Routine>::Element
|
||||
|
||||
Routine *next = _next(all);
|
||||
|
||||
if (next == _current)
|
||||
if (next == _current) {
|
||||
_check_dead();
|
||||
return;
|
||||
}
|
||||
|
||||
/* return when restored */
|
||||
if (_current && _setjmp(_current->_env)) {
|
||||
|
@ -120,4 +120,9 @@ namespace Storage
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
namespace Nic
|
||||
{
|
||||
void init(Genode::Signal_receiver *recv);
|
||||
}
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
||||
|
174
dde_linux/src/drivers/usb/signal/dispatch.h
Normal file
174
dde_linux/src/drivers/usb/signal/dispatch.h
Normal file
@ -0,0 +1,174 @@
|
||||
/**
|
||||
* \brief Packet-stream-session components
|
||||
* \author Sebastian Sumpf
|
||||
* \author Norman Feske
|
||||
* \date 2012-07-06
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2012 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#ifndef _SIGNAL__DISPATCHER_H_
|
||||
#define _SIGNAL__DISPATCHER_H_
|
||||
|
||||
#include "signal.h"
|
||||
|
||||
template <typename T>
|
||||
class Signal_dispatcher : public Driver_context,
|
||||
public Genode::Signal_context_capability
|
||||
{
|
||||
private:
|
||||
|
||||
T &obj;
|
||||
void (T::*member) ();
|
||||
Genode::Signal_receiver *sig_rec;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param sig_rec signal receiver to associate the signal
|
||||
* handler with
|
||||
* \param obj,member object and member function to call when
|
||||
* the signal occurs
|
||||
*/
|
||||
Signal_dispatcher(Genode::Signal_receiver *sig_rec,
|
||||
T &obj, void (T::*member)())
|
||||
:
|
||||
Genode::Signal_context_capability(sig_rec->manage(this)),
|
||||
obj(obj), member(member),
|
||||
sig_rec(sig_rec)
|
||||
{ }
|
||||
|
||||
~Signal_dispatcher() { sig_rec->dissolve(this); }
|
||||
|
||||
void handle() { (obj.*member)(); }
|
||||
char const *debug() { return "Signal_dispatcher"; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Session components that overrides signal handlers
|
||||
*/
|
||||
template <typename RPC>
|
||||
class Packet_session_component : public RPC
|
||||
{
|
||||
private:
|
||||
|
||||
Signal_dispatcher<Packet_session_component> _process_packet_dispatcher;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void _process_packets() = 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_ */
|
@ -52,6 +52,53 @@ 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 **
|
||||
************************/
|
||||
@ -59,8 +106,14 @@ void Event::init(Genode::Signal_receiver *recv) {
|
||||
void __wake_up() { Routine::schedule_all(); }
|
||||
|
||||
|
||||
void __wait_event() {
|
||||
Service_handler::s()->process(); }
|
||||
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)
|
||||
@ -167,3 +220,21 @@ int wake_up_process(struct task_struct *tsk)
|
||||
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;
|
||||
}
|
||||
|
@ -93,9 +93,13 @@ class Irq_context : public Driver_context,
|
||||
/* report IRQ to all clients */
|
||||
for (Irq_handler *h = _handler_list.first(); h; h = h->next()) {
|
||||
irqreturn_t rc;
|
||||
if ((rc = h->handler(_irq, h->dev)) == IRQ_HANDLED)
|
||||
|
||||
rc = h->handler(_irq, h->dev);
|
||||
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u %p", _irq, rc, h->handler);
|
||||
if (rc == IRQ_HANDLED) {
|
||||
Routine::schedule_all();
|
||||
dde_kit_log(DEBUG_IRQ, "IRQ: %u ret: %u", _irq, rc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
#include <root/component.h>
|
||||
#include <block_session/rpc_object.h>
|
||||
|
||||
#include "signal.h"
|
||||
#include <signal/dispatch.h>
|
||||
|
||||
namespace Block {
|
||||
|
||||
@ -25,7 +25,7 @@ namespace Block {
|
||||
|
||||
class Session_component;
|
||||
|
||||
struct Device
|
||||
struct Device : ::Device
|
||||
{
|
||||
/**
|
||||
* Request block size for driver and medium
|
||||
@ -42,49 +42,14 @@ namespace Block {
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
class Signal_dispatcher : public Driver_context,
|
||||
public Signal_context_capability
|
||||
{
|
||||
private:
|
||||
|
||||
T &obj;
|
||||
void (T::*member) ();
|
||||
Signal_receiver *sig_rec;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param sig_rec signal receiver to associate the signal
|
||||
* handler with
|
||||
* \param obj,member object and member function to call when
|
||||
* the signal occurs
|
||||
*/
|
||||
Signal_dispatcher(Signal_receiver *sig_rec,
|
||||
T &obj, void (T::*member)())
|
||||
:
|
||||
Signal_context_capability(sig_rec->manage(this)),
|
||||
obj(obj), member(member),
|
||||
sig_rec(sig_rec)
|
||||
{ }
|
||||
|
||||
~Signal_dispatcher() { sig_rec->dissolve(this); }
|
||||
|
||||
void handle() { (obj.*member)(); }
|
||||
char const *debug() { return "Block_context"; }
|
||||
};
|
||||
|
||||
|
||||
class Session_component : public Session_rpc_object
|
||||
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 */
|
||||
|
||||
Signal_dispatcher<Session_component> _process_packet_dispatcher;
|
||||
protected:
|
||||
|
||||
void _process_packets()
|
||||
{
|
||||
@ -105,23 +70,17 @@ namespace Block {
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component(Dataspace_capability rq_ds,
|
||||
Session_component(Dataspace_capability tx_ds,
|
||||
Ram_dataspace_capability rx_ds,
|
||||
Rpc_entrypoint &ep,
|
||||
Signal_receiver *sig_rec,
|
||||
Device *device)
|
||||
::Device *device)
|
||||
:
|
||||
Session_rpc_object(rq_ds, ep),
|
||||
_rq_phys(Dataspace_client(rq_ds).phys_addr()),
|
||||
_device(device),
|
||||
_process_packet_dispatcher(sig_rec, *this,
|
||||
&Session_component::_process_packets)
|
||||
Packet_session_component(tx_ds, ep, sig_rec),
|
||||
_rq_phys(Dataspace_client(tx_ds).phys_addr()),
|
||||
_device(static_cast<Device *>(device))
|
||||
{
|
||||
/*
|
||||
* Register '_process_packets' dispatch function as signal
|
||||
* handler for packet-avail and ready-to-ack signals.
|
||||
*/
|
||||
_tx.sigh_packet_avail(_process_packet_dispatcher);
|
||||
_tx.sigh_ready_to_ack(_process_packet_dispatcher);
|
||||
env()->ram_session()->free(rx_ds);
|
||||
}
|
||||
|
||||
void info(size_t *blk_count, size_t *blk_size,
|
||||
@ -148,58 +107,15 @@ namespace Block {
|
||||
/**
|
||||
* Root component, handling new session requests
|
||||
*/
|
||||
class Root : public Root_component
|
||||
class Root : public Packet_root<Root_component, Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Rpc_entrypoint &_ep;
|
||||
Signal_receiver *_sig_rec;
|
||||
Device *_device;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Always returns the singleton block-session component
|
||||
*/
|
||||
Session_component *_create_session(const char *args)
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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 (md_alloc())
|
||||
Session_component(env()->ram_session()->alloc(tx_buf_size),
|
||||
_ep, _sig_rec, _device);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
|
||||
Signal_receiver *sig_rec, Device *device)
|
||||
:
|
||||
Root_component(session_ep, md_alloc),
|
||||
_ep(*session_ep), _sig_rec(sig_rec), _device(device)
|
||||
{ }
|
||||
Packet_root(session_ep, md_alloc, sig_rec, device) { }
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
#endif /* _STORAGE__COMPONENT_H_ */
|
||||
|
@ -19,9 +19,9 @@
|
||||
|
||||
#include <lx_emul.h>
|
||||
|
||||
#include "component.h"
|
||||
#include <storage/component.h>
|
||||
#include <storage/scsi.h>
|
||||
#include "signal.h"
|
||||
#include "scsi.h"
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
TARGET = usb_drv
|
||||
LIBS = cxx env dde_kit server libc-setjmp signal
|
||||
SRC_CC = main.cc lx_emul.cc irq.cc timer.cc event.cc storage.cc \
|
||||
input_component.cc
|
||||
input_component.cc nic.cc
|
||||
SRC_C = dummies.c scsi.c evdev.c
|
||||
|
||||
CONTRIB_DIR := $(REP_DIR)/contrib
|
||||
@ -82,12 +82,11 @@ else ifeq ($(filter-out $(SPECS),platform_panda),)
|
||||
CC_OPT += -DCONFIG_USB_EHCI_HCD_OMAP -DCONFIG_USB_EHCI_TT_NEWSCHED -DVERBOSE_DEBUG
|
||||
INC_DIR += $(PRG_DIR)/arm
|
||||
INC_DIR += $(CONTRIB_DIR)/arch/arm/plat-omap/include
|
||||
SRC_C += platform_device.c
|
||||
SRC_C += platform_device.c usbnet.c smsc95xx.c
|
||||
SRC_CC += platform.cc
|
||||
#SRC_C += $(CONTRIB_DIR)/arch/arm/mach-omap2/usb-host.c
|
||||
#SRC_C += $(DRIVERS_DIR)/mfd/omap-usb-host.c
|
||||
vpath %.c $(PRG_DIR)/arm/platform
|
||||
vpath %.cc $(PRG_DIR)/arm/platform
|
||||
vpath %.c $(CONTRIB_DIR)/drivers/net/usb
|
||||
|
||||
#
|
||||
# Unsupported
|
||||
@ -135,6 +134,7 @@ vpath %.c $(PRG_DIR)/input
|
||||
vpath %.cc $(PRG_DIR)/input
|
||||
vpath %.cc $(PRG_DIR)/storage
|
||||
vpath %.c $(PRG_DIR)/storage
|
||||
vpath %.cc $(PRG_DIR)/nic
|
||||
|
||||
clean cleanall:
|
||||
$(VERBOSE) rm -r include
|
||||
|
@ -14,6 +14,8 @@
|
||||
#ifndef _X86_32__PLATFORM_H_
|
||||
#define _X86_32__PLATFORM_H_
|
||||
|
||||
#include <platform.h>
|
||||
|
||||
static inline
|
||||
void platform_execute(void *sp, void *func, void *arg)
|
||||
{
|
||||
@ -27,7 +29,7 @@ void platform_execute(void *sp, void *func, void *arg)
|
||||
extern "C" void module_ehci_hcd_init();
|
||||
extern "C" void module_uhci_hcd_init();
|
||||
|
||||
static inline void platform_hcd_init(void)
|
||||
inline void platform_hcd_init(Services *s)
|
||||
{
|
||||
|
||||
/* ehci_hcd should always be loaded before uhci_hcd and ohci_hcd, not after */
|
||||
|
Loading…
Reference in New Issue
Block a user