[PATCH] modified firmware_class.c to support no hotplug

Upgrade the request_firmware_nowait function to not start the hotplug
action on a firmware update.

This patch is tested along with dell_rbu driver on i386 and x86-64 systems.

Signed-off-by: Abhay Salunke <Abhay_Salunke@dell.com>
Cc: Greg KH <greg@kroah.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Abhay Salunke 2005-09-06 15:17:13 -07:00 committed by Linus Torvalds
parent f3ef6f63e5
commit 6e3eaab020
2 changed files with 54 additions and 30 deletions

View file

@ -28,6 +28,7 @@ enum {
FW_STATUS_DONE, FW_STATUS_DONE,
FW_STATUS_ABORT, FW_STATUS_ABORT,
FW_STATUS_READY, FW_STATUS_READY,
FW_STATUS_READY_NOHOTPLUG,
}; };
static int loading_timeout = 10; /* In seconds */ static int loading_timeout = 10; /* In seconds */
@ -344,7 +345,7 @@ error_kfree:
static int static int
fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p, fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
const char *fw_name, struct device *device) const char *fw_name, struct device *device, int hotplug)
{ {
struct class_device *class_dev; struct class_device *class_dev;
struct firmware_priv *fw_priv; struct firmware_priv *fw_priv;
@ -376,7 +377,10 @@ fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
goto error_unreg; goto error_unreg;
} }
if (hotplug)
set_bit(FW_STATUS_READY, &fw_priv->status); set_bit(FW_STATUS_READY, &fw_priv->status);
else
set_bit(FW_STATUS_READY_NOHOTPLUG, &fw_priv->status);
*class_dev_p = class_dev; *class_dev_p = class_dev;
goto out; goto out;
@ -386,6 +390,65 @@ out:
return retval; return retval;
} }
static int
_request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device, int hotplug)
{
struct class_device *class_dev;
struct firmware_priv *fw_priv;
struct firmware *firmware;
int retval;
if (!firmware_p)
return -EINVAL;
*firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
__FUNCTION__);
retval = -ENOMEM;
goto out;
}
memset(firmware, 0, sizeof (*firmware));
retval = fw_setup_class_device(firmware, &class_dev, name, device,
hotplug);
if (retval)
goto error_kfree_fw;
fw_priv = class_get_devdata(class_dev);
if (hotplug) {
if (loading_timeout > 0) {
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
add_timer(&fw_priv->timeout);
}
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
wait_for_completion(&fw_priv->completion);
set_bit(FW_STATUS_DONE, &fw_priv->status);
del_timer_sync(&fw_priv->timeout);
} else
wait_for_completion(&fw_priv->completion);
down(&fw_lock);
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
retval = -ENOENT;
release_firmware(fw_priv->fw);
*firmware_p = NULL;
}
fw_priv->fw = NULL;
up(&fw_lock);
class_device_unregister(class_dev);
goto out;
error_kfree_fw:
kfree(firmware);
*firmware_p = NULL;
out:
return retval;
}
/** /**
* request_firmware: - request firmware to hotplug and wait for it * request_firmware: - request firmware to hotplug and wait for it
* Description: * Description:
@ -402,56 +465,8 @@ int
request_firmware(const struct firmware **firmware_p, const char *name, request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device) struct device *device)
{ {
struct class_device *class_dev; int hotplug = 1;
struct firmware_priv *fw_priv; return _request_firmware(firmware_p, name, device, hotplug);
struct firmware *firmware;
int retval;
if (!firmware_p)
return -EINVAL;
*firmware_p = firmware = kmalloc(sizeof (struct firmware), GFP_KERNEL);
if (!firmware) {
printk(KERN_ERR "%s: kmalloc(struct firmware) failed\n",
__FUNCTION__);
retval = -ENOMEM;
goto out;
}
memset(firmware, 0, sizeof (*firmware));
retval = fw_setup_class_device(firmware, &class_dev, name, device);
if (retval)
goto error_kfree_fw;
fw_priv = class_get_devdata(class_dev);
if (loading_timeout > 0) {
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
add_timer(&fw_priv->timeout);
}
kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
wait_for_completion(&fw_priv->completion);
set_bit(FW_STATUS_DONE, &fw_priv->status);
del_timer_sync(&fw_priv->timeout);
down(&fw_lock);
if (!fw_priv->fw->size || test_bit(FW_STATUS_ABORT, &fw_priv->status)) {
retval = -ENOENT;
release_firmware(fw_priv->fw);
*firmware_p = NULL;
}
fw_priv->fw = NULL;
up(&fw_lock);
class_device_unregister(class_dev);
goto out;
error_kfree_fw:
kfree(firmware);
*firmware_p = NULL;
out:
return retval;
} }
/** /**
@ -491,6 +506,7 @@ struct firmware_work {
struct device *device; struct device *device;
void *context; void *context;
void (*cont)(const struct firmware *fw, void *context); void (*cont)(const struct firmware *fw, void *context);
int hotplug;
}; };
static int static int
@ -503,7 +519,8 @@ request_firmware_work_func(void *arg)
return 0; return 0;
} }
daemonize("%s/%s", "firmware", fw_work->name); daemonize("%s/%s", "firmware", fw_work->name);
request_firmware(&fw, fw_work->name, fw_work->device); _request_firmware(&fw, fw_work->name, fw_work->device,
fw_work->hotplug);
fw_work->cont(fw, fw_work->context); fw_work->cont(fw, fw_work->context);
release_firmware(fw); release_firmware(fw);
module_put(fw_work->module); module_put(fw_work->module);
@ -518,6 +535,9 @@ request_firmware_work_func(void *arg)
* Asynchronous variant of request_firmware() for contexts where * Asynchronous variant of request_firmware() for contexts where
* it is not possible to sleep. * it is not possible to sleep.
* *
* @hotplug invokes hotplug event to copy the firmware image if this flag
* is non-zero else the firmware copy must be done manually.
*
* @cont will be called asynchronously when the firmware request is over. * @cont will be called asynchronously when the firmware request is over.
* *
* @context will be passed over to @cont. * @context will be passed over to @cont.
@ -527,7 +547,7 @@ request_firmware_work_func(void *arg)
**/ **/
int int
request_firmware_nowait( request_firmware_nowait(
struct module *module, struct module *module, int hotplug,
const char *name, struct device *device, void *context, const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context)) void (*cont)(const struct firmware *fw, void *context))
{ {
@ -548,6 +568,7 @@ request_firmware_nowait(
.device = device, .device = device,
.context = context, .context = context,
.cont = cont, .cont = cont,
.hotplug = hotplug,
}; };
ret = kernel_thread(request_firmware_work_func, fw_work, ret = kernel_thread(request_firmware_work_func, fw_work,

View file

@ -3,6 +3,9 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
#define FIRMWARE_NAME_MAX 30 #define FIRMWARE_NAME_MAX 30
#define FW_ACTION_NOHOTPLUG 0
#define FW_ACTION_HOTPLUG 1
struct firmware { struct firmware {
size_t size; size_t size;
u8 *data; u8 *data;
@ -11,7 +14,7 @@ struct device;
int request_firmware(const struct firmware **fw, const char *name, int request_firmware(const struct firmware **fw, const char *name,
struct device *device); struct device *device);
int request_firmware_nowait( int request_firmware_nowait(
struct module *module, struct module *module, int hotplug,
const char *name, struct device *device, void *context, const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context)); void (*cont)(const struct firmware *fw, void *context));