日期:2014-05-16 浏览次数:21045 次
有了上一节的基础,下面学习一下如何编写一个字符设备驱动,并通过客户端测试,验证字符设备驱动是否创建成功
下面是字符设备驱动源码
borytest.c
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/uaccess.h>
#include <linux/timer.h>
#include <asm/atomic.h>
#include <linux/slab.h>
#define BORY_MAJOR 255 /*预设bory的主设备号*/
static int bory_major = BORY_MAJOR;
struct bory_dev /*设备号结构体*/
{
struct cdev cdev;
atomic_t counter;
struct timer_list s_timer;
};
struct bory_dev *bory_devp; /*设备结构体指针*/
static void bory_timer_handle(unsigned long arg) /*定时器处理函数*/
{
printk(KERN_NOTICE "======== bory_timer_handle ");
mod_timer(&bory_devp->s_timer, jiffies + HZ);
atomic_inc(&bory_devp->counter);
printk(KERN_ERR "current jiffies is %ld\n", jiffies);
}
int bory_open(struct inode *inode, struct file *filp) /*文件打开函数*/
{
printk(KERN_NOTICE "======== bory_open ");
init_timer(&bory_devp->s_timer);
bory_devp->s_timer.function = &bory_timer_handle;
bory_devp->s_timer.expires = jiffies + HZ;
add_timer(&bory_devp->s_timer); /*注册定时器*/
atomic_set(&bory_devp->counter, 0);
return 0;
}
int bory_release(struct inode *inode, struct file *filp) /*文件释放*/
{
printk(KERN_NOTICE "======== bory_release ");
del_timer(&bory_devp->s_timer);
return 0;
}
static ssize_t bory_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
printk(KERN_NOTICE "======== bory_read ");
int counter;
counter = atomic_read(&bory_devp->counter);
if(put_user(counter, (int*)buf))
{
return -EFAULT;
}else
{
return sizeof(unsigned int);
}
}
/* 文件操作结构体*/
static const struct file_operations bory_fops =
{
.owner = THIS_MODULE,
.open = bory_open,
.release = bory_release,
.read = bory_read,
};
/*初始化并注册cdev*/
static void bory_setup_cdev(struct bory_dev *dev, int index)
{
printk(KERN_NOTICE "======== bory_setup_cdev 1");
int err, devno = MKDEV(bory_major, index);
printk(KERN_NOTICE "======== bory_setup_cdev 2");
cdev_init(&dev->cdev, &bory_fops);
printk(KERN_NOTICE "======== bory_setup_cdev 3");
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &bory_fops;
printk(KERN_NOTICE "======== bory_setup_cdev 4");
err = cdev_add(&dev->cdev, devno, 1);
printk(KERN_NOTICE "======== bory_setup_cdev 5");
if(err)
{
printk(KERN_NOTICE "Error %d add bory %d", err, index);
}
}
int bory_init(void)
{
printk(KERN_NOTICE "======== bory_init ");
int ret;
dev_t devno = MKDEV(bory_major, 0);
/*申请设备号*/
if(bory_major)
{
printk(KERN_NOTICE "======== bory_init 1");
ret = register_chrdev_region(devno, 1, "bory");
}else
{
printk(KERN_NOTICE "======== bory_init 2");
ret = alloc_chrdev_region(&devno,0,1,"bory");
bory_major = MAJOR(devno);
}
if(ret < 0)
{
printk(KERN_NOTICE "======== bory_init 3");
return ret;
}
/*动态申请设备结构体内存*/
bory_devp = kmalloc(sizeof(struct bory_dev), GFP_KERNEL);
if(!bory_devp) /*申请失败*/
{
ret = -ENOMEM;
printk(KERN_NOTICE "Error add bory");
goto fail_malloc;
}
memset(bory_devp,0,sizeof(struct bory_dev));
printk(KERN_NOTICE "======== bory_init 3");
bory_setup_cdev(bory_devp, 0);
printk(KERN_NOTICE "======== bory_init 4");
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
}
void bory_exit(void) /*模块卸载*/
{
printk(KERN_NOTICE "End bory");
cdev_del(&bory_devp->cdev); /*注销cdev*/
kfree(bory_devp);