dde_linux: remove usb_modem driver

The driver is superseded by the USB network driver (usb_net) which also
contains MBIM support for LTE modems previously provided by this
driver.

issue #4958
This commit is contained in:
Sebastian Sumpf 2023-08-18 19:36:18 +02:00 committed by Christian Helmuth
parent 7e823f7c19
commit 798fb709a2
24 changed files with 0 additions and 4219 deletions

View File

@ -1,11 +0,0 @@
USB_MODEM_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_modem
include $(call select_from_repositories,lib/import/import-usb_arch_include.mk)
#
# The order of include-search directories is important, we need to look into
# 'contrib' before falling back to our custom 'lx_emul.h' header.
#
INC_DIR += $(ARCH_SRC_INC_DIR)
INC_DIR += $(USB_MODEM_CONTRIB_DIR)/include
INC_DIR += $(LIB_CACHE_DIR)/usb_modem_include/include/include/include

View File

@ -1,37 +0,0 @@
ifeq ($(called_from_lib_mk),yes)
USB_MODEM_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_modem
LX_EMUL_H := $(REP_DIR)/src/drivers/usb_modem/lx_emul.h
#
# Determine the header files included by the contrib code. For each
# of these header files we create a symlink to 'lx_emul.h'.
#
SCAN_DIRS := $(addprefix $(USB_MODEM_CONTRIB_DIR)/include/, asm-generic linux uapi net) \
$(addprefix $(USB_MODEM_CONTRIB_DIR)/, drivers net)
GEN_INCLUDES := $(shell grep -rIh "^\#include .*\/" $(SCAN_DIRS) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" |\
sort | uniq)
#
# Filter out original Linux headers that exist in the contrib directory
#
NO_GEN_INCLUDES := $(shell cd $(USB_MODEM_CONTRIB_DIR)/; find include -name "*.h" |\
sed "s/.\///" | sed "s/.*include\///")
GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES))
#
# Put Linux headers in 'GEN_INC' dir, since some include use "../../" paths use
# three level include hierarchy
#
GEN_INC := $(shell pwd)/include/include/include
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
all: $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -s $(LX_EMUL_H) $@
endif
CC_CXX_WARN_STRICT =

View File

@ -1,2 +0,0 @@
Runtime for USB GSM/LTE modem driver

View File

@ -1 +0,0 @@
_/src/usb_modem_drv

View File

@ -1 +0,0 @@
2023-08-21 9f84b33811807c30d1f3ad65d80934aeb95c8f46

View File

@ -1,12 +0,0 @@
<runtime ram="16M" caps="300" binary="usb_modem_drv">
<requires> <uplink/> <usb/> <rm/> </requires>
<provides> <terminal/> </provides>
<config mac="02:00:00:00:01:01"/>
<content>
<rom label="ld.lib.so"/>
<rom label="usb_modem_drv"/>
</content>
</runtime>

View File

@ -1,36 +0,0 @@
PORT_DIR := $(call port_dir,$(REP_DIR)/ports/dde_linux)
MIRROR_FROM_REP_DIR := src/drivers/usb_modem \
src/lib/legacy/lx_kit \
src/lib/lx_kit/spec \
src/include/legacy \
lib/import/import-usb_modem_include.mk \
lib/import/import-usb_arch_include.mk \
lib/mk/usb_modem_include.mk \
$(foreach SPEC, \
arm arm_64 arm_v6 arm_v7 x86 x86_32 x86_64, \
src/include/spec/$(SPEC)) \
$(foreach SPEC, \
arm arm_64 x86_32 x86_64, \
lib/mk/spec/$(SPEC)/lx_kit_setjmp.mk)
MIRROR_FROM_PORT_DIR := $(shell cd $(PORT_DIR); \
find src/drivers/usb_modem -type f | \
grep -v ".git")
MIRROR_FROM_PORT_DIR := $(filter-out $(MIRROR_FROM_REP_DIR), \
$(MIRROR_FROM_PORT_DIR))
content: $(MIRROR_FROM_REP_DIR) $(MIRROR_FROM_PORT_DIR)
$(MIRROR_FROM_REP_DIR):
$(mirror_from_rep_dir)
$(MIRROR_FROM_PORT_DIR):
mkdir -p $(dir $@)
cp $(PORT_DIR)/$@ $@
content: LICENSE
LICENSE:
( echo "GNU General Public License version 2, see:"; \
echo "https://www.kernel.org/pub/linux/kernel/COPYING" ) > $@

View File

@ -1 +0,0 @@
2023-08-21 dd458cda686faf044323cbf00decbfc452b1799c

View File

@ -1,9 +0,0 @@
base
os
format
nic_session
uplink_session
usb_session
timer_session
terminal_session
nic_driver

View File

@ -1,33 +0,0 @@
USB GSM modem driver
####################
Driver for GSM modem cards connected via USB/M.2
Currently there is support for MBIM (Mobile Broadband Interface Model) devices
only. QMI devices might be supported in the future.
Tested devices:
Huawai ME906s (P/V: 12d1:15c1)
Fibocom L830-EB-00 (P/V: 2cb7:0210)
Other devices can be added by enabling the MBIM configuration profile for the
USB device in ' Driver::Device::set_config' (main.cc) of this driver.
Configuration snippet:
!<start name="usb_modem_drv">
! <resource name="RAM" quantum="10M"/>
! <requires>
! <service name="Uplink"/>
! </requires>
! <provides>
! <service name="Terminal"/>
! </provides>
! <config mac="02:00:00:00:01:01"/>
!</start>
The driver offers two Genode sessions: The first one is a terminal session where
raw packet data, for example, MBIM packets can be send to the device via CDC WDM
(wireless communication device class). An example can be found in Genode World
(_src/app/mbimcli_). Once a data connection is established via the Terminal
session, the Uplink session can be used to transfer Ethernet frames.

View File

@ -1,175 +0,0 @@
/*
* \brief USB net driver
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2018-06-27
*/
/*
* Copyright (C) 2018-2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SRC__DRIVERS__USB_MODEM__DRIVER_H_
#define _SRC__DRIVERS__USB_MODEM__DRIVER_H_
/* Genode includes */
#include <base/allocator_avl.h>
#include <base/attached_rom_dataspace.h>
#include <base/heap.h>
#include <usb_session/connection.h>
#include <util/reconstructible.h>
/* local includes */
#include <uplink_client.h>
#include <terminal.h>
/* Linux emulation environment includes */
#include <legacy/lx_kit/scheduler.h>
#include <lx_emul.h>
#include <legacy/lx_emul/extern_c_begin.h>
#include <linux/usb.h>
#include <legacy/lx_emul/extern_c_end.h>
struct usb_device_id;
struct usb_interface;
struct usb_device;
struct Driver
{
using Label = Genode::String<64>;
struct Task
{
Lx::Task task;
Genode::Signal_handler<Task> handler;
void handle_signal()
{
task.unblock();
Lx::scheduler().schedule();
}
template <typename... ARGS>
Task(Genode::Entrypoint & ep, ARGS &&... args)
: task(args...), handler(ep, *this, &Task::handle_signal) {}
};
struct Device
{
using Le = Genode::List_element<Device>;
Le le { this };
Label label;
Driver &driver;
Genode::Env &env;
Genode::Allocator_avl &alloc;
Task state_task;
Task urb_task;
Usb::Connection usb { env, &alloc, label.string(),
512 * 1024, state_task.handler };
usb_device * udev = nullptr;
bool updated = true;
Device(Driver & drv, Label label);
~Device();
static void state_task_entry(void *);
static void urb_task_entry(void *);
void register_device();
void unregister_device();
void scan_interfaces(unsigned iface_idx);
void scan_altsettings(usb_interface * iface,
unsigned iface_idx, unsigned alt_idx);
void probe_interface(usb_interface *, usb_device_id *);
void remove_interface(usb_interface *);
void set_config(Usb::Device_descriptor const &desc);
};
struct Devices : Genode::List<Device::Le>
{
template <typename FN>
void for_each(FN const & fn)
{
Device::Le * cur = first();
for (Device::Le * next = cur ? cur->next() : nullptr; cur;
cur = next, next = cur ? cur->next() : nullptr)
fn(*cur->object());
}
};
class Sync_packet : public Usb::Completion
{
private:
Usb::Session_client & _usb;
Usb::Packet_descriptor _packet { _usb.alloc_packet(0) };
completion _comp;
public:
Sync_packet(Usb::Session_client &usb) : _usb(usb)
{
init_completion(&_comp);
}
virtual ~Sync_packet()
{
_usb.source()->release_packet(_packet);
}
void complete(Usb::Packet_descriptor &p) override
{
::complete(&_comp);
}
void send()
{
_packet.completion = this;
_usb.source()->submit_packet(_packet);
wait_for_completion(&_comp);
}
void config(int configuration)
{
_packet.type = Usb::Packet_descriptor::CONFIG;
_packet.number = configuration;
send();
}
void alt_setting(int interface, int alt_setting)
{
_packet.type = Usb::Packet_descriptor::ALT_SETTING;
_packet.interface.number = interface;
_packet.interface.alt_setting = alt_setting;
send();
}
};
Devices devices;
Genode::Env &env;
Genode::Entrypoint &ep { env.ep() };
Genode::Attached_rom_dataspace config_rom { env, "config" };
Genode::Heap heap { env.ram(), env.rm() };
Genode::Allocator_avl alloc { &heap };
Genode::Constructible<Genode::Uplink_client> uplink_client { };
Terminal::Root terminal_root { env, heap };
Genode::Constructible<Task> main_task;
Genode::Constructible<Genode::Attached_rom_dataspace> report_rom;
Driver(Genode::Env &env);
void activate_network_session()
{
uplink_client.construct(
env, heap,
config_rom.xml().attribute_value(
"uplink_label", Genode::Session_label::String { "" }));
}
static void main_task_entry(void *);
};
#endif /* _SRC__DRIVERS__USB_HID__DRIVER_H_ */

View File

@ -1,624 +0,0 @@
/*
* \brief Dummies
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2020-12-02
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <lx_emul.h>
#if 0
#define TRACE \
do { \
lx_printf("%s not implemented from %p\n", __func__, __builtin_return_address(0)); \
} while (0)
#else
#define TRACE do { ; } while (0)
#endif
#define TRACE_AND_STOP \
do { \
lx_printf("%s not implemented from %p\n", __func__, __builtin_return_address(0)); \
BUG(); \
} while (0)
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
TRACE_AND_STOP;
return NULL;
}
u16 bitrev16(u16 in)
{
TRACE_AND_STOP;
return -1;
}
u16 crc16(u16 crc, const u8 *buffer, size_t len)
{
TRACE_AND_STOP;
return -1;
}
__sum16 csum_fold(__wsum csum)
{
TRACE_AND_STOP;
return -1;
}
__wsum csum_partial(const void *buff, int len, __wsum sum)
{
TRACE_AND_STOP;
return -1;
}
void dev_hold(struct net_device *dev)
{
TRACE_AND_STOP;
}
void dev_put(struct net_device *dev)
{
TRACE_AND_STOP;
}
const char *dev_name(const struct device *dev)
{
TRACE;
return NULL;
}
int device_set_wakeup_enable(struct device *dev, bool enable)
{
TRACE_AND_STOP;
return -1;
}
void dst_release(struct dst_entry *dst)
{
TRACE_AND_STOP;
}
struct net_device;
u32 ethtool_op_get_link(struct net_device *dev)
{
TRACE_AND_STOP;
return -1;
}
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti)
{
TRACE_AND_STOP;
return -1;
}
bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
{
TRACE_AND_STOP;
return -1;
}
void free_netdev(struct net_device * ndev)
{
TRACE_AND_STOP;
}
void free_uid(struct user_struct * user)
{
TRACE_AND_STOP;
}
struct mii_if_info;
int generic_mii_ioctl(struct mii_if_info *mii_if, struct mii_ioctl_data *mii_data, int cmd, unsigned int *duplex_changed)
{
TRACE_AND_STOP;
return -1;
}
void get_page(struct page *page)
{
TRACE_AND_STOP;
}
bool gfpflags_allow_blocking(const gfp_t gfp_flags)
{
TRACE_AND_STOP;
return -1;
}
bool gfp_pfmemalloc_allowed(gfp_t gfp_flags)
{
TRACE_AND_STOP;
return -1;
}
int hex2bin(u8 *dst, const char *src, size_t count)
{
TRACE_AND_STOP;
return -1;
}
int in_irq()
{
TRACE_AND_STOP;
return -1;
}
void *kmap_atomic(struct page *page)
{
TRACE_AND_STOP;
return NULL;
}
int memcmp(const void *s1, const void *s2, size_t size)
{
TRACE_AND_STOP;
return -1;
}
void mii_ethtool_get_link_ksettings( struct mii_if_info *mii, struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
}
int mii_ethtool_set_link_ksettings( struct mii_if_info *mii, const struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
unsigned netdev_mc_count(struct net_device * dev)
{
TRACE;
return 1;
}
int netdev_mc_empty(struct net_device * ndev)
{
TRACE;
return 1;
}
void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, const struct net_device_stats *netdev_stats)
{
TRACE_AND_STOP;
}
bool netdev_uses_dsa(struct net_device *dev)
{
TRACE;
return false;
}
void netif_device_attach(struct net_device *dev)
{
TRACE;
}
void netif_device_detach(struct net_device *dev)
{
TRACE_AND_STOP;
}
int netif_device_present(struct net_device * d)
{
TRACE;
return 1;
}
u32 netif_msg_init(int arg0, int arg1)
{
TRACE;
return 0;
}
void netif_start_queue(struct net_device *dev)
{
TRACE;
}
void netif_stop_queue(struct net_device *dev)
{
TRACE;
}
void netif_trans_update(struct net_device *dev)
{
TRACE;
}
void netif_tx_wake_all_queues(struct net_device *dev)
{
TRACE_AND_STOP;
}
void netif_wake_queue(struct net_device * d)
{
TRACE;
}
void netif_tx_lock_bh(struct net_device *dev)
{
TRACE;
}
void netif_tx_unlock_bh(struct net_device *dev)
{
TRACE;
}
const void *of_get_mac_address(struct device_node *np)
{
TRACE;
return NULL;
}
void pm_runtime_enable(struct device *dev)
{
TRACE;
}
void read_lock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
void read_unlock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
void unregister_netdev(struct net_device * dev)
{
TRACE_AND_STOP;
}
void secpath_reset(struct sk_buff * skb)
{
TRACE;
}
void __set_current_state(int state)
{
TRACE_AND_STOP;
}
void sg_init_table(struct scatterlist *sg, unsigned int arg)
{
TRACE_AND_STOP;
}
void sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
{
TRACE_AND_STOP;
}
void sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len, unsigned int offset)
{
TRACE_AND_STOP;
}
void sk_free(struct sock *sk)
{
TRACE_AND_STOP;
}
void sock_efree(struct sk_buff *skb)
{
TRACE_AND_STOP;
}
void spin_lock(spinlock_t *lock)
{
TRACE;
}
void spin_lock_irq(spinlock_t *lock)
{
TRACE;
}
void spin_lock_nested(spinlock_t *lock, int subclass)
{
TRACE;
}
void spin_unlock_irq(spinlock_t *lock)
{
TRACE;
}
void spin_lock_bh(spinlock_t *lock)
{
TRACE;
}
void spin_unlock_bh(spinlock_t *lock)
{
TRACE;
}
size_t strlcpy(char *dest, const char *src, size_t size)
{
TRACE_AND_STOP;
return -1;
}
void tasklet_kill(struct tasklet_struct *t)
{
TRACE_AND_STOP;
}
void trace_consume_skb(struct sk_buff *skb)
{
TRACE;
}
void trace_kfree_skb(struct sk_buff *skb, void *arg)
{
TRACE;
}
unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *p)
{
TRACE_AND_STOP;
return -1;
}
bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *p, unsigned int s)
{
TRACE_AND_STOP;
return -1;
}
struct usb_device;
int usb_clear_halt(struct usb_device *dev, int pipe)
{
TRACE_AND_STOP;
return -1;
}
struct usb_driver;
struct usb_interface;
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
TRACE_AND_STOP;
}
struct usb_anchor;
struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
{
TRACE_AND_STOP;
return NULL;
}
struct urb *usb_get_urb(struct urb *urb)
{
TRACE_AND_STOP;
return NULL;
}
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
{
TRACE_AND_STOP;
return -1;
}
void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
{
TRACE_AND_STOP;
}
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
TRACE_AND_STOP;
return -1;
}
const struct usb_device_id *usb_match_id(struct usb_interface *interface,
const struct usb_device_id *id)
{
TRACE_AND_STOP;
return NULL;
}
struct usb_host_interface *usb_altnum_to_altsetting(
const struct usb_interface *intf, unsigned int altnum)
{
TRACE_AND_STOP;
return NULL;
}
ktime_t ktime_get_real(void)
{
TRACE_AND_STOP;
return -1;
}
void kunmap_atomic(void *addr)
{
TRACE_AND_STOP;
}
int kstrtoul(const char *s, unsigned int base, unsigned long *res)
{
TRACE_AND_STOP;
return -1;
}
void might_sleep()
{
TRACE_AND_STOP;
}
bool page_is_pfmemalloc(struct page *page)
{
TRACE_AND_STOP;
return -1;
}
void put_page(struct page *page)
{
TRACE_AND_STOP;
}
void usb_kill_urb(struct urb *urb)
{
TRACE_AND_STOP;
}
int usb_unlink_urb(struct urb *urb)
{
TRACE_AND_STOP;
return -1;
}
void usleep_range(unsigned long min, unsigned long max)
{
TRACE;
}
void phy_stop(struct phy_device *phydev)
{
TRACE;
}
void phy_disconnect(struct phy_device *phydev)
{
TRACE;
}
void phy_print_status(struct phy_device *phydev)
{
TRACE;
}
int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
{
TRACE;
return 0;
}
typedef int phy_interface_t;
struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, void (*handler)(struct net_device *), phy_interface_t interface)
{
TRACE;
return 0;
}
int genphy_resume(struct phy_device *phydev) { TRACE; return 0; }
void phy_start(struct phy_device *phydev) { TRACE; }
struct mii_bus;
void mdiobus_free(struct mii_bus *bus) { TRACE; }
void mdiobus_unregister(struct mii_bus *bus) { TRACE; }
struct mii_bus *mdiobus_alloc_size(size_t size)
{
TRACE_AND_STOP;
return NULL;
}
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_get_link_ksettings(struct net_device *ndev, struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_nway_reset(struct net_device *ndev)
{
TRACE_AND_STOP;
return -1;
}
int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
{
TRACE;
return -1;
}
void __vlan_hwaccel_put_tag(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
{
TRACE;
}
struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb)
{
TRACE_AND_STOP;
return NULL;
}
struct net_device *
__vlan_find_dev_deep_rcu(struct net_device *real_dev, __be16 vlan_proto, u16 vlan_id)
{
TRACE_AND_STOP;
return NULL;
}
bool ipv6_addr_is_solict_mult(const struct in6_addr *addr)
{
TRACE;
return false;
}
int ipv6_addr_type(const struct in6_addr *addr)
{
TRACE;
return -1;
}
struct inet6_dev *in6_dev_get(const struct net_device *dev)
{
TRACE_AND_STOP;
return NULL;
}
void in6_dev_put(struct inet6_dev *idev)
{
TRACE_AND_STOP;
}
struct usb_class_driver;
void usb_deregister_dev(struct usb_interface *intf,struct usb_class_driver *class_driver)
{
TRACE_AND_STOP;
}
void poll_wait(struct file *f, wait_queue_head_t *w, poll_table *p)
{
TRACE_AND_STOP;
}
loff_t noop_llseek(struct file *file, loff_t offset, int whence)
{
TRACE_AND_STOP;
return 0;
}
int sysctl_tstamp_allow_data;
struct user_namespace init_user_ns;
const struct ipv6_stub *ipv6_stub;

View File

@ -1,89 +0,0 @@
/*
* \brief Virtual interface of a network session connected to the driver
* \author Martin Stein
* \date 2020-12-13
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <fec_nic.h>
#include <legacy/lx_kit/scheduler.h>
#include <lx_emul.h>
void Fec_nic::_run_tx_task(void * args)
{
Tx_data *data = static_cast<Tx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
net_device * ndev = data->ndev;
struct sk_buff * skb = data->skb;
ndev->netdev_ops->ndo_start_xmit(skb, ndev);
}
}
void Fec_nic::_run_rx_task(void * args)
{
Rx_data *data = static_cast<Rx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
int ret = 0;
struct napi_struct * n = data->napi;
for (;;) {
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidentally calling ->poll() when NAPI is not scheduled.
*/
if (!test_bit(NAPI_STATE_SCHED, &n->state)) break;
int weight = n->weight;
int work = n->poll(n, weight);
ret += work;
if (work < weight) break;
Genode::warning("Too much incoming traffic, we should "
"schedule RX more intelligent");
}
}
}
Fec_nic::Fec_nic(Genode::Session_label const &label)
:
_ndev { _register_fec_nic(*this, label) }
{
if (!_ndev) {
throw Genode::Service_denied();
}
}
bool Fec_nic::_read_link_state_from_ndev() const
{
return !(_ndev->state & (1UL << __LINK_STATE_NOCARRIER));
}
void Fec_nic::unblock_rx_task(napi_struct * n)
{
_rx_data.napi = n;
_rx_task.unblock();
}

View File

@ -1,77 +0,0 @@
/*
* \brief Virtual interface of a network session connected to the driver
* \author Martin Stein
* \date 2020-12-13
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SRC__DRIVERS__NIC__FEC__FEC_NIC_H_
#define _SRC__DRIVERS__NIC__FEC__FEC_NIC_H_
#include <legacy/lx_kit/scheduler.h>
/* forward declarations */
extern "C" {
struct net_device;
struct napi_struct;
struct sk_buff;
}
class Fec_nic
{
protected:
enum { HEAD_ROOM = 8 };
struct Tx_data
{
net_device * ndev;
sk_buff * skb;
};
struct Rx_data
{
struct napi_struct * napi;
};
net_device * _ndev = nullptr;
Tx_data _tx_data;
Rx_data _rx_data;
Lx::Task _tx_task { _run_tx_task, &_tx_data, "tx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
Lx::Task _rx_task { _run_rx_task, &_rx_data, "rx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
static void _run_tx_task(void * args);
static void _run_rx_task(void * args);
static net_device *_register_fec_nic(Fec_nic &fec_nic,
Genode::Session_label label);
bool _read_link_state_from_ndev() const;
public:
Fec_nic(Genode::Session_label const &label);
void unblock_rx_task(napi_struct * n);
/***********************
** Virtual interface **
***********************/
virtual void receive(struct sk_buff *skb) = 0;
virtual void link_state(bool state) = 0;
};
#endif /* _SRC__DRIVERS__NIC__FEC__FEC_NIC_H_ */

View File

@ -1,663 +0,0 @@
/*
* \brief Linux emulation
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2020-12-02
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/env.h>
#include <usb_session/client.h>
#include <format/snprintf.h>
#include <nic_session/nic_session.h>
#include <util/xml_node.h>
#include <driver.h>
#include <lx_emul.h>
#include <legacy/lx_emul/extern_c_begin.h>
#include <linux/usb.h>
#include <legacy/lx_emul/extern_c_end.h>
#define TRACE do { ; } while (0)
#include <legacy/lx_emul/impl/delay.h>
#include <legacy/lx_emul/impl/slab.h>
#include <legacy/lx_emul/impl/work.h>
#include <legacy/lx_emul/impl/spinlock.h>
#include <legacy/lx_emul/impl/mutex.h>
#include <legacy/lx_emul/impl/sched.h>
#include <legacy/lx_emul/impl/timer.h>
#include <legacy/lx_emul/impl/completion.h>
#include <legacy/lx_emul/impl/wait.h>
#include <legacy/lx_emul/impl/usb.h>
#include <legacy/lx_kit/backend_alloc.h>
#include <legacy/lx_emul/extern_c_begin.h>
#include <legacy/lx_emul/impl/kernel.h>
#include <linux/mii.h>
static int usb_match_device(struct usb_device *dev,
const struct usb_device_id *id)
{
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
return 0;
return 1;
}
static int usb_match_one_id_intf(struct usb_device *dev,
struct usb_host_interface *intf,
const struct usb_device_id *id)
{
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
USB_DEVICE_ID_MATCH_INT_PROTOCOL |
USB_DEVICE_ID_MATCH_INT_NUMBER)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
(id->bInterfaceNumber != intf->desc.bInterfaceNumber))
return 0;
return 1;
}
int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
if (id == NULL)
return 0;
intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);
if (!usb_match_device(dev, id))
return 0;
return usb_match_one_id_intf(dev, intf, id);
}
#include <legacy/lx_emul/extern_c_end.h>
class Addr_to_page_mapping : public Genode::List<Addr_to_page_mapping>::Element
{
private:
struct page *_page { nullptr };
static Genode::List<Addr_to_page_mapping> & _list()
{
static Genode::List<Addr_to_page_mapping> _l;
return _l;
}
public:
Addr_to_page_mapping(struct page *page)
: _page(page) { }
static void insert(struct page * page)
{
Addr_to_page_mapping *m = (Addr_to_page_mapping*)
Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping));
m->_page = page;
_list().insert(m);
}
static struct page * remove(unsigned long addr)
{
for (Addr_to_page_mapping *m = _list().first(); m; m = m->next())
if ((unsigned long)m->_page->addr == addr) {
struct page * ret = m->_page;
_list().remove(m);
Lx::Malloc::mem().free(m);
return ret;
}
return nullptr;
}
};
struct Lx_driver
{
using Element = Genode::List_element<Lx_driver>;
using List = Genode::List<Element>;
usb_driver & drv;
Element le { this };
Lx_driver(usb_driver & drv) : drv(drv) { list().insert(&le); }
usb_device_id * match(usb_interface * iface)
{
struct usb_device_id * id = const_cast<usb_device_id*>(drv.id_table);
for (; id->idVendor || id->idProduct || id->bDeviceClass ||
id->bInterfaceClass || id->driver_info; id++)
if (usb_match_one_id(iface, id)) return id;
return nullptr;
}
int probe(usb_interface * iface, usb_device_id * id)
{
iface->dev.driver = &drv.drvwrap.driver;
if (drv.probe) return drv.probe(iface, id);
return 0;
}
static List & list()
{
static List _list;
return _list;
}
};
struct task_struct *current;
struct workqueue_struct *system_wq;
unsigned long jiffies;
Genode::Ram_dataspace_capability Lx::backend_alloc(Genode::addr_t size,
Genode::Cache cache)
{
return Lx_kit::env().env().ram().alloc(size, cache);
}
int usb_register_driver(struct usb_driver * driver, struct module *, const char *)
{
INIT_LIST_HEAD(&driver->dynids.list);
if (driver) new (Lx::Malloc::mem()) Lx_driver(*driver);
return 0;
}
Genode::addr_t Lx::backend_dma_addr(Genode::Ram_dataspace_capability)
{
return 0;
}
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv)
{
usb_device *udev = interface_to_usbdev(iface);
Usb::Connection *usb = reinterpret_cast<Usb::Connection *>(udev->bus->controller);
try {
usb->claim_interface(iface->cur_altsetting->desc.bInterfaceNumber);
} catch (...) {
return -1;
}
return 0;
}
int usb_set_interface(struct usb_device *udev, int ifnum, int alternate)
{
Usb::Connection *usb = reinterpret_cast<Usb::Connection *>(udev->bus->controller);
Driver::Sync_packet packet { *usb };
packet.alt_setting(ifnum, alternate);
usb_interface *iface = udev->config->interface[ifnum];
iface->cur_altsetting = &iface->altsetting[alternate];
return 0;
}
int usb_register_dev(struct usb_interface *intf, struct usb_class_driver *class_driver)
{
usb_device *udev = interface_to_usbdev(intf);
if (Genode::strcmp(class_driver->name, "cdc-wdm", 7) == 0) {
Terminal::Root *terminal = reinterpret_cast<Terminal::Root *>(udev->bus->sysdev);
terminal->class_driver(class_driver);
return 0;
}
Genode::error(__func__, " no device for class driver '",
(char const*)class_driver->name, "'");
return -1;
}
void Driver::Device::probe_interface(usb_interface * iface, usb_device_id * id)
{
using Le = Genode::List_element<Lx_driver>;
for (Le *le = Lx_driver::list().first(); le; le = le->next()) {
usb_device_id * id = le->object()->match(iface);
if (id) {
int ret = le->object()->probe(iface, id);
if (ret == 0) return;
}
}
}
void Driver::Device::remove_interface(usb_interface * iface)
{
to_usb_driver(iface->dev.driver)->disconnect(iface);
for (unsigned i = 0; i < iface->num_altsetting; i++) {
if (iface->altsetting[i].extra)
kfree(iface->altsetting[i].extra);
kfree(iface->altsetting[i].endpoint);
kfree(iface->altsetting);
}
kfree(iface);
}
long __wait_completion(struct completion *work, unsigned long timeout)
{
Lx::timer_update_jiffies();
struct process_timer timer { *Lx::scheduler().current() };
unsigned long expire = timeout + jiffies;
if (timeout) {
timer_setup(&timer.timer, process_timeout, 0);
mod_timer(&timer.timer, expire);
}
while (!work->done) {
if (timeout && expire <= jiffies) return 0;
Lx::Task * task = Lx::scheduler().current();
work->task = (void *)task;
task->block_and_schedule();
}
if (timeout) del_timer(&timer.timer);
work->done = 0;
return (expire > jiffies) ? (expire - jiffies) : 1;
}
u16 get_unaligned_le16(const void *p)
{
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
return ptr->x;
}
u32 get_unaligned_le32(const void *p)
{
const struct __una_u32 *ptr = (const struct __una_u32 *)p;
return ptr->x;
}
enum { MAC_LEN = 17 };
static void snprint_mac(char *buf, u8 *mac)
{
for (int i = 0; i < ETH_ALEN; i++) {
Format::snprintf((char *)&buf[i * 3], 3, "%02x", mac[i]);
if ((i * 3) < MAC_LEN)
buf[(i * 3) + 2] = ':';
}
buf[MAC_LEN] = 0;
}
static void random_ether_addr(u8 *addr)
{
using namespace Genode;
char str[MAC_LEN + 1];
u8 fallback[] = { 0x2e, 0x60, 0x90, 0x0c, 0x4e, 0x01 };
Nic::Mac_address mac;
Xml_node config_node = Lx_kit::env().config_rom().xml();
/* try using configured mac */
try {
Xml_node::Attribute mac_node = config_node.attribute("mac");
mac_node.value(mac);
} catch (...) {
/* use fallback mac */
snprint_mac(str, fallback);
Genode::warning("No mac address or wrong format attribute in <nic> - using fallback (", Genode::Cstring(str), ")");
Genode::memcpy(addr, fallback, ETH_ALEN);
return;
}
/* use configured mac*/
Genode::memcpy(addr, mac.addr, ETH_ALEN);
snprint_mac(str, (u8 *)mac.addr);
Genode::log("Using configured mac: ", Genode::Cstring(str));
}
void eth_hw_addr_random(struct net_device *dev)
{
random_ether_addr(dev->dev_addr);
}
void eth_random_addr(u8 *addr)
{
random_ether_addr(addr);
}
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 = (unsigned char*) kzalloc(ETH_ALEN, 0);
//memset(dev->_dev_addr, 0, sizeof(dev->_dev_addr));
return dev;
}
void *__alloc_percpu(size_t size, size_t align)
{
return kmalloc(size, 0);
}
int mii_nway_restart(struct mii_if_info *mii)
{
/* if autoneg is off, it's an error */
int bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
if (bmcr & BMCR_ANENABLE) {
printk("Reenable\n");
bmcr |= BMCR_ANRESTART;
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
return 0;
}
return -EINVAL;
}
static net_device * single_net_device = nullptr;
int register_netdev(struct net_device *dev)
{
dev->state |= 1 << __LINK_STATE_START;
int err = dev->netdev_ops->ndo_open(dev);
if (err) return err;
if (dev->netdev_ops->ndo_set_rx_mode)
dev->netdev_ops->ndo_set_rx_mode(dev);
single_net_device = dev;
return 0;
};
net_device * Fec_nic::_register_fec_nic(Fec_nic &fec_nic,
Genode::Session_label policy)
{
if (single_net_device) single_net_device->session_component = &fec_nic;
return single_net_device;
}
void tasklet_schedule(struct tasklet_struct *t)
{
Lx::Work *lx_work = (Lx::Work *)tasklet_wq->task;
lx_work->schedule_tasklet(t);
lx_work->unblock();
}
struct workqueue_struct *create_singlethread_workqueue(char const *name)
{
workqueue_struct *wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
Lx::Work *work = Lx::Work::alloc_work_queue(&Lx::Malloc::mem(), name);
wq->task = (void *)work;
return wq;
}
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags,
int max_active, ...)
{
return create_singlethread_workqueue(fmt);
}
int dev_set_drvdata(struct device *dev, void *data)
{
dev->driver_data = data;
return 0;
}
void * dev_get_drvdata(const struct device *dev)
{
return dev->driver_data;
}
int netif_running(const struct net_device *dev)
{
return dev->state & (1 << __LINK_STATE_START);
}
void netif_carrier_off(struct net_device *dev)
{
dev->state |= 1 << __LINK_STATE_NOCARRIER;
if (dev->session_component)
reinterpret_cast<Fec_nic*>(dev->session_component)->link_state(false);
}
int netif_carrier_ok(const struct net_device *dev)
{
return !(dev->state & (1 << __LINK_STATE_NOCARRIER));
}
void *kmem_cache_alloc_node(struct kmem_cache *cache, gfp_t gfp_flags, int arg)
{
return (void*)cache->alloc_element();
}
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
ecmd->duplex = DUPLEX_FULL;
return 0;
}
void netif_carrier_on(struct net_device *dev)
{
dev->state &= ~(1 << __LINK_STATE_NOCARRIER);
if (dev->session_component)
reinterpret_cast<Fec_nic*>(dev->session_component)->link_state(true);
}
int netif_rx(struct sk_buff * skb)
{
if (skb->dev->session_component)
reinterpret_cast<Fec_nic*>(skb->dev->session_component)->receive(skb);
dev_kfree_skb(skb);
return NET_RX_SUCCESS;
}
struct sk_buff;
void dev_kfree_skb_any(struct sk_buff *skb)
{
TRACE;
kfree_skb(skb);
}
int is_valid_ether_addr(const u8 * a)
{
for (unsigned i = 0; i < ETH_ALEN; i++)
if (a[i] != 0 && a[i] != 255) return 1;
return 0;
}
unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, unsigned int init_media)
{
if (mii_link_ok(mii)) netif_carrier_on(mii->dev);
else netif_carrier_off(mii->dev);
return 0;
}
int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
return 1;
return 0;
}
static struct page *allocate_pages(gfp_t gfp_mask, unsigned int size)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
page->addr = Lx::Malloc::dma().alloc_large(size);
page->size = size;
if (!page->addr) {
Genode::error("alloc_pages: ", size, " failed");
kfree(page);
return 0;
}
Addr_to_page_mapping::insert(page);
atomic_set(&page->_count, 1);
return page;
}
void *page_frag_alloc(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask)
{
struct page *page = allocate_pages(gfp_mask, fragsz);
if (!page) return nullptr;
return page->addr;
}
void page_frag_free(void *addr)
{
struct page *page = Addr_to_page_mapping::remove((unsigned long)addr);
if (!atomic_dec_and_test(&page->_count))
Genode::error("page reference count != 0");
Lx::Malloc::dma().free_large(page->addr);
kfree(page);
}
unsigned iminor(const struct inode *inode)
{
return 0;
}
void *memdup_user(const void *src, size_t len)
{
void *out = kmalloc(len, 0);
memcpy(out, src, len);
return out;
}
long copy_to_user(void *to, const void *from, unsigned long n)
{
memcpy(to, from, n);
return 0;
}
int mutex_lock_interruptible(struct mutex *m)
{
mutex_lock(m);
return 0;
}
void hrtimer_start(struct hrtimer *timer, ktime_t tim, const enum hrtimer_mode mode)
{
hrtimer_start_range_ns(timer, tim, 0, mode);
}
int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
{
TRACE;
*vlan_tci = 0;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,247 +0,0 @@
/*
* \brief Linux emulation code
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2014-03-07
*/
/*
* Copyright (C) 2014-2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* linux includes */
#include <lx_emul.h>
#include <linux/skbuff.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/cdc.h>
/* local includes */
#include <lxc.h>
struct Skb skb_helper(struct sk_buff *skb)
{
struct Skb helper;
skb_push(skb, ETH_HLEN);
helper.packet = skb->data;
helper.packet_size = skb->len;
helper.frag = 0;
helper.frag_size = 0;
/**
* If received packets are too large (as of now 128 bytes) the actually
* payload is put into a fragment. Otherwise the payload is stored directly
* in the sk_buff.
*/
if (skb_shinfo(skb)->nr_frags) {
if (skb_shinfo(skb)->nr_frags > 1)
printk("more than 1 fragment in skb: %p nr_frags: %d", skb,
skb_shinfo(skb)->nr_frags);
skb_frag_t *f = &skb_shinfo(skb)->frags[0];
helper.frag = skb_frag_address(f);
helper.frag_size = skb_frag_size(f);
/* fragment contains payload but header is still found in packet */
helper.packet_size = ETH_HLEN;
}
return helper;
}
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom)
{
struct sk_buff *skb = alloc_skb(len + headroom, GFP_KERNEL | GFP_LX_DMA);
skb_reserve(skb, headroom);
return skb;
}
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len)
{
return skb_put(skb, len);
}
/**
* cdc_parse_cdc_header - parse the extra headers present in CDC devices
* @hdr: the place to put the results of the parsing
* @intf: the interface for which parsing is requested
* @buffer: pointer to the extra headers to be parsed
* @buflen: length of the extra headers
*
* This evaluates the extra headers present in CDC devices which
* bind the interfaces for data and control and provide details
* about the capabilities of the device.
*
* Return: number of descriptors parsed or -EINVAL
* if the header is contradictory beyond salvage
*/
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr,
struct usb_interface *intf,
u8 *buffer,
int buflen)
{
/* duplicates are ignored */
struct usb_cdc_union_desc *union_header = NULL;
/* duplicates are not tolerated */
struct usb_cdc_header_desc *header = NULL;
struct usb_cdc_ether_desc *ether = NULL;
struct usb_cdc_mdlm_detail_desc *detail = NULL;
struct usb_cdc_mdlm_desc *desc = NULL;
unsigned int elength;
int cnt = 0;
memset(hdr, 0x00, sizeof(struct usb_cdc_parsed_header));
hdr->phonet_magic_present = false;
while (buflen > 0) {
elength = buffer[0];
if (!elength) {
dev_err(&intf->dev, "skipping garbage byte\n");
elength = 1;
goto next_desc;
}
if ((buflen < elength) || (elength < 3)) {
dev_err(&intf->dev, "invalid descriptor buffer length\n");
break;
}
if (buffer[1] != USB_DT_CS_INTERFACE) {
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
if (elength < sizeof(struct usb_cdc_union_desc))
goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one union descriptor, skipping ...\n");
goto next_desc;
}
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE:
if (elength < sizeof(struct usb_cdc_country_functional_desc))
goto next_desc;
hdr->usb_cdc_country_functional_desc =
(struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE:
if (elength != sizeof(struct usb_cdc_header_desc))
goto next_desc;
if (header)
return -EINVAL;
header = (struct usb_cdc_header_desc *)buffer;
break;
case USB_CDC_ACM_TYPE:
if (elength < sizeof(struct usb_cdc_acm_descriptor))
goto next_desc;
hdr->usb_cdc_acm_descriptor =
(struct usb_cdc_acm_descriptor *)buffer;
break;
case USB_CDC_ETHERNET_TYPE:
if (elength != sizeof(struct usb_cdc_ether_desc))
goto next_desc;
if (ether)
return -EINVAL;
ether = (struct usb_cdc_ether_desc *)buffer;
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
if (elength < sizeof(struct usb_cdc_call_mgmt_descriptor))
goto next_desc;
hdr->usb_cdc_call_mgmt_descriptor =
(struct usb_cdc_call_mgmt_descriptor *)buffer;
break;
case USB_CDC_DMM_TYPE:
if (elength < sizeof(struct usb_cdc_dmm_desc))
goto next_desc;
hdr->usb_cdc_dmm_desc =
(struct usb_cdc_dmm_desc *)buffer;
break;
case USB_CDC_MDLM_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_desc *))
goto next_desc;
if (desc)
return -EINVAL;
desc = (struct usb_cdc_mdlm_desc *)buffer;
break;
case USB_CDC_MDLM_DETAIL_TYPE:
if (elength < sizeof(struct usb_cdc_mdlm_detail_desc *))
goto next_desc;
if (detail)
return -EINVAL;
detail = (struct usb_cdc_mdlm_detail_desc *)buffer;
break;
case USB_CDC_NCM_TYPE:
if (elength < sizeof(struct usb_cdc_ncm_desc))
goto next_desc;
hdr->usb_cdc_ncm_desc = (struct usb_cdc_ncm_desc *)buffer;
break;
case USB_CDC_MBIM_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_desc))
goto next_desc;
hdr->usb_cdc_mbim_desc = (struct usb_cdc_mbim_desc *)buffer;
break;
case USB_CDC_MBIM_EXTENDED_TYPE:
if (elength < sizeof(struct usb_cdc_mbim_extended_desc))
break;
hdr->usb_cdc_mbim_extended_desc =
(struct usb_cdc_mbim_extended_desc *)buffer;
break;
case CDC_PHONET_MAGIC_NUMBER:
hdr->phonet_magic_present = true;
break;
default:
/*
* there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: type %02x, length %ud\n",
buffer[2], elength);
goto next_desc;
}
cnt++;
next_desc:
buflen -= elength;
buffer += elength;
}
hdr->usb_cdc_union_desc = union_header;
hdr->usb_cdc_header_desc = header;
hdr->usb_cdc_mdlm_detail_desc = detail;
hdr->usb_cdc_mdlm_desc = desc;
hdr->usb_cdc_ether_desc = ether;
return cnt;
}
struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev,
unsigned ifnum)
{
struct usb_host_config *config = dev->actconfig;
int i;
if (!config) {
lx_printf("No config for %u\n", ifnum);
return NULL;
}
for (i = 0; i < config->desc.bNumInterfaces; i++) {
if (config->interface[i]->altsetting[0]
.desc.bInterfaceNumber == ifnum) {
return config->interface[i];
}
}
lx_printf("No interface for %u\n");
return NULL;
}
EXPORT_SYMBOL(cdc_parse_cdc_header);

View File

@ -1,41 +0,0 @@
/*
* \brief Lx C env
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2016-03-04
*/
/*
* Copyright (C) 2016-2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LXC_H_
#define _LXC_H_
/*
* The sk_buff struct contains empty array members whose
* size differs between C and C++. Since we want to access
* certain members of the sk_buff from C++ we have to use
* a uniform format useable from both languages.W
*
* Note: we pull struct skb_buff as well as size_t from
* headers included before this one.
*/
struct Skb
{
void *packet;
size_t packet_size;
void *frag;
size_t frag_size;
};
struct Skb skb_helper(struct sk_buff *skb);
bool is_eapol(struct sk_buff *skb);
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom);
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len);
#endif /* _LXC_H_ */

View File

@ -1,252 +0,0 @@
/*
* \brief USB modem driver
* \author Stefan Kalkowski
* \author Sebastian Sumpf
* \date 2018-06-07
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/component.h>
#include <driver.h>
#include <lx_emul.h>
#include <legacy/lx_kit/env.h>
#include <legacy/lx_kit/malloc.h>
#include <legacy/lx_kit/scheduler.h>
#include <legacy/lx_kit/timer.h>
#include <legacy/lx_kit/work.h>
struct workqueue_struct *tasklet_wq;
void Driver::Device::scan_altsettings(usb_interface * iface,
unsigned iface_idx, unsigned alt_idx)
{
Usb::Interface_descriptor iface_desc;
usb.interface_descriptor(iface_idx, alt_idx, &iface_desc);
Genode::memcpy(&iface->altsetting[alt_idx].desc, &iface_desc,
sizeof(usb_interface_descriptor));
if (iface_desc.active)
iface->cur_altsetting = &iface->altsetting[alt_idx];
Usb::Interface_extra iface_extra;
if (usb.interface_extra(iface_idx, alt_idx, &iface_extra)) {
iface->altsetting[alt_idx].extra = (unsigned char *)kzalloc(iface_extra.length, 0);
Genode::memcpy(iface->altsetting[alt_idx].extra, iface_extra.data,
iface_extra.length);
iface->altsetting[alt_idx].extralen = iface_extra.length;
}
iface->altsetting[alt_idx].endpoint = (usb_host_endpoint*)
kzalloc(sizeof(usb_host_endpoint)*iface->altsetting[alt_idx].desc.bNumEndpoints, GFP_KERNEL);
for (unsigned i = 0; i < iface->altsetting[alt_idx].desc.bNumEndpoints; i++) {
Usb::Endpoint_descriptor ep_desc;
usb.endpoint_descriptor(iface_idx, alt_idx, i, &ep_desc);
Genode::memcpy(&iface->altsetting[alt_idx].endpoint[i].desc,
&ep_desc, sizeof(usb_endpoint_descriptor));
int epnum = usb_endpoint_num(&iface->altsetting[alt_idx].endpoint[i].desc);
if (usb_endpoint_dir_out(&iface->altsetting[alt_idx].endpoint[i].desc))
udev->ep_out[epnum] = &iface->altsetting[alt_idx].endpoint[i];
else
udev->ep_in[epnum] = &iface->altsetting[alt_idx].endpoint[i];
}
}
void Driver::Device::scan_interfaces(unsigned iface_idx)
{
struct usb_interface * iface =
(usb_interface*) kzalloc(sizeof(usb_interface), GFP_KERNEL);
iface->num_altsetting = usb.alt_settings(iface_idx);
iface->altsetting = (usb_host_interface*)
kzalloc(sizeof(usb_host_interface)*iface->num_altsetting, GFP_KERNEL);
iface->dev.parent = &udev->dev;
iface->dev.bus = (bus_type*) 0xdeadbeef;
for (unsigned i = 0; i < iface->num_altsetting; i++)
scan_altsettings(iface, iface_idx, i);
udev->config->interface[iface_idx] = iface;
}
void Driver::Device::set_config(Usb::Device_descriptor const &desc)
{
/* Huawei ME906s */
if (desc.vendor_id == 0x12d1 && desc.product_id == 0x15c1) {
Genode::log("Found Huawei ME906s choosing configuration #3");
/* set unconfigured first */
Sync_packet(usb).config(0);
/* configuration 3 is MBIM for this modem */
Sync_packet(usb).config(3);
}
}
void Driver::Device::register_device()
{
if (udev) {
Genode::error("device already registered!");
return;
}
Usb::Device_descriptor dev_desc;
Usb::Config_descriptor config_desc;
usb.config_descriptor(&dev_desc, &config_desc);
udev = (usb_device*) kzalloc(sizeof(usb_device), GFP_KERNEL);
udev->bus = (usb_bus*) kzalloc(sizeof(usb_bus), GFP_KERNEL);
udev->config = (usb_host_config*) kzalloc(sizeof(usb_host_config), GFP_KERNEL);
udev->bus->bus_name = "usbbus";
udev->bus->controller = (device*) (&usb);
udev->bus->sysdev = (device*) (&driver.terminal_root);
udev->descriptor.idVendor = dev_desc.vendor_id;
udev->descriptor.idProduct = dev_desc.product_id;
udev->descriptor.bcdDevice = dev_desc.device_release;
set_config(dev_desc);
/* re-read config */
usb.config_descriptor(&dev_desc, &config_desc);
/* device specific configuration profile */
for (unsigned i = 0; i < config_desc.num_interfaces; i++)
scan_interfaces(i);
udev->actconfig = udev->config;
udev->config->desc.bNumInterfaces = config_desc.num_interfaces;
for (unsigned i = 0; i < config_desc.num_interfaces; i++) {
struct usb_device_id id;
probe_interface(udev->config->interface[i], &id);
}
driver.activate_network_session();
driver.env.parent().announce(driver.ep.manage(driver.terminal_root));
}
void Driver::Device::unregister_device()
{
for (unsigned i = 0; i < USB_MAXINTERFACES; i++) {
if (!udev->config->interface[i]) break;
else remove_interface(udev->config->interface[i]);
}
kfree(udev->bus);
kfree(udev->config);
kfree(udev);
udev = nullptr;
}
void Driver::Device::state_task_entry(void * arg)
{
Device & dev = *reinterpret_cast<Device*>(arg);
for (;;) {
if (dev.usb.plugged() && !dev.udev)
dev.register_device();
if (!dev.usb.plugged() && dev.udev)
dev.unregister_device();
Lx::scheduler().current()->block_and_schedule();
}
}
void Driver::Device::urb_task_entry(void * arg)
{
Device & dev = *reinterpret_cast<Device*>(arg);
for (;;) {
while (dev.udev && dev.usb.source()->ack_avail()) {
Usb::Packet_descriptor p = dev.usb.source()->get_acked_packet();
if (p.completion) p.completion->complete(p);
dev.usb.source()->release_packet(p);
}
Lx::scheduler().current()->block_and_schedule();
}
}
Driver::Device::Device(Driver & driver, Label label)
: label(label),
driver(driver),
env(driver.env),
alloc(driver.alloc),
state_task(env.ep(), state_task_entry, reinterpret_cast<void*>(this),
"usb_state", Lx::Task::PRIORITY_0, Lx::scheduler()),
urb_task(env.ep(), urb_task_entry, reinterpret_cast<void*>(this),
"usb_urb", Lx::Task::PRIORITY_0, Lx::scheduler())
{
usb.tx_channel()->sigh_ack_avail(urb_task.handler);
driver.devices.insert(&le);
}
Driver::Device::~Device()
{
driver.devices.remove(&le);
if (udev) unregister_device();
while (usb.source()->ack_avail()) {
Usb::Packet_descriptor p = usb.source()->get_acked_packet();
usb.source()->release_packet(p);
}
}
void Driver::main_task_entry(void * arg)
{
LX_MUTEX_INIT(wdm_mutex);
Driver * driver = reinterpret_cast<Driver*>(arg);
tasklet_wq = alloc_workqueue("tasklet_wq", 0, 0);
skb_init();
module_usbnet_init();
module_wdm_driver_init();
module_cdc_ncm_driver_init();
module_cdc_mbim_driver_init();
static Device dev(*driver, Label(""));
for (;;) Lx::scheduler().current()->block_and_schedule();
}
Driver::Driver(Genode::Env &env) : env(env)
{
Genode::log("--- USB net driver ---");
Lx_kit::construct_env(env);
Lx::scheduler(&env);
Lx::malloc_init(env, heap);
Lx::timer(&env, &ep, &heap, &jiffies);
Lx::Work::work_queue(&heap);
main_task.construct(env.ep(), main_task_entry, reinterpret_cast<void*>(this),
"main", Lx::Task::PRIORITY_0, Lx::scheduler());
/* give all task a first kick before returning */
Lx::scheduler().schedule();
}
void Component::construct(Genode::Env &env)
{
env.exec_static_constructors();
static Driver driver(env);
}

View File

@ -1,29 +0,0 @@
TARGET := usb_modem_drv
SRC_C := dummies.c lxc.c
SRC_CC := main.cc lx_emul.cc terminal.cc fec_nic.cc
SRC_CC += printf.cc bug.cc timer.cc scheduler.cc malloc.cc env.cc work.cc
SRC_CC += uplink_client.cc
LIBS := base usb_modem_include lx_kit_setjmp nic_driver format
USB_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_modem
INC_DIR += $(PRG_DIR)
INC_DIR += $(REP_DIR)/src/include
SRC_C += drivers/net/usb/usbnet.c
SRC_C += drivers/net/usb/cdc_ncm.c
SRC_C += drivers/net/usb/cdc_mbim.c
SRC_C += drivers/usb/class/cdc-wdm.c
SRC_C += net/core/skbuff.c
SRC_C += net/ethernet/eth.c
CC_C_OPT += -Wno-comment -Wno-int-conversion -Wno-incompatible-pointer-types \
-Wno-unused-variable -Wno-pointer-sign -Wno-uninitialized \
-Wno-maybe-uninitialized -Wno-format -Wno-discarded-qualifiers \
-Wno-unused-function -Wno-unused-but-set-variable
CC_CXX_WARN_STRICT =
vpath %.c $(USB_CONTRIB_DIR)
vpath %.cc $(REP_DIR)/src/lib/legacy/lx_kit

View File

@ -1,100 +0,0 @@
/*
* \brief USB modem driver terminal service
* \author Sebastian Sumpf
* \author Josef Soentgen
* \date 2020-12-02
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <terminal.h>
#include <lx_emul.h>
#include <legacy/lx_emul/extern_c_begin.h>
#include <linux/usb.h>
#include <legacy/lx_emul/extern_c_end.h>
using namespace Terminal;
Session_component::Session_component(Genode::Env &env,
Genode::size_t io_buffer_size,
usb_class_driver *class_driver)
:
_io_buffer(env.ram(), env.rm(), io_buffer_size),
_io_buffer_size(io_buffer_size),
_class_driver(class_driver)
{
if (class_driver == nullptr) {
Genode::error("No class driver for terminal");
throw Genode::Service_denied();
}
Lx::scheduler().schedule();
}
void Session_component::_run_wdm_device(void *args)
{
Session_component *session = static_cast<Session_component *>(args);
usb_class_driver *driver = session->_class_driver;
int err = -1;
struct file file { };
if ((err = driver->fops->open(nullptr, &file))) {
Genode::error("Could not open WDM device: ", err);
return;
}
session->_wdm_device = file.private_data;
Lx::scheduler().current()->block_and_schedule();
//XXX: close
}
void Session_component::_run_wdm_write(void *args)
{
Lx::scheduler().current()->block_and_schedule();
Session_component *session = static_cast<Session_component *>(args);
usb_class_driver *driver = session->_class_driver;
struct file file { .private_data = session->_wdm_device };
while (1) {
ssize_t length = driver->fops->write(&file, session->buffer(),
session->_data_avail, nullptr);
if (length < 0) {
Genode::error("WDM write error: ", length);
}
session->_schedule_read();
Lx::scheduler().current()->block_and_schedule();
}
}
void Session_component::_run_wdm_read(void *args)
{
Lx::scheduler().current()->block_and_schedule();
Session_component *session = static_cast<Session_component *>(args);
usb_class_driver *driver = session->_class_driver;
struct file file { .private_data = session->_wdm_device };
while (1) {
ssize_t length = driver->fops->read(&file, session->buffer(), 0x1000, nullptr);
if (length > 0) {
session->_data_avail = length;
session->signal_data_avail();
}
Lx::scheduler().current()->block_and_schedule();
}
}

View File

@ -1,180 +0,0 @@
/*
* \brief Service providing the 'Terminal_session' interface for a Linux file
* \author Josef Soentgen
* \author Sebastian Sumpf
* \date 2020-07-09
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__DRIVERS__USB_MODEM__TERMINAL_H_
#define _SRC__DRIVERS__USB_MODEM__TERMINAL_H_
/* Genode includes */
#include <base/attached_ram_dataspace.h>
#include <base/log.h>
#include <os/session_policy.h>
#include <root/component.h>
#include <terminal_session/terminal_session.h>
#include <legacy/lx_kit/scheduler.h>
namespace Terminal {
class Session_component;
class Root;
}
extern "C" {
struct usb_class_driver;
}
class Terminal::Session_component : public Genode::Rpc_object<Session, Session_component>
{
using size_t = Genode::size_t;
private:
enum State { WRITE, READ };
Genode::Attached_ram_dataspace _io_buffer;
Genode::Signal_context_capability _read_avail_sigh { };
State _state { WRITE };
size_t _data_avail { 0 };
size_t _io_buffer_size;
void *_wdm_device { nullptr };
usb_class_driver *_class_driver { nullptr };
static void _run_wdm_device(void *args);
static void _run_wdm_write(void *args);
static void _run_wdm_read(void *args);
Lx::Task _task_write { _run_wdm_write, this, "wdm_task_write",
Lx::Task::PRIORITY_1, Lx::scheduler() };
Lx::Task _task_read { _run_wdm_read, this, "wdm_task_read",
Lx::Task::PRIORITY_1, Lx::scheduler() };
Lx::Task _task_device { _run_wdm_device, this, "wdm_task_devie",
Lx::Task::PRIORITY_1, Lx::scheduler() };
void _schedule_read()
{
_task_read.unblock();
}
public:
Session_component(Genode::Env &env,
Genode::size_t io_buffer_size,
usb_class_driver *class_driver);
/********************************
** Terminal session interface **
********************************/
Size size() override { return Size(0, 0); }
bool avail() override
{
return _data_avail > 0;
}
Genode::size_t _read(Genode::size_t dst_len)
{
if (_state != READ) return 0;
size_t length = Genode::min(dst_len, _data_avail);
if (dst_len < _data_avail)
Genode::warning("dst_len < data_avail (", dst_len, " < ", _data_avail, ") not supported");
_data_avail -= length;
if (_data_avail == 0) {
_state = WRITE;
_schedule_read();
}
return length;
}
Genode::size_t _write(Genode::size_t num_bytes)
{
if (_state == READ) return 0;
_data_avail = num_bytes;
_state = WRITE;
_task_write.unblock();
Lx::scheduler().schedule();
return 0;
}
Genode::Dataspace_capability _dataspace()
{
return _io_buffer.cap();
}
void read_avail_sigh(Genode::Signal_context_capability sigh) override
{
_read_avail_sigh = sigh;
}
void connected_sigh(Genode::Signal_context_capability sigh) override
{
Genode::Signal_transmitter(sigh).submit();
}
void size_changed_sigh(Genode::Signal_context_capability) override { }
size_t read(void *, size_t) override { return 0; }
size_t write(void const *, size_t) override { return 0; }
char *buffer() { return _io_buffer.local_addr<char>(); }
void signal_data_avail()
{
if (_read_avail_sigh.valid() == false) return;
_state = READ;
Genode::Signal_transmitter(_read_avail_sigh).submit();
}
};
class Terminal::Root : public Genode::Root_component<Session_component>
{
private:
Genode::Env &_env;
usb_class_driver *_class_driver { nullptr };
protected:
Session_component *_create_session(const char *args) override
{
Genode::size_t const io_buffer_size = 4096ul;
return new (md_alloc())
Session_component(_env, io_buffer_size, _class_driver);
}
public:
/**
* Constructor
*/
Root(Genode::Env &env,
Genode::Allocator &md_alloc)
:
Genode::Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
_env(env)
{ }
void class_driver(usb_class_driver *class_driver) { _class_driver = class_driver; }
};
#endif /* _SRC__DRIVERS__USB_MODEM__TERMINAL_H_ */

View File

@ -1,93 +0,0 @@
/*
* \brief Uplink session client role of the driver
* \author Martin Stein
* \date 2020-12-10
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* local include */
#include <uplink_client.h>
#include <lx_emul.h>
extern "C" {
#include <lxc.h>
};
Genode::Uplink_client::Transmit_result
Genode::Uplink_client::_drv_transmit_pkt(const char *conn_rx_pkt_base,
size_t conn_rx_pkt_size)
{
/*
* We must not be called from another task, just from the
* packet stream dispatcher.
*/
if (Lx::scheduler().active()) {
warning("scheduler active");
return Transmit_result::RETRY;
}
struct sk_buff *skb {
lxc_alloc_skb(conn_rx_pkt_size +
HEAD_ROOM, HEAD_ROOM) };
unsigned char *data = lxc_skb_put(skb, conn_rx_pkt_size);
memcpy(data, conn_rx_pkt_base, conn_rx_pkt_size);
_tx_data.ndev = _ndev;
_tx_data.skb = skb;
_tx_task.unblock();
Lx::scheduler().schedule();
return Transmit_result::ACCEPTED;
}
Genode::Uplink_client::Uplink_client(Env &env,
Allocator &alloc,
Session_label const &label)
:
Fec_nic { label },
Uplink_client_base { env, alloc,
Net::Mac_address(_ndev->dev_addr) }
{
_drv_handle_link_state(_read_link_state_from_ndev());
}
void Genode::Uplink_client::link_state(bool state)
{
_drv_handle_link_state(state);
}
void Genode::Uplink_client::receive(struct sk_buff *skb)
{
Skb skb_helpr { skb_helper(skb) };
_drv_rx_handle_pkt(
skb_helpr.packet_size + skb_helpr.frag_size,
[&] (void *conn_tx_pkt_base,
size_t &)
{
memcpy(
conn_tx_pkt_base,
skb_helpr.packet,
skb_helpr.packet_size);
if (skb_helpr.frag_size) {
memcpy(
(char *)conn_tx_pkt_base + skb_helpr.packet_size,
skb_helpr.frag,
skb_helpr.frag_size);
}
return Write_result::WRITE_SUCCEEDED;
});
}

View File

@ -1,58 +0,0 @@
/*
* \brief Uplink session client role of the driver
* \author Martin Stein
* \date 2020-12-10
*/
/*
* Copyright (C) 2020 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _SRC__DRIVERS__NIC__FEC__UPLINK_CLIENT_H_
#define _SRC__DRIVERS__NIC__FEC__UPLINK_CLIENT_H_
/* NIC driver includes */
#include <drivers/nic/uplink_client_base.h>
/* local include */
#include <fec_nic.h>
namespace Genode {
class Uplink_client;
}
class Genode::Uplink_client : public Fec_nic,
public Uplink_client_base
{
private:
/************************
** Uplink_client_base **
************************/
Transmit_result
_drv_transmit_pkt(const char *conn_rx_pkt_base,
size_t conn_rx_pkt_size) override;
public:
Uplink_client(Env &env,
Allocator &alloc,
Session_label const &label);
/*************
** Fec_nic **
*************/
void link_state(bool state) override;
void receive(struct sk_buff *skb) override;
};
#endif /* _SRC__DRIVERS__NIC__FEC__UPLINK_CLIENT_H_ */