Merge branch 'master' of git://git.denx.de/u-boot-mpc5xxx
[platform/kernel/u-boot.git] / api / api.c
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
59 typedef int (*cfp_t)(va_list argp);
60
61 static int calls_no;
62
63 /*
64  * pseudo signature:
65  *
66  * int API_getc(int *c)
67  */
68 static 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  */
84 static 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  */
100 static 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  */
116 static 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  */
132 static 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  */
148 static 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  */
164 static 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  */
180 static 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
214 static 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
247 static 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
279 static 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  */
331 static 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  */
398 static 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  */
469 static 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  */
492 static 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  */
513 static 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  */
561 static 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  */
577 static 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  */
594 static int API_display_clear(va_list ap)
595 {
596         display_clear();
597         return 0;
598 }
599
600 static 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  */
618 int 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
641 void 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
691 void 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 }