linux 驱动开篇终极总结

1、 驱动背景

Ubuntu 操作系统、 学习 ARM 裸机、 学习系统移植   就是为了学习   Linux驱动开发

驱动分为 字符设备驱动  块设备驱动  网络设备驱动。

字符设备 最多,从最简单的 点灯 I2C SPI、LCD 音频  等都属于 字符设备驱动 的类型。
就是因为其复杂所以 半导体厂商 一般都给我们编写好了,大多数情况下都是 直接可以使
用的
在   Linux 中一切皆为文件, 驱动加载成功  以后会在 “ /dev ” 目录下生成一个相应的文件,应
用程序通过对这个名为 “/dev/xxx ”  (xxx 是具体的驱动文件名字 ) 的文件进行 相应的操作  即可实
现对硬件的操作。
每一 个统调用 ,在驱动中都有与之对应的一个 驱动函数 ,在 Linux 内核文件   include/linux/fs.h 
有个叫做   file_operations    的结构体,此结构体就是 Linux 内核驱动操作函数集合.
在 Linux 驱动开发中 肯定也是要初始化相应的外设寄存器 ,这个是毫无疑问的。
在 Linux 驱动开发中 肯定也是要初始化相应的外设寄存器 ,这个是毫无疑问的。
在 Linux 驱动开发中 肯定也是要初始化相应的外设寄存器 ,这个是毫无疑问的。
重要的事情说3遍!         重要的事情说3遍!         重要的事情说3遍!
只是在 Linux 驱动开发中 我们需要按照 kernel 规定的 框架 来编写 驱动 (设备文件操作 函数指针) ,所以说学 Linux 驱动开发 重点 是学习 其驱动框架

2.   驱动 的加载和卸载

第一种就是将驱动编译进 Linux 内核中  Linux 内核启动的时候就会自动运行驱动程序
第二种就是将驱动编译成模块 (Linux 下模块扩展名为 .ko) ,在 Linux 内核启动以后使用“ insmod ”命令加载驱动模块。
在调试驱动的时候一般都选择将其编译 为模块,这样我们修改驱动以后只需要 编译一下驱动代码 即可, 不需要编译整个 Linux 代码
module_init(xxx_init);
// 注册模块加载函数
module_exit(xxx_exit);
// 注册模块卸载函数
当使用 “insmod” 命令加载驱动的时候, xxx_init 这个函数就会被调用。
rmmod”命令 卸载具体驱动的时候 xxx_exit 函数就会被调用。

3.   字符设备注册 和 注销

当驱动模块加载成功以后需要注册字符设备,同样,卸载驱动模 块的时候也需要注销掉字符设备。
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)

4. 传统的驱动编程框架

static struct file_operations test_fops ;
static int __init xxx_init ( void ) {
         int retvalue = 0 ;
         retvalue = register_chrdev ( 200 , "chrtest" , & test_fops );
         if ( retvalue < 0 ){ }
        return 0;
}
static void __exit xxx_exit ( void ) {
         unregister_chrdev ( 200 , "chrtest" );
}
module_init(xxx_init);
module_exit(xxx_exit);
MODULE_LICENSE(“GPL”)    // 添加模块 LICENSE 信息
MODULE_AUTHOR("zhengyang")    // 添加模块作者信息
register_chrdev  接口调用后 可以在cat proc/devices 可以看到注册的设备 

5. 终极核心  就是 实现  file_operations  这个结构体

file_operations 结构体就是设备的具体操作函数
open release read write 等具体的设备操作函数。
static int chrtest_open ( struct inode * inode , struct file * filp ) {}
static ssize_t chrtest_read ( struct file * filp , char __user * buf , size_t cnt , loff_t * offt ){}
static ssize_t chrtest_write ( struct file * filp , const char __user * buf , size_t cnt , loff_t * offt ){}
static int chrtest_release ( struct inode * inode , struct file * filp ) {}
static struct file_operations test_fops = {
        . owner = THIS_MODULE ,
        . open = chrtest_open ,
        . read = chrtest_read ,
        . write = chrtest_write ,
        . release = chrtest_release ,
};

6.Linux设备号

为了 方便管理, Linux 中每个设备  都有一个设备号,设备号由  主设备号  和  次设备 号两部分 组成, 主设备号 表示  某一个具体的驱动 ,次设备号表示  使用这个驱动的各个设备
typedef __u32  dev_t   定义在文件   include/linux/types.h    里面
高 12 位为 主设备号, 低 20 位为 次设备号
#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))
直接注册设备号register_chrdev
动态分配注册设备号
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, const char *name)

7. 驱动 Makefile 编写 

KERNELDIR := /home/zuozhongkai/linux/IMX6ULL/linux/temp/linux-imx
rel_imx_4.1.15_2.1.0_ga_alientek 
CURRENT_PATH := $(shell pwd)
obj-m := chrdevbase.o
build :   kernel_modules
kernel_modules :
        $(MAKE)   -C   $(KERNELDIR) M = $(CURRENT_PATH)   modules  
clean :
        $(MAKE)   -C   $(KERNELDIR) M = $(CURRENT_PATH)   clean
KERNELDIR  表示开发板所使用的 Linux 内核源码目录,使用绝对路径

8.创建设备节点文件

驱动加载成功需要在 /dev 目录下创建一个与之对应的设备节点文件,应用程序就是通过操
作这个设备节点文件来完成对具体设备的操作。
mknod /dev/chrdevbase  c  200  0
insmod  rmmod
ls /dev/chrdevbase -l

9. 驱动程序的测试手法

应用层app程序: open  close  read   write  等函数应用。

./chrdevbaseApp  /dev/chrdevbase 1
./chrdevbaseApp  /dev/chrdevbase 2
 
字符设备驱动的开发框架以及测试方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦幽风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值