日期:2014-05-16 浏览次数:20741 次
有了上一节的基础,下面学习一下如何编写一个字符设备驱动,并通过客户端测试,验证字符设备驱动是否创建成功
下面是字符设备驱动源码
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);