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