2016-02-08 19:02:55 +01:00
|
|
|
/*
|
|
|
|
* \brief Usb session to Block session translator
|
|
|
|
* \author Josef Soentgen
|
|
|
|
* \date 2016-02-08
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2017-01-16 15:33:56 +01:00
|
|
|
* Copyright (C) 2016-2017 Genode Labs GmbH
|
2016-02-08 19:02:55 +01:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2016-02-08 19:02:55 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/allocator_avl.h>
|
2016-05-27 23:14:36 +02:00
|
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
#include <base/component.h>
|
|
|
|
#include <base/log.h>
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
#include <base/heap.h>
|
2016-02-08 19:02:55 +01:00
|
|
|
#include <block/component.h>
|
|
|
|
#include <block/driver.h>
|
|
|
|
#include <block_session/connection.h>
|
|
|
|
#include <os/reporter.h>
|
|
|
|
#include <timer_session/connection.h>
|
|
|
|
#include <usb/usb.h>
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
/* used by cbw_csw.h so declare it here */
|
2016-02-08 19:02:55 +01:00
|
|
|
static bool verbose_scsi = false;
|
|
|
|
|
|
|
|
/* local includes */
|
|
|
|
#include <cbw_csw.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace Usb {
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
struct Block_driver;
|
2016-05-27 23:14:36 +02:00
|
|
|
struct Main;
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*********************************************************
|
|
|
|
** USB Mass Storage (BBB) Block::Driver implementation **
|
|
|
|
*********************************************************/
|
|
|
|
|
|
|
|
struct Usb::Block_driver : Usb::Completion,
|
|
|
|
Block::Driver
|
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
Env &env;
|
|
|
|
Entrypoint &ep;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Signal_context_capability announce_sigh;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Pending block request
|
|
|
|
*/
|
|
|
|
struct Block_request
|
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Block::Packet_descriptor packet { };
|
|
|
|
Block::sector_t lba { 0 };
|
|
|
|
char *buffer { nullptr };
|
|
|
|
size_t size { 0 };
|
|
|
|
bool read { false };
|
|
|
|
bool pending { false };
|
|
|
|
} req { };
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
bool initialized = false;
|
|
|
|
bool device_plugged = false;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle stage change signal
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
void handle_state_change()
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
if (!usb.plugged()) {
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::log("Device unplugged");
|
2016-02-08 19:02:55 +01:00
|
|
|
device_plugged = false;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (initialized) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Device was already initialized");
|
2016-02-08 19:02:55 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
Genode::log("Device plugged");
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
if (!initialize()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* all is well, announce the device */
|
|
|
|
Signal_transmitter(announce_sigh).submit();
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Signal_handler<Block_driver> state_change_dispatcher = {
|
2016-02-08 19:02:55 +01:00
|
|
|
ep, *this, &Block_driver::handle_state_change };
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
/*
|
|
|
|
* Config ROM
|
|
|
|
*/
|
|
|
|
Attached_rom_dataspace config { env, "config" };
|
|
|
|
|
2016-02-08 19:02:55 +01:00
|
|
|
/*
|
|
|
|
* Read Usb session label from the configuration
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
static char const *get_label(Xml_node node)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
static Genode::String<256> usb_label;
|
|
|
|
try {
|
2019-01-21 10:48:39 +01:00
|
|
|
node.attribute("label").value(usb_label);
|
2016-02-08 19:02:55 +01:00
|
|
|
return usb_label.string();
|
|
|
|
} catch (...) { }
|
|
|
|
|
|
|
|
return "usb_storage";
|
|
|
|
}
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
/*
|
|
|
|
* USB session
|
|
|
|
*/
|
|
|
|
Allocator_avl alloc;
|
|
|
|
Usb::Connection usb { env, &alloc, get_label(config.xml()), 2 * (1<<20), state_change_dispatcher };
|
|
|
|
Usb::Device device;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
/*
|
|
|
|
* Reporter
|
|
|
|
*/
|
2017-01-03 11:24:16 +01:00
|
|
|
Reporter reporter { env, "devices" };
|
2016-02-08 19:02:55 +01:00
|
|
|
bool _report_device = false;
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
/*
|
|
|
|
* Block session
|
|
|
|
*/
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Block::Session::Operations _block_ops { };
|
|
|
|
Block::sector_t _block_count { 0 };
|
|
|
|
size_t _block_size { 0 };
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
bool _writeable = false;
|
|
|
|
|
2018-05-07 15:54:18 +02:00
|
|
|
bool force_cmd_16 = false;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
uint8_t active_interface = 0;
|
|
|
|
uint8_t active_lun = 0;
|
|
|
|
|
|
|
|
uint32_t active_tag = 0;
|
|
|
|
uint32_t new_tag() { return ++active_tag % 0xffffffu; }
|
|
|
|
|
|
|
|
enum Tags {
|
|
|
|
INQ_TAG = 0x01, RDY_TAG = 0x02, CAP_TAG = 0x04,
|
|
|
|
REQ_TAG = 0x08, SS_TAG = 0x10
|
|
|
|
};
|
2018-05-07 11:54:14 +02:00
|
|
|
|
|
|
|
uint8_t ep_in = 0;
|
|
|
|
uint8_t ep_out = 0;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2018-05-22 15:32:28 +02:00
|
|
|
bool reset_device = false;
|
|
|
|
|
2016-02-08 19:02:55 +01:00
|
|
|
/*
|
|
|
|
* Completion used while initializing the device
|
|
|
|
*/
|
|
|
|
struct Init_completion : Usb::Completion
|
|
|
|
{
|
|
|
|
bool inquiry = false;
|
|
|
|
bool unit_ready = false;
|
|
|
|
bool read_capacity = false;
|
|
|
|
bool request_sense = false;
|
|
|
|
|
|
|
|
bool no_medium = false;
|
|
|
|
bool try_again = false;
|
|
|
|
|
|
|
|
Usb::Device &device;
|
2016-05-27 23:14:36 +02:00
|
|
|
uint8_t interface;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Block::sector_t block_count = 0;
|
|
|
|
size_t block_size = 0;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
char vendor[Scsi::Inquiry_response::Vid::ITEMS+1];
|
|
|
|
char product[Scsi::Inquiry_response::Pid::ITEMS+1];
|
|
|
|
|
|
|
|
Init_completion(Usb::Device &device, uint8_t interface)
|
|
|
|
: device(device), interface(interface) { }
|
|
|
|
|
|
|
|
void complete(Packet_descriptor &p)
|
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Usb::Interface iface = device.interface(interface);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (p.type != Packet_descriptor::BULK) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Can only handle BULK packets");
|
2016-02-08 19:02:55 +01:00
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!p.succeded) {
|
2017-11-05 16:36:14 +01:00
|
|
|
Genode::error("init complete error: packet not succeeded");
|
2016-02-08 19:02:55 +01:00
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OUT transfer finished */
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!p.read_transfer()) {
|
2016-02-08 19:02:55 +01:00
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int const actual_size = p.transfer.actual_size;
|
|
|
|
char * const data = reinterpret_cast<char*>(iface.content(p));
|
|
|
|
|
|
|
|
using namespace Scsi;
|
|
|
|
|
|
|
|
switch (actual_size) {
|
|
|
|
case Inquiry_response::LENGTH:
|
|
|
|
{
|
|
|
|
Inquiry_response r((addr_t)data);
|
|
|
|
if (verbose_scsi) r.dump();
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
if (!r.sbc()) {
|
|
|
|
Genode::warning("Device does not use SCSI Block Commands and may not work");
|
|
|
|
}
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
r.get_id<Inquiry_response::Vid>(vendor, sizeof(vendor));
|
|
|
|
r.get_id<Inquiry_response::Pid>(product, sizeof(product));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Capacity_response_10::LENGTH:
|
|
|
|
{
|
|
|
|
Capacity_response_10 r((addr_t)data);
|
|
|
|
if (verbose_scsi) r.dump();
|
|
|
|
|
2018-05-07 16:10:39 +02:00
|
|
|
block_count = r.last_block() + 1;
|
2016-02-08 19:02:55 +01:00
|
|
|
block_size = r.block_size();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Capacity_response_16::LENGTH:
|
|
|
|
{
|
|
|
|
Capacity_response_16 r((addr_t)data);
|
|
|
|
if (verbose_scsi) r.dump();
|
|
|
|
|
2018-05-07 16:10:39 +02:00
|
|
|
block_count = r.last_block() + 1;
|
2016-02-08 19:02:55 +01:00
|
|
|
block_size = r.block_size();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Request_sense_response::LENGTH:
|
|
|
|
{
|
|
|
|
Request_sense_response r((addr_t)data);
|
|
|
|
if (verbose_scsi) r.dump();
|
|
|
|
|
|
|
|
uint8_t const asc = r.read<Request_sense_response::Asc>();
|
|
|
|
uint8_t const asq = r.read<Request_sense_response::Asq>();
|
|
|
|
|
|
|
|
enum { MEDIUM_NOT_PRESENT = 0x3a, NOT_READY_TO_READY_CHANGE = 0x28 };
|
|
|
|
switch (asc) {
|
|
|
|
case MEDIUM_NOT_PRESENT:
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Not ready - medium not present");
|
2016-02-08 19:02:55 +01:00
|
|
|
no_medium = true;
|
|
|
|
break;
|
|
|
|
case NOT_READY_TO_READY_CHANGE: /* asq == 0x00 */
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("Not ready - try again");
|
2016-02-08 19:02:55 +01:00
|
|
|
try_again = true;
|
|
|
|
break;
|
|
|
|
default:
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Request_sense_response asc: ",
|
|
|
|
Hex(asc, Hex::PREFIX, Hex::PAD),
|
|
|
|
" asq: ", Hex(asq, Hex::PREFIX, Hex::PAD));
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case Csw::LENGTH:
|
|
|
|
{
|
|
|
|
Csw csw((addr_t)data);
|
|
|
|
|
|
|
|
uint32_t const sig = csw.sig();
|
|
|
|
if (sig != Csw::SIG) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("CSW signature does not match: ",
|
|
|
|
Hex(sig, Hex::PREFIX, Hex::PAD));
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t const tag = csw.tag();
|
|
|
|
uint8_t const status = csw.sts();
|
|
|
|
if (status != Csw::PASSED) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
|
|
|
|
" tag: ", tag);
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
inquiry |= tag & INQ_TAG;
|
|
|
|
unit_ready |= tag & RDY_TAG;
|
|
|
|
read_capacity |= tag & CAP_TAG;
|
|
|
|
request_sense |= tag & REQ_TAG;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
iface.release(p);
|
|
|
|
}
|
|
|
|
} init { device, active_interface };
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send CBW
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
void cbw(void *cb, Completion &c, bool block = false)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
enum { CBW_VALID_SIZE = Cbw::LENGTH };
|
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2018-05-07 11:54:14 +02:00
|
|
|
Usb::Endpoint &ep = iface.endpoint(ep_out);
|
2016-02-08 19:02:55 +01:00
|
|
|
Usb::Packet_descriptor p = iface.alloc(CBW_VALID_SIZE);
|
|
|
|
memcpy(iface.content(p), cb, CBW_VALID_SIZE);
|
2016-10-17 14:13:51 +02:00
|
|
|
iface.bulk_transfer(p, ep, block, &c);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive CSW
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
void csw(Completion &c, bool block = false)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
enum { CSW_VALID_SIZE = Csw::LENGTH };
|
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2018-05-07 11:54:14 +02:00
|
|
|
Usb::Endpoint &ep = iface.endpoint(ep_in);
|
2016-02-08 19:02:55 +01:00
|
|
|
Usb::Packet_descriptor p = iface.alloc(CSW_VALID_SIZE);
|
2016-10-17 14:13:51 +02:00
|
|
|
iface.bulk_transfer(p, ep, block, &c);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Receive response
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
void resp(size_t size, Completion &c, bool block = false)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2018-05-07 11:54:14 +02:00
|
|
|
Usb::Endpoint &ep = iface.endpoint(ep_in);
|
2016-02-08 19:02:55 +01:00
|
|
|
Usb::Packet_descriptor p = iface.alloc(size);
|
2016-10-17 14:13:51 +02:00
|
|
|
iface.bulk_transfer(p, ep, block, &c);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Report block device
|
|
|
|
*/
|
|
|
|
void report_device(char const *vendor, char const *product,
|
|
|
|
Block::sector_t count, size_t size)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
Genode::Reporter::Xml_generator xml(reporter, [&] () {
|
|
|
|
xml.node("device", [&] () {
|
|
|
|
xml.attribute("vendor", vendor);
|
|
|
|
xml.attribute("product", product);
|
|
|
|
xml.attribute("block_count", count);
|
|
|
|
xml.attribute("block_size", size);
|
|
|
|
xml.attribute("writeable", _writeable);
|
|
|
|
});
|
|
|
|
});
|
2016-05-27 23:14:36 +02:00
|
|
|
} catch (...) { Genode::warning("Could not report block device"); }
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize device
|
|
|
|
*
|
|
|
|
* All USB transfers in this method are done synchronously. First we reset
|
2018-05-22 15:32:28 +02:00
|
|
|
* the device (optional), then we query the max LUN. Afterwards we start
|
|
|
|
* sending CBWs.
|
2016-02-08 19:02:55 +01:00
|
|
|
*
|
|
|
|
* Since it might take some time for the device to get ready to use, we
|
|
|
|
* have to check the SCSI logical unit several times.
|
|
|
|
*/
|
|
|
|
bool initialize()
|
|
|
|
{
|
|
|
|
device.update_config();
|
|
|
|
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2016-02-08 19:02:55 +01:00
|
|
|
try { iface.claim(); }
|
|
|
|
catch (Usb::Session::Interface_already_claimed) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Device already claimed");
|
2016-02-08 19:02:55 +01:00
|
|
|
return false;
|
|
|
|
} catch (Usb::Session::Interface_not_found) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Interface not found");
|
2016-02-08 19:02:55 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
enum {
|
|
|
|
ICLASS_MASS_STORAGE = 8,
|
|
|
|
ISUBCLASS_SCSI = 6,
|
|
|
|
IPROTO_BULK_ONLY = 80
|
|
|
|
};
|
2018-05-07 11:54:14 +02:00
|
|
|
|
2018-06-11 15:09:29 +02:00
|
|
|
Alternate_interface &alt_iface = iface.current();
|
2018-05-07 11:54:14 +02:00
|
|
|
|
2018-06-11 15:09:29 +02:00
|
|
|
if (alt_iface.iclass != ICLASS_MASS_STORAGE
|
|
|
|
|| alt_iface.isubclass != ISUBCLASS_SCSI
|
|
|
|
|| alt_iface.iprotocol != IPROTO_BULK_ONLY) {
|
|
|
|
Genode::error("No mass storage SCSI bulk-only device");
|
2016-02-08 19:02:55 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-11 15:09:29 +02:00
|
|
|
for (int i = 0; i < alt_iface.num_endpoints; i++) {
|
|
|
|
Endpoint ep = alt_iface.endpoint(i);
|
|
|
|
if (!ep.bulk())
|
|
|
|
continue;
|
|
|
|
if (ep.address & Usb::ENDPOINT_IN)
|
|
|
|
ep_in = i;
|
|
|
|
else
|
|
|
|
ep_out = i;
|
|
|
|
}
|
|
|
|
|
2016-02-08 19:02:55 +01:00
|
|
|
try {
|
2018-05-22 15:32:28 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* reset
|
|
|
|
*
|
|
|
|
* This command caused write command errors on a
|
|
|
|
* 'SanDisk Cruzer Force' (0781:557d) USB stick, so it is
|
|
|
|
* omitted by default.
|
|
|
|
*/
|
|
|
|
if (reset_device) {
|
|
|
|
Usb::Packet_descriptor p = iface.alloc(0);
|
|
|
|
iface.control_transfer(p, 0x21, 0xff, 0, active_interface, 100);
|
|
|
|
if (!p.succeded) {
|
|
|
|
Genode::error("Could not reset device");
|
|
|
|
iface.release(p);
|
|
|
|
throw -1;
|
|
|
|
}
|
2018-05-07 17:20:56 +02:00
|
|
|
iface.release(p);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let us do GetMaxLUN and simply ignore the return value because none
|
|
|
|
* of the devices that were tested did infact report another value than 0.
|
|
|
|
*/
|
2018-05-22 15:32:28 +02:00
|
|
|
Usb::Packet_descriptor p = iface.alloc(1);
|
2016-02-08 19:02:55 +01:00
|
|
|
iface.control_transfer(p, 0xa1, 0xfe, 0, active_interface, 100);
|
|
|
|
uint8_t max_lun = *(uint8_t*)iface.content(p);
|
|
|
|
if (p.succeded && max_lun == 0) { max_lun = 1; }
|
|
|
|
iface.release(p);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Query device
|
|
|
|
*/
|
|
|
|
|
|
|
|
char cbw_buffer[Cbw::LENGTH];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We should probably execute the SCSI REPORT_LUNS command first
|
|
|
|
* but we will receive LOGICAL UNIT NOT SUPPORTED if we try to
|
|
|
|
* access an invalid unit. The user has to specify the LUN in
|
|
|
|
* the configuration anyway.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Scsi::Opcode::INQUIRY */
|
|
|
|
Inquiry inq((addr_t)cbw_buffer, INQ_TAG, active_lun);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cbw_buffer, init, true);
|
|
|
|
resp(Scsi::Inquiry_response::LENGTH, init, true);
|
|
|
|
csw(init, true);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (!init.inquiry) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("Inquiry_cmd failed");
|
2016-02-08 19:02:55 +01:00
|
|
|
throw -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scsi::Opcode::TEST_UNIT_READY */
|
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
Timer::Connection timer { env };
|
2016-02-08 19:02:55 +01:00
|
|
|
/*
|
|
|
|
* It might take some time for devices to get ready (e.g. the ZTE Open C
|
|
|
|
* takes 3 retries to actually present us a medium and another try to
|
|
|
|
* let us use the medium.
|
|
|
|
*/
|
|
|
|
enum { MAX_RETRIES = 10 };
|
|
|
|
int retries;
|
|
|
|
for (retries = 0; retries < MAX_RETRIES; retries++) {
|
|
|
|
Test_unit_ready unit_ready((addr_t)cbw_buffer, RDY_TAG, active_lun);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cbw_buffer, init, true);
|
|
|
|
csw(init, true);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (!init.unit_ready) {
|
|
|
|
Request_sense sense((addr_t)cbw_buffer, REQ_TAG, active_lun);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cbw_buffer, init, true);
|
|
|
|
resp(Scsi::Request_sense_response::LENGTH, init, true);
|
|
|
|
csw(init, true);
|
2016-02-08 19:02:55 +01:00
|
|
|
if (!init.request_sense) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("Request_sense failed");
|
2016-02-08 19:02:55 +01:00
|
|
|
throw -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init.no_medium) {
|
|
|
|
/* do nothing for now */
|
|
|
|
} else if (init.try_again) {
|
|
|
|
init.try_again = false;
|
|
|
|
} else break;
|
|
|
|
} else break;
|
|
|
|
|
|
|
|
timer.msleep(1000);
|
|
|
|
}
|
|
|
|
if (retries == MAX_RETRIES) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("Test_unit_ready_cmd failed");
|
2016-02-08 19:02:55 +01:00
|
|
|
throw -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-07 15:54:18 +02:00
|
|
|
/*
|
|
|
|
* Some devices (e.g. corsair voyager usb stick (1b1c:1a03)) failed
|
|
|
|
* when the 16-byte command was tried first and when the 10-byte
|
|
|
|
* command was tried afterwards as a fallback.
|
|
|
|
*
|
|
|
|
* For this reason, we use the 10-byte commands by default and the
|
|
|
|
* 16-byte commands only when the capacity of the device requires
|
|
|
|
* it.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Scsi::Opcode::READ_CAPACITY_10 */
|
|
|
|
Read_capacity_10 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cbw_buffer, init, true);
|
2018-05-07 15:54:18 +02:00
|
|
|
resp(Scsi::Capacity_response_10::LENGTH, init, true);
|
2016-05-27 23:14:36 +02:00
|
|
|
csw(init, true);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (!init.read_capacity) {
|
2018-05-07 15:54:18 +02:00
|
|
|
Genode::warning("Read_capacity_cmd failed");
|
|
|
|
throw -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (init.block_count == 0x100000000) {
|
|
|
|
|
|
|
|
/* capacity too large, try Scsi::Opcode::READ_CAPACITY_16 next */
|
|
|
|
Read_capacity_16 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
|
|
|
|
|
|
|
init.read_capacity = false;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cbw_buffer, init, true);
|
2018-05-07 15:54:18 +02:00
|
|
|
resp(Scsi::Capacity_response_16::LENGTH, init, true);
|
2016-05-27 23:14:36 +02:00
|
|
|
csw(init, true);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (!init.read_capacity) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("Read_capacity_cmd failed");
|
2016-02-08 19:02:55 +01:00
|
|
|
throw -1;
|
|
|
|
}
|
|
|
|
|
2018-05-07 15:54:18 +02:00
|
|
|
force_cmd_16 = true;
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_block_size = init.block_size;
|
|
|
|
_block_count = init.block_count;
|
|
|
|
|
|
|
|
initialized = true;
|
|
|
|
device_plugged = true;
|
|
|
|
|
|
|
|
char vendor[32];
|
|
|
|
char product[32];
|
|
|
|
|
|
|
|
device.manufactorer_string.to_char(vendor, sizeof(vendor));
|
|
|
|
device.product_string.to_char(product, sizeof(product));
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::log("Found USB device: ", (char const*)vendor, " (",
|
|
|
|
(char const*)product, ") block size: ", _block_size,
|
|
|
|
" count: ", _block_count);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (_report_device)
|
|
|
|
report_device(init.vendor, init.product,
|
|
|
|
init.block_count, init.block_size);
|
|
|
|
return true;
|
|
|
|
} catch (int) {
|
|
|
|
/* handle command failures */
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Could not initialize storage device");
|
2016-02-08 19:02:55 +01:00
|
|
|
return false;
|
|
|
|
} catch (...) {
|
|
|
|
/* handle Usb::Session failures */
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Could not initialize storage device");
|
2016-02-08 19:02:55 +01:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Execute pending request
|
|
|
|
*
|
|
|
|
* Called after the CBW has been successfully received by the device
|
|
|
|
* to initiate read/write transaction.
|
|
|
|
*/
|
|
|
|
bool execute_pending_request()
|
|
|
|
{
|
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2018-05-07 11:54:14 +02:00
|
|
|
Usb::Endpoint ep = iface.endpoint(req.read ? ep_in : ep_out);
|
2016-02-08 19:02:55 +01:00
|
|
|
Usb::Packet_descriptor p = iface.alloc(req.size);
|
|
|
|
|
|
|
|
if (!req.read) memcpy(iface.content(p), req.buffer, req.size);
|
|
|
|
|
2016-10-17 14:13:51 +02:00
|
|
|
iface.bulk_transfer(p, ep, false, this);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Acknowledge currently pending request
|
|
|
|
*
|
|
|
|
* After receiving the CSW ack the request at the Block session.
|
|
|
|
*/
|
|
|
|
void ack_pending_request(bool success = true)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Needs to be reset bevor calling ack_packet to prevent getting a new
|
|
|
|
* request imediately and throwing Request_congestion() in io() again.
|
|
|
|
*/
|
|
|
|
req.pending = false;
|
|
|
|
|
|
|
|
Block::Packet_descriptor p = req.packet;
|
|
|
|
ack_packet(p, success);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Handle packet completion
|
|
|
|
*
|
|
|
|
* This method is called several times while doing one transaction. First
|
|
|
|
* the CWB is sent, than the payload read or written. At the end, the CSW
|
|
|
|
* is requested.
|
|
|
|
*/
|
|
|
|
void complete(Packet_descriptor &p)
|
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Usb::Interface iface = device.interface(active_interface);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
if (p.type != Packet_descriptor::BULK) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("No BULK packet");
|
2016-02-08 19:02:55 +01:00
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!p.succeded) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("complete error: packet not succeded");
|
2016-02-08 19:02:55 +01:00
|
|
|
if (req.pending) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("request pending: tag: ", active_tag, " read: ",
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
(int)req.read, " buffer: ", (void *)req.buffer, " lba: ",
|
2016-05-27 23:14:36 +02:00
|
|
|
req.lba, " size: ", req.size);
|
2016-02-08 19:02:55 +01:00
|
|
|
ack_pending_request(false);
|
|
|
|
}
|
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool request_executed = false;
|
2016-05-11 18:21:47 +02:00
|
|
|
if (!p.read_transfer()) {
|
2016-02-08 19:02:55 +01:00
|
|
|
/* send read/write request */
|
|
|
|
if (req.pending) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The CBW was successfully sent to the device, now read/write the
|
|
|
|
* actual content.
|
|
|
|
*/
|
|
|
|
if (!request_executed) {
|
|
|
|
request_executed = execute_pending_request();
|
|
|
|
} else {
|
|
|
|
/* the content was successfully written, get the CSW */
|
2016-05-27 23:14:36 +02:00
|
|
|
csw(*this);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int actual_size = p.transfer.actual_size;
|
|
|
|
if (actual_size < 0) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("Transfer actual size: ", actual_size);
|
2016-02-08 19:02:55 +01:00
|
|
|
actual_size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* the size indicates an IN I/O packet */
|
|
|
|
if ((uint32_t)actual_size >= _block_size) {
|
|
|
|
if (req.pending) {
|
|
|
|
|
|
|
|
/* the content was successfully read, get the CSW */
|
|
|
|
memcpy(req.buffer, iface.content(p), actual_size);
|
2016-05-27 23:14:36 +02:00
|
|
|
csw(*this);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
iface.release(p);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* when ending up here, we should have gotten an CSW packet */
|
|
|
|
if (actual_size != Csw::LENGTH)
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::warning("This is not the actual size you are looking for");
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
do {
|
|
|
|
Csw csw((addr_t)iface.content(p));
|
|
|
|
|
|
|
|
uint32_t const sig = csw.sig();
|
|
|
|
if (sig != Csw::SIG) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("CSW signature does not match: ",
|
|
|
|
Hex(sig, Hex::PREFIX, Hex::PAD));
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t const tag = csw.tag();
|
|
|
|
if (tag != active_tag) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("CSW tag mismatch. Got ", tag, " expected: ",
|
|
|
|
active_tag);
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t const status = csw.sts();
|
|
|
|
if (status != Csw::PASSED) {
|
2016-05-27 23:14:36 +02:00
|
|
|
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
|
base: avoid use of deprecated base/printf.h
Besides adapting the components to the use of base/log.h, the patch
cleans up a few base headers, i.e., it removes unused includes from
root/component.h, specifically base/heap.h and
ram_session/ram_session.h. Hence, components that relied on the implicit
inclusion of those headers have to manually include those headers now.
While adjusting the log messages, I repeatedly stumbled over the problem
that printing char * arguments is ambiguous. It is unclear whether to
print the argument as pointer or null-terminated string. To overcome
this problem, the patch introduces a new type 'Cstring' that allows the
caller to express that the argument should be handled as null-terminated
string. As a nice side effect, with this type in place, the optional len
argument of the 'String' class could be removed. Instead of supplying a
pair of (char const *, size_t), the constructor accepts a 'Cstring'.
This, in turn, clears the way let the 'String' constructor use the new
output mechanism to assemble a string from multiple arguments (and
thereby getting rid of snprintf within Genode in the near future).
To enforce the explicit resolution of the char * ambiguity, the 'char *'
overload of the 'print' function is marked as deleted.
Issue #1987
2016-07-13 19:07:09 +02:00
|
|
|
" read: ", (int)req.read, " buffer: ", (void *)req.buffer,
|
2016-05-27 23:14:36 +02:00
|
|
|
" lba: ", req.lba, " size: ", req.size);
|
2016-02-08 19:02:55 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t const dr = csw.dr();
|
2016-05-27 23:14:36 +02:00
|
|
|
if (dr) {
|
|
|
|
Genode::warning("CSW data residue: ", dr, " not considered");
|
|
|
|
}
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
/* ack Block::Packet_descriptor */
|
|
|
|
request_executed = false;
|
|
|
|
ack_pending_request();
|
|
|
|
} while (0);
|
|
|
|
|
|
|
|
iface.release(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse configuration
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
void parse_config(Xml_node node)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
|
|
|
_block_ops.set_operation(Block::Packet_descriptor::READ);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
_writeable = node.attribute_value<bool>("writeable", false);
|
2016-02-08 19:02:55 +01:00
|
|
|
if (_writeable)
|
|
|
|
_block_ops.set_operation(Block::Packet_descriptor::WRITE);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
_report_device = node.attribute_value<bool>("report", false);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
active_interface = node.attribute_value<unsigned long>("interface", 0);
|
|
|
|
active_lun = node.attribute_value<unsigned long>("lun", 0);
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2018-05-22 15:32:28 +02:00
|
|
|
reset_device = node.attribute_value<bool>("reset_device", false);
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
verbose_scsi = node.attribute_value<bool>("verbose_scsi", false);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
*
|
|
|
|
* \param alloc allocator used by Usb::Connection
|
|
|
|
* \param ep Server::Endpoint
|
|
|
|
* \param sigh signal context used for annoucing Block service
|
|
|
|
*/
|
2016-05-27 23:14:36 +02:00
|
|
|
Block_driver(Env &env, Genode::Allocator &alloc,
|
2016-02-08 19:02:55 +01:00
|
|
|
Genode::Signal_context_capability sigh)
|
|
|
|
:
|
2017-01-16 15:33:56 +01:00
|
|
|
Block::Driver(env.ram()),
|
2016-05-27 23:14:36 +02:00
|
|
|
env(env), ep(env.ep()), announce_sigh(sigh), alloc(&alloc),
|
|
|
|
device(&alloc, usb, ep)
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
parse_config(config.xml());
|
2016-02-08 19:02:55 +01:00
|
|
|
reporter.enabled(true);
|
|
|
|
|
|
|
|
/* USB device gets initialized by handle_state_change() */
|
|
|
|
}
|
|
|
|
|
2017-11-05 16:36:14 +01:00
|
|
|
~Block_driver()
|
|
|
|
{
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
Usb::Interface &iface = device.interface(active_interface);
|
2017-11-05 16:36:14 +01:00
|
|
|
iface.release();
|
|
|
|
}
|
|
|
|
|
2016-02-08 19:02:55 +01:00
|
|
|
/**
|
|
|
|
* Send CBW
|
|
|
|
*/
|
|
|
|
void send_cbw(Block::sector_t lba, size_t len, bool read)
|
|
|
|
{
|
|
|
|
uint32_t const t = new_tag();
|
|
|
|
|
|
|
|
char cb[Cbw::LENGTH];
|
|
|
|
if (read) {
|
2018-05-07 15:54:18 +02:00
|
|
|
if (force_cmd_16) Read_16 r((addr_t)cb, t, active_lun, lba, len, _block_size);
|
|
|
|
else Read_10 r((addr_t)cb, t, active_lun, lba, len, _block_size);
|
2016-02-08 19:02:55 +01:00
|
|
|
} else {
|
2018-05-07 15:54:18 +02:00
|
|
|
if (force_cmd_16) Write_16 w((addr_t)cb, t, active_lun, lba, len, _block_size);
|
|
|
|
else Write_10 w((addr_t)cb, t, active_lun, lba, len, _block_size);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
cbw(cb, *this);
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Perform IO/ request
|
|
|
|
*
|
|
|
|
* \param read set to true when reading, false when writting
|
|
|
|
* \param lba address of the starting block
|
|
|
|
* \param buffer source/destination buffer
|
|
|
|
* \param p Block::Packet_descriptor
|
|
|
|
*/
|
|
|
|
void io(bool read, Block::sector_t lba, size_t count,
|
|
|
|
char *buffer, Block::Packet_descriptor &p)
|
|
|
|
{
|
|
|
|
if (!device_plugged) throw Io_error();
|
|
|
|
if (lba+count > _block_count) throw Io_error();
|
|
|
|
if (req.pending) throw Request_congestion();
|
|
|
|
|
|
|
|
req.pending = true;
|
|
|
|
req.packet = p;
|
|
|
|
req.lba = lba;
|
|
|
|
req.size = count * _block_size;
|
|
|
|
req.buffer = buffer;
|
|
|
|
req.read = read;
|
|
|
|
|
|
|
|
send_cbw(lba, count, read);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************
|
|
|
|
** Block::Driver interface **
|
|
|
|
*******************************/
|
|
|
|
|
|
|
|
size_t block_size() override { return _block_size; }
|
|
|
|
Block::sector_t block_count() override { return _block_count; }
|
|
|
|
Block::Session::Operations ops() override { return _block_ops; }
|
|
|
|
|
|
|
|
void read(Block::sector_t lba, size_t count,
|
|
|
|
char *buffer, Block::Packet_descriptor &p) override {
|
|
|
|
io(true, lba, count, buffer, p); }
|
|
|
|
|
|
|
|
void write(Block::sector_t lba, size_t count,
|
|
|
|
char const *buffer, Block::Packet_descriptor &p) override {
|
|
|
|
io(false, lba, count, const_cast<char*>(buffer), p); }
|
|
|
|
|
|
|
|
void sync() override { /* maybe implement SYNCHRONIZE_CACHE_10/16? */ }
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
struct Usb::Main
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
Env &env;
|
|
|
|
Heap heap { env.ram(), env.rm() };
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
void announce()
|
2016-02-08 19:02:55 +01:00
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
env.parent().announce(env.ep().manage(root));
|
2016-02-08 19:02:55 +01:00
|
|
|
}
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Signal_handler<Main> announce_dispatcher {
|
|
|
|
env.ep(), *this, &Usb::Main::announce };
|
2016-02-08 19:02:55 +01:00
|
|
|
|
|
|
|
struct Factory : Block::Driver_factory
|
|
|
|
{
|
2016-05-27 23:14:36 +02:00
|
|
|
Env &env;
|
|
|
|
Allocator &alloc;
|
|
|
|
Signal_context_capability sigh;
|
2018-05-07 15:02:04 +02:00
|
|
|
Usb::Block_driver driver;
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Factory(Env &env, Allocator &alloc,
|
|
|
|
Signal_context_capability sigh)
|
2018-05-07 15:02:04 +02:00
|
|
|
: env(env), alloc(alloc), sigh(sigh),
|
|
|
|
driver(env, alloc, sigh) { }
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2018-05-07 15:02:04 +02:00
|
|
|
Block::Driver *create() override { return &driver; }
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2018-05-07 15:02:04 +02:00
|
|
|
void destroy(Block::Driver *) override { }
|
Follow practices suggested by "Effective C++"
The patch adjust the code of the base, base-<kernel>, and os repository.
To adapt existing components to fix violations of the best practices
suggested by "Effective C++" as reported by the -Weffc++ compiler
argument. The changes follow the patterns outlined below:
* A class with virtual functions can no longer publicly inherit base
classed without a vtable. The inherited object may either be moved
to a member variable, or inherited privately. The latter would be
used for classes that inherit 'List::Element' or 'Avl_node'. In order
to enable the 'List' and 'Avl_tree' to access the meta data, the
'List' must become a friend.
* Instead of adding a virtual destructor to abstract base classes,
we inherit the new 'Interface' class, which contains a virtual
destructor. This way, single-line abstract base classes can stay
as compact as they are now. The 'Interface' utility resides in
base/include/util/interface.h.
* With the new warnings enabled, all member variables must be explicitly
initialized. Basic types may be initialized with '='. All other types
are initialized with braces '{ ... }' or as class initializers. If
basic types and non-basic types appear in a row, it is nice to only
use the brace syntax (also for basic types) and align the braces.
* If a class contains pointers as members, it must now also provide a
copy constructor and assignment operator. In the most cases, one
would make them private, effectively disallowing the objects to be
copied. Unfortunately, this warning cannot be fixed be inheriting
our existing 'Noncopyable' class (the compiler fails to detect that
the inheriting class cannot be copied and still gives the error).
For now, we have to manually add declarations for both the copy
constructor and assignment operator as private class members. Those
declarations should be prepended with a comment like this:
/*
* Noncopyable
*/
Thread(Thread const &);
Thread &operator = (Thread const &);
In the future, we should revisit these places and try to replace
the pointers with references. In the presence of at least one
reference member, the compiler would no longer implicitly generate
a copy constructor. So we could remove the manual declaration.
Issue #465
2017-12-21 15:42:15 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Noncopyable
|
|
|
|
*/
|
|
|
|
Factory(Factory const &);
|
|
|
|
Factory &operator = (Factory const &);
|
2016-02-08 19:02:55 +01:00
|
|
|
};
|
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Factory factory { env, heap, announce_dispatcher };
|
2017-07-31 19:53:34 +02:00
|
|
|
Block::Root root { env.ep(), heap, env.rm(), factory, true };
|
2016-02-08 19:02:55 +01:00
|
|
|
|
2016-05-27 23:14:36 +02:00
|
|
|
Main(Env &env) : env(env) { }
|
2016-02-08 19:02:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2016-11-28 15:13:14 +01:00
|
|
|
void Component::construct(Genode::Env &env) { static Usb::Main main(env); }
|