Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b4ecda3e authored by Oliver Neukum's avatar Oliver Neukum Committed by Dmitry Torokhov
Browse files

Input: yealink - reliably kill urbs



Yealink uses two URBs that submit each other. This arrangement
cannot be reliably killed with usb_kill_urb() alone, as there's
a window during which the wrong URB may be killed. The fix is
to introduce a flag.

[dtor@mail.ru: remove spinlock, flag alone should be enough]
Signed-off-by: default avatarOliver Neukum <oneukum@suse.de>
Signed-off-by: default avatarDmitry Torokhov <dtor@mail.ru>
parent 4ad88901
Loading
Loading
Loading
Loading
+29 −15
Original line number Diff line number Diff line
@@ -119,6 +119,8 @@ struct yealink_dev {
	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
	int key_code;			/* last reported key	 */

	unsigned int shutdown:1;

	int	stat_ix;
	union {
		struct yld_status s;
@@ -424,10 +426,10 @@ send_update:
static void urb_irq_callback(struct urb *urb)
{
	struct yealink_dev *yld = urb->context;
	int ret;
	int ret, status = urb->status;

	if (urb->status)
		err("%s - urb status %d", __func__, urb->status);
	if (status)
		err("%s - urb status %d", __func__, status);

	switch (yld->irq_data->cmd) {
	case CMD_KEYPRESS:
@@ -447,32 +449,37 @@ static void urb_irq_callback(struct urb *urb)

	yealink_do_idle_tasks(yld);

	if (!yld->shutdown) {
		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
	if (ret)
		if (ret && ret != -EPERM)
			err("%s - usb_submit_urb failed %d", __func__, ret);
	}
}

static void urb_ctl_callback(struct urb *urb)
{
	struct yealink_dev *yld = urb->context;
	int ret;
	int ret = 0, status = urb->status;

	if (urb->status)
		err("%s - urb status %d", __func__, urb->status);
	if (status)
		err("%s - urb status %d", __func__, status);

	switch (yld->ctl_data->cmd) {
	case CMD_KEYPRESS:
	case CMD_SCANCODE:
		/* ask for a response */
		if (!yld->shutdown)
			ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
		break;
	default:
		/* send new command */
		yealink_do_idle_tasks(yld);
		if (!yld->shutdown)
			ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
		break;
	}

	if (ret)
	if (ret && ret != -EPERM)
		err("%s - usb_submit_urb failed %d", __func__, ret);
}

@@ -531,8 +538,18 @@ static void input_close(struct input_dev *dev)
{
	struct yealink_dev *yld = input_get_drvdata(dev);

	yld->shutdown = 1;
	/*
	 * Make sure the flag is seen by other CPUs before we start
	 * killing URBs so new URBs won't be submitted
	 */
	smp_wmb();

	usb_kill_urb(yld->urb_ctl);
	usb_kill_urb(yld->urb_irq);

	yld->shutdown = 0;
	smp_wmb();
}

/*******************************************************************************
@@ -809,9 +826,6 @@ static int usb_cleanup(struct yealink_dev *yld, int err)
	if (yld == NULL)
		return err;

	usb_kill_urb(yld->urb_irq);	/* parameter validation in core/urb */
	usb_kill_urb(yld->urb_ctl);	/* parameter validation in core/urb */

        if (yld->idev) {
		if (err)
			input_free_device(yld->idev);