uboot/api/api.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007 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 <command.h>
  28#include <common.h>
  29#include <malloc.h>
  30#include <environment.h>
  31#include <linux/types.h>
  32#include <api_public.h>
  33
  34#include "api_private.h"
  35
  36#define DEBUG
  37#undef DEBUG
  38
  39/*****************************************************************************
  40 *
  41 * This is the API core.
  42 *
  43 * API_ functions are part of U-Boot code and constitute the lowest level
  44 * calls:
  45 *
  46 *  - they know what values they need as arguments
  47 *  - their direct return value pertains to the API_ "shell" itself (0 on
  48 *    success, some error code otherwise)
  49 *  - if the call returns a value it is buried within arguments
  50 *
  51 ****************************************************************************/
  52
  53#ifdef DEBUG
  54#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
  55#else
  56#define debugf(fmt, args...)
  57#endif
  58
  59typedef int (*cfp_t)(va_list argp);
  60
  61static int calls_no;
  62
  63/*
  64 * pseudo signature:
  65 *
  66 * int API_getc(int *c)
  67 */
  68static int API_getc(va_list ap)
  69{
  70        int *c;
  71
  72        if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
  73                return API_EINVAL;
  74
  75        *c = getc();
  76        return 0;
  77}
  78
  79/*
  80 * pseudo signature:
  81 *
  82 * int API_tstc(int *c)
  83 */
  84static int API_tstc(va_list ap)
  85{
  86        int *t;
  87
  88        if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
  89                return API_EINVAL;
  90
  91        *t = tstc();
  92        return 0;
  93}
  94
  95/*
  96 * pseudo signature:
  97 *
  98 * int API_putc(char *ch)
  99 */
 100static int API_putc(va_list ap)
 101{
 102        char *c;
 103
 104        if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
 105                return API_EINVAL;
 106
 107        putc(*c);
 108        return 0;
 109}
 110
 111/*
 112 * pseudo signature:
 113 *
 114 * int API_puts(char **s)
 115 */
 116static int API_puts(va_list ap)
 117{
 118        char *s;
 119
 120        if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
 121                return API_EINVAL;
 122
 123        puts(s);
 124        return 0;
 125}
 126
 127/*
 128 * pseudo signature:
 129 *
 130 * int API_reset(void)
 131 */
 132static int API_reset(va_list ap)
 133{
 134        do_reset(NULL, 0, 0, NULL);
 135
 136        /* NOT REACHED */
 137        return 0;
 138}
 139
 140/*
 141 * pseudo signature:
 142 *
 143 * int API_get_sys_info(struct sys_info *si)
 144 *
 145 * fill out the sys_info struct containing selected parameters about the
 146 * machine
 147 */
 148static int API_get_sys_info(va_list ap)
 149{
 150        struct sys_info *si;
 151
 152        si = (struct sys_info *)va_arg(ap, u_int32_t);
 153        if (si == NULL)
 154                return API_ENOMEM;
 155
 156        return (platform_sys_info(si)) ? 0 : API_ENODEV;
 157}
 158
 159/*
 160 * pseudo signature:
 161 *
 162 * int API_udelay(unsigned long *udelay)
 163 */
 164static int API_udelay(va_list ap)
 165{
 166        unsigned long *d;
 167
 168        if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
 169                return API_EINVAL;
 170
 171        udelay(*d);
 172        return 0;
 173}
 174
 175/*
 176 * pseudo signature:
 177 *
 178 * int API_get_timer(unsigned long *current, unsigned long *base)
 179 */
 180static int API_get_timer(va_list ap)
 181{
 182        unsigned long *base, *cur;
 183
 184        cur = (unsigned long *)va_arg(ap, u_int32_t);
 185        if (cur == NULL)
 186                return API_EINVAL;
 187
 188        base = (unsigned long *)va_arg(ap, u_int32_t);
 189        if (base == NULL)
 190                return API_EINVAL;
 191
 192        *cur = get_timer(*base);
 193        return 0;
 194}
 195
 196
 197/*****************************************************************************
 198 *
 199 * pseudo signature:
 200 *
 201 * int API_dev_enum(struct device_info *)
 202 *
 203 *
 204 * cookies uniqely identify the previously enumerated device instance and
 205 * provide a hint for what to inspect in current enum iteration:
 206 *
 207 *   - net: &eth_device struct address from list pointed to by eth_devices
 208 *
 209 *   - storage: block_dev_desc_t struct address from &ide_dev_desc[n],
 210 *     &scsi_dev_desc[n] and similar tables
 211 *
 212 ****************************************************************************/
 213
 214static int API_dev_enum(va_list ap)
 215{
 216        struct device_info *di;
 217
 218        /* arg is ptr to the device_info struct we are going to fill out */
 219        di = (struct device_info *)va_arg(ap, u_int32_t);
 220        if (di == NULL)
 221                return API_EINVAL;
 222
 223        if (di->cookie == NULL) {
 224                /* start over - clean up enumeration */
 225                dev_enum_reset();       /* XXX shouldn't the name contain 'stor'? */
 226                debugf("RESTART ENUM\n");
 227
 228                /* net device enumeration first */
 229                if (dev_enum_net(di))
 230                        return 0;
 231        }
 232
 233        /*
 234         * The hidden assumption is there can only be one active network
 235         * device and it is identified upon enumeration (re)start, so there's
 236         * no point in trying to find network devices in other cases than the
 237         * (re)start and hence the 'next' device can only be storage
 238         */
 239        if (!dev_enum_storage(di))
 240                /* make sure we mark there are no more devices */
 241                di->cookie = NULL;
 242
 243        return 0;
 244}
 245
 246
 247static int API_dev_open(va_list ap)
 248{
 249        struct device_info *di;
 250        int err = 0;
 251
 252        /* arg is ptr to the device_info struct */
 253        di = (struct device_info *)va_arg(ap, u_int32_t);
 254        if (di == NULL)
 255                return API_EINVAL;
 256
 257        /* Allow only one consumer of the device at a time */
 258        if (di->state == DEV_STA_OPEN)
 259                return API_EBUSY;
 260
 261        if (di->cookie == NULL)
 262                return API_ENODEV;
 263
 264        if (di->type & DEV_TYP_STOR)
 265                err = dev_open_stor(di->cookie);
 266
 267        else if (di->type & DEV_TYP_NET)
 268                err = dev_open_net(di->cookie);
 269        else
 270                err = API_ENODEV;
 271
 272        if (!err)
 273                di->state = DEV_STA_OPEN;
 274
 275        return err;
 276}
 277
 278
 279static int API_dev_close(va_list ap)
 280{
 281        struct device_info *di;
 282        int err = 0;
 283
 284        /* arg is ptr to the device_info struct */
 285        di = (struct device_info *)va_arg(ap, u_int32_t);
 286        if (di == NULL)
 287                return API_EINVAL;
 288
 289        if (di->state == DEV_STA_CLOSED)
 290                return 0;
 291
 292        if (di->cookie == NULL)
 293                return API_ENODEV;
 294
 295        if (di->type & DEV_TYP_STOR)
 296                err = dev_close_stor(di->cookie);
 297
 298        else if (di->type & DEV_TYP_NET)
 299                err = dev_close_net(di->cookie);
 300        else
 301                /*
 302                 * In case of unknown device we cannot change its state, so
 303                 * only return error code
 304                 */
 305                err = API_ENODEV;
 306
 307        if (!err)
 308                di->state = DEV_STA_CLOSED;
 309
 310        return err;
 311}
 312
 313
 314/*
 315 * Notice: this is for sending network packets only, as U-Boot does not
 316 * support writing to storage at the moment (12.2007)
 317 *
 318 * pseudo signature:
 319 *
 320 * int API_dev_write(
 321 *      struct device_info *di,
 322 *      void *buf,
 323 *      int *len
 324 * )
 325 *
 326 * buf: ptr to buffer from where to get the data to send
 327 *
 328 * len: length of packet to be sent (in bytes)
 329 *
 330 */
 331static int API_dev_write(va_list ap)
 332{
 333        struct device_info *di;
 334        void *buf;
 335        int *len;
 336        int err = 0;
 337
 338        /* 1. arg is ptr to the device_info struct */
 339        di = (struct device_info *)va_arg(ap, u_int32_t);
 340        if (di == NULL)
 341                return API_EINVAL;
 342
 343        /* XXX should we check if device is open? i.e. the ->state ? */
 344
 345        if (di->cookie == NULL)
 346                return API_ENODEV;
 347
 348        /* 2. arg is ptr to buffer from where to get data to write */
 349        buf = (void *)va_arg(ap, u_int32_t);
 350        if (buf == NULL)
 351                return API_EINVAL;
 352
 353        /* 3. arg is length of buffer */
 354        len = (int *)va_arg(ap, u_int32_t);
 355        if (len == NULL)
 356                return API_EINVAL;
 357        if (*len <= 0)
 358                return API_EINVAL;
 359
 360        if (di->type & DEV_TYP_STOR)
 361                /*
 362                 * write to storage is currently not supported by U-Boot:
 363                 * no storage device implements block_write() method
 364                 */
 365                return API_ENODEV;
 366
 367        else if (di->type & DEV_TYP_NET)
 368                err = dev_write_net(di->cookie, buf, *len);
 369        else
 370                err = API_ENODEV;
 371
 372        return err;
 373}
 374
 375
 376/*
 377 * pseudo signature:
 378 *
 379 * int API_dev_read(
 380 *      struct device_info *di,
 381 *      void *buf,
 382 *      size_t *len,
 383 *      unsigned long *start
 384 *      size_t *act_len
 385 * )
 386 *
 387 * buf: ptr to buffer where to put the read data
 388 *
 389 * len: ptr to length to be read
 390 *      - network: len of packet to read (in bytes)
 391 *      - storage: # of blocks to read (can vary in size depending on define)
 392 *
 393 * start: ptr to start block (only used for storage devices, ignored for
 394 *        network)
 395 *
 396 * act_len: ptr to where to put the len actually read
 397 */
 398static int API_dev_read(va_list ap)
 399{
 400        struct device_info *di;
 401        void *buf;
 402        lbasize_t *len_stor, *act_len_stor;
 403        lbastart_t *start;
 404        int *len_net, *act_len_net;
 405
 406        /* 1. arg is ptr to the device_info struct */
 407        di = (struct device_info *)va_arg(ap, u_int32_t);
 408        if (di == NULL)
 409                return API_EINVAL;
 410
 411        /* XXX should we check if device is open? i.e. the ->state ? */
 412
 413        if (di->cookie == NULL)
 414                return API_ENODEV;
 415
 416        /* 2. arg is ptr to buffer from where to put the read data */
 417        buf = (void *)va_arg(ap, u_int32_t);
 418        if (buf == NULL)
 419                return API_EINVAL;
 420
 421        if (di->type & DEV_TYP_STOR) {
 422                /* 3. arg - ptr to var with # of blocks to read */
 423                len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
 424                if (!len_stor)
 425                        return API_EINVAL;
 426                if (*len_stor <= 0)
 427                        return API_EINVAL;
 428
 429                /* 4. arg - ptr to var with start block */
 430                start = (lbastart_t *)va_arg(ap, u_int32_t);
 431
 432                /* 5. arg - ptr to var where to put the len actually read */
 433                act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
 434                if (!act_len_stor)
 435                        return API_EINVAL;
 436
 437                *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
 438
 439        } else if (di->type & DEV_TYP_NET) {
 440
 441                /* 3. arg points to the var with length of packet to read */
 442                len_net = (int *)va_arg(ap, u_int32_t);
 443                if (!len_net)
 444                        return API_EINVAL;
 445                if (*len_net <= 0)
 446                        return API_EINVAL;
 447
 448                /* 4. - ptr to var where to put the len actually read */
 449                act_len_net = (int *)va_arg(ap, u_int32_t);
 450                if (!act_len_net)
 451                        return API_EINVAL;
 452
 453                *act_len_net = dev_read_net(di->cookie, buf, *len_net);
 454
 455        } else
 456                return API_ENODEV;
 457
 458        return 0;
 459}
 460
 461
 462/*
 463 * pseudo signature:
 464 *
 465 * int API_env_get(const char *name, char **value)
 466 *
 467 * name: ptr to name of env var
 468 */
 469static int API_env_get(va_list ap)
 470{
 471        char *name, **value;
 472
 473        if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
 474                return API_EINVAL;
 475        if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
 476                return API_EINVAL;
 477
 478        *value = getenv(name);
 479
 480        return 0;
 481}
 482
 483/*
 484 * pseudo signature:
 485 *
 486 * int API_env_set(const char *name, const char *value)
 487 *
 488 * name: ptr to name of env var
 489 *
 490 * value: ptr to value to be set
 491 */
 492static int API_env_set(va_list ap)
 493{
 494        char *name, *value;
 495
 496        if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
 497                return API_EINVAL;
 498        if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
 499                return API_EINVAL;
 500
 501        setenv(name, value);
 502
 503        return 0;
 504}
 505
 506/*
 507 * pseudo signature:
 508 *
 509 * int API_env_enum(const char *last, char **next)
 510 *
 511 * last: ptr to name of env var found in last iteration
 512 */
 513static int API_env_enum(va_list ap)
 514{
 515        int i, n;
 516        char *last, **next;
 517
 518        last = (char *)va_arg(ap, u_int32_t);
 519
 520        if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
 521                return API_EINVAL;
 522
 523        if (last == NULL)
 524                /* start over */
 525                *next = ((char *)env_get_addr(0));
 526        else {
 527                *next = last;
 528
 529                for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
 530                        for (n = i; env_get_char(n) != '\0'; ++n) {
 531                                if (n >= CONFIG_ENV_SIZE) {
 532                                        /* XXX shouldn't we set *next = NULL?? */
 533                                        return 0;
 534                                }
 535                        }
 536
 537                        if (envmatch((uchar *)last, i) < 0)
 538                                continue;
 539
 540                        /* try to get next name */
 541                        i = n + 1;
 542                        if (env_get_char(i) == '\0') {
 543                                /* no more left */
 544                                *next = NULL;
 545                                return 0;
 546                        }
 547
 548                        *next = ((char *)env_get_addr(i));
 549                        return 0;
 550                }
 551        }
 552
 553        return 0;
 554}
 555
 556/*
 557 * pseudo signature:
 558 *
 559 * int API_display_get_info(int type, struct display_info *di)
 560 */
 561static int API_display_get_info(va_list ap)
 562{
 563        int type;
 564        struct display_info *di;
 565
 566        type = va_arg(ap, int);
 567        di = va_arg(ap, struct display_info *);
 568
 569        return display_get_info(type, di);
 570}
 571
 572/*
 573 * pseudo signature:
 574 *
 575 * int API_display_draw_bitmap(ulong bitmap, int x, int y)
 576 */
 577static int API_display_draw_bitmap(va_list ap)
 578{
 579        ulong bitmap;
 580        int x, y;
 581
 582        bitmap = va_arg(ap, ulong);
 583        x = va_arg(ap, int);
 584        y = va_arg(ap, int);
 585
 586        return display_draw_bitmap(bitmap, x, y);
 587}
 588
 589/*
 590 * pseudo signature:
 591 *
 592 * void API_display_clear(void)
 593 */
 594static int API_display_clear(va_list ap)
 595{
 596        display_clear();
 597        return 0;
 598}
 599
 600static cfp_t calls_table[API_MAXCALL] = { NULL, };
 601
 602/*
 603 * The main syscall entry point - this is not reentrant, only one call is
 604 * serviced until finished.
 605 *
 606 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
 607 *
 608 * call:        syscall number
 609 *
 610 * retval:      points to the return value placeholder, this is the place the
 611 *              syscall puts its return value, if NULL the caller does not
 612 *              expect a return value
 613 *
 614 * ...          syscall arguments (variable number)
 615 *
 616 * returns:     0 if the call not found, 1 if serviced
 617 */
 618int syscall(int call, int *retval, ...)
 619{
 620        va_list ap;
 621        int rv;
 622
 623        if (call < 0 || call >= calls_no) {
 624                debugf("invalid call #%d\n", call);
 625                return 0;
 626        }
 627
 628        if (calls_table[call] == NULL) {
 629                debugf("syscall #%d does not have a handler\n", call);
 630                return 0;
 631        }
 632
 633        va_start(ap, retval);
 634        rv = calls_table[call](ap);
 635        if (retval != NULL)
 636                *retval = rv;
 637
 638        return 1;
 639}
 640
 641void api_init(void)
 642{
 643        struct api_signature *sig = NULL;
 644
 645        /* TODO put this into linker set one day... */
 646        calls_table[API_RSVD] = NULL;
 647        calls_table[API_GETC] = &API_getc;
 648        calls_table[API_PUTC] = &API_putc;
 649        calls_table[API_TSTC] = &API_tstc;
 650        calls_table[API_PUTS] = &API_puts;
 651        calls_table[API_RESET] = &API_reset;
 652        calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
 653        calls_table[API_UDELAY] = &API_udelay;
 654        calls_table[API_GET_TIMER] = &API_get_timer;
 655        calls_table[API_DEV_ENUM] = &API_dev_enum;
 656        calls_table[API_DEV_OPEN] = &API_dev_open;
 657        calls_table[API_DEV_CLOSE] = &API_dev_close;
 658        calls_table[API_DEV_READ] = &API_dev_read;
 659        calls_table[API_DEV_WRITE] = &API_dev_write;
 660        calls_table[API_ENV_GET] = &API_env_get;
 661        calls_table[API_ENV_SET] = &API_env_set;
 662        calls_table[API_ENV_ENUM] = &API_env_enum;
 663        calls_table[API_DISPLAY_GET_INFO] = &API_display_get_info;
 664        calls_table[API_DISPLAY_DRAW_BITMAP] = &API_display_draw_bitmap;
 665        calls_table[API_DISPLAY_CLEAR] = &API_display_clear;
 666        calls_no = API_MAXCALL;
 667
 668        debugf("API initialized with %d calls\n", calls_no);
 669
 670        dev_stor_init();
 671
 672        /*
 673         * Produce the signature so the API consumers can find it
 674         */
 675        sig = malloc(sizeof(struct api_signature));
 676        if (sig == NULL) {
 677                printf("API: could not allocate memory for the signature!\n");
 678                return;
 679        }
 680
 681        debugf("API sig @ 0x%08x\n", sig);
 682        memcpy(sig->magic, API_SIG_MAGIC, 8);
 683        sig->version = API_SIG_VERSION;
 684        sig->syscall = &syscall;
 685        sig->checksum = 0;
 686        sig->checksum = crc32(0, (unsigned char *)sig,
 687                              sizeof(struct api_signature));
 688        debugf("syscall entry: 0x%08x\n", sig->syscall);
 689}
 690
 691void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
 692                        int flags)
 693{
 694        int i;
 695
 696        if (!si->mr || !size || (flags == 0))
 697                return;
 698
 699        /* find free slot */
 700        for (i = 0; i < si->mr_no; i++)
 701                if (si->mr[i].flags == 0) {
 702                        /* insert new mem region */
 703                        si->mr[i].start = start;
 704                        si->mr[i].size = size;
 705                        si->mr[i].flags = flags;
 706                        return;
 707                }
 708}
 709