first, device-driven layered thinking: Take platform device drive, input device driver as an example to see how they embody the layered ideology
"1" at the core level: A class of device bus common features, if a device supported by the bus comparison can not use these features, in their own device bus structure
to overload.
Example (1) Platform core layer: Defined in the Drivers/base/platform.c file
The Linux kernel first makes a global abstraction of the device bus, which summarizes the features of all device-driven buses:
struct Bus_type {//With bus name, bus properties, device properties on bus, driver on bus properties Const CHAR*NAME;STRUCT bus_attribute*bus_attrs;struct Device_attribute The *dev_attrs;struct driver_attribute*drv_attrs;//has a matching, hot-swap, probe, and remove device scheme 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),//With power management scheme 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 device has different characteristics-this is itself a commonality};
for platform devices, the kernel does not implement these general functional properties, after all, in reality, most of the situation, the different functions of the device is still more, unless it is to control the volume of the same equipment under a CPU, this is my personal view
struct Bus_type Platform_bus_type = {. Name= "platform",. dev_attrs= platform_dev_attrs,.match= platform_match,.uevent= Platform_uevent,.pm= Platform_pm_ops_ptr,};
in other words, the kernel thinks that the common features of platform devices in most cases have the above 5 aspects and give them the default scheme .
carefully we found that there is no probe member in the platform bus, and it can be considered that there is no or no need for such a function in the bus.
after the initialization of the kernel call:
int __init platform_bus_init (void);
Bus_register (&platform_bus_type);
A set of default schemes for this type of device is on the platform bus.
Example (2) input core layer: An overall abstraction of the management of input devices
struct Input_handle {void *private;int open;const char *name;struct input_dev *dev ;//# #关键成员struct Input_handler * Handler # #关键成员struct list_headd_node;struct List_headh_node;};
derived to:
struct Evdev {int exist;int open;int Minor;char name[16];struct input_handle handle;//inherit Input_handle base class Wait_queue_head_ T wait;struct evdev_client *grab;struct list_head client_list;spinlock_t client_lock; /* Protects client_list */struct mutex mutex;struct device dev;};
when is it instantiated?
before analyzing the input device driver framework, he was the Connect function through the event-driven layer after the input device and the drive Mach succeeded
Evdev_connect (struct Input_handler *handler, struct input_dev *dev,const struct input_device_id *id) {... evdev = Kzalloc (sizeof (struct evdev), gfp_kernel); Evdev->minor = Minor;evdev->handle.dev = Input_get_device (dev); Point to Input_devevdev->handle.name = Evdev->name;evdev->handle.handler = handler; Point to Input_handlerevdev->handle.private = Evdev;error = Input_register_handle (&evdev->handle);//Let Input_ Dev and Input_handler h_list point to Evdev->handle ...}
"2" on the device layer and the drive layer: Similarly, the kernel abstracts the device-driven base class, derives a device driver, and then instantiates it into a specific device driver .
Example (1) platform device/drive layer
the global abstraction:
//Device base class:
struct Device {struct device*parent;struct device_private*p;struct kobject kobj;const char*init_name;/* Initial name of T He device this is the traditional bus_id, specific to each device as the default value */struct device_type*type;......struct bus_type*bus;/* type of bus device is on */ struct Device_driver *driver;/* which driver have 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);};
//Drive base class:
struct Device_driver {const char*name;struct bus_type*bus;struct module*owner;const char *mod_name;/* used for built-in m Odules */int (*probe) (struct device *dev); int (*remove) (struct device *dev); void (*shutdown) (struct device *de v); 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;};
platform Device/driver derivation:
struct Platform_device {const char*name;intid; Symbol of hardware equipment/representative of the struct Devicedev; This inherits the base class U32num_resources;struct resource* resource;//The resource struct platform_device_id*id_entry used by this drive;}; struct Platform_driver {int (*probe) (struct platform_device *);//This function is usually implemented by itself to implement Int (*remove) (struct platform_device *); void (*shutdown) (struct platform_device *); int (*suspend) (struct Platform_device *, pm_message_t State); Int (*suspend_ Late) (struct Platform_device *, pm_message_t State); Int (*resume_early) (struct platform_device *); int (*resume) (struct Platform_device *); struct Device_driver driver; Inherit base class struct platform_device_id *id_table;};
instantiate to a specific led device:
static struct Platform_device Led_dev = { . Name = "Myled", . ID =-1, . num_resources = Array_ SIZE (Led_resource), . Resource = Led_resource, . dev = { . Release = Led_release, }, }; struct Platform_driver led_drv = { . Probe = Led_probe, . Remove = Led_remove, . Driver = { . Name = "myled", } };
Example (2) input device/event-driven layer :
derived input device base class:
struct Input_dev {const char *name;const char *phys;const char *uniq;struct input_id id;unsigned long evbit[bits_to_longs ( EV_CNT)];unsigned long keybit[bits_to_longs (key_cnt)];unsigned long relbit[bits_to_longs (rel_cnt)];unsigned long Absbit[bits_to_longs (abs_cnt)];......struct timer_list timer;int sync;int Abs[abs_max + 1];int Rep[REP_MAX + 1]; unsigned long key[bits_to_longs (key_cnt)];unsigned long led[bits_to_longs (led_cnt)];......int (*open) (struct input_ Dev *dev), void (*close) (struct Input_dev *dev), int (*flush) (struct Input_dev *dev, struct file *file), int (*event) (struct Input_dev *dev, unsigned int type, unsigned int code, int value); struct input_handle *grab;......struct device dev; Also inherit from the kernel abstraction out of the device base class struct list_headh_list;struct list_headnode;};
input Device Instantiation--key:
struct Input_dev Buttons_dev = Input_allocate_device (); Set_bit (Ev_key, buttons_dev->evbit); Set_bit (Ev_rep, buttons_dev->evbit); Set_bit (key_l, buttons_dev->keybit); Set_bit (key_s, buttons_dev->keybit); Set_bit (Key_enter, buttons_dev->keybit); Set_bit (Key_leftshift, buttons_dev->keybit);
Event-Handling base class:
struct Input_handler {void *private;void (*event) (struct input_handle *handle, unsigned int type, unsigned int code, int v alue); int (*connect) (struct Input_handler *handler, struct input_dev *dev, const struct input_device_id *id); Void (* Disconnect) (struct input_handle *handle); void (*start) (struct input_handle *handle); const struct File_operations *fops ; int Minor;const char *name;const struct input_device_id *id_table;const struct input_device_id *blacklist;struct list_ Headh_list;struct List_headnode;};
Event-Handling base class instantiation:
static struct Input_handler Evdev_handler = {. event= evdev_event,.connect= evdev_connect,.disconnect= Evdev_disconnect ,. fops= &evdev_fops,.minor= evdev_minor_base,.name= "Evdev",. id_table= Evdev_ids,};
Summary:
The above analysis is from the data structure of the characteristics of local stratification, the driving framework of hierarchical management in the above two special driving models also have obvious embodiment:
① drives the platform device with the bus-device-drive model as the framework:
Core layer: bus--provides functions such as registration interface and match match criteria for the following layer
device layer/Drive layer: dev/drv--is registered using the interface of the core layer
drawings: Borrow Vedon Teacher's explanation diagram
The ② is driven by a non-bus-device-drive-to-frame input device:
Core layer: To provide a registration interface to the following layer, while providing the app with the Open interface in File_operation
Device Layer: Use the registration interface provided by the core layer
Event-driven layer: Re-implement Interface in File_operation using the registration interface provided by the core layer
drawings: borrow Vedon Teacher's explanation diagram
----------------------------------------------------------------------------------------------------------- --------------------------------------------
second, the host drive and peripheral drive separation of ideas
Host drive: A relatively stable driver of pure software
Peripheral Drivers: hardware platform-related resources
As mentioned above: Platform device layer and drive layer, input device layer and event processing layer
Drawings:
The benefits of such a design are mainly reflected in :
(1) The CPU is unchanged, assuming 2440, the number of peripherals is increased by K
① not to be separated:
then need to write the controller to the peripheral driver K, drive each peripheral to involve the host controller related content and peripheral related content,
for the sake of comparison we here write a host controller content as a driver, a peripheral related content as a driver, that is to say:
2 drivers are required to drive a peripheral, so you need to add 2k of drive content
② to separate the case:
only need to increase the driver content of K peripheral
(2) when changing J different host CPUs, the number of peripherals n is unchanged
① not to be separated:
need to rewrite the driver of the N host controller operation peripherals, the content of the writing also involves the operation of the host controller and peripheral related operations
Imagine: If I change the J CPU, the peripheral is still the same, then I need to write j*2n drive content
② to separate the case:
all you need to do is write j*x driver content.
we know that the number of host controllers is usually much less than the number of peripherals, if your host controller number more than the number of peripherals can only
indicates that some of your controllers are not actually applied. This means that x is less than or equal to N, and is obviously at least one-fold less content.
Linux device driver Model--separation and layering thought