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 25*b4a721d9SPekka Enberg /* 26*b4a721d9SPekka Enberg * Commands 27*b4a721d9SPekka Enberg */ 28*b4a721d9SPekka Enberg #define I8042_CMD_CTL_RCTR 0x20 29*b4a721d9SPekka Enberg #define I8042_CMD_CTL_WCTR 0x60 30*b4a721d9SPekka Enberg #define I8042_CMD_AUX_LOOP 0xD3 31*b4a721d9SPekka Enberg #define I8042_CMD_AUX_SEND 0xD4 32*b4a721d9SPekka Enberg #define I8042_CMD_AUX_TEST 0xA9 33*b4a721d9SPekka Enberg #define I8042_CMD_AUX_DISABLE 0xA7 34*b4a721d9SPekka 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 143e342083cSJohn Floren /* 144e342083cSJohn Floren * This function is called when the OS issues a write to port 0x64 145e342083cSJohn Floren */ 146e342083cSJohn Floren static void kbd_write_command(u32 val) 147e342083cSJohn Floren { 148e342083cSJohn Floren switch (val) { 149*b4a721d9SPekka Enberg case I8042_CMD_CTL_RCTR: 150e342083cSJohn Floren kbd_queue(state.mode); 151e342083cSJohn Floren break; 152*b4a721d9SPekka Enberg case I8042_CMD_CTL_WCTR: 153*b4a721d9SPekka Enberg case I8042_CMD_AUX_SEND: 154*b4a721d9SPekka Enberg case I8042_CMD_AUX_LOOP: 155e342083cSJohn Floren state.write_cmd = val; 156e342083cSJohn Floren break; 157*b4a721d9SPekka Enberg case I8042_CMD_AUX_TEST: 158e342083cSJohn Floren /* 0 means we're a normal PS/2 mouse */ 159e342083cSJohn Floren mouse_queue(0); 160e342083cSJohn Floren break; 161*b4a721d9SPekka Enberg case I8042_CMD_AUX_DISABLE: 162e342083cSJohn Floren state.mode |= MODE_DISABLE_AUX; 163e342083cSJohn Floren break; 164*b4a721d9SPekka Enberg case I8042_CMD_AUX_ENABLE: 165e342083cSJohn Floren state.mode &= ~MODE_DISABLE_AUX; 166e342083cSJohn Floren break; 167e342083cSJohn Floren default: 168e342083cSJohn Floren break; 169e342083cSJohn Floren } 170e342083cSJohn Floren } 171e342083cSJohn Floren 172e342083cSJohn Floren /* 173e342083cSJohn Floren * Called when the OS reads from port 0x60 (PS/2 data) 174e342083cSJohn Floren */ 175e342083cSJohn Floren static u32 kbd_read_data(void) 176e342083cSJohn Floren { 177e342083cSJohn Floren u32 ret; 178e342083cSJohn Floren int i; 179e342083cSJohn Floren 180e342083cSJohn Floren if (state.kcount != 0) { 181e342083cSJohn Floren /* Keyboard data gets read first */ 182e342083cSJohn Floren ret = state.kq[state.kread++ % QUEUE_SIZE]; 183e342083cSJohn Floren state.kcount--; 184e342083cSJohn Floren kvm__irq_line(state.kvm, KBD_IRQ, 0); 185e342083cSJohn Floren kbd_update_irq(); 186e342083cSJohn Floren } else if (state.mcount > 0) { 187e342083cSJohn Floren /* Followed by the mouse */ 188e342083cSJohn Floren ret = state.mq[state.mread++ % QUEUE_SIZE]; 189e342083cSJohn Floren state.mcount--; 190e342083cSJohn Floren kvm__irq_line(state.kvm, AUX_IRQ, 0); 191e342083cSJohn Floren kbd_update_irq(); 192e342083cSJohn Floren } else if (state.kcount == 0) { 193e342083cSJohn Floren i = state.kread - 1; 194e342083cSJohn Floren if (i < 0) 195e342083cSJohn Floren i = QUEUE_SIZE; 196e342083cSJohn Floren ret = state.kq[i]; 197e342083cSJohn Floren } 198e342083cSJohn Floren return ret; 199e342083cSJohn Floren } 200e342083cSJohn Floren 201e342083cSJohn Floren /* 202e342083cSJohn Floren * Called when the OS read from port 0x64, the command port 203e342083cSJohn Floren */ 204e342083cSJohn Floren static u32 kbd_read_status(void) 205e342083cSJohn Floren { 206e342083cSJohn Floren return (u32)state.status; 207e342083cSJohn Floren } 208e342083cSJohn Floren 209e342083cSJohn Floren /* 210e342083cSJohn Floren * Called when the OS writes to port 0x60 (data port) 211e342083cSJohn Floren * Things written here are generally arguments to commands previously 212e342083cSJohn Floren * written to port 0x64 and stored in state.write_cmd 213e342083cSJohn Floren */ 214e342083cSJohn Floren static void kbd_write_data(u32 val) 215e342083cSJohn Floren { 216e342083cSJohn Floren switch (state.write_cmd) { 217*b4a721d9SPekka Enberg case I8042_CMD_CTL_WCTR: 218e342083cSJohn Floren state.mode = val; 219e342083cSJohn Floren kbd_update_irq(); 220e342083cSJohn Floren break; 221*b4a721d9SPekka Enberg case I8042_CMD_AUX_LOOP: 222e342083cSJohn Floren mouse_queue(val); 223e342083cSJohn Floren mouse_queue(RESPONSE_ACK); 224e342083cSJohn Floren break; 225*b4a721d9SPekka Enberg case I8042_CMD_AUX_SEND: 226e342083cSJohn Floren /* The OS wants to send a command to the mouse */ 227e342083cSJohn Floren mouse_queue(RESPONSE_ACK); 228e342083cSJohn Floren switch (val) { 229e342083cSJohn Floren case 0xe6: 230e342083cSJohn Floren /* set scaling = 1:1 */ 231e342083cSJohn Floren state.mstatus &= ~AUX_SCALING_FLAG; 232e342083cSJohn Floren break; 233e342083cSJohn Floren case 0xe8: 234e342083cSJohn Floren /* set resolution */ 235e342083cSJohn Floren state.mres = val; 236e342083cSJohn Floren break; 237e342083cSJohn Floren case 0xe9: 238e342083cSJohn Floren /* Report mouse status/config */ 239e342083cSJohn Floren mouse_queue(state.mstatus); 240e342083cSJohn Floren mouse_queue(state.mres); 241e342083cSJohn Floren mouse_queue(state.msample); 242e342083cSJohn Floren break; 243e342083cSJohn Floren case 0xf2: 244e342083cSJohn Floren /* send ID */ 245e342083cSJohn Floren mouse_queue(0); /* normal mouse */ 246e342083cSJohn Floren break; 247e342083cSJohn Floren case 0xf3: 248e342083cSJohn Floren /* set sample rate */ 249e342083cSJohn Floren state.msample = val; 250e342083cSJohn Floren break; 251e342083cSJohn Floren case 0xf4: 252e342083cSJohn Floren /* enable reporting */ 253e342083cSJohn Floren state.mstatus |= AUX_ENABLE_REPORTING; 254e342083cSJohn Floren break; 255e342083cSJohn Floren case 0xf5: 256e342083cSJohn Floren state.mstatus &= ~AUX_ENABLE_REPORTING; 257e342083cSJohn Floren break; 258e342083cSJohn Floren case 0xf6: 259e342083cSJohn Floren /* set defaults, just fall through to reset */ 260e342083cSJohn Floren case 0xff: 261e342083cSJohn Floren /* reset */ 262e342083cSJohn Floren state.mstatus = 0x0; 263e342083cSJohn Floren state.mres = AUX_DEFAULT_RESOLUTION; 264e342083cSJohn Floren state.msample = AUX_DEFAULT_SAMPLE; 265e342083cSJohn Floren break; 266e342083cSJohn Floren default: 267e342083cSJohn Floren break; 268e342083cSJohn Floren } 269e342083cSJohn Floren break; 270e342083cSJohn Floren case 0: 271e342083cSJohn Floren /* Just send the ID */ 272e342083cSJohn Floren kbd_queue(RESPONSE_ACK); 273e342083cSJohn Floren kbd_queue(0xab); 274e342083cSJohn Floren kbd_queue(0x41); 275e342083cSJohn Floren kbd_update_irq(); 276e342083cSJohn Floren break; 277e342083cSJohn Floren default: 278e342083cSJohn Floren /* Yeah whatever */ 279e342083cSJohn Floren break; 280e342083cSJohn Floren } 281e342083cSJohn Floren state.write_cmd = 0; 282e342083cSJohn Floren } 283e342083cSJohn Floren 284e342083cSJohn Floren static void kbd_reset(void) 285e342083cSJohn Floren { 286e342083cSJohn Floren state = (struct kbd_state) { 287e9f4d662SPekka Enberg .status = I8042_STR_MUXERR | I8042_STR_CMDDAT | I8042_STR_KEYLOCK, /* 0x1c */ 288e342083cSJohn Floren .mode = KBD_MODE_KBD_INT | KBD_MODE_SYS, /* 0x3 */ 289e342083cSJohn Floren .mres = AUX_DEFAULT_RESOLUTION, 290e342083cSJohn Floren .msample = AUX_DEFAULT_SAMPLE, 291e342083cSJohn Floren }; 292e342083cSJohn Floren } 293e342083cSJohn Floren 294e342083cSJohn Floren /* 295e342083cSJohn Floren * We can map the letters and numbers without a fuss, 296e342083cSJohn Floren * but the other characters not so much. 297e342083cSJohn Floren */ 298e342083cSJohn Floren static char letters[26] = { 299e342083cSJohn Floren 0x1c, 0x32, 0x21, 0x23, 0x24, /* a-e */ 300e342083cSJohn Floren 0x2b, 0x34, 0x33, 0x43, 0x3b, /* f-j */ 301e342083cSJohn Floren 0x42, 0x4b, 0x3a, 0x31, 0x44, /* k-o */ 302e342083cSJohn Floren 0x4d, 0x15, 0x2d, 0x1b, 0x2c, /* p-t */ 303e342083cSJohn Floren 0x3c, 0x2a, 0x1d, 0x22, 0x35, /* u-y */ 304e342083cSJohn Floren 0x1a, 305e342083cSJohn Floren }; 306e342083cSJohn Floren 307e342083cSJohn Floren static char num[10] = { 308e342083cSJohn Floren 0x45, 0x16, 0x1e, 0x26, 0x2e, 0x23, 0x36, 0x3d, 0x3e, 0x46, 309e342083cSJohn Floren }; 310e342083cSJohn Floren 311e342083cSJohn Floren /* 312e342083cSJohn Floren * This is called when the VNC server receives a key event 313e342083cSJohn Floren * The reason this function is such a beast is that we have 314e342083cSJohn Floren * to convert from ASCII characters (which is what VNC gets) 315e342083cSJohn Floren * to PC keyboard scancodes, which is what Linux expects to 316e342083cSJohn Floren * get from its keyboard. ASCII and the scancode set don't 317e342083cSJohn Floren * really seem to mesh in any good way beyond some basics with 318e342083cSJohn Floren * the letters and numbers. 319e342083cSJohn Floren */ 320e342083cSJohn Floren void kbd_handle_key(rfbBool down, rfbKeySym key, rfbClientPtr cl) 321e342083cSJohn Floren { 322e342083cSJohn Floren char tosend = 0; 323e342083cSJohn Floren 324e342083cSJohn Floren if (key >= 0x41 && key <= 0x5a) 325e342083cSJohn Floren key += 0x20; /* convert to lowercase */ 326e342083cSJohn Floren 327e342083cSJohn Floren if (key >= 0x61 && key <= 0x7a) /* a-z */ 328e342083cSJohn Floren tosend = letters[key - 0x61]; 329e342083cSJohn Floren 330e342083cSJohn Floren if (key >= 0x30 && key <= 0x39) 331e342083cSJohn Floren tosend = num[key - 0x30]; 332e342083cSJohn Floren 333e342083cSJohn Floren switch (key) { 334e342083cSJohn Floren case XK_Insert: kbd_queue(0xe0); tosend = 0x70; break; 335e342083cSJohn Floren case XK_Delete: kbd_queue(0xe0); tosend = 0x71; break; 336e342083cSJohn Floren case XK_Up: kbd_queue(0xe0); tosend = 0x75; break; 337e342083cSJohn Floren case XK_Down: kbd_queue(0xe0); tosend = 0x72; break; 338e342083cSJohn Floren case XK_Left: kbd_queue(0xe0); tosend = 0x6b; break; 339e342083cSJohn Floren case XK_Right: kbd_queue(0xe0); tosend = 0x74; break; 340e342083cSJohn Floren case XK_Page_Up: kbd_queue(0xe0); tosend = 0x7d; break; 341e342083cSJohn Floren case XK_Page_Down: kbd_queue(0xe0); tosend = 0x7a; break; 342e342083cSJohn Floren case XK_Home: kbd_queue(0xe0); tosend = 0x6c; break; 343e342083cSJohn Floren case XK_BackSpace: tosend = 0x66; break; 344e342083cSJohn Floren case XK_Tab: tosend = 0x0d; break; 345e342083cSJohn Floren case XK_Return: tosend = 0x5a; break; 346e342083cSJohn Floren case XK_Escape: tosend = 0x76; break; 347e342083cSJohn Floren case XK_End: tosend = 0x69; break; 348e342083cSJohn Floren case XK_Shift_L: tosend = 0x12; break; 349e342083cSJohn Floren case XK_Shift_R: tosend = 0x59; break; 350e342083cSJohn Floren case XK_Control_R: kbd_queue(0xe0); 351e342083cSJohn Floren case XK_Control_L: tosend = 0x14; break; 352e342083cSJohn Floren case XK_Alt_R: kbd_queue(0xe0); 353e342083cSJohn Floren case XK_Alt_L: tosend = 0x11; break; 354e342083cSJohn Floren case XK_quoteleft: tosend = 0x0e; break; 355e342083cSJohn Floren case XK_minus: tosend = 0x4e; break; 356e342083cSJohn Floren case XK_equal: tosend = 0x55; break; 357e342083cSJohn Floren case XK_bracketleft: tosend = 0x54; break; 358e342083cSJohn Floren case XK_bracketright: tosend = 0x5b; break; 359e342083cSJohn Floren case XK_backslash: tosend = 0x5d; break; 360e342083cSJohn Floren case XK_Caps_Lock: tosend = 0x58; break; 361e342083cSJohn Floren case XK_semicolon: tosend = 0x4c; break; 362e342083cSJohn Floren case XK_quoteright: tosend = 0x52; break; 363e342083cSJohn Floren case XK_comma: tosend = 0x41; break; 364e342083cSJohn Floren case XK_period: tosend = 0x49; break; 365e342083cSJohn Floren case XK_slash: tosend = 0x4a; break; 366e342083cSJohn Floren case XK_space: tosend = 0x29; break; 367e342083cSJohn Floren 368e342083cSJohn Floren /* 369e342083cSJohn Floren * This is where I handle the shifted characters. 370e342083cSJohn Floren * They don't really map nicely the way A-Z maps to a-z, 371e342083cSJohn Floren * so I'm doing it manually 372e342083cSJohn Floren */ 373e342083cSJohn Floren case XK_exclam: tosend = 0x16; break; 374e342083cSJohn Floren case XK_quotedbl: tosend = 0x52; break; 375e342083cSJohn Floren case XK_numbersign: tosend = 0x26; break; 376e342083cSJohn Floren case XK_dollar: tosend = 0x25; break; 377e342083cSJohn Floren case XK_percent: tosend = 0x2e; break; 378e342083cSJohn Floren case XK_ampersand: tosend = 0x3d; break; 379e342083cSJohn Floren case XK_parenleft: tosend = 0x46; break; 380e342083cSJohn Floren case XK_parenright: tosend = 0x45; break; 381e342083cSJohn Floren case XK_asterisk: tosend = 0x3e; break; 382e342083cSJohn Floren case XK_plus: tosend = 0x55; break; 383e342083cSJohn Floren case XK_colon: tosend = 0x4c; break; 384e342083cSJohn Floren case XK_less: tosend = 0x41; break; 385e342083cSJohn Floren case XK_greater: tosend = 0x49; break; 386e342083cSJohn Floren case XK_question: tosend = 0x4a; break; 387e342083cSJohn Floren case XK_at: tosend = 0x1e; break; 388e342083cSJohn Floren case XK_asciicircum: tosend = 0x36; break; 389e342083cSJohn Floren case XK_underscore: tosend = 0x4e; break; 390e342083cSJohn Floren case XK_braceleft: tosend = 0x54; break; 391e342083cSJohn Floren case XK_braceright: tosend = 0x5b; break; 392e342083cSJohn Floren case XK_bar: tosend = 0x5d; break; 393e342083cSJohn Floren case XK_asciitilde: tosend = 0x0e; break; 394e342083cSJohn Floren default: break; 395e342083cSJohn Floren } 396e342083cSJohn Floren 397e342083cSJohn Floren /* 398e342083cSJohn Floren * If this is a "key up" event (the user has released the key, we 399e342083cSJohn Floren * need to send 0xf0 first. 400e342083cSJohn Floren */ 401e342083cSJohn Floren if (!down && tosend != 0x0) 402e342083cSJohn Floren kbd_queue(0xf0); 403e342083cSJohn Floren 404e342083cSJohn Floren if (tosend) 405e342083cSJohn Floren kbd_queue(tosend); 406e342083cSJohn Floren } 407e342083cSJohn Floren 408e342083cSJohn Floren /* The previous X and Y coordinates of the mouse */ 409e342083cSJohn Floren static int xlast, ylast = -1; 410e342083cSJohn Floren 411e342083cSJohn Floren /* 412e342083cSJohn Floren * This function is called by the VNC server whenever a mouse event occurs. 413e342083cSJohn Floren */ 414e342083cSJohn Floren void kbd_handle_ptr(int buttonMask, int x, int y, rfbClientPtr cl) 415e342083cSJohn Floren { 416e342083cSJohn Floren int dx, dy; 417e342083cSJohn Floren char b1 = 0x8; 418e342083cSJohn Floren 419e342083cSJohn Floren /* The VNC mask and the PS/2 button encoding are the same */ 420e342083cSJohn Floren b1 |= buttonMask; 421e342083cSJohn Floren 422e342083cSJohn Floren if (xlast >= 0 && ylast >= 0) { 423e342083cSJohn Floren /* The PS/2 mouse sends deltas, not absolutes */ 424e342083cSJohn Floren dx = x - xlast; 425e342083cSJohn Floren dy = ylast - y; 426e342083cSJohn Floren 427e342083cSJohn Floren /* Set overflow bits if needed */ 428e342083cSJohn Floren if (dy > 255) 429e342083cSJohn Floren b1 |= 0x80; 430e342083cSJohn Floren if (dx > 255) 431e342083cSJohn Floren b1 |= 0x40; 432e342083cSJohn Floren 433e342083cSJohn Floren /* Set negative bits if needed */ 434e342083cSJohn Floren if (dy < 0) 435e342083cSJohn Floren b1 |= 0x20; 436e342083cSJohn Floren if (dx < 0) 437e342083cSJohn Floren b1 |= 0x10; 438e342083cSJohn Floren 439e342083cSJohn Floren mouse_queue(b1); 440e342083cSJohn Floren mouse_queue(dx); 441e342083cSJohn Floren mouse_queue(dy); 442e342083cSJohn Floren } 443e342083cSJohn Floren 444e342083cSJohn Floren xlast = x; 445e342083cSJohn Floren ylast = y; 446e342083cSJohn Floren rfbDefaultPtrAddEvent(buttonMask, x, y, cl); 447e342083cSJohn Floren } 448e342083cSJohn Floren 449e342083cSJohn Floren /* 450e342083cSJohn Floren * Called when the OS has written to one of the keyboard's ports (0x60 or 0x64) 451e342083cSJohn Floren */ 452e342083cSJohn Floren static bool kbd_in(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 453e342083cSJohn Floren { 454e342083cSJohn Floren u32 result; 455e342083cSJohn Floren 45667307cddSPekka Enberg if (port == I8042_COMMAND_REG) { 457e342083cSJohn Floren result = kbd_read_status(); 458e342083cSJohn Floren ioport__write8(data, (char)result); 459e342083cSJohn Floren } else { 460e342083cSJohn Floren result = kbd_read_data(); 461e342083cSJohn Floren ioport__write32(data, result); 462e342083cSJohn Floren } 463e342083cSJohn Floren return true; 464e342083cSJohn Floren } 465e342083cSJohn Floren 466e342083cSJohn Floren /* 467e342083cSJohn Floren * Called when the OS attempts to read from a keyboard port (0x60 or 0x64) 468e342083cSJohn Floren */ 469e342083cSJohn Floren static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 470e342083cSJohn Floren { 47167307cddSPekka Enberg if (port == I8042_COMMAND_REG) 472e342083cSJohn Floren kbd_write_command(*((u32 *)data)); 473e342083cSJohn Floren else 474e342083cSJohn Floren kbd_write_data(*((u32 *)data)); 475e342083cSJohn Floren 476e342083cSJohn Floren return true; 477e342083cSJohn Floren } 478e342083cSJohn Floren 479e342083cSJohn Floren static struct ioport_operations kbd_ops = { 480e342083cSJohn Floren .io_in = kbd_in, 481e342083cSJohn Floren .io_out = kbd_out, 482e342083cSJohn Floren }; 483e342083cSJohn Floren 484e342083cSJohn Floren void kbd__init(struct kvm *kvm) 485e342083cSJohn Floren { 486e342083cSJohn Floren kbd_reset(); 487e342083cSJohn Floren state.kvm = kvm; 48867307cddSPekka Enberg ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL); 48967307cddSPekka Enberg ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL); 490e342083cSJohn Floren } 491