“Kernel driver example - timer”的版本间的差异
来自个人维基
free6d1823(讨论 | 贡献) |
free6d1823(讨论 | 贡献) |
||
第4行: | 第4行: | ||
* driver - mytimer.c | * driver - mytimer.c | ||
<source lang="c"> | <source lang="c"> | ||
− | #include <linux/module.h> | + | #include <linux/module.h> //THIS_MODULE |
#include <linux/fs.h> | #include <linux/fs.h> | ||
#include <linux/mm.h> | #include <linux/mm.h> | ||
− | #include <linux/init.h> | + | #include <linux/init.h> //module_init, module_exit |
#include <linux/cdev.h> | #include <linux/cdev.h> | ||
#include <linux/slab.h> | #include <linux/slab.h> |
2020年4月26日 (日) 23:39的版本
- Environment:
Host PC: 4.15.0-96-generic #97~16.04.1-Ubuntu x86_64 GNU/Linux
- driver - mytimer.c
#include <linux/module.h> //THIS_MODULE #include <linux/fs.h> #include <linux/mm.h> #include <linux/init.h> //module_init, module_exit #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; 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
make
- Execution
sudo insmod mytimer.ko cat /proc/devices |grep "mytimer" #242 mytimer sudo mknod /dev/mytimer c 242 0 sudo ./test sudo rmmod mytimer sudo rm /dev/mytimer
- Test Result
Output:
0.000007: seconds after open /dev/mytimer :0 1.009257: seconds after open /dev/mytimer :1 2.036013: seconds after open /dev/mytimer :2 3.059482: seconds after open /dev/mytimer :3 4.082057: seconds after open /dev/mytimer :4 5.105336: seconds after open /dev/mytimer :5 6.129471: seconds after open /dev/mytimer :6 7.153507: seconds after open /dev/mytimer :7 8.183314: seconds after open /dev/mytimer :8 9.206942: seconds after open /dev/mytimer :9 10.226353: seconds after open /dev/mytimer :10 11.249455: seconds after open /dev/mytimer :11 ^C
dmesg:
[200489.822716] mytimer_init: [200489.822718] mytimer_init OK [200750.766876] mytimer_open: [200751.776125] current jiffies is 4345080240 [200752.800261] current jiffies is 4345080496 [200753.824125] current jiffies is 4345080752 [200754.848022] current jiffies is 4345081008 [200755.872202] current jiffies is 4345081264 [200756.896340] current jiffies is 4345081520 [200757.920352] current jiffies is 4345081776 [200758.944019] current jiffies is 4345082032 [200759.968773] current jiffies is 4345082288 [200760.992193] current jiffies is 4345082544 [200762.016323] current jiffies is 4345082800 [200762.399336] mytimer_release:
dmesg after remove driver
[200844.858563] mytimer_exit: