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 252
static 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 = gcc
OBJ := hi_timer
obj-m := $(OBJ).o
DEVICE_NAME := second
MAJOR := 252
TEST_FILENAME:=second_test
moudles:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
install:
sudo insmod $(OBJ).ko
sudo mknod /dev/$(DEVICE_NAME) c $(MAJOR) 0
sudo 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