本文是对视频学习的笔记记录。
platform总线、设备与驱动
在linux2.6以后的设备驱动模型中,需关心总线、设备和驱动这3个实体,总线将设备和驱动绑定。在系统没注册一个设备的时候,会寻找与之匹配的驱动,相反的,在系统每注册一个驱动的时候,会寻找与之匹配的设备,而匹配有总线完成。实现资源与驱动的分离。
platform_device指定资源。
struct platform_device {
const char *name;
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;
};
platform_driver
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;
bool prevent_deferred_probe;
};
DEV与DRV匹配规则
先比较
- platform_device.driver_override和 platform_driver.driver.name ;可以设置 platform_device 的 driver_override,强制选择某个 platform_driver。
再比较
- platform_device. name和 platform_driver.id_table[i].name ;Platform_driver.id_table 是“platform_device_id”指针,表示该 drv 支持若干个 device,它里面列出了各个 device的{.name, .driver_data},其中的“name”表示该drv支持的设备的名字,driver_data是些提供给该 device的私有数据
最后比较
- platform_device.name和 platform_driver.driver.name ;platform_driver.id_table可能为空, 这时可以根据platform_driver.driver.name来寻找同名的platform_device
board_A_led.c
#include "led_resource.h"
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
struct resource res[] = {
{
.start = GROUP_PIN(5,3),
.flags = IORESOURCE_IRQ,
},
{
.start = GROUP_PIN(3,3),
.flags = IORESOURCE_IRQ,
},
{
.start = GROUP_PIN(4,3),
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device board_A_led_dev={
.name="ss_led",
.resource=res,
.num_resources=ARRAY_SIZE(res),
};
static int __init board_A_led_dev_init(void){
return platform_device_register(&board_A_led_dev);
}
static void __exit board_A_led_dev_exit(void){
platform_device_unregister(&board_A_led_dev);
}
module_init(board_A_led_dev_init);
module_exit(board_A_led_dev_exit);
MODULE_LICENSE("GPL");
chip_demo_gpio.c主要部分
int chip_demo_gpio_drv_probe(struct platform_device *pdev){
int i=0;
struct resource *r;
pin_num=0;
while(1){
//获取资源
r=platform_get_resource(pdev,IORESOURCE_IRQ,i++);
if(r){
pin[pin_num]=r->start;
//使用leddrv.c提供接口进行device_create
led_device_create(pin_num++);
}
else break;
}
return 0;
}
int chip_demo_gpio_drv_remove(struct platform_device *pdev){
while(pin_num){
//使用leddrv.c提供接口进行device_destroy
led_device_destroy(pin_num--);
}
return 0;
}
static struct platform_driver chip_demo_gpio_drv={
.probe=chip_demo_gpio_drv_probe,
.remove=chip_demo_gpio_drv_remove,
.driver={
.name="ss_led",
}
};
static int __init chip_demo_gpio_drv_init(void){
//chip_demo_gpio.c底层调用,为的就是把led_opr传给leddrv.c
regester_led_operation(&led_opr);
return platform_driver_register(&chip_demo_gpio_drv);
}
static void __exit chip_demo_gpio_drv_exit(void){
platform_driver_unregister(&chip_demo_gpio_drv);
}
module_init(chip_demo_gpio_drv_init);
module_exit(chip_demo_gpio_drv_exit);
MODULE_LICENSE("GPL");
leddrv.c重要部分
static int __init led_init(void){
printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
major=register_chrdev(0,"myled",&led_drv);
led_class=class_create(THIS_MODULE,"myled_class");
return 0;
}
static void __exit led_exit(void){
printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
led_opr->unmap();
class_destroy(led_class);
unregister_chrdev(major,"myled");
}
//给chip_demo_gpio.c底层提供的接口,为了device_create
void led_device_create(int minor){
device_create(led_class,NULL,MKDEV(major,minor),NULL,"myled%d",minor);
}
//给chip_demo_gpio.c底层提供的接口,为了device_destroy
void led_device_destroy(int minor){
device_destroy(led_class,MKDEV(major,minor));
}
//给chip_demo_gpio.c底层提供的接口,为了能得到led_opr
void regester_led_operation(struct led_operations * opr){
led_opr=opr;
led_opr->map();
}
EXPORT_SYMBOL(led_device_destroy);
EXPORT_SYMBOL(led_device_create);
EXPORT_SYMBOL(regester_led_operation);
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
文件之间关系图
chip_demo_gpio.c和leddrv.c之间看着存在相互依赖的关系,chip_demo_gpio.c需要leddrv.c提供led_class,,,,, leddev.c需要chip_demo_gpio.c返回led_opr。
所以,先加载leddev,然后加载chip_demo_gpio,需要chip_demo_gpio主动调用regester_led_operation返回led_opr给leddrv.