Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mtd_oobtest.c
Go to the documentation of this file.
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 <[email protected]>
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 
33 static int dev = -EINVAL;
34 module_param(dev, int, S_IRUGO);
35 MODULE_PARM_DESC(dev, "MTD device number to use");
36 
37 static struct mtd_info *mtd;
38 static unsigned char *readbuf;
39 static unsigned char *writebuf;
40 static unsigned char *bbt;
41 
42 static int ebcnt;
43 static int pgcnt;
44 static int errcnt;
45 static int use_offset;
46 static int use_len;
47 static int use_len_max;
48 static int vary_offset;
49 static unsigned long next = 1;
50 
51 static inline unsigned int simple_rand(void)
52 {
53  next = next * 1103515245 + 12345;
54  return (unsigned int)((next / 65536) % 32768);
55 }
56 
57 static inline void simple_srand(unsigned long seed)
58 {
59  next = seed;
60 }
61 
62 static 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 
70 static 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 
96 static 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 
114 static 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 
125 static 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 
158 static 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 
178 static 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 
271 static 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 
307 static 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 
327 static 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 
338 static 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 
359 static 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);
720 out:
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 }
730 module_init(mtd_oobtest_init);
731 
732 static void __exit mtd_oobtest_exit(void)
733 {
734  return;
735 }
736 module_exit(mtd_oobtest_exit);
737 
738 MODULE_DESCRIPTION("Out-of-band test module");
739 MODULE_AUTHOR("Adrian Hunter");
740 MODULE_LICENSE("GPL");