The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mtx/kbd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 #include        "u.h"
    2 #include        "../port/lib.h"
    3 #include        "mem.h"
    4 #include        "dat.h"
    5 #include        "fns.h"
    6 #include        "io.h"
    7 #include        "../port/error.h"
    8 
    9 enum {
   10         Data=           0x60,           /* data port */
   11 
   12         Status=         0x64,           /* status port */
   13          Inready=       0x01,           /*  input character ready */
   14          Outbusy=       0x02,           /*  output busy */
   15          Sysflag=       0x04,           /*  system flag */
   16          Cmddata=       0x08,           /*  cmd==0, data==1 */
   17          Inhibit=       0x10,           /*  keyboard/mouse inhibited */
   18          Minready=      0x20,           /*  mouse character ready */
   19          Rtimeout=      0x40,           /*  general timeout */
   20          Parity=        0x80,
   21 
   22         Cmd=            0x64,           /* command port (write only) */
   23 
   24         Spec=           0x80,
   25 
   26         PF=             Spec|0x20,      /* num pad function key */
   27         View=           Spec|0x00,      /* view (shift window up) */
   28         KF=             0xF000, /* function key (begin Unicode private space) */
   29         Shift=          Spec|0x60,
   30         Break=          Spec|0x61,
   31         Ctrl=           Spec|0x62,
   32         Latin=          Spec|0x63,
   33         Caps=           Spec|0x64,
   34         Num=            Spec|0x65,
   35         Middle=         Spec|0x66,
   36         No=             0x00,           /* peter */
   37 
   38         Home=           KF|13,
   39         Up=             KF|14,
   40         Pgup=           KF|15,
   41         Print=          KF|16,
   42         Left=           KF|17,
   43         Right=          KF|18,
   44         End=            '\r',
   45         Down=           View,
   46         Pgdown=         KF|19,
   47         Ins=            KF|20,
   48         Del=            0x7F,
   49         Scroll=         KF|21,
   50 };
   51 
   52 /*
   53  * The codes at 0x79 and 0x81 are produed by the PFU Happy Hacking keyboard.
   54  * A 'standard' keyboard doesn't produce anything above 0x58.
   55  */
   56 Rune kbtab[] = 
   57 {
   58 [0x00]  No,     0x1b,   '1',    '2',    '3',    '4',    '5',    '6',
   59 [0x08]  '7',    '8',    '9',    '',    '-',    '=',    '\b',   '\t',
   60 [0x10]  'q',    'w',    'e',    'r',    't',    'y',    'u',    'i',
   61 [0x18]  'o',    'p',    '[',    ']',    '\n',   Ctrl,   'a',    's',
   62 [0x20]  'd',    'f',    'g',    'h',    'j',    'k',    'l',    ';',
   63 [0x28]  '\'',   '`',    Shift,  '\\',   'z',    'x',    'c',    'v',
   64 [0x30]  'b',    'n',    'm',    ',',    '.',    '/',    Shift,  '*',
   65 [0x38]  Latin,  ' ',    Ctrl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
   66 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Num,    Scroll, '7',
   67 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
   68 [0x50]  '2',    '3',    '',    '.',    No,     No,     No,     KF|11,
   69 [0x58]  KF|12,  No,     No,     No,     No,     No,     No,     No,
   70 [0x60]  No,     No,     No,     No,     No,     No,     No,     No,
   71 [0x68]  No,     No,     No,     No,     No,     No,     No,     No,
   72 [0x70]  No,     No,     No,     No,     No,     No,     No,     No,
   73 [0x78]  No,     View,   No,     Up,     No,     No,     No,     No,
   74 };
   75 
   76 Rune kbtabshift[] =
   77 {
   78 [0x00]  No,     0x1b,   '!',    '@',    '#',    '$',    '%',    '^',
   79 [0x08]  '&',    '*',    '(',    ')',    '_',    '+',    '\b',   '\t',
   80 [0x10]  'Q',    'W',    'E',    'R',    'T',    'Y',    'U',    'I',
   81 [0x18]  'O',    'P',    '{',    '}',    '\n',   Ctrl,   'A',    'S',
   82 [0x20]  'D',    'F',    'G',    'H',    'J',    'K',    'L',    ':',
   83 [0x28]  '"',    '~',    Shift,  '|',    'Z',    'X',    'C',    'V',
   84 [0x30]  'B',    'N',    'M',    '<',    '>',    '?',    Shift,  '*',
   85 [0x38]  Latin,  ' ',    Ctrl,   KF|1,   KF|2,   KF|3,   KF|4,   KF|5,
   86 [0x40]  KF|6,   KF|7,   KF|8,   KF|9,   KF|10,  Num,    Scroll, '7',
   87 [0x48]  '8',    '9',    '-',    '4',    '5',    '6',    '+',    '1',
   88 [0x50]  '2',    '3',    '',    '.',    No,     No,     No,     KF|11,
   89 [0x58]  KF|12,  No,     No,     No,     No,     No,     No,     No,
   90 [0x60]  No,     No,     No,     No,     No,     No,     No,     No,
   91 [0x68]  No,     No,     No,     No,     No,     No,     No,     No,
   92 [0x70]  No,     No,     No,     No,     No,     No,     No,     No,
   93 [0x78]  No,     Up,     No,     Up,     No,     No,     No,     No,
   94 };
   95 
   96 Rune kbtabesc1[] =
   97 {
   98 [0x00]  No,     No,     No,     No,     No,     No,     No,     No,
   99 [0x08]  No,     No,     No,     No,     No,     No,     No,     No,
  100 [0x10]  No,     No,     No,     No,     No,     No,     No,     No,
  101 [0x18]  No,     No,     No,     No,     '\n',   Ctrl,   No,     No,
  102 [0x20]  No,     No,     No,     No,     No,     No,     No,     No,
  103 [0x28]  No,     No,     Shift,  No,     No,     No,     No,     No,
  104 [0x30]  No,     No,     No,     No,     No,     '/',    No,     Print,
  105 [0x38]  Latin,  No,     No,     No,     No,     No,     No,     No,
  106 [0x40]  No,     No,     No,     No,     No,     No,     Break,  Home,
  107 [0x48]  Up,     Pgup,   No,     Left,   No,     Right,  No,     End,
  108 [0x50]  Down,   Pgdown, Ins,    Del,    No,     No,     No,     No,
  109 [0x58]  No,     No,     No,     No,     No,     No,     No,     No,
  110 [0x60]  No,     No,     No,     No,     No,     No,     No,     No,
  111 [0x68]  No,     No,     No,     No,     No,     No,     No,     No,
  112 [0x70]  No,     No,     No,     No,     No,     No,     No,     No,
  113 [0x78]  No,     Up,     No,     No,     No,     No,     No,     No,
  114 };
  115 
  116 enum
  117 {
  118         /* controller command byte */
  119         Cscs1=          (1<<6),         /* scan code set 1 */
  120         Cauxdis=        (1<<5),         /* mouse disable */
  121         Ckbddis=        (1<<4),         /* kbd disable */
  122         Csf=            (1<<2),         /* system flag */
  123         Cauxint=        (1<<1),         /* mouse interrupt enable */
  124         Ckbdint=        (1<<0),         /* kbd interrupt enable */
  125 };
  126 
  127 static Lock i8042lock;
  128 static uchar ccc;
  129 static void (*auxputc)(int, int);
  130 
  131 /*
  132  *  wait for output no longer busy
  133  */
  134 static int
  135 outready(void)
  136 {
  137         int tries;
  138 
  139         for(tries = 0; (inb(Status) & Outbusy); tries++){
  140                 if(tries > 500)
  141                         return -1;
  142                 delay(2);
  143         }
  144         return 0;
  145 }
  146 
  147 /*
  148  *  wait for input
  149  */
  150 static int
  151 inready(void)
  152 {
  153         int tries;
  154 
  155         for(tries = 0; !(inb(Status) & Inready); tries++){
  156                 if(tries > 500)
  157                         return -1;
  158                 delay(2);
  159         }
  160         return 0;
  161 }
  162 
  163 /*
  164  *  ask 8042 to reset the machine
  165  */
  166 void
  167 i8042reset(void)
  168 {
  169         ushort *s = KADDR(0x472);
  170         int i, x;
  171 
  172         *s = 0x1234;            /* BIOS warm-boot flag */
  173 
  174         /*
  175          *  newer reset the machine command
  176          */
  177         outready();
  178         outb(Cmd, 0xFE);
  179         outready();
  180 
  181         /*
  182          *  Pulse it by hand (old somewhat reliable)
  183          */
  184         x = 0xDF;
  185         for(i = 0; i < 5; i++){
  186                 x ^= 1;
  187                 outready();
  188                 outb(Cmd, 0xD1);
  189                 outready();
  190                 outb(Data, x);  /* toggle reset */
  191                 delay(100);
  192         }
  193 }
  194 
  195 int
  196 i8042auxcmd(int cmd)
  197 {
  198         unsigned int c;
  199         int tries;
  200 
  201         c = 0;
  202         tries = 0;
  203 
  204         ilock(&i8042lock);
  205         do{
  206                 if(tries++ > 2)
  207                         break;
  208                 if(outready() < 0)
  209                         break;
  210                 outb(Cmd, 0xD4);
  211                 if(outready() < 0)
  212                         break;
  213                 outb(Data, cmd);
  214                 if(outready() < 0)
  215                         break;
  216                 if(inready() < 0)
  217                         break;
  218                 c = inb(Data);
  219         } while(c == 0xFE || c == 0);
  220         iunlock(&i8042lock);
  221 
  222         if(c != 0xFA){
  223                 print("i8042: %2.2ux returned to the %2.2ux command\n", c, cmd);
  224                 return -1;
  225         }
  226         return 0;
  227 }
  228 
  229 /*
  230  *  keyboard interrupt
  231  */
  232 static void
  233 i8042intr(Ureg*, void*)
  234 {
  235         int s, c, i;
  236         static int esc1, esc2;
  237         static int alt, caps, ctl, num, shift;
  238         static int collecting, nk;
  239         static Rune kc[5];
  240         int keyup;
  241 
  242         /*
  243          *  get status
  244          */
  245         lock(&i8042lock);
  246         s = inb(Status);
  247         if(!(s&Inready)){
  248                 unlock(&i8042lock);
  249                 return;
  250         }
  251 
  252         /*
  253          *  get the character
  254          */
  255         c = inb(Data);
  256         unlock(&i8042lock);
  257 
  258         /*
  259          *  if it's the aux port...
  260          */
  261         if(s & Minready){
  262                 if(auxputc != nil)
  263                         auxputc(c, shift);
  264                 return;
  265         }
  266 
  267         /*
  268          *  e0's is the first of a 2 character sequence
  269          */
  270         if(c == 0xe0){
  271                 esc1 = 1;
  272                 return;
  273         } else if(c == 0xe1){
  274                 esc2 = 2;
  275                 return;
  276         }
  277 
  278         keyup = c&0x80;
  279         c &= 0x7f;
  280         if(c > sizeof kbtab){
  281                 c |= keyup;
  282                 if(c != 0xFF)   /* these come fairly often: CAPSLOCK U Y */
  283                         print("unknown key %ux\n", c);
  284                 return;
  285         }
  286 
  287         if(esc1){
  288                 c = kbtabesc1[c];
  289                 esc1 = 0;
  290         } else if(esc2){
  291                 esc2--;
  292                 return;
  293         } else if(shift)
  294                 c = kbtabshift[c];
  295         else
  296                 c = kbtab[c];
  297 
  298         if(caps && c<='z' && c>='a')
  299                 c += 'A' - 'a';
  300 
  301         /*
  302          *  keyup only important for shifts
  303          */
  304         if(keyup){
  305                 switch(c){
  306                 case Latin:
  307                         alt = 0;
  308                         break;
  309                 case Shift:
  310                         shift = 0;
  311                         break;
  312                 case Ctrl:
  313                         ctl = 0;
  314                         break;
  315                 }
  316                 return;
  317         }
  318 
  319         /*
  320          *  normal character
  321          */
  322         if(!(c & (Spec|KF))){
  323                 if(ctl){
  324                         if(alt && c == Del)
  325                                 exit(0);
  326                         c &= 0x1f;
  327                 }
  328                 if(!collecting){
  329                         kbdputc(kbdq, c);
  330                         return;
  331                 }
  332                 kc[nk++] = c;
  333                 c = latin1(kc, nk);
  334                 if(c < -1)      /* need more keystrokes */
  335                         return;
  336                 if(c != -1)     /* valid sequence */
  337                         kbdputc(kbdq, c);
  338                 else    /* dump characters */
  339                         for(i=0; i<nk; i++)
  340                                 kbdputc(kbdq, kc[i]);
  341                 nk = 0;
  342                 collecting = 0;
  343                 return;
  344         } else {
  345                 switch(c){
  346                 case Caps:
  347                         caps ^= 1;
  348                         return;
  349                 case Num:
  350                         num ^= 1;
  351                         return;
  352                 case Shift:
  353                         shift = 1;
  354                         return;
  355                 case Latin:
  356                         alt = 1;
  357                         collecting = 1;
  358                         nk = 0;
  359                         return;
  360                 case Ctrl:
  361                         ctl = 1;
  362                         return;
  363                 }
  364         }
  365         kbdputc(kbdq, c);
  366 }
  367 
  368 void
  369 i8042auxenable(void (*putc)(int, int))
  370 {
  371         char *err = "i8042: aux init failed\n";
  372 
  373         /* enable kbd/aux xfers and interrupts */
  374         ccc &= ~Cauxdis;
  375         ccc |= Cauxint;
  376 
  377         ilock(&i8042lock);
  378         if(outready() < 0)
  379                 print(err);
  380         outb(Cmd, 0x60);                        /* write control register */
  381         if(outready() < 0)
  382                 print(err);
  383         outb(Data, ccc);
  384         if(outready() < 0)
  385                 print(err);
  386         outb(Cmd, 0xA8);                        /* auxilliary device enable */
  387         if(outready() < 0){
  388                 iunlock(&i8042lock);
  389                 return;
  390         }
  391         auxputc = putc;
  392         intrenable(IrqAUX, i8042intr, 0, BUSUNKNOWN, "kbdaux");
  393         iunlock(&i8042lock);
  394 }
  395 
  396 void
  397 kbdinit(void)
  398 {
  399         int c;
  400 
  401         kbdq = qopen(4*1024, 0, 0, 0);
  402         if(kbdq == nil)
  403                 panic("kbdinit");
  404         qnoblock(kbdq, 1);
  405 
  406         ioalloc(Data, 1, 0, "kbd");
  407         ioalloc(Cmd, 1, 0, "kbd");
  408 
  409         intrenable(IrqKBD, i8042intr, 0, BUSUNKNOWN, "kbd");
  410 
  411         /* wait for a quiescent controller */
  412         while((c = inb(Status)) & (Outbusy | Inready))
  413                 if(c & Inready)
  414                         inb(Data);
  415 
  416         /* get current controller command byte */
  417         outb(Cmd, 0x20);
  418         if(inready() < 0){
  419                 print("kbdinit: can't read ccc\n");
  420                 ccc = 0;
  421         } else
  422                 ccc = inb(Data);
  423 
  424         /* enable kbd xfers and interrupts */
  425         /* disable mouse */
  426         ccc &= ~Ckbddis;
  427         ccc |= Csf | Ckbdint | Cscs1;
  428         if(outready() < 0)
  429                 print("kbd init failed\n");
  430         outb(Cmd, 0x60);
  431         if(outready() < 0)
  432                 print("kbd init failed\n");
  433         outb(Data, ccc);
  434         outready();
  435 }

Cache object: 532e1be632a11bfd85ee19626be18210


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.