总览:
Koject & Kset
设备驱动模型
platform驱动程序
中断处理
按键驱动程序
1、platform总线:由两部分组成:platform_device和platform_driver
2、工作流程:
定义设备:platform_device
注册设备:platform_device
定义驱动:platform_driver
注册驱动:platform_driver
3、平台设备描述
struct platform_device {
const char *name;
int id;设备编号
struct device dev;
u32 num_resource;
struct resource *resource; 设备资源这个参数比较重要,用来表示中断号还是GPIO地址
}
4、如何分配创建一个平台设备
struct platform_device *platfrom_device_alloc(const char *name, int fd);
创建完之后再赋值其他信息。
5、如何注册到内核
int platform_device_add(struct platform_device *pdev);
6、资源信息赋值
struct resource{
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;//资源类型 MEM IO IRQ等等
struct resource *parent, sibing, *child;//资源链表信息
}
举例怎么赋值:
struct resource{ s3c_wet_resource1={
.start = 0x44100000,
.end = 0x44200000.
. flags=OPRESOURCE_MEM,
}
struct resource{ s3c_wet_resource2={
.start = 20,
.end = 20.
.flags=OPRESOURCE_IRQ,
}
7、获取资源信息的接口
struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num);
8、平台驱动
struct platform_driver{
int (*probe)(struct platform_device*);
int (*remove)(struct platform_driver*);
void (*shutdown)(struct platform_device *);
int (*suspend)(struct platform_device *,pm_messgae_t state);
...
int (*resume_early)(struct platform_device*)
int (*resume)(struct platform_device *);
struct device_driver driver;
}
9、平台驱动注册
int platform_driver_register(struct platform_driver * pdriver)
10、创建实例
(1)注册平台驱动
#include <linux/device.h> #include <linix/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/platform_device.h> MODULE_LICENSE("GPL"); int my_probe(struct device *dev) { printk("driver found device which my driver can handle\n"); } int my_remove(struct device *dev) { printk("driver found device remove~\n"); } struct platform_driver my_driver={ .probe = my_probe, .remove = my_remove, .driver = { .owner =THIS_MODULE, .name "my_dev", }, }; int __init my_driver_init(void) { return platform_driver_register(&my_driver); } void __exit my_driver_exit(void) { platform_driver_unregister(&my_driver); } module_init(my_driver_init); module_exit(my_driver_exit);
(2)注册平台设备
#include <linux/device.h> #include <linix/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/string.h> #include <linux/platform_device.h> MODULE_LICENSE("GPL"); struct platform_device *my_device; int __init my_device_init(void) { my_device = platform_device_alloc("my_dev",-1); platform_device_add(my_device); } void __exit my_device_exit(void) { platform_device_unregister(my_device); } module_init(my_device_exit); module_exit(my_device_exit);
(3)效果
insmod platform_dev.ko之后
注册平台设备之后,会在/sys/bus/platform/devices/生成my_dev文件
insmod platform_drv.ko
直接调用平台驱动的probe函数,
注册平台驱动之后,会在/sys/bus/platform/drivers/生成my_dev文件
但是,/dev目录下没有设备文件,因为不确定你的设备文件是字符设备还是块设备还是网卡。
总结:
总线,驱动,设备之间的关系?专题2-总线设备驱动模型-总线设备驱动模型 - 六月下大雨 - 博客园 (cnblogs.com)
在总线的学习中,我们知道总线模型分为三步:注册总线(struct bus_type my_bus_type),注册驱动(strucrt device_driver *drv),注册设备(struct device *dev)
引申到平台总线(struct bus_type platform_bus_type),平台驱动(struct platform_driver *drv),平台设备(struct platform_device *my_device;)之间的关系?
1、平台总线有一个match函数,需要平台设备和驱动设备作为入参进行匹配。
2、平台驱动里面有一个driver_device,和平台设备之间需要名字一样进行匹配。
3、平台设备的添加实际上是驱动设备的注册,
平台驱动是什么时候注册的?如何注册的?
#define platform_driver_register(drv) \ __platform_driver_register(drv, THIS_MODULE)
int __platform_driver_register(struct platform_driver *drv, struct module *owner) { drv->driver.owner = owner; drv->driver.bus = &platform_bus_type; //平台总线结构体 drv->driver.probe = platform_drv_probe; drv->driver.remove = platform_drv_remove; drv->driver.shutdown = platform_drv_shutdown; return driver_register(&drv->driver); //注册设备驱动实际上就是之前的driver_register(&my_driver);
}
总线设备结构体是在内核中已经有的定义,注册平台驱动的时候,需要把自己的平台驱动挂载在平台总线上。当平台驱动加载的时候,实际上是调用了平台总线上的probe函数,在注册平台驱动的时候,把平台驱动的probe函数被赋值了平台总线的probe函数。
int driver_register(struct device_driver *drv) { int ret; struct device_driver *other; other = driver_find(drv->name, drv->bus); ret = bus_add_driver(drv); ret = driver_add_groups(drv, drv->groups); kobject_uevent(&drv->p->kobj, KOBJ_ADD); return ret; }