一、如何对设备操作

linux中对设备进行操作是通过文件的方式进行的,包括open、read、write。
对于设备文件,一般称其为设备节点,
节点有一个属性是设备号(主设备号、次设备号),其中主设备号将设备文件与驱动模块对应起来

当我们open一个设备节点时,告诉了kernel要操作的是是主设备号为XX的节点,然后kernel会通过过XX来寻找合适的内存模块,进而调用内存模块中定义的open函数

由于操作节点之前kernel就需要有主设备号的信息,因此主设备号的申请、具有该主设备号的字符设备的添加都需要在驱动模块的初始化函数中执行

二、主设备号的申请

建议采用动态申请的主设备号的方式,linux中有很多设备,每一个设备对应着一个主设备号,动态申请是由内核分配一个没用的主

设备号,
动态申请函数为alloc_chrdev_region,相对应的释放函数为unregister_chrdev_region。
申请完后,可以从/proc/devices中读到分配的主设备号,后面建立设备节点时还需要用到

三、向kernle添加字符设备

上一步向内核申请了主设备号,就可以向kernel中添加字符设备了
kennel中一个字符设备对应了一个结构体cdev,这个结构体中定义了对字符设备的操作方式file_operations(包括open、read、write),这些操作方式也需要在驱动模块中事先定义好。

字符设备结构体cdev的添加步骤:
cdev初始化:cdev_init,该函数将file_operations与cdev对应起来
向kernel添加:cdev_add,该函数将主设备号与cdev结构体对应起来

当对open设备节点时,首先通过节点找到主设备号,然后再kernel中搜索与主设备号相对应的字符设备cdev,然后动过cdev中file_operations结构体定义的open方法(这个open是需要自己实现的)

四、3个重要的结构体

一个是file_operations,这里面主要包含了驱动的主要实现方法
一个是inode,这个是节点的信息,包含了主设备号和cdev结构体
一个是file,当节点首次被打开时,就会在内核中创建一个file结构体,file结构其充当了file_operations中方法的纽带,要不然read和wirte方法怎么知道操作的是那个设备的数据。

file中的自定义内容(驱动需要的数据)一般是在open中定义,然后read和write就可以操作自定义的数据了。

下面是一个简单的实例,可以看到驱动是怎样把自定义的open方法和主设备号对应起来的

#include <linux/module.h>  /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。*/   

#include <linux/init.h>  

#include <linux/fs.h> //设备号相关函数  

#include <linux/slab.h> //内存分配相关函数  

#include <linux/types.h>  

#include <linux/kdev_t.h>//设备号相关函数  

#include <linux/cdev.h>//字符设备头文件  

#include <linux/module.h>  

  

struct char_dev  

{  

    int size;  

    char *data;  

    struct cdev cdev;//内核中的字符设备  

};  

  

int major = 0;  

int minor = 0;  

struct char_dev char_devices;  

  

int char_open(struct inode *inode, struct file *filep)  

{  

    int Major = 0;  

    Major = MAJOR(inode->i_rdev);  

    printk("open my_char_dev major: %d\n", Major);  

      

    return 0;  

}  

  

struct file_operations char_fops = {  

    .owner = THIS_MODULE,  

    .open = char_open,  

};  

  

  

  

  

static void char_exit(void) //如果init函数中调用了该函数,则不应有 __exit  

{  

    dev_t dev;  

    printk("char device driver exit \n");  

    //释放设备号  

    dev = MKDEV(major, minor);  

    unregister_chrdev_region(dev, 1);  

    printk("release major %d\n", major);  

      

    //释放内存  

    if(char_devices.data){  

        kfree(char_devices.data);  

    }  

      

    //从内核中删除字符设备  

    cdev_del(&(char_devices.cdev));  

}  

  

static int __init char_init(void)//__init一个标记,表明是初始化函数  

{  

    //初始化的代码  

    dev_t dev;  

    int result;   

    printk("char device driver init \n");  

      

    //动态向内核申请设备号      

    result = alloc_chrdev_region(&dev, 0, 1, "my_char_dev");  

    major = MAJOR(dev);  

    minor = MINOR(dev);  

    printk("alloc major %d\n", major);  

    if (result < 0) {  

        printk(KERN_WARNING "my_char_dev: can't get major %d\n", major);  

        return result;  

    }  

      

    //为设备分配一块内存  

    char_devices.size = 100;  

    char_devices.data = (char*)kmalloc(char_devices.size, GFP_KERNEL);  

    if (!char_devices.data) {  

        result = -ENOMEM;  

        goto fail;  //不能直接退出函数,需要释放设备号  

    }  

      

    //向内核中添加字符设备cdev  

    cdev_init(&(char_devices.cdev), &char_fops);  

    char_devices.cdev.owner = THIS_MODULE;  

    char_devices.cdev.ops = &char_fops;  

    result = cdev_add(&(char_devices.cdev), dev, 1);  

    if((result < 0)) {  

        printk(KERN_WARNING "Error %d adding my_char_dev\n", result);  

        goto fail;  

    }  

  

    return 0; //成功  

fail:  

    char_exit();  

    return result;  

}  

  

MODULE_LICENSE("Dual BSD/GPL");  

//当模块被加载时,执行moudle_init函数,该函数会调用初始化函数  

module_init(char_init);  

//模块卸载时,调用,释放资源  

module_exit(char_exit);

KDIR=/usr/src/linux-headers-$(shell uname -r)

PWD=$(shell pwd)

obj-m = CharDevice.o

all:
$(MAKE) -C $(KDIR) M=$(PWD)

注:驱动insmod后,通过/proc/devices查看主设备号,然后通过mknod在/dev下创建设备节点,注意保持主设备好的一致,当前的节点只支持open方法,可以在demsg中进行验证。

[ARM-Linux开发] 主设备号--驱动模块与设备节点联系的纽带的更多相关文章

  1. linux设备管理之主设备号与次设备号

    主设备号和次设备号 一个字符设备或者块设备都有一个主设备号和次设备号.主设备号和次设备号统称为设备号.主设备号用来表示一个特定的驱动程序.次设备号用来表示使用该驱动程序的其他设备.(主设备号和控制这类 ...

  2. Linux:主设备号和次设备号

    http://www.linuxidc.com/Linux/2011-03/33863.htm     Linux的设备管理是和文件系统紧密结合的,各种设备都以文件的形式存放在/dev目录下,称为设备 ...

  3. Linux chroot 并使用之前系统设备节点

    /********************************************************************************* * Linux chroot 并使 ...

  4. 在Ubuntu上建立Arm Linux 开发环境

    我使用的是友善2410的板子,以前都是用Fedora,现在家里的电脑被我转为Linux专用的了,装的是Ubuntu.但是嵌入式还是要玩的,在装载过程中也遇到一些小麻烦.在此记录一下,一来自己比较健忘, ...

  5. linux驱动之设备号与创建设备节点

    设备号: 1.自己主动分配 major = register_chrdev(0,"first_drv",&first_sdv_fops);//注冊 注冊设备时给设备号写0, ...

  6. 成功移植SQLite3到ARM Linux开发板

    SQLite,是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了 ...

  7. minigui移植到arm linux开发板上无法执行

    要保证目录下有该文件 /etc/MiniGUI.cfg 复制过程使用cp –af 强制复制

  8. 嵌入式Linux学习笔记(三) 字符型设备驱动--LED的驱动开发

    在成功构建了一个能够运行在开发板平台的系统后,下一步就要正式开始应用的开发(这里前提是有一定的C语言基础,对ARM体系的软/硬件,这部分有疑问可能要参考其它教程),根据需求仔细分解任务,可以发现包含的 ...

  9. 【Linux开发】linux设备驱动归纳总结(三):1.字符型设备之设备申请

    linux设备驱动归纳总结(三):1.字符型设备之设备申请 操作系统:Ubunru 10.04 实验平台:S3C2440 + linux2.6.29内核 注:在今后驱动程序的学习中经常需要查看内核源代 ...

随机推荐

  1. Boring counting HDU - 3518 (后缀数组)

    Boring counting \[ Time Limit: 1000 ms \quad Memory Limit: 32768 kB \] 题意 给出一个字符串,求出其中出现两次及以上的子串个数,要 ...

  2. leetcode 合并重叠区间变异 合并多个时间段 取并集

    public class Solution { public static ArrayList<Interval> merge(ArrayList<Interval> inte ...

  3. csp-s 考前刷题记录

    洛谷 P2615 神奇的幻方 洛谷 P2678 跳石头 洛谷 P1226 [模板]快速幂||取余运算 洛谷 P2661 信息传递 LOJ P10147 石子合并 LOJ P10148 能量项链 LOJ ...

  4. [RN] React Native 封装选择弹出框(ios&android)

    之前看到react-native-image-picker中自带了一个选择器,可以选择拍照还是图库,但我们的项目中有多处用到这个选择弹出框,所以就自己写了一下,最最重要的是ios和Android通用. ...

  5. win10系统2分钟睡眠

    https://blog.csdn.net/widenstage/article/details/78982722 HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSe ...

  6. zabbix监控ESXI主机

    ESXI6.0默认SSH关闭的,打开SSH的方法如下图: SSH打开后,主机会有警报,关闭警报的方法如下图 esxcli system  snmp  set  --communities  publi ...

  7. ubuntu之路——day17.3 简单的CNN和CNN的常用结构池化层

    来看上图的简单CNN: 从39x39x3的原始图像 不填充且步长为1的情况下经过3x3的10个filter卷积后 得到了 37x37x10的数据 不填充且步长为2的情况下经过5x5的20个filter ...

  8. ELK(Elasticsearch + Logstash + Kibana) 日志收集

    单体应用或微服务的场景下,每个服务部署在不同的服务器上,需要对日志进行集重收集,然后统一查看所以日志. ELK日志收集流程: 1.微服务器上部署Logstash,对日志文件进行数据采集,将采集到的数据 ...

  9. uniapp - 点赞动画插件

    更新时间: 2019/8/31 - 点击下载demo 点赞动画插件配合animate.css更好用! 该组件参考于:https://github.com/OYsun/VueStar/tree/mast ...

  10. [转]详解vue父组件传递props异步数据到子组件的问题

    原文地址:https://www.cnblogs.com/goloving/p/9114389.html 案例一 父组件parent.vue // asyncData为异步获取的数据,想传递给子组件使 ...