In Linux, devices and drivers are merged into the device driver model for management.
Device Driver features:
1. Hardware Device initialization and release
2. Manage devices, including real parameter settings, and provide unified operation interfaces for devices.
3. Read the data transmitted by the application to the device file or send back the data requested by the application.
4. Detect or handle device errors
The device driver model provides hardware abstraction including:
1. Power Supply Management
In fact, power management means that when some devices do not work, let them rest for a while and sleep for a while (the lowest consumption) to save power.
One of its important functions is:
In power-saving mode, devices in the system are suspended in a certain order.
Enables system devices to resume operation in a certain sequence in full-speed mode.
This means that a bus can be suspended only when n devices are suspended. However, if one device recovers, the bus must be restored.
2. plug-and-play Device Support
Everyone has a deep understanding. You pull out the PS/2 mouse and keyboard, and then plug it in to see if it didn't respond. However, you can continue to use the USB mouse and keyboard.
This is the legendary support for plug-and-play.
3. Communication with user space
There are many ways to communicate with users. The previously well-known proc file system is a clear representative. It gives users a pair of thousands of eyes. However, proc was won by the later sysfs file system, and is now upgraded.
Although proc remains alive, its influence has declined. At the same time, it must be said that proc has been the world, and it must have exclusive characteristics, where sysfs may be frustrated. But the strong are still not so shaken.
The Linux Device Driver Model has several basic data structure models: kobject, kset, and subsystem.
Kobject: This is the basis of the device drive model. It is like floor tiles and bricks in a building. Sysfs is its Son, son, and sun.
Struct kobject
{
Const char * name; // name displayed in sysfs
Struct list_head entry; // the structure of the next kobject
Struct kobject * parent; // point to the parent kobject struct, if any
Struct kset * kset; // point to the kset set
Struct kobj_type * ktype; // point to the kobject type descriptor
Struct sysfs_dirent * sd; // file directory of sysfs
Struct kref; // kobject reference count
Unsigned int state_initialized: 1; // whether to initialize
Unsigned int state_in_sysfs: 1; // whether to add sysfs
Unsigned int state_add_uevent_sent: 1; // whether hot insertion is supported
Unsigned int state_remove_uevent_sent: 1; // whether hot pulling is supported
}
Void kobject_init (struct kobject * kobj, struct kobj_type * ktype)
{
Char * err_str;
If (! Kobj)
{
Err_str = "invalid kobject pointer! "
Goto error;
}
If (! Ktype)
{
Err_str = "must have a ktype to be initialized properly! \ N ";
Goto error;
}
If (kobj-> state_initialized)
{
Printk (KERN_ERR "kobject (% p): tried to init an initialized"
"Object, something is seriously wrong. \ n", kobj );
Dump_stack ();
}
Kobject_init_internal (kobj); // Initialize an internal Member of kobject
Kobj-> ktype = ktype; // bind a ktype attribute to kobject
Return;
Error:
Printk (KERN_ERR "kobject (% p): % s \ n", kobj, err_str );
Dump_stack ();
}
Static void kobject_init_internal (struct koject * kobj)
{
If (! Kobj)
Return;
Kref_init (& kobj-> kerf );
INIT_LIST_HEAD (& kobj-> entry );
Kobj-> state_in_sysfs = 0;
Kobj-> state_add_uevent_sent = 0;
Kobj-> state_remove_uevent_sent = 0;
Kobj-> state_initialized = 1;
}
Kernel interface:
Kobject_init (); initialize kobject
Kobject_get (); increases the reference count of kobject.
Kobject_put (); reduces the reference count of kobject. If the count is zero, call kobject_release () to release it. It is in kobj_type.
Kobject_set_name (); set the name
Kobject_rename (); rename
Kobject_add () add
Each kobject has a property kobj_type.
Struct kobj_type
{
Void (* release) (struct kobject * kobj); // release kobject and other functions that occupy Resources
Struct sysfs_ops * sysfs_ops; // operation attribute Method
Struct attribute ** default_attrs; // attribute array
};
Struct attribute
{
Const char * name; // attribute name
Struct module * owner; // only modules with this attribute are not often used.
Mode_t mode; // attribute read/write permission
};
Struct sysfs_ops
{
Ssize_t (* show) (struct kobject *, struct attribute *, char *); // read attribute operation function
Ssize_t (* store) (struct kobject *, struct attribute *, const char *, size_t); // write attribute operation function
};
Struct kobject * kobject_get (struct kobject * kobj)
{
If (kobj)
Kref_get (& kobj-> kerf );
Return kobj;
}
Void kobject_put (struct kobject * kobj)
{
If (kobj)
{
If (! Kobj-> state_initialized)
WARN (1, KERN_WARNING "kobject: '% s' (% p): is not initialized, yet kobject_put () is being called. \ n ", kobject_name (kobj), kobj );
Kref_put (& kobj-> kref, kobject_release );
}
}
Generally, the default_attr Member of the kobject type defines all the default attributes of kobjet. However, in special cases, you can add some default attributes:
Add an attribute file:
Int sysfs_create_file (struct kobject * kobj, const struct attribute * attr );
Delete an attribute file:
Void sysfs_remove_file (struct kobject * kobj, const struct attribute * attr );
Struct kset
{
Struct list_head list; // connect the first address of the linked list of the included kobject object
Spinlock_t list_lock; // maintains the spin lock of the list linked list.
Struct kobject kobj; // the built-in kobject indicates that the kset itself is also a directory
Struct kset_uevent_ops * uevent_ops; // hot swapping event
};
Struct kset_uevent_ops
{
Int (* filter) (struct kset * kset, struct kobject * kobj );
Const char * (* name) (struct kset * kset, struct kobject * kobj );
Int (* uevent) (struct kset * kset, struct kobject * kobj, struct kobj_uevent_ent * env );
};
Relationship between kset and kobject:
1. The kset set contains the corresponding kobject struct. The kset. list linked list is used to connect the first and last kobject objects. The first kobject uses the entry to connect the kset set and the second kobject object. The second kobject object uses the entry to connect the first kobject object and the third kobject object, and so on. Finally, a linked list of the kobject object is formed.
2. The parent pointer of all the kobject structures points to the kobject object contained in the kset to form a parent-child hierarchy.
3. All kset pointers of kobject point to the kset set containing it, so it is easy to find the kset set through the kobject object.
4. The kobj_type pointer of kobject points to its own kobj_type. Each kobject has a separate kobj_type structure. In addition, there is also a kobject struct in the kset set. The XXX of this struct also points to a kobj_type struct. Kobj_type defines a set of attributes and operation attributes. Note: the priority of kobj_type in kset is higher than that of kobj_type in the kobject object. If both kobj_type exist, the kset function is called first. If the value of kobj_type in kset is null, the function in kobj_type corresponding to each kobject struct is called.
5. kobj in kset is also responsible for counting kset references.
Kset operation
Void kset_init (struct kset * k) // Initialization
{
Kobject_init_internal (& k-> kobj );
INIT_LIST_HEAD (& k-> list );
Spin_lock_init (& k-> list_lock );
}
Int kset_register (struct kset * k); // registers a function.
Void kset_unregister (struct kset * k); // deregister the Function
Static inline struct kset * kset_get (struct kset * k );
Static inline void kset_put (struct kset * k );
Three Components of the device driver model
Bus:
Struct bus_type
{
Const char * name;
Struct bus_attribute * bus_attrs;
Struct device_attribute * dev_attrs;
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 );
Struct dev_pm_ops * pm;
Struct bus_type_private * p;
};
Struct bus_type_private
{
Struct kset subsys; // represents the bus subsystem. The kobj in it is the main kobj of the bus, that is, the top layer.
Struct kset * drivers_kset; // a collection of all drivers mounted to the bus.
Struct kset * devices_kset; // a collection of all devices mounted to the bus.
Struct klist klist_devices; // list of all devices
Struct klist klist_drivers; // list of all drivers
Struct block_notifier_head bus_notifier;
Unsigned int drivers_autoprobe: 1; // sets whether the driver is registered. The device is automatically displayed.
Struct bus_type * bus; // indicates the bus that contains the current user.
};
Int bus_register (struct bus_type * bus );
Void bus_unregister (struct bus_type * bus );
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 );
};
Int bus_create_file (struct bus_type * bus, struct bus_attribute * attr );
Void bus_remove_file (struct bus_type * bus, struct bus_attribute * attr );
Device:
Struct device
{
Struct klist klist_children; // connect the linked list of the sub-Device
Struct device * parent; // pointer to the parent device
Struct kobject kobj; // embedded kobject
Char bus_id [BUS_ID_SIZE]; // location connected to the bus
Unsigned uevent_supress: 1; // whether hot swapping events are supported
Const char * init_name; // device initialization name
Struct device_type * type; // special device-related processing functions
Struct bus_type * bus; // pointer to the connected bus
Struct device_driver * driver; // The driver pointing to the device
Void * driver_data; // pointer to private data of the driver
Struct dev_pm_info power; // power Management Information
Dev_t devt; // device number
Struct class * class; // point to the class to which the device belongs.
Struct attribute_group ** groups; // group attribute of the device
Void (* release) (struct device * dev); // call back the device descriptor.
...
};
Int device_register (struct device * dev );
Void device_unregister (struct device * dev );
Struct device_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 * device, struct device_attribute );
Void device_remove_file (struct device * dev, struct device_attribute * attr );
Driver:
Struct device_driver
{
Const char * name; // device driver name
Struct bus_type * bus; // point to the bus to which the driver belongs. There are many devices on the bus.
Struct module * owner; // the device driver module.
Const char * mod_name; // device driver name
Int (* probe) (struct device * dev);/probe function
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 ** group;
Struct dev_pm_ops * pm;
Struct driver_private * p;
};
Struct driver_private
{
Struct kobject kobj; // embedded with the kobject structure, used to build a device driver model
Struct klist klist_devices; // list of all devices supported by the driver
Struct klist_node knode_bus; // bus to which the driver belongs
Struct module_kobject * mkobj; // Driver Module
Struct device_driver * driver; // point to the driver itself
};
Int driver_register (struct device_driver * drv );
Void driver_unregister (struct device_driver * drv );
Struct driver_attribute
{
Struct attribute attr;
Ssize_t (* show) (struct device_driver * driver, char * buf );
Ssize_t (* store) (struct device_driver * driver, const char * buf, size_t count );
};
Int driver_create_file (struct device_driver * drv, struct driver_attribute * attr );
Void driver_remove_file (struct device_driver * drv, struct driver_attribute * attr );