PageRenderTime 25ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/tools/qemu/hw/pckbd.c

https://github.com/coriolis/vmxray
C | 461 lines | 371 code | 49 blank | 41 comment | 17 complexity | 1fd5356bd03360dfa9c35b3dcd3f7319 MD5 | raw file
  1. /*
  2. * QEMU PC keyboard emulation
  3. *
  4. * Copyright (c) 2003 Fabrice Bellard
  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 "hw.h"
  25. #include "isa.h"
  26. #include "pc.h"
  27. #include "ps2.h"
  28. #include "sysemu.h"
  29. /* debug PC keyboard */
  30. //#define DEBUG_KBD
  31. /* Keyboard Controller Commands */
  32. #define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */
  33. #define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */
  34. #define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */
  35. #define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */
  36. #define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */
  37. #define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */
  38. #define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */
  39. #define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */
  40. #define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */
  41. #define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */
  42. #define KBD_CCMD_READ_INPORT 0xC0 /* read input port */
  43. #define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */
  44. #define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */
  45. #define KBD_CCMD_WRITE_OBUF 0xD2
  46. #define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if
  47. initiated by the auxiliary device */
  48. #define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */
  49. #define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */
  50. #define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */
  51. #define KBD_CCMD_RESET 0xFE
  52. /* Keyboard Commands */
  53. #define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */
  54. #define KBD_CMD_ECHO 0xEE
  55. #define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */
  56. #define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */
  57. #define KBD_CMD_ENABLE 0xF4 /* Enable scanning */
  58. #define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */
  59. #define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */
  60. #define KBD_CMD_RESET 0xFF /* Reset */
  61. /* Keyboard Replies */
  62. #define KBD_REPLY_POR 0xAA /* Power on reset */
  63. #define KBD_REPLY_ACK 0xFA /* Command ACK */
  64. #define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */
  65. /* Status Register Bits */
  66. #define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */
  67. #define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */
  68. #define KBD_STAT_SELFTEST 0x04 /* Self test successful */
  69. #define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */
  70. #define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */
  71. #define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */
  72. #define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */
  73. #define KBD_STAT_PERR 0x80 /* Parity error */
  74. /* Controller Mode Register Bits */
  75. #define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */
  76. #define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */
  77. #define KBD_MODE_SYS 0x04 /* The system flag (?) */
  78. #define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */
  79. #define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */
  80. #define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */
  81. #define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */
  82. #define KBD_MODE_RFU 0x80
  83. /* Mouse Commands */
  84. #define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */
  85. #define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */
  86. #define AUX_SET_RES 0xE8 /* Set resolution */
  87. #define AUX_GET_SCALE 0xE9 /* Get scaling factor */
  88. #define AUX_SET_STREAM 0xEA /* Set stream mode */
  89. #define AUX_POLL 0xEB /* Poll */
  90. #define AUX_RESET_WRAP 0xEC /* Reset wrap mode */
  91. #define AUX_SET_WRAP 0xEE /* Set wrap mode */
  92. #define AUX_SET_REMOTE 0xF0 /* Set remote mode */
  93. #define AUX_GET_TYPE 0xF2 /* Get type */
  94. #define AUX_SET_SAMPLE 0xF3 /* Set sample rate */
  95. #define AUX_ENABLE_DEV 0xF4 /* Enable aux device */
  96. #define AUX_DISABLE_DEV 0xF5 /* Disable aux device */
  97. #define AUX_SET_DEFAULT 0xF6
  98. #define AUX_RESET 0xFF /* Reset aux device */
  99. #define AUX_ACK 0xFA /* Command byte ACK. */
  100. #define MOUSE_STATUS_REMOTE 0x40
  101. #define MOUSE_STATUS_ENABLED 0x20
  102. #define MOUSE_STATUS_SCALE21 0x10
  103. #define KBD_PENDING_KBD 1
  104. #define KBD_PENDING_AUX 2
  105. typedef struct KBDState {
  106. uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
  107. uint8_t status;
  108. uint8_t mode;
  109. /* Bitmask of devices with data available. */
  110. uint8_t pending;
  111. void *kbd;
  112. void *mouse;
  113. qemu_irq irq_kbd;
  114. qemu_irq irq_mouse;
  115. target_phys_addr_t mask;
  116. } KBDState;
  117. static KBDState kbd_state;
  118. /* update irq and KBD_STAT_[MOUSE_]OBF */
  119. /* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
  120. incorrect, but it avoids having to simulate exact delays */
  121. static void kbd_update_irq(KBDState *s)
  122. {
  123. int irq_kbd_level, irq_mouse_level;
  124. irq_kbd_level = 0;
  125. irq_mouse_level = 0;
  126. s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
  127. if (s->pending) {
  128. s->status |= KBD_STAT_OBF;
  129. /* kbd data takes priority over aux data. */
  130. if (s->pending == KBD_PENDING_AUX) {
  131. s->status |= KBD_STAT_MOUSE_OBF;
  132. if (s->mode & KBD_MODE_MOUSE_INT)
  133. irq_mouse_level = 1;
  134. } else {
  135. if ((s->mode & KBD_MODE_KBD_INT) &&
  136. !(s->mode & KBD_MODE_DISABLE_KBD))
  137. irq_kbd_level = 1;
  138. }
  139. }
  140. qemu_set_irq(s->irq_kbd, irq_kbd_level);
  141. qemu_set_irq(s->irq_mouse, irq_mouse_level);
  142. }
  143. static void kbd_update_kbd_irq(void *opaque, int level)
  144. {
  145. KBDState *s = (KBDState *)opaque;
  146. if (level)
  147. s->pending |= KBD_PENDING_KBD;
  148. else
  149. s->pending &= ~KBD_PENDING_KBD;
  150. kbd_update_irq(s);
  151. }
  152. static void kbd_update_aux_irq(void *opaque, int level)
  153. {
  154. KBDState *s = (KBDState *)opaque;
  155. if (level)
  156. s->pending |= KBD_PENDING_AUX;
  157. else
  158. s->pending &= ~KBD_PENDING_AUX;
  159. kbd_update_irq(s);
  160. }
  161. static uint32_t kbd_read_status(void *opaque, uint32_t addr)
  162. {
  163. KBDState *s = opaque;
  164. int val;
  165. val = s->status;
  166. #if defined(DEBUG_KBD)
  167. printf("kbd: read status=0x%02x\n", val);
  168. #endif
  169. return val;
  170. }
  171. static void kbd_queue(KBDState *s, int b, int aux)
  172. {
  173. if (aux)
  174. ps2_queue(s->mouse, b);
  175. else
  176. ps2_queue(s->kbd, b);
  177. }
  178. static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
  179. {
  180. KBDState *s = opaque;
  181. #ifdef DEBUG_KBD
  182. printf("kbd: write cmd=0x%02x\n", val);
  183. #endif
  184. switch(val) {
  185. case KBD_CCMD_READ_MODE:
  186. kbd_queue(s, s->mode, 0);
  187. break;
  188. case KBD_CCMD_WRITE_MODE:
  189. case KBD_CCMD_WRITE_OBUF:
  190. case KBD_CCMD_WRITE_AUX_OBUF:
  191. case KBD_CCMD_WRITE_MOUSE:
  192. case KBD_CCMD_WRITE_OUTPORT:
  193. s->write_cmd = val;
  194. break;
  195. case KBD_CCMD_MOUSE_DISABLE:
  196. s->mode |= KBD_MODE_DISABLE_MOUSE;
  197. break;
  198. case KBD_CCMD_MOUSE_ENABLE:
  199. s->mode &= ~KBD_MODE_DISABLE_MOUSE;
  200. break;
  201. case KBD_CCMD_TEST_MOUSE:
  202. kbd_queue(s, 0x00, 0);
  203. break;
  204. case KBD_CCMD_SELF_TEST:
  205. s->status |= KBD_STAT_SELFTEST;
  206. kbd_queue(s, 0x55, 0);
  207. break;
  208. case KBD_CCMD_KBD_TEST:
  209. kbd_queue(s, 0x00, 0);
  210. break;
  211. case KBD_CCMD_KBD_DISABLE:
  212. s->mode |= KBD_MODE_DISABLE_KBD;
  213. kbd_update_irq(s);
  214. break;
  215. case KBD_CCMD_KBD_ENABLE:
  216. s->mode &= ~KBD_MODE_DISABLE_KBD;
  217. kbd_update_irq(s);
  218. break;
  219. case KBD_CCMD_READ_INPORT:
  220. kbd_queue(s, 0x00, 0);
  221. break;
  222. case KBD_CCMD_READ_OUTPORT:
  223. /* XXX: check that */
  224. #ifdef TARGET_I386
  225. val = 0x01 | (ioport_get_a20() << 1);
  226. #else
  227. val = 0x01;
  228. #endif
  229. if (s->status & KBD_STAT_OBF)
  230. val |= 0x10;
  231. if (s->status & KBD_STAT_MOUSE_OBF)
  232. val |= 0x20;
  233. kbd_queue(s, val, 0);
  234. break;
  235. #ifdef TARGET_I386
  236. case KBD_CCMD_ENABLE_A20:
  237. ioport_set_a20(1);
  238. break;
  239. case KBD_CCMD_DISABLE_A20:
  240. ioport_set_a20(0);
  241. break;
  242. #endif
  243. case KBD_CCMD_RESET:
  244. qemu_system_reset_request();
  245. break;
  246. case 0xff:
  247. /* ignore that - I don't know what is its use */
  248. break;
  249. default:
  250. fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
  251. break;
  252. }
  253. }
  254. static uint32_t kbd_read_data(void *opaque, uint32_t addr)
  255. {
  256. KBDState *s = opaque;
  257. uint32_t val;
  258. if (s->pending == KBD_PENDING_AUX)
  259. val = ps2_read_data(s->mouse);
  260. else
  261. val = ps2_read_data(s->kbd);
  262. #if defined(DEBUG_KBD)
  263. printf("kbd: read data=0x%02x\n", val);
  264. #endif
  265. return val;
  266. }
  267. static void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
  268. {
  269. KBDState *s = opaque;
  270. #ifdef DEBUG_KBD
  271. printf("kbd: write data=0x%02x\n", val);
  272. #endif
  273. switch(s->write_cmd) {
  274. case 0:
  275. ps2_write_keyboard(s->kbd, val);
  276. break;
  277. case KBD_CCMD_WRITE_MODE:
  278. s->mode = val;
  279. ps2_keyboard_set_translation(s->kbd, (s->mode & KBD_MODE_KCC) != 0);
  280. /* ??? */
  281. kbd_update_irq(s);
  282. break;
  283. case KBD_CCMD_WRITE_OBUF:
  284. kbd_queue(s, val, 0);
  285. break;
  286. case KBD_CCMD_WRITE_AUX_OBUF:
  287. kbd_queue(s, val, 1);
  288. break;
  289. case KBD_CCMD_WRITE_OUTPORT:
  290. #ifdef TARGET_I386
  291. ioport_set_a20((val >> 1) & 1);
  292. #endif
  293. if (!(val & 1)) {
  294. qemu_system_reset_request();
  295. }
  296. break;
  297. case KBD_CCMD_WRITE_MOUSE:
  298. ps2_write_mouse(s->mouse, val);
  299. break;
  300. default:
  301. break;
  302. }
  303. s->write_cmd = 0;
  304. }
  305. static void kbd_reset(void *opaque)
  306. {
  307. KBDState *s = opaque;
  308. s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
  309. s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
  310. }
  311. static const VMStateDescription vmstate_kbd = {
  312. .name = "pckbd",
  313. .version_id = 3,
  314. .minimum_version_id = 3,
  315. .minimum_version_id_old = 3,
  316. .fields = (VMStateField []) {
  317. VMSTATE_UINT8(write_cmd, KBDState),
  318. VMSTATE_UINT8(status, KBDState),
  319. VMSTATE_UINT8(mode, KBDState),
  320. VMSTATE_UINT8(pending, KBDState),
  321. VMSTATE_END_OF_LIST()
  322. }
  323. };
  324. /* Memory mapped interface */
  325. static uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
  326. {
  327. KBDState *s = opaque;
  328. if (addr & s->mask)
  329. return kbd_read_status(s, 0) & 0xff;
  330. else
  331. return kbd_read_data(s, 0) & 0xff;
  332. }
  333. static void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
  334. {
  335. KBDState *s = opaque;
  336. if (addr & s->mask)
  337. kbd_write_command(s, 0, value & 0xff);
  338. else
  339. kbd_write_data(s, 0, value & 0xff);
  340. }
  341. static CPUReadMemoryFunc * const kbd_mm_read[] = {
  342. &kbd_mm_readb,
  343. &kbd_mm_readb,
  344. &kbd_mm_readb,
  345. };
  346. static CPUWriteMemoryFunc * const kbd_mm_write[] = {
  347. &kbd_mm_writeb,
  348. &kbd_mm_writeb,
  349. &kbd_mm_writeb,
  350. };
  351. void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq,
  352. target_phys_addr_t base, ram_addr_t size,
  353. target_phys_addr_t mask)
  354. {
  355. KBDState *s = &kbd_state;
  356. int s_io_memory;
  357. s->irq_kbd = kbd_irq;
  358. s->irq_mouse = mouse_irq;
  359. s->mask = mask;
  360. vmstate_register(0, &vmstate_kbd, s);
  361. s_io_memory = cpu_register_io_memory(kbd_mm_read, kbd_mm_write, s);
  362. cpu_register_physical_memory(base, size, s_io_memory);
  363. s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
  364. s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
  365. #ifdef TARGET_I386
  366. vmmouse_init(s->mouse);
  367. #endif
  368. qemu_register_reset(kbd_reset, s);
  369. }
  370. typedef struct ISAKBDState {
  371. ISADevice dev;
  372. KBDState kbd;
  373. } ISAKBDState;
  374. static const VMStateDescription vmstate_kbd_isa = {
  375. .name = "pckbd",
  376. .version_id = 3,
  377. .minimum_version_id = 3,
  378. .minimum_version_id_old = 3,
  379. .fields = (VMStateField []) {
  380. VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
  381. VMSTATE_END_OF_LIST()
  382. }
  383. };
  384. static int i8042_initfn(ISADevice *dev)
  385. {
  386. KBDState *s = &(DO_UPCAST(ISAKBDState, dev, dev)->kbd);
  387. isa_init_irq(dev, &s->irq_kbd, 1);
  388. isa_init_irq(dev, &s->irq_mouse, 12);
  389. register_ioport_read(0x60, 1, 1, kbd_read_data, s);
  390. register_ioport_write(0x60, 1, 1, kbd_write_data, s);
  391. register_ioport_read(0x64, 1, 1, kbd_read_status, s);
  392. register_ioport_write(0x64, 1, 1, kbd_write_command, s);
  393. s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
  394. s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
  395. #ifdef TARGET_I386
  396. vmmouse_init(s->mouse);
  397. #endif
  398. qemu_register_reset(kbd_reset, s);
  399. return 0;
  400. }
  401. static ISADeviceInfo i8042_info = {
  402. .qdev.name = "i8042",
  403. .qdev.size = sizeof(ISAKBDState),
  404. .qdev.vmsd = &vmstate_kbd_isa,
  405. .qdev.no_user = 1,
  406. .init = i8042_initfn,
  407. };
  408. static void i8042_register(void)
  409. {
  410. isa_qdev_register(&i8042_info);
  411. }
  412. device_init(i8042_register)