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.


added symbiotic interface
[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     } else if (evt->scan_code == 0x43) { // F9 Sym test
331         PrintDebug("Testing sym call\n");
332         v3_sym_call5(info, SYMCALL_TEST, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, NULL, NULL);
333     } else if (evt->scan_code == 0x42) { // F8 Sym test2
334         PrintDebug("Testing sym call\n");
335         v3_sym_call1(info, SYMCALL_MEM_LOOKUP, 0, NULL, NULL);
336     }
337
338
339
340     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
341
342     if ( (state->status.enabled == 1)      // onboard is enabled
343          && (state->cmd.disable == 0) )  {   // keyboard is enabled
344     
345         push_to_output_queue(dev, evt->scan_code, DATA, KEYBOARD);
346     }
347
348     v3_unlock_irqrestore(state->kb_lock, irq_state);
349   
350     return 0;
351 }
352
353
354 static int mouse_event_handler(struct guest_info * info, 
355                                struct v3_mouse_event * evt, 
356                                void * private_data) {
357     struct vm_device * dev = (struct vm_device *)private_data;
358     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
359     int ret = 0;
360
361     PrintDebug("keyboard: injected mouse packet 0x %x %x %x\n",
362                evt->data[0], evt->data[1], evt->data[2]);
363   
364     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
365
366     switch (state->mouse_state) { 
367         case STREAM:
368
369             if (state->cmd.mouse_disable == 0) {
370                 push_to_output_queue(dev, evt->data[0], DATA, MOUSE);
371                 push_to_output_queue(dev, evt->data[1], DATA, MOUSE);
372                 push_to_output_queue(dev, evt->data[2], DATA, MOUSE);
373             }
374             break;
375         default:
376             PrintError("Invalid mouse state\n");
377             ret = -1;
378             break;
379     }
380
381
382     v3_unlock_irqrestore(state->kb_lock, irq_state);
383
384     return ret;
385 }
386
387
388 static int keyboard_reset_device(struct vm_device * dev) {
389     struct keyboard_internal * data = (struct keyboard_internal *)(dev->private_data);
390   
391     memset(data, 0, sizeof(struct keyboard_internal));
392
393     data->state = NORMAL;
394     data->mouse_state = STREAM;
395
396
397     // PS2, keyboard+mouse enabled, generic translation    
398     data->cmd.val = 0;
399
400     data->cmd.irq_en = 1;
401     data->cmd.mouse_irq_en = 1;
402     data->cmd.self_test_ok = 1;
403     /** **/
404
405
406     // buffers empty, no errors
407     data->status.val = 0; 
408
409     data->status.self_test_ok = 1; // self-tests passed
410     data->status.enabled = 1;// keyboard ready
411     /** **/
412
413     
414     data->output_byte = 0;  //  ?
415
416     data->input_byte = INPUT_RAM;  // we have some
417     // also display=color, jumper 0, keyboard enabled 
418
419     PrintDebug("keyboard: reset device\n");
420  
421     return 0;
422
423 }
424
425
426
427 static int keyboard_start_device(struct vm_device * dev) {
428     PrintDebug("keyboard: start device\n");
429     return 0;
430 }
431
432
433 static int keyboard_stop_device(struct vm_device * dev) {
434     PrintDebug("keyboard: stop device\n");
435     return 0;
436 }
437
438
439
440 static int mouse_write_output(struct vm_device * dev, uint8_t data) {
441     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
442
443     switch (state->mouse_state) { 
444         case NORMAL:
445             switch (data) {
446
447                 case 0xff: //reset
448                     if (state->mouse_enabled == 0) {
449                         push_to_output_queue(dev, 0xfe, DATA, MOUSE) ;   // no mouse!
450                     } else {
451                         push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
452                         push_to_output_queue(dev, 0xaa, DATA, MOUSE) ; 
453                         push_to_output_queue(dev, 0x00, DATA, MOUSE) ; 
454                     }
455                     break;
456
457 /*              case 0xfe: //resend */
458 /*                  PushToOutputQueue(dev, 0xfa, OVERWRITE, DATA, MOUSE) ;  */
459 /*                  PrintDebug(" mouse resend begins "); */
460 /*                  state->mouse_done_after_ack = 0; */
461 /*                  state->mouse_needs_ack = 0; */
462 /*                  state->mouse_state = STREAM1; */
463 /*                  return 0;  // not done */
464 /*                  break; */
465       
466                 case 0xf6: // set defaults
467                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
468                     PrintDebug(" mouse set defaults ");
469
470                     break;
471       
472                 case 0xf5: // disable data reporting 
473                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
474                     PrintDebug(" mouse disable data reporting ");
475                     break;
476       
477                 case 0xf4: // enable data reporting 
478                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
479                     PrintDebug(" mouse enable data reporting ");
480                     break;
481       
482                 case 0xf3: // set sample rate
483                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
484                     state->mouse_state = SAMPLE;
485                     PrintDebug(" mouse set sample rate begins ");
486                     break;
487       
488                 case 0xf2: // get device id
489                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
490                     push_to_output_queue(dev, 0x0,  DATA, MOUSE); 
491                     PrintDebug(" mouse get device id begins ");
492                     break;
493       
494                 case 0xf0: // set remote mode
495                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
496                     PrintDebug(" mouse set remote mode  ");
497                     break;
498
499                 case 0xee: // set wrap mode
500                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
501                     PrintError(" mouse set wrap mode (ignored)  ");
502                     break;
503
504                 case 0xec: // reset wrap mode
505                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
506                     PrintError(" mouse reset wrap mode (ignored)  ");
507                     break;
508
509                 case 0xeb: // read data
510                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
511                     PrintError(" mouse switch to wrap mode (ignored)  ");
512                     break;
513       
514                 case 0xea: // set stream mode
515                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
516                     PrintDebug(" mouse set stream mode  ");
517                     break;
518
519                 case 0xe9: // status request
520                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
521                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
522                     push_to_output_queue(dev, 0x00, DATA, MOUSE);
523                     push_to_output_queue(dev, 0x00, DATA, MOUSE); 
524                     PrintDebug(" mouse status request begins  ");
525                     break;
526
527                 case 0xe8: // set resolution
528                     push_to_output_queue(dev, MOUSE_ACK,  DATA, MOUSE) ; 
529                     PrintDebug(" mouse set resolution begins  ");
530                     state->mouse_state = SET_RES;
531                     break;
532
533                 case 0xe7: // set scaling 2:1
534                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
535                     PrintDebug(" mouse set scaling 2:1 ");
536                     break;
537
538                 case 0xe6: // set scaling 1:1
539                     push_to_output_queue(dev, MOUSE_ACK, DATA, MOUSE) ; 
540                     PrintDebug(" mouse set scaling 1:1 ");
541                     break;
542       
543                 default:
544                     PrintDebug(" receiving unknown mouse command (0x%x) in acceptable state ", data);
545                     break;
546             }
547
548             break;
549         case SAMPLE:
550         case SET_RES:
551         default:
552             PrintDebug(" receiving mouse output in unhandled state (0x%x) ", state->mouse_state);
553             return -1;
554     }
555
556     return 0;
557 }
558
559
560
561 #if KEYBOARD_DEBUG_80H
562 static int keyboard_write_delay(ushort_t port, void * src,  uint_t length, struct vm_device * dev) {
563
564     if (length == 1) { 
565         PrintDebug("keyboard: write of 0x%x to 80h\n", *((uint8_t*)src));
566         return 1;
567     } else {
568         PrintDebug("keyboard: write of >1 byte to 80h\n", *((uint8_t*)src));
569         return length;
570     }
571 }
572
573 static int keyboard_read_delay(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
574
575     if (length == 1) { 
576         *(uint8_t *)dest = v3_inb(port);
577
578         PrintDebug("keyboard: read of 0x%x from 80h\n", *((uint8_t*)dest));
579
580         return 1;
581     } else {
582         PrintDebug("keyboard: read of >1 byte from 80h\n");
583
584         return length;
585     }
586 }
587 #endif
588     
589   
590
591
592
593 static int keyboard_write_command(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
594     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
595     uint8_t cmd = *(uint8_t *)src;
596
597     // Should always be single byte write
598     if (length != 1) { 
599         PrintError("keyboard: write of >1 bytes (%d) to 64h\n", length);
600         return -1;
601     }
602
603
604     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
605
606     if (state->state != NORMAL) { 
607         PrintDebug("keyboard: warning - receiving command on 64h but state != NORMAL\n");
608     }
609   
610     PrintDebug("keyboard: command 0x%x on 64h\n", cmd);
611
612     switch (cmd) { 
613         case 0x20:  // READ COMMAND BYTE (returned in 60h)
614             push_to_output_queue(dev, state->cmd.val, COMMAND, KEYBOARD);
615             PrintDebug("keyboard: command byte 0x%x returned\n", state->cmd.val);
616             break;
617
618         case 0x60:  // WRITE COMMAND BYTE (read from 60h)
619             state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
620             PrintDebug("keyboard: prepare to write command byte\n");
621             break;
622
623             // case 0x90-9f - write to output port  (?)
624
625         case 0xa1: // Get version number
626             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
627             PrintDebug("keyboard: version number 0x0 returned\n");
628             break;
629
630         case 0xa4:  // is password installed?  send result to 0x60
631             // we don't support passwords
632             push_to_output_queue(dev, 0xf1, COMMAND, KEYBOARD);
633             PrintDebug("keyboard: password not installed\n");
634             break;
635
636         case 0xa5:  // new password will arrive on 0x60
637             state->state = TRANSMIT_PASSWD;
638             PrintDebug("keyboard: pepare to transmit password\n");
639             break;
640
641         case 0xa6:  // check passwd;
642             // since we do not support passwords, we will simply ignore this
643             // the implication is that any password check immediately succeeds 
644             // with a blank password
645             PrintDebug("keyboard: password check succeeded\n");
646             break;
647
648         case 0xa7:  // disable mouse
649             state->cmd.mouse_disable = 1;
650             PrintDebug("keyboard: mouse disabled\n");
651             break;
652
653         case 0xa8:  // enable mouse
654             state->cmd.mouse_disable = 0;
655             PrintDebug("keyboard: mouse enabled\n");
656             break;
657
658         case 0xa9:  // mouse interface test  (always succeeds)
659             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
660             PrintDebug("keyboard: mouse interface test succeeded\n");
661             break;
662
663         case 0xaa:  // controller self test (always succeeds)
664             push_to_output_queue(dev, 0x55, COMMAND, KEYBOARD);
665             PrintDebug("keyboard: controller self test succeeded\n");
666             break;
667
668         case 0xab:  // keyboard interface test (always succeeds)
669             push_to_output_queue(dev, 0, COMMAND, KEYBOARD);
670             PrintDebug("keyboard: keyboard interface test succeeded\n");
671             break;
672
673         case 0xad:  // disable keyboard
674             state->cmd.disable = 1;
675             PrintDebug("keyboard: keyboard disabled\n");
676             break;
677
678         case 0xae:  // enable keyboard
679             state->cmd.disable = 0;
680             PrintDebug("keyboard: keyboard enabled\n");
681             break;
682
683         case 0xaf:  // get version
684             push_to_output_queue(dev, 0x00, COMMAND, KEYBOARD);
685             PrintDebug("keyboard: version 0 returned \n");
686             break;
687
688         case 0xd0: // return microcontroller output on 60h
689             push_to_output_queue(dev, state->output_byte, COMMAND, KEYBOARD);
690             PrintDebug("keyboard: output byte 0x%x returned\n", state->output_byte);
691             break;
692
693         case 0xd1: // request to write next byte on 60h to the microcontroller output port
694             state->state = WRITING_OUTPUT_PORT;
695             PrintDebug("keyboard: prepare to write output byte\n");
696             break;
697
698         case 0xd2:  //  write keyboard buffer (inject key)
699             state->state = INJECTING_KEY;
700             PrintDebug("keyboard: prepare to inject key\n");
701             break;
702
703         case 0xd3: //  write mouse buffer (inject mouse)
704             state->state = INJECTING_MOUSE;
705             PrintDebug("keyboard: prepare to inject mouse\n");
706             break;
707
708         case 0xd4: // write mouse device (command to mouse?)
709             state->state = IN_MOUSE;
710             PrintDebug("keyboard: prepare to inject mouse command\n");
711             break;
712
713         case 0xc0: //  read input port 
714             push_to_output_queue(dev, state->input_byte, COMMAND, KEYBOARD);
715             PrintDebug("keyboard: input byte 0x%x returned\n", state->input_byte);
716             break;
717
718         case 0xc1:  //copy input port lsn to status msn
719             state->status.val &= 0x0f;
720             state->status.val |= (state->input_byte & 0xf) << 4;
721             PrintDebug("keyboard: copied input byte low 4 bits to status reg hi 4 bits\n");
722             break;
723
724         case 0xc2: // copy input port msn to status msn
725             state->status.val &= 0x0f;
726             state->status.val |= (state->input_byte & 0xf0);
727             PrintDebug("keyboard: copied input byte hi 4 bits to status reg hi 4 bits\n");
728             break;
729     
730         case 0xe0: // read test port
731             push_to_output_queue(dev, state->output_byte >> 6, COMMAND, KEYBOARD);
732             PrintDebug("keyboard: read 0x%x from test port\n", state->output_byte >> 6);
733             break;
734
735    
736         case 0xf0:   // pulse output port
737         case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
738         case 0xf2:   // instead of what is currently in output_byte (I think)
739         case 0xf3:   // main effect is taht if bit zero is zero
740         case 0xf4:   // should cause reset
741         case 0xf5:   // I doubt anything more recent than a 286 running 
742         case 0xf6:   // OS2 with the penalty box will care
743         case 0xf7:
744         case 0xf8:
745         case 0xf9:
746         case 0xfa:
747         case 0xfb:
748         case 0xfc:
749         case 0xfd:
750         case 0xfe:
751         case 0xff:
752             PrintDebug("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n", (cmd & 0xf));
753             break;
754    
755             // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
756         default:
757             PrintDebug("keyboard: ignoring command (unimplemented)\n");
758             break;
759     }
760
761     v3_unlock_irqrestore(state->kb_lock, irq_state);
762
763     return length;
764 }
765
766 static int keyboard_read_status(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
767     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
768
769     if (length != 1) { 
770         PrintError("keyboard: >1 byte read for status (64h)\n");
771         return -1;
772     }
773
774     PrintDebug("keyboard: read status (64h): ");
775
776     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
777
778     *(uint8_t *)dest = state->status.val;
779
780     v3_unlock_irqrestore(state->kb_lock, irq_state);
781     
782     PrintDebug("0x%x\n", *(uint8_t *)dest);
783     
784     return length;
785 }
786
787 static int keyboard_write_output(ushort_t port, void * src, uint_t length, struct vm_device * dev) {
788     struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
789     int ret = length;
790
791     if (length != 1) { 
792         PrintError("keyboard: write of 60h with >1 byte\n");
793         return -1;
794     }
795
796     uint8_t data = *(uint8_t *)src;
797   
798     PrintDebug("keyboard: output 0x%x on 60h\n", data);
799
800     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
801
802     switch (state->state) {
803         case WRITING_CMD_BYTE:
804             state->cmd.val = data;
805             state->state = NORMAL;
806             PrintDebug("keyboard: wrote new command byte 0x%x\n", state->cmd.val);
807             break;
808
809         case WRITING_OUTPUT_PORT:
810             state->output_byte = data;
811             state->state = NORMAL;
812             PrintDebug("keyboard: wrote new output byte 0x%x\n", state->output_byte);
813             break;
814
815         case INJECTING_KEY:
816             push_to_output_queue(dev, data, COMMAND, KEYBOARD);  // probably should be a call to deliver_key_to_vmm()
817             state->state = NORMAL;
818             PrintDebug("keyboard: injected key 0x%x\n", data);
819             break;
820
821         case INJECTING_MOUSE:
822             push_to_output_queue(dev, data, DATA, MOUSE);
823             //      PrintDebug("keyboard: ignoring injected mouse event 0x%x\n", data);
824             PrintDebug("keyboard: injected mouse event 0x%x\n", data);
825             state->state = NORMAL;
826             break;
827
828         case IN_MOUSE:
829             PrintDebug("keyboard: mouse action: ");
830             if (mouse_write_output(dev, data)) { 
831                 state->state = NORMAL;
832             }
833             PrintDebug("\n");
834             break;
835
836         case TRANSMIT_PASSWD:
837             if (data) {
838                 //ignore passwd
839                 PrintDebug("keyboard: ignoring password character 0x%x\n",data);
840             } else {
841                 // end of password
842                 state->state = NORMAL;
843                 PrintDebug("keyboard: done with password\n");
844             }
845             break;
846
847         case SET_LEDS:
848             PrintDebug("Keyboard: LEDs being set...\n");
849             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
850             state->state = NORMAL;
851             break;
852
853         case SET_RATE:
854             PrintDebug("Keyboard: Rate being set...\n");
855             push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
856             state->state = NORMAL;
857             break;
858
859         default:
860         case NORMAL: {
861             // command is being sent to keyboard controller
862             switch (data) { 
863                 case 0xff: // reset
864                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD); // ack
865                     push_to_output_queue(dev, 0xaa, COMMAND, KEYBOARD);
866                     PrintDebug("keyboard: reset complete and acked\n");
867                     break;
868
869                 case 0xf5: // disable scanning
870                 case 0xf4: // enable scanning
871                     // ack
872                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
873                     // should do something here... PAD
874                     PrintDebug("keyboard: %s scanning done and acked\n", (data == 0xf5) ? "disable" : "enable");
875                     break;
876
877                 case 0xf3:
878                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
879                     state->state = SET_RATE;
880                     break;
881
882                 case 0xf2: // get keyboard ID
883                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
884                     push_to_output_queue(dev, 0xab, COMMAND, KEYBOARD);
885                     push_to_output_queue(dev, 0x83, COMMAND, KEYBOARD);
886                     PrintDebug("Keyboard: Requesting Keyboard ID\n");
887                     break;
888
889                 case 0xed: // enable keyboard LEDs
890                     push_to_output_queue(dev, 0xfa, COMMAND, KEYBOARD);
891                     state->state = SET_LEDS;
892                     break;
893
894                 case 0xfe: // resend
895                 case 0xfd: // set key type make
896                 case 0xfc: // set key typ make/break
897                 case 0xfb: // set key type typematic
898                 case 0xfa: // set all typematic make/break/typematic
899                 case 0xf9: // set all make
900                 case 0xf8: // set all make/break
901                 case 0xf7: // set all typemaktic
902                 case 0xf6: // set defaults
903                     PrintError("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
904                     ret = -1;
905                     break;
906
907                 default:
908                     PrintError("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
909                     state->status.out_buf_full = 1;
910                     ret = -1;
911                     break;
912             }
913             break;
914         }
915     }
916   
917     v3_unlock_irqrestore(state->kb_lock, irq_state);
918
919     return ret;
920 }
921
922 static int keyboard_read_input(ushort_t port, void * dest, uint_t length, struct vm_device * dev) {
923     struct keyboard_internal * state = (struct keyboard_internal *)(dev->private_data);
924
925     if (length != 1) {
926         PrintError("keyboard: unknown size read from input (60h)\n");
927         return -1;
928     }
929     
930     addr_t irq_state = v3_lock_irqsave(state->kb_lock);
931
932     pull_from_output_queue(dev, (uint8_t *)dest);
933       
934     v3_unlock_irqrestore(state->kb_lock, irq_state);
935
936     PrintDebug("keyboard: read from input (60h): 0x%x\n", *(uint8_t *)dest);
937
938     return length;
939 }
940
941
942
943
944
945
946 static int keyboard_free(struct vm_device * dev) {
947
948     v3_dev_unhook_io(dev, KEYBOARD_60H);
949     v3_dev_unhook_io(dev, KEYBOARD_64H);
950 #if KEYBOARD_DEBUG_80H
951     v3_dev_unhook_io(dev, KEYBOARD_DELAY_80H);
952 #endif
953     keyboard_reset_device(dev);
954     return 0;
955 }
956
957
958
959
960
961 static struct v3_device_ops dev_ops = { 
962     .free = keyboard_free,
963     .reset = keyboard_reset_device,
964     .start = keyboard_start_device,
965     .stop = keyboard_stop_device,
966 };
967
968
969
970
971 static int keyboard_init(struct guest_info * vm, void * cfg_data) {
972     struct keyboard_internal * keyboard_state = NULL;
973
974
975     PrintDebug("keyboard: init_device\n");
976
977     keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
978
979     keyboard_state->mouse_queue.start = 0;
980     keyboard_state->mouse_queue.end = 0;
981     keyboard_state->mouse_queue.count = 0;
982
983     keyboard_state->kbd_queue.start = 0;
984     keyboard_state->kbd_queue.end = 0;
985     keyboard_state->kbd_queue.count = 0;
986
987     keyboard_state->mouse_enabled = 0;
988
989     struct vm_device * dev = v3_allocate_device("KEYBOARD", &dev_ops, keyboard_state);
990
991     if (v3_attach_device(vm, dev) == -1) {
992         PrintError("Could not attach device %s\n", "KEYBOARD");
993         return -1;
994     }
995
996
997     keyboard_reset_device(dev);
998
999
1000     v3_lock_init(&(keyboard_state->kb_lock));
1001
1002
1003     // hook ports
1004     v3_dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
1005     v3_dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
1006
1007     v3_hook_host_event(vm, HOST_KEYBOARD_EVT, V3_HOST_EVENT_HANDLER(key_event_handler), dev);
1008     v3_hook_host_event(vm, HOST_MOUSE_EVT, V3_HOST_EVENT_HANDLER(mouse_event_handler), dev);
1009
1010
1011 #if KEYBOARD_DEBUG_80H
1012     v3_dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
1013 #endif
1014
1015   
1016     //
1017     // We do not hook the IRQ here.  Instead, the underlying device driver
1018     // is responsible to call us back
1019     // 
1020
1021     return 0;
1022 }
1023
1024
1025 device_register("KEYBOARD", keyboard_init)