]> rtime.felk.cvut.cz Git - zynq/linux.git/commitdiff
Input: pxrc - fix freeing URB on device teardown
authorDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 18 Jul 2018 18:03:36 +0000 (18:03 +0000)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Wed, 25 Jul 2018 19:04:15 +0000 (19:04 +0000)
URB is the only resource that is not managed, and thus is destroyed too early,
before we unregister input device and stop URB in pxrc_close(). To fix it let's
install custom devm handler to free the URB at the right time in devm unwind
sequence.

Reviewed-by: Marcus Folkesson <marcus.folkesson@gmail.com>
Tested-by: Marcus Folkesson <marcus.folkesson@gmail.com>
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/joystick/pxrc.c

index 000b9b7da744643bfb1fa552b5d2ff6493c16f83..1560f0e39c3446e782da1118a0a3cbe551a81a8b 100644 (file)
@@ -119,49 +119,52 @@ static void pxrc_close(struct input_dev *input)
        mutex_unlock(&pxrc->pm_mutex);
 }
 
+static void pxrc_free_urb(void *_pxrc)
+{
+       struct pxrc *pxrc = _pxrc;
+
+       usb_free_urb(pxrc->urb);
+}
+
 static int pxrc_usb_init(struct pxrc *pxrc)
 {
        struct usb_device *udev = interface_to_usbdev(pxrc->intf);
        struct usb_endpoint_descriptor *epirq;
        unsigned int pipe;
-       int retval;
+       int error;
 
        /* Set up the endpoint information */
        /* This device only has an interrupt endpoint */
-       retval = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
-                       NULL, NULL, &epirq, NULL);
-       if (retval) {
-               dev_err(&pxrc->intf->dev,
-                       "Could not find endpoint\n");
-               goto error;
+       error = usb_find_common_endpoints(pxrc->intf->cur_altsetting,
+                                         NULL, NULL, &epirq, NULL);
+       if (error) {
+               dev_err(&pxrc->intf->dev, "Could not find endpoint\n");
+               return error;
        }
 
        pxrc->bsize = usb_endpoint_maxp(epirq);
        pxrc->epaddr = epirq->bEndpointAddress;
        pxrc->data = devm_kmalloc(&pxrc->intf->dev, pxrc->bsize, GFP_KERNEL);
-       if (!pxrc->data) {
-               retval = -ENOMEM;
-               goto error;
-       }
+       if (!pxrc->data)
+               return -ENOMEM;
 
        usb_set_intfdata(pxrc->intf, pxrc);
        usb_make_path(udev, pxrc->phys, sizeof(pxrc->phys));
        strlcat(pxrc->phys, "/input0", sizeof(pxrc->phys));
 
        pxrc->urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!pxrc->urb) {
-               retval = -ENOMEM;
-               goto error;
-       }
+       if (!pxrc->urb)
+               return -ENOMEM;
+
+       error = devm_add_action_or_reset(&pxrc->intf->dev, pxrc_free_urb, pxrc);
+       if (error)
+               return error;
 
        pipe = usb_rcvintpipe(udev, pxrc->epaddr),
        usb_fill_int_urb(pxrc->urb, udev, pipe, pxrc->data, pxrc->bsize,
                         pxrc_usb_irq, pxrc, 1);
 
-error:
-       return retval;
-
-
+       return 0;
 }
 
 static int pxrc_input_init(struct pxrc *pxrc)
@@ -197,7 +200,7 @@ static int pxrc_probe(struct usb_interface *intf,
                      const struct usb_device_id *id)
 {
        struct pxrc *pxrc;
-       int retval;
+       int error;
 
        pxrc = devm_kzalloc(&intf->dev, sizeof(*pxrc), GFP_KERNEL);
        if (!pxrc)
@@ -206,29 +209,20 @@ static int pxrc_probe(struct usb_interface *intf,
        mutex_init(&pxrc->pm_mutex);
        pxrc->intf = intf;
 
-       retval = pxrc_usb_init(pxrc);
-       if (retval)
-               goto error;
+       error = pxrc_usb_init(pxrc);
+       if (error)
+               return error;
 
-       retval = pxrc_input_init(pxrc);
-       if (retval)
-               goto err_free_urb;
+       error = pxrc_input_init(pxrc);
+       if (error)
+               return error;
 
        return 0;
-
-err_free_urb:
-       usb_free_urb(pxrc->urb);
-
-error:
-       return retval;
 }
 
 static void pxrc_disconnect(struct usb_interface *intf)
 {
-       struct pxrc *pxrc = usb_get_intfdata(intf);
-
-       usb_free_urb(pxrc->urb);
-       usb_set_intfdata(intf, NULL);
+       /* All driver resources are devm-managed. */
 }
 
 static int pxrc_suspend(struct usb_interface *intf, pm_message_t message)