首先装载模块
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为次设备号。
sudomknod /dev/scull0 c 249 0
ls -l /dev
可以看到,有一个叫sucll0的设备出现在dev目录下。现在可以对这个字符设备进行读写操作了。我写了一个函数来验证scull是否能正确工作,先往scull里写数字,然后读出来,现写1000个整数,也就是4000Bytes,从0写到999,看能否正确的读出来。代码如下:
点击(此处)折叠或打开
#include
#include
#include
#include
#include
#include
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
#include
#include
#include
#include
#include
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
*(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
{
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
#include
#include
#include
#include
#include
#include
#include
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
*(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-count;
content+=count/sizeof(int);
count=write(fd,content,rest);
}
}
if(rest
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-=count;
buffer+=count/sizeof(int);
count=read(fd,buffer,rest);
}
}
if(rest
buffer-=numbers-rest/sizeof(int);
for(i=0;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个数据会卡死的,哈哈。最后附上测试文件