openwrt之字符设备驱动框架

第三章 字符设备驱动程序框架

字符设备驱动程序框架简介
出入口函数
module_init(drv_init);//告诉内核入口函数
module_exit(drv_exit);//告诉内核出口函数

drv_init()这个函数就变成了我们的驱动程序的入口函数了,drv_exit()这个函数就变成了我们的驱动程序的出口函数了

给应用程序提供接口
  • 定义 file_operations 结构体(该结构体是驱动和应用程序交互的接口)
  • 调用 register_chrdev() 函数将该结构体注册进内核
  struct file_operations 
  {
    struct module *owner;
    loff_t (*llseek) (struct file *, loff_t, int);
    ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
    unsigned int (*poll) (struct file *, struct poll_table_struct *);
    int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
    long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
    int (*mmap) (struct file *, struct vm_area_struct *);
    int (*open) (struct inode *, struct file *);
    int (*flush) (struct file *, fl_owner_t id);
    int (*release) (struct inode *, struct file *);
    int (*fsync) (struct file *, struct dentry *, int datasync);
    int (*aio_fsync) (struct kiocb *, int datasync);
    int (*fasync) (int, struct file *, int);
    int (*lock) (struct file *, int, struct file_lock *);
    ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
    unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
    int (*check_flags)(int);
    int (*flock) (struct file *, int, struct file_lock *);
    ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);
    ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
    int (*setlease)(struct file *, long, struct file_lock **);
  };

驱动程序要给应用程序提供哪些接口,就只需要填充相应的成员即可。

字符设备驱动程序框架实现
#include <linux/mm.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/raw.h>
#include <linux/tty.h>
#include <linux/capability.h>
#include <linux/ptrace.h>
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/crash_dump.h>
#include <linux/backing-dev.h>
#include <linux/bootmem.h>
#include <linux/splice.h>
#include <linux/pfn.h>
#include <linux/export.h>
#include <linux/io.h>
#include <linux/aio.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <linux/ioctl.h>

/****************          基本定义        **********************/
//内核空间缓冲区定义
#if 0
    #define KB_MAX_SIZE 20
    #define kbuf[KB_MAX_SIZE]
#endif

//加密函数参数内容: _IOW(IOW_CHAR , IOW_NUMn , IOW_TYPE)
//加密函数用于xxx_ioctl函数中
//使用举例:ioctl(fd , _IOW('L',0x80,long) , 0x01);
//#define NUMn xxx , if you need!
#define IOW_CHAR 'L'
#define IOW_TYPE  long
#define IOW_NUM1  0x80

//初始化函数必要资源定义
//device number;
dev_t dev_num;
//struct dev
struct cdev xxx_cdev;
//auto "mknode /dev/xxx c dev_num minor_num"
struct class *xxx_class = NULL;
struct device *xxx_device = NULL;

/**************** 结构体 file_operations 成员函数 *****************/
//open
static int xxx_open(struct inode *inode, struct file *file)
{
    printk("xxx drive open...\n");
    return 0;
}

//close
static int xxx_close(struct inode *inode , struct file *file)
{
    printk("xxx drive close...\n");
    return 0;
}

//read
static ssize_t xxx_read(struct file *file, char __user *buffer,
                size_t len, loff_t *pos)
{
    int ret_v = 0;
    printk("xxx drive read...\n");
    return ret_v;
}

//write
static ssize_t xxx_write( struct file *file , const char __user *buffer,
               size_t len , loff_t *offset )
{
    int ret_v = 0;
    printk("xxx drive write...\n");
    return ret_v;
}

//unlocked_ioctl
static int xxx_ioctl (struct file *filp , unsigned int cmd , unsigned long arg)
{
    int ret_v = 0;
    printk("xxx drive ioctl...\n");
    switch(cmd)
    {
        //cmd值自行进行修改
        case 0x01:
        {
            if(arg == 0x01) //第二条件
            {

            }
        }
        break;

        //带密码保护:
        //请在"基本定义"进行必要的定义
        case _IOW(IOW_CHAR,IOW_NUM1,IOW_TYPE):
        {
            if(arg == 0x01) //第二条件
            {

            }
        }
        break;
        default:
            break;
    }
    return ret_v;
}

/***************** 结构体: file_operations ************************/
//struct
static const struct file_operations xxx_fops = {
    .owner   = THIS_MODULE,
    .open    = xxx_open,
    .release = xxx_close,   
    .read    = xxx_read,
    .write   = xxx_write,
    .unlocked_ioctl = xxx_ioctl,
};

/*************      functions: init , exit      *******************/
//条件值变量,用于指示资源是否正常使用
unsigned char init_flag = 0;
unsigned char add_code_flag = 0;
//init
static __init int xxx_init(void)
{
    int ret_v = 0;
    printk("xxx drive init...\n");
    //函数 alloc_chrdev_region 主要参数说明:
    //参数2:次设备号
    //参数3:创建多少个设备
    if( ( ret_v = alloc_chrdev_region(&dev_num,0,1,"xxx") ) < 0 )
    {
        goto dev_reg_error;
    }
    init_flag = 1; //标示设备创建成功
    printk("The drive info of xxx:\nmajor: %d\nminor: %d\n",
                MAJOR(dev_num),MINOR(dev_num));
    cdev_init(&xxx_cdev,&xxx_fops);
    if( (ret_v = cdev_add(&xxx_cdev,dev_num,1)) != 0 )
    {
        goto cdev_add_error;
    }
    xxx_class = class_create(THIS_MODULE,"xxx");
    if( IS_ERR(xxx_class) )
    {
        goto class_c_error;
    }
    xxx_device = device_create(xxx_class,NULL,dev_num,NULL,"xxx");
    if( IS_ERR(xxx_device) )
    {
        goto device_c_error;
    }
    printk("auto mknod success!\n");

    //-----------------   请在此添加您的初始化程序  -------------------//
        //如果需要做错误处理,请:goto xxx_error;   
     add_code_flag = 1;
    //------------------------  END  --------------------------------// 
    goto init_success;

dev_reg_error:
    printk("alloc_chrdev_region failed\n"); 
    return ret_v;
cdev_add_error:
    printk("cdev_add failed\n");
    unregister_chrdev_region(dev_num, 1);
    init_flag = 0;
    return ret_v;
class_c_error:
    printk("class_create failed\n");
    cdev_del(&xxx_cdev);
    unregister_chrdev_region(dev_num, 1);
    init_flag = 0;
    return PTR_ERR(xxx_class);
device_c_error:
    printk("device_create failed\n");
    cdev_del(&xxx_cdev);
    unregister_chrdev_region(dev_num, 1);
    class_destroy(xxx_class);
    init_flag = 0;
    return PTR_ERR(xxx_device);
//--------------------- 请在此添加您的错误处理内容 -------------------//
xxx_error:
    add_code_flag = 0;
    return -1;
//----------------------          END         ----------------------//
init_success:
    printk("xxx init success!\n");
    return 0;
}
//exit
static __exit void xxx_exit(void)
{
    printk("xxx drive exit...\n");  
    if(add_code_flag == 1)
    {   
        //------------   请在这里释放您的程序占有的资源   -------------//
        printk("free your resources...\n");                

        printk("free finish\n");                       
        //----------------------     END      ----------------------//
    }                               
    if(init_flag == 1)
    {
        //释放初始化使用到的资源
        cdev_del(&xxx_cdev);
    unregister_chrdev_region(dev_num, 1);
    device_unregister(xxx_device);
    class_destroy(xxx_class);
    }
}
/********************* module operations*************************/
//module loading
module_init(xxx_init);
module_exit(xxx_exit);

//some infomation
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("from Jafy");
MODULE_DESCRIPTION("xxx drive");
/***********************  The End *******************************/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值