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.


*** empty log message ***
[palacios.git] / palacios / src / devices / keyboard.c
1 #include <devices/keyboard.h>
2 #include <geekos/io.h>
3 #include <palacios/vmm.h>
4 #include <palacios/vmm_types.h>
5
6 #define KEYBOARD_DEBUG 0
7
8 #define KEYBOARD_DEBUG_80H   0
9
10 #if KEYBOARD_DEBUG
11 #define KEYBOARD_DEBUG_PRINT(first, rest...) PrintDebug(first, ##rest)
12 #else
13 #define KEYBOARD_DEBUG_PRINT(first, rest...)
14 #endif
15
16
17 #define KEYBOARD_60H          0x60  // keyboard microcontroller
18 #define KEYBOARD_64H          0x64  // onboard microcontroller
19
20 #define KEYBOARD_DELAY_80H    0x80  // written for timing
21
22 #define KEYBOARD_IRQ          0x1
23
24
25 // extract bits for status byte
26 #define STATUS_OUTPUT_BUFFER_FULL   0x01  // 1=full (data for system)
27 #define STATUS_INPUT_BUFFER_FULL    0x02  // 1=full (data for 8042)
28 #define STATUS_SYSTEM               0x04  // 1=self-test-passed
29 #define STATUS_COMMAND_DATA_AVAIL   0x08  // internal: 0=data on 60h, 0=cmd on 64h
30 #define STATUS_ENABLED              0x10  // 1=keyboard is enabled
31 #define STATUS_MOUSE_BUFFER_FULL    0x20  // 1= mouse output buffer full
32 #define STATUS_TIMEOUT              0x40  // 1=timeout of keybd
33 #define STATUS_PARITY               0x80  // 1=parity error
34
35 // bits for cmd byte
36
37 #define CMD_INTR                0x01  // 1=interrupts enabled
38 #define CMD_MOUSE_INTR          0x02  // 1=interrupts enabled for mouse
39 #define CMD_SYSTEM              0x04  // 1= self test passed
40 #define CMD_OVERRIDE            0x08  // FORCE 0 for  PS2
41 #define CMD_DISABLE             0x10  // 1=disabled keyboard
42 #define CMD_MOUSE_DISABLE       0x20  // 1=disabled mouse
43 #define CMD_SCANCODE_XLATE      0x40  // 1=translate to set 1 scancodes
44 #define CMD_RESERVED            0x80  // should be zero
45
46 // The currently targetted keyboard
47 static struct vm_device *thekeyboard = NULL;
48
49
50 struct keyboard_internal {
51   // 
52   // 0x60 is the port for the keyboard microcontroller
53   //   writes are commands
54   //   reads from it usually return scancodes
55   //   however, it can also return other data 
56   //   depending on the state of the onboard microcontroller
57   //
58   // 0x64 is the port for the onboard microcontroller
59   //   writes are commands
60   //   reads are status
61   //
62
63   // state of the onboard microcontroller
64   // this is needed because sometimes 0x60 reads come
65   // from the onboard microcontroller
66   enum {// Normal mode measn we deliver keys
67         // to the vm and accept commands from it
68         NORMAL,
69         // after receiving cmd 0x60
70         // keybaord uC cmd will subsequently arrive
71         WRITING_CMD_BYTE,  
72         // after recieving 0xa5
73         // password arrives on data port, null terminated
74         TRANSMIT_PASSWD,
75         // after having reset sent to 0x60
76         // we immediately ack, and then
77         // push BAT success (0xaa) after the ack
78         RESET,
79   } state;
80         
81
82
83   uchar_t cmd_byte;         //  for keyboard uC - read/written 
84                             //     via read/write cmd byte command
85   uchar_t status_byte;      //  for on-board uC - read via 64h
86
87   // Data for 8042
88   uchar_t input_queue;      //  
89   uint_t  input_queue_len;  //  
90   // Data for system
91   uchar_t output_queue;     //  
92   uint_t  output_queue_len; //  
93 };
94
95
96 // 
97 // push item onto outputqueue, optionally overwriting if there is no room
98 // returns 0 if successful
99 //
100 static int PushToOutputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite) 
101 {
102   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
103   
104   if ((state->output_queue_len == 0) || overwrite) { 
105
106     state->output_queue = value;
107     state->output_queue_len = 1;
108     state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
109
110     return 0;
111   } else {
112     KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
113     return -1;
114   }
115 }
116
117 #if 1
118 // 
119 // pull item from outputqueue 
120 // returns 0 if successful
121 //
122 static int PullFromOutputQueue(struct vm_device *dev, uchar_t *value) 
123 {
124   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
125
126   if (state->output_queue_len == 1) { 
127
128     *value = state->output_queue;
129     state->output_queue_len = 0;
130     state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
131
132     return 0;
133   } else {
134     KEYBOARD_DEBUG_PRINT("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
135     return -1;
136   }
137 }
138 #endif
139
140 #if 0
141 // 
142 // push item onto inputqueue, optionally overwriting if there is no room
143 // returns 0 if successful
144 //
145 static int PushToInputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite) 
146 {
147   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
148
149   if ((state->input_queue_len == 0) || overwrite) { 
150
151     state->input_queue = value;
152     state->input_queue_len = 1;
153     state->status_byte |= STATUS_INPUT_BUFFER_FULL;
154
155     return 0;
156   } else {
157     KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
158     return -1;
159   }
160 }
161
162 // 
163 // pull item from inputqueue 
164 // returns 0 if successful
165 //
166 static int PullFromInputQueue(struct vm_device *dev, uchar_t *value) 
167 {
168   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
169
170   if (state->input_queue_len == 1) { 
171
172     *value = state->input_queue;
173     state->input_queue_len = 0;
174     state->status_byte &= ~STATUS_INPUT_BUFFER_FULL;
175
176     return 0;
177   } else {
178     KEYBOARD_DEBUG_PRINT("keyboard: PullFromInputQueue Failed - Queue Empty\n");
179
180     return -1;
181   }
182 }
183
184 #endif
185
186 static struct vm_device *demultiplex_injected_key(uchar_t status, uchar_t scancode)
187 {
188   // this currently does nothing
189   return thekeyboard;
190 }
191
192 int keyboard_interrupt(uint_t irq, struct vm_device * dev);
193
194 void deliver_key_to_vmm(uchar_t status, uchar_t scancode)
195 {
196   struct vm_device *dev = demultiplex_injected_key(status, scancode);
197   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
198
199   KEYBOARD_DEBUG_PRINT("keyboard: injected status 0x%x, and scancode 0x%x\n", status, scancode);
200   
201   if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
202        && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
203
204     PushToOutputQueue(dev, scancode, 1);
205
206     if (state->cmd_byte & CMD_INTR) { 
207       keyboard_interrupt(KEYBOARD_IRQ, dev);
208     }
209         
210   }
211 }
212
213 int keyboard_reset_device(struct vm_device * dev)
214 {
215   struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
216   
217   memset(data, 0, sizeof(struct keyboard_internal));
218
219   data->cmd_byte =   
220       CMD_INTR        // interrupts on
221     | CMD_MOUSE_INTR  // mouse interupts on
222     | CMD_SYSTEM ;    // self test passed
223                       // PS2, keyboard+mouse enabled, generic translation    
224   
225   data->status_byte = 
226       STATUS_SYSTEM     // self-tests passed
227     | STATUS_ENABLED ;  // keyboard ready
228                         // buffers empty, no errors
229
230   KEYBOARD_DEBUG_PRINT("keyboard: reset device\n");
231  
232   return 0;
233
234 }
235
236
237
238 int keyboard_start_device(struct vm_device *dev)
239 {
240   KEYBOARD_DEBUG_PRINT("keyboard: start device\n");
241   return 0;
242 }
243
244
245 int keyboard_stop_device(struct vm_device *dev)
246 {
247   KEYBOARD_DEBUG_PRINT("keyboard: stop device\n");
248   return 0;
249 }
250
251
252 #if KEYBOARD_DEBUG_80H
253 int keyboard_write_delay(ushort_t port,
254                          void * src, 
255                          uint_t length,
256                          struct vm_device * dev)
257 {
258
259   if (length == 1) { 
260     KEYBOARD_DEBUG_PRINT("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
261
262     return 1;
263   } else {
264     KEYBOARD_DEBUG_PRINT("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
265
266     return length;
267   }
268 }
269
270 int keyboard_read_delay(ushort_t port,
271                         void * dest, 
272                         uint_t length,
273                         struct vm_device * dev)
274 {
275
276   if (length == 1) { 
277     *((uchar_t*)dest) = In_Byte(port);
278
279     KEYBOARD_DEBUG_PRINT("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
280
281     return 1;
282   } else {
283     KEYBOARD_DEBUG_PRINT("keyboard: read of >1 byte from 80h\n");
284
285     return length;
286   }
287 }
288 #endif
289     
290   
291
292
293
294 int keyboard_write_command(ushort_t port,
295                            void * src, 
296                            uint_t length,
297                            struct vm_device * dev)
298 {
299   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
300   uchar_t cmd;
301
302   // Should always be single byte write
303
304   if (length != 1) { 
305     KEYBOARD_DEBUG_PRINT("keyboard: write of >1 bytes (%d) to 64h\n", length);
306     return -1;
307   }
308
309   cmd = *((uchar_t*)src); 
310
311   if (state->state != NORMAL) { 
312     KEYBOARD_DEBUG_PRINT("keyboard: warning - receiving command on 64h but state != NORMAL\n");
313   }
314   
315   KEYBOARD_DEBUG_PRINT("keyboard: command 0x%x on 64h\n", cmd);
316
317   switch (cmd) { 
318
319   case 0x20:  // READ COMMAND BYTE (returned in 60h)
320     PushToOutputQueue(dev, state->cmd_byte, 1);
321     state->state = NORMAL;  // the next read on 0x60 will get the right data
322     break;
323
324   case 0x60:  // WRITE COMMAND BYTE (read from 60h)
325     state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
326     break;
327
328   // case 0x90-9f - write to output port  (?)
329
330   case 0xa1: // Get version number
331     PushToOutputQueue(dev, 0, 1);
332     state->state = NORMAL;
333     break;
334
335   case 0xa4:  // is password installed?  send result to 0x60
336     // we don't support passwords
337     PushToOutputQueue(dev, 0xf1, 1);
338     state->state = NORMAL;
339     break;
340
341   case 0xa5:  // new password will arrive on 0x60
342     state->state = TRANSMIT_PASSWD;
343     break;
344
345   case 0xa6:  // check passwd;
346     // since we do not support passwords, we will simply ignore this
347     // the implication is that any password check immediately succeeds 
348     // with a blank password
349     state->state = NORMAL;
350     break;
351
352   case 0xa7:  // disable mouse
353     state->cmd_byte |= CMD_MOUSE_DISABLE;
354     state->state = NORMAL;
355     break;
356
357   case 0xa8:  // enable mouse
358     state->cmd_byte &= ~CMD_MOUSE_DISABLE;
359     state->state = NORMAL;
360     break;
361
362   case 0xa9:  // mouse interface test  (always succeeds)
363     PushToOutputQueue(dev, 0, 1);
364     state->state = NORMAL;
365     break;
366
367   case 0xaa:  // controller self test (always succeeds)
368     PushToOutputQueue(dev, 0x55, 1);
369     state->state = NORMAL;
370     break;
371
372   case 0xab:  // keyboard interface test (always succeeds)
373     PushToOutputQueue(dev, 0, 1);
374     state->state = NORMAL;
375     break;
376
377   case 0xad:  // disable keyboard
378     state->cmd_byte |= CMD_DISABLE;
379     state->state = NORMAL;
380     break;
381
382   case 0xae:  // enable keyboard
383     state->cmd_byte &= ~CMD_DISABLE;
384     state->state = NORMAL;
385     break;
386
387   case 0xaf:  // get version
388     PushToOutputQueue(dev, 0x00, 1);
389     state->state = NORMAL;
390     break;
391
392   // case c0  read input port ?
393   // case c1  copy input port lsn to status
394   // case c2  copy input port msn to status
395   
396   // case d0 read output port
397   // case d1 write output port
398   // case d2 write keyboard buffer (inject key)
399   // case d3 write mouse buffer (inject mouse)
400   // case d4 write mouse device (command to mouse?)
401
402   // case e0 read test port
403   
404   // case f0..ff pulse output port ?
405
406    
407   default:
408     KEYBOARD_DEBUG_PRINT("keyboard: ignoring command (unimplemented)\n");
409     state->state = NORMAL;
410     break;
411   }
412
413   return 1;
414
415 }
416
417 int keyboard_read_status(ushort_t port,
418                          void * dest, 
419                          uint_t length,
420                          struct vm_device * dev)
421 {
422   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
423
424   if (length == 1) { 
425
426     KEYBOARD_DEBUG_PRINT("keyboard: read status (64h): ");
427
428     *((uchar_t*)dest) = state->status_byte;
429
430     KEYBOARD_DEBUG_PRINT("0x%x\n", *((uchar_t*)dest));
431
432     return 1;
433   } else {
434     KEYBOARD_DEBUG_PRINT("keyboard: >1 byte read for status (64h)\n");
435     return -1;
436   }
437 }
438
439 int keyboard_write_output(ushort_t port,
440                           void * src, 
441                           uint_t length,
442                           struct vm_device * dev)
443 {
444   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
445
446   if (length != 1) { 
447     KEYBOARD_DEBUG_PRINT("keyboard: write of 60h with >1 byte\n");
448     return -1;
449   }
450
451   uchar_t data = *((uchar_t*)src);
452   
453   switch (state->state) {
454   case WRITING_CMD_BYTE:
455     state->cmd_byte = data;
456     state->state = NORMAL;
457     break;
458   case TRANSMIT_PASSWD:
459     if (data) {
460       //ignore passwd
461     } else {
462       // end of password
463       state->state = NORMAL;
464     }
465     break;
466   case NORMAL:
467     {
468       // command is being sent to keyboard controller
469       switch (data) { 
470       case 0xff: // reset
471         PushToOutputQueue(dev, 0xfa, 1); // ack
472         state->state = RESET;
473         break;
474       case 0xf5: // disable scanning
475       case 0xf4: // enable scanning
476         // ack
477         PushToOutputQueue(dev, 0xfa, 1);
478         // should do something here... PAD
479         state->state = NORMAL;
480         break;
481       case 0xfe: // resend
482       case 0xfd: // set key type make
483       case 0xfc: // set key typ make/break
484       case 0xfb: // set key type typematic
485       case 0xfa: // set all typematic make/break/typematic
486       case 0xf9: // set all make
487       case 0xf8: // set all make/break
488       case 0xf7: // set all typemaktic
489       case 0xf6: // set defaults
490       case 0xf3: // set typematic delay/rate
491       default:
492         KEYBOARD_DEBUG_PRINT("keyboard: unhandled command 0x%x on output buffer (60h)\n", data);
493         break;
494       }
495       break;
496     }
497   default:
498     KEYBOARD_DEBUG_PRINT("keyboard: unknown state %x on command 0x%x on output buffer (60h)\n", state->state, data);
499   }
500   
501   return 1;
502 }
503
504 int keyboard_read_input(ushort_t port,
505                         void * dest, 
506                         uint_t length,
507                         struct vm_device * dev)
508 {
509   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
510
511   if (length == 1) { 
512     uchar_t data;
513
514     KEYBOARD_DEBUG_PRINT("keyboard: read from input (60h): ");
515
516     PullFromOutputQueue(dev, &data);
517
518     if (state->state == RESET) { 
519       // We just delivered the ack for the reset
520       // now we will ready ourselves to deliver the BAT code (success)
521       PushToOutputQueue(dev, 0xaa, 1);
522       state->state = NORMAL;
523     }
524       
525     KEYBOARD_DEBUG_PRINT("0x%x\n", data);
526
527     *((uchar_t*)dest) = data;
528
529     return 1;
530   } else {
531     KEYBOARD_DEBUG_PRINT("keyboard: unknown size read from input (60h)\n");
532     return -1;
533   }
534 }
535
536
537 int keyboard_interrupt(uint_t irq, struct vm_device * dev) 
538 {
539   KEYBOARD_DEBUG_PRINT("keyboard: interrupt\n");
540
541   dev->vm->vm_ops.raise_irq(dev->vm, irq);
542
543   return 0;
544
545 }
546
547
548 int keyboard_init_device(struct vm_device * dev) 
549 {
550  
551   //  struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
552
553   KEYBOARD_DEBUG_PRINT("keyboard: init_device\n");
554
555   // Would read state here
556
557   keyboard_reset_device(dev);
558
559   // hook ports
560   dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
561   dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
562
563 #if KEYBOARD_DEBUG_80H
564   dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
565 #endif
566
567   
568   //
569   // We do not hook the IRQ here.  Instead, the underlying device driver
570   // is responsible to call us back
571   // 
572
573   return 0;
574 }
575
576 int keyboard_deinit_device(struct vm_device *dev)
577 {
578
579   dev_unhook_io(dev, KEYBOARD_60H);
580   dev_unhook_io(dev, KEYBOARD_64H);
581 #if KEYBOARD_DEBUG_80H
582   dev_unhook_io(dev, KEYBOARD_DELAY_80H);
583 #endif
584   keyboard_reset_device(dev);
585   return 0;
586 }
587
588
589
590
591
592 static struct vm_device_ops dev_ops = { 
593   .init = keyboard_init_device, 
594   .deinit = keyboard_deinit_device,
595   .reset = keyboard_reset_device,
596   .start = keyboard_start_device,
597   .stop = keyboard_stop_device,
598 };
599
600
601
602
603 struct vm_device *create_keyboard() {
604   
605   if (thekeyboard != NULL) { 
606     KEYBOARD_DEBUG_PRINT("keyboard: creating >1 keyboard device.  This will probably fail!\n");
607   }
608   
609   struct keyboard_internal * keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
610
611   struct vm_device *device = create_device("KEYBOARD", &dev_ops, keyboard_state);
612
613   thekeyboard = device;
614   
615   return device;
616 }