📄 demo.c
字号:
/* * A sample, extra-simple block driver. * Copyright (C) 2007, 2010 fengGuojin(fgjnew@163.com) * Copyright 2003 Eklektix, Inc. Redistributable under the terms * of the GNU GPL. */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/init.h>#include <linux/kernel.h> /* printk() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/vmalloc.h>#include <linux/genhd.h>#include <linux/blkdev.h>#include <linux/hdreg.h>MODULE_LICENSE("Dual BSD/GPL");static int major_num = 0;module_param(major_num, int, 0);static int hardsect_size = 512;module_param(hardsect_size, int, 0);static int nsectors = 1024; /* How big the drive is */module_param(nsectors, int, 0);/* * We can tweak our hardware sector size, but the kernel talks to us * in terms of small sectors, always. */#define KERNEL_SECTOR_SIZE 512/* * Our request queue. */static struct request_queue *Queue;/* * The internal representation of our device. */static struct sbd_device { unsigned long size; spinlock_t lock; u8 *data; struct gendisk *gd;} Device;/* * Handle an I/O request. */static void sbd_transfer(struct sbd_device *dev, unsigned long sector, unsigned long nsect, char *buffer, int write){ unsigned long offset = sector*hardsect_size; unsigned long nbytes = nsect*hardsect_size; if ((offset + nbytes) > dev->size) { printk (KERN_NOTICE "sbd: Beyond-end write (%ld %ld)\n", offset, nbytes); return; } if (write) memcpy(dev->data + offset, buffer, nbytes); else memcpy(buffer, dev->data + offset, nbytes);}static void sbd_request(request_queue_t *q){ struct request *req; while ((req = elv_next_request(q)) != NULL) { if (! blk_fs_request(req)) { printk (KERN_NOTICE "Skip non-CMD request\n"); end_request(req, 0); continue; } sbd_transfer(&Device, req->sector, req->current_nr_sectors, req->buffer, rq_data_dir(req)); end_request(req, 1); }}/* * Ioctl. */int sbd_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ long size; struct hd_geometry geo; switch(cmd) { /* * The only command we need to interpret is HDIO_GETGEO, since * we can't partition the drive otherwise. We have no real * geometry, of course, so make something up. */ case HDIO_GETGEO: size = Device.size*(hardsect_size/KERNEL_SECTOR_SIZE); geo.cylinders = (size & ~0x3f) >> 6; geo.heads = 4; geo.sectors = 16; geo.start = 4; if (copy_to_user((void *) arg, &geo, sizeof(geo))) return -EFAULT; return 0; } return -ENOTTY; /* unknown command */}/* * The device operations structure. */static struct block_device_operations sbd_ops = { .owner = THIS_MODULE, .ioctl = sbd_ioctl};static int __init sbd_init(void){/* * Set up our internal device. */ Device.size = nsectors*hardsect_size; spin_lock_init(&Device.lock); Device.data = vmalloc(Device.size); if (Device.data == NULL) return -ENOMEM;/* * Get a request queue. */ Queue = blk_init_queue(sbd_request, &Device.lock); if (Queue == NULL) goto out; blk_queue_hardsect_size(Queue, hardsect_size);/* * Get registered. */ major_num = register_blkdev(major_num, "sbd"); if (major_num <= 0) { printk(KERN_WARNING "sbd: unable to get major number\n"); goto out; }/* * And the gendisk structure. */ Device.gd = alloc_disk(16); if (! Device.gd) goto out_unregister; Device.gd->major = major_num; Device.gd->first_minor = 0; Device.gd->fops = &sbd_ops; Device.gd->private_data = &Device; strcpy (Device.gd->disk_name, "sbd0"); set_capacity(Device.gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE)); Device.gd->queue = Queue; add_disk(Device.gd); return 0; out_unregister: unregister_blkdev(major_num, "sbd"); out: vfree(Device.data); return -ENOMEM;}static void __exit sbd_exit(void){ del_gendisk(Device.gd); put_disk(Device.gd); unregister_blkdev(major_num, "sbd"); blk_cleanup_queue(Queue); vfree(Device.data);} module_init(sbd_init);module_exit(sbd_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -