一、如何对设备操作

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. SQL编程规范整理

    一.排版规范 1.代码缩进 对于判断.循环等处理使用字符缩进 缩进的空格最好不要使用TAB键 2.空格及换行 变量定义.相对独立的程序块等要单独成行,便于阅读 太长的程序(超过110列)应做换行处理 ...

  2. HTTP1.0、HTTP1.1、HTTP2.0的关系和区别

    一.汇总对比 HTTP1.0 无状态.无连接HTTP1.1 持久连接请求管道化增加缓存处理(新的字段如cache-control)增加Host字段.支持断点传输等(把文件分成几部分)HTTP2.0 二 ...

  3. Docker中Maven私服的搭建

    为何用到Maven私服? 在实际开发中,项目中可能会用到第三方的jar.内部通讯的服务接口都会打入到公司的私服中. 我们从项目实际开发来看: 一些无法从外部仓库下载的构件,例如内部的项目还能部署到私服 ...

  4. (13)使用python+flask实现树莓派的WEB控制

    https://blog.csdn.net/qq_34803821/article/details/86240096 如果你想在网页上点击按钮,并且让树莓派接收到响应,并做响应的处理,实现网页上与树莓 ...

  5. MongoDB远程连接-MongoDB Compass

    MongoDB Compass Community连接界面设置

  6. 20101010 exam

    目录 2018 10.10 exam 解题报告 T1:LOJ #10078 新年好 题目描述(原题来自:CQOI 2005): 输入格式: 输出格式: 样例输入: 样例输出: 数据范围与提示: 思路: ...

  7. nginx架构分析之 事件驱动模型

    事件驱动模型 事件驱动模型是实现异步非阻塞的一个手段.事件驱动模型中,一个进程(线程)就可以了. 对于web服务器来说,客户端A的请求连接到服务端时,服务端的某个进程(Nginx worker pro ...

  8. putty WinScp 免密登录远程 Linux

    该方法的原理是预先生成一对公钥和私钥,私钥以文件的形式保存在本地,公钥保存在远程机器上.这样每次登录只需指定私钥文件,远程机器通过比对公钥和私钥来验证登录的合法性. Putty 免密登录 第一步 生成 ...

  9. python字符串转整形异常

    python字符串转整形异常 问题 在使用int("xx")转化字符串为整形时,如果字符串是float形式,这样转化会异常 int('3.0') Traceback (most r ...

  10. fastjson WriteClassName,Double类型不打3.3D

    方式一: public class SerializeConfigX extends SerializeConfig { public SerializeConfigX() { put(Double. ...