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$
23 *****************************************************************************/
24
25#include "at91rm9200_lowlevel.h"
26#include "at91rm9200.h"
27#include "emac.h"
28#include "loader_prompt.h"
29#include "env_vars.h"
30#include "lib.h"
31#include "spi_flash.h"
32#include "ee.h"
33
34/******************************* GLOBALS *************************************/
35
36
37/*********************** PRIVATE FUNCTIONS/DATA ******************************/
38
39static char	inputBuffer[MAX_INPUT_SIZE];
40static int	buffCount;
41
42// argv pointer are either NULL or point to locations in inputBuffer
43static char	*argv[MAX_COMMAND_PARAMS];
44
45#define FLASH_OFFSET (0 * FLASH_PAGE_SIZE)
46#define KERNEL_OFFSET (220 * FLASH_PAGE_SIZE)
47#define KERNEL_LEN (6 * 1024 * FLASH_PAGE_SIZE)
48static const char *backspaceString = "\010 \010";
49
50static const command_entry_t	CommandTable[] = {
51	{COMMAND_DUMP, "d"},
52	{COMMAND_EXEC, "e"},
53	{COMMAND_LOCAL_IP, "ip"},
54	{COMMAND_MAC, "m"},
55	{COMMAND_SERVER_IP, "server_ip"},
56	{COMMAND_TFTP, "tftp"},
57	{COMMAND_XMODEM, "x"},
58	{COMMAND_RESET, "R"},
59	{COMMAND_LOAD_SPI_KERNEL, "k"},
60	{COMMAND_REPLACE_KERNEL_VIA_XMODEM, "K"},
61	{COMMAND_REPLACE_FLASH_VIA_XMODEM, "I"},
62	{COMMAND_REPLACE_ID_EEPROM, "E"},
63	{COMMAND_FINAL_FLAG, 0}
64};
65
66/*
67 * .KB_C_FN_DEFINITION_START
68 * unsigned BuildIP(void)
69 *  This private function packs the test IP info to an unsigned value.
70 * .KB_C_FN_DEFINITION_END
71 */
72static unsigned
73BuildIP(void)
74{
75	return ((p_ASCIIToDec(argv[1]) << 24) |
76	    (p_ASCIIToDec(argv[2]) << 16) |
77	    (p_ASCIIToDec(argv[3]) << 8) |
78	    p_ASCIIToDec(argv[4]));
79}
80
81
82/*
83 * .KB_C_FN_DEFINITION_START
84 * int StringToCommand(char *cPtr)
85 *  This private function converts a command string to a command code.
86 * .KB_C_FN_DEFINITION_END
87 */
88static int
89StringToCommand(char *cPtr)
90{
91	int	i;
92
93	for (i = 0; CommandTable[i].command != COMMAND_FINAL_FLAG; ++i)
94		if (!strcmp(CommandTable[i].c_string, cPtr))
95			return (CommandTable[i].command);
96
97	return (COMMAND_INVALID);
98}
99
100
101/*
102 * .KB_C_FN_DEFINITION_START
103 * int BreakCommand(char *)
104 *  This private function splits the buffer into separate strings as pointed
105 * by argv and returns the number of parameters (< 0 on failure).
106 * .KB_C_FN_DEFINITION_END
107 */
108static int
109BreakCommand(char *buffer)
110{
111	int	pCount, cCount, state;
112
113	state = pCount = 0;
114	p_memset((char*)argv, 0, sizeof(argv));
115
116	for (cCount = 0; cCount < MAX_INPUT_SIZE; ++cCount) {
117
118		if (!state) {
119			/* look for next command */
120			if (!p_IsWhiteSpace(buffer[cCount])) {
121				argv[pCount++] = &buffer[cCount];
122				state = 1;
123			} else {
124				buffer[cCount] = 0;
125			}
126		} else {
127			/* in command, find next white space */
128			if (p_IsWhiteSpace(buffer[cCount])) {
129				buffer[cCount] = 0;
130				state = 0;
131			}
132		}
133
134		if (pCount >= MAX_COMMAND_PARAMS) {
135			return (-1);
136		}
137	}
138
139	return (pCount);
140}
141
142#if 0
143static void
144UpdateEEProm(int eeaddr)
145{
146	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
147	int len;
148
149	while ((len = xmodem_rx(addr)) == -1)
150		continue;
151	printf("\nDownloaded %u bytes.\n", len);
152	WriteEEPROM(eeaddr, 0, addr, len);
153}
154#endif
155
156static void
157UpdateFlash(int offset)
158{
159	char *addr = (char *)SDRAM_BASE + (1 << 20); /* Load to base + 1MB */
160	int len, i, off;
161
162	while ((len = xmodem_rx(addr)) == -1)
163		continue;
164	printf("\nDownloaded %u bytes.\n", len);
165	for (i = 0; i < len; i+= FLASH_PAGE_SIZE) {
166		off = i + offset;
167		SPI_WriteFlash(off, addr + i, FLASH_PAGE_SIZE);
168	}
169}
170
171static void
172LoadKernelFromSpi(char *addr)
173{
174	int i, off;
175
176	for (i = 0; i < KERNEL_LEN; i+= FLASH_PAGE_SIZE) {
177		off = i + KERNEL_OFFSET;
178		SPI_ReadFlash(off, addr + i, FLASH_PAGE_SIZE);
179	}
180}
181
182/*
183 * .KB_C_FN_DEFINITION_START
184 * void ParseCommand(char *)
185 *  This private function executes matching functions.
186 * .KB_C_FN_DEFINITION_END
187 */
188static void
189ParseCommand(char *buffer)
190{
191	int		argc, i;
192
193	if ((argc = BreakCommand(buffer)) < 1)
194		return;
195
196	switch (StringToCommand(argv[0])) {
197	case COMMAND_DUMP:
198		// display boot commands
199		DumpBootCommands();
200		break;
201
202	case COMMAND_EXEC:
203	{
204		// "e <address>"
205		// execute at address
206		void (*execAddr)(unsigned, unsigned);
207
208		if (argc > 1) {
209			/* in future, include machtypes (MACH_KB9200 = 612) */
210			execAddr = (void (*)(unsigned, unsigned))
211			    p_ASCIIToHex(argv[1]);
212			(*execAddr)(0, 612);
213		}
214		break;
215	}
216
217	case COMMAND_TFTP:
218	{
219		// "tftp <local_dest_addr filename>"
220		//  tftp download
221		unsigned address = 0;
222
223		if (argc > 2)
224			address = p_ASCIIToHex(argv[1]);
225		TFTP_Download(address, argv[2]);
226		break;
227	}
228
229	case COMMAND_SERVER_IP:
230		// "server_ip <server IP 192 200 1 20>"
231		// set download server address
232		if (argc > 4)
233			SetServerIPAddress(BuildIP());
234		break;
235
236	case COMMAND_LOCAL_IP:
237		// "local_ip <local IP 192 200 1 21>
238		// set ip of this module
239		if (argc > 4)
240			SetLocalIPAddress(BuildIP());
241		break;
242
243	case COMMAND_MAC:
244	{
245		// "m <mac address 12 34 56 78 9a bc>
246		// set mac address using 6 byte values
247		unsigned char mac[6];
248
249		if (argc > 6) {
250			for (i = 0; i < 6; i++)
251				mac[i] = p_ASCIIToHex(argv[i + 1]);
252			EMAC_SetMACAddress(mac);
253		}
254		break;
255	}
256
257	case COMMAND_LOAD_SPI_KERNEL:
258		// "k <address>"
259		if (argc > 1)
260			LoadKernelFromSpi((char *)p_ASCIIToHex(argv[1]));
261		break;
262
263	case COMMAND_XMODEM:
264		// "x <address>"
265		// download X-modem record at address
266		if (argc > 1)
267			xmodem_rx((char *)p_ASCIIToHex(argv[1]));
268		break;
269
270	case COMMAND_RESET:
271		printf("Reset\n");
272		reset();
273		while (1) continue;
274		break;
275
276	case COMMAND_REPLACE_KERNEL_VIA_XMODEM:
277		printf("Updating KERNEL image\n");
278		UpdateFlash(KERNEL_OFFSET);
279		break;
280	case COMMAND_REPLACE_FLASH_VIA_XMODEM:
281		printf("Updating FLASH image\n");
282		UpdateFlash(FLASH_OFFSET);
283		break;
284
285	case COMMAND_REPLACE_ID_EEPROM:
286	{
287	    char buf[25];
288		printf("Testing Config EEPROM\n");
289		EEWrite(0, "This is a test", 15);
290		EERead(0, buf, 15);
291		printf("Found '%s'\n", buf);
292		break;
293	}
294	default:
295		break;
296	}
297
298	printf("\n");
299}
300
301
302/*
303 * .KB_C_FN_DEFINITION_START
304 * void ServicePrompt(char)
305 *  This private function process each character checking for valid commands.
306 * This function is only executed if the character is considered valid.
307 * Each command is terminated with NULL (0) or ''.
308 * .KB_C_FN_DEFINITION_END
309 */
310static void
311ServicePrompt(char p_char)
312{
313	if (p_char == '\r')
314		p_char = 0;
315
316	if (p_char == '\010') {
317		if (buffCount) {
318			/* handle backspace BS */
319			inputBuffer[--buffCount] = 0;
320			printf(backspaceString);
321		}
322		return;
323	}
324	if (buffCount < MAX_INPUT_SIZE - 1) {
325		inputBuffer[buffCount++] = p_char;
326		putchar(p_char);
327	}
328	if (!p_char) {
329		printf("\n");
330		ParseCommand(inputBuffer);
331		p_memset(inputBuffer, 0, MAX_INPUT_SIZE);
332		buffCount = 0;
333		printf("\n>");
334	}
335}
336
337
338/* ************************** GLOBAL FUNCTIONS ********************************/
339
340
341/*
342 * .KB_C_FN_DEFINITION_START
343 * void Bootloader(void *inputFunction)
344 *  This global function is the entry point for the bootloader.  If the
345 * inputFunction pointer is NULL, the loader input will be serviced from
346 * the uart.  Otherwise, inputFunction is called to get characters which
347 * the loader will parse.
348 * .KB_C_FN_DEFINITION_END
349 */
350void
351Bootloader(int(*inputFunction)(int))
352{
353	int	ch = 0;
354
355	p_memset((void*)inputBuffer, 0, sizeof(inputBuffer));
356	buffCount = 0;
357
358	printf("\n>");
359
360	while (1)
361		if ((ch = ((*inputFunction)(0))) > 0)
362			ServicePrompt(ch);
363}
364