This is a patch with modifications in firmware_class.c to have no hotplug
support.
The current code invokes hotplug script and cannot be controlled manually.
The function request_firmware_nohotplug() is a new addition without
breaking the existing code all the drivers dependent on firmware_class.c
should see no difference.
This fix is required in firmware_class.c to make dell_rbu driver work with
firmware subsystem without having to do any hotplug stuff as per Greg's
suggestion.
The nohotplug function makes the copying of the firmware image a manual
process. Still the steps taken by the hotplug script will now need to be
done manually. The user will need start the copy by first writign 1 to
/sys/class/firmware/xxx/loading and then copy data to
/sys/class/firmware/xxx/data. Finally the copy process ends when the user
copies 0 or -1 to /sys/class/firmware/xxx/loading.
By making a contribution to this project, I certify that:
The contribution was created in whole or in part by me and I have the
right to submit it under the open source license indicated in the file.
Resubmitting after cleaning up spaces/tabs etc...
Signed-off-by: Abhay Salunke <[email protected]>
Thanks,
Abhay Salunke
Software Engineer.
DELL Inc
diff -uprN /usr/src/linux-2.6.11.11.ORIG/drivers/base/firmware_class.c /usr/src/linux-2.6.11.11/drivers/base/firmware_class.c
--- /usr/src/linux-2.6.11.11.ORIG/drivers/base/firmware_class.c 2005-06-08 09:49:57.874162352 -0500
+++ /usr/src/linux-2.6.11.11/drivers/base/firmware_class.c 2005-06-08 09:51:43.051173016 -0500
@@ -87,7 +87,7 @@ static struct class firmware_class = {
.name = "firmware",
.hotplug = firmware_class_hotplug,
.release = fw_class_dev_release,
-};
+};
int
firmware_class_hotplug(struct class_device *class_dev, char **envp,
@@ -364,6 +364,7 @@ fw_setup_class_device(struct firmware *f
printk(KERN_ERR "%s: class_device_create_file failed\n",
__FUNCTION__);
goto error_unreg;
+r
}
set_bit(FW_STATUS_READY, &fw_priv->status);
@@ -376,6 +377,65 @@ out:
return retval;
}
+static int
+_request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device, int fw_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);
+ if (retval)
+ goto error_kfree_fw;
+
+ fw_priv = class_get_devdata(class_dev);
+
+ if ( fw_hotplug == FW_DO_HOTPLUG) {
+ if (loading_timeout) {
+ 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;
+}
+
/**
* request_firmware: - request firmware to hotplug and wait for it
* Description:
@@ -392,56 +452,7 @@ int
request_firmware(const struct firmware **firmware_p, const char *name,
struct device *device)
{
- 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);
- if (retval)
- goto error_kfree_fw;
-
- fw_priv = class_get_devdata(class_dev);
-
- if (loading_timeout) {
- 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;
+ return _request_firmware(firmware_p, name, device, FW_DO_HOTPLUG);
}
/**
@@ -472,14 +483,15 @@ register_firmware(const char *name, cons
* decide if firmware caching is reasonable just leave it as a
* noop */
}
-
+
/* Async support */
struct firmware_work {
struct work_struct work;
- struct module *module;
+ struct module *module;
const char *name;
struct device *device;
void *context;
+ int hotplug;
void (*cont)(const struct firmware *fw, void *context);
};
@@ -493,7 +505,7 @@ request_firmware_work_func(void *arg)
return 0;
}
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);
release_firmware(fw);
module_put(fw_work->module);
@@ -501,23 +513,9 @@ request_firmware_work_func(void *arg)
return 0;
}
-/**
- * request_firmware_nowait:
- *
- * Description:
- * Asynchronous variant of request_firmware() for contexts where
- * it is not possible to sleep.
- *
- * @cont will be called asynchronously when the firmware request is over.
- *
- * @context will be passed over to @cont.
- *
- * @fw may be %NULL if firmware request fails.
- *
- **/
-int
-request_firmware_nowait(
- struct module *module,
+static int
+_request_firmware_nowait(
+ struct module *module, int fw_hotplug,
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context))
{
@@ -528,7 +526,7 @@ request_firmware_nowait(
if (!fw_work)
return -ENOMEM;
if (!try_module_get(module)) {
- kfree(fw_work);
+ kfree(fw_work);
return -EFAULT;
}
@@ -538,6 +536,7 @@ request_firmware_nowait(
.device = device,
.context = context,
.cont = cont,
+ .hotplug = fw_hotplug,
};
ret = kernel_thread(request_firmware_work_func, fw_work,
@@ -550,6 +549,41 @@ request_firmware_nowait(
return 0;
}
+/**
+ * request_firmware_nowait:
+ *
+ * Description:
+ * Asynchronous variant of request_firmware() for contexts where
+ * it is not possible to sleep.
+ *
+ * @cont will be called asynchronously when the firmware request is over.
+ *
+ * @context will be passed over to @cont.
+ *
+ * @fw may be %NULL if firmware request fails.
+ *
+ **/
+int
+request_firmware_nowait(
+ struct module *module,
+ const char *name, struct device *device, void *context,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ return _request_firmware_nowait(module, FW_DO_HOTPLUG, name,
+ device, context, cont);
+}
+
+int
+request_firmware_nohotplug(
+ struct module *module,
+ const char *name, struct device *device,void *context,
+ void (*cont)(const struct firmware *fw, void *context))
+{
+ return _request_firmware_nowait(module, FW_NO_HOTPLUG_NO_TIMEOUT,
+ name, device, context, cont);
+}
+
+
static int __init
firmware_class_init(void)
{
@@ -568,6 +602,7 @@ firmware_class_init(void)
return error;
}
+r
static void __exit
firmware_class_exit(void)
{
@@ -581,3 +616,5 @@ EXPORT_SYMBOL(release_firmware);
EXPORT_SYMBOL(request_firmware);
EXPORT_SYMBOL(request_firmware_nowait);
EXPORT_SYMBOL(register_firmware);
+EXPORT_SYMBOL(request_firmware_nohotplug);
+
diff -uprN /usr/src/linux-2.6.11.11.ORIG/include/linux/firmware.h /usr/src/linux-2.6.11.11/include/linux/firmware.h
--- /usr/src/linux-2.6.11.11.ORIG/include/linux/firmware.h 2005-06-08 09:49:57.711187128 -0500
+++ /usr/src/linux-2.6.11.11/include/linux/firmware.h 2005-06-08 09:50:41.714497608 -0500
@@ -3,6 +3,8 @@
#include <linux/module.h>
#include <linux/types.h>
#define FIRMWARE_NAME_MAX 30
+#define FW_DO_HOTPLUG (0)
+#define FW_NO_HOTPLUG_NO_TIMEOUT (1)
struct firmware {
size_t size;
u8 *data;
@@ -15,6 +17,11 @@ int request_firmware_nowait(
const char *name, struct device *device, void *context,
void (*cont)(const struct firmware *fw, void *context));
+int request_firmware_nohotplug(
+ struct module *module,
+ const char *name, struct device *device, void *context,
+ void (*cont)(const struct firmware *fw, void *context));
+
void release_firmware(const struct firmware *fw);
void register_firmware(const char *name, const u8 *data, size_t size);
#endif
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]