]> git.proxmox.com Git - mirror_qemu.git/blame - hw/input/pl050.c
pl050: don't use legacy ps2_mouse_init() function
[mirror_qemu.git] / hw / input / pl050.c
CommitLineData
5fafdf24 1/*
69db0ac7 2 * Arm PrimeCell PL050 Keyboard / Mouse Interface
cdbdb648 3 *
9e61ec31 4 * Copyright (c) 2006-2007 CodeSourcery.
cdbdb648
PB
5 * Written by Paul Brook
6 *
8e31bf38 7 * This code is licensed under the GPL.
cdbdb648
PB
8 */
9
1d9d4b07
MCA
10/*
11 * QEMU interface:
12 * + sysbus MMIO region 0: MemoryRegion defining the PL050 registers
13 * + Named GPIO input "ps2-input-irq": set to 1 if the downstream PS2 device
14 * has asserted its irq
15 * + sysbus IRQ 0: PL050 output irq
16 */
17
8ef94f0b 18#include "qemu/osdep.h"
83c9f4ca 19#include "hw/sysbus.h"
d6454270 20#include "migration/vmstate.h"
0d09e41a 21#include "hw/input/ps2.h"
bce0e9c1 22#include "hw/input/pl050.h"
64552b6b 23#include "hw/irq.h"
03dd024f 24#include "qemu/log.h"
0b8fa32f 25#include "qemu/module.h"
db1015e9 26#include "qom/object.h"
cdbdb648 27
cdbdb648 28
d6ac172a
PM
29static const VMStateDescription vmstate_pl050 = {
30 .name = "pl050",
e8945b4f
PM
31 .version_id = 2,
32 .minimum_version_id = 2,
d6ac172a 33 .fields = (VMStateField[]) {
e607f25a
AF
34 VMSTATE_UINT32(cr, PL050State),
35 VMSTATE_UINT32(clk, PL050State),
36 VMSTATE_UINT32(last, PL050State),
37 VMSTATE_INT32(pending, PL050State),
d6ac172a
PM
38 VMSTATE_END_OF_LIST()
39 }
40};
41
9e61ec31
PB
42#define PL050_TXEMPTY (1 << 6)
43#define PL050_TXBUSY (1 << 5)
44#define PL050_RXFULL (1 << 4)
45#define PL050_RXBUSY (1 << 3)
46#define PL050_RXPARITY (1 << 2)
47#define PL050_KMIC (1 << 1)
48#define PL050_KMID (1 << 0)
49
600f7110
MCA
50static const unsigned char pl050_id[] = {
51 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
52};
cdbdb648 53
eca9e870
MCA
54static void pl050_update_irq(PL050State *s)
55{
56 int level = (s->pending && (s->cr & 0x10) != 0)
57 || (s->cr & 0x08) != 0;
58
59 qemu_set_irq(s->irq, level);
60}
61
423bcb23 62static void pl050_set_irq(void *opaque, int n, int level)
cdbdb648 63{
e607f25a 64 PL050State *s = (PL050State *)opaque;
cdbdb648
PB
65
66 s->pending = level;
eca9e870 67 pl050_update_irq(s);
cdbdb648
PB
68}
69
a8170e5e 70static uint64_t pl050_read(void *opaque, hwaddr offset,
b8f7a738 71 unsigned size)
cdbdb648 72{
e607f25a 73 PL050State *s = (PL050State *)opaque;
600f7110
MCA
74
75 if (offset >= 0xfe0 && offset < 0x1000) {
cdbdb648 76 return pl050_id[(offset - 0xfe0) >> 2];
600f7110 77 }
cdbdb648
PB
78
79 switch (offset >> 2) {
80 case 0: /* KMICR */
81 return s->cr;
82 case 1: /* KMISTAT */
9e61ec31
PB
83 {
84 uint8_t val;
85 uint32_t stat;
86
87 val = s->last;
88 val = val ^ (val >> 4);
89 val = val ^ (val >> 2);
90 val = (val ^ (val >> 1)) & 1;
91
92 stat = PL050_TXEMPTY;
600f7110 93 if (val) {
9e61ec31 94 stat |= PL050_RXPARITY;
600f7110
MCA
95 }
96 if (s->pending) {
9e61ec31 97 stat |= PL050_RXFULL;
600f7110 98 }
9e61ec31
PB
99
100 return stat;
cdbdb648
PB
101 }
102 case 2: /* KMIDATA */
600f7110 103 if (s->pending) {
33e0958e 104 s->last = ps2_read_data(s->ps2dev);
600f7110 105 }
cdbdb648
PB
106 return s->last;
107 case 3: /* KMICLKDIV */
108 return s->clk;
109 case 4: /* KMIIR */
110 return s->pending | 2;
111 default:
fbfecf43
PM
112 qemu_log_mask(LOG_GUEST_ERROR,
113 "pl050_read: Bad offset %x\n", (int)offset);
cdbdb648
PB
114 return 0;
115 }
116}
117
a8170e5e 118static void pl050_write(void *opaque, hwaddr offset,
b8f7a738 119 uint64_t value, unsigned size)
cdbdb648 120{
e607f25a 121 PL050State *s = (PL050State *)opaque;
600f7110 122
cdbdb648
PB
123 switch (offset >> 2) {
124 case 0: /* KMICR */
125 s->cr = value;
eca9e870 126 pl050_update_irq(s);
cdbdb648
PB
127 /* ??? Need to implement the enable/disable bit. */
128 break;
129 case 2: /* KMIDATA */
130 /* ??? This should toggle the TX interrupt line. */
131 /* ??? This means kbd/mouse can block each other. */
132 if (s->is_mouse) {
33e0958e 133 ps2_write_mouse(PS2_MOUSE_DEVICE(s->ps2dev), value);
cdbdb648 134 } else {
33e0958e 135 ps2_write_keyboard(PS2_KBD_DEVICE(s->ps2dev), value);
cdbdb648
PB
136 }
137 break;
138 case 3: /* KMICLKDIV */
139 s->clk = value;
140 return;
141 default:
fbfecf43
PM
142 qemu_log_mask(LOG_GUEST_ERROR,
143 "pl050_write: Bad offset %x\n", (int)offset);
cdbdb648
PB
144 }
145}
b8f7a738
AK
146static const MemoryRegionOps pl050_ops = {
147 .read = pl050_read,
148 .write = pl050_write,
149 .endianness = DEVICE_NATIVE_ENDIAN,
cdbdb648
PB
150};
151
988e501a 152static void pl050_realize(DeviceState *dev, Error **errp)
cdbdb648 153{
3e5dd364 154 PL050State *s = PL050(dev);
cdbdb648 155
33e0958e 156 qdev_connect_gpio_out(DEVICE(s->ps2dev), PS2_DEVICE_IRQ,
423bcb23 157 qdev_get_gpio_in_named(dev, "ps2-input-irq", 0));
cdbdb648 158}
86394e96 159
87efd282
MCA
160static void pl050_kbd_realize(DeviceState *dev, Error **errp)
161{
162 PL050DeviceClass *pdc = PL050_GET_CLASS(dev);
6a05d0b3 163 PL050KbdState *s = PL050_KBD_DEVICE(dev);
87efd282
MCA
164 PL050State *ps = PL050(dev);
165
6a05d0b3
MCA
166 if (!sysbus_realize(SYS_BUS_DEVICE(&s->kbd), errp)) {
167 return;
168 }
169
170 ps->ps2dev = PS2_DEVICE(&s->kbd);
87efd282
MCA
171 pdc->parent_realize(dev, errp);
172}
173
b6c575d8 174static void pl050_kbd_init(Object *obj)
86394e96 175{
6a05d0b3
MCA
176 PL050KbdState *s = PL050_KBD_DEVICE(obj);
177 PL050State *ps = PL050(obj);
86394e96 178
6a05d0b3
MCA
179 ps->is_mouse = false;
180 object_initialize_child(obj, "kbd", &s->kbd, TYPE_PS2_KBD_DEVICE);
86394e96
PB
181}
182
5b0138b3
MCA
183static void pl050_mouse_realize(DeviceState *dev, Error **errp)
184{
185 PL050DeviceClass *pdc = PL050_GET_CLASS(dev);
6f9f245b 186 PL050MouseState *s = PL050_MOUSE_DEVICE(dev);
5b0138b3
MCA
187 PL050State *ps = PL050(dev);
188
6f9f245b
MCA
189 if (!sysbus_realize(SYS_BUS_DEVICE(&s->mouse), errp)) {
190 return;
191 }
192
193 ps->ps2dev = PS2_DEVICE(&s->mouse);
5b0138b3
MCA
194 pdc->parent_realize(dev, errp);
195}
196
3e5dd364 197static void pl050_mouse_init(Object *obj)
999e12bb 198{
6f9f245b
MCA
199 PL050MouseState *s = PL050_MOUSE_DEVICE(obj);
200 PL050State *ps = PL050(obj);
999e12bb 201
6f9f245b
MCA
202 ps->is_mouse = true;
203 object_initialize_child(obj, "mouse", &s->mouse, TYPE_PS2_MOUSE_DEVICE);
999e12bb
AL
204}
205
87efd282
MCA
206static void pl050_kbd_class_init(ObjectClass *oc, void *data)
207{
208 DeviceClass *dc = DEVICE_CLASS(oc);
209 PL050DeviceClass *pdc = PL050_CLASS(oc);
210
211 device_class_set_parent_realize(dc, pl050_kbd_realize,
212 &pdc->parent_realize);
213}
214
8c43a6f0 215static const TypeInfo pl050_kbd_info = {
1d59315d 216 .name = TYPE_PL050_KBD_DEVICE,
3e5dd364 217 .parent = TYPE_PL050,
b6c575d8 218 .instance_init = pl050_kbd_init,
1d59315d 219 .instance_size = sizeof(PL050KbdState),
87efd282 220 .class_init = pl050_kbd_class_init,
d6ac172a
PM
221};
222
5b0138b3
MCA
223static void pl050_mouse_class_init(ObjectClass *oc, void *data)
224{
225 DeviceClass *dc = DEVICE_CLASS(oc);
226 PL050DeviceClass *pdc = PL050_CLASS(oc);
227
228 device_class_set_parent_realize(dc, pl050_mouse_realize,
229 &pdc->parent_realize);
230}
231
3e5dd364 232static const TypeInfo pl050_mouse_info = {
0a3c1e1b 233 .name = TYPE_PL050_MOUSE_DEVICE,
3e5dd364
AF
234 .parent = TYPE_PL050,
235 .instance_init = pl050_mouse_init,
0a3c1e1b 236 .instance_size = sizeof(PL050MouseState),
5b0138b3 237 .class_init = pl050_mouse_class_init,
3e5dd364
AF
238};
239
423bcb23
MCA
240static void pl050_init(Object *obj)
241{
3d5e0995
MCA
242 PL050State *s = PL050(obj);
243 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
244
245 memory_region_init_io(&s->iomem, obj, &pl050_ops, s, "pl050", 0x1000);
246 sysbus_init_mmio(sbd, &s->iomem);
247 sysbus_init_irq(sbd, &s->irq);
248
423bcb23
MCA
249 qdev_init_gpio_in_named(DEVICE(obj), pl050_set_irq, "ps2-input-irq", 1);
250}
251
3e5dd364 252static void pl050_class_init(ObjectClass *oc, void *data)
999e12bb 253{
3e5dd364 254 DeviceClass *dc = DEVICE_CLASS(oc);
999e12bb 255
988e501a 256 dc->realize = pl050_realize;
39bffca2 257 dc->vmsd = &vmstate_pl050;
999e12bb
AL
258}
259
3e5dd364
AF
260static const TypeInfo pl050_type_info = {
261 .name = TYPE_PL050,
39bffca2 262 .parent = TYPE_SYS_BUS_DEVICE,
423bcb23 263 .instance_init = pl050_init,
e607f25a 264 .instance_size = sizeof(PL050State),
475a4d46
MCA
265 .class_init = pl050_class_init,
266 .class_size = sizeof(PL050DeviceClass),
3e5dd364
AF
267 .abstract = true,
268 .class_init = pl050_class_init,
d6ac172a
PM
269};
270
83f7d43a 271static void pl050_register_types(void)
86394e96 272{
3e5dd364 273 type_register_static(&pl050_type_info);
39bffca2
AL
274 type_register_static(&pl050_kbd_info);
275 type_register_static(&pl050_mouse_info);
86394e96
PB
276}
277
83f7d43a 278type_init(pl050_register_types)