| /* | |
| * 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; | |
| } |