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 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 // bits for the output port 
47
48
49 #define OUTPUT_RESET        0x01  // System reset on 0
50 #define OUTPUT_A20          0x02  // A20 gate (1= A20 is gated)
51 #define OUTPUT_RES1         0x04  // reserved
52 #define OUTPUT_RES2         0x08  // reserved
53 #define OUTPUT_OUTPUT_FULL  0x10  // output buffer full
54 #define OUTPUT_INPUT_EMPTY  0x20  // input buffer empty
55 #define OUTPUT_KBD_CLOCK    0x40  // keyboard clock (?)
56 #define OUTPUT_KBD_DATA     0x80  // keyboard data
57
58 // bits for the input port
59
60 #define INPUT_RES0          0x01  // reserved
61 #define INPUT_RES1          0x02  // reserved
62 #define INPUT_RES2          0x04  // reserved
63 #define INPUT_RES3          0x08  // reserved
64 #define INPUT_RAM           0x10  // set to 1 if RAM exists?
65 #define INPUT_JUMPER        0x20  // manufacturing jumper?
66 #define INPUT_DISPLAY       0x40  // 0=color, 1=mono
67 #define INPUT_KBD_INHIBIT   0x80  // 1=inhibit keyboard ?
68
69
70 #define QUEUE               0
71 #define OVERWRITE           1
72 #define DATA                0
73 #define COMMAND             1
74
75
76 // The currently targetted keyboard
77 static struct vm_device *thekeyboard = NULL;
78
79
80 struct keyboard_internal {
81   // 
82   // 0x60 is the port for the keyboard microcontroller
83   //   writes are commands
84   //   reads from it usually return scancodes
85   //   however, it can also return other data 
86   //   depending on the state of the onboard microcontroller
87   //
88   // 0x64 is the port for the onboard microcontroller
89   //   writes are commands
90   //   reads are status
91   //
92
93   // state of the onboard microcontroller
94   // this is needed because sometimes 0x60 reads come
95   // from the onboard microcontroller
96   enum {// Normal mode measn we deliver keys
97         // to the vm and accept commands from it
98         NORMAL,
99         // after receiving cmd 0x60
100         // keybaord uC cmd will subsequently arrive
101         WRITING_CMD_BYTE,  
102         // after recieving 0xa5
103         // password arrives on data port, null terminated
104         TRANSMIT_PASSWD,
105         // after having reset sent to 0x60
106         // we immediately ack, and then
107         // push BAT success (0xaa) after the ack
108         RESET,
109         // after having a d1 sent to 64
110         // we wait for a new output byte on 60
111         WRITING_OUTPUT_PORT,
112         // after having a d2 sent to 64
113         // we wait for a new output byte on 60
114         // then make it available as a keystroke
115         INJECTING_KEY,
116         // after having a d3 sent to 64
117         // we wait for a new output byte on 60
118         // then make it available as a mouse event
119         INJECTING_MOUSE,
120         // after having a d4 sent to 64
121         // we wait for a new output byte on 60
122         // then send it to the mouse
123         WRITING_MOUSE_CMD,
124   } state;
125         
126
127
128   uchar_t cmd_byte;         //  for keyboard uC - read/written 
129                             //     via read/write cmd byte command
130   uchar_t status_byte;      //  for on-board uC - read via 64h
131
132   uchar_t output_byte;      //  output port of onboard uC (e.g. A20)
133
134   uchar_t input_byte;       //  input port of onboard uC
135
136   // Data for 8042
137   uchar_t input_queue;      //  
138   uint_t  input_queue_len;  //  
139   // Data for system
140   uchar_t output_queue;     //  
141   uint_t  output_queue_len; //  
142 };
143
144
145 // 
146 // push item onto outputqueue, optionally overwriting if there is no room
147 // returns 0 if successful
148 //
149 static int PushToOutputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite, uchar_t cmd) 
150 {
151   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
152   
153   if ((state->output_queue_len == 0) || overwrite) { 
154
155     state->output_queue = value;
156     state->output_queue_len = 1;
157     state->status_byte |= STATUS_OUTPUT_BUFFER_FULL;
158     
159     if (cmd) {
160       state->status_byte |= STATUS_COMMAND_DATA_AVAIL;
161     } else {
162       state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
163     }
164
165     return 0;
166   } else {
167     KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
168     return -1;
169   }
170 }
171
172 #if 1
173 // 
174 // pull item from outputqueue 
175 // returns 0 if successful
176 //
177 static int PullFromOutputQueue(struct vm_device *dev, uchar_t *value) 
178 {
179   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
180
181   if (state->output_queue_len == 1) { 
182
183     *value = state->output_queue;
184     state->output_queue_len = 0;
185     state->status_byte &= ~STATUS_OUTPUT_BUFFER_FULL;
186
187     if (state->status_byte & STATUS_COMMAND_DATA_AVAIL) { 
188       state->status_byte &= ~STATUS_COMMAND_DATA_AVAIL;
189     } // reset to data
190
191     return 0;
192   } else {
193     KEYBOARD_DEBUG_PRINT("keyboard: PullFromOutputQueue Failed - Queue Empty\n");
194     return -1;
195   }
196 }
197 #endif
198
199 #if 0
200 // 
201 // push item onto inputqueue, optionally overwriting if there is no room
202 // returns 0 if successful
203 //
204 static int PushToInputQueue(struct vm_device *dev, uchar_t value, uchar_t overwrite) 
205 {
206   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
207
208   if ((state->input_queue_len == 0) || overwrite) { 
209
210     state->input_queue = value;
211     state->input_queue_len = 1;
212     state->status_byte |= STATUS_INPUT_BUFFER_FULL;
213
214     return 0;
215   } else {
216     KEYBOARD_DEBUG_PRINT("keyboard: PushToOutputQueue Failed - Queue Full\n");
217     return -1;
218   }
219 }
220
221 // 
222 // pull item from inputqueue 
223 // returns 0 if successful
224 //
225 static int PullFromInputQueue(struct vm_device *dev, uchar_t *value) 
226 {
227   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
228
229   if (state->input_queue_len == 1) { 
230
231     *value = state->input_queue;
232     state->input_queue_len = 0;
233     state->status_byte &= ~STATUS_INPUT_BUFFER_FULL;
234
235     return 0;
236   } else {
237     KEYBOARD_DEBUG_PRINT("keyboard: PullFromInputQueue Failed - Queue Empty\n");
238
239     return -1;
240   }
241 }
242
243 #endif
244
245 static struct vm_device *demultiplex_injected_key(uchar_t status, uchar_t scancode)
246 {
247   // this currently does nothing
248   return thekeyboard;
249 }
250
251 int keyboard_interrupt(uint_t irq, struct vm_device * dev);
252
253 void deliver_key_to_vmm(uchar_t status, uchar_t scancode)
254 {
255   struct vm_device *dev = demultiplex_injected_key(status, scancode);
256   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
257
258   KEYBOARD_DEBUG_PRINT("keyboard: injected status 0x%x, and scancode 0x%x\n", status, scancode);
259   
260   if ( (state->status_byte & STATUS_ENABLED)      // onboard is enabled
261        && (!(state->cmd_byte & CMD_DISABLE)) )  {   // keyboard is enabled
262
263     PushToOutputQueue(dev, scancode, OVERWRITE, DATA);
264
265     if (state->cmd_byte & CMD_INTR) { 
266       keyboard_interrupt(KEYBOARD_IRQ, dev);
267     }
268         
269   }
270 }
271
272 int keyboard_reset_device(struct vm_device * dev)
273 {
274   struct keyboard_internal *data = (struct keyboard_internal *)(dev->private_data);
275   
276   memset(data, 0, sizeof(struct keyboard_internal));
277
278   data->cmd_byte =   
279       CMD_INTR        // interrupts on
280     | CMD_MOUSE_INTR  // mouse interupts on
281     | CMD_SYSTEM ;    // self test passed
282                       // PS2, keyboard+mouse enabled, generic translation    
283   
284   data->status_byte = 
285       STATUS_SYSTEM     // self-tests passed
286     | STATUS_ENABLED ;  // keyboard ready
287                         // buffers empty, no errors
288
289   data->output_byte = 0;  //  ?
290
291   data->input_byte = 
292     INPUT_RAM ;            // we have some
293                            // also display=color, jumper 0, keyboard enabled 
294
295   KEYBOARD_DEBUG_PRINT("keyboard: reset device\n");
296  
297   return 0;
298
299 }
300
301
302
303 int keyboard_start_device(struct vm_device *dev)
304 {
305   KEYBOARD_DEBUG_PRINT("keyboard: start device\n");
306   return 0;
307 }
308
309
310 int keyboard_stop_device(struct vm_device *dev)
311 {
312   KEYBOARD_DEBUG_PRINT("keyboard: stop device\n");
313   return 0;
314 }
315
316
317 #if KEYBOARD_DEBUG_80H
318 int keyboard_write_delay(ushort_t port,
319                          void * src, 
320                          uint_t length,
321                          struct vm_device * dev)
322 {
323
324   if (length == 1) { 
325     KEYBOARD_DEBUG_PRINT("keyboard: write of 0x%x to 80h\n", *((uchar_t*)src));
326
327     return 1;
328   } else {
329     KEYBOARD_DEBUG_PRINT("keyboard: write of >1 byte to 80h\n", *((uchar_t*)src));
330
331     return length;
332   }
333 }
334
335 int keyboard_read_delay(ushort_t port,
336                         void * dest, 
337                         uint_t length,
338                         struct vm_device * dev)
339 {
340
341   if (length == 1) { 
342     *((uchar_t*)dest) = In_Byte(port);
343
344     KEYBOARD_DEBUG_PRINT("keyboard: read of 0x%x from 80h\n", *((uchar_t*)dest));
345
346     return 1;
347   } else {
348     KEYBOARD_DEBUG_PRINT("keyboard: read of >1 byte from 80h\n");
349
350     return length;
351   }
352 }
353 #endif
354     
355   
356
357
358
359 int keyboard_write_command(ushort_t port,
360                            void * src, 
361                            uint_t length,
362                            struct vm_device * dev)
363 {
364   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
365   uchar_t cmd;
366
367   // Should always be single byte write
368
369   if (length != 1) { 
370     KEYBOARD_DEBUG_PRINT("keyboard: write of >1 bytes (%d) to 64h\n", length);
371     return -1;
372   }
373
374   cmd = *((uchar_t*)src); 
375
376   if (state->state != NORMAL) { 
377     KEYBOARD_DEBUG_PRINT("keyboard: warning - receiving command on 64h but state != NORMAL\n");
378   }
379   
380   KEYBOARD_DEBUG_PRINT("keyboard: command 0x%x on 64h\n", cmd);
381
382   switch (cmd) { 
383
384   case 0x20:  // READ COMMAND BYTE (returned in 60h)
385     PushToOutputQueue(dev, state->cmd_byte, OVERWRITE, COMMAND);
386     state->state = NORMAL;  // the next read on 0x60 will get the right data
387     KEYBOARD_DEBUG_PRINT("keyboard: command byte 0x%x returned\n",state->cmd_byte);
388     break;
389
390   case 0x60:  // WRITE COMMAND BYTE (read from 60h)
391     state->state = WRITING_CMD_BYTE; // we need to make sure we send the next 0x60 byte appropriately
392     KEYBOARD_DEBUG_PRINT("keyboard: prepare to write command byte\n");
393     break;
394
395   // case 0x90-9f - write to output port  (?)
396
397   case 0xa1: // Get version number
398     PushToOutputQueue(dev, 0, OVERWRITE, COMMAND);
399     state->state = NORMAL;
400     KEYBOARD_DEBUG_PRINT("keyboard: version number 0x0 returned\n");
401     break;
402
403   case 0xa4:  // is password installed?  send result to 0x60
404     // we don't support passwords
405     PushToOutputQueue(dev, 0xf1, OVERWRITE, COMMAND);
406     KEYBOARD_DEBUG_PRINT("keyboard: password not installed\n");
407     state->state = NORMAL;
408     break;
409
410   case 0xa5:  // new password will arrive on 0x60
411     state->state = TRANSMIT_PASSWD;
412     KEYBOARD_DEBUG_PRINT("keyboard: pepare to transmit password\n");
413     break;
414
415   case 0xa6:  // check passwd;
416     // since we do not support passwords, we will simply ignore this
417     // the implication is that any password check immediately succeeds 
418     // with a blank password
419     state->state = NORMAL;
420     KEYBOARD_DEBUG_PRINT("keyboard: password check succeeded\n");
421     break;
422
423   case 0xa7:  // disable mouse
424     state->cmd_byte |= CMD_MOUSE_DISABLE;
425     state->state = NORMAL;
426     KEYBOARD_DEBUG_PRINT("keyboard: mouse disabled\n");
427     break;
428
429   case 0xa8:  // enable mouse
430     state->cmd_byte &= ~CMD_MOUSE_DISABLE;
431     state->state = NORMAL;
432     KEYBOARD_DEBUG_PRINT("keyboard: mouse enabled\n");
433     break;
434
435   case 0xa9:  // mouse interface test  (always succeeds)
436     PushToOutputQueue(dev, 0, OVERWRITE,COMMAND);
437     KEYBOARD_DEBUG_PRINT("keyboard: mouse interface test succeeded\n");
438     state->state = NORMAL;
439     break;
440
441   case 0xaa:  // controller self test (always succeeds)
442     PushToOutputQueue(dev, 0x55, OVERWRITE, COMMAND);
443     KEYBOARD_DEBUG_PRINT("keyboard: controller self test succeeded\n");
444     state->state = NORMAL;
445     break;
446
447   case 0xab:  // keyboard interface test (always succeeds)
448     PushToOutputQueue(dev, 0, OVERWRITE, COMMAND);
449     state->state = NORMAL;
450     KEYBOARD_DEBUG_PRINT("keyboard: keyboard interface test succeeded\n");
451     break;
452
453   case 0xad:  // disable keyboard
454     state->cmd_byte |= CMD_DISABLE;
455     state->state = NORMAL;
456     KEYBOARD_DEBUG_PRINT("keyboard: keyboard disabled\n");
457     break;
458
459   case 0xae:  // enable keyboard
460     state->cmd_byte &= ~CMD_DISABLE;
461     state->state = NORMAL;
462     KEYBOARD_DEBUG_PRINT("keyboard: keyboard enabled\n");
463     break;
464
465   case 0xaf:  // get version
466     PushToOutputQueue(dev, 0x00, OVERWRITE, COMMAND);
467     state->state = NORMAL;
468     KEYBOARD_DEBUG_PRINT("keyboard: version 0 returned \n");
469     break;
470
471   case 0xd0: // return microcontroller output on 60h
472     PushToOutputQueue(dev,state->output_byte,OVERWRITE,COMMAND);
473     state->state = NORMAL;
474     KEYBOARD_DEBUG_PRINT("keyboard: output byte 0x%x returned\n",state->output_byte);
475     break;
476
477   case 0xd1: // request to write next byte on 60h to the microcontroller output port
478     state->state = WRITING_OUTPUT_PORT;
479     KEYBOARD_DEBUG_PRINT("keyboard: prepare to write output byte\n");
480     break;
481
482   case 0xd2:  //  write keyboard buffer (inject key)
483     state->state = INJECTING_KEY;
484     KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject key\n");
485     break;
486
487   case 0xd3: //  write mouse buffer (inject mouse)
488     state->state = INJECTING_MOUSE;
489     KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject mouse\n");
490     break;
491
492   case 0xd4: // write mouse device (command to mouse?)
493     state->state = WRITING_MOUSE_CMD;
494     KEYBOARD_DEBUG_PRINT("keyboard: prepare to inject mouse command\n");
495     break;
496
497   case 0xc0: //  read input port 
498     PushToOutputQueue(dev,state->input_byte,OVERWRITE,COMMAND);
499     state->state=NORMAL;
500     KEYBOARD_DEBUG_PRINT("keyboard: input byte 0x%x returned\n",state->input_byte);
501     break;
502
503   case 0xc1:  //copy input port lsn to status msn
504     state->status_byte &= 0x0f;
505     state->status_byte |= (state->input_byte & 0xf)<<4;
506     state->state=NORMAL;
507     KEYBOARD_DEBUG_PRINT("keyboard: copied input byte lsn to status msn\n");
508     break;
509
510   case 0xc2: // copy input port msn to status msn
511     state->status_byte &= 0x0f;
512     state->status_byte |= (state->input_byte & 0xf0);
513     state->state=NORMAL;
514     KEYBOARD_DEBUG_PRINT("keyboard: copied input byte msn to status msn\n");
515     break;
516     
517   case 0xe0: // read test port
518     PushToOutputQueue(dev,state->output_byte>>6,OVERWRITE,COMMAND);
519     state->state=NORMAL;
520     KEYBOARD_DEBUG_PRINT("keyboard: read 0x%x from test port\n",state->output_byte>>6);
521     break;
522    
523   case 0xf0:   // pulse output port
524   case 0xf1:   // this should pulse 0..3 of cmd_byte on output port 
525   case 0xf2:   // instead of what is currently in output_byte (I think)
526   case 0xf3:   // main effect is taht if bit zero is zero
527   case 0xf4:   // should cause reset
528   case 0xf5:   // I doubt anything more recent than a 286 running 
529   case 0xf6:   // OS2 with the penalty box will care
530   case 0xf7:
531   case 0xf8:
532   case 0xf9:
533   case 0xfa:
534   case 0xfb:
535   case 0xfc:
536   case 0xfd:
537   case 0xfe:
538   case 0xff:
539     KEYBOARD_DEBUG_PRINT("keyboard: ignoring pulse of 0x%x (low=pulsed) on output port\n",cmd&0xf);
540     state->state=NORMAL;
541     break;
542    
543
544   // case ac  diagonstic - returns 16 bytes from keyboard microcontroler on 60h
545   default:
546     KEYBOARD_DEBUG_PRINT("keyboard: ignoring command (unimplemented)\n");
547     state->state = NORMAL;
548     break;
549   }
550
551   return 1;
552
553 }
554
555 int keyboard_read_status(ushort_t port,
556                          void * dest, 
557                          uint_t length,
558                          struct vm_device * dev)
559 {
560   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
561
562   if (length == 1) { 
563
564     KEYBOARD_DEBUG_PRINT("keyboard: read status (64h): ");
565
566     *((uchar_t*)dest) = state->status_byte;
567
568     KEYBOARD_DEBUG_PRINT("0x%x\n", *((uchar_t*)dest));
569
570     return 1;
571   } else {
572     KEYBOARD_DEBUG_PRINT("keyboard: >1 byte read for status (64h)\n");
573     return -1;
574   }
575 }
576
577 int keyboard_write_output(ushort_t port,
578                           void * src, 
579                           uint_t length,
580                           struct vm_device * dev)
581 {
582   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
583
584   if (length != 1) { 
585     KEYBOARD_DEBUG_PRINT("keyboard: write of 60h with >1 byte\n");
586     return -1;
587   }
588
589   uchar_t data = *((uchar_t*)src);
590   
591   KEYBOARD_DEBUG_PRINT("keyboard: output 0x%x on 60h\n", data);
592
593   switch (state->state) {
594   case WRITING_CMD_BYTE:
595     state->cmd_byte = data;
596     state->state = NORMAL;
597     KEYBOARD_DEBUG_PRINT("keyboard: wrote new command byte 0x%x\n",state->cmd_byte);
598     break;
599   case WRITING_OUTPUT_PORT:
600     state->output_byte = data;
601     state->state = NORMAL;
602     KEYBOARD_DEBUG_PRINT("keyboard: wrote new output byte 0x%x\n",state->output_byte);
603     break;
604   case INJECTING_KEY:
605     PushToOutputQueue(dev,data,OVERWRITE,DATA);  // probably should be a call to deliver_key_to_vmm()
606     state->state = NORMAL;
607     KEYBOARD_DEBUG_PRINT("keyboard: injected key 0x%x\n",data);
608     break;
609   case INJECTING_MOUSE:
610     KEYBOARD_DEBUG_PRINT("keyboard: ignoring injected mouse event 0x%x\n",data);
611     state->state = NORMAL;
612     break;
613   case WRITING_MOUSE_CMD:
614     KEYBOARD_DEBUG_PRINT("keyboard: ignoring injected mouse command 0x%x\n",data);
615     state->state = NORMAL;
616     break;
617   case TRANSMIT_PASSWD:
618     if (data) {
619       //ignore passwd
620       KEYBOARD_DEBUG_PRINT("keyboard: ignoring password character 0x%x\n",data);
621     } else {
622       // end of password
623       state->state = NORMAL;
624       KEYBOARD_DEBUG_PRINT("keyboard: done with password\n");
625     }
626     break;
627   case NORMAL:
628     {
629       // command is being sent to keyboard controller
630       switch (data) { 
631       case 0xff: // reset
632         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND); // ack
633         state->state = RESET;
634         KEYBOARD_DEBUG_PRINT("keyboard: reset complete and acked\n",data);
635         break;
636       case 0xf5: // disable scanning
637       case 0xf4: // enable scanning
638         // ack
639         PushToOutputQueue(dev, 0xfa, OVERWRITE, COMMAND);
640         // should do something here... PAD
641         state->state = NORMAL;
642         KEYBOARD_DEBUG_PRINT("keyboard: %s scanning done and acked\n",data==0xf5 ? "disable" : "enable", data);
643         break;
644       case 0xfe: // resend
645       case 0xfd: // set key type make
646       case 0xfc: // set key typ make/break
647       case 0xfb: // set key type typematic
648       case 0xfa: // set all typematic make/break/typematic
649       case 0xf9: // set all make
650       case 0xf8: // set all make/break
651       case 0xf7: // set all typemaktic
652       case 0xf6: // set defaults
653       case 0xf3: // set typematic delay/rate
654         KEYBOARD_DEBUG_PRINT("keyboard: unhandled known command 0x%x on output buffer (60h)\n", data);
655         break;
656       default:
657         KEYBOARD_DEBUG_PRINT("keyboard: unhandled unknown command 0x%x on output buffer (60h)\n", data);
658         break;
659       }
660       break;
661     }
662   default:
663     KEYBOARD_DEBUG_PRINT("keyboard: unknown state %x on command 0x%x on output buffer (60h)\n", state->state, data);
664   }
665   
666   return 1;
667 }
668
669 int keyboard_read_input(ushort_t port,
670                         void * dest, 
671                         uint_t length,
672                         struct vm_device * dev)
673 {
674   struct keyboard_internal *state = (struct keyboard_internal *)(dev->private_data);
675
676   if (length == 1) { 
677     uchar_t data;
678
679     KEYBOARD_DEBUG_PRINT("keyboard: read from input (60h): ");
680
681     PullFromOutputQueue(dev, &data);
682
683     if (state->state == RESET) { 
684       // We just delivered the ack for the reset
685       // now we will ready ourselves to deliver the BAT code (success)
686       PushToOutputQueue(dev, 0xaa, OVERWRITE,COMMAND);
687       state->state = NORMAL;
688       KEYBOARD_DEBUG_PRINT(" (in reset, pushing BAT test code 0xaa) ");
689     }
690       
691     KEYBOARD_DEBUG_PRINT("0x%x\n", data);
692
693     *((uchar_t*)dest) = data;
694
695     return 1;
696   } else {
697     KEYBOARD_DEBUG_PRINT("keyboard: unknown size read from input (60h)\n");
698     return -1;
699   }
700 }
701
702
703 int keyboard_interrupt(uint_t irq, struct vm_device * dev) 
704 {
705   KEYBOARD_DEBUG_PRINT("keyboard: interrupt\n");
706
707   dev->vm->vm_ops.raise_irq(dev->vm, irq);
708
709   return 0;
710
711 }
712
713
714 int keyboard_init_device(struct vm_device * dev) 
715 {
716  
717   //  struct keyboard_internal *data = (struct keyboard_internal *) dev->private_data;
718
719   KEYBOARD_DEBUG_PRINT("keyboard: init_device\n");
720
721   // Would read state here
722
723   keyboard_reset_device(dev);
724
725   // hook ports
726   dev_hook_io(dev, KEYBOARD_64H, &keyboard_read_status, &keyboard_write_command);
727   dev_hook_io(dev, KEYBOARD_60H, &keyboard_read_input, &keyboard_write_output);
728
729 #if KEYBOARD_DEBUG_80H
730   dev_hook_io(dev, KEYBOARD_DELAY_80H, &keyboard_read_delay, &keyboard_write_delay);
731 #endif
732
733   
734   //
735   // We do not hook the IRQ here.  Instead, the underlying device driver
736   // is responsible to call us back
737   // 
738
739   return 0;
740 }
741
742 int keyboard_deinit_device(struct vm_device *dev)
743 {
744
745   dev_unhook_io(dev, KEYBOARD_60H);
746   dev_unhook_io(dev, KEYBOARD_64H);
747 #if KEYBOARD_DEBUG_80H
748   dev_unhook_io(dev, KEYBOARD_DELAY_80H);
749 #endif
750   keyboard_reset_device(dev);
751   return 0;
752 }
753
754
755
756
757
758 static struct vm_device_ops dev_ops = { 
759   .init = keyboard_init_device, 
760   .deinit = keyboard_deinit_device,
761   .reset = keyboard_reset_device,
762   .start = keyboard_start_device,
763   .stop = keyboard_stop_device,
764 };
765
766
767
768
769 struct vm_device *create_keyboard() {
770   
771   if (thekeyboard != NULL) { 
772     KEYBOARD_DEBUG_PRINT("keyboard: creating >1 keyboard device.  This will probably fail!\n");
773   }
774   
775   struct keyboard_internal * keyboard_state = (struct keyboard_internal *)V3_Malloc(sizeof(struct keyboard_internal));
776
777   struct vm_device *device = create_device("KEYBOARD", &dev_ops, keyboard_state);
778
779   thekeyboard = device;
780   
781   return device;
782 }