aboutsummaryrefslogtreecommitdiffstats
path: root/api
diff options
context:
space:
mode:
authorRafal Jaworowski2008-01-09 12:39:36 -0600
committerRafal Jaworowski2008-01-09 12:39:36 -0600
commit500856eb1707ed17d9204baa61dd59948d3b2899 (patch)
treee29338498cbf1b92ad496271e65934b890115545 /api
parent26a41790f8eba19ad450e18ae91351daf485b3e2 (diff)
downloadu-boot-500856eb1707ed17d9204baa61dd59948d3b2899.tar.gz
u-boot-500856eb1707ed17d9204baa61dd59948d3b2899.tar.xz
u-boot-500856eb1707ed17d9204baa61dd59948d3b2899.zip
API for external applications.
This is an API for external (standalone) applications running on top of U-Boot, and is meant to be more extensible and robust than the existing jumptable mechanism. It is similar to UNIX syscall approach. See api/README for more details. Included is the demo application using this new framework (api_examples). Please note this is still an experimental feature, and is turned off by default. Signed-off-by: Rafal Jaworowski <raj@semihalf.com>
Diffstat (limited to 'api')
-rw-r--r--api/Makefile40
-rw-r--r--api/README55
-rw-r--r--api/api.c670
-rw-r--r--api/api_net.c113
-rw-r--r--api/api_platform-arm.c60
-rw-r--r--api/api_platform-ppc.c79
-rw-r--r--api/api_private.h48
-rw-r--r--api/api_storage.c370
8 files changed, 1435 insertions, 0 deletions
diff --git a/api/Makefile b/api/Makefile
new file mode 100644
index 0000000000..94de3dc395
--- /dev/null
+++ b/api/Makefile
@@ -0,0 +1,40 @@
1#
2# (C) Copyright 2007 Semihalf
3#
4# See file CREDITS for list of people who contributed to this
5# project.
6#
7# This program is free software; you can redistribute it and/or
8# modify it under the terms of the GNU General Public License as
9# published by the Free Software Foundatio; either version 2 of
10# the License, or (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20# MA 02111-1307 USA
21#
22
23include $(TOPDIR)/config.mk
24
25LIB = $(obj)libapi.a
26
27COBJS = api.o api_net.o api_storage.o api_platform-$(ARCH).o
28
29SRCS := $(COBJS:.o=.c)
30OBJS := $(addprefix $(obj),$(COBJS))
31
32all: $(LIB)
33
34$(LIB): $(obj).depend $(OBJS)
35 $(AR) $(ARFLAGS) $@ $(OBJS)
36
37# defines $(obj).depend target
38include $(SRCTREE)/rules.mk
39
40sinclude $(obj).depend
diff --git a/api/README b/api/README
new file mode 100644
index 0000000000..c8f9c457c4
--- /dev/null
+++ b/api/README
@@ -0,0 +1,55 @@
1U-Boot machine/arch independent API for external apps
2=====================================================
3
41. Main assumptions
5
6 - there is a single entry point (syscall) to the API
7
8 - per current design the syscall is a C-callable function in the U-Boot
9 text, which might evolve into a real syscall using machine exception trap
10 once this initial version proves functional
11
12 - the consumer app is responsible for producing appropriate context (call
13 number and arguments)
14
15 - upon entry, the syscall dispatches the call to other (existing) U-Boot
16 functional areas like networking or storage operations
17
18 - consumer application will recognize the API is available by searching
19 a specified (assumed by convention) range of address space for the
20 signature
21
22 - the U-Boot integral part of the API is meant to be thin and non-intrusive,
23 leaving as much processing as possible on the consumer application side,
24 for example it doesn't keep states, but relies on hints from the app and
25 so on
26
27 - optional (CONFIG_API)
28
29
302. Calls
31
32 - console related (getc, putc, tstc etc.)
33 - system (reset, platform info)
34 - time (delay, current)
35 - env vars (enumerate all, get, set)
36 - devices (enumerate all, open, close, read, write); currently two classes
37 of devices are recognized and supported: network and storage (ide, scsi,
38 usb etc.)
39
40
413. Structure overview
42
43 - core API, integral part of U-Boot, mandatory
44 - implements the single entry point (mimics UNIX syscall)
45
46 - glue
47 - entry point at the consumer side, allows to make syscall, mandatory
48 part
49
50 - helper conveniency wrappers so that consumer app does not have to use
51 the syscall directly, but in a more friendly manner (a la libc calls),
52 optional part
53
54 - consumer application
55 - calls directly, or leverages the provided glue mid-layer
diff --git a/api/api.c b/api/api.c
new file mode 100644
index 0000000000..10f83eb691
--- /dev/null
+++ b/api/api.c
@@ -0,0 +1,670 @@
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 <linux/types.h>
34#include <api_public.h>
35
36#include "api_private.h"
37
38#define DEBUG
39#undef DEBUG
40
41/* U-Boot routines needed */
42extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
43extern uchar (*env_get_char)(int);
44extern uchar *env_get_addr(int);
45
46/*****************************************************************************
47 *
48 * This is the API core.
49 *
50 * API_ functions are part of U-Boot code and constitute the lowest level
51 * calls:
52 *
53 * - they know what values they need as arguments
54 * - their direct return value pertains to the API_ "shell" itself (0 on
55 * success, some error code otherwise)
56 * - if the call returns a value it is buried within arguments
57 *
58 ****************************************************************************/
59
60#ifdef DEBUG
61#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
62#else
63#define debugf(fmt, args...)
64#endif
65
66typedef int (*cfp_t)(va_list argp);
67
68static int calls_no;
69
70/*
71 * pseudo signature:
72 *
73 * int API_getc(int *c)
74 */
75static int API_getc(va_list ap)
76{
77 int *c;
78
79 if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
80 return API_EINVAL;
81
82 *c = getc();
83 return 0;
84}
85
86/*
87 * pseudo signature:
88 *
89 * int API_tstc(int *c)
90 */
91static int API_tstc(va_list ap)
92{
93 int *t;
94
95 if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
96 return API_EINVAL;
97
98 *t = tstc();
99 return 0;
100}
101
102/*
103 * pseudo signature:
104 *
105 * int API_putc(char *ch)
106 */
107static int API_putc(va_list ap)
108{
109 char *c;
110
111 if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
112 return API_EINVAL;
113
114 putc(*c);
115 return 0;
116}
117
118/*
119 * pseudo signature:
120 *
121 * int API_puts(char **s)
122 */
123static int API_puts(va_list ap)
124{
125 char *s;
126
127 if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
128 return API_EINVAL;
129
130 puts(s);
131 return 0;
132}
133
134/*
135 * pseudo signature:
136 *
137 * int API_reset(void)
138 */
139static int API_reset(va_list ap)
140{
141 do_reset(NULL, 0, 0, NULL);
142
143 /* NOT REACHED */
144 return 0;
145}
146
147/*
148 * pseudo signature:
149 *
150 * int API_get_sys_info(struct sys_info *si)
151 *
152 * fill out the sys_info struct containing selected parameters about the
153 * machine
154 */
155static int API_get_sys_info(va_list ap)
156{
157 struct sys_info *si;
158
159 si = (struct sys_info *)va_arg(ap, u_int32_t);
160 if (si == NULL)
161 return API_ENOMEM;
162
163 return (platform_sys_info(si)) ? 0 : API_ENODEV;
164}
165
166/*
167 * pseudo signature:
168 *
169 * int API_udelay(unsigned long *udelay)
170 */
171static int API_udelay(va_list ap)
172{
173 unsigned long *d;
174
175 if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
176 return API_EINVAL;
177
178 udelay(*d);
179 return 0;
180}
181
182/*
183 * pseudo signature:
184 *
185 * int API_get_timer(unsigned long *current, unsigned long *base)
186 */
187static int API_get_timer(va_list ap)
188{
189 unsigned long *base, *cur;
190
191 cur = (unsigned long *)va_arg(ap, u_int32_t);
192 if (cur == NULL)
193 return API_EINVAL;
194
195 base = (unsigned long *)va_arg(ap, u_int32_t);
196 if (base == NULL)
197 return API_EINVAL;
198
199 *cur = get_timer(*base);
200 return 0;
201}
202
203
204/*****************************************************************************
205 *
206 * pseudo signature:
207 *
208 * int API_dev_enum(struct device_info *)
209 *
210 *
211 * cookies uniqely identify the previously enumerated device instance and
212 * provide a hint for what to inspect in current enum iteration:
213 *
214 * - net: &eth_device struct address from list pointed to by eth_devices
215 *
216 * - storage: block_dev_desc_t struct address from &ide_dev_desc[n],
217 * &scsi_dev_desc[n] and similar tables
218 *
219 ****************************************************************************/
220
221static int API_dev_enum(va_list ap)
222{
223 struct device_info *di;
224
225 /* arg is ptr to the device_info struct we are going to fill out */
226 di = (struct device_info *)va_arg(ap, u_int32_t);
227 if (di == NULL)
228 return API_EINVAL;
229
230 if (di->cookie == NULL) {
231 /* start over - clean up enumeration */
232 dev_enum_reset(); /* XXX shouldn't the name contain 'stor'? */
233 debugf("RESTART ENUM\n");
234
235 /* net device enumeration first */
236 if (dev_enum_net(di))
237 return 0;
238 }
239
240 /*
241 * The hidden assumption is there can only be one active network
242 * device and it is identified upon enumeration (re)start, so there's
243 * no point in trying to find network devices in other cases than the
244 * (re)start and hence the 'next' device can only be storage
245 */
246 if (!dev_enum_storage(di))
247 /* make sure we mark there are no more devices */
248 di->cookie = NULL;
249
250 return 0;
251}
252
253
254static int API_dev_open(va_list ap)
255{
256 struct device_info *di;
257 int err = 0;
258
259 /* arg is ptr to the device_info struct */
260 di = (struct device_info *)va_arg(ap, u_int32_t);
261 if (di == NULL)
262 return API_EINVAL;
263
264 /* Allow only one consumer of the device at a time */
265 if (di->state == DEV_STA_OPEN)
266 return API_EBUSY;
267
268 if (di->cookie == NULL)
269 return API_ENODEV;
270
271 if (di->type & DEV_TYP_STOR)
272 err = dev_open_stor(di->cookie);
273
274 else if (di->type & DEV_TYP_NET)
275 err = dev_open_net(di->cookie);
276 else
277 err = API_ENODEV;
278
279 if (!err)
280 di->state = DEV_STA_OPEN;
281
282 return err;
283}
284
285
286static int API_dev_close(va_list ap)
287{
288 struct device_info *di;
289 int err = 0;
290
291 /* arg is ptr to the device_info struct */
292 di = (struct device_info *)va_arg(ap, u_int32_t);
293 if (di == NULL)
294 return API_EINVAL;
295
296 if (di->state == DEV_STA_CLOSED)
297 return 0;
298
299 if (di->cookie == NULL)
300 return API_ENODEV;
301
302 if (di->type & DEV_TYP_STOR)
303 err = dev_close_stor(di->cookie);
304
305 else if (di->type & DEV_TYP_NET)
306 err = dev_close_net(di->cookie);
307 else
308 /*
309 * In case of unknown device we cannot change its state, so
310 * only return error code
311 */
312 err = API_ENODEV;
313
314 if (!err)
315 di->state = DEV_STA_CLOSED;
316
317 return err;
318}
319
320
321/*
322 * Notice: this is for sending network packets only, as U-Boot does not
323 * support writing to storage at the moment (12.2007)
324 *
325 * pseudo signature:
326 *
327 * int API_dev_write(
328 * struct device_info *di,
329 * void *buf,
330 * int *len
331 * )
332 *
333 * buf: ptr to buffer from where to get the data to send
334 *
335 * len: length of packet to be sent (in bytes)
336 *
337 */
338static int API_dev_write(va_list ap)
339{
340 struct device_info *di;
341 void *buf;
342 int *len;
343 int err = 0;
344
345 /* 1. arg is ptr to the device_info struct */
346 di = (struct device_info *)va_arg(ap, u_int32_t);
347 if (di == NULL)
348 return API_EINVAL;
349
350 /* XXX should we check if device is open? i.e. the ->state ? */
351
352 if (di->cookie == NULL)
353 return API_ENODEV;
354
355 /* 2. arg is ptr to buffer from where to get data to write */
356 buf = (void *)va_arg(ap, u_int32_t);
357 if (buf == NULL)
358 return API_EINVAL;
359
360 /* 3. arg is length of buffer */
361 len = (int *)va_arg(ap, u_int32_t);
362 if (len == NULL)
363 return API_EINVAL;
364 if (*len <= 0)
365 return API_EINVAL;
366
367 if (di->type & DEV_TYP_STOR)
368 /*
369 * write to storage is currently not supported by U-Boot:
370 * no storage device implements block_write() method
371 */
372 return API_ENODEV;
373
374 else if (di->type & DEV_TYP_NET)
375 err = dev_write_net(di->cookie, buf, *len);
376 else
377 err = API_ENODEV;
378
379 return err;
380}
381
382
383/*
384 * pseudo signature:
385 *
386 * int API_dev_read(
387 * struct device_info *di,
388 * void *buf,
389 * size_t *len,
390 * unsigned long *start
391 * size_t *act_len
392 * )
393 *
394 * buf: ptr to buffer where to put the read data
395 *
396 * len: ptr to length to be read
397 * - network: len of packet to read (in bytes)
398 * - storage: # of blocks to read (can vary in size depending on define)
399 *
400 * start: ptr to start block (only used for storage devices, ignored for
401 * network)
402 *
403 * act_len: ptr to where to put the len actually read
404 */
405static int API_dev_read(va_list ap)
406{
407 struct device_info *di;
408 void *buf;
409 lbasize_t *len_stor, *act_len_stor;
410 lbastart_t *start;
411 int *len_net, *act_len_net;
412
413 /* 1. arg is ptr to the device_info struct */
414 di = (struct device_info *)va_arg(ap, u_int32_t);
415 if (di == NULL)
416 return API_EINVAL;
417
418 /* XXX should we check if device is open? i.e. the ->state ? */
419
420 if (di->cookie == NULL)
421 return API_ENODEV;
422
423 /* 2. arg is ptr to buffer from where to put the read data */
424 buf = (void *)va_arg(ap, u_int32_t);
425 if (buf == NULL)
426 return API_EINVAL;
427
428 if (di->type & DEV_TYP_STOR) {
429 /* 3. arg - ptr to var with # of blocks to read */
430 len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
431 if (!len_stor)
432 return API_EINVAL;
433 if (*len_stor <= 0)
434 return API_EINVAL;
435
436 /* 4. arg - ptr to var with start block */
437 start = (lbastart_t *)va_arg(ap, u_int32_t);
438
439 /* 5. arg - ptr to var where to put the len actually read */
440 act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
441 if (!act_len_stor)
442 return API_EINVAL;
443
444 *act_len_stor = dev_read_stor(di->cookie, buf, *len_stor, *start);
445
446 } else if (di->type & DEV_TYP_NET) {
447
448 /* 3. arg points to the var with length of packet to read */
449 len_net = (int *)va_arg(ap, u_int32_t);
450 if (!len_net)
451 return API_EINVAL;
452 if (*len_net <= 0)
453 return API_EINVAL;
454
455 /* 4. - ptr to var where to put the len actually read */
456 act_len_net = (int *)va_arg(ap, u_int32_t);
457 if (!act_len_net)
458 return API_EINVAL;
459
460 *act_len_net = dev_read_net(di->cookie, buf, *len_net);
461
462 } else
463 return API_ENODEV;
464
465 return 0;
466}
467
468
469/*
470 * pseudo signature:
471 *
472 * int API_env_get(const char *name, char **value)
473 *
474 * name: ptr to name of env var
475 */
476static int API_env_get(va_list ap)
477{
478 char *name, **value;
479
480 if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
481 return API_EINVAL;
482 if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
483 return API_EINVAL;
484
485 *value = getenv(name);
486
487 return 0;
488}
489
490/*
491 * pseudo signature:
492 *
493 * int API_env_set(const char *name, const char *value)
494 *
495 * name: ptr to name of env var
496 *
497 * value: ptr to value to be set
498 */
499static int API_env_set(va_list ap)
500{
501 char *name, *value;
502
503 if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
504 return API_EINVAL;
505 if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
506 return API_EINVAL;
507
508 setenv(name, value);
509
510 return 0;
511}
512
513/*
514 * pseudo signature:
515 *
516 * int API_env_enum(const char *last, char **next)
517 *
518 * last: ptr to name of env var found in last iteration
519 */
520static int API_env_enum(va_list ap)
521{
522 int i, n;
523 char *last, **next;
524
525 last = (char *)va_arg(ap, u_int32_t);
526
527 if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
528 return API_EINVAL;
529
530 if (last == NULL)
531 /* start over */
532 *next = ((char *)env_get_addr(0));
533 else {
534 *next = last;
535
536 for (i = 0; env_get_char(i) != '\0'; i = n + 1) {
537 for (n = i; env_get_char(n) != '\0'; ++n) {
538 if (n >= CFG_ENV_SIZE) {
539 /* XXX shouldn't we set *next = NULL?? */
540 return 0;
541 }
542 }
543
544 if (envmatch((uchar *)last, i) < 0)
545 continue;
546
547 /* try to get next name */
548 i = n + 1;
549 if (env_get_char(i) == '\0') {
550 /* no more left */
551 *next = NULL;
552 return 0;
553 }
554
555 *next = ((char *)env_get_addr(i));
556 return 0;
557 }
558 }
559
560 return 0;
561}
562
563static cfp_t calls_table[API_MAXCALL] = { NULL, };
564
565/*
566 * The main syscall entry point - this is not reentrant, only one call is
567 * serviced until finished.
568 *
569 * e.g. syscall(1, int *, u_int32_t, u_int32_t, u_int32_t, u_int32_t);
570 *
571 * call: syscall number
572 *
573 * retval: points to the return value placeholder, this is the place the
574 * syscall puts its return value, if NULL the caller does not
575 * expect a return value
576 *
577 * ... syscall arguments (variable number)
578 *
579 * returns: 0 if the call not found, 1 if serviced
580 */
581int syscall(int call, int *retval, ...)
582{
583 va_list ap;
584 int rv;
585
586 if (call < 0 || call >= calls_no || calls_table[call] == NULL) {
587 debugf("invalid call #%d\n", call);
588 return 0;
589 }
590
591 if (calls_table[call] == NULL) {
592 debugf("syscall #%d does not have a handler\n", call);
593 return 0;
594 }
595
596 va_start(ap, retval);
597 rv = calls_table[call](ap);
598 if (retval != NULL)
599 *retval = rv;
600
601 return 1;
602}
603
604void api_init(void)
605{
606 struct api_signature *sig = NULL;
607
608 /* TODO put this into linker set one day... */
609 calls_table[API_RSVD] = NULL;
610 calls_table[API_GETC] = &API_getc;
611 calls_table[API_PUTC] = &API_putc;
612 calls_table[API_TSTC] = &API_tstc;
613 calls_table[API_PUTS] = &API_puts;
614 calls_table[API_RESET] = &API_reset;
615 calls_table[API_GET_SYS_INFO] = &API_get_sys_info;
616 calls_table[API_UDELAY] = &API_udelay;
617 calls_table[API_GET_TIMER] = &API_get_timer;
618 calls_table[API_DEV_ENUM] = &API_dev_enum;
619 calls_table[API_DEV_OPEN] = &API_dev_open;
620 calls_table[API_DEV_CLOSE] = &API_dev_close;
621 calls_table[API_DEV_READ] = &API_dev_read;
622 calls_table[API_DEV_WRITE] = &API_dev_write;
623 calls_table[API_ENV_GET] = &API_env_get;
624 calls_table[API_ENV_SET] = &API_env_set;
625 calls_table[API_ENV_ENUM] = &API_env_enum;
626 calls_no = API_MAXCALL;
627
628 debugf("API initialized with %d calls\n", calls_no);
629
630 dev_stor_init();
631
632 /*
633 * Produce the signature so the API consumers can find it
634 */
635 sig = malloc(sizeof(struct api_signature));
636 if (sig == NULL) {
637 printf("API: could not allocate memory for the signature!\n");
638 return;
639 }
640
641 debugf("API sig @ 0x%08x\n", sig);
642 memcpy(sig->magic, API_SIG_MAGIC, 8);
643 sig->version = API_SIG_VERSION;
644 sig->syscall = &syscall;
645 sig->checksum = 0;
646 sig->checksum = crc32(0, (unsigned char *)sig,
647 sizeof(struct api_signature));
648 debugf("syscall entry: 0x%08x\n", sig->syscall);
649}
650
651void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
652 int flags)
653{
654 int i;
655
656 if (!si->mr || !size || (flags == 0))
657 return;
658
659 /* find free slot */
660 for (i = 0; i < si->mr_no; i++)
661 if (si->mr[i].flags == 0) {
662 /* insert new mem region */
663 si->mr[i].start = start;
664 si->mr[i].size = size;
665 si->mr[i].flags = flags;
666 return;
667 }
668}
669
670#endif /* CONFIG_API */
diff --git a/api/api_net.c b/api/api_net.c
new file mode 100644
index 0000000000..9b20a1740c
--- /dev/null
+++ b/api/api_net.c
@@ -0,0 +1,113 @@
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 <common.h>
31#include <net.h>
32#include <linux/types.h>
33#include <api_public.h>
34
35DECLARE_GLOBAL_DATA_PTR;
36
37#define DEBUG
38#undef DEBUG
39
40#if !defined(CONFIG_NET_MULTI)
41#error "API/net is currently only available for platforms with CONFIG_NET_MULTI"
42#endif
43
44#ifdef DEBUG
45#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
46#else
47#define debugf(fmt, args...)
48#endif
49
50#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
51
52
53static int dev_valid_net(void *cookie)
54{
55 return ((void *)eth_get_dev() == cookie) ? 1 : 0;
56}
57
58int dev_open_net(void *cookie)
59{
60 if (!dev_valid_net(cookie))
61 return API_ENODEV;
62
63 if (eth_init(gd->bd) < 0)
64 return API_EIO;
65
66 return 0;
67}
68
69int dev_close_net(void *cookie)
70{
71 if (!dev_valid_net(cookie))
72 return API_ENODEV;
73
74 eth_halt();
75 return 0;
76}
77
78/*
79 * There can only be one active eth interface at a time - use what is
80 * currently set to eth_current
81 */
82int dev_enum_net(struct device_info *di)
83{
84 struct eth_device *eth_current = eth_get_dev();
85
86 di->type = DEV_TYP_NET;
87 di->cookie = (void *)eth_current;
88 if (di->cookie == NULL)
89 return 0;
90
91 memcpy(di->di_net.hwaddr, eth_current->enetaddr, 6);
92
93 debugf("device found, returning cookie 0x%08x\n",
94 (u_int32_t)di->cookie);
95
96 return 1;
97}
98
99int dev_write_net(void *cookie, void *buf, int len)
100{
101 /* XXX verify that cookie points to a valid net device??? */
102
103 return eth_send(buf, len);
104}
105
106int dev_read_net(void *cookie, void *buf, int len)
107{
108 /* XXX verify that cookie points to a valid net device??? */
109
110 return eth_receive(buf, len);
111}
112
113#endif /* CONFIG_API */
diff --git a/api/api_platform-arm.c b/api/api_platform-arm.c
new file mode 100644
index 0000000000..ca15ca5a98
--- /dev/null
+++ b/api/api_platform-arm.c
@@ -0,0 +1,60 @@
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 * This file contains routines that fetch data from ARM-dependent sources
26 * (bd_info etc.)
27 *
28 */
29
30#include <config.h>
31
32#if defined(CONFIG_API)
33
34#include <linux/types.h>
35#include <api_public.h>
36
37#include <asm/u-boot.h>
38#include <asm/global_data.h>
39
40#include "api_private.h"
41
42DECLARE_GLOBAL_DATA_PTR;
43
44/*
45 * Important notice: handling of individual fields MUST be kept in sync with
46 * include/asm-arm/u-boot.h and include/asm-arm/global_data.h, so any changes
47 * need to reflect their current state and layout of structures involved!
48 */
49int platform_sys_info(struct sys_info *si)
50{
51 int i;
52
53 for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++)
54 platform_set_mr(si, gd->bd->bi_dram[i].start,
55 gd->bd->bi_dram[i].size, MR_ATTR_DRAM);
56
57 return 1;
58}
59
60#endif /* CONFIG_API */
diff --git a/api/api_platform-ppc.c b/api/api_platform-ppc.c
new file mode 100644
index 0000000000..ca9f9a5cd1
--- /dev/null
+++ b/api/api_platform-ppc.c
@@ -0,0 +1,79 @@
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 * This file contains routines that fetch data from PowerPC-dependent sources
26 * (bd_info etc.)
27 *
28 */
29
30#include <config.h>
31
32#if defined(CONFIG_API)
33
34#include <linux/types.h>
35#include <api_public.h>
36
37#include <asm/u-boot.h>
38#include <asm/global_data.h>
39
40#include "api_private.h"
41
42DECLARE_GLOBAL_DATA_PTR;
43
44/*
45 * Important notice: handling of individual fields MUST be kept in sync with
46 * include/asm-ppc/u-boot.h and include/asm-ppc/global_data.h, so any changes
47 * need to reflect their current state and layout of structures involved!
48 */
49int platform_sys_info(struct sys_info *si)
50{
51 si->clk_bus = gd->bus_clk;
52 si->clk_cpu = gd->cpu_clk;
53
54#if defined(CONFIG_5xx) || defined(CONFIG_8xx) || defined(CONFIG_8260) || \
55 defined(CONFIG_E500) || defined(CONFIG_MPC86xx)
56#define bi_bar bi_immr_base
57#elif defined(CONFIG_MPC5xxx)
58#define bi_bar bi_mbar_base
59#elif defined(CONFIG_MPC83XX)
60#define bi_bar bi_immrbar
61#elif defined(CONFIG_MPC8220)
62#define bi_bar bi_mbar_base
63#endif
64
65#if defined(bi_bar)
66 si->bar = gd->bd->bi_bar;
67#undef bi_bar
68#else
69 si->bar = NULL;
70#endif
71
72 platform_set_mr(si, gd->bd->bi_memstart, gd->bd->bi_memsize, MR_ATTR_DRAM);
73 platform_set_mr(si, gd->bd->bi_flashstart, gd->bd->bi_flashsize, MR_ATTR_FLASH);
74 platform_set_mr(si, gd->bd->bi_sramstart, gd->bd->bi_sramsize, MR_ATTR_SRAM);
75
76 return 1;
77}
78
79#endif /* CONFIG_API */
diff --git a/api/api_private.h b/api/api_private.h
new file mode 100644
index 0000000000..94a7fc509c
--- /dev/null
+++ b/api/api_private.h
@@ -0,0 +1,48 @@
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#ifndef _API_PRIVATE_H_
27#define _API_PRIVATE_H_
28
29void api_init(void);
30void platform_set_mr(struct sys_info *, unsigned long, unsigned long, int);
31int platform_sys_info(struct sys_info *);
32
33void dev_enum_reset(void);
34int dev_enum_storage(struct device_info *);
35int dev_enum_net(struct device_info *);
36
37int dev_open_stor(void *);
38int dev_open_net(void *);
39int dev_close_stor(void *);
40int dev_close_net(void *);
41
42lbasize_t dev_read_stor(void *, void *, lbasize_t, lbastart_t);
43int dev_read_net(void *, void *, int);
44int dev_write_net(void *, void *, int);
45
46void dev_stor_init(void);
47
48#endif /* _API_PRIVATE_H_ */
diff --git a/api/api_storage.c b/api/api_storage.c
new file mode 100644
index 0000000000..7cd4efb45b
--- /dev/null
+++ b/api/api_storage.c
@@ -0,0 +1,370 @@
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 <common.h>
31#include <api_public.h>
32
33#define DEBUG
34#undef DEBUG
35
36#ifdef DEBUG
37#define debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt, ##args); } while (0)
38#else
39#define debugf(fmt, args...)
40#endif
41
42#define errf(fmt, args...) do { printf("ERROR @ %s(): ", __func__); printf(fmt, ##args); } while (0)
43
44
45#define ENUM_IDE 0
46#define ENUM_USB 1
47#define ENUM_SCSI 2
48#define ENUM_MMC 3
49#define ENUM_MAX 4
50
51struct stor_spec {
52 int max_dev;
53 int enum_started;
54 int enum_ended;
55 int type; /* "external" type: DT_STOR_{IDE,USB,etc} */
56 char name[4];
57};
58
59static struct stor_spec specs[ENUM_MAX] = { { 0, 0, 0, 0, "" }, };
60
61
62void dev_stor_init(void)
63{
64#if (CONFIG_COMMANDS & CFG_CMD_IDE)
65 specs[ENUM_IDE].max_dev = CFG_IDE_MAXDEVICE;
66 specs[ENUM_IDE].enum_started = 0;
67 specs[ENUM_IDE].enum_ended = 0;
68 specs[ENUM_IDE].type = DEV_TYP_STOR | DT_STOR_IDE;
69 specs[ENUM_IDE].name = "ide";
70#endif
71#if (CONFIG_COMMANDS & CFG_CMD_USB)
72 specs[ENUM_USB].max_dev = USB_MAX_STOR_DEV;
73 specs[ENUM_USB].enum_started = 0;
74 specs[ENUM_USB].enum_ended = 0;
75 specs[ENUM_USB].type = DEV_TYP_STOR | DT_STOR_USB;
76 specs[ENUM_USB].name = "usb";
77#endif
78#if (CONFIG_COMMANDS & CFG_CMD_SCSI)
79 specs[ENUM_SCSI].max_dev = CFG_SCSI_MAX_DEVICE;
80 specs[ENUM_SCSI].enum_started = 0;
81 specs[ENUM_SCSI].enum_ended = 0;
82 specs[ENUM_SCSI].type = DEV_TYP_STOR | DT_STOR_SCSI;
83 specs[ENUM_SCSI].name = "scsi";
84#endif
85}
86
87/*
88 * Finds next available device in the storage group
89 *
90 * type: storage group type - ENUM_IDE, ENUM_SCSI etc.
91 *
92 * first: if 1 the first device in the storage group is returned (if
93 * exists), if 0 the next available device is searched
94 *
95 * more: returns 0/1 depending if there are more devices in this group
96 * available (for future iterations)
97 *
98 * returns: 0/1 depending if device found in this iteration
99 */
100static int dev_stor_get(int type, int first, int *more, struct device_info *di)
101{
102 int found = 0;
103 *more = 0;
104
105 int i;
106
107 block_dev_desc_t *dd;
108
109 if (first) {
110 di->cookie = (void *)get_dev(specs[type].name, 0);
111 found = 1;
112
113 } else {
114 for (i = 0; i < specs[type].max_dev; i++)
115 if (di->cookie == (void *)get_dev(specs[type].name, i)) {
116 /* previous cookie found -- advance to the
117 * next device, if possible */
118
119 if (++i >= specs[type].max_dev) {
120 /* out of range, no more to enum */
121 di->cookie = NULL;
122 break;
123 }
124
125 di->cookie = (void *)get_dev(specs[type].name, i);
126 found = 1;
127
128 /* provide hint if there are more devices in
129 * this group to enumerate */
130 if ((i + 1) < specs[type].max_dev)
131 *more = 1;
132
133 break;
134 }
135 }
136
137 if (found) {
138 di->type = specs[type].type;
139
140 if (di->cookie != NULL) {
141 dd = (block_dev_desc_t *)di->cookie;
142 if (dd->type == DEV_TYPE_UNKNOWN) {
143 debugf("device instance exists, but is not active..");
144 found = 0;
145 } else {
146 di->di_stor.block_count = dd->lba;
147 di->di_stor.block_size = dd->blksz;
148 }
149 }
150
151 } else
152 di->cookie = NULL;
153
154 return found;
155}
156
157
158/*
159 * returns: ENUM_IDE, ENUM_USB etc. based on block_dev_desc_t
160 */
161static int dev_stor_type(block_dev_desc_t *dd)
162{
163 int i, j;
164
165 for (i = ENUM_IDE; i < ENUM_MAX; i++)
166 for (j = 0; j < specs[i].max_dev; j++)
167 if (dd == get_dev(specs[i].name, j))
168 return i;
169
170 return ENUM_MAX;
171}
172
173
174/*
175 * returns: 0/1 whether cookie points to some device in this group
176 */
177static int dev_is_stor(int type, struct device_info *di)
178{
179 return (dev_stor_type(di->cookie) == type) ? 1 : 0;
180}
181
182
183static int dev_enum_stor(int type, struct device_info *di)
184{
185 int found = 0, more = 0;
186
187 debugf("called, type %d\n", type);
188
189 /*
190 * Formulae for enumerating storage devices:
191 * 1. if cookie (hint from previous enum call) is NULL we start again
192 * with enumeration, so return the first available device, done.
193 *
194 * 2. if cookie is not NULL, check if it identifies some device in
195 * this group:
196 *
197 * 2a. if cookie is a storage device from our group (IDE, USB etc.),
198 * return next available (if exists) in this group
199 *
200 * 2b. if it isn't device from our group, check if such devices were
201 * ever enumerated before:
202 * - if not, return the first available device from this group
203 * - else return 0
204 */
205
206 if (di->cookie == NULL) {
207
208 debugf("group%d - enum restart\n", type);
209
210 /*
211 * 1. Enumeration (re-)started: take the first available
212 * device, if exists
213 */
214 found = dev_stor_get(type, 1, &more, di);
215 specs[type].enum_started = 1;
216
217 } else if (dev_is_stor(type, di)) {
218
219 debugf("group%d - enum continued for the next device\n", type);
220
221 if (specs[type].enum_ended) {
222 debugf("group%d - nothing more to enum!\n", type);
223 return 0;
224 }
225
226 /* 2a. Attempt to take a next available device in the group */
227 found = dev_stor_get(type, 0, &more, di);
228
229 } else {
230
231 if (specs[type].enum_ended) {
232 debugf("group %d - already enumerated, skipping\n", type);
233 return 0;
234 }
235
236 debugf("group%d - first time enum\n", type);
237
238 if (specs[type].enum_started == 0) {
239 /*
240 * 2b. If enumerating devices in this group did not
241 * happen before, it means the cookie pointed to a
242 * device frome some other group (another storage
243 * group, or network); in this case try to take the
244 * first available device from our group
245 */
246 specs[type].enum_started = 1;
247
248 /*
249 * Attempt to take the first device in this group:
250 *'first element' flag is set
251 */
252 found = dev_stor_get(type, 1, &more, di);
253
254 } else {
255 errf("group%d - out of order iteration\n", type);
256 found = 0;
257 more = 0;
258 }
259 }
260
261 /*
262 * If there are no more devices in this group, consider its
263 * enumeration finished
264 */
265 specs[type].enum_ended = (!more) ? 1 : 0;
266
267 if (found)
268 debugf("device found, returning cookie 0x%08x\n",
269 (u_int32_t)di->cookie);
270 else
271 debugf("no device found\n");
272
273 return found;
274}
275
276void dev_enum_reset(void)
277{
278 int i;
279
280 for (i = 0; i < ENUM_MAX; i ++) {
281 specs[i].enum_started = 0;
282 specs[i].enum_ended = 0;
283 }
284}
285
286int dev_enum_storage(struct device_info *di)
287{
288 int i;
289
290 /*
291 * check: ide, usb, scsi, mmc
292 */
293 for (i = ENUM_IDE; i < ENUM_MAX; i ++) {
294 if (dev_enum_stor(i, di))
295 return 1;
296 }
297
298 return 0;
299}
300
301static int dev_stor_is_valid(int type, block_dev_desc_t *dd)
302{
303 int i;
304
305 for (i = 0; i < specs[type].max_dev; i++)
306 if (dd == get_dev(specs[type].name, i))
307 if (dd->type != DEV_TYPE_UNKNOWN)
308 return 1;
309
310 return 0;
311}
312
313
314int dev_open_stor(void *cookie)
315{
316 int type = dev_stor_type(cookie);
317
318 if (type == ENUM_MAX)
319 return API_ENODEV;
320
321 if (dev_stor_is_valid(type, (block_dev_desc_t *)cookie))
322 return 0;
323
324 return API_ENODEV;
325}
326
327
328int dev_close_stor(void *cookie)
329{
330 /*
331 * Not much to do as we actually do not alter storage devices upon
332 * close
333 */
334 return 0;
335}
336
337
338static int dev_stor_index(block_dev_desc_t *dd)
339{
340 int i, type;
341
342 type = dev_stor_type(dd);
343 for (i = 0; i < specs[type].max_dev; i++)
344 if (dd == get_dev(specs[type].name, i))
345 return i;
346
347 return (specs[type].max_dev);
348}
349
350
351lbasize_t dev_read_stor(void *cookie, void *buf, lbasize_t len, lbastart_t start)
352{
353 int type;
354 block_dev_desc_t *dd = (block_dev_desc_t *)cookie;
355
356 if ((type = dev_stor_type(dd)) == ENUM_MAX)
357 return 0;
358
359 if (!dev_stor_is_valid(type, dd))
360 return 0;
361
362 if ((dd->block_read) == NULL) {
363 debugf("no block_read() for device 0x%08x\n");
364 return 0;
365 }
366
367 return (dd->block_read(dev_stor_index(dd), start, len, buf));
368}
369
370#endif /* CONFIG_API */