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里的参数定义,设备类型定义等.