1 设备树
定义:描述设备硬件信息的一种数据结构
exynos4412-fs4412.dtb--》硬件信息
uImage-->代码框架
将代码逻辑和数据信息分离的思想
硬件:内存 flash gpio uart usb...---》可以用一种数据结构来表示--》设备树--》信息
软件:uImage-->linux内核软件--》逻辑
dt:device tree
dtb:设备树二进制文件 exynos4412-fs4412.dtb
dts:设备树源文件exynos4412-fs4412.dts
dtsi:设备树头文件,它相当于C的头文件
注意:一张板卡对应一个设备树文件
linux内核代码支持ARM体系部分从3.0版本以后就将描述设备数据的文件和描述
设备的逻辑代码分开了,描述设备硬件数据的文件称为设备树文件,描述设备的
逻辑代码称为内核(kernel)。
一个设备树源文件对应一张板卡的所有外设硬件信息,在文件中描述硬件节点的语法
是设备树语法。
设备树文件语法:
1 /{} 表示一张板卡的所有硬件信息,它是根节点。
2 节点名称@地址{节点属性}--》子节点
3 compatible:根节点:制造商和产品型号
子节点:用来关联驱动和被驱动的设备
4 reg:可寻址设备用来表示编码地址的信息,是一个列表
led2--->gpx2_7 0x11000c40 4 0x11000c44 4 1/0
reg=<地址1 长度1 地址2 长度2 。。。>
每一个可编址的设备都有一个reg ,它是一个元组表,每一个元组都表示一个
设备的地址范围。
5 interrupt-parent:中断控制器节点指针,设备节点通过它来指定它所依附
的中断控制器
6 interrupts:中断指示符列表 (中断号和触发方式)
<中断类型 中断号 中断的触发方式>
系统移植试验五:
DM9000(DM9000IRQ)--->转化器--》con5--》con4-->U1A(gpx0_6)
2 平台设备驱动框架
设备:硬件设备 led uart spi i2c usb 网卡。。。--》设备树节点--》硬件信息
驱动:软件
使用虚拟总线可以将设备和它的驱动程序关联起来,虚拟总线就称为平台platform。
我们将挂接在虚拟总线上的设备称为平台设备platform_device
我们将挂接在虚拟总线上的驱动称为平台驱动platform_driver
当在Linux 系统中注册一个设备时,设备会通过虚拟总线去找与之匹配的驱动程序
当在Linux系统中注册一个驱动时,驱动程序会通过虚拟总线去找与之匹配的设备
平台设备驱动框架:
init:
{
1 注册平台设备
int platform_device_register(struct platform_device *pdev)
(将设备挂接在平台总线上)
2 注册平台驱动
int platform_driver_register(struct platform_driver *pdr)
(将驱动挂接在平台总线上)
}
exit:
{
1 去注册平台驱动
void platform_driver_unregister(struct platform_driver *)
(将驱动从平台总线上移除)
2 去注册平台设备
void platform_device_unregister(struct platform_device *pdev)
(将设备从平台总线上移除)
}
在Linux内核中用struct platform_device来描述一个平台设备
struct platform_device {
const char *name;--》设备名
int id;--》设备ID
bool id_auto;
struct device dev;--》代表一个内核设备---》release:释放平台设备
u32 num_resources;--》资源总数
struct resource *resource;--》设备资源
。。。
}
在Linux内核中用struct 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;
};
3 平台设备和平台驱动分开
平台设备--》hello.ko
平台驱动--》driver.ko
注意:安装时,先安装平台设备,再安装平台驱动
卸载时,先卸载平台驱动,再卸载平台设备
4 平台设备添加资源
如何给平台设备添加资源?
使用平台设备中的struct resource来增加资源
struct resource {-->用来描述设备资源
resource_size_t start;--》起始地址
resource_size_t end;--》结束地址
const char *name;--》资源名称
unsigned long flags;--》资源类型
struct resource *parent, *sibling, *child;
};
struct resource res[]=
{
{
.start=0x11000c40,
.end=0x11000c43,
.flags=IORESOURCE_MEM,-->内存资源
},
{
.start=88,
.flags=IORESOURCE_IRQ,
},
}
4 平台驱动获取资源
当注册平台驱动时,平台驱动的helloProbe函数就会通过虚拟总线去获取到
挂接在虚拟总线上的设备信息
helloProbe(struct platform_device *pdev)
{
pdev->resource
if(pdev->resource->flags&IORESOURCE_MEM)
{
使用
}
}
5 mmap
mmap-->系统调用函数
fd=open(“/dev/haha0”)
void *mmap(void *addr, size_t length, int prot, int flags,
int fd, off_t offset);---》vma-->起始,结束 保护标志 flags
作用:将用户空间的地址映射到内核空间
*addr:被映射的用户空间地址,通常给NULL,
length:映射地址的长度
prot:内核保护标志 PROT_READ PROT_WRITE
flags:MAP_SHARED MAP_PRIVATE
fd:文件描述符
offset:被映射对象的读写偏移量 0
返回值:成功:被映射区的地址(指针)
失败:MAP_FAILED
int munmap(void *addr, size_t length);----》取消映射
*addr:被映射区的地址---》用户空间地址
length:映射地址的长度
返回值: 0 成功
-1 失败
驱动:
int (*mmap) (struct file *, struct vm_area_struct *);
HelloMmap(struct file *pFile,struct vm_area_struct *vma)
*pFile:指向内核打开的文件
*vma:指向应用层调用mmap映射成功后生成的映射结构体对象
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
unsigned long pfn, unsigned long size, pgprot_t prot)
作用:将映射结构体中指定的用户内存地址映射到内核虚拟地址,并将该
虚拟地址对应到具体的物理地址上
*vma:应用层使用mmap后,内核生成的映射结构体变量
addr:被映射的用户空间地址的起始值 vma->vm_start;
pfn:内核虚拟地址对应的物理地址的页编号
virt_to_phys(g_buf)>>12
size:被映射区域的大小
prot:内核保护标志
g_buf=kmalloc(size,GFP_KERNEL) -->申请的空间在物理上是连续的--》kfree
作用:申请一块内核内存空间
vmalloc--》申请的空间在物理上是不连续的-->vfree
struct vm_area_struct {
unsigned long vm_start;--》起始地址
unsigned long vm_end;--》结束地址
pgprot_t vm_page_prot;--》保护标志
unsigned long vm_flags;--》MAP_SHARED MAP_PRIVATE
....
}