Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


c05b00e06fca10bebd0c527751f04ff70518f50b
[palacios.git] / palacios / src / devices / keyboard.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2008, Peter Dinda <pdinda@northwestern.edu> 
11  * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Peter Dinda <pdinda@northwestern.edu>
15  *
16  * This is free software.  You are permitted to use,
17  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
18  */
19
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_types.h>
23
24 #include <palacios/vmm_ringbuffer.h>
25 #include <palacios/vmm_lock.h>
26
27
28 #ifndef CONFIG_DEBUG_KEYBOARD
29 #undef PrintDebug
30 #define PrintDebug(fmt, args...)
31 #endif
32
33 #define KEYBOARD_DEBUG_80H   0
34
35
36
37 #define KEYBOARD_60H          0x60  // keyboard microcontroller
38 #define KEYBOARD_64H          0x64  // onboard microcontroller
39
40 #define KEYBOARD_DELAY_80H    0x80  // written for timing
41
42 #define KEYBOARD_IRQ          0x1
43 #define MOUSE_IRQ             0xc   
44
45
46
47 // bits for the output port 
48 #define OUTPUT_RESET        0x01  // System reset on 0
49 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
50 #define OUTPUT_RES1         0x04  // reserved
51 #define OUTPUT_RES2         0x08  // reserved
52 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
53 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
54 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
55 #define OUTPUT_KBD_DATA     0x80  // keyboard data
56
57 // bits for the input port
58
59 #define INPUT_RES0          0x01  // reserved
60 #define INPUT_RES1          0x02  // reserved
61 #define INPUT_RES2          0x04  // reserved
62 #define INPUT_RES3          0x08  // reserved
63 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
64 #define INPUT_JUMPER        0x20  // manufacturing jumper?
65 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
66 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
67
68
69 #define MOUSE_ACK           0xfa
70
71 // for queue operations
72 #define QUEUE               0
73 #define OVERWRITE           1
74
75 // for queue operations - whether it's data or cmd waiting on 60h
76 #define DATA                0
77 #define COMMAND             1
78
79 // for queue operations - whether this is keyboard or mouse data on 60h
80 #define KEYBOARD            0
81 #define MOUSE               1
82
83
84
85 struct cmd_reg {
86     union {
87         uint8_t val;
88         struct {
89             uint8_t irq_en        : 1;  // 1=interrupts enabled
90             uint8_t mouse_irq_en  : 1;  // 1=interrupts enabled for mouse
91             uint8_t self_test_ok  : 1;  // 1= self test passed
92             uint8_t override      : 1;  // MBZ for  PS2
93             uint8_t disable       : 1;  // 1=disabled keyboard
94             uint8_t mouse_disable : 1;  // 1=disabled mouse
95             uint8_t translate     : 1;  // 1=translate to set 1 scancodes (For PC Compatibility)
96             uint8_t rsvd          : 1;  // must be zero
97         } __attribute__((packed));
98     } __attribute__((packed));
99 } __attribute__((packed));
100
101
102
103
104 struct status_reg {
105     union {
106         uint8_t val;
107         struct {
108             uint8_t out_buf_full        : 1; // 1=full (data for system)
109             uint8_t in_buf_full         : 1; // 1=full (data for 8042)
110             uint8_t self_test_ok        : 1; // 1=self-test-passed
111             uint8_t cmd                 : 1; // 0=data on 60h, 1=cmd on 64h
112             uint8_t enabled             : 1; // 1=keyboard is enabled
113             uint8_t mouse_buf_full      : 1; // 1= mouse output buffer full
114             uint8_t timeout_err         : 1; // 1=timeout of keybd
115             uint8_t parity_err          : 1; // 1=parity error
116         } __attribute__((packed));
117     } __attribute__((packed));
118 } __attribute__((packed));
119
120
121
122
123
124
125 /* This QUEUE_SIZE must be 256 */
126 /* Its designed this way to cause the start/end index to automatically
127    wrap around (2^8 = 256) so an overrun will automatically readjust the 
128    indexes 
129 */
130 #define QUEUE_SIZE 256
131 struct queue {
132     uint8_t queue[QUEUE_SIZE];
133
134     uint8_t start;
135     uint8_t end;
136     int count;
137 };
138
139 struct keyboard_internal {
140     // 
141     // 0x60 is the port for the keyboard microcontroller
142     //   writes are commands
143     //   reads from it usually return scancodes
144     //   however, it can also return other data 
145     //   depending on the state of the onboard microcontroller
146     //
147     // 0x64 is the port for the onboard microcontroller
148     //   writes are commands
149     //   reads are status
150     //
151
152     // state of the onboard microcontroller
153     // this is needed because sometimes 0x60 reads come
154     // from the onboard microcontroller
155     enum {// Normal mode measn we deliver keys
156         // to the vm and accept commands from it
157         NORMAL,
158         // after receiving cmd 0x60
159         // keybaord uC cmd will subsequently arrive
160         WRITING_CMD_BYTE,  
161         // after recieving 0xa5
162         // password arrives on data port, null terminated
163         TRANSMIT_PASSWD,
164         // after having a d1 sent to 64
165         // we wait for a new output byte on 60
166         WRITING_OUTPUT_PORT,
167         // after having a d2 sent to 64
168         // we wait for a new output byte on 60
169         // then make it available as a keystroke
170         INJECTING_KEY,
171         // after having a d3 sent to 64
172         // we wait for a new output byte on 60
173         // then make it available as a mouse event
174         INJECTING_MOUSE,
175         // after having a d4 sent to 64
176         // we wait for a new output byte on 60
177         // then send it to the mouse
178         IN_MOUSE,
179         // After the Keyboard LEDs are enabled
180         // we wait for the output byte on 64?
181         SET_LEDS,
182         // After the Keyboard SET_RATE is called
183         // we wait for the output byte on 64?
184         SET_RATE,
185     } state;
186
187
188     enum {
189         // Normal mouse state
190         STREAM, 
191         // this is used for setting sample rate
192         SAMPLE,
193         // set resolution
194         SET_RES,
195     } mouse_state;
196
197
198
199     struct cmd_reg cmd;
200     struct status_reg status;
201
202     uint8_t output_byte;      //  output port of onboard uC (e.g. A20)
203     uint8_t input_byte;       //  input port of onboard uC
204
205     // Data for system
206     uint8_t wrap;     
207
208     int mouse_enabled;
209
210     struct queue kbd_queue;
211     struct queue mouse_queue;
212
213     v3_lock_t kb_lock;
214 };
215
216
217 static int update_kb_irq(struct vm_device * dev) {
218     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
219     int irq_num = 0;
220
221
222     state->status.out_buf_full = 0;
223     state->status.mouse_buf_full = 0;
224
225
226     // If there is pending Keyboard data then it overrides mouse data
227     if (state->kbd_queue.count > 0) {
228         irq_num = KEYBOARD_IRQ;
229     } else if (state->mouse_queue.count > 0) {
230         irq_num = MOUSE_IRQ;
231         state->status.mouse_buf_full = 1;
232     } 
233     
234     PrintDebug("keyboard: interrupt 0x%d\n", irq_num);
235     
236     if (irq_num) {
237         // Global output buffer flag (for both Keyboard and mouse)
238         state->status.out_buf_full = 1;
239         
240         if (state->cmd.irq_en == 1) { 
241             v3_raise_irq(dev->vm, irq_num);
242         }
243     }
244
245     return 0;
246 }
247
248
249
250 /* Only one byte is read per irq 
251  * So if the queue is still full after a data read, we re-raise the irq
252  * If we keep reading an empty queue we return the last queue entry
253  */
254
255 static int push_to_output_queue(struct vm_device * dev, uint8_t value, uint8_t cmd, uint8_t mouse) {
256     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
257     struct queue * q = NULL;
258
259
260     if (mouse) {
261         q = &(state->mouse_queue);
262     } else {
263         q = &(state->kbd_queue);
264     }
265
266     if (q->count == QUEUE_SIZE) {
267         return 0;
268     }
269
270     if (cmd) {
271         state->status.cmd = 1;
272     } else {
273         state->status.cmd = 0;
274     }
275
276     q->queue[q->end++] = value;
277     q->count++;
278
279
280     update_kb_irq(dev);
281
282     return 0;
283 }
284
285
286
287 static int pull_from_output_queue(struct vm_device * dev, uint8_t * value) {
288     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
289     struct queue * q = NULL;
290
291     if (state->kbd_queue.count > 0) {
292         q = &(state->kbd_queue);
293         PrintDebug("Reading from Keyboard Queue\n");
294     } else if (state->mouse_queue.count > 0) {
295         q = &(state->mouse_queue);
296         PrintDebug("Reading from Mouse Queue\n");
297     } else {
298         uint8_t idx = state->kbd_queue.start - 1;
299         PrintDebug("No Data in any queue\n");
300         *value = state->kbd_queue.queue[idx];
301         return 0;
302     }
303
304     *value = q->queue[q->start++];
305     q->count--;
306
307
308     PrintDebug("Read from Queue: %x\n", *value);
309     PrintDebug("QStart=%d, QEnd=%d\n", q->start, q->end);
310
311     update_kb_irq(dev);
312
313     return 0;
314 }
315
316
317
318
319 static int key_event_handler(struct guest_info * info, 
320                              struct v3_keyboard_event * evt, 
321                              void * private_data) {
322     struct vm_device * dev = (struct vm_device *)private_data;
323     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
324
325     PrintDebug("keyboard: injected status 0x%x, and scancode 0x%x\n", evt->status, evt->scan_code);
326
327     if (evt->scan_code == 0x44) { // F10 debug dump
328         v3_print_guest_state(info);
329         //      PrintGuestPageTables(info, info->shdw_pg_state.guest_cr3);
330     } 
331 #ifdef CONFIG_SYMBIOTIC
332 else if (evt->scan_code == 0x43) { // F9 Sym test
333         PrintDebug("Testing sym call\n");
334         sym_arg_t a0 = 0x1111;
335         sym_arg_t a1 = 0x2222;
336         sym_arg_t a2 = 0x3333;
337         sym_arg_t a3 = 0x4444;
338         sym_arg_t a4 = 0x5555;
339
340         v3_sym_call5(info, SYMCALL_TEST, &a0, &a1, &a2, &a3, &a4);
341
342         V3_Print("Symcall  Test Returned arg0=%x, arg1=%x, arg2=%x, arg3=%x, arg4=%x\n",
343                  (uint32_t)a0, (uint32_t)a1, (uint32_t)a2, (uint32_t)a3, (uint32_t)a4);
344
345     } else if (evt->scan_code == 0x42) { // F8 Sym test2
346         PrintDebug("Testing sym call\n");
347         sym_arg_t addr = 0;
348         v3_sym_call1(info, SYMCALL_MEM_LOOKUP, &addr);
349     }
350 #endif
351
352
353     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
354
355     if ( (state->status.enabled == 1)      // onboard is enabled
356          && (state->cmd.disable == 0) )  {   // keyboard is enabled
357     
358         push_to_output_queue(dev, evt->scan_code, DATA, KEYBOARD);
359     }
360
361     v3_unlock_irqrestore(state->kb_lock, irq_state);
362   
363     return 0;
364 }
365
366
367 static int mouse_event_handler(struct guest_info * info, 
368                                struct v3_mouse_event * evt, 
369                                void * private_data) {
370     struct vm_device * dev = (struct vm_device *)private_data;
371     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
372     int ret = 0;
373
374     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
375                evt->data[0], evt->data[1], evt->data[2]);
376   
377     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
378
379     switch (state->mouse_state) { 
380         case STREAM:
381
382             if (state->cmd.mouse_disable == 0) {
383                 push_to_output_queue(dev, evt->data[0], DATA, MOUSE);
384                 push_to_output_queue(dev, evt->data[1], DATA, MOUSE);
385                 push_to_output_queue(dev, evt->data[2], DATA, MOUSE);
386             }
387             break;
388         default:
389             PrintError("Invalid mouse state\n");
390             ret = -1;
391             break;
392     }
393
394
395     v3_unlock_irqrestore(state->kb_lock, irq_state);
396
397     return ret;
398 }
399
400
401 static int keyboard_reset_device(struct vm_device * dev) {
402     struct keyboard_internal * data = (struct keyboard_internal *)(dev->private_data);
403   
404     memset(data, 0, sizeof(struct keyboard_internal));
405
406     data->state = NORMAL;
407     data->mouse_state = STREAM;
408
409
410     // PS2, keyboard+mouse enabled, generic translation    
411     data->cmd.val = 0;
412
413     data->cmd.irq_en = 1;
414     data->cmd.mouse_irq_en = 1;
415     data->cmd.self_test_ok = 1;
416     /** **/
417
418
419     // buffers empty, no errors
420     data->status.val = 0; 
421
422     data->status.self_test_ok = 1; // self-tests passed
423     data->status.enabled = 1;// keyboard ready
424     /** **/
425
426     
427     data->output_byte = 0;  //  ?
428
429     data->input_byte = INPUT_RAM;  // we have some
430     // also display=color, jumper 0, keyboard enabled 
431
432     PrintDebug("keyboard: reset device\n");
433  
434     return 0;
435
436 }
437
438
439
440 static int keyboard_start_device(struct vm_device * dev) {
441     PrintDebug("keyboard: start device\n");
442     return 0;
443 }
444
445
446 static int keyboard_stop_device(struct vm_device * dev) {
447     PrintDebug("keyboard: stop device\n");
448     return 0;
449 }
450
451
452
453 static int mouse_write_output(struct vm_device * dev, uint8_t data) {
454     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
455
456     switch (state->mouse_state) { 
457         case NORMAL:
458             switch (data) {
459
460                 case 0xff: //reset
461                     if (state->mouse_enabled == 0) {
462                         push_to_output_queue(dev, 0xfe, DATA, MOUSE) ;   // no mouse!
463                     } else {
464                         push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
465                         push_to_output_queue(dev, 0xaa, DATA, MOUSE) ; 
466                         push_to_output_queue(dev, 0x00, DATA, MOUSE) ; 
467                     }
468                     break;
469
470 /*              case 0xfe: //resend */
471 /*                  PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
472 /*                  PrintDebug(" mouse resend begins "); */
473 /*                  state->mouse_done_after_ack = 0; */
474 /*                  state->mouse_needs_ack = 0; */
475 /*                  state->mouse_state = STREAM1; */
476 /*                  return 0;  // not done */
477 /*                  break; */
478       
479                 case 0xf6: // set defaults
480                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
481                     PrintDebug(" mouse set defaults ");
482
483                     break;
484       
485                 case 0xf5: // disable data reporting 
486                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
487                     PrintDebug(" mouse disable data reporting ");
488                     break;
489       
490                 case 0xf4: // enable data reporting 
491                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
492                     PrintDebug(" mouse enable data reporting ");
493                     break;
494       
495                 case 0xf3: // set sample rate
496                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
497                     state->mouse_state = SAMPLE;
498                     PrintDebug(" mouse set sample rate begins ");
499                     break;
500       
501                 case 0xf2: // get device id
502                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
503                     push_to_output_queue(dev, 0x0,  DATA, MOUSE); 
504                     PrintDebug(" mouse get device id begins ");
505                     break;
506       
507                 case 0xf0: // set remote mode
508                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
509                     PrintDebug(" mouse set remote mode  ");
510                     break;
511
512                 case 0xee: // set wrap mode
513                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
514                     PrintError(" mouse set wrap mode (ignored)  ");
515                     break;
516
517                 case 0xec: // reset wrap mode
518                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
519                     PrintError(" mouse reset wrap mode (ignored)  ");
520                     break;
521
522                 case 0xeb: // read data
523                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
524                     PrintError(" mouse switch to wrap mode (ignored)  ");
525                     break;
526       
527                 case 0xea: // set stream mode
528                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
529                     PrintDebug(" mouse set stream mode  ");
530                     break;
531
532                 case 0xe9: // status request
533                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
534                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
535                     push_to_output_queue(dev, 0x00, DATA, MOUSE);
536                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
537                     PrintDebug(" mouse status request begins  ");
538                     break;
539
540                 case 0xe8: // set resolution
541                     push_to_output_queue(dev, MOUSE_ACK,  DATA, MOUSE) ; 
542                     PrintDebug(" mouse set resolution begins  ");
543                     state->mouse_state = SET_RES;
544                     break;
545
546                 case 0xe7: // set scaling 2:1
547                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
548                     PrintDebug(" mouse set scaling 2:1 ");
549                     break;
550
551                 case 0xe6: // set scaling 1:1
552                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
553                     PrintDebug(" mouse set scaling 1:1 ");
554                     break;
555       
556                 default:
557                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
558                     break;
559             }
560
561             break;
562         case SAMPLE:
563         case SET_RES:
564         default:
565             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
566             return -1;
567     }
568
569     return 0;
570 }
571
572
573
574 #if KEYBOARD_DEBUG_80H
575 static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, struct vm_device * dev) {
576
577     if (length == 1) { 
578         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
579         return 1;
580     } else {
581         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
582         return length;
583     }
584 }
585
586 static int keyboard_read_delay(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
587
588     if (length == 1) { 
589         *(uint8_t *)dest = v3_inb(port);
590
591         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
592
593         return 1;
594     } else {
595         PrintDebug("keyboard: read of >1 byte from 80h\n");
596
597         return length;
598     }
599 }
600 #endif
601     
602   
603
604
605
606 static int keyboard_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
607     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
608     uint8_t cmd = *(uint8_t *)src;
609
610     // Should always be single byte write
611     if (length != 1) { 
612         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
613         return -1;
614     }
615
616
617     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
618
619     if (state->state != NORMAL) { 
620         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
621     }
622   
623     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
624
625     switch (cmd) { 
626         case 0x20:  // READ COMMAND BYTE (returned in 60h)
627             push_to_output_queue(dev, state->cmd.val, COMMAND, KEYBOARD);
628             PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd.val);
629             break;
630
631         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
632             state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
633             PrintDebug("keyboard: prepare to write command byte\n");
634             break;
635
636             // case 0x90-9f - write to output port  (?)
637
638         case 0xa1: // Get version number
639             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
640             PrintDebug("keyboard: version number 0x0 returned\n");
641             break;
642
643         case 0xa4:  // is password installed?  send result to 0x60
644             // we don't support passwords
645             push_to_output_queue(dev, 0xf1, COMMAND, KEYBOARD);
646             PrintDebug("keyboard: password not installed\n");
647             break;
648
649         case 0xa5:  // new password will arrive on 0x60
650             state->state = TRANSMIT_PASSWD;
651             PrintDebug("keyboard: pepare to transmit password\n");
652             break;
653
654         case 0xa6:  // check passwd;
655             // since we do not support passwords, we will simply ignore this
656             // the implication is that any password check immediately succeeds 
657             // with a blank password
658             PrintDebug("keyboard: password check succeeded\n");
659             break;
660
661         case 0xa7:  // disable mouse
662             state->cmd.mouse_disable = 1;
663             PrintDebug("keyboard: mouse disabled\n");
664             break;
665
666         case 0xa8:  // enable mouse
667             state->cmd.mouse_disable = 0;
668             PrintDebug("keyboard: mouse enabled\n");
669             break;
670
671         case 0xa9:  // mouse interface test  (always succeeds)
672             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
673             PrintDebug("keyboard: mouse interface test succeeded\n");
674             break;
675
676         case 0xaa:  // controller self test (always succeeds)
677             push_to_output_queue(dev, 0x55, COMMAND, KEYBOARD);
678             PrintDebug("keyboard: controller self test succeeded\n");
679             break;
680
681         case 0xab:  // keyboard interface test (always succeeds)
682             push_to_output_queue(dev, 0, COMMAND, KEYBOARD);
683             PrintDebug("keyboard: keyboard interface test succeeded\n");
684             break;
685
686         case 0xad:  // disable keyboard
687             state->cmd.disable = 1;
688             PrintDebug("keyboard: keyboard disabled\n");
689             break;
690
691         case 0xae:  // enable keyboard
692             state->cmd.disable = 0;
693             PrintDebug("keyboard: keyboard enabled\n");
694             break;
695
696         case 0xaf:  // get version
697             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
698             PrintDebug("keyboard: version 0 returned \n");
699             break;
700
701         case 0xd0: // return microcontroller output on 60h
702             push_to_output_queue(dev, state->output_byte, COMMAND, KEYBOARD);
703             PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
704             break;
705
706         case 0xd1: // request to write next byte on 60h to the microcontroller output port
707             state->state = WRITING_OUTPUT_PORT;
708             PrintDebug("keyboard: prepare to write output byte\n");
709             break;
710
711         case 0xd2:  //  write keyboard buffer (inject key)
712             state->state = INJECTING_KEY;
713             PrintDebug("keyboard: prepare to inject key\n");
714             break;
715
716         case 0xd3: //  write mouse buffer (inject mouse)
717             state->state = INJECTING_MOUSE;
718             PrintDebug("keyboard: prepare to inject mouse\n");
719             break;
720
721         case 0xd4: // write mouse device (command to mouse?)
722             state->state = IN_MOUSE;
723             PrintDebug("keyboard: prepare to inject mouse command\n");
724             break;
725
726         case 0xc0: //  read input port 
727             push_to_output_queue(dev, state->input_byte, COMMAND, KEYBOARD);
728             PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
729             break;
730
731         case 0xc1:  //copy input port lsn to status msn
732             state->status.val &= 0x0f;
733             state->status.val |= (state->input_byte & 0xf) << 4;
734             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
735             break;
736
737         case 0xc2: // copy input port msn to status msn
738             state->status.val &= 0x0f;
739             state->status.val |= (state->input_byte & 0xf0);
740             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
741             break;
742     
743         case 0xe0: // read test port
744             push_to_output_queue(dev, state->output_byte >> 6, COMMAND, KEYBOARD);
745             PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
746             break;
747
748    
749         case 0xf0:   // pulse output port
750         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
751         case 0xf2:   // instead of what is currently in output_byte (I think)
752         case 0xf3:   // main effect is taht if bit zero is zero
753         case 0xf4:   // should cause reset
754         case 0xf5:   // I doubt anything more recent than a 286 running 
755         case 0xf6:   // OS2 with the penalty box will care
756         case 0xf7:
757         case 0xf8:
758         case 0xf9:
759         case 0xfa:
760         case 0xfb:
761         case 0xfc:
762         case 0xfd:
763         case 0xfe:
764         case 0xff:
765             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
766             break;
767    
768             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
769         default:
770             PrintDebug("keyboard: ignoring command (unimplemented)\n");
771             break;
772     }
773
774     v3_unlock_irqrestore(state->kb_lock, irq_state);
775
776     return length;
777 }
778
779 static int keyboard_read_status(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
780     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
781
782     if (length != 1) { 
783         PrintError("keyboard: >1 byte read for status (64h)\n");
784         return -1;
785     }
786
787     PrintDebug("keyboard: read status (64h): ");
788
789     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
790
791     *(uint8_t *)dest = state->status.val;
792
793     v3_unlock_irqrestore(state->kb_lock, irq_state);
794     
795     PrintDebug("0x%x\n", *(uint8_t *)dest);
796     
797     return length;
798 }
799
800 static int keyboard_write_output(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
801     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
802     int ret = length;
803
804     if (length != 1) { 
805         PrintError("keyboard: write of 60h with >1 byte\n");
806         return -1;
807     }
808
809     uint8_t data = *(uint8_t *)src;
810   
811     PrintDebug("keyboard: output 0x%x on 60h\n", data);
812
813     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
814
815     switch (state->state) {
816         case WRITING_CMD_BYTE:
817             state->cmd.val = data;
818             state->state = NORMAL;
819             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd.val);
820             break;
821
822         case WRITING_OUTPUT_PORT:
823             state->output_byte = data;
824             state->state = NORMAL;
825             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
826             break;
827
828         case INJECTING_KEY:
829             push_to_output_queue(dev, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
830             state->state = NORMAL;
831             PrintDebug("keyboard: injected key 0x%x\n", data);
832             break;
833
834         case INJECTING_MOUSE:
835             push_to_output_queue(dev, data, DATA, MOUSE);
836             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
837             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
838             state->state = NORMAL;
839             break;
840
841         case IN_MOUSE:
842             PrintDebug("keyboard: mouse action: ");
843             if (mouse_write_output(dev, data)) { 
844                 state->state = NORMAL;
845             }
846             PrintDebug("\n");
847             break;
848
849         case TRANSMIT_PASSWD:
850             if (data) {
851                 //ignore passwd
852                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
853             } else {
854                 // end of password
855                 state->state = NORMAL;
856                 PrintDebug("keyboard: done with password\n");
857             }
858             break;
859
860         case SET_LEDS:
861             PrintDebug("Keyboard: LEDs being set...\n");
862             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
863             state->state = NORMAL;
864             break;
865
866         case SET_RATE:
867             PrintDebug("Keyboard: Rate being set...\n");
868             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
869             state->state = NORMAL;
870             break;
871
872         default:
873         case NORMAL: {
874             // command is being sent to keyboard controller
875             switch (data) { 
876                 case 0xff: // reset
877                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD); // ack
878                     push_to_output_queue(dev, 0xaa, COMMAND, KEYBOARD);
879                     PrintDebug("keyboard: reset complete and acked\n");
880                     break;
881
882                 case 0xf5: // disable scanning
883                 case 0xf4: // enable scanning
884                     // ack
885                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
886                     // should do something here... PAD
887                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
888                     break;
889
890                 case 0xf3:
891                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
892                     state->state = SET_RATE;
893                     break;
894
895                 case 0xf2: // get keyboard ID
896                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
897                     push_to_output_queue(dev, 0xab, COMMAND, KEYBOARD);
898                     push_to_output_queue(dev, 0x83, COMMAND, KEYBOARD);
899                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
900                     break;
901
902                 case 0xed: // enable keyboard LEDs
903                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
904                     state->state = SET_LEDS;
905                     break;
906
907                 case 0xfe: // resend
908                 case 0xfd: // set key type make
909                 case 0xfc: // set key typ make/break
910                 case 0xfb: // set key type typematic
911                 case 0xfa: // set all typematic make/break/typematic
912                 case 0xf9: // set all make
913                 case 0xf8: // set all make/break
914                 case 0xf7: // set all typemaktic
915                 case 0xf6: // set defaults
916                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
917                     ret = -1;
918                     break;
919
920                 default:
921                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
922                     state->status.out_buf_full = 1;
923                     ret = -1;
924                     break;
925             }
926             break;
927         }
928     }
929   
930     v3_unlock_irqrestore(state->kb_lock, irq_state);
931
932     return ret;
933 }
934
935 static int keyboard_read_input(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
936     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
937
938     if (length != 1) {
939         PrintError("keyboard: unknown size read from input (60h)\n");
940         return -1;
941     }
942     
943     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
944
945     pull_from_output_queue(dev, (uint8_t *)dest);
946       
947     v3_unlock_irqrestore(state->kb_lock, irq_state);
948
949     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
950
951     return length;
952 }
953
954
955
956
957
958
959 static int keyboard_free(struct vm_device * dev) {
960
961     v3_dev_unhook_io(dev, KEYBOARD_60H);
962     v3_dev_unhook_io(dev, KEYBOARD_64H);
963 #if KEYBOARD_DEBUG_80H
964     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
965 #endif
966     keyboard_reset_device(dev);
967     return 0;
968 }
969
970
971
972
973
974 static struct v3_device_ops dev_ops = { 
975     .free = keyboard_free,
976     .reset = keyboard_reset_device,
977     .start = keyboard_start_device,
978     .stop = keyboard_stop_device,
979 };
980
981
982
983
984 static int keyboard_init(struct guest_info * vm, void * cfg_data) {
985     struct keyboard_internal * keyboard_state = NULL;
986
987
988     PrintDebug("keyboard: init_device\n");
989
990     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
991
992     keyboard_state->mouse_queue.start = 0;
993     keyboard_state->mouse_queue.end = 0;
994     keyboard_state->mouse_queue.count = 0;
995
996     keyboard_state->kbd_queue.start = 0;
997     keyboard_state->kbd_queue.end = 0;
998     keyboard_state->kbd_queue.count = 0;
999
1000     keyboard_state->mouse_enabled = 0;
1001
1002     struct vm_device * dev = v3_allocate_device("KEYBOARD", &dev_ops, keyboard_state);
1003
1004     if (v3_attach_device(vm, dev) == -1) {
1005         PrintError("Could not attach device %s\n", "KEYBOARD");
1006         return -1;
1007     }
1008
1009
1010     keyboard_reset_device(dev);
1011
1012
1013     v3_lock_init(&(keyboard_state->kb_lock));
1014
1015
1016     // hook ports
1017     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1018     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1019
1020     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1021     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1022
1023
1024 #if KEYBOARD_DEBUG_80H
1025     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1026 #endif
1027
1028   
1029     //
1030     // We do not hook the IRQ here.  Instead, the underlying device driver
1031     // is responsible to call us back
1032     // 
1033
1034     return 0;
1035 }
1036
1037
1038 device_register("KEYBOARD", keyboard_init)