1.驱动程序
#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>#include <linux/timer.h> /*包括timer.h头文件*/#include <asm/atomic.h> #define SECOND_MAJOR 252static int second_major = SECOND_MAJOR ;struct second_dev{ struct cdev cdev; atomic_t counter; struct timer_list s_timer;};struct second_dev *second_devp;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); if(put_user(counter,(int*)buf)) return - EFAULT; else return sizeof(unsigned int);}static void second_timer_handle(unsigned long arg){ mod_timer(&second_devp->s_timer,jiffies + HZ/4 ); atomic_inc(&second_devp->counter); printk(KERN_NOTICE "hi,this is a timer executing...%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); return 0;}int second_release(struct inode *inode,struct file *filp){ del_timer(&second_devp->s_timer); return 0;}static const struct file_operations second_fops = { .owner = THIS_MODULE, .open = second_open, .release = second_release, .read = second_read,};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; } memset(second_devp,0,sizeof(struct second_dev)); cdev_init(&second_devp->cdev,&second_fops); ret = cdev_add(&second_devp->cdev,devno,1); if(ret) { printk(KERN_ALERT "ERROR ADDING CHAR DEVICE WHILE INITING TIMER.\n"); goto fail; } return 0;fail: if(second_devp) { kfree(second_devp); second_devp = NULL; } unregister_chrdev_region(devno,1); return ret; }void second_exit(void){ cdev_del(&second_devp->cdev); kfree(second_devp); unregister_chrdev_region(MKDEV(second_major,0),1);}MODULE_AUTHOR("ustc");MODULE_LICENSE("GPL");module_param(second_major,int,S_IRUGO);module_init(second_init);module_exit(second_exit);
2.测试文件
/*====================================================================== A test program to access /dev/second This example is to help understand kernel timer The initial developer of the original code is Baohua Song <author@linuxdriver.cn>. All Rights Reserved.======================================================================*/#include <sys/types.h>#include <sys/stat.h>#include <stdio.h>#include <fcntl.h>#include <unistd.h>#include <sys/time.h>int main(int argc,char *argv[]){ int fd; int counter = 0; int old_counter = 0; if(argc<2) { printf("wrong parameter !\n"); return -1; } fd = open(argv[1], O_RDONLY); if (fd != - 1) { while (1) { read(fd,&counter, sizeof(unsigned int));//读目前经历的秒数 if(counter >= 20)break; if(counter!=old_counter) { printf("1/4 seconds after open %s :%d\n",argv[1],counter); old_counter = counter; } } close(fd); } else { printf("Device open failure\n"); } return 0;}
3. Makefile文件
KERNELDIR = /usr/src/linux-headers-$(shell uname -r)PWD := $(shell pwd)CC = gccOBJ := hi_timerobj-m := $(OBJ).o DEVICE_NAME := secondMAJOR := 252TEST_FILENAME:=second_testmoudles:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesinstall:sudo insmod $(OBJ).kosudo mknod /dev/$(DEVICE_NAME) c $(MAJOR) 0sudo chmod ugo+rw /dev/$(DEVICE_NAME)exec:$(CC) -o $(TEST_FILENAME) $(TEST_FILENAME).c./$(TEST_FILENAME) /dev/$(DEVICE_NAME)uninstall:sudo rmmod $(OBJ)sudo rm -rf /dev/$(DEVICE_NAME)clean:rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions $(TEST_FILENAME) *symvers