qemu

Форк
0
/
goldfish_tty.c 
285 строк · 7.1 Кб
1
/*
2
 * SPDX-License-Identifier: GPL-2.0-or-later
3
 *
4
 * Goldfish TTY
5
 *
6
 * (c) 2020 Laurent Vivier <laurent@vivier.eu>
7
 *
8
 */
9

10
#include "qemu/osdep.h"
11
#include "hw/irq.h"
12
#include "hw/qdev-properties-system.h"
13
#include "hw/sysbus.h"
14
#include "migration/vmstate.h"
15
#include "chardev/char-fe.h"
16
#include "qemu/log.h"
17
#include "trace.h"
18
#include "exec/address-spaces.h"
19
#include "sysemu/dma.h"
20
#include "hw/char/goldfish_tty.h"
21

22
#define GOLDFISH_TTY_VERSION 1
23

24
/* registers */
25

26
enum {
27
    REG_PUT_CHAR      = 0x00,
28
    REG_BYTES_READY   = 0x04,
29
    REG_CMD           = 0x08,
30
    REG_DATA_PTR      = 0x10,
31
    REG_DATA_LEN      = 0x14,
32
    REG_DATA_PTR_HIGH = 0x18,
33
    REG_VERSION       = 0x20,
34
};
35

36
/* commands */
37

38
enum {
39
    CMD_INT_DISABLE   = 0x00,
40
    CMD_INT_ENABLE    = 0x01,
41
    CMD_WRITE_BUFFER  = 0x02,
42
    CMD_READ_BUFFER   = 0x03,
43
};
44

45
static uint64_t goldfish_tty_read(void *opaque, hwaddr addr,
46
                                  unsigned size)
47
{
48
    GoldfishTTYState *s = opaque;
49
    uint64_t value = 0;
50

51
    switch (addr) {
52
    case REG_BYTES_READY:
53
        value = fifo8_num_used(&s->rx_fifo);
54
        break;
55
    case REG_VERSION:
56
        value = GOLDFISH_TTY_VERSION;
57
        break;
58
    default:
59
        qemu_log_mask(LOG_UNIMP,
60
                      "%s: unimplemented register read 0x%02"HWADDR_PRIx"\n",
61
                      __func__, addr);
62
        break;
63
    }
64

65
    trace_goldfish_tty_read(s, addr, size, value);
66

67
    return value;
68
}
69

70
static void goldfish_tty_cmd(GoldfishTTYState *s, uint32_t cmd)
71
{
72
    uint32_t to_copy;
73
    uint8_t data_out[GOLFISH_TTY_BUFFER_SIZE];
74
    int len;
75
    uint64_t ptr;
76

77
    switch (cmd) {
78
    case CMD_INT_DISABLE:
79
        if (s->int_enabled) {
80
            if (!fifo8_is_empty(&s->rx_fifo)) {
81
                qemu_set_irq(s->irq, 0);
82
            }
83
            s->int_enabled = false;
84
        }
85
        break;
86
    case CMD_INT_ENABLE:
87
        if (!s->int_enabled) {
88
            if (!fifo8_is_empty(&s->rx_fifo)) {
89
                qemu_set_irq(s->irq, 1);
90
            }
91
            s->int_enabled = true;
92
        }
93
        break;
94
    case CMD_WRITE_BUFFER:
95
        len = s->data_len;
96
        ptr = s->data_ptr;
97
        while (len) {
98
            to_copy = MIN(GOLFISH_TTY_BUFFER_SIZE, len);
99

100
            dma_memory_read_relaxed(&address_space_memory, ptr,
101
                                    data_out, to_copy);
102
            qemu_chr_fe_write_all(&s->chr, data_out, to_copy);
103

104
            len -= to_copy;
105
            ptr += to_copy;
106
        }
107
        break;
108
    case CMD_READ_BUFFER:
109
        len = s->data_len;
110
        ptr = s->data_ptr;
111
        while (len && !fifo8_is_empty(&s->rx_fifo)) {
112
            const uint8_t *buf = fifo8_pop_bufptr(&s->rx_fifo, len, &to_copy);
113

114
            dma_memory_write_relaxed(&address_space_memory, ptr, buf, to_copy);
115

116
            len -= to_copy;
117
            ptr += to_copy;
118
        }
119
        if (s->int_enabled && fifo8_is_empty(&s->rx_fifo)) {
120
            qemu_set_irq(s->irq, 0);
121
        }
122
        break;
123
    }
124
}
125

126
static void goldfish_tty_write(void *opaque, hwaddr addr,
127
                               uint64_t value, unsigned size)
128
{
129
    GoldfishTTYState *s = opaque;
130
    unsigned char c;
131

132
    trace_goldfish_tty_write(s, addr, size, value);
133

134
    switch (addr) {
135
    case REG_PUT_CHAR:
136
        c = value;
137
        qemu_chr_fe_write_all(&s->chr, &c, sizeof(c));
138
        break;
139
    case REG_CMD:
140
        goldfish_tty_cmd(s, value);
141
        break;
142
    case REG_DATA_PTR:
143
        s->data_ptr = value;
144
        break;
145
    case REG_DATA_PTR_HIGH:
146
        s->data_ptr = deposit64(s->data_ptr, 32, 32, value);
147
        break;
148
    case REG_DATA_LEN:
149
        s->data_len = value;
150
        break;
151
    default:
152
        qemu_log_mask(LOG_UNIMP,
153
                      "%s: unimplemented register write 0x%02"HWADDR_PRIx"\n",
154
                      __func__, addr);
155
        break;
156
    }
157
}
158

159
static const MemoryRegionOps goldfish_tty_ops = {
160
    .read = goldfish_tty_read,
161
    .write = goldfish_tty_write,
162
    .endianness = DEVICE_NATIVE_ENDIAN,
163
    .valid.max_access_size = 4,
164
    .impl.max_access_size = 4,
165
    .impl.min_access_size = 4,
166
};
167

168
static int goldfish_tty_can_receive(void *opaque)
169
{
170
    GoldfishTTYState *s = opaque;
171
    int available = fifo8_num_free(&s->rx_fifo);
172

173
    trace_goldfish_tty_can_receive(s, available);
174

175
    return available;
176
}
177

178
static void goldfish_tty_receive(void *opaque, const uint8_t *buffer, int size)
179
{
180
    GoldfishTTYState *s = opaque;
181

182
    trace_goldfish_tty_receive(s, size);
183

184
    g_assert(size <= fifo8_num_free(&s->rx_fifo));
185

186
    fifo8_push_all(&s->rx_fifo, buffer, size);
187

188
    if (s->int_enabled && !fifo8_is_empty(&s->rx_fifo)) {
189
        qemu_set_irq(s->irq, 1);
190
    }
191
}
192

193
static void goldfish_tty_reset(DeviceState *dev)
194
{
195
    GoldfishTTYState *s = GOLDFISH_TTY(dev);
196

197
    trace_goldfish_tty_reset(s);
198

199
    fifo8_reset(&s->rx_fifo);
200
    s->int_enabled = false;
201
    s->data_ptr = 0;
202
    s->data_len = 0;
203
}
204

205
static void goldfish_tty_realize(DeviceState *dev, Error **errp)
206
{
207
    GoldfishTTYState *s = GOLDFISH_TTY(dev);
208

209
    trace_goldfish_tty_realize(s);
210

211
    fifo8_create(&s->rx_fifo, GOLFISH_TTY_BUFFER_SIZE);
212
    memory_region_init_io(&s->iomem, OBJECT(s), &goldfish_tty_ops, s,
213
                          "goldfish_tty", 0x24);
214

215
    if (qemu_chr_fe_backend_connected(&s->chr)) {
216
        qemu_chr_fe_set_handlers(&s->chr, goldfish_tty_can_receive,
217
                                 goldfish_tty_receive, NULL, NULL,
218
                                 s, NULL, true);
219
    }
220
}
221

222
static void goldfish_tty_unrealize(DeviceState *dev)
223
{
224
    GoldfishTTYState *s = GOLDFISH_TTY(dev);
225

226
    trace_goldfish_tty_unrealize(s);
227

228
    fifo8_destroy(&s->rx_fifo);
229
}
230

231
static const VMStateDescription vmstate_goldfish_tty = {
232
    .name = "goldfish_tty",
233
    .version_id = 1,
234
    .minimum_version_id = 1,
235
    .fields = (const VMStateField[]) {
236
        VMSTATE_UINT32(data_len, GoldfishTTYState),
237
        VMSTATE_UINT64(data_ptr, GoldfishTTYState),
238
        VMSTATE_BOOL(int_enabled, GoldfishTTYState),
239
        VMSTATE_FIFO8(rx_fifo, GoldfishTTYState),
240
        VMSTATE_END_OF_LIST()
241
    }
242
};
243

244
static Property goldfish_tty_properties[] = {
245
    DEFINE_PROP_CHR("chardev", GoldfishTTYState, chr),
246
    DEFINE_PROP_END_OF_LIST(),
247
};
248

249
static void goldfish_tty_instance_init(Object *obj)
250
{
251
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
252
    GoldfishTTYState *s = GOLDFISH_TTY(obj);
253

254
    trace_goldfish_tty_instance_init(s);
255

256
    sysbus_init_mmio(dev, &s->iomem);
257
    sysbus_init_irq(dev, &s->irq);
258
}
259

260
static void goldfish_tty_class_init(ObjectClass *oc, void *data)
261
{
262
    DeviceClass *dc = DEVICE_CLASS(oc);
263

264
    device_class_set_props(dc, goldfish_tty_properties);
265
    dc->reset = goldfish_tty_reset;
266
    dc->realize = goldfish_tty_realize;
267
    dc->unrealize = goldfish_tty_unrealize;
268
    dc->vmsd = &vmstate_goldfish_tty;
269
    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
270
}
271

272
static const TypeInfo goldfish_tty_info = {
273
    .name = TYPE_GOLDFISH_TTY,
274
    .parent = TYPE_SYS_BUS_DEVICE,
275
    .class_init = goldfish_tty_class_init,
276
    .instance_init = goldfish_tty_instance_init,
277
    .instance_size = sizeof(GoldfishTTYState),
278
};
279

280
static void goldfish_tty_register_types(void)
281
{
282
    type_register_static(&goldfish_tty_info);
283
}
284

285
type_init(goldfish_tty_register_types)
286

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.