diff options
Diffstat (limited to 'drivers/input/misc/yealink.c')
-rw-r--r-- | drivers/input/misc/yealink.c | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/drivers/input/misc/yealink.c b/drivers/input/misc/yealink.c index 46279ef2b64..facefd3dba2 100644 --- a/drivers/input/misc/yealink.c +++ b/drivers/input/misc/yealink.c @@ -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", __FUNCTION__, urb->status); + if (status) + err("%s - urb status %d", __func__, status); switch (yld->irq_data->cmd) { case CMD_KEYPRESS: @@ -447,33 +449,38 @@ static void urb_irq_callback(struct urb *urb) yealink_do_idle_tasks(yld); - ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); - if (ret) - err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); + if (!yld->shutdown) { + ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); + 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", __FUNCTION__, 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 */ - ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC); + if (!yld->shutdown) + ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC); break; default: /* send new command */ yealink_do_idle_tasks(yld); - ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); + if (!yld->shutdown) + ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC); + break; } - if (ret) - err("%s - usb_submit_urb failed %d", __FUNCTION__, ret); + if (ret && ret != -EPERM) + err("%s - usb_submit_urb failed %d", __func__, ret); } /******************************************************************************* @@ -505,7 +512,7 @@ static int input_open(struct input_dev *dev) struct yealink_dev *yld = input_get_drvdata(dev); int i, ret; - dbg("%s", __FUNCTION__); + dbg("%s", __func__); /* force updates to device */ for (i = 0; i<sizeof(yld->master); i++) @@ -521,7 +528,7 @@ static int input_open(struct input_dev *dev) yld->ctl_data->sum = 0x100-CMD_INIT-10; if ((ret = usb_submit_urb(yld->urb_ctl, GFP_KERNEL)) != 0) { dbg("%s - usb_submit_urb failed with result %d", - __FUNCTION__, ret); + __func__, ret); return ret; } return 0; @@ -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); |