1c8e8bc85SThomas Huth /* 2c8e8bc85SThomas Huth * QEMU NeXT Keyboard/Mouse emulation 3c8e8bc85SThomas Huth * 4c8e8bc85SThomas Huth * Copyright (c) 2011 Bryce Lanham 5c8e8bc85SThomas Huth * 6c8e8bc85SThomas Huth * Permission is hereby granted, free of charge, to any person obtaining a copy 7c8e8bc85SThomas Huth * of this software and associated documentation files (the "Software"), to deal 8c8e8bc85SThomas Huth * in the Software without restriction, including without limitation the rights 9c8e8bc85SThomas Huth * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10c8e8bc85SThomas Huth * copies of the Software, and to permit persons to whom the Software is 11c8e8bc85SThomas Huth * furnished to do so, subject to the following conditions: 12c8e8bc85SThomas Huth * 13c8e8bc85SThomas Huth * The above copyright notice and this permission notice shall be included in 14c8e8bc85SThomas Huth * all copies or substantial portions of the Software. 15c8e8bc85SThomas Huth * 16c8e8bc85SThomas Huth * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17c8e8bc85SThomas Huth * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18c8e8bc85SThomas Huth * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19c8e8bc85SThomas Huth * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20c8e8bc85SThomas Huth * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21c8e8bc85SThomas Huth * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22c8e8bc85SThomas Huth * THE SOFTWARE. 23c8e8bc85SThomas Huth */ 24c8e8bc85SThomas Huth 25c8e8bc85SThomas Huth /* 26c8e8bc85SThomas Huth * This is admittedly hackish, but works well enough for basic input. Mouse 27c8e8bc85SThomas Huth * support will be added once we can boot something that needs the mouse. 28c8e8bc85SThomas Huth */ 29c8e8bc85SThomas Huth 30c8e8bc85SThomas Huth #include "qemu/osdep.h" 31c8e8bc85SThomas Huth #include "qemu/log.h" 32c8e8bc85SThomas Huth #include "hw/sysbus.h" 33c8e8bc85SThomas Huth #include "hw/m68k/next-cube.h" 34c8e8bc85SThomas Huth #include "ui/console.h" 35c8e8bc85SThomas Huth #include "migration/vmstate.h" 36db1015e9SEduardo Habkost #include "qom/object.h" 37c8e8bc85SThomas Huth 388063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(NextKBDState, NEXTKBD) 39c8e8bc85SThomas Huth 408b81968cSMichael Tokarev /* following definitions from next68k netbsd */ 41c8e8bc85SThomas Huth #define CSR_INT 0x00800000 42c8e8bc85SThomas Huth #define CSR_DATA 0x00400000 43c8e8bc85SThomas Huth 44c8e8bc85SThomas Huth #define KD_KEYMASK 0x007f 45c8e8bc85SThomas Huth #define KD_DIRECTION 0x0080 /* pressed or released */ 46c8e8bc85SThomas Huth #define KD_CNTL 0x0100 47c8e8bc85SThomas Huth #define KD_LSHIFT 0x0200 48c8e8bc85SThomas Huth #define KD_RSHIFT 0x0400 49c8e8bc85SThomas Huth #define KD_LCOMM 0x0800 50c8e8bc85SThomas Huth #define KD_RCOMM 0x1000 51c8e8bc85SThomas Huth #define KD_LALT 0x2000 52c8e8bc85SThomas Huth #define KD_RALT 0x4000 53c8e8bc85SThomas Huth #define KD_VALID 0x8000 /* only set for scancode keys ? */ 54c8e8bc85SThomas Huth #define KD_MODS 0x4f00 55c8e8bc85SThomas Huth 56c8e8bc85SThomas Huth #define KBD_QUEUE_SIZE 256 57c8e8bc85SThomas Huth 58c8e8bc85SThomas Huth typedef struct { 59c8e8bc85SThomas Huth uint8_t data[KBD_QUEUE_SIZE]; 60c8e8bc85SThomas Huth int rptr, wptr, count; 61c8e8bc85SThomas Huth } KBDQueue; 62c8e8bc85SThomas Huth 63c8e8bc85SThomas Huth 64db1015e9SEduardo Habkost struct NextKBDState { 65c8e8bc85SThomas Huth SysBusDevice sbd; 66c8e8bc85SThomas Huth MemoryRegion mr; 67c8e8bc85SThomas Huth KBDQueue queue; 68c8e8bc85SThomas Huth uint16_t shift; 69db1015e9SEduardo Habkost }; 70c8e8bc85SThomas Huth 71c8e8bc85SThomas Huth 72c8e8bc85SThomas Huth /* lots of magic numbers here */ 73c8e8bc85SThomas Huth static uint32_t kbd_read_byte(void *opaque, hwaddr addr) 74c8e8bc85SThomas Huth { 75c8e8bc85SThomas Huth switch (addr & 0x3) { 76c8e8bc85SThomas Huth case 0x0: /* 0xe000 */ 77c8e8bc85SThomas Huth return 0x80 | 0x20; 78c8e8bc85SThomas Huth 79c8e8bc85SThomas Huth case 0x1: /* 0xe001 */ 80c8e8bc85SThomas Huth return 0x80 | 0x40 | 0x20 | 0x10; 81c8e8bc85SThomas Huth 82c8e8bc85SThomas Huth case 0x2: /* 0xe002 */ 83c8e8bc85SThomas Huth /* returning 0x40 caused mach to hang */ 84c8e8bc85SThomas Huth return 0x10 | 0x2 | 0x1; 85c8e8bc85SThomas Huth 86c8e8bc85SThomas Huth default: 87c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr); 88c8e8bc85SThomas Huth } 89c8e8bc85SThomas Huth 90c8e8bc85SThomas Huth return 0; 91c8e8bc85SThomas Huth } 92c8e8bc85SThomas Huth 93c8e8bc85SThomas Huth static uint32_t kbd_read_word(void *opaque, hwaddr addr) 94c8e8bc85SThomas Huth { 95c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr); 96c8e8bc85SThomas Huth return 0; 97c8e8bc85SThomas Huth } 98c8e8bc85SThomas Huth 99c8e8bc85SThomas Huth /* even more magic numbers */ 100c8e8bc85SThomas Huth static uint32_t kbd_read_long(void *opaque, hwaddr addr) 101c8e8bc85SThomas Huth { 102c8e8bc85SThomas Huth int key = 0; 103c8e8bc85SThomas Huth NextKBDState *s = NEXTKBD(opaque); 104c8e8bc85SThomas Huth KBDQueue *q = &s->queue; 105c8e8bc85SThomas Huth 106c8e8bc85SThomas Huth switch (addr & 0xf) { 107c8e8bc85SThomas Huth case 0x0: /* 0xe000 */ 108c8e8bc85SThomas Huth return 0xA0F09300; 109c8e8bc85SThomas Huth 110c8e8bc85SThomas Huth case 0x8: /* 0xe008 */ 111c8e8bc85SThomas Huth /* get keycode from buffer */ 112c8e8bc85SThomas Huth if (q->count > 0) { 113c8e8bc85SThomas Huth key = q->data[q->rptr]; 114c8e8bc85SThomas Huth if (++q->rptr == KBD_QUEUE_SIZE) { 115c8e8bc85SThomas Huth q->rptr = 0; 116c8e8bc85SThomas Huth } 117c8e8bc85SThomas Huth 118c8e8bc85SThomas Huth q->count--; 119c8e8bc85SThomas Huth 120c8e8bc85SThomas Huth if (s->shift) { 121c8e8bc85SThomas Huth key |= s->shift; 122c8e8bc85SThomas Huth } 123c8e8bc85SThomas Huth 124c8e8bc85SThomas Huth if (key & 0x80) { 125c8e8bc85SThomas Huth return 0; 126c8e8bc85SThomas Huth } else { 127c8e8bc85SThomas Huth return 0x10000000 | KD_VALID | key; 128c8e8bc85SThomas Huth } 129c8e8bc85SThomas Huth } else { 130c8e8bc85SThomas Huth return 0; 131c8e8bc85SThomas Huth } 132c8e8bc85SThomas Huth 133c8e8bc85SThomas Huth default: 134c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr); 135c8e8bc85SThomas Huth return 0; 136c8e8bc85SThomas Huth } 137c8e8bc85SThomas Huth } 138c8e8bc85SThomas Huth 139c8e8bc85SThomas Huth static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size) 140c8e8bc85SThomas Huth { 141c8e8bc85SThomas Huth switch (size) { 142c8e8bc85SThomas Huth case 1: 143c8e8bc85SThomas Huth return kbd_read_byte(opaque, addr); 144c8e8bc85SThomas Huth case 2: 145c8e8bc85SThomas Huth return kbd_read_word(opaque, addr); 146c8e8bc85SThomas Huth case 4: 147c8e8bc85SThomas Huth return kbd_read_long(opaque, addr); 148c8e8bc85SThomas Huth default: 149c8e8bc85SThomas Huth g_assert_not_reached(); 150c8e8bc85SThomas Huth } 151c8e8bc85SThomas Huth } 152c8e8bc85SThomas Huth 153c8e8bc85SThomas Huth static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value, 154c8e8bc85SThomas Huth unsigned size) 155c8e8bc85SThomas Huth { 156c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx 157c8e8bc85SThomas Huth "val=0x%"PRIx64"\n", size, addr, value); 158c8e8bc85SThomas Huth } 159c8e8bc85SThomas Huth 160c8e8bc85SThomas Huth static const MemoryRegionOps kbd_ops = { 161c8e8bc85SThomas Huth .read = kbd_readfn, 162c8e8bc85SThomas Huth .write = kbd_writefn, 163c8e8bc85SThomas Huth .valid.min_access_size = 1, 164c8e8bc85SThomas Huth .valid.max_access_size = 4, 165c8e8bc85SThomas Huth .endianness = DEVICE_NATIVE_ENDIAN, 166c8e8bc85SThomas Huth }; 167c8e8bc85SThomas Huth 168*44e21ef0SMark Cave-Ayland static const int qcode_to_nextkbd_keycode[] = { 169*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_ESC] = 0x49, 170*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_1] = 0x4a, 171*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_2] = 0x4b, 172*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_3] = 0x4c, 173*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_4] = 0x4d, 174*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_5] = 0x50, 175*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_6] = 0x4f, 176*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_7] = 0x4e, 177*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_8] = 0x1e, 178*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_9] = 0x1f, 179*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_0] = 0x20, 180*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_MINUS] = 0x1d, 181*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_EQUAL] = 0x1c, 182*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_BACKSPACE] = 0x1b, 183c8e8bc85SThomas Huth 184*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_Q] = 0x42, 185*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_W] = 0x43, 186*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_E] = 0x44, 187*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_R] = 0x45, 188*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_T] = 0x48, 189*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_Y] = 0x47, 190*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_U] = 0x46, 191*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_I] = 0x06, 192*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_O] = 0x07, 193*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_P] = 0x08, 194*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_RET] = 0x2a, 195*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_A] = 0x39, 196*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_S] = 0x3a, 197*44e21ef0SMark Cave-Ayland 198*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_D] = 0x3b, 199*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_F] = 0x3c, 200*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_G] = 0x3d, 201*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_H] = 0x40, 202*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_J] = 0x3f, 203*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_K] = 0x3e, 204*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_L] = 0x2d, 205*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_SEMICOLON] = 0x2c, 206*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_APOSTROPHE] = 0x2b, 207*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_GRAVE_ACCENT] = 0x26, 208*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_Z] = 0x31, 209*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_X] = 0x32, 210*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_C] = 0x33, 211*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_V] = 0x34, 212*44e21ef0SMark Cave-Ayland 213*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_B] = 0x35, 214*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_N] = 0x37, 215*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_M] = 0x36, 216*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_COMMA] = 0x2e, 217*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_DOT] = 0x2f, 218*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_SLASH] = 0x30, 219*44e21ef0SMark Cave-Ayland 220*44e21ef0SMark Cave-Ayland [Q_KEY_CODE_SPC] = 0x38, 221c8e8bc85SThomas Huth }; 222c8e8bc85SThomas Huth 223*44e21ef0SMark Cave-Ayland static void nextkbd_put_keycode(NextKBDState *s, int keycode) 224c8e8bc85SThomas Huth { 225c8e8bc85SThomas Huth KBDQueue *q = &s->queue; 226c8e8bc85SThomas Huth 227c8e8bc85SThomas Huth if (q->count >= KBD_QUEUE_SIZE) { 228c8e8bc85SThomas Huth return; 229c8e8bc85SThomas Huth } 230c8e8bc85SThomas Huth 231*44e21ef0SMark Cave-Ayland q->data[q->wptr] = keycode; 232c8e8bc85SThomas Huth if (++q->wptr == KBD_QUEUE_SIZE) { 233c8e8bc85SThomas Huth q->wptr = 0; 234c8e8bc85SThomas Huth } 235c8e8bc85SThomas Huth 236c8e8bc85SThomas Huth q->count++; 237c8e8bc85SThomas Huth 238c8e8bc85SThomas Huth /* 239c8e8bc85SThomas Huth * might need to actually trigger the NeXT irq, but as the keyboard works 240c8e8bc85SThomas Huth * at the moment, I'll worry about it later 241c8e8bc85SThomas Huth */ 242c8e8bc85SThomas Huth /* s->update_irq(s->update_arg, 1); */ 243c8e8bc85SThomas Huth } 244c8e8bc85SThomas Huth 245*44e21ef0SMark Cave-Ayland static void nextkbd_event(DeviceState *dev, QemuConsole *src, InputEvent *evt) 246*44e21ef0SMark Cave-Ayland { 247*44e21ef0SMark Cave-Ayland NextKBDState *s = NEXTKBD(dev); 248*44e21ef0SMark Cave-Ayland int qcode, keycode; 249*44e21ef0SMark Cave-Ayland bool key_down = evt->u.key.data->down; 250*44e21ef0SMark Cave-Ayland 251*44e21ef0SMark Cave-Ayland qcode = qemu_input_key_value_to_qcode(evt->u.key.data->key); 252*44e21ef0SMark Cave-Ayland if (qcode >= ARRAY_SIZE(qcode_to_nextkbd_keycode)) { 253*44e21ef0SMark Cave-Ayland return; 254*44e21ef0SMark Cave-Ayland } 255*44e21ef0SMark Cave-Ayland 256*44e21ef0SMark Cave-Ayland /* Shift key currently has no keycode, so handle separately */ 257*44e21ef0SMark Cave-Ayland if (qcode == Q_KEY_CODE_SHIFT) { 258*44e21ef0SMark Cave-Ayland if (key_down) { 259*44e21ef0SMark Cave-Ayland s->shift |= KD_LSHIFT; 260*44e21ef0SMark Cave-Ayland } else { 261*44e21ef0SMark Cave-Ayland s->shift &= ~KD_LSHIFT; 262*44e21ef0SMark Cave-Ayland } 263*44e21ef0SMark Cave-Ayland } 264*44e21ef0SMark Cave-Ayland 265*44e21ef0SMark Cave-Ayland if (qcode == Q_KEY_CODE_SHIFT_R) { 266*44e21ef0SMark Cave-Ayland if (key_down) { 267*44e21ef0SMark Cave-Ayland s->shift |= KD_RSHIFT; 268*44e21ef0SMark Cave-Ayland } else { 269*44e21ef0SMark Cave-Ayland s->shift &= ~KD_RSHIFT; 270*44e21ef0SMark Cave-Ayland } 271*44e21ef0SMark Cave-Ayland } 272*44e21ef0SMark Cave-Ayland 273*44e21ef0SMark Cave-Ayland keycode = qcode_to_nextkbd_keycode[qcode]; 274*44e21ef0SMark Cave-Ayland if (!keycode) { 275*44e21ef0SMark Cave-Ayland return; 276*44e21ef0SMark Cave-Ayland } 277*44e21ef0SMark Cave-Ayland 278*44e21ef0SMark Cave-Ayland /* If key release event, create keyboard break code */ 279*44e21ef0SMark Cave-Ayland if (!key_down) { 280*44e21ef0SMark Cave-Ayland keycode |= 0x80; 281*44e21ef0SMark Cave-Ayland } 282*44e21ef0SMark Cave-Ayland 283*44e21ef0SMark Cave-Ayland nextkbd_put_keycode(s, keycode); 284*44e21ef0SMark Cave-Ayland } 285*44e21ef0SMark Cave-Ayland 286*44e21ef0SMark Cave-Ayland static const QemuInputHandler nextkbd_handler = { 287*44e21ef0SMark Cave-Ayland .name = "QEMU NeXT Keyboard", 288*44e21ef0SMark Cave-Ayland .mask = INPUT_EVENT_MASK_KEY, 289*44e21ef0SMark Cave-Ayland .event = nextkbd_event, 290*44e21ef0SMark Cave-Ayland }; 291*44e21ef0SMark Cave-Ayland 292c8e8bc85SThomas Huth static void nextkbd_reset(DeviceState *dev) 293c8e8bc85SThomas Huth { 294c8e8bc85SThomas Huth NextKBDState *nks = NEXTKBD(dev); 295c8e8bc85SThomas Huth 296c8e8bc85SThomas Huth memset(&nks->queue, 0, sizeof(KBDQueue)); 297c8e8bc85SThomas Huth nks->shift = 0; 298c8e8bc85SThomas Huth } 299c8e8bc85SThomas Huth 300c8e8bc85SThomas Huth static void nextkbd_realize(DeviceState *dev, Error **errp) 301c8e8bc85SThomas Huth { 302c8e8bc85SThomas Huth NextKBDState *s = NEXTKBD(dev); 303c8e8bc85SThomas Huth 304c8e8bc85SThomas Huth memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000); 305c8e8bc85SThomas Huth sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 306c8e8bc85SThomas Huth 307*44e21ef0SMark Cave-Ayland qemu_input_handler_register(dev, &nextkbd_handler); 308c8e8bc85SThomas Huth } 309c8e8bc85SThomas Huth 310c8e8bc85SThomas Huth static const VMStateDescription nextkbd_vmstate = { 311c8e8bc85SThomas Huth .name = TYPE_NEXTKBD, 312c8e8bc85SThomas Huth .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */ 313c8e8bc85SThomas Huth }; 314c8e8bc85SThomas Huth 315c8e8bc85SThomas Huth static void nextkbd_class_init(ObjectClass *oc, void *data) 316c8e8bc85SThomas Huth { 317c8e8bc85SThomas Huth DeviceClass *dc = DEVICE_CLASS(oc); 318c8e8bc85SThomas Huth 319c8e8bc85SThomas Huth set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 320c8e8bc85SThomas Huth dc->vmsd = &nextkbd_vmstate; 321c8e8bc85SThomas Huth dc->realize = nextkbd_realize; 322e3d08143SPeter Maydell device_class_set_legacy_reset(dc, nextkbd_reset); 323c8e8bc85SThomas Huth } 324c8e8bc85SThomas Huth 325c8e8bc85SThomas Huth static const TypeInfo nextkbd_info = { 326c8e8bc85SThomas Huth .name = TYPE_NEXTKBD, 327c8e8bc85SThomas Huth .parent = TYPE_SYS_BUS_DEVICE, 328c8e8bc85SThomas Huth .instance_size = sizeof(NextKBDState), 329c8e8bc85SThomas Huth .class_init = nextkbd_class_init, 330c8e8bc85SThomas Huth }; 331c8e8bc85SThomas Huth 332c8e8bc85SThomas Huth static void nextkbd_register_types(void) 333c8e8bc85SThomas Huth { 334c8e8bc85SThomas Huth type_register_static(&nextkbd_info); 335c8e8bc85SThomas Huth } 336c8e8bc85SThomas Huth 337c8e8bc85SThomas Huth type_init(nextkbd_register_types) 338