嵌入式linux驱动开发流程

转载自http://blog.163.com/qwz_007@126/blog/static/3701811920141895541695/,感谢原做者
嵌入式linux驱动开发流程
嵌入式系统中,操做系统是经过各类驱动程序来驾驭硬件设备的。设备驱动程序是操做系统内核和硬件设备之间的接口,它为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,能够像操做普通文件同样对硬件设备进行操做。设备驱动程序是内核的一部分,完成如下功能:
◇ 驱动程序的注册和注销。
◇ 设备的打开和释放。
◇ 设备的读写操做。
◇ 设备的控制操做。
◇ 设备的中断和轮询处理。
Linux主要将设备分为三类:字符设备、块设备和网络设备。字符设备是指发送和接收数据以字符的形式进行,没有缓冲区的设备;块设备是指发送和接收数据以整个数据缓冲区的形式进行的设备;网络设备是指网络设备访问的BSD socket 接口。下面以字符设备为例,写出其驱动编写框架:
1、 编写驱动程序初始化函数
  驱动程序的初始化在函数xxx_init()中完成,包括对硬件初始化、中断函数、向内核注册驱动程序等。
  首先理解硬件结构,搞清楚其功能,接口寄存器以及CPU怎么访问控制这些寄存器等。
  其次向内核注册驱动程序。设备驱动程序能够直接编译进内核,在系统启动的时候初始化,也能够在须要的时候以模块的方式动态加载到内核中去。每一个字符设备或是块设备都是经过register_chrdev()函数注册,调用该函数后就能够向系统申请主设备号,操做成功,设备名就会出如今/proc/devices里。
  此外,在关闭设备时,须要先解除原先设备的注册,须要有清除函数,在xxx_exit()中经过unregister_chrdev()函数在实现,此后设备就会从/proc/devices里消失。
  当驱动程序被编译成模块时,使用insmod加载模块,模块的初始化函数xxx_init()被调用,向内核注册驱动程序;使用rmmod卸载模块,模块的清除函数xxx_exit()被调用。
2、 构造file_operations结构中要用到的各个成员函数
  Linux操做系统将全部的设备都当作文件,以操做文件的方式访问设备。应用程序不能直接操做硬件,使用统一的接口函数调用硬件驱动程序,这组接口被成为系统调用。每一个系统调用中都有一个与之对应的函数(open、release、read、write、ioctl等),在字符驱动程序中,这些函数集合在一个file_operations类型的数据结构中。以一个键盘驱动程序为例:
struct file_operations Key7279_fops =  
{
.open = Key7279_Open,  
.ioctl = Key7279_Ioctl,  
.release = Key7279_Close,
.read = Key7279_Read,
};
一、 设备的打开和释放
  打开设备是由open()函数来完成,在大部分设备驱动中open完成以下工做:
  ◇ 递增计数器
  ◇ 检查特定设备的特殊状况
  ◇ 初始化设备
  ◇ 识别次设备号
  释放设备由release()函数来完成。当一个进程释放设备时,其它进程还能继续使用该设备,只是该进程暂时中止对该设备的的使用,而当一个进程关闭设备时,其它进程必须从新打开此设备才能使用。Release完成以下工做:
◇ 递减计数
◇ 在最后一次释放设备操做时关闭设备
二、 设备的读写操做
  读写设备的主要任务就是把内核空间的数据复制到用户空间,或者是从用户空间复制到内核空间,也就是将内核空间缓冲区里的数据复制到用户空间的缓冲区中或者相反。字符设备使用各自的read()函数和write()函数来进行数据读写。
三、 设备的控制操做
大部分设备除了读写能力,还可进行超出简单的数据传输以外的操做,因此设备驱动也必须具有进行各类硬件控制操做的能力. 这些操做经常经过 ioctl 方法来支持。与读写操做不一样,ioctl()的用法与具体设备密切相关。以键盘Key7279_Ioctl为例:
static int Key7279_Ioctl(struct inode *inode,struct file *file,unsigned int cmd, unsigned long arg)
{
switch(cmd)  
  {
  case Key7279_GETKEY:
return key7279_getkey();
  default:
  printk("Unkown Keyboard Command ID.\n");
  }
  return 0;
}
  cmd的取值及含义都与具体的设备有关,除了ioctl(),设备驱动程序还可能有其余控制函数,好比llseek()等。
  当应用程序使用open、release等函数打开某个设备时,设备驱动程序的file_operations结构中的相应成员就会被调用。
3、设备的中断和轮询处理
  对于不支持中断的设备,读写时须要轮询设备状态,以及是否须要继续进行数据传输。例如,打印机。若是设备支持中断,则可按照中断方式进行。
模块在使用中断前要先请求一个中断通道(或者 IRQ中断请求),并在使用后释放它。经过request_irq()函数来注册中断,free_irq()函数来释放。
4、驱动程序的测试
  对驱动程序的调试能够经过打印的方式来进行,就是经过在驱动程序中添加printk()打印函数,来跟踪驱动程序的执行过程,以此来判断问题。
  以上是我根据本身的学习总结的,可能写的比较简单,对于比较复杂的驱动函数,会添加更多的函数,可是大致的框架就是这样了。