1.内核模块代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <asm/uaccess.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <asm/atomic.h>
int timer_open(struct inode *, struct file *);
int timer_release(struct inode *, struct file *);
ssize_t timer_read(struct file *, char __user *, size_t, loff_t *);
ssize_t timer_write(struct file *, char __user *, size_t, loff_t *);
loff_t timer_llseek(struct file *, loff_t, int);
int timer_ioctl(struct file *, unsigned int, unsigned long);
#define N 100
#define CLEAR_DATA 1
struct timer_dev{
struct cdev cdev;
struct timer_list timer;
atomic_t counter;
};
struct file_operations timer_fops = {
.owner = THIS_MODULE,
.llseek = timer_llseek,
.open = timer_open,
.release = timer_release,
.unlocked_ioctl = timer_ioctl,
.read = timer_read,
.write = timer_write,
};
dev_t dev_num;
struct timer_dev *dev;
void timer_func(unsigned long data)
{
mod_timer(&dev->timer, jiffies + HZ);
atomic_inc(&dev->counter);
return ;
}
int timer_open(struct inode *inodep, struct file *filp)
{
init_timer(&dev->timer);
dev->timer.function = timer_func;
dev->timer.expires = jiffies + HZ;
add_timer(&dev->timer);
return 0;
}
int timer_release(struct inode *inodep, struct file *filp)
{
del_timer(&dev->timer);
return 0;
}
ssize_t timer_read(struct file *filp, char __user *buf, size_t len, loff_t *fpos)
{
int counter;
counter = atomic_read(&dev->counter);
if(put_user(counter, (int *)buf) < 0)
{
return -EFAULT;
}
return sizeof(int);
}
ssize_t timer_write(struct file *filp, char __user *buf, size_t len, loff_t *fpos)
{
return 0;
}
loff_t timer_llseek(struct file *filp, loff_t off, int whence)
{
return 0;
}
int timer_ioctl(struct file *filp, unsigned int cmd, unsigned long val)
{
return 0;
}
static int __init timer_init(void)
{
if(alloc_chrdev_region(&dev_num, 0, 1, "timer"))
return -EFAULT;
dev = kzalloc(sizeof(struct timer_dev), GFP_KERNEL);
cdev_init(&dev->cdev, &timer_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &timer_fops;
int err = cdev_add(&dev->cdev, dev_num, 1);
if(err)
goto fail;
printk("timer_init is success\n");
return 0;
fail:
kfree(dev);
return err;
}
static void __exit timer_exit(void)
{
unregister_chrdev_region(dev_num, 1);
cdev_del(&dev->cdev);
kfree(dev);
printk("timer_exit is success\n");
return ;
}
MODULE_LICENSE("GPL");
module_init(timer_init);
module_exit(timer_exit);
2.Makefile文件
TARGET= timer
obj-m := ${TARGET}.o
CURRENT_PATH := $(shell pwd)
LINUX_KERNEL := $(shell uname -r)
LINUX_KERNEL_PATH := /usr/src/linux-headers-${LINUX_KERNEL}
.PHONY: all
.PHONY: clean
.PHONY: install
.PHONY: remove
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean
install:
sudo ./${TARGET}.sh
remove:
sudo ./clean.sh
3. timer.sh 脚本
#!/bin/sh
module="timer"
mode="666"
/sbin/insmod ${module}.ko || exit 1
rm -f /dev/${module}
major=$(awk 'BEGIN{count = 0;} {if($2 == module && count == 0) {print $1; count++;} }' module=$module /proc/devices)
mknod /dev/${module} c $major 0
chmod $mode /dev/${module}
4. clean.sh脚本
#!/bin/bash
module="timer"
/sbin/rmmod ${module} || exit 1
rm -f /dev/${module}
5.应用程序的使用:
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(int argc, char *argv[])
{
int fd;
if((fd = open("/dev/timer", O_RDWR)) < 0)
goto fail;
int counter = 0, old_counter = 0;
while(1)
{
if(read(fd, &counter, sizeof(counter)) < 0)
goto fail;
if(counter != old_counter)
printf("counter = %d\n", counter);
old_counter = counter;
}
return 0;
fail:
printf("read_timer error: %s\n", strerror(errno));
exit(1);
}