105 lines
		
	
	
	
		
			2.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			105 lines
		
	
	
	
		
			2.4 KiB
			
		
	
	
	
		
			C
		
	
	
	
	
	
|   | /*
 | ||
|  |  * A udbg backend which logs messages and reads input from in memory | ||
|  |  * buffers. | ||
|  |  * | ||
|  |  * The console output can be read from memcons_output which is a | ||
|  |  * circular buffer whose next write position is stored in memcons.output_pos. | ||
|  |  * | ||
|  |  * Input may be passed by writing into the memcons_input buffer when it is | ||
|  |  * empty. The input buffer is empty when both input_pos == input_start and | ||
|  |  * *input_start == '\0'. | ||
|  |  * | ||
|  |  * Copyright (C) 2003-2005 Anton Blanchard and Milton Miller, IBM Corp | ||
|  |  * Copyright (C) 2013 Alistair Popple, IBM Corp | ||
|  |  * | ||
|  |  *      This program is free software; you can redistribute it and/or | ||
|  |  *      modify it under the terms of the GNU General Public License | ||
|  |  *      as published by the Free Software Foundation; either version | ||
|  |  *      2 of the License, or (at your option) any later version. | ||
|  |  */ | ||
|  | 
 | ||
|  | #include <linux/kernel.h>
 | ||
|  | #include <asm/barrier.h>
 | ||
|  | #include <asm/page.h>
 | ||
|  | #include <asm/processor.h>
 | ||
|  | #include <asm/udbg.h>
 | ||
|  | 
 | ||
|  | struct memcons { | ||
|  | 	char *output_start; | ||
|  | 	char *output_pos; | ||
|  | 	char *output_end; | ||
|  | 	char *input_start; | ||
|  | 	char *input_pos; | ||
|  | 	char *input_end; | ||
|  | }; | ||
|  | 
 | ||
|  | static char memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE]; | ||
|  | static char memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE]; | ||
|  | 
 | ||
|  | struct memcons memcons = { | ||
|  | 	.output_start = memcons_output, | ||
|  | 	.output_pos = memcons_output, | ||
|  | 	.output_end = &memcons_output[CONFIG_PPC_MEMCONS_OUTPUT_SIZE], | ||
|  | 	.input_start = memcons_input, | ||
|  | 	.input_pos = memcons_input, | ||
|  | 	.input_end = &memcons_input[CONFIG_PPC_MEMCONS_INPUT_SIZE], | ||
|  | }; | ||
|  | 
 | ||
|  | void memcons_putc(char c) | ||
|  | { | ||
|  | 	char *new_output_pos; | ||
|  | 
 | ||
|  | 	*memcons.output_pos = c; | ||
|  | 	wmb(); | ||
|  | 	new_output_pos = memcons.output_pos + 1; | ||
|  | 	if (new_output_pos >= memcons.output_end) | ||
|  | 		new_output_pos = memcons.output_start; | ||
|  | 
 | ||
|  | 	memcons.output_pos = new_output_pos; | ||
|  | } | ||
|  | 
 | ||
|  | int memcons_getc_poll(void) | ||
|  | { | ||
|  | 	char c; | ||
|  | 	char *new_input_pos; | ||
|  | 
 | ||
|  | 	if (*memcons.input_pos) { | ||
|  | 		c = *memcons.input_pos; | ||
|  | 
 | ||
|  | 		new_input_pos = memcons.input_pos + 1; | ||
|  | 		if (new_input_pos >= memcons.input_end) | ||
|  | 			new_input_pos = memcons.input_start; | ||
|  | 		else if (*new_input_pos == '\0') | ||
|  | 			new_input_pos = memcons.input_start; | ||
|  | 
 | ||
|  | 		*memcons.input_pos = '\0'; | ||
|  | 		wmb(); | ||
|  | 		memcons.input_pos = new_input_pos; | ||
|  | 		return c; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return -1; | ||
|  | } | ||
|  | 
 | ||
|  | int memcons_getc(void) | ||
|  | { | ||
|  | 	int c; | ||
|  | 
 | ||
|  | 	while (1) { | ||
|  | 		c = memcons_getc_poll(); | ||
|  | 		if (c == -1) | ||
|  | 			cpu_relax(); | ||
|  | 		else | ||
|  | 			break; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	return c; | ||
|  | } | ||
|  | 
 | ||
|  | void udbg_init_memcons(void) | ||
|  | { | ||
|  | 	udbg_putc = memcons_putc; | ||
|  | 	udbg_getc = memcons_getc; | ||
|  | 	udbg_getc_poll = memcons_getc_poll; | ||
|  | } |