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