In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >
Share
Shulou(Shulou.com)06/01 Report--
Linux driver development in the introduction and usage of device model, many novices are not very clear about this, in order to help you solve this problem, the following editor will explain in detail for you, people with this need can come to learn, I hope you can gain something.
What is device model?
Linux's device model is a model designed to manage all device drivers in a unified manner.
It is like a large-scale building:
Kobject, kset, attribute and so on are used as basic building materials.
The three components of bus, device and driver are constructed to support the driving world.
Finally, the hierarchical relationship between various basic building materials is established through sysfs, and the document interface is provided to the outside world to interact with the facilities in the building.
What is the purpose of device model?
The hardware description of device can be separated from driver to improve the code reuse rate of driver.
Device can be classified
You can traverse device and driver
It can better present the topological relationship of the device.
The device can be accessed through sysfs
The device can be hot-swappable
...
In order to control the length, this paper focuses on the three components bus, device and driver, which are most closely related to the driver engineer.
2. Three core concepts of device model
There are three core concepts in device model:
Bus
Device
Driver
What is bus?
Bus represents a bus, such as I2C, SPI, Usb, etc.
Bus is the core framework of the Linux device driver model, and the devices and drivers in the system are attached to it.
After booting the system, you can use / sys/bus to see which buses are currently in the system.
Bus is described by struct bus_type:
Struct bus_type {const char * name; const char * dev_name; struct device * dev_root; const struct attribute_group * * bus_groups; const struct attribute_group * * dev_groups; const struct attribute_group * * drv_groups; 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); Struct subsys_private * p; struct lock_class_key lock_key;}
You don't need to know the role of each member at once, but explain it when you use it.
Focus on members:
Int (* match) (struct device * dev, struct device_driver * drv), a callback function used to determine whether the device and driver hanging on the bus match
Int (* probe) (struct device * dev). This callback function is provided if bus has the ability to detect devices.
Struct subsys_private * p, used to manage the data structure of devices and drivers on bus
Api for registering bus:
Int bus_register (struct bus_type * bus)
What is device?
Device represents a device.
Described by struct device:
Struct device {struct device * parent; struct device_private * p; struct kobject kobj; const char * init_name; const struct device_type * type; struct mutex mutex; struct bus_type * bus; struct device_driver * driver; void * platform_data; void * driver_data;.}
Focus on members:
Struct kobject kobj, kernel object
Struct bus_type * bus, the bus on which the device is located
Struct device_driver * driver, the driver bound to the device. If it is not already bound, it is NULL.
Api for registering device:
Int device_register (struct device * dev)
What is driver?
Driver stands for device driver.
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 * / bool suppress_bind_attrs; / * disables bind/unbind via sysfs * / enum probe_type probe_type; const struct of_device_id * of_match_table; const struct acpi_device_id * acpi_match_table; 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); const struct attribute_group * * groups; const struct dev_pm_ops * pm; struct driver_private * p;}
Focus on members:
Struct bus_type * bus
Int (* probe) (struct device * dev)
It is worth mentioning that the bus controller is also a device.
For example, the I2C bus controller is a device, and the corresponding driver is I2C controller driver.
For the device hanging on the I2C bus, the corresponding driver is I2C device driver.
Api for registering driver:
Int driver_register (struct device_driver * drv)
3. How are bus, device and driver related?
The core work of device model is to maintain these three types of abstract instances and establish relationships between them.
How does bus manage device and driver?
There is a struct subsys_private * p pointer in struct bus_type, which is responsible for managing all devices and drivers hanging on the bus, which is defined as follows:
Struct subsys_private {struct kset subsys; struct kset * devices_kset; struct list_head interfaces; struct mutex mutex; struct kset * drivers_kset; struct klist klist_devices; struct klist klist_drivers; struct blocking_notifier_head bus_notifier; unsigned int drivers_autoprobe:1; struct bus_type * bus; struct kset glue_dirs; struct class * class;}
Two klist members link all drivers and devices on the bus together in the form of a linked list.
Struct kset * drivers_kset and struct kset * devices_kset are kset dynamically generated to accommodate all drivers and devices on the bus when registering the current new bus with the system.
In the kernel, an object is represented by kobject, and kset is an abbreviation for kobject set, that is, a collection of kernel objects.
The kernel uses data structures such as kobject and kset as raw materials to build the framework of device model in an object-oriented way.
Finally, the bus members of device and device_driver also point to the bus:
Binding of device and driver
Whether registering a device to bus through device_register ()
Or register a device_driver to bus through driver_register ()
Both cause bus to attempt to bind device and driver.
1. Binding triggered by device_register ()
When registering for device:
Int device_register (struct device * dev); device_add (dev); bus_probe_device (dev); _ _ device_attach (dev, true)
_ _ device_attach (dev, true) traverses all driver on bus for device:
Bus_for_each_drv (dev- > bus, NULL, & data, _ _ device_attach_driver); driver_match_device (drv, dev); drv- > bus- > match? Drv- > bus- > match (dev, drv): 1; driver_probe_device (drv, dev)
Driver_match_device () determines whether device and driver match through the match function in bus.
Whether match is judged by of_match_table or id_table is generally used as the criterion.
Take the match function of i2C bus as an example:
Static int i2c_device_match (struct device * dev, struct device_driver * drv) {struct i2c_client * client = i2c_verify_client (dev); struct i2c_driver * driver; / * Attempt an OF style match * / if (i2c_of_match_device (drv- > of_match_table, client) return 1; / * Then ACPI style match * / if (acpi_driver_match_device (dev, drv)) return 1; driver = to_i2c_driver (drv) / * Finally an I2C match * / if (i2c_match_id (driver- > id_table, client) return 1; return 0;}
Once the match is successful, driver_probe_device () is called to trigger the behavior of the probe device:
Int driver_probe_device (struct device_driver * drv, struct device * dev); really_probe (dev, drv); if (dev- > bus- > probe) {ret = dev- > bus- > probe (dev);} else if (drv- > probe) {ret = drv- > probe (dev);}
If bus has the ability to detect devices, such as pci bus, then bus- > probe () will be used to detect devices
Otherwise, use driver- > probe () to detect the device, and the probe operation of the driver is linked to the specific hardware device.
two。 Bindings triggered by driver_register ()
Int driver_register (struct device_driver * drv); bus_add_driver (drv); driver_attach (drv)
Driver_attach (drv) traverses all device on bus for driver:
Int driver_attach (struct device_driver * drv); bus_for_each_dev (drv- > bus, NULL, drv, _ _ driver_attach); _ _ driver_attach (); driver_match_device (drv, dev); driver_probe_device (drv, dev)
Like device_register (), driver_match_device (drv, dev) is eventually called.
And then through the match function in bus to determine whether device and driver match.
Similarly, once the match is successful, driver_probe_device () is called to trigger the behavior of the probe device, and the subsequent operation is exactly the same as when registering the device.
3. The binding relationship between device and drvier
Now that we talked about how the binding is triggered, let's clarify the specific operation of the binding.
For device and driver that can successfully match, the relationship between them is N to 1, that is, there can be multiple device and 1 driver bound together.
For device:
Its driver member points to the bound device_driver.
Int driver_probe_device (struct device_driver * drv, struct device * dev) really_probe (dev, drv); dev- > driver = drv
For driver:
In device_driver, the linked list klist_devices holds all the device bound to that driver.
Int driver_probe_device (struct device_driver * drv, struct device * dev) really_probe (dev, drv); driver_bound (dev); klist_add_tail (& dev- > p-> knode_driver, & dev- > driver- > p-> klist_devices)
In / driver/base/driver.c, some api is provided for traversing all the device bound on the processing driver:
Int driver_for_each_device ()
Struct device * driver_find_device ()
Fourth, the simplest examples of bus, device and driver
The following example
A bus instance named "simple_bus" is constructed.
Static int sb_match (struct device * dev, struct device_driver * driver) {return! strncmp (dev_name (dev), driver- > name, strlen (driver- > name));} struct bus_type sb_bus_type = {.name = "sb", .match = sb_match,}; static ssize_t version_show (struct bus_type * bus, char * buf) {return snprintf (buf, PAGE_SIZE, "% s\ n", Version) } static BUS_ATTR_RO (version); static void sb_dev_release (struct device * dev) {} int register_sb_device (struct sb_device * sbdev) {sbdev- > dev.bus = & sb_bus_type; sbdev- > dev.release = sb_dev_release; dev_set_name (& sbdev- > dev, sbdev- > name); return device_register (& sbdev- > dev);} EXPORT_SYMBOL (register_sb_device) Void unregister_sb_device (struct sb_device * sbdev) {device_unregister (& sbdev- > dev);} EXPORT_SYMBOL (unregister_sb_device); static int sb_drv_probe (struct device * dev) {printk (KERN_INFO "sb_drv probe% s\ n", dev_name (dev)); return 0;} int register_sb_driver (struct sb_driver * sdrv) {sdrv- > driver.bus = & sb_bus_type Sdrv- > driver.probe = & sb_drv_probe; return driver_register (& sdrv- > driver);} EXPORT_SYMBOL (register_sb_driver); void unregister_sb_driver (struct sb_driver * driver) {driver_unregister (& driver- > driver);} EXPORT_SYMBOL (unregister_sb_driver); static int _ init sb_bus_init (void) {int ret; ret = bus_register (& sb_bus_type) If (ret) {printk (KERN_ERR "Unable to register sb bus, failure was% d\ n", ret); return ret;} if (bus_create_file (& sb_bus_type, & bus_attr_version)) printk (KERN_ERR "Unable to create version attribute\ n"); return 0;} static void sb_bus_exit (void) {bus_unregister (& sb_bus_type);} module_init (sb_bus_init) Module_exit (sb_bus_exit)
Xxx_chip.c: register 4 device named "chipX"
Struct xxx_chip {char devname [20]; struct sb_device sdev;}; int chipdev_num = 4; struct xxx_chip * chipdev; static void chip_register_dev (struct xxx_chip * dev, int index) {snprintf (dev- > devname, sizeof (dev- > devname), "chip%d", index); dev- > sdev.name = dev- > devname; dev_set_drvdata (& dev- > sdev.dev, dev); register_sb_device (& dev- > sdev) } int chip_init (void) {int i; chipdev = kmalloc (chipdev_num*sizeof (struct xxx_chip), GFP_KERNEL); memset (chipdev, 0, chipdev_num*sizeof (struct xxx_chip)); for (I = 0; I
< chipdev_num; i++) { chip_register_dev(chipdev + i, i); } return 0; } void chip_cleanup(void) { int i; for (i = 0; i < chipdev_num; i++) { unregister_sb_device(&chipdev[i].sdev); } kfree(chipdev); } module_init(chip_init); module_exit(chip_cleanup); xxx_chip_drv.c:注册1个名为 "chip" 的 driver static struct sb_driver sculld_driver = { .driver = { .name = "chip", }, }; int xxx_chipdrv_init(void) { return register_sb_driver(&sculld_driver); } void xxx_chipdrv_cleanup(void) { unregister_sb_driver(&sculld_driver); } module_init(xxx_chipdrv_init); module_exit(xxx_chipdrv_cleanup); 运行效果: root@buildroot:~# insmod simple_bus.ko root@buildroot:~# tree /sys/bus/sb /sys/bus/sb ├── devices ├── drivers ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version root@buildroot:~# insmod xxx_chip.ko root@buildroot:~# tree /sys/bus/sb /sys/bus/sb ├── devices │ ├── chip0 ->.. / devices/chip0 │ ├── chip1->.. / devices/chip1 │ ├── chip2->.. / devices/chip2 │ └── chip3->.. / devices/chip3 ├── drivers ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version root@buildroot:~# insmod xxx_chip_drv.ko sb_drv probe chip0 sb_ Drv probe chip1 sb_drv probe chip2 sb_drv probe chip3 root@buildroot:~# tree / sys/bus/sb / sys/bus/sb ├── devices │ ├── chip0->.. / devices/chip0 │ ├── chip1->.. / devices/chip1 │ ├── chip2->.. / devices/chip2 │ └── chip3->.. / devices/chip3 ├── drivers │ └── chip │ ├── bind │ ├── chip0->.. / devices/chip0 │ ├── chip1->.. / devices/chip1 │ ├── chip2->.. / devices/chip2 │ ├── chip3->.. /.. / devices/chip3 │ ├── uevent │ └── unbind ├── drivers_autoprobe ├── drivers_probe ├── uevent └── version
From the print information, device and driver determine whether or not match via bus, and then execute the probe () function of driver, which is consistent with our previous analysis.
5. Summary
Linux's device model is a very complex system.
From a higher level, it is mainly composed of bus, device and driver.
In order to realize the correlation between these components, the kernel defines the basic underlying data structures such as kobject and kset, then shows the interconnection hierarchical relationship between the components in the kernel space through the sysfs file system, and provides a simple way for the user space program to access the attribute information of the kernel object by the way of file system interface.
Is it helpful for you to read the above content? If you want to know more about the relevant knowledge or read more related articles, please follow the industry information channel, thank you for your support.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.