Commit 312c004d authored by Kay Sievers's avatar Kay Sievers Committed by Greg Kroah-Hartman

[PATCH] driver core: replace "hotplug" by "uevent"

Leave the overloaded "hotplug" word to susbsystems which are handling
real devices. The driver core does not "plug" anything, it just exports
the state to userspace and generates events.
Signed-off-by: default avatarKay Sievers <kay.sievers@suse.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 5f123fbd
...@@ -115,7 +115,7 @@ Current PPC64 Linux EEH Implementation ...@@ -115,7 +115,7 @@ Current PPC64 Linux EEH Implementation
At this time, a generic EEH recovery mechanism has been implemented, At this time, a generic EEH recovery mechanism has been implemented,
so that individual device drivers do not need to be modified to support so that individual device drivers do not need to be modified to support
EEH recovery. This generic mechanism piggy-backs on the PCI hotplug EEH recovery. This generic mechanism piggy-backs on the PCI hotplug
infrastructure, and percolates events up through the hotplug/udev infrastructure, and percolates events up through the userspace/udev
infrastructure. Followiing is a detailed description of how this is infrastructure. Followiing is a detailed description of how this is
accomplished. accomplished.
...@@ -172,7 +172,7 @@ A handler for the EEH notifier_block events is implemented in ...@@ -172,7 +172,7 @@ A handler for the EEH notifier_block events is implemented in
drivers/pci/hotplug/pSeries_pci.c, called handle_eeh_events(). drivers/pci/hotplug/pSeries_pci.c, called handle_eeh_events().
It saves the device BAR's and then calls rpaphp_unconfig_pci_adapter(). It saves the device BAR's and then calls rpaphp_unconfig_pci_adapter().
This last call causes the device driver for the card to be stopped, This last call causes the device driver for the card to be stopped,
which causes hotplug events to go out to user space. This triggers which causes uevents to go out to user space. This triggers
user-space scripts that might issue commands such as "ifdown eth0" user-space scripts that might issue commands such as "ifdown eth0"
for ethernet cards, and so on. This handler then sleeps for 5 seconds, for ethernet cards, and so on. This handler then sleeps for 5 seconds,
hoping to give the user-space scripts enough time to complete. hoping to give the user-space scripts enough time to complete.
...@@ -258,29 +258,30 @@ rpa_php_unconfig_pci_adapter() { // in rpaphp_pci.c ...@@ -258,29 +258,30 @@ rpa_php_unconfig_pci_adapter() { // in rpaphp_pci.c
calls calls
pci_destroy_dev (struct pci_dev *) { pci_destroy_dev (struct pci_dev *) {
calls calls
device_unregister (&dev->dev) { // in /drivers/base/core.c device_unregister (&dev->dev) { // in /drivers/base/core.c
calls calls
device_del(struct device * dev) { // in /drivers/base/core.c device_del(struct device * dev) { // in /drivers/base/core.c
calls calls
kobject_del() { //in /libs/kobject.c kobject_del() { //in /libs/kobject.c
calls calls
kobject_hotplug() { // in /libs/kobject.c kobject_uevent() { // in /libs/kobject.c
calls calls
kset_hotplug() { // in /lib/kobject.c kset_uevent() { // in /lib/kobject.c
calls calls
kset->hotplug_ops->hotplug() which is really just kset->uevent_ops->uevent() // which is really just
a call to a call to
dev_hotplug() { // in /drivers/base/core.c dev_uevent() { // in /drivers/base/core.c
calls calls
dev->bus->hotplug() which is really just a call to dev->bus->uevent() which is really just a call to
pci_hotplug () { // in drivers/pci/hotplug.c pci_uevent () { // in drivers/pci/hotplug.c
which prints device name, etc.... which prints device name, etc....
} }
} }
then kset_hotplug() calls then kobject_uevent() sends a netlink uevent to userspace
call_usermodehelper () with --> userspace uevent
argv[0]=hotplug_path[] which is "/sbin/hotplug" (during early boot, nobody listens to netlink events and
--> event to userspace, kobject_uevent() executes uevent_helper[], which runs the
event process /sbin/hotplug)
} }
} }
kobject_del() then calls sysfs_remove_dir(), which would kobject_del() then calls sysfs_remove_dir(), which would
......
...@@ -293,6 +293,6 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp, ...@@ -293,6 +293,6 @@ static int vio_hotplug(struct device *dev, char **envp, int num_envp,
struct bus_type vio_bus_type = { struct bus_type vio_bus_type = {
.name = "vio", .name = "vio",
.hotplug = vio_hotplug, .uevent = vio_hotplug,
.match = vio_bus_match, .match = vio_bus_match,
}; };
...@@ -358,7 +358,7 @@ static struct sysfs_ops disk_sysfs_ops = { ...@@ -358,7 +358,7 @@ static struct sysfs_ops disk_sysfs_ops = {
static ssize_t disk_uevent_store(struct gendisk * disk, static ssize_t disk_uevent_store(struct gendisk * disk,
const char *buf, size_t count) const char *buf, size_t count)
{ {
kobject_hotplug(&disk->kobj, KOBJ_ADD); kobject_uevent(&disk->kobj, KOBJ_ADD);
return count; return count;
} }
static ssize_t disk_dev_read(struct gendisk * disk, char *page) static ssize_t disk_dev_read(struct gendisk * disk, char *page)
...@@ -455,14 +455,14 @@ static struct kobj_type ktype_block = { ...@@ -455,14 +455,14 @@ static struct kobj_type ktype_block = {
extern struct kobj_type ktype_part; extern struct kobj_type ktype_part;
static int block_hotplug_filter(struct kset *kset, struct kobject *kobj) static int block_uevent_filter(struct kset *kset, struct kobject *kobj)
{ {
struct kobj_type *ktype = get_ktype(kobj); struct kobj_type *ktype = get_ktype(kobj);
return ((ktype == &ktype_block) || (ktype == &ktype_part)); return ((ktype == &ktype_block) || (ktype == &ktype_part));
} }
static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp, static int block_uevent(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size) int num_envp, char *buffer, int buffer_size)
{ {
struct kobj_type *ktype = get_ktype(kobj); struct kobj_type *ktype = get_ktype(kobj);
...@@ -474,40 +474,40 @@ static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp, ...@@ -474,40 +474,40 @@ static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
if (ktype == &ktype_block) { if (ktype == &ktype_block) {
disk = container_of(kobj, struct gendisk, kobj); disk = container_of(kobj, struct gendisk, kobj);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u", disk->first_minor); &length, "MINOR=%u", disk->first_minor);
} else if (ktype == &ktype_part) { } else if (ktype == &ktype_part) {
disk = container_of(kobj->parent, struct gendisk, kobj); disk = container_of(kobj->parent, struct gendisk, kobj);
part = container_of(kobj, struct hd_struct, kobj); part = container_of(kobj, struct hd_struct, kobj);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "MINOR=%u", &length, "MINOR=%u",
disk->first_minor + part->partno); disk->first_minor + part->partno);
} else } else
return 0; return 0;
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &length, add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
"MAJOR=%u", disk->major); "MAJOR=%u", disk->major);
/* add physical device, backing this device */ /* add physical device, backing this device */
physdev = disk->driverfs_dev; physdev = disk->driverfs_dev;
if (physdev) { if (physdev) {
char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL); char *path = kobject_get_path(&physdev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path); &length, "PHYSDEVPATH=%s", path);
kfree(path); kfree(path);
if (physdev->bus) if (physdev->bus)
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"PHYSDEVBUS=%s", "PHYSDEVBUS=%s",
physdev->bus->name); physdev->bus->name);
if (physdev->driver) if (physdev->driver)
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", "PHYSDEVDRIVER=%s",
physdev->driver->name); physdev->driver->name);
} }
/* terminate, set to next free slot, shrink available space */ /* terminate, set to next free slot, shrink available space */
...@@ -520,13 +520,13 @@ static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp, ...@@ -520,13 +520,13 @@ static int block_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
return 0; return 0;
} }
static struct kset_hotplug_ops block_hotplug_ops = { static struct kset_uevent_ops block_uevent_ops = {
.filter = block_hotplug_filter, .filter = block_uevent_filter,
.hotplug = block_hotplug, .uevent = block_uevent,
}; };
/* declare block_subsys. */ /* declare block_subsys. */
static decl_subsys(block, &ktype_block, &block_hotplug_ops); static decl_subsys(block, &ktype_block, &block_uevent_ops);
/* /*
......
...@@ -172,21 +172,21 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context) ...@@ -172,21 +172,21 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (ACPI_FAILURE(status) || !device) { if (ACPI_FAILURE(status) || !device) {
result = container_device_add(&device, handle); result = container_device_add(&device, handle);
if (!result) if (!result)
kobject_hotplug(&device->kobj, kobject_uevent(&device->kobj,
KOBJ_ONLINE); KOBJ_ONLINE);
else else
printk("Failed to add container\n"); printk("Failed to add container\n");
} }
} else { } else {
if (ACPI_SUCCESS(status)) { if (ACPI_SUCCESS(status)) {
/* device exist and this is a remove request */ /* device exist and this is a remove request */
kobject_hotplug(&device->kobj, KOBJ_OFFLINE); kobject_uevent(&device->kobj, KOBJ_OFFLINE);
} }
} }
break; break;
case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_NOTIFY_EJECT_REQUEST:
if (!acpi_bus_get_device(handle, &device) && device) { if (!acpi_bus_get_device(handle, &device) && device) {
kobject_hotplug(&device->kobj, KOBJ_OFFLINE); kobject_uevent(&device->kobj, KOBJ_OFFLINE);
} }
break; break;
default: default:
......
...@@ -748,7 +748,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device) ...@@ -748,7 +748,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
if ((pr->id >= 0) && (pr->id < NR_CPUS)) { if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE); kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
} }
return_VALUE(0); return_VALUE(0);
} }
...@@ -788,13 +788,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) ...@@ -788,13 +788,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
} }
if (pr->id >= 0 && (pr->id < NR_CPUS)) { if (pr->id >= 0 && (pr->id < NR_CPUS)) {
kobject_hotplug(&device->kobj, KOBJ_OFFLINE); kobject_uevent(&device->kobj, KOBJ_OFFLINE);
break; break;
} }
result = acpi_processor_start(device); result = acpi_processor_start(device);
if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) { if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
kobject_hotplug(&device->kobj, KOBJ_ONLINE); kobject_uevent(&device->kobj, KOBJ_ONLINE);
} else { } else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device [%s] failed to start\n", "Device [%s] failed to start\n",
...@@ -818,7 +818,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data) ...@@ -818,7 +818,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
} }
if ((pr->id < NR_CPUS) && (cpu_present(pr->id))) if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
kobject_hotplug(&device->kobj, KOBJ_OFFLINE); kobject_uevent(&device->kobj, KOBJ_OFFLINE);
break; break;
default: default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
......
...@@ -78,7 +78,7 @@ static struct kobj_type ktype_acpi_ns = { ...@@ -78,7 +78,7 @@ static struct kobj_type ktype_acpi_ns = {
.release = acpi_device_release, .release = acpi_device_release,
}; };
static int namespace_hotplug(struct kset *kset, struct kobject *kobj, static int namespace_uevent(struct kset *kset, struct kobject *kobj,
char **envp, int num_envp, char *buffer, char **envp, int num_envp, char *buffer,
int buffer_size) int buffer_size)
{ {
...@@ -89,8 +89,8 @@ static int namespace_hotplug(struct kset *kset, struct kobject *kobj, ...@@ -89,8 +89,8 @@ static int namespace_hotplug(struct kset *kset, struct kobject *kobj,
if (!dev->driver) if (!dev->driver)
return 0; return 0;
if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len, if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
"PHYSDEVDRIVER=%s", dev->driver->name)) "PHYSDEVDRIVER=%s", dev->driver->name))
return -ENOMEM; return -ENOMEM;
envp[i] = NULL; envp[i] = NULL;
...@@ -98,8 +98,8 @@ static int namespace_hotplug(struct kset *kset, struct kobject *kobj, ...@@ -98,8 +98,8 @@ static int namespace_hotplug(struct kset *kset, struct kobject *kobj,
return 0; return 0;
} }
static struct kset_hotplug_ops namespace_hotplug_ops = { static struct kset_uevent_ops namespace_uevent_ops = {
.hotplug = &namespace_hotplug, .uevent = &namespace_uevent,
}; };
static struct kset acpi_namespace_kset = { static struct kset acpi_namespace_kset = {
...@@ -108,7 +108,7 @@ static struct kset acpi_namespace_kset = { ...@@ -108,7 +108,7 @@ static struct kset acpi_namespace_kset = {
}, },
.subsys = &acpi_subsys, .subsys = &acpi_subsys,
.ktype = &ktype_acpi_ns, .ktype = &ktype_acpi_ns,
.hotplug_ops = &namespace_hotplug_ops, .uevent_ops = &namespace_uevent_ops,
}; };
static void acpi_device_register(struct acpi_device *device, static void acpi_device_register(struct acpi_device *device,
...@@ -347,7 +347,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) ...@@ -347,7 +347,7 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
} }
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
ACPI hotplug sysfs device file support ACPI sysfs device file support
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static ssize_t acpi_eject_store(struct acpi_device *device, static ssize_t acpi_eject_store(struct acpi_device *device,
const char *buf, size_t count); const char *buf, size_t count);
......
...@@ -19,11 +19,11 @@ config PREVENT_FIRMWARE_BUILD ...@@ -19,11 +19,11 @@ config PREVENT_FIRMWARE_BUILD
If unsure say Y here. If unsure say Y here.
config FW_LOADER config FW_LOADER
tristate "Hotplug firmware loading support" tristate "Userspace firmware loading support"
select HOTPLUG select HOTPLUG
---help--- ---help---
This option is provided for the case where no in-kernel-tree modules This option is provided for the case where no in-kernel-tree modules
require hotplug firmware loading support, but a module built outside require userspace firmware loading support, but a module built outside
the kernel tree does. the kernel tree does.
config DEBUG_DRIVER config DEBUG_DRIVER
......
...@@ -178,7 +178,7 @@ static void class_device_create_release(struct class_device *class_dev) ...@@ -178,7 +178,7 @@ static void class_device_create_release(struct class_device *class_dev)
} }
/* needed to allow these devices to have parent class devices */ /* needed to allow these devices to have parent class devices */
static int class_device_create_hotplug(struct class_device *class_dev, static int class_device_create_uevent(struct class_device *class_dev,
char **envp, int num_envp, char **envp, int num_envp,
char *buffer, int buffer_size) char *buffer, int buffer_size)
{ {
...@@ -331,7 +331,7 @@ static struct kobj_type ktype_class_device = { ...@@ -331,7 +331,7 @@ static struct kobj_type ktype_class_device = {
.release = class_dev_release, .release = class_dev_release,
}; };
static int class_hotplug_filter(struct kset *kset, struct kobject *kobj) static int class_uevent_filter(struct kset *kset, struct kobject *kobj)
{ {
struct kobj_type *ktype = get_ktype(kobj); struct kobj_type *ktype = get_ktype(kobj);
...@@ -343,14 +343,14 @@ static int class_hotplug_filter(struct kset *kset, struct kobject *kobj) ...@@ -343,14 +343,14 @@ static int class_hotplug_filter(struct kset *kset, struct kobject *kobj)
return 0; return 0;
} }
static const char *class_hotplug_name(struct kset *kset, struct kobject *kobj) static const char *class_uevent_name(struct kset *kset, struct kobject *kobj)
{ {
struct class_device *class_dev = to_class_dev(kobj); struct class_device *class_dev = to_class_dev(kobj);
return class_dev->class->name; return class_dev->class->name;
} }
static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp, static int class_uevent(struct kset *kset, struct kobject *kobj, char **envp,
int num_envp, char *buffer, int buffer_size) int num_envp, char *buffer, int buffer_size)
{ {
struct class_device *class_dev = to_class_dev(kobj); struct class_device *class_dev = to_class_dev(kobj);
...@@ -365,29 +365,29 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp, ...@@ -365,29 +365,29 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
struct device *dev = class_dev->dev; struct device *dev = class_dev->dev;
char *path = kobject_get_path(&dev->kobj, GFP_KERNEL); char *path = kobject_get_path(&dev->kobj, GFP_KERNEL);
add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
&length, "PHYSDEVPATH=%s", path); &length, "PHYSDEVPATH=%s", path);
kfree(path); kfree(path);
if (dev->bus) if (dev->bus)
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"PHYSDEVBUS=%s", dev->bus->name); "PHYSDEVBUS=%s", dev->bus->name);
if (dev->driver) if (dev->driver)
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"PHYSDEVDRIVER=%s", dev->driver->name); "PHYSDEVDRIVER=%s", dev->driver->name);
} }
if (MAJOR(class_dev->devt)) { if (MAJOR(class_dev->devt)) {
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"MAJOR=%u", MAJOR(class_dev->devt)); "MAJOR=%u", MAJOR(class_dev->devt));
add_hotplug_env_var(envp, num_envp, &i, add_uevent_var(envp, num_envp, &i,
buffer, buffer_size, &length, buffer, buffer_size, &length,
"MINOR=%u", MINOR(class_dev->devt)); "MINOR=%u", MINOR(class_dev->devt));
} }
/* terminate, set to next free slot, shrink available space */ /* terminate, set to next free slot, shrink available space */
...@@ -397,30 +397,30 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp, ...@@ -397,30 +397,30 @@ static int class_hotplug(struct kset *kset, struct kobject *kobj, char **envp,
buffer = &buffer[length]; buffer = &buffer[length];
buffer_size -= length; buffer_size -= length;
if (class_dev->hotplug) { if (class_dev->uevent) {
/* have the class device specific function add its stuff */ /* have the class device specific function add its stuff */
retval = class_dev->hotplug(class_dev, envp, num_envp, retval = class_dev->uevent(class_dev, envp, num_envp,
buffer, buffer_size); buffer, buffer_size);
if (retval) if (retval)
pr_debug("class_dev->hotplug() returned %d\n", retval); pr_debug("class_dev->uevent() returned %d\n", retval);
} else if (class_dev->class->hotplug) { } else if (class_dev->class->uevent) {
/* have the class specific function add its stuff */ /* have the class specific function add its stuff */
retval = class_dev->class->hotplug(class_dev, envp, num_envp, retval = class_dev->class->uevent(class_dev, envp, num_envp,
buffer, buffer_size); buffer, buffer_size);
if (retval) if (retval)
pr_debug("class->hotplug() returned %d\n", retval); pr_debug("class->uevent() returned %d\n", retval);
} }
return retval; return retval;
} }
static struct kset_hotplug_ops class_hotplug_ops = { static struct kset_uevent_ops class_uevent_ops = {
.filter = class_hotplug_filter, .filter = class_uevent_filter,
.name = class_hotplug_name, .name = class_uevent_name,
.hotplug = class_hotplug, .uevent = class_uevent,
}; };
static decl_subsys(class_obj, &ktype_class_device, &class_hotplug_ops); static decl_subsys(class_obj, &ktype_class_device, &class_uevent_ops);
static int class_device_add_attrs(struct class_device * cd) static int class_device_add_attrs(struct class_device * cd)
...@@ -464,7 +464,7 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf) ...@@ -464,7 +464,7 @@ static ssize_t show_dev(struct class_device *class_dev, char *buf)
static ssize_t store_uevent(struct class_device *class_dev, static ssize_t store_uevent(struct class_device *class_dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
kobject_hotplug(&class_dev->kobj, KOBJ_ADD); kobject_uevent(&class_dev->kobj, KOBJ_ADD);
return count; return count;
} }
...@@ -559,7 +559,7 @@ int class_device_add(struct class_device *class_dev) ...@@ -559,7 +559,7 @@ int class_device_add(struct class_device *class_dev)
class_name); class_name);
} }
kobject_hotplug(&class_dev->kobj, KOBJ_ADD); kobject_uevent(&class_dev->kobj, KOBJ_ADD);
/* notify any interfaces this device is now here */ /* notify any interfaces this device is now here */
if (parent_class) { if (parent_class) {
...@@ -632,7 +632,7 @@ struct class_device *class_device_create(struct class *cls, ...@@ -632,7 +632,7 @@ struct class_device *class_device_create(struct class *cls,