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 "exec/address-spaces.h" 33c8e8bc85SThomas Huth #include "hw/hw.h" 34c8e8bc85SThomas Huth #include "hw/sysbus.h" 35c8e8bc85SThomas Huth #include "hw/m68k/next-cube.h" 36c8e8bc85SThomas Huth #include "ui/console.h" 37c8e8bc85SThomas Huth #include "sysemu/sysemu.h" 38c8e8bc85SThomas Huth #include "migration/vmstate.h" 39db1015e9SEduardo Habkost #include "qom/object.h" 40c8e8bc85SThomas Huth 41*8063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(NextKBDState, NEXTKBD) 42c8e8bc85SThomas Huth 43c8e8bc85SThomas Huth /* following defintions from next68k netbsd */ 44c8e8bc85SThomas Huth #define CSR_INT 0x00800000 45c8e8bc85SThomas Huth #define CSR_DATA 0x00400000 46c8e8bc85SThomas Huth 47c8e8bc85SThomas Huth #define KD_KEYMASK 0x007f 48c8e8bc85SThomas Huth #define KD_DIRECTION 0x0080 /* pressed or released */ 49c8e8bc85SThomas Huth #define KD_CNTL 0x0100 50c8e8bc85SThomas Huth #define KD_LSHIFT 0x0200 51c8e8bc85SThomas Huth #define KD_RSHIFT 0x0400 52c8e8bc85SThomas Huth #define KD_LCOMM 0x0800 53c8e8bc85SThomas Huth #define KD_RCOMM 0x1000 54c8e8bc85SThomas Huth #define KD_LALT 0x2000 55c8e8bc85SThomas Huth #define KD_RALT 0x4000 56c8e8bc85SThomas Huth #define KD_VALID 0x8000 /* only set for scancode keys ? */ 57c8e8bc85SThomas Huth #define KD_MODS 0x4f00 58c8e8bc85SThomas Huth 59c8e8bc85SThomas Huth #define KBD_QUEUE_SIZE 256 60c8e8bc85SThomas Huth 61c8e8bc85SThomas Huth typedef struct { 62c8e8bc85SThomas Huth uint8_t data[KBD_QUEUE_SIZE]; 63c8e8bc85SThomas Huth int rptr, wptr, count; 64c8e8bc85SThomas Huth } KBDQueue; 65c8e8bc85SThomas Huth 66c8e8bc85SThomas Huth 67db1015e9SEduardo Habkost struct NextKBDState { 68c8e8bc85SThomas Huth SysBusDevice sbd; 69c8e8bc85SThomas Huth MemoryRegion mr; 70c8e8bc85SThomas Huth KBDQueue queue; 71c8e8bc85SThomas Huth uint16_t shift; 72db1015e9SEduardo Habkost }; 73c8e8bc85SThomas Huth 74c8e8bc85SThomas Huth static void queue_code(void *opaque, int code); 75c8e8bc85SThomas Huth 76c8e8bc85SThomas Huth /* lots of magic numbers here */ 77c8e8bc85SThomas Huth static uint32_t kbd_read_byte(void *opaque, hwaddr addr) 78c8e8bc85SThomas Huth { 79c8e8bc85SThomas Huth switch (addr & 0x3) { 80c8e8bc85SThomas Huth case 0x0: /* 0xe000 */ 81c8e8bc85SThomas Huth return 0x80 | 0x20; 82c8e8bc85SThomas Huth 83c8e8bc85SThomas Huth case 0x1: /* 0xe001 */ 84c8e8bc85SThomas Huth return 0x80 | 0x40 | 0x20 | 0x10; 85c8e8bc85SThomas Huth 86c8e8bc85SThomas Huth case 0x2: /* 0xe002 */ 87c8e8bc85SThomas Huth /* returning 0x40 caused mach to hang */ 88c8e8bc85SThomas Huth return 0x10 | 0x2 | 0x1; 89c8e8bc85SThomas Huth 90c8e8bc85SThomas Huth default: 91c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read byte %"HWADDR_PRIx"\n", addr); 92c8e8bc85SThomas Huth } 93c8e8bc85SThomas Huth 94c8e8bc85SThomas Huth return 0; 95c8e8bc85SThomas Huth } 96c8e8bc85SThomas Huth 97c8e8bc85SThomas Huth static uint32_t kbd_read_word(void *opaque, hwaddr addr) 98c8e8bc85SThomas Huth { 99c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read word %"HWADDR_PRIx"\n", addr); 100c8e8bc85SThomas Huth return 0; 101c8e8bc85SThomas Huth } 102c8e8bc85SThomas Huth 103c8e8bc85SThomas Huth /* even more magic numbers */ 104c8e8bc85SThomas Huth static uint32_t kbd_read_long(void *opaque, hwaddr addr) 105c8e8bc85SThomas Huth { 106c8e8bc85SThomas Huth int key = 0; 107c8e8bc85SThomas Huth NextKBDState *s = NEXTKBD(opaque); 108c8e8bc85SThomas Huth KBDQueue *q = &s->queue; 109c8e8bc85SThomas Huth 110c8e8bc85SThomas Huth switch (addr & 0xf) { 111c8e8bc85SThomas Huth case 0x0: /* 0xe000 */ 112c8e8bc85SThomas Huth return 0xA0F09300; 113c8e8bc85SThomas Huth 114c8e8bc85SThomas Huth case 0x8: /* 0xe008 */ 115c8e8bc85SThomas Huth /* get keycode from buffer */ 116c8e8bc85SThomas Huth if (q->count > 0) { 117c8e8bc85SThomas Huth key = q->data[q->rptr]; 118c8e8bc85SThomas Huth if (++q->rptr == KBD_QUEUE_SIZE) { 119c8e8bc85SThomas Huth q->rptr = 0; 120c8e8bc85SThomas Huth } 121c8e8bc85SThomas Huth 122c8e8bc85SThomas Huth q->count--; 123c8e8bc85SThomas Huth 124c8e8bc85SThomas Huth if (s->shift) { 125c8e8bc85SThomas Huth key |= s->shift; 126c8e8bc85SThomas Huth } 127c8e8bc85SThomas Huth 128c8e8bc85SThomas Huth if (key & 0x80) { 129c8e8bc85SThomas Huth return 0; 130c8e8bc85SThomas Huth } else { 131c8e8bc85SThomas Huth return 0x10000000 | KD_VALID | key; 132c8e8bc85SThomas Huth } 133c8e8bc85SThomas Huth } else { 134c8e8bc85SThomas Huth return 0; 135c8e8bc85SThomas Huth } 136c8e8bc85SThomas Huth 137c8e8bc85SThomas Huth default: 138c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd read long %"HWADDR_PRIx"\n", addr); 139c8e8bc85SThomas Huth return 0; 140c8e8bc85SThomas Huth } 141c8e8bc85SThomas Huth } 142c8e8bc85SThomas Huth 143c8e8bc85SThomas Huth static uint64_t kbd_readfn(void *opaque, hwaddr addr, unsigned size) 144c8e8bc85SThomas Huth { 145c8e8bc85SThomas Huth switch (size) { 146c8e8bc85SThomas Huth case 1: 147c8e8bc85SThomas Huth return kbd_read_byte(opaque, addr); 148c8e8bc85SThomas Huth case 2: 149c8e8bc85SThomas Huth return kbd_read_word(opaque, addr); 150c8e8bc85SThomas Huth case 4: 151c8e8bc85SThomas Huth return kbd_read_long(opaque, addr); 152c8e8bc85SThomas Huth default: 153c8e8bc85SThomas Huth g_assert_not_reached(); 154c8e8bc85SThomas Huth } 155c8e8bc85SThomas Huth } 156c8e8bc85SThomas Huth 157c8e8bc85SThomas Huth static void kbd_writefn(void *opaque, hwaddr addr, uint64_t value, 158c8e8bc85SThomas Huth unsigned size) 159c8e8bc85SThomas Huth { 160c8e8bc85SThomas Huth qemu_log_mask(LOG_UNIMP, "NeXT kbd write: size=%u addr=0x%"HWADDR_PRIx 161c8e8bc85SThomas Huth "val=0x%"PRIx64"\n", size, addr, value); 162c8e8bc85SThomas Huth } 163c8e8bc85SThomas Huth 164c8e8bc85SThomas Huth static const MemoryRegionOps kbd_ops = { 165c8e8bc85SThomas Huth .read = kbd_readfn, 166c8e8bc85SThomas Huth .write = kbd_writefn, 167c8e8bc85SThomas Huth .valid.min_access_size = 1, 168c8e8bc85SThomas Huth .valid.max_access_size = 4, 169c8e8bc85SThomas Huth .endianness = DEVICE_NATIVE_ENDIAN, 170c8e8bc85SThomas Huth }; 171c8e8bc85SThomas Huth 172c8e8bc85SThomas Huth static void nextkbd_event(void *opaque, int ch) 173c8e8bc85SThomas Huth { 174c8e8bc85SThomas Huth /* 175c8e8bc85SThomas Huth * Will want to set vars for caps/num lock 176c8e8bc85SThomas Huth * if (ch & 0x80) -> key release 177c8e8bc85SThomas Huth * there's also e0 escaped scancodes that might need to be handled 178c8e8bc85SThomas Huth */ 179c8e8bc85SThomas Huth queue_code(opaque, ch); 180c8e8bc85SThomas Huth } 181c8e8bc85SThomas Huth 182c8e8bc85SThomas Huth static const unsigned char next_keycodes[128] = { 183c8e8bc85SThomas Huth 0x00, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x50, 0x4F, 184c8e8bc85SThomas Huth 0x4E, 0x1E, 0x1F, 0x20, 0x1D, 0x1C, 0x1B, 0x00, 185c8e8bc85SThomas Huth 0x42, 0x43, 0x44, 0x45, 0x48, 0x47, 0x46, 0x06, 186c8e8bc85SThomas Huth 0x07, 0x08, 0x00, 0x00, 0x2A, 0x00, 0x39, 0x3A, 187c8e8bc85SThomas Huth 0x3B, 0x3C, 0x3D, 0x40, 0x3F, 0x3E, 0x2D, 0x2C, 188c8e8bc85SThomas Huth 0x2B, 0x26, 0x00, 0x00, 0x31, 0x32, 0x33, 0x34, 189c8e8bc85SThomas Huth 0x35, 0x37, 0x36, 0x2e, 0x2f, 0x30, 0x00, 0x00, 190c8e8bc85SThomas Huth 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 191c8e8bc85SThomas Huth 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192c8e8bc85SThomas Huth 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 193c8e8bc85SThomas Huth 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 194c8e8bc85SThomas Huth 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 195c8e8bc85SThomas Huth }; 196c8e8bc85SThomas Huth 197c8e8bc85SThomas Huth static void queue_code(void *opaque, int code) 198c8e8bc85SThomas Huth { 199c8e8bc85SThomas Huth NextKBDState *s = NEXTKBD(opaque); 200c8e8bc85SThomas Huth KBDQueue *q = &s->queue; 201c8e8bc85SThomas Huth int key = code & KD_KEYMASK; 202c8e8bc85SThomas Huth int release = code & 0x80; 203c8e8bc85SThomas Huth static int ext; 204c8e8bc85SThomas Huth 205c8e8bc85SThomas Huth if (code == 0xE0) { 206c8e8bc85SThomas Huth ext = 1; 207c8e8bc85SThomas Huth } 208c8e8bc85SThomas Huth 209c8e8bc85SThomas Huth if (code == 0x2A || code == 0x1D || code == 0x36) { 210c8e8bc85SThomas Huth if (code == 0x2A) { 211c8e8bc85SThomas Huth s->shift = KD_LSHIFT; 212c8e8bc85SThomas Huth } else if (code == 0x36) { 213c8e8bc85SThomas Huth s->shift = KD_RSHIFT; 214c8e8bc85SThomas Huth ext = 0; 215c8e8bc85SThomas Huth } else if (code == 0x1D && !ext) { 216c8e8bc85SThomas Huth s->shift = KD_LCOMM; 217c8e8bc85SThomas Huth } else if (code == 0x1D && ext) { 218c8e8bc85SThomas Huth ext = 0; 219c8e8bc85SThomas Huth s->shift = KD_RCOMM; 220c8e8bc85SThomas Huth } 221c8e8bc85SThomas Huth return; 222c8e8bc85SThomas Huth } else if (code == (0x2A | 0x80) || code == (0x1D | 0x80) || 223c8e8bc85SThomas Huth code == (0x36 | 0x80)) { 224c8e8bc85SThomas Huth s->shift = 0; 225c8e8bc85SThomas Huth return; 226c8e8bc85SThomas Huth } 227c8e8bc85SThomas Huth 228c8e8bc85SThomas Huth if (q->count >= KBD_QUEUE_SIZE) { 229c8e8bc85SThomas Huth return; 230c8e8bc85SThomas Huth } 231c8e8bc85SThomas Huth 232c8e8bc85SThomas Huth q->data[q->wptr] = next_keycodes[key] | release; 233c8e8bc85SThomas Huth 234c8e8bc85SThomas Huth if (++q->wptr == KBD_QUEUE_SIZE) { 235c8e8bc85SThomas Huth q->wptr = 0; 236c8e8bc85SThomas Huth } 237c8e8bc85SThomas Huth 238c8e8bc85SThomas Huth q->count++; 239c8e8bc85SThomas Huth 240c8e8bc85SThomas Huth /* 241c8e8bc85SThomas Huth * might need to actually trigger the NeXT irq, but as the keyboard works 242c8e8bc85SThomas Huth * at the moment, I'll worry about it later 243c8e8bc85SThomas Huth */ 244c8e8bc85SThomas Huth /* s->update_irq(s->update_arg, 1); */ 245c8e8bc85SThomas Huth } 246c8e8bc85SThomas Huth 247c8e8bc85SThomas Huth static void nextkbd_reset(DeviceState *dev) 248c8e8bc85SThomas Huth { 249c8e8bc85SThomas Huth NextKBDState *nks = NEXTKBD(dev); 250c8e8bc85SThomas Huth 251c8e8bc85SThomas Huth memset(&nks->queue, 0, sizeof(KBDQueue)); 252c8e8bc85SThomas Huth nks->shift = 0; 253c8e8bc85SThomas Huth } 254c8e8bc85SThomas Huth 255c8e8bc85SThomas Huth static void nextkbd_realize(DeviceState *dev, Error **errp) 256c8e8bc85SThomas Huth { 257c8e8bc85SThomas Huth NextKBDState *s = NEXTKBD(dev); 258c8e8bc85SThomas Huth 259c8e8bc85SThomas Huth memory_region_init_io(&s->mr, OBJECT(dev), &kbd_ops, s, "next.kbd", 0x1000); 260c8e8bc85SThomas Huth sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr); 261c8e8bc85SThomas Huth 262c8e8bc85SThomas Huth qemu_add_kbd_event_handler(nextkbd_event, s); 263c8e8bc85SThomas Huth } 264c8e8bc85SThomas Huth 265c8e8bc85SThomas Huth static const VMStateDescription nextkbd_vmstate = { 266c8e8bc85SThomas Huth .name = TYPE_NEXTKBD, 267c8e8bc85SThomas Huth .unmigratable = 1, /* TODO: Implement this when m68k CPU is migratable */ 268c8e8bc85SThomas Huth }; 269c8e8bc85SThomas Huth 270c8e8bc85SThomas Huth static void nextkbd_class_init(ObjectClass *oc, void *data) 271c8e8bc85SThomas Huth { 272c8e8bc85SThomas Huth DeviceClass *dc = DEVICE_CLASS(oc); 273c8e8bc85SThomas Huth 274c8e8bc85SThomas Huth set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 275c8e8bc85SThomas Huth dc->vmsd = &nextkbd_vmstate; 276c8e8bc85SThomas Huth dc->realize = nextkbd_realize; 277c8e8bc85SThomas Huth dc->reset = nextkbd_reset; 278c8e8bc85SThomas Huth } 279c8e8bc85SThomas Huth 280c8e8bc85SThomas Huth static const TypeInfo nextkbd_info = { 281c8e8bc85SThomas Huth .name = TYPE_NEXTKBD, 282c8e8bc85SThomas Huth .parent = TYPE_SYS_BUS_DEVICE, 283c8e8bc85SThomas Huth .instance_size = sizeof(NextKBDState), 284c8e8bc85SThomas Huth .class_init = nextkbd_class_init, 285c8e8bc85SThomas Huth }; 286c8e8bc85SThomas Huth 287c8e8bc85SThomas Huth static void nextkbd_register_types(void) 288c8e8bc85SThomas Huth { 289c8e8bc85SThomas Huth type_register_static(&nextkbd_info); 290c8e8bc85SThomas Huth } 291c8e8bc85SThomas Huth 292c8e8bc85SThomas Huth type_init(nextkbd_register_types) 293