1、动态申请 设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)
函数
alloc_chrdev_region
用于申请设备号,此函数有
4
个参数:
dev
:保存申请到的设备号。
baseminor
:
次设备号起始地址,
alloc_chrdev_region
可以申请一段连续的多个设备号,这
些设备号的主设备号一样,但是次设备号不同,次设备号以
baseminor
为起始地址地址开始递
增。一般
baseminor
为
0
,也就是说次设备号从
0
开始。
count
:
要申请的设备号数量。
name
:设备名字。
retvalue
=
register_chrdev
(
CHRDEVBASE_MAJOR
,
CHRDEVBASE_NAME
,
&
chrdevbase_fops
);
2、卸载设备号
注销字符设备之后要释放掉设备号,设备号释放函数如下:
void unregister_chrdev_region(dev_t from, unsigned count)
此函数有两个参数:
from
:要释放的设备号。
count
:
表示从
from
开始,要释放的设备号数量
3、register_chrdev
static inline int register_chrdev(unsigned int major, const char *name,
const struct file_operations *fops)
static inline void unregister_chrdev(unsigned int major, const char *name)
register_chrdev
函数用于注册字符设备,此函数一共有三个参数,这三个参数的含义如下:
major
:
主设备号,
Linux
下每个设备都有一个设备号,设备号分为主设备号和次设备号两
部分,关于设备号后面会详细讲解。
name
:设备名字,指向一串字符串。
fops
:
结构体
file_operations
类型指针,指向设备的操作函数集合变量。
unregister_chrdev
函数用户注销字符设备,此函数有两个参数,这两个参数含义如下:
major
:
要注销的设备对应的主设备号。
name
:
要注销的设备对应的设备名
4、unregister_chrdev
卸载设备驱动
在linux2.6版本里面,
register_chrdev_region是register_chrdev的升级版。
使用register_chrdev_region函数时,首先要定义一个dev_t变量来作为一个设备号,dev_t dev_num;如果想静态申请,那么
dev_num=MKDEV(major_no,0);major_no表示设备号的变量,然后便可以使用register_chrdev_region(dev_num,2,"my_dev");第二个参数表示注册的设备数量,第三个表示驱动名
如果要动态的注册设备号,使用下面alloc_chrdev_region(&dev_num,0,2,"memdev");次设备号从0开始,注册两个设备,设备名为memdev。
前面只是注册了设备号,后面要向内核添加设备了;
使用register_chrdev_region函数时,首先要定义一个dev_t变量来作为一个设备号,dev_t dev_num;如果想静态申请,那么
dev_num=MKDEV(major_no,0);major_no表示设备号的变量,然后便可以使用register_chrdev_region(dev_num,2,"my_dev");第二个参数表示注册的设备数量,第三个表示驱动名
如果要动态的注册设备号,使用下面alloc_chrdev_region(&dev_num,0,2,"memdev");次设备号从0开始,注册两个设备,设备名为memdev。
前面只是注册了设备号,后面要向内核添加设备了;
5、
led 驱动
Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。
所以本章的
LED
灯驱动最
终也是对
I.MX6ULL
的
IO
口进行配置,与裸机实验不同的是,在
Linux
下编写驱动要符合
Linux
的驱动框架。I.MX6U-ALPHA 开发板上的
LED
连接到
I.MX6ULL
的
GPIO1_IO03
这个引脚上,
因此本章实验的重点就是编写
Linux
下
I.MX6UL
引脚控制驱动。
我们必 须得到 0X020E0068
这个物理地址在
Linux
系统里面对应的虚拟地址,这里就涉及到了物理内 存和虚拟内存之间的转换,需要用到两个函数:ioremap
和
iounmap
ioremap
函 数 用 于 获 取 指 定 物 理 地 址 空 间 对 应 的 虚 拟 地 址 空 间 , 定 义 在
arch/arm/include/asm/io.h
文件中,定义如下:
ioremap
是个宏,有两个参数:
cookie
和
size
,真正起作用的是函数
__arm_ioremap
,此函
数有三个参数和一个返回值,这些参数和返回值的含义如下:
phys_addr
:要映射给的物理起始地址。
size
:要映射的内存空间大小。
mtype
:
ioremap
的类型,可以选择
MT_DEVICE
、
MT_DEVICE_NONSHARED
、
MT_DEVICE_CACHED
和
MT_DEVICE_WC
,
ioremap
函数选择
MT_DEVICE
。
返回值:
__iomem
类型的指针,指向映射后的虚拟空间首地址。
假如我们要获取
I.MX6ULL
的
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
寄存器对应
的虚拟地址,使用如下代码即可:
#define SW_MUX_GPIO1_IO03_BASE
(0X020E0068)
static void __iomem* SW_MUX_GPIO1_IO03;
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
宏
SW_MUX_GPIO1_IO03_BASE
是寄存器物理地址,
SW_MUX_GPIO1_IO03
是映射后
的虚拟地址。对于
I.MX6ULL
来说一个寄存器是
4
字节
(32
位
)
的,因此映射的内存长度为
4
。
映射完成以后直接对
SW_MUX_GPIO1_IO03
进行读写操作即可。
iounmap
只有一个参数
addr
,此参数就是要取消映射的虚拟地址空间首地址。假如我们现
在要取消掉
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
寄存器的地址映射,使用如下代码
即可:
iounmap(SW_MUX_GPIO1_IO03);
1
、读操作函数
读操作函数有如下几个:
示例代码 41.1.2.1 读操作函数
u8 readb
(
const volatile void
__iomem
*
addr
)
u16 readw
(
const volatile void
__iomem
*
addr
)
u32 readl
(
const volatile void
__iomem
*
addr
)
readb
、
readw
和
readl
这三个函数分别对应
8bit
、
16bit
和
32bit
读操作,参数
addr
就是要
读取写内存地址,返回值就是读取到的数据。
2
、写操作函数
写操作函数有如下几个:
示例代码 41.1.2.2 写操作函数
void
writeb
(
u8 value
,
volatile void
__iomem
*
addr
)
void
writew
(
u16 value
,
volatile void
__iomem
*
addr
)
void
writel
(
u32 value
,
volatile void
__iomem
*
addr
)
writeb
、
writew
和
writel
这三个函数分别对应
8bit
、
16bit
和
32bit
写操作,参数
value
是要
写入的数值,
addr
是要写入的地址。
一般驱动程序文件都会有一个
OF
匹配表,此
OF
匹配表保存着一些
compatible
值,如果设
备节点的
compatible
属性值和
OF
匹配表中的任何一个值相等,那么就表示设备可以使用这个
驱动。