Linux驱动过程总览
以上是Linux驱动从入口函数到驱动probe函数的整个流程。
module_init(xxx_init_module):驱动入口函数,一般在驱动代码的最下方。其参数即为驱动初始化函数。
module_init(xxx_init_module)//这就入口
module_exit(xxx_exit_module)//这就设备退掉的时候调的,不是出口啊,一般来说不要...
xxx_init_module:驱动初始化函数,当一个设备接入后,它的路就从这里开始了。
xxx_register_driver:这通常是一个宏控,其本体为__xxx_register_driver。
#define xxx_register_driver(drv) \
__xxx_register_driver(struct xxx_driver *,struct module *)
//这个xxx_driver还挺关键,随后再议。
__xxx_register_driver:这个函数中包含了很多对驱动结构体中函数的重定向,这个之后再说,先关注一下它的返回值。
int __xxx_register_driver(struct xxx_driver *drv ,struct module *owner)
{
...
return driver_register(drv->driver);
}
driver_register:这个函数的运行结果就是__xxx_register_driver函数的返回值。
int driver_register(struct device_driver *drv){}//device_driver它出现了...0.0
bus_add_driver:在函数driver_register中运行,它的结果将决定总线是否可完成设备和驱动的匹配。参数和上面那个函数是一样的。
driver_attach:它来了,它来了,他们又开始套娃了 …可能是我太菜了,不能理解这个函数是干嘛的…
int driver_attach(struct device_driver *drv)
{
return bus_of_each_dev(drv->bus,NULL,drv,__driver_attach);
}
bus_for_each_dev:driver_attach函数只做了一件事,就是返回这个函数的结果。(所以为什么不直接返回这个函数的结果???)这个函数有四个参数,我就不打出来了…费劲…
fn(dev,data):bus_for_each_dev函数的第四个参数是__driver_attach函数,fn事实上就是指向__driver_attach的函数指针。所以这里事实上运行的是__driver_attach 。
driver_match_device:这个函数是__driver_attach函数中的一个函数,主要目的就是为了匹配设备和驱动。它将会返回这么个玩意:别问我这干啥的,我也不知道…嘿嘿嘿… 不过假如没匹配上,那这个驱动就GG了。
static inline int driver_match_device(struct device_driver *drv,struct device *dev)//device它出现了..0.0
{
return drv->bus->match ? drv->bus->match(dev,drv) : 1 ;
}
driver_probe_device:这个函数建立在设备与驱动已经匹配上的情况下,它在函数__driver_attach中,走到这它还会提示一下驱动设备已经匹配了哦嘿嘿嘿 我自己加的printk,不知道你们加没加…
int driver_probe_device(struct device_driver *drv,struct device *dev)
{
...
printk("bus:mmm is matching dev:yyy and drv:zzz OK!!");//大概就这样吧,log里就会打出来已经匹配成功了。
ret = really_probe(dev,drv);
...
}
really_probe:如函数名所示,really_probe。就是真正的probe函数从这里开始,在函数中会调用drv->probe,从而开始驱动代码中的probe函数。
(以上观点仅代表个人看法,欢迎指正。)
Linux驱动关键结构体
1.struct bus_type
struct bus_type {
const char *name;
const char *dev_name;
struct device *dev_root;
struct device_attribute *dev_attrs;
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);
int (*online)(struct device *dev);
int (*offline)(struct device *dev);
const struct dev_pm_ops *pm;
struct iommu_ops *iommu_ops;
struct subsys_private *p;
struct lock_class_key lock_key;
};
2.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; //平台特定数据,设备核心不碰它
struct dev_pm_info power;
struct dev_pm_domain *pm_domain;
#ifdef CONMFIG_PINCTRL
struct dev_pin_info *pins;
#endif
#ifdef CONFIG_NUMA
int num_node; //NUMA节点与该设备接近
#endif
u64 *dma_mask; //ama掩码,如果dma设备被开启
u64 coherent_dma_mask; /*类似于dma掩码,但是对于内存一致映射,
并不是所有的硬件都支持64位地址来一致分配这样的描述符*/
struct device_dma_parameters *dma_parms;
struct list_head dma_pools; //dma池
struct dma_coherent_mem *dma_mem //内部为连贯的内存覆写
#ifdef CONFIG_DMA_CMA
struct cma *cma_area; //用于dma分配的连续内存区域
#endif
/*arch 主要附加*/
struct dev_archdata archdata;
struct device_node *of_node; //关联设备树节点
struct acpi_dev_node acpi_node; //关联ACPI设备节点
dev_t devt; //dev_t,创建sysfs节点dev
u32 id; //设备实例
spinlock_t devres_lock;
struct list_head;
struct klist_node knode_class;
struct class *class;
const struct attribute_group **groups; //可选组
void (*release)(struct device *dev);
struct iommu_group *iommu_group;
bool offline_disabled:1;
bool offline:1;
}
3.struct device_driver
struct device_driver{
const char *name;
struct bus_type *bus;
struct module *owner;
const char *mod_name; //用于内置模块
bool suppress_bind_attrs; //通过sysfs禁用 绑定/解绑定
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;
}
其实在Linux内核中,所有设备的驱动的定义,都是以struct device_driver为基类进行继承扩展的。
device_driver和device分别表示驱动和设备,这两都依附在一种总线上,因此都包含struct bus_type指针。在Linux内核中,设备和驱动是分开注册的,注册一个设备的时候,并不需要驱动已经存在。(驱动:俺也一样。)设备和驱动各自涌向内核,然后找另一半。总线则用match函数把他们捆绑在一块。匹配成功后则执行驱动的probe函数。
总线驱动和设备最终都会落实为sysfs这玩意我稍后再议中的一个目录,进一步追踪代码会发现,他们实际上都可是kobject的派生类,kobject可看作是所有总线、设备和驱动的抽象基类,1个kobject对应sysfs中的1个目录。
总线、设备和驱动中的各个attribute则直接落实为sysfs中的1个文件,attribute会伴随着show()和store()这两个函数,分别用于读写该attribute对应的sysfs文件。
(上面这三段话熟吗,熟就对了,来自于Linux设备驱动开发详解基于最新的Linux4.0第125页…目前就这样吧,等有啥改动了,回头再改…)
转载请注明出处,谢谢...0.0