*
*/
+#include <linux/config.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/kdev_t.h>
#include <asm/semaphore.h>
* sysfs bindings for devices.
*/
-/**
- * dev_driver_string - Return a device's driver name, if at all possible
- * @dev: struct device to get the name of
- *
- * Will return the device's driver's name if it is bound to a device. If
- * the device is not bound to a device, it will return the name of the bus
- * it is attached to. If it is not attached to a bus either, an empty
- * string will be returned.
- */
-const char *dev_driver_string(struct device *dev)
-{
- return dev->driver ? dev->driver->name :
- (dev->bus ? dev->bus->name : "");
-}
-EXPORT_SYMBOL_GPL(dev_driver_string);
-
#define to_dev(obj) container_of(obj, struct device, kobj)
#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr)
struct device *dev = to_dev(kobj);
if (dev->bus)
return 1;
- if (dev->class)
- return 1;
}
return 0;
}
{
struct device *dev = to_dev(kobj);
- if (dev->bus)
- return dev->bus->name;
- if (dev->class)
- return dev->class->name;
- return NULL;
+ return dev->bus->name;
}
static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
int length = 0;
int retval = 0;
- /* add the major/minor if present */
- if (MAJOR(dev->devt)) {
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MAJOR=%u", MAJOR(dev->devt));
- add_uevent_var(envp, num_envp, &i,
- buffer, buffer_size, &length,
- "MINOR=%u", MINOR(dev->devt));
- }
-
/* add bus name of physical device */
if (dev->bus)
add_uevent_var(envp, num_envp, &i,
return count;
}
-static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- return print_dev_t(buf, dev->devt);
-}
-
/*
* devices_subsys - structure to be registered with kobject core.
*/
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
- INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
device_init_wakeup(dev, 0);
}
int device_add(struct device *dev)
{
struct device *parent = NULL;
- char *class_name = NULL;
int error = -EINVAL;
dev = get_device(dev);
dev->uevent_attr.store = store_uevent;
device_create_file(dev, &dev->uevent_attr);
- if (MAJOR(dev->devt)) {
- struct device_attribute *attr;
- attr = kzalloc(sizeof(*attr), GFP_KERNEL);
- if (!attr) {
- error = -ENOMEM;
- goto PMError;
- }
- attr->attr.name = "dev";
- attr->attr.mode = S_IRUGO;
- if (dev->driver)
- attr->attr.owner = dev->driver->owner;
- attr->show = show_dev;
- error = device_create_file(dev, attr);
- if (error) {
- kfree(attr);
- goto attrError;
- }
-
- dev->devt_attr = attr;
- }
-
- if (dev->class) {
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kset.kobj,
- "subsystem");
- sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj,
- dev->bus_id);
-
- sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
- }
-
+ kobject_uevent(&dev->kobj, KOBJ_ADD);
if ((error = device_pm_add(dev)))
goto PMError;
if ((error = bus_add_device(dev)))
goto BusError;
- kobject_uevent(&dev->kobj, KOBJ_ADD);
- bus_attach_device(dev);
if (parent)
klist_add_tail(&dev->knode_parent, &parent->klist_children);
- if (dev->class) {
- /* tie the class to the device */
- down(&dev->class->sem);
- list_add_tail(&dev->node, &dev->class->devices);
- up(&dev->class->sem);
- }
-
/* notify platform of device entry */
if (platform_notify)
platform_notify(dev);
Done:
- kfree(class_name);
put_device(dev);
return error;
BusError:
device_pm_remove(dev);
PMError:
- if (dev->devt_attr) {
- device_remove_file(dev, dev->devt_attr);
- kfree(dev->devt_attr);
- }
- attrError:
kobject_uevent(&dev->kobj, KOBJ_REMOVE);
kobject_del(&dev->kobj);
Error:
void device_del(struct device * dev)
{
struct device * parent = dev->parent;
- char *class_name = NULL;
if (parent)
klist_del(&dev->knode_parent);
- if (dev->devt_attr)
- device_remove_file(dev, dev->devt_attr);
- if (dev->class) {
- sysfs_remove_link(&dev->kobj, "subsystem");
- sysfs_remove_link(&dev->class->subsys.kset.kobj, dev->bus_id);
- class_name = make_class_name(dev->class->name, &dev->kobj);
- sysfs_remove_link(&dev->kobj, "device");
- sysfs_remove_link(&dev->parent->kobj, class_name);
- kfree(class_name);
- down(&dev->class->sem);
- list_del_init(&dev->node);
- up(&dev->class->sem);
- }
device_remove_file(dev, &dev->uevent_attr);
/* Notify the platform of the removal, in case they
EXPORT_SYMBOL_GPL(device_create_file);
EXPORT_SYMBOL_GPL(device_remove_file);
-
-
-static void device_create_release(struct device *dev)
-{
- pr_debug("%s called for %s\n", __FUNCTION__, dev->bus_id);
- kfree(dev);
-}
-
-/**
- * device_create - creates a device and registers it with sysfs
- * @class: pointer to the struct class that this device should be registered to
- * @parent: pointer to the parent struct device of this new device, if any
- * @devt: the dev_t for the char device to be added
- * @fmt: string for the device's name
- *
- * This function can be used by char device classes. A struct device
- * will be created in sysfs, registered to the specified class.
- *
- * A "dev" file will be created, showing the dev_t for the device, if
- * the dev_t is not 0,0.
- * If a pointer to a parent struct device is passed in, the newly created
- * struct device will be a child of that device in sysfs.
- * The pointer to the struct device will be returned from the call.
- * Any further sysfs files that might be required can be created using this
- * pointer.
- *
- * Note: the struct class passed to this function must have previously
- * been created with a call to class_create().
- */
-struct device *device_create(struct class *class, struct device *parent,
- dev_t devt, char *fmt, ...)
-{
- va_list args;
- struct device *dev = NULL;
- int retval = -ENODEV;
-
- if (class == NULL || IS_ERR(class))
- goto error;
- if (parent == NULL) {
- printk(KERN_WARNING "%s does not work yet for NULL parents\n", __FUNCTION__);
- goto error;
- }
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- retval = -ENOMEM;
- goto error;
- }
-
- dev->devt = devt;
- dev->class = class;
- dev->parent = parent;
- dev->release = device_create_release;
-
- va_start(args, fmt);
- vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args);
- va_end(args);
- retval = device_register(dev);
- if (retval)
- goto error;
-
- return dev;
-
-error:
- kfree(dev);
- return ERR_PTR(retval);
-}
-EXPORT_SYMBOL_GPL(device_create);
-
-/**
- * device_destroy - removes a device that was created with device_create()
- * @class: pointer to the struct class that this device was registered with
- * @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
- */
-void device_destroy(struct class *class, dev_t devt)
-{
- struct device *dev = NULL;
- struct device *dev_tmp;
-
- down(&class->sem);
- list_for_each_entry(dev_tmp, &class->devices, node) {
- if (dev_tmp->devt == devt) {
- dev = dev_tmp;
- break;
- }
- }
- up(&class->sem);
-
- if (dev)
- device_unregister(dev);
-}
-EXPORT_SYMBOL_GPL(device_destroy);