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 25e342083cSJohn Floren #define CMD_READ_MODE 0x20 26e342083cSJohn Floren #define CMD_WRITE_MODE 0x60 27e342083cSJohn Floren #define CMD_WRITE_AUX_BUF 0xD3 28e342083cSJohn Floren #define CMD_WRITE_AUX 0xD4 29e342083cSJohn Floren #define CMD_TEST_AUX 0xA9 30e342083cSJohn Floren #define CMD_DISABLE_AUX 0xA7 31e342083cSJohn Floren #define CMD_ENABLE_AUX 0xA8 32e342083cSJohn Floren 33e342083cSJohn Floren #define RESPONSE_ACK 0xFA 34e342083cSJohn Floren 35e342083cSJohn Floren #define MODE_DISABLE_AUX 0x20 36e342083cSJohn Floren 37e342083cSJohn Floren #define AUX_ENABLE_REPORTING 0x20 38e342083cSJohn Floren #define AUX_SCALING_FLAG 0x10 39e342083cSJohn Floren #define AUX_DEFAULT_RESOLUTION 0x2 40e342083cSJohn Floren #define AUX_DEFAULT_SAMPLE 100 41e342083cSJohn Floren 4298cbe4d9SPekka Enberg /* 4398cbe4d9SPekka Enberg * Status register bits 4498cbe4d9SPekka Enberg */ 45*e9f4d662SPekka Enberg #define I8042_STR_AUXDATA 0x20 46*e9f4d662SPekka Enberg #define I8042_STR_KEYLOCK 0x10 47*e9f4d662SPekka Enberg #define I8042_STR_CMDDAT 0x08 48*e9f4d662SPekka Enberg #define I8042_STR_MUXERR 0x04 49*e9f4d662SPekka Enberg #define I8042_STR_OBF 0x01 50e342083cSJohn Floren 51e342083cSJohn Floren #define KBD_MODE_KBD_INT 0x01 52e342083cSJohn Floren #define KBD_MODE_SYS 0x02 53e342083cSJohn Floren 54e342083cSJohn Floren #define QUEUE_SIZE 128 55e342083cSJohn Floren 56e342083cSJohn Floren /* 57e342083cSJohn Floren * This represents the current state of the PS/2 keyboard system, 58e342083cSJohn Floren * including the AUX device (the mouse) 59e342083cSJohn Floren */ 60e342083cSJohn Floren struct kbd_state { 61e342083cSJohn Floren struct kvm *kvm; 62e342083cSJohn Floren 63e342083cSJohn Floren char kq[QUEUE_SIZE]; /* Keyboard queue */ 64e342083cSJohn Floren int kread, kwrite; /* Indexes into the queue */ 65e342083cSJohn Floren int kcount; /* number of elements in queue */ 66e342083cSJohn Floren 67e342083cSJohn Floren char mq[QUEUE_SIZE]; 68e342083cSJohn Floren int mread, mwrite; 69e342083cSJohn Floren int mcount; 70e342083cSJohn Floren 71e342083cSJohn Floren u8 mstatus; /* Mouse status byte */ 72e342083cSJohn Floren u8 mres; /* Current mouse resolution */ 73e342083cSJohn Floren u8 msample; /* Current mouse samples/second */ 74e342083cSJohn Floren 75e342083cSJohn Floren u8 mode; /* i8042 mode register */ 76e342083cSJohn Floren u8 status; /* i8042 status register */ 77e342083cSJohn Floren /* 78e342083cSJohn Floren * Some commands (on port 0x64) have arguments; 79e342083cSJohn Floren * we store the command here while we wait for the argument 80e342083cSJohn Floren */ 81e342083cSJohn Floren u32 write_cmd; 82e342083cSJohn Floren }; 83e342083cSJohn Floren 84e342083cSJohn Floren static struct kbd_state state; 85e342083cSJohn Floren 86e342083cSJohn Floren /* 87e342083cSJohn Floren * If there are packets to be read, set the appropriate IRQs high 88e342083cSJohn Floren */ 89e342083cSJohn Floren static void kbd_update_irq(void) 90e342083cSJohn Floren { 91e342083cSJohn Floren u8 klevel = 0; 92e342083cSJohn Floren u8 mlevel = 0; 93e342083cSJohn Floren 94e342083cSJohn Floren /* First, clear the kbd and aux output buffer full bits */ 95*e9f4d662SPekka Enberg state.status &= ~(I8042_STR_OBF | I8042_STR_AUXDATA); 96e342083cSJohn Floren 97e342083cSJohn Floren if (state.kcount > 0) { 98*e9f4d662SPekka Enberg state.status |= I8042_STR_OBF; 99e342083cSJohn Floren klevel = 1; 100e342083cSJohn Floren } 101e342083cSJohn Floren 102e342083cSJohn Floren /* Keyboard has higher priority than mouse */ 103e342083cSJohn Floren if (klevel == 0 && state.mcount != 0) { 104*e9f4d662SPekka Enberg state.status |= I8042_STR_OBF | I8042_STR_AUXDATA; 105e342083cSJohn Floren mlevel = 1; 106e342083cSJohn Floren } 107e342083cSJohn Floren 108e342083cSJohn Floren kvm__irq_line(state.kvm, KBD_IRQ, klevel); 109e342083cSJohn Floren kvm__irq_line(state.kvm, AUX_IRQ, mlevel); 110e342083cSJohn Floren } 111e342083cSJohn Floren 112e342083cSJohn Floren /* 113e342083cSJohn Floren * Add a byte to the mouse queue, then set IRQs 114e342083cSJohn Floren */ 115e342083cSJohn Floren static void mouse_queue(u8 c) 116e342083cSJohn Floren { 117e342083cSJohn Floren if (state.mcount >= QUEUE_SIZE) 118e342083cSJohn Floren return; 119e342083cSJohn Floren 120e342083cSJohn Floren state.mq[state.mwrite++ % QUEUE_SIZE] = c; 121e342083cSJohn Floren 122e342083cSJohn Floren state.mcount++; 123e342083cSJohn Floren kbd_update_irq(); 124e342083cSJohn Floren } 125e342083cSJohn Floren 126e342083cSJohn Floren /* 127e342083cSJohn Floren * Add a byte to the keyboard queue, then set IRQs 128e342083cSJohn Floren */ 129e342083cSJohn Floren static void kbd_queue(u8 c) 130e342083cSJohn Floren { 131e342083cSJohn Floren if (state.kcount >= QUEUE_SIZE) 132e342083cSJohn Floren return; 133e342083cSJohn Floren 134e342083cSJohn Floren state.kq[state.kwrite++ % QUEUE_SIZE] = c; 135e342083cSJohn Floren 136e342083cSJohn Floren state.kcount++; 137e342083cSJohn Floren kbd_update_irq(); 138e342083cSJohn Floren } 139e342083cSJohn Floren 140e342083cSJohn Floren /* 141e342083cSJohn Floren * This function is called when the OS issues a write to port 0x64 142e342083cSJohn Floren */ 143e342083cSJohn Floren static void kbd_write_command(u32 val) 144e342083cSJohn Floren { 145e342083cSJohn Floren switch (val) { 146e342083cSJohn Floren case CMD_READ_MODE: 147e342083cSJohn Floren kbd_queue(state.mode); 148e342083cSJohn Floren break; 149e342083cSJohn Floren case CMD_WRITE_MODE: 150e342083cSJohn Floren case CMD_WRITE_AUX: 151e342083cSJohn Floren case CMD_WRITE_AUX_BUF: 152e342083cSJohn Floren state.write_cmd = val; 153e342083cSJohn Floren break; 154e342083cSJohn Floren case CMD_TEST_AUX: 155e342083cSJohn Floren /* 0 means we're a normal PS/2 mouse */ 156e342083cSJohn Floren mouse_queue(0); 157e342083cSJohn Floren break; 158e342083cSJohn Floren case CMD_DISABLE_AUX: 159e342083cSJohn Floren state.mode |= MODE_DISABLE_AUX; 160e342083cSJohn Floren break; 161e342083cSJohn Floren case CMD_ENABLE_AUX: 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) { 214e342083cSJohn Floren case CMD_WRITE_MODE: 215e342083cSJohn Floren state.mode = val; 216e342083cSJohn Floren kbd_update_irq(); 217e342083cSJohn Floren break; 218e342083cSJohn Floren case CMD_WRITE_AUX_BUF: 219e342083cSJohn Floren mouse_queue(val); 220e342083cSJohn Floren mouse_queue(RESPONSE_ACK); 221e342083cSJohn Floren break; 222e342083cSJohn Floren case CMD_WRITE_AUX: 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) { 284*e9f4d662SPekka 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 { 451e342083cSJohn Floren u32 result; 452e342083cSJohn Floren 45367307cddSPekka Enberg if (port == I8042_COMMAND_REG) { 454e342083cSJohn Floren result = kbd_read_status(); 455e342083cSJohn Floren ioport__write8(data, (char)result); 456e342083cSJohn Floren } else { 457e342083cSJohn Floren result = kbd_read_data(); 458e342083cSJohn Floren ioport__write32(data, result); 459e342083cSJohn Floren } 460e342083cSJohn Floren return true; 461e342083cSJohn Floren } 462e342083cSJohn Floren 463e342083cSJohn Floren /* 464e342083cSJohn Floren * Called when the OS attempts to read from a keyboard port (0x60 or 0x64) 465e342083cSJohn Floren */ 466e342083cSJohn Floren static bool kbd_out(struct ioport *ioport, struct kvm *kvm, u16 port, void *data, int size, u32 count) 467e342083cSJohn Floren { 46867307cddSPekka Enberg if (port == I8042_COMMAND_REG) 469e342083cSJohn Floren kbd_write_command(*((u32 *)data)); 470e342083cSJohn Floren else 471e342083cSJohn Floren kbd_write_data(*((u32 *)data)); 472e342083cSJohn Floren 473e342083cSJohn Floren return true; 474e342083cSJohn Floren } 475e342083cSJohn Floren 476e342083cSJohn Floren static struct ioport_operations kbd_ops = { 477e342083cSJohn Floren .io_in = kbd_in, 478e342083cSJohn Floren .io_out = kbd_out, 479e342083cSJohn Floren }; 480e342083cSJohn Floren 481e342083cSJohn Floren void kbd__init(struct kvm *kvm) 482e342083cSJohn Floren { 483e342083cSJohn Floren kbd_reset(); 484e342083cSJohn Floren state.kvm = kvm; 48567307cddSPekka Enberg ioport__register(I8042_DATA_REG, &kbd_ops, 2, NULL); 48667307cddSPekka Enberg ioport__register(I8042_COMMAND_REG, &kbd_ops, 2, NULL); 487e342083cSJohn Floren } 488