Chinaunix首页 | 论坛 | 博客
  • 博客访问: 43097
  • 博文数量: 11
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 23
  • 用 户 组: 普通用户
  • 注册时间: 2016-10-10 10:28
文章分类

全部博文(11)

文章存档

2016年(11)

我的朋友

分类: LINUX

2016-12-11 20:24:18

终于通过编译了。接下来就要在用户空间测试驱动程序。应该如何测试驱动程序能否正确工作呢?事实上应该对驱动程序提供的每一种方法都进行验证,本文只验证了驱动程序的核心函数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,看能否正确的读出来。代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<fcntl.h>

  7. int main(int argc,char **argv)
  8. {
  9.     int i,fd;
  10.     int *content,*buffer;

  11.     fd=open("/dev/scull0",O_RDWR);
  12.     content=(int*)malloc(1000*sizeof(int))
  13.     for(i=0;i<1000;i++)   //初始化content内容为0~999
  14.         *(content+i)=i;   
  15.     write(fd,content,i*sizeof(int)); //此处write是以byte为单位的

  16.     lseek(fd,0L,SEEK_SET);  //指针重新定位到文件开头

  17.     buffer=(int*)malloc(1000*sizeof(int));
  18.     read(fd,buffer,i*sizeof(int)); //同样,读也是以byte为单位
  19.     for(i=0;i<1000;i++)  
  20.     {
  21.         printf("%d\t",*(buffer+i));
  22.         if((i+1)%10==0)
  23.              printf("\n");
  24.     }
  25.     printf("\n");
  26.     return 0;
  27. }
执行,终端打印了0-999共4000Byte单位的内存内容,那么,如果要写入更多呢?我们可以稍微修改一下程序,使得可以从终端读入需要写入scull的长度。代码进行小改动,如下

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<fcntl.h>

  7. void usage()
  8. {
  9.     printf("usage: command \n");
  10.     exit(0);
  11. }

  12. int main(int argc,char **argv)
  13. {
  14.     int i,fd,numbers;
  15.     int *content,*buffer;

  16.     if(argc!=2)
  17.         usage();
  18.     
  19.     numbers=atoi(argv[1]); //将输入转化为int型

  20.     fd=open("/dev/scull0",O_RDWR);
  21.     content=(int*)malloc(numbers*sizeof(int));
  22.     for(i=0;i<numbers;i++)
  23.         *(content+i)=i;
  24.     write(fd,content,numbers*sizeof(int));

  25.     lseek(fd,0L,SEEK_SET);

  26.     buffer=(int*)malloc(numbers*sizeof(int));
  27.     read(fd,buffer,numbers*sizeof(int));
  28.     for(i=0;i<numbers;i++)
  29.     {
  30.         printf("%d\t",*(buffer+i));
  31.     if((i+1)%10==0)
  32.      printf("\n");
  33.     }
  34.     printf("\n");
  35.     return 0;
  36. }
现在我们可以随意指定写入scull的尺寸了。OK!那就试试写入更多的数字吧。运行./testScull 1100,发现1000以后的都是0了,这是怎么回事呢?仔细观察scull的write方法,原来,我们的驱动程序默认是一次写入1个quartum,4000字节,即使你只写了1个byte,也会消耗4000byte内存,而超过4000的数据会被截短。

点击(此处)折叠或打开

  1. if(!dptr->data[s_pos])
  2. {
  3.     dptr->data[s_pos]=kmalloc(quantum,GFP_KERNEL);  //每次分配一个量子的内存
  4.     ...
  5. }
  6. if(count>quantum-q_pos)  //如果count大于quantum的大小,将截短
  7.     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的返回值进行检查。修改后的代码如下

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include<stdlib.h>
  3. #include<unistd.h>
  4. #include<sys/types.h>
  5. #include<sys/stat.h>
  6. #include<fcntl.h>
  7. #include<errno.h>
  8. #include<string.h>

  9. void usage()
  10. {
  11.     printf("usage: command \n");
  12.     exit(0);
  13. }

  14. int main(int argc,char **argv)
  15. {
  16.     int i,fd,numbers,count,rest;
  17.     int *content,*buffer;

  18.     if(argc!=2)
  19.         usage();

  20.     numbers=atoi(argv[1]); //将输入转化为int型
  21.     rest=numbers*sizeof(int);

  22.     fd=open("/dev/scull0",O_RDWR);
  23.     content=(int*)malloc(numbers*sizeof(int));
  24.     if(content<0)
  25.         printf("malloc failed:%s",strerror(errno));
  26.     for(i=0;i<numbers;i++)
  27.         *(content+i)=i;
  28.     count=write(fd,content,numbers*sizeof(int));

  29.     while(count!=rest)
  30.     {
  31.         if(count<0)
  32.         {
  33.             printf("%s\n",strerror(errno));
  34.             exit(0);
  35.         }
  36.         else if(count<rest)
  37.         {
  38.             rest=rest-count;

  39.             content+=count/sizeof(int);
  40.             count=write(fd,content,rest);
  41.         }
  42.     }
  43.     if(rest<numbers*sizeof(int))
  44.         content-=numbers-rest/sizeof(int);
  45.     free(content);

  46.     lseek(fd,0L,SEEK_SET);
  47.     rest=numbers*sizeof(int);

  48.     buffer=(int*)malloc(numbers*sizeof(int));
  49.     if(buffer<0)
  50.         printf("malloc failed:%s\n",strerror(errno));

  51.     count=read(fd,buffer,rest);
  52.     while(count!=rest)
  53.     {
  54.         if(count<0)
  55.         {
  56.             printf("%s",strerror(errno));
  57.             exit(0);
  58.         }
  59.         else if(count <rest)
  60.         {
  61.             rest-=count;
  62.             buffer+=count/sizeof(int);
  63.             count=read(fd,buffer,rest);
  64.         }
  65.     }

  66.     if(rest<numbers*sizeof(int))
  67.         buffer-=numbers-rest/sizeof(int);

  68.     for(i=0;i<numbers;i++)
  69.     {
  70.         printf("%d\t",*(buffer+i));
  71.         if((i+1)%10==0)
  72.              printf("\n");
  73.     }
  74.     printf("\n");
  75.     free(buffer);

  76.     return 0;
  77. }
  78.                                                                                 89,1 Bot
运行程序,后面可以写入很大的数据,观察内存占用的情况。比如可以写100M数据,在命令行用free查看,当然,这个时候需要先把79到85行注释掉先,不然电脑打印100M个数据会卡死的,哈哈。最后附上测试文件


阅读(1665) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~