在linux2.6以后的内核驱动模型中,关心总线、设备、驱动这三块。 总线是连接设备和驱动的,一个设备注册后会通过总线去找驱动,而驱动注册后也会通过总线去找对应的设备。 这种设备模型就需要设备和驱动挂接在一个总线上面,对有实际总线的设备和驱动那是没问题的,但有一些挂接在soc内存空间的外设,则没有对应的总线来挂接,由此引入了platform总线的概念, 即虚拟总线。
platform总线上面的设备和驱动分别是platform_device 和platform_dirver。设备和驱动通过一些特殊的方式进行匹配,下面进行具体代码分析。
描述设备信息的通常有三种方法:平台文件、模块和设备树,这里以模块方式加载设备信息。 关于设备信息结构体描述在platform_device.h文件中
struct platform_device { /*一般都是通过名字来匹配的*/ const char *name; /*ID是-1的话,则通过过名字来匹配*/ int id; bool id_auto; /*设备信息*/ struct device dev; /*资源信息的大小*/ u32 num_resources; /*这个结构体里面填充相应的设备资源信息,是一个结构体数组*/ struct resource *resource; const struct platform_device_id *id_entry; char *driver_override; /* Driver name to force a match */ /* MFD cell pointer */ struct mfd_cell *mfd_cell; /* arch specific additions */ struct pdev_archdata archdata;};resource结构体填充—>下面只是举的一个例子
struct resource res[]={ [0]={ .start = 0x11, .end = 0x22, .flags = IORESOURCE_MEM, /*寄存器信息*/ }, [1]={ .start = 0x33, .end = 0x44, .flags = IORESOURCE_MEM, }, [2]={ .start = 25, .end = 25, .flags = IORESOURCE_IRQ, /*中断信息*/ },};一般驱动几个步骤,定义,初始化,注册和释放。上面将设备信息模块的定义与初始化讲完了。 下面说说设备信息模块的注册与释放,同样他们也在platform_device.h文件中。 注册
extern int platform_device_register(struct platform_device *);释放
extern void platform_device_unregister(struct platform_device *);无论设备信息用何种方式描述,驱动方法都是使用同样的一种套路。驱动方法一般都是以模块的方式加载进内核当中的。 同样驱动方法的编写离不开四大步:定义,初始化,注册和释放。 驱动方法所使用的函数和结构体都在platform_device.h当中。
定义结构体
struct platform_driver { /*设备的注册和相应的操作在PRobe中完成*/ int (*probe)(struct platform_device *); /*设备的注销在remove中完成*/ int (*remove)(struct platform_device *); void (*shutdown)(struct platform_device *); int (*suspend)(struct platform_device *, pm_message_t state); int (*resume)(struct platform_device *); /*这个结构体重描述设备信息,如名字什么的,总线通过driver结构体的内容进行匹配*/ struct device_driver driver; const struct platform_device_id *id_table; bool prevent_deferred_probe;};当驱动信息对应字符设备时,字符设备的获取设备号及注册的工作在probe里面完成,字符设备的注销在remove里面完成。而相应的模块的注册和模块的注销则还是在init和exit函数中完成。
获取资源 一旦匹配成功,程序就会进入probe当中,在probe中通过获取资源的一些函数操作可以得到相应的设备信息中的内容。
extern struct resource *platform_get_resource(struct platform_device *, unsigned int, unsigned int);举一个实例,对应上面的device中的设备信息
struct resource * res =NULL; res = platform_get_resource(dev,IORESOURCE_MEM, 0); printk("res->start = %#x/n",res->start); printk("res->end = %#x/n",res->end); printk("res->flags = %#x/n",res->flags); /*这里是得到reg信息,然后打印出来*/注册及注销模块
platform_driver_register(drv)extern void platform_driver_unregister(struct platform_driver *);以上也只是platform总线的最基础模块的编写,如果在实际工作中还需要编写对下硬件的操作,对上层提供函数接口的工作。
新闻热点
疑难解答