Statistics
| Branch: | Revision:

root / hw / spapr_vty.c @ 0201e2da

History | View | Annotate | Download (4.1 kB)

1
#include "qdev.h"
2
#include "qemu-char.h"
3
#include "hw/spapr.h"
4
#include "hw/spapr_vio.h"
5

    
6
#define VTERM_BUFSIZE   16
7

    
8
typedef struct VIOsPAPRVTYDevice {
9
    VIOsPAPRDevice sdev;
10
    CharDriverState *chardev;
11
    uint32_t in, out;
12
    uint8_t buf[VTERM_BUFSIZE];
13
} VIOsPAPRVTYDevice;
14

    
15
static int vty_can_receive(void *opaque)
16
{
17
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
18

    
19
    return (dev->in - dev->out) < VTERM_BUFSIZE;
20
}
21

    
22
static void vty_receive(void *opaque, const uint8_t *buf, int size)
23
{
24
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)opaque;
25
    int i;
26

    
27
    if ((dev->in == dev->out) && size) {
28
        /* toggle line to simulate edge interrupt */
29
        qemu_irq_pulse(dev->sdev.qirq);
30
    }
31
    for (i = 0; i < size; i++) {
32
        assert((dev->in - dev->out) < VTERM_BUFSIZE);
33
        dev->buf[dev->in++ % VTERM_BUFSIZE] = buf[i];
34
    }
35
}
36

    
37
static int vty_getchars(VIOsPAPRDevice *sdev, uint8_t *buf, int max)
38
{
39
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
40
    int n = 0;
41

    
42
    while ((n < max) && (dev->out != dev->in)) {
43
        buf[n++] = dev->buf[dev->out++ % VTERM_BUFSIZE];
44
    }
45

    
46
    return n;
47
}
48

    
49
void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len)
50
{
51
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
52

    
53
    /* FIXME: should check the qemu_chr_write() return value */
54
    qemu_chr_write(dev->chardev, buf, len);
55
}
56

    
57
static int spapr_vty_init(VIOsPAPRDevice *sdev)
58
{
59
    VIOsPAPRVTYDevice *dev = (VIOsPAPRVTYDevice *)sdev;
60

    
61
    qemu_chr_add_handlers(dev->chardev, vty_can_receive,
62
                          vty_receive, NULL, dev);
63

    
64
    return 0;
65
}
66

    
67
static target_ulong h_put_term_char(CPUState *env, sPAPREnvironment *spapr,
68
                                    target_ulong opcode, target_ulong *args)
69
{
70
    target_ulong reg = args[0];
71
    target_ulong len = args[1];
72
    target_ulong char0_7 = args[2];
73
    target_ulong char8_15 = args[3];
74
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
75
    uint8_t buf[16];
76

    
77
    if (!sdev) {
78
        return H_PARAMETER;
79
    }
80

    
81
    if (len > 16) {
82
        return H_PARAMETER;
83
    }
84

    
85
    *((uint64_t *)buf) = cpu_to_be64(char0_7);
86
    *((uint64_t *)buf + 1) = cpu_to_be64(char8_15);
87

    
88
    vty_putchars(sdev, buf, len);
89

    
90
    return H_SUCCESS;
91
}
92

    
93
static target_ulong h_get_term_char(CPUState *env, sPAPREnvironment *spapr,
94
                                    target_ulong opcode, target_ulong *args)
95
{
96
    target_ulong reg = args[0];
97
    target_ulong *len = args + 0;
98
    target_ulong *char0_7 = args + 1;
99
    target_ulong *char8_15 = args + 2;
100
    VIOsPAPRDevice *sdev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
101
    uint8_t buf[16];
102

    
103
    if (!sdev) {
104
        return H_PARAMETER;
105
    }
106

    
107
    *len = vty_getchars(sdev, buf, sizeof(buf));
108
    if (*len < 16) {
109
        memset(buf + *len, 0, 16 - *len);
110
    }
111

    
112
    *char0_7 = be64_to_cpu(*((uint64_t *)buf));
113
    *char8_15 = be64_to_cpu(*((uint64_t *)buf + 1));
114

    
115
    return H_SUCCESS;
116
}
117

    
118
void spapr_vty_create(VIOsPAPRBus *bus,
119
                      uint32_t reg, CharDriverState *chardev,
120
                      qemu_irq qirq, uint32_t vio_irq_num)
121
{
122
    DeviceState *dev;
123
    VIOsPAPRDevice *sdev;
124

    
125
    dev = qdev_create(&bus->bus, "spapr-vty");
126
    qdev_prop_set_uint32(dev, "reg", reg);
127
    qdev_prop_set_chr(dev, "chardev", chardev);
128
    qdev_init_nofail(dev);
129
    sdev = (VIOsPAPRDevice *)dev;
130
    sdev->qirq = qirq;
131
    sdev->vio_irq_num = vio_irq_num;
132
}
133

    
134
static void vty_hcalls(VIOsPAPRBus *bus)
135
{
136
    spapr_register_hypercall(H_PUT_TERM_CHAR, h_put_term_char);
137
    spapr_register_hypercall(H_GET_TERM_CHAR, h_get_term_char);
138
}
139

    
140
static VIOsPAPRDeviceInfo spapr_vty = {
141
    .init = spapr_vty_init,
142
    .dt_name = "vty",
143
    .dt_type = "serial",
144
    .dt_compatible = "hvterm1",
145
    .hcalls = vty_hcalls,
146
    .qdev.name = "spapr-vty",
147
    .qdev.size = sizeof(VIOsPAPRVTYDevice),
148
    .qdev.props = (Property[]) {
149
        DEFINE_PROP_UINT32("reg", VIOsPAPRDevice, reg, 0),
150
        DEFINE_PROP_CHR("chardev", VIOsPAPRVTYDevice, chardev),
151
        DEFINE_PROP_END_OF_LIST(),
152
    },
153
};
154

    
155
static void spapr_vty_register(void)
156
{
157
    spapr_vio_bus_register_withprop(&spapr_vty);
158
}
159
device_init(spapr_vty_register);