mirror of
https://github.com/genodelabs/genode.git
synced 2025-06-19 15:43:56 +00:00
committed by
Norman Feske
parent
48f216f481
commit
bfbfa86cd4
@ -63,11 +63,11 @@ append_platform_drv_config
|
|||||||
|
|
||||||
append config {
|
append config {
|
||||||
<start name="timer">
|
<start name="timer">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
<provides><service name="Timer"/></provides>
|
<provides><service name="Timer"/></provides>
|
||||||
</start>
|
</start>
|
||||||
<start name="usb_drv">
|
<start name="usb_drv">
|
||||||
<resource name="RAM" quantum="7M"/>
|
<resource name="RAM" quantum="32M"/>
|
||||||
<provides><service name="Usb"/></provides>
|
<provides><service name="Usb"/></provides>
|
||||||
<config uhci="yes" ehci="yes" xhci="yes">
|
<config uhci="yes" ehci="yes" xhci="yes">
|
||||||
<raw>
|
<raw>
|
||||||
@ -76,11 +76,11 @@ append config {
|
|||||||
</config>
|
</config>
|
||||||
</start>
|
</start>
|
||||||
<start name="usb_terminal">
|
<start name="usb_terminal">
|
||||||
<resource name="RAM" quantum="2M"/>
|
<resource name="RAM" quantum="4M"/>
|
||||||
<provides><service name="Terminal"/></provides>
|
<provides><service name="Terminal"/></provides>
|
||||||
</start>
|
</start>
|
||||||
<start name="test-terminal_echo">
|
<start name="test-terminal_echo">
|
||||||
<resource name="RAM" quantum="1M"/>
|
<resource name="RAM" quantum="2M"/>
|
||||||
</start>
|
</start>
|
||||||
</config>}
|
</config>}
|
||||||
|
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
/*
|
/*
|
||||||
* \brief PL2303-USB-UART driver that exposes a terminal session
|
* \brief PL2303-USB-UART driver that exposes a terminal session
|
||||||
* \author Sebastian Sumpf
|
* \author Sebastian Sumpf
|
||||||
|
* \author Christian Helmuth
|
||||||
* \date 2014-12-17
|
* \date 2014-12-17
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2014 Genode Labs GmbH
|
* Copyright (C) 2014-2017 Genode Labs GmbH
|
||||||
*
|
*
|
||||||
* This file is part of the Genode OS framework, which is distributed
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
* under the terms of the GNU General Public License version 2.
|
* under the terms of the GNU General Public License version 2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <base/component.h>
|
||||||
#include <base/heap.h>
|
#include <base/heap.h>
|
||||||
#include <os/attached_ram_dataspace.h>
|
#include <os/attached_ram_dataspace.h>
|
||||||
#include <os/ring_buffer.h>
|
#include <os/ring_buffer.h>
|
||||||
#include <os/server.h>
|
#include <os/static_root.h>
|
||||||
#include <root/component.h>
|
|
||||||
#include <terminal_session/terminal_session.h>
|
#include <terminal_session/terminal_session.h>
|
||||||
#include <usb/usb.h>
|
#include <usb/usb.h>
|
||||||
|
|
||||||
@ -58,108 +59,36 @@ struct Usb::Pl2303_driver : Completion
|
|||||||
|
|
||||||
typedef Genode::Ring_buffer<char, 4096, Genode::Ring_buffer_unsynchronized> Ring_buffer;
|
typedef Genode::Ring_buffer<char, 4096, Genode::Ring_buffer_unsynchronized> Ring_buffer;
|
||||||
|
|
||||||
Ring_buffer ring_buffer;
|
Env &_env;
|
||||||
Server::Entrypoint &ep;
|
Heap &_heap;
|
||||||
Server::Signal_rpc_member<Pl2303_driver> dispatcher{ ep, *this, &Pl2303_driver::state_change };
|
Ring_buffer _ring_buffer;
|
||||||
Genode::Allocator_avl alloc;
|
Genode::Allocator_avl _alloc { &_heap };
|
||||||
Usb::Connection connection{ &alloc, "usb_serial", 512 * 1024, dispatcher };
|
|
||||||
Usb::Device device;
|
|
||||||
Signal_context_capability connected_sigh;
|
|
||||||
Signal_context_capability read_sigh;
|
|
||||||
|
|
||||||
|
Genode::Signal_handler<Pl2303_driver> _state_handler {
|
||||||
|
_env.ep(), *this, &Pl2303_driver::_handle_state_change };
|
||||||
|
|
||||||
Pl2303_driver(Server::Entrypoint &ep)
|
Usb::Connection _connection { &_alloc, "usb_serial", 512 * 1024, _state_handler };
|
||||||
: ep(ep), alloc(Genode::env()->heap()),
|
Usb::Device _device { &_heap, _connection, _env.ep() };
|
||||||
device(Genode::env()->heap(), connection, ep)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
Signal_context_capability _connected_sigh;
|
||||||
/* send control message for to read/write from/to PL2303 endpoint */
|
Signal_context_capability _read_avail_sigh;
|
||||||
void pl2303_magic(Usb::Interface &iface, uint16_t value, uint16_t index, bool read)
|
|
||||||
{
|
|
||||||
Usb::Packet_descriptor p = iface.alloc(0);
|
|
||||||
|
|
||||||
uint8_t request_type = read ? Usb::ENDPOINT_IN : Usb::ENDPOINT_OUT
|
|
||||||
| Usb::TYPE_VENDOR
|
|
||||||
| Usb::RECIPIENT_DEVICE;
|
|
||||||
|
|
||||||
iface.control_transfer(p, request_type, 1, value, index,100);
|
|
||||||
iface.release(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pl2303_magic_read(Usb::Interface &iface, uint16_t value, uint16_t index) {
|
|
||||||
pl2303_magic(iface, value, index, true); }
|
|
||||||
|
|
||||||
void pl2303_magic_write(Usb::Interface &iface, uint16_t value, uint16_t index) {
|
|
||||||
pl2303_magic(iface, value, index, false); }
|
|
||||||
|
|
||||||
void bulk_packet(Packet_descriptor &p)
|
|
||||||
{
|
|
||||||
Interface iface = device.interface(0);
|
|
||||||
|
|
||||||
/* error or write packet */
|
|
||||||
if (!p.succeded || !p.read_transfer()) {
|
|
||||||
iface.release(p);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* buffer data */
|
|
||||||
bool send_sigh = ring_buffer.empty() && p.transfer.actual_size;
|
|
||||||
char *data = (char *)iface.content(p);
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (int i = 0; i < p.transfer.actual_size; i++)
|
|
||||||
ring_buffer.add(data[i]);
|
|
||||||
} catch (Ring_buffer::Overflow) {
|
|
||||||
Genode::warning("Pl2303 buffer overflow");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* submit back to device (async) */
|
|
||||||
iface.submit(p);
|
|
||||||
|
|
||||||
/* notify client */
|
|
||||||
if (send_sigh && read_sigh.valid())
|
|
||||||
Signal_transmitter(read_sigh).submit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void complete(Packet_descriptor &p)
|
|
||||||
{
|
|
||||||
switch (p.type) {
|
|
||||||
case Packet_descriptor::BULK: bulk_packet(p); break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t write(void *dst, size_t num_bytes)
|
|
||||||
{
|
|
||||||
num_bytes = min(num_bytes, MAX_PACKET_SIZE);
|
|
||||||
|
|
||||||
Interface &iface = device.interface(0);
|
|
||||||
Endpoint &ep = iface.endpoint(OUT);
|
|
||||||
Packet_descriptor p = iface.alloc(num_bytes);
|
|
||||||
|
|
||||||
memcpy(iface.content(p), dst, num_bytes);
|
|
||||||
iface.bulk_transfer(p, ep, false, this);
|
|
||||||
|
|
||||||
return num_bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Init 2303 controller
|
* Init 2303 controller
|
||||||
*/
|
*/
|
||||||
void init()
|
void _init()
|
||||||
{
|
{
|
||||||
/* read device configuration */
|
/* read device configuration */
|
||||||
device.update_config();
|
_device.update_config();
|
||||||
|
|
||||||
enum { BUF = 128 };
|
enum { BUF = 128 };
|
||||||
char buffer[BUF];
|
char buffer[BUF];
|
||||||
|
|
||||||
Genode::log("PL2303 controller: ready");
|
Genode::log("PL2303 controller: ready");
|
||||||
Genode::log("Manufacturer : ", Cstring(device.manufactorer_string.to_char(buffer, BUF)));
|
Genode::log("Manufacturer : ", Cstring(_device.manufactorer_string.to_char(buffer, BUF)));
|
||||||
Genode::log("Product : ", Cstring(device.product_string.to_char(buffer, BUF)));
|
Genode::log("Product : ", Cstring(_device.product_string.to_char(buffer, BUF)));
|
||||||
|
|
||||||
Interface &iface = device.interface(0);
|
Interface &iface = _device.interface(0);
|
||||||
iface.claim();
|
iface.claim();
|
||||||
|
|
||||||
/* undocumented magic, taken from Linux and GRUB */
|
/* undocumented magic, taken from Linux and GRUB */
|
||||||
@ -200,28 +129,111 @@ struct Usb::Pl2303_driver : Completion
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* send signal to terminal client */
|
/* send signal to terminal client */
|
||||||
if (connected_sigh.valid())
|
if (_connected_sigh.valid())
|
||||||
Signal_transmitter(connected_sigh).submit();
|
Signal_transmitter(_connected_sigh).submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void _handle_state_change()
|
||||||
* Called from USB driver when the desired device is active
|
|
||||||
*/
|
|
||||||
void state_change(unsigned)
|
|
||||||
{
|
{
|
||||||
if (connection.plugged())
|
if (_connection.plugged())
|
||||||
init();
|
_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Pl2303_driver(Genode::Env &env, Heap &heap)
|
||||||
|
: _env(env), _heap(heap) { }
|
||||||
|
|
||||||
|
void read_avail_sigh(Signal_context_capability sigh)
|
||||||
|
{
|
||||||
|
_read_avail_sigh = sigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void connected_sigh(Signal_context_capability sigh)
|
||||||
|
{
|
||||||
|
_connected_sigh = sigh;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* send control message for to read/write from/to PL2303 endpoint */
|
||||||
|
void pl2303_magic(Usb::Interface &iface, uint16_t value, uint16_t index, bool read)
|
||||||
|
{
|
||||||
|
Usb::Packet_descriptor p = iface.alloc(0);
|
||||||
|
|
||||||
|
uint8_t request_type = read ? Usb::ENDPOINT_IN : Usb::ENDPOINT_OUT
|
||||||
|
| Usb::TYPE_VENDOR
|
||||||
|
| Usb::RECIPIENT_DEVICE;
|
||||||
|
|
||||||
|
iface.control_transfer(p, request_type, 1, value, index,100);
|
||||||
|
iface.release(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pl2303_magic_read(Usb::Interface &iface, uint16_t value, uint16_t index) {
|
||||||
|
pl2303_magic(iface, value, index, true); }
|
||||||
|
|
||||||
|
void pl2303_magic_write(Usb::Interface &iface, uint16_t value, uint16_t index) {
|
||||||
|
pl2303_magic(iface, value, index, false); }
|
||||||
|
|
||||||
|
void bulk_packet(Packet_descriptor &p)
|
||||||
|
{
|
||||||
|
Interface iface = _device.interface(0);
|
||||||
|
|
||||||
|
/* error or write packet */
|
||||||
|
if (!p.succeded || !p.read_transfer()) {
|
||||||
|
iface.release(p);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* buffer data */
|
||||||
|
bool const notify_sigh = _ring_buffer.empty() && p.transfer.actual_size;
|
||||||
|
char *data = (char *)iface.content(p);
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < p.transfer.actual_size; i++)
|
||||||
|
_ring_buffer.add(data[i]);
|
||||||
|
} catch (Ring_buffer::Overflow) {
|
||||||
|
Genode::warning("Pl2303 buffer overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* submit back to device (async) */
|
||||||
|
iface.submit(p);
|
||||||
|
|
||||||
|
/* notify client */
|
||||||
|
if (notify_sigh && _read_avail_sigh.valid())
|
||||||
|
Signal_transmitter(_read_avail_sigh).submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void complete(Packet_descriptor &p)
|
||||||
|
{
|
||||||
|
switch (p.type) {
|
||||||
|
case Packet_descriptor::BULK: bulk_packet(p); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(void *dst, size_t num_bytes)
|
||||||
|
{
|
||||||
|
num_bytes = min(num_bytes, MAX_PACKET_SIZE);
|
||||||
|
|
||||||
|
Interface &iface = _device.interface(0);
|
||||||
|
Endpoint &ep = iface.endpoint(OUT);
|
||||||
|
Packet_descriptor p = iface.alloc(num_bytes);
|
||||||
|
|
||||||
|
memcpy(iface.content(p), dst, num_bytes);
|
||||||
|
iface.bulk_transfer(p, ep, false, this);
|
||||||
|
|
||||||
|
return num_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return true if data is available
|
* Return true if data is available
|
||||||
*/
|
*/
|
||||||
bool avail() const { return !ring_buffer.empty(); }
|
bool avail() const { return !_ring_buffer.empty(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Obtain character
|
* Obtain character
|
||||||
*/
|
*/
|
||||||
char get() { return ring_buffer.get(); }
|
char get() { return _ring_buffer.get(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -234,18 +246,21 @@ class Terminal::Session_component : public Rpc_object<Session, Session_component
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Session_component(size_t io_buffer_size, Usb::Pl2303_driver &driver)
|
Session_component(Genode::Env &env, size_t io_buffer_size,
|
||||||
: _io_buffer(env()->ram_session(), io_buffer_size), _driver(driver)
|
Usb::Pl2303_driver &driver)
|
||||||
|
:
|
||||||
|
_io_buffer(env.ram(), env.rm(), io_buffer_size),
|
||||||
|
_driver(driver)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
void read_avail_sigh(Signal_context_capability sigh)
|
void read_avail_sigh(Signal_context_capability sigh)
|
||||||
{
|
{
|
||||||
_driver.read_sigh = sigh;
|
_driver.read_avail_sigh(sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void connected_sigh(Signal_context_capability sigh)
|
void connected_sigh(Signal_context_capability sigh)
|
||||||
{
|
{
|
||||||
_driver.connected_sigh = sigh;
|
_driver.connected_sigh(sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
Size size() { return Size(0, 0); }
|
Size size() { return Size(0, 0); }
|
||||||
@ -279,48 +294,19 @@ class Terminal::Session_component : public Rpc_object<Session, Session_component
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Terminal::Root_component : public Genode::Root_component<Session_component, Single_client>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
Usb::Pl2303_driver _driver;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
Session_component *_create_session(char const *args)
|
|
||||||
{
|
|
||||||
size_t const io_buffer_size = 4096;
|
|
||||||
return new (md_alloc()) Session_component(io_buffer_size, _driver);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
Root_component(Server::Entrypoint &ep, Genode::Allocator &md_alloc)
|
|
||||||
: Genode::Root_component<Session_component, Genode::Single_client>(&ep.rpc_ep(), &md_alloc),
|
|
||||||
_driver(ep)
|
|
||||||
{ }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct Terminal::Main
|
struct Terminal::Main
|
||||||
{
|
{
|
||||||
Server::Entrypoint &ep;
|
Env &_env;
|
||||||
Sliced_heap heap = { env()->ram_session(), env()->rm_session() };
|
Heap _heap { _env.ram(), _env.rm() };
|
||||||
Root_component terminal_root = { ep, heap };
|
Usb::Pl2303_driver _driver { _env, _heap };
|
||||||
|
Session_component _session { _env, 4096, _driver };
|
||||||
|
Static_root<Session> _root { _env.ep().manage(_session) };
|
||||||
|
|
||||||
Main(Server::Entrypoint &ep) : ep(ep)
|
Main(Genode::Env &env) : _env(env)
|
||||||
{
|
{
|
||||||
env()->parent()->announce(ep.manage(terminal_root));
|
env.parent().announce(env.ep().manage(_root));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
namespace Server {
|
void Component::construct(Genode::Env &env) { static Terminal::Main inst(env); }
|
||||||
char const *name() { return "usb_terminal_ep"; };
|
|
||||||
size_t stack_size() { return 16*1024*sizeof(long); }
|
|
||||||
|
|
||||||
void construct(Entrypoint &ep)
|
|
||||||
{
|
|
||||||
static Terminal::Main server(ep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
TARGET = usb_terminal
|
TARGET = usb_terminal
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
LIBS = base server
|
LIBS = base
|
||||||
|
Reference in New Issue
Block a user