使用内核定时器的秒字符设备

                                         秒字符设备

      秒字符设备也是字符驱动,所以与之前的字符设备驱动程序的框架类似,模块编译,模块加载与卸载也与内核模块的编译,加载卸载一致。秒字符设备驱(second)的实现,创建目录(second),在该目录下创建设备文件(second.c),内容按下面的代码写即可,在同一目录下编写相应的Makefile文件,然后make就可以编译模块了,然后插入模块(可以带参数,如:sudo insmod second.ko second_major=249),设备驱动程序就好了,但是现在在/dev中并没有”second”这个字符设备驱动,必须创建设备节点才行,创建设备节点的命令是:mknod /dev/chardev0 c 250 0其中chardev0是设备名,c说明设备是字符设备,250是主设备号,0是次设备号,这些都要根据自己的设备驱动程序来赋予相应的值(此处为:mknod /dev/second c 249 0)。设备节点创建成功后在/dev中就可以看到自己创建的设备了或者使用ls-l second(设备名)来查看详细信息。

秒字符设备驱动实现后要进行测试,创建测试文件(test.c)内容按下面的代码写即可。然后编译运行测试文件,就可以看到效果了。

秒字符设备(second.c)源码:

#include<linux/module.h>

#include<linux/types.h>

#include<linux/fs.h>

#include<linux/errno.h>

#include<linux/mm.h>

#include<linux/sched.h>

#include<linux/init.h>

#include<linux/cdev.h>

#include<asm/io.h>

#include<asm/system.h>

#include<asm/uaccess.h>

 

#define SECOND_MAJOR 249//宏定义主设备号

static int second_major =SECOND_MAJOR; //模块参数,可以输入主设备号

 

struct second_dev//second设备结构体

{

struct cdev cdev;//cdev结构体

atomic_t counter;//一共经历的秒数

struct timer_lists_timer;//设备要使用的定时器

};

 

struct second_dev*second_devp; //设备结构体指针

 

//定时器处理函数

static voidsecond_timer_handle(unsigned long arg)

{

mod_timer(&second_devp->s_timer,jiffies+HZ);

atomic_inc(&second_devp->counter);//counter1

printk(KERN_NOTICE "currentjiffies is %d \n",jiffies);

}

 

//文件打开

int second_open(struct inode*inode,struct file *filp)

{

//初始化定时器

init_timer(&second_devp->s_timer);

second_devp->s_timer.function=&second_timer_handle;

second_devp->s_timer.expires=jiffies+HZ;

 

add_timer(&second_devp->s_timer);//注册定时器

 

atomic_set(&second_devp->counter,0);//设置counter初值为0

return 0;

}

 

/文件释放

int second_release(structinode *inode,struct file *filp)

{

del_timer(&second_devp->s_timer);//释放定时器

 

return 0;

}

 

//读函数

static ssize_tsecond_read(struct file *filp,char __user *buf,size_t count,loff_t*ppos)

{

int counter;

 

counter=atomic_read(&second_devp->counter);//获得counter 的当前值

if(put_user(counter,(int*)buf)) //由于内核空间和用户空间不能直接互访,所以用put_user函数将counter的值从内核复制到用户buf所指的空间。

return -EFAULT;

else

return sizeof(unsigned int);

}

 

//文件操作结构体

static const structfile_operations second_fops =

{

.owner=THIS_MODULE,

.open=second_open,

.release=second_release,

.read=second_read

};

 

//初始化并注册cdev

static voidsecond_setup_cdev(struct second_dev *dev,int index)

{

interr,devno=MKDEV(second_major,index); //获得主设备号

cdev_init(&dev->cdev,&second_fops);

dev->cdev.owner=THIS_MODULE;

dev->cdev.ops=&second_fops;

err=cdev_add(&dev->cdev,devno,1);//注册设备号

if(err)

printk(KERN_NOTICE "error %dadding led %d",err,index);

}

 

//模块加载函数

intsecond_init(void)

{

int ret;

dev_tdevno=MKDEV(second_major,0);

 

if(second_major)

ret=register_chrdev_region(devno,1,"second");//申请设备号

else

{

ret=alloc_chrdev_region(&devno,0,1,"second");//动态申请设备号

second_major=MAJOR(devno);//获得申请到的设备号

}

if(ret<0)

return ret;

//动态申请设备结构体的内存

second_devp=kmalloc(sizeof(structsecond_dev),GFP_KERNEL);

if(!second_devp)//申请失败

{

ret = -ENOMEM;

goto fail_malloc;

}

 

//设置second_devp所指的大小为sizeof(strcutsecond_dev)的内存均为0

memset(second_devp,0,sizeof(struct second_dev));

second_setup_cdev(second_devp,0);//初始化并注册cdev

return 0;

fail_malloc:unregister_chrdev_region(devno,1);

}

 

//模块卸载函数

voidsecond_exit(void)

{

cdev_del(&second_devp->cdev);//注销cdev

kfree(second_devp);//释放设备结构体内存

unregister_chrdev_region(MKDEV(second_major,0),1);//释放设备号

}

 

MODULE_AUTHOR("wangfangyong");

MODULE_LICENSE("GPL");

 

module_param(second_major,int,S_IRUGO);

 

module_init(second_init);

module_exit(second_exit);

 

 

Makefile文件源码:

obj-m := second.o

path =/usr/src/linux-headers-$(shell uname -r)

all:

make -C $(path) M=$(PWD)modules

clean:

make -C $(path) M=$(PWD)clean

 

 

 

测试文件(test.c)源码:

#include<stdio.h>

#include<stdlib.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<unistd.h>

#include<fcntl.h>

#include<string.h>

 

int main()

{

int fd;

int counter=0;

int old_counter=0;

fd=open("/dev/second",O_RDONLY); //打开设备文件

if(fd!=-1)

{

while(1)

{

read(fd,&counter,sizeof(unsigned int ));//读目前经历的秒数

if(counter!=old_counter)

{

printf("seconds after open/dev/second:%d\n",counter);

old_counter=counter;

}

}

}

else

printf("device openfail\n");

}

posted on 2010-10-08 18:49  生活费  阅读(450)  评论(0编辑  收藏  举报

导航