Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / drivers / mtd / mtdcore.c
1 /*
2  * Core registration and callback routines for MTD
3  * drivers and users.
4  *
5  * bdi bits are:
6  * Copyright © 2006 Red Hat, Inc. All Rights Reserved.
7  * Written by David Howells (dhowells@redhat.com)
8  */
9
10 #include <linux/module.h>
11 #include <linux/kernel.h>
12 #include <linux/ptrace.h>
13 #include <linux/string.h>
14 #include <linux/timer.h>
15 #include <linux/major.h>
16 #include <linux/fs.h>
17 #include <linux/err.h>
18 #include <linux/ioctl.h>
19 #include <linux/init.h>
20 #include <linux/mtd/compatmac.h>
21 #include <linux/proc_fs.h>
22 #include <linux/idr.h>
23 #include <linux/backing-dev.h>
24 #include <linux/gfp.h>
25
26 #include <linux/mtd/mtd.h>
27
28 #include "mtdcore.h"
29 /*
30  * backing device capabilities for non-mappable devices (such as NAND flash)
31  * - permits private mappings, copies are taken of the data
32  */
33 struct backing_dev_info mtd_bdi_unmappable = {
34         .capabilities   = BDI_CAP_MAP_COPY,
35 };
36
37 /*
38  * backing device capabilities for R/O mappable devices (such as ROM)
39  * - permits private mappings, copies are taken of the data
40  * - permits non-writable shared mappings
41  */
42 struct backing_dev_info mtd_bdi_ro_mappable = {
43         .capabilities   = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
44                            BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
45 };
46
47 /*
48  * backing device capabilities for writable mappable devices (such as RAM)
49  * - permits private mappings, copies are taken of the data
50  * - permits non-writable shared mappings
51  */
52 struct backing_dev_info mtd_bdi_rw_mappable = {
53         .capabilities   = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
54                            BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
55                            BDI_CAP_WRITE_MAP),
56 };
57
58 static int mtd_cls_suspend(struct device *dev, pm_message_t state);
59 static int mtd_cls_resume(struct device *dev);
60
61 static struct class mtd_class = {
62         .name = "mtd",
63         .owner = THIS_MODULE,
64         .suspend = mtd_cls_suspend,
65         .resume = mtd_cls_resume,
66 };
67
68 static DEFINE_IDR(mtd_idr);
69
70 /* These are exported solely for the purpose of mtd_blkdevs.c. You
71    should not use them for _anything_ else */
72 DEFINE_MUTEX(mtd_table_mutex);
73 EXPORT_SYMBOL_GPL(mtd_table_mutex);
74
75 struct mtd_info *__mtd_next_device(int i)
76 {
77         return idr_get_next(&mtd_idr, &i);
78 }
79 EXPORT_SYMBOL_GPL(__mtd_next_device);
80
81 static LIST_HEAD(mtd_notifiers);
82
83
84 #if defined(CONFIG_MTD_CHAR) || defined(CONFIG_MTD_CHAR_MODULE)
85 #define MTD_DEVT(index) MKDEV(MTD_CHAR_MAJOR, (index)*2)
86 #else
87 #define MTD_DEVT(index) 0
88 #endif
89
90 /* REVISIT once MTD uses the driver model better, whoever allocates
91  * the mtd_info will probably want to use the release() hook...
92  */
93 static void mtd_release(struct device *dev)
94 {
95         dev_t index = MTD_DEVT(dev_to_mtd(dev)->index);
96
97         /* remove /dev/mtdXro node if needed */
98         if (index)
99                 device_destroy(&mtd_class, index + 1);
100 }
101
102 static int mtd_cls_suspend(struct device *dev, pm_message_t state)
103 {
104         struct mtd_info *mtd = dev_to_mtd(dev);
105
106         if (mtd && mtd->suspend)
107                 return mtd->suspend(mtd);
108         else
109                 return 0;
110 }
111
112 static int mtd_cls_resume(struct device *dev)
113 {
114         struct mtd_info *mtd = dev_to_mtd(dev);
115         
116         if (mtd && mtd->resume)
117                 mtd->resume(mtd);
118         return 0;
119 }
120
121 static ssize_t mtd_type_show(struct device *dev,
122                 struct device_attribute *attr, char *buf)
123 {
124         struct mtd_info *mtd = dev_to_mtd(dev);
125         char *type;
126
127         switch (mtd->type) {
128         case MTD_ABSENT:
129                 type = "absent";
130                 break;
131         case MTD_RAM:
132                 type = "ram";
133                 break;
134         case MTD_ROM:
135                 type = "rom";
136                 break;
137         case MTD_NORFLASH:
138                 type = "nor";
139                 break;
140         case MTD_NANDFLASH:
141                 type = "nand";
142                 break;
143         case MTD_DATAFLASH:
144                 type = "dataflash";
145                 break;
146         case MTD_UBIVOLUME:
147                 type = "ubi";
148                 break;
149         default:
150                 type = "unknown";
151         }
152
153         return snprintf(buf, PAGE_SIZE, "%s\n", type);
154 }
155 static DEVICE_ATTR(type, S_IRUGO, mtd_type_show, NULL);
156
157 static ssize_t mtd_flags_show(struct device *dev,
158                 struct device_attribute *attr, char *buf)
159 {
160         struct mtd_info *mtd = dev_to_mtd(dev);
161
162         return snprintf(buf, PAGE_SIZE, "0x%lx\n", (unsigned long)mtd->flags);
163
164 }
165 static DEVICE_ATTR(flags, S_IRUGO, mtd_flags_show, NULL);
166
167 static ssize_t mtd_size_show(struct device *dev,
168                 struct device_attribute *attr, char *buf)
169 {
170         struct mtd_info *mtd = dev_to_mtd(dev);
171
172         return snprintf(buf, PAGE_SIZE, "%llu\n",
173                 (unsigned long long)mtd->size);
174
175 }
176 static DEVICE_ATTR(size, S_IRUGO, mtd_size_show, NULL);
177
178 static ssize_t mtd_erasesize_show(struct device *dev,
179                 struct device_attribute *attr, char *buf)
180 {
181         struct mtd_info *mtd = dev_to_mtd(dev);
182
183         return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->erasesize);
184
185 }
186 static DEVICE_ATTR(erasesize, S_IRUGO, mtd_erasesize_show, NULL);
187
188 static ssize_t mtd_writesize_show(struct device *dev,
189                 struct device_attribute *attr, char *buf)
190 {
191         struct mtd_info *mtd = dev_to_mtd(dev);
192
193         return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->writesize);
194
195 }
196 static DEVICE_ATTR(writesize, S_IRUGO, mtd_writesize_show, NULL);
197
198 static ssize_t mtd_subpagesize_show(struct device *dev,
199                 struct device_attribute *attr, char *buf)
200 {
201         struct mtd_info *mtd = dev_to_mtd(dev);
202         unsigned int subpagesize = mtd->writesize >> mtd->subpage_sft;
203
204         return snprintf(buf, PAGE_SIZE, "%u\n", subpagesize);
205
206 }
207 static DEVICE_ATTR(subpagesize, S_IRUGO, mtd_subpagesize_show, NULL);
208
209 static ssize_t mtd_oobsize_show(struct device *dev,
210                 struct device_attribute *attr, char *buf)
211 {
212         struct mtd_info *mtd = dev_to_mtd(dev);
213
214         return snprintf(buf, PAGE_SIZE, "%lu\n", (unsigned long)mtd->oobsize);
215
216 }
217 static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
218
219 static ssize_t mtd_numeraseregions_show(struct device *dev,
220                 struct device_attribute *attr, char *buf)
221 {
222         struct mtd_info *mtd = dev_to_mtd(dev);
223
224         return snprintf(buf, PAGE_SIZE, "%u\n", mtd->numeraseregions);
225
226 }
227 static DEVICE_ATTR(numeraseregions, S_IRUGO, mtd_numeraseregions_show,
228         NULL);
229
230 static ssize_t mtd_name_show(struct device *dev,
231                 struct device_attribute *attr, char *buf)
232 {
233         struct mtd_info *mtd = dev_to_mtd(dev);
234
235         return snprintf(buf, PAGE_SIZE, "%s\n", mtd->name);
236
237 }
238 static DEVICE_ATTR(name, S_IRUGO, mtd_name_show, NULL);
239
240 static struct attribute *mtd_attrs[] = {
241         &dev_attr_type.attr,
242         &dev_attr_flags.attr,
243         &dev_attr_size.attr,
244         &dev_attr_erasesize.attr,
245         &dev_attr_writesize.attr,
246         &dev_attr_subpagesize.attr,
247         &dev_attr_oobsize.attr,
248         &dev_attr_numeraseregions.attr,
249         &dev_attr_name.attr,
250         NULL,
251 };
252
253 static struct attribute_group mtd_group = {
254         .attrs          = mtd_attrs,
255 };
256
257 static const struct attribute_group *mtd_groups[] = {
258         &mtd_group,
259         NULL,
260 };
261
262 static struct device_type mtd_devtype = {
263         .name           = "mtd",
264         .groups         = mtd_groups,
265         .release        = mtd_release,
266 };
267
268 /**
269  *      add_mtd_device - register an MTD device
270  *      @mtd: pointer to new MTD device info structure
271  *
272  *      Add a device to the list of MTD devices present in the system, and
273  *      notify each currently active MTD 'user' of its arrival. Returns
274  *      zero on success or 1 on failure, which currently will only happen
275  *      if there is insufficient memory or a sysfs error.
276  */
277
278 int add_mtd_device(struct mtd_info *mtd)
279 {
280         struct mtd_notifier *not;
281         int i, error;
282
283         if (!mtd->backing_dev_info) {
284                 switch (mtd->type) {
285                 case MTD_RAM:
286                         mtd->backing_dev_info = &mtd_bdi_rw_mappable;
287                         break;
288                 case MTD_ROM:
289                         mtd->backing_dev_info = &mtd_bdi_ro_mappable;
290                         break;
291                 default:
292                         mtd->backing_dev_info = &mtd_bdi_unmappable;
293                         break;
294                 }
295         }
296
297         BUG_ON(mtd->writesize == 0);
298         mutex_lock(&mtd_table_mutex);
299
300         do {
301                 if (!idr_pre_get(&mtd_idr, GFP_KERNEL))
302                         goto fail_locked;
303                 error = idr_get_new(&mtd_idr, mtd, &i);
304         } while (error == -EAGAIN);
305
306         if (error)
307                 goto fail_locked;
308
309         mtd->index = i;
310         mtd->usecount = 0;
311
312         if (is_power_of_2(mtd->erasesize))
313                 mtd->erasesize_shift = ffs(mtd->erasesize) - 1;
314         else
315                 mtd->erasesize_shift = 0;
316
317         if (is_power_of_2(mtd->writesize))
318                 mtd->writesize_shift = ffs(mtd->writesize) - 1;
319         else
320                 mtd->writesize_shift = 0;
321
322         mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1;
323         mtd->writesize_mask = (1 << mtd->writesize_shift) - 1;
324
325         /* Some chips always power up locked. Unlock them now */
326         if ((mtd->flags & MTD_WRITEABLE)
327             && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) {
328                 if (mtd->unlock(mtd, 0, mtd->size))
329                         printk(KERN_WARNING
330                                "%s: unlock failed, writes may not work\n",
331                                mtd->name);
332         }
333
334         /* Caller should have set dev.parent to match the
335          * physical device.
336          */
337         mtd->dev.type = &mtd_devtype;
338         mtd->dev.class = &mtd_class;
339         mtd->dev.devt = MTD_DEVT(i);
340         dev_set_name(&mtd->dev, "mtd%d", i);
341         dev_set_drvdata(&mtd->dev, mtd);
342         if (device_register(&mtd->dev) != 0)
343                 goto fail_added;
344
345         if (MTD_DEVT(i))
346                 device_create(&mtd_class, mtd->dev.parent,
347                               MTD_DEVT(i) + 1,
348                               NULL, "mtd%dro", i);
349
350         DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name);
351         /* No need to get a refcount on the module containing
352            the notifier, since we hold the mtd_table_mutex */
353         list_for_each_entry(not, &mtd_notifiers, list)
354                 not->add(mtd);
355
356         mutex_unlock(&mtd_table_mutex);
357         /* We _know_ we aren't being removed, because
358            our caller is still holding us here. So none
359            of this try_ nonsense, and no bitching about it
360            either. :) */
361         __module_get(THIS_MODULE);
362         return 0;
363
364 fail_added:
365         idr_remove(&mtd_idr, i);
366 fail_locked:
367         mutex_unlock(&mtd_table_mutex);
368         return 1;
369 }
370
371 /**
372  *      del_mtd_device - unregister an MTD device
373  *      @mtd: pointer to MTD device info structure
374  *
375  *      Remove a device from the list of MTD devices present in the system,
376  *      and notify each currently active MTD 'user' of its departure.
377  *      Returns zero on success or 1 on failure, which currently will happen
378  *      if the requested device does not appear to be present in the list.
379  */
380
381 int del_mtd_device (struct mtd_info *mtd)
382 {
383         int ret;
384         struct mtd_notifier *not;
385
386         mutex_lock(&mtd_table_mutex);
387
388         if (idr_find(&mtd_idr, mtd->index) != mtd) {
389                 ret = -ENODEV;
390                 goto out_error;
391         }
392
393         /* No need to get a refcount on the module containing
394                 the notifier, since we hold the mtd_table_mutex */
395         list_for_each_entry(not, &mtd_notifiers, list)
396                 not->remove(mtd);
397
398         if (mtd->usecount) {
399                 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n",
400                        mtd->index, mtd->name, mtd->usecount);
401                 ret = -EBUSY;
402         } else {
403                 device_unregister(&mtd->dev);
404
405                 idr_remove(&mtd_idr, mtd->index);
406
407                 module_put(THIS_MODULE);
408                 ret = 0;
409         }
410
411 out_error:
412         mutex_unlock(&mtd_table_mutex);
413         return ret;
414 }
415
416 /**
417  *      register_mtd_user - register a 'user' of MTD devices.
418  *      @new: pointer to notifier info structure
419  *
420  *      Registers a pair of callbacks function to be called upon addition
421  *      or removal of MTD devices. Causes the 'add' callback to be immediately
422  *      invoked for each MTD device currently present in the system.
423  */
424
425 void register_mtd_user (struct mtd_notifier *new)
426 {
427         struct mtd_info *mtd;
428
429         mutex_lock(&mtd_table_mutex);
430
431         list_add(&new->list, &mtd_notifiers);
432
433         __module_get(THIS_MODULE);
434
435         mtd_for_each_device(mtd)
436                 new->add(mtd);
437
438         mutex_unlock(&mtd_table_mutex);
439 }
440
441 /**
442  *      unregister_mtd_user - unregister a 'user' of MTD devices.
443  *      @old: pointer to notifier info structure
444  *
445  *      Removes a callback function pair from the list of 'users' to be
446  *      notified upon addition or removal of MTD devices. Causes the
447  *      'remove' callback to be immediately invoked for each MTD device
448  *      currently present in the system.
449  */
450
451 int unregister_mtd_user (struct mtd_notifier *old)
452 {
453         struct mtd_info *mtd;
454
455         mutex_lock(&mtd_table_mutex);
456
457         module_put(THIS_MODULE);
458
459         mtd_for_each_device(mtd)
460                 old->remove(mtd);
461
462         list_del(&old->list);
463         mutex_unlock(&mtd_table_mutex);
464         return 0;
465 }
466
467
468 /**
469  *      get_mtd_device - obtain a validated handle for an MTD device
470  *      @mtd: last known address of the required MTD device
471  *      @num: internal device number of the required MTD device
472  *
473  *      Given a number and NULL address, return the num'th entry in the device
474  *      table, if any.  Given an address and num == -1, search the device table
475  *      for a device with that address and return if it's still present. Given
476  *      both, return the num'th driver only if its address matches. Return
477  *      error code if not.
478  */
479
480 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)
481 {
482         struct mtd_info *ret = NULL, *other;
483         int err = -ENODEV;
484
485         mutex_lock(&mtd_table_mutex);
486
487         if (num == -1) {
488                 mtd_for_each_device(other) {
489                         if (other == mtd) {
490                                 ret = mtd;
491                                 break;
492                         }
493                 }
494         } else if (num >= 0) {
495                 ret = idr_find(&mtd_idr, num);
496                 if (mtd && mtd != ret)
497                         ret = NULL;
498         }
499
500         if (!ret) {
501                 ret = ERR_PTR(err);
502                 goto out;
503         }
504
505         err = __get_mtd_device(ret);
506         if (err)
507                 ret = ERR_PTR(err);
508 out:
509         mutex_unlock(&mtd_table_mutex);
510         return ret;
511 }
512
513
514 int __get_mtd_device(struct mtd_info *mtd)
515 {
516         int err;
517
518         if (!try_module_get(mtd->owner))
519                 return -ENODEV;
520
521         if (mtd->get_device) {
522
523                 err = mtd->get_device(mtd);
524
525                 if (err) {
526                         module_put(mtd->owner);
527                         return err;
528                 }
529         }
530         mtd->usecount++;
531         return 0;
532 }
533
534 /**
535  *      get_mtd_device_nm - obtain a validated handle for an MTD device by
536  *      device name
537  *      @name: MTD device name to open
538  *
539  *      This function returns MTD device description structure in case of
540  *      success and an error code in case of failure.
541  */
542
543 struct mtd_info *get_mtd_device_nm(const char *name)
544 {
545         int err = -ENODEV;
546         struct mtd_info *mtd = NULL, *other;
547
548         mutex_lock(&mtd_table_mutex);
549
550         mtd_for_each_device(other) {
551                 if (!strcmp(name, other->name)) {
552                         mtd = other;
553                         break;
554                 }
555         }
556
557         if (!mtd)
558                 goto out_unlock;
559
560         if (!try_module_get(mtd->owner))
561                 goto out_unlock;
562
563         if (mtd->get_device) {
564                 err = mtd->get_device(mtd);
565                 if (err)
566                         goto out_put;
567         }
568
569         mtd->usecount++;
570         mutex_unlock(&mtd_table_mutex);
571         return mtd;
572
573 out_put:
574         module_put(mtd->owner);
575 out_unlock:
576         mutex_unlock(&mtd_table_mutex);
577         return ERR_PTR(err);
578 }
579
580 void put_mtd_device(struct mtd_info *mtd)
581 {
582         mutex_lock(&mtd_table_mutex);
583         __put_mtd_device(mtd);
584         mutex_unlock(&mtd_table_mutex);
585
586 }
587
588 void __put_mtd_device(struct mtd_info *mtd)
589 {
590         --mtd->usecount;
591         BUG_ON(mtd->usecount < 0);
592
593         if (mtd->put_device)
594                 mtd->put_device(mtd);
595
596         module_put(mtd->owner);
597 }
598
599 /* default_mtd_writev - default mtd writev method for MTD devices that
600  *                      don't implement their own
601  */
602
603 int default_mtd_writev(struct mtd_info *mtd, const struct kvec *vecs,
604                        unsigned long count, loff_t to, size_t *retlen)
605 {
606         unsigned long i;
607         size_t totlen = 0, thislen;
608         int ret = 0;
609
610         if(!mtd->write) {
611                 ret = -EROFS;
612         } else {
613                 for (i=0; i<count; i++) {
614                         if (!vecs[i].iov_len)
615                                 continue;
616                         ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base);
617                         totlen += thislen;
618                         if (ret || thislen != vecs[i].iov_len)
619                                 break;
620                         to += vecs[i].iov_len;
621                 }
622         }
623         if (retlen)
624                 *retlen = totlen;
625         return ret;
626 }
627
628 EXPORT_SYMBOL_GPL(add_mtd_device);
629 EXPORT_SYMBOL_GPL(del_mtd_device);
630 EXPORT_SYMBOL_GPL(get_mtd_device);
631 EXPORT_SYMBOL_GPL(get_mtd_device_nm);
632 EXPORT_SYMBOL_GPL(__get_mtd_device);
633 EXPORT_SYMBOL_GPL(put_mtd_device);
634 EXPORT_SYMBOL_GPL(__put_mtd_device);
635 EXPORT_SYMBOL_GPL(register_mtd_user);
636 EXPORT_SYMBOL_GPL(unregister_mtd_user);
637 EXPORT_SYMBOL_GPL(default_mtd_writev);
638
639 #ifdef CONFIG_PROC_FS
640
641 /*====================================================================*/
642 /* Support for /proc/mtd */
643
644 static struct proc_dir_entry *proc_mtd;
645
646 static inline int mtd_proc_info(char *buf, struct mtd_info *this)
647 {
648         return sprintf(buf, "mtd%d: %8.8llx %8.8x \"%s\"\n", this->index,
649                        (unsigned long long)this->size,
650                        this->erasesize, this->name);
651 }
652
653 static int mtd_read_proc (char *page, char **start, off_t off, int count,
654                           int *eof, void *data_unused)
655 {
656         struct mtd_info *mtd;
657         int len, l;
658         off_t   begin = 0;
659
660         mutex_lock(&mtd_table_mutex);
661
662         len = sprintf(page, "dev:    size   erasesize  name\n");
663         mtd_for_each_device(mtd) {
664                 l = mtd_proc_info(page + len, mtd);
665                 len += l;
666                 if (len+begin > off+count)
667                         goto done;
668                 if (len+begin < off) {
669                         begin += len;
670                         len = 0;
671                 }
672         }
673
674         *eof = 1;
675
676 done:
677         mutex_unlock(&mtd_table_mutex);
678         if (off >= len+begin)
679                 return 0;
680         *start = page + (off-begin);
681         return ((count < begin+len-off) ? count : begin+len-off);
682 }
683
684 #endif /* CONFIG_PROC_FS */
685
686 /*====================================================================*/
687 /* Init code */
688
689 static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name)
690 {
691         int ret;
692
693         ret = bdi_init(bdi);
694         if (!ret)
695                 ret = bdi_register(bdi, NULL, name);
696
697         if (ret)
698                 bdi_destroy(bdi);
699
700         return ret;
701 }
702
703 static int __init init_mtd(void)
704 {
705         int ret;
706
707         ret = class_register(&mtd_class);
708         if (ret)
709                 goto err_reg;
710
711         ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");
712         if (ret)
713                 goto err_bdi1;
714
715         ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");
716         if (ret)
717                 goto err_bdi2;
718
719         ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");
720         if (ret)
721                 goto err_bdi3;
722
723 #ifdef CONFIG_PROC_FS
724         if ((proc_mtd = create_proc_entry( "mtd", 0, NULL )))
725                 proc_mtd->read_proc = mtd_read_proc;
726 #endif /* CONFIG_PROC_FS */
727         return 0;
728
729 err_bdi3:
730         bdi_destroy(&mtd_bdi_ro_mappable);
731 err_bdi2:
732         bdi_destroy(&mtd_bdi_unmappable);
733 err_bdi1:
734         class_unregister(&mtd_class);
735 err_reg:
736         pr_err("Error registering mtd class or bdi: %d\n", ret);
737         return ret;
738 }
739
740 static void __exit cleanup_mtd(void)
741 {
742 #ifdef CONFIG_PROC_FS
743         if (proc_mtd)
744                 remove_proc_entry( "mtd", NULL);
745 #endif /* CONFIG_PROC_FS */
746         class_unregister(&mtd_class);
747         bdi_destroy(&mtd_bdi_unmappable);
748         bdi_destroy(&mtd_bdi_ro_mappable);
749         bdi_destroy(&mtd_bdi_rw_mappable);
750 }
751
752 module_init(init_mtd);
753 module_exit(cleanup_mtd);
754
755 MODULE_LICENSE("GPL");
756 MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
757 MODULE_DESCRIPTION("Core MTD registration and access routines");