Platform device driver framework setup analysis, platform Framework

Source: Internet
Author: User

Platform device driver framework setup analysis, platform Framework

Previously, the character device driver is a very simple Linux character device driver.Separation of devices and driversAndDevice-Driven Hierarchy, Does not have"Bus-device-driver"Model concept. Next, we will analyze the setup process of the platform Device Driver Model to see what the Linux Device Driver Model is like?

Build the platform Driver Model:

(1) platform core layer: Provides registration interfaces for the device layer and driver layer, and provides standards for device layer and driver layer matching.

① Build a bus framework:
Bus struct:
Struct bus_type {const char * name; struct bus_attribute * bus_attrs; struct device_attribute * character; struct driver_attribute * drv_attrs; 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; // The qualified domain keyword in the C ++ class is displayed as this private member };
Bus class instantiation: platform Bus
Struct bus_type platform_bus_type = {. name = "platform",. dev_attrs = platform,. match = platform_match, // key member. uevent = platform_uevent,. pm = PLATFORM_PM_OPS_PTR ,};
The platform bus registration process:
Platform_bus_init (){..... error = bus_register (& platform_bus_type); // register the core work of the platform bus .....} bus_register (struct bus_type * bus) {// create the bus attribute file retval = bus_create_file (bus, & bus_attr_uevent );...... // In the/sys/bus-> name directory, create the devices directory priv-> devices_kset = kset_create_and_add ("devices", NULL, & priv-> subsys. kobj );.... // In the/sys/bus-> name directory, create the drivers directory priv-> drivers_kset = kset_create_and_add ("drivers", NULL, & priv-> subsys. kobj); // initialize the klist_init (& priv-> klist_devices, klist_devices_get, klist_devices_put); klist_init (& priv-> klist_drivers, NULL, NULL );}
Core layer achievements:Two linked lists, klist_devices and klist_drivers, were initialized. I didn't talk about how to determine the matching between the device and the driver? ". Match = platform_match" is initialized, but when is it called?
When a driver is attached to the bus, the match method of the bus is called. Similarly, when a device is attached to the bus, platform_match is also called. That is to say, the core layer only provides matching methods! It won't help them match. They need to complete this big event in their own lives!
This is easy to handle. When it is attached to the bus, it will certainly be encountered during analysis in the future. Let's put it for now. Let's first look at his implementation:
Platform_match (struct device * dev, struct device_driver * drv) {struct platform_device * pdev = to_platform_device (dev); struct platform_driver * pdrv = to_platform_driver (drv ); /* match against the id table first */if (pdrv-> id_table) // check whether there is a ready-to-match device record in drv id_table: return platform_match_id (pdrv-> id_table, pdev )! = NULL;/* fall-back to driver name match */return (strcmp (pdev-> name, drv-> name) = 0);/* match successful, strcmp returns 0, and statement logic returns 1 */}
② Provide the registration API for the device layer and the automatic matching interface function
Device base class:
Struct device {struct device * parent; struct device_private * p; struct kobject kobj; const char * init_name;/* initial name of the device this is the traditional bus_id, use the default value */struct device_type * after each device ;...... 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 */...... void (* release) (struct device * dev );};
Derived class: platform Device
Struct platform_device {const char * name; intid; // symbol of the hardware device/Represents struct devicedev; // inherits the base class u32num_resources; struct resource * resource; // The resource struct platform_device_id * id_entry used by this driver ;};
Register the function call relationship of the platform device:
Platform_device_register(Struct platform_device * pdev)
Platform_device_add(Struct platform_device * pdev)
Pdev-> dev. bus = & platform_bus_type;
Device_add(& Pdev-> dev );
Bus_attach_device(Struct device * dev)
Device_attach(Dev );
Bus_for_each_drv(Dev-> bus, NULL, dev, _ Device_attach);
Implementation of the bus_for_each_drv () function:
bus_for_each_drv(struct bus_type *bus, struct device_driver *start,     void *data, int (*fn)(struct device_driver *, void *)){......while ((drv = next_driver(&i)) && !error)error = fn(drv, data);......}
Analysis:
First, care about his last form parameter (* fn). When registering platform_device RedirectionTo the _ device_attach () function, the use of callback functions is not uncommon in the kernel source code! Because it can reduce a lot of repeated code.
Now the focus of the analysis is shifted to the _ device_attach function:
_ Device_attach (struct device_driver * drv, void * data) {struct device * dev = data; if (! Driver_match_device (drv, dev) return 0; return driver_probe_device (drv, dev); // If match is successful, this function is executed and he finally calls really_probe () function} driver_match_device (struct device_driver * drv, struct device * dev) {return drv-> bus-> match? Drv-> bus-> match (dev, drv): 1; // when you see this sentence, the above questions are resolved: the matching and judgment standard match interface left by the original core layer is called here !!! Great! ^ _ ^} Really_probe (struct device * dev, struct device_driver * drv ){...... if (dev-> bus-> probe) // if the probe member in the bus_type structure is defined, the {ret = dev-> bus-> probe (dev) is called first ); if (ret) goto probe_failed;} else if (drv-> probe) // if not, call the probe member function {ret = drv-> probe (dev); if (ret) goto probe_failed;} driver_bound (dev) in the matched drv structure ); // bound means binding. The device that matches the successful match is added to the device linked list of the driver ......}
③ Provide APIs for the driver layer and automatic matching interface functions
Driver base class:
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;};
Driver derived class:
Struct platform_driver {int (* probe) (struct platform_device *); // This function usually needs to implement int (* remove) (struct platform_device *) by itself; void (* shutdown) (struct platform_device *); int (* suspend) (struct platform_device *, pm_message_t state); int (* handle) (struct platform_device *, pm_message_t state); int (* resume_early) (struct platform_device *); int (* resume) (struct platform_device *); struct device_driver driver; // inherits the base class struct platform_device_id * id_table ;};
Register the platform_driver driver struct function execution process:
Platform_driver_register (struct platform_driver * drv) {/*. If the derived platform_driver does not initialize a special member, set it to the default */drv-> driver. bus = & platform_bus_type; // point to the bus type to which the driver belongs: platformif (drv-> probe) // There Is A redirection drv-> driver. probe = platform_drv_probe; if (drv-> remove) // There Is A redirection drv-> driver. remove = platform_drv_remove ;...... return driver_register (& drv-> driver); [go to analysis] // The key material for registration is platform_driver-> driver-> bus: the key is to register the bus type platform_bus_type} driver_register (struct device_driver * drv ){...... struct device_driver * other ;...... other = driver_find (drv-> name, drv-> bus); // you can check whether the driver corresponding to the driver name of the device exists on the bus if (other) {// if the device already has a corresponding Driver, the following Error occurs: put_driver (other); printk (KERN_ERR "Error: Driver '% s' is already registered, "" aborting... \ n ", drv-> name); return-EEXIST;} bus_add_driver (drv);/* Add the driver to the bus. The final result is as follows: generate the "name" directory under the "bus/platform/drivers" directory, and generate four bind module uevent unbind files */......}
Further analysis:
Bus_add_driver(Struct device_driver * drv)
Driver_attach(Drv);/* try to bind the driver to the device */
Bus_for_each_dev(Drv-> bus, NULL, drv, _ Driver_attach); // Here we can clearly find that something similar to what the device layer does is almost symmetric.
/* Execute _ driver_attach for every device on the bus. It is used as a callback function here to check whether it matches, this function is basically the same as the _ device_attach function. I will not go into details here */

(2) device layer: The main task is to use the APIS provided by the core layer.
1. Set the platform_device struct members, including name, resource, num_resources, id, dev-> release,

2. Use platform_device_register () to link the struct to the klist_devices linked list of the core layer.


(3) driver layer: Use the interface functions provided by the core layer.
1. Set the platform_driver struct members: probe, remove, driver-> name
2. Use the platform_driver_register () function to link this struct to the klist_drivers linked list of the core layer.
3. Implement the probe member function
4. Generally, the materials used by the probe function are completed at the end, which is generally a file_operation struct member, so that the application layer can use this interface to operate the device.

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.