前言
这个系列文章,是我个人linux驱动学习之余的记录,以免后面忘记。
一、Linux驱动
linux系统今天已经运行在数十亿设备上面,兼容30多个体系。面对数不尽的驱动,linux抽象成字符设备、块设备、网络设备。
字符设备可以将设备以字符流的形式,进行读写,大多数硬件设备均可以抽象成字符设备,如常见的串口、spi、i2c、led、按键等等,这个也是开发中主要遇到的,块设备相比较而言会难很多,块设备按照块为单位进行读写,需要相关调度算法调度设备进行读写。网络设备则和网络通信相关。
本文主要接受最简单的字符驱动—hello world驱动。
二、hello world驱动
1.字符驱动构成
一个字符设备构成主要由以下部分:
static int hello_init(void); //模块加载时调用的函数
static void hello_exit(void); //模块卸载时调用的函数
module_init(hello_init); //告诉内核这是一个模块的入口函数
module_exit(hello_exit); //出口函数
MODULE_LICENSE("GPL"); //模块使用的协议
MODULE_AUTHOR("xxx"); //模块的作者xxx
其中,hello_init、hello_exit、module_init(hello_init)module_exit(hello_exit)是必须要有的。
2.Makefile
内容如下:
KERNELDIR := /home/xxx/imx6ull/linux_source
CURRENT_PATH := $(shell pwd)
obj-m := hello.o
build: kernel_modules
kernel_modules:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
clean:
$(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
其中,KERNELDIR指内核的路径, obj-m := hello.o表示模块编译出来的名字为hello.o。
编译是直接make即可得到hello.ko文件,使用insmod hello.ko即可加载到内核中,使用lsmod,可以看到内核中加载了hello驱动模块。
该处使用的url网络请求的数据。
3.文件操作接口
static struct fb_ops结构体如下:
static const struct file_operations hello_fops = {
.open = hello_open,
.read =hello_read,
.write = hello_write,
.unlocked_ioctl = hello_unlocked_ioctl,
.release = hello_release,
};
static int hello_open (struct inode *node, struct file *filp);
static ssize_t hello_read(struct file *filp, char __user * buf, size_t size, loff_t * off);
static ssize_t hello_write (struct file *filp, const char __user *buf, size_t size, loff_t * off)
static long hello_unlocked_ioctl(struct file * filp, unsigned int cmd, unsigned long arg);
static int hello_release(struct inode *node, struct file *size) ;
hello_fops 一般填充由open、read、write、ioctl、release函数,其他的如poll用到再去学习。
总结
linux系统已经对驱动设备进行了必要抽象,并提供相应的API函数,写linux驱动就是填充相应的结构体,调用相应的API函数告诉内核,并在相应的函数里面完成相应的功能。