字符驱动(按键)初始化函数分析:

 int charDrvInit(void)
 {

     devNum = MKDEV(reg_major, reg_minor);

     printk(KERN_EMERG"devNum is %d\r\n", devNum);
     if(OK == register_chrdev_region(devNum, subDevNum, DEVICE_NAME))//subdevnum:要申请的第一个次设备号
     {
         printk(KERN_EMERG"register_chrdev_region ok\r\n");
     }
     else
     {
         printk(KERN_EMERG"register_chrdev_region error\r\n");
         return ERROR;
     }
16
 /**
  * register_chrdev_region() - register a range of device numbers
  * @from: the first in the desired range of device numbers; must include
  *        the major number.
  * @count: the number of consecutive device numbers required
  * @name: the name of the device or driver.
  *
  * Return value is zero on success, a negative error code on failure.
  */
 int register_chrdev_region(dev_t from, unsigned count, const char *name) //count = 1
 {
     struct char_device_struct *cd;
 static struct char_device_struct {
     struct char_device_struct *next;
     unsigned int major;
     unsigned int baseminor;
     int minorct;
     ];
     struct cdev *cdev;        /* will die */
 } *chrdevs[CHRDEV_MAJOR_HASH_SIZE];

struct char_device_struct

     dev_t to = from + count;
     dev_t n, next;

     for (n = from; n < to; n = next) {
         next = MKDEV(MAJOR(n)+, );/*先得到下一个设备号(其实也是一个设备号,只不过此时的次设备号为0)并存储于next中*/
18         if (next > to) /*溢出的情况*/          /*判断在from的基础上再追加count个设备(dev_t to = from+count)是否已经溢出到下一个主设备号*/
             next = to;
/*           如果没有溢出(next小于to),那么整个for语句就只执行个一次__register_chrdev_region函数;
             否则当设备号溢出时,会把当前溢出的设备号范围划分为几个小范围,分别调用__register_chrdev_region函数。  */
 
 /*
  * Register a single major with a specified minor range.
  *
  * If major == 0 this functions will dynamically allocate a major and return
  * its number.
  *
  * If major > 0 this function will attempt to reserve the passed range of
  * minors and will return zero on success.
  *
  * Returns a -ve errno on failure.
  */
 static struct char_device_struct *
13 __register_chrdev_region(unsigned int major, unsigned int baseminor,
14                int minorct, const char *name)
 {
     struct char_device_struct *cd, **cp;
     ;
     int i;

     cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL);
     if (cd == NULL)
         return ERR_PTR(-ENOMEM);

     mutex_lock(&chrdevs_lock);

     /* temporary */
//此if语句目的在于如果主设备号为零,则自动分配主设备号(寻找设备号列表中的空的位置(从大到小))并返回
     ) {
         ; i > ; i--) {
             if (chrdevs[i] == NULL)
                 break;
         }

         ) {
             ret = -EBUSY;
             goto out;
         }
         major = i;
         ret = major;
     }
 //新元素赋值
     cd->major = major;
     cd->baseminor = baseminor;
     cd->minorct = minorct;
     strlcpy(cd->name, name, sizeof(cd->name));

     i = major_to_index(major);
 
 /* index in the above */
 static inline int major_to_index(unsigned major)
 {
     return major % CHRDEV_MAJOR_HASH_SIZE;
 }

//寻找新元素插入的位置

     for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
         if ((*cp)->major > major ||
             ((*cp)->major == major &&
              (((*cp)->baseminor >= baseminor) ||
               ((*cp)->baseminor + (*cp)->minorct > baseminor))))
             break;

     /* Check for overlapping minor ranges.  */
     if (*cp && (*cp)->major == major) {//如果当前元素存在并且主设备号和要添加的主设备号一致
         int old_min = (*cp)->baseminor;//更新旧的最小值,值为当前元素的次设备号
         ;////更新旧的最大值,值为当前次设备号+要申请号的设备个数-1,-1是因为从0开始的次设备号
         int new_min = baseminor;//新的最小值为要添加的次设备号
         ;
 //新的最大值为要添加的次设备号+要申请号的设备个数-1,-1是因为次设备号从0开始
         /* New driver overlaps from the left.  */
//显然生成的新的值必须要大于旧的最大值或者小于旧的最小值
         if (new_max >= old_min && new_max <= old_max) {
             ret = -EBUSY;
             goto out;
         }

         /* New driver overlaps from the right.  */
         if (new_min <= old_max && new_min >= old_min) {
             ret = -EBUSY;
             goto out;
         }
     }

     cd->next = *cp;
     *cp = cd;
     mutex_unlock(&chrdevs_lock);
     return cd;
 out:
     mutex_unlock(&chrdevs_lock);
     kfree(cd);
     return ERR_PTR(ret);
 }

         if (IS_ERR(cd))
             goto fail;
     }
     ;
 fail:
     to = n;
     for (n = from; n < to; n = next) {
         next = MKDEV(MAJOR(n)+, );
         kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n));
     }
     return PTR_ERR(cd);
 }

     gDev = kzalloc(sizeof(struct cdev), GFP_KERNEL);
     gFile = kzalloc(sizeof(struct file_operations), GFP_KERNEL);

     gFile->open = butsOpen;
 //注册设备函数到file_operations结构体gFile

    //gDev->owner = THIS_MODULE;
     gFile->owner = THIS_MODULE;
     cdev_init(gDev, gFile);
 //在cdev结构体中添加指针指向file_operations结构体gFile
     cdev_add(gDev, devNum, );
 //建立设备号与cdev结构体联系
     printk(KERN_EMERG"button driver initial done...\r\n");
     ;
 }

Linux字符设备驱动--No.3的更多相关文章

  1. 深入理解Linux字符设备驱动

    文章从上层应用访问字符设备驱动开始,一步步地深入分析Linux字符设备的软件层次.组成框架和交互.如何编写驱动.设备文件的创建和mdev原理,对Linux字符设备驱动有全面的讲解.本文整合之前发表的& ...

  2. Linux字符设备驱动结构(一)--cdev结构体、设备号相关知识机械【转】

    本文转载自:http://blog.csdn.net/zqixiao_09/article/details/50839042 一.字符设备基础知识 1.设备驱动分类 linux系统将设备分为3类:字符 ...

  3. Smart210学习记录----beep linux字符设备驱动

    今天搞定了beep linux字符设备驱动,心里还是很开心的,哈哈...但在完成的过程中却遇到了一个非常棘手的问题,花费了我大量的时间,,,, 还是把问题描述一下吧,好像这个问题很普遍的,网上许多解决 ...

  4. Linux字符设备驱动实现

    Linux字符设备驱动实现 要求 编写一个字符设备驱动,并利用对字符设备的同步操作,设计实现一个聊天程序.可以有一个读,一个写进程共享该字符设备,进行聊天:也可以由多个读和多个写进程共享该字符设备,进 ...

  5. Linux字符设备驱动基本结构

    1.Linux字符设备驱动的基本结构 Linux系统下具有三种设备,分别是字符设备.块设备和网络设备,Linux下的字符设备是指只能一个字节一个字节读写的设备,不能随机读取设备内存中某一数据,读取数据 ...

  6. (57)Linux驱动开发之三Linux字符设备驱动

    1.一般情况下,对每一种设备驱动都会定义一个软件模块,这个工程模块包含.h和.c文件,前者定义该设备驱动的数据结构并声明外部函数,后者进行设备驱动的具体实现. 2.典型的无操作系统下的逻辑开发程序是: ...

  7. Linux字符设备驱动框架

    字符设备是Linux三大设备之一(另外两种是块设备,网络设备),字符设备就是字节流形式通讯的I/O设备,绝大部分设备都是字符设备,常见的字符设备包括鼠标.键盘.显示器.串口等等,当我们执行ls -l ...

  8. Linux 字符设备驱动模型

    一.使用字符设备驱动程序 1. 编译/安装驱动 在Linux系统中,驱动程序通常采用内核模块的程序结构来进行编码.因此,编译/安装一个驱动程序,其实质就是编译/安装一个内核模块 2. 创建设备文件 通 ...

  9. linux字符设备驱动学习笔记(一):简单的字符设备驱动

    最近在鼓捣lnux字符设备驱动,在网上搜集的各种关于linux设备驱动的代码和注释,要么是针对2.4的,要么是错误百出,根本就不能运行成功,真希望大家在发博客的时候能认真核对下代码的正确性,特别是要把 ...

  10. Linux字符设备驱动

    一.字符设备基础 字符设备 二.字符设备驱动与用户空间访问该设备的程序三者之间的关系 三.字符设备模型 1.Linux内核中,使用 struct cdev 来描述一个字符设备 动态申请(构造)cdev ...

随机推荐

  1. 微软操作系统 Windows Server 2012 R2 官方原版镜像

    微软操作系统 Windows Server 2012 R2 官方原版镜像 Windows Server 2012 R2 是由微软公司(Microsoft)设计开发的新一代的服务器专属操作系统,其核心版 ...

  2. 最短路径-Dijkstra算法与Floyd算法

    一.最短路径 ①在非网图中,最短路径是指两顶点之间经历的边数最少的路径. AE:1    ADE:2   ADCE:3   ABCE:3 ②在网图中,最短路径是指两顶点之间经历的边上权值之和最短的路径 ...

  3. Linux账号管理和ACL

    by zjmyster version :1.2 Linux账号管理和ACL权限设置: 主要相关配置文件:/etc/passwd /etc/shadow /etc/group /etc/gshadow ...

  4. CSAPP buffer lab记录——IA32版本

    CSAPP buffer lab为深入理解计算机系统(原书第二版)的配套的缓冲区溢出实验,该实验要求利用缓冲区溢出的原理解决5个难度递增的问题,分别为smoke(level 0).fizz(level ...

  5. 可变长度参数以及foreach循环原理

    语法糖 接下来几篇文章要开启一个Java语法糖系列,所以首先讲讲什么是语法糖.语法糖是一种几乎每种语言或多或少都提供过的一些方便程序员开发代码的语法,它只是编译器实现的一些小把戏罢了,编译期间以特定的 ...

  6. oracle 10g将数据导入到指定表空间的步骤

    --创建临时表空间 create temporary tablespace  yhtemp tempfile 'D:/oracle/oradata/Oracle10g/yhtemp.dbf' size ...

  7. bzoj2336 [HNOI2011]任务调度

    Description 正解:搜索+随机化. 先写个搜索,枚举所有没有要求的任务属于哪一种任务,然后再用爬山来更新最优解. 具体来说就是先把所有先做任务$A$的按照$a$时间从大到小排序,先做任务$B ...

  8. FreeRTOS 查询任务 剩余的栈空间的 方法

    FreeRTOS 源码下载地址 1.官方文档提供了   函数  用来查询  任务 剩余   栈 空间,首先是看官方的文档解释(某位大神 翻译 的 官方文档.) 参数解释:     xTask:被查询任 ...

  9. 01-Python学习笔记-基础语法

    Python标识符 -d           在解析时显示调试信息 -O           生成优化代码 ( .pyo 文件 ) -S           启动时不引入查找Python路径的位置 - ...

  10. STM32之系统时钟

    转载:http://www.openedv.com/posts/list/302.htm 时钟系统是处理器的核心,所以在学习STM32所有外设之前,认真学习时钟系统是必要的,有助于深入理解STM32. ...