Subversion Repositories shark

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 pj 1
/*
2
 * Project: S.Ha.R.K.
3
 *
4
 * Coordinators:
5
 *   Giorgio Buttazzo    <giorgio@sssup.it>
6
 *   Paolo Gai           <pj@gandalf.sssup.it>
7
 *
8
 * Authors     :
9
 *   Paolo Gai           <pj@gandalf.sssup.it>
10
 *   Massimiliano Giorgi <massy@gandalf.sssup.it>
11
 *   Luca Abeni          <luca@gandalf.sssup.it>
12
 *   (see the web pages for full authors list)
13
 *
14
 * ReTiS Lab (Scuola Superiore S.Anna - Pisa - Italy)
15
 *
16
 * http://www.sssup.it
17
 * http://retis.sssup.it
18
 * http://shark.sssup.it
19
 */
20
 
21
/**
22
 ------------
23
 CVS :        $Id: 8042.c,v 1.1.1.1 2002-03-29 14:12:49 pj Exp $
24
 
25
 File:        $File$
26
 Revision:    $Revision: 1.1.1.1 $
27
 Last update: $Date: 2002-03-29 14:12:49 $
28
 ------------
29
 
30
 8042.h
31
 
32
 Interface between high level drivers
33
 and the 8042 keyboard and PS/2 mouse controller
34
 
35
 Revision:    1.0
36
 Last update: 22/Mar/1999
37
 
38
 Revision 1.0
39
 
40
 This file contains :
41
 -- A fast handler that get the scan code from the key interface
42
 -- A fast handler for the ps2 mouse port
43
 -- Some functions (exported) to initialize the interface
44
 -- Some functions (exported) to enable/disable and get data from
45
    the keyboard or ps/2 mouse
46
 
47
 Created by Massimiliano Giorgi, modified by Paolo Gai to support the
48
 kernel 4.0.0
49
 
50
**/
51
 
52
/*
53
 * Copyright (C) 2000 Paolo Gai
54
 *
55
 * This program is free software; you can redistribute it and/or modify
56
 * it under the terms of the GNU General Public License as published by
57
 * the Free Software Foundation; either version 2 of the License, or
58
 * (at your option) any later version.
59
 *
60
 * This program is distributed in the hope that it will be useful,
61
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
62
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
63
 * GNU General Public License for more details.
64
 *
65
 * You should have received a copy of the GNU General Public License
66
 * along with this program; if not, write to the Free Software
67
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
68
 *
69
 */
70
 
71
/* if defined: show on first two lines BYTE received from cotroller */
72
//#define __DEBUG_8042__ 1
73
 
74
//#define __DEBUG_INIT__ 1
75
 
76
/* if defined: show messages during sys_end() */
77
//#define __TRACE_EXIT__ 1
78
 
79
/* if defined: trace ps/2 enable/disable */
80
//#define __TRACE_PS2ENDIS__ 1
81
 
82
//#include <config.h>
83
//#include <string.h>
84
//#include <stdlib.h>
85
//#include <cons.h>
86
 
87
//#include "vm.h"
88
#include <kernel/kern.h>
89
//#include "exc.h"
90
//#include "port.h"
91
 
92
#include "8042.h"
93
 
94
//#ifdef __SAFEXBIOS__
95
//#include "x86/xsys.h"
96
//#endif
97
 
98
#ifdef __DEBUG_8042__
99
static char debug_buffer[256];
100
static void debug_output(char *s,int v)
101
{
102
  if (v>=0) cprintf("%s: %d\n",s,v);
103
  else      cprintf("%s: -%d\n",s,-v);
104
}
105
#endif
106
 
107
/* there is a ps2mouse in the system? */
108
static BYTE ps2mouse_present=0;
109
 
110
/* has been activated? */
111
static BYTE ps2mouse_active=0;
112
 
113
/*
114
 * Wait (to write)
115
 *
116
 * return:
117
 * 0    -> input buffer empty (OK to write)
118
 * else -> input buffer full
119
 */
120
static int C8042_wait_towrite(void)
121
{
122
  unsigned long counter;
123
  BYTE          status;
124
 
125
  counter=0;
126
  while (counter++<0xffffff) {
127
    status=ll_in(KBD_STATUS_REG);
128
    /*if ((!(status&KBD_STAT_OBF))&&(!(status&KBD_STAT_IBF))) return 0;*/
129
    if(!(status&KBD_STAT_IBF)) return 0;
130
  }
131
  return -1;
132
}
133
 
134
/*
135
 * Wait (to read)
136
 *
137
 * return:
138
 * 0    -> output buffer full (OK to read)
139
 * else -> output buffer empty
140
 */
141
static int C8042_wait_toread(void)
142
{
143
  unsigned long counter;
144
  BYTE          status;
145
 
146
  counter=0;
147
  while (counter++<0xffffff) {
148
    status=ll_in(KBD_STATUS_REG);
149
    if (status&KBD_STAT_OBF) return 0;
150
  }
151
  return -1;
152
}
153
 
154
/*
155
 * Send data to the keyboard
156
 *
157
 * return:
158
 * 0    -> OK
159
 * else -> "I can't send!"
160
 */
161
static __inline__ int C8042_sendkeybdata(BYTE data)
162
{
163
    if (!C8042_wait_towrite()) {
164
      ll_out(KBD_DATA_REG,data);
165
      return 0;
166
    }
167
    return -1;
168
}
169
 
170
/*
171
 * Send data to the controller
172
 *
173
 * return:
174
 * 0    -> OK
175
 * else -> "I can't send!"
176
 */
177
static __inline__ int C8042_sendctrldata(BYTE data)
178
{
179
    if (!C8042_wait_towrite()) {
180
      ll_out(KBD_CNTL_REG,data);
181
      return 0;
182
    }
183
    return -1;
184
}
185
 
186
/*
187
 * Send data to PS/2 mouse
188
 *
189
 * return:
190
 * 0    -> OK
191
 * else -> error
192
 */
193
static __inline__ int C8042_sendauxdata(BYTE data)
194
{
195
  if (C8042_sendctrldata(KBD_CCMD_WRITE_MOUSE)) return -1;
196
  if (C8042_sendkeybdata(data)) return -2;
197
  return 0;
198
}
199
 
200
/*
201
 * Read data from the conroller
202
 *
203
 * return:
204
 * else -> BYTE read
205
 * -1   -> "I can't read!"
206
 */
207
static __inline__ int C8042_readdata(void)
208
{
209
    if (!C8042_wait_toread()) return (int)ll_in(KBD_DATA_REG);
210
    return -1;
211
}
212
 
213
/*
214
 * Read aux data from the controller
215
 *
216
 * return:
217
 * else -> BYTE read
218
 * -1   -> "I can't read!"
219
 */
220
static __inline__ int C8042_readauxdata(void)
221
{
222
  BYTE status;
223
 
224
  if (!C8042_wait_toread()) {
225
    status=ll_in(KBD_STATUS_REG);
226
    if (status&KBD_STAT_MOUSE_OBF) return ll_in(KBD_DATA_REG);
227
  }
228
  return -1;
229
}
230
 
231
/*
232
 * Clear output buffer
233
 *
234
 */
235
static void C8042_clearkeyboardbuffer(void)
236
{
237
  unsigned long counter;
238
  BYTE          status;
239
 
240
  counter=0;
241
  while (counter++<0xffff) {
242
    status=ll_in(KBD_STATUS_REG);
243
    if (!(status&KBD_STAT_OBF)) return;
244
    ll_in(KBD_DATA_REG);
245
  }
246
}
247
 
248
/*
249
 * Send data and receive ACK (with the keyboard)
250
 *
251
 * return:
252
 * 0  -> OK
253
 * -1 -> can't send command
254
 * -2 -> can't read reply
255
 * -3 -> reply unknown
256
 * -4 -> max retries
257
 */
258
static int C8042_keyboardhandshake(BYTE cmd)
259
{
260
  int maxretries=50;
261
  int c;
262
 
263
  while (maxretries-->0) {
264
    if (C8042_sendkeybdata(cmd)) return -1;
265
    c=C8042_readdata();
266
    if (c==-1) return -2;
267
    if (c==KBD_REPLY_ACK) return 0;
268
    if (c!=KBD_REPLY_RESEND) return -3;
269
  }
270
  return -4;
271
}
272
 
273
/*
274
 * Send data and receive ACK (with PS/2 mouse)
275
 */
276
static int C8042_auxhandshake(BYTE cmd)
277
{
278
  int c;
279
 
280
  if (C8042_sendauxdata(cmd)) return -1;
281
  c=C8042_readauxdata();
282
  if (c<0) return c;
283
  if (c!=AUX_ACK) return -2;
284
  return 0;
285
}
286
 
287
/*
288
 * Values for controller "command register"
289
 *
290
 * CMDREG_NORMAL:
291
 *   normal operation (PS/2 mouse interrupts disabled)
292
 *
293
 * CMDREG_PS2:
294
 *   keyboard and PS/2 mouse enabled
295
 */
296
 
297
#define CMDREG_NORMAL (KBD_MODE_KBD_INT |\
298
                       KBD_MODE_SYS |\
299
                       KBD_MODE_DISABLE_MOUSE |\
300
                       KBD_MODE_KCC \
301
                       )
302
 
303
#define CMDREG_PS2    (KBD_MODE_KCC |\
304
                       KBD_MODE_SYS |\
305
                       KBD_MODE_MOUSE_INT |\
306
                       KBD_MODE_KBD_INT \
307
                       )
308
 
309
/*
310
 * Some default values
311
 */
312
 
313
/* default typematic keyboard rate (maximum - I hope) */
314
/* (I don't know how to coding this information) */
315
#define DEFAULT_KEYBRATE 0x00
316
 
317
/* 100 samples/sec */
318
#define DEFAULT_PS2_SAMPLESEC 100
319
 
320
/* 8 count per mm */
321
#define DEFAULT_PS2_RES       3
322
 
323
/* 2:1 scaling */
324
#define DEFAULT_PS2_SCALE AUX_SET_SCALE21    
325
 
326
/*
327
 *
328
 * Controller initialization
329
 *
330
 */
331
 
332
/*
333
 * Reset keyboard
334
 *
335
 * Reset the keyboard and set it to a known state
336
 * (Must be called after exiting from S.Ha.R.K.)
337
 *
338
 * return:
339
 * 0    -> OK
340
 * else -> Error
341
 */
342
 
343
#ifdef __TRACE_EXIT__
344
#define trace(x) ll_printf("%s\n",(x))
345
#else
346
#define trace(x)
347
#endif
348
 
349
static int C8042_reset(void)
350
{
351
  int c;
352
  int retries=16;
353
 
354
  trace("8042 reset START");
355
 
356
  /* Reset keyboard */
357
  /* If there is not retries some machines hang */
358
  while (retries-->0) {
359
    trace("Sending keyboard reset command...");
360
    c=C8042_keyboardhandshake(KBD_CMD_RESET);
361
    if (c) return -3;
362
    trace("Waiting reply...");
363
    c=C8042_readdata();
364
    if (c==KBD_REPLY_POR) break;
365
    trace("Reset fail!!!\n");
366
  }
367
  if (c!=KBD_REPLY_POR) return -4;
368
 
369
  /* Disable keyboard (for the following phase) */
370
  trace("Disabling keyboard...");
371
  c=C8042_keyboardhandshake(KBD_CMD_DISABLE);
372
  if (c) return -5;
373
 
374
  /* Initialize controller "command register" */
375
  trace("Command register writing...");
376
  C8042_sendctrldata(KBD_CCMD_WRITE_MODE);
377
  trace("Sending command register value...");
378
  C8042_sendkeybdata(CMDREG_NORMAL);
379
 
380
  /* Enable keyboard */
381
  trace("Enabling keyboard...");
382
  c=C8042_keyboardhandshake(KBD_CMD_ENABLE);
383
  if (c) return -6;
384
 
385
  trace("8042 reset END");
386
  return 0;
387
}
388
 
389
/*
390
 * 8042 restore
391
 *
392
 * This function must be called after system sthudown
393
 * to proper restore keyboard handling by DOS
394
 */
395
 
396
#ifdef __TRACE_EXIT__
397
#define trace(x) ll_printf("%s\n",(x))
398
#else
399
#define trace(x)
400
#endif
401
 
402
void C8042_restore(void)
403
{
404
  int c;
405
  SYS_FLAGS f;
406
 
407
  trace("Restore in progress");
408
 
409
  /* disable interrupts */
410
  f=kern_fsave();
411
 
412
  /* Disable the PS/2 mouse port (if present) */
413
  if (ps2mouse_active) {
414
    trace("Deactivating aux port (ps/2)...");
415
    C8042_auxportdisable();
416
  }
417
 
418
  /* Reset */
419
  trace("Reseting start...");
420
  C8042_reset();
421
  trace("Resetting end");
422
 
423
  /* Set keyboard typematic rate */
424
  trace("Sending keyboard rate command...");
425
  c=C8042_keyboardhandshake(KBD_CMD_SET_RATE);
426
  if (c) return;
427
  trace("Sending rate...");
428
  c=C8042_keyboardhandshake(DEFAULT_KEYBRATE);
429
  if (c) return;
430
 
431
  /* restore interrupts status */
432
  kern_frestore(f);
433
  trace("Restore end");
434
}
435
 
436
/*
437
 * 8042 initialization
438
 *
439
 * test controller,set default values and search a PS/2 mouse
440
 *
441
 * return:
442
 * 0  -> OK
443
 * <0 -> error (-index into  initialize_msg[])
444
 *
445
 * set ps2mouse_present if a mouse is present!
446
 */
447
 
448
#if defined(__DEBUG_8042__)||defined(__DEBUG_INIT__)
449
static char *initialize_msg[]={
450
  /* 0 */
451
  "ok",
452
  /* 1..8 */
453
  "controller self test failed",
454
  "keyboard interface self test failed",
455
  "keyboard reset error",
456
  "keyboard reset (not POR)",
457
  "keyboard disable (not ACK)",
458
  "keyboard enable (not ACK)",
459
  "keyboard typematic rate code (not ACK)",
460
  "keyboard typematic rate (not ACK)",
461
  /* 9.. */
462
  "controller self test (can't send command)",
463
  "controller interface self test (can't send command)",
464
  "can't enable keyboard",
465
  "controller aux interface self test (can't send command)",
466
  "ps/2 mouse interface self test failed",
467
  /* 14.. */
468
  "can't send command GET_MODE",
469
  "can't read GET_MODE reply",
470
  "error sending CODE for mouse",
471
  "error sending data to mouse",
472
  /* 18 */
473
  "can't disable ps/2 mouse",
474
  "can't enable ps/2 mouse",
475
  /* 20 */
476
  "PS/2 mouse not present"
477
};
478
#endif
479
 
480
static int C8042_initialize(void)
481
{
482
  int c;
483
 
484
  /* Disable controller and clear keyboard output buffer */
485
  C8042_clearkeyboardbuffer();
486
  C8042_sendctrldata(KBD_CCMD_KBD_DISABLE);
487
  C8042_clearkeyboardbuffer();
488
 
489
  /* Controller self test */
490
  c=C8042_sendctrldata(KBD_CCMD_SELF_TEST);
491
  if (c) return -9;
492
  c=C8042_readdata();
493
  if (c!=KBD_REPLY_CSTOK) return -1;
494
 
495
  /* Controller to keyboard interface test */
496
  c=C8042_sendctrldata(KBD_CCMD_KBD_TEST);
497
  if (c) return -10;
498
  c=C8042_readdata();
499
  if (c!=KBD_REPLY_KISTOK) return -2;
500
 
501
  /* Enable data from/to keyboard */
502
  c=C8042_sendctrldata(KBD_CCMD_KBD_ENABLE);
503
  if (c) return -11;
504
 
505
  /*
506
   * Reset keyboard
507
   */
508
  c=C8042_reset();
509
  if (c) return c;
510
 
511
  /* Set keyboard typematic rate */
512
  c=C8042_keyboardhandshake(KBD_CMD_SET_RATE);
513
  if (c) return -7;
514
  c=C8042_keyboardhandshake(DEFAULT_KEYBRATE);
515
  if (c) return -8;
516
 
517
  /*
518
   * PS/2 mouse
519
   */
520
  ps2mouse_present=0;
521
 
522
  /* Test keyboard controller type */
523
  /*
524
  This cause a crash on some systems
525
  c=C8042_sendctrldata(KBD_CCMD_GET_MODE);
526
  if (c) return -14;
527
  c=C8042_readdata();
528
  if (c==-1) return -15;
529
  */
530
  /* if it isn't in PS/2 mode... exit */
531
  //if ((c&KBD_CREPLY_GETMODEMASK)!=KBD_CREPLY_PS2MODE) return 0;
532
 
533
  /* Mouse interface test */
534
  c=C8042_sendctrldata(KBD_CCMD_TEST_MOUSE);
535
  if (c) return -12;
536
  c=C8042_readdata();
537
  if (c!=KBD_REPLY_MISTOK) return -13;
538
 
539
  /* Enable mouse interface */
540
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
541
  if (c) return -11;
542
 
543
  /* Detect if a mouse is connected to PS/2 port */
544
  /* Send a dummy value to the mouse and wait a reply */
545
  /* (this code is from Linux) */
546
  c=C8042_sendctrldata(KBD_CCMD_WRITE_AUX_OBUF);
547
  if (c) return -16;
548
  c=C8042_sendkeybdata(0x5a);
549
  if (c) return -17;
550
  {
551
    int loop=0xffff;
552
    int v;
553
 
554
    while (loop--) {
555
      v=ll_in(KBD_STATUS_REG);
556
      if (v&KBD_STAT_OBF) {
557
        c=ll_in(KBD_DATA_REG);
558
        if (v&KBD_STAT_MOUSE_OBF&&c==0x5a) {
559
          ps2mouse_present=1; /* => mouse present */
560
          break;
561
        }
562
      }
563
    }
564
  }  
565
 
566
  /* Disable mouse interface */
567
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
568
  if (c) return -11;
569
 
570
  /* if there is a PS2 mouse... */
571
  if (ps2mouse_present) {
572
    int v;
573
 
574
    ps2mouse_present=0;
575
 
576
    /* Enable PS/2 mouse port (to initialize) */
577
    c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
578
    if (c) return -18;
579
 
580
    /* sample/sec */
581
    v=C8042_auxhandshake(AUX_SET_SAMPLE);
582
    v+=C8042_auxhandshake(DEFAULT_PS2_SAMPLESEC);
583
    /* resolution */
584
    v+=C8042_auxhandshake(AUX_SET_RES);
585
    v+=C8042_auxhandshake(DEFAULT_PS2_RES);
586
    /* scaling */
587
    v+=C8042_auxhandshake(AUX_SET_SCALE21);
588
 
589
    /* Disable PS/2 mouse port */
590
    c=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
591
    if (c) return -19;
592
 
593
    if (!v) ps2mouse_present=1;
594
  }
595
 
596
  return 0;
597
}
598
 
599
#ifdef __SAFEXBIOS__
600
static void C8042_safe_after(void);
601
static void C8042_safe_before(void);
602
#endif
603
 
604
/* 8042 initialization */
605
static int C8042_init(void)
606
{
607
  static int initstatus=-1;
608
  static int first=1;
609
 
610
  if (!first) return initstatus;
611
 
612
  cli();
613
  initstatus=C8042_initialize();
614
  first=0;
615
  sti();
616
 
617
  #if defined(__DEBUG_8042__)||defined(__DEBUG_INIT__)
618
  #if defined(__DEBUG_INIT__)&&!defined(__DEBUG_8042__)
619
  if (initstatus) {
620
    #endif
621
    cprintf("8042 init : %d (%s)\n",-initstatus,initialize_msg[-initstatus]);
622
    cprintf("8042 mouse: %d (%s)\n",ps2mouse_present,
623
            ps2mouse_present?"PS/2 mouse present":"PS/2 mouse not found"
624
            );
625
    #if defined(__DEBUG_INIT)&&!defined(__DEBUG_8042__)
626
  }
627
  #endif
628
  #endif
629
 
630
  if (initstatus) {
631
    cli();
632
    C8042_reset();
633
    sti();
634
  }
635
 
636
  #ifdef __SAFEXBIOS__
637
  if (!initstatus) {
638
     xbios_regfun(C8042_safe_before,-1);
639
     xbios_regfun(C8042_safe_after,1);
640
  }
641
  #endif
642
 
643
  return initstatus;
644
}
645
 
646
/*
647
 *
648
 * Keyboard led manager
649
 *
650
 * a 1 swicth led on, a 0 off
651
 */
652
 
653
/* if are waiting an ack from the keyboard */
654
static int ackStatusLed=0;
655
 
656
/* last keyboard led values */
657
static unsigned ledsValue=0;
658
 
659
void C8042_keyboardleds(BYTE numlock, BYTE capslock, BYTE scrolllock)
660
{
661
 
662
  if (capslock) ledsValue = ledsValue | KBD_LED_CAPSLOCK;
663
  else ledsValue = ledsValue & (KBD_LED_CAPSLOCK ^ KBD_LED_MASK);
664
  if (numlock) ledsValue = ledsValue | KBD_LED_NUMLOCK;
665
  else ledsValue = ledsValue & (KBD_LED_NUMLOCK ^ KBD_LED_MASK);
666
  if (scrolllock) ledsValue = ledsValue | KBD_LED_SCROLLLOCK;
667
  else ledsValue = ledsValue & (KBD_LED_SCROLLLOCK ^ KBD_LED_MASK);
668
 
669
  /* Disable keyboard */
670
  C8042_sendkeybdata(KBD_CMD_DISABLE);
671
  /* send the command to the keyboard to light led */
672
  C8042_sendkeybdata(KBD_CMD_SET_LEDS);
673
  /* wait for the ack */
674
  ackStatusLed++;
675
}
676
 
677
/*
678
 *
679
 * ACK managers
680
 *
681
 */
682
 
683
/* numebr of ACK that we are waiting for */
684
static volatile int ackPending=0;
685
 
686
/*
687
 * this procedure is called when an ACK is received from the
688
 * keyboard
689
 * return:
690
 * 0  : OK (ACK processed)
691
 * -1 : no ACK waiting (return this ACK code to the caller)
692
 */
693
 
694
static int C8042_keyboardACK(void)
695
{
696
  /* if some ACK are waiting... */
697
 
698
  if (ackPending) {
699
    ackPending--;
700
    return 0;
701
  }
702
 
703
  /* if ACK for Led commands... */
704
 
705
  if (ackStatusLed == 1){
706
    /* send it to keyboard */
707
    C8042_sendkeybdata(ledsValue);
708
    /* wait for the ack */
709
    ackStatusLed++;
710
    return 0;
711
  }
712
  else if (ackStatusLed == 2) {
713
    /* ok we enable keyboard, and begin again */
714
    ackStatusLed = 0;
715
    C8042_sendkeybdata(KBD_CMD_ENABLE);
716
    return 0;
717
  }
718
 
719
  /* else .... nothing */
720
  return 1;
721
}
722
 
723
/*
724
 * this when an ACK is received from the PS/2 mouse
725
 * (return code: see C8042_keyboardACK)
726
 */
727
 
728
static volatile int auxackPending=0;
729
 
730
static int C8042_auxACK(void)
731
{
732
  if (auxackPending) {
733
    auxackPending--;
734
    return 0;
735
  }
736
  return -1;
737
}
738
 
739
/*
740
 *
741
 * Fast Handlers
742
 *
743
 */
744
 
745
/*
746
 * Fast keyboard handler
747
 */
748
 
749
/* keyboard buffer
750
 * (without port, semaphores, ...)
751
 */
752
 
753
/* buffer size */
754
#define KBUFFERSIZE 256
755
/* buffer mask ( i=(i+1)&MASK is better than i=(i+1)%SIZE ) */
756
#define KBUFFERMASK 0xff
757
/* circular buffer */
758
static BYTE kbuffer[KBUFFERSIZE];
759
/* buffer pointers */
760
/* data is inserted to khead */
761
/* data is kept from ktail+1 */
762
/* (khead point to ktail+1 when buffer is empty) */
763
static unsigned ktail,khead;
764
 
765
/* keyboard fast handler */
766
static void keyb_handler(int dummy)
767
{
768
    BYTE data;
769
    SYS_FLAGS f;
770
 
771
    /* get data from the controller */
772
    data=ll_in(KBD_DATA_REG);
773
 
774
    /* insert into buffer */
775
    f=kern_fsave();
776
    if (ktail!=khead) {
777
      kbuffer[khead]=data;
778
      khead=(khead+1)&KBUFFERMASK;
779
    }
780
    kern_frestore(f);
781
}
782
 
783
/*
784
 * Fast PS/2 mouse handler
785
 */
786
 
787
/* buffer size */
788
#define ABUFFERSIZE 64
789
/* buffer mask */
790
#define ABUFFERMASK 0x3f
791
/* circula buffer */
792
static BYTE abuffer[ABUFFERSIZE];
793
/* buffer pointers */
794
static unsigned atail,ahead;
795
 
796
/* count bytes into a packet */
797
static int acount;
798
/* ps2server is activated when a packet is received */
799
static PID ps2server=NIL;
800
 
801
/* ps2 fast handler */
802
static void ps2mouse_handler(int dummy)
803
{
804
  BYTE data;
805
  SYS_FLAGS f;
806
 
807
  /* get data */
808
  data=ll_in(KBD_DATA_REG);
809
 
810
  /* check packet start or ACK */
811
  if (acount==0) {
812
     if (data==AUX_ACK) {
813
        auxackPending--;
814
        return;
815
     }
816
     if ((data&0xc0)!=0x00) return;
817
  }
818
  acount++;
819
 
820
  /* insert data into buffer */
821
  f=kern_fsave();
822
  if (atail!=ahead) {
823
    abuffer[ahead]=data;
824
    ahead=(ahead+1)&ABUFFERMASK;
825
  }
826
  else {
827
    ahead=(ahead-(acount-1)+ABUFFERSIZE)&ABUFFERMASK;      
828
    acount=0;
829
  }
830
  kern_frestore(f);
831
 
832
  /* if a packet is received activate the task */
833
  if (acount==3) {
834
    acount=0;
835
    task_activate(ps2server);
836
  }
837
}
838
 
839
/*
840
 *
841
 * Interface with high level drivers
842
 *
843
 */
844
 
845
/* keyboard initialization */
846
int C8042_keyboardinit(PID task)
847
{
848
  int status;
849
 
850
  /* initialize buffer variables */
851
  khead=1;
852
  ktail=0;
853
 
854
  /* hardware initialization */
855
  status=C8042_init();
856
  if (status) return status;
857
 
858
  /* set fast handler and task */
859
  handler_set(C8042_KEYBOARDIRQ,keyb_handler,task);
860
  return 0;
861
}
862
 
863
 
864
/* PS/2 mouse port initialization */
865
int C8042_auxinit(PID task)
866
{
867
  int status;
868
  static int first=TRUE;
869
 
870
  /* initialize buffer variables */
871
  if (first) {
872
    ahead=1;
873
    atail=0;
874
    acount=0;
875
    first=FALSE;
876
  }
877
  ps2server=task;
878
 
879
  /* init hardware */
880
  status=C8042_init();
881
  if (status) return status;
882
  if (!ps2mouse_present) return -20;
883
 
884
  /* set fast handler and task */
885
  handler_set(C8042_PS2IRQ,ps2mouse_handler,NIL);
886
 
887
  /* OK, now ps/2 mouse port is active! */
888
  ps2mouse_active=1;
889
  return 0;
890
}
891
 
892
/* PS/2 release resources */
893
int C8042_auxend(void)
894
{
895
  if (ps2mouse_active) C8042_auxportdisable();
896
  handler_remove(C8042_PS2IRQ);
897
  /* now ps/2 mouse port is disabled */
898
  ps2mouse_active=0;
899
  return 0;
900
}
901
 
902
/* test if there is a PS/2 mouse */
903
int C8042_ps2mousepresent(void)
904
{
905
  int status;
906
 
907
  status=C8042_init();
908
  if (status) return 0;
909
 
910
  return ps2mouse_present;
911
}
912
 
913
#ifdef __DEBUG_8042__
914
 
915
/* debug values for keyboadget() and auxget() */
916
#define YDEB     0
917
#define COLORDEB WHITE
918
 
919
static int keyx=2;
920
static int auxx=2;
921
 
922
#endif
923
 
924
/*
925
 * get data from the keyboard (primary port)
926
 *
927
 * it's follow the port_receive() semantic
928
 */
929
int C8042_keyboardget(BYTE *data,BYTE access)
930
{
931
  SYS_FLAGS f;
932
 
933
 
934
  f=kern_fsave();
935
  //if (khead!=(ktail+1)%KBUFFERMASK)  {        
936
    ktail=(ktail+1)&KBUFFERMASK;
937
    *data=kbuffer[ktail];
938
  //} 
939
  kern_frestore(f);
940
 
941
#ifdef __DEBUG_8042__
942
  /*
943
   * if debug...
944
   * show all data from the keyboard on YDEB line of the screen
945
   */
946
  {
947
    if (keyx+5>=80) {
948
      printf_xy(keyx,YDEB,COLORDEB," ");
949
      keyx=2;
950
    }
951
    if (keyx==2) printf_xy(0,YDEB,COLORDEB,"K ");
952
    if (*data==0) {
953
      /* why this if? seems to be a bug in ucvt() (the initial test)*/
954
      printf_xy(keyx,YDEB,COLORDEB,"00 > ");
955
    } else {
956
      printf_xy(keyx,YDEB,COLORDEB,"%-2x > ",(unsigned)*data);
957
    }
958
    keyx+=3;
959
  }
960
#endif
961
 
962
  /* check for ACK */
963
  if (*data==KBD_REPLY_ACK)
964
    return C8042_keyboardACK();
965
 
966
  return 1;  
967
}
968
 
969
/*
970
 * get data from PS/2 mouse port (auxiliary port)
971
 *
972
 * it's follows the port_receive() semantic
973
 */
974
int C8042_auxget(BYTE *data,BYTE access)
975
{
976
  SYS_FLAGS f;
977
 
978
  f=kern_fsave();
979
  atail=(atail+1)&ABUFFERMASK;
980
  *data++=abuffer[atail];
981
  atail=(atail+1)&ABUFFERMASK;
982
  *data++=abuffer[atail];
983
  atail=(atail+1)&ABUFFERMASK;
984
  *data++=abuffer[atail];    
985
  kern_frestore(f);
986
 
987
#ifdef __DEBUG_8042__
988
  /*
989
   * if debug...
990
   * show all data from the keyboard on YDEB line of the screen
991
   */
992
  {
993
    int i;
994
    for (i=-3;i<0;i++) {       
995
      if (auxx+5 >= 80) {
996
        printf_xy(auxx,YDEB+1,COLORDEB," ");
997
        auxx=2;
998
      }
999
      if (auxx==2) printf_xy(0,YDEB+1,COLORDEB,"M ");
1000
      printf_xy(auxx,YDEB+1,COLORDEB,"%02x > ",(unsigned)*(data+i));
1001
      auxx+=3;
1002
    }
1003
  }
1004
#endif
1005
 
1006
  return 3;
1007
}
1008
 
1009
/*
1010
 * Enable/Disable keyboard
1011
 */
1012
 
1013
int C8042_keyboarddisable(void)
1014
{
1015
  /* Disable keyboard */
1016
  ackPending++;
1017
  return C8042_sendkeybdata(KBD_CMD_DISABLE);
1018
}
1019
 
1020
int C8042_keyboardenable(void)
1021
{
1022
  /* Enable keyboard */
1023
  ackPending++;
1024
  return C8042_sendkeybdata(KBD_CMD_ENABLE);
1025
}
1026
 
1027
/*
1028
 * Enable/Disable PS/2 mouse
1029
 */
1030
 
1031
#ifdef __TRACE_PS2ENDIS__
1032
#define trace(x) ll_printf("%s\n",(x))
1033
#else
1034
#define trace(x)
1035
#endif
1036
 
1037
int C8042_auxportdisable(void)
1038
{
1039
  //int retries;
1040
  SYS_FLAGS f;
1041
  int c=0;
1042
 
1043
  trace("auxportdisable() START");
1044
 
1045
  /* DISABLE ps/2 mouse (not port)*/
1046
  auxackPending++;
1047
  C8042_sendauxdata(AUX_DISABLE_DEV);
1048
  //retries=1000000;
1049
  //while (auxackPending&&retries) {
1050
  //  retries--;
1051
  //}
1052
 
1053
  /* disable interrupts */
1054
  trace("disabling interrupts");
1055
  f=kern_fsave();
1056
 
1057
  /* Disable keyboard (for the following phase) */
1058
  trace("disabling keyboard");
1059
  c=C8042_keyboardhandshake(KBD_CMD_DISABLE);
1060
  if (c) return -5;
1061
 
1062
  /* Disable PS/2 mouse port */
1063
  trace("disabling PS/2 mouse port");
1064
  c+=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
1065
 
1066
  /* Initialize controller "command register" */
1067
  trace("senfing WRITE_MODE command");
1068
  C8042_sendctrldata(KBD_CCMD_WRITE_MODE);
1069
  trace("sending normal command mode");
1070
  C8042_sendkeybdata(CMDREG_NORMAL);
1071
 
1072
  /* Enable keyboard */
1073
  trace("enabling keyboard");
1074
  c+=C8042_keyboardhandshake(KBD_CMD_ENABLE);
1075
 
1076
  /* restore interrupt mask */
1077
  trace("enabling interrupts");
1078
  kern_frestore(f);
1079
 
1080
  trace("auxportdisable() END");
1081
  ps2mouse_active=0;
1082
  return c;
1083
}
1084
 
1085
int C8042_auxportenable(void)
1086
{
1087
  SYS_FLAGS f;
1088
  int c;
1089
 
1090
  trace("auxportenabled() START");
1091
 
1092
  if (!ps2mouse_present) return -1;
1093
 
1094
  /* disable interrupts */
1095
  trace("disabling interrupts");
1096
  f=kern_fsave();
1097
 
1098
  /* Disable keyboard (for the following phase) */
1099
  trace("disabling keyboard");
1100
  c=C8042_keyboardhandshake(KBD_CMD_DISABLE);
1101
  if (c) return -5;
1102
 
1103
  /* Initialize controller "command register" */
1104
  trace("senfing WRITE_MODE command");
1105
  C8042_sendctrldata(KBD_CCMD_WRITE_MODE);
1106
  trace("sending ps/2 command mode");
1107
  C8042_sendkeybdata(CMDREG_PS2);
1108
 
1109
  /* Enable PS/2 mouse port */
1110
  trace("enabling ps/2 mouse port");
1111
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
1112
  if (c) return -18;
1113
 
1114
  /* Enable keyboard */
1115
  trace("enabling keyboard");
1116
  c=C8042_keyboardhandshake(KBD_CMD_ENABLE);
1117
  if (c) return -37;
1118
 
1119
  /* restore interrupt mask */
1120
  trace("enabling interrupts");
1121
  kern_frestore(f);
1122
 
1123
  /* Enable ps/2 mouse */
1124
  /* PS: auxackPending is a share resource and shall be protected */
1125
  /* by a semaphore */
1126
  trace("enabling ps/2 mouse");
1127
  auxackPending++;
1128
  C8042_sendauxdata(AUX_ENABLE_DEV);
1129
 
1130
  trace("auxportenable() end");
1131
  ps2mouse_active=1;
1132
  return 0;
1133
}
1134
 
1135
/*
1136
 * Safe procedure
1137
 */
1138
 
1139
#ifdef __SAFEXBIOS__
1140
 
1141
static int ps2_flag;
1142
 
1143
static void C8042_safe_before(void)
1144
{
1145
   /* don't work */
1146
   /*
1147
   if (ps2mouse_active) {
1148
     C8042_auxportdisable();
1149
     ps2_flag=1;
1150
   } else
1151
     ps2_flag=0
1152
   C8042_keyboarddisable();
1153
   */
1154
}
1155
 
1156
static void C8042_safe_after(void)
1157
{
1158
   /* don't work */
1159
   /*
1160
   BYTE status;
1161
   SYS_FLAGS f;
1162
 
1163
   C8042_keyboardenable();
1164
   if (ps2_flag) C8042_auxportenable();
1165
   ps2_flag=0;
1166
   */
1167
}
1168
 
1169
#endif