[PATCH] m68k: bitops update [3/20]
[linux-2.6/history.git] / drivers / mtd / mtdblock_ro.c
blob62c3b3bb17bb23bd7b5db592e070f23a34208173
1 /*
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
6 */
8 #ifdef MTDBLOCK_DEBUG
9 #define DEBUGLVL debug
10 #endif
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)
28 #else
29 #define RQFUNC_ARG request_queue_t *q
30 #endif
32 #ifdef MTDBLOCK_DEBUG
33 static int debug = MTDBLOCK_DEBUG;
34 MODULE_PARM(debug, "i");
35 #endif
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;
45 int dev;
47 DEBUG(1,"mtdblock_open\n");
49 if (inode == 0)
50 return -EINVAL;
52 dev = minor(inode->i_rdev);
54 mtd = get_mtd_device(NULL, dev);
55 if (!mtd)
56 return -EINVAL;
57 if (MTD_ABSENT == mtd->type) {
58 put_mtd_device(mtd);
59 return -EINVAL;
62 mtd_sizes[dev] = mtd->size>>9;
64 DEBUG(1, "ok\n");
66 return 0;
69 static release_t mtdblock_release(struct inode *inode, struct file *file)
71 int dev;
72 struct mtd_info *mtd;
74 DEBUG(1, "mtdblock_release\n");
76 if (inode == NULL)
77 release_return(-ENODEV);
79 invalidate_device(inode->i_rdev, 1);
81 dev = minor(inode->i_rdev);
82 mtd = __get_mtd_device(NULL, dev);
84 if (!mtd) {
85 printk(KERN_WARNING "MTD device is absent on mtd_release!\n");
86 release_return(-ENODEV);
89 if (mtd->sync)
90 mtd->sync(mtd);
92 put_mtd_device(mtd);
94 DEBUG(1, "ok\n");
96 release_return(0);
99 static inline void mtdblock_end_request(struct request *req, int uptodate)
101 if (end_that_request_first(req, uptodate, req->hard_cur_sectors))
102 return;
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;
113 while (1)
115 /* Grab the Request and unlink it from the request list, INIT_REQUEST
116 will execute a return if we are done. */
117 INIT_REQUEST;
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);
124 continue;
127 // Grab our MTD structure
129 mtd = __get_mtd_device(NULL, minor(current_request->rq_dev));
130 if (!mtd) {
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);
141 continue;
144 /* Remove the request we are handling from the request list so nobody messes
145 with it */
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);
151 #endif
153 // Handle the request
154 switch (current_request->cmd)
156 size_t retlen;
158 case READ:
159 if (MTD_READ(mtd,current_request->sector<<9,
160 current_request->nr_sectors << 9,
161 &retlen, current_request->buffer) == 0)
162 res = 1;
163 else
164 res = 0;
165 break;
167 case WRITE:
169 /* printk("mtdblock_request WRITE sector=%d(%d)\n",current_request->sector,
170 current_request->nr_sectors);
173 // Read only device
174 if ((mtd->flags & MTD_CAP_RAM) == 0)
176 res = 0;
177 break;
180 // Do the write
181 if (MTD_WRITE(mtd,current_request->sector<<9,
182 current_request->nr_sectors << 9,
183 &retlen, current_request->buffer) == 0)
184 res = 1;
185 else
186 res = 0;
187 break;
189 // Shouldn't happen
190 default:
191 printk("mtd: unknown request\n");
192 break;
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);
198 #endif
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;
214 switch (cmd) {
215 case BLKGETSIZE: /* Return device size */
216 return put_user((mtd->size >> 9), (unsigned long *) arg);
217 case BLKGETSIZE64:
218 return put_user((u64)mtd->size, (u64 *)arg);
220 case BLKFLSBUF:
221 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
222 if(!capable(CAP_SYS_ADMIN)) return -EACCES;
223 #endif
224 fsync_bdev(inode->i_bdev);
225 invalidate_bdev(inode->i_bdev, 0);
226 if (mtd->sync)
227 mtd->sync(mtd);
228 return 0;
230 default:
231 return -ENOTTY;
235 #if LINUX_VERSION_CODE < 0x20326
236 static struct file_operations mtd_fops =
238 open: mtdblock_open,
239 ioctl: mtdblock_ioctl,
240 release: mtdblock_release,
241 read: block_read,
242 write: block_write
244 #else
245 static struct block_device_operations mtd_fops =
247 owner: THIS_MODULE,
248 open: mtdblock_open,
249 release: mtdblock_release,
250 ioctl: mtdblock_ioctl
252 #endif
254 int __init init_mtdblock(void)
256 int i;
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",
260 MTD_BLOCK_MAJOR);
261 return -EAGAIN;
264 /* We fill it in at open() time. */
265 for (i=0; i< MAX_MTD_DEVICES; i++) {
266 mtd_sizes[i] = 0;
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);
273 return 0;
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");