Commit 4f208d4e authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] dvb_usb_v2: refactor delayed init

Move work to the struct dvb_usb_device that we can access
it inside .disconnect().

Also many other minor changes.
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0a867356
...@@ -358,6 +358,8 @@ struct dvb_usb_device { ...@@ -358,6 +358,8 @@ struct dvb_usb_device {
const char *rc_map; const char *rc_map;
struct dvb_usb_rc rc; struct dvb_usb_rc rc;
struct usb_device *udev; struct usb_device *udev;
struct work_struct probe_work;
struct usb_interface *intf;
#define DVB_USB_STATE_INIT 0x000 #define DVB_USB_STATE_INIT 0x000
#define DVB_USB_STATE_I2C 0x001 #define DVB_USB_STATE_I2C 0x001
......
...@@ -251,44 +251,29 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff) ...@@ -251,44 +251,29 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
/* /*
* USB * USB
*/ */
int dvb_usbv2_device_init_(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct dvb_usb_device *d = NULL;
struct dvb_usb_driver_info *driver_info =
(struct dvb_usb_driver_info *) id->driver_info;
const struct dvb_usb_device_properties *props;
int ret = -ENOMEM;
bool cold = false;
if (!id->driver_info) {
pr_err("%s: driver_info is null", KBUILD_MODNAME);
ret = -ENODEV;
goto err;
}
props = driver_info->props; /*
* udev, which is used for the firmware downloading, requires we cannot
* block during module_init(). module_init() calls USB probe() which
* is this routine. Due to that we delay actual operation using workqueue
* and return always success here.
*/
d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL); static void dvb_usbv2_init_work(struct work_struct *work)
if (d == NULL) { {
err("no memory for 'struct dvb_usb_device'"); int ret;
return -ENOMEM; struct dvb_usb_device *d =
} container_of(work, struct dvb_usb_device, probe_work);
bool cold = false;
d->udev = udev; pr_debug("%s:\n", __func__);
d->name = driver_info->name;
d->rc_map = driver_info->rc_map;
memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
mutex_init(&d->usb_mutex);
mutex_init(&d->i2c_mutex);
if (d->props.size_of_priv > 0) { if (d->props.size_of_priv) {
d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL); d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
if (d->priv == NULL) { if (!d->priv) {
err("no memory for priv in 'struct dvb_usb_device'"); pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME);
ret = -ENOMEM; ret = -ENOMEM;
goto err_kfree; goto err_usb_driver_release_interface;
} }
} }
...@@ -300,77 +285,41 @@ int dvb_usbv2_device_init_(struct usb_interface *intf, ...@@ -300,77 +285,41 @@ int dvb_usbv2_device_init_(struct usb_interface *intf,
cold = true; cold = true;
ret = 0; ret = 0;
} else { } else {
goto err_kfree; goto err_usb_driver_release_interface;
} }
} }
if (cold) { if (cold) {
info("found a '%s' in cold state, will try to load a firmware", pr_info("%s: found a '%s' in cold state\n",
d->name); KBUILD_MODNAME, d->name);
ret = dvb_usb_download_firmware(d); ret = dvb_usb_download_firmware(d);
if (ret == 0) { if (ret == 0) {
; ;
} else if (ret == RECONNECTS_USB) { } else if (ret == RECONNECTS_USB) {
ret = 0; ret = 0;
goto err_kfree; goto exit_usb_driver_release_interface;
} else { } else {
goto err_kfree; goto err_usb_driver_release_interface;
} }
} }
info("found a '%s' in warm state.", d->name); pr_info("%s: found a '%s' in warm state\n", KBUILD_MODNAME, d->name);
usb_set_intfdata(intf, d);
ret = dvb_usb_init(d); ret = dvb_usb_init(d);
if (ret < 0)
goto err_usb_driver_release_interface;
if (ret == 0) pr_info("%s: '%s' successfully initialized and connected\n",
info("%s successfully initialized and connected.", d->name); KBUILD_MODNAME, d->name);
else
info("%s error while loading driver (%d)", d->name, ret);
return 0;
err_kfree:
kfree(d->priv);
kfree(d);
err:
pr_debug("%s: failed=%d\n", __func__, ret);
return ret;
}
/*
* udev, which is used for the firmware downloading, requires we cannot
* block during module_init(). module_init() calls USB probe() which
* is this routine. Due to that we delay actual operation using workqueue
* and return always success here.
*/
struct dvb_usb_delayed_init {
struct usb_interface *intf;
const struct usb_device_id *id;
struct work_struct work;
};
static void dvb_usbv2_init_work(struct work_struct *work)
{
int ret;
struct dvb_usb_delayed_init *delayed_init =
container_of(work, struct dvb_usb_delayed_init, work);
ret = dvb_usbv2_device_init_(delayed_init->intf, delayed_init->id);
if (ret < 0) {
usb_driver_release_interface(
to_usb_driver(delayed_init->intf->dev.driver),
delayed_init->intf);
kfree(delayed_init);
goto err;
}
kfree(delayed_init);
return; return;
err: err_usb_driver_release_interface:
pr_info("%s: '%s' error while loading driver (%d)\n", KBUILD_MODNAME,
d->name, ret);
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: failed=%d\n", __func__, ret);
return; return;
} }
...@@ -379,28 +328,45 @@ int dvb_usbv2_device_init(struct usb_interface *intf, ...@@ -379,28 +328,45 @@ int dvb_usbv2_device_init(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
int ret; int ret;
struct dvb_usb_delayed_init *delayed_init; struct dvb_usb_device *d;
struct dvb_usb_driver_info *driver_info =
(struct dvb_usb_driver_info *) id->driver_info;
delayed_init = kzalloc(sizeof(struct dvb_usb_delayed_init), GFP_KERNEL); pr_debug("%s:\n", __func__);
if (!delayed_init) {
pr_err("%s: kzalloc() failed", DVB_USB_LOG_PREFIX); if (!id->driver_info) {
ret = -ENOMEM; pr_err("%s: driver_info failed\n", KBUILD_MODNAME);
ret = -ENODEV;
goto err; goto err;
} }
delayed_init->intf = intf; d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
delayed_init->id = id; if (!d) {
INIT_WORK(&delayed_init->work, dvb_usbv2_init_work); pr_err("%s: kzalloc() failed\n", KBUILD_MODNAME);
ret = -ENOMEM;
goto err;
}
ret = schedule_work(&delayed_init->work); d->name = driver_info->name;
d->rc_map = driver_info->rc_map;
d->udev = interface_to_usbdev(intf);
d->intf = intf;
memcpy(&d->props, driver_info->props,
sizeof(struct dvb_usb_device_properties));
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);
if (ret < 0) { if (ret < 0) {
pr_err("%s: schedule_work() failed", DVB_USB_LOG_PREFIX); pr_err("%s: schedule_work() failed\n", KBUILD_MODNAME);
goto err_kfree; goto err_kfree;
} }
return 0; return 0;
err_kfree: err_kfree:
kfree(delayed_init); usb_set_intfdata(intf, NULL);
kfree(d);
err: err:
pr_debug("%s: failed=%d\n", __func__, ret); pr_debug("%s: failed=%d\n", __func__, ret);
return ret; return ret;
...@@ -413,9 +379,14 @@ void dvb_usbv2_device_exit(struct usb_interface *intf) ...@@ -413,9 +379,14 @@ void dvb_usbv2_device_exit(struct usb_interface *intf)
struct dvb_usb_device *d = usb_get_intfdata(intf); struct dvb_usb_device *d = usb_get_intfdata(intf);
const char *name = "generic DVB-USB module"; const char *name = "generic DVB-USB module";
pr_debug("%s:\n", __func__);
/* /*
* FIXME: we should ensure our device initialization work is finished * FIXME: We should ensure initialization work is finished
* until exit from this routine (cancel_work_sync?) * until exit from this routine (cancel_work_sync / flush_work).
* Unfortunately usb_driver_release_interface() call finally goes
* here too and in that case we endup deadlock. How to perform
* operation conditionally only on disconned / unload?
*/ */
usb_set_intfdata(intf, NULL); usb_set_intfdata(intf, NULL);
...@@ -423,7 +394,9 @@ void dvb_usbv2_device_exit(struct usb_interface *intf) ...@@ -423,7 +394,9 @@ void dvb_usbv2_device_exit(struct usb_interface *intf)
name = d->name; name = d->name;
dvb_usb_exit(d); dvb_usb_exit(d);
} }
info("%s successfully deinitialized and disconnected.", name);
pr_info("%s: '%s' successfully deinitialized and disconnected\n",
KBUILD_MODNAME, name);
} }
EXPORT_SYMBOL(dvb_usbv2_device_exit); EXPORT_SYMBOL(dvb_usbv2_device_exit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment