mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-22 06:57:51 +00:00
parent
e479b9e8e8
commit
0c2bdf9edd
@ -4,8 +4,8 @@ LIB_INC_DIR = $(LIB_DIR)/include
|
||||
# FIXME should we *really* dde_kit to this shared library?
|
||||
LIBS += dde_kit libc-setjmp config
|
||||
SRC_CC += main.cc lx_emul.cc irq.cc timer.cc event.cc storage.cc \
|
||||
input_component.cc nic.cc
|
||||
SRC_C += dummies.c scsi.c evdev.c
|
||||
input_component.cc nic.cc raw.cc
|
||||
SRC_C += dummies.c scsi.c evdev.c raw_driver.c
|
||||
|
||||
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/lib/usb
|
||||
DRIVERS_DIR := $(LX_CONTRIB_DIR)/drivers
|
||||
@ -110,6 +110,8 @@ vpath %.cc $(LIB_DIR)/input
|
||||
vpath %.cc $(LIB_DIR)/storage
|
||||
vpath %.c $(LIB_DIR)/storage
|
||||
vpath %.cc $(LIB_DIR)/nic
|
||||
vpath %.cc $(LIB_DIR)/raw
|
||||
vpath %.c $(LIB_DIR)/raw
|
||||
vpath lib/int_sqrt.c $(LX_CONTRIB_DIR)
|
||||
|
||||
# vi: set ft=make :
|
||||
|
@ -4,6 +4,13 @@
|
||||
* \date 2013-02-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2014 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 <os/server.h>
|
||||
|
||||
extern void start_usb_driver(Server::Entrypoint &e);
|
||||
|
@ -4,6 +4,13 @@
|
||||
* \date 2013-02-20
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2013-2014 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.
|
||||
*/
|
||||
|
||||
int main()
|
||||
{
|
||||
extern void start_usb_driver();
|
||||
|
@ -22,7 +22,9 @@
|
||||
|
||||
/* Emulation */
|
||||
#include <platform/platform.h>
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
#include <platform.h>
|
||||
|
||||
/* Linux */
|
||||
|
@ -19,7 +19,10 @@
|
||||
#include <io_mem_session/connection.h>
|
||||
#include <util/mmio.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
#include <linux/platform_data/usb-omap.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
@ -19,7 +19,10 @@
|
||||
/* emulation */
|
||||
#include <platform/platform.h>
|
||||
#include <platform.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
/* dwc-otg */
|
||||
#define new new_
|
||||
|
@ -107,14 +107,6 @@ char *kstrdup(const char *s, gfp_t gfp) { TRACE; return 0; }
|
||||
char *strstr(const char *h, const char *n) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/nls.h **
|
||||
*****************/
|
||||
|
||||
int utf16s_to_utf8s(const wchar_t *pwcs, int len,
|
||||
enum utf16_endian endian, u8 *s, int maxlen) { TRACE; return 0; }
|
||||
|
||||
|
||||
/*******************
|
||||
** linux/ctype.h **
|
||||
*******************/
|
||||
@ -344,7 +336,6 @@ void device_unregister(struct device *dev) { TRACE; }
|
||||
void device_lock(struct device *dev) { TRACE; }
|
||||
int device_trylock(struct device *dev) { TRACE; return 0; }
|
||||
void device_unlock(struct device *dev) { TRACE; }
|
||||
void device_del(struct device *dev) { TRACE; }
|
||||
void device_initialize(struct device *dev) { TRACE; }
|
||||
int device_attach(struct device *dev) { TRACE; return 0; }
|
||||
int device_is_registered(struct device *dev) { TRACE; return 0; }
|
||||
|
26
repos/dde_linux/src/lib/usb/include/extern_c_begin.h
Normal file
26
repos/dde_linux/src/lib/usb/include/extern_c_begin.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* \brief Include before including Linux headers in C++
|
||||
* \author Christian Helmuth
|
||||
* \date 2014-08-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#define extern_c_begin
|
||||
|
||||
extern "C" {
|
||||
|
||||
/* some warnings should only be switched of for Linux headers */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wpointer-arith"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
/* deal with C++ keywords used for identifiers etc. */
|
||||
#define private private_
|
||||
#define class class_
|
||||
#define new new_
|
20
repos/dde_linux/src/lib/usb/include/extern_c_end.h
Normal file
20
repos/dde_linux/src/lib/usb/include/extern_c_end.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* \brief Include after including Linux headers in C++
|
||||
* \author Christian Helmuth
|
||||
* \date 2014-08-21
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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.
|
||||
*/
|
||||
|
||||
#undef new
|
||||
#undef class
|
||||
#undef private
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
} /* extern "C" */
|
@ -18,10 +18,6 @@
|
||||
#ifndef _LX_EMUL_H_
|
||||
#define _LX_EMUL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* DDE Kit includes */
|
||||
#include <dde_kit/types.h>
|
||||
#include <dde_kit/printf.h>
|
||||
@ -1583,11 +1579,6 @@ bool device_can_wakeup(struct device *dev);
|
||||
** linux/device.h **
|
||||
********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define class device_class
|
||||
#endif
|
||||
|
||||
|
||||
#define dev_info(dev, format, arg...) dde_kit_printf("dev_info: " format, ## arg)
|
||||
#define dev_warn(dev, format, arg...) dde_kit_printf("dev_warn: " format, ## arg)
|
||||
#define dev_WARN(dev, format, arg...) dde_kit_printf("dev_WARN: " format, ## arg)
|
||||
@ -1807,10 +1798,6 @@ void devm_kfree(struct device *dev, void *p);
|
||||
|
||||
void *dev_get_platdata(const struct device *dev);
|
||||
|
||||
#ifdef __cplusplus
|
||||
#undef class
|
||||
#endif
|
||||
|
||||
|
||||
/*****************************
|
||||
** linux/platform_device.h **
|
||||
@ -2389,10 +2376,6 @@ typedef enum { PCI_D0 = 0 } pci_power_t;
|
||||
/*
|
||||
* Deal with C++ keyword used as member name of 'pci_dev'
|
||||
*/
|
||||
#ifdef __cplusplus
|
||||
#define class device_class
|
||||
#endif /* __cplusplus */
|
||||
|
||||
struct msix_entry
|
||||
{
|
||||
u32 vector;
|
||||
@ -2436,9 +2419,6 @@ struct pci_fixup {
|
||||
unsigned int class_shift; /* should be 0, 8, 16 */
|
||||
void (*hook)(struct pci_dev *dev);
|
||||
};
|
||||
#ifdef __cplusplus
|
||||
#undef class
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
/* quirks */
|
||||
@ -2780,9 +2760,7 @@ enum { HID_DEBUG_BUFSIZE=512 };
|
||||
** linux/list.h **
|
||||
******************/
|
||||
|
||||
#define new _new
|
||||
#include <linux/list.h>
|
||||
#undef new
|
||||
|
||||
|
||||
/********************
|
||||
@ -3906,8 +3884,4 @@ static inline void trace_xhci_dbg_reset_ep(struct va_format *v) { }
|
||||
static inline void trace_xhci_dbg_quirks(struct va_format *v) { }
|
||||
static inline void trace_xhci_dbg_address(struct va_format *v) { }
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* _LX_EMUL_H_ */
|
||||
|
@ -23,26 +23,24 @@
|
||||
struct Services
|
||||
{
|
||||
/* USB profiles */
|
||||
bool hid;
|
||||
bool stor;
|
||||
bool nic;
|
||||
bool hid = false;
|
||||
bool stor = false;
|
||||
bool nic = false;
|
||||
bool raw = false;
|
||||
|
||||
/* Controller types */
|
||||
bool uhci; /* 1.0 */
|
||||
bool ehci; /* 2.0 */
|
||||
bool xhci; /* 3.0 */
|
||||
bool uhci = false; /* 1.0 */
|
||||
bool ehci = false; /* 2.0 */
|
||||
bool xhci = false; /* 3.0 */
|
||||
|
||||
/*
|
||||
* Screen resolution used by touch devices to convert touchscreen
|
||||
* absolute coordinates to screen absolute coordinates
|
||||
*/
|
||||
unsigned long screen_x;
|
||||
unsigned long screen_y;
|
||||
unsigned long screen_x = 0;
|
||||
unsigned long screen_y = 0;
|
||||
|
||||
Services()
|
||||
: hid(false), stor(false), nic(false),
|
||||
uhci(false), ehci(false), xhci(false),
|
||||
screen_x(0), screen_y(0)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
@ -76,6 +74,13 @@ struct Services
|
||||
PDBG("No <nic> config node found - not starting the USB Nic (Network) service");
|
||||
}
|
||||
|
||||
try {
|
||||
config()->xml_node().sub_node("raw");
|
||||
raw = true;
|
||||
} catch (Xml_node::Nonexistent_sub_node) {
|
||||
PDBG("No <raw> config node found - not starting external USB service");
|
||||
}
|
||||
|
||||
try {
|
||||
if (!config()->xml_node().attribute("uhci").has_value("yes"))
|
||||
throw -1;
|
||||
|
@ -170,24 +170,25 @@ class Routine : public Genode::List<Routine>::Element
|
||||
/**
|
||||
* Add an object
|
||||
*/
|
||||
static void add(int (*func)(void *), void *arg, char const *name,
|
||||
bool started = false)
|
||||
static Routine *add(int (*func)(void *), void *arg, char const *name,
|
||||
bool started = false)
|
||||
{
|
||||
_list()->insert(new (Genode::env()->heap())
|
||||
Routine(func, arg, name, started));
|
||||
Routine *r = new (Genode::env()->heap()) Routine(func, arg, name, started);
|
||||
_list()->insert(r);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove this object
|
||||
*/
|
||||
static void remove()
|
||||
static void remove(Routine *r = nullptr)
|
||||
{
|
||||
if (!_current)
|
||||
if (!_current && !r)
|
||||
return;
|
||||
|
||||
_dead = _current;
|
||||
_dead = r ? r : _current;
|
||||
|
||||
schedule();
|
||||
schedule_main();
|
||||
}
|
||||
|
||||
static void main()
|
||||
|
@ -98,4 +98,9 @@ namespace Nic
|
||||
void init(Server::Entrypoint &ep);
|
||||
}
|
||||
|
||||
namespace Raw
|
||||
{
|
||||
void init(Server::Entrypoint &ep);
|
||||
}
|
||||
|
||||
#endif /* _SIGNAL_H_ */
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include <input/root.h>
|
||||
#include <os/ring_buffer.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
#undef RELEASE
|
||||
|
||||
|
@ -22,9 +22,12 @@
|
||||
/* Local includes */
|
||||
#include "routine.h"
|
||||
#include "signal.h"
|
||||
#include "lx_emul.h"
|
||||
#include "platform/lx_mem.h"
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include "lx_emul.h"
|
||||
#include <extern_c_end.h>
|
||||
|
||||
/* DDE kit includes */
|
||||
extern "C" {
|
||||
#include <dde_kit/semaphore.h>
|
||||
@ -770,8 +773,8 @@ class Driver : public Genode::List<Driver>::Element
|
||||
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);
|
||||
dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p %p",
|
||||
_drv->name, ret, _drv->bus->match, _drv->probe);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -786,7 +789,7 @@ class Driver : public Genode::List<Driver>::Element
|
||||
dde_kit_log(DEBUG_DRIVER, "Probing device bus %p", dev->bus->probe);
|
||||
return dev->bus->probe(dev);
|
||||
} else if (_drv->probe) {
|
||||
dde_kit_log(DEBUG_DRIVER, "Probing driver: %s", _drv->name);
|
||||
dde_kit_log(DEBUG_DRIVER, "Probing driver: %s %p", _drv->name, _drv->probe);
|
||||
return _drv->probe(dev);
|
||||
}
|
||||
|
||||
@ -822,6 +825,14 @@ int device_add(struct device *dev)
|
||||
}
|
||||
|
||||
|
||||
void device_del(struct device *dev)
|
||||
{
|
||||
dde_kit_log(DEBUG_DRIVER, "Remove device %p", dev);
|
||||
if (dev->driver && dev->driver->remove)
|
||||
dev->driver->remove(dev);
|
||||
}
|
||||
|
||||
|
||||
int device_register(struct device *dev)
|
||||
{
|
||||
//XXX: initialize DMA pools (see device_initialize)
|
||||
@ -870,7 +881,6 @@ void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp)
|
||||
|
||||
void *dev_get_platdata(const struct device *dev)
|
||||
{
|
||||
PDBG("called");
|
||||
return (void *)dev->platform_data;
|
||||
}
|
||||
|
||||
@ -1312,3 +1322,23 @@ int waitqueue_active(wait_queue_head_t *q)
|
||||
{
|
||||
return q->q ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/*****************
|
||||
** linux/nls.h **
|
||||
*****************/
|
||||
|
||||
int utf16s_to_utf8s(const wchar_t *pwcs, int len,
|
||||
enum utf16_endian endian, u8 *s, int maxlen)
|
||||
{
|
||||
/*
|
||||
* We do not convert to char, we simply copy the UTF16 plane 0 values
|
||||
*/
|
||||
u16 *out = (u16 *)s;
|
||||
u16 *in = (u16 *)pwcs;
|
||||
int length = Genode::min(len, maxlen / 2);
|
||||
for (int i = 0; i < length; i++)
|
||||
out[i] = in[i];
|
||||
|
||||
return 2 * length;
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ extern "C" void module_usb_storage_driver_init();
|
||||
extern "C" void module_wacom_driver_init();
|
||||
extern "C" void module_ch_driver_init();
|
||||
extern "C" void module_mt_driver_init();
|
||||
extern "C" void module_raw_driver_init();
|
||||
|
||||
extern "C" void start_input_service(void *ep, unsigned long, unsigned long);
|
||||
|
||||
@ -81,6 +82,10 @@ static void init(Services *services)
|
||||
/* storage */
|
||||
if (services->stor)
|
||||
module_usb_storage_driver_init();
|
||||
|
||||
if (services->raw)
|
||||
/* low level interface */
|
||||
module_raw_driver_init();
|
||||
}
|
||||
|
||||
|
||||
@ -97,6 +102,9 @@ void start_usb_driver(Server::Entrypoint &ep)
|
||||
Storage::init(ep);
|
||||
Nic::init(ep);
|
||||
|
||||
if (services.raw)
|
||||
Raw::init(ep);
|
||||
|
||||
Routine::add(0, 0, "Main", true);
|
||||
Routine::make_main_current();
|
||||
init(&services);
|
||||
|
@ -19,15 +19,15 @@
|
||||
#include <nic/xml_node.h>
|
||||
#include <util/xml_node.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/usbnet.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
#include <nic/component.h>
|
||||
#include "signal.h"
|
||||
|
||||
extern "C" {
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/usbnet.h>
|
||||
}
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
|
@ -18,7 +18,9 @@
|
||||
#include <pci_device/client.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
#include <platform/lx_mem.h>
|
||||
|
||||
struct bus_type pci_bus_type;
|
||||
@ -56,7 +58,7 @@ class Pci_driver
|
||||
|
||||
_dev->vendor = client.vendor_id();
|
||||
_dev->device = client.device_id();
|
||||
_dev->device_class = client.class_code();
|
||||
_dev->class_ = client.class_code();
|
||||
_dev->revision = client.config_read(REV, Device::ACCESS_8BIT);
|
||||
_dev->dev.driver = &_drv->driver;
|
||||
|
||||
@ -236,15 +238,15 @@ int pci_register_driver(struct pci_driver *drv)
|
||||
|
||||
bool found = false;
|
||||
|
||||
while (id->device_class || id->class_mask || id->device_class) {
|
||||
while (id->class_ || id->class_mask || id->class_) {
|
||||
|
||||
if (id->device_class == (unsigned)PCI_ANY_ID) {
|
||||
if (id->class_ == (unsigned)PCI_ANY_ID) {
|
||||
dde_kit_log(DEBUG_PCI, "Skipping PCI_ANY_ID device class");
|
||||
id++;
|
||||
continue;
|
||||
}
|
||||
|
||||
Pci::Device_capability cap = pci.first_device(id->device_class,
|
||||
Pci::Device_capability cap = pci.first_device(id->class_,
|
||||
id->class_mask);
|
||||
while (cap.valid()) {
|
||||
|
||||
@ -278,7 +280,7 @@ int pci_register_driver(struct pci_driver *drv)
|
||||
}
|
||||
|
||||
Pci::Device_capability free_up = cap;
|
||||
cap = pci.next_device(cap, id->device_class, id->class_mask);
|
||||
cap = pci.next_device(cap, id->class_, id->class_mask);
|
||||
if (!pci_drv)
|
||||
pci.release_device(free_up);
|
||||
}
|
||||
|
694
repos/dde_linux/src/lib/usb/raw/raw.cc
Normal file
694
repos/dde_linux/src/lib/usb/raw/raw.cc
Normal file
@ -0,0 +1,694 @@
|
||||
/**
|
||||
* \brief Server side USB session implementation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
#include <root/component.h>
|
||||
#include <usb_session/rpc_object.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <linux/usb.h>
|
||||
#include "raw.h"
|
||||
#include <extern_c_end.h>
|
||||
#include <signal.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
extern "C" int usb_set_configuration(struct usb_device *dev, int configuration);
|
||||
|
||||
constexpr bool verbose_raw = false;
|
||||
|
||||
|
||||
namespace Usb {
|
||||
class Session_component;
|
||||
class Root;
|
||||
class Worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep track of all registered USB devices (via raw driver)
|
||||
*/
|
||||
struct Device : List<Device>::Element
|
||||
{
|
||||
usb_device *udev;
|
||||
|
||||
Device(usb_device *udev) : udev(udev)
|
||||
{
|
||||
list()->insert(this);
|
||||
}
|
||||
|
||||
~Device() { list()->remove(this); }
|
||||
|
||||
static List<Device> *list()
|
||||
{
|
||||
static List<Device> _l;
|
||||
return &_l;
|
||||
}
|
||||
|
||||
static Device * device(uint16_t vendor, uint16_t product)
|
||||
{
|
||||
for (Device *d = list()->first(); d; d = d->next()) {
|
||||
if (d->udev->descriptor.idVendor == vendor && d->udev->descriptor.idProduct == product)
|
||||
return d;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
usb_interface *interface(unsigned index)
|
||||
{
|
||||
usb_interface *iface = udev->actconfig->interface[index];
|
||||
return iface;
|
||||
}
|
||||
|
||||
usb_host_endpoint *endpoint(usb_interface *iface, unsigned alt_setting,
|
||||
unsigned endpoint_num)
|
||||
{
|
||||
return &iface->altsetting[alt_setting].endpoint[endpoint_num];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle packet stream request, this way the entrypoint always returns to it's
|
||||
* server loop
|
||||
*/
|
||||
class Usb::Worker
|
||||
{
|
||||
private:
|
||||
|
||||
completion _packet_avail;
|
||||
|
||||
Session::Tx::Sink *_sink;
|
||||
Device *_device = nullptr;
|
||||
Signal_context_capability _sigh_ready;
|
||||
Routine *_routine = nullptr;
|
||||
unsigned _p_in_flight = 0;
|
||||
|
||||
void _ack_packet(Packet_descriptor &p)
|
||||
{
|
||||
_sink->acknowledge_packet(p);
|
||||
_p_in_flight--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve string descriptor at index given in packet
|
||||
*/
|
||||
void _retrieve_string(Packet_descriptor &p)
|
||||
{
|
||||
char *buffer = _sink->packet_content(p);
|
||||
int length;
|
||||
|
||||
if ((length = usb_string(_device->udev, p.string.index, buffer, p.size())) < 0) {
|
||||
PWRN("Could not read string descriptor index: %u", p.string.index);
|
||||
p.string.length = 0;
|
||||
} else {
|
||||
/* returned length is in bytes (char) */
|
||||
p.string.length = length / 2;
|
||||
p.succeded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read control transfer
|
||||
*/
|
||||
void _ctrl_in(Packet_descriptor &p)
|
||||
{
|
||||
void *buf = kmalloc(4096, GFP_NOIO);
|
||||
|
||||
int err = usb_control_msg(_device->udev, usb_rcvctrlpipe(_device->udev, 0),
|
||||
p.control.request, p.control.request_type,
|
||||
p.control.value, p.control.index, buf,
|
||||
p.size(), p.control.timeout);
|
||||
|
||||
if (err > 0 && p.size())
|
||||
Genode::memcpy(_sink->packet_content(p), buf, err);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if (err < 0 && err != -EPIPE) {
|
||||
p.succeded = false;
|
||||
return;
|
||||
}
|
||||
|
||||
p.succeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write control transfer
|
||||
*/
|
||||
void _ctrl_out(Packet_descriptor &p)
|
||||
{
|
||||
void *buf = kmalloc(4096, GFP_NOIO);
|
||||
|
||||
if (p.size())
|
||||
Genode::memcpy(buf, _sink->packet_content(p), p.size());
|
||||
|
||||
int err = usb_control_msg(_device->udev, usb_sndctrlpipe(_device->udev, 0),
|
||||
p.control.request, p.control.request_type,
|
||||
p.control.value, p.control.index, buf, p.size(),
|
||||
p.control.timeout);
|
||||
if (err >= 0 || err== -EPIPE)
|
||||
p.succeded = true;
|
||||
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronous transfer helpers
|
||||
*/
|
||||
struct Complete_data
|
||||
{
|
||||
Worker *worker;
|
||||
Packet_descriptor packet;
|
||||
};
|
||||
|
||||
void _async_finish(Packet_descriptor &p, urb *urb, bool read)
|
||||
{
|
||||
p.transfer.actual_size = urb->actual_length;
|
||||
p.succeded = true;
|
||||
|
||||
if (read)
|
||||
Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer,
|
||||
urb->actual_length);
|
||||
|
||||
_ack_packet(p);
|
||||
}
|
||||
|
||||
static void _async_complete(urb *urb)
|
||||
{
|
||||
Complete_data *data = (Complete_data *)urb->context;
|
||||
|
||||
data->worker->_async_finish(data->packet, urb,
|
||||
!!(data->packet.transfer.ep & USB_DIR_IN));
|
||||
kfree (data);
|
||||
kfree (urb->transfer_buffer);
|
||||
usb_free_urb(urb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bulk transfer
|
||||
*/
|
||||
bool _bulk(Packet_descriptor &p, bool read)
|
||||
{
|
||||
unsigned pipe;
|
||||
void *buf = kmalloc(p.size(), GFP_NOIO);
|
||||
|
||||
if (read)
|
||||
pipe = usb_rcvbulkpipe(_device->udev, p.transfer.ep);
|
||||
else {
|
||||
pipe = usb_sndbulkpipe(_device->udev, p.transfer.ep);
|
||||
Genode::memcpy(buf, _sink->packet_content(p), p.size());
|
||||
}
|
||||
|
||||
urb *bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!bulk_urb) {
|
||||
PERR("Failed to allocate bulk URB");
|
||||
kfree(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
Complete_data *data = (Complete_data *)kmalloc(sizeof(Complete_data), GFP_KERNEL);
|
||||
data->packet = p;
|
||||
data->worker = this;
|
||||
|
||||
usb_fill_bulk_urb(bulk_urb, _device->udev, pipe, buf, p.size(),
|
||||
_async_complete, data);
|
||||
|
||||
if (usb_submit_urb(bulk_urb, GFP_KERNEL))
|
||||
PERR("Failed to submit URB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* IRQ transfer
|
||||
*/
|
||||
bool _irq(Packet_descriptor &p, bool read)
|
||||
{
|
||||
unsigned pipe;
|
||||
void *buf = kmalloc(p.size(), GFP_NOIO);
|
||||
|
||||
if (read)
|
||||
pipe = usb_rcvintpipe(_device->udev, p.transfer.ep);
|
||||
else {
|
||||
pipe = usb_sndintpipe(_device->udev, p.transfer.ep);
|
||||
Genode::memcpy(buf, _sink->packet_content(p), p.size());
|
||||
}
|
||||
|
||||
urb *irq_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
if (!irq_urb) {
|
||||
PERR("Failed to allocate interrupt URB");
|
||||
kfree(buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
Complete_data *data = (Complete_data *)kmalloc(sizeof(Complete_data), GFP_KERNEL);
|
||||
data->packet = p;
|
||||
data->worker = this;
|
||||
|
||||
usb_fill_int_urb(irq_urb, _device->udev, pipe, buf, p.size(),
|
||||
_async_complete, data, p.transfer.timeout);
|
||||
|
||||
if (usb_submit_urb(irq_urb, GFP_KERNEL))
|
||||
PERR("Failed to submit URB");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change alternate settings for device
|
||||
*/
|
||||
void _alt_setting(Packet_descriptor &p)
|
||||
{
|
||||
int err = usb_set_interface(_device->udev, p.interface.number,
|
||||
p.interface.alt_setting);
|
||||
if (!err)
|
||||
p.succeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set configuration
|
||||
*/
|
||||
void _config(Packet_descriptor &p)
|
||||
{
|
||||
usb_host_config *config = _device->udev->actconfig;
|
||||
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
for (unsigned i = 0; i < config->desc.bNumInterfaces; i++) {
|
||||
if (usb_interface_claimed(config->interface[i])) {
|
||||
PERR("There are interfaces claimed, won't set configuration");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int err = usb_set_configuration(_device->udev, p.number);
|
||||
|
||||
if (!err)
|
||||
p.succeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release interface
|
||||
*/
|
||||
void _release_interface(Packet_descriptor &p)
|
||||
{
|
||||
usb_interface *iface = _device->interface(p.number);
|
||||
|
||||
if (!iface)
|
||||
return;
|
||||
|
||||
usb_driver_release_interface(&raw_intf_driver, iface);
|
||||
p.succeded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch incoming packet types
|
||||
*/
|
||||
void _dispatch()
|
||||
{
|
||||
/*
|
||||
* Get packets until there are no more free ack slots or avaiable
|
||||
* packets
|
||||
*/
|
||||
while (_p_in_flight < _sink->ack_slots_free() && _sink->packet_avail())
|
||||
{
|
||||
Packet_descriptor p = _sink->get_packet();
|
||||
|
||||
if (verbose_raw)
|
||||
PDBG("PACKET: %u first value: %x", p.type, p.number);
|
||||
|
||||
_p_in_flight++;
|
||||
|
||||
if (!_device || !_device->udev) {
|
||||
_ack_packet(p);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (p.type) {
|
||||
|
||||
case Packet_descriptor::STRING:
|
||||
_retrieve_string(p);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CTRL:
|
||||
if (p.control.request_type & Usb::ENDPOINT_IN)
|
||||
_ctrl_in(p);
|
||||
else
|
||||
_ctrl_out(p);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::BULK:
|
||||
if (_bulk(p, !!(p.transfer.ep & USB_DIR_IN)))
|
||||
continue;
|
||||
|
||||
case Packet_descriptor::IRQ:
|
||||
if (_irq(p, !!(p.transfer.ep & USB_DIR_IN)))
|
||||
continue;
|
||||
|
||||
case Packet_descriptor::ALT_SETTING:
|
||||
_alt_setting(p);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::CONFIG:
|
||||
_config(p);
|
||||
break;
|
||||
|
||||
case Packet_descriptor::RELEASE_IF:
|
||||
_release_interface(p);
|
||||
break;
|
||||
}
|
||||
|
||||
_ack_packet(p);
|
||||
}
|
||||
}
|
||||
|
||||
void _wait_for_device()
|
||||
{
|
||||
_wait_event(_device);
|
||||
_wait_event(_device->udev->actconfig);
|
||||
|
||||
/* set raw driver */
|
||||
_device->udev->dev.driver = &raw_driver.drvwrap.driver;
|
||||
|
||||
if (_sigh_ready.valid())
|
||||
Signal_transmitter(_sigh_ready).submit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for packets
|
||||
*/
|
||||
void _wait()
|
||||
{
|
||||
/* wait for device to become ready */
|
||||
init_completion(&_packet_avail);
|
||||
|
||||
_wait_for_device();
|
||||
|
||||
while (true) {
|
||||
wait_for_completion(&_packet_avail);
|
||||
|
||||
_dispatch();
|
||||
Routine::schedule_all();
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
static int run(void *worker)
|
||||
{
|
||||
Worker *w = static_cast<Worker *>(worker);
|
||||
w->_wait();
|
||||
return 0;
|
||||
}
|
||||
|
||||
Worker(Session::Tx::Sink *sink)
|
||||
: _sink(sink)
|
||||
{ }
|
||||
|
||||
void start()
|
||||
{
|
||||
if (!_routine)
|
||||
_routine = Routine::add(run, this, "worker");
|
||||
}
|
||||
|
||||
void stop()
|
||||
{
|
||||
if (_routine)
|
||||
Routine::remove(_routine);
|
||||
_routine = nullptr;
|
||||
}
|
||||
|
||||
void packet_avail() { ::complete(&_packet_avail); }
|
||||
|
||||
void device(Device *device, Signal_context_capability sigh_ready = Signal_context_capability())
|
||||
{
|
||||
_device = device;
|
||||
_sigh_ready = sigh_ready;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*****************
|
||||
** USB session **
|
||||
*****************/
|
||||
|
||||
class Usb::Session_component : public Session_rpc_object,
|
||||
public List<Session_component>::Element
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
unsigned long _vendor;
|
||||
unsigned long _product;
|
||||
Device *_device = nullptr;
|
||||
Signal_context_capability _sigh_state_change;
|
||||
Signal_rpc_member<Session_component> _packet_avail;
|
||||
Signal_rpc_member<Session_component> _ready_ack;
|
||||
Worker _worker;
|
||||
|
||||
|
||||
void _signal_state_change()
|
||||
{
|
||||
if (_sigh_state_change.valid())
|
||||
Signal_transmitter(_sigh_state_change).submit(1);
|
||||
}
|
||||
|
||||
void _receive(unsigned)
|
||||
{
|
||||
_worker.packet_avail();
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
enum State {
|
||||
DEVICE_ADD,
|
||||
DEVICE_REMOVE,
|
||||
};
|
||||
|
||||
Session_component(Genode::Dataspace_capability tx_ds, Server::Entrypoint &ep,
|
||||
unsigned long vendor, unsigned long product)
|
||||
: Session_rpc_object(tx_ds, ep.rpc_ep()),
|
||||
_ep(ep),
|
||||
_vendor(vendor), _product(product),
|
||||
_packet_avail(ep, *this, &Session_component::_receive),
|
||||
_ready_ack(ep, *this, &Session_component::_receive),
|
||||
_worker(sink())
|
||||
{
|
||||
_device = Device::device(_vendor, _product);
|
||||
if (_device)
|
||||
PDBG("Found device");
|
||||
|
||||
/* register signal handlers */
|
||||
_tx.sigh_packet_avail(_packet_avail);
|
||||
}
|
||||
|
||||
/***********************
|
||||
** Session interface **
|
||||
***********************/
|
||||
|
||||
bool plugged() { return _device != nullptr; }
|
||||
|
||||
void claim_interface(unsigned interface_num) override
|
||||
{
|
||||
usb_interface *iface = _device->interface(interface_num);
|
||||
if (!iface)
|
||||
throw Interface_not_found();
|
||||
|
||||
if (usb_driver_claim_interface(&raw_intf_driver, iface, nullptr))
|
||||
throw Interface_already_claimed();
|
||||
}
|
||||
|
||||
void config_descriptor(Device_descriptor *device_descr,
|
||||
Config_descriptor *config_descr) override
|
||||
{
|
||||
Genode::memcpy(device_descr, &_device->udev->descriptor, sizeof(usb_device_descriptor));
|
||||
Genode::memcpy(config_descr, &_device->udev->actconfig->desc, sizeof(usb_config_descriptor));
|
||||
|
||||
device_descr->bus = _device->udev->bus->busnum;
|
||||
device_descr->num = _device->udev->devnum;
|
||||
device_descr->speed = _device->udev->speed;
|
||||
}
|
||||
|
||||
unsigned alt_settings(unsigned index) override
|
||||
{
|
||||
return _device->interface(index)->num_altsetting;
|
||||
}
|
||||
|
||||
void interface_descriptor(unsigned index, unsigned alt_setting,
|
||||
Interface_descriptor *interface_descr) override
|
||||
{
|
||||
if (!_device)
|
||||
throw Device_not_found();
|
||||
|
||||
if (index >= _device->udev->actconfig->desc.bNumInterfaces)
|
||||
throw Interface_not_found();
|
||||
|
||||
usb_interface *iface = _device->interface(index);
|
||||
Genode::memcpy(interface_descr, &iface->altsetting[alt_setting].desc,
|
||||
sizeof(usb_interface_descriptor));
|
||||
|
||||
if (&iface->altsetting[alt_setting] == iface->cur_altsetting)
|
||||
interface_descr->active = true;
|
||||
}
|
||||
|
||||
void endpoint_descriptor(unsigned interface_num,
|
||||
unsigned alt_setting,
|
||||
unsigned endpoint_num,
|
||||
Endpoint_descriptor *endpoint_descr) override
|
||||
{
|
||||
if (!_device)
|
||||
throw Device_not_found();
|
||||
|
||||
if (interface_num >= _device->udev->actconfig->desc.bNumInterfaces)
|
||||
throw Interface_not_found();
|
||||
|
||||
usb_interface *iface = usb_ifnum_to_if(_device->udev, interface_num);
|
||||
Genode::memcpy(endpoint_descr, &_device->endpoint(iface, alt_setting,
|
||||
endpoint_num)->desc, sizeof(usb_endpoint_descriptor));
|
||||
}
|
||||
|
||||
/*********************
|
||||
** Local interface **
|
||||
*********************/
|
||||
|
||||
bool session_device(Device *device)
|
||||
{
|
||||
usb_device_descriptor *descr = &device->udev->descriptor;
|
||||
return (descr->idVendor == _vendor && descr->idProduct == _product) ? true : false;
|
||||
}
|
||||
|
||||
bool state_change(State state, Device *device)
|
||||
{
|
||||
switch (state) {
|
||||
case DEVICE_ADD:
|
||||
if (!session_device(device))
|
||||
return false;
|
||||
|
||||
if (_device)
|
||||
PWRN("Device type already present (vendor: %x product: %x). Overwrite!",
|
||||
device->udev->descriptor.idVendor,
|
||||
device->udev->descriptor.idProduct);
|
||||
|
||||
_device = device;
|
||||
_worker.device(_device, _sigh_state_change);
|
||||
_worker.start();
|
||||
return true;
|
||||
|
||||
case DEVICE_REMOVE:
|
||||
if (!session_device(device))
|
||||
return false;
|
||||
_device = nullptr;
|
||||
_worker.stop();
|
||||
_signal_state_change();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void sigh_state_change(Signal_context_capability sigh) { _sigh_state_change = sigh; }
|
||||
};
|
||||
|
||||
|
||||
struct Session : public List<Usb::Session_component>
|
||||
{
|
||||
static Session *list()
|
||||
{
|
||||
static Session _l;
|
||||
return &_l;
|
||||
}
|
||||
|
||||
void state_change(Usb::Session_component::State state, Device *device)
|
||||
{
|
||||
for (Usb::Session_component *session = list()->first(); session; session = session->next())
|
||||
if (session->state_change(state, device))
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Root : public Genode::Root_component<Session_component>
|
||||
{
|
||||
private:
|
||||
|
||||
Server::Entrypoint &_ep;
|
||||
|
||||
protected:
|
||||
|
||||
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);
|
||||
|
||||
unsigned long vendor = Arg_string::find_arg(args, "vendor").ulong_value(0);
|
||||
unsigned long product = Arg_string::find_arg(args, "product").ulong_value(0);
|
||||
|
||||
/* check session quota */
|
||||
size_t session_size = max<size_t>(4096, sizeof(Session_component));
|
||||
if (ram_quota < session_size)
|
||||
throw Root::Quota_exceeded();
|
||||
|
||||
if (tx_buf_size > ram_quota - session_size) {
|
||||
PERR("Insufficient 'ram_quota',got %zu, need %zu",
|
||||
ram_quota, tx_buf_size + session_size);
|
||||
throw Root::Quota_exceeded();
|
||||
}
|
||||
|
||||
Dataspace_capability tx_ds = env()->ram_session()->alloc(tx_buf_size);
|
||||
Session_component *session = new (md_alloc())
|
||||
Session_component(tx_ds, _ep, vendor, product);
|
||||
::Session::list()->insert(session);
|
||||
return session;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Root(Server::Entrypoint &session_ep,
|
||||
Genode::Allocator *md_alloc)
|
||||
: Genode::Root_component<Session_component>(&session_ep.rpc_ep(), md_alloc),
|
||||
_ep(session_ep) { }
|
||||
};
|
||||
|
||||
|
||||
void Raw::init(Server::Entrypoint &ep)
|
||||
{
|
||||
static Usb::Root root(ep, env()->heap());
|
||||
Genode::env()->parent()->announce(ep.rpc_ep().manage(&root));
|
||||
}
|
||||
|
||||
|
||||
/*****************
|
||||
** C interface **
|
||||
*****************/
|
||||
|
||||
void raw_register_device(struct usb_device *udev)
|
||||
{
|
||||
::Session::list()->state_change(Usb::Session_component::DEVICE_ADD,
|
||||
new (env()->heap()) Device(udev));
|
||||
}
|
||||
|
||||
|
||||
void raw_unregister_device(struct usb_device *udev)
|
||||
{
|
||||
Device *dev = Device::device(udev->descriptor.idVendor,
|
||||
udev->descriptor.idProduct);
|
||||
if (dev)
|
||||
::Session::list()->state_change(Usb::Session_component::DEVICE_REMOVE, dev);
|
||||
}
|
||||
|
14
repos/dde_linux/src/lib/usb/raw/raw.h
Normal file
14
repos/dde_linux/src/lib/usb/raw/raw.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef _RAW_H_
|
||||
#define _RAW_H_
|
||||
|
||||
struct usb_device;
|
||||
struct usb_driver;
|
||||
|
||||
extern struct usb_device_driver raw_driver;
|
||||
extern struct usb_driver raw_intf_driver;
|
||||
|
||||
void raw_register_device(struct usb_device *udev);
|
||||
void raw_unregister_device(struct usb_device *udev);
|
||||
|
||||
|
||||
#endif /* _RAW_H_ */
|
87
repos/dde_linux/src/lib/usb/raw/raw_driver.c
Normal file
87
repos/dde_linux/src/lib/usb/raw/raw_driver.c
Normal file
@ -0,0 +1,87 @@
|
||||
/**
|
||||
* \brief Low level USB access driver
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-11-11
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 <linux/usb.h>
|
||||
#include "raw.h"
|
||||
|
||||
static int raw_probe(struct usb_device *udev)
|
||||
{
|
||||
printk("RAW: vendor: %x product: %x dev %p\n",
|
||||
udev->descriptor.idVendor, udev->descriptor.idProduct, udev);
|
||||
|
||||
raw_register_device(udev);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void raw_disconnect(struct usb_device *udev)
|
||||
{
|
||||
printk("driver disconnect called\n");
|
||||
raw_unregister_device(udev);
|
||||
}
|
||||
|
||||
|
||||
struct usb_device_driver raw_driver =
|
||||
{
|
||||
.name = "raw",
|
||||
.probe = raw_probe,
|
||||
.disconnect = raw_disconnect,
|
||||
.supports_autosuspend = 0,
|
||||
};
|
||||
|
||||
|
||||
static int raw_intf_probe(struct usb_interface *intf,
|
||||
struct usb_device_id const *id)
|
||||
{
|
||||
struct usb_device *udev = interface_to_usbdev(intf);
|
||||
|
||||
printk("RAW_INTF: vendor: %04x product: %04x\n", udev->descriptor.idVendor,
|
||||
udev->descriptor.idProduct);
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
void raw_intf_disconnect(struct usb_interface *intf) { }
|
||||
|
||||
static const struct usb_device_id raw_intf_id_table[] = {
|
||||
{ .driver_info = 1 }
|
||||
};
|
||||
|
||||
|
||||
struct usb_driver raw_intf_driver =
|
||||
{
|
||||
.name = "rawintf",
|
||||
.probe = raw_intf_probe,
|
||||
.disconnect = raw_intf_disconnect,
|
||||
.supports_autosuspend = 0,
|
||||
};
|
||||
|
||||
|
||||
static int raw_driver_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if ((err = usb_register_device_driver(&raw_driver, THIS_MODULE)))
|
||||
return err;
|
||||
|
||||
printk("RAW: driver registered\n");
|
||||
|
||||
if ((err = usb_register(&raw_intf_driver)))
|
||||
return err;
|
||||
|
||||
printk("RAW: interface driver registered\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(raw_driver_init);
|
@ -12,7 +12,9 @@
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
||||
|
@ -12,7 +12,10 @@
|
||||
*/
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
extern "C" {
|
||||
#include <dde_kit/interrupt.h>
|
||||
|
@ -14,7 +14,9 @@
|
||||
#include <base/env.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <extern_c_end.h>
|
||||
#include "signal.h"
|
||||
|
||||
static void handler(void *timer);
|
||||
|
@ -17,10 +17,12 @@
|
||||
#include <util/endian.h>
|
||||
#include <util/list.h>
|
||||
|
||||
#include <extern_c_begin.h>
|
||||
#include <lx_emul.h>
|
||||
#include <storage/scsi.h>
|
||||
#include <extern_c_end.h>
|
||||
|
||||
#include <platform/lx_mem.h>
|
||||
#include <storage/scsi.h>
|
||||
#include "signal.h"
|
||||
|
||||
static Signal_helper *_signal = 0;
|
||||
|
132
repos/os/include/usb/packet_handler.h
Normal file
132
repos/os/include/usb/packet_handler.h
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* \brief Packet stream helper
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB__PACKET_HANDLER_
|
||||
#define _INCLUDE__USB__PACKET_HANDLER_
|
||||
|
||||
#include <base/lock.h>
|
||||
#include <usb_session/connection.h>
|
||||
|
||||
namespace Usb {
|
||||
class Packet_handler;
|
||||
}
|
||||
|
||||
class Usb::Packet_handler
|
||||
{
|
||||
private:
|
||||
|
||||
Usb::Connection &_connection;
|
||||
Signal_rpc_member<Packet_handler> _rpc_ack_avail;
|
||||
Signal_rpc_member<Packet_handler> _rpc_ready_submit;
|
||||
|
||||
bool _ready_submit = true;
|
||||
|
||||
void _packet_handler(unsigned)
|
||||
{
|
||||
if (!_ready_submit)
|
||||
return;
|
||||
|
||||
while (packet_avail()) {
|
||||
Packet_descriptor p = _connection.source()->get_acked_packet();
|
||||
|
||||
if (p.completion)
|
||||
p.completion->complete(p);
|
||||
else
|
||||
release(p);
|
||||
}
|
||||
}
|
||||
|
||||
void _ready_handler(unsigned)
|
||||
{
|
||||
_ready_submit = true;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Packet_handler(Connection &connection, Server::Entrypoint &ep)
|
||||
: _connection(connection),
|
||||
_rpc_ack_avail(ep, *this, &Packet_handler::_packet_handler),
|
||||
_rpc_ready_submit(ep, *this, &Packet_handler::_ready_handler)
|
||||
{
|
||||
/* connect 'ack_avail' to our rpc member */
|
||||
_connection.tx_channel()->sigh_ack_avail(_rpc_ack_avail);
|
||||
_connection.tx_channel()->sigh_ready_to_submit(_rpc_ready_submit);
|
||||
}
|
||||
|
||||
|
||||
/***************************
|
||||
** Packet stream wrapper **
|
||||
***************************/
|
||||
|
||||
bool packet_avail() const
|
||||
{
|
||||
return _connection.source()->ack_avail();
|
||||
}
|
||||
|
||||
void wait_for_packet()
|
||||
{
|
||||
packet_avail() ? _packet_handler(0) : Server::wait_and_dispatch_one_signal();
|
||||
}
|
||||
|
||||
Packet_descriptor alloc(size_t size)
|
||||
{
|
||||
/* is size larger than packet stream */
|
||||
if (size > _connection.source()->bulk_buffer_size()) {
|
||||
PERR("Packet allocation of (%zu bytes) too large, buffer has %zu bytes",
|
||||
size, _connection.source()->bulk_buffer_size());
|
||||
throw Usb::Session::Tx::Source::Packet_alloc_failed();
|
||||
}
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
Packet_descriptor p = _connection.source()->alloc_packet(size);
|
||||
return p;
|
||||
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
||||
/* block until some packets are freed */
|
||||
wait_for_packet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void submit(Packet_descriptor &p)
|
||||
{
|
||||
/* check if submit queue is full */
|
||||
if (!_connection.source()->ready_to_submit()) {
|
||||
_ready_submit = false;
|
||||
|
||||
/* wait for ready_to_submit signal */
|
||||
while (!_ready_submit)
|
||||
Server::wait_and_dispatch_one_signal();
|
||||
}
|
||||
|
||||
_connection.source()->submit_packet(p);
|
||||
|
||||
/*
|
||||
* If an acknowledgement available signal occurred in the meantime,
|
||||
* retrieve packets.
|
||||
*/
|
||||
if (packet_avail())
|
||||
_packet_handler(0);
|
||||
}
|
||||
|
||||
void *content(Packet_descriptor &p)
|
||||
{
|
||||
return _connection.source()->packet_content(p);
|
||||
}
|
||||
|
||||
void release(Packet_descriptor &p)
|
||||
{
|
||||
_connection.source()->release_packet(p);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB__PACKET_HANDLER_ */
|
210
repos/os/include/usb/types.h
Normal file
210
repos/os/include/usb/types.h
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* \brief Basic types for USB
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB__TYPES_H_
|
||||
#define _INCLUDE__USB__TYPES_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
namespace Usb {
|
||||
struct Device_descriptor;
|
||||
struct Config_descriptor;
|
||||
struct Interface_descriptor;
|
||||
struct Endpoint_descriptor;
|
||||
struct String;
|
||||
}
|
||||
|
||||
namespace Usb {
|
||||
|
||||
enum Endpoint_type {
|
||||
ENDPOINT_BULK = 0x2,
|
||||
ENDPOINT_INTERRUPT = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* The following three enums are ORed together to form a control request
|
||||
* type
|
||||
*/
|
||||
enum Endpoint_direction {
|
||||
ENDPOINT_OUT = 0,
|
||||
ENDPOINT_IN = 0x80,
|
||||
};
|
||||
|
||||
enum Request_type {
|
||||
TYPE_STANDARD = 0,
|
||||
TYPE_CLASS = (1U << 5),
|
||||
TYPE_VENDOR = (2U << 5),
|
||||
TYPE_RESERVED = (3U << 5),
|
||||
};
|
||||
|
||||
enum Recipient {
|
||||
RECIPIENT_DEVICE = 0,
|
||||
RECIPIENT_INTERFACE = 0x1,
|
||||
RECIPIENT_ENDPOINT = 0x2,
|
||||
RECIPIENT_OTHER = 0x3,
|
||||
};
|
||||
|
||||
/**
|
||||
* UTF-16 string
|
||||
*/
|
||||
typedef Genode::uint16_t utf16_t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* String containing UTF-16 plane 0 characters
|
||||
*/
|
||||
struct Usb::String
|
||||
{
|
||||
utf16_t *string = nullptr;
|
||||
unsigned length = 0;
|
||||
|
||||
void copy(unsigned len, void *from, Genode::Allocator *md_alloc)
|
||||
{
|
||||
length = len;
|
||||
string = (utf16_t *)md_alloc->alloc(length * sizeof(utf16_t));
|
||||
Genode::memcpy(string, from, sizeof(utf16_t) * length);
|
||||
}
|
||||
|
||||
void free(Genode::Allocator *md_alloc)
|
||||
{
|
||||
if (!string)
|
||||
return;
|
||||
|
||||
md_alloc->free(string, length * sizeof(utf16_t));
|
||||
string = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create char version
|
||||
*/
|
||||
char *to_char(char *buffer, unsigned len)
|
||||
{
|
||||
if (!length)
|
||||
return (char *)"<unknown>";
|
||||
|
||||
len = Genode::min(length, len);
|
||||
for (unsigned i = 0; i < len; i++)
|
||||
buffer[i] = string[i] & 0xff;
|
||||
|
||||
buffer[len] = 0;
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print for debugging
|
||||
*/
|
||||
void print()
|
||||
{
|
||||
char buffer[128];
|
||||
Genode::printf("%s\n", to_char(buffer, 128));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* USB hardware device descriptor
|
||||
*/
|
||||
struct Usb::Device_descriptor
|
||||
{
|
||||
Genode::uint8_t length;
|
||||
Genode::uint8_t type = 0x1;
|
||||
|
||||
Genode::uint16_t usb; /* USB version in BCD (binary-coded decimal ) */
|
||||
Genode::uint8_t dclass;
|
||||
Genode::uint8_t dsubclass;
|
||||
Genode::uint8_t dprotocol;
|
||||
Genode::uint8_t max_packet_size; /* of endpoint zero */
|
||||
|
||||
Genode::uint16_t vendor_id;
|
||||
Genode::uint16_t product_id;
|
||||
Genode::uint16_t device_release; /* release number in BCD */
|
||||
|
||||
Genode::uint8_t manufactorer_index; /* index of string describing manufacturer */
|
||||
Genode::uint8_t product_index;
|
||||
Genode::uint8_t serial_number_index;
|
||||
|
||||
Genode::uint8_t num_configs;
|
||||
|
||||
/**
|
||||
* Genode extensions (POD only)
|
||||
*/
|
||||
unsigned bus;
|
||||
unsigned num;
|
||||
unsigned speed;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* USB hardware configuration descriptor
|
||||
*/
|
||||
struct Usb::Config_descriptor
|
||||
{
|
||||
Genode::uint8_t length;
|
||||
Genode::uint8_t type = 0x2;
|
||||
|
||||
/*
|
||||
* Total length of data returned for this configuration. Includes the
|
||||
* combined length of all descriptors (configuration, interface, endpoint,
|
||||
* and class or vendor specific) returned for this configuration.
|
||||
*/
|
||||
Genode::uint16_t total_length;
|
||||
Genode::uint8_t num_interfaces;
|
||||
|
||||
Genode::uint8_t config_value; /* value used to set this configuration */
|
||||
Genode::uint8_t config_index; /* index of string descriptor */
|
||||
|
||||
Genode::uint8_t attributes;
|
||||
Genode::uint8_t max_power; /* maximum power consumption */
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* USB hardware interface descriptor
|
||||
*/
|
||||
struct Usb::Interface_descriptor
|
||||
{
|
||||
Genode::uint8_t length;
|
||||
Genode::uint8_t type = 0x4;
|
||||
|
||||
Genode::uint8_t number; /* interface number */
|
||||
Genode::uint8_t alt_settings; /* value used for setting alternate setting
|
||||
using the 'number' field */
|
||||
Genode::uint8_t num_endpoints;
|
||||
|
||||
Genode::uint8_t iclass;
|
||||
Genode::uint8_t isubclass;
|
||||
Genode::uint8_t iprotocol;
|
||||
|
||||
Genode::uint8_t interface_index; /* index of string descriptor */
|
||||
|
||||
/**
|
||||
* Genode extensions (POD only)
|
||||
*/
|
||||
bool active = false;
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* USB hardware endpoint descriptor
|
||||
*/
|
||||
struct Usb::Endpoint_descriptor
|
||||
{
|
||||
Genode::uint8_t length;
|
||||
Genode::uint8_t type = 0x5;
|
||||
|
||||
Genode::uint8_t address;
|
||||
Genode::uint8_t attributes;
|
||||
|
||||
Genode::uint16_t max_packet_size; /* for this endpoint */
|
||||
Genode::uint8_t polling_interval;
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif /* _INCLUDE__USB__TYPES_H_ */
|
556
repos/os/include/usb/usb.h
Normal file
556
repos/os/include/usb/usb.h
Normal file
@ -0,0 +1,556 @@
|
||||
/**
|
||||
* \brief USB session wrapper
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB__USB_H_
|
||||
#define _INCLUDE__USB__USB_H_
|
||||
|
||||
#include <base/allocator.h>
|
||||
#include <usb/types.h>
|
||||
#include <usb/packet_handler.h>
|
||||
#include <usb_session/connection.h>
|
||||
|
||||
#include <base/printf.h>
|
||||
|
||||
namespace Usb {
|
||||
|
||||
/* debugging */
|
||||
bool constexpr verbose_descr = false;
|
||||
|
||||
class Device;
|
||||
class Config;
|
||||
class Alternate_interface;
|
||||
class Interface;
|
||||
class Endpoint;
|
||||
class Meta_data;
|
||||
class Sync_completion;
|
||||
}
|
||||
|
||||
|
||||
class Usb::Meta_data
|
||||
{
|
||||
protected:
|
||||
|
||||
Genode::Allocator * const _md_alloc;
|
||||
Connection &_connection;
|
||||
Packet_handler &_handler;
|
||||
|
||||
public:
|
||||
|
||||
Meta_data(Genode::Allocator * const md_alloc, Connection &device,
|
||||
Packet_handler &handler)
|
||||
: _md_alloc(md_alloc), _connection(device), _handler(handler) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Completion for synchronous calls
|
||||
*/
|
||||
class Usb::Sync_completion : Completion
|
||||
{
|
||||
private:
|
||||
|
||||
bool _completed = false;
|
||||
Packet_descriptor &_p;
|
||||
|
||||
public:
|
||||
|
||||
Sync_completion(Packet_handler &handler, Packet_descriptor &p)
|
||||
: _p(p)
|
||||
{
|
||||
Completion *c = p.completion;
|
||||
p.completion = this;
|
||||
|
||||
handler.submit(p);
|
||||
|
||||
while (!_completed)
|
||||
handler.wait_for_packet();
|
||||
|
||||
if (c)
|
||||
c->complete(p);
|
||||
}
|
||||
|
||||
void complete(Packet_descriptor &p) override
|
||||
{
|
||||
_p = p;
|
||||
_completed = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Endpoint : public Endpoint_descriptor
|
||||
{
|
||||
public:
|
||||
|
||||
Endpoint(Endpoint_descriptor &endpoint_descr)
|
||||
: Endpoint_descriptor(endpoint_descr) { }
|
||||
|
||||
bool is_bulk() const { return (attributes & 0x3) == ENDPOINT_BULK; }
|
||||
bool is_interrupt() const { return (attributes & 0x3) == ENDPOINT_INTERRUPT; }
|
||||
|
||||
void dump()
|
||||
{
|
||||
if (verbose_descr)
|
||||
PLOG("\tEndpoint: len: %x type: %x address: %x attributes: %x",
|
||||
length, type, address, attributes);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Alternate_interface : public Interface_descriptor,
|
||||
public Meta_data
|
||||
{
|
||||
private:
|
||||
|
||||
enum { MAX_ENDPOINTS = 16 };
|
||||
Endpoint *_endpoints[MAX_ENDPOINTS];
|
||||
|
||||
public:
|
||||
|
||||
String interface_string;
|
||||
|
||||
Alternate_interface(Interface_descriptor &interface_desc,
|
||||
Meta_data &md)
|
||||
: Interface_descriptor(interface_desc), Meta_data(md)
|
||||
{
|
||||
dump();
|
||||
|
||||
for (Genode::uint8_t i = 0; i < num_endpoints; i++)
|
||||
{
|
||||
Endpoint_descriptor descr;
|
||||
_connection.endpoint_descriptor(number, alt_settings, i, &descr);
|
||||
_endpoints[i] = new (_md_alloc) Endpoint(descr);
|
||||
_endpoints[i]->dump();
|
||||
}
|
||||
}
|
||||
|
||||
~Alternate_interface()
|
||||
{
|
||||
for (unsigned i = 0; i < num_endpoints; i++)
|
||||
destroy(_md_alloc, _endpoints[i]);
|
||||
|
||||
interface_string.free(_md_alloc);
|
||||
}
|
||||
|
||||
Endpoint &endpoint(unsigned index)
|
||||
{
|
||||
if (index >= num_endpoints)
|
||||
throw Session::Invalid_endpoint();
|
||||
|
||||
return *_endpoints[index];
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
if (!verbose_descr)
|
||||
return;
|
||||
|
||||
PWRN("Interface: len: %x: type: %x number: %x alt_setting: %x",
|
||||
length, type, number, alt_settings);
|
||||
PWRN(" num_endpoints: %x class: %x subclass: %x: protocol: %x",
|
||||
num_endpoints, iclass, isubclass, iprotocol);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Interface : public Meta_data
|
||||
{
|
||||
private:
|
||||
|
||||
friend class Config;
|
||||
|
||||
enum { MAX_ALT = 10 };
|
||||
|
||||
Alternate_interface *_interface[MAX_ALT];
|
||||
unsigned _count = 0;
|
||||
Alternate_interface *_current = nullptr;
|
||||
bool _claimed = false;
|
||||
|
||||
|
||||
void _check()
|
||||
{
|
||||
if (!_claimed)
|
||||
throw Session::Interface_not_claimed();
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void _add(Alternate_interface *iface)
|
||||
{
|
||||
_interface[_count++] = iface;
|
||||
|
||||
if (iface->active)
|
||||
_current = iface;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Interface(Meta_data &md)
|
||||
: Meta_data(md) { }
|
||||
|
||||
|
||||
/***************
|
||||
** Accessors **
|
||||
***************/
|
||||
|
||||
unsigned alternate_count() const { return _count; }
|
||||
Alternate_interface ¤t() { return *_current; }
|
||||
|
||||
Alternate_interface &alternate_interface(unsigned index)
|
||||
{
|
||||
if (index >= _count)
|
||||
throw Session::Interface_not_found();
|
||||
|
||||
return *_interface[index];
|
||||
}
|
||||
|
||||
Endpoint &endpoint(unsigned index) { return _current->endpoint(index); }
|
||||
|
||||
|
||||
/***************************
|
||||
** Packet stream helpers **
|
||||
***************************/
|
||||
|
||||
Packet_descriptor alloc(size_t size)
|
||||
{
|
||||
return _handler.alloc(size);
|
||||
}
|
||||
|
||||
void submit(Packet_descriptor &p)
|
||||
{
|
||||
_handler.submit(p);
|
||||
}
|
||||
|
||||
void release(Packet_descriptor &p)
|
||||
{
|
||||
_handler.release(p);
|
||||
}
|
||||
|
||||
void *content(Packet_descriptor &p)
|
||||
{
|
||||
return _handler.content(p);
|
||||
}
|
||||
|
||||
/******************************
|
||||
** Interface to USB service **
|
||||
******************************/
|
||||
|
||||
/**
|
||||
* Claim interface
|
||||
*/
|
||||
void claim()
|
||||
{
|
||||
_connection.claim_interface(_interface[0]->number);
|
||||
_claimed = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Release interface
|
||||
*/
|
||||
void release()
|
||||
{
|
||||
if (_claimed)
|
||||
return;
|
||||
|
||||
Packet_descriptor p = alloc(0);
|
||||
p.type = Packet_descriptor::RELEASE_IF;
|
||||
p.number = _interface[0]->number;
|
||||
p.succeded = false;
|
||||
|
||||
Sync_completion sync(_handler, p);
|
||||
|
||||
if (p.succeded)
|
||||
_claimed = false;
|
||||
}
|
||||
|
||||
void set_alternate_interface(Alternate_interface &alternate)
|
||||
{
|
||||
_check();
|
||||
|
||||
Packet_descriptor p = alloc(0);
|
||||
p.type = Packet_descriptor::ALT_SETTING;
|
||||
p.succeded = false;
|
||||
p.interface.number = alternate.number;
|
||||
p.interface.alt_setting = alternate.alt_settings;
|
||||
|
||||
Sync_completion sync(_handler, p);
|
||||
|
||||
if (p.succeded)
|
||||
_current = _interface[p.interface.alt_setting];
|
||||
}
|
||||
|
||||
void control_transfer(Packet_descriptor &p, uint8_t request_type, uint8_t request,
|
||||
uint16_t value, uint16_t index, int timeout,
|
||||
bool block = true, Completion *c = nullptr)
|
||||
{
|
||||
_check();
|
||||
|
||||
p.type = Usb::Packet_descriptor::CTRL;
|
||||
p.succeded = false;
|
||||
p.control.request = request;
|
||||
p.control.request_type = request_type;
|
||||
p.control.value = value;
|
||||
p.control.index = index;
|
||||
p.control.timeout = timeout;
|
||||
p.completion = c;
|
||||
|
||||
if(block) Sync_completion sync(_handler, p);
|
||||
else _handler.submit(p);
|
||||
}
|
||||
|
||||
void bulk_transfer(Packet_descriptor &p, Endpoint &ep, int timeout,
|
||||
bool block = true, Completion *c = nullptr)
|
||||
{
|
||||
_check();
|
||||
|
||||
if (!ep.is_bulk())
|
||||
throw Session::Invalid_endpoint();
|
||||
|
||||
p.type = Usb::Packet_descriptor::BULK;
|
||||
p.succeded = false;
|
||||
p.transfer.ep = ep.address;
|
||||
p.transfer.timeout = timeout;
|
||||
p.completion = c;
|
||||
|
||||
if(block) Sync_completion sync(_handler, p);
|
||||
else _handler.submit(p);
|
||||
}
|
||||
|
||||
void interrupt_transfer(Packet_descriptor &p, Endpoint &ep, int timeout,
|
||||
bool block = true, Completion *c = nullptr)
|
||||
{
|
||||
_check();
|
||||
|
||||
if (!ep.is_interrupt())
|
||||
throw Session::Invalid_endpoint();
|
||||
|
||||
p.type = Usb::Packet_descriptor::IRQ;
|
||||
p.succeded = false;
|
||||
p.transfer.ep = ep.address;
|
||||
p.transfer.timeout = timeout;
|
||||
p.completion = c;
|
||||
|
||||
if(block) Sync_completion sync(_handler, p);
|
||||
else _handler.submit(p);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Config : public Config_descriptor,
|
||||
public Meta_data
|
||||
{
|
||||
private:
|
||||
|
||||
enum { MAX_INTERFACES = 32 };
|
||||
|
||||
Interface *_interfaces[MAX_INTERFACES];
|
||||
unsigned _total_interfaces = 0;
|
||||
|
||||
public:
|
||||
|
||||
String config_string;
|
||||
|
||||
Config(Config_descriptor &config_desc, Meta_data &md)
|
||||
: Config_descriptor(config_desc), Meta_data(md)
|
||||
{
|
||||
dump();
|
||||
|
||||
for (Genode::uint8_t i = 0; i < num_interfaces; i++) {
|
||||
|
||||
Interface_descriptor descr;
|
||||
_connection.interface_descriptor(i, 0, &descr);
|
||||
_interfaces[descr.number] = new(_md_alloc) Interface(md);
|
||||
|
||||
/* read number of alternative settings */
|
||||
unsigned alt_settings = _connection.alt_settings(i);
|
||||
_total_interfaces += alt_settings;
|
||||
|
||||
/* alt settings */
|
||||
for (unsigned j = 0; j < alt_settings; j++) {
|
||||
_connection.interface_descriptor(i, j, &descr);
|
||||
if (descr.number != i)
|
||||
PERR("Interface number != index");
|
||||
|
||||
_interfaces[descr.number]->_add(new(_md_alloc) Alternate_interface(descr, md));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~Config()
|
||||
{
|
||||
for (unsigned i = 0; i < num_interfaces; i++)
|
||||
destroy(_md_alloc, _interfaces[i]);
|
||||
|
||||
config_string.free(_md_alloc);
|
||||
}
|
||||
|
||||
Interface &interface(unsigned num)
|
||||
{
|
||||
|
||||
if (num >= num_interfaces)
|
||||
throw Session::Interface_not_found();
|
||||
|
||||
return *_interfaces[num];
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
if (verbose_descr)
|
||||
PINF("Config: len: %x type %x total_len: %x num_intf: %x config_value: %x",
|
||||
length, type, total_length, num_interfaces, config_value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Usb::Device : public Meta_data
|
||||
{
|
||||
private:
|
||||
|
||||
Packet_handler _handler;
|
||||
|
||||
void _clear()
|
||||
{
|
||||
if (!config)
|
||||
return;
|
||||
|
||||
manufactorer_string.free(_md_alloc);
|
||||
product_string.free(_md_alloc);
|
||||
serial_number_string.free(_md_alloc);
|
||||
destroy(_md_alloc, config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
enum Speed {
|
||||
SPEED_UNKNOWN = 0, /* enumerating */
|
||||
SPEED_LOW,
|
||||
SPEED_FULL, /* usb 1.1 */
|
||||
SPEED_HIGH, /* usb 2.0 */
|
||||
SPEED_WIRELESS, /* wireless (usb 2.5) */
|
||||
SPEED_SUPER, /* usb 3.0 */
|
||||
};
|
||||
|
||||
Device_descriptor device_descr;
|
||||
Config *config = nullptr;
|
||||
|
||||
String manufactorer_string;
|
||||
String product_string;
|
||||
String serial_number_string;
|
||||
|
||||
Device(Genode::Allocator * const md_alloc, Connection &connection,
|
||||
Server::Entrypoint &ep)
|
||||
: Meta_data(md_alloc, connection, _handler), _handler(connection, ep)
|
||||
{ }
|
||||
|
||||
Device_descriptor const *descriptor() { return &device_descr; }
|
||||
Config *config_descriptor() { return config; }
|
||||
|
||||
char const *speed_string(unsigned speed)
|
||||
{
|
||||
switch (speed) {
|
||||
case SPEED_LOW : return "LOW";
|
||||
case SPEED_FULL : return "FULL";
|
||||
case SPEED_HIGH : return "HIGH";
|
||||
case SPEED_WIRELESS: return "WIRELESS";
|
||||
case SPEED_SUPER : return "SUPER";
|
||||
|
||||
default: return "<unknown>";
|
||||
}
|
||||
}
|
||||
|
||||
void string_descriptor(uint8_t index, String *target)
|
||||
{
|
||||
Packet_descriptor p = _handler.alloc(128);
|
||||
p.type = Packet_descriptor::STRING;
|
||||
p.string.index = index;
|
||||
p.string.length = 128;
|
||||
|
||||
Sync_completion sync(_handler, p);
|
||||
target->copy(p.string.length, _handler.content(p), _md_alloc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-read all descriptors (device, config, interface, and endpoints)
|
||||
* Must be called before Usb::Device can be used (asynchronous)
|
||||
*/
|
||||
void update_config()
|
||||
{
|
||||
/* free info from previous call */
|
||||
_clear();
|
||||
|
||||
Config_descriptor config_descr;
|
||||
|
||||
_connection.config_descriptor(&device_descr, &config_descr);
|
||||
dump();
|
||||
|
||||
config = new (_md_alloc) Config(config_descr, *this);
|
||||
|
||||
/* retrieve string descriptors */
|
||||
string_descriptor(device_descr.manufactorer_index, &manufactorer_string);
|
||||
string_descriptor(device_descr.product_index, &product_string);
|
||||
string_descriptor(device_descr.serial_number_index, &serial_number_string);
|
||||
string_descriptor(config->config_index, &config->config_string);
|
||||
|
||||
for (unsigned i = 0; i < config->num_interfaces; i++) {
|
||||
Interface &iface = config->interface(i);
|
||||
|
||||
for (unsigned j = 0; j < iface.alternate_count(); j++)
|
||||
string_descriptor(iface.alternate_interface(j).interface_index,
|
||||
&iface.alternate_interface(j).interface_string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set configuration, no interfaces can be claimed (asynchronous)
|
||||
*/
|
||||
void set_configuration(uint8_t num)
|
||||
{
|
||||
if (!config) {
|
||||
PERR("No current configuration found");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!num || num > device_descr.num_configs) {
|
||||
PERR("Valid configuration values: 1 ... %u", device_descr.num_configs);
|
||||
return;
|
||||
}
|
||||
|
||||
if (config && num == config->config_value)
|
||||
return;
|
||||
|
||||
Packet_descriptor p = _handler.alloc(0);
|
||||
p.type = Packet_descriptor::CONFIG;
|
||||
p.number = num;
|
||||
|
||||
Sync_completion sync(_handler, p);
|
||||
|
||||
if (p.succeded)
|
||||
update_config();
|
||||
}
|
||||
|
||||
Interface &interface(unsigned interface_num)
|
||||
{
|
||||
return config->interface(interface_num);
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
if (!verbose_descr)
|
||||
return;
|
||||
|
||||
PINF("Device: len: %x type: %x class: %x sub-class: %x proto: %x max_packet: %x",
|
||||
device_descr.length, device_descr.type, device_descr.dclass, device_descr.dsubclass,
|
||||
device_descr.dprotocol, device_descr.max_packet_size);
|
||||
PINF(" vendor: %x product: %x configs: %x",
|
||||
device_descr.vendor_id, device_descr.product_id, device_descr.num_configs);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB__USB_H_ */
|
23
repos/os/include/usb_session/capability.h
Normal file
23
repos/os/include/usb_session/capability.h
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* \brief USB session capability
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB_SESSION__CAPABILITY_H_
|
||||
#define _INCLUDE__USB_SESSION__CAPABILITY_H_
|
||||
|
||||
#include <base/capability.h>
|
||||
|
||||
namespace Usb {
|
||||
class Session;
|
||||
typedef Genode::Capability<Session> Session_capability;
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__USB_SESSION__CAPABILITY_H_ */
|
95
repos/os/include/usb_session/client.h
Normal file
95
repos/os/include/usb_session/client.h
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* \brief USB session client implementation
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB_SESSION__CLIENT_H_
|
||||
#define _INCLUDE__USB_SESSION__CLIENT_H_
|
||||
|
||||
#include <base/rpc_client.h>
|
||||
|
||||
#include <packet_stream_tx/client.h>
|
||||
#include <usb_session/capability.h>
|
||||
#include <usb_session/usb_session.h>
|
||||
|
||||
namespace Usb {
|
||||
class Session_client;
|
||||
class Interface_client;
|
||||
}
|
||||
|
||||
class Usb::Session_client : public Genode::Rpc_client<Session>
|
||||
{
|
||||
private:
|
||||
|
||||
Packet_stream_tx::Client<Tx> _tx;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param session session capability
|
||||
* \param tx_buffer_alloc allocator used for managing the
|
||||
* transmission buffer
|
||||
*/
|
||||
Session_client(Session_capability session,
|
||||
Genode::Range_allocator *tx_buffer_alloc,
|
||||
Genode::Signal_context_capability state_change)
|
||||
:
|
||||
Genode::Rpc_client<Session>(session),
|
||||
_tx(call<Rpc_tx_cap>(), tx_buffer_alloc)
|
||||
{
|
||||
if (state_change.valid())
|
||||
sigh_state_change(state_change);
|
||||
}
|
||||
|
||||
/***************************
|
||||
** USB session interface **
|
||||
***************************/
|
||||
|
||||
bool plugged() override { return call<Rpc_plugged>(); }
|
||||
Tx *tx_channel() override { return &_tx; }
|
||||
Tx::Source *source() override { return _tx.source(); }
|
||||
|
||||
void sigh_state_change(Genode::Signal_context_capability sigh) override {
|
||||
call<Rpc_sigh_state_change>(sigh); }
|
||||
|
||||
void config_descriptor(Device_descriptor *device_descr,
|
||||
Config_descriptor *config_descr) override
|
||||
{
|
||||
call<Rpc_config_descr>(device_descr, config_descr);
|
||||
}
|
||||
|
||||
unsigned alt_settings(unsigned index)
|
||||
{
|
||||
return call<Rpc_alt_settings>(index);
|
||||
}
|
||||
|
||||
void interface_descriptor(unsigned index, unsigned alt_setting,
|
||||
Interface_descriptor *interface_descr) override
|
||||
{
|
||||
call<Rpc_iface_descr>(index, alt_setting, interface_descr);
|
||||
}
|
||||
|
||||
void endpoint_descriptor(unsigned interface_num,
|
||||
unsigned alt_setting,
|
||||
unsigned endpoint_num,
|
||||
Endpoint_descriptor *endpoint_descr) override
|
||||
{
|
||||
call<Rpc_ep_descr>(interface_num, alt_setting, endpoint_num, endpoint_descr);
|
||||
}
|
||||
|
||||
void claim_interface(unsigned interface_num)
|
||||
{
|
||||
call<Rpc_claim_interface>(interface_num);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB_SESSION__CLIENT_H_ */
|
38
repos/os/include/usb_session/connection.h
Normal file
38
repos/os/include/usb_session/connection.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* \brief Client connection to USB server
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB_SESSION__CONNECTION_H_
|
||||
#define _INCLUDE__USB_SESSION__CONNECTION_H_
|
||||
|
||||
#include <usb_session/client.h>
|
||||
#include <base/connection.h>
|
||||
#include <base/allocator.h>
|
||||
|
||||
namespace Usb {
|
||||
struct Connection;
|
||||
}
|
||||
|
||||
struct Usb::Connection : Genode::Connection<Session>, Session_client
|
||||
{
|
||||
Connection(Genode::Range_allocator *tx_block_alloc,
|
||||
unsigned long vendor_id, unsigned long product_id,
|
||||
Genode::size_t tx_buf_size = 512 * 1024,
|
||||
Genode::Signal_context_capability sigh_state_changed =
|
||||
Genode::Signal_context_capability())
|
||||
:
|
||||
Genode::Connection<Session>(session("ram_quota=%zd, tx_buf_size=%zd, vendor=%lu, product=%lu",
|
||||
3 * 4096 + tx_buf_size, tx_buf_size, vendor_id, product_id)),
|
||||
Session_client(cap(), tx_block_alloc, sigh_state_changed)
|
||||
{ }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB_SESSION__CONNECTION_H_ */
|
54
repos/os/include/usb_session/rpc_object.h
Normal file
54
repos/os/include/usb_session/rpc_object.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* \brief Server RPC object with packet stream
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB_SESSION__RPC_OBJECT_H_
|
||||
#define _INCLUDE__USB_SESSION__RPC_OBJECT_H_
|
||||
|
||||
#include <base/rpc_server.h>
|
||||
#include <packet_stream_tx/rpc_object.h>
|
||||
#include <usb_session/usb_session.h>
|
||||
|
||||
namespace Usb {
|
||||
class Session_rpc_object;
|
||||
}
|
||||
|
||||
class Usb::Session_rpc_object : public Genode::Rpc_object<Session, Session_rpc_object>
|
||||
{
|
||||
protected:
|
||||
|
||||
Packet_stream_tx::Rpc_object<Tx> _tx;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param tx_ds dataspace used as communication buffer
|
||||
* for the tx packet stream
|
||||
* \param ep entry point used for packet-stream channel
|
||||
*/
|
||||
Session_rpc_object(Genode::Dataspace_capability tx_ds,
|
||||
Genode::Rpc_entrypoint &ep)
|
||||
: _tx(tx_ds, ep) { }
|
||||
|
||||
/**
|
||||
* Return capability to packet-stream channel
|
||||
*
|
||||
* This function is called by the client via an RPC call at session
|
||||
* construction time.
|
||||
*/
|
||||
Genode::Capability<Tx> _tx_cap() { return _tx.cap(); }
|
||||
|
||||
Tx::Sink *sink() { return _tx.sink(); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB_SESSION__RPC_OBJECT_H_ */
|
193
repos/os/include/usb_session/usb_session.h
Normal file
193
repos/os/include/usb_session/usb_session.h
Normal file
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* \brief USB session for raw device connection
|
||||
* \author Sebastian Sumpf
|
||||
* \date 2014-12-08
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2014 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 _INCLUDE__USB_SESSION__USB_SESSION_H_
|
||||
#define _INCLUDE__USB_SESSION__USB_SESSION_H_
|
||||
|
||||
#include <os/packet_stream.h>
|
||||
#include <packet_stream_tx/packet_stream_tx.h>
|
||||
#include <session/session.h>
|
||||
#include <usb/types.h>
|
||||
|
||||
|
||||
namespace Usb {
|
||||
using namespace Genode;
|
||||
class Session;
|
||||
struct Packet_descriptor;
|
||||
struct Completion;
|
||||
}
|
||||
|
||||
/**
|
||||
* USB packet type
|
||||
*/
|
||||
struct Usb::Packet_descriptor : ::Packet_descriptor
|
||||
{
|
||||
enum Type { STRING, CTRL, BULK, IRQ, ALT_SETTING, CONFIG, RELEASE_IF };
|
||||
|
||||
Type type;
|
||||
bool succeded = false;
|
||||
Completion *completion = nullptr;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t index;
|
||||
unsigned length;
|
||||
} string;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t request;
|
||||
uint8_t request_type;
|
||||
uint16_t value;
|
||||
uint16_t index;
|
||||
int timeout;
|
||||
} control;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t ep;
|
||||
int actual_size; /* returned */
|
||||
int timeout;
|
||||
} transfer;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t number;
|
||||
uint8_t alt_setting;
|
||||
} interface;
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t number;
|
||||
};
|
||||
};
|
||||
|
||||
bool is_read_transfer() { return transfer.ep & ENDPOINT_IN; }
|
||||
|
||||
Packet_descriptor(off_t offset = 0, size_t size = 0)
|
||||
: ::Packet_descriptor(offset, size) { }
|
||||
|
||||
Packet_descriptor(::Packet_descriptor p, Type type, Completion *completion = nullptr)
|
||||
: ::Packet_descriptor(p.offset(), p.size()), type(type), completion(completion) { }
|
||||
};
|
||||
|
||||
/**
|
||||
* Completion for asynchronous communication
|
||||
*/
|
||||
struct Usb::Completion
|
||||
{
|
||||
virtual void complete(Usb::Packet_descriptor &p) = 0;
|
||||
};
|
||||
|
||||
struct Usb::Session : public Genode::Session
|
||||
{
|
||||
/****************
|
||||
** Exceptions **
|
||||
****************/
|
||||
|
||||
class Device_not_found : public Exception { };
|
||||
class Interface_not_found : public Exception { };
|
||||
class Interface_already_claimed : public Exception { };
|
||||
class Interface_not_claimed : public Exception { };
|
||||
class Invalid_endpoint : public Exception { };
|
||||
|
||||
|
||||
/*******************
|
||||
** Packet stream **
|
||||
*******************/
|
||||
|
||||
enum { TX_QUEUE_SIZE = 64 };
|
||||
|
||||
typedef Packet_stream_policy<Usb::Packet_descriptor,
|
||||
TX_QUEUE_SIZE, TX_QUEUE_SIZE,
|
||||
char> Tx_policy;
|
||||
|
||||
typedef Packet_stream_tx::Channel<Tx_policy> Tx;
|
||||
|
||||
/**
|
||||
* Request packet-transmission channel
|
||||
*/
|
||||
virtual Tx *tx_channel() { return 0; }
|
||||
|
||||
/**
|
||||
* Request client-side packet-stream interface of tx channel
|
||||
*/
|
||||
virtual Tx::Source *source() { return 0; }
|
||||
|
||||
|
||||
/***********************
|
||||
** Session interface **
|
||||
***********************/
|
||||
|
||||
static const char *service_name() { return "Usb"; }
|
||||
|
||||
/**
|
||||
* Send from the server to the client upon device state change
|
||||
*/
|
||||
virtual void sigh_state_change(Signal_context_capability sigh) = 0;
|
||||
|
||||
/**
|
||||
* Is the device present
|
||||
*/
|
||||
virtual bool plugged() = 0;
|
||||
|
||||
/**
|
||||
* Retrieve device and current configurations despcriptors
|
||||
*/
|
||||
virtual void config_descriptor(Device_descriptor *device_descr,
|
||||
Config_descriptor *config_descr) = 0;
|
||||
|
||||
/**
|
||||
* Return number of alt settings for iterface
|
||||
*/
|
||||
virtual unsigned alt_settings(unsigned index) = 0;
|
||||
|
||||
/**
|
||||
* Return interface descriptor for interface index/alternate setting tuple
|
||||
*/
|
||||
virtual void interface_descriptor(unsigned index, unsigned alt_setting,
|
||||
Interface_descriptor *interface_descr) = 0;
|
||||
|
||||
/**
|
||||
* Return endpoint for interface index/alternate setting tuple
|
||||
*/
|
||||
virtual void endpoint_descriptor(unsigned interface_num,
|
||||
unsigned alt_setting,
|
||||
unsigned endpoint_num,
|
||||
Endpoint_descriptor *endpoint_descr) = 0;
|
||||
|
||||
/**
|
||||
* Claim an interface number
|
||||
*/
|
||||
virtual void claim_interface(unsigned interface_num) = 0;
|
||||
|
||||
GENODE_RPC(Rpc_plugged, bool, plugged);
|
||||
GENODE_RPC(Rpc_sigh_state_change, void, sigh_state_change, Signal_context_capability);
|
||||
GENODE_RPC(Rpc_tx_cap, Capability<Tx>, _tx_cap);
|
||||
GENODE_RPC_THROW(Rpc_config_descr, void, config_descriptor, GENODE_TYPE_LIST(Device_not_found),
|
||||
Device_descriptor *, Config_descriptor *);
|
||||
GENODE_RPC(Rpc_alt_settings, unsigned, alt_settings, unsigned);
|
||||
GENODE_RPC_THROW(Rpc_iface_descr, void, interface_descriptor, GENODE_TYPE_LIST(Device_not_found,
|
||||
Interface_not_found), unsigned, unsigned, Interface_descriptor *);
|
||||
GENODE_RPC_THROW(Rpc_ep_descr, void, endpoint_descriptor, GENODE_TYPE_LIST(Device_not_found,
|
||||
Interface_not_found), unsigned, unsigned, unsigned, Endpoint_descriptor *);
|
||||
GENODE_RPC_THROW(Rpc_claim_interface, void, claim_interface, GENODE_TYPE_LIST(Interface_not_found,
|
||||
Interface_already_claimed), unsigned);
|
||||
GENODE_RPC_THROW(Rpc_release_interface, void, release_interface, GENODE_TYPE_LIST(Interface_not_found),
|
||||
unsigned);
|
||||
GENODE_RPC_INTERFACE(Rpc_plugged, Rpc_sigh_state_change, Rpc_tx_cap, Rpc_config_descr,
|
||||
Rpc_iface_descr, Rpc_ep_descr, Rpc_alt_settings, Rpc_claim_interface);
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__USB_SESSION__USB_SESSION_H_ */
|
Loading…
Reference in New Issue
Block a user