Linux systems integrate devices and drivers into device-driven models to manage
Device driver Features:
1, initialization and release of hardware devices
2, manage the device, including the parameter setting, and provide the unified operation interface to the device.
3. Read the data that the application passes to the device file or the loopback application requests
4. Detect or process errors in the device
The device-driven model provides a hardware abstraction including:
1, Power management
In fact, power management is the time when some equipment is not working, let it rest for a while, sleep for a while (minimum consumption), to achieve the purpose of saving electricity
One of its important features is:
Power-down mode to suspend devices in the system in a certain order
In full-speed operation mode, the system's equipment will be resumed in a certain sequence.
That means, a bus has n devices, only when n devices are suspended, the bus can hang. However, as long as one device is restored, the bus has to be restored
2, Plug and Play device support
This everyone has deep experience, you put PS/2 mouse, keyboard pull out, and then plug it up, to see if there is no response. But pull the USB mouse keyboard and plug it in, you can continue to use
This is the legendary plug-and-play support.
3, communication with user space
There are many ways to communicate with users, and the previously famous proc file system is a stark representation. It gives the user a pair of clairvoyance. But proc still by the later Sysfs file system to take down, from now on.
Although Proc is still alive, its influence has fallen. At the same time have to say, Proc got the world, certainly has its extraordinary place, where SYSFS may be frustrated. But the strong is still not so good to shake
The Linux device driver model has several basic data structure models: Kobject,kset,subsystem
Kobject: This is the basis of the device-driven model, like a floor tile and bricks. Sysfs was his offspring, and his father and his grandfather propped it up.
struct Kobject
{
const char *name; Names that appear in the SYSFS
struct List_head entry; Next Kobject structure
struct Kobject *parent; Point to the parent kobject struct, if present
struct Kset *kset; Point to Kset Collection
struct Kobj_type *ktype; Point to Kobject type descriptor
struct Sysfs_dirent *sd; File directory corresponding to Sysfs
struct Kref kref; Kobject reference count
unsigned int state_initialized:1; Whether to initialize
unsigned int state_in_sysfs:1; Whether to join SYSFS
unsigned int state_add_uevent_sent:1; is hot plug-in supported
unsigned int state_remove_uevent_sent:1; Is hot-swappable 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 has 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 the internal members of the Kobject
Kobj->ktype = Ktype; Binding a Ktype property for 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 (); Initiation of Kobject
Kobject_get (); Increase Kobject Reference count
Kobject_put (); Reduce Kobject reference count, Count to zero, call Kobject_release () release, it's inside Kobj_type
Kobject_set_name (); Set name
Kobject_rename (); Renaming
Kobject_add () add
Each kobject will have an attribute Kobj_type
struct Kobj_type
{
void (*release) (struct kobject *kobj); Releasing Kobject and other resource-intensive functions
struct Sysfs_ops *sysfs_ops; Methods for manipulating properties
struct attribute **default_attrs; Property array
};
struct attribute
{
const char *name; Name of the property
struct module *owner; Only the module that owns the property is used infrequently
mode_t mode; Property Read and Write permissions
};
struct SYSFS_OPS
{
ssize_t (*show) (struct kobject *,struct attribute *,char *); Read Property manipulation function
ssize_t (*store) (struct kobject *,struct attribute *,const char *,size_t); Write Property manipulation functions
};
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 isn't Initialized,yet kobject_put () is being called.\n", Kobject_name (Kobj), Kobj);
Kref_put (&kobj->kref,kobject_release);
}
}
Typically, DEFAULT_ATTR members of the Kobject type define all the default properties owned by Kobjet. However, in special cases, you can add some default properties:
To add a property file:
int sysfs_create_file (struct kobject *kobj,const struct attribute *attr);
To delete a property file:
void Sysfs_remove_file (struct kobject *kobj, const struct attribute *attr);
struct Kset
{
struct List_head list; The link list header address of the Kobject object that the connection contains
spinlock_t List_lock; Maintain the spin lock for list lists
struct Kobject kobj; Inline Kobject, indicating that Kset itself is also a directory
struct Kset_uevent_ops *uevent_ops; Hot Swap Events
};
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);
};
Kset and Kobject relations:
The 1,kset collection contains the kobject structure that belongs to it, and the Kset.list list is used to connect the first and last Kobject objects. The first Kobject uses entry to connect the Kset collection and the second Kobject object. The second Kobject object uses entry to connect the first Kobject object and the third Kobject object, and so on, and eventually forms a linked list of Kobject objects.
2, the parent pointer of all kobject structures points to the Kobject object that kset contains, forming a parent-child hierarchical relationship
All Kset pointers to 3,kobject point to the Kset collection that contains it, so kset collections can be easily found by Kobject objects
4,kobject's kobj_type pointer points to its own kobj_type, and each kobject has a separate kobj_type structure. In addition, there is also a kobject structure in the Kset collection, and the xxx of the struct also points to a kobj_type structure. It is known that a set of properties and the methods of manipulating properties are defined in Kobj_type. Note here: The priority of Kobj_type in Kset is higher than the priority of Kobj_type in Kobject object. If two kobj_type are present, then the function in Kset is called first. If Kobj_type in Kset is empty, the function in Kobj_type corresponding to each kobject struct itself is called
The Kobj in 5,kset is also responsible for the reference count of Kset
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); Registration function
void Kset_unregister (struct kset *k); Logoff function
Static inline struct Kset *kset_get (struct kset *k);
static inline void Kset_put (struct kset *k);
Three components of a device-driven 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, where the kobj is the bus's main kobj, which is the top level
struct Kset *drivers_kset; Mounts to all drive sets on the bus
struct Kset * devices_kset; Mounts to all device collections on 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; Set whether the driver registration is, automatically eject the device
struct Bus_type *bus; Point back to the bus containing itself
};
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);
Equipment:
struct device
{
struct Klist klist_children; Linked list of connected sub-devices
struct device *parent; Pointer to parent device
struct Kobject kobj; Built-in Kobject
Char Bus_id[bus_id_size]; Connecting to a location on the bus
unsigned uevent_supress:1; Whether hot-swappable events are supported
const char *init_name; Initialization name of the device
struct Device_type *type; Special processing functions related to equipment
struct Bus_type *bus; The bus pointer to the connection
struct Device_driver *driver; Drivers that point to the device
void *driver_data; Pointers to driver private data
struct Dev_pm_info power; Power Management Information
dev_t devt; Device number
struct class *class; Pointing to the class the device belongs to
struct Attribute_group **groups; Group Properties for Devices
void (*release) (struct device *dev); Release the callback function for 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);
Driven:
struct Device_driver
{
const char *name; Device driver name
struct Bus_type *bus; The bus that points to the drive, there are many devices on the bus
struct module *owner; Device driver Self-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; Built-in kobject structure for building device driver models
struct Klist klist_devices; All device linked lists supported by this driver
struct Klist_node Knode_bus; The driver belongs to the bus
struct Module_kobject *mkobj; Driver-driven modules
struct Device_driver *driver; Point to the drive 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);
Linux Device Driver Model