为什么要将驱动和应用分开?都是操作变量(驱动操作的寄存器变量【应用层也可以去设法去操作】变成二进制时,通过形成不同的0和1去访问不同的门电路,最后将某一硬件引脚拉高拉低)。
答:普通应用和驱动所在的用户模式不同,导致在代码允许中使用的cpu寄存器不同,可以有效防止当应用进程当机影响到内核的正常运行。
1.常规分类:1.1字符设备:最小访问单位为一个字节,支持open,close, read,write 等系统调用。例:串口,按键,led
1.2 块设备:最小访问单位为块(通常为512字节),不能按字节 访问。但是Linux允许块设备按任意字节访问,因此,块设备与字符设备的区别为接口不同,硬盘,flash,SD卡。
1.3 网络接口:用来接收和发送数据报文,可以是硬件接口如:eth0(网卡),也可以是软件接口如LO(回环接口模拟的网卡)。
2.总线分类:usb设备,pci设备,平台总线设备。
3.学习方法:3.1 驱动模型 3.2 硬件操作 3.3编写应用程序测试驱动
3.1硬件访问流程:先将物理地址映射到虚拟地址,然后操作虚拟地址(寄存器)。
3.1.1 动态映射 :使用函数 void * ioremap(physaddr, size)
physaddr:物理地址 size 长度 返回虚拟地址
3.1.2 静态映射 :一个静态映射就有一个结构体来保存映射关系,然后在内核代码中有一个这样的结构体数组,保存了所有静态映射结构体,在内核中调用映射初始化函数时,将这个结构体作为参数就又可以实现静态映射了。单个结构体如下:
struct map_desc {
unsigned long virtual; /* 映射后的址虚拟地址 */
unsigned long pfn; /* 物理地址所在的页帧号*/
unsigned long pfn; /* 物理地址所在的页帧号*/
unsigned long length; /* 度映射长度 */
unsigned int type; /* 映射的设备类型 */
};
pfn: 利用__phys_to_pfn(物 物 理地址) 可以计算出物
理地址所在的物理页帧号
3.1.3 访问虚拟地址:通过系统给的读写函数就能访问虚拟地址。
unsigned ioread8(void *addr)
unsigned ioread16(void *addr)
unsigned ioread32(void *addr)
unsigned readb(address)
unsigned readw(address)
unsigned readw(address)
unsigned readl(address)
void iowrite8(u8 value, void *addr)
void iowrite16(u16 value, void *addr)
void iowrite32(u32 value, void *addr)
void writeb(unsigned value, address)
void writew(unsigned value, address)
void writel(unsigned value, address)
4.设备驱动模型分为:驱动模块初始化 实现设备操作 驱动注销 三步
4.1.驱动模块初始化分为:
4.1.1 分配设备的描述结构:不同的设备驱动类型,其描述结构不同
4.1.2 初始化描述结构
4.1.3 注册设备描述结构
4.1.4 硬件初始化
5.驱动执行生效的三个大步骤:编写好驱动模块编译好安装到开发板
建立与驱动模块对应的的设备驱动文件
编写应用程序对驱动文件进行读写操作