xref: /qemu/hw/input/lasips2.c (revision 2ee1b52db1a22dee7856b140b31fae221f72629c)
1 /*
2  * QEMU HP Lasi PS/2 interface emulation
3  *
4  * Copyright (c) 2019 Sven Schnelle
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 #include "qemu/osdep.h"
25 #include "qemu/log.h"
26 #include "hw/qdev-properties.h"
27 #include "hw/sysbus.h"
28 #include "hw/input/ps2.h"
29 #include "hw/input/lasips2.h"
30 #include "exec/hwaddr.h"
31 #include "trace.h"
32 #include "exec/address-spaces.h"
33 #include "migration/vmstate.h"
34 #include "hw/irq.h"
35 #include "qapi/error.h"
36 
37 
38 static const VMStateDescription vmstate_lasips2 = {
39     .name = "lasips2",
40     .version_id = 0,
41     .minimum_version_id = 0,
42     .fields = (VMStateField[]) {
43         VMSTATE_UINT8(kbd_port.parent_obj.control, LASIPS2State),
44         VMSTATE_UINT8(kbd_port.parent_obj.id, LASIPS2State),
45         VMSTATE_UINT8(mouse_port.parent_obj.control, LASIPS2State),
46         VMSTATE_UINT8(mouse_port.parent_obj.id, LASIPS2State),
47         VMSTATE_END_OF_LIST()
48     }
49 };
50 
51 typedef enum {
52     REG_PS2_ID = 0,
53     REG_PS2_RCVDATA = 4,
54     REG_PS2_CONTROL = 8,
55     REG_PS2_STATUS = 12,
56 } lasips2_read_reg_t;
57 
58 typedef enum {
59     REG_PS2_RESET = 0,
60     REG_PS2_XMTDATA = 4,
61 } lasips2_write_reg_t;
62 
63 typedef enum {
64     LASIPS2_CONTROL_ENABLE = 0x01,
65     LASIPS2_CONTROL_LOOPBACK = 0x02,
66     LASIPS2_CONTROL_DIAG = 0x20,
67     LASIPS2_CONTROL_DATDIR = 0x40,
68     LASIPS2_CONTROL_CLKDIR = 0x80,
69 } lasips2_control_reg_t;
70 
71 typedef enum {
72     LASIPS2_STATUS_RBNE = 0x01,
73     LASIPS2_STATUS_TBNE = 0x02,
74     LASIPS2_STATUS_TERR = 0x04,
75     LASIPS2_STATUS_PERR = 0x08,
76     LASIPS2_STATUS_CMPINTR = 0x10,
77     LASIPS2_STATUS_DATSHD = 0x40,
78     LASIPS2_STATUS_CLKSHD = 0x80,
79 } lasips2_status_reg_t;
80 
81 static const char *lasips2_read_reg_name(uint64_t addr)
82 {
83     switch (addr & 0xc) {
84     case REG_PS2_ID:
85         return " PS2_ID";
86 
87     case REG_PS2_RCVDATA:
88         return " PS2_RCVDATA";
89 
90     case REG_PS2_CONTROL:
91         return " PS2_CONTROL";
92 
93     case REG_PS2_STATUS:
94         return " PS2_STATUS";
95 
96     default:
97         return "";
98     }
99 }
100 
101 static const char *lasips2_write_reg_name(uint64_t addr)
102 {
103     switch (addr & 0x0c) {
104     case REG_PS2_RESET:
105         return " PS2_RESET";
106 
107     case REG_PS2_XMTDATA:
108         return " PS2_XMTDATA";
109 
110     case REG_PS2_CONTROL:
111         return " PS2_CONTROL";
112 
113     default:
114         return "";
115     }
116 }
117 
118 static void lasips2_update_irq(LASIPS2State *s)
119 {
120     int level = s->int_status ? 1 : 0;
121 
122     trace_lasips2_intr(level);
123     qemu_set_irq(s->irq, level);
124 }
125 
126 static void lasips2_set_irq(void *opaque, int n, int level)
127 {
128     LASIPS2State *s = LASIPS2(opaque);
129 
130     if (level) {
131         s->int_status |= BIT(n);
132     } else {
133         s->int_status &= ~BIT(n);
134     }
135 
136     lasips2_update_irq(s);
137 }
138 
139 static void lasips2_reg_write(void *opaque, hwaddr addr, uint64_t val,
140                               unsigned size)
141 {
142     LASIPS2Port *lp = LASIPS2_PORT(opaque);
143 
144     trace_lasips2_reg_write(size, lp->id, addr,
145                             lasips2_write_reg_name(addr), val);
146 
147     switch (addr & 0xc) {
148     case REG_PS2_CONTROL:
149         lp->control = val;
150         break;
151 
152     case REG_PS2_XMTDATA:
153         if (lp->control & LASIPS2_CONTROL_LOOPBACK) {
154             lp->buf = val;
155             lp->loopback_rbne = true;
156             qemu_set_irq(lp->irq, 1);
157             break;
158         }
159 
160         if (lp->id) {
161             ps2_write_mouse(PS2_MOUSE_DEVICE(lp->ps2dev), val);
162         } else {
163             ps2_write_keyboard(PS2_KBD_DEVICE(lp->ps2dev), val);
164         }
165         break;
166 
167     case REG_PS2_RESET:
168         break;
169 
170     default:
171         qemu_log_mask(LOG_UNIMP, "%s: unknown register 0x%02" HWADDR_PRIx "\n",
172                       __func__, addr);
173         break;
174     }
175 }
176 
177 static uint64_t lasips2_reg_read(void *opaque, hwaddr addr, unsigned size)
178 {
179     LASIPS2Port *lp = LASIPS2_PORT(opaque);
180     uint64_t ret = 0;
181 
182     switch (addr & 0xc) {
183     case REG_PS2_ID:
184         ret = lp->id;
185         break;
186 
187     case REG_PS2_RCVDATA:
188         if (lp->control & LASIPS2_CONTROL_LOOPBACK) {
189             lp->loopback_rbne = false;
190             qemu_set_irq(lp->irq, 0);
191             ret = lp->buf;
192             break;
193         }
194 
195         ret = ps2_read_data(lp->ps2dev);
196         break;
197 
198     case REG_PS2_CONTROL:
199         ret = lp->control;
200         break;
201 
202     case REG_PS2_STATUS:
203         ret = LASIPS2_STATUS_DATSHD | LASIPS2_STATUS_CLKSHD;
204 
205         if (lp->control & LASIPS2_CONTROL_DIAG) {
206             if (!(lp->control & LASIPS2_CONTROL_DATDIR)) {
207                 ret &= ~LASIPS2_STATUS_DATSHD;
208             }
209 
210             if (!(lp->control & LASIPS2_CONTROL_CLKDIR)) {
211                 ret &= ~LASIPS2_STATUS_CLKSHD;
212             }
213         }
214 
215         if (lp->control & LASIPS2_CONTROL_LOOPBACK) {
216             if (lp->loopback_rbne) {
217                 ret |= LASIPS2_STATUS_RBNE;
218             }
219         } else {
220             if (!ps2_queue_empty(lp->ps2dev)) {
221                 ret |= LASIPS2_STATUS_RBNE;
222             }
223         }
224 
225         if (lp->lasips2->int_status) {
226             ret |= LASIPS2_STATUS_CMPINTR;
227         }
228         break;
229 
230     default:
231         qemu_log_mask(LOG_UNIMP, "%s: unknown register 0x%02" HWADDR_PRIx "\n",
232                       __func__, addr);
233         break;
234     }
235 
236     trace_lasips2_reg_read(size, lp->id, addr,
237                            lasips2_read_reg_name(addr), ret);
238     return ret;
239 }
240 
241 static const MemoryRegionOps lasips2_reg_ops = {
242     .read = lasips2_reg_read,
243     .write = lasips2_reg_write,
244     .impl = {
245         .min_access_size = 1,
246         .max_access_size = 4,
247     },
248     .endianness = DEVICE_BIG_ENDIAN,
249 };
250 
251 static void lasips2_realize(DeviceState *dev, Error **errp)
252 {
253     LASIPS2State *s = LASIPS2(dev);
254     LASIPS2Port *lp;
255 
256     lp = LASIPS2_PORT(&s->kbd_port);
257     if (!(qdev_realize(DEVICE(lp), NULL, errp))) {
258         return;
259     }
260 
261     qdev_connect_gpio_out(DEVICE(lp), 0,
262                           qdev_get_gpio_in_named(dev, "lasips2-port-input-irq",
263                                                  lp->id));
264 
265     lp = LASIPS2_PORT(&s->mouse_port);
266     if (!(qdev_realize(DEVICE(lp), NULL, errp))) {
267         return;
268     }
269 
270     qdev_connect_gpio_out(DEVICE(lp), 0,
271                           qdev_get_gpio_in_named(dev, "lasips2-port-input-irq",
272                                                  lp->id));
273 }
274 
275 static void lasips2_init(Object *obj)
276 {
277     LASIPS2State *s = LASIPS2(obj);
278     LASIPS2Port *lp;
279 
280     object_initialize_child(obj, "lasips2-kbd-port", &s->kbd_port,
281                             TYPE_LASIPS2_KBD_PORT);
282     object_initialize_child(obj, "lasips2-mouse-port", &s->mouse_port,
283                             TYPE_LASIPS2_MOUSE_PORT);
284 
285     lp = LASIPS2_PORT(&s->kbd_port);
286     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &lp->reg);
287     lp = LASIPS2_PORT(&s->mouse_port);
288     sysbus_init_mmio(SYS_BUS_DEVICE(obj), &lp->reg);
289 
290     sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq);
291 
292     qdev_init_gpio_in_named(DEVICE(obj), lasips2_set_irq,
293                             "lasips2-port-input-irq", 2);
294 }
295 
296 static void lasips2_class_init(ObjectClass *klass, void *data)
297 {
298     DeviceClass *dc = DEVICE_CLASS(klass);
299 
300     dc->realize = lasips2_realize;
301     dc->vmsd = &vmstate_lasips2;
302     set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
303 }
304 
305 static const TypeInfo lasips2_info = {
306     .name          = TYPE_LASIPS2,
307     .parent        = TYPE_SYS_BUS_DEVICE,
308     .instance_init = lasips2_init,
309     .instance_size = sizeof(LASIPS2State),
310     .class_init    = lasips2_class_init,
311 };
312 
313 static void lasips2_port_set_irq(void *opaque, int n, int level)
314 {
315     LASIPS2Port *s = LASIPS2_PORT(opaque);
316 
317     qemu_set_irq(s->irq, level);
318 }
319 
320 static void lasips2_port_realize(DeviceState *dev, Error **errp)
321 {
322     LASIPS2Port *s = LASIPS2_PORT(dev);
323 
324     qdev_connect_gpio_out(DEVICE(s->ps2dev), PS2_DEVICE_IRQ,
325                           qdev_get_gpio_in_named(dev, "ps2-input-irq", 0));
326 }
327 
328 static void lasips2_port_init(Object *obj)
329 {
330     LASIPS2Port *s = LASIPS2_PORT(obj);
331 
332     qdev_init_gpio_out(DEVICE(obj), &s->irq, 1);
333     qdev_init_gpio_in_named(DEVICE(obj), lasips2_port_set_irq,
334                             "ps2-input-irq", 1);
335 }
336 
337 static void lasips2_port_class_init(ObjectClass *klass, void *data)
338 {
339     DeviceClass *dc = DEVICE_CLASS(klass);
340 
341     dc->realize = lasips2_port_realize;
342 }
343 
344 static const TypeInfo lasips2_port_info = {
345     .name          = TYPE_LASIPS2_PORT,
346     .parent        = TYPE_DEVICE,
347     .instance_init = lasips2_port_init,
348     .instance_size = sizeof(LASIPS2Port),
349     .class_init    = lasips2_port_class_init,
350     .class_size    = sizeof(LASIPS2PortDeviceClass),
351     .abstract      = true,
352 };
353 
354 static void lasips2_kbd_port_realize(DeviceState *dev, Error **errp)
355 {
356     LASIPS2Port *lp = LASIPS2_PORT(dev);
357     LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_GET_CLASS(lp);
358 
359     lp->ps2dev = ps2_kbd_init();
360     lpdc->parent_realize(dev, errp);
361 }
362 
363 static void lasips2_kbd_port_init(Object *obj)
364 {
365     LASIPS2KbdPort *s = LASIPS2_KBD_PORT(obj);
366     LASIPS2Port *lp = LASIPS2_PORT(obj);
367 
368     memory_region_init_io(&lp->reg, obj, &lasips2_reg_ops, lp, "lasips2-kbd",
369                           0x100);
370     lp->id = 0;
371     lp->lasips2 = container_of(s, LASIPS2State, kbd_port);
372 }
373 
374 static void lasips2_kbd_port_class_init(ObjectClass *klass, void *data)
375 {
376     DeviceClass *dc = DEVICE_CLASS(klass);
377     LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass);
378 
379     device_class_set_parent_realize(dc, lasips2_kbd_port_realize,
380                                     &lpdc->parent_realize);
381 }
382 
383 static const TypeInfo lasips2_kbd_port_info = {
384     .name          = TYPE_LASIPS2_KBD_PORT,
385     .parent        = TYPE_LASIPS2_PORT,
386     .instance_size = sizeof(LASIPS2KbdPort),
387     .instance_init = lasips2_kbd_port_init,
388     .class_init    = lasips2_kbd_port_class_init,
389 };
390 
391 static void lasips2_mouse_port_realize(DeviceState *dev, Error **errp)
392 {
393     LASIPS2Port *lp = LASIPS2_PORT(dev);
394     LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_GET_CLASS(lp);
395 
396     lp->ps2dev = ps2_mouse_init();
397     lpdc->parent_realize(dev, errp);
398 }
399 
400 static void lasips2_mouse_port_init(Object *obj)
401 {
402     LASIPS2MousePort *s = LASIPS2_MOUSE_PORT(obj);
403     LASIPS2Port *lp = LASIPS2_PORT(obj);
404 
405     memory_region_init_io(&lp->reg, obj, &lasips2_reg_ops, lp, "lasips2-mouse",
406                           0x100);
407     lp->id = 1;
408     lp->lasips2 = container_of(s, LASIPS2State, mouse_port);
409 }
410 
411 static void lasips2_mouse_port_class_init(ObjectClass *klass, void *data)
412 {
413     DeviceClass *dc = DEVICE_CLASS(klass);
414     LASIPS2PortDeviceClass *lpdc = LASIPS2_PORT_CLASS(klass);
415 
416     device_class_set_parent_realize(dc, lasips2_mouse_port_realize,
417                                     &lpdc->parent_realize);
418 }
419 
420 static const TypeInfo lasips2_mouse_port_info = {
421     .name          = TYPE_LASIPS2_MOUSE_PORT,
422     .parent        = TYPE_LASIPS2_PORT,
423     .instance_size = sizeof(LASIPS2MousePort),
424     .instance_init = lasips2_mouse_port_init,
425     .class_init    = lasips2_mouse_port_class_init,
426 };
427 
428 static void lasips2_register_types(void)
429 {
430     type_register_static(&lasips2_info);
431     type_register_static(&lasips2_port_info);
432     type_register_static(&lasips2_kbd_port_info);
433     type_register_static(&lasips2_mouse_port_info);
434 }
435 
436 type_init(lasips2_register_types)
437