秒字符设备

来源:互联网 发布:js 时间字符串转date 编辑:程序博客网 时间:2024/05/29 11:09
 

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

                                         秒字符设备

      秒字符设备也是字符驱动,所以与之前的字符设备驱动程序的框架类似,模块编译,模块加载与卸载也与内核模块的编译,加载卸载一致。秒字符设备驱(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_list s_timer;//设备要使用的定时器}; struct second_dev*second_devp; //设备结构体指针 //定时器处理函数static void second_timer_handle(unsigned long arg){mod_timer(&second_devp->s_timer,jiffies+HZ);atomic_inc(&second_devp->counter);//counter加1printk(KERN_NOTICE "currentjiffies is %ld \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初值为0return 0;} //文件释放int second_release(struct inode *inode,struct file *filp){del_timer(&second_devp->s_timer);//释放定时器 return 0;} //读函数static ssize_t second_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;elsereturn sizeof(unsigned int);} //文件操作结构体static const struct file_operations second_fops ={.owner=THIS_MODULE,.open=second_open,.release=second_release,.read=second_read}; //初始化并注册cdevstatic void second_setup_cdev(struct second_dev *dev,int index){int err,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);} //模块加载函数int second_init(void){int ret;dev_t devno=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(struct second_dev),GFP_KERNEL);if(!second_devp)//申请失败{ret = -ENOMEM;goto fail_malloc;} //设置second_devp所指的大小为sizeof(strcutsecond_dev)的内存均为0memset(second_devp,0,sizeof(struct second_dev));second_setup_cdev(second_devp,0);//初始化并注册cdevreturn 0;fail_malloc:unregister_chrdev_region(devno,1);} //模块卸载函数void second_exit(void){cdev_del(&second_devp->cdev);//注销cdevkfree(second_devp);//释放设备结构体内存unregister_chrdev_region(MKDEV(second_major,0),1);//释放设备号} MODULE_AUTHOR("w");MODULE_LICENSE("GPL"); module_param(second_major,int,S_IRUGO); module_init(second_init);module_exit(second_exit);

Makefile文件源码:

obj-m := second.opath =/usr/src/linux-headers-$(shell uname -r)all:make -C $(path) M=$(PWD)modulesclean: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;}}}elseprintf("device openfail\n");}