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