1*500856ebSRafal Jaworowski /* 2*500856ebSRafal Jaworowski * (C) Copyright 2007 Semihalf 3*500856ebSRafal Jaworowski * 4*500856ebSRafal Jaworowski * Written by: Rafal Jaworowski <raj@semihalf.com> 5*500856ebSRafal Jaworowski * 6*500856ebSRafal Jaworowski * See file CREDITS for list of people who contributed to this 7*500856ebSRafal Jaworowski * project. 8*500856ebSRafal Jaworowski * 9*500856ebSRafal Jaworowski * This program is free software; you can redistribute it and/or 10*500856ebSRafal Jaworowski * modify it under the terms of the GNU General Public License as 11*500856ebSRafal Jaworowski * published by the Free Software Foundation; either version 2 of 12*500856ebSRafal Jaworowski * the License, or (at your option) any later version. 13*500856ebSRafal Jaworowski * 14*500856ebSRafal Jaworowski * This program is distributed in the hope that it will be useful, 15*500856ebSRafal Jaworowski * but WITHOUT ANY WARRANTY; without even the implied warranty of 16*500856ebSRafal Jaworowski * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17*500856ebSRafal Jaworowski * GNU General Public License for more details. 18*500856ebSRafal Jaworowski * 19*500856ebSRafal Jaworowski * You should have received a copy of the GNU General Public License 20*500856ebSRafal Jaworowski * along with this program; if not, write to the Free Software 21*500856ebSRafal Jaworowski * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 22*500856ebSRafal Jaworowski * MA 02111-1307 USA 23*500856ebSRafal Jaworowski * 24*500856ebSRafal Jaworowski */ 25*500856ebSRafal Jaworowski 26*500856ebSRafal Jaworowski #include <config.h> 27*500856ebSRafal Jaworowski 28*500856ebSRafal Jaworowski #if defined(CONFIG_API) 29*500856ebSRafal Jaworowski 30*500856ebSRafal Jaworowski #include <common.h> 31*500856ebSRafal Jaworowski #include <api_public.h> 32*500856ebSRafal Jaworowski 33*500856ebSRafal Jaworowski #define DEBUG 34*500856ebSRafal Jaworowski #undef DEBUG 35*500856ebSRafal Jaworowski 36*500856ebSRafal Jaworowski #ifdef DEBUG 37*500856ebSRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0) 38*500856ebSRafal Jaworowski #else 39*500856ebSRafal Jaworowski #define debugf(fmt, args...) 40*500856ebSRafal Jaworowski #endif 41*500856ebSRafal Jaworowski 42*500856ebSRafal Jaworowski #define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0) 43*500856ebSRafal Jaworowski 44*500856ebSRafal Jaworowski 45*500856ebSRafal Jaworowski #define ENUM_IDE 0 46*500856ebSRafal Jaworowski #define ENUM_USB 1 47*500856ebSRafal Jaworowski #define ENUM_SCSI 2 48*500856ebSRafal Jaworowski #define ENUM_MMC 3 49*500856ebSRafal Jaworowski #define ENUM_MAX 4 50*500856ebSRafal Jaworowski 51*500856ebSRafal Jaworowski struct stor_spec { 52*500856ebSRafal Jaworowski int max_dev; 53*500856ebSRafal Jaworowski int enum_started; 54*500856ebSRafal Jaworowski int enum_ended; 55*500856ebSRafal Jaworowski int type; /* "external" type: DT_STOR_{IDE,USB,etc} */ 56*500856ebSRafal Jaworowski char name[4]; 57*500856ebSRafal Jaworowski }; 58*500856ebSRafal Jaworowski 59*500856ebSRafal Jaworowski static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, }; 60*500856ebSRafal Jaworowski 61*500856ebSRafal Jaworowski 62*500856ebSRafal Jaworowski void dev_stor_init(void) 63*500856ebSRafal Jaworowski { 64*500856ebSRafal Jaworowski #if (CONFIG_COMMANDS & CFG_CMD_IDE) 65*500856ebSRafal Jaworowski specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE; 66*500856ebSRafal Jaworowski specs[ENUM_IDE].enum_started = 0; 67*500856ebSRafal Jaworowski specs[ENUM_IDE].enum_ended = 0; 68*500856ebSRafal Jaworowski specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE; 69*500856ebSRafal Jaworowski specs[ENUM_IDE].name = "ide"; 70*500856ebSRafal Jaworowski #endif 71*500856ebSRafal Jaworowski #if (CONFIG_COMMANDS & CFG_CMD_USB) 72*500856ebSRafal Jaworowski specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV; 73*500856ebSRafal Jaworowski specs[ENUM_USB].enum_started = 0; 74*500856ebSRafal Jaworowski specs[ENUM_USB].enum_ended = 0; 75*500856ebSRafal Jaworowski specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB; 76*500856ebSRafal Jaworowski specs[ENUM_USB].name = "usb"; 77*500856ebSRafal Jaworowski #endif 78*500856ebSRafal Jaworowski #if (CONFIG_COMMANDS & CFG_CMD_SCSI) 79*500856ebSRafal Jaworowski specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE; 80*500856ebSRafal Jaworowski specs[ENUM_SCSI].enum_started = 0; 81*500856ebSRafal Jaworowski specs[ENUM_SCSI].enum_ended = 0; 82*500856ebSRafal Jaworowski specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI; 83*500856ebSRafal Jaworowski specs[ENUM_SCSI].name = "scsi"; 84*500856ebSRafal Jaworowski #endif 85*500856ebSRafal Jaworowski } 86*500856ebSRafal Jaworowski 87*500856ebSRafal Jaworowski /* 88*500856ebSRafal Jaworowski * Finds next available device in the storage group 89*500856ebSRafal Jaworowski * 90*500856ebSRafal Jaworowski * type: storage group type - ENUM_IDE, ENUM_SCSI etc. 91*500856ebSRafal Jaworowski * 92*500856ebSRafal Jaworowski * first: if 1 the first device in the storage group is returned (if 93*500856ebSRafal Jaworowski * exists), if 0 the next available device is searched 94*500856ebSRafal Jaworowski * 95*500856ebSRafal Jaworowski * more: returns 0/1 depending if there are more devices in this group 96*500856ebSRafal Jaworowski * available (for future iterations) 97*500856ebSRafal Jaworowski * 98*500856ebSRafal Jaworowski * returns: 0/1 depending if device found in this iteration 99*500856ebSRafal Jaworowski */ 100*500856ebSRafal Jaworowski static int dev_stor_get(int type, int first, int *more, struct device_info *di) 101*500856ebSRafal Jaworowski { 102*500856ebSRafal Jaworowski int found = 0; 103*500856ebSRafal Jaworowski *more = 0; 104*500856ebSRafal Jaworowski 105*500856ebSRafal Jaworowski int i; 106*500856ebSRafal Jaworowski 107*500856ebSRafal Jaworowski block_dev_desc_t *dd; 108*500856ebSRafal Jaworowski 109*500856ebSRafal Jaworowski if (first) { 110*500856ebSRafal Jaworowski di->cookie = (void *)get_dev(specs[type].name, 0); 111*500856ebSRafal Jaworowski found = 1; 112*500856ebSRafal Jaworowski 113*500856ebSRafal Jaworowski } else { 114*500856ebSRafal Jaworowski for (i = 0; i < specs[type].max_dev; i++) 115*500856ebSRafal Jaworowski if (di->cookie == (void *)get_dev(specs[type].name, i)) { 116*500856ebSRafal Jaworowski /* previous cookie found -- advance to the 117*500856ebSRafal Jaworowski * next device, if possible */ 118*500856ebSRafal Jaworowski 119*500856ebSRafal Jaworowski if (++i >= specs[type].max_dev) { 120*500856ebSRafal Jaworowski /* out of range, no more to enum */ 121*500856ebSRafal Jaworowski di->cookie = NULL; 122*500856ebSRafal Jaworowski break; 123*500856ebSRafal Jaworowski } 124*500856ebSRafal Jaworowski 125*500856ebSRafal Jaworowski di->cookie = (void *)get_dev(specs[type].name, i); 126*500856ebSRafal Jaworowski found = 1; 127*500856ebSRafal Jaworowski 128*500856ebSRafal Jaworowski /* provide hint if there are more devices in 129*500856ebSRafal Jaworowski * this group to enumerate */ 130*500856ebSRafal Jaworowski if ((i + 1) < specs[type].max_dev) 131*500856ebSRafal Jaworowski *more = 1; 132*500856ebSRafal Jaworowski 133*500856ebSRafal Jaworowski break; 134*500856ebSRafal Jaworowski } 135*500856ebSRafal Jaworowski } 136*500856ebSRafal Jaworowski 137*500856ebSRafal Jaworowski if (found) { 138*500856ebSRafal Jaworowski di->type = specs[type].type; 139*500856ebSRafal Jaworowski 140*500856ebSRafal Jaworowski if (di->cookie != NULL) { 141*500856ebSRafal Jaworowski dd = (block_dev_desc_t *)di->cookie; 142*500856ebSRafal Jaworowski if (dd->type == DEV_TYPE_UNKNOWN) { 143*500856ebSRafal Jaworowski debugf("device instance exists, but is not active.."); 144*500856ebSRafal Jaworowski found = 0; 145*500856ebSRafal Jaworowski } else { 146*500856ebSRafal Jaworowski di->di_stor.block_count = dd->lba; 147*500856ebSRafal Jaworowski di->di_stor.block_size = dd->blksz; 148*500856ebSRafal Jaworowski } 149*500856ebSRafal Jaworowski } 150*500856ebSRafal Jaworowski 151*500856ebSRafal Jaworowski } else 152*500856ebSRafal Jaworowski di->cookie = NULL; 153*500856ebSRafal Jaworowski 154*500856ebSRafal Jaworowski return found; 155*500856ebSRafal Jaworowski } 156*500856ebSRafal Jaworowski 157*500856ebSRafal Jaworowski 158*500856ebSRafal Jaworowski /* 159*500856ebSRafal Jaworowski * returns: ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t 160*500856ebSRafal Jaworowski */ 161*500856ebSRafal Jaworowski static int dev_stor_type(block_dev_desc_t *dd) 162*500856ebSRafal Jaworowski { 163*500856ebSRafal Jaworowski int i, j; 164*500856ebSRafal Jaworowski 165*500856ebSRafal Jaworowski for (i = ENUM_IDE; i < ENUM_MAX; i++) 166*500856ebSRafal Jaworowski for (j = 0; j < specs[i].max_dev; j++) 167*500856ebSRafal Jaworowski if (dd == get_dev(specs[i].name, j)) 168*500856ebSRafal Jaworowski return i; 169*500856ebSRafal Jaworowski 170*500856ebSRafal Jaworowski return ENUM_MAX; 171*500856ebSRafal Jaworowski } 172*500856ebSRafal Jaworowski 173*500856ebSRafal Jaworowski 174*500856ebSRafal Jaworowski /* 175*500856ebSRafal Jaworowski * returns: 0/1 whether cookie points to some device in this group 176*500856ebSRafal Jaworowski */ 177*500856ebSRafal Jaworowski static int dev_is_stor(int type, struct device_info *di) 178*500856ebSRafal Jaworowski { 179*500856ebSRafal Jaworowski return (dev_stor_type(di->cookie) == type) ? 1 : 0; 180*500856ebSRafal Jaworowski } 181*500856ebSRafal Jaworowski 182*500856ebSRafal Jaworowski 183*500856ebSRafal Jaworowski static int dev_enum_stor(int type, struct device_info *di) 184*500856ebSRafal Jaworowski { 185*500856ebSRafal Jaworowski int found = 0, more = 0; 186*500856ebSRafal Jaworowski 187*500856ebSRafal Jaworowski debugf("called, type %d\n", type); 188*500856ebSRafal Jaworowski 189*500856ebSRafal Jaworowski /* 190*500856ebSRafal Jaworowski * Formulae for enumerating storage devices: 191*500856ebSRafal Jaworowski * 1. if cookie (hint from previous enum call) is NULL we start again 192*500856ebSRafal Jaworowski * with enumeration, so return the first available device, done. 193*500856ebSRafal Jaworowski * 194*500856ebSRafal Jaworowski * 2. if cookie is not NULL, check if it identifies some device in 195*500856ebSRafal Jaworowski * this group: 196*500856ebSRafal Jaworowski * 197*500856ebSRafal Jaworowski * 2a. if cookie is a storage device from our group (IDE, USB etc.), 198*500856ebSRafal Jaworowski * return next available (if exists) in this group 199*500856ebSRafal Jaworowski * 200*500856ebSRafal Jaworowski * 2b. if it isn't device from our group, check if such devices were 201*500856ebSRafal Jaworowski * ever enumerated before: 202*500856ebSRafal Jaworowski * - if not, return the first available device from this group 203*500856ebSRafal Jaworowski * - else return 0 204*500856ebSRafal Jaworowski */ 205*500856ebSRafal Jaworowski 206*500856ebSRafal Jaworowski if (di->cookie == NULL) { 207*500856ebSRafal Jaworowski 208*500856ebSRafal Jaworowski debugf("group%d - enum restart\n", type); 209*500856ebSRafal Jaworowski 210*500856ebSRafal Jaworowski /* 211*500856ebSRafal Jaworowski * 1. Enumeration (re-)started: take the first available 212*500856ebSRafal Jaworowski * device, if exists 213*500856ebSRafal Jaworowski */ 214*500856ebSRafal Jaworowski found = dev_stor_get(type, 1, &more, di); 215*500856ebSRafal Jaworowski specs[type].enum_started = 1; 216*500856ebSRafal Jaworowski 217*500856ebSRafal Jaworowski } else if (dev_is_stor(type, di)) { 218*500856ebSRafal Jaworowski 219*500856ebSRafal Jaworowski debugf("group%d - enum continued for the next device\n", type); 220*500856ebSRafal Jaworowski 221*500856ebSRafal Jaworowski if (specs[type].enum_ended) { 222*500856ebSRafal Jaworowski debugf("group%d - nothing more to enum!\n", type); 223*500856ebSRafal Jaworowski return 0; 224*500856ebSRafal Jaworowski } 225*500856ebSRafal Jaworowski 226*500856ebSRafal Jaworowski /* 2a. Attempt to take a next available device in the group */ 227*500856ebSRafal Jaworowski found = dev_stor_get(type, 0, &more, di); 228*500856ebSRafal Jaworowski 229*500856ebSRafal Jaworowski } else { 230*500856ebSRafal Jaworowski 231*500856ebSRafal Jaworowski if (specs[type].enum_ended) { 232*500856ebSRafal Jaworowski debugf("group %d - already enumerated, skipping\n", type); 233*500856ebSRafal Jaworowski return 0; 234*500856ebSRafal Jaworowski } 235*500856ebSRafal Jaworowski 236*500856ebSRafal Jaworowski debugf("group%d - first time enum\n", type); 237*500856ebSRafal Jaworowski 238*500856ebSRafal Jaworowski if (specs[type].enum_started == 0) { 239*500856ebSRafal Jaworowski /* 240*500856ebSRafal Jaworowski * 2b. If enumerating devices in this group did not 241*500856ebSRafal Jaworowski * happen before, it means the cookie pointed to a 242*500856ebSRafal Jaworowski * device frome some other group (another storage 243*500856ebSRafal Jaworowski * group, or network); in this case try to take the 244*500856ebSRafal Jaworowski * first available device from our group 245*500856ebSRafal Jaworowski */ 246*500856ebSRafal Jaworowski specs[type].enum_started = 1; 247*500856ebSRafal Jaworowski 248*500856ebSRafal Jaworowski /* 249*500856ebSRafal Jaworowski * Attempt to take the first device in this group: 250*500856ebSRafal Jaworowski *'first element' flag is set 251*500856ebSRafal Jaworowski */ 252*500856ebSRafal Jaworowski found = dev_stor_get(type, 1, &more, di); 253*500856ebSRafal Jaworowski 254*500856ebSRafal Jaworowski } else { 255*500856ebSRafal Jaworowski errf("group%d - out of order iteration\n", type); 256*500856ebSRafal Jaworowski found = 0; 257*500856ebSRafal Jaworowski more = 0; 258*500856ebSRafal Jaworowski } 259*500856ebSRafal Jaworowski } 260*500856ebSRafal Jaworowski 261*500856ebSRafal Jaworowski /* 262*500856ebSRafal Jaworowski * If there are no more devices in this group, consider its 263*500856ebSRafal Jaworowski * enumeration finished 264*500856ebSRafal Jaworowski */ 265*500856ebSRafal Jaworowski specs[type].enum_ended = (!more) ? 1 : 0; 266*500856ebSRafal Jaworowski 267*500856ebSRafal Jaworowski if (found) 268*500856ebSRafal Jaworowski debugf("device found, returning cookie 0x%08x\n", 269*500856ebSRafal Jaworowski (u_int32_t)di->cookie); 270*500856ebSRafal Jaworowski else 271*500856ebSRafal Jaworowski debugf("no device found\n"); 272*500856ebSRafal Jaworowski 273*500856ebSRafal Jaworowski return found; 274*500856ebSRafal Jaworowski } 275*500856ebSRafal Jaworowski 276*500856ebSRafal Jaworowski void dev_enum_reset(void) 277*500856ebSRafal Jaworowski { 278*500856ebSRafal Jaworowski int i; 279*500856ebSRafal Jaworowski 280*500856ebSRafal Jaworowski for (i = 0; i < ENUM_MAX; i ++) { 281*500856ebSRafal Jaworowski specs[i].enum_started = 0; 282*500856ebSRafal Jaworowski specs[i].enum_ended = 0; 283*500856ebSRafal Jaworowski } 284*500856ebSRafal Jaworowski } 285*500856ebSRafal Jaworowski 286*500856ebSRafal Jaworowski int dev_enum_storage(struct device_info *di) 287*500856ebSRafal Jaworowski { 288*500856ebSRafal Jaworowski int i; 289*500856ebSRafal Jaworowski 290*500856ebSRafal Jaworowski /* 291*500856ebSRafal Jaworowski * check: ide, usb, scsi, mmc 292*500856ebSRafal Jaworowski */ 293*500856ebSRafal Jaworowski for (i = ENUM_IDE; i < ENUM_MAX; i ++) { 294*500856ebSRafal Jaworowski if (dev_enum_stor(i, di)) 295*500856ebSRafal Jaworowski return 1; 296*500856ebSRafal Jaworowski } 297*500856ebSRafal Jaworowski 298*500856ebSRafal Jaworowski return 0; 299*500856ebSRafal Jaworowski } 300*500856ebSRafal Jaworowski 301*500856ebSRafal Jaworowski static int dev_stor_is_valid(int type, block_dev_desc_t *dd) 302*500856ebSRafal Jaworowski { 303*500856ebSRafal Jaworowski int i; 304*500856ebSRafal Jaworowski 305*500856ebSRafal Jaworowski for (i = 0; i < specs[type].max_dev; i++) 306*500856ebSRafal Jaworowski if (dd == get_dev(specs[type].name, i)) 307*500856ebSRafal Jaworowski if (dd->type != DEV_TYPE_UNKNOWN) 308*500856ebSRafal Jaworowski return 1; 309*500856ebSRafal Jaworowski 310*500856ebSRafal Jaworowski return 0; 311*500856ebSRafal Jaworowski } 312*500856ebSRafal Jaworowski 313*500856ebSRafal Jaworowski 314*500856ebSRafal Jaworowski int dev_open_stor(void *cookie) 315*500856ebSRafal Jaworowski { 316*500856ebSRafal Jaworowski int type = dev_stor_type(cookie); 317*500856ebSRafal Jaworowski 318*500856ebSRafal Jaworowski if (type == ENUM_MAX) 319*500856ebSRafal Jaworowski return API_ENODEV; 320*500856ebSRafal Jaworowski 321*500856ebSRafal Jaworowski if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie)) 322*500856ebSRafal Jaworowski return 0; 323*500856ebSRafal Jaworowski 324*500856ebSRafal Jaworowski return API_ENODEV; 325*500856ebSRafal Jaworowski } 326*500856ebSRafal Jaworowski 327*500856ebSRafal Jaworowski 328*500856ebSRafal Jaworowski int dev_close_stor(void *cookie) 329*500856ebSRafal Jaworowski { 330*500856ebSRafal Jaworowski /* 331*500856ebSRafal Jaworowski * Not much to do as we actually do not alter storage devices upon 332*500856ebSRafal Jaworowski * close 333*500856ebSRafal Jaworowski */ 334*500856ebSRafal Jaworowski return 0; 335*500856ebSRafal Jaworowski } 336*500856ebSRafal Jaworowski 337*500856ebSRafal Jaworowski 338*500856ebSRafal Jaworowski static int dev_stor_index(block_dev_desc_t *dd) 339*500856ebSRafal Jaworowski { 340*500856ebSRafal Jaworowski int i, type; 341*500856ebSRafal Jaworowski 342*500856ebSRafal Jaworowski type = dev_stor_type(dd); 343*500856ebSRafal Jaworowski for (i = 0; i < specs[type].max_dev; i++) 344*500856ebSRafal Jaworowski if (dd == get_dev(specs[type].name, i)) 345*500856ebSRafal Jaworowski return i; 346*500856ebSRafal Jaworowski 347*500856ebSRafal Jaworowski return (specs[type].max_dev); 348*500856ebSRafal Jaworowski } 349*500856ebSRafal Jaworowski 350*500856ebSRafal Jaworowski 351*500856ebSRafal Jaworowski lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start) 352*500856ebSRafal Jaworowski { 353*500856ebSRafal Jaworowski int type; 354*500856ebSRafal Jaworowski block_dev_desc_t *dd = (block_dev_desc_t *)cookie; 355*500856ebSRafal Jaworowski 356*500856ebSRafal Jaworowski if ((type = dev_stor_type(dd)) == ENUM_MAX) 357*500856ebSRafal Jaworowski return 0; 358*500856ebSRafal Jaworowski 359*500856ebSRafal Jaworowski if (!dev_stor_is_valid(type, dd)) 360*500856ebSRafal Jaworowski return 0; 361*500856ebSRafal Jaworowski 362*500856ebSRafal Jaworowski if ((dd->block_read) == NULL) { 363*500856ebSRafal Jaworowski debugf("no block_read() for device 0x%08x\n"); 364*500856ebSRafal Jaworowski return 0; 365*500856ebSRafal Jaworowski } 366*500856ebSRafal Jaworowski 367*500856ebSRafal Jaworowski return (dd->block_read(dev_stor_index(dd), start, len, buf)); 368*500856ebSRafal Jaworowski } 369*500856ebSRafal Jaworowski 370*500856ebSRafal Jaworowski #endif /* CONFIG_API */ 371