mirror of
https://github.com/genodelabs/genode.git
synced 2025-04-08 03:45:24 +00:00
usb_drv: add isochronous packet support
Commit extents USB session an driver accordingly. issue #2910
This commit is contained in:
parent
b6bc44fd10
commit
037a0d6822
@ -233,7 +233,7 @@ class Usb::Worker : public Genode::Weak_object<Usb::Worker>
|
||||
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<Usb::Worker>
|
||||
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<Usb::Worker>
|
||||
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;
|
||||
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user