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