Re: [patch]reliably killing urbs in yealink driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Am Samstag 28 Juni 2008 17:11:17 schrieb Alfred E. Heggestad:
> Oliver Neukum wrote:
> > Hi,
> > 
> > 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.
> > 
> 
> Hi Oliver,
> 
> just a small comments about this patch;
> 
> - the declaration of 'spin' and 'shutdown' is missing,
>    and hence the module does not build.
> 
> something like this should be added to struct yealink_dev:
> 
>          spinlock_t spin;
>          char shutdown:1;
> 

Very true. My testing environment was bad. Dmitry, please ignore
the original patch, here's a working patch.

	Regards
		Oliver

Signed-off-by: Oliver Neukum <oneukum@xxxxxxx>

---

--- linux-2.6.26-sierra/drivers/input/misc/yealink.alt.c	2008-06-24 10:17:14.000000000 +0200
+++ linux-2.6.26-sierra/drivers/input/misc/yealink.c	2008-06-30 14:02:17.000000000 +0200
@@ -101,6 +101,7 @@ static const struct lcd_segment_map {
 struct yealink_dev {
 	struct input_dev *idev;		/* input device */
 	struct usb_device *udev;	/* usb device */
+	spinlock_t spin;
 
 	/* irq input channel */
 	struct yld_ctl_packet	*irq_data;
@@ -118,6 +119,7 @@ struct yealink_dev {
 
 	u8 lcdMap[ARRAY_SIZE(lcdMap)];	/* state of LCD, LED ... */
 	int key_code;			/* last reported key	 */
+	int shutdown:1;
 
 	int	stat_ix;
 	union {
@@ -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:
@@ -446,34 +448,43 @@ static void urb_irq_callback(struct 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);
+	spin_lock(&yld->spin);
+	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);
+	}
+	spin_unlock(&yld->spin);
 }
 
 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);
+		spin_lock(&yld->spin);
+		if (!yld->shutdown)
+			ret = usb_submit_urb(yld->urb_irq, GFP_ATOMIC);
+		spin_unlock(&yld->spin);
 		break;
 	default:
 		/* send new command */
 		yealink_do_idle_tasks(yld);
-		ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+		spin_lock(&yld->spin);
+		if (!yld->shutdown)
+			ret = usb_submit_urb(yld->urb_ctl, GFP_ATOMIC);
+		spin_unlock(&yld->spin);
 	}
 
-	if (ret)
-		err("%s - usb_submit_urb failed %d", __FUNCTION__, ret);
+	if (ret && ret != -EPERM)
+		err("%s - usb_submit_urb failed %d", __func__, ret);
 }
 
 /*******************************************************************************
@@ -527,12 +538,25 @@ static int input_open(struct input_dev *
 	return 0;
 }
 
-static void input_close(struct input_dev *dev)
+static void stop_traffic(struct yealink_dev *yld)
 {
-	struct yealink_dev *yld = input_get_drvdata(dev);
+	spin_lock_irq(&yld->spin);
+	yld->shutdown = 1;
+	spin_unlock_irq(&yld->spin);
 
 	usb_kill_urb(yld->urb_ctl);
 	usb_kill_urb(yld->urb_irq);
+
+	spin_lock_irq(&yld->spin);
+	yld->shutdown = 0;
+	spin_unlock_irq(&yld->spin);
+}
+
+static void input_close(struct input_dev *dev)
+{
+	struct yealink_dev *yld = input_get_drvdata(dev);
+
+	stop_traffic(yld);
 }
 
 /*******************************************************************************
@@ -809,8 +833,7 @@ static int usb_cleanup(struct yealink_de
 	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 */
+	stop_traffic(yld);
 
         if (yld->idev) {
 		if (err)
@@ -866,6 +889,7 @@ static int usb_probe(struct usb_interfac
 		return -ENOMEM;
 
 	yld->udev = udev;
+	spin_lock_init(&yld->spin);
 
 	yld->idev = input_dev = input_allocate_device();
 	if (!input_dev)
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media Devel]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Linux Wireless Networking]     [Linux Omap]

  Powered by Linux