文章目录
一、地址映射、地址取消映射
ioremap():地址映射
释义:在驱动入口函数中进行地址映射,获取指定物理空间对应的虚拟空间的地址。
即:将返回值赋值给定义好的地址指针,以后操作该指针指向的位置就是操作该地址。
ioremap();
iounmap():地址取消映射
释义:在驱动出口函数中进行地址取消映射,解除实际物理地址和指针变量的关系。
iounmap();
示例
/* 实际物理地址,芯片手册中查询 */
#define GPIO1_BASE_ADDR 0x4804c000
#define GPIO1_OE_ADDR ((GPIO1_BASE_ADDR) + (0x134))
/* 虚拟地址指针变量 */
volatile unsigned long *gpio1_oe = NULL;
/* 驱动入口函数 */
static int __init led_init(void) {
...
gpio1_oe = (volatile unsigned long *)ioremap(GPIO1_OE_ADDR, 32); /* 添加地址映射 */
...
}
/* 驱动出口函数 */
static void __exit led_exit(void) {
...
iounmap(gpio1_oe); /* 取消地址映射 */
...
}
二、IO内存操作函数
当映射完地址以后,可以直接通过指针访问寄存器,如:
/* 将oe寄存器bit25、26、27置0 */
*gpio1_oe &= ((~(1<<25)) | (~(1<<26)) | (~(1<<27)));
也可以使用如下操作函数进行内存读写操作。
2.1 读操作函数
readb()
readw()
readl()
原型如下:
分别对应8/16/32位机器。
参数 addr 就是要读取写内存地址,返回值就是读取到的数据。
u8 readb(const volatile void __iomem *addr)
u16 readw(const volatile void __iomem *addr)
u32 readl(const volatile void __iomem *addr)
2.2 写操作函数
writeb()
writew()
writel()
原型如下:
分别对应8/16/32位机器。
参数 value 是要写入的数值, addr 是要写入的地址。
void writeb(u8 value, volatile void __iomem *addr)
void writew(u16 value, volatile void __iomem *addr)
void writel(u32 value, volatile void __iomem *addr)
三、设备号、主设备号、设备号操作宏
MKDEV(xxx.major, 0)
MAJOR(xxx.devid)
MINOR(xxx.devid)
设备号、主设备号、次设备号操作宏
MKDEV(ma,mi) /* 已经知道主设备号ma和次设备号mi,使用该宏可以合成为完成的设备号 */
MAJOR(xxx.devid)
MINOR(xxx.devid)
上述3个设备号操作宏在内核源码的【】文件中定义。原型如下:
#define MINORBITS 20
#define MINORMASK ((1U << MINORBITS) - 1)
#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))
四、【旧字符设备驱动框架】常用函数总结
4.1 注册、注销设备驱动
register_chrdev():注册设备驱动
注册设备驱动函数一般在【驱动入口函数】中调用。
register_chrdev();
unregister_chrdev():注销设备驱动
注销设备驱动函数一般在【驱动出口函数】中调用。
unregister_chrdev()
五、【新字符设备驱动框架】
5.1 申请、注册、注销设备号
alloc_chrdev_region(xxx.devid);
register_chrdev_region(&xxx.devid);
unregister_chrdev_region()
alloc_chrdev_region()
register_chrdev_region()
unregister_chrdev_region()
5.2 初始化/删除设备结构体
cdev_init(xxx.cdev, &file_operation结构体);
cdev_add(xxx.cdev, xxx.devid, 设备个数);
cdev_del();
cdev_init()
cdev_add()
cdev_del()
5.3 创建类、删除类
class_create();
class_destroy();
class_create():创建类
xxx.class = class_create();
自动创建设备节点代码一般在cdev_add()函数之后完成,创建之前首先要创建一个class类。
class结构在内核源码的【include/linux/device.h 】文件中定义。
和class相关的函数有:
struct class *class_create (struct module *owner, const char *name);
void class_destroy(struct class *cls);
class_destroy():删除类
5.4 创建设备、摧毁设备
device_create();
device_destroy();
device_create():创建设备
xxx.device = device_create(xxx.class…);
设备结构体,在内核中由函数:
struct device *device_create(struct class *class, struct device *parent,
dev_t devt, void *drvdata, const char *fmt, ...)
创建一个设备,返回值由device接收。
device_destroy():摧毁设备
六、短延时函数
6.1 休眠函数(应用层函数):
备注:sleep家族函数,不占用系统资源,休眠时间不是非常准确,比如一般延时1秒,实际延时时间通常大于1秒
sleep(unsigned int seconds)
- 秒级休眠
usleep(useconds_t usec)
- 含义:微妙级延时
6.2 延时函数(内核层函数):
备注:delay家族函数,时间比较准确,但是会占用系统资源,使用过多会导致系统相应变慢。
mdelay(unsigned long msecs)
- 含义:毫秒级阻塞延时
udelay(unsigned long usecs)
- 含义:微秒级阻塞延时
ndelay(unsigned long nsecs)
- 含义:纳秒级延时
七、GPIO常用函数
备注:
-
一般来说,设置一个GPIO口为输出,先执行一次gpio_direction_output,然后接下来只需执行gpio_set_value就行了
-
gpio口的通用函数接口定义在gpiolib.c文件中,声明则在gpio.h中
gpio_direction_output(unsigned gpio, int value)
- 含义:设置gpio为输出功能,同时设置gpio输出的值
gpio_set_value(unsigned gpio, int value)
- 含义:设置gpio寄存器的值
gpio_direction_input(unsigned gpio)
- 含义:设置gpio为输入功能
gpio_get_value(unsigned gpio)
- 含义:获取gpio口的输入的值
gpio_request(unsigned gpio, const char* label)
- 含义:使用gpio口之前,使用该函数申请GPIO的 使用。若申请成功,则说明该gpio口未被使用
gpio_free(unsigned gpio)
- 含义:使用完gpio口之后,用该函数释放gpio口