mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-11 06:54:18 +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?
|
# FIXME should we *really* dde_kit to this shared library?
|
||||||
LIBS += dde_kit libc-setjmp config
|
LIBS += dde_kit libc-setjmp config
|
||||||
SRC_CC += main.cc lx_emul.cc irq.cc timer.cc event.cc storage.cc \
|
SRC_CC += main.cc lx_emul.cc irq.cc timer.cc event.cc storage.cc \
|
||||||
input_component.cc nic.cc
|
input_component.cc nic.cc raw.cc
|
||||||
SRC_C += dummies.c scsi.c evdev.c
|
SRC_C += dummies.c scsi.c evdev.c raw_driver.c
|
||||||
|
|
||||||
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/lib/usb
|
LX_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/lib/usb
|
||||||
DRIVERS_DIR := $(LX_CONTRIB_DIR)/drivers
|
DRIVERS_DIR := $(LX_CONTRIB_DIR)/drivers
|
||||||
@ -110,6 +110,8 @@ vpath %.cc $(LIB_DIR)/input
|
|||||||
vpath %.cc $(LIB_DIR)/storage
|
vpath %.cc $(LIB_DIR)/storage
|
||||||
vpath %.c $(LIB_DIR)/storage
|
vpath %.c $(LIB_DIR)/storage
|
||||||
vpath %.cc $(LIB_DIR)/nic
|
vpath %.cc $(LIB_DIR)/nic
|
||||||
|
vpath %.cc $(LIB_DIR)/raw
|
||||||
|
vpath %.c $(LIB_DIR)/raw
|
||||||
vpath lib/int_sqrt.c $(LX_CONTRIB_DIR)
|
vpath lib/int_sqrt.c $(LX_CONTRIB_DIR)
|
||||||
|
|
||||||
# vi: set ft=make :
|
# vi: set ft=make :
|
||||||
|
@ -4,6 +4,13 @@
|
|||||||
* \date 2013-02-20
|
* \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>
|
#include <os/server.h>
|
||||||
|
|
||||||
extern void start_usb_driver(Server::Entrypoint &e);
|
extern void start_usb_driver(Server::Entrypoint &e);
|
||||||
|
@ -4,6 +4,13 @@
|
|||||||
* \date 2013-02-20
|
* \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()
|
int main()
|
||||||
{
|
{
|
||||||
extern void start_usb_driver();
|
extern void start_usb_driver();
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
|
|
||||||
/* Emulation */
|
/* Emulation */
|
||||||
#include <platform/platform.h>
|
#include <platform/platform.h>
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
/* Linux */
|
/* Linux */
|
||||||
|
@ -19,7 +19,10 @@
|
|||||||
#include <io_mem_session/connection.h>
|
#include <io_mem_session/connection.h>
|
||||||
#include <util/mmio.h>
|
#include <util/mmio.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
#include <linux/platform_data/usb-omap.h>
|
#include <linux/platform_data/usb-omap.h>
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
@ -19,7 +19,10 @@
|
|||||||
/* emulation */
|
/* emulation */
|
||||||
#include <platform/platform.h>
|
#include <platform/platform.h>
|
||||||
#include <platform.h>
|
#include <platform.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
/* dwc-otg */
|
/* dwc-otg */
|
||||||
#define new new_
|
#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; }
|
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 **
|
** linux/ctype.h **
|
||||||
*******************/
|
*******************/
|
||||||
@ -344,7 +336,6 @@ void device_unregister(struct device *dev) { TRACE; }
|
|||||||
void device_lock(struct device *dev) { TRACE; }
|
void device_lock(struct device *dev) { TRACE; }
|
||||||
int device_trylock(struct device *dev) { TRACE; return 0; }
|
int device_trylock(struct device *dev) { TRACE; return 0; }
|
||||||
void device_unlock(struct device *dev) { TRACE; }
|
void device_unlock(struct device *dev) { TRACE; }
|
||||||
void device_del(struct device *dev) { TRACE; }
|
|
||||||
void device_initialize(struct device *dev) { TRACE; }
|
void device_initialize(struct device *dev) { TRACE; }
|
||||||
int device_attach(struct device *dev) { TRACE; return 0; }
|
int device_attach(struct device *dev) { TRACE; return 0; }
|
||||||
int device_is_registered(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_
|
#ifndef _LX_EMUL_H_
|
||||||
#define _LX_EMUL_H_
|
#define _LX_EMUL_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
/* DDE Kit includes */
|
/* DDE Kit includes */
|
||||||
#include <dde_kit/types.h>
|
#include <dde_kit/types.h>
|
||||||
#include <dde_kit/printf.h>
|
#include <dde_kit/printf.h>
|
||||||
@ -1583,11 +1579,6 @@ bool device_can_wakeup(struct device *dev);
|
|||||||
** linux/device.h **
|
** 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_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)
|
||||||
#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);
|
void *dev_get_platdata(const struct device *dev);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#undef class
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************
|
/*****************************
|
||||||
** linux/platform_device.h **
|
** 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'
|
* Deal with C++ keyword used as member name of 'pci_dev'
|
||||||
*/
|
*/
|
||||||
#ifdef __cplusplus
|
|
||||||
#define class device_class
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
struct msix_entry
|
struct msix_entry
|
||||||
{
|
{
|
||||||
u32 vector;
|
u32 vector;
|
||||||
@ -2436,9 +2419,6 @@ struct pci_fixup {
|
|||||||
unsigned int class_shift; /* should be 0, 8, 16 */
|
unsigned int class_shift; /* should be 0, 8, 16 */
|
||||||
void (*hook)(struct pci_dev *dev);
|
void (*hook)(struct pci_dev *dev);
|
||||||
};
|
};
|
||||||
#ifdef __cplusplus
|
|
||||||
#undef class
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
|
|
||||||
/* quirks */
|
/* quirks */
|
||||||
@ -2780,9 +2760,7 @@ enum { HID_DEBUG_BUFSIZE=512 };
|
|||||||
** linux/list.h **
|
** linux/list.h **
|
||||||
******************/
|
******************/
|
||||||
|
|
||||||
#define new _new
|
|
||||||
#include <linux/list.h>
|
#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_quirks(struct va_format *v) { }
|
||||||
static inline void trace_xhci_dbg_address(struct va_format *v) { }
|
static inline void trace_xhci_dbg_address(struct va_format *v) { }
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif /* __cplusplus */
|
|
||||||
|
|
||||||
#endif /* _LX_EMUL_H_ */
|
#endif /* _LX_EMUL_H_ */
|
||||||
|
@ -23,26 +23,24 @@
|
|||||||
struct Services
|
struct Services
|
||||||
{
|
{
|
||||||
/* USB profiles */
|
/* USB profiles */
|
||||||
bool hid;
|
bool hid = false;
|
||||||
bool stor;
|
bool stor = false;
|
||||||
bool nic;
|
bool nic = false;
|
||||||
|
bool raw = false;
|
||||||
|
|
||||||
/* Controller types */
|
/* Controller types */
|
||||||
bool uhci; /* 1.0 */
|
bool uhci = false; /* 1.0 */
|
||||||
bool ehci; /* 2.0 */
|
bool ehci = false; /* 2.0 */
|
||||||
bool xhci; /* 3.0 */
|
bool xhci = false; /* 3.0 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Screen resolution used by touch devices to convert touchscreen
|
* Screen resolution used by touch devices to convert touchscreen
|
||||||
* absolute coordinates to screen absolute coordinates
|
* absolute coordinates to screen absolute coordinates
|
||||||
*/
|
*/
|
||||||
unsigned long screen_x;
|
unsigned long screen_x = 0;
|
||||||
unsigned long screen_y;
|
unsigned long screen_y = 0;
|
||||||
|
|
||||||
Services()
|
Services()
|
||||||
: hid(false), stor(false), nic(false),
|
|
||||||
uhci(false), ehci(false), xhci(false),
|
|
||||||
screen_x(0), screen_y(0)
|
|
||||||
{
|
{
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
@ -76,6 +74,13 @@ struct Services
|
|||||||
PDBG("No <nic> config node found - not starting the USB Nic (Network) service");
|
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 {
|
try {
|
||||||
if (!config()->xml_node().attribute("uhci").has_value("yes"))
|
if (!config()->xml_node().attribute("uhci").has_value("yes"))
|
||||||
throw -1;
|
throw -1;
|
||||||
|
@ -170,24 +170,25 @@ class Routine : public Genode::List<Routine>::Element
|
|||||||
/**
|
/**
|
||||||
* Add an object
|
* Add an object
|
||||||
*/
|
*/
|
||||||
static void add(int (*func)(void *), void *arg, char const *name,
|
static Routine *add(int (*func)(void *), void *arg, char const *name,
|
||||||
bool started = false)
|
bool started = false)
|
||||||
{
|
{
|
||||||
_list()->insert(new (Genode::env()->heap())
|
Routine *r = new (Genode::env()->heap()) Routine(func, arg, name, started);
|
||||||
Routine(func, arg, name, started));
|
_list()->insert(r);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove this object
|
* Remove this object
|
||||||
*/
|
*/
|
||||||
static void remove()
|
static void remove(Routine *r = nullptr)
|
||||||
{
|
{
|
||||||
if (!_current)
|
if (!_current && !r)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_dead = _current;
|
_dead = r ? r : _current;
|
||||||
|
|
||||||
schedule();
|
schedule_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void main()
|
static void main()
|
||||||
|
@ -98,4 +98,9 @@ namespace Nic
|
|||||||
void init(Server::Entrypoint &ep);
|
void init(Server::Entrypoint &ep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Raw
|
||||||
|
{
|
||||||
|
void init(Server::Entrypoint &ep);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _SIGNAL_H_ */
|
#endif /* _SIGNAL_H_ */
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
#include <input/root.h>
|
#include <input/root.h>
|
||||||
#include <os/ring_buffer.h>
|
#include <os/ring_buffer.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
#undef RELEASE
|
#undef RELEASE
|
||||||
|
|
||||||
|
@ -22,9 +22,12 @@
|
|||||||
/* Local includes */
|
/* Local includes */
|
||||||
#include "routine.h"
|
#include "routine.h"
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
#include "lx_emul.h"
|
|
||||||
#include "platform/lx_mem.h"
|
#include "platform/lx_mem.h"
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
|
#include "lx_emul.h"
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
/* DDE kit includes */
|
/* DDE kit includes */
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <dde_kit/semaphore.h>
|
#include <dde_kit/semaphore.h>
|
||||||
@ -770,8 +773,8 @@ class Driver : public Genode::List<Driver>::Element
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
|
bool ret = _drv->bus->match ? _drv->bus->match(dev, _drv) : true;
|
||||||
dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p",
|
dde_kit_log(DEBUG_DRIVER, "MATCH: %s ret: %u match: %p %p",
|
||||||
_drv->name, ret, _drv->bus->match);
|
_drv->name, ret, _drv->bus->match, _drv->probe);
|
||||||
return ret;
|
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);
|
dde_kit_log(DEBUG_DRIVER, "Probing device bus %p", dev->bus->probe);
|
||||||
return dev->bus->probe(dev);
|
return dev->bus->probe(dev);
|
||||||
} else if (_drv->probe) {
|
} 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);
|
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)
|
int device_register(struct device *dev)
|
||||||
{
|
{
|
||||||
//XXX: initialize DMA pools (see device_initialize)
|
//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)
|
void *dev_get_platdata(const struct device *dev)
|
||||||
{
|
{
|
||||||
PDBG("called");
|
|
||||||
return (void *)dev->platform_data;
|
return (void *)dev->platform_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,3 +1322,23 @@ int waitqueue_active(wait_queue_head_t *q)
|
|||||||
{
|
{
|
||||||
return q->q ? 1 : 0;
|
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_wacom_driver_init();
|
||||||
extern "C" void module_ch_driver_init();
|
extern "C" void module_ch_driver_init();
|
||||||
extern "C" void module_mt_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);
|
extern "C" void start_input_service(void *ep, unsigned long, unsigned long);
|
||||||
|
|
||||||
@ -81,6 +82,10 @@ static void init(Services *services)
|
|||||||
/* storage */
|
/* storage */
|
||||||
if (services->stor)
|
if (services->stor)
|
||||||
module_usb_storage_driver_init();
|
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);
|
Storage::init(ep);
|
||||||
Nic::init(ep);
|
Nic::init(ep);
|
||||||
|
|
||||||
|
if (services.raw)
|
||||||
|
Raw::init(ep);
|
||||||
|
|
||||||
Routine::add(0, 0, "Main", true);
|
Routine::add(0, 0, "Main", true);
|
||||||
Routine::make_main_current();
|
Routine::make_main_current();
|
||||||
init(&services);
|
init(&services);
|
||||||
|
@ -19,15 +19,15 @@
|
|||||||
#include <nic/xml_node.h>
|
#include <nic/xml_node.h>
|
||||||
#include <util/xml_node.h>
|
#include <util/xml_node.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <linux/usb.h>
|
||||||
|
#include <linux/usb/usbnet.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
#include <nic/component.h>
|
#include <nic/component.h>
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
extern "C" {
|
|
||||||
#include <linux/usb.h>
|
|
||||||
#include <linux/usb/usbnet.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
static Signal_helper *_signal = 0;
|
static Signal_helper *_signal = 0;
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@
|
|||||||
#include <pci_device/client.h>
|
#include <pci_device/client.h>
|
||||||
|
|
||||||
/* Linux includes */
|
/* Linux includes */
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
#include <platform/lx_mem.h>
|
#include <platform/lx_mem.h>
|
||||||
|
|
||||||
struct bus_type pci_bus_type;
|
struct bus_type pci_bus_type;
|
||||||
@ -56,7 +58,7 @@ class Pci_driver
|
|||||||
|
|
||||||
_dev->vendor = client.vendor_id();
|
_dev->vendor = client.vendor_id();
|
||||||
_dev->device = client.device_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->revision = client.config_read(REV, Device::ACCESS_8BIT);
|
||||||
_dev->dev.driver = &_drv->driver;
|
_dev->dev.driver = &_drv->driver;
|
||||||
|
|
||||||
@ -236,15 +238,15 @@ int pci_register_driver(struct pci_driver *drv)
|
|||||||
|
|
||||||
bool found = false;
|
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");
|
dde_kit_log(DEBUG_PCI, "Skipping PCI_ANY_ID device class");
|
||||||
id++;
|
id++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pci::Device_capability cap = pci.first_device(id->device_class,
|
Pci::Device_capability cap = pci.first_device(id->class_,
|
||||||
id->class_mask);
|
id->class_mask);
|
||||||
while (cap.valid()) {
|
while (cap.valid()) {
|
||||||
|
|
||||||
@ -278,7 +280,7 @@ int pci_register_driver(struct pci_driver *drv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Pci::Device_capability free_up = cap;
|
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)
|
if (!pci_drv)
|
||||||
pci.release_device(free_up);
|
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 <signal.h>
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
static Signal_helper *_signal = 0;
|
static Signal_helper *_signal = 0;
|
||||||
|
|
||||||
|
@ -12,7 +12,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <dde_kit/interrupt.h>
|
#include <dde_kit/interrupt.h>
|
||||||
|
@ -14,7 +14,9 @@
|
|||||||
#include <base/env.h>
|
#include <base/env.h>
|
||||||
#include <base/printf.h>
|
#include <base/printf.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
static void handler(void *timer);
|
static void handler(void *timer);
|
||||||
|
@ -17,10 +17,12 @@
|
|||||||
#include <util/endian.h>
|
#include <util/endian.h>
|
||||||
#include <util/list.h>
|
#include <util/list.h>
|
||||||
|
|
||||||
|
#include <extern_c_begin.h>
|
||||||
#include <lx_emul.h>
|
#include <lx_emul.h>
|
||||||
|
#include <storage/scsi.h>
|
||||||
|
#include <extern_c_end.h>
|
||||||
|
|
||||||
#include <platform/lx_mem.h>
|
#include <platform/lx_mem.h>
|
||||||
#include <storage/scsi.h>
|
|
||||||
#include "signal.h"
|
#include "signal.h"
|
||||||
|
|
||||||
static Signal_helper *_signal = 0;
|
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…
x
Reference in New Issue
Block a user