2 * $Id: mtdblock_ro.c,v 1.12 2001/11/20 11:42:33 dwmw2 Exp $
4 * Read-only version of the mtdblock device, without the
5 * read/erase/modify/writeback stuff
13 #include <linux/module.h>
14 #include <linux/types.h>
16 #include <linux/mtd/mtd.h>
17 #include <linux/mtd/compatmac.h>
19 #define MAJOR_NR MTD_BLOCK_MAJOR
20 #define DEVICE_NAME "mtdblock"
21 #define DEVICE_REQUEST mtdblock_request
22 #define DEVICE_NR(device) (device)
23 #define DEVICE_ON(device)
24 #define DEVICE_OFF(device)
25 #define DEVICE_NO_RANDOM
26 #include <linux/blk.h>
28 #if LINUX_VERSION_CODE < 0x20300
29 #define RQFUNC_ARG void
30 #define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
32 #define RQFUNC_ARG request_queue_t *q
36 static int debug = MTDBLOCK_DEBUG;
37 MODULE_PARM(debug, "i");
40 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)
41 #define BLK_INC_USE_COUNT MOD_INC_USE_COUNT
42 #define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT
44 #define BLK_INC_USE_COUNT do {} while(0)
45 #define BLK_DEC_USE_COUNT do {} while(0)
48 static int mtd_sizes[MAX_MTD_DEVICES];
51 static int mtdblock_open(struct inode *inode, struct file *file)
53 struct mtd_info *mtd = NULL;
57 DEBUG(1,"mtdblock_open\n");
62 dev = MINOR(inode->i_rdev);
64 mtd = get_mtd_device(NULL, dev);
67 if (MTD_ABSENT == mtd->type) {
74 mtd_sizes[dev] = mtd->size>>9;
81 static release_t mtdblock_release(struct inode *inode, struct file *file)
86 DEBUG(1, "mtdblock_release\n");
89 release_return(-ENODEV);
91 dev = MINOR(inode->i_rdev);
92 mtd = __get_mtd_device(NULL, dev);
95 printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
97 release_return(-ENODEV);
112 static void mtdblock_request(RQFUNC_ARG)
114 struct request *current_request;
115 unsigned int res = 0;
116 struct mtd_info *mtd;
120 /* Grab the Request and unlink it from the request list, INIT_REQUEST
121 will execute a return if we are done. */
123 current_request = CURRENT;
125 if (MINOR(current_request->rq_dev) >= MAX_MTD_DEVICES)
127 printk("mtd: Unsupported device!\n");
132 // Grab our MTD structure
134 mtd = __get_mtd_device(NULL, MINOR(current_request->rq_dev));
136 printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV);
140 if (current_request->sector << 9 > mtd->size ||
141 (current_request->sector + current_request->current_nr_sectors) << 9 > mtd->size)
143 printk("mtd: Attempt to read past end of device!\n");
144 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd->size,
145 current_request->sector, current_request->current_nr_sectors);
150 /* Remove the request we are handling from the request list so nobody messes
152 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
153 /* Now drop the lock that the ll_rw_blk functions grabbed for us
154 and process the request. This is necessary due to the extreme time
155 we spend processing it. */
156 spin_unlock_irq(&io_request_lock);
159 // Handle the request
160 switch (current_request->cmd)
165 if (MTD_READ(mtd,current_request->sector<<9,
166 current_request->current_nr_sectors << 9,
167 &retlen, current_request->buffer) == 0)
175 /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
176 current_request->current_nr_sectors);
180 if ((mtd->flags & MTD_CAP_RAM) == 0)
187 if (MTD_WRITE(mtd,current_request->sector<<9,
188 current_request->current_nr_sectors << 9,
189 &retlen, current_request->buffer) == 0)
197 printk("mtd: unknown request\n");
201 // Grab the lock and re-thread the item onto the linked list
202 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
203 spin_lock_irq(&io_request_lock);
211 static int mtdblock_ioctl(struct inode * inode, struct file * file,
212 unsigned int cmd, unsigned long arg)
214 struct mtd_info *mtd;
216 mtd = __get_mtd_device(NULL, MINOR(inode->i_rdev));
218 if (!mtd) return -EINVAL;
221 case BLKGETSIZE: /* Return device size */
222 return put_user((mtd->size >> 9), (unsigned long *) arg);
226 return put_user((u64)mtd->size, (u64 *)arg);
230 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
231 if(!capable(CAP_SYS_ADMIN)) return -EACCES;
233 fsync_dev(inode->i_rdev);
234 invalidate_buffers(inode->i_rdev);
244 #if LINUX_VERSION_CODE < 0x20326
245 static struct file_operations mtd_fops =
248 ioctl: mtdblock_ioctl,
249 release: mtdblock_release,
254 static struct block_device_operations mtd_fops =
256 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,14)
260 release: mtdblock_release,
261 ioctl: mtdblock_ioctl
265 int __init init_mtdblock(void)
269 if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {
270 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n",
275 /* We fill it in at open() time. */
276 for (i=0; i< MAX_MTD_DEVICES; i++) {
280 /* Allow the block size to default to BLOCK_SIZE. */
281 blksize_size[MAJOR_NR] = NULL;
282 blk_size[MAJOR_NR] = mtd_sizes;
284 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);
288 static void __exit cleanup_mtdblock(void)
290 unregister_blkdev(MAJOR_NR,DEVICE_NAME);
291 blk_size[MAJOR_NR] = NULL;
292 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
295 module_init(init_mtdblock);
296 module_exit(cleanup_mtdblock);
299 MODULE_LICENSE("GPL");
300 MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
301 MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");