1 /* 2 * $Id: mtdchar.c,v 1.76 2005/11/07 11:14:20 gleixner Exp $ 3 * 4 * Character-device access to raw MTD devices. 5 * 6 */ 7 8 #include <linux/config.h> 9 #include <linux/device.h> 10 #include <linux/fs.h> 11 #include <linux/init.h> 12 #include <linux/kernel.h> 13 #include <linux/module.h> 14 #include <linux/slab.h> 15 #include <linux/sched.h> 16 17 #include <linux/mtd/mtd.h> 18 #include <linux/mtd/compatmac.h> 19 20 #include <asm/uaccess.h> 21 22 static struct class *mtd_class; 23 24 static void mtd_notify_add(struct mtd_info* mtd) 25 { 26 if (!mtd) 27 return; 28 29 class_device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), 30 NULL, "mtd%d", mtd->index); 31 32 class_device_create(mtd_class, NULL, 33 MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), 34 NULL, "mtd%dro", mtd->index); 35 } 36 37 static void mtd_notify_remove(struct mtd_info* mtd) 38 { 39 if (!mtd) 40 return; 41 42 class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); 43 class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); 44 } 45 46 static struct mtd_notifier notifier = { 47 .add = mtd_notify_add, 48 .remove = mtd_notify_remove, 49 }; 50 51 /* 52 * We use file->private_data to store a pointer to the MTDdevice. 53 * Since alighment is at least 32 bits, we have 2 bits free for OTP 54 * modes as well. 55 */ 56 57 #define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L) 58 59 #define MTD_MODE_OTP_FACT 1 60 #define MTD_MODE_OTP_USER 2 61 #define MTD_MODE(file) ((long)((file)->private_data) & 3) 62 63 #define SET_MTD_MODE(file, mode) \ 64 do { long __p = (long)((file)->private_data); \ 65 (file)->private_data = (void *)((__p & ~3L) | mode); } while (0) 66 67 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) 68 { 69 struct mtd_info *mtd = TO_MTD(file); 70 71 switch (orig) { 72 case 0: 73 /* SEEK_SET */ 74 break; 75 case 1: 76 /* SEEK_CUR */ 77 offset += file->f_pos; 78 break; 79 case 2: 80 /* SEEK_END */ 81 offset += mtd->size; 82 break; 83 default: 84 return -EINVAL; 85 } 86 87 if (offset >= 0 && offset < mtd->size) 88 return file->f_pos = offset; 89 90 return -EINVAL; 91 } 92 93 94 95 static int mtd_open(struct inode *inode, struct file *file) 96 { 97 int minor = iminor(inode); 98 int devnum = minor >> 1; 99 struct mtd_info *mtd; 100 101 DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); 102 103 if (devnum >= MAX_MTD_DEVICES) 104 return -ENODEV; 105 106 /* You can't open the RO devices RW */ 107 if ((file->f_mode & 2) && (minor & 1)) 108 return -EACCES; 109 110 mtd = get_mtd_device(NULL, devnum); 111 112 if (!mtd) 113 return -ENODEV; 114 115 if (MTD_ABSENT == mtd->type) { 116 put_mtd_device(mtd); 117 return -ENODEV; 118 } 119 120 file->private_data = mtd; 121 122 /* You can't open it RW if it's not a writeable device */ 123 if ((file->f_mode & 2) && !(mtd->flags & MTD_WRITEABLE)) { 124 put_mtd_device(mtd); 125 return -EACCES; 126 } 127 128 return 0; 129 } /* mtd_open */ 130 131 /*====================================================================*/ 132 133 static int mtd_close(struct inode *inode, struct file *file) 134 { 135 struct mtd_info *mtd; 136 137 DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); 138 139 mtd = TO_MTD(file); 140 141 if (mtd->sync) 142 mtd->sync(mtd); 143 144 put_mtd_device(mtd); 145 146 return 0; 147 } /* mtd_close */ 148 149 /* FIXME: This _really_ needs to die. In 2.5, we should lock the 150 userspace buffer down and use it directly with readv/writev. 151 */ 152 #define MAX_KMALLOC_SIZE 0x20000 153 154 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) 155 { 156 struct mtd_info *mtd = TO_MTD(file); 157 size_t retlen=0; 158 size_t total_retlen=0; 159 int ret=0; 160 int len; 161 char *kbuf; 162 163 DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); 164 165 if (*ppos + count > mtd->size) 166 count = mtd->size - *ppos; 167 168 if (!count) 169 return 0; 170 171 /* FIXME: Use kiovec in 2.5 to lock down the user's buffers 172 and pass them directly to the MTD functions */ 173 while (count) { 174 if (count > MAX_KMALLOC_SIZE) 175 len = MAX_KMALLOC_SIZE; 176 else 177 len = count; 178 179 kbuf=kmalloc(len,GFP_KERNEL); 180 if (!kbuf) 181 return -ENOMEM; 182 183 switch (MTD_MODE(file)) { 184 case MTD_MODE_OTP_FACT: 185 ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); 186 break; 187 case MTD_MODE_OTP_USER: 188 ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); 189 break; 190 default: 191 ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf); 192 } 193 /* Nand returns -EBADMSG on ecc errors, but it returns 194 * the data. For our userspace tools it is important 195 * to dump areas with ecc errors ! 196 * Userspace software which accesses NAND this way 197 * must be aware of the fact that it deals with NAND 198 */ 199 if (!ret || (ret == -EBADMSG)) { 200 *ppos += retlen; 201 if (copy_to_user(buf, kbuf, retlen)) { 202 kfree(kbuf); 203 return -EFAULT; 204 } 205 else 206 total_retlen += retlen; 207 208 count -= retlen; 209 buf += retlen; 210 if (retlen == 0) 211 count = 0; 212 } 213 else { 214 kfree(kbuf); 215 return ret; 216 } 217 218 kfree(kbuf); 219 } 220 221 return total_retlen; 222 } /* mtd_read */ 223 224 static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) 225 { 226 struct mtd_info *mtd = TO_MTD(file); 227 char *kbuf; 228 size_t retlen; 229 size_t total_retlen=0; 230 int ret=0; 231 int len; 232 233 DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); 234 235 if (*ppos == mtd->size) 236 return -ENOSPC; 237 238 if (*ppos + count > mtd->size) 239 count = mtd->size - *ppos; 240 241 if (!count) 242 return 0; 243 244 while (count) { 245 if (count > MAX_KMALLOC_SIZE) 246 len = MAX_KMALLOC_SIZE; 247 else 248 len = count; 249 250 kbuf=kmalloc(len,GFP_KERNEL); 251 if (!kbuf) { 252 printk("kmalloc is null\n"); 253 return -ENOMEM; 254 } 255 256 if (copy_from_user(kbuf, buf, len)) { 257 kfree(kbuf); 258 return -EFAULT; 259 } 260 261 switch (MTD_MODE(file)) { 262 case MTD_MODE_OTP_FACT: 263 ret = -EROFS; 264 break; 265 case MTD_MODE_OTP_USER: 266 if (!mtd->write_user_prot_reg) { 267 ret = -EOPNOTSUPP; 268 break; 269 } 270 ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); 271 break; 272 default: 273 ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); 274 } 275 if (!ret) { 276 *ppos += retlen; 277 total_retlen += retlen; 278 count -= retlen; 279 buf += retlen; 280 } 281 else { 282 kfree(kbuf); 283 return ret; 284 } 285 286 kfree(kbuf); 287 } 288 289 return total_retlen; 290 } /* mtd_write */ 291 292 /*====================================================================== 293 294 IOCTL calls for getting device parameters. 295 296 ======================================================================*/ 297 static void mtdchar_erase_callback (struct erase_info *instr) 298 { 299 wake_up((wait_queue_head_t *)instr->priv); 300 } 301 302 static int mtd_ioctl(struct inode *inode, struct file *file, 303 u_int cmd, u_long arg) 304 { 305 struct mtd_info *mtd = TO_MTD(file); 306 void __user *argp = (void __user *)arg; 307 int ret = 0; 308 u_long size; 309 310 DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); 311 312 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; 313 if (cmd & IOC_IN) { 314 if (!access_ok(VERIFY_READ, argp, size)) 315 return -EFAULT; 316 } 317 if (cmd & IOC_OUT) { 318 if (!access_ok(VERIFY_WRITE, argp, size)) 319 return -EFAULT; 320 } 321 322 switch (cmd) { 323 case MEMGETREGIONCOUNT: 324 if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) 325 return -EFAULT; 326 break; 327 328 case MEMGETREGIONINFO: 329 { 330 struct region_info_user ur; 331 332 if (copy_from_user(&ur, argp, sizeof(struct region_info_user))) 333 return -EFAULT; 334 335 if (ur.regionindex >= mtd->numeraseregions) 336 return -EINVAL; 337 if (copy_to_user(argp, &(mtd->eraseregions[ur.regionindex]), 338 sizeof(struct mtd_erase_region_info))) 339 return -EFAULT; 340 break; 341 } 342 343 case MEMGETINFO: 344 if (copy_to_user(argp, mtd, sizeof(struct mtd_info_user))) 345 return -EFAULT; 346 break; 347 348 case MEMERASE: 349 { 350 struct erase_info *erase; 351 352 if(!(file->f_mode & 2)) 353 return -EPERM; 354 355 erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL); 356 if (!erase) 357 ret = -ENOMEM; 358 else { 359 wait_queue_head_t waitq; 360 DECLARE_WAITQUEUE(wait, current); 361 362 init_waitqueue_head(&waitq); 363 364 memset (erase,0,sizeof(struct erase_info)); 365 if (copy_from_user(&erase->addr, argp, 366 sizeof(struct erase_info_user))) { 367 kfree(erase); 368 return -EFAULT; 369 } 370 erase->mtd = mtd; 371 erase->callback = mtdchar_erase_callback; 372 erase->priv = (unsigned long)&waitq; 373 374 /* 375 FIXME: Allow INTERRUPTIBLE. Which means 376 not having the wait_queue head on the stack. 377 378 If the wq_head is on the stack, and we 379 leave because we got interrupted, then the 380 wq_head is no longer there when the 381 callback routine tries to wake us up. 382 */ 383 ret = mtd->erase(mtd, erase); 384 if (!ret) { 385 set_current_state(TASK_UNINTERRUPTIBLE); 386 add_wait_queue(&waitq, &wait); 387 if (erase->state != MTD_ERASE_DONE && 388 erase->state != MTD_ERASE_FAILED) 389 schedule(); 390 remove_wait_queue(&waitq, &wait); 391 set_current_state(TASK_RUNNING); 392 393 ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0; 394 } 395 kfree(erase); 396 } 397 break; 398 } 399 400 case MEMWRITEOOB: 401 { 402 struct mtd_oob_buf buf; 403 void *databuf; 404 ssize_t retlen; 405 406 if(!(file->f_mode & 2)) 407 return -EPERM; 408 409 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 410 return -EFAULT; 411 412 if (buf.length > 0x4096) 413 return -EINVAL; 414 415 if (!mtd->write_oob) 416 ret = -EOPNOTSUPP; 417 else 418 ret = access_ok(VERIFY_READ, buf.ptr, 419 buf.length) ? 0 : EFAULT; 420 421 if (ret) 422 return ret; 423 424 databuf = kmalloc(buf.length, GFP_KERNEL); 425 if (!databuf) 426 return -ENOMEM; 427 428 if (copy_from_user(databuf, buf.ptr, buf.length)) { 429 kfree(databuf); 430 return -EFAULT; 431 } 432 433 ret = (mtd->write_oob)(mtd, buf.start, buf.length, &retlen, databuf); 434 435 if (copy_to_user(argp + sizeof(uint32_t), &retlen, sizeof(uint32_t))) 436 ret = -EFAULT; 437 438 kfree(databuf); 439 break; 440 441 } 442 443 case MEMREADOOB: 444 { 445 struct mtd_oob_buf buf; 446 void *databuf; 447 ssize_t retlen; 448 449 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 450 return -EFAULT; 451 452 if (buf.length > 0x4096) 453 return -EINVAL; 454 455 if (!mtd->read_oob) 456 ret = -EOPNOTSUPP; 457 else 458 ret = access_ok(VERIFY_WRITE, buf.ptr, 459 buf.length) ? 0 : -EFAULT; 460 461 if (ret) 462 return ret; 463 464 databuf = kmalloc(buf.length, GFP_KERNEL); 465 if (!databuf) 466 return -ENOMEM; 467 468 ret = (mtd->read_oob)(mtd, buf.start, buf.length, &retlen, databuf); 469 470 if (put_user(retlen, (uint32_t __user *)argp)) 471 ret = -EFAULT; 472 else if (retlen && copy_to_user(buf.ptr, databuf, retlen)) 473 ret = -EFAULT; 474 475 kfree(databuf); 476 break; 477 } 478 479 case MEMLOCK: 480 { 481 struct erase_info_user info; 482 483 if (copy_from_user(&info, argp, sizeof(info))) 484 return -EFAULT; 485 486 if (!mtd->lock) 487 ret = -EOPNOTSUPP; 488 else 489 ret = mtd->lock(mtd, info.start, info.length); 490 break; 491 } 492 493 case MEMUNLOCK: 494 { 495 struct erase_info_user info; 496 497 if (copy_from_user(&info, argp, sizeof(info))) 498 return -EFAULT; 499 500 if (!mtd->unlock) 501 ret = -EOPNOTSUPP; 502 else 503 ret = mtd->unlock(mtd, info.start, info.length); 504 break; 505 } 506 507 case MEMSETOOBSEL: 508 { 509 if (copy_from_user(&mtd->oobinfo, argp, sizeof(struct nand_oobinfo))) 510 return -EFAULT; 511 break; 512 } 513 514 case MEMGETOOBSEL: 515 { 516 if (copy_to_user(argp, &(mtd->oobinfo), sizeof(struct nand_oobinfo))) 517 return -EFAULT; 518 break; 519 } 520 521 case MEMGETBADBLOCK: 522 { 523 loff_t offs; 524 525 if (copy_from_user(&offs, argp, sizeof(loff_t))) 526 return -EFAULT; 527 if (!mtd->block_isbad) 528 ret = -EOPNOTSUPP; 529 else 530 return mtd->block_isbad(mtd, offs); 531 break; 532 } 533 534 case MEMSETBADBLOCK: 535 { 536 loff_t offs; 537 538 if (copy_from_user(&offs, argp, sizeof(loff_t))) 539 return -EFAULT; 540 if (!mtd->block_markbad) 541 ret = -EOPNOTSUPP; 542 else 543 return mtd->block_markbad(mtd, offs); 544 break; 545 } 546 547 #ifdef CONFIG_MTD_OTP 548 case OTPSELECT: 549 { 550 int mode; 551 if (copy_from_user(&mode, argp, sizeof(int))) 552 return -EFAULT; 553 SET_MTD_MODE(file, 0); 554 switch (mode) { 555 case MTD_OTP_FACTORY: 556 if (!mtd->read_fact_prot_reg) 557 ret = -EOPNOTSUPP; 558 else 559 SET_MTD_MODE(file, MTD_MODE_OTP_FACT); 560 break; 561 case MTD_OTP_USER: 562 if (!mtd->read_fact_prot_reg) 563 ret = -EOPNOTSUPP; 564 else 565 SET_MTD_MODE(file, MTD_MODE_OTP_USER); 566 break; 567 default: 568 ret = -EINVAL; 569 case MTD_OTP_OFF: 570 break; 571 } 572 file->f_pos = 0; 573 break; 574 } 575 576 case OTPGETREGIONCOUNT: 577 case OTPGETREGIONINFO: 578 { 579 struct otp_info *buf = kmalloc(4096, GFP_KERNEL); 580 if (!buf) 581 return -ENOMEM; 582 ret = -EOPNOTSUPP; 583 switch (MTD_MODE(file)) { 584 case MTD_MODE_OTP_FACT: 585 if (mtd->get_fact_prot_info) 586 ret = mtd->get_fact_prot_info(mtd, buf, 4096); 587 break; 588 case MTD_MODE_OTP_USER: 589 if (mtd->get_user_prot_info) 590 ret = mtd->get_user_prot_info(mtd, buf, 4096); 591 break; 592 } 593 if (ret >= 0) { 594 if (cmd == OTPGETREGIONCOUNT) { 595 int nbr = ret / sizeof(struct otp_info); 596 ret = copy_to_user(argp, &nbr, sizeof(int)); 597 } else 598 ret = copy_to_user(argp, buf, ret); 599 if (ret) 600 ret = -EFAULT; 601 } 602 kfree(buf); 603 break; 604 } 605 606 case OTPLOCK: 607 { 608 struct otp_info info; 609 610 if (MTD_MODE(file) != MTD_MODE_OTP_USER) 611 return -EINVAL; 612 if (copy_from_user(&info, argp, sizeof(info))) 613 return -EFAULT; 614 if (!mtd->lock_user_prot_reg) 615 return -EOPNOTSUPP; 616 ret = mtd->lock_user_prot_reg(mtd, info.start, info.length); 617 break; 618 } 619 #endif 620 621 default: 622 ret = -ENOTTY; 623 } 624 625 return ret; 626 } /* memory_ioctl */ 627 628 static struct file_operations mtd_fops = { 629 .owner = THIS_MODULE, 630 .llseek = mtd_lseek, 631 .read = mtd_read, 632 .write = mtd_write, 633 .ioctl = mtd_ioctl, 634 .open = mtd_open, 635 .release = mtd_close, 636 }; 637 638 static int __init init_mtdchar(void) 639 { 640 if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { 641 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", 642 MTD_CHAR_MAJOR); 643 return -EAGAIN; 644 } 645 646 mtd_class = class_create(THIS_MODULE, "mtd"); 647 648 if (IS_ERR(mtd_class)) { 649 printk(KERN_ERR "Error creating mtd class.\n"); 650 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 651 return PTR_ERR(mtd_class); 652 } 653 654 register_mtd_user(¬ifier); 655 return 0; 656 } 657 658 static void __exit cleanup_mtdchar(void) 659 { 660 unregister_mtd_user(¬ifier); 661 class_destroy(mtd_class); 662 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 663 } 664 665 module_init(init_mtdchar); 666 module_exit(cleanup_mtdchar); 667 668 669 MODULE_LICENSE("GPL"); 670 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 671 MODULE_DESCRIPTION("Direct character-device access to MTD devices"); 672