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.


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