秒字符设备

来源:互联网 发布:打工软件哪个好 编辑:程序博客网 时间:2024/05/21 07:07

一个字符设备“second”的驱动,它在被打开的时候初始化一个定时器并将其添加到内核定时器链表,每秒输出一次当前的jifies(为此,定时器处理函数中每次都要修改新的expires)。代码如下:second_timer.c


#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/interrupt.h>#include <linux/fs.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/kdev_t.h>#include <linux/cdev.h>#include <linux/slab.h>#include <linux/time.h>#include <linux/jiffies.h>#define SECOND_MAJOR 88 /*预设second的主设备号*/static int second_major = SECOND_MAJOR;/*second 设备结构体*/struct second_dev{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++printk(KERN_NOTICE "current jiffies is %ld\n",jiffies);//KERN_NOTICE 正常但又重要的条件,用于提醒}/*文件打开函数*/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的值,计数清零return 0;}/*文件释放函数*/int second_release(struct inode *inode,struct file *filp){del_timer(&second_devp->s_timer);return 0;}/*globalfifo读函数*/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);//原子读操作/*copy_to_user --   Copy a block of data into user space.put_user ( x, ptr);//Write a simple value into user space.x         Value to copy to user space.ptr  Destination address, in user space.*/if(put_user(counter,(int *)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,};/*初始化并注册cdev*/static void second_setup_cdev(struct second_dev *dev,int index){/*函数:MKDEV(int major,int monor)头文件:<linux/kdev.h>参数:major为主设备号 ,monor为次设备号功能:将主设备号和次设备号转换成dev_t类型返回:dev_t类型的设备编号说明:dev_t dev; //设备号,int 类型,高12位为主设备号,低20位为次设备号  可以使用如下宏调用来获得主、次设备号:  MAJOR(dev_t dev)  MINOR(dev_t dev)   */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);//传入 cdev 结构的指针,起始设备编号,以及设备编号范围。if(err)printk(KERN_NOTICE "Error %d adding 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");/*register_chrdev_region(dev_t first,unsigned int count,char *name) First :要分配的设备编号范围的初始值(次设备号常设为0); Count:连续编号范围. Name:编号相关联的设备名称. (/proc/devices);*/else /*动态申请设备号*/{/*alloc_chrdev_region() 是动态分配主次设备号。register_chrdev()。是老版本的设备号注册方式,他只分配主设备号。从设备号在mknod的时候指定。int alloc_chrdev_region(dev_t *dev,unsigned int firstminor,unsigned int count,char *name); firstminor : 通常为0; *dev:存放返回的设备号; */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);//GFP_KERNEL,他表示内存分配if(!second_devp) /*申请失败*/{ret = - ENOMEM;//核心内存不足goto fail_malloc;}memset(second_devp,0,sizeof(struct second_dev));second_setup_cdev(second_devp,0);return 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("Huang Dezhi");MODULE_LICENSE("GPL");module_param(second_major,int,S_IRUGO);module_init(second_init);module_exit(second_exit);

在second的open()函数中,将启动定时器,此后每秒会再次运行定时器处理函数,在second的release()函数中,定时器被删除。

second_dev结构体中的原子变量counter用于秒计数,每次在定时器处理函数中将被atomic_inc()调用原子增1,second的read()函数会将这个值返回给用户空间。

编译驱动,加载该内核模块并创建“second”设备文件节点后,使用用户空间测试程序打开“second”。

用户测试应用程序会不断地读取自打开“second”设备文件以来经历的秒数。



second设备用户空间测设程序:second_test.c


#include <stdio.h>#include <sys/types.h>    #include <sys/stat.h>    #include <fcntl.h>#include <string.h>#include <unistd.h>#include <stdlib.h>int main(){int fd;int counter = 0;int old_counter = 0;/*打开second设备文件*/fd = open("second",O_RDONLY);if(fd != -1){while(1){read(fd,&counter,sizeof(unsigned int));//读目前经历的秒数if(counter != old_counter){printf("second after open sencond : %d\n",counter);old_counter = counter;}}}else{printf("Device open failure\n");}return 0;}

运行second_test.c后,内核将不断地输出目前的jiffies值。

0 0
原创粉丝点击