Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65025
  • 博文数量: 21
  • 博客积分: 290
  • 博客等级: 二等列兵
  • 技术积分: 286
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-30 16:16
文章分类
文章存档

2019年(3)

2017年(1)

2012年(17)

我的朋友

分类: LINUX

2012-03-31 19:56:57

    1、数据结构说明
 
    我们在分析一个内核驱动程序时,总是从数据结构开始分析,那我们驱动程序也
 
应该如此:从定义数据结构-->初始化数据结构--> 申请设备号-->通知内核-->创建
 
件节点。【最基本的路线】
 
   那我们应该来看看字符驱动的三个重要的数据结构:struct inode;struct
 
file; struct file_operations。图下图:
         
       图1:三个重要又基本的数据结构关系图[图摘自LINUX设备驱动开发详解]
   
    从左往右分析:
   
    1)一个字符设备最基本应该对应一个 struct cdev;它的作用是什么?
   
    2) struct cdev 含有dev_t 设备号成员、struct file_operations
   
    3) struct file_operations 都是系统调用的函数接口,操作方法==>以实现
 
与用户空间的通信。
   
    4)通知和加载、卸载都是与 struct cdev 紧密相关的,可见它的作用之大。
   
    5)用户空间的系统调用,最终是在内核中struct file_operations结构中实现。
   
   从中我们也可以看到如何写一个简单的字符设备驱动程序:
 
字符设备创建
[1]【设备编号注册】
[2]【设备结构分配和初始化】
[3]【文件操作接口】实现
[4]【字符设备添加】
[5]【设备文件节点创建】
 
字符设备销毁
[1] 【设备文件节点销毁】
[1] 【字符设备删除】
[2] 【设备编号回收】
 
/**********************函数说明*********************/
【设备编号获取】
[头文件]
#include      dev_t定义
#include     操作宏定义
 
/*
 * @brief     获取主编号
 * @param[in] dev       设备编号
 * @return    主编号
 */
MAJOR(dev_t dev);
 
/*
 * @brief      获取次编号
 * @param[in]  dev       设备编号
 * @return     次编号
 */
MINOR(dev_t dev);
   
/*
 * @brief      合成设备编号
 * @param[in]  major      主编号
 * @param[in]  minor      次编号
 * @return     设备编号  
 */
MKDEV(major, minor);  
 
[头文件]
#include

/*
 * @brief      获取次编号
 * @param[in]  inode      设备文件节点
 * @return     次编号
 */
static inline unsigned iminor(const struct inode *inode);
/*
 * @brief      获取主编号
 * @param[in]  inode      设备文件节点
 * @return     主编号
 */
static inline unsigned imajor(const struct inode *inode);
 
【设备编号注册】
[头文件]
#include  
/*
 * @brief      分配设备编号
 * @param[in]  first  起始设备编号
 * @param[in]  count  分配编号数量
 * @param[in]  name   设备名称(在/proc/devices文件中可见)
 * @return   =0       分配成功
 *           <0       错误码
 */
int register_chrdev_region(dev_t first, unsigned int count, char 
                          *name);
 
/*
 * @brief       动态分配设备编号
 * @param[out]  dev        设备编号
 * @param[in]   firstminor 分配第一个次编号
 * @param[in]   count      分配编号数量
 * @param[in]   name       设备名称(在/proc/devices文件中可见)
 * @return      == 0       分配成功
 *              <  0       错误码
 */
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,   
                       unsigned int count, char *name);
 
//////////////////////////////////////
为何要采用动态而非静态的呢?
动态申请设备号:内核自动帮我们获取空闲的设备号,无需人工去查阅系统我们预留哪些设备号。
//////////////////////////////////////
【设备编号回收】
[头文件]
#include
/*
 * @brief   回收设备编号
 * @param[in]  first      第一个次编号
 * @param[in]  count      分配编号数量
 */
void unregister_chrdev_region(dev_t first, unsigned int count); 
 
【设备结构分配和初始化】
[头文件]
#include
/*
 * @brief    动态分配struct cdev结构(描述一个字符设备)
 * @return   struct cdev结构指针
 */
struct cdev *cdev_alloc(void);
 
/*
 * @brief      初始化struct cdev结构
 * @param[in]  cdev   struct cdev结构已经定义存在
 * @param[in]  fops   驱动操作接口,为文件操作提供响应
 * @notes   函数会自动做cdev->ops = fops;但是没有
   dev->cdev.owner = THIS_MODULE;
 */
void cdev_init(struct cdev *cdev, struct file_operations *fops);
 
【字符设备添加】
[头文件]
#include
/*
 * @brief      增加一个字符设备到系统
 * @param[in]  p      描述字符设备的struct cdev结构
 * @param[in]  dev    关联到这个设备的第一个设备号
 * @param[in]  count  关联到这个设备的设备号个数
 * @return     == 0   添加成功
 *             < 0    错误码
 * @notes   函数执行成功后,立即可以使用该字符设备,也就是说调用这个之前设备驱动已经完全就绪
 */
int cdev_add(struct cdev *p, dev_t dev, unsigned count);
 
【字符设备删除】
[头文件]
#include
/*
 * @brief      删除一个字符设备
 * @param[in]  cdev  描述字符设备的struct cdev结构
 */
void cdev_del(struct cdev *dev);

【设备文件节点创建】
[头文件]
#include
/*
 * @brief      建立一个类结构
 * @param[in]  owner     模块所有者
 * @param[in]  name      类名
 * @return   类结构
 *     IS_ERR(返回值)    判断是否是错误码
 *     PTR_ERR(返回值)   取得错误码
 */
struct class *class_create(struct module *owner, const char *name);
 
/*
 * @brief   建立设备并且注册它到sysfs中
 * @param[in]  class     设备所要注册到的类
 * @param[in]  parent    父设备
 * @param[in]  devt      字符设备号
 * @param[in]  drvdata   驱动私有数据
 * @param[in]  fmt       格式化的设备名
 * @return   返回设备结构
 *     IS_ERR(返回值)    判断是否是错误码
 *     PTR_ERR(返回值)   取得错误码
 */
struct device *device_create(struct class *class, struct   
      device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
 
【设备文件节点销毁】
[头文件]
#include
/*
 * @brief      设备销毁
 * @param[in]  class      设备所属类
 * @param[in]  devt       设备号
 */
void device_destroy(struct class * class, dev_t devt);
 
/*
 * @brief      类销毁
 * @param[in]  class      要销毁的类
 */
void class_destroy (struct class * cls); 
   
 
阅读(1464) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

cyycyh2012-04-05 01:36:59

星期五啦: 好复杂的数据结构啊!.....
这个图主要说明struct inode 和 struct file 及struct cdev 这三者的关系;你一个一个结构去看,最后在把他们的关系想一想,看能不能比较清楚哦 嘻嘻

星期五啦2012-04-04 21:58:37

好复杂的数据结构啊!