diff options
author | Krzysztof Opasiak <kopasiak90@gmail.com> | 2017-01-19 18:55:27 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-03-12 06:44:16 +0100 |
commit | afa9556b5fe6a5bf0ec95b02dd7e98fcf777aa41 (patch) | |
tree | 72a45290370fec6ad9dbdd6960f674a20183ce7b /drivers/usb | |
parent | 6be8bf7cbcc2b3308db0bd859fa6e9e17fad8c2a (diff) | |
download | linux-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.c | 32 |
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, |