Input: pxrc - fix freeing URB on device teardown

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>
This commit is contained in:
Dmitry Torokhov 2018-07-18 18:03:36 +00:00
parent 9730f60888
commit 34dad2cf11

View 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)