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