1 /* 2 * Core registration and callback routines for MTD 3 * drivers and users. 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 */ 9 10 #include <linux/mtd/mtd.h> 11 #include <linux/mtd/compat.h> 12 #include <ubi_uboot.h> 13 14 struct mtd_info *mtd_table[MAX_MTD_DEVICES]; 15 16 int add_mtd_device(struct mtd_info *mtd) 17 { 18 int i; 19 20 BUG_ON(mtd->writesize == 0); 21 22 for (i = 0; i < MAX_MTD_DEVICES; i++) 23 if (!mtd_table[i]) { 24 mtd_table[i] = mtd; 25 mtd->index = i; 26 mtd->usecount = 0; 27 28 printf("mtd: Giving out device %d to %s\n", 29 i, mtd->name); 30 /* No need to get a refcount on the module containing 31 the notifier, since we hold the mtd_table_mutex */ 32 33 /* We _know_ we aren't being removed, because 34 our caller is still holding us here. So none 35 of this try_ nonsense, and no bitching about it 36 either. :) */ 37 return 0; 38 } 39 40 return 1; 41 } 42 43 /** 44 * del_mtd_device - unregister an MTD device 45 * @mtd: pointer to MTD device info structure 46 * 47 * Remove a device from the list of MTD devices present in the system, 48 * and notify each currently active MTD 'user' of its departure. 49 * Returns zero on success or 1 on failure, which currently will happen 50 * if the requested device does not appear to be present in the list. 51 */ 52 int del_mtd_device(struct mtd_info *mtd) 53 { 54 int ret; 55 56 if (mtd_table[mtd->index] != mtd) { 57 ret = -ENODEV; 58 } else if (mtd->usecount) { 59 printk(KERN_NOTICE "Removing MTD device #%d (%s)" 60 " with use count %d\n", 61 mtd->index, mtd->name, mtd->usecount); 62 ret = -EBUSY; 63 } else { 64 /* No need to get a refcount on the module containing 65 * the notifier, since we hold the mtd_table_mutex */ 66 mtd_table[mtd->index] = NULL; 67 68 ret = 0; 69 } 70 71 return ret; 72 } 73 74 /** 75 * get_mtd_device - obtain a validated handle for an MTD device 76 * @mtd: last known address of the required MTD device 77 * @num: internal device number of the required MTD device 78 * 79 * Given a number and NULL address, return the num'th entry in the device 80 * table, if any. Given an address and num == -1, search the device table 81 * for a device with that address and return if it's still present. Given 82 * both, return the num'th driver only if its address matches. Return 83 * error code if not. 84 */ 85 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) 86 { 87 struct mtd_info *ret = NULL; 88 int i, err = -ENODEV; 89 90 if (num == -1) { 91 for (i = 0; i < MAX_MTD_DEVICES; i++) 92 if (mtd_table[i] == mtd) 93 ret = mtd_table[i]; 94 } else if (num < MAX_MTD_DEVICES) { 95 ret = mtd_table[num]; 96 if (mtd && mtd != ret) 97 ret = NULL; 98 } 99 100 if (!ret) 101 goto out_unlock; 102 103 ret->usecount++; 104 return ret; 105 106 out_unlock: 107 return ERR_PTR(err); 108 } 109 110 /** 111 * get_mtd_device_nm - obtain a validated handle for an MTD device by 112 * device name 113 * @name: MTD device name to open 114 * 115 * This function returns MTD device description structure in case of 116 * success and an error code in case of failure. 117 */ 118 struct mtd_info *get_mtd_device_nm(const char *name) 119 { 120 int i, err = -ENODEV; 121 struct mtd_info *mtd = NULL; 122 123 for (i = 0; i < MAX_MTD_DEVICES; i++) { 124 if (mtd_table[i] && !strcmp(name, mtd_table[i]->name)) { 125 mtd = mtd_table[i]; 126 break; 127 } 128 } 129 130 if (!mtd) 131 goto out_unlock; 132 133 mtd->usecount++; 134 return mtd; 135 136 out_unlock: 137 return ERR_PTR(err); 138 } 139 140 void put_mtd_device(struct mtd_info *mtd) 141 { 142 int c; 143 144 c = --mtd->usecount; 145 BUG_ON(c < 0); 146 } 147