/ payloads / libpayload / libc / console.c
console.c
  1  /*
  2   *
  3   * Copyright (C) 2008 Advanced Micro Devices, Inc.
  4   *
  5   * Redistribution and use in source and binary forms, with or without
  6   * modification, are permitted provided that the following conditions
  7   * are met:
  8   * 1. Redistributions of source code must retain the above copyright
  9   *    notice, this list of conditions and the following disclaimer.
 10   * 2. Redistributions in binary form must reproduce the above copyright
 11   *    notice, this list of conditions and the following disclaimer in the
 12   *    documentation and/or other materials provided with the distribution.
 13   * 3. The name of the author may not be used to endorse or promote products
 14   *    derived from this software without specific prior written permission.
 15   *
 16   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 19   * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 20   * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 21   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 22   * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 23   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 24   * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 25   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 26   * SUCH DAMAGE.
 27   */
 28  
 29  #include <libpayload-config.h>
 30  #include <libpayload.h>
 31  #include <usb/usb.h>
 32  
 33  struct console_output_driver *console_out;
 34  struct console_input_driver *console_in;
 35  static console_input_type last_getchar_input_type;
 36  
 37  static int output_driver_exists(struct console_output_driver *out)
 38  {
 39  	struct console_output_driver *head = console_out;
 40  
 41  	while (head) {
 42  		if (head == out)
 43  			return 1;
 44  		head = head->next;
 45  	}
 46  
 47  	return 0;
 48  }
 49  
 50  static int input_driver_exists(struct console_input_driver *in)
 51  {
 52  	struct console_input_driver *head = console_in;
 53  
 54  	while (head) {
 55  		if (head == in)
 56  			return 1;
 57  		head = head->next;
 58  	}
 59  
 60  	return 0;
 61  }
 62  
 63  void console_add_output_driver(struct console_output_driver *out)
 64  {
 65  	die_if(!out->putchar && !out->write, "Need at least one output func\n");
 66  	/* Check if this driver was already added to the console list */
 67  	if (output_driver_exists(out))
 68  		return;
 69  	out->next = console_out;
 70  	console_out = out;
 71  }
 72  
 73  void console_add_input_driver(struct console_input_driver *in)
 74  {
 75  	/* Check if this driver was already added to the console list */
 76  	if (input_driver_exists(in))
 77  		return;
 78  	/* Flush out the driver input buffer. */
 79  	while (in->havekey())
 80  		in->getchar();
 81  	in->next = console_in;
 82  	console_in = in;
 83  }
 84  
 85  /*
 86   * For when you really need to silence an output driver (e.g. to avoid ugly
 87   * recursions). Takes the pointer of either of the two output functions, since
 88   * the struct console_output_driver itself is often static and inaccessible.
 89   */
 90  int console_remove_output_driver(void *function)
 91  {
 92  	struct console_output_driver **out;
 93  	for (out = &console_out; *out; out = &(*out)->next)
 94  		if ((*out)->putchar == function || (*out)->write == function) {
 95  			*out = (*out)->next;
 96  			return 1;
 97  		}
 98  
 99  	return 0;
100  }
101  
102  void console_init(void)
103  {
104  #if CONFIG(LP_VIDEO_CONSOLE)
105  	video_console_init();
106  #endif
107  #if CONFIG(LP_SERIAL_CONSOLE)
108  	serial_console_init();
109  #endif
110  #if CONFIG(LP_PC_KEYBOARD)
111  	keyboard_init();
112  #endif
113  #if CONFIG(LP_CBMEM_CONSOLE)
114  	cbmem_console_init();
115  #endif
116  }
117  
118  void console_write(const void *buffer, size_t count)
119  {
120  	const char *ptr;
121  	struct console_output_driver *out;
122  	for (out = console_out; out != 0; out = out->next)
123  		if (out->write)
124  			out->write(buffer, count);
125  		else
126  			for (ptr = buffer; (void *)ptr < buffer + count; ptr++)
127  				out->putchar(*ptr);
128  }
129  
130  int putchar(unsigned int i)
131  {
132  	unsigned char c = (unsigned char)i;
133  	console_write(&c, 1);
134  	return (int)c;
135  }
136  
137  int puts(const char *s)
138  {
139  	size_t size = strlen(s);
140  
141  	console_write(s, size);
142  
143  	putchar('\n');
144  	return size + 1;
145  }
146  
147  int havekey(void)
148  {
149  #if CONFIG(LP_USB)
150  	usb_poll();
151  #endif
152  	struct console_input_driver *in;
153  	for (in = console_in; in != 0; in = in->next)
154  		if (in->havekey())
155  			return 1;
156  	return 0;
157  }
158  
159  /**
160   * This returns an ASCII value - the two getchar functions
161   * cook the respective input from the device.
162   */
163  int getchar(void)
164  {
165  	while (1) {
166  #if CONFIG(LP_USB)
167  		usb_poll();
168  #endif
169  		struct console_input_driver *in;
170  		for (in = console_in; in != 0; in = in->next)
171  			if (in->havechar()) {
172  				last_getchar_input_type = in->input_type;
173  				return in->getchar();
174  			}
175  	}
176  }
177  
178  int getchar_timeout(int *ms)
179  {
180  	while (*ms > 0) {
181  		if (havekey())
182  			return getchar();
183  
184  		mdelay(100);
185  		*ms -= 100;
186  	}
187  
188  	if (*ms < 0)
189  		*ms = 0;
190  
191  	return 0;
192  }
193  
194  console_input_type last_key_input_type(void)
195  {
196  	return last_getchar_input_type;
197  }