Requests for out endpoint are allocated in bind() function
but never released.

This commit ensures that all pending requests are released
when we disable out endpoint.

Fixes: 99c515005857 ("usb: gadget: hidg: register OUT INT endpoint for 
SET_REPORT")
Cc: sta...@vger.kernel.org
Signed-off-by: Krzysztof Opasiak <k.opas...@samsung.com>
---
 drivers/usb/gadget/function/f_hid.c | 32 ++++++++++++++++++++++++--------
 1 file changed, 24 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/gadget/function/f_hid.c 
b/drivers/usb/gadget/function/f_hid.c
index e2966f8..ceb1d0c 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -371,20 +371,36 @@ static inline struct usb_request 
*hidg_alloc_ep_req(struct usb_ep *ep,
 static void hidg_set_report_complete(struct usb_ep *ep, struct usb_request 
*req)
 {
        struct f_hidg *hidg = (struct f_hidg *) req->context;
+       struct usb_composite_dev *cdev = hidg->func.config->cdev;
        struct f_hidg_req_list *req_list;
        unsigned long flags;
 
-       req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC);
-       if (!req_list)
-               return;
+       switch (req->status) {
+       case 0:
+               req_list = kzalloc(sizeof(*req_list), GFP_ATOMIC);
+               if (!req_list) {
+                       ERROR(cdev, "Unable to allocate mem for req_list\n");
+                       goto free_req;
+               }
 
-       req_list->req = req;
+               req_list->req = req;
 
-       spin_lock_irqsave(&hidg->spinlock, flags);
-       list_add_tail(&req_list->list, &hidg->completed_out_req);
-       spin_unlock_irqrestore(&hidg->spinlock, flags);
+               spin_lock_irqsave(&hidg->spinlock, flags);
+               list_add_tail(&req_list->list, &hidg->completed_out_req);
+               spin_unlock_irqrestore(&hidg->spinlock, flags);
 
-       wake_up(&hidg->read_queue);
+               wake_up(&hidg->read_queue);
+               break;
+       default:
+               ERROR(cdev, "Set report failed %d\n", req->status);
+               /* FALLTHROUGH */
+       case -ECONNABORTED:             /* hardware forced ep reset */
+       case -ECONNRESET:               /* request dequeued */
+       case -ESHUTDOWN:                /* disconnect from host */
+free_req:
+               free_ep_req(ep, req);
+               return;
+       }
 }
 
 static int hidg_setup(struct usb_function *f,
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to