1/*-
2 * Copyright (c) 2007-2008 Semihalf, Rafal Jaworowski <raj@semihalf.com>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/types.h>
28
29#include <zlib.h>
30#include <stand.h>
31#include "api_public.h"
32#include "glue.h"
33
34#ifdef DEBUG
35#define	debugf(fmt, args...) do { printf("%s(): ", __func__); printf(fmt,##args); } while (0)
36#else
37#define	debugf(fmt, args...)
38#endif
39
40/* Some random address used by U-Boot. */
41extern long uboot_address;
42
43static int
44valid_sig(struct api_signature *sig)
45{
46	uint32_t checksum;
47	struct api_signature s;
48
49	if (sig == NULL)
50		return (0);
51	/*
52	 * Clear the checksum field (in the local copy) so as to calculate the
53	 * CRC with the same initial contents as at the time when the sig was
54	 * produced
55	 */
56	s = *sig;
57	s.checksum = crc32(0, Z_NULL, 0);
58
59	checksum = crc32(s.checksum, (void *)&s, sizeof(struct api_signature));
60
61	if (checksum != sig->checksum)
62		return (0);
63
64	return (1);
65}
66
67/*
68 * Checks to see if API signature's address was given to us as a command line
69 * argument by U-Boot.
70 *
71 * returns 1/0 depending on found/not found result
72 */
73int
74api_parse_cmdline_sig(int argc, char **argv, struct api_signature **sig)
75{
76	unsigned long api_address;
77	int c;
78
79	api_address = 0;
80	opterr = 0;
81	optreset = 1;
82	optind = 1;
83
84	while ((c = getopt (argc, argv, "a:")) != -1)
85		switch (c) {
86		case 'a':
87			api_address = strtoul(optarg, NULL, 16);
88			break;
89		default:
90			break;
91		}
92
93	if (api_address != 0) {
94		*sig = (struct api_signature *)api_address;
95		if (valid_sig(*sig))
96			return (1);
97	}
98
99	return (0);
100}
101
102/*
103 * Searches for the U-Boot API signature
104 *
105 * returns 1/0 depending on found/not found result
106 */
107int
108api_search_sig(struct api_signature **sig)
109{
110	unsigned char *sp, *spend;
111
112	if (sig == NULL)
113		return (0);
114
115	if (uboot_address == 0)
116		uboot_address = 255 * 1024 * 1024;
117
118	sp = (void *)(uboot_address & API_SIG_SEARCH_MASK);
119	spend = sp + API_SIG_SEARCH_LEN - API_SIG_MAGLEN;
120
121	while (sp < spend) {
122		if (!bcmp(sp, API_SIG_MAGIC, API_SIG_MAGLEN)) {
123			*sig = (struct api_signature *)sp;
124			if (valid_sig(*sig))
125				return (1);
126		}
127		sp += API_SIG_MAGLEN;
128	}
129
130	*sig = NULL;
131	return (0);
132}
133
134/****************************************
135 *
136 * console
137 *
138 ****************************************/
139
140int
141ub_getc(void)
142{
143	int c;
144
145	if (!syscall(API_GETC, NULL, &c))
146		return (-1);
147
148	return (c);
149}
150
151int
152ub_tstc(void)
153{
154	int t;
155
156	if (!syscall(API_TSTC, NULL, &t))
157		return (-1);
158
159	return (t);
160}
161
162void
163ub_putc(const char c)
164{
165
166	syscall(API_PUTC, NULL, &c);
167}
168
169void
170ub_puts(const char *s)
171{
172
173	syscall(API_PUTS, NULL, s);
174}
175
176/****************************************
177 *
178 * system
179 *
180 ****************************************/
181
182void
183ub_reset(void)
184{
185
186	syscall(API_RESET, NULL);
187	while (1);	/* fallback if API_RESET failed */
188	__unreachable();
189}
190
191static struct mem_region mr[UB_MAX_MR];
192static struct sys_info si;
193
194struct sys_info *
195ub_get_sys_info(void)
196{
197	int err = 0;
198
199	memset(&si, 0, sizeof(struct sys_info));
200	si.mr = mr;
201	si.mr_no = UB_MAX_MR;
202	memset(&mr, 0, sizeof(mr));
203
204	if (!syscall(API_GET_SYS_INFO, &err, &si))
205		return (NULL);
206
207	return ((err) ? NULL : &si);
208}
209
210/****************************************
211 *
212 * timing
213 *
214 ****************************************/
215
216void
217ub_udelay(unsigned long usec)
218{
219
220	syscall(API_UDELAY, NULL, &usec);
221}
222
223unsigned long
224ub_get_timer(unsigned long base)
225{
226	unsigned long cur;
227
228	if (!syscall(API_GET_TIMER, NULL, &cur, &base))
229		return (0);
230
231	return (cur);
232}
233
234/****************************************************************************
235 *
236 * devices
237 *
238 * Devices are identified by handles: numbers 0, 1, 2, ..., UB_MAX_DEV-1
239 *
240 ***************************************************************************/
241
242static struct device_info devices[UB_MAX_DEV];
243
244struct device_info *
245ub_dev_get(int i)
246{
247
248	return ((i < 0 || i >= UB_MAX_DEV) ? NULL : &devices[i]);
249}
250
251/*
252 * Enumerates the devices: fills out device_info elements in the devices[]
253 * array.
254 *
255 * returns:		number of devices found
256 */
257int
258ub_dev_enum(void)
259{
260	struct device_info *di;
261	int n = 0;
262
263	memset(&devices, 0, sizeof(struct device_info) * UB_MAX_DEV);
264	di = &devices[0];
265
266	if (!syscall(API_DEV_ENUM, NULL, di))
267		return (0);
268
269	while (di->cookie != NULL) {
270
271		if (++n >= UB_MAX_DEV)
272			break;
273
274		/* take another device_info */
275		di++;
276
277		/* pass on the previous cookie */
278		di->cookie = devices[n - 1].cookie;
279
280		if (!syscall(API_DEV_ENUM, NULL, di))
281			return (0);
282	}
283
284	return (n);
285}
286
287/*
288 * handle:	0-based id of the device
289 *
290 * returns:	0 when OK, err otherwise
291 */
292int
293ub_dev_open(int handle)
294{
295	struct device_info *di;
296	int err = 0;
297
298	if (handle < 0 || handle >= UB_MAX_DEV)
299		return (API_EINVAL);
300
301	di = &devices[handle];
302	if (!syscall(API_DEV_OPEN, &err, di))
303		return (-1);
304
305	return (err);
306}
307
308int
309ub_dev_close(int handle)
310{
311	struct device_info *di;
312
313	if (handle < 0 || handle >= UB_MAX_DEV)
314		return (API_EINVAL);
315
316	di = &devices[handle];
317	if (!syscall(API_DEV_CLOSE, NULL, di))
318		return (-1);
319
320	return (0);
321}
322
323/*
324 * Validates device for read/write, it has to:
325 *
326 * - have sane handle
327 * - be opened
328 *
329 * returns:	0/1 accordingly
330 */
331static int
332dev_valid(int handle)
333{
334
335	if (handle < 0 || handle >= UB_MAX_DEV)
336		return (0);
337
338	if (devices[handle].state != DEV_STA_OPEN)
339		return (0);
340
341	return (1);
342}
343
344static int
345dev_stor_valid(int handle)
346{
347
348	if (!dev_valid(handle))
349		return (0);
350
351	if (!(devices[handle].type & DEV_TYP_STOR))
352		return (0);
353
354	return (1);
355}
356
357int
358ub_dev_read(int handle, void *buf, lbasize_t len, lbastart_t start,
359    lbasize_t *rlen)
360{
361	struct device_info *di;
362	lbasize_t act_len;
363	int err = 0;
364
365	if (!dev_stor_valid(handle))
366		return (API_ENODEV);
367
368	di = &devices[handle];
369	if (!syscall(API_DEV_READ, &err, di, buf, &len, &start, &act_len))
370		return (API_ESYSC);
371
372	if (!err && rlen)
373		*rlen = act_len;
374
375	return (err);
376}
377
378static int
379dev_net_valid(int handle)
380{
381
382	if (!dev_valid(handle))
383		return (0);
384
385	if (devices[handle].type != DEV_TYP_NET)
386		return (0);
387
388	return (1);
389}
390
391int
392ub_dev_recv(int handle, void *buf, int len, int *rlen)
393{
394	struct device_info *di;
395	int err = 0, act_len;
396
397	if (!dev_net_valid(handle))
398		return (API_ENODEV);
399
400	di = &devices[handle];
401	if (!syscall(API_DEV_READ, &err, di, buf, &len, &act_len))
402		return (API_ESYSC);
403
404	if (!err)
405		*rlen = act_len;
406
407	return (err);
408}
409
410int
411ub_dev_send(int handle, void *buf, int len)
412{
413	struct device_info *di;
414	int err = 0;
415
416	if (!dev_net_valid(handle))
417		return (API_ENODEV);
418
419	di = &devices[handle];
420	if (!syscall(API_DEV_WRITE, &err, di, buf, &len))
421		return (API_ESYSC);
422
423	return (err);
424}
425
426char *
427ub_stor_type(int type)
428{
429
430	if (type & DT_STOR_IDE)
431		return ("IDE");
432
433	if (type & DT_STOR_SCSI)
434		return ("SCSI");
435
436	if (type & DT_STOR_USB)
437		return ("USB");
438
439	if (type & DT_STOR_MMC)
440		return ("MMC");
441
442	if (type & DT_STOR_SATA)
443		return ("SATA");
444
445	return ("Unknown");
446}
447
448char *
449ub_mem_type(int flags)
450{
451
452	switch (flags & 0x000F) {
453	case MR_ATTR_FLASH:
454		return ("FLASH");
455	case MR_ATTR_DRAM:
456		return ("DRAM");
457	case MR_ATTR_SRAM:
458		return ("SRAM");
459	default:
460		return ("Unknown");
461	}
462}
463
464void
465ub_dump_di(int handle)
466{
467	struct device_info *di = ub_dev_get(handle);
468	int i;
469
470	printf("device info (%d):\n", handle);
471	printf("  cookie\t= %p\n", di->cookie);
472	printf("  type\t\t= 0x%08x\n", di->type);
473
474	if (di->type == DEV_TYP_NET) {
475		printf("  hwaddr\t= ");
476		for (i = 0; i < 6; i++)
477			printf("%02x ", di->di_net.hwaddr[i]);
478
479		printf("\n");
480
481	} else if (di->type & DEV_TYP_STOR) {
482		printf("  type\t\t= %s\n", ub_stor_type(di->type));
483		printf("  blk size\t\t= %ld\n", di->di_stor.block_size);
484		printf("  blk count\t\t= %ld\n", di->di_stor.block_count);
485	}
486}
487
488void
489ub_dump_si(struct sys_info *si)
490{
491	int i;
492
493	printf("sys info:\n");
494	printf("  clkbus\t= %ld MHz\n", si->clk_bus / 1000 / 1000);
495	printf("  clkcpu\t= %ld MHz\n", si->clk_cpu / 1000 / 1000);
496	printf("  bar\t\t= 0x%08lx\n", si->bar);
497
498	printf("---\n");
499	for (i = 0; i < si->mr_no; i++) {
500		if (si->mr[i].flags == 0)
501			break;
502
503		printf("  start\t= 0x%08lx\n", si->mr[i].start);
504		printf("  size\t= 0x%08lx\n", si->mr[i].size);
505		printf("  type\t= %s\n", ub_mem_type(si->mr[i].flags));
506		printf("---\n");
507	}
508}
509
510/****************************************
511 *
512 * env vars
513 *
514 ****************************************/
515
516char *
517ub_env_get(const char *name)
518{
519	char *value;
520
521	if (!syscall(API_ENV_GET, NULL, name, &value))
522		return (NULL);
523
524	return (value);
525}
526
527void
528ub_env_set(const char *name, char *value)
529{
530
531	syscall(API_ENV_SET, NULL, name, value);
532}
533
534static char env_name[256];
535
536const char *
537ub_env_enum(const char *last)
538{
539	const char *env, *str;
540	int i;
541
542	/*
543	 * It's OK to pass only the name piece as last (and not the whole
544	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
545	 * internally, which handles such case
546	 */
547	env = NULL;
548	if (!syscall(API_ENV_ENUM, NULL, last, &env))
549		return (NULL);
550
551	if (env == NULL || last == env)
552		/* no more env. variables to enumerate */
553		return (NULL);
554
555	/* next enumerated env var */
556	memset(env_name, 0, 256);
557	for (i = 0, str = env; *str != '=' && *str != '\0';)
558		env_name[i++] = *str++;
559
560	env_name[i] = '\0';
561
562	return (env_name);
563}
564