Subversion Repositories shark

Rev

Rev 105 | Rev 155 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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