linux驱动程序设计


PROGRAM FOR BLOCK DEVICE DRIVER OF DEVFS TYPE


对linux的devfs类型的驱动程序的编写可以从以下几大内容理解和入手:
通过分析驱动程序源代码可以发现驱动程序一般可分三部分:
核心数据结构;核心数据和资源的初始化,注册以及注消,释放;底层设备操作函数;

还有DMA和Irq的初始化检查和 登记,
int request_irq(unsigned int irq ,void(*handle)(int,void *,struct pt_regs *),unsigned int long flags,

const char *device);

irq: 是要申请的中断。

handle:中断处理函数指针。

flags:SA_INTERRUPT 请求一个快速中断,0 正常中断。

device:设备名。

如果登记成功,返回0,这时在/proc/interrupts文件中可以看你请求的中断。

DMA主要是在内存中分配交换内存空间.还有缓冲区,设备请求队列的初始化.

还有设备控制寄存器的检查和初始化,还有对设备自身相关的数据结构的初始化,填写一些设备特定的数据等.

然后,开始注册
devfs_register()向VFS注册统一的设备操作函数.
static struct file_operations XXX_fops = {
owner: THIS_MODULE, XXX_fops所属的设备模块
read: XXX_read, 读设备操作
write: XXX_write, 写设备操作
ioctl: XXX_ioctl, 控制设备操作
mmap: XXX_mmap, 内存重映射操作
open: XXX_open, 打开设备操作
release: XXX_release 释放设备操作
/* ... */
};


blk_init_queue()队列初始化函数.
request_irq()中断注册函数
相应的注消函数:
devfs_unregister (devfs_handle_t de){};
free_irq()释放中断,I/O资源,释放缓冲区,释放设备,请求队列,VFS节点等.

模块方式驱动程序的加载和卸载.

static int __init _init_module (void)
{
/* ... */
}

static void __exit _cleanup_module (void)
{

}

/* 加载驱动程序模块入口 */
module_init(_init_module);

/* 卸载驱动程序模块入口 */
module_exit(_cleanup_module);


_intrrupt()
设备发生中断时的处理程序.
{
1.对共享中断的处理;
2.对spinlock以及其他的事务的处理;
}

C. 底层设备操作函数的编写
read().write(),open(),release(),check_media_change(),revalidate()等.


open()和release()

打开设备是通过调用file_operations结构中的函数open( )来完成的,它是驱动程序用来为今后的操作完成初始化准备工作的。在大部分驱动程序中,open( )通常需要完成下列工作:

1. 检查设备相关错误,如设备尚未准备好等。
2. 如果是第一次打开,则初始化硬件设备。
3. 识别次设备号,如果有必要则更新读写操作的当前位置指针f_ops。
4. 分配和填写要放在file->private_data里的数据结构。
5. 使用计数增1。

释放设备是通过调用file_operations结构中的函数release( )来完成的,这个设备方法有时也被称为close( ),它的作用正好与open( )相反,通常要完成下列工作:

1. 使用计数减1。
2. 释放在file->private_data中分配的内存。
3. 如果使用计算为0,则关闭设备。

read()和 write()

字符设备的读写操作相对比较简单,直接使用函数read( )和write( )就可以了。但如果是块设备的话,则需要调用函数block_read( )和block_write( )来进行数据读写,这两个函数将向设备请求表中增加读写请求,以便Linux内核可以对请求顺序进行优化。由于是对内存缓冲区而不是直接对设备进行操作的,因此能很大程度上加快读写速度。如果内存缓冲区中没有所要读入的数据,或者需要执行写操作将数据写入设备,那么就要执行真正的数据传输,这是通过调用数据结构blk_dev_struct中的函数request_fn( )来完成的。

ioctl()--将cmd进行解释,并送到设备的控制寄存器.事实上,read()和write()也要通过ioctl()来完成操作的 .
ioctl(){
CASE CMD{
SWITCH CASE1:{...};
SWITCH CASE2:{...};
SWITCH CASE N:{...};
.
.
DEFAULT : {...};
}
END CASE
总结:
我们可以看出一个linux的驱动程序通常包含如下:
初始化设备模块、
{I/O port ,DMA.Irq,内存 buffer,初始化并且填写具体设备数据结构,注册 fops的具体函数等等 }
中断处理模块、设备释放模块、设备卸载模块
设备打开模块、数据读写和控制模块、
驱动装载模块、驱动释放模块.

 

原文地址:http://www.linuxidc.com/Linux/2007-10/8397p2.htm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值