diff --git a/repos/dde_linux/src/drivers/usb/raw/raw.cc b/repos/dde_linux/src/drivers/usb/raw/raw.cc index 564fea4aeb..ea295ed19d 100644 --- a/repos/dde_linux/src/drivers/usb/raw/raw.cc +++ b/repos/dde_linux/src/drivers/usb/raw/raw.cc @@ -28,6 +28,9 @@ #include #include +/* definition from scsi.h conflicts with USB session timeout error */ +#undef TIMEOUT_ERROR + using namespace Genode; extern "C" int usb_set_configuration(struct usb_device *dev, int configuration); @@ -175,9 +178,27 @@ class Usb::Worker : public Genode::Weak_object kfree(buf); - p.control.actual_size = err; + if (err >= 0) { + p.succeded = true; + p.control.actual_size = err; + } else { + p.control.actual_size = 0; - p.succeded = (err < 0 && err != -EPIPE) ? false : true; + if (err == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((err == -ENODEV) || (err == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else if ((err == -EPROTO) || (err == -EILSEQ)) + p.error = Packet_descriptor::PROTOCOL_ERROR; + else if (err == -EPIPE) + p.error = Packet_descriptor::STALL_ERROR; + else if (err == -ETIMEDOUT) + p.error = Packet_descriptor::TIMEOUT_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", err); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } + } } /** @@ -194,16 +215,34 @@ class Usb::Worker : public Genode::Weak_object p.control.request, p.control.request_type, p.control.value, p.control.index, buf, p.size(), p.control.timeout); - if (err >= 0 || err== -EPIPE) { - p.control.actual_size = err; + + if (err >= 0) { p.succeded = true; + p.control.actual_size = err; + + if (p.control.request == USB_REQ_CLEAR_FEATURE && + p.control.value == USB_ENDPOINT_HALT) { + usb_reset_endpoint(_device->udev, p.control.index); + } + } else { + p.control.actual_size = 0; + + if (err == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((err == -ENODEV) || (err == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else if ((err == -EPROTO) || (err == -EILSEQ)) + p.error = Packet_descriptor::PROTOCOL_ERROR; + else if (err == -EPIPE) + p.error = Packet_descriptor::STALL_ERROR; + else if (err == -ETIMEDOUT) + p.error = Packet_descriptor::TIMEOUT_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", err); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } } - if (err >= 0 - && p.control.request == USB_REQ_CLEAR_FEATURE - && p.control.value == USB_ENDPOINT_HALT) { - usb_reset_endpoint(_device->udev, p.control.index); - } kfree(buf); } @@ -242,10 +281,15 @@ class Usb::Worker : public Genode::Weak_object if (read) Genode::memcpy(_sink->packet_content(p), urb->transfer_buffer, urb->actual_length); - } - - if (urb->status == -EPIPE) { + } else if (urb->status == -ESHUTDOWN) { + p.error = Packet_descriptor::NO_DEVICE_ERROR; + } else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) { + p.error = Packet_descriptor::PROTOCOL_ERROR; + } else if (urb->status == -EPIPE) { p.error = Packet_descriptor::STALL_ERROR; + } else { + Genode::error(__func__, ": unhandled error: ", urb->status); + p.error = Packet_descriptor::UNKNOWN_ERROR; } _ack_packet(p); @@ -287,7 +331,7 @@ class Usb::Worker : public Genode::Weak_object if (!bulk_urb) { error("Failed to allocate bulk URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -298,8 +342,14 @@ class Usb::Worker : public Genode::Weak_object int ret = usb_submit_urb(bulk_urb, GFP_KERNEL); if (ret != 0) { - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(bulk_urb); @@ -329,7 +379,7 @@ class Usb::Worker : public Genode::Weak_object if (!irq_urb) { error("Failed to allocate interrupt URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -345,7 +395,7 @@ class Usb::Worker : public Genode::Weak_object if (!ep) { error("could not get ep: ", p.transfer.ep); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; return false; } @@ -359,8 +409,14 @@ class Usb::Worker : public Genode::Weak_object int ret = usb_submit_urb(irq_urb, GFP_KERNEL); if (ret != 0) { - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(irq_urb); @@ -393,7 +449,7 @@ class Usb::Worker : public Genode::Weak_object if (!ep) { error("could not get ep: ", p.transfer.ep); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; return false; } @@ -401,7 +457,7 @@ class Usb::Worker : public Genode::Weak_object if (!urb) { error("Failed to allocate isochronous URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -429,8 +485,14 @@ class Usb::Worker : public Genode::Weak_object if (ret == 0) return true; - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(urb); @@ -447,6 +509,8 @@ class Usb::Worker : public Genode::Weak_object p.interface.alt_setting); if (!err) p.succeded = true; + else + Genode::error(__func__, ": unhandled error: ", err); } /** @@ -469,6 +533,8 @@ class Usb::Worker : public Genode::Weak_object if (!err) p.succeded = true; + else + Genode::error(__func__, ": unhandled error: ", err); } /** @@ -503,7 +569,15 @@ class Usb::Worker : public Genode::Weak_object _p_in_flight++; - if (!_device || !_device->udev || !_sink->packet_valid(p)) { + if (!_device || !_device->udev || + _device->udev->state == USB_STATE_NOTATTACHED) { + p.error = Packet_descriptor::NO_DEVICE_ERROR; + _ack_packet(p); + continue; + } + + if (!_sink->packet_valid(p)) { + p.error = Packet_descriptor::PACKET_INVALID_ERROR; _ack_packet(p); continue; } diff --git a/repos/dde_linux/src/drivers/usb_host/raw.cc b/repos/dde_linux/src/drivers/usb_host/raw.cc index 1d3b87684c..82930d2c8c 100644 --- a/repos/dde_linux/src/drivers/usb_host/raw.cc +++ b/repos/dde_linux/src/drivers/usb_host/raw.cc @@ -186,9 +186,27 @@ class Usb::Worker : public Genode::Weak_object kfree(buf); - p.control.actual_size = err; + if (err >= 0) { + p.succeded = true; + p.control.actual_size = err; + } else { + p.control.actual_size = 0; - p.succeded = (err < 0 && err != -EPIPE) ? false : true; + if (err == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((err == -ENODEV) || (err == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else if ((err == -EPROTO) || (err == -EILSEQ)) + p.error = Packet_descriptor::PROTOCOL_ERROR; + else if (err == -EPIPE) + p.error = Packet_descriptor::STALL_ERROR; + else if (err == -ETIMEDOUT) + p.error = Packet_descriptor::TIMEOUT_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", err); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } + } } /** @@ -205,16 +223,34 @@ class Usb::Worker : public Genode::Weak_object p.control.request, p.control.request_type, p.control.value, p.control.index, buf, p.size(), p.control.timeout); - if (err >= 0 || err== -EPIPE) { - p.control.actual_size = err; + + if (err >= 0) { p.succeded = true; + p.control.actual_size = err; + + if (p.control.request == USB_REQ_CLEAR_FEATURE && + p.control.value == USB_ENDPOINT_HALT) { + usb_reset_endpoint(_device->udev, p.control.index); + } + } else { + p.control.actual_size = 0; + + if (err == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((err == -ENODEV) || (err == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else if ((err == -EPROTO) || (err == -EILSEQ)) + p.error = Packet_descriptor::PROTOCOL_ERROR; + else if (err == -EPIPE) + p.error = Packet_descriptor::STALL_ERROR; + else if (err == -ETIMEDOUT) + p.error = Packet_descriptor::TIMEOUT_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", err); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } } - if (err >= 0 - && p.control.request == USB_REQ_CLEAR_FEATURE - && p.control.value == USB_ENDPOINT_HALT) { - usb_reset_endpoint(_device->udev, p.control.index); - } kfree(buf); } @@ -251,12 +287,17 @@ 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); - } - - if (urb->status == -EPIPE) { + } else if (urb->status == -ESHUTDOWN) { + p.error = Packet_descriptor::NO_DEVICE_ERROR; + } else if ((urb->status == -EPROTO) || (urb->status == -EILSEQ)) { + p.error = Packet_descriptor::PROTOCOL_ERROR; + } else if (urb->status == -EPIPE) { p.error = Packet_descriptor::STALL_ERROR; + } else { + Genode::error(__func__, ": unhandled error: ", urb->status); + p.error = Packet_descriptor::UNKNOWN_ERROR; } _ack_packet(p); @@ -298,7 +339,7 @@ class Usb::Worker : public Genode::Weak_object if (!bulk_urb) { error("Failed to allocate bulk URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -309,8 +350,14 @@ class Usb::Worker : public Genode::Weak_object int ret = usb_submit_urb(bulk_urb, GFP_KERNEL); if (ret != 0) { - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(bulk_urb); @@ -340,7 +387,7 @@ class Usb::Worker : public Genode::Weak_object if (!irq_urb) { error("Failed to allocate interrupt URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -356,7 +403,7 @@ class Usb::Worker : public Genode::Weak_object if (!ep) { error("could not get ep: ", p.transfer.ep); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; return false; } @@ -370,8 +417,14 @@ class Usb::Worker : public Genode::Weak_object int ret = usb_submit_urb(irq_urb, GFP_KERNEL); if (ret != 0) { - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(irq_urb); @@ -404,7 +457,7 @@ class Usb::Worker : public Genode::Weak_object if (!ep) { error("could not get ep: ", p.transfer.ep); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; return false; } @@ -412,7 +465,7 @@ class Usb::Worker : public Genode::Weak_object if (!urb) { error("Failed to allocate isochronous URB"); dma_free(buf); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + p.error = Usb::Packet_descriptor::MEMORY_ERROR; return false; } @@ -440,8 +493,14 @@ class Usb::Worker : public Genode::Weak_object if (ret == 0) return true; - error("Failed to submit URB, error: ", ret); - p.error = Usb::Packet_descriptor::SUBMIT_ERROR; + if (ret == -ENOENT) + p.error = Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR; + else if ((ret == -ENODEV) || (ret == -ESHUTDOWN)) + p.error = Packet_descriptor::NO_DEVICE_ERROR; + else { + Genode::error(__func__, ": unhandled error: ", ret); + p.error = Packet_descriptor::UNKNOWN_ERROR; + } free_complete_data(data); usb_free_urb(urb); @@ -458,6 +517,8 @@ class Usb::Worker : public Genode::Weak_object p.interface.alt_setting); if (!err) p.succeded = true; + else + Genode::error(__func__, ": unhandled error: ", err); } /** @@ -480,6 +541,8 @@ class Usb::Worker : public Genode::Weak_object if (!err) p.succeded = true; + else + Genode::error(__func__, ": unhandled error: ", err); } /** @@ -515,8 +578,14 @@ class Usb::Worker : public Genode::Weak_object _p_in_flight++; if (!_device || !_device->udev || - _device->udev->state == USB_STATE_NOTATTACHED || - !_sink->packet_valid(p)) { + _device->udev->state == USB_STATE_NOTATTACHED) { + p.error = Packet_descriptor::NO_DEVICE_ERROR; + _ack_packet(p); + continue; + } + + if (!_sink->packet_valid(p)) { + p.error = Packet_descriptor::PACKET_INVALID_ERROR; _ack_packet(p); continue; } diff --git a/repos/dde_linux/src/include/lx_emul/impl/usb.h b/repos/dde_linux/src/include/lx_emul/impl/usb.h index f05b46bc13..b6f4c2e78d 100644 --- a/repos/dde_linux/src/include/lx_emul/impl/usb.h +++ b/repos/dde_linux/src/include/lx_emul/impl/usb.h @@ -47,8 +47,16 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, Genode::construct_at(scu, *(Usb::Connection*)(dev->bus->controller), *u); scu->send(timeout); - int ret = u->actual_length; + kfree(scu); + + int ret; + if (u->status >= 0) + ret = u->actual_length; + else + ret = u->status; + usb_free_urb(u); + kfree(dr); return ret; } @@ -74,6 +82,22 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) Genode::construct_at(u, *(Usb::Connection*)(urb->dev->bus->controller), *urb); + /* + * Self-destruction of the 'Urb' object in its completion function + * would not work if the 'Usb' session gets closed before the + * completion function was called. So we store the pointer in the + * otherwise unused 'hcpriv' member and free it in a following + * 'usb_submit_urb()' or 'usb_free_urb()' call. + */ + + if (urb->hcpriv) { + Urb *prev_urb = (Urb*)urb->hcpriv; + prev_urb->~Urb(); + kfree(urb->hcpriv); + } + + urb->hcpriv = u; + u->send(); return 0; } @@ -81,5 +105,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags) void usb_free_urb(struct urb *urb) { + if (!urb) + return; + + /* free 'Urb' object */ + if (urb->hcpriv) { + Urb *u = (Urb*)urb->hcpriv; + u->~Urb(); + kfree(urb->hcpriv); + } + kfree(urb); } diff --git a/repos/dde_linux/src/include/lx_kit/usb.h b/repos/dde_linux/src/include/lx_kit/usb.h index 73d2d1cb90..d9976b6cdd 100644 --- a/repos/dde_linux/src/include/lx_kit/usb.h +++ b/repos/dde_linux/src/include/lx_kit/usb.h @@ -27,6 +27,7 @@ class Urb : public Usb::Completion urb & _urb; Usb::Packet_descriptor _packet { _usb.source()->alloc_packet(_urb.transfer_buffer_length) }; + bool _completed { false }; public: @@ -79,6 +80,12 @@ class Urb : public Usb::Completion }; } + ~Urb() + { + if (!_completed) + _usb.source()->release_packet(_packet); + } + void send() { _usb.source()->submit_packet(_packet); @@ -88,6 +95,7 @@ class Urb : public Usb::Completion { if (packet.succeded) { bool ctrl = (usb_pipetype(_urb.pipe) == PIPE_CONTROL); + _urb.status = 0; _urb.actual_length = ctrl ? packet.control.actual_size : packet.transfer.actual_size; @@ -96,10 +104,44 @@ class Urb : public Usb::Completion Genode::memcpy(_urb.transfer_buffer, _usb.source()->packet_content(packet), _urb.actual_length); + } else { + _urb.actual_length = 0; + switch (packet.error) { + case Usb::Packet_descriptor::NO_ERROR: + Genode::error(__func__, ": got NO_ERROR code in error path"); + _urb.status = -EIO; + break; + case Usb::Packet_descriptor::INTERFACE_OR_ENDPOINT_ERROR: + _urb.status = -ENOENT; + break; + case Usb::Packet_descriptor::MEMORY_ERROR: + _urb.status = -ENOMEM; + break; + case Usb::Packet_descriptor::NO_DEVICE_ERROR: + _urb.status = -ESHUTDOWN; + break; + case Usb::Packet_descriptor::PACKET_INVALID_ERROR: + _urb.status = -EINVAL; + break; + case Usb::Packet_descriptor::PROTOCOL_ERROR: + _urb.status = -EPROTO; + break; + case Usb::Packet_descriptor::STALL_ERROR: + _urb.status = -EPIPE; + break; + case Usb::Packet_descriptor::TIMEOUT_ERROR: + _urb.status = -ETIMEDOUT; + break; + case Usb::Packet_descriptor::UNKNOWN_ERROR: + Genode::error(__func__, ": got UNKNOWN_ERROR code"); + _urb.status = -EIO; + break; + } } if (_urb.complete) _urb.complete(&_urb); - kfree(_packet.completion); + + _completed = true; } }; diff --git a/repos/os/include/usb_session/usb_session.h b/repos/os/include/usb_session/usb_session.h index a0e0309303..a097b0ffd7 100644 --- a/repos/os/include/usb_session/usb_session.h +++ b/repos/os/include/usb_session/usb_session.h @@ -82,7 +82,17 @@ struct Usb::Packet_descriptor : Genode::Packet_descriptor }; }; - enum Error { NO_ERROR, STALL_ERROR, SUBMIT_ERROR }; + enum Error { + NO_ERROR, + INTERFACE_OR_ENDPOINT_ERROR, + MEMORY_ERROR, + NO_DEVICE_ERROR, + PACKET_INVALID_ERROR, + PROTOCOL_ERROR, + STALL_ERROR, + TIMEOUT_ERROR, + UNKNOWN_ERROR + }; Error error = NO_ERROR;