USB: Support usbnet and smsc95xx for omap4

This commit is contained in:
Sebastian Sumpf 2012-06-25 16:31:04 +02:00 committed by Norman Feske
parent b2a62b4b2d
commit 70b8fc2832
22 changed files with 1684 additions and 159 deletions

View File

@ -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

View File

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

View 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
View 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 :

View File

@ -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 */

View File

@ -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

View File

@ -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;
@ -521,7 +521,7 @@ void kunmap(struct page *page) { TRACE; }
** asm-generic/io.h **
**********************/
void iounmap(volatile void *addr) { TRACE; }
void iounmap(volatile void *addr) { TRACE; }
void native_io_delay(void) { TRACE; }
@ -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; }

View File

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

View File

@ -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
@ -135,7 +137,8 @@ typedef dde_kit_size_t size_t;
typedef dde_kit_int64_t int64_t;
typedef dde_kit_uint64_t uint64_t;
typedef uint32_t uint;
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);
@ -951,8 +965,8 @@ void __wait_event(void);
#define _wait_event(condition) \
while(!(condition)) { \
__wait_event(); \
if (!(condition)) \
msleep(1); \
if (!(condition)) \
msleep(1); \
} \
#define _wait_event_timeout(condition, timeout) \
@ -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 **
*********************************/

View File

@ -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();

View 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_ */

View 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);
}

View 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_ */

View File

@ -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)) {

View File

@ -120,4 +120,9 @@ namespace Storage
void init(Genode::Signal_receiver *recv);
}
namespace Nic
{
void init(Genode::Signal_receiver *recv);
}
#endif /* _SIGNAL_H_ */

View 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_ */

View File

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

View File

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

View File

@ -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)
{
/*
* 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);
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,
@ -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,
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_ */

View File

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

View File

@ -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

View File

@ -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 */