驱动编写的新接口

来源:互联网 发布:小麦淘商城 知乎 编辑:程序博客网 时间:2024/06/14 18:29

新接口函数的用法:


主次设备号的理解: 

主设备号是:某一类设备 

次设备号是:这一类中的某一个设备

主设备号 次设备号 设备三者之间的关系

#define MAJOR(dev)((unsigned int) ((dev) >> MINORBITS))
#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK))
#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi))

整个构成:

整个的驱动注册分为两步: 第一步:主设备号的申请   第二步file_operation这个结构体的注册

第一步:手动申请主设备号(方式一)

1.1dev_t devid;  //定义这个变量将来作为输入型参数

1.2devid = MKDEV(major, 0);  //从 主设备号major 从设备号为0开始  (可以写程序验证)

     register_chrdev_region(devid, count, name); 相当于向内核申请一个主设备号
     count 表示个数
     name  表示名字

1.3到达这一步:主设备+次设备号申请结束

第一步:系统自动分配主设备号(方式二)

1.int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)

            例如:alloc_chrdev_region(&devid, unsigned baseminor, unsigned count, DEVNAME);

2.获得主设备号 

major = MAJOR(devid); //主设备号  

 --------------------------------达到这理 主次设备号已经解决主次设备号的问题:


第二步: 向系统注册设备驱动  (file_opretion)

static struct cdev pc8736x_gpio_cdev;//作为输入性参数 在函数退出的事情需要使用

cdev_init(&pc8736x_gpio_cdev, &pc8736x_gpio_fileops);

cdev_add(&pc8736x_gpio_cdev, devid, count);
 

第一步和第二步这个注册结束


第三步:

退出函数:

cdev_del(&fif_cdev); 
unregister_chrdev_region(devid, 255);
  

       //void unregister_chrdev_region(dev_t from, unsigned count) 函数原型:count: the number of device numbers to unregister

----------------------------------------------------------------------------------------------------------------------------------------------------------

源码分析:

老接口的源码分析:  register_chrdev (0, "twl", &twl_fops) 这个例子作为函数的嵌入点:

     参数:major=0    name = "twl"   fops = &twl_fops 
static inline int register_chrdev(unsigned int major, const char *name,const struct file_operations *fops)
参数:major = 0    name = "twl"  fops = &twl_fops
 //这里名字并没有在/dev下创建设备, 某块的名字
__register_chrdev(major, 0, 256, name, fops);
struct char_device_struct *cd; //表示主次设备号
struct cdev *cdev;//
 /*
 //
static struct char_device_struct {
struct char_device_struct *next; //用来做链表
unsigned int major;//主设备号
unsigned int baseminor;//次设备号头
int minorct; //次设备号有多少个
char name[64];//驱动的名字
struct cdev *cdev;/* will die *///存储内部的东西
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
每一个结构体表示一个设备  
 */
 /*
struct cdev {
struct kobject kobj;
struct module *owner; //用来记录把模块挂钩
const struct file_operations *ops;  //file_operations  
struct list_head list;
dev_t dev; //内核中的设备号  主设备号  +  次设备号
unsigned int count; //计数  主要是用来记录 这个设备被调用了几次
};
 */  
以上都是相应的数据结构 
cd = __register_chrdev_region(major, baseminor, count, name); 
struct char_device_struct *cd, **cp;  //定义一个指针
//分配一个内存空间(类型是: struct char_device_struct)
cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
找到之后返回
填充这个结构体

cdev = cdev_alloc();  //创建一个struct cdev 这才是表示一个设备

//填充这个结构体
cdev->owner = fops->owner;
cdev->ops = fops;
kobject_set_name(&cdev->kobj, "%s", name);
//用激活这个设备主次设备号 和 file_operations结构体挂接
err = cdev_add(cdev, MKDEV(cd->major, baseminor), count);//激活


cd->cdev = cdev;
return major ? 0 : cd->major;


总结:
第一步:创建struct char_device_struct *cd; //表示主次设备号 这样的结构体

第二步:在系统中256中寻找一个空位。
---------这样就可以填充主次设备号了----
第三步:struct cdev *cdev;创建这一个并且填充
第四步:把cdev和第二步创建的主次设备号挂接
return  
核心:struct char_device_struct *cd;这个结构体

新接口的源码分析:

MKDEV(171, 0) 
举例:register_chrdev_region(MKDEV(171, 0), 256, "ieee1394")
参数:  from = MKDEV(171, 0) 
参数:  count= 256
参数:  name = "ieee1394"
第一步主次设备号的问题:
int register_chrdev_region(dev_t from, unsigned count, const char *name)
参数:  from = MKDEV(171, 0) 
参数:  count= 256
参数:  name = "ieee1394"
//注意:dev_t的数据结构是一个 u32 long型
for (n =from ; n < to; n = next)
{
循环一次调用:__register_chrdev_region(MAJOR(n), MINOR(n),
      next - n, name);
}

第二步:
static struct cdev fif_cdev; //创建 

cdev_init(&fif_cdev, &seconde_fops);
//主要是把seconde_fops 挂接到了fif_cdev上
adev->cdev.owner = THIS_MODULE;   
cdev_add(&fif_cdev, devid, 255);//激活


总结:内核是如何申请和释放资源的:

思想:
内核中有kzalloc分配内存并且free,但是kzalloc和free并不在一个函数中,
甚至不是由同一个人写的。所以kzalloc分配了一段内存,但是这段内存一般都要等到
其他代码,或者其他人来释放。 kzalloc 和 free很难对应。这样内核就无法维护。
例如:只要你定义了一个内存(通过kzalloc),如果一不小心没有释放,那么就会导致
内存空间浪费

内核提供的解决思路:
当有人用的时候,这个资源+1 ,当没有人用的时候 这个资源减1
当这个资源减到0时,就会把这个资源删除
每次使用的时候就会来检测。这就的优势,导致你可以不用再管谁创建和删除了
这样内存释放和回收都可以进行自动化了




















原创粉丝点击