Linux驱动开发_杂项字符设备框架

举报
DS小龙哥 发表于 2022/04/28 23:36:18 2022/04/28
【摘要】 介绍杂项字符设备模型、驱动模块框架、驱动代码模板,完成驱动的编译、安装、测试、编写ioctl接口。

任务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");
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。