aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mtdchar.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd/mtdchar.c')
-rw-r--r--drivers/mtd/mtdchar.c86
1 files changed, 42 insertions, 44 deletions
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 16df1e4fb0e9..6f044584bdc6 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1,22 +1,23 @@
1/* 1/*
2 * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $ 2 * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $
3 * 3 *
4 * Character-device access to raw MTD devices. 4 * Character-device access to raw MTD devices.
5 * 5 *
6 */ 6 */
7 7
8#include <linux/config.h> 8#include <linux/config.h>
9#include <linux/device.h>
10#include <linux/fs.h>
11#include <linux/init.h>
9#include <linux/kernel.h> 12#include <linux/kernel.h>
10#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/slab.h>
15#include <linux/sched.h>
16
11#include <linux/mtd/mtd.h> 17#include <linux/mtd/mtd.h>
12#include <linux/mtd/compatmac.h> 18#include <linux/mtd/compatmac.h>
13#include <linux/slab.h>
14#include <linux/init.h>
15#include <linux/fs.h>
16#include <linux/sched.h> /* TASK_* */
17#include <asm/uaccess.h>
18 19
19#include <linux/device.h> 20#include <asm/uaccess.h>
20 21
21static struct class *mtd_class; 22static struct class *mtd_class;
22 23
@@ -27,7 +28,7 @@ static void mtd_notify_add(struct mtd_info* mtd)
27 28
28 class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), 29 class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
29 NULL, "mtd%d", mtd->index); 30 NULL, "mtd%d", mtd->index);
30 31
31 class_device_create(mtd_class, NULL, 32 class_device_create(mtd_class, NULL,
32 MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), 33 MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
33 NULL, "mtd%dro", mtd->index); 34 NULL, "mtd%dro", mtd->index);
@@ -70,26 +71,23 @@ static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
70 switch (orig) { 71 switch (orig) {
71 case 0: 72 case 0:
72 /* SEEK_SET */ 73 /* SEEK_SET */
73 file->f_pos = offset;
74 break; 74 break;
75 case 1: 75 case 1:
76 /* SEEK_CUR */ 76 /* SEEK_CUR */
77 file->f_pos += offset; 77 offset += file->f_pos;
78 break; 78 break;
79 case 2: 79 case 2:
80 /* SEEK_END */ 80 /* SEEK_END */
81 file->f_pos =mtd->size + offset; 81 offset += mtd->size;
82 break; 82 break;
83 default: 83 default:
84 return -EINVAL; 84 return -EINVAL;
85 } 85 }
86 86
87 if (file->f_pos < 0) 87 if (offset >= 0 && offset < mtd->size)
88 file->f_pos = 0; 88 return file->f_pos = offset;
89 else if (file->f_pos >= mtd->size)
90 file->f_pos = mtd->size - 1;
91 89
92 return file->f_pos; 90 return -EINVAL;
93} 91}
94 92
95 93
@@ -110,23 +108,23 @@ static int mtd_open(struct inode *inode, struct file *file)
110 return -EACCES; 108 return -EACCES;
111 109
112 mtd = get_mtd_device(NULL, devnum); 110 mtd = get_mtd_device(NULL, devnum);
113 111
114 if (!mtd) 112 if (!mtd)
115 return -ENODEV; 113 return -ENODEV;
116 114
117 if (MTD_ABSENT == mtd->type) { 115 if (MTD_ABSENT == mtd->type) {
118 put_mtd_device(mtd); 116 put_mtd_device(mtd);
119 return -ENODEV; 117 return -ENODEV;
120 } 118 }
121 119
122 file->private_data = mtd; 120 file->private_data = mtd;
123 121
124 /* You can't open it RW if it's not a writeable device */ 122 /* You can't open it RW if it's not a writeable device */
125 if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { 123 if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) {
126 put_mtd_device(mtd); 124 put_mtd_device(mtd);
127 return -EACCES; 125 return -EACCES;
128 } 126 }
129 127
130 return 0; 128 return 0;
131} /* mtd_open */ 129} /* mtd_open */
132 130
@@ -139,10 +137,10 @@ static int mtd_close(struct inode *inode, struct file *file)
139 DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); 137 DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
140 138
141 mtd = TO_MTD(file); 139 mtd = TO_MTD(file);
142 140
143 if (mtd->sync) 141 if (mtd->sync)
144 mtd->sync(mtd); 142 mtd->sync(mtd);
145 143
146 put_mtd_device(mtd); 144 put_mtd_device(mtd);
147 145
148 return 0; 146 return 0;
@@ -161,7 +159,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
161 int ret=0; 159 int ret=0;
162 int len; 160 int len;
163 char *kbuf; 161 char *kbuf;
164 162
165 DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); 163 DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
166 164
167 if (*ppos + count > mtd->size) 165 if (*ppos + count > mtd->size)
@@ -169,11 +167,11 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
169 167
170 if (!count) 168 if (!count)
171 return 0; 169 return 0;
172 170
173 /* FIXME: Use kiovec in 2.5 to lock down the user's buffers 171 /* FIXME: Use kiovec in 2.5 to lock down the user's buffers
174 and pass them directly to the MTD functions */ 172 and pass them directly to the MTD functions */
175 while (count) { 173 while (count) {
176 if (count > MAX_KMALLOC_SIZE) 174 if (count > MAX_KMALLOC_SIZE)
177 len = MAX_KMALLOC_SIZE; 175 len = MAX_KMALLOC_SIZE;
178 else 176 else
179 len = count; 177 len = count;
@@ -181,7 +179,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
181 kbuf=kmalloc(len,GFP_KERNEL); 179 kbuf=kmalloc(len,GFP_KERNEL);
182 if (!kbuf) 180 if (!kbuf)
183 return -ENOMEM; 181 return -ENOMEM;
184 182
185 switch (MTD_MODE(file)) { 183 switch (MTD_MODE(file)) {
186 case MTD_MODE_OTP_FACT: 184 case MTD_MODE_OTP_FACT:
187 ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); 185 ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
@@ -194,7 +192,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
194 } 192 }
195 /* Nand returns -EBADMSG on ecc errors, but it returns 193 /* Nand returns -EBADMSG on ecc errors, but it returns
196 * the data. For our userspace tools it is important 194 * the data. For our userspace tools it is important
197 * to dump areas with ecc errors ! 195 * to dump areas with ecc errors !
198 * Userspace software which accesses NAND this way 196 * Userspace software which accesses NAND this way
199 * must be aware of the fact that it deals with NAND 197 * must be aware of the fact that it deals with NAND
200 */ 198 */
@@ -216,7 +214,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
216 kfree(kbuf); 214 kfree(kbuf);
217 return ret; 215 return ret;
218 } 216 }
219 217
220 kfree(kbuf); 218 kfree(kbuf);
221 } 219 }
222 220
@@ -233,10 +231,10 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
233 int len; 231 int len;
234 232
235 DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); 233 DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
236 234
237 if (*ppos == mtd->size) 235 if (*ppos == mtd->size)
238 return -ENOSPC; 236 return -ENOSPC;
239 237
240 if (*ppos + count > mtd->size) 238 if (*ppos + count > mtd->size)
241 count = mtd->size - *ppos; 239 count = mtd->size - *ppos;
242 240
@@ -244,7 +242,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
244 return 0; 242 return 0;
245 243
246 while (count) { 244 while (count) {
247 if (count > MAX_KMALLOC_SIZE) 245 if (count > MAX_KMALLOC_SIZE)
248 len = MAX_KMALLOC_SIZE; 246 len = MAX_KMALLOC_SIZE;
249 else 247 else
250 len = count; 248 len = count;
@@ -259,7 +257,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
259 kfree(kbuf); 257 kfree(kbuf);
260 return -EFAULT; 258 return -EFAULT;
261 } 259 }
262 260
263 switch (MTD_MODE(file)) { 261 switch (MTD_MODE(file)) {
264 case MTD_MODE_OTP_FACT: 262 case MTD_MODE_OTP_FACT:
265 ret = -EROFS; 263 ret = -EROFS;
@@ -284,7 +282,7 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
284 kfree(kbuf); 282 kfree(kbuf);
285 return ret; 283 return ret;
286 } 284 }
287 285
288 kfree(kbuf); 286 kfree(kbuf);
289 } 287 }
290 288
@@ -308,7 +306,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
308 void __user *argp = (void __user *)arg; 306 void __user *argp = (void __user *)arg;
309 int ret = 0; 307 int ret = 0;
310 u_long size; 308 u_long size;
311 309
312 DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); 310 DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
313 311
314 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; 312 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
@@ -320,7 +318,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
320 if (!access_ok(VERIFY_WRITE, argp, size)) 318 if (!access_ok(VERIFY_WRITE, argp, size))
321 return -EFAULT; 319 return -EFAULT;
322 } 320 }
323 321
324 switch (cmd) { 322 switch (cmd) {
325 case MEMGETREGIONCOUNT: 323 case MEMGETREGIONCOUNT:
326 if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) 324 if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int)))
@@ -372,11 +370,11 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
372 erase->mtd = mtd; 370 erase->mtd = mtd;
373 erase->callback = mtdchar_erase_callback; 371 erase->callback = mtdchar_erase_callback;
374 erase->priv = (unsigned long)&waitq; 372 erase->priv = (unsigned long)&waitq;
375 373
376 /* 374 /*
377 FIXME: Allow INTERRUPTIBLE. Which means 375 FIXME: Allow INTERRUPTIBLE. Which means
378 not having the wait_queue head on the stack. 376 not having the wait_queue head on the stack.
379 377
380 If the wq_head is on the stack, and we 378 If the wq_head is on the stack, and we
381 leave because we got interrupted, then the 379 leave because we got interrupted, then the
382 wq_head is no longer there when the 380 wq_head is no longer there when the
@@ -404,13 +402,13 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
404 struct mtd_oob_buf buf; 402 struct mtd_oob_buf buf;
405 void *databuf; 403 void *databuf;
406 ssize_t retlen; 404 ssize_t retlen;
407 405
408 if(!(file->f_mode & 2)) 406 if(!(file->f_mode & 2))
409 return -EPERM; 407 return -EPERM;
410 408
411 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 409 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
412 return -EFAULT; 410 return -EFAULT;
413 411
414 if (buf.length > 0x4096) 412 if (buf.length > 0x4096)
415 return -EINVAL; 413 return -EINVAL;
416 414
@@ -426,7 +424,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
426 databuf = kmalloc(buf.length, GFP_KERNEL); 424 databuf = kmalloc(buf.length, GFP_KERNEL);
427 if (!databuf) 425 if (!databuf)
428 return -ENOMEM; 426 return -ENOMEM;
429 427
430 if (copy_from_user(databuf, buf.ptr, buf.length)) { 428 if (copy_from_user(databuf, buf.ptr, buf.length)) {
431 kfree(databuf); 429 kfree(databuf);
432 return -EFAULT; 430 return -EFAULT;
@@ -450,7 +448,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
450 448
451 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 449 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf)))
452 return -EFAULT; 450 return -EFAULT;
453 451
454 if (buf.length > 0x4096) 452 if (buf.length > 0x4096)
455 return -EINVAL; 453 return -EINVAL;
456 454
@@ -466,14 +464,14 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
466 databuf = kmalloc(buf.length, GFP_KERNEL); 464 databuf = kmalloc(buf.length, GFP_KERNEL);
467 if (!databuf) 465 if (!databuf)
468 return -ENOMEM; 466 return -ENOMEM;
469 467
470 ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); 468 ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf);
471 469
472 if (put_user(retlen, (uint32_t __user *)argp)) 470 if (put_user(retlen, (uint32_t __user *)argp))
473 ret = -EFAULT; 471 ret = -EFAULT;
474 else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) 472 else if (retlen && copy_to_user(buf.ptr, databuf, retlen))
475 ret = -EFAULT; 473 ret = -EFAULT;
476 474
477 kfree(databuf); 475 kfree(databuf);
478 break; 476 break;
479 } 477 }
@@ -523,7 +521,7 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
523 case MEMGETBADBLOCK: 521 case MEMGETBADBLOCK:
524 { 522 {
525 loff_t offs; 523 loff_t offs;
526 524
527 if (copy_from_user(&offs, argp, sizeof(loff_t))) 525 if (copy_from_user(&offs, argp, sizeof(loff_t)))
528 return -EFAULT; 526 return -EFAULT;
529 if (!mtd->block_isbad) 527 if (!mtd->block_isbad)