• tiny4412--linux驱动学习(2)


    在ubuntu下编写验证字符设备驱动

    并移植到arm开发板上

    1,准备工作

    1.   uname -r  查看电脑版本信息
    2.        apt-get  install  linux-source  安装相应版本的linux内核

    2,编写驱动程序

        Global CharDev.c

    /* GlobalCharDev.c */
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    
    #include <asm/uaccess.h>
    
    
    #define DEV_NAME "GlobalChar"
    
    static ssize_t GlobalRead(struct file *, char *, size_t, loff_t *);
    static ssize_t GlobalWrite(struct file *, const char *, size_t,loff_t *);
    
    static int char_major = 0;
    static int GlobalData = 0; /* "GlobalChar"设备的全局变量 */
    
    /* 初始化字符设备驱动的 file_operations 结构体 */
    struct file_operations globalchar_fops = 
    {
        .read = GlobalRead,
        .write = GlobalWrite
    };
    
    /* 模块初始化 */
    static int __init GlobalChar_init(void)
    {
        int ret;
    
        ret = register_chrdev(char_major, DEV_NAME, &globalchar_fops);/* 注册设备驱动,_driver_char_misc.c 第290行参考  */
        if(ret < 0 )
            printk(KERN_ALERT "GlobalChar Reg Fail
    ");
        else
            {
            printk(KERN_ALERT "GlobalChar Reg Success
    ");
            char_major = ret;
            printk(KERN_ALERT "Major = %d
    ", char_major);
            }
        return ret;
    }
    
    /* 模块卸载函数 */
    static void __exit GlobalChar_exit(void)
    {
        unregister_chrdev(char_major, DEV_NAME); /* 注销设备驱动 */
        return;
    }
    
    /* 模块驱动读函数 */
    static ssize_t GlobalRead(struct file *file, char *buf, size_t len, loff_t *off)
    {
        if (copy_to_user(buf, &GlobalData ,sizeof(int)))  
        {
            /* 从内核复制 GlobalData 到用户空间*/
            return -EFAULT;
        }
        return sizeof(int);
    }
    /* 模块驱动写函数 */ static ssize_t GlobalWrite(struct file *file, const char *buf, size_t len, loff_t *off) { if (copy_from_user(&GlobalData, buf, sizeof(int))) { /* 从用户复制 GlobalData 到内核 */ return -EFAULT; } return sizeof(int); } module_init(GlobalChar_init); module_exit(GlobalChar_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("dongjin");

      Makefile

    ifneq ($(KERNELRELEASE),)    
        obj-m := GlobalCharDev.o
    else
        
    # KERNELDIR ?= /lib/modules/$(shell uname -r)/build
        KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)       //这两个都可以
    
        PWD := $(shell pwd)
    
    default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    
    clean:
        rm -rf rm -rf *.ko *.mod* *.o* *.sy*
    endif

       理解:

          pwd-->  驱动文件目录

          kerneldir -->  内核源码目录

          default -->  表示到内核源码目录中去编译pwd下的驱动文件

    ——————————————————————————————————————————————————————

              make 编译

    root@ubuntu:/home/arm/data/char_driver# make
    make -C /usr/src/linux-headers-4.4.0-31-generic M=/home/arm/data/char_driver modules
    make[1]: 正在进入目录 `/usr/src/linux-headers-4.4.0-31-generic'
      CC [M]  /home/arm/data/char_driver/GlobalCharDev.o
      Building modules, stage 2.
      MODPOST 1 modules
      LD [M]  /home/arm/data/char_driver/GlobalCharDev.ko
    make[1]:正在离开目录 `/usr/src/linux-headers-4.4.0-31-generic'

    出现Global CharDev.ko文件

    2,insmod Global CharDev.ko  将模块加入内核

    3,cat  /proc/devices  查看驱动设备

    4,mknod  /dev/GlobalChar   c  247  0      根据相应的设备号,建立设备节点。

    5,测试文件

    /* GlobaiCharText.c 测试文件*/
    
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <stdio.h>
    #include <fcntl.h>
    #include <unistd.h>
    
    #define DEV_NAME "/dev/GlobalChar"
    
    int main()
    {
         int fd, num;
    
         /* 打开设备文件 */
         fd = open(DEV_NAME, O_RDWR, S_IRUSR | S_IWUSR);
         if(fd < 0)
         {
         printf("Open Device Fail!
    ");
              return -1;
         }
    
         /* 读取当前设备数值 */
         read(fd, &num, sizeof(int));
         printf("The GlobalChar is %d
    ", num);
    
         printf("Please input a numble written to GlobalChar: ");
         scanf("%d", &num);
    
         /* 写入新的数值 */
         write(fd, &num, sizeof(int));
    
         /* 重新读取数值 */
         read(fd, &num, sizeof(int));
         printf("The GlobalChar is %d
    ", num);
    
         close(fd);
         return 0;
    
    }

       gcc -o  GlobalCharText  GlobalCharText.c      编译出可执行文件

       执行:

    root@ubuntu:/home/arm/data/char_driver# ./a.out 
    The GlobalChar is 0
    Please input a numble written to GlobalChar: 111
    The GlobalChar is 111

    ——————————————————————————————————————————————————————————————————————

    通过NFS我们可以建立共享目录,将编写好的驱动加载到arm板,当然也需要配置环境变量。

    1,驱动文件:需要将Make file中KERNLDIR 改成 自己下载内核的地址,如:

        KERNELDIR ?= /home/arm/linux-4.4

     

     

    2,测试文件:理所当然我们需要使用交叉编译去编译出可执行文件。

    注意:首先我们要知道自己制作的做小系统是采用静态编译还是动态编译,我的采用静态编译

      1,静态:

      2,动态:

    需要在制作最小系统时,在  /lib  下加入所需的动态交叉编译库(所选交叉编译工具目录下的链接库),但是我在制作randisk的过程中,提示内存不足,暂没查找其原因。

    如果在静态根文件系统内使用动态编译链所编译的elf,会提示:-sh:./test:no found  (这里 not found 指的是 链接库)

    测试:

    卸载:

    1,删除  /dev  下的设备节点

      rm /dev/GlobalChar

    2,卸载驱动

      rmmod  GlopbalCharDev.ko 

    出现问题:

    ——————————————————————————————————————————————————————

    参考:

    http://tieba.baidu.com/p/3645403366

    https://blog.csdn.net/Ultraman_hs/article/details/53239455

    解决移植到arm上不兼容的问题

    https://blog.csdn.net/zqj6893/article/details/48439711

    解决驱动卸载问题

  • 相关阅读:
    基数排序
    计数排序和桶排序
    部署Java Web项目到云服务器的步骤全解析
    IP地址0.0.0.0/0是什么意思
    Tomcat在阿里云Centos7上正常启动,但浏览器无法访问的解决方法
    eclipse光标怎么返回上一次浏览的位置
    IDEA设置方法自动显示参数提示
    socket通信模型、socket中的accept()阻塞与read()阻塞
    Ubuntu18.04 下修改 root密码
    Ubuntu18.04 安装 VMwareTools
  • 原文地址:https://www.cnblogs.com/chu-yi/p/10671865.html
Copyright © 2020-2023  润新知