source: SVN/rincon/u-boot/api/api.c @ 55

Last change on this file since 55 was 55, checked in by Tim Harvey, 22 months ago

rincon: added latest u-boot source

restored form server backup

Signed-off-by: Tim Harvey <tharvey@…>

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