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.


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