关键词: 内核编译; globalmem字符设备驱动编写; linux; linux设备驱动编写;
虚拟内存设备globalmem驱动实现,编写程序,然后将生成的驱动模块插入到驱动之中,接着编写测试程序,对设备globalmem进行测试。(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
3.13.0-24-generic
)sudo apt-get install build-essential kernel-package libncurses5-dev
.tar.xz
格式,首先将下载的内核移动到/usr/src/
目录下(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)sudo mv linux-3.2.96.tar.xz /usr/src
/usr/src/
目录下,解压缩内核压缩包。由于下载的压缩包是.tar.xz
后缀,解压分为两步:xz -d linux-3.2.96.tar.xz
tar -xvf linux-3.2.96.tar
/usr/src/linux-3.2.96
中,清理旧的编译文件cd /usr/src/linux-3.2.96
make mrproper
/usr/src
的样子就是这样的:/usr/src/linux-3.2.96
中使用命令复制运行中的内核config到linux-3.2.96文件夹中(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)sudo cp /boot/config-3.13.0-24-generic /usr/src/linux-3.2.96
.config
文件也复制到linux-3.2.96中(以我的Ubuntu 14.04为例,现有内核中的.config
即为/usr/src/linux-headers-3.13.0-24-generic/.config
)sudo cp /usr/src/linux-headers-3.13.0-24-generic/.config /usr/src/linux-3.2.96
sudo make menuconfig
选择load an Alternate Configuration file
或者直接用默认的.config,都一样能编译
多作业开始编译
sudo make -j4 all
开始编译:
int globalmem_init(void)
{
int result;
dev_t devno = MKDEV(globalmem_major, 0);
/* 申请设备号 */
if (globalmem_major)
result = register_chrdev_region(devno, 1, "globalmem");
else /* 动态申请设备号(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved) */
{
result = alloc_chrdev_region(&devno, 0, 1, "globalmem");
globalmem_major = MAJOR(devno);
}
if (result < 0)
return result;
/* 动态申请设备结构体的内存(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved) */
globalmem_devp = kmalloc(sizeof(struct globalmem_dev), GFP_KERNEL);
if (!globalmem_devp) /*申请失败*/
{
result = - ENOMEM;
goto fail_malloc;
}
memset(globalmem_devp, 0, sizeof(struct globalmem_dev));
globalmem_setup_cdev(globalmem_devp, 0);
return 0;
fail_malloc: unregister_chrdev_region(devno, 1);
return result;
}
void globalmem_exit(void)
{
cdev_del(&globalmem_devp->cdev); /*注销 cdev*/
kfree(globalmem_devp); /*释放设备结构体内存 (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)*/
unregister_chrdev_region(MKDEV(globalmem_major, 0), 1); /*释放设备号*/
}
完整代码见[传送门]
Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved
在编写makefile的时候,我参考了网上的很多写法,都不能很有效地成功编译设备驱动。以下的makefile写法是我自己摸索出来的,在我的测试环境下,保证能编译成功。但也只保证在我的测试环境下,因为我没有测试其他的环境,如Ubuntu 16.04等。
代码如下:
# Makefile (Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
ifneq ($(KERNELRELEASE),)
# kbuild syntax. dependency relationshsip of files and target modules are listed here.
obj-m := globalmem.o
else
PWD := $(shell pwd)
KERNEL_VER ?= $(shell uname -r)
KERNEL_DIR := /lib/modules/$(KERNEL_VER)/build
all:
$(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
clean:
rm ‐rf *.o *~ core .depend .*.cmd *.ko *.mod.c
endif
编译成功:
运行sudo insmod globalmem.ko
命令加载模块,通过lsmod
命令,发现globalmem模块已被加载。
再通过cat /proc/devices命令查看,发现多出了主设备号为150的globalmem字符设备驱动,如下所示
接着sudo mknod /dev/globalmem c 150 0
这一步我不确定是否需要,因为之前我没sudo insmod
,可能权限不够所以/dev
里面没有globalmem,现在我使用了sudo insmod
,接着又mknod
,/dev
里面有globalmem了,所以我不确定是哪条命令的作用。
两种方法:
直接在终端中输入
sudo su
ehco 'gy1' > /dev/globalmem
作用是向字符设备中写入字符数据”gy1”。然后,在终端中继续输入(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
cat /dev/globalmem
作用是从字符设备中读取已经写入完成的数据(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
在方法1中为什么会先出现gy1然后又出现cat: /dev/globalmem: 没有那个设备或地址这个报错?
答:返回错误值才是正确的,因为读的位置已经越界,所以要返回错误。该返回错误的时候返回正确,那就是错误。至于网上说将globalmem.c中的if (p > = GLOBALMEM_SIZE)改成if (p > GLOBALMEM_SIZE)是错误的。输出的错误信息是正常的debug信息,因为cat调用了read两次。如果不想看到错误信息输出,将cat换成more即可
编写自己的test.c文件
#include
#include
#include
#include
//(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
int main()
{
int fd;
char num[128] = {'\0'};
int arg = 2015;
//打开字符设备
fd = open("/dev/globalmem", O_RDWR); //可读写方式打开设备文件
if(fd != -1) {
//读取字符设备中的初始值
read(fd, num, sizeof(num)); //读取设备变量
printf("The globalmem is %s\n", num);
//文件指针复位
lseek(fd, 0, SEEK_SET);
//获取输入数据
printf("Please input the num written to globalmem\n");
scanf("%s", num);
//写入到字符设备中
write(fd, num, sizeof(num)); //写设备变量
//文件指针复位
lseek(fd, 0, SEEK_SET);
//从字符设备中读取出来
read(fd, num, sizeof(num)); //再次读取刚才写的值
printf("The globalmem is %s\n", num);
//文件指针复位
lseek(fd, 0, SEEK_SET);
//清空文件中的数据
if (0 > ioctl(fd, 0x01, &arg)) {
printf("Call cmd MEM_CLEAR fail\n");
perror("open globalmem");
}
//关闭字符设备
close(fd); //关闭设备文件
} else {
//打开失败
printf("Device open failure\n");
perror("open globalmem");
}
return 0;
}
发现读出了之前方法1中输入到globalmem中的字符gy1,并写入了新的字符gy2
至此实验成功。
编译内核过程遇到问题,提示:
ERROR: "__modver_version_show" [drivers/staging/rts5139/rts5139.ko] undefined!
make[1]: *** [__modpost] Error 1
make: *** [modules] Error 2
解决方法:
sudo gedit /.config
设置CONFIG_RTS5139=n
继续编译,成功:
globalmem的make过程中提示system.h没有这个文件
解决方法:
在globalmem.c中#include
换为
#include
#if LINUX_VERSION_CODE > KERNEL_VERSION(3, 3, 0)
#include
#else
#include
#endif
.ioctl
部分有错误
原因
linux 2.6.29和linux 2.6.38的内核在file_operations
结构发生了变化,否则在linux 2.6.38内核中,继续使 用.ioctl
成员,编译时就会报错:error: unknown field 'ioctl' specified in initializer
,struct file_operations
结构体定义在include/linux/fs.h
文件中。
linux 2.6.38内核取消了原有的ioctl
成员,添加来新的成员
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
原来的ioctl
返回值变为
long long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
内核空间64位,用户空间32位
warning: initialization from incompatible pointer type
出现此种warnning 的原因 “不兼容的指针类型初始化”。是你定义的函数类型与接口函数的类型不一样,如把返回值long
定义成了int
这两个问题都对驱动有影响。
解决方法
static const struct file_operations 。。。 = {
。。。。。。
.unlocked_ioctl = 。。。,
。。。。。。
};
驱动模块编译时出现如下错误:
error: implicit declaration of function 'kmalloc'
error: implicit declaration of function 'kfree'
解决方法
添加如下头文件即可: #include
(防止CSDN总因为外链屏蔽我的文章,去掉网址中的¥¥即可)
ht¥¥tp://www¥¥.linuxidc.com/Linux/2016-04/130459.htm
ht¥¥tp://mzqthu¥¥.iteye.com/blog/2001167
ht¥¥tp://387424-student-sina-com¥¥.iteye.com/blog/728021
ht¥¥tp://blog¥¥.sina.com.cn/s/blog_5dbc002d0100h7hj.html
ht¥¥tp://blog¥¥.sina.com.cn/s/blog_85998e3801011fpf.html
http://blog.csdn.net/fang_yang_wa/article/details/55805560
http://blog.csdn.net/djinglan/article/details/7372956
http://blog.csdn.net/xiaowulang20082008/article/details/50586985
ht¥¥tps://forums¥¥.fedoraforum.org/showthread.php?282144-Missing-system-h
http://blog.csdn.net/qiaoliang328/article/details/4874238
http://blog.csdn.net/rocky_zhm/article/details/47274879
http://blog.csdn.net/qiaoliang328/article/details/4874238
ht¥¥tps://www¥¥.cnblogs.com/feisky/archive/2010/05/29/1746885.html
(Copyright © http://blog.csdn.net/s_gy_zetrov. All Rights Reserved)
visitor tracker
1