终于通过编译了。接下来就要在用户空间测试驱动程序。应该如何测试驱动程序能否正确工作呢?事实上应该对驱动程序提供的每一种方法都进行验证,本文只验证了驱动程序的核心函数read()和write()。
首先装载模块
sudo insmod scull.ko
sudo cat /var/log/messages
Apr 28 21:04:36 garden kernel: [ 868.562322] scullsingle registered at f900008
Apr 28 21:04:36 garden kernel: [ 868.562325] sculluid registered at f900009
Apr 28 21:04:36 garden kernel: [ 868.562326] scullwuid registered at f90000a
Apr 28 21:04:36 garden kernel: [ 868.562327] sullpriv registered at f90000b
看到打印安装成功。通过dmesg命令也可以看到这些消息
cat /proc/devices
Character devices:
...
249 scull
249 scullp
249 sculla
...
看到字符设备下出现了scull,这是函数add_cdev成功将scull加入到了系统中,系统给scull分配的主设备号是249。
现在可以确认scull驱动程序已经运行在系统中了,那么怎么操作它呢?
我们首先要建立一个文件节点,使用mknod 命令,mknod 用法是这样的,mknod name type major minor,分别接节点名,类型,b表示块设备,c表示字符设备(scull是字符设备,因此用c),major是主设备号(scull主设备号是249),minor为次设备号。
sudo mknod /dev/scull0 c 249 0
ls -l /dev
可以看到,有一个叫sucll0的设备出现在dev目录下。现在可以对这个字符设备进行读写操作了。我写了一个函数来验证scull是否能正确工作,先往scull里写数字,然后读出来,现写1000个整数,也就是4000Bytes,从0写到999,看能否正确的读出来。代码如下:
- #include <stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<fcntl.h>
- int main(int argc,char **argv)
- {
- int i,fd;
- int *content,*buffer;
- fd=open("/dev/scull0",O_RDWR);
- content=(int*)malloc(1000*sizeof(int));
- for(i=0;i<1000;i++) //初始化content内容为0~999
- *(content+i)=i;
- write(fd,content,i*sizeof(int)); //此处write是以byte为单位的
- lseek(fd,0L,SEEK_SET); //指针重新定位到文件开头
- buffer=(int*)malloc(1000*sizeof(int));
- read(fd,buffer,i*sizeof(int)); //同样,读也是以byte为单位
- for(i=0;i<1000;i++)
- {
- printf("%d\t",*(buffer+i));
- if((i+1)%10==0)
- printf("\n");
- }
- printf("\n");
- return 0;
- }
执行,终端打印了0-999共4000Byte单位的内存内容,那么,如果要写入更多呢?我们可以稍微修改一下程序,使得可以从终端读入需要写入scull的长度。代码进行小改动,如下
- #include <stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<fcntl.h>
- void usage()
- {
- printf("usage: command \n");
- exit(0);
- }
- int main(int argc,char **argv)
- {
- int i,fd,numbers;
- int *content,*buffer;
- if(argc!=2)
- usage();
-
- numbers=atoi(argv[1]); //将输入转化为int型
- fd=open("/dev/scull0",O_RDWR);
- content=(int*)malloc(numbers*sizeof(int));
- for(i=0;i<numbers;i++)
- *(content+i)=i;
- write(fd,content,numbers*sizeof(int));
- lseek(fd,0L,SEEK_SET);
- buffer=(int*)malloc(numbers*sizeof(int));
- read(fd,buffer,numbers*sizeof(int));
- for(i=0;i<numbers;i++)
- {
- printf("%d\t",*(buffer+i));
- if((i+1)%10==0)
- printf("\n");
- }
- printf("\n");
- return 0;
- }
现在我们可以随意指定写入scull的尺寸了。OK!那就试试写入更多的数字吧。运行./testScull 1100,发现1000以后的都是0了,这是怎么回事呢?仔细观察scull的write方法,原来,我们的驱动程序默认是一次写入1个quartum,4000字节,即使你只写了1个byte,也会消耗4000byte内存,而超过4000的数据会被截短。
- if(!dptr->data[s_pos])
- {
- dptr->data[s_pos]=kmalloc(quantum,GFP_KERNEL); //每次分配一个量子的内存
- ...
- }
- if(count>quantum-q_pos) //如果count大于quantum的大小,将截短
- count=quantum-q_pos;
事实上,我们的测试程序进行系统调用read和write的时候并没有检查它的返回值,这样做是不妥的,在任何时候进行系统调用我们都应该检查它的返回值。返回值有三种情况
1,返回值等于count,这种情况read(write)调用完成了请求
2,返回值小于0,这意味着发生错误了,用strerror(errno)查看错误信息
3,返回值等于0,没有读写发生,系统可能重复调用读写
4,返回值大于0小于count,写入部分,我们呢可以接着调用继续写入剩下的部分。
3和4的情况都不是错误,程序员需要根据返回值进行恰当的动作而不是直接返回error。
看来我们写入4400byte数据只能读出4000byte数据是合理的结果的,我们需要修改程序,对write和read的返回值进行检查。修改后的代码如下
- #include <stdio.h>
- #include<stdlib.h>
- #include<unistd.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<fcntl.h>
- #include<errno.h>
- #include<string.h>
- void usage()
- {
- printf("usage: command \n");
- exit(0);
- }
- int main(int argc,char **argv)
- {
- int i,fd,numbers,count,rest;
- int *content,*buffer;
- if(argc!=2)
- usage();
- numbers=atoi(argv[1]); //将输入转化为int型
- rest=numbers*sizeof(int);
- fd=open("/dev/scull0",O_RDWR);
- content=(int*)malloc(numbers*sizeof(int));
- if(content<0)
- printf("malloc failed:%s",strerror(errno));
- for(i=0;i<numbers;i++)
- *(content+i)=i;
- count=write(fd,content,numbers*sizeof(int));
- while(count!=rest)
- {
- if(count<0)
- {
- printf("%s\n",strerror(errno));
- exit(0);
- }
- else if(count<rest)
- {
- rest=rest-count;
- content+=count/sizeof(int);
- count=write(fd,content,rest);
- }
- }
- if(rest<numbers*sizeof(int))
- content-=numbers-rest/sizeof(int);
- free(content);
- lseek(fd,0L,SEEK_SET);
- rest=numbers*sizeof(int);
- buffer=(int*)malloc(numbers*sizeof(int));
- if(buffer<0)
- printf("malloc failed:%s\n",strerror(errno));
- count=read(fd,buffer,rest);
- while(count!=rest)
- {
- if(count<0)
- {
- printf("%s",strerror(errno));
- exit(0);
- }
- else if(count <rest)
- {
- rest-=count;
- buffer+=count/sizeof(int);
- count=read(fd,buffer,rest);
- }
- }
- if(rest<numbers*sizeof(int))
- buffer-=numbers-rest/sizeof(int);
- for(i=0;i<numbers;i++)
- {
- printf("%d\t",*(buffer+i));
- if((i+1)%10==0)
- printf("\n");
- }
- printf("\n");
- free(buffer);
- return 0;
- }
- 89,1 Bot
运行程序,后面可以写入很大的数据,观察内存占用的情况。比如可以写100M数据,在命令行用free查看,当然,这个时候需要先把79到85行注释掉先,不然电脑打印100M个数据会卡死的,哈哈。最后附上测试文件
阅读(845) | 评论(0) | 转发(0) |