1/******************************************************************************
2 *
3 * Filename: loader_prompt.c
4 *
5 * Instantiation of the interactive loader functions.
6 *
7 * Revision information:
8 *
9 * 20AUG2004	kb_admin	initial creation
10 * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
11 * 05JUL2005	kb_admin	save tag address, and set registers on boot
12 *
13 * BEGIN_KBDD_BLOCK
14 * No warranty, expressed or implied, is included with this software.  It is
15 * provided "AS IS" and no warranty of any kind including statutory or aspects
16 * relating to merchantability or fitness for any purpose is provided.  All
17 * intellectual property rights of others is maintained with the respective
18 * owners.  This software is not copyrighted and is intended for reference
19 * only.
20 * END_BLOCK
21 *
22 * $FreeBSD: releng/11.0/sys/boot/arm/at91/bootiic/loader_prompt.c 163596 2006-10-21 22:43:39Z imp $
23 *****************************************************************************/
24
25#include "at91rm9200_lowlevel.h"
26#ifdef SUPPORT_TAG_LIST
27#include "tag_list.h"
28#endif
29#include "emac.h"
30#include "loader_prompt.h"
31#include "env_vars.h"
32#include "lib.h"
33
34
35/******************************* GLOBALS *************************************/
36
37
38/*********************** PRIVATE FUNCTIONS/DATA ******************************/
39
40static char	inputBuffer[MAX_INPUT_SIZE];
41static int	buffCount;
42
43// argv pointer are either NULL or point to locations in inputBuffer
44static char	*argv[MAX_COMMAND_PARAMS];
45
46static const char *backspaceString = "\010 \010";
47
48static const command_entry_t	CommandTable[] = {
49	{COMMAND_COPY, "c"},
50	{COMMAND_DUMP, "d"},
51	{COMMAND_EXEC, "e"},
52	{COMMAND_HELP, "?"},
53	{COMMAND_LOCAL_IP, "ip"},
54	{COMMAND_MAC, "m"},
55	{COMMAND_SERVER_IP, "server_ip"},
56	{COMMAND_SET, "s"},
57#ifdef SUPPORT_TAG_LIST
58	{COMMAND_TAG, "t"},
59#endif
60	{COMMAND_TFTP, "tftp"},
61	{COMMAND_WRITE, "w"},
62	{COMMAND_XMODEM, "x"},
63	{COMMAND_FINAL_FLAG, 0}
64};
65
66static unsigned tagAddress;
67
68/*
69 * .KB_C_FN_DEFINITION_START
70 * unsigned BuildIP(void)
71 *  This private function packs the test IP info to an unsigned value.
72 * .KB_C_FN_DEFINITION_END
73 */
74static unsigned
75BuildIP(void)
76{
77	return ((p_ASCIIToDec(argv[1]) << 24) |
78	    (p_ASCIIToDec(argv[2]) << 16) |
79	    (p_ASCIIToDec(argv[3]) << 8) |
80	    p_ASCIIToDec(argv[4]));
81}
82
83
84/*
85 * .KB_C_FN_DEFINITION_START
86 * int StringToCommand(char *cPtr)
87 *  This private function converts a command string to a command code.
88 * .KB_C_FN_DEFINITION_END
89 */
90static int
91StringToCommand(char *cPtr)
92{
93	int	i;
94
95	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
96		if (!strcmp(CommandTable[i].c_string, cPtr))
97			return (CommandTable[i].command);
98
99	return (COMMAND_INVALID);
100}
101
102
103/*
104 * .KB_C_FN_DEFINITION_START
105 * void RestoreSpace(int)
106 *  This private function restores NULL characters to spaces in order to
107 * process the remaining args as a string.  The number passed is the argc
108 * of the first entry to begin restoring space in the inputBuffer.
109 * .KB_C_FN_DEFINITION_END
110 */
111static void
112RestoreSpace(int startArgc)
113{
114	char	*cPtr;
115
116	for (startArgc++; startArgc < MAX_COMMAND_PARAMS; startArgc++) {
117		if ((cPtr = argv[startArgc]))
118			*(cPtr - 1) = ' ';
119	}
120}
121
122
123/*
124 * .KB_C_FN_DEFINITION_START
125 * int BreakCommand(char *)
126 *  This private function splits the buffer into separate strings as pointed
127 * by argv and returns the number of parameters (< 0 on failure).
128 * .KB_C_FN_DEFINITION_END
129 */
130static int
131BreakCommand(char *buffer)
132{
133	int	pCount, cCount, state;
134
135	state = pCount = 0;
136	p_memset((char*)argv, 0, sizeof(argv));
137
138	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
139
140		if (!state) {
141			/* look for next command */
142			if (!p_IsWhiteSpace(buffer[cCount])) {
143				argv[pCount++] = &buffer[cCount];
144				state = 1;
145			} else {
146				buffer[cCount] = 0;
147			}
148		} else {
149			/* in command, find next white space */
150			if (p_IsWhiteSpace(buffer[cCount])) {
151				buffer[cCount] = 0;
152				state = 0;
153			}
154		}
155
156		if (pCount >= MAX_COMMAND_PARAMS) {
157			return (-1);
158		}
159	}
160
161	return (pCount);
162}
163
164
165/*
166 * .KB_C_FN_DEFINITION_START
167 * void ParseCommand(char *)
168 *  This private function executes matching functions.
169 * .KB_C_FN_DEFINITION_END
170 */
171static void
172ParseCommand(char *buffer)
173{
174	int		argc, i;
175
176	if ((argc = BreakCommand(buffer)) < 1)
177		return;
178
179	switch (StringToCommand(argv[0])) {
180	case COMMAND_COPY:
181	{
182		// "c <to> <from> <size in bytes>"
183		// copy memory
184		char		*to, *from;
185		unsigned	size;
186
187		if (argc > 3) {
188			to = (char *)p_ASCIIToHex(argv[1]);
189			from = (char *)p_ASCIIToHex(argv[2]);
190			size = p_ASCIIToHex(argv[3]);
191			memcpy(to, from, size);
192		}
193		break;
194	}
195
196	case COMMAND_DUMP:
197		// display boot commands
198		DumpBootCommands();
199		break;
200
201	case COMMAND_EXEC:
202	{
203		// "e <address>"
204		// execute at address
205		void (*execAddr)(unsigned, unsigned, unsigned);
206
207		if (argc > 1) {
208			/* in future, include machtypes (MACH_KB9200 = 612) */
209			execAddr = (void (*)(unsigned, unsigned, unsigned))
210			  p_ASCIIToHex(argv[1]);
211			(*execAddr)(0, 612, tagAddress);
212		}
213		break;
214	}
215
216	case COMMAND_TFTP:
217	{
218		// "tftp <local_dest_addr filename>"
219		//  tftp download
220		unsigned address = 0;
221
222		if (argc > 2)
223			address = p_ASCIIToHex(argv[1]);
224		TFTP_Download(address, argv[2]);
225		break;
226	}
227
228	case COMMAND_SERVER_IP:
229		// "server_ip <server IP 192 200 1 20>"
230		// set download server address
231		if (argc > 4)
232			SetServerIPAddress(BuildIP());
233		break;
234
235	case COMMAND_HELP:
236		// dump command info
237		printf("Commands:\n"
238		"\tc\n"
239		"\td\n"
240		"\te\n"
241		"\tip\n"
242		"\tserver_ip\n"
243		"\tm\n"
244		"\ttftp\n"
245		"\ts\n"
246#ifdef SUPPORT_TAG_LIST
247		"\tt\n"
248#endif
249		"\tw\n"
250		"\tx\n");
251		break;
252
253	case COMMAND_LOCAL_IP:
254		// "local_ip <local IP 192 200 1 21>
255		// set ip of this module
256		if (argc > 4)
257			SetLocalIPAddress(BuildIP());
258		break;
259
260	case COMMAND_MAC:
261	{
262		// "m <mac address 12 34 56 78 9a bc>
263		// set mac address using 6 byte values
264		unsigned char mac[6];
265
266		if (argc > 6) {
267			for (i = 0; i < 6; i++)
268				mac[i] = p_ASCIIToHex(argv[i + 1]);
269			EMAC_SetMACAddress(mac);
270		}
271		break;
272	}
273
274	case COMMAND_SET:
275	{
276		// s <index> <new boot command>
277		// set the boot command at index (0-based)
278		unsigned	index;
279
280		if (argc > 1) {
281			RestoreSpace(2);
282			index = p_ASCIIToHex(argv[1]);
283			SetBootCommand(index, argv[2]);
284		}
285		break;
286	}
287
288#ifdef SUPPORT_TAG_LIST
289	case COMMAND_TAG:
290		// t <address> <boot command line>
291		// create tag-list for linux boot
292		if (argc > 2) {
293			RestoreSpace(2);
294			tagAddress = p_ASCIIToHex(argv[1]);
295			InitTagList(argv[2], (void*)tagAddress);
296		}
297		break;
298#endif
299
300	case COMMAND_WRITE:
301		// write the command table to non-volatile
302		WriteCommandTable();
303		break;
304
305	case COMMAND_XMODEM:
306	{
307		// "x <address>"
308		// download X-modem record at address
309		if (argc > 1)
310			xmodem_rx((char *)p_ASCIIToHex(argv[1]));
311		break;
312	}
313
314	default:
315		break;
316	}
317
318	printf("\n");
319}
320
321
322/*
323 * .KB_C_FN_DEFINITION_START
324 * void ServicePrompt(char)
325 *  This private function process each character checking for valid commands.
326 * This function is only executed if the character is considered valid.
327 * Each command is terminated with NULL (0) or ''.
328 * .KB_C_FN_DEFINITION_END
329 */
330static void
331ServicePrompt(char p_char)
332{
333	if (p_char == '\r')
334		p_char = 0;
335
336	if (p_char == '\010') {
337		if (buffCount) {
338			/* handle backspace BS */
339			inputBuffer[--buffCount] = 0;
340			printf(backspaceString);
341		}
342		return;
343	}
344	if (buffCount < MAX_INPUT_SIZE - 1) {
345		inputBuffer[buffCount++] = p_char;
346		putchar(p_char);
347	}
348	if (!p_char) {
349		printf("\n");
350		ParseCommand(inputBuffer);
351		p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
352		buffCount = 0;
353		printf("\n>");
354	}
355}
356
357
358/* ************************** GLOBAL FUNCTIONS ********************************/
359
360
361/*
362 * .KB_C_FN_DEFINITION_START
363 * void Bootloader(void *inputFunction)
364 *  This global function is the entry point for the bootloader.  If the
365 * inputFunction pointer is NULL, the loader input will be serviced from
366 * the uart.  Otherwise, inputFunction is called to get characters which
367 * the loader will parse.
368 * .KB_C_FN_DEFINITION_END
369 */
370void
371Bootloader(int(*inputFunction)(int))
372{
373	int	ch = 0;
374
375	p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
376
377	buffCount = 0;
378	if (!inputFunction) {
379		inputFunction = getc;
380	}
381
382	printf("\n>");
383
384	while (1)
385		if ((ch = ((*inputFunction)(0))) > 0)
386			ServicePrompt(ch);
387}
388