mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-07 11:50:24 +00:00
usb: support 32 in-flight packets
- move metadata specific to isochronous transfers from the descriptor into the content of USB-session packets - restore support for 32 in-flight packets in the USB C API Fixes #4749
This commit is contained in:
parent
217d59ce68
commit
3c45f5c7ab
@ -246,22 +246,26 @@ class Device : public List<Device>::Element
|
|||||||
p.transfer.actual_size = urb->actual_length;
|
p.transfer.actual_size = urb->actual_length;
|
||||||
p.succeded = true;
|
p.succeded = true;
|
||||||
|
|
||||||
if (read) {
|
/*
|
||||||
/* make sure the client sees the actual amount of data */
|
* We have to copy the whole transfer buffer. In case of
|
||||||
for (int i = 0; i < urb->number_of_packets; i++) {
|
* isochronous transfers, the controller used offsets into the
|
||||||
p.transfer.actual_packet_size[i] = urb->iso_frame_desc[i].actual_length;
|
* original buffer to store the data of multiple packets.
|
||||||
|
*/
|
||||||
|
if (read) _with_packet_stream([&](Tx::Sink &sink) {
|
||||||
|
void * payload = sink.packet_content(p);
|
||||||
|
if (usb_pipeisoc(urb->pipe)) {
|
||||||
|
/* make sure the client sees the actual amount of data */
|
||||||
|
Usb::Isoc_transfer &isoc = *(Usb::Isoc_transfer *)payload;
|
||||||
|
for (int i = 0; i < urb->number_of_packets; i++)
|
||||||
|
isoc.actual_packet_size[i] = urb->iso_frame_desc[i].actual_length;
|
||||||
|
|
||||||
|
/* actual data begins after metdata */
|
||||||
|
payload = isoc.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
Genode::memcpy(payload, urb->transfer_buffer,
|
||||||
* We have to copy the whole transfer buffer because the
|
|
||||||
* controller used the offsets into the original buffer to
|
|
||||||
* store the data.
|
|
||||||
*/
|
|
||||||
_with_packet_stream([&](Tx::Sink &sink) {
|
|
||||||
Genode::memcpy(sink.packet_content(p), urb->transfer_buffer,
|
|
||||||
urb->transfer_buffer_length);
|
urb->transfer_buffer_length);
|
||||||
});
|
});
|
||||||
}
|
|
||||||
} else if (urb->status == -ESHUTDOWN) {
|
} else if (urb->status == -ESHUTDOWN) {
|
||||||
p.error = Packet_descriptor::NO_DEVICE_ERROR;
|
p.error = Packet_descriptor::NO_DEVICE_ERROR;
|
||||||
} else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) {
|
} else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) {
|
||||||
@ -426,12 +430,16 @@ class Device : public List<Device>::Element
|
|||||||
usb_host_endpoint *ep = _host_ep(p.transfer.ep);
|
usb_host_endpoint *ep = _host_ep(p.transfer.ep);
|
||||||
void *buf = dma_malloc(p.size());
|
void *buf = dma_malloc(p.size());
|
||||||
|
|
||||||
|
Usb::Isoc_transfer &isoc = *(Usb::Isoc_transfer *)_sink->packet_content(p);
|
||||||
|
void * const payload = isoc.data();
|
||||||
|
unsigned const payload_size = p.size() - sizeof(isoc);
|
||||||
|
|
||||||
if (read) {
|
if (read) {
|
||||||
pipe = usb_rcvisocpipe(&_udev, p.transfer.ep);
|
pipe = usb_rcvisocpipe(&_udev, p.transfer.ep);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
pipe = usb_sndisocpipe(&_udev, p.transfer.ep);
|
pipe = usb_sndisocpipe(&_udev, p.transfer.ep);
|
||||||
Genode::memcpy(buf, _sink->packet_content(p), p.size());
|
Genode::memcpy(buf, payload, payload_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ep) {
|
if (!ep) {
|
||||||
@ -441,7 +449,7 @@ class Device : public List<Device>::Element
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
urb *urb = usb_alloc_urb(p.transfer.number_of_packets, GFP_KERNEL);
|
urb *urb = usb_alloc_urb(isoc.number_of_packets, GFP_KERNEL);
|
||||||
if (!urb) {
|
if (!urb) {
|
||||||
error("Failed to allocate isochronous URB");
|
error("Failed to allocate isochronous URB");
|
||||||
dma_free(buf);
|
dma_free(buf);
|
||||||
@ -455,18 +463,18 @@ class Device : public List<Device>::Element
|
|||||||
urb->start_frame = -1;
|
urb->start_frame = -1;
|
||||||
urb->stream_id = 0;
|
urb->stream_id = 0;
|
||||||
urb->transfer_buffer = buf;
|
urb->transfer_buffer = buf;
|
||||||
urb->transfer_buffer_length = p.size();
|
urb->transfer_buffer_length = payload_size;
|
||||||
urb->number_of_packets = p.transfer.number_of_packets;
|
urb->number_of_packets = isoc.number_of_packets;
|
||||||
urb->interval = 1 << min(15, ep->desc.bInterval - 1);
|
urb->interval = 1 << min(15, ep->desc.bInterval - 1);
|
||||||
urb->context = (void *)data;
|
urb->context = (void *)data;
|
||||||
urb->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
urb->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
||||||
urb->complete = _async_complete;
|
urb->complete = _async_complete;
|
||||||
|
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
for (int i = 0; i < p.transfer.number_of_packets; i++) {
|
for (unsigned i = 0; i < isoc.number_of_packets; i++) {
|
||||||
urb->iso_frame_desc[i].offset = offset;
|
urb->iso_frame_desc[i].offset = offset;
|
||||||
urb->iso_frame_desc[i].length = p.transfer.packet_size[i];
|
urb->iso_frame_desc[i].length = isoc.packet_size[i];
|
||||||
offset += p.transfer.packet_size[i];
|
offset += isoc.packet_size[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
int ret = usb_submit_urb(urb, GFP_KERNEL);
|
int ret = usb_submit_urb(urb, GFP_KERNEL);
|
||||||
|
@ -542,8 +542,10 @@ handle_transfer_response(struct genode_usb_request_urb req,
|
|||||||
transfer->actual_size = urb->actual_length;
|
transfer->actual_size = urb->actual_length;
|
||||||
|
|
||||||
if (usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe)) {
|
if (usb_pipeisoc(urb->pipe) && usb_pipein(urb->pipe)) {
|
||||||
for (i = 0; i < urb->number_of_packets; i++)
|
struct genode_usb_isoc_transfer *isoc =
|
||||||
transfer->actual_packet_size[i] =
|
(struct genode_usb_isoc_transfer *)payload.addr;
|
||||||
|
for (i = 0; i < isoc->number_of_packets; i++)
|
||||||
|
isoc->actual_packet_size[i] =
|
||||||
urb->iso_frame_desc[i].actual_length;
|
urb->iso_frame_desc[i].actual_length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -700,13 +702,14 @@ static int fill_isoc_urb(struct usb_device * udev,
|
|||||||
req->ep & USB_DIR_IN ? udev->ep_in[req->ep & 0xf]
|
req->ep & USB_DIR_IN ? udev->ep_in[req->ep & 0xf]
|
||||||
: udev->ep_out[req->ep & 0xf];
|
: udev->ep_out[req->ep & 0xf];
|
||||||
|
|
||||||
|
struct genode_usb_isoc_transfer *isoc = (struct genode_usb_isoc_transfer *)buf.addr;
|
||||||
|
|
||||||
if (!buf.addr)
|
if (!buf.addr || isoc->number_of_packets > MAX_PACKETS)
|
||||||
return PACKET_INVALID_ERROR;
|
return PACKET_INVALID_ERROR;
|
||||||
if (!ep)
|
if (!ep)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
|
|
||||||
*urb = usb_alloc_urb(req->number_of_packets, GFP_KERNEL);
|
*urb = usb_alloc_urb(isoc->number_of_packets, GFP_KERNEL);
|
||||||
if (!*urb)
|
if (!*urb)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
@ -714,18 +717,18 @@ static int fill_isoc_urb(struct usb_device * udev,
|
|||||||
(*urb)->pipe = pipe;
|
(*urb)->pipe = pipe;
|
||||||
(*urb)->start_frame = -1;
|
(*urb)->start_frame = -1;
|
||||||
(*urb)->stream_id = 0;
|
(*urb)->stream_id = 0;
|
||||||
(*urb)->transfer_buffer = buf.addr;
|
(*urb)->transfer_buffer = isoc->data;
|
||||||
(*urb)->transfer_buffer_length = buf.size;
|
(*urb)->transfer_buffer_length = buf.size - sizeof(*isoc);
|
||||||
(*urb)->number_of_packets = req->number_of_packets;
|
(*urb)->number_of_packets = isoc->number_of_packets;
|
||||||
(*urb)->interval = 1 << min(15, ep->desc.bInterval - 1);
|
(*urb)->interval = 1 << min(15, ep->desc.bInterval - 1);
|
||||||
(*urb)->context = handle;
|
(*urb)->context = handle;
|
||||||
(*urb)->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
(*urb)->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT);
|
||||||
(*urb)->complete = async_complete;
|
(*urb)->complete = async_complete;
|
||||||
|
|
||||||
for (i = 0; i < req->number_of_packets; i++) {
|
for (i = 0; i < isoc->number_of_packets; i++) {
|
||||||
(*urb)->iso_frame_desc[i].offset = offset;
|
(*urb)->iso_frame_desc[i].offset = offset;
|
||||||
(*urb)->iso_frame_desc[i].length = req->packet_size[i];
|
(*urb)->iso_frame_desc[i].length = isoc->packet_size[i];
|
||||||
offset += req->packet_size[i];
|
offset += isoc->packet_size[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -227,16 +227,18 @@ struct Usb_device
|
|||||||
|
|
||||||
if (IS_XFERIN(transfer)) {
|
if (IS_XFERIN(transfer)) {
|
||||||
|
|
||||||
|
Usb::Isoc_transfer &isoc = *(Usb::Isoc_transfer *)packet_content;
|
||||||
|
|
||||||
unsigned out_offset = 0;
|
unsigned out_offset = 0;
|
||||||
for (int i = 0; i < p.transfer.number_of_packets; i++) {
|
for (unsigned i = 0; i < isoc.number_of_packets; i++) {
|
||||||
size_t const actual_length = p.transfer.actual_packet_size[i];
|
size_t const actual_length = isoc.actual_packet_size[i];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the data from the proper offsets within the buffer as
|
* Copy the data from the proper offsets within the buffer as
|
||||||
* a short read is still stored at this location.
|
* a short read is still stored at this location.
|
||||||
*/
|
*/
|
||||||
unsigned char * dst = transfer->buffer + out_offset;
|
unsigned char * dst = transfer->buffer + out_offset;
|
||||||
char const * src = packet_content + out_offset;
|
char const * src = isoc.data() + out_offset;
|
||||||
|
|
||||||
Genode::memcpy(dst, src, actual_length);
|
Genode::memcpy(dst, src, actual_length);
|
||||||
out_offset += transfer->iso_packet_desc[i].length;
|
out_offset += transfer->iso_packet_desc[i].length;
|
||||||
@ -244,7 +246,7 @@ struct Usb_device
|
|||||||
transfer->iso_packet_desc[i].actual_length = actual_length;
|
transfer->iso_packet_desc[i].actual_length = actual_length;
|
||||||
transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
|
transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
|
||||||
}
|
}
|
||||||
transfer->num_iso_packets = p.transfer.number_of_packets;
|
transfer->num_iso_packets = isoc.number_of_packets;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -611,8 +613,9 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Usb::Packet_descriptor p;
|
Usb::Packet_descriptor p;
|
||||||
|
size_t p_size = Usb::Isoc_transfer::size(total_length);
|
||||||
try {
|
try {
|
||||||
p = usb_device->usb_connection->alloc_packet(total_length);
|
p = usb_device->usb_connection->alloc_packet(p_size);
|
||||||
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
} catch (Usb::Session::Tx::Source::Packet_alloc_failed) {
|
||||||
return LIBUSB_ERROR_BUSY;
|
return LIBUSB_ERROR_BUSY;
|
||||||
}
|
}
|
||||||
@ -624,17 +627,16 @@ static int genode_submit_transfer(struct usbi_transfer * itransfer)
|
|||||||
p.completion = new (libc_alloc) Completion(itransfer);
|
p.completion = new (libc_alloc) Completion(itransfer);
|
||||||
p.transfer.ep = transfer->endpoint;
|
p.transfer.ep = transfer->endpoint;
|
||||||
|
|
||||||
|
Usb::Isoc_transfer &isoc =
|
||||||
|
*(Usb::Isoc_transfer *) usb_device->usb_connection->source()->packet_content(p);
|
||||||
|
isoc.number_of_packets = transfer->num_iso_packets;
|
||||||
for (int i = 0; i < transfer->num_iso_packets; i++) {
|
for (int i = 0; i < transfer->num_iso_packets; i++) {
|
||||||
p.transfer.packet_size[i] = transfer->iso_packet_desc[i].length;
|
isoc.packet_size[i] = transfer->iso_packet_desc[i].length;
|
||||||
|
isoc.actual_packet_size[i] = 0;
|
||||||
}
|
}
|
||||||
p.transfer.number_of_packets = transfer->num_iso_packets;
|
|
||||||
|
|
||||||
if (IS_XFEROUT(transfer)) {
|
if (IS_XFEROUT(transfer))
|
||||||
char *packet_content =
|
Genode::memcpy(isoc.data(), transfer->buffer, transfer->length);
|
||||||
usb_device->usb_connection->source()->packet_content(p);
|
|
||||||
Genode::memcpy(packet_content, transfer->buffer,
|
|
||||||
transfer->length);
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_device->usb_connection->source()->submit_packet(p);
|
usb_device->usb_connection->source()->submit_packet(p);
|
||||||
|
|
||||||
|
@ -55,11 +55,13 @@ class Isoc_packet : Fifo<Isoc_packet>::Element
|
|||||||
|
|
||||||
int _packet_index { 0 };
|
int _packet_index { 0 };
|
||||||
unsigned _packet_in_offset { 0 };
|
unsigned _packet_in_offset { 0 };
|
||||||
|
Usb::Isoc_transfer *_isoc { (Usb::Isoc_transfer *)_content };
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Isoc_packet(Usb::Packet_descriptor packet, char *content)
|
Isoc_packet(Usb::Packet_descriptor packet, char *content)
|
||||||
: _packet(packet), _content(content),
|
:
|
||||||
|
_packet(packet), _content(content),
|
||||||
_size (_packet.read_transfer() ? _packet.transfer.actual_size : _packet.size())
|
_size (_packet.read_transfer() ? _packet.transfer.actual_size : _packet.size())
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
@ -74,13 +76,13 @@ class Isoc_packet : Fifo<Isoc_packet>::Element
|
|||||||
unsigned remaining = _size - _offset;
|
unsigned remaining = _size - _offset;
|
||||||
int copy_size = min(usb_packet->iov.size, remaining);
|
int copy_size = min(usb_packet->iov.size, remaining);
|
||||||
|
|
||||||
usb_packet_copy(usb_packet, _content + _offset, copy_size);
|
usb_packet_copy(usb_packet, _isoc->data() + _offset, copy_size);
|
||||||
|
|
||||||
_offset += copy_size;
|
_offset += copy_size;
|
||||||
|
|
||||||
if (!_packet.read_transfer()) {
|
if (!_packet.read_transfer()) {
|
||||||
_packet.transfer.packet_size[_packet.transfer.number_of_packets] = copy_size;
|
_isoc->packet_size[_isoc->number_of_packets] = copy_size;
|
||||||
_packet.transfer.number_of_packets++;
|
_isoc->number_of_packets++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return remaining <= usb_packet->iov.size;
|
return remaining <= usb_packet->iov.size;
|
||||||
@ -90,24 +92,30 @@ class Isoc_packet : Fifo<Isoc_packet>::Element
|
|||||||
{
|
{
|
||||||
if (!valid()) return false;
|
if (!valid()) return false;
|
||||||
|
|
||||||
unsigned remaining = _packet.transfer.actual_packet_size[_packet_index];
|
unsigned remaining = _isoc->actual_packet_size[_packet_index];
|
||||||
/* this should not happen as there asserts in the qemu code */
|
/* this should not happen as there asserts in the qemu code */
|
||||||
if (remaining > usb_packet->iov.size) {
|
if (remaining > usb_packet->iov.size) {
|
||||||
Genode::error("iov too small, ignoring packet content");
|
Genode::error("iov too small, ignoring packet content");
|
||||||
}
|
}
|
||||||
int copy_size = min(usb_packet->iov.size, remaining);
|
int copy_size = min(usb_packet->iov.size, remaining);
|
||||||
|
|
||||||
char *src = _content + _packet_in_offset;
|
char *src = _isoc->data() + _packet_in_offset;
|
||||||
usb_packet_copy(usb_packet, src, copy_size);
|
usb_packet_copy(usb_packet, src, copy_size);
|
||||||
|
|
||||||
_packet_in_offset += _packet.transfer.packet_size[_packet_index];
|
_packet_in_offset += _isoc->packet_size[_packet_index];
|
||||||
++_packet_index;
|
++_packet_index;
|
||||||
|
|
||||||
return _packet_index == _packet.transfer.number_of_packets;
|
return _packet_index == _isoc->number_of_packets;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool valid() const { return _content != nullptr; }
|
bool valid() const { return _content != nullptr; }
|
||||||
unsigned packet_count() const { return _packet.transfer.number_of_packets; }
|
|
||||||
|
unsigned packet_count() const
|
||||||
|
{
|
||||||
|
if (!valid()) return 0;
|
||||||
|
|
||||||
|
return _isoc->number_of_packets;
|
||||||
|
}
|
||||||
|
|
||||||
Usb::Packet_descriptor& packet() { return _packet; }
|
Usb::Packet_descriptor& packet() { return _packet; }
|
||||||
};
|
};
|
||||||
@ -253,7 +261,7 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
Completion completion[NUM_COMPLETIONS];
|
Completion completion[NUM_COMPLETIONS];
|
||||||
|
|
||||||
Fifo<Isoc_packet> isoc_read_queue { };
|
Fifo<Isoc_packet> isoc_read_queue { };
|
||||||
Reconstructible<Isoc_packet> isoc_write_packet { Usb::Packet_descriptor(), nullptr };
|
Reconstructible<Isoc_packet> isoc_write_packet { };
|
||||||
|
|
||||||
Genode::Ring_buffer<Isoc_packet, 5, Genode::Ring_buffer_unsynchronized> _isoch_out_queue { };
|
Genode::Ring_buffer<Isoc_packet, 5, Genode::Ring_buffer_unsynchronized> _isoch_out_queue { };
|
||||||
unsigned _isoch_out_pending { 0 };
|
unsigned _isoch_out_pending { 0 };
|
||||||
@ -376,9 +384,8 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
|
|
||||||
bool isoc_read(USBPacket *packet)
|
bool isoc_read(USBPacket *packet)
|
||||||
{
|
{
|
||||||
if (isoc_read_queue.empty()) {
|
if (isoc_read_queue.empty())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
isoc_read_queue.head([&] (Isoc_packet &head) {
|
isoc_read_queue.head([&] (Isoc_packet &head) {
|
||||||
if (head.copy_read(packet)) {
|
if (head.copy_read(packet)) {
|
||||||
@ -406,16 +413,19 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = usb_packet->ep->max_packet_size * NUMBER_OF_PACKETS;
|
size_t const payload_size = usb_packet->ep->max_packet_size * NUMBER_OF_PACKETS;
|
||||||
|
size_t const packet_size = Usb::Isoc_transfer::size(payload_size);
|
||||||
try {
|
try {
|
||||||
Usb::Packet_descriptor packet = alloc_packet(size);
|
Usb::Packet_descriptor packet = alloc_packet(packet_size, true);
|
||||||
packet.type = Packet_type::ISOC;
|
packet.type = Packet_type::ISOC;
|
||||||
packet.transfer.ep = usb_packet->ep->nr | USB_DIR_IN;
|
packet.transfer.ep = usb_packet->ep->nr | USB_DIR_IN;
|
||||||
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
||||||
packet.transfer.number_of_packets = NUMBER_OF_PACKETS;
|
|
||||||
for (unsigned i = 0; i < NUMBER_OF_PACKETS; i++) {
|
Usb::Isoc_transfer &isoc =
|
||||||
packet.transfer.packet_size[i] = usb_packet->ep->max_packet_size;
|
*(Usb::Isoc_transfer *)usb_raw.source()->packet_content(packet);
|
||||||
}
|
isoc.number_of_packets = NUMBER_OF_PACKETS;
|
||||||
|
for (unsigned i = 0; i < NUMBER_OF_PACKETS; i++)
|
||||||
|
isoc.packet_size[i] = usb_packet->ep->max_packet_size;
|
||||||
|
|
||||||
Completion *c = dynamic_cast<Completion *>(packet.completion);
|
Completion *c = dynamic_cast<Completion *>(packet.completion);
|
||||||
c->p = nullptr;
|
c->p = nullptr;
|
||||||
@ -427,7 +437,7 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
submit(packet);
|
submit(packet);
|
||||||
} catch (Packet_alloc_failed) {
|
} catch (Packet_alloc_failed) {
|
||||||
if (verbose_warnings)
|
if (verbose_warnings)
|
||||||
warning("xHCI: packet allocation failed (size ", Hex(size), "in ", __func__, ")");
|
warning("xHCI: packet allocation failed (size ", Hex(packet_size), "in ", __func__, ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -451,37 +461,41 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
{
|
{
|
||||||
enum { NUMBER_OF_PACKETS = 32 };
|
enum { NUMBER_OF_PACKETS = 32 };
|
||||||
|
|
||||||
bool valid = isoc_write_packet->valid();
|
bool const valid = isoc_write_packet->valid();
|
||||||
if (valid) {
|
if (valid) {
|
||||||
isoc_write_packet->copy(usb_packet);
|
isoc_write_packet->copy(usb_packet);
|
||||||
|
|
||||||
if (isoc_write_packet->packet_count() < NUMBER_OF_PACKETS)
|
if (isoc_write_packet->packet_count() < NUMBER_OF_PACKETS)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_isoch_out_queue.add(*&*isoc_write_packet);
|
_isoch_out_queue.add(*isoc_write_packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size = usb_packet->ep->max_packet_size * NUMBER_OF_PACKETS;
|
size_t const payload_size = usb_packet->ep->max_packet_size * NUMBER_OF_PACKETS;
|
||||||
|
size_t const packet_size = Usb::Isoc_transfer::size(payload_size);
|
||||||
try {
|
try {
|
||||||
Usb::Packet_descriptor packet = alloc_packet(size, false);
|
Usb::Packet_descriptor packet = alloc_packet(packet_size, false);
|
||||||
packet.type = Packet_type::ISOC;
|
packet.type = Packet_type::ISOC;
|
||||||
packet.transfer.ep = usb_packet->ep->nr;
|
packet.transfer.ep = usb_packet->ep->nr;
|
||||||
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
||||||
packet.transfer.number_of_packets = 0;
|
|
||||||
|
|
||||||
isoc_write_packet.construct(packet, usb_raw.source()->packet_content(packet));
|
char *packet_content = usb_raw.source()->packet_content(packet);
|
||||||
|
|
||||||
|
Usb::Isoc_transfer &isoc = *(Usb::Isoc_transfer *)packet_content;
|
||||||
|
isoc.number_of_packets = 0;
|
||||||
|
|
||||||
|
isoc_write_packet.construct(packet, packet_content);
|
||||||
if (!valid) isoc_write_packet->copy(usb_packet);
|
if (!valid) isoc_write_packet->copy(usb_packet);
|
||||||
|
|
||||||
} catch (Packet_alloc_failed) {
|
} catch (Packet_alloc_failed) {
|
||||||
if (verbose_warnings)
|
if (verbose_warnings)
|
||||||
warning("xHCI: packet allocation failed (size ", Hex(size), "in ", __func__, ")");
|
warning("xHCI: packet allocation failed (size ", Hex(packet_size), "in ", __func__, ")");
|
||||||
isoc_write_packet.construct(Usb::Packet_descriptor(), nullptr);
|
isoc_write_packet.construct();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isoch_out_pending == 0 && _isoch_out_queue.avail_capacity() > 1) {
|
if (_isoch_out_pending == 0 && _isoch_out_queue.avail_capacity() > 1)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
while (!_isoch_out_queue.empty()) {
|
while (!_isoch_out_queue.empty()) {
|
||||||
Isoc_packet i = _isoch_out_queue.get();
|
Isoc_packet i = _isoch_out_queue.get();
|
||||||
@ -528,7 +542,7 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
** Packet stream **
|
** Packet stream **
|
||||||
*******************/
|
*******************/
|
||||||
|
|
||||||
Usb::Packet_descriptor alloc_packet(int length, bool completion = true)
|
Usb::Packet_descriptor alloc_packet(int length, bool completion)
|
||||||
{
|
{
|
||||||
if (!usb_raw.source()->ready_to_submit()) {
|
if (!usb_raw.source()->ready_to_submit()) {
|
||||||
throw Packet_alloc_failed();
|
throw Packet_alloc_failed();
|
||||||
@ -621,7 +635,7 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
_release_interfaces();
|
_release_interfaces();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Usb::Packet_descriptor packet = alloc_packet(0);
|
Usb::Packet_descriptor packet = alloc_packet(0, true);
|
||||||
packet.type = Usb::Packet_descriptor::CONFIG;
|
packet.type = Usb::Packet_descriptor::CONFIG;
|
||||||
packet.number = value;
|
packet.number = value;
|
||||||
|
|
||||||
@ -641,7 +655,7 @@ struct Usb_host_device : List<Usb_host_device>::Element
|
|||||||
void set_interface(int index, uint8_t value, USBPacket *p)
|
void set_interface(int index, uint8_t value, USBPacket *p)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Usb::Packet_descriptor packet = alloc_packet(0);
|
Usb::Packet_descriptor packet = alloc_packet(0, true);
|
||||||
packet.type = Usb::Packet_descriptor::ALT_SETTING;
|
packet.type = Usb::Packet_descriptor::ALT_SETTING;
|
||||||
packet.interface.number = index;
|
packet.interface.number = index;
|
||||||
packet.interface.alt_setting = value;
|
packet.interface.alt_setting = value;
|
||||||
@ -828,7 +842,7 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Usb::Packet_descriptor packet = dev->alloc_packet(size);
|
Usb::Packet_descriptor packet = dev->alloc_packet(size, true);
|
||||||
packet.type = type;
|
packet.type = type;
|
||||||
packet.transfer.ep = p->ep->nr | (in ? USB_DIR_IN : 0);
|
packet.transfer.ep = p->ep->nr | (in ? USB_DIR_IN : 0);
|
||||||
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
packet.transfer.polling_interval = Usb::Packet_descriptor::DEFAULT_POLLING_INTERVAL;
|
||||||
@ -883,7 +897,7 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
|
|||||||
|
|
||||||
Usb::Packet_descriptor packet;
|
Usb::Packet_descriptor packet;
|
||||||
try {
|
try {
|
||||||
packet = dev->alloc_packet(length);
|
packet = dev->alloc_packet(length, true);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
if (verbose_warnings)
|
if (verbose_warnings)
|
||||||
warning("Packet allocation failed");
|
warning("Packet allocation failed");
|
||||||
|
@ -147,16 +147,21 @@ struct genode_usb_request_control
|
|||||||
int timeout;
|
int timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Iso { MAX_PACKETS = 32 };
|
|
||||||
|
|
||||||
struct genode_usb_request_transfer
|
struct genode_usb_request_transfer
|
||||||
{
|
{
|
||||||
unsigned char ep;
|
unsigned char ep;
|
||||||
int actual_size;
|
int actual_size;
|
||||||
int polling_interval;
|
int polling_interval;
|
||||||
int number_of_packets;
|
};
|
||||||
unsigned long packet_size[MAX_PACKETS];
|
|
||||||
unsigned long actual_packet_size[MAX_PACKETS];
|
enum Isoc { MAX_PACKETS = 32 };
|
||||||
|
|
||||||
|
struct genode_usb_isoc_transfer
|
||||||
|
{
|
||||||
|
unsigned number_of_packets;
|
||||||
|
unsigned packet_size[MAX_PACKETS];
|
||||||
|
unsigned actual_packet_size[MAX_PACKETS];
|
||||||
|
char data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Urb_type { CTRL, BULK, IRQ, ISOC, NONE };
|
enum Urb_type { CTRL, BULK, IRQ, ISOC, NONE };
|
||||||
|
@ -24,6 +24,7 @@ namespace Usb {
|
|||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
class Session;
|
class Session;
|
||||||
struct Packet_descriptor;
|
struct Packet_descriptor;
|
||||||
|
struct Isoc_transfer;
|
||||||
struct Completion;
|
struct Completion;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +35,6 @@ namespace Usb {
|
|||||||
struct Usb::Packet_descriptor : Genode::Packet_descriptor
|
struct Usb::Packet_descriptor : Genode::Packet_descriptor
|
||||||
{
|
{
|
||||||
enum Type { STRING, CTRL, BULK, IRQ, ISOC, ALT_SETTING, CONFIG, RELEASE_IF, FLUSH_TRANSFERS };
|
enum Type { STRING, CTRL, BULK, IRQ, ISOC, ALT_SETTING, CONFIG, RELEASE_IF, FLUSH_TRANSFERS };
|
||||||
enum Iso { MAX_PACKETS = 32 };
|
|
||||||
|
|
||||||
/* use the polling interval stated in the endpoint descriptor */
|
/* use the polling interval stated in the endpoint descriptor */
|
||||||
enum { DEFAULT_POLLING_INTERVAL = -1 };
|
enum { DEFAULT_POLLING_INTERVAL = -1 };
|
||||||
@ -66,9 +66,6 @@ struct Usb::Packet_descriptor : Genode::Packet_descriptor
|
|||||||
uint8_t ep;
|
uint8_t ep;
|
||||||
int actual_size; /* returned */
|
int actual_size; /* returned */
|
||||||
int polling_interval; /* for interrupt transfers */
|
int polling_interval; /* for interrupt transfers */
|
||||||
int number_of_packets;
|
|
||||||
size_t packet_size[MAX_PACKETS];
|
|
||||||
size_t actual_packet_size[MAX_PACKETS];
|
|
||||||
} transfer;
|
} transfer;
|
||||||
|
|
||||||
struct
|
struct
|
||||||
@ -110,6 +107,26 @@ struct Usb::Packet_descriptor : Genode::Packet_descriptor
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Isochronous transfer metadata (located at start of stream packet)
|
||||||
|
*/
|
||||||
|
struct Usb::Isoc_transfer
|
||||||
|
{
|
||||||
|
enum { MAX_PACKETS = 32 };
|
||||||
|
|
||||||
|
unsigned number_of_packets;
|
||||||
|
unsigned packet_size[MAX_PACKETS];
|
||||||
|
unsigned actual_packet_size[MAX_PACKETS];
|
||||||
|
|
||||||
|
char *data() { return (char *)(this + 1); }
|
||||||
|
|
||||||
|
static size_t size(unsigned data_size)
|
||||||
|
{
|
||||||
|
return sizeof(Isoc_transfer) + data_size;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completion for asynchronous communication
|
* Completion for asynchronous communication
|
||||||
*/
|
*/
|
||||||
|
@ -73,9 +73,9 @@ class genode_usb_session : public Usb::Session_rpc_object
|
|||||||
|
|
||||||
friend class ::Root;
|
friend class ::Root;
|
||||||
|
|
||||||
enum { MAX_PACKETS_IN_FLY = 10 };
|
enum { MAX_PACKETS_IN_FLIGHT = 32 };
|
||||||
|
|
||||||
Constructible<Usb::Packet_descriptor> packets[MAX_PACKETS_IN_FLY] { };
|
Constructible<Usb::Packet_descriptor> packets[MAX_PACKETS_IN_FLIGHT] { };
|
||||||
|
|
||||||
::Root & _root;
|
::Root & _root;
|
||||||
genode_shared_dataspace * _ds;
|
genode_shared_dataspace * _ds;
|
||||||
@ -84,7 +84,7 @@ class genode_usb_session : public Usb::Session_rpc_object
|
|||||||
Session_label const _label;
|
Session_label const _label;
|
||||||
List_element<genode_usb_session> _le { this };
|
List_element<genode_usb_session> _le { this };
|
||||||
|
|
||||||
unsigned _packets_in_fly();
|
unsigned _packets_in_flight();
|
||||||
void _ack(int err, Usb::Packet_descriptor p);
|
void _ack(int err, Usb::Packet_descriptor p);
|
||||||
|
|
||||||
genode_usb_buffer _buffer_of_packet(Usb::Packet_descriptor p);
|
genode_usb_buffer _buffer_of_packet(Usb::Packet_descriptor p);
|
||||||
@ -414,7 +414,7 @@ void genode_usb_session::release_interface(unsigned iface)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned genode_usb_session::_packets_in_fly()
|
unsigned genode_usb_session::_packets_in_flight()
|
||||||
{
|
{
|
||||||
unsigned ret = 0;
|
unsigned ret = 0;
|
||||||
for (auto const &p : packets)
|
for (auto const &p : packets)
|
||||||
@ -463,7 +463,7 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
|
|||||||
break;
|
break;
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
if (idx == MAX_PACKETS_IN_FLY)
|
if (idx == MAX_PACKETS_IN_FLIGHT)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Packet_descriptor p;
|
Packet_descriptor p;
|
||||||
@ -471,7 +471,7 @@ bool genode_usb_session::request(genode_usb_request_callbacks & req, void * data
|
|||||||
/* get next packet from request stream */
|
/* get next packet from request stream */
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!sink()->packet_avail() ||
|
if (!sink()->packet_avail() ||
|
||||||
(sink()->ack_slots_free() <= _packets_in_fly()))
|
(sink()->ack_slots_free() <= _packets_in_flight()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
p = sink()->get_packet();
|
p = sink()->get_packet();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user