[PATCH] dvb_usb_v2 [RFC] draft use delayed work.

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

 



dvb_usb_v2 [RFC] use delayed work.

The problem with an ordinary work queue it executes immediately.

changes made
1. Three extra states added DVB_USB_STATE_PROBE, DVB_USB_STATE_COLD
	and DVB_USB_STATE_WARM.
2. Initialise of priv moved to probe this shouldn't really be done in the
	work queue.
3. The initial delay 200ms waits for the probe to clear.
4. State DVB_USB_STATE_PROBE checks for interface to be BOUND then calls the 
	identify_state(possibly extra timeout signals needed if binding fails).
5. The next schedule time now increases to 500ms execution following as before
	with state changing accordingly.
6. DVB_USB_STATE_INIT uses the value of 0x7 so clears the other states.

The work queue then dies forever. However, it could continue on as the remote work.


Signed-off-by: Malcolm Priestley <tvboxspy@xxxxxxxxx>

---
 drivers/media/dvb/dvb-usb/dvb_usb.h      |   13 ++--
 drivers/media/dvb/dvb-usb/dvb_usb_init.c |  117 ++++++++++++++++--------------
 2 files changed, 69 insertions(+), 61 deletions(-)

diff --git a/drivers/media/dvb/dvb-usb/dvb_usb.h b/drivers/media/dvb/dvb-usb/dvb_usb.h
index b443817..cdd3e7f 100644
--- a/drivers/media/dvb/dvb-usb/dvb_usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb_usb.h
@@ -321,14 +321,17 @@ struct dvb_usb_device {
 	const char *rc_map;
 	struct dvb_usb_rc rc;
 	struct usb_device *udev;
-	struct work_struct probe_work;
+	struct delayed_work probe_work;
 	pid_t work_pid;
 	struct usb_interface *intf;
+#define DVB_USB_STATE_PROBE	0x00
+#define DVB_USB_STATE_COLD	0x01
+#define DVB_USB_STATE_WARM	0x03
+#define DVB_USB_STATE_INIT	0x07
+#define DVB_USB_STATE_I2C	0x08
+#define DVB_USB_STATE_DVB	0x10
+#define DVB_USB_STATE_REMOTE	0x20
 
-#define DVB_USB_STATE_INIT        0x000
-#define DVB_USB_STATE_I2C         0x001
-#define DVB_USB_STATE_DVB         0x002
-#define DVB_USB_STATE_REMOTE      0x004
 	int state;
 
 	int powered;
diff --git a/drivers/media/dvb/dvb-usb/dvb_usb_init.c b/drivers/media/dvb/dvb-usb/dvb_usb_init.c
index b2eb8ac..ddb052d 100644
--- a/drivers/media/dvb/dvb-usb/dvb_usb_init.c
+++ b/drivers/media/dvb/dvb-usb/dvb_usb_init.c
@@ -212,7 +212,7 @@ static int dvb_usb_exit(struct dvb_usb_device *d)
 	dvb_usb_adapter_exit(d);
 	dvb_usb_i2c_exit(d);
 	pr_debug("%s: state should be zero now: %x\n", __func__, d->state);
-	d->state = DVB_USB_STATE_INIT;
+	d->state &= ~DVB_USB_STATE_INIT;
 	kfree(d->priv);
 	kfree(d);
 
@@ -291,61 +291,54 @@ err:
  * and return always success here.
  */
 
+#define INIT_WORK_TIMEOUT 200
+#define CONT_WORK_TIMEOUT 500
+
 static void dvb_usbv2_init_work(struct work_struct *work)
 {
 	int ret;
-	struct dvb_usb_device *d =
-			container_of(work, struct dvb_usb_device, probe_work);
-	bool cold = false;
-
-	d->work_pid = current->pid;
-
-	pr_debug("%s: work_pid=%d\n", __func__, d->work_pid);
-
-	if (d->props.size_of_priv) {
-		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
-		if (!d->priv) {
-			pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME);
-			ret = -ENOMEM;
-			goto err_usb_driver_release_interface;
+	struct dvb_usb_device *d = container_of(work,
+		struct dvb_usb_device, probe_work.work);
+
+	switch (d->state) {
+	case DVB_USB_STATE_PROBE:
+		if (d->intf->condition != USB_INTERFACE_BOUND) {
+			pr_info("Waiting for Interface\n");
+			break;
 		}
-	}
-
-	if (d->props.identify_state) {
-		ret = d->props.identify_state(d);
-		if (ret == 0) {
-			;
-		} else if (ret == COLD) {
-			cold = true;
-			ret = 0;
-		} else {
-			goto err_usb_driver_release_interface;
-		}
-	}
-
-	if (cold) {
+		if (d->props.identify_state) {
+			ret = d->props.identify_state(d);
+			if (ret == 0)
+				d->state |= DVB_USB_STATE_WARM;
+			else if (ret == COLD)
+				d->state |= DVB_USB_STATE_COLD;
+			else
+				goto err_usb_driver_release_interface;
+		} else
+			d->state = DVB_USB_STATE_WARM;
+		break;
+	case DVB_USB_STATE_COLD:
 		pr_info("%s: found a '%s' in cold state\n",
 				KBUILD_MODNAME, d->name);
 		ret = dvb_usb_download_firmware(d);
-		if (ret == 0) {
-			;
-		} else if (ret == RECONNECTS_USB) {
-			ret = 0;
+		if (ret == 0)
+			d->state |= DVB_USB_STATE_WARM;
+		else if (ret == RECONNECTS_USB)
 			goto exit_usb_driver_release_interface;
-		} else {
+		else
 			goto err_usb_driver_release_interface;
-		}
-	}
-
-	pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name);
-
-	ret = dvb_usb_init(d);
-	if (ret < 0)
-		goto err_usb_driver_release_interface;
-
-	pr_info("%s: '%s' successfully initialized and connected\n",
+	case DVB_USB_STATE_WARM:
+		pr_info("%s: found a '%s' in warm state\n",
 			KBUILD_MODNAME, d->name);
-
+		ret = dvb_usb_init(d);
+		if (ret < 0)
+			goto err_usb_driver_release_interface;
+		pr_info("%s: '%s' successfully initialized and connected\n",
+				KBUILD_MODNAME, d->name);
+		return;
+	}
+	schedule_delayed_work(&d->probe_work,
+		msecs_to_jiffies(CONT_WORK_TIMEOUT));
 	return;
 err_usb_driver_release_interface:
 	pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME,
@@ -354,7 +347,7 @@ exit_usb_driver_release_interface:
 	/* it finally calls .disconnect() which frees mem */
 	usb_driver_release_interface(to_usb_driver(d->intf->dev.driver),
 			d->intf);
-	pr_debug("%s: failed=%d\n", __func__, ret);
+	pr_debug("%s: driver released=%d\n", __func__, ret);
 	return;
 }
 
@@ -402,17 +395,32 @@ int dvb_usbv2_probe(struct usb_interface *intf,
 		}
 	}
 
+	if (d->props.size_of_priv) {
+		d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
+		if (!d->priv) {
+			pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME);
+			ret = -ENOMEM;
+			goto err_pfree;
+		}
+	}
+
+	usb_set_intfdata(intf, d);
+
+	INIT_DELAYED_WORK(&d->probe_work, dvb_usbv2_init_work);
+
 	mutex_init(&d->usb_mutex);
 	mutex_init(&d->i2c_mutex);
-	INIT_WORK(&d->probe_work, dvb_usbv2_init_work);
-	usb_set_intfdata(intf, d);
-	ret = schedule_work(&d->probe_work);
+
+	ret = schedule_delayed_work(&d->probe_work,
+		msecs_to_jiffies(INIT_WORK_TIMEOUT));
 	if (ret < 0) {
-		pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME);
+		pr_err("%s: schedule_delayed_work() failed\n", KBUILD_MODNAME);
 		goto err_kfree;
 	}
 
 	return 0;
+err_pfree:
+	kfree(d->priv);
 err_kfree:
 	kfree(d);
 err:
@@ -426,12 +434,9 @@ void dvb_usbv2_disconnect(struct usb_interface *intf)
 	struct dvb_usb_device *d = usb_get_intfdata(intf);
 	const char *name;
 
-	pr_debug("%s: pid=%d work_pid=%d\n", __func__, current->pid,
-			d->work_pid);
-
 	/* ensure initialization work is finished until release resources */
-	if (d->work_pid != current->pid)
-		cancel_work_sync(&d->probe_work);
+	if (d->state < DVB_USB_STATE_INIT)
+		cancel_delayed_work_sync(&d->probe_work);
 
 	if (d->props.disconnect)
 		d->props.disconnect(d);
-- 
1.7.10










--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux