块设备
---------------------------------------------
主要特点是:任意寻址
1.块设备是基于磁盘设备出来的,所以它很大一部分实现是优化I/O请求。
2.分区,类型:主分区,扩展分区
3.文件,文件系统(要放文件就必须有文件系统)
.-----------------.
| register_blkdev |
'-----------------'
|
v
.-----------------.
| alloc_disk | (次设备号的数量)也就是分区数
'-----------------'
|
v
.-----------------.
| 初始化 |
'-----------------'
|
v
.-----------------.
| add_disk |
'-----------------'
|
v
.-----------------.
|unregister_blkdev|
'-----------------'
|
v
.-----------------.
| del_gendisk |
'-----------------'
初始化部分:
-------------------------------------------------
test.gd->major = TEST_MAJOR; 主设备号
test.gd->first = 0; 次设备号的开始号
test.gd->fops = &test_ops; ops
test.gd->queue = blk_init_queue(request_proc, &test.lock);
我们申请的请求队列,request_proc处理请求,为什么我们后面还要有个自旋锁呢?因为请求队列的竞态有可能发生在操作系统底层,和驱动上层,为了防止重复锁。
strcpy(test.gd->disk_name,"test");
可以在/proc/devices中看到这个名字,我们在/dev下面不用自己建立设备文件,系统帮我们建立。
set_capacity(test.gd, TEST_NSECTORS);
设置这个磁盘有多大,这里的单位是扇区数,每个扇区内核规定是512B。如果设备的扇区不是512B,驱动要自己处理,做一个转换,欺骗内核。
test.gd->private_data = &test;
test.data = vmalloc(SECTOR_SIZE*TEST_NSECTORS);
memset(test.data, 0x00, SECTOR_SIZE*TEST_NSECTORS);
-------------------------------------------------
在旧内核中一般有一个ioctl的命令GETGEO来得到磁头数,磁道扇区数,柱面数,开始扇区号。
在新内核中在block_device_operations现在有一个成员.getgeo来代替ioctl这个命令。
int test_getgeo(struct block_device *dev, struct hd_geometry *geo)
{
/* heads : 磁头数 , 盘面数 */
/* sectors: 每个磁道的扇区数 */
/* cylinders; 柱面数, 每个盘面的磁道数 */
/* start: 开始扇区号 */
/* 一个盘面的扇区数 = 每盘磁道数 x 每磁道的扇区数 */
/* 整个硬盘柱面数 x 每磁道的扇区数*/
/* cylinders x sectors */
/* cylinders = 一个盘面的扇区数 / 每个磁道的扇区数 */
/* 整个硬盘的扇区数 / 每个柱面的扇区数 */
geo->heads = 4;
geo->sectors = 128;
geo->cylinders = TEST_NSECTORS / (geo->heads * geo->sectors);
geo->start = 0;
return 0;
}
分区这些动作不是我们驱动做的是,而是fdisk这种东西用内核的函数来做的,我们只管建立整个磁盘就行了。
主要的函数是这两个:
void test_trans(struct test_dev *dev, int offset, int sector_count, unsigned
char *buf, int write)
{
if ((offset + sector_count) > TEST_NSECTORS) {
return;
}
if (write) {
memcpy(dev->data + offset * SECTOR_SIZE, buf, sector_count * SECTOR_SIZE);
} else {
memcpy(buf, dev->data + offset * SECTOR_SIZE, sector_count * SECTOR_SIZE);
}
}
void request_proc(request_queue_t *rq) {
struct request *re;
struct test_dev *dev;
while(( re = elv_next_request(rq)) != NULL) {
if (blk_fs_request(re)) {
dev = re->rq_disk->private_data;
test_trans(dev ,re->sector, re->current_nr_sectors, re->buffer, rq_data_dir(re));
end_request(re, 1);
} else {
end_request(re, 0);
}
}
}
没有列出所有源程序。只是单单列出了,重要的部分
阅读(457) | 评论(0) | 转发(0) |