151973Smsmith/******************************************************************************
251973Smsmith *
351973Smsmith * Filename: loader_prompt.c
451973Smsmith *
551973Smsmith * Instantiation of the interactive loader functions.
651973Smsmith *
751973Smsmith * Revision information:
851973Smsmith *
951973Smsmith * 20AUG2004	kb_admin	initial creation
1051973Smsmith * 12JAN2005	kb_admin	massive changes for tftp, strings, and more
1151973Smsmith * 05JUL2005	kb_admin	save tag address, and set registers on boot
1251973Smsmith *
1351973Smsmith * BEGIN_KBDD_BLOCK
1451973Smsmith * No warranty, expressed or implied, is included with this software.  It is
1551973Smsmith * provided "AS IS" and no warranty of any kind including statutory or aspects
1651973Smsmith * relating to merchantability or fitness for any purpose is provided.  All
1751973Smsmith * intellectual property rights of others is maintained with the respective
1851973Smsmith * owners.  This software is not copyrighted and is intended for reference
1951973Smsmith * only.
2051973Smsmith * END_BLOCK
2151973Smsmith *
2251973Smsmith * $FreeBSD: releng/10.2/sys/boot/arm/at91/bootiic/loader_prompt.c 163596 2006-10-21 22:43:39Z imp $
2351973Smsmith *****************************************************************************/
2451973Smsmith
2551973Smsmith#include "at91rm9200_lowlevel.h"
2651973Smsmith#ifdef SUPPORT_TAG_LIST
27119418Sobrien#include "tag_list.h"
28119418Sobrien#endif
29119418Sobrien#include "emac.h"
3051973Smsmith#include "loader_prompt.h"
3151973Smsmith#include "env_vars.h"
32240963Sjhb#include "lib.h"
3351973Smsmith
34240608Sjhb
35129879Sphk/******************************* GLOBALS *************************************/
36240608Sjhb
37240608Sjhb
3851973Smsmith/*********************** PRIVATE FUNCTIONS/DATA ******************************/
3951973Smsmith
4051973Smsmithstatic char	inputBuffer[MAX_INPUT_SIZE];
4151973Smsmithstatic int	buffCount;
4251973Smsmith
4351973Smsmith// argv pointer are either NULL or point to locations in inputBuffer
4451973Smsmithstatic char	*argv[MAX_COMMAND_PARAMS];
4551973Smsmith
46112946Sphkstatic const char *backspaceString = "\010 \010";
47112946Sphk
48119285Simpstatic const command_entry_t	CommandTable[] = {
49119285Simp	{COMMAND_COPY, "c"},
5051973Smsmith	{COMMAND_DUMP, "d"},
5151973Smsmith	{COMMAND_EXEC, "e"},
5251973Smsmith	{COMMAND_HELP, "?"},
5352544Smsmith	{COMMAND_LOCAL_IP, "ip"},
5451973Smsmith	{COMMAND_MAC, "m"},
5551973Smsmith	{COMMAND_SERVER_IP, "server_ip"},
5651973Smsmith	{COMMAND_SET, "s"},
5751973Smsmith#ifdef SUPPORT_TAG_LIST
5851973Smsmith	{COMMAND_TAG, "t"},
5951973Smsmith#endif
6051973Smsmith	{COMMAND_TFTP, "tftp"},
6151973Smsmith	{COMMAND_WRITE, "w"},
6251973Smsmith	{COMMAND_XMODEM, "x"},
6351973Smsmith	{COMMAND_FINAL_FLAG, 0}
6451973Smsmith};
6551973Smsmith
6651973Smsmithstatic unsigned tagAddress;
67227843Smarius
6851973Smsmith/*
6951973Smsmith * .KB_C_FN_DEFINITION_START
7051973Smsmith * unsigned BuildIP(void)
7151973Smsmith *  This private function packs the test IP info to an unsigned value.
7251973Smsmith * .KB_C_FN_DEFINITION_END
7351973Smsmith */
7451973Smsmithstatic unsigned
7551973SmsmithBuildIP(void)
7651973Smsmith{
7751973Smsmith	return ((p_ASCIIToDec(argv[1]) << 24) |
7854419Smsmith	    (p_ASCIIToDec(argv[2]) << 16) |
7951973Smsmith	    (p_ASCIIToDec(argv[3]) << 8) |
8051973Smsmith	    p_ASCIIToDec(argv[4]));
8151973Smsmith}
8254419Smsmith
8354419Smsmith
8451973Smsmith/*
8551973Smsmith * .KB_C_FN_DEFINITION_START
8651973Smsmith * int StringToCommand(char *cPtr)
8758188Smsmith *  This private function converts a command string to a command code.
8854419Smsmith * .KB_C_FN_DEFINITION_END
8954419Smsmith */
9054419Smsmithstatic int
9154419SmsmithStringToCommand(char *cPtr)
9251973Smsmith{
9351973Smsmith	int	i;
94240608Sjhb
95240608Sjhb	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
96240608Sjhb		if (!strcmp(CommandTable[i].c_string, cPtr))
97240608Sjhb			return (CommandTable[i].command);
98240608Sjhb
99240608Sjhb	return (COMMAND_INVALID);
100240608Sjhb}
101240608Sjhb
102240608Sjhb
103240608Sjhb/*
104240608Sjhb * .KB_C_FN_DEFINITION_START
105240608Sjhb * void RestoreSpace(int)
106240608Sjhb *  This private function restores NULL characters to spaces in order to
107240608Sjhb * process the remaining args as a string.  The number passed is the argc
108240608Sjhb * of the first entry to begin restoring space in the inputBuffer.
10951973Smsmith * .KB_C_FN_DEFINITION_END
11051973Smsmith */
11151973Smsmithstatic void
11254419SmsmithRestoreSpace(int startArgc)
11351973Smsmith{
11458188Smsmith	char	*cPtr;
11551973Smsmith
116240608Sjhb	for (startArgc++; startArgc < MAX_COMMAND_PARAMS; startArgc++) {
117240608Sjhb		if ((cPtr = argv[startArgc]))
118240608Sjhb			*(cPtr - 1) = ' ';
119240608Sjhb	}
12051973Smsmith}
12151973Smsmith
12251973Smsmith
12351973Smsmith/*
12451973Smsmith * .KB_C_FN_DEFINITION_START
12551973Smsmith * int BreakCommand(char *)
12651973Smsmith *  This private function splits the buffer into separate strings as pointed
12751973Smsmith * by argv and returns the number of parameters (< 0 on failure).
128240608Sjhb * .KB_C_FN_DEFINITION_END
129240608Sjhb */
13051973Smsmithstatic int
13158188SmsmithBreakCommand(char *buffer)
13251973Smsmith{
133240608Sjhb	int	pCount, cCount, state;
13451973Smsmith
13551973Smsmith	state = pCount = 0;
13651973Smsmith	p_memset((char*)argv, 0, sizeof(argv));
13751973Smsmith
13851973Smsmith	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
13951973Smsmith
14051973Smsmith		if (!state) {
14151973Smsmith			/* look for next command */
142240608Sjhb			if (!p_IsWhiteSpace(buffer[cCount])) {
143240608Sjhb				argv[pCount++] = &buffer[cCount];
14451973Smsmith				state = 1;
145240608Sjhb			} else {
146240608Sjhb				buffer[cCount] = 0;
147240608Sjhb			}
148240608Sjhb		} else {
149240608Sjhb			/* in command, find next white space */
150240608Sjhb			if (p_IsWhiteSpace(buffer[cCount])) {
15151973Smsmith				buffer[cCount] = 0;
15251973Smsmith				state = 0;
15351973Smsmith			}
15451973Smsmith		}
15564223Smsmith
15658188Smsmith		if (pCount >= MAX_COMMAND_PARAMS) {
15758188Smsmith			return (-1);
15858188Smsmith		}
15969292Smdodd	}
16069292Smdodd
161127135Snjl	return (pCount);
162127135Snjl}
16364223Smsmith
16469292Smdodd
16569292Smdodd/*
166127135Snjl * .KB_C_FN_DEFINITION_START
167127135Snjl * void ParseCommand(char *)
16864223Smsmith *  This private function executes matching functions.
16958188Smsmith * .KB_C_FN_DEFINITION_END
17058188Smsmith */
17158188Smsmithstatic void
17269292SmdoddParseCommand(char *buffer)
17369292Smdodd{
174127135Snjl	int		argc, i;
175127135Snjl
17658188Smsmith	if ((argc = BreakCommand(buffer)) < 1)
17758188Smsmith		return;
17851973Smsmith
17951973Smsmith	switch (StringToCommand(argv[0])) {
18051973Smsmith	case COMMAND_COPY:
18151973Smsmith	{
18251973Smsmith		// "c <to> <from> <size in bytes>"
18351973Smsmith		// copy memory
18451973Smsmith		char		*to, *from;
18551973Smsmith		unsigned	size;
18651973Smsmith
187232854Sscottl		if (argc > 3) {
18851973Smsmith			to = (char *)p_ASCIIToHex(argv[1]);
18951973Smsmith			from = (char *)p_ASCIIToHex(argv[2]);
19051973Smsmith			size = p_ASCIIToHex(argv[3]);
19151973Smsmith			memcpy(to, from, size);
19260074Smsmith		}
19351973Smsmith		break;
19451973Smsmith	}
195117126Sscottl
196117126Sscottl	case COMMAND_DUMP:
19751973Smsmith		// display boot commands
19851973Smsmith		DumpBootCommands();
19951973Smsmith		break;
20051973Smsmith
20151973Smsmith	case COMMAND_EXEC:
20251973Smsmith	{
20351973Smsmith		// "e <address>"
20451973Smsmith		// execute at address
20551973Smsmith		void (*execAddr)(unsigned, unsigned, unsigned);
20651973Smsmith
20751973Smsmith		if (argc > 1) {
208148570Scsjp			/* in future, include machtypes (MACH_KB9200 = 612) */
209144161Sphk			execAddr = (void (*)(unsigned, unsigned, unsigned))
21051973Smsmith			  p_ASCIIToHex(argv[1]);
211148570Scsjp			(*execAddr)(0, 612, tagAddress);
21251973Smsmith		}
21351973Smsmith		break;
21451973Smsmith	}
21551973Smsmith
21651973Smsmith	case COMMAND_TFTP:
21751973Smsmith	{
21851973Smsmith		// "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