2 * $Id: mtdblock_ro.c,v 1.9 2001/10/02 15:05:11 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 LOCAL_END_REQUEST
20 #define MAJOR_NR MTD_BLOCK_MAJOR
21 #define DEVICE_NAME "mtdblock"
22 #define DEVICE_NR(device) (device)
23 #include <linux/blk.h>
25 #if LINUX_VERSION_CODE < 0x20300
26 #define RQFUNC_ARG void
27 #define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0)
29 #define RQFUNC_ARG request_queue_t *q
33 static int debug
= MTDBLOCK_DEBUG
;
34 MODULE_PARM(debug
, "i");
38 static int mtd_sizes
[MAX_MTD_DEVICES
];
41 static int mtdblock_open(struct inode
*inode
, struct file
*file
)
43 struct mtd_info
*mtd
= NULL
;
47 DEBUG(1,"mtdblock_open\n");
52 dev
= minor(inode
->i_rdev
);
54 mtd
= get_mtd_device(NULL
, dev
);
57 if (MTD_ABSENT
== mtd
->type
) {
62 mtd_sizes
[dev
] = mtd
->size
>>9;
69 static release_t
mtdblock_release(struct inode
*inode
, struct file
*file
)
74 DEBUG(1, "mtdblock_release\n");
77 release_return(-ENODEV
);
79 invalidate_device(inode
->i_rdev
, 1);
81 dev
= minor(inode
->i_rdev
);
82 mtd
= __get_mtd_device(NULL
, dev
);
85 printk(KERN_WARNING
"MTD device is absent on mtd_release!\n");
86 release_return(-ENODEV
);
99 static inline void mtdblock_end_request(struct request
*req
, int uptodate
)
101 if (end_that_request_first(req
, uptodate
, req
->hard_cur_sectors
))
103 blkdev_dequeue_request(req
);
104 end_that_request_last(req
);
107 static void mtdblock_request(RQFUNC_ARG
)
109 struct request
*current_request
;
110 unsigned int res
= 0;
111 struct mtd_info
*mtd
;
115 /* Grab the Request and unlink it from the request list, INIT_REQUEST
116 will execute a return if we are done. */
118 current_request
= CURRENT
;
120 if (minor(current_request
->rq_dev
) >= MAX_MTD_DEVICES
)
122 printk("mtd: Unsupported device!\n");
123 mtdblock_end_request(current_request
, 0);
127 // Grab our MTD structure
129 mtd
= __get_mtd_device(NULL
, minor(current_request
->rq_dev
));
131 printk("MTD device %d doesn't appear to exist any more\n", CURRENT_DEV
);
132 mtdblock_end_request(current_request
, 0);
135 if (current_request
->sector
<< 9 > mtd
->size
||
136 (current_request
->sector
+ current_request
->nr_sectors
) << 9 > mtd
->size
)
138 printk("mtd: Attempt to read past end of device!\n");
139 printk("size: %x, sector: %lx, nr_sectors %lx\n", mtd
->size
, current_request
->sector
, current_request
->nr_sectors
);
140 mtdblock_end_request(current_request
, 0);
144 /* Remove the request we are handling from the request list so nobody messes
146 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
147 /* Now drop the lock that the ll_rw_blk functions grabbed for us
148 and process the request. This is necessary due to the extreme time
149 we spend processing it. */
150 spin_unlock_irq(&io_request_lock
);
153 // Handle the request
154 switch (current_request
->cmd
)
159 if (MTD_READ(mtd
,current_request
->sector
<<9,
160 current_request
->nr_sectors
<< 9,
161 &retlen
, current_request
->buffer
) == 0)
169 /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
170 current_request->nr_sectors);
174 if ((mtd
->flags
& MTD_CAP_RAM
) == 0)
181 if (MTD_WRITE(mtd
,current_request
->sector
<<9,
182 current_request
->nr_sectors
<< 9,
183 &retlen
, current_request
->buffer
) == 0)
191 printk("mtd: unknown request\n");
195 // Grab the lock and re-thread the item onto the linked list
196 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
197 spin_lock_irq(&io_request_lock
);
199 mtdblock_end_request(current_request
, res
);
205 static int mtdblock_ioctl(struct inode
* inode
, struct file
* file
,
206 unsigned int cmd
, unsigned long arg
)
208 struct mtd_info
*mtd
;
210 mtd
= __get_mtd_device(NULL
, minor(inode
->i_rdev
));
212 if (!mtd
) return -EINVAL
;
215 case BLKGETSIZE
: /* Return device size */
216 return put_user((mtd
->size
>> 9), (unsigned long *) arg
);
218 return put_user((u64
)mtd
->size
, (u64
*)arg
);
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
222 if(!capable(CAP_SYS_ADMIN
)) return -EACCES
;
224 fsync_bdev(inode
->i_bdev
);
225 invalidate_bdev(inode
->i_bdev
, 0);
235 #if LINUX_VERSION_CODE < 0x20326
236 static struct file_operations mtd_fops
=
239 ioctl
: mtdblock_ioctl
,
240 release
: mtdblock_release
,
245 static struct block_device_operations mtd_fops
=
249 release
: mtdblock_release
,
250 ioctl
: mtdblock_ioctl
254 int __init
init_mtdblock(void)
258 if (register_blkdev(MAJOR_NR
,DEVICE_NAME
,&mtd_fops
)) {
259 printk(KERN_NOTICE
"Can't allocate major number %d for Memory Technology Devices.\n",
264 /* We fill it in at open() time. */
265 for (i
=0; i
< MAX_MTD_DEVICES
; i
++) {
269 /* Allow the block size to default to BLOCK_SIZE. */
270 blk_size
[MAJOR_NR
] = mtd_sizes
;
272 blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
), &mtdblock_request
);
276 static void __exit
cleanup_mtdblock(void)
278 unregister_blkdev(MAJOR_NR
,DEVICE_NAME
);
279 blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR
));
282 module_init(init_mtdblock
);
283 module_exit(cleanup_mtdblock
);
286 MODULE_LICENSE("GPL");
287 MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al.");
288 MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices");