最近在做linux块设备驱动开发,看到ChinaUnix上有一个很好的入门帖子http://bbs.chinaunix.net/thread-2017377-1-1.html 不过代码在Ubuntu10.04的内核上(linux 2.6.32)无法使用.查阅了一些资料,对第一章的代码而言修改如下就可以编译通过了,并能够进行insmod mkfs mount 操作。
insmod之后 用 sudo hdparm -tT /dev/simp_blkdev 测试了一下:
/dev/simp_blkdev:
Timing cached reads: 2250 MB in 2.00 seconds = 1124.53 MB/sec
Timing buffered disk reads: 16 MB in 0.03 seconds = 482.63 MB/sec
#include <linux/module.h>
#include <linux/blkdev.h>
#define SIMP_BLKDEV_DEVICEMAJOR COMPAQ_SMART2_MAJOR
#define SIMP_BLKDEV_DISKNAME "simp_blkdev"
#define SIMP_BLKDEV_BYTES (16*1024*1024) //16MB
unsigned char simp_blkdev_data[SIMP_BLKDEV_BYTES];
static struct request_queue *simp_blkdev_queue;
static struct gendisk *simp_blkdev_disk;
static void simp_blkdev_do_request(struct request_queue *q)
{
struct request *req;
sector_t sector = 0;
unsigned int current_nr_sectors = 0;
req = blk_fetch_request(q);
while (req != NULL) {
int err = 0;
sector = blk_rq_pos (req);
current_nr_sectors = blk_rq_cur_sectors (req);
if ((sector + current_nr_sectors)<< 9 > SIMP_BLKDEV_BYTES) {
printk(KERN_ERR SIMP_BLKDEV_DISKNAME": bad request: block=%llu, count=%u\n",
sector,
current_nr_sectors);
err = -EIO;
goto done;
}
switch (rq_data_dir(req)) {
case READ:
memcpy(req->buffer,
simp_blkdev_data + (sector << 9),
current_nr_sectors << 9);
break;
case WRITE:
memcpy(simp_blkdev_data + (sector << 9),
req->buffer, current_nr_sectors << 9);
break;
default:
/* No default because rq_data_dir(req) is 1 bit */
break;
}
done:
if (!__blk_end_request_cur(req, err))
req = blk_fetch_request(q);
}
}
struct block_device_operations simp_blkdev_fops = {
.owner = THIS_MODULE,
};
static int __init simp_blkdev_init(void)
{
int ret;
simp_blkdev_queue = blk_init_queue(simp_blkdev_do_request, NULL);
if (!simp_blkdev_queue) {
ret = -ENOMEM;
goto err_init_queue;
}
simp_blkdev_disk = alloc_disk(1);
if (!simp_blkdev_disk) {
ret = -ENOMEM;
goto err_alloc_disk;
}
strcpy(simp_blkdev_disk->disk_name, SIMP_BLKDEV_DISKNAME);
simp_blkdev_disk->major = SIMP_BLKDEV_DEVICEMAJOR;
simp_blkdev_disk->first_minor = 0;
simp_blkdev_disk->fops = &simp_blkdev_fops;
simp_blkdev_disk->queue = simp_blkdev_queue;
set_capacity(simp_blkdev_disk, SIMP_BLKDEV_BYTES>>9);
add_disk(simp_blkdev_disk);
return 0;
err_alloc_disk:
blk_cleanup_queue(simp_blkdev_queue);
err_init_queue:
return ret;
}
static void __exit simp_blkdev_exit(void)
{
del_gendisk(simp_blkdev_disk);
put_disk(simp_blkdev_disk);
blk_cleanup_queue(simp_blkdev_queue);
}
module_init(simp_blkdev_init);
module_exit(simp_blkdev_exit);
MODULE_LICENSE("GPL");