From: Jon Smirl <jonsmirl@gmail.com>
To: linux-hotplug@vger.kernel.org
Subject: Rework of request firmware
Date: Sun, 20 Mar 2005 04:06:59 +0000 [thread overview]
Message-ID: <9e473391050319200625032789@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 29341 bytes --]
On Sat, 26 Feb 2005 20:41:16 +0100, Kay Sievers <kay.sievers@vrfy.org> wrote:
> I think the request_firmware() should be redesigned in a generic
> request_user_data(kobj) call. This event would copy arbitrary data into
> a sysfs file and something like KOBJ_REQUEST_DATA would do it.
>
> The call should create a file inside of a existing device and the event
> handler should copy the data into this file instead of creating a own
> class device for the firmware as we do today.
This is a rework of request firmware to move the attributes from their
own class into the device sysfs directory. I am also generalizing
things so that I can request a post (this is what I need) as well as
firmware. This is a first post of the code, please tell me what I can
do to improve it before I send it to lkml. The changes in radeonfb are
so that I can test it. There are also some debug printf's still in.
Use the attachment with patch, gmail word wraps and I can't stop it.
I made a few changes in the base code:
1) I modified kobj_hotplug() to take an extra function for adding
variables. This lets the event add the normal variable for the kset
and then I can tack mine on too.
2) New event KOBJ_POST. $POST and $FIRMWARE are used to differentiate
post versus firmware load in the script. Should this be two events
instead?
3) The script now needs to be in
/etc/hotplug.d/default/30-post.hotplug. firmware.agent isn't used
anymore. The firmware doesn't need to change or move.
4) I added a pointer to 'struct device' to track the firmware in
sysfs. Is there a better way to do this?
5) I added the time out to /sys/firmware/post_timeout since there is
no /sys/class/firmware any more.
6) How should everything be named? firmware, post, initialization, etc??
7) Should request_firmware() be deprecated forcing the move to
request_firmware_nowait?
8) Should I keep the different signatures on the nowait callbacks?
--
Jon Smirl
jonsmirl@gmail.com
===== drivers/acpi/container.c 1.2 vs edited =====
--- 1.2/drivers/acpi/container.c 2004-11-11 02:56:31 -05:00
+++ edited/drivers/acpi/container.c 2005-03-19 01:38:11 -05:00
@@ -182,16 +182,16 @@
if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle);
if (!result)
- kobject_hotplug(&device->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&device->kobj, KOBJ_ONLINE, NULL);
} else {
/* device exist and this is a remove request */
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
}
break;
default:
===== drivers/acpi/processor_core.c 1.80 vs edited =====
--- 1.80/drivers/acpi/processor_core.c 2004-12-14 07:14:54 -05:00
+++ edited/drivers/acpi/processor_core.c 2005-03-19 01:38:57 -05:00
@@ -730,7 +730,7 @@
return_VALUE(-ENODEV);
if ((pr->id >=0) && (pr->id < NR_CPUS)) {
- kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE, NULL);
}
return_VALUE(0);
}
@@ -774,13 +774,13 @@
}
if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
break;
}
result = acpi_processor_start(device);
if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) {
- kobject_hotplug(&device->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&device->kobj, KOBJ_ONLINE, NULL);
} else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device [%s] failed to start\n",
@@ -801,7 +801,7 @@
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
===== drivers/base/cpu.c 1.22 vs edited =====
--- 1.22/drivers/base/cpu.c 2005-01-31 01:33:46 -05:00
+++ edited/drivers/base/cpu.c 2005-03-19 01:39:16 -05:00
@@ -33,7 +33,7 @@
case '0':
ret = cpu_down(cpu->sysdev.id);
if (!ret)
- kobject_hotplug(&dev->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&dev->kobj, KOBJ_OFFLINE, NULL);
break;
case '1':
ret = cpu_up(cpu->sysdev.id);
===== drivers/base/firmware.c 1.9 vs edited =====
--- 1.9/drivers/base/firmware.c 2004-09-24 14:45:35 -04:00
+++ edited/drivers/base/firmware.c 2005-03-19 11:16:01 -05:00
@@ -14,21 +14,57 @@
static decl_subsys(firmware, NULL, NULL);
+int post_timeout = 10; /* In seconds */
+EXPORT_SYMBOL_GPL(post_timeout);
+
int firmware_register(struct subsystem * s)
{
kset_set_kset_s(s, firmware_subsys);
return subsystem_register(s);
}
+EXPORT_SYMBOL_GPL(firmware_register);
void firmware_unregister(struct subsystem * s)
{
subsystem_unregister(s);
}
+EXPORT_SYMBOL_GPL(firmware_unregister);
+
+/**
+ * post_timeout_store:
+ * Description:
+ * Sets the number of seconds to wait for the post/firmware load.
+ * Once this expires an error will be return to the driver and no
+ * firmware will be provided.
+ *
+ * Note: zero means 'wait for ever'
+ *
+ **/
+static ssize_t post_timeout_store(struct subsystem *subsys, const
char *buf, size_t count)
+{
+ post_timeout = simple_strtol(buf, NULL, 10);
+ return count;
+}
+static ssize_t post_timeout_show(struct subsystem *subsys, char *buf)
+{
+ return sprintf(buf, "%d\n", post_timeout);
+}
+static struct subsys_attribute post_timeout_attr = {
+ .attr = {.name = "post_timeout", .mode = 0644, .owner = THIS_MODULE},
+ .show = post_timeout_show,
+ .store = post_timeout_store
+};
int __init firmware_init(void)
{
- return subsystem_register(&firmware_subsys);
+ int error;
+ if ((error = subsystem_register(&firmware_subsys)))
+ return error;
+
+ if ((error = subsys_create_file(&firmware_subsys, &post_timeout_attr))) {
+ subsystem_unregister(&firmware_subsys);
+ return error;
+ }
+ return 0;
}
-EXPORT_SYMBOL_GPL(firmware_register);
-EXPORT_SYMBOL_GPL(firmware_unregister);
===== drivers/base/firmware_class.c 1.25 vs edited =====
--- 1.25/drivers/base/firmware_class.c 2004-11-26 15:26:48 -05:00
+++ edited/drivers/base/firmware_class.c 2005-03-19 21:11:15 -05:00
@@ -1,7 +1,8 @@
/*
- * firmware_class.c - Multi purpose firmware loading support
+ * firmware_class.c - Multi purpose post support
*
* Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ * Copyright (c) 2005 Jon Smirl <jonsmirl@gmail.com>
*
* Please see Documentation/firmware_class/ for more information.
*
@@ -20,7 +21,7 @@
#include "base.h"
MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-MODULE_DESCRIPTION("Multi purpose firmware loading support");
+MODULE_DESCRIPTION("Multi purpose post support");
MODULE_LICENSE("GPL");
enum {
@@ -30,8 +31,6 @@
FW_STATUS_READY,
};
-static int loading_timeout = 10; /* In seconds */
-
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
static DECLARE_MUTEX(fw_lock);
@@ -49,69 +48,41 @@
static inline void
fw_load_abort(struct firmware_priv *fw_priv)
{
+ printk(KERN_ERR "fw_load_abort\n");
set_bit(FW_STATUS_ABORT, &fw_priv->status);
wmb();
complete(&fw_priv->completion);
}
-static ssize_t
-firmware_timeout_show(struct class *class, char *buf)
-{
- return sprintf(buf, "%d\n", loading_timeout);
-}
-
-/**
- * firmware_timeout_store:
- * Description:
- * Sets the number of seconds to wait for the firmware. Once
- * this expires an error will be return to the driver and no
- * firmware will be provided.
- *
- * Note: zero means 'wait for ever'
- *
- **/
-static ssize_t
-firmware_timeout_store(struct class *class, const char *buf, size_t count)
-{
- loading_timeout = simple_strtol(buf, NULL, 10);
- return count;
-}
-
-static CLASS_ATTR(timeout, 0644, firmware_timeout_show,
firmware_timeout_store);
-
-static void fw_class_dev_release(struct class_device *class_dev);
-int firmware_class_hotplug(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-
-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,
+post_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct firmware_priv *fw_priv = dev->post_data;
int i = 0, len = 0;
if (!test_bit(FW_STATUS_READY, &fw_priv->status))
return -ENODEV;
- if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "FIRMWARE=%s", fw_priv->fw_id))
- return -ENOMEM;
-
+ if (fw_priv->fw) {
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer,
+ buffer_size, &len, "FIRMWARE=%s", fw_priv->fw_id))
+ return -ENOMEM;
+ } else {
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer,
+ buffer_size, &len, "POST=%s", fw_priv->fw_id))
+ return -ENOMEM;
+ }
envp[i] = NULL;
return 0;
}
static ssize_t
-firmware_loading_show(struct class_device *class_dev, char *buf)
+post_status_show(struct device *dev, char *buf)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct firmware_priv *fw_priv = dev->post_data;
int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
return sprintf(buf, "%d\n", loading);
}
@@ -126,13 +97,13 @@
* -1: Conclude the load with an error and discard any written data.
**/
static ssize_t
-firmware_loading_store(struct class_device *class_dev,
- const char *buf, size_t count)
+post_status_store(struct device *dev, const char *buf, size_t count)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
- int loading = simple_strtol(buf, NULL, 10);
+ struct firmware_priv *fw_priv = dev->post_data;
+ int status = simple_strtol(buf, NULL, 10);
- switch (loading) {
+ printk(KERN_ERR "post_status_store: status %d\n", status);
+ switch (status) {
case 1:
down(&fw_lock);
vfree(fw_priv->fw->data);
@@ -151,7 +122,7 @@
/* fallthrough */
default:
printk(KERN_ERR "%s: unexpected value (%d)\n", __FUNCTION__,
- loading);
+ status);
/* fallthrough */
case -1:
fw_load_abort(fw_priv);
@@ -161,15 +132,14 @@
return count;
}
-static CLASS_DEVICE_ATTR(loading, 0644,
- firmware_loading_show, firmware_loading_store);
+static DEVICE_ATTR(post_status, 0644, post_status_show, post_status_store);
static ssize_t
-firmware_data_read(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+post_data_read(struct kobject *kobj,
+ char *buffer, loff_t offset, size_t count)
{
- struct class_device *class_dev = to_class_dev(kobj);
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct firmware_priv *fw_priv = dev->post_data;
struct firmware *fw;
ssize_t ret_count = count;
@@ -191,6 +161,7 @@
up(&fw_lock);
return ret_count;
}
+
static int
fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
@@ -225,8 +196,8 @@
* the driver as a firmware image.
**/
static ssize_t
-firmware_data_write(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+post_data_write(struct kobject *kobj,
+ char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
@@ -254,124 +225,82 @@
return retval;
}
static struct bin_attribute firmware_attr_data_tmpl = {
- .attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE},
+ .attr = {.name = "post_data", .mode = 0644, .owner = THIS_MODULE},
.size = 0,
- .read = firmware_data_read,
- .write = firmware_data_write,
+ .read = post_data_read,
+ .write = post_data_write,
};
static void
-fw_class_dev_release(struct class_device *class_dev)
-{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
- kfree(fw_priv);
- kfree(class_dev);
-
- module_put(THIS_MODULE);
-}
-
-static void
-firmware_class_timeout(u_long data)
+post_timeout_abort(u_long data)
{
struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+ printk(KERN_ERR "post_timeout_abort: time out\n");
fw_load_abort(fw_priv);
}
-static inline void
-fw_setup_class_device_id(struct class_device *class_dev, struct device *dev)
-{
- /* XXX warning we should watch out for name collisions */
- strlcpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE);
-}
-
static int
-fw_register_class_device(struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+fw_register_device(const char *fw_name, struct device *device)
{
int retval;
struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
GFP_KERNEL);
- struct class_device *class_dev = kmalloc(sizeof (struct class_device),
- GFP_KERNEL);
-
- *class_dev_p = NULL;
- if (!fw_priv || !class_dev) {
+ if (!fw_priv) {
printk(KERN_ERR "%s: kmalloc failed\n", __FUNCTION__);
retval = -ENOMEM;
goto error_kfree;
}
memset(fw_priv, 0, sizeof (*fw_priv));
- memset(class_dev, 0, sizeof (*class_dev));
init_completion(&fw_priv->completion);
fw_priv->attr_data = firmware_attr_data_tmpl;
strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
- fw_priv->timeout.function = firmware_class_timeout;
+ fw_priv->timeout.function = post_timeout_abort;
fw_priv->timeout.data = (u_long) fw_priv;
init_timer(&fw_priv->timeout);
+
+ device->post_data = fw_priv;
- fw_setup_class_device_id(class_dev, device);
- class_dev->dev = device;
- class_dev->class = &firmware_class;
- class_set_devdata(class_dev, fw_priv);
- retval = class_device_register(class_dev);
- if (retval) {
- printk(KERN_ERR "%s: class_device_register failed\n",
- __FUNCTION__);
- goto error_kfree;
- }
- *class_dev_p = class_dev;
return 0;
error_kfree:
kfree(fw_priv);
- kfree(class_dev);
return retval;
}
static int
-fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+fw_setup_device(struct firmware *fw, const char *fw_name, struct
device *device)
{
- struct class_device *class_dev;
struct firmware_priv *fw_priv;
int retval;
- *class_dev_p = NULL;
- retval = fw_register_class_device(&class_dev, fw_name, device);
+ retval = fw_register_device(fw_name, device);
if (retval)
goto out;
- /* Need to pin this module until class device is destroyed */
- __module_get(THIS_MODULE);
-
- fw_priv = class_get_devdata(class_dev);
-
+ fw_priv = device->post_data;
fw_priv->fw = fw;
- retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data);
+
+ retval = sysfs_create_bin_file(&device->kobj, &fw_priv->attr_data);
if (retval) {
printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
__FUNCTION__);
- goto error_unreg;
+ goto out;
}
- retval = class_device_create_file(class_dev,
- &class_device_attr_loading);
- if (retval) {
- printk(KERN_ERR "%s: class_device_create_file failed\n",
- __FUNCTION__);
- goto error_unreg;
+ if (fw) {
+ retval = device_create_file(device, &dev_attr_post_status);
+ if (retval) {
+ printk(KERN_ERR "%s: device_create_file failed\n",
+ __FUNCTION__);
+ goto out;
+ }
}
-
set_bit(FW_STATUS_READY, &fw_priv->status);
- *class_dev_p = class_dev;
goto out;
-error_unreg:
- class_device_unregister(class_dev);
out:
return retval;
}
@@ -388,62 +317,79 @@
* should be distinctive enough not to be confused with any other
* firmware image for this or any other device.
**/
-int
-request_firmware(const struct firmware **firmware_p, const char *name,
+static int
+request(const struct firmware **firmware_p, const char *name,
struct device *device)
{
- struct class_device *class_dev;
struct firmware_priv *fw_priv;
- struct firmware *firmware;
+ struct firmware *firmware = NULL;
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;
+ if (firmware_p) {
+ *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));
}
- memset(firmware, 0, sizeof (*firmware));
- retval = fw_setup_class_device(firmware, &class_dev, name, device);
+ retval = fw_setup_device(firmware, name, device);
if (retval)
goto error_kfree_fw;
- fw_priv = class_get_devdata(class_dev);
+ fw_priv = device->post_data;
- if (loading_timeout) {
- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+ if (post_timeout) {
+ fw_priv->timeout.expires = jiffies + post_timeout * HZ;
add_timer(&fw_priv->timeout);
}
- kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+ printk(KERN_ERR "request_firmware: hotplug event\n");
+ kobject_hotplug(&device->kobj, KOBJ_POST, post_hotplug);
wait_for_completion(&fw_priv->completion);
set_bit(FW_STATUS_DONE, &fw_priv->status);
+ printk(KERN_ERR "request_firmware: complete\n");
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;
+ if (firmware_p) {
+ 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);
+
+ sysfs_remove_bin_file(&device->kobj, &fw_priv->attr_data);
}
- fw_priv->fw = NULL;
- up(&fw_lock);
- class_device_unregister(class_dev);
+ device_remove_file(device, &dev_attr_post_status);
+
goto out;
error_kfree_fw:
- kfree(firmware);
- *firmware_p = NULL;
+ if (firmware) {
+ kfree(firmware);
+ *firmware_p = NULL;
+ }
out:
return retval;
}
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ if (!firmware_p)
+ return -EINVAL;
+ return request(firmware_p, name, device);
+}
+EXPORT_SYMBOL(request_firmware);
+
/**
* release_firmware: - release the resource associated with a firmware image
**/
@@ -455,6 +401,7 @@
kfree(fw);
}
}
+EXPORT_SYMBOL(release_firmware);
/**
* register_firmware: - provide a firmware image for later usage
@@ -472,6 +419,7 @@
* decide if firmware caching is reasonable just leave it as a
* noop */
}
+EXPORT_SYMBOL(register_firmware);
/* Async support */
struct firmware_work {
@@ -480,11 +428,12 @@
const char *name;
struct device *device;
void *context;
- void (*cont)(const struct firmware *fw, void *context);
+ void (*cont_fw)(const struct firmware *fw, void *context);
+ void (*cont_post)(void *context);
};
static int
-request_firmware_work_func(void *arg)
+request_post_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
@@ -492,10 +441,15 @@
WARN_ON(1);
return 0;
}
- daemonize("%s/%s", "firmware", fw_work->name);
- request_firmware(&fw, fw_work->name, fw_work->device);
- fw_work->cont(fw, fw_work->context);
- release_firmware(fw);
+ daemonize("%s/%s", "post", fw_work->name);
+ if (fw_work->cont_fw) {
+ request(&fw, fw_work->name, fw_work->device);
+ fw_work->cont_fw(fw, fw_work->context);
+ release_firmware(fw);
+ } else {
+ request(NULL, fw_work->name, fw_work->device);
+ fw_work->cont_post(fw_work->context);
+ }
module_put(fw_work->module);
kfree(fw_work);
return 0;
@@ -515,11 +469,12 @@
* @fw may be %NULL if firmware request fails.
*
**/
-int
-request_firmware_nowait(
+static int
+request_nowait(
struct module *module,
const char *name, struct device *device, void *context,
- void (*cont)(const struct firmware *fw, void *context))
+ void (*cont_fw)(const struct firmware *fw, void *context),
+ void (*cont_post)(void *context))
{
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC);
@@ -537,47 +492,37 @@
.name = name,
.device = device,
.context = context,
- .cont = cont,
+ .cont_fw = cont_fw,
+ .cont_post = cont_post,
};
- ret = kernel_thread(request_firmware_work_func, fw_work,
+ ret = kernel_thread(request_post_work_func, fw_work,
CLONE_FS | CLONE_FILES);
if (ret < 0) {
- fw_work->cont(NULL, fw_work->context);
+ if (fw_work->cont_fw)
+ fw_work->cont_fw(NULL, fw_work->context);
+ if (fw_work->cont_post)
+ fw_work->cont_post(fw_work->context);
return ret;
}
return 0;
}
-static int __init
-firmware_class_init(void)
+int
+request_firmware_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_fw)(const struct firmware *fw, void *context))
{
- int error;
- error = class_register(&firmware_class);
- if (error) {
- printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__);
- return error;
- }
- error = class_create_file(&firmware_class, &class_attr_timeout);
- if (error) {
- printk(KERN_ERR "%s: class_create_file failed\n",
- __FUNCTION__);
- class_unregister(&firmware_class);
- }
- return error;
-
+ return request_nowait(module, name, device, context, cont_fw, NULL);
}
-static void __exit
-firmware_class_exit(void)
+EXPORT_SYMBOL(request_firmware_nowait);
+
+int
+request_post_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_post)(void *context))
{
- class_unregister(&firmware_class);
+ return request_nowait(module, name, device, context, NULL, cont_post);
}
-
-module_init(firmware_class_init);
-module_exit(firmware_class_exit);
-
-EXPORT_SYMBOL(release_firmware);
-EXPORT_SYMBOL(request_firmware);
-EXPORT_SYMBOL(request_firmware_nowait);
-EXPORT_SYMBOL(register_firmware);
+EXPORT_SYMBOL(request_post_nowait);
===== drivers/video/aty/radeon_base.c 1.44 vs edited =====
--- 1.44/drivers/video/aty/radeon_base.c 2005-03-10 03:39:11 -05:00
+++ edited/drivers/video/aty/radeon_base.c 2005-03-19 21:17:49 -05:00
@@ -71,6 +71,7 @@
#include <linux/vmalloc.h>
#include <linux/device.h>
#include <linux/i2c.h>
+#include <linux/firmware.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -2206,6 +2207,9 @@
.read = radeon_show_edid2,
};
+static void radeon_post_finished(void *data) {
+ printk(KERN_ERR "radeon_post_finished\n");
+}
static int radeonfb_pci_register (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -2410,6 +2414,8 @@
}
#endif
+ request_post_nowait(THIS_MODULE, "vbios.vm86", &pdev->dev, rinfo,
radeon_post_finished);
+
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
if (rinfo->bios_seg)
@@ -2453,7 +2459,19 @@
if (!rinfo)
return;
+ /* Register some sysfs stuff (should be done better) */
+ if (rinfo->mon1_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+ if (rinfo->mon2_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
+
radeonfb_pm_exit(rinfo);
+
+ /* Register some sysfs stuff (should be done better) */
+ if (rinfo->mon1_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+ if (rinfo->mon2_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
#if 0
/* restore original state
===== include/linux/device.h 1.138 vs edited =====
--- 1.138/include/linux/device.h 2005-03-09 12:03:56 -05:00
+++ edited/include/linux/device.h 2005-03-19 11:11:34 -05:00
@@ -271,6 +271,7 @@
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */
+ void *post_data; /* active during firmware load or post */
struct dev_pm_info power;
u32 detach_state; /* State to enter when device is
@@ -399,6 +400,7 @@
/* drivers/base/firmware.c */
extern int firmware_register(struct subsystem *);
extern void firmware_unregister(struct subsystem *);
+extern int post_timeout; /* In seconds */
/* debugging and troubleshooting/diagnostic helpers. */
#define dev_printk(level, dev, format, arg...) \
===== include/linux/firmware.h 1.3 vs edited =====
--- 1.3/include/linux/firmware.h 2005-02-02 04:49:28 -05:00
+++ edited/include/linux/firmware.h 2005-03-19 21:12:52 -05:00
@@ -1,20 +1,27 @@
#ifndef _LINUX_FIRMWARE_H
#define _LINUX_FIRMWARE_H
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/types.h>
+
#define FIRMWARE_NAME_MAX 30
+
struct firmware {
size_t size;
u8 *data;
};
-struct device;
+
+int request_post_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_post)(void *context));
+
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
-int request_firmware_nowait(
- struct module *module,
- const char *name, struct device *device, void *context,
- void (*cont)(const struct firmware *fw, void *context));
-
+int request_firmware_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_fw)(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
===== include/linux/kobject.h 1.39 vs edited =====
--- 1.39/include/linux/kobject.h 2005-03-09 12:04:09 -05:00
+++ edited/include/linux/kobject.h 2005-03-19 01:32:55 -05:00
@@ -242,13 +242,19 @@
extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
#ifdef CONFIG_HOTPLUG
-void kobject_hotplug(struct kobject *kobj, enum kobject_action action);
+void kobject_hotplug(struct kobject *kobj, enum kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+ );
int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
char *buffer, int buffer_size, int *cur_len,
const char *format, ...)
__attribute__((format (printf, 7, 8)));
#else
-static inline void kobject_hotplug(struct kobject *kobj, enum
kobject_action action) { }
+static inline void kobject_hotplug(struct kobject *kobj, enum
kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+ ) { }
static inline int add_hotplug_env_var(char **envp, int num_envp, int
*cur_index,
char *buffer, int buffer_size, int *cur_len,
const char *format, ...)
===== include/linux/kobject_uevent.h 1.6 vs edited =====
--- 1.6/include/linux/kobject_uevent.h 2004-11-08 14:43:30 -05:00
+++ edited/include/linux/kobject_uevent.h 2005-03-17 10:36:00 -05:00
@@ -29,6 +29,7 @@
KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for
block devices */
KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* offline event for
hotplug devices */
KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* online event for
hotplug devices */
+ KOBJ_POST = (__force kobject_action_t) 0x08, /* post event supports
user space initialization */
};
===== lib/kobject.c 1.58 vs edited =====
--- 1.58/lib/kobject.c 2005-03-09 12:04:09 -05:00
+++ edited/lib/kobject.c 2005-03-19 01:39:37 -05:00
@@ -185,7 +185,7 @@
if (parent)
kobject_put(parent);
} else {
- kobject_hotplug(kobj, KOBJ_ADD);
+ kobject_hotplug(kobj, KOBJ_ADD, NULL);
}
return error;
@@ -301,7 +301,7 @@
void kobject_del(struct kobject * kobj)
{
- kobject_hotplug(kobj, KOBJ_REMOVE);
+ kobject_hotplug(kobj, KOBJ_REMOVE, NULL);
sysfs_remove_dir(kobj);
unlink(kobj);
}
===== lib/kobject_uevent.c 1.18 vs edited =====
--- 1.18/lib/kobject_uevent.c 2005-01-08 00:44:13 -05:00
+++ edited/lib/kobject_uevent.c 2005-03-19 01:48:04 -05:00
@@ -44,6 +44,8 @@
return "offline";
case KOBJ_ONLINE:
return "online";
+ case KOBJ_POST:
+ return "post";
default:
return NULL;
}
@@ -187,7 +189,9 @@
* @action: action that is happening (usually "ADD" or "REMOVE")
* @kobj: struct kobject that the action is happening to
*/
-void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
+void kobject_hotplug(struct kobject *kobj, enum kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size))
{
char *argv [3];
char **envp = NULL;
@@ -279,6 +283,17 @@
if (hotplug_ops->hotplug) {
/* have the kset specific function add its stuff */
retval = hotplug_ops->hotplug (kset, kobj,
+ &envp[i], NUM_ENVP - i, scratch,
+ BUFFER_SIZE - (scratch - buffer));
+ if (retval) {
+ pr_debug ("%s - hotplug() returned %d\n",
+ __FUNCTION__, retval);
+ goto exit;
+ }
+ }
+ if (hotplug) {
+ /* have the call specific function add on its stuff */
+ retval = hotplug (kset, kobj,
&envp[i], NUM_ENVP - i, scratch,
BUFFER_SIZE - (scratch - buffer));
if (retval) {
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: firmware.patch --]
[-- Type: text/x-diff; name="firmware.patch", Size: 28315 bytes --]
===== drivers/acpi/container.c 1.2 vs edited =====
--- 1.2/drivers/acpi/container.c 2004-11-11 02:56:31 -05:00
+++ edited/drivers/acpi/container.c 2005-03-19 01:38:11 -05:00
@@ -182,16 +182,16 @@
if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle);
if (!result)
- kobject_hotplug(&device->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&device->kobj, KOBJ_ONLINE, NULL);
} else {
/* device exist and this is a remove request */
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
}
}
break;
case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) {
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
}
break;
default:
===== drivers/acpi/processor_core.c 1.80 vs edited =====
--- 1.80/drivers/acpi/processor_core.c 2004-12-14 07:14:54 -05:00
+++ edited/drivers/acpi/processor_core.c 2005-03-19 01:38:57 -05:00
@@ -730,7 +730,7 @@
return_VALUE(-ENODEV);
if ((pr->id >=0) && (pr->id < NR_CPUS)) {
- kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE, NULL);
}
return_VALUE(0);
}
@@ -774,13 +774,13 @@
}
if (pr->id >= 0 && (pr->id < NR_CPUS)) {
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
break;
}
result = acpi_processor_start(device);
if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) {
- kobject_hotplug(&device->kobj, KOBJ_ONLINE);
+ kobject_hotplug(&device->kobj, KOBJ_ONLINE, NULL);
} else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device [%s] failed to start\n",
@@ -801,7 +801,7 @@
}
if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
- kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE, NULL);
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
===== drivers/base/cpu.c 1.22 vs edited =====
--- 1.22/drivers/base/cpu.c 2005-01-31 01:33:46 -05:00
+++ edited/drivers/base/cpu.c 2005-03-19 01:39:16 -05:00
@@ -33,7 +33,7 @@
case '0':
ret = cpu_down(cpu->sysdev.id);
if (!ret)
- kobject_hotplug(&dev->kobj, KOBJ_OFFLINE);
+ kobject_hotplug(&dev->kobj, KOBJ_OFFLINE, NULL);
break;
case '1':
ret = cpu_up(cpu->sysdev.id);
===== drivers/base/firmware.c 1.9 vs edited =====
--- 1.9/drivers/base/firmware.c 2004-09-24 14:45:35 -04:00
+++ edited/drivers/base/firmware.c 2005-03-19 11:16:01 -05:00
@@ -14,21 +14,57 @@
static decl_subsys(firmware, NULL, NULL);
+int post_timeout = 10; /* In seconds */
+EXPORT_SYMBOL_GPL(post_timeout);
+
int firmware_register(struct subsystem * s)
{
kset_set_kset_s(s, firmware_subsys);
return subsystem_register(s);
}
+EXPORT_SYMBOL_GPL(firmware_register);
void firmware_unregister(struct subsystem * s)
{
subsystem_unregister(s);
}
+EXPORT_SYMBOL_GPL(firmware_unregister);
+
+/**
+ * post_timeout_store:
+ * Description:
+ * Sets the number of seconds to wait for the post/firmware load.
+ * Once this expires an error will be return to the driver and no
+ * firmware will be provided.
+ *
+ * Note: zero means 'wait for ever'
+ *
+ **/
+static ssize_t post_timeout_store(struct subsystem *subsys, const char *buf, size_t count)
+{
+ post_timeout = simple_strtol(buf, NULL, 10);
+ return count;
+}
+static ssize_t post_timeout_show(struct subsystem *subsys, char *buf)
+{
+ return sprintf(buf, "%d\n", post_timeout);
+}
+static struct subsys_attribute post_timeout_attr = {
+ .attr = {.name = "post_timeout", .mode = 0644, .owner = THIS_MODULE},
+ .show = post_timeout_show,
+ .store = post_timeout_store
+};
int __init firmware_init(void)
{
- return subsystem_register(&firmware_subsys);
+ int error;
+ if ((error = subsystem_register(&firmware_subsys)))
+ return error;
+
+ if ((error = subsys_create_file(&firmware_subsys, &post_timeout_attr))) {
+ subsystem_unregister(&firmware_subsys);
+ return error;
+ }
+ return 0;
}
-EXPORT_SYMBOL_GPL(firmware_register);
-EXPORT_SYMBOL_GPL(firmware_unregister);
===== drivers/base/firmware_class.c 1.25 vs edited =====
--- 1.25/drivers/base/firmware_class.c 2004-11-26 15:26:48 -05:00
+++ edited/drivers/base/firmware_class.c 2005-03-19 21:11:15 -05:00
@@ -1,7 +1,8 @@
/*
- * firmware_class.c - Multi purpose firmware loading support
+ * firmware_class.c - Multi purpose post support
*
* Copyright (c) 2003 Manuel Estrada Sainz <ranty@debian.org>
+ * Copyright (c) 2005 Jon Smirl <jonsmirl@gmail.com>
*
* Please see Documentation/firmware_class/ for more information.
*
@@ -20,7 +21,7 @@
#include "base.h"
MODULE_AUTHOR("Manuel Estrada Sainz <ranty@debian.org>");
-MODULE_DESCRIPTION("Multi purpose firmware loading support");
+MODULE_DESCRIPTION("Multi purpose post support");
MODULE_LICENSE("GPL");
enum {
@@ -30,8 +31,6 @@
FW_STATUS_READY,
};
-static int loading_timeout = 10; /* In seconds */
-
/* fw_lock could be moved to 'struct firmware_priv' but since it is just
* guarding for corner cases a global lock should be OK */
static DECLARE_MUTEX(fw_lock);
@@ -49,69 +48,41 @@
static inline void
fw_load_abort(struct firmware_priv *fw_priv)
{
+ printk(KERN_ERR "fw_load_abort\n");
set_bit(FW_STATUS_ABORT, &fw_priv->status);
wmb();
complete(&fw_priv->completion);
}
-static ssize_t
-firmware_timeout_show(struct class *class, char *buf)
-{
- return sprintf(buf, "%d\n", loading_timeout);
-}
-
-/**
- * firmware_timeout_store:
- * Description:
- * Sets the number of seconds to wait for the firmware. Once
- * this expires an error will be return to the driver and no
- * firmware will be provided.
- *
- * Note: zero means 'wait for ever'
- *
- **/
-static ssize_t
-firmware_timeout_store(struct class *class, const char *buf, size_t count)
-{
- loading_timeout = simple_strtol(buf, NULL, 10);
- return count;
-}
-
-static CLASS_ATTR(timeout, 0644, firmware_timeout_show, firmware_timeout_store);
-
-static void fw_class_dev_release(struct class_device *class_dev);
-int firmware_class_hotplug(struct class_device *dev, char **envp,
- int num_envp, char *buffer, int buffer_size);
-
-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,
+post_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct firmware_priv *fw_priv = dev->post_data;
int i = 0, len = 0;
if (!test_bit(FW_STATUS_READY, &fw_priv->status))
return -ENODEV;
- if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
- "FIRMWARE=%s", fw_priv->fw_id))
- return -ENOMEM;
-
+ if (fw_priv->fw) {
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer,
+ buffer_size, &len, "FIRMWARE=%s", fw_priv->fw_id))
+ return -ENOMEM;
+ } else {
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer,
+ buffer_size, &len, "POST=%s", fw_priv->fw_id))
+ return -ENOMEM;
+ }
envp[i] = NULL;
return 0;
}
static ssize_t
-firmware_loading_show(struct class_device *class_dev, char *buf)
+post_status_show(struct device *dev, char *buf)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct firmware_priv *fw_priv = dev->post_data;
int loading = test_bit(FW_STATUS_LOADING, &fw_priv->status);
return sprintf(buf, "%d\n", loading);
}
@@ -126,13 +97,13 @@
* -1: Conclude the load with an error and discard any written data.
**/
static ssize_t
-firmware_loading_store(struct class_device *class_dev,
- const char *buf, size_t count)
+post_status_store(struct device *dev, const char *buf, size_t count)
{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
- int loading = simple_strtol(buf, NULL, 10);
+ struct firmware_priv *fw_priv = dev->post_data;
+ int status = simple_strtol(buf, NULL, 10);
- switch (loading) {
+ printk(KERN_ERR "post_status_store: status %d\n", status);
+ switch (status) {
case 1:
down(&fw_lock);
vfree(fw_priv->fw->data);
@@ -151,7 +122,7 @@
/* fallthrough */
default:
printk(KERN_ERR "%s: unexpected value (%d)\n", __FUNCTION__,
- loading);
+ status);
/* fallthrough */
case -1:
fw_load_abort(fw_priv);
@@ -161,15 +132,14 @@
return count;
}
-static CLASS_DEVICE_ATTR(loading, 0644,
- firmware_loading_show, firmware_loading_store);
+static DEVICE_ATTR(post_status, 0644, post_status_show, post_status_store);
static ssize_t
-firmware_data_read(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+post_data_read(struct kobject *kobj,
+ char *buffer, loff_t offset, size_t count)
{
- struct class_device *class_dev = to_class_dev(kobj);
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct firmware_priv *fw_priv = dev->post_data;
struct firmware *fw;
ssize_t ret_count = count;
@@ -191,6 +161,7 @@
up(&fw_lock);
return ret_count;
}
+
static int
fw_realloc_buffer(struct firmware_priv *fw_priv, int min_size)
{
@@ -225,8 +196,8 @@
* the driver as a firmware image.
**/
static ssize_t
-firmware_data_write(struct kobject *kobj,
- char *buffer, loff_t offset, size_t count)
+post_data_write(struct kobject *kobj,
+ char *buffer, loff_t offset, size_t count)
{
struct class_device *class_dev = to_class_dev(kobj);
struct firmware_priv *fw_priv = class_get_devdata(class_dev);
@@ -254,124 +225,82 @@
return retval;
}
static struct bin_attribute firmware_attr_data_tmpl = {
- .attr = {.name = "data", .mode = 0644, .owner = THIS_MODULE},
+ .attr = {.name = "post_data", .mode = 0644, .owner = THIS_MODULE},
.size = 0,
- .read = firmware_data_read,
- .write = firmware_data_write,
+ .read = post_data_read,
+ .write = post_data_write,
};
static void
-fw_class_dev_release(struct class_device *class_dev)
-{
- struct firmware_priv *fw_priv = class_get_devdata(class_dev);
-
- kfree(fw_priv);
- kfree(class_dev);
-
- module_put(THIS_MODULE);
-}
-
-static void
-firmware_class_timeout(u_long data)
+post_timeout_abort(u_long data)
{
struct firmware_priv *fw_priv = (struct firmware_priv *) data;
+ printk(KERN_ERR "post_timeout_abort: time out\n");
fw_load_abort(fw_priv);
}
-static inline void
-fw_setup_class_device_id(struct class_device *class_dev, struct device *dev)
-{
- /* XXX warning we should watch out for name collisions */
- strlcpy(class_dev->class_id, dev->bus_id, BUS_ID_SIZE);
-}
-
static int
-fw_register_class_device(struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+fw_register_device(const char *fw_name, struct device *device)
{
int retval;
struct firmware_priv *fw_priv = kmalloc(sizeof (struct firmware_priv),
GFP_KERNEL);
- struct class_device *class_dev = kmalloc(sizeof (struct class_device),
- GFP_KERNEL);
-
- *class_dev_p = NULL;
- if (!fw_priv || !class_dev) {
+ if (!fw_priv) {
printk(KERN_ERR "%s: kmalloc failed\n", __FUNCTION__);
retval = -ENOMEM;
goto error_kfree;
}
memset(fw_priv, 0, sizeof (*fw_priv));
- memset(class_dev, 0, sizeof (*class_dev));
init_completion(&fw_priv->completion);
fw_priv->attr_data = firmware_attr_data_tmpl;
strlcpy(fw_priv->fw_id, fw_name, FIRMWARE_NAME_MAX);
- fw_priv->timeout.function = firmware_class_timeout;
+ fw_priv->timeout.function = post_timeout_abort;
fw_priv->timeout.data = (u_long) fw_priv;
init_timer(&fw_priv->timeout);
+
+ device->post_data = fw_priv;
- fw_setup_class_device_id(class_dev, device);
- class_dev->dev = device;
- class_dev->class = &firmware_class;
- class_set_devdata(class_dev, fw_priv);
- retval = class_device_register(class_dev);
- if (retval) {
- printk(KERN_ERR "%s: class_device_register failed\n",
- __FUNCTION__);
- goto error_kfree;
- }
- *class_dev_p = class_dev;
return 0;
error_kfree:
kfree(fw_priv);
- kfree(class_dev);
return retval;
}
static int
-fw_setup_class_device(struct firmware *fw, struct class_device **class_dev_p,
- const char *fw_name, struct device *device)
+fw_setup_device(struct firmware *fw, const char *fw_name, struct device *device)
{
- struct class_device *class_dev;
struct firmware_priv *fw_priv;
int retval;
- *class_dev_p = NULL;
- retval = fw_register_class_device(&class_dev, fw_name, device);
+ retval = fw_register_device(fw_name, device);
if (retval)
goto out;
- /* Need to pin this module until class device is destroyed */
- __module_get(THIS_MODULE);
-
- fw_priv = class_get_devdata(class_dev);
-
+ fw_priv = device->post_data;
fw_priv->fw = fw;
- retval = sysfs_create_bin_file(&class_dev->kobj, &fw_priv->attr_data);
+
+ retval = sysfs_create_bin_file(&device->kobj, &fw_priv->attr_data);
if (retval) {
printk(KERN_ERR "%s: sysfs_create_bin_file failed\n",
__FUNCTION__);
- goto error_unreg;
+ goto out;
}
- retval = class_device_create_file(class_dev,
- &class_device_attr_loading);
- if (retval) {
- printk(KERN_ERR "%s: class_device_create_file failed\n",
- __FUNCTION__);
- goto error_unreg;
+ if (fw) {
+ retval = device_create_file(device, &dev_attr_post_status);
+ if (retval) {
+ printk(KERN_ERR "%s: device_create_file failed\n",
+ __FUNCTION__);
+ goto out;
+ }
}
-
set_bit(FW_STATUS_READY, &fw_priv->status);
- *class_dev_p = class_dev;
goto out;
-error_unreg:
- class_device_unregister(class_dev);
out:
return retval;
}
@@ -388,62 +317,79 @@
* should be distinctive enough not to be confused with any other
* firmware image for this or any other device.
**/
-int
-request_firmware(const struct firmware **firmware_p, const char *name,
+static int
+request(const struct firmware **firmware_p, const char *name,
struct device *device)
{
- struct class_device *class_dev;
struct firmware_priv *fw_priv;
- struct firmware *firmware;
+ struct firmware *firmware = NULL;
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;
+ if (firmware_p) {
+ *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));
}
- memset(firmware, 0, sizeof (*firmware));
- retval = fw_setup_class_device(firmware, &class_dev, name, device);
+ retval = fw_setup_device(firmware, name, device);
if (retval)
goto error_kfree_fw;
- fw_priv = class_get_devdata(class_dev);
+ fw_priv = device->post_data;
- if (loading_timeout) {
- fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
+ if (post_timeout) {
+ fw_priv->timeout.expires = jiffies + post_timeout * HZ;
add_timer(&fw_priv->timeout);
}
- kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
+ printk(KERN_ERR "request_firmware: hotplug event\n");
+ kobject_hotplug(&device->kobj, KOBJ_POST, post_hotplug);
wait_for_completion(&fw_priv->completion);
set_bit(FW_STATUS_DONE, &fw_priv->status);
+ printk(KERN_ERR "request_firmware: complete\n");
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;
+ if (firmware_p) {
+ 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);
+
+ sysfs_remove_bin_file(&device->kobj, &fw_priv->attr_data);
}
- fw_priv->fw = NULL;
- up(&fw_lock);
- class_device_unregister(class_dev);
+ device_remove_file(device, &dev_attr_post_status);
+
goto out;
error_kfree_fw:
- kfree(firmware);
- *firmware_p = NULL;
+ if (firmware) {
+ kfree(firmware);
+ *firmware_p = NULL;
+ }
out:
return retval;
}
+int
+request_firmware(const struct firmware **firmware_p, const char *name,
+ struct device *device)
+{
+ if (!firmware_p)
+ return -EINVAL;
+ return request(firmware_p, name, device);
+}
+EXPORT_SYMBOL(request_firmware);
+
/**
* release_firmware: - release the resource associated with a firmware image
**/
@@ -455,6 +401,7 @@
kfree(fw);
}
}
+EXPORT_SYMBOL(release_firmware);
/**
* register_firmware: - provide a firmware image for later usage
@@ -472,6 +419,7 @@
* decide if firmware caching is reasonable just leave it as a
* noop */
}
+EXPORT_SYMBOL(register_firmware);
/* Async support */
struct firmware_work {
@@ -480,11 +428,12 @@
const char *name;
struct device *device;
void *context;
- void (*cont)(const struct firmware *fw, void *context);
+ void (*cont_fw)(const struct firmware *fw, void *context);
+ void (*cont_post)(void *context);
};
static int
-request_firmware_work_func(void *arg)
+request_post_work_func(void *arg)
{
struct firmware_work *fw_work = arg;
const struct firmware *fw;
@@ -492,10 +441,15 @@
WARN_ON(1);
return 0;
}
- daemonize("%s/%s", "firmware", fw_work->name);
- request_firmware(&fw, fw_work->name, fw_work->device);
- fw_work->cont(fw, fw_work->context);
- release_firmware(fw);
+ daemonize("%s/%s", "post", fw_work->name);
+ if (fw_work->cont_fw) {
+ request(&fw, fw_work->name, fw_work->device);
+ fw_work->cont_fw(fw, fw_work->context);
+ release_firmware(fw);
+ } else {
+ request(NULL, fw_work->name, fw_work->device);
+ fw_work->cont_post(fw_work->context);
+ }
module_put(fw_work->module);
kfree(fw_work);
return 0;
@@ -515,11 +469,12 @@
* @fw may be %NULL if firmware request fails.
*
**/
-int
-request_firmware_nowait(
+static int
+request_nowait(
struct module *module,
const char *name, struct device *device, void *context,
- void (*cont)(const struct firmware *fw, void *context))
+ void (*cont_fw)(const struct firmware *fw, void *context),
+ void (*cont_post)(void *context))
{
struct firmware_work *fw_work = kmalloc(sizeof (struct firmware_work),
GFP_ATOMIC);
@@ -537,47 +492,37 @@
.name = name,
.device = device,
.context = context,
- .cont = cont,
+ .cont_fw = cont_fw,
+ .cont_post = cont_post,
};
- ret = kernel_thread(request_firmware_work_func, fw_work,
+ ret = kernel_thread(request_post_work_func, fw_work,
CLONE_FS | CLONE_FILES);
if (ret < 0) {
- fw_work->cont(NULL, fw_work->context);
+ if (fw_work->cont_fw)
+ fw_work->cont_fw(NULL, fw_work->context);
+ if (fw_work->cont_post)
+ fw_work->cont_post(fw_work->context);
return ret;
}
return 0;
}
-static int __init
-firmware_class_init(void)
+int
+request_firmware_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_fw)(const struct firmware *fw, void *context))
{
- int error;
- error = class_register(&firmware_class);
- if (error) {
- printk(KERN_ERR "%s: class_register failed\n", __FUNCTION__);
- return error;
- }
- error = class_create_file(&firmware_class, &class_attr_timeout);
- if (error) {
- printk(KERN_ERR "%s: class_create_file failed\n",
- __FUNCTION__);
- class_unregister(&firmware_class);
- }
- return error;
-
+ return request_nowait(module, name, device, context, cont_fw, NULL);
}
-static void __exit
-firmware_class_exit(void)
+EXPORT_SYMBOL(request_firmware_nowait);
+
+int
+request_post_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_post)(void *context))
{
- class_unregister(&firmware_class);
+ return request_nowait(module, name, device, context, NULL, cont_post);
}
-
-module_init(firmware_class_init);
-module_exit(firmware_class_exit);
-
-EXPORT_SYMBOL(release_firmware);
-EXPORT_SYMBOL(request_firmware);
-EXPORT_SYMBOL(request_firmware_nowait);
-EXPORT_SYMBOL(register_firmware);
+EXPORT_SYMBOL(request_post_nowait);
===== drivers/video/aty/radeon_base.c 1.44 vs edited =====
--- 1.44/drivers/video/aty/radeon_base.c 2005-03-10 03:39:11 -05:00
+++ edited/drivers/video/aty/radeon_base.c 2005-03-19 21:17:49 -05:00
@@ -71,6 +71,7 @@
#include <linux/vmalloc.h>
#include <linux/device.h>
#include <linux/i2c.h>
+#include <linux/firmware.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -2206,6 +2207,9 @@
.read = radeon_show_edid2,
};
+static void radeon_post_finished(void *data) {
+ printk(KERN_ERR "radeon_post_finished\n");
+}
static int radeonfb_pci_register (struct pci_dev *pdev,
const struct pci_device_id *ent)
@@ -2410,6 +2414,8 @@
}
#endif
+ request_post_nowait(THIS_MODULE, "vbios.vm86", &pdev->dev, rinfo, radeon_post_finished);
+
printk ("radeonfb (%s): %s\n", pci_name(rinfo->pdev), rinfo->name);
if (rinfo->bios_seg)
@@ -2453,7 +2459,19 @@
if (!rinfo)
return;
+ /* Register some sysfs stuff (should be done better) */
+ if (rinfo->mon1_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+ if (rinfo->mon2_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
+
radeonfb_pm_exit(rinfo);
+
+ /* Register some sysfs stuff (should be done better) */
+ if (rinfo->mon1_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid1_attr);
+ if (rinfo->mon2_EDID)
+ sysfs_remove_bin_file(&rinfo->pdev->dev.kobj, &edid2_attr);
#if 0
/* restore original state
===== include/linux/device.h 1.138 vs edited =====
--- 1.138/include/linux/device.h 2005-03-09 12:03:56 -05:00
+++ edited/include/linux/device.h 2005-03-19 11:11:34 -05:00
@@ -271,6 +271,7 @@
void *driver_data; /* data private to the driver */
void *platform_data; /* Platform specific data (e.g. ACPI,
BIOS data relevant to device) */
+ void *post_data; /* active during firmware load or post */
struct dev_pm_info power;
u32 detach_state; /* State to enter when device is
@@ -399,6 +400,7 @@
/* drivers/base/firmware.c */
extern int firmware_register(struct subsystem *);
extern void firmware_unregister(struct subsystem *);
+extern int post_timeout; /* In seconds */
/* debugging and troubleshooting/diagnostic helpers. */
#define dev_printk(level, dev, format, arg...) \
===== include/linux/firmware.h 1.3 vs edited =====
--- 1.3/include/linux/firmware.h 2005-02-02 04:49:28 -05:00
+++ edited/include/linux/firmware.h 2005-03-19 21:12:52 -05:00
@@ -1,20 +1,27 @@
#ifndef _LINUX_FIRMWARE_H
#define _LINUX_FIRMWARE_H
+#include <linux/device.h>
#include <linux/module.h>
#include <linux/types.h>
+
#define FIRMWARE_NAME_MAX 30
+
struct firmware {
size_t size;
u8 *data;
};
-struct device;
+
+int request_post_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_post)(void *context));
+
int request_firmware(const struct firmware **fw, const char *name,
struct device *device);
-int request_firmware_nowait(
- struct module *module,
- const char *name, struct device *device, void *context,
- void (*cont)(const struct firmware *fw, void *context));
-
+int request_firmware_nowait(struct module *module, const char *name,
+ struct device *device, void *context,
+ void (*cont_fw)(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
===== include/linux/kobject.h 1.39 vs edited =====
--- 1.39/include/linux/kobject.h 2005-03-09 12:04:09 -05:00
+++ edited/include/linux/kobject.h 2005-03-19 01:32:55 -05:00
@@ -242,13 +242,19 @@
extern void subsys_remove_file(struct subsystem * , struct subsys_attribute *);
#ifdef CONFIG_HOTPLUG
-void kobject_hotplug(struct kobject *kobj, enum kobject_action action);
+void kobject_hotplug(struct kobject *kobj, enum kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+ );
int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
char *buffer, int buffer_size, int *cur_len,
const char *format, ...)
__attribute__((format (printf, 7, 8)));
#else
-static inline void kobject_hotplug(struct kobject *kobj, enum kobject_action action) { }
+static inline void kobject_hotplug(struct kobject *kobj, enum kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+ ) { }
static inline int add_hotplug_env_var(char **envp, int num_envp, int *cur_index,
char *buffer, int buffer_size, int *cur_len,
const char *format, ...)
===== include/linux/kobject_uevent.h 1.6 vs edited =====
--- 1.6/include/linux/kobject_uevent.h 2004-11-08 14:43:30 -05:00
+++ edited/include/linux/kobject_uevent.h 2005-03-17 10:36:00 -05:00
@@ -29,6 +29,7 @@
KOBJ_UMOUNT = (__force kobject_action_t) 0x05, /* umount event for block devices */
KOBJ_OFFLINE = (__force kobject_action_t) 0x06, /* offline event for hotplug devices */
KOBJ_ONLINE = (__force kobject_action_t) 0x07, /* online event for hotplug devices */
+ KOBJ_POST = (__force kobject_action_t) 0x08, /* post event supports user space initialization */
};
===== lib/kobject.c 1.58 vs edited =====
--- 1.58/lib/kobject.c 2005-03-09 12:04:09 -05:00
+++ edited/lib/kobject.c 2005-03-19 01:39:37 -05:00
@@ -185,7 +185,7 @@
if (parent)
kobject_put(parent);
} else {
- kobject_hotplug(kobj, KOBJ_ADD);
+ kobject_hotplug(kobj, KOBJ_ADD, NULL);
}
return error;
@@ -301,7 +301,7 @@
void kobject_del(struct kobject * kobj)
{
- kobject_hotplug(kobj, KOBJ_REMOVE);
+ kobject_hotplug(kobj, KOBJ_REMOVE, NULL);
sysfs_remove_dir(kobj);
unlink(kobj);
}
===== lib/kobject_uevent.c 1.18 vs edited =====
--- 1.18/lib/kobject_uevent.c 2005-01-08 00:44:13 -05:00
+++ edited/lib/kobject_uevent.c 2005-03-19 01:48:04 -05:00
@@ -44,6 +44,8 @@
return "offline";
case KOBJ_ONLINE:
return "online";
+ case KOBJ_POST:
+ return "post";
default:
return NULL;
}
@@ -187,7 +189,9 @@
* @action: action that is happening (usually "ADD" or "REMOVE")
* @kobj: struct kobject that the action is happening to
*/
-void kobject_hotplug(struct kobject *kobj, enum kobject_action action)
+void kobject_hotplug(struct kobject *kobj, enum kobject_action action,
+ int (*hotplug)(struct kset *kset, struct kobject *kobj, char **envp,
+ int num_envp, char *buffer, int buffer_size))
{
char *argv [3];
char **envp = NULL;
@@ -279,6 +283,17 @@
if (hotplug_ops->hotplug) {
/* have the kset specific function add its stuff */
retval = hotplug_ops->hotplug (kset, kobj,
+ &envp[i], NUM_ENVP - i, scratch,
+ BUFFER_SIZE - (scratch - buffer));
+ if (retval) {
+ pr_debug ("%s - hotplug() returned %d\n",
+ __FUNCTION__, retval);
+ goto exit;
+ }
+ }
+ if (hotplug) {
+ /* have the call specific function add on its stuff */
+ retval = hotplug (kset, kobj,
&envp[i], NUM_ENVP - i, scratch,
BUFFER_SIZE - (scratch - buffer));
if (retval) {
[-- Attachment #3: 30-post.hotplug --]
[-- Type: application/octet-stream, Size: 1343 bytes --]
#!/bin/sh
#
# Firmware-specific hotplug policy agent.
#
# Kernel firmware hotplug params include:
#
# ACTION=%s [add or remove]
# DEVPATH=%s [in 2.5 kernels, /sys/$DEVPATH]
# FIRMWARE=%s
#
# HISTORY:
#
# 24-Jul-2003 Initial version of "new" hotplug agent.
#
# $Id: firmware.agent,v 1.3 2004/03/14 15:52:56 ukai Exp $
#
cd /etc/hotplug
. ./hotplug.functions
# DEBUG=yes export DEBUG
# directory of the firmware files
FIRMWARE_DIR=/lib/firmware
# mountpoint of sysfs
SYSFS=$(sed -n 's/^.* \([^ ]*\) sysfs .*$/\1/p' /proc/mounts)
# use /proc for 2.4 kernels
if [ "$SYSFS" = "" ]; then
SYSFS=/proc
fi
#
# What to do with this firmware hotplug event?
#
case "$ACTION" in
post)
if [ ! -e $SYSFS/$DEVPATH/post_status ]; then
sleep 1
fi
if [ "$FIRMWARE" != "" ]; then
if [ -f "$FIRMWARE_DIR/$FIRMWARE" ]; then
echo 1 > $SYSFS/$DEVPATH/post_status
cp "$FIRMWARE_DIR/$FIRMWARE" $SYSFS/$DEVPATH/post_data
echo 0 > $SYSFS/$DEVPATH/post_status
else
echo -1 > $SYSFS/$DEVPATH/post_status
fi
fi
if [ "$POST" != "" ]; then
echo "Posting! $POST" >/post
echo 1 > $SYSFS/$DEVPATH/post_status
exec $POST "$@"
echo 0 > $SYSFS/$DEVPATH/post_status
echo "Posted! $POST" >>/post
fi
;;
*)
;;
esac
next reply other threads:[~2005-03-20 4:06 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2005-03-20 4:06 Jon Smirl [this message]
2005-03-20 13:37 ` Rework of request firmware Kay Sievers
2005-03-20 15:35 ` Jon Smirl
2005-03-20 16:47 ` Jon Smirl
2005-03-20 17:16 ` Kay Sievers
2005-03-20 17:19 ` David Zeuthen
2005-03-20 17:39 ` Kay Sievers
2005-03-20 17:52 ` Kay Sievers
2005-03-20 17:52 ` Darren Salt
2005-03-20 18:00 ` Kay Sievers
2005-03-20 18:24 ` Jon Smirl
2005-03-20 19:02 ` Jon Smirl
2005-03-20 19:17 ` Kay Sievers
2005-03-20 19:27 ` Kay Sievers
2005-03-20 19:50 ` Jon Smirl
2005-03-20 20:25 ` Kay Sievers
2005-03-20 20:39 ` Jon Smirl
2005-03-21 2:37 ` Kay Sievers
2005-03-22 0:29 ` Linas Vepstas
2005-03-22 2:25 ` Kay Sievers
2005-03-22 3:06 ` Jon Smirl
2005-03-22 8:27 ` Roman Kagan
2005-03-22 10:45 ` Kay Sievers
2005-03-22 10:55 ` Kay Sievers
2005-03-22 14:37 ` Jon Smirl
2005-03-22 17:53 ` Linas Vepstas
2005-03-22 18:09 ` Linas Vepstas
2005-03-22 18:43 ` Jon Smirl
2005-03-23 1:08 ` Greg KH
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=9e473391050319200625032789@mail.gmail.com \
--to=jonsmirl@gmail.com \
--cc=linux-hotplug@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).