电信主站 网通分站
购买流程 付款方式 常见问题 在线提问 续租服务 购物车
用户名: 密 码: 忘记密码?
首 页
域名注册
虚拟主机
双线主机
服务器租用
VPS主机
企业邮局
代理专区
客服中心
虚拟主机行业资讯 虚拟主机评测对比 互联网最新动态 技术学院 站长资讯 在线教程 网站运营
搜索优化 服务器 网络编程 图形图象 站长之家 网页制作 操作系统
冲浪宝典 软件教学 视频通信 办公软件 邮件系统 网络安全 认证考试
您当前位置:西部数码->资讯中心-> 服务器
linux驱动程序设计
作者:未知 点击:0
  西部数码-全国虚拟主机10强!20余项虚拟主机管理功能,全国领先!第6代双线路虚拟主机,南北访问畅通无阻!虚拟主机可在线rar解压,自动数据恢复设置虚拟目录等.虚拟主机免费赠送访问统计,企业邮局.Cn域名注册10元/年,自助建站480元起,免费试用7天,满意再付款!P4主机租用799元/月.月付免压金!
文章页数:[1] 
 
PROGRAM FOR BLOCK DEVICE DRIVER OF DEVFS TYPE


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

A.核心数据结构
struct file_operations fops 设备驱动程序接口
struct file_operations {
struct module *owner;
loff_t (*llseek) (struct file *, loff_t, int);
ssize_t (*read) (struct file *, char *, size_t, loff_t *);
ssize_t (*write) (struct file *, const char *, size_t, loff_t *);
int (*readdir) (struct file *, void *, filldir_t);
unsigned int (*poll) (struct file *, struct poll_table_struct *);
int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long);
int (*mmap) (struct file *, struct vm_area_struct *);
int (*open) (struct inode *, struct file *);
int (*flush) (struct file *);
int (*release) (struct inode *, struct file *);
int (*fsync) (struct file *, struct dentry *, int datasync);
int (*fasync) (int, struct file *, int);
int (*lock) (struct file *, int, struct file_lock *);
ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
};


block_device_operations 块设备驱动程序接口
{ int (*open) (struct inode *, struct file *);
int (*release) (struct inode *, struct file *);
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
int (*check_media_change) (kdev_t);
int (*revalidate) (kdev_t);
struct module *owner;
};块设备的READ().WRITE()不在这里注册,而是在设备的读写请求队列里注册,内核在这里将调用通用的blk_read(),blk_write().向读写队列
发出读写请求.

Linux 利用这些数据结构向内核注册open(),release(),ioctl(),check_media_change(),rvalidate()等函数的入口句柄.
我们将要编写的open(),release(),ioctl(),check_media_change(),revalidate()等函数,将在驱动初始化的时候,
通过一个此结构类型的变量向内核提供函数的 入口.

struct request_queue_t 设备请求队列的数据结构
struct request_list {
unsigned int count;
unsigned int pending[2];
struct list_head free;
};
struct request {
struct list_head queue;
int elevator_sequence;
kdev_t rq_dev;
int cmd; /* READ or WRITE */
int errors;
unsigned long start_time;
unsigned long sector;
unsigned long nr_sectors;
unsigned long hard_sector, hard_nr_sectors;
unsigned int nr_segments;
unsigned int nr_hw_segments;
unsigned long current_nr_sectors, hard_cur_sectors;
void * special;
char * buffer;
struct completion * waiting;
struct buffer_head * bh;
struct buffer_head * bhtail;
request_queue_t *q;
};

struct request_queue
{
/*
* the queue request freelist, one for reads and one for writes
*/
struct request_list rq;

/*
* The total number of requests on each queue
*/
int nr_requests;

/*
* Batching threshold for sleep/wakeup decisions
*/
int batch_requests;

/*
* The total number of 512byte blocks on each queue
*/
atomic_t nr_sectors;

/*
* Batching threshold for sleep/wakeup decisions
*/
int batch_sectors;

/*
* The max number of 512byte blocks on each queue
*/
int max_queue_sectors;

/*
* Together with queue_head for cacheline sharing
*/
struct list_head queue_head;
elevator_t elevator;

request_fn_proc * request_fn;
merge_request_fn * back_merge_fn;
merge_request_fn * front_merge_fn;
merge_requests_fn * merge_requests_fn;
make_request_fn * make_request_fn;
plug_device_fn * plug_device_fn;
/*
* The queue owner gets to use this for whatever they like.
* ll_rw_blk doesn't touch it.
*/
void * queuedata;

/*
* This is used to remove the plug when tq_disk runs.
*/
struct tq_struct plug_tq;

/*
* Boolean that indicates whether this queue is plugged or not.
*/
int plugged:1;

/*
* Boolean that indicates whether current_request is active or
* not.
*/
int head_active:1;

/*
* Boolean that indicates you will use blk_started_sectors
* and blk_finished_sectors in addition to blk_started_io
* and blk_finished_io. It enables the throttling code to
* help keep the sectors in flight to a reasonable value
*/
int can_throttle:1;

unsigned long bounce_pfn;

/*
* Is meant to protect the queue in the future instead of
* io_request_lock
*/
spinlock_t queue_lock;

/*
* Tasks wait here for free read and write requests
*/
wait_queue_head_t wait_for_requests;

struct request *last_request;
};

缓冲区和对缓冲区相应的I/O操作在此任务队列中相关联,等待内核的调度.如果是字符设备就不需要此数据结构.而
块设备的read(),write()函数则在buffer_queue的initize和设备请求队列进行处理请求时候传递给request_fn().
struct request_queue_t{}设备请求队列的变量类型,驱动程序在初始化的时候需要填写request_fn().

其他的数据结构还有 I/O port,Irq,DMA 资源分配,符合POSIX标准的ioctl的cmd的构造和定义,以及描述设备自身的
相关数据结构定义-如设备的控制寄存器的相关数据结构定义,BIOS里的参数定义,设备类型定义等.

B.初始化和注册和注消,模块方式驱动程序的加载和卸载.

设备驱动程序在定义了数据结构后 ,首先开始初始化:
如I/O 端口的检查和登记,内核对 I/O PORT的检查和登记提供了两个 函数check_region(int io_port, int off_set)
和request_region(int io_port, int off_set,char *devname).I/O Port登记后,就可以用inb()和outb()进行操作了 .

还有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.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!
相关主题
文章页数:[1] 
Google
热门文章
·LINUX学习笔记--FTP服务器设置篇
·在内核2.6.0-test中安装最新驱动NVIDIA 1.0-4620(共三种方法)
·无软驱和光驱安装Redhat方法
·如何通过PXE的方式远程安装linux(本地无 光 , 软驱)
·网络安装的一点实践
·VI 快速上手
·Linux下Apache并发连接数和带宽控制
·轻轻松松的安装Slackware Linux -- 5.其他非标准安装程序解析
·在Linux下建立强大的FTP搜索引擎(二
·Iptables来限制上QQ

最新文章
·造成服务器不稳定的因素有以下七点
·机房是海外服务器安全稳定重要因素
·UniCache 行业垂直门户网站加速方案
·VPS服务器是主机业务的革命性技术
·如何选好虚拟主机的五个关键细节
·虚拟化技术会造成服务器市场的低迷吗?
·IP KVM打造“保姆”服务的IDC机房
·服务器能耗吞噬资源 优化数据中心
·ASP.NET2.0服务器控件之捕获回传事件
·服务器虚拟化必须考虑的十大重要因素


 
 


版权申明:本站文章均来自网络,如有侵权,请联系我们,我们收到后立即删除,谢谢!

特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有。
  打印  刷新  关闭
返回首页 |关于我们 | 联系我们 | 付款方式 | 创业联盟 | 虚拟主机 | 资讯中心 | 友情链接 | 网站地图

版权所有 西部数码(www.west263.com)
CopyRight (c) 2002~2006 west263.com all right reserved.
公司地址:四川成都市万和路90号天象大厦4楼 邮编:610031
电话总机:028-86262244 86263048 86263408 86263960 86264018 86267838
售前咨询:总机转201 202 203 204 206 208
售后服务:总机转211 212 213 214
财务咨询:总机转224 223 传真:028-86264041 财务QQ:点击发送消息给对方635483282
售前咨询QQ:点击发送消息给对方2182518 点击发送消息给对方241975952 点击发送消息给对方275026793 点击发送消息给对方408235859
售后服务QQ:点击发送消息给对方17708515 点击发送消息给对方307742704 点击发送消息给对方287976517 点击发送消息给对方363783715
《中华人民共和国增值电信业务经营许可证》编号:川B2-20030065号