diff --git a/repos/libports/src/lib/qemu-usb/host.cc b/repos/libports/src/lib/qemu-usb/host.cc index 9f72cd3739..5889b2a71b 100644 --- a/repos/libports/src/lib/qemu-usb/host.cc +++ b/repos/libports/src/lib/qemu-usb/host.cc @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -63,6 +64,10 @@ class Isoc_packet : Fifo::Element _size (_packet.read_transfer() ? _packet.transfer.actual_size : _packet.size()) { } + Isoc_packet() + : _packet { Usb::Packet_descriptor() }, _content { nullptr }, _size { 0 } + { } + bool copy(USBPacket *usb_packet) { if (!valid()) return false; @@ -243,6 +248,9 @@ struct Usb_host_device : List::Element Fifo isoc_read_queue { }; Reconstructible isoc_write_packet { Usb::Packet_descriptor(), nullptr }; + Genode::Ring_buffer _isoch_out_queue { }; + unsigned _isoch_out_pending { 0 }; + Entrypoint &_ep; Signal_handler state_dispatcher { _ep, *this, &Usb_host_device::state_change }; @@ -334,8 +342,12 @@ struct Usb_host_device : List::Element Usb::Packet_descriptor packet = usb_raw.source()->get_acked_packet(); Completion *c = dynamic_cast(packet.completion); - if ((packet.type == Packet_type::ISOC && !packet.read_transfer()) || - (c && c->state == Completion::CANCELED)) { + if ((packet.type == Packet_type::ISOC && !packet.read_transfer())) { + free_packet(packet); + _isoch_out_pending--; + continue; + } + if ((c && c->state == Completion::CANCELED)) { free_packet(packet); continue; } @@ -447,7 +459,7 @@ struct Usb_host_device : List::Element if (isoc_write_packet->packet_count() < NUMBER_OF_PACKETS) return; - submit(isoc_write_packet->packet()); + _isoch_out_queue.add(*&*isoc_write_packet); } size_t size = usb_packet->ep->max_packet_size * NUMBER_OF_PACKETS; @@ -467,6 +479,16 @@ struct Usb_host_device : List::Element isoc_write_packet.construct(Usb::Packet_descriptor(), nullptr); return; } + + if (_isoch_out_pending == 0 && _isoch_out_queue.avail_capacity() > 1) { + return; + } + + while (!_isoch_out_queue.empty()) { + Isoc_packet i = _isoch_out_queue.get(); + submit(i.packet()); + _isoch_out_pending++; + } }