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/i386ps2/kd_abios.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 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1991 Carnegie Mellon University
    4  * Copyright (c) 1991 IBM Corporation 
    5  * All Rights Reserved.
    6  * 
    7  * Permission to use, copy, modify and distribute this software and its
    8  * documentation is hereby granted, provided that both the copyright
    9  * notice and this permission notice appear in all copies of the
   10  * software, derivative works or modified versions, and any portions
   11  * thereof, and that both notices appear in supporting documentation,
   12  * and that the name IBM not be used in advertising or publicity 
   13  * pertaining to distribution of the software without specific, written
   14  * prior permission.
   15  * 
   16  * CARNEGIE MELLON AND IBM ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   17  * CONDITION.  CARNEGIE MELLON AND IBM DISCLAIM ANY LIABILITY OF ANY KIND FOR
   18  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   19  * 
   20  * Carnegie Mellon requests users of this software to return to
   21  * 
   22  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   23  *  School of Computer Science
   24  *  Carnegie Mellon University
   25  *  Pittsburgh PA 15213-3890
   26  * 
   27  * any improvements or extensions that they make and grant Carnegie Mellon
   28  * the rights to redistribute these changes.
   29  */
   30 
   31 /*
   32  * HISTORY
   33  * $Log:        kd_abios.c,v $
   34  * Revision 2.2  93/02/04  08:00:50  danner
   35  *      Integrate PS2 code from IBM.
   36  *      [93/01/18            prithvi]
   37  * 
   38  */
   39 
   40 /* ported --------------------------------------------------------------*/
   41 
   42 #define KBD_DATA_PORT                           0x60
   43 #define KBD_STATUS_PORT                         0x64
   44 #define OUTPUT_BUFFER_FULL                      BIT0
   45 #define INPUT_BUFFER_FULL                       BIT1
   46 #define KBD_TX                                  BIT6
   47 #define KBD_RESET_CMD                           0xff
   48 #define KBD_ACK                                 0xfa
   49 #define KBD_BAT_RC                              0xaa
   50 #define CTLR_READ_CMD_BYTE                      0x20
   51 #define CTLR_WRITE_CMD_BYTE                     0x60
   52 
   53 #define K_pad4SC   0x4b
   54 
   55 static void
   56 kbd_wait( int i)
   57 {
   58         while (i) i--;
   59 }
   60 
   61 static u_char
   62 kbd_read_data_port()
   63 {
   64         while ((inb(KBD_STATUS_PORT) & OUTPUT_BUFFER_FULL) == 0); /* wait */
   65         /*
   66          * Hardware ref manual says we need to wait 7 usec before the
   67          * data byte would show up at KBD_DATA_PORT.  Wait a little
   68          * longer just to be sure.
   69          */
   70         kbd_wait(7+3);                  
   71         return(inb(KBD_DATA_PORT));
   72 }
   73 
   74 static void
   75 kbd_write_port(int port, u_char val)
   76 {
   77         while (inb(KBD_STATUS_PORT) & (INPUT_BUFFER_FULL | OUTPUT_BUFFER_FULL));
   78         outb(port, val);
   79 }
   80 
   81 static void
   82 kbd_clr_hw_buffer()
   83 {
   84         /*
   85          * get rid of any characters may have left in the keyboard
   86          * hardware buffer (just want to start out clean)
   87          */
   88         while (inb(KBD_STATUS_PORT) & OUTPUT_BUFFER_FULL)
   89                 kbd_read_data_port();
   90 } /* kbd_clr_hw_buffer */
   91 
   92 /*
   93  * kbd_tx_off
   94  *
   95  * Turn off keyboard controler scan code translation.  For PC compatability,
   96  * type 1 kbd controler will do scan code translation, which means you can
   97  * only use scan code set 1.  To use scan code set 3, we need to turn the
   98  * translation off.
   99  *
  100  * It goes like this:
  101  * outb(0x64, 0x20)                     read controler command byte
  102  * ch = inb(0x60) & ~BIT6               turn off kbd translate
  103  * outb(0x64, 0x60)                     write controler command byte
  104  * outb(0x60, ch)
  105  *
  106  * This routine is called very early in main().  After hardware init
  107  * but before debugger init.
  108  */
  109 void
  110 kbd_tx_off()
  111 {
  112         u_char  ch;
  113 
  114         kbd_clr_hw_buffer();
  115         kbd_write_port(KBD_STATUS_PORT, CTLR_READ_CMD_BYTE);
  116         ch = kbd_read_data_port() & (~KBD_TX);  /* turn off kbd translate */
  117         kbd_write_port(KBD_STATUS_PORT, CTLR_WRITE_CMD_BYTE);
  118         kbd_write_port(KBD_DATA_PORT, ch);      /* write it back */
  119 
  120 } /* kbd_tx_off */
  121 
  122 void
  123 kbd_tx_on()
  124 {
  125         u_char  ch;
  126 
  127         kbd_clr_hw_buffer();
  128         kbd_write_port(KBD_STATUS_PORT, CTLR_READ_CMD_BYTE);
  129         ch = kbd_read_data_port() | KBD_TX;     /* turn on kbd translate */
  130         kbd_write_port(KBD_STATUS_PORT, CTLR_WRITE_CMD_BYTE);
  131         kbd_write_port(KBD_DATA_PORT, ch);      /* write it back */
  132 
  133 } /* kbd_tx_on */
  134 
  135 /*
  136  * kbd_debugger_init
  137  *
  138  * Init the keyboard for the kernel debugger.  At power on, kbd
  139  * default to scan code set 2.  We want to use scan code set 3.
  140  * So some juggling is needed here.  Can't use abios here since
  141  * this is done very early in the boot process.  In the normal
  142  * boot (without debugger), this is done in ktsopen().  It goes
  143  * something like this:
  144  *
  145  *                                      cmds            ack     rc good/bad
  146  *      reset kbd                       0xff            0xfa    0xaa/0xfc
  147  *      select scan code set 3          0xf0,0x03       0xfa,0xfa
  148  *      set all key t/m/b               0xfa            0xfa
  149  *      set individual key m/b          0xfc            0xfa
  150  *      sc3 for left-alt                0x19            0xfa
  151  *      sc3 for right-alt               0x39            0xfa
  152  *      sc3 for left-ctrl               0x11            0xfa
  153  *      sc3 for action (right-ctrl)     0x58            0xfa
  154  *      sc3 for left-shift              0x12            0xfa
  155  *      sc3 for right-shift             0x59            0xfa
  156  *      sc3 for capslock                0x14            0xfa
  157  *      sc3 for numlock                 0x76            0xfa
  158  *      enable kbd                      0xf4            0xfa
  159  */
  160 u_char debugger_kbdcmds[] = {
  161                         0xf0,           /* select alternate scan code */
  162                         0x03,           /* scan code set 3 */
  163                         0xfa,           /* set all key t/m/b */
  164                         0xfc,           /* set individual key m/b */
  165                         0x19,           /* sc3 for left-alt */
  166                         0x39,           /* sc3 for right-alt*/
  167                         0x11,           /* sc3 for left-ctrl */
  168                         0x58,           /* sc3 for action (right-ctrl) */
  169                         0x12,           /* sc3 for left-shift */
  170                         0x59,           /* sc3 for right-shift */
  171                         0x14,           /* sc3 for capslock */
  172                         0x76,           /* sc3 for numlock */
  173                         0xf4};          /* enable kbd */
  174 /*
  175  * kbd_debugger_init
  176  *
  177  * Init the keyboard for the kernel debugger.  At power on, kbd
  178  * default to scan code set 2.  OSF want to use scan code set 1.
  179  * So some juggling is needed here.  Can't use abios here since
  180  * this is done very early in the boot process.  In the normal
  181  * boot (without debugger), this is done in ktsopen().  It goes
  182  * something like this:
  183  *
  184  *                                      cmds            ack     rc good/bad
  185  *      reset kbd                       0xff            0xfa    0xaa/0xfc
  186  *      select scan code set 1          0xf0,0x03       0xfa,0xfa
  187  */
  188 u_char osf_debugger_kbdcmds[] = {
  189                         0xf0,           /* select alternate scan code */
  190                         0x01};          /* scan code set 1 */
  191 
  192 static void
  193 kbd_debugger_init()
  194 {
  195         u_char  ch;
  196         int             i;
  197 
  198         kbd_clr_hw_buffer();
  199 
  200         /*
  201          * reset the keyboard
  202          */
  203         kbd_write_port(KBD_DATA_PORT, KBD_RESET_CMD);
  204         ch = kbd_read_data_port();      /* read ack to reset cmd */
  205         if (ch != KBD_ACK) {
  206                 DEBUGF(kddebug & DEBUG_ERR_COND,
  207                 printf("kbd_debugger_init: ERROR, expect 0x%x got 0x%x\n",
  208                                 KBD_ACK, ch));
  209         }
  210         kbd_wait(500000);               /* reset needs 1/2 second to complete */
  211         ch = kbd_read_data_port();      /* read BAT completion code */
  212         if (ch != KBD_BAT_RC) {
  213                 DEBUGF(kddebug & DEBUG_ERR_COND,
  214                 printf("kbd_debugger_init: ERROR, expect 0x%x got 0x%x\n",
  215                                 KBD_BAT_RC, ch));
  216         }
  217 
  218         kbd_tx_off();                   /* turn off keyboard translation */
  219 
  220         /*
  221          * now send the cmds
  222          */
  223         for (i = 0; i < sizeof(osf_debugger_kbdcmds); i++) {
  224                 kbd_write_port(KBD_DATA_PORT, osf_debugger_kbdcmds[i]);
  225                 ch = kbd_read_data_port();      /* read ack to the cmd */
  226                 if (ch != KBD_ACK) {
  227                         DEBUGF(kddebug & DEBUG_ERR_COND,
  228                         printf("kbd_debugger_init: ERROR, cmd 0x%x got 0x%x\n",
  229                                         osf_debugger_kbdcmds[i], ch));
  230                 }
  231         }
  232 
  233 } /* kbd_debugger_init */
  234 
  235 void
  236 kbd_init_keyboard()
  237 {
  238         if (kbd_debugger_inited)
  239                 return;
  240         kbd_debugger_init();
  241         kbd_debugger_inited = TRUE;
  242         DEBUGF(kddebug & KTSDEBUG_INFO,
  243                 printf("kbd_init_keyboard: keyboard inited.\n"));
  244 }
  245 
  246 int
  247 kbdcall_abios(int abios_function, register struct Kbd_request * rb)
  248 {
  249         int     rc;
  250 
  251         DEBUGF(kddebug & DEBUG_ABIOS,
  252                 printf("kbdcall_abios: entering...\n"));
  253 
  254         rb->r_function = abios_function;
  255         rb->r_return_code = ABIOS_UNDEFINED;
  256         rb->state |= KBD_RB_STARTED;
  257         abios_common_start(rb, kbd_abios_data.lid_flags);
  258         rc = rb->r_return_code;
  259         DEBUGF(kddebug & DEBUG_ABIOS,
  260                 printf("kbdcall_abios: abios_common_start(), rc=0x%x\n", rc));
  261 
  262 #ifdef LATER
  263         /* need to use timeout() instead of busy wait loop ... */
  264         if (rb->r_return_code == ABIOS_STAGE_ON_TIME) {
  265                 kbd_wait(KBD_TIME_TO_WAIT(*rb));        /* in usec */
  266                 abios_common_interrupt(rb, kbd_abios_data.lid_flags);
  267                 rb->state = KBD_RB_IDLE;
  268         }
  269         /*
  270          * work...
  271          * start a watchdog timer, w_start(), here in case the interrupt
  272          * didn't happen.  (rb->r_time_out >> 3) is the number of seconds
  273          * to wait.  If it is zero, this operation didn't have a timeout.
  274          *
  275          * kbd_watchdog_handler() may need to see the stuffs between
  276          * ifdef LATER.
  277          */
  278         while (rb->r_return_code == ABIOS_STAGE_ON_INT) {
  279                 int pri_level = i_disable(INTMAX);
  280                 rb->state |= KBD_RB_SLEEPING;
  281                 i_enable(pri_level);
  282                 ktsstub_e_sleep(&rb->sleep_on_intr, EVENT_SIGRET);
  283         }
  284         /*
  285          * work... may need w_stop() here 
  286          * also, need to setup a watchdog timer handler somewhere in
  287          * ktsopen().  When the timer pop, e.g: the expected intr didn't
  288          * happen, the handler arranges to call abios_common_timeout().
  289          */
  290 
  291         DEBUGF(kddebug & DEBUG_ABIOS,
  292                 printf("kbdcall_abios: resolving final return code:\n"));
  293         DEBUGF(kddebug & DEBUG_ABIOS,
  294                 dump_abios_rb((caddr_t) rb, DUMP_ENTIRE_BLOCK));
  295 #endif /* LATER */
  296 
  297         /* work... need to handle other returned codes here */
  298         switch (rc) {
  299         case ABIOS_DONE:
  300                 break;
  301         default:
  302                 DEBUGF(kddebug & DEBUG_ERR_COND,
  303                         printf("kbdcall_abios: ERROR, unknown rc=0x%x\n", rc));
  304         } /* switch */
  305 
  306         DEBUGF(kddebug & DEBUG_ABIOS, printf("kbdcall_abios: leaving...\n"));
  307         return (rc);
  308 } /* kbdcall_abios*/
  309 
  310 int kdintr();
  311 
  312 kdabios_init()
  313 {
  314         int     rc;
  315         int     i, s, rb_len, num_rb;
  316                 
  317         if (kdabios_initialized)
  318                 return;
  319 
  320         DEBUGF(kddebug & DEBUG_ABIOS,
  321                 printf("kdabios_init: entering...\n"));
  322 
  323 
  324         kbd_abios_data.lid = abios_next_LID(KBD_ID,2);
  325         rb_len = sizeof(struct Kbd_request);
  326         num_rb = sizeof(kreq) / rb_len;
  327         kbd_abios_data.num_rb = num_rb;
  328         DEBUGF(kddebug & DEBUG_ABIOS,
  329                 printf("kdabios_init: num_rb=%d rb_len=%d\n", num_rb, rb_len));
  330 
  331         /*
  332          * initialize kbd request blocks
  333          *
  334          * request block kreq[0] is for continuous read function (0x08),
  335          * (e.g.: get the keystrokes)
  336          *
  337          * request block kreq[1] is for single stage or discrete multi
  338          * stage functions, (e.g.: reset, read leds, set leds, ...)
  339          */
  340         for (i = 0; i < num_rb; i++) {
  341                 kreq[i].r_current_req_blck_len = rb_len;
  342                 kreq[i].r_logical_id = kbd_abios_data.lid;
  343                 kreq[i].r_unit = 0;
  344                 kreq[i].request_header.Request_Block_Flags = 0;
  345                 kreq[i].request_header.ELA_Offset = 0;
  346                 kreq[i].r_return_code = ABIOS_UNDEFINED;
  347                 kreq[i].state = KBD_RB_IDLE;
  348                 kreq[i].sleep_on_intr = FALSE;
  349         }
  350 
  351         /*
  352          * read logical id parameters for keyboard
  353          *
  354          * work...
  355          * If we ever decided that the config manager will do abios
  356          * read logical paramater for all devices, then this is
  357          * not needed.
  358          */
  359         DEBUGF(kddebug & DEBUG_ABIOS,
  360                 printf("kdabios_init: ABIOS_LOGICAL_PARAMETER\n"));
  361         KBD_SET_RESERVED_ABIOS_LOGICAL_PARAMETER(kreq[1]);
  362         kbd_abios_data.lid_flags = 0;
  363         rc = kbdcall_abios(ABIOS_LOGICAL_PARAMETER, &kreq[1]);
  364         if (rc) {
  365                 DEBUGF(kddebug & DEBUG_ERR_COND,
  366                         printf("kdabios_init: ERROR, rc=0x%x\n", rc));
  367                 return;
  368         }
  369 
  370         /*
  371          * update certain fields based on what abios just told us
  372          */
  373         kbd_abios_data.installed = (kreq[1].r_number_units > 0);
  374         if (kbd_abios_data.installed == FALSE) {
  375                 DEBUGF(kddebug & DEBUG_ERR_COND,
  376                         printf("kdabios_init: ERROR, no keyboard!\n"));
  377                 return;
  378         }
  379         kbd_abios_data.lid_flags = kreq[1].r_logical_id_flags;
  380         rb_len = kreq[1].r_request_block_length;
  381         for (i = 0; i < num_rb; i++) {
  382                 kreq[i].r_current_req_blck_len = rb_len;
  383         }
  384 
  385 
  386         /*
  387          * start reading keystrokes
  388          */
  389         DEBUGF(kddebug & DEBUG_ABIOS,
  390                 printf("kdabios_init: ABIOS_READ\n"));
  391         KBD_SET_RESERVED_ABIOS_READ(kreq[0]);
  392         kreq[0].r_function = ABIOS_READ;
  393         kreq[0].r_return_code = ABIOS_UNDEFINED;
  394         kreq[0].state |= KBD_RB_STARTED;
  395         s = SPLKD();
  396 #ifdef OSF
  397         kd_handler.ih_level = kreq[1].r_hardware_intr;
  398         kd_handler.ih_handler = kdintr;
  399         kd_handler.ih_resolver = (int (*)()) NULL;
  400         kd_handler.ih_stats.intr_type = INTR_DEVICE;
  401         kd_handler.ih_stats.intr_cnt = 0;
  402         kd_handler.ih_priority = SPL6;
  403         kd_handler.ih_flags = IH_FLAG_NOSHARE;
  404         if ((kd_handler_id = handler_add( &kd_handler )) != NULL)
  405             handler_enable( kd_handler_id );
  406         else
  407             return;
  408 #else
  409         take_irq(kreq[1].r_hardware_intr, 0, kdintr, SPL6, "kd");
  410 #endif OSF
  411         abios_common_start(&kreq[0], kbd_abios_data.lid_flags);
  412         rc = kreq[0].r_return_code;
  413         splx(s);
  414         DEBUGF(kddebug & DEBUG_ABIOS,
  415                 printf("kdabios_init: abios_common_start(), rc=%x\n", rc));
  416         if (rc != ABIOS_STAGE_ON_INT) {                 /* read key fail */
  417                 kreq[0].state = KBD_RB_IDLE;
  418                 DEBUGF(kddebug & DEBUG_ERR_COND,
  419                         printf("kdabios_init: ERROR, READ, rc=%x\n", rc));
  420                 return;
  421         }
  422 
  423         kdabios_initialized = TRUE;
  424 
  425         DEBUGF(kddebug & KTSDEBUG_INFO,
  426         printf("When in loop, Ctrl-Alt-pad4=debugger, Ctrl-Alt-Del=reboot.\n"));
  427         DEBUGF(kddebug & DEBUG_ABIOS, printf("kdabios_init: leaving...\n"));
  428 }
  429 
  430 int
  431 kdabios_intr()
  432 {
  433         struct Kbd_abios_data *kabios;  /* ptr to kbd abios global data */
  434         int     rc, abios_rc;
  435         int     i;
  436 
  437         DEBUGF(kddebug & DEBUG_INTR,
  438                 printf("\nkdabios_intr: ENTERING ...\n"));
  439 
  440         kabios = &kbd_abios_data;
  441         kabios->sc = 0;
  442         rc = INTR_FAIL;
  443 
  444         for (i = 0; i < kabios->num_rb; i++) {
  445                 abios_rc = kreq[i].r_return_code;
  446                 if ((kreq[i].state == KBD_RB_IDLE) ||
  447                     (abios_rc == ABIOS_UNDEFINED))
  448                                 continue;       /* not me! */
  449 
  450                 if ((abios_rc & ABIOS_STAGE_ON_INT) == 0)
  451                                 continue;       /* not me either! */
  452 
  453                 abios_common_interrupt(&kreq[i], kabios->lid_flags);
  454                 abios_rc = kreq[i].r_return_code;
  455                 DEBUGF(kddebug & DEBUG_INTR,
  456                         printf("kdabios_intr: kreq[%d], abios_common_interrupt(), rc=0x%x\n", i, abios_rc));
  457 
  458                 if (abios_rc & ABIOS_NOT_MY_INT)
  459                                 continue;       /* not me either! */
  460 
  461                 rc = INTR_SUCC;
  462                 switch (abios_rc) {             /* it is me */
  463                 case ABIOS_STAGE_ON_INT:
  464                         /*
  465                          * discrete multi stages, just continue.  Eventualy
  466                          * we will get a done or some sort of errors.
  467                          */
  468                         kreq[i].state |= KBD_RB_STAGING;
  469                         break;
  470 
  471                 case ABIOS_KBD_RC_KEY_AVAIL:
  472                         /*
  473                          * key stroke available, grasp it, process it
  474                          * and continue to wait for the next one
  475                          */
  476                         kreq[i].state |= KBD_RB_STAGING;
  477                         kabios->sc = KBD_SCAN_CODE(kreq[i]);
  478                         DEBUGF(kddebug & KTSDEBUG_TERSE,
  479                                 printf("kdabios_intr: got a scancode, 0x%02x\n",
  480                                         kabios->sc));
  481                         break;
  482 
  483                 default:
  484                         /*
  485                          * All other abios return codes, good or bad, will be
  486                          * handled by caller of abios.  As far as interrupt
  487                          * is concerned, we just have a successful one.
  488                          */
  489                         kreq[i].state = KBD_RB_IDLE;
  490                         break;
  491 
  492                 } /* switch */
  493         } /* for */
  494 
  495         DEBUGF(kddebug & DEBUG_INTR,
  496                 printf("kdabios_intr: rc = 0x%x %d\n", rc, rc));
  497         if (rc != INTR_SUCC) {
  498                 DEBUGF(kddebug & DEBUG_ERR_COND,
  499                 printf("kdabios_intr: spurious intr from kbd, count=%d\n",
  500                                 ++kabios->bad_intr_count));
  501         }
  502 
  503         DEBUGF(kddebug & DEBUG_INTR, printf("kdabios_intr: LEAVING ...\n"));
  504         return (rc);
  505 } /* kdabios_intr */
  506 
  507 int
  508 kbd_clr_ctrl_alt_pad4()
  509 {
  510         int     ctrl_up, alt_up, pad4_up;
  511         u_char  ch;
  512 
  513         ctrl_up = alt_up = pad4_up = FALSE;
  514         while ((ctrl_up==FALSE) || (alt_up==FALSE) || (pad4_up==FALSE)) {
  515                 ch = kbd_read_data_port();
  516                 if (ch == (K_CTLSC | K_UP))
  517                         ctrl_up = TRUE;
  518                 else if (ch == (K_ALTSC | K_UP))
  519                         alt_up = TRUE;
  520                 else if (ch == (K_pad4SC | K_UP))
  521                         pad4_up = TRUE;
  522         }
  523 } /* kbd_clr_ctrl_alt_pad4 */
  524 
  525 /* un-ported -----------------------------------------------------------*/

Cache object: 40fce4b96b6da440cbac5c75ab1a7c69


[ 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.