Linux driver programming-Device Model 2

Source: Internet
Author: User
After learning kobject and kset, you can't wait to start & ldquo; research & rdquo; device model

I learned beforeKobjectAndKsetThen, I can't wait to start "researching" the device model. After several days of study, I feel that I have benefited a lot. So I sorted out my understanding.

To drive a device, it involves three parts: Bus, device, and driver. Of course, these "new" nodes ultimately inherit from kobject.

1. Bus

The BUS is responsible for establishing connections between devices and drivers, including I2C, PCI, serial port, and platform. The platform is a virtual bus.

1.1 struct

The information structure is bus_type.

struct bus_type {const char*name;//the name of busstruct bus_attribute*bus_attrs;//attribute for bus, contain attribute file and some operate function.// this is a interface between kernel space and user space.struct device_attribute *dev_attrs;//attribute for device, struct driver_attribute *drv_attrs;//attribute for deriverint (*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;//power managestruct bus_type_private *p;//private data for bus. In fact, it is core of this structure};

Bus_attrs, dev_attrs, and drv_attrs record some attributes of the bus, and the most important information used to build the logical structure of the bus is recorded in bus_type_private. The parsing of the private data structure corresponding to this bus is as follows.

struct bus_type_private {struct kset subsys;//there are two points://1).this is a set. It is contain some devices and derivers about this bus.//2). it's parent is @bus_kset, which is the root of all other bus.@bus_kset have many subset, this is just one of them.//struct kset *drivers_kset;//all drivers about this bus will belong to this set.struct kset *devices_kset;//all devices of this bus will belong to this set.struct klist klist_devices;struct klist klist_drivers;//they are two lists , for mount all corresponding nodes.struct blocking_notifier_head bus_notifier;unsigned int drivers_autoprobe:1;//is this bus automaticly run when a new devices arrvied.//sometime, we can see some attribute files in user space.(for example:@drivers_autoprobe).//it is interface that kernel leave user to modify this argument.struct bus_type *bus;//just a port for return this bus.};

The klist_devices and klist_drivers linked lists are used to mount the devices and drivers of the bus. When you need to find something, it will go to the two sides. The above two ksets are their respective collections. Different sets correspond to different operation features. This is a very powerful organizational structure. Here, we use kobject to organize a two-dimensional linked list (or another data structure), where each kobject acts as a node. However, you want to make some specified kobject nodes have some attributes. Kset is equivalent to the attribute of kobject. It contains some data required for event notification. Whenever a kobject needs to be used, it will find its own kset or the kset of the higher-level kobject.

1.2 important function analysis

The following functions are required for bus registration. it is helpful to understand the logic structure of bus_type by analyzing its behavior.

/*** Bus_register-register a bus with the system. * @ bus: bus. ** Once we have that, we registered the bus with the kobject * infrastructure, then register the children subsystems it has: * the devices and drivers that belong to the bus. */int bus_register (struct bus_type * bus) {int retval; struct bus_type_private * priv; // alloc a private data package for @ bus. it is the core of this structure, // I Nclude device list, deriver list and so on. priv = kzarloc (sizeof (struct bus_type_private), GFP_KERNEL); if (! Priv) return-ENOMEM; priv-> bus = bus; bus-> p = priv; BLOCKING_INIT_NOTIFIER_HEAD (& priv-> bus_notifier); // before we keep on, what we shoshould to know is that this bus is one of members of the great building, // so it must be inherit form @ kobject. // and @ (priv-> subsys. kobj) is it's kobject. retval = kobject_set_name (& priv-> subsys. kobj, "% s", bus-> name); if (retval) goto out; priv-> subsys. kobj. kset = bus_kset ;// 1 ). @ bus_kset is the root of all buses. 2 ). this structure is the type of bus. priv-> subsys. kobj. ktype = & bus_ktype; // corresponding operation function for buspriv-> drivers_autoprobe = 1; // automaticly probe when new device arrived. retval = kset_register (& priv-> subsys); if (retval) goto out; retval = bus_create_file (bus, & bus_attr_uevent); // create attribute file for bus, it is a interface between user sp Ace and kernel space. if (retval) goto bus_uevent_fail; // Create a subset of devices for the bus. it is the set of all devices about this bus. // in the file system, a subdirectory named "devices" is added to the Directory of the bus. // you must also note that: the hierarchical relationship in the device model is specified by the kobject object. Therefore, all nodes belonging to the device model must inherit the kobject. priv-> devices_kset = kset_create_and_add ("devices", NULL, & priv-> subsys. kobj); if (! Priv-> devices_kset) {retval =-ENOMEM; goto bus_devices_fail;} // create a deriver set for this buspriv-> drivers_kset = kset_create_and_add ("drivers", NULL, & amp; priv-& gt; subsys. kobj); if (! Priv-> drivers_kset) {retval =-ENOMEM; goto bus_drivers_fail;} // thoes two list is used to mount some nodes. device-node or deriver-node.klist_init (& priv-> klist_devices, klist_devices_get, klist_devices_put); klist_init (& priv-> klist_drivers, NULL, NULL ); // create attribute file for this structureretval = add_probe_files (bus); if (retval) goto values; retval = bus_add_attrs (bus); // create attribute file for @ bus_attrif (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); Identifier: bus_remove_file (bus, & gt; Identifier); identifier: kset_unregister (& bus-> p-> subsys); kfree (bus-> p); out: bus-> p = NULL; return retval ;}

The behavior has been analyzed in detail in the function body.

1.3 device_bind_driver

So how exactly is device bound to a driver? Let them find each other as needed

// Bind a driver to one device.int device_bind_driver (struct device * dev) {int ret; ret = driver_sysfs_add (dev); if (! Ret) driver_bound (dev); return ret;} // This function is used after the device is bound to a driver, static void driver_bound (struct device * dev) {if (klist_node_attached (& dev-> p-> knode_driver) {printk (KERN_WARNING "% s: device % s already bound \ n" ,__ func __, kobject_name (& dev-> kobj); return;} pr_debug ("driver: '% s': % s: bound to device' % s' \ n ", dev_name (dev), _ func __, dev-> driver-> name); if (dev-> bus) blocking_notifier_call_chain (& dev-> bus-> p-> bus _ Notifier, bus_policy_bound_driver, dev); // add the device node to the node linked list of the driver //? Now that the device can find its own driver, why do I need to add the linked list of the driver //? A driver may support a group of devices. for devices with the same logic operation, all drivers have a device linked list klist_add_tail (& dev-> p-> knode_driver, & dev-> driver-> p-> klist_devices );}
II. Structure of device information 2.1

One end of the bus is mounted with a device. The struct used to record data and operations isDevice.

Struct device {struct device * parent; // parent devicestruct device_private * p; // private data for device, including its topological structure information struct kobject kobj; // @ device is inherit from @ kobject. so it is belong to @ devices_kset, which is created by kernel for devices and contain of some operation functions for devices. // devices_ksetconst char * init_name;/* initial name of the device */struct device_type * type; struct semaphoresem;/* semaphore to synchronize cballs 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 '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_archdata archdata; dev_tdevt;/* dev_t, creates the sysfs "dev" */comment; struct list_headdevres_head; struct klist_nodeknode_class; struct class * class; struct attribute_group ** groups;/* optional groups */void (* release) (struct device * dev );};

The topology information of this node is stored in device_private.

struct device_private {struct klist klist_children;//klist containing all children of this devicestruct klist_node knode_parent;//node in sibling liststruct klist_node knode_driver;//node in driver list, @device is mount on the list of driver by this member.//In linux system, one device have only one driver.//But it is not same as to driver, one driver may have a lot of devices, if only those device have a same logical operation.struct klist_node knode_bus;//apparently, this device is need to mount on the list of bus, too.struct device *device;//point to this device};

2.2 Important functions

The device registration function is device_register (), which establishes the topological relationship between devices and adds devices to the topology list of the corresponding bus.

int device_register(struct device *dev){device_initialize(dev);return device_add(dev);}

TheDevice_initialize ()Initialize the device. A very important variable used during initialization isDevices_ksetIs a collection of devices that the kernel creates at startup. Another two items are initialized together.

Void device_initialize (struct device * dev) {dev-> kobj. kset = devices_kset; // @ devices_kset is created by kernel as the parent of all devices. kobject_init (& dev-> kobj, & device_ktype); // @ device_ktype defines two operation functions for kobj: INIT_LIST_HEAD (& dev-> dma_pools ); init_MUTEX (& dev-> sem); spin_lock_init (& dev-> devres_lock); INIT_LIST_HEAD (& dev-> devres_head); device_init_wakeup (dev, 0); device_pm_init (dev ); set_dev_node (dev,-1 );}

The story of the three important devices is from here.

int __init devices_init(void){......devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);dev_kobj = kobject_create_and_add("dev", NULL);sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj);sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj);......}

For device registration, the core operations are as follows:Device_add ()The simplified version is as follows:

Int device_add (struct device * dev) {... kobject_uevent (& dev-> kobj, KOBJ_ADD); // start to call the event notification functionBus_attach_device (dev );// Attach @ device to bus if (parent) klist_add_tail (& dev-> p-> knode_parent, & parent-> p-> klist_children );......}

In this functionBus_attach_device ()After the final operation is completed, the device is mounted to the linked list of the bus, which can be clearly seen in the bold section.

void bus_attach_device(struct device *dev){struct bus_type *bus = dev->bus;int ret = 0;if (bus) {if (bus->p->drivers_autoprobe)ret = device_attach(dev);// if autoprobe = 1,it will bind to driverWARN_ON(ret < 0);//add @device to the devices-list of @busif (ret >= 0)klist_add_tail(&dev->p->knode_bus,       &bus->p->klist_devices);//@device will be add to the list of the bus.//@knode_bus is a mount point. think about @containerof() }}
3. driver information 3.1 struct

The structure that records the driver information is device_driver, which is the last of the device, bus, and driver triangle model.

struct device_driver {const char*name;//it is used to match with the device.struct bus_type *bus;//corresponding bus for this driverstruct module*owner;const char*mod_name;/* used for built-in modules */int (*probe) (struct device *dev);//this is a probe function, for ensure whether this driver is match with the device.int (*remove) (struct device *dev);//when this device is removed.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;//as the counterpart of  @device and @bus, it is also contain of the hierarchy information.};

Of course, like the other two, the struct also creates a struct specifically used to install the topology information of the driver node, that isDriver_private

Struct driver_private {struct kobject kobj; // of course, @ driver is also a @ kobject. // we use kobj to add this node to this virtual hierarchy. Struct klist klist_devices; // the list of devices. thanks for device-model, we cocould use a driver serices for a serice of devices, // only if they have a similar operation. struct klist_node knode_bus; // @ driver will be mounted on the list of driver of the bus. // Usually, there are two list for the bus. struct module_kobject * mkobj; struct device_driver * driver; // point to container .};
3.2 Important functions

Below we will sort out the driver registration functionDriver_registerBecause it includes the final interpretation right of this struct.

int driver_register(struct device_driver *drv){......//add @driver to the list of drivers of bus.ret = bus_add_driver(drv);......}

Continue searching down the core part

Int bus_add_driver (struct device_driver * drv ){...... priv = kzarloc (sizeof (* priv), GFP_KERNEL );...... // the driver object belongs to the driver set priv of the corresponding bus-> kobj. kset = bus-> p-> drivers_kset; error = kobject_init_and_add (& priv-> kobj, & driver_ktype, NULL, "% s", drv-> name );// If automatic detection is enabled, try to load the device if (drv-> bus-> p-> drivers_autoprobe) {error = driver_attach (drv); if (error) goto out_unregister;} // add @ driver to the list of drivers of the busklist_add_tail (& priv-> knode_bus, & bus-> p-> klist_drivers );Module_add_driver (drv-> owner, drv); // create attribute file for drivererror = driver_create_file (drv, & driver_attr_uevent); error = driver_add_attrs (bus, drv ); error = add_bind_files (drv); // Configure Y a event, this will consume y the user space.Kobject_uevent (& priv-> kobj, KOBJ_ADD );Return 0 ;......}

There are two things: first, the function willDriverMounted to the linked list of the corresponding bus"Klist_add_tail (& priv-> knode_bus, & bus-> p-> klist_drivers)", Now I see it againContainerofEvil. SinceContainerofLater, the kernel often made some linked lists that I was new. Second, the function automatically detects the corresponding device and callsDriver_attach.Here is another interesting thing.

/** * driver_attach - try to bind driver to devices. * @drv: driver. * * Walk the list of devices that the bus has on it and try to * match the driver with each one.  If driver_probe_device() * returns 0 and the @dev->driver is set, we've found a * compatible pair. */int driver_attach(struct device_driver *drv){return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);}

Driver_attachThe function traverses the device list of the bus and calls_ Driver_attachAnd check whether the device is the one you are looking.

Static int _ driver_attach (struct device * dev, void * data) {/** Lock device and try to bind to it. we drop the error * here and always return 0, because we need to keep trying * to bind to devices and some drivers will return an error * simply if it didn't support the device. ** driver_probe_device () will spit a warning if there * is an error. * /// if this device is not the one you are looking for, immediately exit if (!Driver_match_device (drv, dev) Return 0; ...... // and the device has no driver. if it already exists, it will not work if (! Dev-> driver)Driver_probe_device (drv, dev );... Return 0 ;}

NextDriver_probe_deviceThe probe function (bus or ours) will be called to check whether the device actually corresponds to the driver.

Int driver_probe_device (struct device_driver * drv, struct device * dev ){......Ret = really_probe (dev, drv );......} Static int really_probe (struct device * dev, struct device_driver * drv ){...... // if no probe function is defined on the bus, the probe function entered by the user is called. // if the probe function returns 0, the probe function is selected. If (dev-> bus-> probe ){Ret = dev-> bus-> probe (dev );If (ret) goto probe_failed;} else if (drv-> probe ){Ret = drv-> probe (dev );If (ret) goto probe_failed;} ...... // driver bindingDriver_bound (dev );}

We have seen the use of probe functions from above. let's look at the last part.

Static void driver_bound (struct device * dev) {...... // add the device node to the drive node linked list //? Now that the device can find its own driver, why do I need to add the linked list of the driver //? A driver may support a group of devices. for devices with the same logic operation, all drivers have a device linked list klist_add_tail (& dev-> p-> knode_driver, & dev-> driver-> p-> klist_devices );......}

This is the actual operation of this driver.

IV. Summary

This is the three basic parts of the device model. Then the next question is, does a variety of models have been formed by entering different parameters for these three information structures?

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.