您的位置 首页 5G

驱动学习1

看了好长一段时间的书,开始做驱动,从简单的开始学习,实现最简单的字符设备驱动,实现的功能是对两块内存空间(物理内存)进行控制,实现

看了好长一段时间的书,开端做驱动,从简略的开端学习,完成最简略的字符设备驱动,完成的功用是对两块内存空间(物理内存)进行操控,完成读写操作。
根本的完成与许多学习驱动程序规划的办法相同,跟着他人的程序跑,自己弄了解,搞清楚其间的道理。详细的完成进程,结合注释能够看清楚。首要总结榜首次写驱动进程中存在的问题,以及相应的解决办法。
字符设备驱动的根本流程:
首要,驱动函数的初始化,以及铲除函数(这部分首要是按着必定的形式编程)
1、 请求主设备号,其间能够选用静态或许动态的办法请求。
2、 创立字符设备,其间包含初始化字符设备(分配设备空间),绑定相关的操作(相应的操作),最终是增加字符设备(完成所请求的设备号与设备的绑定)。
3、 设备的详细完成以及过错的处理问题。
4、 铲除函数首要包含分配物理空间的开释以及设备号的开释,字符设备的刊出等。
第二,首要是设备相关操作的详细完成进程。(这部分首要是触及内核的一些常识)包含详细的文件翻开,封闭,以及读写,定位操作。详细的参看源码。
第三,Makefile的根本完成(也是必定的模块,可是能够了解其间的道理)或许直接编译到内核中。
呈现的问题首要是Makefile文档的规划以及加载问题。
问题一,是kmalloc函数等的运用需求相应的头文件,kmalloc的头文件是linux/slab.h,关于过错(errno.h)是与CPU系统密切相关的,因而一般是asm/errno.h,这个也是常见的问题。
问题二,是加载犯错的问题。呈现下面的过错,
insmod:error inserting /home/gong/program/cprogram/module/memdev/memdev.ko: -1 Device or resource busy
这个过错发生的原因首要是因为主设备号真正被其他驱动程序运用导致的。能够经过cat /proc/devices查看详细的状况
251 hidraw
252 usbmon
253 bsg
254 rtc
需求从头界说主设备号。然后从头编译,即可加载成功。
问题三,Makefile文件的规划
编译驱动有两种办法,能够选用直接内核编译的办法,这种办法首要经过修正源码中的Makefile和Kconfig完成。这种办法比较直观,可是会损坏源码的完整性。
一般选用自己编写Makefile的办法完成驱动的编译。这种办法需求了解Makefile的一些语法,一起需求了解自己的源码结构,可是这种形式具有很大的相似性,都是根据模块的规划办法。
常用的Makefile模块如下所示:
ifneq ($(KERNELRELEASE),)
obj-m := memdev.o
else
KDIR :=/opt/LinuxKernel/linux-2.6.38.1
PWD :=$(shell pwd)
default:
make -C $(KDIR) M=$(PWD) modules
clean:
rm -f *.ko *.o *.mod.o *.mod.c *.symvers
endif
详细的剖析我说说自己的了解吧。首要榜首句ifneq ($(KERNELRELEASE),)是完成两个变量的比较。比较两个参量是否不持平。假如不持平则履行下面的句子:obj-m := memdev.o,假如持平就履行else后边的句子。
详细的进程如下:
假如驱动代码是在内核源码中完成,那么KERNELRELEASE便是一个已知的值,详细的值是:
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
可是另一个值为空,这样两个值便是不持平的,这样就履行obj-m := memdev.o。
可是假如不是在内核源码中完成,那么KERNELRELEASE便是一个空值,这样两个参数便是持平的。履行else今后的句子。
KDIR :=/opt/LinuxKernel/linux-2.6.38.1
PWD :=$(shell pwd)
上面的两句是界说两个变量,其间的KDIR是内核源码的根目录,PWD则是当时驱动代码地点的目录。
然后履行
default:
make -C $(KDIR) M=$(PWD) modules
default是一个默许的方针,没有相关的依靠,规则是make -C $(KDIR) M=$(PWD) modules
其间参数-C和M=都有各自的含义,详细的能够参看Makefile的相关材料。
我的了解便是:
-C 选项的作用是指将当时工作目录搬运到你所指定的方位(页便是内核源码的根目录)
“M=dir”,内核程序会主动到你所指定的dir目录中查找模块源码,将其编译,生成.KO文件。完成驱动程序的编译。
详细的留意事项:KERNELRELEASE这个变量不要写错,这个比较简单犯错,还简单查看出来。我榜首次写代码就呈现了相应的过错。
需求留意的是该makefile被履行了两次,其间榜首次是因为没有界说KERNELRELEASE目标,当进入到内核源码今后,这时KERNELRELEASE目标现已被界说好了,然后返回到当时的文件夹下,这时候直接履行榜首句obj-m := memdev.o。这样就完成了内核的编译。
详细的使用程序代码我都是按着他人的代码修正调试的。
下面是我的源码:
榜首个代码是头文件:
#ifndef _MEMDEV_H_H_
#define _MEMDEV_H_H_
#ifndef MEMDEV_MAJOR
#define MEMDEV_MAJOR 555
#endif
#ifndef MEMDEV_NR_DEVS
#define MEMDEV_NR_DEVS 2
#endif
#ifndef MEMDEV_SIZE
#define MEMDEV_SIZE 2048
#endif
struct mem_dev
{
char *data;
unsigned long size;
};
#endif
第二个是C文件:
#include
#include
#include
//#include
#include
#include
#include
/*该头文件首要完成内存的操控,包含kmalloc等函数*/
#include
#include
#include
#include
/*过错的不同,需求详细的类型*/
#include
/*自己界说的头文件*/
#include”memdev.h”
static mem_major = MEMDEV_MAJOR;
module_param(mem_major,int,S_IRUGO);
module_param(mem_major,int,S_IRUGO);
struct mem_dev *mem_devp;
struct cdev cdev;
/*函数的声明*/
static int memdev_init(void);
static void memdev_exit(void);
int mem_open(struct inode *inode,struct file *filp);
int mem_release(struct inode *inode, struct file *flip);
static ssize_t mem_read(struct file *flip,char __user *buf, size_t size,loff_t *ppos);
static ssize_t mem_write(struct file *filp,const char __user *buf,size_t size,loff_t *ppos);
static loff_t mem_llseek(struct file *filp,loff_t offset, int whence);
/*增加该模块的根本文件操作支撑*/
static const struct file_operations mem_fops =
{
.owner = THIS_MODULE,
.llseek = mem_llseek,
.read = mem_read,
.write = mem_write,
.open = mem_open,
.release = mem_release,
};
/*初始化函数*/
static int memdev_init(void)
{
int result;
int i;
/*创立一个设备号*/
dev_t devno = MKDEV(mem_major,0);
/*注册一个设备号*/
/*假如界说了主设备号选用静态请求的办法*/
if(mem_major)
result = register_chrdev_region(devno,2,”mem_dev”);
else/*动态请求设备号*/
{
result = alloc_chrdev_region(&devno,0,2,”mem_dev”);
mem_major = MAJOR(result);
}
/*过错处理*/
if(result < 0)
return result;
/*创立一个设备*/
/*初始化cdev,并将相关的文件操作增加进来*/
cdev_init(&cdev,&mem_fops);
cdev.owner = THIS_MODULE;
cdev.ops = &mem_fops;
/*注册字符设备*/
cdev_add(&cdev,MKDEV(mem_major,0),MEMDEV_NR_DEVS);
/*分配两个内存空间,此处是在物理内存上完成分配,本质是创立两个设备*/
mem_devp = kmalloc(MEMDEV_NR_DEVS * sizeof(struct mem_dev),GFP_KERNEL);
if(!mem_devp)/*犯错的相应操作*/
{
result = -ENOMEM;
/*过错处理,选用典型的goto句子*/
goto fail_malloc;
}

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/yingyong/5g/317798.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部