一、如何对设备操作

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. 将Eclipse设置为黑色主题

    将Eclipse设置为黑色主题 觉得黑色的主题&配色很高大上,于是花了点时间实践出下面一种方法. 修改代码编辑区配色 修改整个软件主题 先上成果图: 但是进度条依旧是白色的,不知道怎么弄了╮( ...

  2. CF1102D-Balanced Ternary String-(贪心)

    http://codeforces.com/problemset/problem/1102/D 题意: 有n个字符,只能为012,现要通过变换让012的数量相等,并且使字典序最小. 解题: 由样例可以 ...

  3. Jupyter的快捷键使用

    命令模式 (按键 Esc 开启) Enter : 转入编辑模式 Shift-Enter : 运行本单元,选中下个单元 Ctrl-Enter : 运行本单元 Alt-Enter : 运行本单元,在其下插 ...

  4. html 复习(for循环不同内容的div)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  5. MYSQL中group_concat( )函数中参数的排序方法

    使用mysql中的group_concat( )函数连接指定字段时,可以先对该字段进行排序. PS:是因为二刷mysql的51道题的第12题遇到的:查询和" 01 "号同学学习的课 ...

  6. vim文本编辑器——替换、保存退出

    1.替换: (1)全文替换: 利用查询命令查询: (2)指定替换的字符串的范围: 2.保存.退出命令: (1)在命令行模式下保存(:w) (2)另存为(:w+要保存的文件的路径) (3)保存退出(:w ...

  7. 在IDEA编辑器中建立Spring Cloud的子项目包(构建微服务)

    本文介绍在IDEA编辑器中建立Spring Cloud的子项目包 总共分为5个包: 外层使用maven quickstart建立,子modules直接选择了springboot

  8. 大厂HR面试必备ES6中的深入浅出面试题知识点

    ESMAScript6简介,ES6是JavaScript语言的下一代标准,目的是让JavaScript语言可以写复杂的大型应用程序,成为企业级语言.那么ECMAScript和JavaScript的关系 ...

  9. 原生js实现元素类名的判存、添加和移除

    1.addClass:为指定的dom元素添加样式. 2.removeClass:删除指定dom元素的样式. 3.toggleClass:如果存在(不存在),就删除(添加)一个样式. 4.hasClas ...

  10. 淘宝接口-IP返回运营商

    #!/usr/bin/evn python# -*- coding:utf-8 -*-import jsonimport urllib2import datetimeimport reimport Q ...