mirror of
https://github.com/genodelabs/genode.git
synced 2025-05-06 10:38:31 +00:00
parent
f772dfaccd
commit
833c9e01f5
@ -13,16 +13,17 @@
|
|||||||
|
|
||||||
/* Genode includes */
|
/* Genode includes */
|
||||||
#include <base/allocator_avl.h>
|
#include <base/allocator_avl.h>
|
||||||
|
#include <base/attached_rom_dataspace.h>
|
||||||
|
#include <base/component.h>
|
||||||
|
#include <base/log.h>
|
||||||
#include <block/component.h>
|
#include <block/component.h>
|
||||||
#include <block/driver.h>
|
#include <block/driver.h>
|
||||||
#include <block_session/connection.h>
|
#include <block_session/connection.h>
|
||||||
#include <os/config.h>
|
|
||||||
#include <os/reporter.h>
|
#include <os/reporter.h>
|
||||||
#include <os/server.h>
|
|
||||||
#include <timer_session/connection.h>
|
#include <timer_session/connection.h>
|
||||||
#include <usb/usb.h>
|
#include <usb/usb.h>
|
||||||
|
|
||||||
|
/* used by cbw_csw.h so declare it here */
|
||||||
static bool verbose_scsi = false;
|
static bool verbose_scsi = false;
|
||||||
|
|
||||||
/* local includes */
|
/* local includes */
|
||||||
@ -33,6 +34,7 @@ namespace Usb {
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
struct Block_driver;
|
struct Block_driver;
|
||||||
|
struct Main;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -43,9 +45,10 @@ namespace Usb {
|
|||||||
struct Usb::Block_driver : Usb::Completion,
|
struct Usb::Block_driver : Usb::Completion,
|
||||||
Block::Driver
|
Block::Driver
|
||||||
{
|
{
|
||||||
Server::Entrypoint &ep;
|
Env &env;
|
||||||
|
Entrypoint &ep;
|
||||||
|
|
||||||
Genode::Signal_context_capability announce_sigh;
|
Signal_context_capability announce_sigh;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Pending block request
|
* Pending block request
|
||||||
@ -66,7 +69,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
/**
|
/**
|
||||||
* Handle stage change signal
|
* Handle stage change signal
|
||||||
*/
|
*/
|
||||||
void handle_state_change(unsigned)
|
void handle_state_change()
|
||||||
{
|
{
|
||||||
if (!usb.plugged()) {
|
if (!usb.plugged()) {
|
||||||
PDBG("Device unplugged");
|
PDBG("Device unplugged");
|
||||||
@ -75,43 +78,61 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (initialized) {
|
if (initialized) {
|
||||||
PERR("Device was already initialized");
|
Genode::error("Device was already initialized");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PDBG("Device plugged");
|
PDBG("Device plugged");
|
||||||
|
|
||||||
if (initialize())
|
if (!initialize()) {
|
||||||
Genode::Signal_transmitter(announce_sigh).submit();
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Server::Signal_rpc_member<Block_driver> state_change_dispatcher = {
|
/* all is well, announce the device */
|
||||||
|
Signal_transmitter(announce_sigh).submit();
|
||||||
|
}
|
||||||
|
|
||||||
|
Signal_handler<Block_driver> state_change_dispatcher = {
|
||||||
ep, *this, &Block_driver::handle_state_change };
|
ep, *this, &Block_driver::handle_state_change };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Config ROM
|
||||||
|
*/
|
||||||
|
Attached_rom_dataspace config { env, "config" };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read Usb session label from the configuration
|
* Read Usb session label from the configuration
|
||||||
*/
|
*/
|
||||||
static char const *get_label()
|
static char const *get_label(Xml_node node)
|
||||||
{
|
{
|
||||||
static Genode::String<256> usb_label;
|
static Genode::String<256> usb_label;
|
||||||
try {
|
try {
|
||||||
Genode::config()->xml_node().attribute("label").value(&usb_label);
|
node.attribute("label").value(&usb_label);
|
||||||
return usb_label.string();
|
return usb_label.string();
|
||||||
} catch (...) { }
|
} catch (...) { }
|
||||||
|
|
||||||
return "usb_storage";
|
return "usb_storage";
|
||||||
}
|
}
|
||||||
|
|
||||||
Genode::Allocator_avl alloc;
|
/*
|
||||||
Usb::Connection usb { &alloc, get_label(), 2 * (1<<20), state_change_dispatcher };
|
* USB session
|
||||||
|
*/
|
||||||
|
Allocator_avl alloc;
|
||||||
|
Usb::Connection usb { env, &alloc, get_label(config.xml()), 2 * (1<<20), state_change_dispatcher };
|
||||||
Usb::Device device;
|
Usb::Device device;
|
||||||
|
|
||||||
Genode::Reporter reporter { "devices" };
|
/*
|
||||||
|
* Reporter
|
||||||
|
*/
|
||||||
|
Reporter reporter { "devices" };
|
||||||
bool _report_device = false;
|
bool _report_device = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Block session
|
||||||
|
*/
|
||||||
Block::Session::Operations _block_ops;
|
Block::Session::Operations _block_ops;
|
||||||
Block::sector_t _block_count;
|
Block::sector_t _block_count;
|
||||||
Genode::size_t _block_size;
|
size_t _block_size;
|
||||||
|
|
||||||
bool _writeable = false;
|
bool _writeable = false;
|
||||||
|
|
||||||
@ -146,7 +167,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
uint8_t interface;
|
uint8_t interface;
|
||||||
|
|
||||||
Block::sector_t block_count;
|
Block::sector_t block_count;
|
||||||
Genode::size_t block_size;
|
size_t block_size;
|
||||||
|
|
||||||
char vendor[Scsi::Inquiry_response::Vid::ITEMS+1];
|
char vendor[Scsi::Inquiry_response::Vid::ITEMS+1];
|
||||||
char product[Scsi::Inquiry_response::Pid::ITEMS+1];
|
char product[Scsi::Inquiry_response::Pid::ITEMS+1];
|
||||||
@ -159,13 +180,13 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
Interface iface = device.interface(interface);
|
Interface iface = device.interface(interface);
|
||||||
|
|
||||||
if (p.type != Packet_descriptor::BULK) {
|
if (p.type != Packet_descriptor::BULK) {
|
||||||
PERR("Can only handle BULK packets");
|
Genode::error("Can only handle BULK packets");
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.succeded) {
|
if (!p.succeded) {
|
||||||
PERR("init complete error: packet not succeded");
|
Genode::error("init complete error: packet not succeded");
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -188,8 +209,9 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
Inquiry_response r((addr_t)data);
|
Inquiry_response r((addr_t)data);
|
||||||
if (verbose_scsi) r.dump();
|
if (verbose_scsi) r.dump();
|
||||||
|
|
||||||
if (!r.sbc())
|
if (!r.sbc()) {
|
||||||
PWRN("Device does not use SCSI Block Commands and may not work");
|
Genode::warning("Device does not use SCSI Block Commands and may not work");
|
||||||
|
}
|
||||||
|
|
||||||
r.get_id<Inquiry_response::Vid>(vendor, sizeof(vendor));
|
r.get_id<Inquiry_response::Vid>(vendor, sizeof(vendor));
|
||||||
r.get_id<Inquiry_response::Pid>(product, sizeof(product));
|
r.get_id<Inquiry_response::Pid>(product, sizeof(product));
|
||||||
@ -224,15 +246,17 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
enum { MEDIUM_NOT_PRESENT = 0x3a, NOT_READY_TO_READY_CHANGE = 0x28 };
|
enum { MEDIUM_NOT_PRESENT = 0x3a, NOT_READY_TO_READY_CHANGE = 0x28 };
|
||||||
switch (asc) {
|
switch (asc) {
|
||||||
case MEDIUM_NOT_PRESENT:
|
case MEDIUM_NOT_PRESENT:
|
||||||
PERR("Not ready - medium not present");
|
Genode::error("Not ready - medium not present");
|
||||||
no_medium = true;
|
no_medium = true;
|
||||||
break;
|
break;
|
||||||
case NOT_READY_TO_READY_CHANGE: /* asq == 0x00 */
|
case NOT_READY_TO_READY_CHANGE: /* asq == 0x00 */
|
||||||
PWRN("Not ready - try again");
|
Genode::warning("Not ready - try again");
|
||||||
try_again = true;
|
try_again = true;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
PERR("Request_sense_response asc: 0x%02x asq: 0x%02x", asc, asq);
|
Genode::error("Request_sense_response asc: ",
|
||||||
|
Hex(asc, Hex::PREFIX, Hex::PAD),
|
||||||
|
" asq: ", Hex(asq, Hex::PREFIX, Hex::PAD));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -243,14 +267,16 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
|
|
||||||
uint32_t const sig = csw.sig();
|
uint32_t const sig = csw.sig();
|
||||||
if (sig != Csw::SIG) {
|
if (sig != Csw::SIG) {
|
||||||
PERR("CSW signature does not match: 0x%04x", sig);
|
Genode::error("CSW signature does not match: ",
|
||||||
|
Hex(sig, Hex::PREFIX, Hex::PAD));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t const tag = csw.tag();
|
uint32_t const tag = csw.tag();
|
||||||
uint8_t const status = csw.sts();
|
uint8_t const status = csw.sts();
|
||||||
if (status != Csw::PASSED) {
|
if (status != Csw::PASSED) {
|
||||||
PERR("CSW failed: 0x%02x tag: %u", status, tag);
|
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
|
||||||
|
" tag: ", tag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -270,37 +296,37 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
/**
|
/**
|
||||||
* Send CBW
|
* Send CBW
|
||||||
*/
|
*/
|
||||||
void cbw(void *cb, Completion *c, bool block = false)
|
void cbw(void *cb, Completion &c, bool block = false)
|
||||||
{
|
{
|
||||||
enum { CBW_VALID_SIZE = Cbw::LENGTH };
|
enum { CBW_VALID_SIZE = Cbw::LENGTH };
|
||||||
Usb::Interface &iface = device.interface(active_interface);
|
Usb::Interface &iface = device.interface(active_interface);
|
||||||
Usb::Endpoint &ep = iface.endpoint(OUT);
|
Usb::Endpoint &ep = iface.endpoint(OUT);
|
||||||
Usb::Packet_descriptor p = iface.alloc(CBW_VALID_SIZE);
|
Usb::Packet_descriptor p = iface.alloc(CBW_VALID_SIZE);
|
||||||
memcpy(iface.content(p), cb, CBW_VALID_SIZE);
|
memcpy(iface.content(p), cb, CBW_VALID_SIZE);
|
||||||
iface.bulk_transfer(p, ep, 0, block, c);
|
iface.bulk_transfer(p, ep, 0, block, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive CSW
|
* Receive CSW
|
||||||
*/
|
*/
|
||||||
void csw(Completion *c, bool block = false)
|
void csw(Completion &c, bool block = false)
|
||||||
{
|
{
|
||||||
enum { CSW_VALID_SIZE = Csw::LENGTH };
|
enum { CSW_VALID_SIZE = Csw::LENGTH };
|
||||||
Usb::Interface &iface = device.interface(active_interface);
|
Usb::Interface &iface = device.interface(active_interface);
|
||||||
Usb::Endpoint &ep = iface.endpoint(IN);
|
Usb::Endpoint &ep = iface.endpoint(IN);
|
||||||
Usb::Packet_descriptor p = iface.alloc(CSW_VALID_SIZE);
|
Usb::Packet_descriptor p = iface.alloc(CSW_VALID_SIZE);
|
||||||
iface.bulk_transfer(p, ep, 0, block, c);
|
iface.bulk_transfer(p, ep, 0, block, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Receive response
|
* Receive response
|
||||||
*/
|
*/
|
||||||
void resp(size_t size, Completion *c, bool block = false)
|
void resp(size_t size, Completion &c, bool block = false)
|
||||||
{
|
{
|
||||||
Usb::Interface &iface = device.interface(active_interface);
|
Usb::Interface &iface = device.interface(active_interface);
|
||||||
Usb::Endpoint &ep = iface.endpoint(IN);
|
Usb::Endpoint &ep = iface.endpoint(IN);
|
||||||
Usb::Packet_descriptor p = iface.alloc(size);
|
Usb::Packet_descriptor p = iface.alloc(size);
|
||||||
iface.bulk_transfer(p, ep, 0, block, c);
|
iface.bulk_transfer(p, ep, 0, block, &c);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -319,7 +345,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
xml.attribute("writeable", _writeable);
|
xml.attribute("writeable", _writeable);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (...) { PWRN("Could not report block device"); }
|
} catch (...) { Genode::warning("Could not report block device"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -338,10 +364,10 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
Interface &iface = device.interface(active_interface);
|
Interface &iface = device.interface(active_interface);
|
||||||
try { iface.claim(); }
|
try { iface.claim(); }
|
||||||
catch (Usb::Session::Interface_already_claimed) {
|
catch (Usb::Session::Interface_already_claimed) {
|
||||||
PERR("Device already claimed");
|
Genode::error("Device already claimed");
|
||||||
return false;
|
return false;
|
||||||
} catch (Usb::Session::Interface_not_found) {
|
} catch (Usb::Session::Interface_not_found) {
|
||||||
PERR("Interface not found");
|
Genode::error("Interface not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,11 +383,11 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
if (alt_iface.iclass != ICLASS_MASS_STORAGE
|
if (alt_iface.iclass != ICLASS_MASS_STORAGE
|
||||||
|| alt_iface.isubclass != ISUBCLASS_SCSI
|
|| alt_iface.isubclass != ISUBCLASS_SCSI
|
||||||
|| alt_iface.iprotocol != IPROTO_BULK_ONLY) {
|
|| alt_iface.iprotocol != IPROTO_BULK_ONLY) {
|
||||||
PERR("No mass storage SCSI bulk-only device");
|
Genode::error("No mass storage SCSI bulk-only device");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (Usb::Session::Interface_not_found) {
|
} catch (Usb::Session::Interface_not_found) {
|
||||||
PERR("Interface not found");
|
Genode::error("Interface not found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +396,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
Usb::Packet_descriptor p = iface.alloc(0);
|
Usb::Packet_descriptor p = iface.alloc(0);
|
||||||
iface.control_transfer(p, 0x21, 0xff, 0, active_interface, 100);
|
iface.control_transfer(p, 0x21, 0xff, 0, active_interface, 100);
|
||||||
if (!p.succeded) {
|
if (!p.succeded) {
|
||||||
PERR("Could not reset device");
|
Genode::error("Could not reset device");
|
||||||
throw -1;
|
throw -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,18 +426,18 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
/* Scsi::Opcode::INQUIRY */
|
/* Scsi::Opcode::INQUIRY */
|
||||||
Inquiry inq((addr_t)cbw_buffer, INQ_TAG, active_lun);
|
Inquiry inq((addr_t)cbw_buffer, INQ_TAG, active_lun);
|
||||||
|
|
||||||
cbw(cbw_buffer, &init, true);
|
cbw(cbw_buffer, init, true);
|
||||||
resp(Scsi::Inquiry_response::LENGTH, &init, true);
|
resp(Scsi::Inquiry_response::LENGTH, init, true);
|
||||||
csw(&init, true);
|
csw(init, true);
|
||||||
|
|
||||||
if (!init.inquiry) {
|
if (!init.inquiry) {
|
||||||
PWRN("Inquiry_cmd failed");
|
Genode::warning("Inquiry_cmd failed");
|
||||||
throw -1;
|
throw -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scsi::Opcode::TEST_UNIT_READY */
|
/* Scsi::Opcode::TEST_UNIT_READY */
|
||||||
{
|
{
|
||||||
Timer::Connection timer;
|
Timer::Connection timer { env };
|
||||||
/*
|
/*
|
||||||
* It might take some time for devices to get ready (e.g. the ZTE Open C
|
* 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
|
* takes 3 retries to actually present us a medium and another try to
|
||||||
@ -422,17 +448,17 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
for (retries = 0; retries < MAX_RETRIES; retries++) {
|
for (retries = 0; retries < MAX_RETRIES; retries++) {
|
||||||
Test_unit_ready unit_ready((addr_t)cbw_buffer, RDY_TAG, active_lun);
|
Test_unit_ready unit_ready((addr_t)cbw_buffer, RDY_TAG, active_lun);
|
||||||
|
|
||||||
cbw(cbw_buffer, &init, true);
|
cbw(cbw_buffer, init, true);
|
||||||
csw(&init, true);
|
csw(init, true);
|
||||||
|
|
||||||
if (!init.unit_ready) {
|
if (!init.unit_ready) {
|
||||||
Request_sense sense((addr_t)cbw_buffer, REQ_TAG, active_lun);
|
Request_sense sense((addr_t)cbw_buffer, REQ_TAG, active_lun);
|
||||||
|
|
||||||
cbw(cbw_buffer, &init, true);
|
cbw(cbw_buffer, init, true);
|
||||||
resp(Scsi::Request_sense_response::LENGTH, &init, true);
|
resp(Scsi::Request_sense_response::LENGTH, init, true);
|
||||||
csw(&init, true);
|
csw(init, true);
|
||||||
if (!init.request_sense) {
|
if (!init.request_sense) {
|
||||||
PWRN("Request_sense failed");
|
Genode::warning("Request_sense failed");
|
||||||
throw -1;
|
throw -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,7 +472,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
timer.msleep(1000);
|
timer.msleep(1000);
|
||||||
}
|
}
|
||||||
if (retries == MAX_RETRIES) {
|
if (retries == MAX_RETRIES) {
|
||||||
PWRN("Test_unit_ready_cmd failed");
|
Genode::warning("Test_unit_ready_cmd failed");
|
||||||
throw -1;
|
throw -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,24 +480,24 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
/* Scsi::Opcode::READ_CAPACITY_16 */
|
/* Scsi::Opcode::READ_CAPACITY_16 */
|
||||||
Read_capacity_16 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
Read_capacity_16 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
||||||
|
|
||||||
cbw(cbw_buffer, &init, true);
|
cbw(cbw_buffer, init, true);
|
||||||
resp(Scsi::Capacity_response_16::LENGTH, &init, true);
|
resp(Scsi::Capacity_response_16::LENGTH, init, true);
|
||||||
csw(&init, true);
|
csw(init, true);
|
||||||
|
|
||||||
if (!init.read_capacity) {
|
if (!init.read_capacity) {
|
||||||
/* try Scsi::Opcode::READ_CAPACITY_10 next */
|
/* try Scsi::Opcode::READ_CAPACITY_10 next */
|
||||||
Read_capacity_10 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
Read_capacity_10 read_cap((addr_t)cbw_buffer, CAP_TAG, active_lun);
|
||||||
|
|
||||||
cbw(cbw_buffer, &init, true);
|
cbw(cbw_buffer, init, true);
|
||||||
resp(Scsi::Capacity_response_10::LENGTH, &init, true);
|
resp(Scsi::Capacity_response_10::LENGTH, init, true);
|
||||||
csw(&init, true);
|
csw(init, true);
|
||||||
|
|
||||||
if (!init.read_capacity) {
|
if (!init.read_capacity) {
|
||||||
PWRN("Read_capacity_cmd failed");
|
Genode::warning("Read_capacity_cmd failed");
|
||||||
throw -1;
|
throw -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
PWRN("Device does not support CDB 16-byte commands, force 10-byte commands");
|
Genode::warning("Device does not support CDB 16-byte commands, force 10-byte commands");
|
||||||
force_cmd_10 = true;
|
force_cmd_10 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -487,8 +513,9 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
device.manufactorer_string.to_char(vendor, sizeof(vendor));
|
device.manufactorer_string.to_char(vendor, sizeof(vendor));
|
||||||
device.product_string.to_char(product, sizeof(product));
|
device.product_string.to_char(product, sizeof(product));
|
||||||
|
|
||||||
PINF("Found USB device: %s (%s) block size: %zu count: %llu",
|
Genode::log("Found USB device: ", (char const*)vendor, " (",
|
||||||
vendor, product, _block_size, _block_count);
|
(char const*)product, ") block size: ", _block_size,
|
||||||
|
" count: ", _block_count);
|
||||||
|
|
||||||
if (_report_device)
|
if (_report_device)
|
||||||
report_device(init.vendor, init.product,
|
report_device(init.vendor, init.product,
|
||||||
@ -496,11 +523,11 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
return true;
|
return true;
|
||||||
} catch (int) {
|
} catch (int) {
|
||||||
/* handle command failures */
|
/* handle command failures */
|
||||||
PERR("Could not initialize storage device");
|
Genode::error("Could not initialize storage device");
|
||||||
return false;
|
return false;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
/* handle Usb::Session failures */
|
/* handle Usb::Session failures */
|
||||||
PERR("Could not initialize storage device");
|
Genode::error("Could not initialize storage device");
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -554,16 +581,17 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
Interface iface = device.interface(active_interface);
|
Interface iface = device.interface(active_interface);
|
||||||
|
|
||||||
if (p.type != Packet_descriptor::BULK) {
|
if (p.type != Packet_descriptor::BULK) {
|
||||||
PERR("No BULK packet");
|
Genode::error("No BULK packet");
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!p.succeded) {
|
if (!p.succeded) {
|
||||||
PERR("complete error: packet not succeded");
|
Genode::error("complete error: packet not succeded");
|
||||||
if (req.pending) {
|
if (req.pending) {
|
||||||
PERR("req.pending: tag: %u is_read: %d buffer: %p lba: %llu size: %zu",
|
Genode::error("request pending: tag: ", active_tag, " read: ",
|
||||||
active_tag, req.read, req.buffer, req.lba, req.size);
|
(int)req.read, " buffer: ", req.buffer, " lba: ",
|
||||||
|
req.lba, " size: ", req.size);
|
||||||
ack_pending_request(false);
|
ack_pending_request(false);
|
||||||
}
|
}
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
@ -583,7 +611,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
request_executed = execute_pending_request();
|
request_executed = execute_pending_request();
|
||||||
} else {
|
} else {
|
||||||
/* the content was successfully written, get the CSW */
|
/* the content was successfully written, get the CSW */
|
||||||
csw(this);
|
csw(*this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -593,7 +621,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
|
|
||||||
int actual_size = p.transfer.actual_size;
|
int actual_size = p.transfer.actual_size;
|
||||||
if (actual_size < 0) {
|
if (actual_size < 0) {
|
||||||
PERR("Transfer actual size: %d", actual_size);
|
Genode::error("Transfer actual size: ", actual_size);
|
||||||
actual_size = 0;
|
actual_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -603,7 +631,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
|
|
||||||
/* the content was successfully read, get the CSW */
|
/* the content was successfully read, get the CSW */
|
||||||
memcpy(req.buffer, iface.content(p), actual_size);
|
memcpy(req.buffer, iface.content(p), actual_size);
|
||||||
csw(this);
|
csw(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
iface.release(p);
|
iface.release(p);
|
||||||
@ -612,33 +640,37 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
|
|
||||||
/* when ending up here, we should have gotten an CSW packet */
|
/* when ending up here, we should have gotten an CSW packet */
|
||||||
if (actual_size != Csw::LENGTH)
|
if (actual_size != Csw::LENGTH)
|
||||||
PWRN("This is not the actual size you are looking for");
|
Genode::warning("This is not the actual size you are looking for");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
Csw csw((addr_t)iface.content(p));
|
Csw csw((addr_t)iface.content(p));
|
||||||
|
|
||||||
uint32_t const sig = csw.sig();
|
uint32_t const sig = csw.sig();
|
||||||
if (sig != Csw::SIG) {
|
if (sig != Csw::SIG) {
|
||||||
PERR("CSW signature does not match: 0x%04x", sig);
|
Genode::error("CSW signature does not match: ",
|
||||||
|
Hex(sig, Hex::PREFIX, Hex::PAD));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t const tag = csw.tag();
|
uint32_t const tag = csw.tag();
|
||||||
if (tag != active_tag) {
|
if (tag != active_tag) {
|
||||||
PERR("CSW tag mismatch. Got %u expected: %u", tag, active_tag);
|
Genode::error("CSW tag mismatch. Got ", tag, " expected: ",
|
||||||
|
active_tag);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t const status = csw.sts();
|
uint8_t const status = csw.sts();
|
||||||
if (status != Csw::PASSED) {
|
if (status != Csw::PASSED) {
|
||||||
PERR("CSW failed: 0x%02x tag: %u req.read: %d req.buffer: %p "
|
Genode::error("CSW failed: ", Hex(status, Hex::PREFIX, Hex::PAD),
|
||||||
"req.lba: %llu req.size: %zu", status, tag, req.read,
|
" read: ", (int)req.read, " buffer: ", req.buffer,
|
||||||
req.buffer, req.lba, req.size);
|
" lba: ", req.lba, " size: ", req.size);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t const dr = csw.dr();
|
uint32_t const dr = csw.dr();
|
||||||
if (dr) PWRN("CSW data residue: %u not considered", dr);
|
if (dr) {
|
||||||
|
Genode::warning("CSW data residue: ", dr, " not considered");
|
||||||
|
}
|
||||||
|
|
||||||
/* ack Block::Packet_descriptor */
|
/* ack Block::Packet_descriptor */
|
||||||
request_executed = false;
|
request_executed = false;
|
||||||
@ -651,22 +683,20 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
/**
|
/**
|
||||||
* Parse configuration
|
* Parse configuration
|
||||||
*/
|
*/
|
||||||
void parse_config()
|
void parse_config(Xml_node node)
|
||||||
{
|
{
|
||||||
Genode::Xml_node config = Genode::config()->xml_node();
|
|
||||||
|
|
||||||
_block_ops.set_operation(Block::Packet_descriptor::READ);
|
_block_ops.set_operation(Block::Packet_descriptor::READ);
|
||||||
|
|
||||||
_writeable = config.attribute_value<bool>("writeable", false);
|
_writeable = node.attribute_value<bool>("writeable", false);
|
||||||
if (_writeable)
|
if (_writeable)
|
||||||
_block_ops.set_operation(Block::Packet_descriptor::WRITE);
|
_block_ops.set_operation(Block::Packet_descriptor::WRITE);
|
||||||
|
|
||||||
_report_device = config.attribute_value<bool>("report", false);
|
_report_device = node.attribute_value<bool>("report", false);
|
||||||
|
|
||||||
active_interface = config.attribute_value<unsigned long>("interface", 0);
|
active_interface = node.attribute_value<unsigned long>("interface", 0);
|
||||||
active_lun = config.attribute_value<unsigned long>("lun", 0);
|
active_lun = node.attribute_value<unsigned long>("lun", 0);
|
||||||
|
|
||||||
verbose_scsi = config.attribute_value<bool>("verbose_scsi", false);
|
verbose_scsi = node.attribute_value<bool>("verbose_scsi", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -676,13 +706,13 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
* \param ep Server::Endpoint
|
* \param ep Server::Endpoint
|
||||||
* \param sigh signal context used for annoucing Block service
|
* \param sigh signal context used for annoucing Block service
|
||||||
*/
|
*/
|
||||||
Block_driver(Genode::Allocator &alloc, Server::Entrypoint &ep,
|
Block_driver(Env &env, Genode::Allocator &alloc,
|
||||||
Genode::Signal_context_capability sigh)
|
Genode::Signal_context_capability sigh)
|
||||||
:
|
:
|
||||||
ep(ep), announce_sigh(sigh), alloc(Genode::env()->heap()),
|
env(env), ep(env.ep()), announce_sigh(sigh), alloc(&alloc),
|
||||||
device(Genode::env()->heap(), usb, ep)
|
device(&alloc, usb, ep)
|
||||||
{
|
{
|
||||||
parse_config();
|
parse_config(config.xml());
|
||||||
reporter.enabled(true);
|
reporter.enabled(true);
|
||||||
|
|
||||||
/* USB device gets initialized by handle_state_change() */
|
/* USB device gets initialized by handle_state_change() */
|
||||||
@ -704,7 +734,7 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
else Write_10 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
cbw(cb, this);
|
cbw(cb, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -752,31 +782,32 @@ struct Usb::Block_driver : Usb::Completion,
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Main
|
struct Usb::Main
|
||||||
{
|
{
|
||||||
Server::Entrypoint &ep;
|
Env &env;
|
||||||
|
Heap heap { env.ram(), env.rm() };
|
||||||
|
|
||||||
void announce(unsigned)
|
void announce()
|
||||||
{
|
{
|
||||||
Genode::env()->parent()->announce(ep.manage(root));
|
env.parent().announce(env.ep().manage(root));
|
||||||
}
|
}
|
||||||
|
|
||||||
Server::Signal_rpc_member<Main> announce_dispatcher {
|
Signal_handler<Main> announce_dispatcher {
|
||||||
ep, *this, &Main::announce };
|
env.ep(), *this, &Usb::Main::announce };
|
||||||
|
|
||||||
struct Factory : Block::Driver_factory
|
struct Factory : Block::Driver_factory
|
||||||
{
|
{
|
||||||
Genode::Allocator &alloc;
|
Env &env;
|
||||||
Server::Entrypoint &ep;
|
Allocator &alloc;
|
||||||
Genode::Signal_context_capability sigh;
|
Signal_context_capability sigh;
|
||||||
|
|
||||||
Usb::Block_driver *driver = nullptr;
|
Usb::Block_driver *driver = nullptr;
|
||||||
|
|
||||||
Factory(Genode::Allocator &alloc, Server::Entrypoint &ep,
|
Factory(Env &env, Allocator &alloc,
|
||||||
Genode::Signal_context_capability sigh)
|
Signal_context_capability sigh)
|
||||||
: alloc(alloc), ep(ep), sigh(sigh)
|
: env(env), alloc(alloc), sigh(sigh)
|
||||||
{
|
{
|
||||||
driver = new (Genode::env()->heap()) Usb::Block_driver(alloc, ep, sigh);
|
driver = new (&alloc) Usb::Block_driver(env, alloc, sigh);
|
||||||
}
|
}
|
||||||
|
|
||||||
Block::Driver *create() { return driver; }
|
Block::Driver *create() { return driver; }
|
||||||
@ -784,20 +815,18 @@ struct Main
|
|||||||
void destroy(Block::Driver *driver) { }
|
void destroy(Block::Driver *driver) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
Factory factory { *Genode::env()->heap(), ep, announce_dispatcher };
|
Factory factory { env, heap, announce_dispatcher };
|
||||||
Block::Root root;
|
Block::Root root { env.ep(), &heap, factory };
|
||||||
|
|
||||||
Main(Server::Entrypoint &ep)
|
Main(Env &env) : env(env) { }
|
||||||
: ep(ep), root(ep, Genode::env()->heap(), factory) { }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/************
|
/***************
|
||||||
** Server **
|
** Component **
|
||||||
************/
|
***************/
|
||||||
|
|
||||||
namespace Server {
|
namespace Component {
|
||||||
char const *name() { return "usb_block_ep"; }
|
|
||||||
size_t stack_size() { return 2*1024*sizeof(long); }
|
size_t stack_size() { return 2*1024*sizeof(long); }
|
||||||
void construct(Entrypoint &ep) { static Main main(ep); }
|
void construct(Genode::Env &env) { static Usb::Main main(env); }
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TARGET = usb_block_drv
|
TARGET = usb_block_drv
|
||||||
SRC_CC = main.cc
|
SRC_CC = main.cc
|
||||||
INC_DIR = $(PRG_DIR)
|
INC_DIR = $(PRG_DIR)
|
||||||
LIBS = base config server
|
LIBS = base
|
||||||
|
Loading…
x
Reference in New Issue
Block a user