summaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorKrzysztof Opasiak <kopasiak90@gmail.com>2017-01-19 18:55:27 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-03-12 06:44:16 +0100
commitafa9556b5fe6a5bf0ec95b02dd7e98fcf777aa41 (patch)
tree72a45290370fec6ad9dbdd6960f674a20183ce7b /drivers/usb
parent6be8bf7cbcc2b3308db0bd859fa6e9e17fad8c2a (diff)
downloadlinux-stable-afa9556b5fe6a5bf0ec95b02dd7e98fcf777aa41.tar.gz
linux-stable-afa9556b5fe6a5bf0ec95b02dd7e98fcf777aa41.tar.bz2
linux-stable-afa9556b5fe6a5bf0ec95b02dd7e98fcf777aa41.zip
usb: gadget: f_hid: fix: Free out requests
commit 20d2ca955bd09639c7b01db5761d157c297aea0a upstream. 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") Tested-by: David Lechner <david@lechnology.com> Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/function/f_hid.c32
1 files changed, 24 insertions, 8 deletions
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index 5f8139b8e601..62cf79815506 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -425,20 +425,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,