节拍 :两次时钟中断的间隔就称为节拍( tick ) 。可以看到,节拍等于节拍率分之一。
jiffies: 全局变量 jiffies 用来记录系统自启动以来产生的节拍总数 。 通过 jiffies/HZ 就可获取系统自启动以来的秒数。
/* pc下驱动, arm开发板上驱动要添加<linux/kernel.h> 等头文件*/
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
struct sec_dev
{
struct cdev cdev;
atomic_t count;
struct timer_list s_timer;
};
static int sec_major = 0;
static struct sec_dev *sec_devp;
static struct class *sec_class;
static struct device *sec_device;
static void sec_timer_handle(unsigned long arg)
{
mod_timer(&sec_devp->s_timer, jiffies+HZ);
atomic_inc(&sec_devp->count);
}
static int sec_open(struct inode *inode, struct file *filp)
{
struct sec_dev *devp;
devp = container_of(inode->i_cdev, struct sec_dev, cdev);
filp->private_data= devp;
init_timer(&devp->s_timer);
devp->s_timer.function = sec_timer_handle;
devp->s_timer.expires = jiffies + HZ;
add_timer(&devp->s_timer);
atomic_set(&devp->count, 0);
return 0;
}
static int sec_release(struct inode *inode, struct file *filp)
{
del_timer(&sec_devp->s_timer);
return 0;
}
static ssize_t sec_read(struct file *filp, const char __user *buf, size_t size, loff_t *fops)
{
struct sec_dev *devp = filp->private_data;
int counts;
counts = atomic_read(&devp->count);
if(put_user(counts, (int *)buf)
return -EFAULT;
else
return sizeof(int);
}
static struct file_operations sec_fops =
{
.owner = THIS_MODULE,
.read = sec_read,
.open = sec_open,
.release = sec_release,
};
static void sec_setup_cdev(struct sec_dev *devp, int index)
{
int err;
dev_t dev = MKDEV(sec_major, index);
cdev_init(&devp->cdev, &sec_fops);
devp->cdev.owner = THIS_MODULE;
devp->cdev.ops = &sec_fops;
err = cdev_add(&devp->cdev, dev, 1);
if(err)
printk(KERN_NOTICE "ERROR %d adding sec_timer 0", err);
}
static int __init sec_init(void)
{
int result;
dev_t dev;
if(sec_major)
{
dev = MKDEV(sec_major, 0);
result = register_chrdev_region(dev, 1, "TIMER");
}
else
{
result = alloc_chrdev_region(&dev, 0, 1, "TIMER");
sec_major = MAJOR(dev);
}
if(result < 0)
return result;
sec_devp = kmalloc(sizeof(struct sec_dev), GFP_KERNEL);
if(sec_devp == NULL)
{
result = -ENOMEM;
goto fail;
}
memset(sec_devp, 0, sizeof(struct sec_dev));
sec_setup_cdev(sec_devp, 0);
sec_class = class_create(THIS_MODULE, "sec_timer");
if(IS_ERR(sec_class))
{
printk(KERN_NOTICE "can't create sec_class");
goto fail;
}
sec_device = device_create(sec_class, NULL, dev, NULL, "sec_timer");
return 0;
fail:
unregister_chrdev_region(dev, 1);
return result;
}
static void __exit sec_exit(void)
{
cdev_del(&sec_devp->cdev);
kfree(sec_devp);
device_destroy(sec_class, MKDEV(sec_major, 0));
class_destroy(sec_class);
unregister_chrdev_region(MKDEV(sec_major, 0), 1);
}
module_init(sec_init);
module_exit(sec_exit);
MODULE_AUTHOR("RIVER");
MODULE_LICENSE("Dual BSD/GPL");
/* 验证程序 */
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h> #include <stdlib.h>
int main(void)
{
int count = 0, old_count = 0;
int fd, test = 20;
fd = open("/dev/sec_timer", 0);
if(fd < 0)
{
fprintf(stderr, "can't open /dev/sec_timer\n");
exit(1);
}
while(test--)
{
read(fd, &count, sizeof(int));
if(count != old_count)
{
fprintf(stderr, "count after sec_timer %d\n", count);
old_count = count;
}
}
close(fd);
return 0;
}