From 037a0d6822362edde53eff2f146f65b8d4bf74c0 Mon Sep 17 00:00:00 2001 From: Sebastian Sumpf Date: Fri, 6 Jul 2018 15:13:43 +0200 Subject: [PATCH] usb_drv: add isochronous packet support Commit extents USB session an driver accordingly. issue #2910 --- repos/dde_linux/src/lib/usb/raw/raw.cc | 71 +++++++++++++++++++++- repos/os/include/usb_session/usb_session.h | 5 +- 2 files changed, 72 insertions(+), 4 deletions(-) diff --git a/repos/dde_linux/src/lib/usb/raw/raw.cc b/repos/dde_linux/src/lib/usb/raw/raw.cc index 1a9eb15525..f7a0aaa5f8 100644 --- a/repos/dde_linux/src/lib/usb/raw/raw.cc +++ b/repos/dde_linux/src/lib/usb/raw/raw.cc @@ -233,7 +233,7 @@ class Usb::Worker : public Genode::Weak_object p.succeded = true; if (read) - Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer, + Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer, urb->actual_length); } @@ -356,6 +356,66 @@ class Usb::Worker : public Genode::Weak_object return true; } + /** + * Isochronous transfer + */ + bool _isoc(Packet_descriptor &p, bool read) + { + unsigned pipe; + usb_host_endpoint *ep; + void *buf = dma_malloc(p.size()); + + if (read) { + pipe = usb_rcvisocpipe(_device->udev, p.transfer.ep); + ep = _device->udev->ep_in[p.transfer.ep & 0x0f]; + } + else { + pipe = usb_sndisocpipe(_device->udev, p.transfer.ep); + ep = _device->udev->ep_out[p.transfer.ep & 0x0f]; + Genode::memcpy(buf, _sink->packet_content(p), p.size()); + } + + urb *urb = usb_alloc_urb(p.transfer.number_of_packets, GFP_KERNEL); + if (!urb) { + error("Failed to allocate isochronous URB"); + dma_free(buf); + p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + return false; + } + + Complete_data *data = alloc_complete_data(p); + urb->dev = _device->udev; + urb->pipe = pipe; + urb->start_frame = -1; + urb->stream_id = 0; + urb->transfer_buffer = buf; + urb->transfer_buffer_length = p.size(); + urb->number_of_packets = p.transfer.number_of_packets; + urb->interval = 1 << min(15, ep->desc.bInterval - 1); + urb->context = (void *)data; + urb->transfer_flags = URB_ISO_ASAP | (read ? URB_DIR_IN : URB_DIR_OUT); + urb->complete = _async_complete; + + unsigned offset = 0; + for (int i = 0; i < p.transfer.number_of_packets; i++) { + urb->iso_frame_desc[i].offset = offset; + urb->iso_frame_desc[i].length = p.transfer.packet_size[i]; + offset += p.transfer.packet_size[i]; + } + + int ret = usb_submit_urb(urb, GFP_KERNEL); + if (ret == 0) + return true; + + error("Failed to submit URB, error: ", ret); + p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + + free_complete_data(data); + usb_free_urb(urb); + dma_free(buf); + return false; + } + /** * Change alternate settings for device */ @@ -441,12 +501,17 @@ class Usb::Worker : public Genode::Weak_object break; case Packet_descriptor::BULK: - if (_bulk(p, !!(p.transfer.ep & USB_DIR_IN))) + if (_bulk(p, p.read_transfer())) continue; break; case Packet_descriptor::IRQ: - if (_irq(p, !!(p.transfer.ep & USB_DIR_IN))) + if (_irq(p, p.read_transfer())) + continue; + break; + + case Packet_descriptor::ISOC: + if (_isoc(p, p.read_transfer())) continue; break; diff --git a/repos/os/include/usb_session/usb_session.h b/repos/os/include/usb_session/usb_session.h index fa5262e4be..60b3b5704e 100644 --- a/repos/os/include/usb_session/usb_session.h +++ b/repos/os/include/usb_session/usb_session.h @@ -33,7 +33,8 @@ namespace Usb { */ struct Usb::Packet_descriptor : Genode::Packet_descriptor { - enum Type { STRING, CTRL, BULK, IRQ, ALT_SETTING, CONFIG, RELEASE_IF }; + enum Type { STRING, CTRL, BULK, IRQ, ISOC, ALT_SETTING, CONFIG, RELEASE_IF }; + enum Iso { MAX_PACKETS = 32 }; /* use the polling interval stated in the endpoint descriptor */ enum { DEFAULT_POLLING_INTERVAL = -1 }; @@ -65,6 +66,8 @@ struct Usb::Packet_descriptor : Genode::Packet_descriptor uint8_t ep; int actual_size; /* returned */ int polling_interval; /* for interrupt transfers */ + int number_of_packets; + size_t packet_size[MAX_PACKETS]; } transfer; struct