qemu

Форк
0
/
etraxfs_ser.c 
267 строк · 7.1 Кб
1
/*
2
 * QEMU ETRAX System Emulator
3
 *
4
 * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB.
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24

25
#include "qemu/osdep.h"
26
#include "hw/irq.h"
27
#include "hw/qdev-properties.h"
28
#include "hw/qdev-properties-system.h"
29
#include "hw/sysbus.h"
30
#include "chardev/char-fe.h"
31
#include "qemu/log.h"
32
#include "qemu/module.h"
33
#include "qom/object.h"
34

35
#define D(x)
36

37
#define RW_TR_CTRL     (0x00 / 4)
38
#define RW_TR_DMA_EN   (0x04 / 4)
39
#define RW_REC_CTRL    (0x08 / 4)
40
#define RW_DOUT        (0x1c / 4)
41
#define RS_STAT_DIN    (0x20 / 4)
42
#define R_STAT_DIN     (0x24 / 4)
43
#define RW_INTR_MASK   (0x2c / 4)
44
#define RW_ACK_INTR    (0x30 / 4)
45
#define R_INTR         (0x34 / 4)
46
#define R_MASKED_INTR  (0x38 / 4)
47
#define R_MAX          (0x3c / 4)
48

49
#define STAT_DAV     16
50
#define STAT_TR_IDLE 22
51
#define STAT_TR_RDY  24
52

53
#define TYPE_ETRAX_FS_SERIAL "etraxfs-serial"
54
typedef struct ETRAXSerial ETRAXSerial;
55
DECLARE_INSTANCE_CHECKER(ETRAXSerial, ETRAX_SERIAL,
56
                         TYPE_ETRAX_FS_SERIAL)
57

58
struct ETRAXSerial {
59
    SysBusDevice parent_obj;
60

61
    MemoryRegion mmio;
62
    CharBackend chr;
63
    qemu_irq irq;
64

65
    int pending_tx;
66

67
    uint8_t rx_fifo[16];
68
    unsigned int rx_fifo_pos;
69
    unsigned int rx_fifo_len;
70

71
    /* Control registers.  */
72
    uint32_t regs[R_MAX];
73
};
74

75
static void ser_update_irq(ETRAXSerial *s)
76
{
77

78
    if (s->rx_fifo_len) {
79
        s->regs[R_INTR] |= 8;
80
    } else {
81
        s->regs[R_INTR] &= ~8;
82
    }
83

84
    s->regs[R_MASKED_INTR] = s->regs[R_INTR] & s->regs[RW_INTR_MASK];
85
    qemu_set_irq(s->irq, !!s->regs[R_MASKED_INTR]);
86
}
87

88
static uint64_t
89
ser_read(void *opaque, hwaddr addr, unsigned int size)
90
{
91
    ETRAXSerial *s = opaque;
92
    uint32_t r = 0;
93

94
    addr >>= 2;
95
    switch (addr)
96
    {
97
        case R_STAT_DIN:
98
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
99
            if (s->rx_fifo_len) {
100
                r |= 1 << STAT_DAV;
101
            }
102
            r |= 1 << STAT_TR_RDY;
103
            r |= 1 << STAT_TR_IDLE;
104
            break;
105
        case RS_STAT_DIN:
106
            r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 15];
107
            if (s->rx_fifo_len) {
108
                r |= 1 << STAT_DAV;
109
                s->rx_fifo_len--;
110
            }
111
            r |= 1 << STAT_TR_RDY;
112
            r |= 1 << STAT_TR_IDLE;
113
            break;
114
        default:
115
            r = s->regs[addr];
116
            D(qemu_log("%s " HWADDR_FMT_plx "=%x\n", __func__, addr, r));
117
            break;
118
    }
119
    return r;
120
}
121

122
static void
123
ser_write(void *opaque, hwaddr addr,
124
          uint64_t val64, unsigned int size)
125
{
126
    ETRAXSerial *s = opaque;
127
    uint32_t value = val64;
128
    unsigned char ch = val64;
129

130
    D(qemu_log("%s " HWADDR_FMT_plx "=%x\n",  __func__, addr, value));
131
    addr >>= 2;
132
    switch (addr)
133
    {
134
        case RW_DOUT:
135
            /* XXX this blocks entire thread. Rewrite to use
136
             * qemu_chr_fe_write and background I/O callbacks */
137
            qemu_chr_fe_write_all(&s->chr, &ch, 1);
138
            s->regs[R_INTR] |= 3;
139
            s->pending_tx = 1;
140
            s->regs[addr] = value;
141
            break;
142
        case RW_ACK_INTR:
143
            if (s->pending_tx) {
144
                value &= ~1;
145
                s->pending_tx = 0;
146
                D(qemu_log("fixedup value=%x r_intr=%x\n",
147
                           value, s->regs[R_INTR]));
148
            }
149
            s->regs[addr] = value;
150
            s->regs[R_INTR] &= ~value;
151
            D(printf("r_intr=%x\n", s->regs[R_INTR]));
152
            break;
153
        default:
154
            s->regs[addr] = value;
155
            break;
156
    }
157
    ser_update_irq(s);
158
}
159

160
static const MemoryRegionOps ser_ops = {
161
    .read = ser_read,
162
    .write = ser_write,
163
    .endianness = DEVICE_NATIVE_ENDIAN,
164
    .valid = {
165
        .min_access_size = 4,
166
        .max_access_size = 4
167
    }
168
};
169

170
static Property etraxfs_ser_properties[] = {
171
    DEFINE_PROP_CHR("chardev", ETRAXSerial, chr),
172
    DEFINE_PROP_END_OF_LIST(),
173
};
174

175
static void serial_receive(void *opaque, const uint8_t *buf, int size)
176
{
177
    ETRAXSerial *s = opaque;
178
    int i;
179

180
    /* Got a byte.  */
181
    if (s->rx_fifo_len >= 16) {
182
        D(qemu_log("WARNING: UART dropped char.\n"));
183
        return;
184
    }
185

186
    for (i = 0; i < size; i++) { 
187
        s->rx_fifo[s->rx_fifo_pos] = buf[i];
188
        s->rx_fifo_pos++;
189
        s->rx_fifo_pos &= 15;
190
        s->rx_fifo_len++;
191
    }
192

193
    ser_update_irq(s);
194
}
195

196
static int serial_can_receive(void *opaque)
197
{
198
    ETRAXSerial *s = opaque;
199

200
    /* Is the receiver enabled?  */
201
    if (!(s->regs[RW_REC_CTRL] & (1 << 3))) {
202
        return 0;
203
    }
204

205
    return sizeof(s->rx_fifo) - s->rx_fifo_len;
206
}
207

208
static void serial_event(void *opaque, QEMUChrEvent event)
209
{
210

211
}
212

213
static void etraxfs_ser_reset(DeviceState *d)
214
{
215
    ETRAXSerial *s = ETRAX_SERIAL(d);
216

217
    /* transmitter begins ready and idle.  */
218
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_RDY);
219
    s->regs[RS_STAT_DIN] |= (1 << STAT_TR_IDLE);
220

221
    s->regs[RW_REC_CTRL] = 0x10000;
222

223
}
224

225
static void etraxfs_ser_init(Object *obj)
226
{
227
    ETRAXSerial *s = ETRAX_SERIAL(obj);
228
    SysBusDevice *dev = SYS_BUS_DEVICE(obj);
229

230
    sysbus_init_irq(dev, &s->irq);
231
    memory_region_init_io(&s->mmio, obj, &ser_ops, s,
232
                          "etraxfs-serial", R_MAX * 4);
233
    sysbus_init_mmio(dev, &s->mmio);
234
}
235

236
static void etraxfs_ser_realize(DeviceState *dev, Error **errp)
237
{
238
    ETRAXSerial *s = ETRAX_SERIAL(dev);
239

240
    qemu_chr_fe_set_handlers(&s->chr,
241
                             serial_can_receive, serial_receive,
242
                             serial_event, NULL, s, NULL, true);
243
}
244

245
static void etraxfs_ser_class_init(ObjectClass *klass, void *data)
246
{
247
    DeviceClass *dc = DEVICE_CLASS(klass);
248

249
    dc->reset = etraxfs_ser_reset;
250
    device_class_set_props(dc, etraxfs_ser_properties);
251
    dc->realize = etraxfs_ser_realize;
252
}
253

254
static const TypeInfo etraxfs_ser_info = {
255
    .name          = TYPE_ETRAX_FS_SERIAL,
256
    .parent        = TYPE_SYS_BUS_DEVICE,
257
    .instance_size = sizeof(ETRAXSerial),
258
    .instance_init = etraxfs_ser_init,
259
    .class_init    = etraxfs_ser_class_init,
260
};
261

262
static void etraxfs_serial_register_types(void)
263
{
264
    type_register_static(&etraxfs_ser_info);
265
}
266

267
type_init(etraxfs_serial_register_types)
268

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

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

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

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