• 字符设备驱动框架的搭建


    #include 
    #include 
    #include 
    #include 
    
    
    #define CHRDEVBASE_MAJOR    200
    #define CHRDEVBASE_NAME     "chrdevbase"
    
    static int chrdevbase_open(struct inode *inode, struct file *filp) {
          printk ( " chrdevbase open \r\n" ) ;
          return  0 ;
    }
    static int chrdevbase_release(struct inode *inode, struct file *filp) {
          printk ( " chrdevbase close \r\n") ;
          return  0 ;
    }
    
    static ssize_t chrdevbase_read(struct file *filp, __user char *buf, size_t count, loff_t *ppos)
    {
            printk ( " chrdevbase read \r\n" ) ;
            return  0 ;
    }
    
    static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
    {
            printk ( " chrdevbase write \r\n" ) ;
            return  0 ;
    }
    
    //字符操作的 集合
    static struct file_operations chrdevbase_fop = {
    	.owner		= THIS_MODULE        ,
    	.open   	= chrdevbase_open    ,      //
    	.release    = chrdevbase_release ,
        .read       = chrdevbase_read    ,
        .write      = chrdevbase_write   ,
    };
    
    static int __init chrdevbase_init(void)
    {   
    
        int ret = 0;
        printk("chrdevbase_init\r\n");
        ret =  register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fop);
        if( ret < 0) {
              printk("chrdevbase_init failed\r\n");
        }
        return 0;
    }
    // unregister_chrdev(major, DEVICE_NAME);
    static void __exit chrdevbase_exit(void)
    {
    /* 注销字符设备驱动 */
       printk("chrdevbase_exit \r\n");
       unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME);
    }
    module_init(chrdevbase_init)   ;
    module_exit(chrdevbase_exit)   ;
    MODULE_LICENSE ( "GPL") ;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    App.C

    #include "stdio.h"
    #include "unistd.h"
    #include "sys/types.h"
    #include "sys/stat.h"
    #include "fcntl.h"
    #include "stdlib.h"
    #include "string.h"
    
    
    /*----------------------------------------------------------------
     
    argc :     应用程序的参数个数
    *argv[] :  具体的参数内内容
    chrdevbaseAPP  
    
    */
    
    int main ( int argc , char *argv[])
    {
        int fd  ;
        char *filename ;
    
        int  retvalue ;
        char readbuf[100]  ;
        char writebuf[100] ; 
        
      
        filename = argv [1] ;
        fd = open(filename,O_RDWR) ;
        if( fd < 0 )
        {
           printf ( "can not open file  %s \r\n ",filename) ;
           return  -1 ;
        }
        
        retvalue = read (fd ,readbuf , 50) ;
        if( retvalue < 0 ) {
            printf("read file %s failed!\r\n", filename);
        }
        else 
        {
            printf("read data:%s\r\n",readbuf);
        }
        retvalue = write( fd , writebuf ,50 );
        if(retvalue < 0) {
            printf("write file %s failed!\r\n", filename);
        }
    
        retvalue = close (fd) ;
        if(retvalue < 0) {
            printf("Can't close file %s \r\n", filename);
            return -1 ;
        }
        return   0 ;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    一、字符设备驱动框架

    字符设备驱动的编写主要就是驱动对应的open,close,read……。其实,就是file_operations结构体的成员变量的实现。

    二、驱动模块的的加载与卸载
    Linux驱动程序可以编译到kernel里面,也就是zlmage,也可以编译为模块.ko。测试的时候只需要加载.ko 模块就可以。
    编写驱动的时候注意事项:
    1.编写驱动的时候需要用到linux内核源码,因此需要解压linux内核源码,编译Linux内核源码。得到zlmage 和dtb。需要使用编译后的到的zlmage 和dtb 启动系统。
    2.从SD 卡启动,SD 卡烧写了 uboot。uboot 过 tftp 从 ubuntu 里面获取 zimage 和
    dtb,rootfs 也是通过 nfs 挂载。
    3.设置bootcmd 和 bootargs。bootargs=console=ttymxc0,115200 nfsroot=192.168.1.66:/home/zzk/linux/nfs/rootfs。
    ip=192.168.1.50:192.168.1.66:192.168.1.1:255.255.255.0:eth0:off
    bootcmd=tftp 80800000 zlmagetftp 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000-83000000;
    4.将编译出来的.ko 文件放到根文件系统里面。加载驱动会用到加载命令: insmod,
    modbrobe。移除驱动使用命令rmmod。

    三、设备号
    dev_t 其实就是 unsigned int 类型,是一个 32 位的数据类型。这 32 位的数据构
    成了主设备号和次设备号两部分,其中高 12 位为主设备号,低 20 位为次设备号。因此 Linux 系统中主设备号范围为 0~4095,所以大家在选择主设备号的时候一定不要超过这个范围。

    四、其他:

    创建的模块:
    Make

    交叉编译: arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseAPP
    将APP编译好了。Ko的驱动模块也编译好了。进行拷贝到根文件系统中。

    sudo cp chrdevbase.ko chrdevbaseAPP /home/gz/linux/nfs/rootfs/lib/modules/4.1.15/ -f

    Cd lib/modules/4.1.15

    (删除之前的模块:rmmod chrdevbase)
    查看存在的模块:lsmod
    加载: modprobe chrdevbase.ko

    加载成功就不用这个了 (自动生成 modules.dep :depmod)
    查看设备号:cat /proc/devices

    配置设备节点:mknod /dev/chardevbase c 200 0

    运行APP进行测试:./chrdevbaseAPP /dev/chrdevbase 1

    如果测试后需要进行代码修改:
    Make
    arm-linux-gnueabihf-gcc chrdevbaseApp.c -o chrdevbaseAPP
    卸载mod: rmmod chrdevbase
    加载: modprobe chrdevbase.ko
    mknod /dev/chardevbase c 200 0

    调试出现的问题
    出现rmmod led.ko,然后查看设备号cat /proc/devices 还存在:
    在这里插入图片描述
    因为

    static void __exit led_exit(void)
    {
    /* 注销字符设备驱动 */
       printk("led_exit \r\n");
       unregister_chrdev(LED_MAJOR, LED_NAME);   //
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在驱动模块卸载函数__exit中的cdev_del(struct cdev *)函数调用后即注销字符设备后调用 unregister_chrdev_region(dev_t devno, unsigned count)函数释放在驱动加载函数__init中通过register_chrdev_region、alloc_chrdev_region,注册的主设备号。(cdev_del函数、unregister_chrdev_region函数缺一不可);即2.4之前的版本的unregister_chrdev函数。

  • 相关阅读:
    MySQL 详解 存储过程 和 存储函数
    三个统一..........
    ECharts与Excel的结合实战
    二十一、动态内存管理
    Oracle笔记 之 空值null的处理
    【算法题】8029. 与车相交的点
    跨域问题的原理分析
    【自学笔记】Python中的逻辑函数:any()、all()及同类函数的用法与示例
    C 基础语法3 —— 指针
    MyBatis源码之MyBatis中SQL语句执行过程
  • 原文地址:https://blog.csdn.net/qqmrchen124/article/details/134441091