字符设备驱动5(platform总线设备,后面的总结比较实用)

设备驱动模型的底层架构
kobject
(1)定义在linux/kobject.h中
(2)各种对象最基本单元,提供一些公用型服务如:对象引用计数、维护对象链表、对象上锁、对用户空间的表示
(3)设备驱动模型中的各种对象其内部都会包含一个kobject
(4)地位相当于面向对象体系架构中的总基类
、kobj_type
(1)很多书中简称为ktype,每一个kobject都需要绑定一个ktype来提供相应功能
(2)关键点1:sysfs_ops,提供该对象在sysfs中的操作方法(show和store)
(2)关键点2:attribute,提供在sysfs中以文件形式存在的属性,其实就是应用接口
、kset
(1)kset的主要作用是做顶层kobject的容器类
(2)kset的主要目的是将各个kobject(代表着各个对象)组织出目录层次架构
(3)可以认为kset就是为了在sysfs中弄出目录,从而让设备驱动模型中的多个对象能够有层次有逻辑性的组织在一起

总线结构体bus_type,内核负责管理总线,总线负责管理相关的设备和驱动。现在大部分驱动并不用以前的方式,而是用总线进行管理。

总线
(1)物理上的真实总线及其作用(英文bus)
(2)驱动框架中的总线式设计
(3)bus_type结构体,关键是match函数和uevent函数
设备
(1)struct device是硬件设备在内核驱动框架中的抽象
(2)device_register用于向内核驱动框架注册一个设备
(3)通常device不会单独使用,而是被包含在一个具体设备结构体中,如struct usb_device
驱动
(1)struct device_driver是驱动程序在内核驱动框架中的抽象
(2)关键元素1:name,驱动程序的名字,很重要,经常被用来作为驱动和设备的匹配依据
(3)关键元素2:probe,驱动程序的探测函数,用来检测一个设备是否可以被该驱动所管理

(1)相关结构体:struct class 和 struct class_device
(2)udev的使用离不开class
(3)class的真正意义在于作为同属于一个class的多个设备的容器。也就是说,class是一种人造概念,目的就是为了对各种设备进行分类管理。当然,class在分类的同时还对每个类贴上了一些“标签”,这也是设备驱动模型为我们写驱动提供的基础设施。
不同于USB,i2c等物理总线,platform总线是虚拟的,抽象出来的。是对应地址总线式连接的设备,大部分基础设备都是平台总线。为了给没有固定总线的设备添加到总线中去。
platform工作体系都定义在drivers/base/platform.c中
两个结构体:platform_device(硬件设备的抽象,内核移植的人提供)和platform_driver(写驱动的人提供)
两个接口函数:platform_device_register和platform_driver_register
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 additions */
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表
};

内核启动时会自动创建platform总线,同时会调用
__init leds_init
leds_class = class_create(THIS_MODULE, “leds”);//创建类

在arch/arm/mach-s3c2440/mach-mini2440.c文件夹
/**************** LEDS填充s3c24xx_led_platdata*************** */

static struct s3c24xx_led_platdata mini2440_led1_pdata = {
    .name       = "led1",
    .gpio       = S3C2410_GPB(5),
    .flags      = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
    .def_trigger    = "heartbeat",
};

static struct s3c24xx_led_platdata mini2440_led2_pdata = {
    .name       = "led2",
    .gpio       = S3C2410_GPB(6),
    .flags      = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
    .def_trigger    = "nand-disk",
};
/******填充platform_device结构体***********/
static struct platform_device mini2440_led1 = {
    .name       = "s3c24xx_led",
    .id     = 1,
    .dev        = {
        .platform_data  = &mini2440_led1_pdata,
    },
};

static struct platform_device mini2440_led2 = {
    .name       = "s3c24xx_led",
    .id     = 2,
    .dev        = {
        .platform_data  = &mini2440_led2_pdata,
    },
};

static struct platform_device mini2440_led3 = {
    .name       = "s3c24xx_led",
    .id     = 3,
    .dev        = {
        .platform_data  = &mini2440_led3_pdata,
    },
};
/********将所有的platform_device设备封装到一个数组,然后用一个循环挨个注册*********/
    static struct platform_device *mini2440_devices[] __initdata = {

    &mini2440_led1,
    &mini2440_led2,
    &mini2440_led3,
    &mini2440_led4,
    &mini2440_button_device,
    }
//将设备数组中的设备挨个进行注册
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));

以上完成了对设备的注册接下来是insmod装载驱动时候执行的程序

static int __init s3c24xx_led_init(void)
{
    return platform_driver_register(&s3c24xx_led_driver);
}

//platform平台总线注册驱动,注册后会执行platform_match函数,按照驱动的名字和已经注册的设备名字进行匹配,如果匹配上了,则执行驱动中的s3c24xx_led_probe(struct platform_device *dev)函数,驱动会将device中的设备信息读取过来,操作设备。

猜你喜欢

转载自blog.csdn.net/jiushimanya/article/details/82350178