1、什么是设备驱动模型
2、为什么需要设备驱动模型
3、驱动开发的两个点
1、kobject
2、kobj_type
3、kset
1、总线(bus)
2、设备
3、驱动
4、类
5、总结
1、何为平台总线
2、平台总线下管理的两员大将
struct platform_device
{
const char* name;//平台总线下设备的名字
int id;
struct device dev;//所有设备通用的属性部分
u32 num_resources;//设备使用到的resource的个数
struct resource* resource;//设备使用到的资源数组的首地址
const struct platform_device_id* id_entry;//设备id表
/*arch specific addition*/
struct pdev_archdata archdata;//自留地,用来提供扩展性的
}
struct platform_driver
{
int(*probe)(struct platform_device*);//驱动探测函数
int(*remove)(struct platform_device*);//去掉一个设备
void(*shutdown)(struct platform_device*);//关闭一个设备
int(*suspend)(struct platform_device*,pm_message_t state);
int(*resume)(struct platform_device*);
struct device_driver driver;//所有设备共用的一些属性
const struct platform_device_id* id_table;//设备ID 表
}
1、平台总线体系工作流程
2、代码分析:platform本身注册
1、以 leds-s3c24xx.c 为例来分析 platform 设备和驱动的注册过程
2、platdata 简介
1.在驱动程序里添加 platform_driver 相关代码。
2.测试 platform_device 和 platform_driver 相遇时会怎样。
#include // module_init module_exit
#include // __init __exit
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define X210_LED_OFF 1
#define X210_LED_ON 0
// 定义大结构体
struct s5pv210_gpio_led{
struct led_classdev cdev;
struct s5pv210_led_platdata* pdata;
};
// 由 platform_device 指针得到 s5pv210_gpio_led 指针
static inline struct s5pv210_gpio_led* pdev_to_gpio(struct platform_device* dev)
{
return platform_get_drvdata(dev);
}
//通过led_classdev得到s5pv210_gpio_led指针
static inline struct s5pv210_gpio_led* to_gpio(struct led_classdev* led_cdev)
{
return container_of(led_cdev,struct s5pv210_gpio_led,cdev);
}
//这个函数就是要去完成具体的硬件读写任务的
static void s5pv210_led_set(struct led_classdev* led_cdev,enum led_brightness value)
{
struct s5pv210_gpio_led* p=to_gpio(led_cdev);//透过led_classdev得到s5pv210_gpio_led指针
printk(KERN_INFO "s5pv210_led_set\n");
if (value == LED_OFF)// 用户给了个 0,希望 LED 灭
gpio_set_value(p->pdata->gpio, X210_LED_OFF);
else// 用户给的是非 0,希望 LED 亮
gpio_set_value(p->pdata->gpio, X210_LED_ON);
}
//platform_device和platform_driver匹配后调用这函数
static int s5pv210_led_probe(struct platform_device* dev)
{
int ret=-1;
struct s5pv210_led_platdata* pdata=dev->dev.platform_data;//获取platform_data
struct s5pv210_gpio_led* led;//实例化
printk(KERN_INFO "----s5pv210_led_probe---\n");
led=kzalloc(sizeof(struct s5pv210_gpio_led),GFP_KERNEL);//申请所需内存空间
if(led==NULL){
dev_err(&dev->dev,"No memory for device\n");return -ENOMEM;
}
platform_set_drvdata(dev,led);
//在这里去申请驱动用到的各种资源,当前驱动中就是GPIO资源
if(gpio_request(pdata->gpio,pdata->name))
printk(KERN_ERR "gpio_request failed\n");
else// 设置为输出模式,并且默认输出 1 让 LED 灯灭
gpio_direction_output(pdata->gpio, 1);
//struct s5pv210_gpio_led的填充
led->cdev.name=pdata->name;
led->cdev.brightness=0;
led->cedv.brightness_set=s5pv210_led_set;
led->pdata=pdata;
//注册led_classdev
ret=led_classdev_register(&dev->dev,&led->cdev);
if(ret<0){
printk(KERN_ERR"led_classdev_register failed\n");return ret;
}
return 0;
}
//卸载平台设备驱动时调用该函数
static int s5pv210_led_remove(struct platform_device* dev)
{
struct s5pv210_gpio_led* p=pdev_to_gpio(dev);//由platform_device指针得到s5pv210_gpio_led指针
led_classdev_unregister(&p->cdev);//注销led_classdev
gpio_free(p->pdata->gpio);//释放gpio资源
kfree(p);//kfree最后一步
return 0;
}
//platform_driver实例化
static struct platform_driver s5pv210_led_driver={
.probe=s5pv210_led_probe,
.remove=s5pv210_led_remove,
.driver={
.name="s5pv210_led",
,owner=THIS_MODULE,
},
}
static int __init s5pv210_led_init(void)
{
return platform_driver_register(&s5pv210_led_driver);//注册设备驱动
}
static void __exit s5pv210_led_exit(void)
{
platform_driver_unregister(&s5pv210_led_driver);//卸载设备驱动
}
module_init(s5pv210_led_init);
module_exit(s5pv210_led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("aston <1264671872@qq.com>");
MODULE_DESCRIPTION("s5pv210 led driver");
MODULE_ALIAS("s5pv210_led");