#include
#include
#include
#include
#include
#include
/*参考内核块设备驱动写:z2ram.c在内存中开辟一块空间来模拟成块设备*/
/*转载请注明原文地址:http://blog.csdn.net/oyhb_1992
测试方法:
1 insmod
2 格式化 mkdosfs /dev/xxx
3 挂载块设备 mount /dev/xxx /mnt
4 读写块设备
*/
enum {
SECTOR_SIZE = 512,//扇区大小
DEVICE_SIZE = SECTOR_SIZE*2*1024*1, //设备容量1M
};
#define DEVICE_NAME "ldm_blk"
//static DEFINE_SPINLOCK(ldm_lock);//静态创建自旋锁
struct ldm_info{ //自定义结构体描述驱动
struct gendisk *dev; //块设备描述结构体
spinlock_t ldm_lock; //动态创建自旋锁
struct block_device_operations ldm_fops; //操作函数集
void * addr;//在内存中开辟一块空间来模拟成块设备,
};
static struct ldm_info ldm;
//块设备的请求队列操作函数
static void ldm_request(struct request_queue *q)
{
struct request *req;
//从队列里取出一个请求
req = blk_fetch_request(q);
while (req) {
unsigned long start = blk_rq_pos(req) * SECTOR_SIZE; //扇区号*512= 从哪个字节开始访问,偏移量
unsigned long len = blk_rq_cur_bytes(req); //这次请求需要操作多少个字节
if (rq_data_dir(req) == READ) //应用层要读数据
{
memcpy(req->buffer, (char *)ldm.addr+start, len);
printk("read %d bytes from addr %d\n", start, len);//可观察到应用层发出请求后,块设备
//驱动不一定马上响应,有一个缓存机制,可能会把几个请求合成为一个请求,减少请求次数,
//存储设备只适合于大文件批量写入,
}
else //应用层要写数据
{
memcpy((char *)ldm.addr+start, req->buffer, len);
printk("write %d bytes from addr %d\n", start, len);
}
done:
if (!__blk_end_request_cur(req, 0)){ //检查当前请求是否完成,
//完成请求返回0,未完成返回1
req = blk_fetch_request(q); //获取下一个请求,请求处理完req = NULL
}
}
}
static int test_init(void)
{
int ret;
/*参考内核块设备驱动写:z2ram.c在内存中开辟一块空间来模拟成块设备*/
printk("%s: %s \n", __FUNCTION__, __FILE__);
//1:申请主设备号:参考内核源码Documentation/devices.txt查找空闲的块设备号,
//或者由系统自动分配:添0就是自动分配
/*ldm.dev->major = register_blkdev(0, DEVICE_NAME);
if (ldm.dev->major)//申请块设备号
{
printk(KERN_ERR "register_blkdev failed\n");
goto err;
}*/
if (register_blkdev(125, DEVICE_NAME))//申请块设备号
{
printk(KERN_ERR "register_blkdev failed\n");
goto err;
}
//2:创建块设备主对象,参数是次设备号
ldm.dev = alloc_disk(10);
if (!ldm.dev)
{
ret = -ENOMEM;
printk(KERN_ERR "alloc_disk failed\n");
goto out_disk;
}
//3:初始化自旋锁spinlock.h
spin_lock_init(&ldm.ldm_lock);
//4:为块设备创建操作队列,当应用层操作当前块设备时,操作请求会被发送到请求队列中
//,由驱动响应操作请求。
ldm.dev->queue = blk_init_queue(ldm_request, &ldm.ldm_lock);
if (!ldm.dev->queue)
{
printk(KERN_ERR "blk_init_queue failed\n");
goto out_queue;
}
//5:填充块设备主对象的成员
//ldm.dev->major = Z2RAM_MAJOR;
ldm.dev->first_minor = 0;
ldm.dev->fops = &ldm.ldm_fops;
sprintf(ldm.dev->disk_name, DEVICE_NAME); //创建出的设备节点名字
//strcpy(ldm.dev->disk_name, DEVICE_NAME); //等价
//6:设置块设备容量大小 >> 9 = /512 单位是扇区不是字节
set_capacity(ldm.dev, DEVICE_SIZE/SECTOR_SIZE);
//7:注册块设备
add_disk(ldm.dev);
//8:给设备分配存储空间,这里用内存来虚拟存储设备
//vmalloc适合分配大块内存,在物理地址上不连续,在虚拟地址上是连续的,是
//通过小块的内存碎片拼接而成
//kmalloc分配的内存是物理地址上连续的,不适合分配大块内存
ldm.addr = vmalloc(DEVICE_SIZE);//vzalloc分配空间并清零模拟块设备
if(NULL == ldm.addr)
{
printk(KERN_ERR "vmalloc failed\n");
ret = -ENOMEM;
goto err_vmalloc;
}
// blk_register_region(MKDEV(Z2RAM_MAJOR, 0), Z2MINOR_COUNT, THIS_MODULE,
// z2_find, NULL, NULL);
return 0;
err_vmalloc:
blk_cleanup_queue(ldm.dev->queue);
out_queue:
put_disk(ldm.dev); //alloc_disk
out_disk:
unregister_blkdev(0, DEVICE_NAME);
err:
return ret;
}
static void __exit test_exit(void)
{
printk("%s: %s \n", __FUNCTION__, __FILE__);
del_gendisk(ldm.dev); //和test_init注册时相反
vfree(ldm.addr);
blk_cleanup_queue(ldm.dev->queue);
unregister_blkdev(ldm.dev->major, DEVICE_NAME);
put_disk(ldm.dev);
return;
}
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");
安装模块后,在响应块设备请求时mencpy出现了段错误!原因正在查找
# insmod ldm_blk.ko
test_init: /home/S5-driver/lesson8/ldm_blk/ldm_blk.c
------------[ cut here ]------------
WARNING: at block/genhd.c:526 add_disk+0x78/0x150()
Modules linked in: ldm_blk(+)
Backtrace:
[] (dump_backtrace+0x0/0x10c) from [] (dump_stack+0x18/0x1c)
r7:00000000 r6:c0145e1c r5:c03fea8c r4:0000020e
[] (dump_stack+0x0/0x1c) from [] (warn_slowpath_common+0x4c/0x80)
[] (warn_slowpath_common+0x0/0x80) from [] (warn_slowpath_null+0x18/0x1c)
r7:bf0002f0 r6:bf0004bc r5:c3948a00 r4:c3948a00
[] (warn_slowpath_null+0x0/0x1c) from [] (add_disk+0x78/0x150)
[] (add_disk+0x0/0x150) from [] (test_init+0x98/0x130 [ldm_blk])
r5:bf0004b8 r4:c3948a00
[] (test_init+0x0/0x130 [ldm_blk]) from [] (do_one_initcall+0x3c/0x1c8)
r9:00000000 r8:c048b040 r7:c39c2000 r6:bf000398 r5:001c85fd
r4:00000f50
[] (do_one_initcall+0x0/0x1c8) from [] (sys_init_module+0xd0/0x204)
[] (sys_init_module+0x0/0x204) from [] (ret_fast_syscall+0x0/0x28)
r7:00000080 r6:beab1eb8 r5:00000000 r4:00000000
---[ end trace d6d69c142c6be93f ]---
ldm_blk:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = c39d8000
[00000000] *pgd=339d4031, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1]
last sysfs file: /sys/devices/platform/soc-audio/sound/card0/mixer/dev
Modules linked in: ldm_blk(+)
CPU: 0 Tainted: G W (2.6.32.2-FriendlyARM #8)
PC is at memcpy+0x28/0x29c
LR is at ldm_request+0x78/0xe0 [ldm_blk]
pc : [] lr : [] psr: 20000093
sp : c39c3c1c ip : 00000000 fp : c39c3c5c
r10: c0075d0c r9 : 00000001 r8 : c39168c8
r7 : bf0004b8 r6 : 00000000 r5 : 00001000 r4 : c38b1640
r3 : 01082420 r2 : 00000fe0 r1 : 00000000 r0 : c39e0000
Flags: nzCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment user
Control: c000717f Table: 339d8000 DAC: 00000015
Process insmod (pid: 637, stack limit = 0xc39c2270)
Stack: (0xc39c3c1c to 0xc39c4000)
3c00: 00001000
3c20: 00000000 bf0004b8 c39168c8 c39e0000 c38b1640 bf0001a8 c39168c8 c39c3d08
3c40: c39c3cfc c0540168 00000002 00000001 c39c3c74 c39c3c60 c013fcdc bf000140
3c60: c39c3cf4 c39c3d08 c39c3c84 c39c3c78 c013fd08 c013fcac c39c3c94 c39c3c88
3c80: c013de68 c013fcf0 c39c3ca4 c39c3c98 c013de80 c013de58 c39c3cb4 c39c3ca8
3ca0: c00be68c c013de7c c39c3cc4 c39c3cb8 c0075d48 c00be658 c39c3cec c39c3cc8
3cc0: c03386ec c0075d1c 00000000 c39c3d08 c3894f00 00000000 00000000 c00c5f68
3ce0: c39c3d2c c39c3cf0 c0075ce0 c0338698 c00760d4 c0533c00 00000000 00000001
3d00: c3894f00 c005f198 c0540168 c0540168 c39c3d2c c0533c00 00000000 c3402280
3d20: c39c3d54 c39c3d30 c0076404 c0075c3c 00000000 c39c3dd4 c393b000 c00df474
3d40: c3402180 c393b000 c39c3d6c c39c3d58 c00764ac c0076340 00000000 c39c3dd4
3d60: c39c3d84 c39c3d70 c00de8f8 c00764ac 00000000 c3948a00 c39c3e04 c39c3d88
3d80: c00df4c0 c00de8d8 ffffffff ffffffff c3948a50 c3402180 c3948a00 c393b000
3da0: 00000000 c3402180 c39c3e6c 00000000 c39c3dd4 00000000 c3948a00 c393b000
3dc0: c3402190 c3402180 c39c3e6c 00000000 c39c3df4 c39c3de0 c033796c 00000000
3de0: c3948a00 c393b000 c00df474 c3402180 c393b020 00000000 c39c3e5c c39c3e08
3e00: c00df16c c00df484 c3948a50 00000000 c39c3e34 c39c3e20 c014bba0 00000000
3e20: c3948a00 00000000 00000001 00000002 c0185068 c3402180 00000000 c3948a00
3e40: c3402190 00000000 c39c3e6c 00000001 c39c3e9c c39c3e60 c00c6578 c00df028
3e60: c014ba44 00000000 c00c5c98 00000000 c39c3e7c c3948a00 00000001 c3948a50
3e80: c3402180 00000000 00000000 bf000000 c39c3eac c39c3ea0 c00c6758 c00c642c
3ea0: c39c3edc c39c3eb0 c00dea8c c00c6754 c3948a00 c3948a00 c3948a00 bf0004bc
3ec0: c3948a00 c3948a00 bf0004bc bf0002f0 c39c3f0c c39c3ee0 c0145e8c c00de960
3ee0: c0145300 c0145840 c3948a00 bf000000 c39c3f0c 00000000 c3948a00 bf0004b8
3f00: c39c3f34 c39c3f10 bf000098 c0145db4 00000f50 001c85fd bf000398 c39c2000
3f20: c048b040 00000000 c39c3f7c c39c3f38 c003032c bf000010 00000000 00000000
3f40: 00000000 00000f50 001c85fd bf000398 00000000 00000f50 001c85fd bf000398
3f60: 00000000 c00310c8 c39c2000 00000000 c39c3fa4 c39c3f80 c0070144 c0030300
3f80: c009b118 c009b008 00000000 00000000 beab1eb8 00000080 00000000 c39c3fa8
3fa0: c0030f20 c0070084 00000000 00000000 001e0fd8 00000f50 001c85fd 00000000
3fc0: 00000000 00000000 beab1eb8 00000080 beab1eb4 beab1eb8 00000001 beab1eb4
3fe0: 00000069 beab1b7c 0002bf44 000094b4 60000010 001e0fd8 30542031 30542431
Backtrace:
[] (ldm_request+0x0/0xe0 [ldm_blk]) from [] (__generic_unplug_device+0x40/0x44)
r9:00000001 r8:00000002 r7:c0540168 r6:c39c3cfc r5:c39c3d08
r4:c39168c8
[] (__generic_unplug_device+0x0/0x44) from [] (generic_unplug_device+0x28/0x38)
r5:c39c3d08 r4:c39c3cf4
[] (generic_unplug_device+0x0/0x38) from [] (blk_unplug+0x20/0x24)
[] (blk_unplug+0x0/0x24) from [] (blk_backing_dev_unplug+0x14/0x18)
[] (blk_backing_dev_unplug+0x0/0x18) from [] (block_sync_page+0x44/0x48)
[] (block_sync_page+0x0/0x48) from [] (sync_page+0x3c/0x48)
[] (sync_page+0x0/0x48) from [] (__wait_on_bit_lock+0x64/0xb0)
[] (__wait_on_bit_lock+0x0/0xb0) from [] (__lock_page+0xb4/0xc8)
[] (__lock_page+0x0/0xc8) from [] (read_cache_page_async+0xd4/0x16c)
r6:c3402280 r5:00000000 r4:c0533c00
[] (read_cache_page_async+0x0/0x16c) from [] (read_cache_page+0x10/0x68)
[] (read_cache_page+0x0/0x68) from [] (read_dev_sector+0x30/0x88)
r5:c39c3dd4 r4:00000000
[] (read_dev_sector+0x0/0x88) from [] (msdos_partition+0x4c/0x750)
r5:c3948a00 r4:00000000
[] (msdos_partition+0x0/0x750) from [] (rescan_partitions+0x154/0x3d8)
[] (rescan_partitions+0x0/0x3d8) from [] (__blkdev_get+0x15c/0x328)
[] (__blkdev_get+0x0/0x328) from [] (blkdev_get+0x14/0x18)
[] (blkdev_get+0x0/0x18) from [] (register_disk+0x13c/0x160)
[] (register_disk+0x0/0x160) from [] (add_disk+0xe8/0x150)
r7:bf0002f0 r6:bf0004bc r5:c3948a00 r4:c3948a00
[] (add_disk+0x0/0x150) from [] (test_init+0x98/0x130 [ldm_blk])
r5:bf0004b8 r4:c3948a00
[] (test_init+0x0/0x130 [ldm_blk]) from [] (do_one_initcall+0x3c/0x1c8)
r9:00000000 r8:c048b040 r7:c39c2000 r6:bf000398 r5:001c85fd
r4:00000f50
[] (do_one_initcall+0x0/0x1c8) from [] (sys_init_module+0xd0/0x204)
[] (sys_init_module+0x0/0x204) from [] (ret_fast_syscall+0x0/0x28)
r7:00000080 r6:beab1eb8 r5:00000000 r4:00000000
Code: 1a000031 e252201c e92d01e0 ba000003 (e8b151f8)
---[ end trace 2c6be940c048b8b0 ]---
Segmentation fault
# s3c2410fb: blank(mode=1, info=c3872800)
s3c2410fb: setting TPAL to output 0x000000
lk.ko