syborg_keyboard.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Syborg keyboard controller.
  3. *
  4. * Copyright (c) 2008 CodeSourcery
  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 "sysbus.h"
  25. #include "console.h"
  26. #include "syborg.h"
  27. //#define DEBUG_SYBORG_KEYBOARD
  28. #ifdef DEBUG_SYBORG_KEYBOARD
  29. #define DPRINTF(fmt, ...) \
  30. do { printf("syborg_keyboard: " fmt , ##args); } while (0)
  31. #define BADF(fmt, ...) \
  32. do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
  33. exit(1);} while (0)
  34. #else
  35. #define DPRINTF(fmt, ...) do {} while(0)
  36. #define BADF(fmt, ...) \
  37. do { fprintf(stderr, "syborg_keyboard: error: " fmt , ## __VA_ARGS__); \
  38. } while (0)
  39. #endif
  40. enum {
  41. KBD_ID = 0,
  42. KBD_DATA = 1,
  43. KBD_FIFO_COUNT = 2,
  44. KBD_INT_ENABLE = 3,
  45. KBD_FIFO_SIZE = 4
  46. };
  47. typedef struct {
  48. SysBusDevice busdev;
  49. uint32_t int_enabled;
  50. int extension_bit;
  51. uint32_t fifo_size;
  52. uint32_t *key_fifo;
  53. uint32_t read_pos, read_count;
  54. qemu_irq irq;
  55. } SyborgKeyboardState;
  56. static void syborg_keyboard_update(SyborgKeyboardState *s)
  57. {
  58. int level = s->read_count && s->int_enabled;
  59. DPRINTF("Update IRQ %d\n", level);
  60. qemu_set_irq(s->irq, level);
  61. }
  62. static uint32_t syborg_keyboard_read(void *opaque, target_phys_addr_t offset)
  63. {
  64. SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
  65. int c;
  66. DPRINTF("reg read %d\n", (int)offset);
  67. offset &= 0xfff;
  68. switch (offset >> 2) {
  69. case KBD_ID:
  70. return SYBORG_ID_KEYBOARD;
  71. case KBD_FIFO_COUNT:
  72. return s->read_count;
  73. case KBD_DATA:
  74. if (s->read_count == 0) {
  75. c = -1;
  76. DPRINTF("FIFO underflow\n");
  77. } else {
  78. c = s->key_fifo[s->read_pos];
  79. DPRINTF("FIFO read 0x%x\n", c);
  80. s->read_count--;
  81. s->read_pos++;
  82. if (s->read_pos == s->fifo_size)
  83. s->read_pos = 0;
  84. }
  85. syborg_keyboard_update(s);
  86. return c;
  87. case KBD_INT_ENABLE:
  88. return s->int_enabled;
  89. case KBD_FIFO_SIZE:
  90. return s->fifo_size;
  91. default:
  92. cpu_abort(cpu_single_env, "syborg_keyboard_read: Bad offset %x\n",
  93. (int)offset);
  94. return 0;
  95. }
  96. }
  97. static void syborg_keyboard_write(void *opaque, target_phys_addr_t offset,
  98. uint32_t value)
  99. {
  100. SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
  101. DPRINTF("reg write %d\n", (int)offset);
  102. offset &= 0xfff;
  103. switch (offset >> 2) {
  104. case KBD_INT_ENABLE:
  105. s->int_enabled = value;
  106. syborg_keyboard_update(s);
  107. break;
  108. default:
  109. cpu_abort(cpu_single_env, "syborg_keyboard_write: Bad offset %x\n",
  110. (int)offset);
  111. }
  112. }
  113. static CPUReadMemoryFunc * const syborg_keyboard_readfn[] = {
  114. syborg_keyboard_read,
  115. syborg_keyboard_read,
  116. syborg_keyboard_read
  117. };
  118. static CPUWriteMemoryFunc * const syborg_keyboard_writefn[] = {
  119. syborg_keyboard_write,
  120. syborg_keyboard_write,
  121. syborg_keyboard_write
  122. };
  123. static void syborg_keyboard_event(void *opaque, int keycode)
  124. {
  125. SyborgKeyboardState *s = (SyborgKeyboardState *)opaque;
  126. int slot;
  127. uint32_t val;
  128. /* Strip off 0xe0 prefixes and reconstruct the full scancode. */
  129. if (keycode == 0xe0 && !s->extension_bit) {
  130. DPRINTF("Extension bit\n");
  131. s->extension_bit = 0x80;
  132. return;
  133. }
  134. val = (keycode & 0x7f) | s->extension_bit;
  135. if (keycode & 0x80)
  136. val |= 0x80000000u;
  137. s->extension_bit = 0;
  138. DPRINTF("FIFO push 0x%x\n", val);
  139. slot = s->read_pos + s->read_count;
  140. if (slot >= s->fifo_size)
  141. slot -= s->fifo_size;
  142. if (s->read_count < s->fifo_size) {
  143. s->read_count++;
  144. s->key_fifo[slot] = val;
  145. } else {
  146. fprintf(stderr, "syborg_keyboard error! FIFO overflow\n");
  147. }
  148. syborg_keyboard_update(s);
  149. }
  150. static const VMStateDescription vmstate_syborg_keyboard = {
  151. .name = "syborg_keyboard",
  152. .version_id = 1,
  153. .minimum_version_id = 1,
  154. .minimum_version_id_old = 1,
  155. .fields = (VMStateField[]) {
  156. VMSTATE_UINT32_EQUAL(fifo_size, SyborgKeyboardState),
  157. VMSTATE_UINT32(int_enabled, SyborgKeyboardState),
  158. VMSTATE_UINT32(read_pos, SyborgKeyboardState),
  159. VMSTATE_UINT32(read_count, SyborgKeyboardState),
  160. VMSTATE_VARRAY_UINT32(key_fifo, SyborgKeyboardState, fifo_size, 1,
  161. vmstate_info_uint32, uint32),
  162. VMSTATE_END_OF_LIST()
  163. }
  164. };
  165. static int syborg_keyboard_init(SysBusDevice *dev)
  166. {
  167. SyborgKeyboardState *s = FROM_SYSBUS(SyborgKeyboardState, dev);
  168. int iomemtype;
  169. sysbus_init_irq(dev, &s->irq);
  170. iomemtype = cpu_register_io_memory(syborg_keyboard_readfn,
  171. syborg_keyboard_writefn, s,
  172. DEVICE_NATIVE_ENDIAN);
  173. sysbus_init_mmio(dev, 0x1000, iomemtype);
  174. if (s->fifo_size <= 0) {
  175. fprintf(stderr, "syborg_keyboard: fifo too small\n");
  176. s->fifo_size = 16;
  177. }
  178. s->key_fifo = g_malloc0(s->fifo_size * sizeof(s->key_fifo[0]));
  179. qemu_add_kbd_event_handler(syborg_keyboard_event, s);
  180. vmstate_register(&dev->qdev, -1, &vmstate_syborg_keyboard, s);
  181. return 0;
  182. }
  183. static SysBusDeviceInfo syborg_keyboard_info = {
  184. .init = syborg_keyboard_init,
  185. .qdev.name = "syborg,keyboard",
  186. .qdev.size = sizeof(SyborgKeyboardState),
  187. .qdev.props = (Property[]) {
  188. DEFINE_PROP_UINT32("fifo-size", SyborgKeyboardState, fifo_size, 16),
  189. DEFINE_PROP_END_OF_LIST(),
  190. }
  191. };
  192. static void syborg_keyboard_register_devices(void)
  193. {
  194. sysbus_register_withprop(&syborg_keyboard_info);
  195. }
  196. device_init(syborg_keyboard_register_devices)