Linux驱动开发_杂项字符设备框架
任务1: 杂项字符设备框架
开发板运行之后: 地址被划分为两个地址: (1) 物理地址 (2) 虚拟地址 ( MMU )
MMU: 主要功能实现虚拟地址与物理地址的转换。
当CPU启动MMU功能之后,MMU会拦截CPU所有的地址请求,这个时候CPU会认为自己最大可以访问4G的空间。
在linux下所有的设备皆文件: 字符设备、块设备、网络设备(没有设备节点的)
除了网络设备之外,其他设备都会在/dev下生成设备节点文件。
常见的类型: c表示字符设备,b表示块设备。
[root@wbyq rootfs]# ls /dev/sda sda sda1 sda2 [root@wbyq rootfs]# ls /dev/sda -l brw-rw----. 1 root disk 8, 0 11月 26 15:30 /dev/sda You have new mail in /var/spool/mail/root [root@wbyq rootfs]# ls /dev/fb0 -l crw-rw----. 1 root root 29, 0 11月 15 19:32 /dev/fb0 29表示主设备号,0表示次设备号 |
操作系统如何识别设备文件? 依靠设备号区分。 分为主设备(11高位)和次设备(低20位) 一个共32位。
1.1 杂项字符设备特性
1. 主设备号: 10
2. 次设备号: 0~255 (实际使用只能是0~254) 填255表示自动分配次设备号。
3. 支持自动创建设备节点。(可以在/dev目录下直接生成设备节点文件)
杂项设备的核心文件: misc.c和miscdevice.h
Linux下的驱动文件: 以.ko为后缀。 xxx.ko
因为驱动安装到内核里的,驱动的编译工作由内核来完成。
KER_DRI = /work/Tiny4412/linux-3.5/ all: make -C $(KER_DRI) M=`pwd` modules make -C $(KER_DRI) M=`pwd` modules clean :表示清除之前编译生的一堆文件。 obj-m +=tiny4412_MiscDevice.o -C :指定路径。 比如: tar xvf 123.tar -C /work M=`pwd` :获取shell命令的返回值给一个变量 modules :是Makefile里的一个命令。表示编译成模块。 |
驱动的动态加载相关的一些命令
1. 安装驱动: insmod <驱动文件xxx.ko>
2. 查看动态安装的所有驱动: lsmod
3. 查看指定驱动详细信息: modinfo <驱动文件xxx.ko >
4. 卸载动态安装的驱动: rmmod <驱动文件xxx.ko >
错误解决方式:
[root@tiny4412 code]#ls 123.c tiny4412_MiscDevice.ko [root@tiny4412 code]#insmod tiny4412_MiscDevice.ko [ 253.120000] 驱动安装成功! [root@tiny4412 code]#modinfo tiny4412_MiscDevice.ko modinfo: can't open '/lib/modules/3.5.0-FriendlyARM/modules.dep': No such file or directory [root@tiny4412 code]#lsmod tiny4412_MiscDevice 593 0 - Live 0xbf000000 (O) [root@tiny4412 code]#rmmod tiny4412_MiscDevice.ko rmmod: can't change directory to '/lib/modules': No such file or directory [root@tiny4412 code]#mkdir /lib/modules/3.5.0-FriendlyARM/ -p [root@tiny4412 code]#touch /lib/modules/3.5.0-FriendlyARM/modules.dep [root@tiny4412 code]#modinfo tiny4412_MiscDevice.ko filename: tiny4412_MiscDevice.ko license: GPL author: tiny4412 wbyq depends: vermagic: 3.5.0-FriendlyARM SMP preempt mod_unload ARMv7 p2v8 [root@tiny4412 code]#rmmod tiny4412_MiscDevice.ko [ 359.940000] 驱动卸载成功! [root@tiny4412 code]# |
1.2 用户空间与驱动空间的数据拷贝
copy_to_user(<用户空间指针>,<驱动空间指针>, <拷贝的数量>); /*将驱动层的数据拷贝给用户层*/ copy_from_user(<驱动空间指针>,<用户空间指针>, <拷贝的数量>); /*将应用层的数据拷贝给驱动层*/ |
1.3 驱动层访问物理地址的方法
内核层的IO映射函数:
ioremap(<待转换的物理地址>, <转换的字节单位>); 返回值是转换之后的虚拟地址。 iounmap(<转换之后的虚拟地址>); |
开发板上的资源: 4盏LED灯(核心板)、一个蜂鸣器(底板)、4个按键(底板)。
在4412数据手册里: XXX_CON表示是配置寄存器、XXX_DAT表示数据寄存器(输入输出寄存器)
1.4 ioctl接口
Ioctl接口比较适合于控制类: 比如: 开关LED、控制蜂鸣器、配置摄像头参数、配置LCD屏参数。
驱动层文件操作集合: long (*unlocked_ioctl) (struct file *file, unsigned int cmd, unsigned long data)
应用层的函数接口:
#include <sys/ioctl.h> int ioctl(int d, <控制命令>, ...); ...表示可变形参。 |
系统提供的标准宏:
#define _IOC(dir,type,nr,size) \ (((dir) << _IOC_DIRSHIFT) | \ ((type) << _IOC_TYPESHIFT) | \ ((nr) << _IOC_NRSHIFT) | \ ((size) << _IOC_SIZESHIFT)) #define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) #define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) #define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) #define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) |
学习的知识点:
1. 解决根文件系统安装卸载驱动出现的错误。
2. 学习杂项设备注册方式。
3. 学习应用层数据和驱动层数据拷贝。
4. 物理地址转为虚拟地址方法。
5. Ioctl函数接口。
6. 蜂鸣器控制: 原理图、数据手册查看方法。
练习:
1. 编写LED灯驱动,在应用层控制LED灯。
2. 编写按键驱动,在应用层打印出按键值。
3. 在应用层实现按键控制LED灯。(程序里需要安装两个驱动)
驱动模板:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
static int __init tiny4412_misc_dev_init(void)
{
printk("驱动安装成功!\n"); /*提示语句*/
return 0;
}
static void __exit tiny4412_misc_dev_exit(void)
{
printk("驱动卸载成功!\n");
}
module_init(tiny4412_misc_dev_init);
module_exit(tiny4412_misc_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tiny4412 wbyq");
杂项设备代码模板:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#define Tiny4412_DevName "tiny4412_miscdev"
static int tiny4412_open(struct inode *inode, struct file *file)
{
printk("tiny4412_open\n");
return 0;
}
static ssize_t tiny4412_read(struct file *file, char __user *buf, size_t cnt, loff_t *loff)
{
printk("tiny4412_read\n");
return 0;
}
static ssize_t tiny4412_write(struct file *file, const char __user *buf, size_t cnt, loff_t *loff)
{
printk("tiny4412_write\n");
return 0;
}
static int tiny4412_release(struct inode *inode, struct file *file)
{
printk("tiny4412_release\n");
return 0;
}
/*
虚拟文件操作集合,是与应用程序通信桥梁
*/
static struct file_operations tiny4412_fops=
{
.open=tiny4412_open,
.read=tiny4412_read,
.write=tiny4412_write,
.release=tiny4412_release
};
/*
杂项设备结构体
*/
static struct miscdevice misc_dev=
{
.minor=MISC_DYNAMIC_MINOR, /*自动分配次设备号*/
.name=Tiny4412_DevName,
.fops=&tiny4412_fops
};
static int __init tiny4412_misc_dev_init(void)
{
misc_register(&misc_dev);
printk("驱动安装成功!\n"); /*提示语句*/
return 0;
}
static void __exit tiny4412_misc_dev_exit(void)
{
misc_deregister(&misc_dev);
printk("驱动卸载成功!\n");
}
module_init(tiny4412_misc_dev_init);
module_exit(tiny4412_misc_dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("tiny4412 wbyq");
- 点赞
- 收藏
- 关注作者
评论(0)