Kernel driver example - timer

来自个人维基
2020年4月26日 (日) 17:55free6d1823讨论 | 贡献的版本

(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转至: 导航搜索
  • Environment:

Host PC: 4.15.0-96-generic #97~16.04.1-Ubuntu x86_64 GNU/Linux

  • driver - mytimer.c
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
 
#include <linux/timer.h> //init_timer
 
static int mytimer_major = 0;
module_param(mytimer_major, int, S_IRUGO);
 
struct mytimer_dev {
    struct cdev cdev;
    atomic_t counter;
    struct timer_list s_timer;
};
 
static struct mytimer_dev *mytimer_devp;
 
static void mytimer_timer_handler(struct timer_list * pTimer)
{
    mod_timer(pTimer, jiffies + HZ); /* 触发下一次定时 */
    atomic_inc(&mytimer_devp->counter); /* 增加秒计数 */
 
    printk(KERN_INFO "current jiffies is %ld\n", jiffies);
}
 
static int mytimer_open(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "mytimer_open:\n");
 
    mytimer_devp->s_timer.function = &mytimer_timer_handler;
    mytimer_devp->s_timer.expires = jiffies + HZ;
 
    timer_setup(&mytimer_devp->s_timer, &mytimer_timer_handler, 0);
    add_timer(&mytimer_devp->s_timer);
 
    atomic_set(&mytimer_devp->counter, 0);  /* 初始化秒计数为0 */                   
 
    return 0;
}
 
static int mytimer_release(struct inode *inode, struct file *filp)
{
    printk(KERN_INFO "mytimer_release:\n");
    del_timer(&mytimer_devp->s_timer);
 
    return 0;
}
 
static ssize_t mytimer_read(struct file *filp, char __user * buf, size_t count, loff_t * ppos)
{
    int counter;
    printk(KERN_INFO "mytimer_read:\n");
    counter = atomic_read(&mytimer_devp->counter);
    if (put_user(counter, (int *)buf)) /* 拷贝counter到userspace */
        return -EFAULT;
    else
        return sizeof(unsigned int);
}
 
static const struct file_operations mytimer_fops = {
        .owner = THIS_MODULE,
        .open = mytimer_open,
        .release = mytimer_release,
        .read = mytimer_read,
};
 
static void mytimer_setup_cdev(struct mytimer_dev *dev, int index)
{
    int err, devno = MKDEV(mytimer_major, index);
 
    cdev_init(&dev->cdev, &mytimer_fops);
    dev->cdev.owner = THIS_MODULE;
    err = cdev_add(&dev->cdev, devno, 1);
    if (err)
        printk(KERN_ERR "Failed to add mytimer device\n");
}
 
static int __init mytimer_init(void)
{
    int ret;
    dev_t devno = MKDEV(mytimer_major, 0);
 
    printk(KERN_INFO "mytimer_init:\n");
 
    if (mytimer_major)
        ret = register_chrdev_region(devno, 1, "mytimer");
    else {        
        ret = alloc_chrdev_region(&devno, 0, 1, "mytimer");
        mytimer_major = MAJOR(devno);
    }
    if (ret < 0) {
        printk(KERN_ERR "mytimer: Failed alloc_chrdev_region!\n");
        return ret;
    }  
        mytimer_devp = kzalloc(sizeof(*mytimer_devp), GFP_KERNEL);
    if (!mytimer_devp) {
        ret = -ENOMEM;
        printk(KERN_ERR "kzalloc error\n");
        goto fail_malloc;
    }
 
    mytimer_setup_cdev(mytimer_devp, 0);
    printk(KERN_INFO "mytimer_init OK\n");
    return 0;
 
fail_malloc:
    unregister_chrdev_region(devno, 1);
    return ret;
}
 
module_init(mytimer_init);
 
static void __exit mytimer_exit(void)
{
    printk(KERN_INFO "mytimer_exit:\n");
    cdev_del(&mytimer_devp->cdev);    
    kfree(mytimer_devp);    
    unregister_chrdev_region(MKDEV(mytimer_major, 0), 1);
}
module_exit(mytimer_exit);
 
MODULE_AUTHOR("free6d1823");
MODULE_LICENSE("GPL v2");
  • test program test.c
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h> 
#include <unistd.h>
#include <sys/time.h>
 
 
int main(int argc, char **argv){
    int fd;
 
    int c1 = 0;
    int c2 = -1;
    struct timeval tvStart;
    struct timeval tvEnd;
 
    gettimeofday(&tvStart, NULL);
    fd = open("/dev/mytimer", O_RDONLY);
 
    if (fd != - 1) {
        while (1) {
            if(c1!=c2) {   
                gettimeofday(&tvEnd, NULL); 
		        long int dt = (tvEnd.tv_sec-tvStart.tv_sec)*1000000+(tvEnd.tv_usec - tvStart.tv_usec);
                printf("%3ld.%06ld: seconds after open /dev/mytimer :%d\n",  dt/1000000, dt%1000000,  c1);
                c2 = c1;
            }
            read(fd,&c1, sizeof(unsigned int));
        }    
    } else {
        printf("Device open failed\n");
    }
}
  • Makefile
PWD := $(shell pwd)
 
obj-m := mytimer.o
 
 
all:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
	make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
 
test: test.c
	gcc -o test test.c
  • Build
  • Execution
  • Test Result