Path for Linux Device Driver engineers-device model (Lower Layer) Upper Layer Model
K-Style
Reprinted please indicate from Hengyang Normal University 08 electric 2 Y-Kee http://blog.csdn.net/ayangke,QQ:843308498
1. Important knowledge points:
The device model consists of three elements: Bus, device, and driver.
The underlying model determines the upper layer model. In the structure of the bus, device, and driver, you can always see that they indirectly or directly contain the kobject structure or kset structure.
1. Bus
The bus is the channel between the processor and the device. In the device model, all devices are connected through the bus, and even the internal virtual "platform" bus. In the linux device model, the bus is represented by the bus_type structure. Defined in <linux/device>.
Bus description
Struct bus_type {const char * name; // bus name struct bus_attribute * bus_attrs // bus attribute struct device_attribute * dev_attrs; // device attribute struct driver_attribute * drv_attrs; // driver attribute int (* match) (struct device * dev, struct device_driver * drv); int (* uevent) (struct device * dev, struct kobj_uevent_env * env ); int (* probe) (struct device * dev); int (* remove) (struct device * dev); void (* shutdown) (struct device * dev ); int (* suspend) (struct device * dev, pm_message_t state); int (* suspend_late) (struct device * dev, pm_message_t state); int (* resume_early) (struct device * dev); int (* resume) (struct device * dev); struct dev_pm_ops * pm; struct bus_type_private * p ;};
Bus_type_private member of bus_type
struct bus_type_private {struct kset subsys;struct kset *drivers_kset;struct kset *devices_kset;struct klist klist_devices;struct klist klist_drivers;struct blocking_notifier_head bus_notifier;unsigned int drivers_autoprobe:1;struct bus_type *bus;};
It can be seen that the struct contains the kset object with device and dirver.
Bus registration:
Int bus_register (structbus_type * bus );
If it succeeds, the new bus will be added to the system, which can be seen in the/sys/bus directory.
We are looking at this function in depth.
int bus_register(struct bus_type *bus){int retval;struct bus_type_private *priv;priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);if (!priv)return -ENOMEM;priv->bus = bus;bus->p = priv;
BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);if (retval)goto out;priv->subsys.kobj.kset = bus_kset;priv->subsys.kobj.ktype = &bus_ktype;priv->drivers_autoprobe = 1;retval = kset_register(&priv->subsys);if (retval)goto out;retval = bus_create_file(bus, &bus_attr_uevent);if (retval)goto bus_uevent_fail;priv->devices_kset = kset_create_and_add("devices", NULL,&priv->subsys.kobj);if (!priv->devices_kset) {retval = -ENOMEM;goto bus_devices_fail;}priv->drivers_kset = kset_create_and_add("drivers", NULL,&priv->subsys.kobj);if (!priv->drivers_kset) {retval = -ENOMEM;goto bus_drivers_fail;}klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);klist_init(&priv->klist_drivers, NULL, NULL);retval = add_probe_files(bus);if (retval)goto bus_probe_files_fail;retval = bus_add_attrs(bus);if (retval)goto bus_attrs_fail;pr_debug("bus: '%s': registered\n", bus->name);return 0;bus_attrs_fail:remove_probe_files(bus);bus_probe_files_fail:kset_unregister(bus->p->drivers_kset);bus_drivers_fail:kset_unregister(bus->p->devices_kset);bus_devices_fail:bus_remove_file(bus, &bus_attr_uevent);bus_uevent_fail:kset_unregister(&bus->p->subsys);kfree(bus->p);out:return retval;}
From here
Priv-> subsys. kobj. kset = bus_kset;
Priv-> subsys. kobj. ktype = & bus_ktype;
You can see that the bus initialized its own kset object.
Delete Bus
Void bus_unregister (struct bus_type * Bus );
Bus Match Method
INT (* match) (struct device * Dev, struct device_driver * DRV );
When a new device or driver is added to the bus, this method is called to determine whether the specified driver can process the specified device. If yes, a non-zero value is returned. The following test program matches the dev-> bus_id string of the device and the DRV-> name string of the driver to determine whether the driver can process the device.
Bus uevent Method
INT (* uevent) (structdevice * Dev, char ** envp, int num_envp)
Before a hot swapping event is generated for the user, This method allows the bus to add environment variables.
Bus attributes are described by the structure bus_attribute:
Struct bus_attribute {
Struct attribute ATTR;
Ssize_t (* Show) (struct bus_type * bus, char * BUF );
Ssize_t (* store) (struct bus_type * bus, const char * Buf, size_t count );
};
Bus_attr (name, mode, show, store)
Create and initialize the bus_attribute structure during compilation. It uses bus_attr _ as the given prefix to create the real name of the bus.
For example, static bus_attr (version, s_irugo, show_bus_version, null );
Creates a bus_attr_version struct object.
Int bus_create_file (struct bus_type * bus, struct bus_attribute * ATTR)
Create an attribute File
Void bus_remove_file (struct bus_type * bus, struct bus_attribute * ATTR)
Delete attribute files
2. Device
struct device {struct klist klist_children;struct klist_nodeknode_parent;/* node in sibling list */struct klist_nodeknode_driver;struct klist_nodeknode_bus;struct device *parent;struct kobject kobj;char bus_id[BUS_ID_SIZE];/* position on parent bus */unsigned uevent_suppress:1;const char *init_name; /* initial name of the device */struct device_type*type;struct semaphoresem;/* semaphore to synchronize calls to* its driver.*/struct bus_type*bus;/* type of bus device is on */struct device_driver *driver;/* which driver has allocated this device */void *driver_data;/* data private to the driver */void *platform_data;/* Platform specific data, device core doesn't touch it */struct dev_pm_infopower;#ifdef CONFIG_NUMAint numa_node;/* NUMA node this device is close to */#endifu64 *dma_mask;/* dma mask (if dma'able device) */u64 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit addresses for consistent allocations such descriptors. */struct device_dma_parameters *dma_parms;struct list_headdma_pools;/* dma pools (if dma'ble) */struct dma_coherent_mem*dma_mem; /* internal for coherent mem override *//* arch specific additions */struct dev_archdataarchdata;dev_t devt;/* dev_t, creates the sysfs "dev" */spinlock_t devres_lock;struct list_headdevres_head;struct klist_nodeknode_class;struct class *class;struct attribute_group**groups;/* optional groups */void (*release)(struct device *dev);};
It can be seen that the device struct also contains a kobject object
Intdevice_register (struct device * Dev );
Register a device
Vioddevice_unregister (struct device * Dev)
Cancel a device
The device property is described by struct device_attribute.
Structdevice_attribute {
Struct attribute ATTR;
Ssize_t (* Show) (struct device * Dev, struct device_attribute * ATTR,
Char * BUF );
Ssize_t (* store) (struct device * Dev, struct device_attribute * ATTR,
Const char * Buf, size_t count );
};
Int device_create_file (struct device * Dev, struct device_attibute * entry)
Create an attribute File
Void device_remove_file (struct device * Dev, struct device_attibute * entry)
Delete attribute files
3. Driver
The driver is described by struct device_driver:
struct device_driver {const char *name;struct bus_type*bus;struct module *owner;const char *mod_name;/* used for built-in modules */int (*probe) (struct device *dev);int (*remove) (struct device *dev);void (*shutdown) (struct device *dev);int (*suspend) (struct device *dev, pm_message_t state);int (*resume) (struct device *dev);struct attribute_group **groups;struct dev_pm_ops *pm;struct driver_private *p;};
Check the driver_private object of device_dirver.
Struct driver_private {
Struct kobject kobj;
Struct klist klist_devices;
Struct klist_node knode_bus;
Struct module_kobject * mkobj;
Struct device_driver * driver;
};
It can be seen that the driver_private struct also contains a kobject object. And the linked list of connected devices.
When the bus match returns a non-0 value, that is, when the bus finds the device that matches the driver, the driver's probe function will be called.
When the device is deleted from the system, it is called remove.
Shutdown is called when the system is shut down.
Int driver_register (structdevice_driver * DRV)
Register the driver on the bus
Void driver_unregister (struct device_driver * DRV)
Cancel driver on Bus
The driver attributes are described using structdriver_attribute.
Structdriver_attribute {
Structattribue ATTR;
Ssize_t (* Show) (struct device_driver * DRV, const char * BUF );
Ssize_t (* store) (struct device_driver * DRV, const char * Buf, size_t count );
}
Int dirver_create_file (struct device_driver * DRV, struct driver_attribute * ATTR );
Create an attribute File
Void driver_remove_file struct device_driver * DRV, struct driver_attribute * ATTR );
Delete attribute files
Ii. Test Module
1. Bus
# Include <Linux/device. h> # include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/init. h> # include <Linux/string. h> module_author ("David xie"); module_license ("dual BSD/GPL"); static char * version = "$ revision: 1.9 {1} quot ;; static int my_match (struct device * Dev, struct device_driver * driver) {return! Strncmp (Dev-> bus_id, driver-> name, strlen (Driver-> name);} static void my_bus_release (struct device * Dev) {printk (kern_debug "My bus release \ n");} struct device my_bus = {. bus_id = "my_bus0 ",. release = my_bus_release}; struct bus_type my_bus_type = {. name = "my_bus ",. match = my_match,}; export_symbol (my_bus); export_symbol (my_bus_type);/** export a simple attribute. */static ssize_t show_bus_version (Str UCT bus_type * bus, char * BUF) {return snprintf (BUF, page_size, "% s \ n", version);} static bus_attr (version, s_irugo, show_bus_version, null ); static int _ init my_bus_init (void) {int ret;/* Register bus */ret = bus_register (& my_bus_type); If (RET) return ret; /* Create an attribute file */If (bus_create_file (& my_bus_type, & bus_attr_version) printk (kern_notice "fail to create version attribute! \ N ");/* register the bus device */ret = device_register (& my_bus); If (RET) printk (kern_notice" fail to register device: my_bus! \ N "); return ret;} static void my_bus_exit (void) {device_unregister (& my_bus); bus_unregister (& register);} module_init (my_bus_init); module_exit (my_bus_exit );
Create a bus named my_bus_type and a bus device named my_bus. Note that the bus is also a device and must be registered.
Test results:
2. Device
# Include <Linux/device. h> # include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/init. h> # include <Linux/string. h> module_author ("David xie"); module_license ("dual BSD/GPL"); extern struct device my_bus; extern bus_type my_bus_type;/* Why need this? */Static void my_dev_release (struct device * Dev) {} struct device my_dev = {. bus = & my_bus_type ,. parent = & my_bus ,. release = my_dev_release,};/** export a simple attribute. */static ssize_t mydev_show (struct device * Dev, char * BUF) {return sprintf (BUF, "% s \ n", "This is My device! ");} Static device_attr (Dev, s_irugo, mydev_show, null); static int _ init my_device_init (void) {int ret = 0; /* initialize the device */strncpy (my_dev.bus_id, "my_dev", bus_id_size);/* register the device */device_register (& my_dev ); /* create Attribute file */device_create_file (& my_dev, & dev_attr_dev); return ret;} static void my_device_exit (void) {device_unregister (& my_dev);} module_init (my_device_init ); module_exit (my_device_exit );
Register a device named my_dev named bus_id. The bus Member of the device points to the my_bus_type bus created in the previous step. The parent Member points to the my_bus bus device created in the previous step.
Test results:
3. Driver
# Include <Linux/device. h> # include <Linux/module. h> # include <Linux/kernel. h> # include <Linux/init. h> # include <Linux/string. h> module_author ("David xie"); module_license ("dual BSD/GPL"); extern struct bus_type my_bus_type; static int my_probe (struct device * Dev) {printk ("driver found device which my driver can handle! \ N "); Return 0;} static int my_remove (struct device * Dev) {printk (" driver found device unpluged! \ N "); Return 0;} struct device_driver my_driver = {. name = "my_dev ",. bus = & my_bus_type ,. probe = my_probe ,. remove = my_remove,};/** export a simple attribute. */static ssize_t mydriver_show (struct device_driver * driver, char * BUF) {return sprintf (BUF, "% s \ n", "This is my driver! ");} Static driver_attr (DRV, s_irugo, mydriver_show, null); static int _ init my_driver_init (void) {int ret = 0; /* register the driver */driver_register (& my_driver);/* Create an attribute file */driver_create_file (& my_driver, & driver_attr_drv); return;} static void my_driver_exit (void) {driver_unregister (& my_driver);} module_init (my_driver_init); module_exit (my_driver_exit );
Create a driver named "bus_dev" and point the bus member to the my_bus_type bus created in step 1.
Test results: