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.


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