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.


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