ac54e0167eb63e8eb9189bc1b6b36c2417f789c4
[karo-tx-uboot.git] / drivers / serial / sandbox.c
1 /*
2  * Copyright (c) 2011 The Chromium OS Authors.
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6
7 /*
8  * This provide a test serial port. It provides an emulated serial port where
9  * a test program and read out the serial output and inject serial input for
10  * U-Boot.
11  */
12
13 #include <common.h>
14 #include <dm.h>
15 #include <fdtdec.h>
16 #include <lcd.h>
17 #include <os.h>
18 #include <serial.h>
19 #include <linux/compiler.h>
20 #include <asm/state.h>
21
22 DECLARE_GLOBAL_DATA_PTR;
23
24 /*
25  *
26  *   serial_buf: A buffer that holds keyboard characters for the
27  *               Sandbox U-boot.
28  *
29  * invariants:
30  *   serial_buf_write            == serial_buf_read -> empty buffer
31  *   (serial_buf_write + 1) % 16 == serial_buf_read -> full buffer
32  */
33 static char serial_buf[16];
34 static unsigned int serial_buf_write;
35 static unsigned int serial_buf_read;
36
37 static int sandbox_serial_probe(struct udevice *dev)
38 {
39         struct sandbox_state *state = state_get_current();
40
41         if (state->term_raw != STATE_TERM_COOKED)
42                 os_tty_raw(0, state->term_raw == STATE_TERM_RAW_WITH_SIGS);
43
44         return 0;
45 }
46
47 static int sandbox_serial_putc(struct udevice *dev, const char ch)
48 {
49         os_write(1, &ch, 1);
50
51         return 0;
52 }
53
54 static unsigned int increment_buffer_index(unsigned int index)
55 {
56         return (index + 1) % ARRAY_SIZE(serial_buf);
57 }
58
59 static int sandbox_serial_pending(struct udevice *dev, bool input)
60 {
61         const unsigned int next_index =
62                 increment_buffer_index(serial_buf_write);
63         ssize_t count;
64
65         if (!input)
66                 return 0;
67
68         os_usleep(100);
69 #ifdef CONFIG_LCD
70         lcd_sync();
71 #endif
72         if (next_index == serial_buf_read)
73                 return 1;       /* buffer full */
74
75         count = os_read_no_block(0, &serial_buf[serial_buf_write], 1);
76         if (count == 1)
77                 serial_buf_write = next_index;
78
79         return serial_buf_write != serial_buf_read;
80 }
81
82 static int sandbox_serial_getc(struct udevice *dev)
83 {
84         int result;
85
86         if (!sandbox_serial_pending(dev, true))
87                 return -EAGAIN; /* buffer empty */
88
89         result = serial_buf[serial_buf_read];
90         serial_buf_read = increment_buffer_index(serial_buf_read);
91         return result;
92 }
93
94 static const struct dm_serial_ops sandbox_serial_ops = {
95         .putc = sandbox_serial_putc,
96         .pending = sandbox_serial_pending,
97         .getc = sandbox_serial_getc,
98 };
99
100 static const struct udevice_id sandbox_serial_ids[] = {
101         { .compatible = "sandbox,serial" },
102         { }
103 };
104
105 U_BOOT_DRIVER(serial_sandbox) = {
106         .name   = "serial_sandbox",
107         .id     = UCLASS_SERIAL,
108         .of_match = sandbox_serial_ids,
109         .probe = sandbox_serial_probe,
110         .ops    = &sandbox_serial_ops,
111         .flags = DM_FLAG_PRE_RELOC,
112 };
113
114 U_BOOT_DEVICE(serial_sandbox_non_fdt) = {
115         .name = "serial_sandbox",
116 };