1e342083cSJohn Floren #include "kvm/read-write.h" 2e342083cSJohn Floren #include "kvm/ioport.h" 3e342083cSJohn Floren #include "kvm/mutex.h" 4e342083cSJohn Floren #include "kvm/util.h" 5e342083cSJohn Floren #include "kvm/term.h" 6e342083cSJohn Floren #include "kvm/kvm.h" 7e342083cSJohn Floren #include "kvm/i8042.h" 8e342083cSJohn Floren 9e342083cSJohn Floren #include <rfb/keysym.h> 10e342083cSJohn Floren #include <rfb/rfb.h> 11e342083cSJohn Floren #include <stdint.h> 12e342083cSJohn Floren 1367307cddSPekka Enberg /* 1467307cddSPekka Enberg * IRQs 1567307cddSPekka Enberg */ 16e342083cSJohn Floren #define KBD_IRQ 1 17e342083cSJohn Floren #define AUX_IRQ 12 18e342083cSJohn Floren 1967307cddSPekka Enberg /* 2067307cddSPekka Enberg * Registers 2167307cddSPekka Enberg */ 2267307cddSPekka Enberg #define I8042_DATA_REG 0x60 2367307cddSPekka Enberg #define I8042_COMMAND_REG 0x64 2467307cddSPekka Enberg 25b4a721d9SPekka Enberg /* 26b4a721d9SPekka Enberg * Commands 27b4a721d9SPekka Enberg */ 28b4a721d9SPekka Enberg #define I8042_CMD_CTL_RCTR 0x20 29b4a721d9SPekka Enberg #define I8042_CMD_CTL_WCTR 0x60 30b4a721d9SPekka Enberg #define I8042_CMD_AUX_LOOP 0xD3 31b4a721d9SPekka Enberg #define I8042_CMD_AUX_SEND 0xD4 32b4a721d9SPekka Enberg #define I8042_CMD_AUX_TEST 0xA9 33b4a721d9SPekka Enberg #define I8042_CMD_AUX_DISABLE 0xA7 34b4a721d9SPekka Enberg #define I8042_CMD_AUX_ENABLE 0xA8 35e342083cSJohn Floren 36e342083cSJohn Floren #define RESPONSE_ACK 0xFA 37e342083cSJohn Floren 38e342083cSJohn Floren #define MODE_DISABLE_AUX 0x20 39e342083cSJohn Floren 40e342083cSJohn Floren #define AUX_ENABLE_REPORTING 0x20 41e342083cSJohn Floren #define AUX_SCALING_FLAG 0x10 42e342083cSJohn Floren #define AUX_DEFAULT_RESOLUTION 0x2 43e342083cSJohn Floren #define AUX_DEFAULT_SAMPLE 100 44e342083cSJohn Floren 4598cbe4d9SPekka Enberg /* 4698cbe4d9SPekka Enberg * Status register bits 4798cbe4d9SPekka Enberg */ 48e9f4d662SPekka Enberg #define I8042_STR_AUXDATA 0x20 49e9f4d662SPekka Enberg #define I8042_STR_KEYLOCK 0x10 50e9f4d662SPekka Enberg #define I8042_STR_CMDDAT 0x08 51e9f4d662SPekka Enberg #define I8042_STR_MUXERR 0x04 52e9f4d662SPekka Enberg #define I8042_STR_OBF 0x01 53e342083cSJohn Floren 54e342083cSJohn Floren #define KBD_MODE_KBD_INT 0x01 55e342083cSJohn Floren #define KBD_MODE_SYS 0x02 56e342083cSJohn Floren 57e342083cSJohn Floren #define QUEUE_SIZE 128 58e342083cSJohn Floren 59e342083cSJohn Floren /* 60e342083cSJohn Floren * This represents the current state of the PS/2 keyboard system, 61e342083cSJohn Floren * including the AUX device (the mouse) 62e342083cSJohn Floren */ 63e342083cSJohn Floren struct kbd_state { 64e342083cSJohn Floren struct kvm *kvm; 65e342083cSJohn Floren 66e342083cSJohn Floren char kq[QUEUE_SIZE]; /* Keyboard queue */ 67e342083cSJohn Floren int kread, kwrite; /* Indexes into the queue */ 68e342083cSJohn Floren int kcount; /* number of elements in queue */ 69e342083cSJohn Floren 70e342083cSJohn Floren char mq[QUEUE_SIZE]; 71e342083cSJohn Floren int mread, mwrite; 72e342083cSJohn Floren int mcount; 73e342083cSJohn Floren 74e342083cSJohn Floren u8 mstatus; /* Mouse status byte */ 75e342083cSJohn Floren u8 mres; /* Current mouse resolution */ 76e342083cSJohn Floren u8 msample; /* Current mouse samples/second */ 77e342083cSJohn Floren 78e342083cSJohn Floren u8 mode; /* i8042 mode register */ 79e342083cSJohn Floren u8 status; /* i8042 status register */ 80e342083cSJohn Floren /* 81e342083cSJohn Floren * Some commands (on port 0x64) have arguments; 82e342083cSJohn Floren * we store the command here while we wait for the argument 83e342083cSJohn Floren */ 84e342083cSJohn Floren u32 write_cmd; 85e342083cSJohn Floren }; 86e342083cSJohn Floren 87e342083cSJohn Floren static struct kbd_state state; 88e342083cSJohn Floren 89e342083cSJohn Floren /* 90e342083cSJohn Floren * If there are packets to be read, set the appropriate IRQs high 91e342083cSJohn Floren */ 92e342083cSJohn Floren static void kbd_update_irq(void) 93e342083cSJohn Floren { 94e342083cSJohn Floren u8 klevel = 0; 95e342083cSJohn Floren u8 mlevel = 0; 96e342083cSJohn Floren 97e342083cSJohn Floren /* First, clear the kbd and aux output buffer full bits */ 98e9f4d662SPekka Enberg state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA); 99e342083cSJohn Floren 100e342083cSJohn Floren if (state.kcount > 0) { 101e9f4d662SPekka Enberg state.status |= I8042_STR_OBF; 102e342083cSJohn Floren klevel = 1; 103e342083cSJohn Floren } 104e342083cSJohn Floren 105e342083cSJohn Floren /* Keyboard has higher priority than mouse */ 106e342083cSJohn Floren if (klevel == 0 && state.mcount != 0) { 107e9f4d662SPekka Enberg state.status |= I8042_STR_OBF | I8042_STR_AUXDATA; 108e342083cSJohn Floren mlevel = 1; 109e342083cSJohn Floren } 110e342083cSJohn Floren 111e342083cSJohn Floren kvm__irq_line(state.kvm, KBD_IRQ, klevel); 112e342083cSJohn Floren kvm__irq_line(state.kvm, AUX_IRQ, mlevel); 113e342083cSJohn Floren } 114e342083cSJohn Floren 115e342083cSJohn Floren /* 116e342083cSJohn Floren * Add a byte to the mouse queue, then set IRQs 117e342083cSJohn Floren */ 118e342083cSJohn Floren static void mouse_queue(u8 c) 119e342083cSJohn Floren { 120e342083cSJohn Floren if (state.mcount >= QUEUE_SIZE) 121e342083cSJohn Floren return; 122e342083cSJohn Floren 123e342083cSJohn Floren state.mq[state.mwrite++ % QUEUE_SIZE] = c; 124e342083cSJohn Floren 125e342083cSJohn Floren state.mcount++; 126e342083cSJohn Floren kbd_update_irq(); 127e342083cSJohn Floren } 128e342083cSJohn Floren 129e342083cSJohn Floren /* 130e342083cSJohn Floren * Add a byte to the keyboard queue, then set IRQs 131e342083cSJohn Floren */ 132e342083cSJohn Floren static void kbd_queue(u8 c) 133e342083cSJohn Floren { 134e342083cSJohn Floren if (state.kcount >= QUEUE_SIZE) 135e342083cSJohn Floren return; 136e342083cSJohn Floren 137e342083cSJohn Floren state.kq[state.kwrite++ % QUEUE_SIZE] = c; 138e342083cSJohn Floren 139e342083cSJohn Floren state.kcount++; 140e342083cSJohn Floren kbd_update_irq(); 141e342083cSJohn Floren } 142e342083cSJohn Floren 143*ca9326bbSPekka Enberg static void kbd_write_command(u8 val) 144e342083cSJohn Floren { 145e342083cSJohn Floren switch (val) { 146b4a721d9SPekka Enberg case I8042_CMD_CTL_RCTR: 147e342083cSJohn Floren kbd_queue(state.mode); 148e342083cSJohn Floren break; 149b4a721d9SPekka Enberg case I8042_CMD_CTL_WCTR: 150b4a721d9SPekka Enberg case I8042_CMD_AUX_SEND: 151b4a721d9SPekka Enberg case I8042_CMD_AUX_LOOP: 152e342083cSJohn Floren state.write_cmd = val; 153e342083cSJohn Floren break; 154b4a721d9SPekka Enberg case I8042_CMD_AUX_TEST: 155e342083cSJohn Floren /* 0 means we're a normal PS/2 mouse */ 156e342083cSJohn Floren mouse_queue(0); 157e342083cSJohn Floren break; 158b4a721d9SPekka Enberg case I8042_CMD_AUX_DISABLE: 159e342083cSJohn Floren state.mode |= MODE_DISABLE_AUX; 160e342083cSJohn Floren break; 161b4a721d9SPekka Enberg case I8042_CMD_AUX_ENABLE: 162e342083cSJohn Floren state.mode &= ~MODE_DISABLE_AUX; 163e342083cSJohn Floren break; 164e342083cSJohn Floren default: 165e342083cSJohn Floren break; 166e342083cSJohn Floren } 167e342083cSJohn Floren } 168e342083cSJohn Floren 169e342083cSJohn Floren /* 170e342083cSJohn Floren * Called when the OS reads from port 0x60 (PS/2 data) 171e342083cSJohn Floren */ 172e342083cSJohn Floren static u32 kbd_read_data(void) 173e342083cSJohn Floren { 174e342083cSJohn Floren u32 ret; 175e342083cSJohn Floren int i; 176e342083cSJohn Floren 177e342083cSJohn Floren if (state.kcount != 0) { 178e342083cSJohn Floren /* Keyboard data gets read first */ 179e342083cSJohn Floren ret = state.kq[state.kread++ % QUEUE_SIZE]; 180e342083cSJohn Floren state.kcount--; 181e342083cSJohn Floren kvm__irq_line(state.kvm, KBD_IRQ, 0); 182e342083cSJohn Floren kbd_update_irq(); 183e342083cSJohn Floren } else if (state.mcount > 0) { 184e342083cSJohn Floren /* Followed by the mouse */ 185e342083cSJohn Floren ret = state.mq[state.mread++ % QUEUE_SIZE]; 186e342083cSJohn Floren state.mcount--; 187e342083cSJohn Floren kvm__irq_line(state.kvm, AUX_IRQ, 0); 188e342083cSJohn Floren kbd_update_irq(); 189e342083cSJohn Floren } else if (state.kcount == 0) { 190e342083cSJohn Floren i = state.kread - 1; 191e342083cSJohn Floren if (i < 0) 192e342083cSJohn Floren i = QUEUE_SIZE; 193e342083cSJohn Floren ret = state.kq[i]; 194e342083cSJohn Floren } 195e342083cSJohn Floren return ret; 196e342083cSJohn Floren } 197e342083cSJohn Floren 198e342083cSJohn Floren /* 199e342083cSJohn Floren * Called when the OS read from port 0x64, the command port 200e342083cSJohn Floren */ 201e342083cSJohn Floren static u32 kbd_read_status(void) 202e342083cSJohn Floren { 203e342083cSJohn Floren return (u32)state.status; 204e342083cSJohn Floren } 205e342083cSJohn Floren 206e342083cSJohn Floren /* 207e342083cSJohn Floren * Called when the OS writes to port 0x60 (data port) 208e342083cSJohn Floren * Things written here are generally arguments to commands previously 209e342083cSJohn Floren * written to port 0x64 and stored in state.write_cmd 210e342083cSJohn Floren */ 211e342083cSJohn Floren static void kbd_write_data(u32 val) 212e342083cSJohn Floren { 213e342083cSJohn Floren switch (state.write_cmd) { 214b4a721d9SPekka Enberg case I8042_CMD_CTL_WCTR: 215e342083cSJohn Floren state.mode = val; 216e342083cSJohn Floren kbd_update_irq(); 217e342083cSJohn Floren break; 218b4a721d9SPekka Enberg case I8042_CMD_AUX_LOOP: 219e342083cSJohn Floren mouse_queue(val); 220e342083cSJohn Floren mouse_queue(RESPONSE_ACK); 221e342083cSJohn Floren break; 222b4a721d9SPekka Enberg case I8042_CMD_AUX_SEND: 223e342083cSJohn Floren /* The OS wants to send a command to the mouse */ 224e342083cSJohn Floren mouse_queue(RESPONSE_ACK); 225e342083cSJohn Floren switch (val) { 226e342083cSJohn Floren case 0xe6: 227e342083cSJohn Floren /* set scaling = 1:1 */ 228e342083cSJohn Floren state.mstatus &= ~AUX_SCALING_FLAG; 229e342083cSJohn Floren break; 230e342083cSJohn Floren case 0xe8: 231e342083cSJohn Floren /* set resolution */ 232e342083cSJohn Floren state.mres = val; 233e342083cSJohn Floren break; 234e342083cSJohn Floren case 0xe9: 235e342083cSJohn Floren /* Report mouse status/config */ 236e342083cSJohn Floren mouse_queue(state.mstatus); 237e342083cSJohn Floren mouse_queue(state.mres); 238e342083cSJohn Floren mouse_queue(state.msample); 239e342083cSJohn Floren break; 240e342083cSJohn Floren case 0xf2: 241e342083cSJohn Floren /* send ID */ 242e342083cSJohn Floren mouse_queue(0); /* normal mouse */ 243e342083cSJohn Floren break; 244e342083cSJohn Floren case 0xf3: 245e342083cSJohn Floren /* set sample rate */ 246e342083cSJohn Floren state.msample = val; 247e342083cSJohn Floren break; 248e342083cSJohn Floren case 0xf4: 249e342083cSJohn Floren /* enable reporting */ 250e342083cSJohn Floren state.mstatus |= AUX_ENABLE_REPORTING; 251e342083cSJohn Floren break; 252e342083cSJohn Floren case 0xf5: 253e342083cSJohn Floren state.mstatus &= ~AUX_ENABLE_REPORTING; 254e342083cSJohn Floren break; 255e342083cSJohn Floren case 0xf6: 256e342083cSJohn Floren /* set defaults, just fall through to reset */ 257e342083cSJohn Floren case 0xff: 258e342083cSJohn Floren /* reset */ 259e342083cSJohn Floren state.mstatus = 0x0; 260e342083cSJohn Floren state.mres = AUX_DEFAULT_RESOLUTION; 261e342083cSJohn Floren state.msample = AUX_DEFAULT_SAMPLE; 262e342083cSJohn Floren break; 263e342083cSJohn Floren default: 264e342083cSJohn Floren break; 265e342083cSJohn Floren } 266e342083cSJohn Floren break; 267e342083cSJohn Floren case 0: 268e342083cSJohn Floren /* Just send the ID */ 269e342083cSJohn Floren kbd_queue(RESPONSE_ACK); 270e342083cSJohn Floren kbd_queue(0xab); 271e342083cSJohn Floren kbd_queue(0x41); 272e342083cSJohn Floren kbd_update_irq(); 273e342083cSJohn Floren break; 274e342083cSJohn Floren default: 275e342083cSJohn Floren /* Yeah whatever */ 276e342083cSJohn Floren break; 277e342083cSJohn Floren } 278e342083cSJohn Floren state.write_cmd = 0; 279e342083cSJohn Floren } 280e342083cSJohn Floren 281e342083cSJohn Floren static void kbd_reset(void) 282e342083cSJohn Floren { 283e342083cSJohn Floren state = (struct kbd_state) { 284e9f4d662SPekka Enberg .status = I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */ 285e342083cSJohn Floren .mode = KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */ 286e342083cSJohn Floren .mres = AUX_DEFAULT_RESOLUTION, 287e342083cSJohn Floren .msample = AUX_DEFAULT_SAMPLE, 288e342083cSJohn Floren }; 289e342083cSJohn Floren } 290e342083cSJohn Floren 291e342083cSJohn Floren /* 292e342083cSJohn Floren * We can map the letters and numbers without a fuss, 293e342083cSJohn Floren * but the other characters not so much. 294e342083cSJohn Floren */ 295e342083cSJohn Floren static char letters[26] = { 296e342083cSJohn Floren 0x1c, 0x32, 0x21, 0x23, 0x24, /* a-e */ 297e342083cSJohn Floren 0x2b, 0x34, 0x33, 0x43, 0x3b, /* f-j */ 298e342083cSJohn Floren 0x42, 0x4b, 0x3a, 0x31, 0x44, /* k-o */ 299e342083cSJohn Floren 0x4d, 0x15, 0x2d, 0x1b, 0x2c, /* p-t */ 300e342083cSJohn Floren 0x3c, 0x2a, 0x1d, 0x22, 0x35, /* u-y */ 301e342083cSJohn Floren 0x1a, 302e342083cSJohn Floren }; 303e342083cSJohn Floren 304e342083cSJohn Floren static char num[10] = { 305e342083cSJohn Floren 0x45, 0x16, 0x1e, 0x26, 0x2e, 0x23, 0x36, 0x3d, 0x3e, 0x46, 306e342083cSJohn Floren }; 307e342083cSJohn Floren 308e342083cSJohn Floren /* 309e342083cSJohn Floren * This is called when the VNC server receives a key event 310e342083cSJohn Floren * The reason this function is such a beast is that we have 311e342083cSJohn Floren * to convert from ASCII characters (which is what VNC gets) 312e342083cSJohn Floren * to PC keyboard scancodes, which is what Linux expects to 313e342083cSJohn Floren * get from its keyboard. ASCII and the scancode set don't 314e342083cSJohn Floren * really seem to mesh in any good way beyond some basics with 315e342083cSJohn Floren * the letters and numbers. 316e342083cSJohn Floren */ 317e342083cSJohn Floren void kbd_handle_key(rfbBool down, rfbKeySym key, rfbClientPtr cl) 318e342083cSJohn Floren { 319e342083cSJohn Floren char tosend = 0; 320e342083cSJohn Floren 321e342083cSJohn Floren if (key >= 0x41 && key <= 0x5a) 322e342083cSJohn Floren key += 0x20; /* convert to lowercase */ 323e342083cSJohn Floren 324e342083cSJohn Floren if (key >= 0x61 && key <= 0x7a) /* a-z */ 325e342083cSJohn Floren tosend = letters[key - 0x61]; 326e342083cSJohn Floren 327e342083cSJohn Floren if (key >= 0x30 && key <= 0x39) 328e342083cSJohn Floren tosend = num[key - 0x30]; 329e342083cSJohn Floren 330e342083cSJohn Floren switch (key) { 331e342083cSJohn Floren case XK_Insert: kbd_queue(0xe0); tosend = 0x70; break; 332e342083cSJohn Floren case XK_Delete: kbd_queue(0xe0); tosend = 0x71; break; 333e342083cSJohn Floren case XK_Up: kbd_queue(0xe0); tosend = 0x75; break; 334e342083cSJohn Floren case XK_Down: kbd_queue(0xe0); tosend = 0x72; break; 335e342083cSJohn Floren case XK_Left: kbd_queue(0xe0); tosend = 0x6b; break; 336e342083cSJohn Floren case XK_Right: kbd_queue(0xe0); tosend = 0x74; break; 337e342083cSJohn Floren case XK_Page_Up: kbd_queue(0xe0); tosend = 0x7d; break; 338e342083cSJohn Floren case XK_Page_Down: kbd_queue(0xe0); tosend = 0x7a; break; 339e342083cSJohn Floren case XK_Home: kbd_queue(0xe0); tosend = 0x6c; break; 340e342083cSJohn Floren case XK_BackSpace: tosend = 0x66; break; 341e342083cSJohn Floren case XK_Tab: tosend = 0x0d; break; 342e342083cSJohn Floren case XK_Return: tosend = 0x5a; break; 343e342083cSJohn Floren case XK_Escape: tosend = 0x76; break; 344e342083cSJohn Floren case XK_End: tosend = 0x69; break; 345e342083cSJohn Floren case XK_Shift_L: tosend = 0x12; break; 346e342083cSJohn Floren case XK_Shift_R: tosend = 0x59; break; 347e342083cSJohn Floren case XK_Control_R: kbd_queue(0xe0); 348e342083cSJohn Floren case XK_Control_L: tosend = 0x14; break; 349e342083cSJohn Floren case XK_Alt_R: kbd_queue(0xe0); 350e342083cSJohn Floren case XK_Alt_L: tosend = 0x11; break; 351e342083cSJohn Floren case XK_quoteleft: tosend = 0x0e; break; 352e342083cSJohn Floren case XK_minus: tosend = 0x4e; break; 353e342083cSJohn Floren case XK_equal: tosend = 0x55; break; 354e342083cSJohn Floren case XK_bracketleft: tosend = 0x54; break; 355e342083cSJohn Floren case XK_bracketright: tosend = 0x5b; break; 356e342083cSJohn Floren case XK_backslash: tosend = 0x5d; break; 357e342083cSJohn Floren case XK_Caps_Lock: tosend = 0x58; break; 358e342083cSJohn Floren case XK_semicolon: tosend = 0x4c; break; 359e342083cSJohn Floren case XK_quoteright: tosend = 0x52; break; 360e342083cSJohn Floren case XK_comma: tosend = 0x41; break; 361e342083cSJohn Floren case XK_period: tosend = 0x49; break; 362e342083cSJohn Floren case XK_slash: tosend = 0x4a; break; 363e342083cSJohn Floren case XK_space: tosend = 0x29; break; 364e342083cSJohn Floren 365e342083cSJohn Floren /* 366e342083cSJohn Floren * This is where I handle the shifted characters. 367e342083cSJohn Floren * They don't really map nicely the way A-Z maps to a-z, 368e342083cSJohn Floren * so I'm doing it manually 369e342083cSJohn Floren */ 370e342083cSJohn Floren case XK_exclam: tosend = 0x16; break; 371e342083cSJohn Floren case XK_quotedbl: tosend = 0x52; break; 372e342083cSJohn Floren case XK_numbersign: tosend = 0x26; break; 373e342083cSJohn Floren case XK_dollar: tosend = 0x25; break; 374e342083cSJohn Floren case XK_percent: tosend = 0x2e; break; 375e342083cSJohn Floren case XK_ampersand: tosend = 0x3d; break; 376e342083cSJohn Floren case XK_parenleft: tosend = 0x46; break; 377e342083cSJohn Floren case XK_parenright: tosend = 0x45; break; 378e342083cSJohn Floren case XK_asterisk: tosend = 0x3e; break; 379e342083cSJohn Floren case XK_plus: tosend = 0x55; break; 380e342083cSJohn Floren case XK_colon: tosend = 0x4c; break; 381e342083cSJohn Floren case XK_less: tosend = 0x41; break; 382e342083cSJohn Floren case XK_greater: tosend = 0x49; break; 383e342083cSJohn Floren case XK_question: tosend = 0x4a; break; 384e342083cSJohn Floren case XK_at: tosend = 0x1e; break; 385e342083cSJohn Floren case XK_asciicircum: tosend = 0x36; break; 386e342083cSJohn Floren case XK_underscore: tosend = 0x4e; break; 387e342083cSJohn Floren case XK_braceleft: tosend = 0x54; break; 388e342083cSJohn Floren case XK_braceright: tosend = 0x5b; break; 389e342083cSJohn Floren case XK_bar: tosend = 0x5d; break; 390e342083cSJohn Floren case XK_asciitilde: tosend = 0x0e; break; 391e342083cSJohn Floren default: break; 392e342083cSJohn Floren } 393e342083cSJohn Floren 394e342083cSJohn Floren /* 395e342083cSJohn Floren * If this is a "key up" event (the user has released the key, we 396e342083cSJohn Floren * need to send 0xf0 first. 397e342083cSJohn Floren */ 398e342083cSJohn Floren if (!down && tosend != 0x0) 399e342083cSJohn Floren kbd_queue(0xf0); 400e342083cSJohn Floren 401e342083cSJohn Floren if (tosend) 402e342083cSJohn Floren kbd_queue(tosend); 403e342083cSJohn Floren } 404e342083cSJohn Floren 405e342083cSJohn Floren /* The previous X and Y coordinates of the mouse */ 406e342083cSJohn Floren static int xlast, ylast = -1; 407e342083cSJohn Floren 408e342083cSJohn Floren /* 409e342083cSJohn Floren * This function is called by the VNC server whenever a mouse event occurs. 410e342083cSJohn Floren */ 411e342083cSJohn Floren void kbd_handle_ptr(int buttonMask, int x, int y, rfbClientPtr cl) 412e342083cSJohn Floren { 413e342083cSJohn Floren int dx, dy; 414e342083cSJohn Floren char b1 = 0x8; 415e342083cSJohn Floren 416e342083cSJohn Floren /* The VNC mask and the PS/2 button encoding are the same */ 417e342083cSJohn Floren b1 |= buttonMask; 418e342083cSJohn Floren 419e342083cSJohn Floren if (xlast >= 0 && ylast >= 0) { 420e342083cSJohn Floren /* The PS/2 mouse sends deltas, not absolutes */ 421e342083cSJohn Floren dx = x - xlast; 422e342083cSJohn Floren dy = ylast - y; 423e342083cSJohn Floren 424e342083cSJohn Floren /* Set overflow bits if needed */ 425e342083cSJohn Floren if (dy > 255) 426e342083cSJohn Floren b1 |= 0x80; 427e342083cSJohn Floren if (dx > 255) 428e342083cSJohn Floren b1 |= 0x40; 429e342083cSJohn Floren 430e342083cSJohn Floren /* Set negative bits if needed */ 431e342083cSJohn Floren if (dy < 0) 432e342083cSJohn Floren b1 |= 0x20; 433e342083cSJohn Floren if (dx < 0) 434e342083cSJohn Floren b1 |= 0x10; 435e342083cSJohn Floren 436e342083cSJohn Floren mouse_queue(b1); 437e342083cSJohn Floren mouse_queue(dx); 438e342083cSJohn Floren mouse_queue(dy); 439e342083cSJohn Floren } 440e342083cSJohn Floren 441e342083cSJohn Floren xlast = x; 442e342083cSJohn Floren ylast = y; 443e342083cSJohn Floren rfbDefaultPtrAddEvent(buttonMask, x, y, cl); 444e342083cSJohn Floren } 445e342083cSJohn Floren 446e342083cSJohn Floren /* 447e342083cSJohn Floren * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64) 448e342083cSJohn Floren */ 449e342083cSJohn Floren static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 450e342083cSJohn Floren { 451*ca9326bbSPekka Enberg switch (port) { 452*ca9326bbSPekka Enberg case I8042_COMMAND_REG: { 453*ca9326bbSPekka Enberg u8 value = kbd_read_status(); 454*ca9326bbSPekka Enberg ioport__write8(data, value); 455*ca9326bbSPekka Enberg break; 456e342083cSJohn Floren } 457*ca9326bbSPekka Enberg case I8042_DATA_REG: { 458*ca9326bbSPekka Enberg u32 value = kbd_read_data(); 459*ca9326bbSPekka Enberg ioport__write32(data, value); 460*ca9326bbSPekka Enberg break; 461*ca9326bbSPekka Enberg } 462*ca9326bbSPekka Enberg default: 463*ca9326bbSPekka Enberg return false; 464*ca9326bbSPekka Enberg } 465*ca9326bbSPekka Enberg 466e342083cSJohn Floren return true; 467e342083cSJohn Floren } 468e342083cSJohn Floren 469e342083cSJohn Floren static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 470e342083cSJohn Floren { 471*ca9326bbSPekka Enberg switch (port) { 472*ca9326bbSPekka Enberg case I8042_COMMAND_REG: { 473*ca9326bbSPekka Enberg u8 value = ioport__read8(data); 474*ca9326bbSPekka Enberg kbd_write_command(value); 475*ca9326bbSPekka Enberg break; 476*ca9326bbSPekka Enberg } 477*ca9326bbSPekka Enberg case I8042_DATA_REG: { 478*ca9326bbSPekka Enberg u32 value = ioport__read32(data); 479*ca9326bbSPekka Enberg kbd_write_data(value); 480*ca9326bbSPekka Enberg break; 481*ca9326bbSPekka Enberg } 482*ca9326bbSPekka Enberg default: 483*ca9326bbSPekka Enberg return false; 484*ca9326bbSPekka Enberg } 485e342083cSJohn Floren 486e342083cSJohn Floren return true; 487e342083cSJohn Floren } 488e342083cSJohn Floren 489e342083cSJohn Floren static struct ioport_operations kbd_ops = { 490e342083cSJohn Floren .io_in = kbd_in, 491e342083cSJohn Floren .io_out = kbd_out, 492e342083cSJohn Floren }; 493e342083cSJohn Floren 494e342083cSJohn Floren void kbd__init(struct kvm *kvm) 495e342083cSJohn Floren { 496e342083cSJohn Floren kbd_reset(); 497e342083cSJohn Floren state.kvm = kvm; 49867307cddSPekka Enberg ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL); 49967307cddSPekka Enberg ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL); 500e342083cSJohn Floren } 501