/*
* scan.c - support for transforming the ACPI namespace into individual objects
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
#define _COMPONENT ACPI_BUS_COMPONENT
ACPI_MODULE_NAME("scan")
#define STRUCT_TO_INT(s) (*((int*)&s))
extern struct acpi_device *acpi_root;
#define ACPI_BUS_CLASS "system_bus"
#define ACPI_BUS_HID "ACPI_BUS"
#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver"
#define ACPI_BUS_DEVICE_NAME "System Bus"
static LIST_HEAD(acpi_device_list);
DEFINE_SPINLOCK(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
static void acpi_device_release(struct kobject *kobj)
{
struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
kfree(dev->pnp.cid_list);
kfree(dev);
}
struct acpi_device_attribute {
struct attribute attr;
ssize_t(*show) (struct acpi_device *, char *);
ssize_t(*store) (struct acpi_device *, const char *, size_t);
};
typedef void acpi_device_sysfs_files(struct kobject *,
const struct attribute *);
static void setup_sys_fs_device_files(struct acpi_device *dev,
acpi_device_sysfs_files * func);
#define create_sysfs_device_files(dev) \
setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
#define remove_sysfs_device_files(dev) \
setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
static ssize_t acpi_device_attr_show(struct kobject *kobj,
struct attribute *attr, char *buf)
{
struct acpi_device *device = to_acpi_device(kobj);
struct acpi_device_attribute *attribute = to_handle_attr(attr);
return attribute->show ? attribute->show(device, buf) : -EIO;
}
static ssize_t acpi_device_attr_store(struct kobject *kobj,
struct attribute *attr, const char *buf,
size_t len)
{
struct acpi_device *device = to_acpi_device(kobj);
struct acpi_device_attribute *attribute = to_handle_attr(attr);
return attribute->store ? attribute->store(device, buf, len) : -EIO;
}
static struct sysfs_ops acpi_device_sysfs_ops = {
.show = acpi_device_attr_show,
.store = acpi_device_attr_store,
};
static struct kobj_type ktype_acpi_ns = {
.sysfs_ops = &acpi_device_sysfs_ops,
.release = acpi_device_release,
};
static int namespace_uevent(struct kset *kset, struct kobject *kobj,
char **envp, int num_envp, char *buffer,
int buffer_size)
{
struct acpi_device *dev = to_acpi_device(kobj);
int i = 0;
int len = 0;
if (!dev->driver)
return 0;
if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
"PHYSDEVDRIVER=%s", dev->driver->name))
return -ENOMEM;
envp[i] = NULL;
return 0;
}
static struct kset_uevent_ops namespace_uevent_ops = {
.uevent = &namespace_uevent,
};
static struct kset acpi_namespace_kset = {
.kobj = {
.name = "namespace",
},
.subsys = &acpi_subsys,
.ktype = &ktype_acpi_ns,
.uevent_ops = &namespace_uevent_ops,
};
static void acpi_device_register(struct acpi_device *device,
struct acpi_device *parent)
{
/*
* Linkage
* -------
* Link this device to its parent and siblings.
*/
INIT_LIST_HEAD(&device->children);
INIT_LIST_HEAD(&device->node);
INIT_LIST_HEAD(&d
|