day10
来源:互联网 发布:sql 时间区间条件查询 编辑:程序博客网 时间:2024/04/29 10:19
回顾:
1.linux内核等待队列机制编程方法
产生根本目的:慢
功能:休眠
方法1:
休眠+唤醒=九步骤
方法2:
休眠+唤醒=三步骤
唤醒之前置真
唤醒以后置假
2.linux内核实现按键去抖动的原理图
内核软件定时器
3.如何将外设的物理地址映射到内核虚拟地址上
ioremap
4.如果将外设的物理地址映射到用户虚拟地址上
mmap
注意:
1.利用mmap对GPIO进行输入和输出操作时,一定要将Cache缓存功能禁止掉
CPU下发的操作数据如果缓存在Cache,可能不会立即影响到具体的硬件寄存器
建议:关闭cache功能
vma->vm_page_prot =
pgprot_noncached(vma->vm_page_prot); //数据访问不再需要Cache
mmap(0, 1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
实际操作系统给你强制分配了4KB的虚拟内存!
2.mmap在地址映射时,已知的用户起始虚拟地址vm_start(保证的)
和已知的物理地址一定要是页面大小(4KB=0x1000)的整数倍
例如:物理地址:0xC001C000(合法)
remap_pfn_range(vma,vma->vm_start,0xC001C000>>12,...);//成功
物理地址: 0xC001C004(不合法)
remap_pfn_range(vma,vma->vm_start,0xC001C004>>12,...);//失败
3.利用mmap对硬件设备的访问效率要高,mmap特别适合用于
操作的数据量比较大的硬件外设(摄像头,声卡,显卡,LCD显示屏)
缺点是分配的用用户虚拟内存都是4KB的整数倍,所以将来操作的
数据量是4KB的整数倍,mmap最好使用(数据只需一次拷贝)
而read,write,ioctl对数据的操作都是经过两次拷贝完成
如果操作的数据量比较小,对系统性能的影响几乎可以忽略不计
如果操作的数据量比较答,势必不考虑使用read,write,ioctl
*********************************************************
2.linux内核分离思想,platform机制
2.1.分析案例:将LED1对应的GPIOC12更换成GPIOE6
观察ioremap实现的LED驱动需要做哪些地方的改动
结论:
0.一个完成的硬件设备驱动必然包含两个部分:
纯硬件相关内容:寄存器的起始地址,GPIO编号等
纯软件相关内容:if...else,混杂设备,接口等
纯软件用来操作纯硬件
1.如果仅仅是硬件GPIO编号进行了改动,驱动的改动
仅仅也只是修改硬件相关(寄存器的起始地址和
GPIO编号)的修改,软件无需改动
2.并且发现昨天的代码的改动量相当之大,如果让驱动代码的
改动量小,移植性好,首先相当利用宏替换驱动代码中的
硬件相关的内容
3.但是寄存器的起始地址,GPIO编号他们同样是“事物”同样
具有额外的其他属性,利用宏不能完整描述特性,势必
要考虑到结构体进行描述
问:linux内核如何做到既可以让驱动的可移植性变得好
并且对硬件信息的描述更加的丰富呢?
答:利用linux内核的分离思想,platform机制
分离思想:就是将驱动的纯硬件信息和纯软件信息进行
彻底分开,一旦将来软件写好,就无需改动,将来驱动
开发者的重心放在硬件信息即可
本质目的就是让驱动代码的可移植性变得非常好
问:如何实现内核的分离思想呢?
答:利用platform机制
问:内核的platform机制如何实现的呢?
答:ftp://DRV/ESD_DRV_09.ppt
总结:驱动如果采用platform机制实现,只需关注以下两个数据结构:
struct platform_device
struct platform_driver
2.2.struct platform_device如何使用
struct platform_device {
const char * name;
int id;
struct resource * resource;
u32 num_resources;
struct device dev;
.platform_data
...
};
功能:用于描述一个驱动中纯硬件信息
成员说明:
name:硬件节点的名称,将来用于匹配,必须初始化
id:硬件节点的编号,如果dev链表上,仅有一个名称为name
的硬件节点,id=-1即可,如果dev链表上,有多个名称为name(同名)
通过id进行编号(0,1,2,...)
resource:装载纯硬件信息相关内容
struct resource {
unsigned long start;
unsigned long end;
unsigned long flags;
...
};
功能:用于描述硬件信息
成员:
start:起始硬件信息
例如:寄存器的起始地址
end:结束硬件信息
例如:寄存器的结束地址
flags:硬件信息的标志
IORESOURCE_MEM:用于指示此硬件信息为地址信息
0xC001C000这个物理地址可以用此标志修饰
IORESOURCE_IRQ:用于指示此硬件信息为GPIO信息
PAD_GPIO_C+12这个GPIO可以用此标志进行修饰
num_resources:用来指示用struct resource描述的硬件信息的个数
dev:此结构体变量中重点关注其中的void *platform_data字段
platform_data字段可以用来装载驱动开发者自定义的硬件信息
例如:自定义的硬件信息
struct led_resource
.gpio
.name
struct btn_resource
.gpio
.name
.code
总结:platform_device装载硬件信息的方法有三种:
1.单独使用struct resource进行描述
2.单独使用自定义的描述硬件信息的数据结构来描述
3.可以同时使用struct resource和自定义的描述硬件
信息的数据结构来描述硬件信息
两个配套函数:
platform_device_register(&硬件节点对象)
向内核dev链表添加注册硬件节点对象
一旦添加完毕,什么遍历drv链表,什么匹配,什么调用probe
函数,什么给probe函数传递硬件节点的首地址这些都是由
内核完成!如果一旦匹配成功,硬件节点对象的首地址
会传递给匹配成功的软件节点的probe函数
platform_device_unregister(&硬件节点对象)
从内核的dev链表删除硬件节点对象
内核会调用软件节点的remove函数
案例:利用platform机制优化LED驱动程序
实施步骤:
上位机执行:
mkdir /opt/drivers/day10/1.0 -p
cd /opt/drivers/day10/1.0
touch led_dev.c led_drv.c
vim led_dev.c
vim Makefile
make
cp *.ko /opt/rootfs/home/drivers/
下位机执行:
cd /home/drivers
insmod led_dev.ko
2.3.struct platform_driver如何使用
struct platform_driver {
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
struct device_driver driver;
...
};
功能:描述一个驱动中纯软件相关内容
成员说明:
probe: 一旦纯硬件节点和纯软件节点匹配成功,内核就会
调用此函数,也就是说此函数是否被调用,至关重要
probe函数被调用,说明硬件软件匹配成功,一个完整的
硬件设备驱动诞生,这样纯软件才可以踏踏实实访问
纯硬件
形参pdev指针指向匹配成功的硬件节点对象
remove:从dev链表删除硬件节点或者从drv链表删除
软件节点,不管删除哪一个,都代表这个驱动不再完整
此时内核就会调用remove函数
remove函数和probe函数是一对死对头!
形参pdev指针指向匹配成功的硬件节点对象
driver:重点关注其中的name字段,此字段将来用于匹配
配套函数:
platform_driver_register(&软件节点对象)
向内核drv链表添加软件节点对象
内核会帮你遍历dev链表,帮你匹配,如果匹配成功,帮你
调用probe函数,帮你把匹配成功的硬件节点传递给probe函数
platform_driver_unregister(&软件节点对象)
从内核drv链表删除软件节点
内核会调用软件节点的remove函数
案例:利用platform机制优化LED驱动程序
实施步骤:
上位机执行:
mkdir /opt/drivers/day10/1.0 -p
cd /opt/drivers/day10/1.0
touch led_dev.c led_drv.c
vim led_drv.c
vim Makefile
make
cp *.ko /opt/rootfs/home/drivers/
下位机执行:
cd /home/drivers
insmod led_dev.ko
insmod led_drv.ko //查看probe函数是否被调用
rmmod led_drv //查看remove函数是否被调用
rmmod led_dev
insmod led_drv.ko
insmod led_dev.ko //查看probe函数是否被调用
rmmod led_dev //查看remove函数是否被调用
rmmod led_drv
2.4.问:probe函数做哪些工作呢?
答:明确:probe函数被调用预示着一个完整的驱动诞生
预示着纯软件可以操作访问纯硬件
probe函数一般做如下工作:
1.通过形参pdev指针获取匹配成功的纯硬件信息(寄存器物理地址,编号等)
2.要处理获取到的纯硬件信息(各种该)
该地址映射的地址映射
该申请资源的申请资源
该注册的注册
该初始化的初始化
3.注册混杂设备或者字符设备给用户提供访问操作硬件的接口
总结:2,3两个步骤之前都是在驱动的入口函数中完成
而现在统一放在probe函数中完成
remove和probe对着干!
问:probe函数通过形参pdev指针如何获取到纯硬件信息呢(resource描述的硬件信息)
答:用以下函数即可获取
struct resource *platform_get_resource(
struct platform_device *pdev,
unsigned long flags,
int index
)
函数功能:probe函数或者remove函数通过形参pdev
指针来获取到匹配成功的resource描述的硬件信息
参数:
pdev:传递匹配成功的硬件节点的首地址
flags:要获取的硬件信息的类型
要不是IORESOURCE_MEM要不是IORESOURCE_IRQ
index:同类型资源的偏移量
返回值:返回获取的resource描述的硬件信息对象首地址
案例:最终完成LED驱动
2.5.用自定义的数据结构来描述硬件信息
具体参见:ftp://day10/4.0源码
1.linux内核等待队列机制编程方法
产生根本目的:慢
功能:休眠
方法1:
休眠+唤醒=九步骤
方法2:
休眠+唤醒=三步骤
唤醒之前置真
唤醒以后置假
2.linux内核实现按键去抖动的原理图
内核软件定时器
3.如何将外设的物理地址映射到内核虚拟地址上
ioremap
4.如果将外设的物理地址映射到用户虚拟地址上
mmap
注意:
1.利用mmap对GPIO进行输入和输出操作时,一定要将Cache缓存功能禁止掉
CPU下发的操作数据如果缓存在Cache,可能不会立即影响到具体的硬件寄存器
建议:关闭cache功能
vma->vm_page_prot =
pgprot_noncached(vma->vm_page_prot); //数据访问不再需要Cache
mmap(0, 1, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
实际操作系统给你强制分配了4KB的虚拟内存!
2.mmap在地址映射时,已知的用户起始虚拟地址vm_start(保证的)
和已知的物理地址一定要是页面大小(4KB=0x1000)的整数倍
例如:物理地址:0xC001C000(合法)
remap_pfn_range(vma,vma->vm_start,0xC001C000>>12,...);//成功
物理地址: 0xC001C004(不合法)
remap_pfn_range(vma,vma->vm_start,0xC001C004>>12,...);//失败
3.利用mmap对硬件设备的访问效率要高,mmap特别适合用于
操作的数据量比较大的硬件外设(摄像头,声卡,显卡,LCD显示屏)
缺点是分配的用用户虚拟内存都是4KB的整数倍,所以将来操作的
数据量是4KB的整数倍,mmap最好使用(数据只需一次拷贝)
而read,write,ioctl对数据的操作都是经过两次拷贝完成
如果操作的数据量比较小,对系统性能的影响几乎可以忽略不计
如果操作的数据量比较答,势必不考虑使用read,write,ioctl
*********************************************************
2.linux内核分离思想,platform机制
2.1.分析案例:将LED1对应的GPIOC12更换成GPIOE6
观察ioremap实现的LED驱动需要做哪些地方的改动
结论:
0.一个完成的硬件设备驱动必然包含两个部分:
纯硬件相关内容:寄存器的起始地址,GPIO编号等
纯软件相关内容:if...else,混杂设备,接口等
纯软件用来操作纯硬件
1.如果仅仅是硬件GPIO编号进行了改动,驱动的改动
仅仅也只是修改硬件相关(寄存器的起始地址和
GPIO编号)的修改,软件无需改动
2.并且发现昨天的代码的改动量相当之大,如果让驱动代码的
改动量小,移植性好,首先相当利用宏替换驱动代码中的
硬件相关的内容
3.但是寄存器的起始地址,GPIO编号他们同样是“事物”同样
具有额外的其他属性,利用宏不能完整描述特性,势必
要考虑到结构体进行描述
问:linux内核如何做到既可以让驱动的可移植性变得好
并且对硬件信息的描述更加的丰富呢?
答:利用linux内核的分离思想,platform机制
分离思想:就是将驱动的纯硬件信息和纯软件信息进行
彻底分开,一旦将来软件写好,就无需改动,将来驱动
开发者的重心放在硬件信息即可
本质目的就是让驱动代码的可移植性变得非常好
问:如何实现内核的分离思想呢?
答:利用platform机制
问:内核的platform机制如何实现的呢?
答:ftp://DRV/ESD_DRV_09.ppt
总结:驱动如果采用platform机制实现,只需关注以下两个数据结构:
struct platform_device
struct platform_driver
2.2.struct platform_device如何使用
struct platform_device {
const char * name;
int id;
struct resource * resource;
u32 num_resources;
struct device dev;
.platform_data
...
};
功能:用于描述一个驱动中纯硬件信息
成员说明:
name:硬件节点的名称,将来用于匹配,必须初始化
id:硬件节点的编号,如果dev链表上,仅有一个名称为name
的硬件节点,id=-1即可,如果dev链表上,有多个名称为name(同名)
通过id进行编号(0,1,2,...)
resource:装载纯硬件信息相关内容
struct resource {
unsigned long start;
unsigned long end;
unsigned long flags;
...
};
功能:用于描述硬件信息
成员:
start:起始硬件信息
例如:寄存器的起始地址
end:结束硬件信息
例如:寄存器的结束地址
flags:硬件信息的标志
IORESOURCE_MEM:用于指示此硬件信息为地址信息
0xC001C000这个物理地址可以用此标志修饰
IORESOURCE_IRQ:用于指示此硬件信息为GPIO信息
PAD_GPIO_C+12这个GPIO可以用此标志进行修饰
num_resources:用来指示用struct resource描述的硬件信息的个数
dev:此结构体变量中重点关注其中的void *platform_data字段
platform_data字段可以用来装载驱动开发者自定义的硬件信息
例如:自定义的硬件信息
struct led_resource
.gpio
.name
struct btn_resource
.gpio
.name
.code
总结:platform_device装载硬件信息的方法有三种:
1.单独使用struct resource进行描述
2.单独使用自定义的描述硬件信息的数据结构来描述
3.可以同时使用struct resource和自定义的描述硬件
信息的数据结构来描述硬件信息
两个配套函数:
platform_device_register(&硬件节点对象)
向内核dev链表添加注册硬件节点对象
一旦添加完毕,什么遍历drv链表,什么匹配,什么调用probe
函数,什么给probe函数传递硬件节点的首地址这些都是由
内核完成!如果一旦匹配成功,硬件节点对象的首地址
会传递给匹配成功的软件节点的probe函数
platform_device_unregister(&硬件节点对象)
从内核的dev链表删除硬件节点对象
内核会调用软件节点的remove函数
案例:利用platform机制优化LED驱动程序
实施步骤:
上位机执行:
mkdir /opt/drivers/day10/1.0 -p
cd /opt/drivers/day10/1.0
touch led_dev.c led_drv.c
vim led_dev.c
vim Makefile
make
cp *.ko /opt/rootfs/home/drivers/
下位机执行:
cd /home/drivers
insmod led_dev.ko
2.3.struct platform_driver如何使用
struct platform_driver {
int (*probe)(struct platform_device *pdev);
int (*remove)(struct platform_device *pdev);
struct device_driver driver;
...
};
功能:描述一个驱动中纯软件相关内容
成员说明:
probe: 一旦纯硬件节点和纯软件节点匹配成功,内核就会
调用此函数,也就是说此函数是否被调用,至关重要
probe函数被调用,说明硬件软件匹配成功,一个完整的
硬件设备驱动诞生,这样纯软件才可以踏踏实实访问
纯硬件
形参pdev指针指向匹配成功的硬件节点对象
remove:从dev链表删除硬件节点或者从drv链表删除
软件节点,不管删除哪一个,都代表这个驱动不再完整
此时内核就会调用remove函数
remove函数和probe函数是一对死对头!
形参pdev指针指向匹配成功的硬件节点对象
driver:重点关注其中的name字段,此字段将来用于匹配
配套函数:
platform_driver_register(&软件节点对象)
向内核drv链表添加软件节点对象
内核会帮你遍历dev链表,帮你匹配,如果匹配成功,帮你
调用probe函数,帮你把匹配成功的硬件节点传递给probe函数
platform_driver_unregister(&软件节点对象)
从内核drv链表删除软件节点
内核会调用软件节点的remove函数
案例:利用platform机制优化LED驱动程序
实施步骤:
上位机执行:
mkdir /opt/drivers/day10/1.0 -p
cd /opt/drivers/day10/1.0
touch led_dev.c led_drv.c
vim led_drv.c
vim Makefile
make
cp *.ko /opt/rootfs/home/drivers/
下位机执行:
cd /home/drivers
insmod led_dev.ko
insmod led_drv.ko //查看probe函数是否被调用
rmmod led_drv //查看remove函数是否被调用
rmmod led_dev
insmod led_drv.ko
insmod led_dev.ko //查看probe函数是否被调用
rmmod led_dev //查看remove函数是否被调用
rmmod led_drv
2.4.问:probe函数做哪些工作呢?
答:明确:probe函数被调用预示着一个完整的驱动诞生
预示着纯软件可以操作访问纯硬件
probe函数一般做如下工作:
1.通过形参pdev指针获取匹配成功的纯硬件信息(寄存器物理地址,编号等)
2.要处理获取到的纯硬件信息(各种该)
该地址映射的地址映射
该申请资源的申请资源
该注册的注册
该初始化的初始化
3.注册混杂设备或者字符设备给用户提供访问操作硬件的接口
总结:2,3两个步骤之前都是在驱动的入口函数中完成
而现在统一放在probe函数中完成
remove和probe对着干!
问:probe函数通过形参pdev指针如何获取到纯硬件信息呢(resource描述的硬件信息)
答:用以下函数即可获取
struct resource *platform_get_resource(
struct platform_device *pdev,
unsigned long flags,
int index
)
函数功能:probe函数或者remove函数通过形参pdev
指针来获取到匹配成功的resource描述的硬件信息
参数:
pdev:传递匹配成功的硬件节点的首地址
flags:要获取的硬件信息的类型
要不是IORESOURCE_MEM要不是IORESOURCE_IRQ
index:同类型资源的偏移量
返回值:返回获取的resource描述的硬件信息对象首地址
案例:最终完成LED驱动
2.5.用自定义的数据结构来描述硬件信息
具体参见:ftp://day10/4.0源码
阅读全文
0 0
- day10
- day10
- day10
- day10
- day10
- day10
- DAY10
- day10
- day10
- day10
- Day10
- day10
- Day10
- day10
- day10
- DAY10
- Day10
- day10-笔记
- 文件上传图片覆盖在 上传框上
- Python基础(九)- 异常处理
- typeof和instanceof的区别
- 教您修复mysql数据库的方法
- PHP变量类型+整型类型细节
- day10
- 微信config:invalid signature
- BZOJ 4318 OSU!期望DP
- Android开发人员不得不收集的代码
- ASP.NET获取客户端、服务器端基础信息
- grub的reboot 命令实现
- CentOS下yum命令出现Loaded plugins: fastestmirror
- 个推服务器端设置代理服务器
- C++ 基础学习教程 第二章 变量(2)