设备驱动程序:
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/wait.h>
MODULE_LICENSE("GPL");
#define BUF_SIZE 256
#define DEVICE ((const char*)"kgrunt")
struct kgrunt_dev
{
struct cdev cdev;
char *buf;
int len;
int bytes;
struct timer_list timer;
int timer_flag;
wait_queue_head_t queue;
dev_t dev;
};
static struct kgrunt_dev kgrunt;
static void kgrunt_timer_fn(unsigned long d)
{
struct kgrunt_dev *dev = (struct kgrunt_dev *)d;
struct timer_list *timer = &dev->timer;
dev->bytes = snprintf(dev->buf, dev->len,\
"timer experis: %lu,jiffers: %lu, current pid: %d, comm:%s\n",\
timer->expires,jiffies, current->pid, current->comm);
wake_up_interruptible(&dev->queue);//唤醒等待队列
if (dev->timer_flag)
mod_timer(timer, timer->expires + HZ);
}
static int kgrunt_open(struct inode *inode, struct file *file)
{
printk("kgrunt open\n");
struct kgrunt_dev *dev = \
container_of(inode->i_cdev, struct kgrunt_dev, cdev);//由inode对应的字符设备指针得到kgrunt设备的地址
file->private_data = dev;
mod_timer(&dev->timer, jiffies + HZ);//注册定时器
dev->timer_flag = 1;
return 0;
}
static int kgrunt_realse(struct inode *inode, struct file *file)
{
printk("kgrunt release\n");
struct kgrunt_dev * dev = container_of(inode->i_cdev, struct kgrunt_dev, cdev);
dev->timer_flag = 0;
del_timer_sync(&dev->timer);
return 0;
}
static ssize_t kgrunt_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
int err;
struct kgrunt_dev *dev = (struct kgrunt_dev *)file->private_data;
printk("read data ,count: %d, pos: %d\n", count, (int)*pos);
if (count < 0)
return -EINVAL;
if (count == 0)
return 0;
if (dev->bytes == 0)
if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
err = wait_event_interruptible(dev->queue, dev->bytes > 0);//等待队列
if (err == ERESTARTSYS)
return -EINTR;
if (count > dev->bytes)
count = dev->bytes;
if (copy_to_user(buf, dev->buf, count) > 0)
{
printk("copy data to user failed\n");
return -EFAULT;
}
dev->bytes = 0;
return count;
}
static ssize_t kgrunt_write(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
/*nothing to do*/
return -EPERM;
}
static loff_t kgrunt_llseek(struct file *file, loff_t offset, int whence)
{
/*nothing to do*/
return -EPERM;
}
static struct file_operations kgrunt_fops =
{
.owner = THIS_MODULE,
.open = kgrunt_open,
.release= kgrunt_realse,
.read = kgrunt_read,
.write = kgrunt_write,
.llseek = kgrunt_llseek,
};
static __init int kgrunt_init(void)
{
int err;
printk("init kgrunt\n");
if ((err = alloc_chrdev_region(&kgrunt.dev, 0, 1, DEVICE)) < 0)//自动注册设备号
{
printk("alloc_chardev_region ERR\n");
goto cdev_alloc_fail;
}
printk("MAJOR: %d, MINOR: %d\n", MAJOR(kgrunt.dev), MINOR(kgrunt.dev));
if ((kgrunt.buf = kmalloc(BUF_SIZE, GFP_KERNEL)) == NULL)
{
goto kmalloc_fali;
}
printk("kmalloc succfull\n");
kgrunt.len = BUF_SIZE;
kgrunt.bytes = 0;
cdev_init(&kgrunt.cdev, &kgrunt_fops);//初始化设备
kgrunt.cdev.owner = kgrunt_fops.owner;
setup_timer(&kgrunt.timer, kgrunt_timer_fn, (unsigned long)&kgrunt);//初始化、设置定时器
kgrunt.timer_flag = 0;
init_waitqueue_head(&kgrunt.queue);//初始化等待队列
if ((err = cdev_add(&kgrunt.cdev, kgrunt.dev, 1)) < 0)//注册设备
{
printk("cedv_add fail\n");
goto cdev_add_fail;
}
return 0;
cdev_add_fail:
kfree(&kgrunt.buf);
kmalloc_fali:
unregister_chrdev_region(kgrunt.dev, 1);
cdev_alloc_fail:
return err;
}
static __exit void kgrunt_exit(void)
{
printk("kgrunt exit\n");
cdev_del(&kgrunt.cdev);
kfree(kgrunt.buf);
unregister_chrdev_region(kgrunt.dev, 1);
}
module_init(kgrunt_init);
module_exit(kgrunt_exit);
应用程序:
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define DEVICE (const char*)"/dev/kgrunt"
int main(int argc, char **argv)
{
char buf[256];
int fd, ret;
memset(buf, 0, sizeof(buf));
if ((fd = open(DEVICE, O_RDONLY)) < 0)
{
printf("open device failed\n");
return 0;
}
while(1)
{
memset(buf, 0, sizeof(buf));
if ((ret = read(fd, buf, sizeof(buf))) < 0)
{
sleep(1);
continue;
}
sleep(1);
printf("read data: %s\n", buf);
}
}