首页 >> 大全

Linux驱动开发基础(二)

2023-11-21 大全 29 作者:考证青年

一、地址映射 1.MMU原理

MMU( Unit):内存管理单元。

MMU主要功能:

①完成虚拟空间到物理空间的映射

②内存保护,设置存储器的访问权限,设置虚拟存储空间的缓冲特性

虚拟空间到物理空间的映射即地址映射。对于 32 位的处理器来说,虚拟地址(VA,

)范围是 2^32=4GB;阿尔法开发板上有512MB 的 DDR3,即物理内存。物理内存512MB经过 MMU 可以将其映射到整个 4GB 的虚拟空间。

Linux内核启动的时候会初始化MMU,设置好内存映射,CPU访问的都是虚拟地址。

在老版本的 Linux 中要求处理器必须有 MMU,但是现在Linux 内核已经支持无 MMU 的处理器了

2.内存映射函数

LInux初始化时开启了MMU,并且设置了内存映射,CPU只能访问虚拟地址,不能直接向寄存器地址写入数据,必须得到寄存器物理地址在Linux系统中对应的虚拟地址。物理内存和虚拟内存之间的转换,需要用到: 和 两个函数

函数用于获取指定物理地址空间对应的虚拟地址空间,定义在arch/arm//asm/io.h 文件中

#define ioremap(cookie,size) __arm_ioremap((cookie), (size),MT_DEVICE)void __iomem * __arm_ioremap(phys_addr_t phys_addr, size_t size, unsigned int mtype)
{return arch_ioremap_caller(phys_addr, size, mtype, __builtin_return_address(0));
}

是个宏定义,真正起作用的是函数。

:要映射给的物理起始地址()

size:要映射的内存空间大小

mtype: 的类型,可以选择 、 、 和 , 函数选择

返回值: 类型的指针,指向映射后的虚拟空间首地址

获取某个寄存器对应的虚拟地址

# addr () // 物理地址

void * va; //指向映射后的虚拟空间首地址的指针

va=(addr, 4); // 得到虚拟地址首地址

阿尔法的寄存器是 4 字节,因此映射的内存长度为 4,映射完成后va进行读写操作,就是对物理地址寄存器操作。

卸载驱动的时需要使用 函数释放掉 函数所做的映射。

void iounmap (volatile void __iomem *addr)

参数 addr:要取消映射的虚拟地址空间首地址

取消寄存器的映射地址:(va);

二、I/O内存访问函数

当外部寄存器或内存映射到 IO 空间时,称为 I/O 端口。当外部寄存器或内存映射到内存空间时,称为 I/O 内存。但是对于 ARM 来说没有 I/O 空间,因此 ARM 体系下只有 I/O 内存(可以直接理解为内存)。使用 函数将寄存器的物理地址映射到虚拟地址后,可以直接通过指针访问这些地址,但是 Linux 内核不建议这么做,而是推荐使用一组操作函数来对映射后的内存进行读写操作。

linux驱动开发是什么_linux驱动开发入门书籍_

1.读操作函数

u8 readb(const void *addr)

u16 readw(const void *addr)

u32 readl(const void *addr)

readb、 readw 和 readl 分别对应 8bit、 16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值是读取到的数据

2.写操作函数

void (u8 value, void *addr)

void (u16 value, void *addr)

void (u32 value, void *addr)

、 和 分别对应 8bit、 16bit 和 32bit 写操作,参数 value 是要写入的数值, addr 是要写入的地址。

三、字符设备操作函数

在 Linux 中使用 cdev 结构体表示一个字符设备, cdev 结构体在 /linux/cdev.h 文件中

struct cdev {struct kobject kobj;struct module *owner;const struct file_operations *ops;struct list_head list;dev_t dev;unsigned int count;
};

在 cdev 中有两个重要的成员变量: ops 和 dev,字符设备文件操作函数集合 以及设备号 dev_t。

1. 函数

函数对cdev进行初始化。

void ( cdev *cdev, const *fops)

cdev :要初始化的 cdev 结构体变量

fops :字符设备文件操作函数集合

2. 函数

函数用于向 Linux 系统添加字符设备(cdev 结构体变量)

int ( cdev *p, dev_t dev, count)

p :向要添加的字符设备(cdev 结构体变量)

dev :设备所使用的设备号

count :要添加的设备数量

3. 函数

使用 函数在卸载驱动时从 Linux 内核中删除相应的字符设备。

void ( cdev *p)

p :要删除的字符设备

和 gion 这两个函数合起来相当于 函数

四、自动创建设备节点

使用加载驱动程序后还需要使用mknod指令创建设备节点。可以在驱动中实现自动创建设备节点的功能以后,使用 加载驱动模块成功的话就会自动在/dev 目录下创建对应的设备文件。

1.mdev机制

udev 是一个用户程序,在 Linux 下通过 udev 来实现设备文件的创建与删除, udev 可以检测系统中硬件设备状态,可以根据系统中硬件设备状态来创建或者删除设备文件。

使用 命令成功加载驱动模块后就会自动在/dev 目录下创建对应的设备节点文件,使用

rmmod 命令卸载驱动模块以后就删除掉/dev 目录下的设备节点文件。

使用 构建根文件系统的时, 会创建一个 udev 的简化版本—mdev,所以在嵌入式 Linux 中使用mdev 来实现设备节点文件的自动创建与删除, Linux 系统中的热插拔事件也由mdev 管理。

2.创建类和删除类

自动创建设备节点是在驱动程序的入口函数中完成的,一般在 函数后面添加自动创建设备节点相关代码。

首先要创建一个 class 类, class 是个结构体,定义在文件/linux/.h 里面

#define class_create(owner, name) \
({                                 \static struct lock_class_key __key; \__class_create(owner, name, &__key); \
})struct class *__class_create(struct module *owner, const char *name,struct lock_class_key *key)

是类创建函数, 是个宏定义。展开以后如下:

struct class *class_create (struct module *owner, const char *name)
owner :THIS_MODULE
name :类名字
返回值:指向结构体 class 的指针,也就是创建的类

卸载驱动程序的时需要删除掉类,类删除函数为

void class_destroy(struct class *cls);cls:要删除的类

3.创建设备

创建好类后还不能实现自动创建设备节点,还需要在这个类下创建一个设备。使用 函数在类下面创建设备。

struct device *device_create(struct class *class,struct device *parent,dev_t devt,void *drvdata,const char *fmt, ...)

是个可变参数函数

class :设备要创建哪个类下面

:父设备,一般为 NULL,也就是没有父设备

devt 是设备号

:设备可能会使用的一些数据,一般为 NULL

fmt :设备名字,如果设置 fmt=xxx 的话,就会生成/dev/xxx这个设备文件

返回值就是创建好的设备

卸载驱动的时需要删除掉创建的设备,设备删除函数为 ,

void ( class *class, dev_t devt)

class :要删除的设备所处的类

devt :要删除的设备号

注意:在卸载驱动时,要先删除设备,然后在在删除类。应该在创建设备时用了类。

五、文件私有数据

每个硬件设备都有一些属性,如主设备号(dev_t),类(class)、设备()、开关状态(state)等等,在编写驱动的时可以将这些属性全部写成变量的形式。

对于一个设备的所有属性信息最好将其设置为一个结构体。

/* 设备结构体 */
struct test_dev{dev_t devid; /* 设备号 */struct cdev cdev; /* cdev */struct class *class; /* 类 */struct device *device; /* 设备 */int major; /* 主设备号 */int minor; /* 次设备号 */
};

然后编写驱动 open 函数的时将设备结构体作为私有数据添加到设备文件中。在 open 函数里面设置好私有数据后,在 write、 read、 close 等函数中直接读取 即可得到设备结构体

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了