Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.5 740 lines 18 kB view raw
1/* 2 * Copyright (C) 2006-2008 Nokia Corporation 3 * 4 * This program is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 as published by 6 * the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 11 * more details. 12 * 13 * You should have received a copy of the GNU General Public License along with 14 * this program; see the file COPYING. If not, write to the Free Software 15 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16 * 17 * Test OOB read and write on MTD device. 18 * 19 * Author: Adrian Hunter <ext-adrian.hunter@nokia.com> 20 */ 21 22#include <asm/div64.h> 23#include <linux/init.h> 24#include <linux/module.h> 25#include <linux/moduleparam.h> 26#include <linux/err.h> 27#include <linux/mtd/mtd.h> 28#include <linux/slab.h> 29#include <linux/sched.h> 30 31#define PRINT_PREF KERN_INFO "mtd_oobtest: " 32 33static int dev = -EINVAL; 34module_param(dev, int, S_IRUGO); 35MODULE_PARM_DESC(dev, "MTD device number to use"); 36 37static struct mtd_info *mtd; 38static unsigned char *readbuf; 39static unsigned char *writebuf; 40static unsigned char *bbt; 41 42static int ebcnt; 43static int pgcnt; 44static int errcnt; 45static int use_offset; 46static int use_len; 47static int use_len_max; 48static int vary_offset; 49static unsigned long next = 1; 50 51static inline unsigned int simple_rand(void) 52{ 53 next = next * 1103515245 + 12345; 54 return (unsigned int)((next / 65536) % 32768); 55} 56 57static inline void simple_srand(unsigned long seed) 58{ 59 next = seed; 60} 61 62static void set_random_data(unsigned char *buf, size_t len) 63{ 64 size_t i; 65 66 for (i = 0; i < len; ++i) 67 buf[i] = simple_rand(); 68} 69 70static int erase_eraseblock(int ebnum) 71{ 72 int err; 73 struct erase_info ei; 74 loff_t addr = ebnum * mtd->erasesize; 75 76 memset(&ei, 0, sizeof(struct erase_info)); 77 ei.mtd = mtd; 78 ei.addr = addr; 79 ei.len = mtd->erasesize; 80 81 err = mtd_erase(mtd, &ei); 82 if (err) { 83 printk(PRINT_PREF "error %d while erasing EB %d\n", err, ebnum); 84 return err; 85 } 86 87 if (ei.state == MTD_ERASE_FAILED) { 88 printk(PRINT_PREF "some erase error occurred at EB %d\n", 89 ebnum); 90 return -EIO; 91 } 92 93 return 0; 94} 95 96static int erase_whole_device(void) 97{ 98 int err; 99 unsigned int i; 100 101 printk(PRINT_PREF "erasing whole device\n"); 102 for (i = 0; i < ebcnt; ++i) { 103 if (bbt[i]) 104 continue; 105 err = erase_eraseblock(i); 106 if (err) 107 return err; 108 cond_resched(); 109 } 110 printk(PRINT_PREF "erased %u eraseblocks\n", i); 111 return 0; 112} 113 114static void do_vary_offset(void) 115{ 116 use_len -= 1; 117 if (use_len < 1) { 118 use_offset += 1; 119 if (use_offset >= use_len_max) 120 use_offset = 0; 121 use_len = use_len_max - use_offset; 122 } 123} 124 125static int write_eraseblock(int ebnum) 126{ 127 int i; 128 struct mtd_oob_ops ops; 129 int err = 0; 130 loff_t addr = ebnum * mtd->erasesize; 131 132 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 133 set_random_data(writebuf, use_len); 134 ops.mode = MTD_OPS_AUTO_OOB; 135 ops.len = 0; 136 ops.retlen = 0; 137 ops.ooblen = use_len; 138 ops.oobretlen = 0; 139 ops.ooboffs = use_offset; 140 ops.datbuf = NULL; 141 ops.oobbuf = writebuf; 142 err = mtd_write_oob(mtd, addr, &ops); 143 if (err || ops.oobretlen != use_len) { 144 printk(PRINT_PREF "error: writeoob failed at %#llx\n", 145 (long long)addr); 146 printk(PRINT_PREF "error: use_len %d, use_offset %d\n", 147 use_len, use_offset); 148 errcnt += 1; 149 return err ? err : -1; 150 } 151 if (vary_offset) 152 do_vary_offset(); 153 } 154 155 return err; 156} 157 158static int write_whole_device(void) 159{ 160 int err; 161 unsigned int i; 162 163 printk(PRINT_PREF "writing OOBs of whole device\n"); 164 for (i = 0; i < ebcnt; ++i) { 165 if (bbt[i]) 166 continue; 167 err = write_eraseblock(i); 168 if (err) 169 return err; 170 if (i % 256 == 0) 171 printk(PRINT_PREF "written up to eraseblock %u\n", i); 172 cond_resched(); 173 } 174 printk(PRINT_PREF "written %u eraseblocks\n", i); 175 return 0; 176} 177 178static int verify_eraseblock(int ebnum) 179{ 180 int i; 181 struct mtd_oob_ops ops; 182 int err = 0; 183 loff_t addr = ebnum * mtd->erasesize; 184 185 for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { 186 set_random_data(writebuf, use_len); 187 ops.mode = MTD_OPS_AUTO_OOB; 188 ops.len = 0; 189 ops.retlen = 0; 190 ops.ooblen = use_len; 191 ops.oobretlen = 0; 192 ops.ooboffs = use_offset; 193 ops.datbuf = NULL; 194 ops.oobbuf = readbuf; 195 err = mtd_read_oob(mtd, addr, &ops); 196 if (err || ops.oobretlen != use_len) { 197 printk(PRINT_PREF "error: readoob failed at %#llx\n", 198 (long long)addr); 199 errcnt += 1; 200 return err ? err : -1; 201 } 202 if (memcmp(readbuf, writebuf, use_len)) { 203 printk(PRINT_PREF "error: verify failed at %#llx\n", 204 (long long)addr); 205 errcnt += 1; 206 if (errcnt > 1000) { 207 printk(PRINT_PREF "error: too many errors\n"); 208 return -1; 209 } 210 } 211 if (use_offset != 0 || use_len < mtd->ecclayout->oobavail) { 212 int k; 213 214 ops.mode = MTD_OPS_AUTO_OOB; 215 ops.len = 0; 216 ops.retlen = 0; 217 ops.ooblen = mtd->ecclayout->oobavail; 218 ops.oobretlen = 0; 219 ops.ooboffs = 0; 220 ops.datbuf = NULL; 221 ops.oobbuf = readbuf; 222 err = mtd_read_oob(mtd, addr, &ops); 223 if (err || ops.oobretlen != mtd->ecclayout->oobavail) { 224 printk(PRINT_PREF "error: readoob failed at " 225 "%#llx\n", (long long)addr); 226 errcnt += 1; 227 return err ? err : -1; 228 } 229 if (memcmp(readbuf + use_offset, writebuf, use_len)) { 230 printk(PRINT_PREF "error: verify failed at " 231 "%#llx\n", (long long)addr); 232 errcnt += 1; 233 if (errcnt > 1000) { 234 printk(PRINT_PREF "error: too many " 235 "errors\n"); 236 return -1; 237 } 238 } 239 for (k = 0; k < use_offset; ++k) 240 if (readbuf[k] != 0xff) { 241 printk(PRINT_PREF "error: verify 0xff " 242 "failed at %#llx\n", 243 (long long)addr); 244 errcnt += 1; 245 if (errcnt > 1000) { 246 printk(PRINT_PREF "error: too " 247 "many errors\n"); 248 return -1; 249 } 250 } 251 for (k = use_offset + use_len; 252 k < mtd->ecclayout->oobavail; ++k) 253 if (readbuf[k] != 0xff) { 254 printk(PRINT_PREF "error: verify 0xff " 255 "failed at %#llx\n", 256 (long long)addr); 257 errcnt += 1; 258 if (errcnt > 1000) { 259 printk(PRINT_PREF "error: too " 260 "many errors\n"); 261 return -1; 262 } 263 } 264 } 265 if (vary_offset) 266 do_vary_offset(); 267 } 268 return err; 269} 270 271static int verify_eraseblock_in_one_go(int ebnum) 272{ 273 struct mtd_oob_ops ops; 274 int err = 0; 275 loff_t addr = ebnum * mtd->erasesize; 276 size_t len = mtd->ecclayout->oobavail * pgcnt; 277 278 set_random_data(writebuf, len); 279 ops.mode = MTD_OPS_AUTO_OOB; 280 ops.len = 0; 281 ops.retlen = 0; 282 ops.ooblen = len; 283 ops.oobretlen = 0; 284 ops.ooboffs = 0; 285 ops.datbuf = NULL; 286 ops.oobbuf = readbuf; 287 err = mtd_read_oob(mtd, addr, &ops); 288 if (err || ops.oobretlen != len) { 289 printk(PRINT_PREF "error: readoob failed at %#llx\n", 290 (long long)addr); 291 errcnt += 1; 292 return err ? err : -1; 293 } 294 if (memcmp(readbuf, writebuf, len)) { 295 printk(PRINT_PREF "error: verify failed at %#llx\n", 296 (long long)addr); 297 errcnt += 1; 298 if (errcnt > 1000) { 299 printk(PRINT_PREF "error: too many errors\n"); 300 return -1; 301 } 302 } 303 304 return err; 305} 306 307static int verify_all_eraseblocks(void) 308{ 309 int err; 310 unsigned int i; 311 312 printk(PRINT_PREF "verifying all eraseblocks\n"); 313 for (i = 0; i < ebcnt; ++i) { 314 if (bbt[i]) 315 continue; 316 err = verify_eraseblock(i); 317 if (err) 318 return err; 319 if (i % 256 == 0) 320 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 321 cond_resched(); 322 } 323 printk(PRINT_PREF "verified %u eraseblocks\n", i); 324 return 0; 325} 326 327static int is_block_bad(int ebnum) 328{ 329 int ret; 330 loff_t addr = ebnum * mtd->erasesize; 331 332 ret = mtd_block_isbad(mtd, addr); 333 if (ret) 334 printk(PRINT_PREF "block %d is bad\n", ebnum); 335 return ret; 336} 337 338static int scan_for_bad_eraseblocks(void) 339{ 340 int i, bad = 0; 341 342 bbt = kmalloc(ebcnt, GFP_KERNEL); 343 if (!bbt) { 344 printk(PRINT_PREF "error: cannot allocate memory\n"); 345 return -ENOMEM; 346 } 347 348 printk(PRINT_PREF "scanning for bad eraseblocks\n"); 349 for (i = 0; i < ebcnt; ++i) { 350 bbt[i] = is_block_bad(i) ? 1 : 0; 351 if (bbt[i]) 352 bad += 1; 353 cond_resched(); 354 } 355 printk(PRINT_PREF "scanned %d eraseblocks, %d are bad\n", i, bad); 356 return 0; 357} 358 359static int __init mtd_oobtest_init(void) 360{ 361 int err = 0; 362 unsigned int i; 363 uint64_t tmp; 364 struct mtd_oob_ops ops; 365 loff_t addr = 0, addr0; 366 367 printk(KERN_INFO "\n"); 368 printk(KERN_INFO "=================================================\n"); 369 370 if (dev < 0) { 371 printk(PRINT_PREF "Please specify a valid mtd-device via module paramter\n"); 372 printk(KERN_CRIT "CAREFUL: This test wipes all data on the specified MTD device!\n"); 373 return -EINVAL; 374 } 375 376 printk(PRINT_PREF "MTD device: %d\n", dev); 377 378 mtd = get_mtd_device(NULL, dev); 379 if (IS_ERR(mtd)) { 380 err = PTR_ERR(mtd); 381 printk(PRINT_PREF "error: cannot get MTD device\n"); 382 return err; 383 } 384 385 if (mtd->type != MTD_NANDFLASH) { 386 printk(PRINT_PREF "this test requires NAND flash\n"); 387 goto out; 388 } 389 390 tmp = mtd->size; 391 do_div(tmp, mtd->erasesize); 392 ebcnt = tmp; 393 pgcnt = mtd->erasesize / mtd->writesize; 394 395 printk(PRINT_PREF "MTD device size %llu, eraseblock size %u, " 396 "page size %u, count of eraseblocks %u, pages per " 397 "eraseblock %u, OOB size %u\n", 398 (unsigned long long)mtd->size, mtd->erasesize, 399 mtd->writesize, ebcnt, pgcnt, mtd->oobsize); 400 401 err = -ENOMEM; 402 readbuf = kmalloc(mtd->erasesize, GFP_KERNEL); 403 if (!readbuf) { 404 printk(PRINT_PREF "error: cannot allocate memory\n"); 405 goto out; 406 } 407 writebuf = kmalloc(mtd->erasesize, GFP_KERNEL); 408 if (!writebuf) { 409 printk(PRINT_PREF "error: cannot allocate memory\n"); 410 goto out; 411 } 412 413 err = scan_for_bad_eraseblocks(); 414 if (err) 415 goto out; 416 417 use_offset = 0; 418 use_len = mtd->ecclayout->oobavail; 419 use_len_max = mtd->ecclayout->oobavail; 420 vary_offset = 0; 421 422 /* First test: write all OOB, read it back and verify */ 423 printk(PRINT_PREF "test 1 of 5\n"); 424 425 err = erase_whole_device(); 426 if (err) 427 goto out; 428 429 simple_srand(1); 430 err = write_whole_device(); 431 if (err) 432 goto out; 433 434 simple_srand(1); 435 err = verify_all_eraseblocks(); 436 if (err) 437 goto out; 438 439 /* 440 * Second test: write all OOB, a block at a time, read it back and 441 * verify. 442 */ 443 printk(PRINT_PREF "test 2 of 5\n"); 444 445 err = erase_whole_device(); 446 if (err) 447 goto out; 448 449 simple_srand(3); 450 err = write_whole_device(); 451 if (err) 452 goto out; 453 454 /* Check all eraseblocks */ 455 simple_srand(3); 456 printk(PRINT_PREF "verifying all eraseblocks\n"); 457 for (i = 0; i < ebcnt; ++i) { 458 if (bbt[i]) 459 continue; 460 err = verify_eraseblock_in_one_go(i); 461 if (err) 462 goto out; 463 if (i % 256 == 0) 464 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 465 cond_resched(); 466 } 467 printk(PRINT_PREF "verified %u eraseblocks\n", i); 468 469 /* 470 * Third test: write OOB at varying offsets and lengths, read it back 471 * and verify. 472 */ 473 printk(PRINT_PREF "test 3 of 5\n"); 474 475 err = erase_whole_device(); 476 if (err) 477 goto out; 478 479 /* Write all eraseblocks */ 480 use_offset = 0; 481 use_len = mtd->ecclayout->oobavail; 482 use_len_max = mtd->ecclayout->oobavail; 483 vary_offset = 1; 484 simple_srand(5); 485 486 err = write_whole_device(); 487 if (err) 488 goto out; 489 490 /* Check all eraseblocks */ 491 use_offset = 0; 492 use_len = mtd->ecclayout->oobavail; 493 use_len_max = mtd->ecclayout->oobavail; 494 vary_offset = 1; 495 simple_srand(5); 496 err = verify_all_eraseblocks(); 497 if (err) 498 goto out; 499 500 use_offset = 0; 501 use_len = mtd->ecclayout->oobavail; 502 use_len_max = mtd->ecclayout->oobavail; 503 vary_offset = 0; 504 505 /* Fourth test: try to write off end of device */ 506 printk(PRINT_PREF "test 4 of 5\n"); 507 508 err = erase_whole_device(); 509 if (err) 510 goto out; 511 512 addr0 = 0; 513 for (i = 0; i < ebcnt && bbt[i]; ++i) 514 addr0 += mtd->erasesize; 515 516 /* Attempt to write off end of OOB */ 517 ops.mode = MTD_OPS_AUTO_OOB; 518 ops.len = 0; 519 ops.retlen = 0; 520 ops.ooblen = 1; 521 ops.oobretlen = 0; 522 ops.ooboffs = mtd->ecclayout->oobavail; 523 ops.datbuf = NULL; 524 ops.oobbuf = writebuf; 525 printk(PRINT_PREF "attempting to start write past end of OOB\n"); 526 printk(PRINT_PREF "an error is expected...\n"); 527 err = mtd_write_oob(mtd, addr0, &ops); 528 if (err) { 529 printk(PRINT_PREF "error occurred as expected\n"); 530 err = 0; 531 } else { 532 printk(PRINT_PREF "error: can write past end of OOB\n"); 533 errcnt += 1; 534 } 535 536 /* Attempt to read off end of OOB */ 537 ops.mode = MTD_OPS_AUTO_OOB; 538 ops.len = 0; 539 ops.retlen = 0; 540 ops.ooblen = 1; 541 ops.oobretlen = 0; 542 ops.ooboffs = mtd->ecclayout->oobavail; 543 ops.datbuf = NULL; 544 ops.oobbuf = readbuf; 545 printk(PRINT_PREF "attempting to start read past end of OOB\n"); 546 printk(PRINT_PREF "an error is expected...\n"); 547 err = mtd_read_oob(mtd, addr0, &ops); 548 if (err) { 549 printk(PRINT_PREF "error occurred as expected\n"); 550 err = 0; 551 } else { 552 printk(PRINT_PREF "error: can read past end of OOB\n"); 553 errcnt += 1; 554 } 555 556 if (bbt[ebcnt - 1]) 557 printk(PRINT_PREF "skipping end of device tests because last " 558 "block is bad\n"); 559 else { 560 /* Attempt to write off end of device */ 561 ops.mode = MTD_OPS_AUTO_OOB; 562 ops.len = 0; 563 ops.retlen = 0; 564 ops.ooblen = mtd->ecclayout->oobavail + 1; 565 ops.oobretlen = 0; 566 ops.ooboffs = 0; 567 ops.datbuf = NULL; 568 ops.oobbuf = writebuf; 569 printk(PRINT_PREF "attempting to write past end of device\n"); 570 printk(PRINT_PREF "an error is expected...\n"); 571 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 572 if (err) { 573 printk(PRINT_PREF "error occurred as expected\n"); 574 err = 0; 575 } else { 576 printk(PRINT_PREF "error: wrote past end of device\n"); 577 errcnt += 1; 578 } 579 580 /* Attempt to read off end of device */ 581 ops.mode = MTD_OPS_AUTO_OOB; 582 ops.len = 0; 583 ops.retlen = 0; 584 ops.ooblen = mtd->ecclayout->oobavail + 1; 585 ops.oobretlen = 0; 586 ops.ooboffs = 0; 587 ops.datbuf = NULL; 588 ops.oobbuf = readbuf; 589 printk(PRINT_PREF "attempting to read past end of device\n"); 590 printk(PRINT_PREF "an error is expected...\n"); 591 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 592 if (err) { 593 printk(PRINT_PREF "error occurred as expected\n"); 594 err = 0; 595 } else { 596 printk(PRINT_PREF "error: read past end of device\n"); 597 errcnt += 1; 598 } 599 600 err = erase_eraseblock(ebcnt - 1); 601 if (err) 602 goto out; 603 604 /* Attempt to write off end of device */ 605 ops.mode = MTD_OPS_AUTO_OOB; 606 ops.len = 0; 607 ops.retlen = 0; 608 ops.ooblen = mtd->ecclayout->oobavail; 609 ops.oobretlen = 0; 610 ops.ooboffs = 1; 611 ops.datbuf = NULL; 612 ops.oobbuf = writebuf; 613 printk(PRINT_PREF "attempting to write past end of device\n"); 614 printk(PRINT_PREF "an error is expected...\n"); 615 err = mtd_write_oob(mtd, mtd->size - mtd->writesize, &ops); 616 if (err) { 617 printk(PRINT_PREF "error occurred as expected\n"); 618 err = 0; 619 } else { 620 printk(PRINT_PREF "error: wrote past end of device\n"); 621 errcnt += 1; 622 } 623 624 /* Attempt to read off end of device */ 625 ops.mode = MTD_OPS_AUTO_OOB; 626 ops.len = 0; 627 ops.retlen = 0; 628 ops.ooblen = mtd->ecclayout->oobavail; 629 ops.oobretlen = 0; 630 ops.ooboffs = 1; 631 ops.datbuf = NULL; 632 ops.oobbuf = readbuf; 633 printk(PRINT_PREF "attempting to read past end of device\n"); 634 printk(PRINT_PREF "an error is expected...\n"); 635 err = mtd_read_oob(mtd, mtd->size - mtd->writesize, &ops); 636 if (err) { 637 printk(PRINT_PREF "error occurred as expected\n"); 638 err = 0; 639 } else { 640 printk(PRINT_PREF "error: read past end of device\n"); 641 errcnt += 1; 642 } 643 } 644 645 /* Fifth test: write / read across block boundaries */ 646 printk(PRINT_PREF "test 5 of 5\n"); 647 648 /* Erase all eraseblocks */ 649 err = erase_whole_device(); 650 if (err) 651 goto out; 652 653 /* Write all eraseblocks */ 654 simple_srand(11); 655 printk(PRINT_PREF "writing OOBs of whole device\n"); 656 for (i = 0; i < ebcnt - 1; ++i) { 657 int cnt = 2; 658 int pg; 659 size_t sz = mtd->ecclayout->oobavail; 660 if (bbt[i] || bbt[i + 1]) 661 continue; 662 addr = (i + 1) * mtd->erasesize - mtd->writesize; 663 for (pg = 0; pg < cnt; ++pg) { 664 set_random_data(writebuf, sz); 665 ops.mode = MTD_OPS_AUTO_OOB; 666 ops.len = 0; 667 ops.retlen = 0; 668 ops.ooblen = sz; 669 ops.oobretlen = 0; 670 ops.ooboffs = 0; 671 ops.datbuf = NULL; 672 ops.oobbuf = writebuf; 673 err = mtd_write_oob(mtd, addr, &ops); 674 if (err) 675 goto out; 676 if (i % 256 == 0) 677 printk(PRINT_PREF "written up to eraseblock " 678 "%u\n", i); 679 cond_resched(); 680 addr += mtd->writesize; 681 } 682 } 683 printk(PRINT_PREF "written %u eraseblocks\n", i); 684 685 /* Check all eraseblocks */ 686 simple_srand(11); 687 printk(PRINT_PREF "verifying all eraseblocks\n"); 688 for (i = 0; i < ebcnt - 1; ++i) { 689 if (bbt[i] || bbt[i + 1]) 690 continue; 691 set_random_data(writebuf, mtd->ecclayout->oobavail * 2); 692 addr = (i + 1) * mtd->erasesize - mtd->writesize; 693 ops.mode = MTD_OPS_AUTO_OOB; 694 ops.len = 0; 695 ops.retlen = 0; 696 ops.ooblen = mtd->ecclayout->oobavail * 2; 697 ops.oobretlen = 0; 698 ops.ooboffs = 0; 699 ops.datbuf = NULL; 700 ops.oobbuf = readbuf; 701 err = mtd_read_oob(mtd, addr, &ops); 702 if (err) 703 goto out; 704 if (memcmp(readbuf, writebuf, mtd->ecclayout->oobavail * 2)) { 705 printk(PRINT_PREF "error: verify failed at %#llx\n", 706 (long long)addr); 707 errcnt += 1; 708 if (errcnt > 1000) { 709 printk(PRINT_PREF "error: too many errors\n"); 710 goto out; 711 } 712 } 713 if (i % 256 == 0) 714 printk(PRINT_PREF "verified up to eraseblock %u\n", i); 715 cond_resched(); 716 } 717 printk(PRINT_PREF "verified %u eraseblocks\n", i); 718 719 printk(PRINT_PREF "finished with %d errors\n", errcnt); 720out: 721 kfree(bbt); 722 kfree(writebuf); 723 kfree(readbuf); 724 put_mtd_device(mtd); 725 if (err) 726 printk(PRINT_PREF "error %d occurred\n", err); 727 printk(KERN_INFO "=================================================\n"); 728 return err; 729} 730module_init(mtd_oobtest_init); 731 732static void __exit mtd_oobtest_exit(void) 733{ 734 return; 735} 736module_exit(mtd_oobtest_exit); 737 738MODULE_DESCRIPTION("Out-of-band test module"); 739MODULE_AUTHOR("Adrian Hunter"); 740MODULE_LICENSE("GPL");