Linux2.6.32驱动笔记(1)驱动开发概述及硬件访问技术

来源:互联网 发布:淘宝查权重 编辑:程序博客网 时间:2024/06/04 23:11

摘要:介绍了linux下驱动的分类和学习方法,描述了linux下硬件访问的思路和具体实现方法。

一、linux下设备驱动分类

     linux系统的设备常规分为字符设备(char device),块设备(block device)和网络设备(network device),对应的驱动也分为这三类。

    字符设备:字符设备是一种按照字节来访问的设备,并且存取时没有缓存设备。这样的驱动通常用来实现open,read,write和close系统调用,字符设备包括:串口,LED,按键等。

    块设备:linux允许块设备传送任意字节的数据,可以是一个字节一个字节,也可以是一块一块例如512字节,他们的主要区别在于块设备使用了缓存来支持,并且能够随机存取,块设备驱动与内核的接口是和字符设备不同的。常见的块设备包括flash,sd卡,cd等等。

    网络接口:网络接口设备驱动主要是基于socket机制,主要是负责发送和接收数据报文,在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据传递,网络接口设备包括例如eth0这样的硬件网卡,也可以是回环loop这样的纯软件。

另外,按照总线方式的不同,还可以分为USB设备,PCI设备和平台总线设备。

 

二、驱动学习方法

    第一:驱动模型

    用自己的话理解吧,其实内核里面,各个驱动的模型是比较固定的,学习的时候按照这个模式先去往里填,框架熟悉了,就能摸索出一点心得出来。大致我认为驱动学习,百分之三十要归结到模型上,百分之三十在内核,剩下的百分之四十是要对硬件的操作比较熟悉,因为驱动驱动,驱动到最后一定要操作硬件(也有软件模型比如loop),你对外设有多少的掌握和理解,时序,寄存器,读写方式,中断等等,驱动为什么难,难就难在需要一个系统的思维去学习,对底层硬件的东西掌握需要比较多,还要对内核对驱动的支持机制掌握,然后编写驱动的时候要遵照模型,驱动写完了还得写应用测试程序。

    第二:硬件操作

    这个刚才已经说了,比如你要驱动一个按键,首先按键的操作方式要了解,起码看得懂硬件连接,高低电平,按键对应的I/O口物理地址,寄存器配置方式,轮询肯定不行了,那就得要用中断,内核对中断的机制是如何的,还有访问硬件有哪些方式,我们按键对应的物理地址如何对应到我在驱动中操作的虚拟地址,等等这些。按键只是个最最简单的比方,后面IIC,SPI,网络驱动,有时候难度并不在驱动本身了,而是你对他们的理解,比如通信协议,需要ACK,需要校验,怎么发,怎么收,发到哪里,谁去接受等等等等。所以好的驱动工程师,个人认为跟你编写过的外设驱动数量和种类是有很大关系的。

    第三:测试程序

    驱动写好了,就要编写测试程序来测试这个驱动是否可用,这时候就需要对驱动接口比较了解,还要考虑是否有什么小的问题,响应时间,内存占用等等,这部分其实是应用程序开发的功力。

   

三、硬件访问技术

    要对设备进行控制,实际上是控制设备的寄存器,如何访问这些硬件设备,实际上就是探讨如何访问寄存器。做到这样需要两步:第一,地址映射;第二:读写寄存器。

    地址映射

    因为s3c2440给出的是物理地址,而我们使用的需要虚拟地址,所以必须要先完成物理地址到虚拟地址的转化,转化分为动态映射方式和静态映射方式。

   

    动态映射方式函数:void *ioremap(physaddr,size)

    函数原型:void *__ioremap(unsigned longphys_addr,unsigned long size,unsigned long flags)

    函数功能:将phys_addr指向的物理地址映射size字节大小到虚拟地址空间,返回值为该段虚拟地址的起始地址。

返回值:映射后的虚拟地址。

phys_addr:要映射的起始的I/O地址。

    size:要映射的空间大小。

    flags:要映射的I/O空间的权限有关的标志。

   

    静态映射方式就是根据用户指定,在linux内核启动的时候就会自动的将某些物理地址和虚拟地址应设好了。首先是填充一个结构体,然后是通知内核。

    用户通过map_desc结构来指明物理地址与虚拟地址的映射关系。

    structmap_desc{

    unsignedlong virtual;

    unsignedlong pfn;

    unsignedlong length;

    unsignedint type;

}

    virtual:映射后的虚拟地址。

pfn:利用__phys_to_pfn(物理地址)可以计算出物理地址所在的物理页帧号。

    length:映射的长度。

    type:映射的设备类型。

   

    读写寄存器

    完成地址映射以后,内核提供了一组用来访问寄存器的函数,如下:

    读I/O内存,8,16,32就是一个字节,两个字节,四个字节的意思。

    unsignedioread8(void *addr)

    unsignedioread16(void *addr)

    unsignedioread32(void *addr)

    unsignedreadb(address)

    unsignedreadw(address)

    unsignedreadl(address)

   

    写I/O内存,同上:

    voidiowrite8(u8 value,void *addr)

    voidiowrite16(u16 value,void *addr)

    voidiowrite32(u32 value,void *addr)

    voidwriteb(unsigned value,address)

    voidwritew(unsigned value,address)

    voidwritel(unsigned value,address)

   

    这篇帖子就到这里吧,如有不正确的地方还请指出,大家共同进步。


0 0
原创粉丝点击