Subversion Repositories shark

Rev

Rev 1007 | 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
 ------------
1007 mauro 23
 CVS :        $Id: 8042.c,v 1.7 2005-05-10 17:20:10 mauro Exp $
105 pj 24
 
25
 File:        $File$
1007 mauro 26
 Revision:    $Revision: 1.7 $
27
 Last update: $Date: 2005-05-10 17:20:10 $
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
 
927 pj 86
/* if defined: show messages during exit */
105 pj 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);
228 giacomo 436
  if (c) {
437
    kern_frestore(f);
438
    return;
439
  }
105 pj 440
  trace("Sending rate...");
441
  c=C8042_keyboardhandshake(DEFAULT_KEYBRATE);
228 giacomo 442
  if (c) {
443
    kern_frestore(f);
444
    return;
445
  }
105 pj 446
 
447
  /* restore interrupts status */
448
  kern_frestore(f);
449
  trace("Restore end");
450
}
451
 
452
/*
453
 * 8042 initialization
454
 *
455
 * test controller,set default values and search a PS/2 mouse
456
 *
457
 * return:
458
 * 0  -> OK
459
 * <0 -> error (-index into  initialize_msg[])
460
 *
461
 * set ps2mouse_present if a mouse is present!
462
 */
463
 
464
#if defined(__DEBUG_8042__)||defined(__DEBUG_INIT__)
465
static char *initialize_msg[]={
466
  /* 0 */
467
  "ok",
468
  /* 1..8 */
469
  "controller self test failed",
470
  "keyboard interface self test failed",
471
  "keyboard reset error",
472
  "keyboard reset (not POR)",
473
  "keyboard disable (not ACK)",
474
  "keyboard enable (not ACK)",
475
  "keyboard typematic rate code (not ACK)",
476
  "keyboard typematic rate (not ACK)",
477
  /* 9.. */
478
  "controller self test (can't send command)",
479
  "controller interface self test (can't send command)",
480
  "can't enable keyboard",
481
  "controller aux interface self test (can't send command)",
482
  "ps/2 mouse interface self test failed",
483
  /* 14.. */
484
  "can't send command GET_MODE",
485
  "can't read GET_MODE reply",
486
  "error sending CODE for mouse",
487
  "error sending data to mouse",
488
  /* 18 */
489
  "can't disable ps/2 mouse",
490
  "can't enable ps/2 mouse",
491
  /* 20 */
492
  "PS/2 mouse not present"
493
};
494
#endif
495
 
496
static int C8042_initialize(void)
497
{
498
  int c;
499
 
500
  /* Disable controller and clear keyboard output buffer */
501
  C8042_clearkeyboardbuffer();
502
  C8042_sendctrldata(KBD_CCMD_KBD_DISABLE);
503
  C8042_clearkeyboardbuffer();
504
 
505
  /* Controller self test */
506
  c=C8042_sendctrldata(KBD_CCMD_SELF_TEST);
507
  if (c) return -9;
508
  c=C8042_readdata();
509
  if (c!=KBD_REPLY_CSTOK) return -1;
510
 
511
  /* Controller to keyboard interface test */
512
  c=C8042_sendctrldata(KBD_CCMD_KBD_TEST);
513
  if (c) return -10;
514
  c=C8042_readdata();
155 pj 515
#ifndef __KEYB_NO_INIT_CHECK__
105 pj 516
  if (c!=KBD_REPLY_KISTOK) return -2;
153 pj 517
#endif
105 pj 518
 
519
  /* Enable data from/to keyboard */
520
  c=C8042_sendctrldata(KBD_CCMD_KBD_ENABLE);
521
  if (c) return -11;
522
 
523
  /*
524
   * Reset keyboard
525
   */
526
  c=C8042_reset();
527
  if (c) return c;
528
 
529
  /* Set keyboard typematic rate */
530
  c=C8042_keyboardhandshake(KBD_CMD_SET_RATE);
531
  if (c) return -7;
532
  c=C8042_keyboardhandshake(DEFAULT_KEYBRATE);
533
  if (c) return -8;
534
 
535
  /*
536
   * PS/2 mouse
537
   */
538
  ps2mouse_present=0;
539
 
540
  /* Test keyboard controller type */
541
  /*
542
  This cause a crash on some systems
543
  c=C8042_sendctrldata(KBD_CCMD_GET_MODE);
544
  if (c) return -14;
545
  c=C8042_readdata();
546
  if (c==-1) return -15;
547
  */
548
  /* if it isn't in PS/2 mode... exit */
549
  //if ((c&KBD_CREPLY_GETMODEMASK)!=KBD_CREPLY_PS2MODE) return 0;
550
 
551
  /* Mouse interface test */
552
  c=C8042_sendctrldata(KBD_CCMD_TEST_MOUSE);
553
  if (c) return -12;
554
  c=C8042_readdata();
155 pj 555
#ifndef __KEYB_NO_INIT_CHECK__
105 pj 556
  if (c!=KBD_REPLY_MISTOK) return -13;
153 pj 557
#endif
105 pj 558
 
559
  /* Enable mouse interface */
560
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
561
  if (c) return -11;
562
 
563
  /* Detect if a mouse is connected to PS/2 port */
564
  /* Send a dummy value to the mouse and wait a reply */
565
  /* (this code is from Linux) */
566
  c=C8042_sendctrldata(KBD_CCMD_WRITE_AUX_OBUF);
567
  if (c) return -16;
568
  c=C8042_sendkeybdata(0x5a);
569
  if (c) return -17;
570
  {
571
    int loop=0xffff;
572
    int v;
573
 
574
    while (loop--) {
575
      v=ll_in(KBD_STATUS_REG);
576
      if (v&KBD_STAT_OBF) {
577
        c=ll_in(KBD_DATA_REG);
578
        if (v&KBD_STAT_MOUSE_OBF&&c==0x5a) {
579
          ps2mouse_present=1; /* => mouse present */
580
          break;
581
        }
582
      }
583
    }
584
  }  
585
 
586
  /* Disable mouse interface */
587
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
588
  if (c) return -11;
589
 
590
  /* if there is a PS2 mouse... */
591
  if (ps2mouse_present) {
592
    int v;
593
 
594
    ps2mouse_present=0;
595
 
596
    /* Enable PS/2 mouse port (to initialize) */
597
    c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
598
    if (c) return -18;
599
 
600
    /* sample/sec */
601
    v=C8042_auxhandshake(AUX_SET_SAMPLE);
602
    v+=C8042_auxhandshake(DEFAULT_PS2_SAMPLESEC);
603
    /* resolution */
604
    v+=C8042_auxhandshake(AUX_SET_RES);
605
    v+=C8042_auxhandshake(DEFAULT_PS2_RES);
606
    /* scaling */
607
    v+=C8042_auxhandshake(AUX_SET_SCALE21);
608
 
609
    /* Disable PS/2 mouse port */
610
    c=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
611
    if (c) return -19;
612
 
613
    if (!v) ps2mouse_present=1;
614
  }
615
 
616
  return 0;
617
}
618
 
619
#ifdef __SAFEXBIOS__
620
static void C8042_safe_after(void);
621
static void C8042_safe_before(void);
622
#endif
623
 
624
/* 8042 initialization */
625
static int C8042_init(void)
626
{
627
  static int initstatus=-1;
628
  static int first=1;
629
 
630
  if (!first) return initstatus;
631
 
632
  cli();
633
  initstatus=C8042_initialize();
634
  first=0;
635
  sti();
636
 
637
  #if defined(__DEBUG_8042__)||defined(__DEBUG_INIT__)
638
  #if defined(__DEBUG_INIT__)&&!defined(__DEBUG_8042__)
639
  if (initstatus) {
640
    #endif
641
    cprintf("8042 init : %d (%s)\n",-initstatus,initialize_msg[-initstatus]);
642
    cprintf("8042 mouse: %d (%s)\n",ps2mouse_present,
643
            ps2mouse_present?"PS/2 mouse present":"PS/2 mouse not found"
644
            );
645
    #if defined(__DEBUG_INIT)&&!defined(__DEBUG_8042__)
646
  }
647
  #endif
648
  #endif
649
 
650
  if (initstatus) {
651
    cli();
652
    C8042_reset();
653
    sti();
654
  }
655
 
656
  #ifdef __SAFEXBIOS__
657
  if (!initstatus) {
658
     xbios_regfun(C8042_safe_before,-1);
659
     xbios_regfun(C8042_safe_after,1);
660
  }
661
  #endif
662
 
663
  return initstatus;
664
}
665
 
666
/*
667
 *
668
 * Keyboard led manager
669
 *
670
 * a 1 swicth led on, a 0 off
671
 */
672
 
673
/* if are waiting an ack from the keyboard */
674
static int ackStatusLed=0;
675
 
676
/* last keyboard led values */
677
static unsigned ledsValue=0;
678
 
679
void C8042_keyboardleds(BYTE numlock, BYTE capslock, BYTE scrolllock)
680
{
681
 
682
  if (capslock) ledsValue = ledsValue | KBD_LED_CAPSLOCK;
683
  else ledsValue = ledsValue & (KBD_LED_CAPSLOCK ^ KBD_LED_MASK);
684
  if (numlock) ledsValue = ledsValue | KBD_LED_NUMLOCK;
685
  else ledsValue = ledsValue & (KBD_LED_NUMLOCK ^ KBD_LED_MASK);
686
  if (scrolllock) ledsValue = ledsValue | KBD_LED_SCROLLLOCK;
687
  else ledsValue = ledsValue & (KBD_LED_SCROLLLOCK ^ KBD_LED_MASK);
688
 
689
  /* Disable keyboard */
690
  C8042_sendkeybdata(KBD_CMD_DISABLE);
691
  /* send the command to the keyboard to light led */
692
  C8042_sendkeybdata(KBD_CMD_SET_LEDS);
693
  /* wait for the ack */
694
  ackStatusLed++;
695
}
696
 
697
/*
698
 *
699
 * ACK managers
700
 *
701
 */
702
 
703
/* numebr of ACK that we are waiting for */
704
static volatile int ackPending=0;
705
 
706
/*
707
 * this procedure is called when an ACK is received from the
708
 * keyboard
709
 * return:
710
 * 0  : OK (ACK processed)
711
 * -1 : no ACK waiting (return this ACK code to the caller)
712
 */
713
 
714
static int C8042_keyboardACK(void)
715
{
716
  /* if some ACK are waiting... */
717
 
718
  if (ackPending) {
719
    ackPending--;
720
    return 0;
721
  }
722
 
723
  /* if ACK for Led commands... */
724
 
725
  if (ackStatusLed == 1){
726
    /* send it to keyboard */
727
    C8042_sendkeybdata(ledsValue);
728
    /* wait for the ack */
729
    ackStatusLed++;
730
    return 0;
731
  }
732
  else if (ackStatusLed == 2) {
733
    /* ok we enable keyboard, and begin again */
734
    ackStatusLed = 0;
735
    C8042_sendkeybdata(KBD_CMD_ENABLE);
736
    return 0;
737
  }
738
 
739
  /* else .... nothing */
740
  return 1;
741
}
742
 
743
/*
744
 * this when an ACK is received from the PS/2 mouse
745
 * (return code: see C8042_keyboardACK)
746
 */
747
 
748
static volatile int auxackPending=0;
749
 
750
static int C8042_auxACK(void)
751
{
752
  if (auxackPending) {
753
    auxackPending--;
754
    return 0;
755
  }
756
  return -1;
757
}
758
 
759
/*
760
 *
761
 * Fast Handlers
762
 *
763
 */
764
 
765
/*
766
 * Fast keyboard handler
767
 */
768
 
769
/* keyboard buffer
770
 * (without port, semaphores, ...)
771
 */
772
 
773
/* buffer size */
774
#define KBUFFERSIZE 256
775
/* buffer mask ( i=(i+1)&MASK is better than i=(i+1)%SIZE ) */
776
#define KBUFFERMASK 0xff
777
/* circular buffer */
778
static BYTE kbuffer[KBUFFERSIZE];
779
/* buffer pointers */
780
/* data is inserted to khead */
781
/* data is kept from ktail+1 */
782
/* (khead point to ktail+1 when buffer is empty) */
783
static unsigned ktail,khead;
784
 
785
/* keyboard fast handler */
786
static void keyb_handler(int dummy)
787
{
788
    BYTE data;
789
    SYS_FLAGS f;
790
 
791
    /* get data from the controller */
792
    data=ll_in(KBD_DATA_REG);
793
 
794
    /* insert into buffer */
795
    f=kern_fsave();
796
    if (ktail!=khead) {
797
      kbuffer[khead]=data;
798
      khead=(khead+1)&KBUFFERMASK;
799
    }
800
    kern_frestore(f);
801
}
802
 
803
/*
804
 * Fast PS/2 mouse handler
805
 */
806
 
807
/* buffer size */
808
#define ABUFFERSIZE 64
809
/* buffer mask */
810
#define ABUFFERMASK 0x3f
811
/* circula buffer */
812
static BYTE abuffer[ABUFFERSIZE];
813
/* buffer pointers */
814
static unsigned atail,ahead;
815
 
816
/* count bytes into a packet */
817
static int acount;
818
/* ps2server is activated when a packet is received */
819
static PID ps2server=NIL;
820
 
821
/* ps2 fast handler */
822
static void ps2mouse_handler(int dummy)
823
{
824
  BYTE data;
825
  SYS_FLAGS f;
826
 
827
  /* get data */
828
  data=ll_in(KBD_DATA_REG);
829
 
830
  /* check packet start or ACK */
831
  if (acount==0) {
832
     if (data==AUX_ACK) {
833
        auxackPending--;
834
        return;
835
     }
836
     if ((data&0xc0)!=0x00) return;
837
  }
838
  acount++;
839
 
840
  /* insert data into buffer */
841
  f=kern_fsave();
842
  if (atail!=ahead) {
843
    abuffer[ahead]=data;
844
    ahead=(ahead+1)&ABUFFERMASK;
845
  }
846
  else {
847
    ahead=(ahead-(acount-1)+ABUFFERSIZE)&ABUFFERMASK;      
848
    acount=0;
849
  }
850
  kern_frestore(f);
851
 
852
  /* if a packet is received activate the task */
853
  if (acount==3) {
854
    acount=0;
855
    task_activate(ps2server);
856
  }
857
}
858
 
859
/*
860
 *
861
 * Interface with high level drivers
862
 *
863
 */
864
 
865
/* keyboard initialization */
866
int C8042_keyboardinit(PID task)
867
{
868
  int status;
869
 
870
  /* initialize buffer variables */
871
  khead=1;
872
  ktail=0;
873
 
874
  /* hardware initialization */
875
  status=C8042_init();
876
  if (status) return status;
877
 
878
  /* set fast handler and task */
1007 mauro 879
  handler_set(C8042_KEYBOARDIRQ, keyb_handler, TRUE, task, NULL);
105 pj 880
  return 0;
881
}
882
 
883
 
884
/* PS/2 mouse port initialization */
885
int C8042_auxinit(PID task)
886
{
887
  int status;
888
  static int first=TRUE;
889
 
890
  /* initialize buffer variables */
891
  if (first) {
892
    ahead=1;
893
    atail=0;
894
    acount=0;
895
    first=FALSE;
896
  }
897
  ps2server=task;
898
 
899
  /* init hardware */
900
  status=C8042_init();
901
  if (status) return status;
902
  if (!ps2mouse_present) return -20;
903
 
904
  /* set fast handler and task */
1007 mauro 905
  handler_set(C8042_PS2IRQ, ps2mouse_handler, TRUE, NIL, NULL);
105 pj 906
 
907
  /* OK, now ps/2 mouse port is active! */
908
  ps2mouse_active=1;
909
  return 0;
910
}
911
 
912
/* PS/2 release resources */
913
int C8042_auxend(void)
914
{
915
  if (ps2mouse_active) C8042_auxportdisable();
916
  handler_remove(C8042_PS2IRQ);
917
  /* now ps/2 mouse port is disabled */
918
  ps2mouse_active=0;
919
  return 0;
920
}
921
 
922
/* test if there is a PS/2 mouse */
923
int C8042_ps2mousepresent(void)
924
{
925
  int status;
926
 
927
  status=C8042_init();
928
  if (status) return 0;
929
 
930
  return ps2mouse_present;
931
}
932
 
933
#ifdef __DEBUG_8042__
934
 
935
/* debug values for keyboadget() and auxget() */
936
#define YDEB     0
937
#define COLORDEB WHITE
938
 
939
static int keyx=2;
940
static int auxx=2;
941
 
942
#endif
943
 
944
/*
945
 * get data from the keyboard (primary port)
946
 *
947
 * it's follow the port_receive() semantic
948
 */
949
int C8042_keyboardget(BYTE *data,BYTE access)
950
{
951
  SYS_FLAGS f;
952
 
953
 
954
  f=kern_fsave();
955
  //if (khead!=(ktail+1)%KBUFFERMASK)  {        
956
    ktail=(ktail+1)&KBUFFERMASK;
957
    *data=kbuffer[ktail];
958
  //} 
959
  kern_frestore(f);
960
 
961
#ifdef __DEBUG_8042__
962
  /*
963
   * if debug...
964
   * show all data from the keyboard on YDEB line of the screen
965
   */
966
  {
967
    if (keyx+5>=80) {
968
      printf_xy(keyx,YDEB,COLORDEB," ");
969
      keyx=2;
970
    }
971
    if (keyx==2) printf_xy(0,YDEB,COLORDEB,"K ");
972
    if (*data==0) {
973
      /* why this if? seems to be a bug in ucvt() (the initial test)*/
974
      printf_xy(keyx,YDEB,COLORDEB,"00 > ");
975
    } else {
976
      printf_xy(keyx,YDEB,COLORDEB,"%-2x > ",(unsigned)*data);
977
    }
978
    keyx+=3;
979
  }
980
#endif
981
 
982
  /* check for ACK */
983
  if (*data==KBD_REPLY_ACK)
984
    return C8042_keyboardACK();
985
 
986
  return 1;  
987
}
988
 
989
/*
990
 * get data from PS/2 mouse port (auxiliary port)
991
 *
992
 * it's follows the port_receive() semantic
993
 */
994
int C8042_auxget(BYTE *data,BYTE access)
995
{
996
  SYS_FLAGS f;
997
 
998
  f=kern_fsave();
999
  atail=(atail+1)&ABUFFERMASK;
1000
  *data++=abuffer[atail];
1001
  atail=(atail+1)&ABUFFERMASK;
1002
  *data++=abuffer[atail];
1003
  atail=(atail+1)&ABUFFERMASK;
1004
  *data++=abuffer[atail];    
1005
  kern_frestore(f);
1006
 
1007
#ifdef __DEBUG_8042__
1008
  /*
1009
   * if debug...
1010
   * show all data from the keyboard on YDEB line of the screen
1011
   */
1012
  {
1013
    int i;
1014
    for (i=-3;i<0;i++) {       
1015
      if (auxx+5 >= 80) {
1016
        printf_xy(auxx,YDEB+1,COLORDEB," ");
1017
        auxx=2;
1018
      }
1019
      if (auxx==2) printf_xy(0,YDEB+1,COLORDEB,"M ");
1020
      printf_xy(auxx,YDEB+1,COLORDEB,"%02x > ",(unsigned)*(data+i));
1021
      auxx+=3;
1022
    }
1023
  }
1024
#endif
1025
 
1026
  return 3;
1027
}
1028
 
1029
/*
1030
 * Enable/Disable keyboard
1031
 */
1032
 
1033
int C8042_keyboarddisable(void)
1034
{
1035
  /* Disable keyboard */
1036
  ackPending++;
1037
  return C8042_sendkeybdata(KBD_CMD_DISABLE);
1038
}
1039
 
1040
int C8042_keyboardenable(void)
1041
{
1042
  /* Enable keyboard */
1043
  ackPending++;
1044
  return C8042_sendkeybdata(KBD_CMD_ENABLE);
1045
}
1046
 
1047
/*
1048
 * Enable/Disable PS/2 mouse
1049
 */
1050
 
1051
#ifdef __TRACE_PS2ENDIS__
1052
#define trace(x) ll_printf("%s\n",(x))
1053
#else
1054
#define trace(x)
1055
#endif
1056
 
1057
int C8042_auxportdisable(void)
1058
{
1059
  //int retries;
1060
  SYS_FLAGS f;
1061
  int c=0;
1062
 
1063
  trace("auxportdisable() START");
1064
 
1065
  /* DISABLE ps/2 mouse (not port)*/
1066
  auxackPending++;
1067
  C8042_sendauxdata(AUX_DISABLE_DEV);
1068
  //retries=1000000;
1069
  //while (auxackPending&&retries) {
1070
  //  retries--;
1071
  //}
1072
 
1073
  /* disable interrupts */
1074
  trace("disabling interrupts");
1075
  f=kern_fsave();
1076
 
1077
  /* Disable keyboard (for the following phase) */
1078
  trace("disabling keyboard");
1079
  c=C8042_keyboardhandshake(KBD_CMD_DISABLE);
228 giacomo 1080
  if (c) {
1081
    kern_frestore(f);
1082
    return -5;
1083
  }
105 pj 1084
 
1085
  /* Disable PS/2 mouse port */
1086
  trace("disabling PS/2 mouse port");
1087
  c+=C8042_sendctrldata(KBD_CCMD_MOUSE_DISABLE);
1088
 
1089
  /* Initialize controller "command register" */
1090
  trace("senfing WRITE_MODE command");
1091
  C8042_sendctrldata(KBD_CCMD_WRITE_MODE);
1092
  trace("sending normal command mode");
1093
  C8042_sendkeybdata(CMDREG_NORMAL);
1094
 
1095
  /* Enable keyboard */
1096
  trace("enabling keyboard");
1097
  c+=C8042_keyboardhandshake(KBD_CMD_ENABLE);
1098
 
1099
  /* restore interrupt mask */
1100
  trace("enabling interrupts");
1101
  kern_frestore(f);
1102
 
1103
  trace("auxportdisable() END");
1104
  ps2mouse_active=0;
1105
  return c;
1106
}
1107
 
1108
int C8042_auxportenable(void)
1109
{
1110
  SYS_FLAGS f;
1111
  int c;
1112
 
1113
  trace("auxportenabled() START");
1114
 
1115
  if (!ps2mouse_present) return -1;
1116
 
1117
  /* disable interrupts */
1118
  trace("disabling interrupts");
1119
  f=kern_fsave();
1120
 
1121
  /* Disable keyboard (for the following phase) */
1122
  trace("disabling keyboard");
1123
  c=C8042_keyboardhandshake(KBD_CMD_DISABLE);
228 giacomo 1124
  if (c) {
1125
    kern_frestore(f);
1126
    return -5;
1127
  }
105 pj 1128
 
1129
  /* Initialize controller "command register" */
1130
  trace("senfing WRITE_MODE command");
1131
  C8042_sendctrldata(KBD_CCMD_WRITE_MODE);
1132
  trace("sending ps/2 command mode");
1133
  C8042_sendkeybdata(CMDREG_PS2);
1134
 
1135
  /* Enable PS/2 mouse port */
1136
  trace("enabling ps/2 mouse port");
1137
  c=C8042_sendctrldata(KBD_CCMD_MOUSE_ENABLE);
228 giacomo 1138
  if (c) {
1139
    kern_frestore(f);
1140
    return -18;
1141
  }
105 pj 1142
 
1143
  /* Enable keyboard */
1144
  trace("enabling keyboard");
1145
  c=C8042_keyboardhandshake(KBD_CMD_ENABLE);
228 giacomo 1146
  if (c) {
1147
    kern_frestore(f);
1148
    return -37;
1149
  }
105 pj 1150
 
1151
  /* restore interrupt mask */
1152
  trace("enabling interrupts");
1153
  kern_frestore(f);
1154
 
1155
  /* Enable ps/2 mouse */
1156
  /* PS: auxackPending is a share resource and shall be protected */
1157
  /* by a semaphore */
1158
  trace("enabling ps/2 mouse");
1159
  auxackPending++;
1160
  C8042_sendauxdata(AUX_ENABLE_DEV);
1161
 
1162
  trace("auxportenable() end");
1163
  ps2mouse_active=1;
1164
  return 0;
1165
}
1166
 
1167
/*
1168
 * Safe procedure
1169
 */
1170
 
1171
#ifdef __SAFEXBIOS__
1172
 
1173
static int ps2_flag;
1174
 
1175
static void C8042_safe_before(void)
1176
{
1177
   /* don't work */
1178
   /*
1179
   if (ps2mouse_active) {
1180
     C8042_auxportdisable();
1181
     ps2_flag=1;
1182
   } else
1183
     ps2_flag=0
1184
   C8042_keyboarddisable();
1185
   */
1186
}
1187
 
1188
static void C8042_safe_after(void)
1189
{
1190
   /* don't work */
1191
   /*
1192
   BYTE status;
1193
   SYS_FLAGS f;
1194
 
1195
   C8042_keyboardenable();
1196
   if (ps2_flag) C8042_auxportenable();
1197
   ps2_flag=0;
1198
   */
1199
}
1200
 
1201
#endif