diff options
Diffstat (limited to 'arch/powerpc/sysdev/udbg_memcons.c')
| -rw-r--r-- | arch/powerpc/sysdev/udbg_memcons.c | 105 | 
1 files changed, 105 insertions, 0 deletions
diff --git a/arch/powerpc/sysdev/udbg_memcons.c b/arch/powerpc/sysdev/udbg_memcons.c new file mode 100644 index 00000000000..ce5a7b489e4 --- /dev/null +++ b/arch/powerpc/sysdev/udbg_memcons.c @@ -0,0 +1,105 @@ +/* + * 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/init.h> +#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; +}  | 
