<const 关键字>

在嵌入式系开发中,const关键字就是“只读”的意思
 
<为什么要ARM需要进行C语言环境的初始化>
在汇编情况下,指令的跳转,保护现场需要保存的数据很少,并且可以直接访问寄存器,但是到了C语言环境中,函数的调用。
(1)无时无刻都需要保护现场,(2)并且无法直接访问寄存器,(3)函数需要传递参数,参数的保存地址。所以最好的方式就是指定一个对整个系统而言来说是一个约定固定的地址作为现场数据的保存地方。———堆栈
 
<bss段>
一个程序编译后分为“数据段”.data和“指令段”.text还有“全局未初始化段”.bss,首先将数据和指令分开是因为,数据段执是可读可写的,而指令段是不可读也不可写,为了防止将指令串改,所以分开存放保险写。
 
<完成量>
struct completion {  
    unsigned int done;/*用于同步的原子量*/  
    wait_queue_head_t wait;/*等待事件队列*/  
};
所谓的完成量能够在互斥访问中激活对应的进程就是靠着wait_queue_head_t 上面睡眠的进程
 
<USB中struct device 和struct interface之间的关系>
举个例子:现代的打印机一般是一个复合设备一般具有“打印”,“扫描”,“复印”等功能这些功能都统筹到一
struct usb_device 的结构体中。但是从Linux设备驱动模型来看,应该将每一个功能划分出一个device出来。这样做就存在一个问题是驱动将变得相当繁琐复杂。于是驱动框架开发者就设计出了interface来代替device的一些功能。
 
<USB固件程序与USB设备驱动>
一般USB固件中包含“出厂信息”,“厂商ID”,"产品ID",主版本号,另USB设备固件中还包含有一组程序用于USB设备的协议处理和设备的读写操作(将数据发送到总线,或将总线上的数据存储到USB设备)。
 
USB设备驱动只是将USB设备规范定义的请求发送给固件程序。
 
usb设备中的 各种*****description 都是在产品出场的时候烧写进去的,当设备接入系统,usb_core 就会去读取这些信息
 
<init进程问题>
Linux中所有进程都是从init进程而来,子进程会复制父进程的“代码段”“数据段”“堆栈段”,那么 子进程和父进程之间就没有什么区别了,但是实际情况不是这样为什呢?
 
<ext2和ext3>
ext2文件系统适用于高速读写
ext3在ext2的基础上增加了记录日志文件的功能
 
<memset()函数>
Linux内核中开辟内存的函数kmolloc()并不将开辟出来的内存中数据清零,所以在编写驱动的时候为某个设设备结构体开辟内存的时候一定要清零。要不然会出现一些稀奇古怪的错误。
 
<非总线上的设备和驱动>
对于Linux中非总线上的设备(比如IIC 控制器,usb控制器),对于这类设备往往是在驱动中完成设备模型的直接将其分配并初始化然后注册进内核。(不像总线驱动和设备,有一个匹配match()和probe())
 
<Linux驱动之串口和USB之间的关系>
a:由上图可以看出UART 和USB串口之间是一种平行关系,并不是包含关系。
b:线路规程的作用,就是进行数据数据封装,因为UART 设备有很多(网卡,蓝牙,wifi ,红外线通信)。针对的设备其数据格式肯定不一样,所以线路规程就是一种以各种协议为基础的数据包装作用。
c:tty的作用,由于存在形形色色的硬件,tty 作为中间层,将硬件和和上层驱动隔离开来提供统一接口(api)
d:各层次关系
<输入子系统和tty 之间的关系>
 
 
<I/O端口>
    很多soc都会进行I/O操作,经常提及I/O空间。所谓的I/O空间就是指外设的各种寄存器(数据寄存器,控制寄存器,状态 寄存器),外设的I/O内存资源的物理地址是已知的,由硬件的设计决定。但是CPU通常并没有为这些已知的外设I/O内存资源的物理地址预定义虚拟地址范围,驱动程序并不能直接通过物理地址访问I/O内存资源,而必须将它们映射到核心虚地址空间内(通过页表),然后才能根据映射所得到的核心虚地址范围,通过访内指令访问这些I/O内存资源。Linux在io.h头文件中声 明了函数ioremap(),用来将I/O内存资源的物理地址映射到核心虚地址空间。
    但要使用I/O内存首先要申请,然后才能映射,使用I/O端口首先要申请,或者叫请求,对于I/O端口的请求意思是让内核知道你要访问这个端口,这样内核知道了以后它就不会再让别人也访问这个端口了.毕竟这个世界僧多粥少啊.申请I/O端口的函数是request_region, 申请I/O内存的函数是request_mem_region。
 
<设备号>
Linux中申请设备号的目的是为了设备文件进行准备。根据主设备号相同次设备号
不同的设备可以使用相同的驱动原理,加强了驱动的复用性
 
<回调函数和一般函数>
A:对普通函数的调用:
调用程序发出对普通函数的调用后,程序执行立即转向被调用函数执行,直到被调用函数执行完毕后,再返回调用程序继续执行。从发出调用的程序的角度看,这个过程为“调用-->等待被调用函数执行完毕-->继续执行”
B:对回调函数调用:
调用程序发出对回调函数的调用后,不等函数执行完毕,立即返回并继续执行。这样,调用程序执和被调用函数同时在执行。当被调函数执行完毕后,被调函数会反过来调用某个事先指定函数,以通知调用程序:函数调用结束。这个过程称为回调(Callback),这正是回调函数名称的由来。
 
<平台设备开发流程>
 
<input设备(输入子系统)概要>
A:输入子系统所有设备公用一个主设备号(13),0_31子设备号的设备公用一个handler()函数
 
由上图可以看出input_handle 在input子系统中起到"总线的作用"将input_device 和input_handler联系起来。
 
 
<windows 应用程序安装机制>
A:在program file 文件中新建安装文件夹(一般是默认)
B:复制相关动态链接库(依赖库)到程序文件夹火系统文件夹(比如system 32)下面,比如dll文件。
C:复制可执行文件到程序文件夹下面。比如(.exe 文件)
D:复制相关配置文件到程序文件夹下或系统文件夹下面。比如ini文件。
E:把启动配置或者程序依赖的配置放到注册表中  
F:如果有自定义的服务程序,注册并启动服务程序、。
 
<linux 应用程序安装机制>
A:在usr文件中新建程序安装文件
B:复制相关的动态链接库(依赖库)到程序安装文件或系统文件(/bin)(Linux 中的动态链接库是.so)
C:复制可执行文件(根据文件权限)程序安装文件夹下面。
D:复制相关配置文件到程序安装文件(一般是usr/”程序文件夹“/etc 或者是/usr/etc 主要是/etc).
E;如果有自定义的服务程序,注册并启动(主要是相关etc文件夹下面的init.d 文件夹)
注:etc 文件夹下面凡是后缀带有rc 的一般都是启动脚本文件
 
<linux 启动机制(Ubuntu)>
A:init文件夹放启动配置文件
B:init.d 文件放启动守护进程
C:Linux启动的时候是以xwindows 还是一字符形式启动取决与启动等级(不同的Linux发行版本同等级效果不一样)
D:一般服务性进程都会安装在/sbin....目录下,但是我们一般都可以在/etc/init.d 目录下找到其映射。如果想要查看配置,可以在/etc.....目录下找到一个同名的.conf 文件(所谓配置:Linux中断 服务也是一种程序,程序就会有相应的配置,比如SSH服务就会配置默认文件传输目录)
 
<国嵌移植系统到tq2440步骤>
A:使用USB转串口线将windows客户机和开发板连接起来(并安装USB转串口驱动)
    注意:这样就可以使secureCRT 软件将开发板和windows 客户机链接起来,接下来会使用该软件进行Linux系统的移植工作。
B:windows 上安装jtag软件,使用该软件将开发板辅助程序(images中的supervivi-128.bin)下载到norflash 中。
C:将红帽企业版6 的usb下载驱动安装到虚拟机中
D:将开发板的启动开关拨到norflash启动,同时将usb下载线和开发板链接,usb转串口线也连接好。
E:打开开发板电源,并使用secureCRT 观察启动情况,并使用选择[v]该选项,这时supervivi-128,将处于等待状态。
F:使用Linux中的usb下载驱动将bootloader (images/Linux/supervivi-128)下载到开发板内存中去。
./dnw filename 30000000 
注:下载完成后,安装辅助程序就会将bootloader移动到nandflash 中
G:在secureCRT 中选择选项[k],进行kernel 下载,此时安装辅助程序处于等待状态
H:进入虚拟机中将kernel(zImage_35) 下载到开发板内存中去。当下载完成后,安装辅助程序再将其移动到nandflash 中去。
./dnw filename 30000000
I:在secureCRT 中选择选项[y],进行文件系统的下载,此时安装辅助程序处于安装等待状态。
J:进入虚拟机将文件系统(root_fsqtopia_qt4)下载到开发板内存中去
./dnw filename 30000000
k:将开发板启动选项开关拨到nandflash。启动开发板。
 
注:为什么需要一个安装辅助程序,因为nandflash 并没有和CPU直接相连,需要通过控制器访问nandflash ,说白了安装辅助程序就是用来控制nandflash的控制器的。也就是说nandflash 并没有参与CPU的统一编址。
 
<GNU 关键字volatile >
a:对于硬件的操作代码中,经常且必须使用该关键字。比如
P1 = 0X010011
P1 = 0X001000
对于上面两个两个语句,对于编译器来讲,就会进行优化,只是执行第二句。在嵌入式开发中,可能这两条语句是设置硬件的两种硬件状态,而不是对内存的同一个单元赋值。
b:对于声明为volatile 的数据,对数据的操作都是基于内存的操作,不会将数据放入到CPU的内部寄存器中做预取处理,这样可以防止内存数据和寄存器数不同步(内部寄存器的数据已经被修改,但是内存中的数据没有更改)
 
 
<linux 系统操作IO内存空步骤>
a:request_men_region()
    申请空间struct resource *request_mem_region(unsigned long start, unsinged long len, char *name) 该函数从start开始分配len字节长的内存空间。实际上是平台设备的资源的动态分配。(注:该函数并不是必须的,但是建议使用,该函数的作用是检查申请的资源是不是可用,如果可用,则申请成功,并标志为申请成功,然后其他驱动再想使用就会申请失败。)
b:ioremap()
    该函数实际上是调用的phy_to_virt() 函数,应为在有操作系统的情况下不能直接操作硬件寄存器,所以需要将其转换成虚拟地址。
c:ioread32()/iowrite32()
d:iounmap()
e:release_men_region()
 
<PCI 设备的访问>
a:什么是PCI 配置空间?
    PCI 配置空间是是指PCI device上的一些寄存器(存在于设备中)。
b:如何访问PCI 配置空间
    cpu首先要访问pci控制器,pci控制器访问pci设备 
    pci设备有3种空间:配置空间、IO空间、mem空间,所以要区分每个pci设备就需要完全区分这3种空间。
    其中mem空间就是pci设备分得的pci总线地址,每一个pci设备分得的pci地址空间是不会重叠的。cpu通过pci总线控制器访问不同的pci地址空间,就能访问到不同的pci设备。
  x86的CPU只有内存和I/O两种空间,没有专用的配置空间,PCI协议规定利用特定的I/O空间操作驱动PCI桥路转换成配置空间的操作。这种机制使用了两个特定的32位I/O空间,即CF8h和CFCh。这两个空间对应于PCI桥路的两个寄存器,当桥路看到CPU在局部总线对这两个I/O空间进行双字 操作时,就将该I/O操作转变为PCI总线的配置操作。寄存器CF8h用于产生配置空间的地址(CONFIG-ADDRESS),寄存器CFCh用于保存 配置空间的读写数据(CONFIG-DATA)。
比较特殊的是pci配置空间,但是没有pci配置空间,也就不可能配置IO空间和mem空间。
每个pci设备(这里只逻辑设备,一个pci物理设备可以有多个逻辑设备,就是所谓的多功能pci设备)的配置空间的地址,是一个32位的地址。由总线号+槽位号+功能号组成。
pci总线控制器决定了pci总线号。
 
<Linux文件系统>
a:什么是inode?
    首先inode块中保存文件系统中全部的inode.在Linux中所有的资源都被当作文件来看待。当系统中添加文件或硬件设备的时候,系统就会在inode块中为该文件或设备分配一个inode节点。这个inode节点中保存了大量的文件属性(注意:有两个文件属性不保存在inode 中,分别是文件名和节点号,原因是inode节点按照顺序排列,所以文件系统就采用了简单的算法,就可以得到inode节点号)。
b:怎么通过inode 访问磁盘上的文件?
    在in偶的节点中存储这一个重要信息——保存了一个包含了13-15位指针元素的数组,这些元素是磁盘块区 的地址。系统就是依靠这些指针定位到磁盘中的文件。所以说inode是问价系统的核心。
c:超级快是什么?
    如果说inode是文件系统的核心,那么超级块就是文件系统是心脏。主要是超级块中保存了全局文件信息(比如:磁盘使用空间,数据块可用空间,inode节点信息)。做个形象是比如,超级块就像是企业是资产负载表,一个文件系统有哪些信息都记录在这个表中。当操作系统启动的时候,操作系统把超级快中的信息复制包内存中,并间断性跟新其中的内容,这就导致内存中的超级块和硬盘中的超级块有可能是不同步的,如果出现意外掉电导致内存中的信息没有来得及写入磁盘,会导致系统不稳定。工程师往往使用命令sysn将没来的急写入超级块中的信息写入磁盘,重新开机会对比其中的信息并更新。这也是Linux比windows更加稳定的原因。
 
<ARM MMU虚拟地址转物理地址>
a:转换原理图
b:TTB(转换页表基地址)
    这个基地址是由工程师来规定,该地址存在CP15 (总共有16个32位的寄存器)的C2中。
 
c:translation table
   MMU会利用这张表来索引物理地址,系统首先使用虚拟地址的高12位[31-20],结合TTB索引到一级页表的位置。
根据索引的一级页表的后2位[1-0]来判断如何索引二级页表。
00:该次转换无效
01:粗页转换
10:段转换
    截取该一级页表的高12位作为物理地址的高12位(寻址1M)作为基地址寻址,虚拟地址的低20位[19-0]作为偏移。 
11:细页转换
   细页转细页转换也是Linux系统采用的方式。截取一级页表的高20位[31-20]作为二级页表的基地址的索引。利用虚拟地址的中间10位[19-10],作为二级页表的索引。根据表项的最后两位判断是1k/4k/64k的页表
        00:无效转换
        01:64k
        10:4k
        11:1k
        然后再根据虚拟地址的后10[9-0]位索引到物理地址.
 
<CP15协处理器的访问>
MCR{<cond>} <p>,<opcode_1>,<Rd>,<CRn>,<CRm>{,<opcode_2>}
MCR{<cond>} p15,0,<Rd>,<CRn>,<CRm>{,<opcode_2>}
其中,<cond>为指令执行的条件码。当<cond>忽略时指令为无条件执行。
 
<opcode_1>为协处理器将执行的操作的操作码。对于CP15协处理器来说,< opcode_1>永远为0b000,当< opcode_1>不为0b000时,该指令操作结果不可预知。
 
<Rd>作为源寄存器的ARM寄存器,其值将被传送到协处理器寄存器中。
 
<CRn>作为目标寄存器的协处理器寄存器,其编号可能是C0,C1,…,C15。
 
<CRm>和<opcode_2>两者组合决定对协处理器寄存器进行所需要的操作,如果没有指定,则将为<CRm>为C0,opcode_2为0,否则可能导致不可预知的结果。
<makefile 注解>
    a:编译驱动模块
obj-m: 编译成内核模块
obj-y: 编译进内核
obj-n:不编译
 
 
<2440 内存起始地址为什么是0x30000000>
该芯片总共有27根地址总线,和8根片选信号线。CPU利用这几根线对外部的RAM和ROM进行编址。RAM的基地址被被设定为0x30000000。(注意:CPU需要通过存储控制器才能访问外部的rom和ram。)
 
<并发访问注意事项(互斥)>
    任何拥有锁的代码都必须是原子的,不能休眠。
a:自旋锁:
    (1)获得锁是要注意不能调用会导致休眠的API。
    (2)拥有自旋锁之前必须禁止本地中断。
b:原子变量
    原子变量不能是一个大于24位的数据。
 
<等待队列头和等待队列>
等待队列的实现
(1)双向列表:
struct list_head {
struct list_head *next, *prev;
};
(2)等待队列头:
struct __wait_queue_head {
spinlock_t lock;
struct list_head task_list;
};
typedef struct __wait_queue_head wait_queue_head_t;
(3)等待队列:
struct __wait_queue {
unsigned int flags;
#define WQ_FLAG_EXCLUSIVE0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
};
 
<enum经常使用的地方>
enum 是一种用在大规模使用define定义常量的时候取代define。
比如有些地方要定义一个星期:
#define  1 Mon;
#define  2 Tue;
#define   3 Wed;
#define   4 Thu;
#define    5 Fri;
#define   6  Sat;
#define    7  Sun;
定义7个还好,但是多了就显得麻烦了,这时候可以使用enum代替。
 
<union的使用>
a:先说struct的定义
struct student
{
     char mark;
     long num;
     float score;
};
该结构体在内存中的分布方式:
调用函数:sizeof(struct student) =12;
b:再说union的定义
union test
{
    char mark;
    long num;
    float score;
}
该结构体在内存中的分布:

 调用函数sizeof(union test) = 4;
c:总结
struct 会为该结构体中的所有变量分配相印的内存,然而union 只会分配该结构体中的定的数据中占用内存最大的一个,并且只会保存最后写入该内存中的数据,覆盖之前的数据。
 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

 
 
 
 

linux驱动之一语点破天机的更多相关文章

  1. linux 驱动学习笔记01--Linux 内核的编译

    由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...

  2. Linux驱动设计—— 中断与时钟

    中断和时钟技术可以提升驱动程序的效率 中断 中断在Linux中的实现 通常情况下,一个驱动程序只需要申请中断,并添加中断处理函数就可以了,中断的到达和中断函数的调用都是内核实现框架完成的.所以程序员只 ...

  3. linux驱动面试题整理

    1.字符型驱动设备你是怎么创建设备文件的,就是/dev/下面的设备文件,供上层应用程序打开使用的文件? 答:mknod命令结合设备的主设备号和次设备号,可创建一个设备文件. 评:这只是其中一种方式,也 ...

  4. Linux代码的重用与强行卸载Linux驱动

    (一)Linux代码的重用 重用=静态重用(将要重用的代码放到其他的文件的头文件中声明)+动态重用(使用另外一个Linux驱动中的资源,例如函数.变量.宏等) 1.编译是由多个文件组成的Linux驱动 ...

  5. Linux驱动学习之常用的模块操作命令

    1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...

  6. Linux驱动学习之驱动开发准备工作

    一.开启驱动开发之路 1.驱动开发的准备工作 (1)正常运行linux系统的开发板.要求开发板中的linux的zImage必须是自己编译的,不能是别人编译的.原因在于在安装模块的时候会进行安全性校验 ...

  7. Linux驱动学习之什么是驱动?

    一.什么是驱动? 1: 驱动一词的字面意思 2: 物理上的驱动 3: 硬件中的驱动 4: linux内核驱动.软件层面上的驱动广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序. ...

  8. 嵌入式Linux驱动开发日记

    嵌入式Linux驱动开发日记 主机硬件环境 开发机:虚拟机Ubuntu12.04 内存: 1G 硬盘:80GB 目标板硬件环境 CPU: SP5V210 (开发板:QT210) SDRAM: 512M ...

  9. linux驱动程序设计的硬件基础,王明学learn

    linux驱动程序设计的硬件基础(一) 本章讲总结学习linux设备程序设计的硬件基础. 一.处理器 1.1通用处理器 通用处理器(GPP)并不针对特定的应用领域进行体系结构和指令集的优化,它们具有一 ...

随机推荐

  1. 微服务深入浅出(6)-- 熔断器Hystrix

    概念 在分布式系统中,一种不可避免的情况就是某些服务会出现故障,导致依赖他们的其他服务出现远程调度的线程问题(雪崩效应).而Hystrix提供的熔断器,通过隔离服务的访问点,能阻止这种分布式系统中出现 ...

  2. zabbix lld使用trapper方式(zabbix_sender)

    自动发现脚本文件输出格式: { "data": [ { "{#BIND_PERF}": "BIND INCOMING QUERY" }, { ...

  3. Linux基础-free窥内存-dd探硬盘

    监控内存篇(RAM)-free free指令可以很直观的看到内存的使用情况 free -m指令以单位为MB的方式查看内存的使用情况(free命令读取的文件是/proc/meminfo) 这个表格的解释 ...

  4. 用Nginx分流绕开Github反爬机制

    用Nginx分流绕开Github反爬机制 0x00 前言 如果哪天有hacker进入到了公司内网为所欲为,你一定激动地以为这是一次蓄谋已久的APT,事实上,还有可能只是某位粗线条的员工把VPN信息泄露 ...

  5. 对接微信支付使用HMAC-SHA256使用签名算法实现方式

    最近做微信押金支付对接,很多坑,心累!这里提醒一下各位: 首先,确保自己商户号进了白名单,没有需要联系客服,否则接口是调不通的,会一直提示参数错误 其次,确保接口文档是最新的,最好去官网去看,否则可能 ...

  6. npm 安装 electron 超时

    由于某些不可描述的原因,俺的某个小项目要用客户端桌面应用,后台那还是 php 了.经广大的群友指导,发现了 Electron 这个项目.它可以用 html, css, javascript 构建跨平台 ...

  7. Linux下C程序的反汇编【转】

    转自:http://blog.csdn.net/u011192270/article/details/50224267 前言:本文主要介绍几种反汇编的方法. gcc gcc的完整编译过程大致为:预处理 ...

  8. C# 执行固定个数任务自行控制进入线程池的线程数量,多任务同时但是并发数据限定

    思路来源:http://bbs.csdn.NET/topics/390819824,引用该页面某网友提供的方法. 题目:我现在有100个任务,需要多线程去完成,但是要限定同时并发数量不能超过5个. 原 ...

  9. 【Android开发日记】之入门篇(十二)——Android组件间的数据传输

    组件我们有了,那么我们缺少一个组件之间传递信息的渠道.利用Intent做载体,这是一个王道的做法.还有呢,可以利用文件系统来做数据共享.也可以使用Application设置全局数据,利用组件来进行控制 ...

  10. web性能优化之js图片懒加载

    html <div class="container"> <ul> <li> <div id="first" clas ...