对驱动的粗浅认识

1.对platform平台总线的认识


1、平台总线:

1)相对于usb、pci、i2c等物理总线来说,platform总线是虚拟的、抽象出来的

2)CPU和外设通信方式:1.cpu内部的地址线端口链接,我们的platform平台总线对应链接SoC的内部外设

                                          2.专用接口式链接,如通过usb协议链接usb设备

2、引入platform平台总线的好处:

1)使得设备被挂接在一个总线下

2)隔离BSP和驱动。在BSP中定义platform设备和设备使用的资源、设备的具体配置信息;而在驱动中,只需要通过通用API去获取资源和数据。

 

3、platform平台总线的工作原理:

(1)第一步:系统启动时在bus系统中注册platform,platform_bus_init函数

(2)第二步:内核移植的人负责提供platform_device,调用platform_device_register注册

(3)第三步:写驱动的人负责提供platform_driver,调用platform_driver_register注册

(4)第四步:platform_match函数通过设备名name匹配driver和device,匹配后调用driver的probe函数安装,然后设备就工作起来了

对第四步的理解:

每种总线(不光是platform,usb、i2c那些也是)都会带一个match方法,match方法用来对总线下的device和driver进行匹配。platform总线的匹配函数为platform_match,platform_match工作原理:如果有id_table就说明驱动可能支持多个设备,所以这时候要去对比id_table中所有的name,只要找到一个相同的就匹配上了不再找了,如果找完id_table都还没找到就说明没配上;如果没有id_table或者每匹配上,那就直接对比device和driver的name,如果匹配上就匹配上了,如果还没匹配上那就匹配失败。

4、驱动如何获取设备数据,相关变量resource结构体、platform_get_resource函数

驱动通过platform_get_resource()这样的API来获取platform_device中的resource(设备资源),resource的定义也通常在BSP的板文件中进行

struct resource {

 resource_size_t start;

 resource_size_t end;

 const char *name;

 unsigned long flags;

 struct resource *parent, *sibling, *child;

};start、end和flags这3个字段决定了这个资源是属于中断、内存、DMA通道中的哪一种

自定义设备数据放在platform_date结构体中

 

struct resource *platform_get_resource(struct platform_device *dev,

                     unsigned int type, unsigned int num)

{int i;

    for (i = 0; i < dev->num_resources; i++) {

       struct resource *r = &dev->resource[i];

       if (type == resource_type(r) && num-- == 0)

           return r;

    }

    return NULL;}     //返回r用来存储设备的资源

 

5.设备驱动模型(设备和驱动组成的一个层次结构)

总线:链接各个设备,例如platform平台总线、usb总线,各个总线下有设备和驱动

设备:在设备/sys/devices/是创建真正的设备文件。而设备类/sys/class/和总线/sys/bus/(总线作用是连接所有设备)以下的子目录中出现的设备都是用符号链接指向/sys/devices/目录下的文件

类:class是一种人造概念,目的就是为了对各种设备进行分类管理


对LED驱动框架的认识


系统资源之GPIO

gpio资源是有限的,为了便于不同外设去使用,我们的做法是:每个驱动模块如果要使用某个GPIO就要先调用特殊的接口去申请,申请到后使用,使用完后要释放,从而引入了gpiolib来管理所有的gpio

内核开放出来的接口:

gpio_request 设备驱动中要想使用某一个gpio,就必须先调用gpio_request接口来向内核的gpiolib部分申请,得到允许后才可以          用这个gpio

gpio_direction_input/gpio_direction_output: 接口用来设置GPIO为输入/输出模式

writel((readl(GPJ0DAT) | (1<<3)), GPJ0DAT);读改写寄存器

gpiochip_add: 用于向内核注册我们的gpiolib

 

代码现状:

市场上不同芯片厂商都有自己的led驱动,但是总体上来说,led-class.c和led-core.c,内核开发者提供的;leds-xxxx.c,由不同厂商的驱动工程师根据自己硬件特点编写添加的。未引入gpiolib概念之前,我们的led_classdev_register其实就是led驱动框架中内核开发者提供给SoC厂家驱动开发者的一个注册驱动的接口,引入gpiolib后,注册接口变为gpiochip_add

 


字符设备驱动

file_operation结构体中元素是一个个函数指针,用来连接实际干活的函数

1.接口

register_chrdev_region()注册主次设备号、设备名

void cdev_init(struct cdev *cdev, const struct file_operations *fops)初始设备结构体,设备操作函数

//cdev_init可由下面//内的代码代替

struct cdev *p;

p== cdev_alloc();

p->owner= 

p->ops= 实例化结构体元素中的file_operations变量(设备操作函数)

//

cdev_add(struct cdev *p, dev_t dev, unsigned count)向内核添加一个设备

 

 

2.页表的建立

1.静态映射表在arch/arm/plat-s5p/cpu.c中的s5p_iodesc,本质是一个结构体数组,数组中每一个元素就是一个映射,这个映射描述了一段物理地址到虚拟地址之间的映射。

2. 页表的建立iotable_init(s5p_iodesc, ARRAY_SIZE(s5p_iodesc))

结构体数组s5p_iodesc[]所记录的几个映射关系被iotable_init()函数使用,将这个结构体数组格式的表建立成MMU所能识别的页表映射关系。

 

ioremap的实现将物理地址映射到页表,返回的内核虚拟地址(3G-4G)去访问之这段I/O内存资源,见https://blog.csdn.net/weixin_37726386/article/details/81697991

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值