精华内容
下载资源
问答
  • 按照自己的平台选择合适的驱动,比如我的是 ARM架构,Linux,就选择了 eGTouch_v2.5.7413.L-ma ARM / MIPS 2019.03.13 3. 按照官方文档配置和修改内核: 《EETI_eGTouch_Programming_Guide 》 4. 更新内核,在文件...

    1. 先将拿到的触摸屏接入USB,终端打印如下信息

    [ 138.121969] usb 2-1.2: USB disconnect, device number 3

    [ 140.030843] usb 2-1.2: new full-speed USB device number 4 using musb-hdrc

    [ 140.151688] usb 2-1.2: New USB device found, idVendor=0eef, idProduct=c002

    [ 140.158940] usb 2-1.2: New USB device strings: Mfr=1, Product=2, SerialNumber=0

    [ 140.166653] usb 2-1.2: Product: eGalaxTouch P80H32 4070 v00_M03 k4.02.146

    [ 140.173809] usb 2-1.2: Manufacturer: eGalax Inc.

    从USB的自描述可以得知屏幕的厂家,然后去官网瞅瞅。

    2. 官网下载驱动

    # 官网

    http://www.eeti.com/

    # 官网驱动

    http://www.eeti.com/drivers_Linux.html

    按照自己的平台选择合适的驱动,比如我的是 ARM架构,Linux,就选择了

    eGTouch_v2.5.7413.L-ma ARM / MIPS 2019.03.13

    3. 按照官方文档配置和修改内核:

    《EETI_eGTouch_Programming_Guide 》

    4. 更新内核,在文件系统中安装驱动

    sh setup.sh

    5. 修改 /etc/eGTouchL.ini 文件

    文件中有详细的说明,注意很多嵌入式设备使用的是tslib,所以 BtnType 一项目要修改为 1;

    6. 运行 eGTouchD, /dev/input/ 目录下应该会多出evenX;

    ls /dev/input/

    cat /proc/bus/input/devices

    7. 使用官方测试工具测试

    arm-linux-gnueabihf-gcc -o GetEvent.out GetEvent.c

    ./GetEvent.out /dev/input/event1 #手触摸到触摸屏的时候可以看到有数值变化

    // 按下

    [ABS_X]code = 0, value = 2012

    [ABS_Y]code = 1, value = 2047

    [ABS_PRESSURE] code = 24, value = 1

    [SYN_REPORT]code = 0, value = 0

    // 抬起

    [ABS_PRESSURE] code = 24, value = 0

    [SYN_REPORT]code = 0, value = 0

    展开全文
  •  防止printk函数降低linux驱动性能  Linux驱动只在开发阶段使用printk函数输出消息。正式发布linux驱动是将可能影响性能的printk函数去掉。利用c语言中的编译指令(#if, #else, #endif等)  通过虚拟文件...
  • 嵌入式Linux驱动开发实战教程(内核驱动、看门狗技术、触摸屏、视频采集系统)适合人群:高级课时数量:109课时用到技术:嵌入式 Linux涉及项目:驱动开发、看门狗技术、触摸屏、视频采集咨询qq:1840215592 课程介绍...

    嵌入式Linux驱动开发实战教程(内核驱动、看门狗技术、触摸屏、视频采集系统)

    适合人群:高级

    课时数量:109课时

    用到技术:嵌入式 Linux

    涉及项目:驱动开发、看门狗技术、触摸屏、视频采集

    咨询qq:1840215592

    a96ff90761283789cec805a14857519d.png

    课程介绍:

    本课程即是针对有兴趣学习嵌入式linux驱动开发又不知道从何处着实开始学习嵌入式linux驱动开发的在校同学以及社会在职人员。本课程采用理论教学与实验相结合的方式,软件与硬件相结合的方式,重点给大家讲解嵌入式linux驱动开发的方法,系统地介绍嵌入式linux驱动开发的过程。通过本课程的学习,学员可以掌握linux内核模块的开发方法、linux内存管理机制、linux进程管理机制、linux内核链表机制、linux系统调用机制、linux字符设备驱动的开发方法、linux网络设备驱动的开发方法、linux块设备驱动的开发方法等能力。引导学员进入linux驱动开发的精彩世界,通过学习嵌入式linux驱动开发使大家成为嵌入式开发的高层次人才。

    嵌入式Linux驱动开发实战视频教程:http://www.ibeifeng.com/goods-475.html

    教学模式说明:

    本课程重点是给大家讲解嵌入式linux驱动的开发方法,采用理论与实践,硬件与软件相结合的方法。

    1、在每节开始之前先简单回顾上一节所讲的主要内容,并对本节所讲的内容先进行概述,讲解概念、技术要点,设计实现思路等内容,最后总结本次课程的要掌握的要点。

    2、每讲解一次理论课后都会讲解硬件原理图和实例代码,帮助大家理解理论知识,详细讲解代码如何实现的以及编程过程中注意的问题。

    3、鉴于linux驱动的特点,在讲课过程中会侧重于讲解linux驱动的软件框架,大家掌握linux驱动的框架是学习的重点。

    4、学习的过程中学员要理论和实践相结合,硬件与软件相结合,讲过的代码学员自行完成修改和调试,以巩固加深学习效果。

    课程进度安排:

    第一阶段:嵌入式linux驱动开发基础-内核模块开发

    第二阶段:嵌入式linux驱动开发基础-内存管理实现机制

    第三阶段:嵌入式linux驱动开发基础-内核链表及内核定时器实现机制

    第四阶段:嵌入式linux驱动开发基础-内核进程控制实现机制

    第五阶段:嵌入式linux驱动开发基础-linux内核空间与用户空间交互机制

    第六阶段:嵌入式linux驱动开发基础-linux字符设备驱动基础

    第七阶段:嵌入式linux驱动开发基础-linux高级字符设备驱动开发

    第八阶段:嵌入式linux驱动开发基础-linux设备驱动模型

    第九阶段:嵌入式linux驱动实例分析

    第十阶段:嵌入式linux项目-基于V4L2的视频采集系统

    展开全文
  • 前言上一篇分享的:《从单片机工程师的角度看嵌入式Linux》中有简单提到Linux的三大类驱动:我们学习编程的时候都会从hello程序开始。同样的,学习Linux驱动我们也从最简单的he...

    前言

    上一篇分享的:《从单片机工程师的角度看嵌入式Linux》中有简单提到Linux的三大类驱动:

    我们学习编程的时候都会从hello程序开始。同样的,学习Linux驱动我们也从最简单的hello驱动学起。

    驱动层和应用层

    还记得实习那会儿我第一次接触嵌入式Linux项目的时候,我的导师让我去学习项目的其它模块,然后尝试着写一个串口相关的应用。

    那时候知道可以把设备当做文件来操作。但是不知道为什么是这样,就去网上搜了一些代码(驱动代码),然后和我的应用代码放在同一个文件里。

    给导师看了之后,导师说那些驱动程序不需要我写,那些驱动已经写好被编译到内核里了,可以直接用了,我只需关注应用层就好了。我当时脑子里就在打转。。what?

    STM32用一个串口不就是串口初始化,然后想怎么用就怎么用吗?后来经过学习才知道原来是那么一回事呀。这就是单片机转转嵌入式Linux的思维误区之一。

    学嵌入式Linux之前我们有必要暂时忘了我们单片机的开发方式,重新梳理嵌入式Linux的开发流程。下面看一下STM32裸机开发与嵌入式Linux开发的一些区别:

    嵌入式Linux的开发方式与STM32裸机开发的方式有点不一样。在STM32的裸机开发中,驱动层与应用层的区分可能没有那么明显,常常都杂揉在一起。

    当然,有些很有水平的裸机程序分层分得还是很明显的。但是,在嵌入式Linux中,驱动和应用的分层是特别明显的,最直观的感受就是驱动程序是一个.c文件里,应用程序是另一个.c文件。

    比如我们这个hello驱动实验中,我们的驱动程序为hello_drv.c、应用程序为hello_app.c。

    驱动模块的加载有两种方式:第一种方式是动态加载的方式,即驱动程序与内核分开编译,在内核运行的过程中加载;第二种方式是静态加载的方式,即驱动程序与内核一同编译,在内核启动过程中加载驱动。

    在调试驱动阶段常常选用第一种方式,因为较为方便;在调试完成之后才采用第二种方式与内核一同编译。

    STM32裸机开发与嵌入式Linux开发还有一点不同的就是:STM32裸机开发最终要烧到板子的常常只有一个文件(除开含有IAP程序的情况或者其它情况),嵌入式Linux就需要分开编译、烧写。

    Linux字符设备驱动框架

    我们先看一个图:

    当我们的应用在调用open、close、write、read等函数时,为什么就能操控硬件设备。那是因为有驱动层在支撑着与硬件相关的操作,应用程序在调用打开、关闭、读、写等操作会触发相应的驱动层函数。

    本篇笔记我们以hello驱动做分享,hello驱动属于字符设备。实现的驱动函数大概是怎么样的是有套路可寻的,这个套路在内核文件include/linux/fs.h中,这个文件中有如下结构体:

    这个结构体里的成员都是些函数指针变量,我们需要根据实际的设备确定我们需要创建哪些驱动函数实体。比如我们的hello驱动的几个基本的函数(打开/关闭/读/写)可创建为(以下代码来自:百问网):

    (1)打开操作

    左右滑动查看全部代码>>>

    static int hello_drv_open (struct inode *node, struct file *file)
    {
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      return 0;
    }
    

    打开函数的两个形参的类型要与struct file_operations结构体里open成员的形参类型一致,里面有一句打印语句,方便直观地看到驱动的运行过程。

    关于函数指针,可阅读往期笔记:

    【C语言笔记】指针函数与函数指针?

    C语言、嵌入式重点知识:回调函数

    (2)关闭操作

    左右滑动查看全部代码>>>

    static int hello_drv_close (struct inode *node, struct file *file)
    {
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      return 0;
    }
    

    (3)读操作

    左右滑动查看全部代码>>>

    static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
      int err;
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      err = copy_to_user(buf, kernel_buf, MIN(1024, size));
      return MIN(1024, size);
    }
    

    copy_to_user函数的原型为:

    左右滑动查看全部代码>>>

    static inline int copy_to_user(void __user *to, const void *from, unsigned long n);
    

    用该函数来读取内核空间(kernel_buf)的数据给到用户空间(buf)。另外,kernel_buf的定义如下:

    static char kernel_buf[1024];
    

    MIN为宏:

    #define MIN(a, b) (a < b ? a : b)
    

    MIN(1024, size)作为copy_to_user的实参意在对拷贝的数据长度做限制(不能超出kernel_buf的大小)。

    (4)写操作

    左右滑动查看全部代码>>>

    static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
      int err;
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      err = copy_from_user(kernel_buf, buf, MIN(1024, size));
      return MIN(1024, size);
    }
    

    copy_from_user函数的原型为:

    左右滑动查看全部代码>>>

    static inline int copy_from_user(void *to,const void __user volatile *from,unsigned long n)
    

    用该函数来将用户空间(buf)的数据传送到内核空间(kernel_buf)。

    有了这些驱动函数,就可以给到一个struct file_operations类型的结构体变量hello_drv,如:

    static struct file_operations hello_drv =
    {
        .owner   = THIS_MODULE,
        .open    = hello_drv_open,
        .read    = hello_drv_read,
        .write   = hello_drv_write,
        .release = hello_drv_close,
    };
    

    有些朋友可能没见过这种结构体初始化的形式(结构体成员前面加个.号),这是C99及C11标准提出的指定初始化器。具体可以去看往期笔记:【C语言笔记】结构体

    上面这个结构体变量hello_drv容纳了我们hello设备的驱动接口,最终我们要把这个hello_drv注册给Linux内核。

    套路就是这样的:把驱动程序注册给内核,之后我们的应用程序就可以使用open/close/write/read等函数来操控我们的设备,Linux内核在这里起到一个中间人的作用,把两头的驱动与应用协调得很好。

    我们前面说了驱动的装载方式之一的动态装载:把驱动程序编译成模块,再动态装载。

    动态装载的体现就是开发板已经启动运行了Linux内核,我们通过开发板串口终端使用命令来装载驱动。装载驱动有两个命令,比如装载我们的hello驱动:

    • 方法一:insmod hello_drv.ko

    • 方法二:modprobe hello_drv.ko

    其中modprobe命令不仅能装载当前驱动,而且还会同时装载与当前驱动相关的依赖驱动。有了转载就有卸载,也有两种方式:

    • 方法一:rmmod hello_drv.ko

    • 方法二:modprobe -r hello_drv.ko

    其中modprobe命令不仅卸载当前驱动,也会同时卸载依赖驱动。

    我们在串口终端调用装载与卸载驱动的命令,怎么就会执行装载与卸载操作。对应到驱动程序里我们有如下两个函数:

    module_init(hello_init); //注册模块加载函数
    module_exit(hello_exit); //注册模块卸载函数
    

    这里加载与注册有用到hello_inithello_exit函数,我们前面说的把hello_drv驱动注册到内核就是在hello_init函数里做,如:

    左右滑动查看全部代码>>>

    static int __init hello_init(void)
    {
      int err;
    
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        /* 注册hello驱动 */
      major = register_chrdev(0, 	/* 主设备号,为0则系统自动分配 */
                        "hello", 	/* 设备名称 */
                        &hello_drv); /* 驱动程序 */
    
      /* 下面操作是为了在/dev目录中生成一个hello设备节点 */
        /* 创建一个类 */
      hello_class = class_create(THIS_MODULE, "hello_class");
      err = PTR_ERR(hello_class);
      if (IS_ERR(hello_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "hello");
        return -1;
      }
    
        /* 创建设备,该设备创建在hello_class类下面 */
      device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
    	
    	return 0;
    }
    

    这里这个驱动程序入口函数hello_init中注册完驱动程序之后,同时通过下面连个创建操作来创建设备节点,即在/dev目录下生成设备文件。

    据我了解,在之前版本的Linux内核中,设备节点需要手动创建,即通过创建节点命令mknod 在/dev目录下自己手动创建设备文件。既然已经有新的方式创建节点了,这里就不抠之前的内容了。

    以上就是分享关于驱动一些内容,通过以上分析,我们知道,其是有套路(就是常说的驱动框架)可寻的,比如:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/init.h>
    /* 其她头文件...... */
    
    /* 一些驱动函数 */
    static ssize_t xxx_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    
    }
    
    static ssize_t xxx_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
    
    }
    
    static int xxx_open (struct inode *node, struct file *file)
    {
    
    }
    
    static int xxx_close (struct inode *node, struct file *file)
    {
    
    }
    /* 其它驱动函数...... */
    
    /* 定义自己的驱动结构体 */
    static struct file_operations xxx_drv = {
      .owner	 = THIS_MODULE,
      .open    = xxx_open,
      .read    = xxx_read,
      .write   = xxx_write,
      .release = xxx_close,
      /* 其它程序......... */
    };
    
    /* 驱动入口函数 */
    static int __init xxx_init(void)
    {
    
    }
    
    /* 驱动出口函数 */
    static void __exit hello_exit(void)
    {
    
    }
    
    /* 模块注册与卸载函数 */
    module_init(xxx_init);
    module_exit(xxx_exit);
    
    /* 模块许可证(必选项) */
    MODULE_LICENSE("GPL");
    

    按照这样的套路来开发驱动程序的,有套路可寻那就比较好学习了,至少不会想着怎么起函数名而烦恼,哈哈,按套路来就好。

    关于驱动的知识,这篇笔记中还可以展开很多内容,限于篇幅就不展开了。我们之后再进行学习、分享。

    下面看一下测试程序/应用程序(hello_drv_test.c中的内容,以下代码来自:百问网):

    左右滑动查看全部代码>>>

    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <stdio.h>
    #include <string.h>
    
    /*
     * ./hello_drv_test -w abc
     * ./hello_drv_test -r
     */
    int main(int argc, char **argv)
    {
      int fd;
      char buf[1024];
      int len;
    
      /* 1. 判断参数 */
      if (argc < 2)
      {
        printf("Usage: %s -w <string>\n", argv[0]);
        printf("       %s -r\n", argv[0]);
        return -1;
      }
    
      /* 2. 打开文件 */
      fd = open("/dev/hello", O_RDWR);
      if (fd == -1)
      {
        printf("can not open file /dev/hello\n");
        return -1;
      }
    
      /* 3. 写文件或读文件 */
      if ((0 == strcmp(argv[1], "-w")) && (argc == 3))
      {
        len = strlen(argv[2]) + 1;
        len = len < 1024 ? len : 1024;
        write(fd, argv[2], len);
      }
      else
      {
        len = read(fd, buf, 1024);		
        buf[1023] = '\0';
        printf("APP read : %s\n", buf);
      }
    
      close(fd);
    
      return 0;
    }
    

    就是一些读写操作,跟我们学习文件操作是一样的。学单片机的有些朋友可能不太熟悉main函数的这种写法:

    int main(int argc, char **argv)
    

    main函数在C中有好几种写法(可查看往期笔记:main()函数有哪几种形式?),在Linux中常用这种写法。

    argc与argv这两个值可以从终端(命令行)输入,因此这两个参数也被称为命令行参数。argc为命令行参数的个数,argv为字符串命令行参数的首地址。

    最后,我们把编译生成的驱动模块hello_drv.ko与应用程序hello_drv_test放到共享目录录nfs_share中,同时在开发板终端挂载共享目录:

    mount -t nfs -o nolock,vers=4 192.168.1.104:/home/book/nfs_share /mnt
    

    关于ntf网络文件系统的使用可查看往期笔记:【Linux笔记】挂载网络文件系统

    然后我们通过insmod 命令装载驱动,但是出现了如下错误:

    这是因为我们的驱动的编译依赖与内核版本,编译用的内核版本与当前开发板运行的内核的版本不一致所以会产生该错误。

    重新编译内核,并把编译生成的Linux内核zImage映像文件与设备树文件*.dts文件拷贝到开发板根文件系统的/boot目录下,然后进行同步操作:

    #mount -t nfs -o nolock,vers=4 192.168.1.114:/home/book/nfs_share /mnt
    #cp /mnt/zImage /boot
    #cp /mnt/.dtb /boot
    #sync
    

    下面是完整的hello驱动程序(来源:百问网):

    左右滑动查看全部代码>>>

    #include <linux/module.h>
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/miscdevice.h>
    #include <linux/kernel.h>
    #include <linux/major.h>
    #include <linux/mutex.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h>
    #include <linux/stat.h>
    #include <linux/init.h>
    #include <linux/device.h>
    #include <linux/tty.h>
    #include <linux/kmod.h>
    #include <linux/gfp.h>
    
    /* 1. 确定主设备号                                                                 */
    static int major = 0;
    static char kernel_buf[1024];
    static struct class *hello_class;
    
    
    #define MIN(a, b) (a < b ? a : b)
    
    /* 3. 实现对应的open/read/write等函数,填入file_operations结构体                   */
    static ssize_t hello_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
      int err;
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      err = copy_to_user(buf, kernel_buf, MIN(1024, size));
      return MIN(1024, size);
    }
    
    static ssize_t hello_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
    {
      int err;
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      err = copy_from_user(kernel_buf, buf, MIN(1024, size));
      return MIN(1024, size);
    }
    
    static int hello_drv_open (struct inode *node, struct file *file)
    {
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      return 0;
    }
    
    static int hello_drv_close (struct inode *node, struct file *file)
    {
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      return 0;
    }
    
    /* 2. 定义自己的file_operations结构体                                              */
    static struct file_operations hello_drv =
    {
      .owner	 = THIS_MODULE,
      .open    = hello_drv_open,
      .read    = hello_drv_read,
      .write   = hello_drv_write,
      .release = hello_drv_close,
    };
    
    /* 4. 把file_operations结构体告诉内核:注册驱动程序                                */
    /* 5. 谁来注册驱动程序啊?得有一个入口函数:安装驱动程序时,就会去调用这个入口函数 */
    static int __init hello_init(void)
    {
      int err;
    
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      major = register_chrdev(0, "hello", &hello_drv);  /* /dev/hello */
    
    
      hello_class = class_create(THIS_MODULE, "hello_class");
      err = PTR_ERR(hello_class);
      if (IS_ERR(hello_class)) {
        printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
        unregister_chrdev(major, "hello");
        return -1;
      }
    
      device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello"); /* /dev/hello */
    
      return 0;
    }
    
    /* 6. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数           */
    static void __exit hello_exit(void)
    {
      printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
      device_destroy(hello_class, MKDEV(major, 0));
      class_destroy(hello_class);
      unregister_chrdev(major, "hello");
    }
    
    
    /* 7. 其他完善:提供设备信息,自动创建设备节点                                     */
    
    module_init(hello_init);
    module_exit(hello_exit);
    
    MODULE_LICENSE("GPL");
    

    最后

    嵌入式Linux的学习内容是很多的、坑也是很多的,需要很有耐心地去学习。以上笔记如有错误,欢迎指出!

    如果觉得文章不错,转发、在看,也是我们继续更新得动力。

      回复「 篮球的大肚子」进入技术群聊

    回复「1024」获取1000G学习资料

    展开全文
  • 但是总觉得业界写的书都是点到为止,可能也有篇幅过长、嵌入式Linux驱动框架碎片化的考虑。在一众嵌入式Linux驱动书中笔者最推崇宋宝华的《Linux设备驱动开发详解》,但他完全可以更进一步上升到驱动框架个例(比如...

    想讲好嵌入式Linux的驱动开发并不容易,各位业界大神从最基础的字符驱动到中断并发再到驱动框架、应用层调用。但是总觉得业界写的书都是点到为止,可能也有篇幅过长、嵌入式Linux驱动框架碎片化的考虑。在一众嵌入式Linux驱动书中笔者最推崇宋宝华的《Linux设备驱动开发详解》,但他完全可以更进一步上升到驱动框架个例(比如USB wifi模块驱动)和应用层调用。有些书从c语言基础谈起,真是莫名其妙,不懂C语言应该去学C语言而不是来学驱动。

    1、基础和原料

    驱动程序本身也是程序,所有程序都有基础和调用原料库(最底层的编译器调用汇编指令集)。所以为了写出驱动程序第一步是要了解写的规则(基础)和调用库(原料)。

    写驱动的规则,一般的书开局一个字符驱动讲到最后就没了,其实字符驱动只是引子。驱动的基础其实太多了。首先是分离分层和设备书概念,但这个是非常具体的,什么东西放设备树以及设备树如何在开机阶段被解析注册进总线的,驱动是如何注册进总线的,驱动如何提供设备名和主次设备号给应用层调用(内核这里看到是驱动,应用层那里看到一个个设备文件)等等。很多人以为驱动就设备树、总线、驱动三个具体的文件包打天下,要是这样只能写出简单的字符驱动,从这三大块很容易分出非常多的文件。然后是中断屏蔽、原子操作、锁、信号量、互斥体、阻塞、非阻塞、异步和同步、中断等纯粹的程序原理性东西,这个跟硬件基本没有关系,是程序设计在驱动开发里的高级体现。最后就是原料了,一本Linux内核API手册也只是字典,活用还是要多看代码。

    熟悉了基础和原料,大概就能写出比较复杂的字符驱动了,但离真正用得上还很远。总体来说在了解驱动的基础和原料后还是要实际看几个大型的驱动才有收获。

    2、驱动框架

    很多人以为写个字符驱动就差不多了,再加个阻塞非阻塞就顶天了,这样的驱动绝不会被合并到内核设备树里,SOC厂也不会放进自己的SDK里发布,因为缺少实际可用的框架包装。Linux的驱动框架种类繁多、单种内容多,比如一个看似很简单的GPIO驱动却要包装sysfs文件系统框架、再配合pinctrl,产生了非常多的源文件,一般人早就云里雾里了。而且应用层接口也是被包进驱动框架里的,比如GPIO被包进sysfs后在应用就是通过/sys里的文件属性操作的。

    驱动的框架可以分为简单框架和复杂框架。简单框架就是类似sysfs(kobject, ktype, kset)、udev(kobject, ktype, kset)、proc还有USB、I2C、SPI等这种一对一的,就是一种驱动就用一种框架。但是在日益复杂的外设面前简单框架基本要被复杂框架套用才能在现实中用上,比如一个USB驱动外面不挂成U盘或wifi能用吗?复杂框架包括input、wifi、framebuffer等等。

    驱动框架这个真没法自己写出来,能看懂改哪里已经不错,更何况现在除了论坛,书本专门讲的很少。

    3、应用层调用

    内核对于应用层真是厚爱,所有难写的代码全在内核层,应用层除了对设备文件和属性文件来几个open、read、write、ioctl等,好像没别的。举个例子framework框架的驱动在底层够复杂了吧,看看在应用层的接口,稍微了解点属性控制的,不难写出显示程序了吧。如果用上成熟的Qt和tslib,完全可以忽略硬件了。

    应用层简单不代表驱动在做应用层接口时简单,很多人以为实现一个file_operation结构体就好了,但是如何实现呢?同步异步、阻塞非阻塞、ioctl属性如何实现呢等等。

    4、驱动重点不是从无到有而是移植修改

    现在的写驱动的书好像真能教人从无到有写出一个驱动,但可惜除了简单的GPIO控制基本用不了。极少有人能单枪匹马实现从无到有写出一个驱动,而且这些一般都在芯片厂或者给Linux内核提供代码的大牛。普通开发者就是拷贝,修改,调试,不行就改改。但要达到知道改哪里的程度也要大量学习。

    嵌入式Linux内核层的开发远不如单片机程序灵活,单片机领域因为碎片化超级严重各种RTOS、框架、状态机等等满天飞。也正因为如此可能很多人觉得过于简单,业内大量程序员转安卓系统底层开发尤其是framework层开发。

     

     

    展开全文
  • 嵌入式Linux驱动程序开发

    千次阅读 多人点赞 2019-01-15 10:55:33
    嵌入式Linux驱动程序开发
  •   linux驱动的加载有动态加载和静态加载两种方式。 1. 动态加载   驱动的动态加载指的是利用了linux的module特性,可以在系统启动后通过insmod或modprobe命令挂载.ko内核目标文件,对模块进行加载,成功后可通过...
  • 1.嵌入式Linux驱动程序开发 嵌入式Linux驱动程序开发包罗万象,基本上每个点都要大概了解一下。 1.1软件工具 Makefile必须要掌握一些,至于Kconfig太简单了只是个配置文件算不上程序技能。shell也必须会一点,...
  • 说到Linux驱动,尤其是嵌入式Linux驱动,大家可能会望而却步,因为入门太难!很多书上或课程基本是这样的:一上来给我们展示一大堆高深莫测的代码,感觉是C语言,又感觉不是C语言。说它是C语言,这里能找到一些C的...
  • 本文描述了在开发嵌入式linux系统时调试程序的一个方法,描述在嵌入式linux下面如何使用NFS文件系统来开发调试应用程序。
  • 目录 目录 前言 GDB 调试工具介绍 GDB调试教程 gcc调试相关编译选项 ...GDB交叉调试环境搭建 ...项目遇到一个问题,就是...这时候突然想到了GDB,从来都没有接触过调试工具,以前的调试都是使用printf直接打印的方式!!!
  • 见另一篇博客《Linux安装交叉编译工具链》 1.2 代码镜像烧写工具 ​ imxdownload :注意需要将imxdownload工具拷贝到工程根目录下,否则会烧写失败 1.3 Ubuntu下所有的设备文件都在目录“/dev”里面, 所以插上 SD ...
  • 书中不仅剖析了嵌入式Linux系统,而且讲述了处理器、内核、引导加载程序、设备驱动程序、文件系统等关键组件,介绍了嵌入式Linux系统的开发工具、调试技术。作者多年积累总结的嵌入式Linux开发技巧和提示,无论对...
  • 嵌入式linux调试技巧

    千次阅读 2017-10-30 22:41:08
    调试内核和驱动都可以采用printk。在Kernel.h (include\linux)中定义了log的等级。 未指定日志级别的 printk() 采用的默认级别是 DEFAULT_MESSAGE_LOGLEVEL,这个宏在kernel/printk.c 中被定义为整数 4,即对应KERN_...
  • 嵌入式Linux下开发调试LCD显示驱动.pdf
  • 嵌入式linux驱动开发流程总结

    千次阅读 2016-08-21 19:07:27
    嵌入式linux驱动开发流程 嵌入式系统中,操作系统是通过各种驱动程序来驾驭硬件设备的。设备驱动程序是操作系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个...
  • 引言  随着人们对开放源代码软件热情的日益增高,Linux作为一个功能强大而稳定的开源操作系统,越来越受到... 1 嵌入式Linux网络驱动程序介绍  Linux网络驱动程序作为Linux网络子系统的一部分,位于TCP/IP网
  • 嵌入式Linux驱动教程(韦东山2期) 2003 年毕业于中国科学技术大学,...
  •  本书从最简单的点亮一个led开始,由浅入深地讲解,使读者最终可以配置、移植、裁剪内核,编写驱动程序,移植gui系统,掌握整个嵌入式linux系统的开发方法。 本书由浅入深,循序渐进,适合刚接触嵌入式linux的初学...
  • 嵌入式Linux下开发调试LCD显示驱动.docx
  • 0 引言  随着人们对开放源代码软件热情的日益增高,Linux作为一个功能强大而稳定的开源操作系统,越来越受到... 1 嵌入式Linux网络驱动程序介绍  Linux网络驱动程序作为Linux网络子系统的一部分,位于TCP/I
  • 随着人们对开放源代码软件热情的日益增高,Linux作为一个功能强大而稳定的开源操作系统,越来越受到... 1 嵌入式Linux网络驱动程序介绍  Linux网络驱动程序作为Linux网络子系统的一部分,位于TCP/IP网络体系结构的
  • 声明:文本是看完韦... 在介绍本文之前,我想先对前面的知识做一下总结,我们知道Linux系统的设备分为字符设备(char device),块设备(block device),以及网络设备(network device)。字符设备是指存取时没...
  • Linux强大的网络支持功能实现了对包括TCP/IP在内的多种协议的支持,满足了面向21世纪的嵌入式系统应用联网的需求。因此,在嵌入式系统开发调试时,网络接口几乎成为不可或缺的模块。
  • 本PDF文档详细描述运用KGDB等手段对嵌入式linux内核与驱动调试原理和方法。
  • 嵌入式Linux应用开发完全手册.pdf

    热门讨论 2013-02-17 16:18:23
    嵌入式Linux应用开发完全手册》从最简单的点亮一个LED开始,由浅入深地讲解,使读者最终可以配置、移植、裁剪内核,编写驱动程序,移植GUI系统,掌握整个嵌入式Linux系统的开发方法。 《嵌入式Linux应用开发完全...
  • 嵌入式Linux一般调试方法;Makefile简介;Makefile简介;Makefile变量;简单Make指令说明;使用Makefile方法;Linux系统中的设备文件;设备驱动程序是内核重要部分;设备驱动的大致结构;设备驱动的作用;设备驱动完成的工作;...
  • 接着系统地讲解了嵌入式Linux的环境搭建,以及嵌入式Linux的I/O与文件系统的开发、进程控制开发、进程间通信开发、网络应用开发、基于中断的开发、设备驱动程序的开发以及嵌入式图形界面的开发等,并且还安排了丰富...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,247
精华内容 10,098
关键字:

嵌入式linux驱动调试

linux 订阅