1 /* 2 * Character-device access to raw MTD devices. 3 * 4 */ 5 6 #include <linux/device.h> 7 #include <linux/fs.h> 8 #include <linux/mm.h> 9 #include <linux/err.h> 10 #include <linux/init.h> 11 #include <linux/kernel.h> 12 #include <linux/module.h> 13 #include <linux/slab.h> 14 #include <linux/sched.h> 15 #include <linux/smp_lock.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 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2), 30 NULL, "mtd%d", mtd->index); 31 32 device_create(mtd_class, NULL, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1), 33 NULL, "mtd%dro", mtd->index); 34 } 35 36 static void mtd_notify_remove(struct mtd_info* mtd) 37 { 38 if (!mtd) 39 return; 40 41 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2)); 42 device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1)); 43 } 44 45 static struct mtd_notifier notifier = { 46 .add = mtd_notify_add, 47 .remove = mtd_notify_remove, 48 }; 49 50 /* 51 * Data structure to hold the pointer to the mtd device as well 52 * as mode information ofr various use cases. 53 */ 54 struct mtd_file_info { 55 struct mtd_info *mtd; 56 enum mtd_file_modes mode; 57 }; 58 59 static loff_t mtd_lseek (struct file *file, loff_t offset, int orig) 60 { 61 struct mtd_file_info *mfi = file->private_data; 62 struct mtd_info *mtd = mfi->mtd; 63 64 switch (orig) { 65 case SEEK_SET: 66 break; 67 case SEEK_CUR: 68 offset += file->f_pos; 69 break; 70 case SEEK_END: 71 offset += mtd->size; 72 break; 73 default: 74 return -EINVAL; 75 } 76 77 if (offset >= 0 && offset <= mtd->size) 78 return file->f_pos = offset; 79 80 return -EINVAL; 81 } 82 83 84 85 static int mtd_open(struct inode *inode, struct file *file) 86 { 87 int minor = iminor(inode); 88 int devnum = minor >> 1; 89 int ret = 0; 90 struct mtd_info *mtd; 91 struct mtd_file_info *mfi; 92 93 DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n"); 94 95 if (devnum >= MAX_MTD_DEVICES) 96 return -ENODEV; 97 98 /* You can't open the RO devices RW */ 99 if ((file->f_mode & FMODE_WRITE) && (minor & 1)) 100 return -EACCES; 101 102 lock_kernel(); 103 mtd = get_mtd_device(NULL, devnum); 104 105 if (IS_ERR(mtd)) { 106 ret = PTR_ERR(mtd); 107 goto out; 108 } 109 110 if (MTD_ABSENT == mtd->type) { 111 put_mtd_device(mtd); 112 ret = -ENODEV; 113 goto out; 114 } 115 116 /* You can't open it RW if it's not a writeable device */ 117 if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) { 118 put_mtd_device(mtd); 119 ret = -EACCES; 120 goto out; 121 } 122 123 mfi = kzalloc(sizeof(*mfi), GFP_KERNEL); 124 if (!mfi) { 125 put_mtd_device(mtd); 126 ret = -ENOMEM; 127 goto out; 128 } 129 mfi->mtd = mtd; 130 file->private_data = mfi; 131 132 out: 133 unlock_kernel(); 134 return ret; 135 } /* mtd_open */ 136 137 /*====================================================================*/ 138 139 static int mtd_close(struct inode *inode, struct file *file) 140 { 141 struct mtd_file_info *mfi = file->private_data; 142 struct mtd_info *mtd = mfi->mtd; 143 144 DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n"); 145 146 /* Only sync if opened RW */ 147 if ((file->f_mode & FMODE_WRITE) && mtd->sync) 148 mtd->sync(mtd); 149 150 put_mtd_device(mtd); 151 file->private_data = NULL; 152 kfree(mfi); 153 154 return 0; 155 } /* mtd_close */ 156 157 /* FIXME: This _really_ needs to die. In 2.5, we should lock the 158 userspace buffer down and use it directly with readv/writev. 159 */ 160 #define MAX_KMALLOC_SIZE 0x20000 161 162 static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos) 163 { 164 struct mtd_file_info *mfi = file->private_data; 165 struct mtd_info *mtd = mfi->mtd; 166 size_t retlen=0; 167 size_t total_retlen=0; 168 int ret=0; 169 int len; 170 char *kbuf; 171 172 DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n"); 173 174 if (*ppos + count > mtd->size) 175 count = mtd->size - *ppos; 176 177 if (!count) 178 return 0; 179 180 /* FIXME: Use kiovec in 2.5 to lock down the user's buffers 181 and pass them directly to the MTD functions */ 182 183 if (count > MAX_KMALLOC_SIZE) 184 kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); 185 else 186 kbuf=kmalloc(count, GFP_KERNEL); 187 188 if (!kbuf) 189 return -ENOMEM; 190 191 while (count) { 192 193 if (count > MAX_KMALLOC_SIZE) 194 len = MAX_KMALLOC_SIZE; 195 else 196 len = count; 197 198 switch (mfi->mode) { 199 case MTD_MODE_OTP_FACTORY: 200 ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf); 201 break; 202 case MTD_MODE_OTP_USER: 203 ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); 204 break; 205 case MTD_MODE_RAW: 206 { 207 struct mtd_oob_ops ops; 208 209 ops.mode = MTD_OOB_RAW; 210 ops.datbuf = kbuf; 211 ops.oobbuf = NULL; 212 ops.len = len; 213 214 ret = mtd->read_oob(mtd, *ppos, &ops); 215 retlen = ops.retlen; 216 break; 217 } 218 default: 219 ret = mtd->read(mtd, *ppos, len, &retlen, kbuf); 220 } 221 /* Nand returns -EBADMSG on ecc errors, but it returns 222 * the data. For our userspace tools it is important 223 * to dump areas with ecc errors ! 224 * For kernel internal usage it also might return -EUCLEAN 225 * to signal the caller that a bitflip has occured and has 226 * been corrected by the ECC algorithm. 227 * Userspace software which accesses NAND this way 228 * must be aware of the fact that it deals with NAND 229 */ 230 if (!ret || (ret == -EUCLEAN) || (ret == -EBADMSG)) { 231 *ppos += retlen; 232 if (copy_to_user(buf, kbuf, retlen)) { 233 kfree(kbuf); 234 return -EFAULT; 235 } 236 else 237 total_retlen += retlen; 238 239 count -= retlen; 240 buf += retlen; 241 if (retlen == 0) 242 count = 0; 243 } 244 else { 245 kfree(kbuf); 246 return ret; 247 } 248 249 } 250 251 kfree(kbuf); 252 return total_retlen; 253 } /* mtd_read */ 254 255 static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos) 256 { 257 struct mtd_file_info *mfi = file->private_data; 258 struct mtd_info *mtd = mfi->mtd; 259 char *kbuf; 260 size_t retlen; 261 size_t total_retlen=0; 262 int ret=0; 263 int len; 264 265 DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n"); 266 267 if (*ppos == mtd->size) 268 return -ENOSPC; 269 270 if (*ppos + count > mtd->size) 271 count = mtd->size - *ppos; 272 273 if (!count) 274 return 0; 275 276 if (count > MAX_KMALLOC_SIZE) 277 kbuf=kmalloc(MAX_KMALLOC_SIZE, GFP_KERNEL); 278 else 279 kbuf=kmalloc(count, GFP_KERNEL); 280 281 if (!kbuf) 282 return -ENOMEM; 283 284 while (count) { 285 286 if (count > MAX_KMALLOC_SIZE) 287 len = MAX_KMALLOC_SIZE; 288 else 289 len = count; 290 291 if (copy_from_user(kbuf, buf, len)) { 292 kfree(kbuf); 293 return -EFAULT; 294 } 295 296 switch (mfi->mode) { 297 case MTD_MODE_OTP_FACTORY: 298 ret = -EROFS; 299 break; 300 case MTD_MODE_OTP_USER: 301 if (!mtd->write_user_prot_reg) { 302 ret = -EOPNOTSUPP; 303 break; 304 } 305 ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf); 306 break; 307 308 case MTD_MODE_RAW: 309 { 310 struct mtd_oob_ops ops; 311 312 ops.mode = MTD_OOB_RAW; 313 ops.datbuf = kbuf; 314 ops.oobbuf = NULL; 315 ops.len = len; 316 317 ret = mtd->write_oob(mtd, *ppos, &ops); 318 retlen = ops.retlen; 319 break; 320 } 321 322 default: 323 ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf); 324 } 325 if (!ret) { 326 *ppos += retlen; 327 total_retlen += retlen; 328 count -= retlen; 329 buf += retlen; 330 } 331 else { 332 kfree(kbuf); 333 return ret; 334 } 335 } 336 337 kfree(kbuf); 338 return total_retlen; 339 } /* mtd_write */ 340 341 /*====================================================================== 342 343 IOCTL calls for getting device parameters. 344 345 ======================================================================*/ 346 static void mtdchar_erase_callback (struct erase_info *instr) 347 { 348 wake_up((wait_queue_head_t *)instr->priv); 349 } 350 351 #ifdef CONFIG_HAVE_MTD_OTP 352 static int otp_select_filemode(struct mtd_file_info *mfi, int mode) 353 { 354 struct mtd_info *mtd = mfi->mtd; 355 int ret = 0; 356 357 switch (mode) { 358 case MTD_OTP_FACTORY: 359 if (!mtd->read_fact_prot_reg) 360 ret = -EOPNOTSUPP; 361 else 362 mfi->mode = MTD_MODE_OTP_FACTORY; 363 break; 364 case MTD_OTP_USER: 365 if (!mtd->read_fact_prot_reg) 366 ret = -EOPNOTSUPP; 367 else 368 mfi->mode = MTD_MODE_OTP_USER; 369 break; 370 default: 371 ret = -EINVAL; 372 case MTD_OTP_OFF: 373 break; 374 } 375 return ret; 376 } 377 #else 378 # define otp_select_filemode(f,m) -EOPNOTSUPP 379 #endif 380 381 static int mtd_ioctl(struct inode *inode, struct file *file, 382 u_int cmd, u_long arg) 383 { 384 struct mtd_file_info *mfi = file->private_data; 385 struct mtd_info *mtd = mfi->mtd; 386 void __user *argp = (void __user *)arg; 387 int ret = 0; 388 u_long size; 389 struct mtd_info_user info; 390 391 DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n"); 392 393 size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT; 394 if (cmd & IOC_IN) { 395 if (!access_ok(VERIFY_READ, argp, size)) 396 return -EFAULT; 397 } 398 if (cmd & IOC_OUT) { 399 if (!access_ok(VERIFY_WRITE, argp, size)) 400 return -EFAULT; 401 } 402 403 switch (cmd) { 404 case MEMGETREGIONCOUNT: 405 if (copy_to_user(argp, &(mtd->numeraseregions), sizeof(int))) 406 return -EFAULT; 407 break; 408 409 case MEMGETREGIONINFO: 410 { 411 uint32_t ur_idx; 412 struct mtd_erase_region_info *kr; 413 struct region_info_user *ur = (struct region_info_user *) argp; 414 415 if (get_user(ur_idx, &(ur->regionindex))) 416 return -EFAULT; 417 418 kr = &(mtd->eraseregions[ur_idx]); 419 420 if (put_user(kr->offset, &(ur->offset)) 421 || put_user(kr->erasesize, &(ur->erasesize)) 422 || put_user(kr->numblocks, &(ur->numblocks))) 423 return -EFAULT; 424 425 break; 426 } 427 428 case MEMGETINFO: 429 info.type = mtd->type; 430 info.flags = mtd->flags; 431 info.size = mtd->size; 432 info.erasesize = mtd->erasesize; 433 info.writesize = mtd->writesize; 434 info.oobsize = mtd->oobsize; 435 /* The below fields are obsolete */ 436 info.ecctype = -1; 437 info.eccsize = 0; 438 if (copy_to_user(argp, &info, sizeof(struct mtd_info_user))) 439 return -EFAULT; 440 break; 441 442 case MEMERASE: 443 { 444 struct erase_info *erase; 445 446 if(!(file->f_mode & FMODE_WRITE)) 447 return -EPERM; 448 449 erase=kzalloc(sizeof(struct erase_info),GFP_KERNEL); 450 if (!erase) 451 ret = -ENOMEM; 452 else { 453 wait_queue_head_t waitq; 454 DECLARE_WAITQUEUE(wait, current); 455 456 init_waitqueue_head(&waitq); 457 458 if (copy_from_user(&erase->addr, argp, 459 sizeof(struct erase_info_user))) { 460 kfree(erase); 461 return -EFAULT; 462 } 463 erase->mtd = mtd; 464 erase->callback = mtdchar_erase_callback; 465 erase->priv = (unsigned long)&waitq; 466 467 /* 468 FIXME: Allow INTERRUPTIBLE. Which means 469 not having the wait_queue head on the stack. 470 471 If the wq_head is on the stack, and we 472 leave because we got interrupted, then the 473 wq_head is no longer there when the 474 callback routine tries to wake us up. 475 */ 476 ret = mtd->erase(mtd, erase); 477 if (!ret) { 478 set_current_state(TASK_UNINTERRUPTIBLE); 479 add_wait_queue(&waitq, &wait); 480 if (erase->state != MTD_ERASE_DONE && 481 erase->state != MTD_ERASE_FAILED) 482 schedule(); 483 remove_wait_queue(&waitq, &wait); 484 set_current_state(TASK_RUNNING); 485 486 ret = (erase->state == MTD_ERASE_FAILED)?-EIO:0; 487 } 488 kfree(erase); 489 } 490 break; 491 } 492 493 case MEMWRITEOOB: 494 { 495 struct mtd_oob_buf buf; 496 struct mtd_oob_ops ops; 497 struct mtd_oob_buf __user *user_buf = argp; 498 uint32_t retlen; 499 500 if(!(file->f_mode & FMODE_WRITE)) 501 return -EPERM; 502 503 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 504 return -EFAULT; 505 506 if (buf.length > 4096) 507 return -EINVAL; 508 509 if (!mtd->write_oob) 510 ret = -EOPNOTSUPP; 511 else 512 ret = access_ok(VERIFY_READ, buf.ptr, 513 buf.length) ? 0 : EFAULT; 514 515 if (ret) 516 return ret; 517 518 ops.ooblen = buf.length; 519 ops.ooboffs = buf.start & (mtd->oobsize - 1); 520 ops.datbuf = NULL; 521 ops.mode = MTD_OOB_PLACE; 522 523 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) 524 return -EINVAL; 525 526 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); 527 if (!ops.oobbuf) 528 return -ENOMEM; 529 530 if (copy_from_user(ops.oobbuf, buf.ptr, buf.length)) { 531 kfree(ops.oobbuf); 532 return -EFAULT; 533 } 534 535 buf.start &= ~(mtd->oobsize - 1); 536 ret = mtd->write_oob(mtd, buf.start, &ops); 537 538 if (ops.oobretlen > 0xFFFFFFFFU) 539 ret = -EOVERFLOW; 540 retlen = ops.oobretlen; 541 if (copy_to_user(&user_buf->length, &retlen, sizeof(buf.length))) 542 ret = -EFAULT; 543 544 kfree(ops.oobbuf); 545 break; 546 547 } 548 549 case MEMREADOOB: 550 { 551 struct mtd_oob_buf buf; 552 struct mtd_oob_ops ops; 553 554 if (copy_from_user(&buf, argp, sizeof(struct mtd_oob_buf))) 555 return -EFAULT; 556 557 if (buf.length > 4096) 558 return -EINVAL; 559 560 if (!mtd->read_oob) 561 ret = -EOPNOTSUPP; 562 else 563 ret = access_ok(VERIFY_WRITE, buf.ptr, 564 buf.length) ? 0 : -EFAULT; 565 if (ret) 566 return ret; 567 568 ops.ooblen = buf.length; 569 ops.ooboffs = buf.start & (mtd->oobsize - 1); 570 ops.datbuf = NULL; 571 ops.mode = MTD_OOB_PLACE; 572 573 if (ops.ooboffs && ops.ooblen > (mtd->oobsize - ops.ooboffs)) 574 return -EINVAL; 575 576 ops.oobbuf = kmalloc(buf.length, GFP_KERNEL); 577 if (!ops.oobbuf) 578 return -ENOMEM; 579 580 buf.start &= ~(mtd->oobsize - 1); 581 ret = mtd->read_oob(mtd, buf.start, &ops); 582 583 if (put_user(ops.oobretlen, (uint32_t __user *)argp)) 584 ret = -EFAULT; 585 else if (ops.oobretlen && copy_to_user(buf.ptr, ops.oobbuf, 586 ops.oobretlen)) 587 ret = -EFAULT; 588 589 kfree(ops.oobbuf); 590 break; 591 } 592 593 case MEMLOCK: 594 { 595 struct erase_info_user einfo; 596 597 if (copy_from_user(&einfo, argp, sizeof(einfo))) 598 return -EFAULT; 599 600 if (!mtd->lock) 601 ret = -EOPNOTSUPP; 602 else 603 ret = mtd->lock(mtd, einfo.start, einfo.length); 604 break; 605 } 606 607 case MEMUNLOCK: 608 { 609 struct erase_info_user einfo; 610 611 if (copy_from_user(&einfo, argp, sizeof(einfo))) 612 return -EFAULT; 613 614 if (!mtd->unlock) 615 ret = -EOPNOTSUPP; 616 else 617 ret = mtd->unlock(mtd, einfo.start, einfo.length); 618 break; 619 } 620 621 /* Legacy interface */ 622 case MEMGETOOBSEL: 623 { 624 struct nand_oobinfo oi; 625 626 if (!mtd->ecclayout) 627 return -EOPNOTSUPP; 628 if (mtd->ecclayout->eccbytes > ARRAY_SIZE(oi.eccpos)) 629 return -EINVAL; 630 631 oi.useecc = MTD_NANDECC_AUTOPLACE; 632 memcpy(&oi.eccpos, mtd->ecclayout->eccpos, sizeof(oi.eccpos)); 633 memcpy(&oi.oobfree, mtd->ecclayout->oobfree, 634 sizeof(oi.oobfree)); 635 oi.eccbytes = mtd->ecclayout->eccbytes; 636 637 if (copy_to_user(argp, &oi, sizeof(struct nand_oobinfo))) 638 return -EFAULT; 639 break; 640 } 641 642 case MEMGETBADBLOCK: 643 { 644 loff_t offs; 645 646 if (copy_from_user(&offs, argp, sizeof(loff_t))) 647 return -EFAULT; 648 if (!mtd->block_isbad) 649 ret = -EOPNOTSUPP; 650 else 651 return mtd->block_isbad(mtd, offs); 652 break; 653 } 654 655 case MEMSETBADBLOCK: 656 { 657 loff_t offs; 658 659 if (copy_from_user(&offs, argp, sizeof(loff_t))) 660 return -EFAULT; 661 if (!mtd->block_markbad) 662 ret = -EOPNOTSUPP; 663 else 664 return mtd->block_markbad(mtd, offs); 665 break; 666 } 667 668 #ifdef CONFIG_HAVE_MTD_OTP 669 case OTPSELECT: 670 { 671 int mode; 672 if (copy_from_user(&mode, argp, sizeof(int))) 673 return -EFAULT; 674 675 mfi->mode = MTD_MODE_NORMAL; 676 677 ret = otp_select_filemode(mfi, mode); 678 679 file->f_pos = 0; 680 break; 681 } 682 683 case OTPGETREGIONCOUNT: 684 case OTPGETREGIONINFO: 685 { 686 struct otp_info *buf = kmalloc(4096, GFP_KERNEL); 687 if (!buf) 688 return -ENOMEM; 689 ret = -EOPNOTSUPP; 690 switch (mfi->mode) { 691 case MTD_MODE_OTP_FACTORY: 692 if (mtd->get_fact_prot_info) 693 ret = mtd->get_fact_prot_info(mtd, buf, 4096); 694 break; 695 case MTD_MODE_OTP_USER: 696 if (mtd->get_user_prot_info) 697 ret = mtd->get_user_prot_info(mtd, buf, 4096); 698 break; 699 default: 700 break; 701 } 702 if (ret >= 0) { 703 if (cmd == OTPGETREGIONCOUNT) { 704 int nbr = ret / sizeof(struct otp_info); 705 ret = copy_to_user(argp, &nbr, sizeof(int)); 706 } else 707 ret = copy_to_user(argp, buf, ret); 708 if (ret) 709 ret = -EFAULT; 710 } 711 kfree(buf); 712 break; 713 } 714 715 case OTPLOCK: 716 { 717 struct otp_info oinfo; 718 719 if (mfi->mode != MTD_MODE_OTP_USER) 720 return -EINVAL; 721 if (copy_from_user(&oinfo, argp, sizeof(oinfo))) 722 return -EFAULT; 723 if (!mtd->lock_user_prot_reg) 724 return -EOPNOTSUPP; 725 ret = mtd->lock_user_prot_reg(mtd, oinfo.start, oinfo.length); 726 break; 727 } 728 #endif 729 730 case ECCGETLAYOUT: 731 { 732 if (!mtd->ecclayout) 733 return -EOPNOTSUPP; 734 735 if (copy_to_user(argp, mtd->ecclayout, 736 sizeof(struct nand_ecclayout))) 737 return -EFAULT; 738 break; 739 } 740 741 case ECCGETSTATS: 742 { 743 if (copy_to_user(argp, &mtd->ecc_stats, 744 sizeof(struct mtd_ecc_stats))) 745 return -EFAULT; 746 break; 747 } 748 749 case MTDFILEMODE: 750 { 751 mfi->mode = 0; 752 753 switch(arg) { 754 case MTD_MODE_OTP_FACTORY: 755 case MTD_MODE_OTP_USER: 756 ret = otp_select_filemode(mfi, arg); 757 break; 758 759 case MTD_MODE_RAW: 760 if (!mtd->read_oob || !mtd->write_oob) 761 return -EOPNOTSUPP; 762 mfi->mode = arg; 763 764 case MTD_MODE_NORMAL: 765 break; 766 default: 767 ret = -EINVAL; 768 } 769 file->f_pos = 0; 770 break; 771 } 772 773 default: 774 ret = -ENOTTY; 775 } 776 777 return ret; 778 } /* memory_ioctl */ 779 780 static const struct file_operations mtd_fops = { 781 .owner = THIS_MODULE, 782 .llseek = mtd_lseek, 783 .read = mtd_read, 784 .write = mtd_write, 785 .ioctl = mtd_ioctl, 786 .open = mtd_open, 787 .release = mtd_close, 788 }; 789 790 static int __init init_mtdchar(void) 791 { 792 if (register_chrdev(MTD_CHAR_MAJOR, "mtd", &mtd_fops)) { 793 printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices.\n", 794 MTD_CHAR_MAJOR); 795 return -EAGAIN; 796 } 797 798 mtd_class = class_create(THIS_MODULE, "mtd"); 799 800 if (IS_ERR(mtd_class)) { 801 printk(KERN_ERR "Error creating mtd class.\n"); 802 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 803 return PTR_ERR(mtd_class); 804 } 805 806 register_mtd_user(¬ifier); 807 return 0; 808 } 809 810 static void __exit cleanup_mtdchar(void) 811 { 812 unregister_mtd_user(¬ifier); 813 class_destroy(mtd_class); 814 unregister_chrdev(MTD_CHAR_MAJOR, "mtd"); 815 } 816 817 module_init(init_mtdchar); 818 module_exit(cleanup_mtdchar); 819 820 821 MODULE_LICENSE("GPL"); 822 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); 823 MODULE_DESCRIPTION("Direct character-device access to MTD devices"); 824