// send a command to the keyboard. re-sends if requested. // returns 0 if the keyboard response is bad, otherwise // returns the response data. unsigned char send_kbd_cmd(unsigned char data) { unsigned char temp; int i; // flush obf flush_obf(); // send the first time check_ibf(); pucPtr[HT6542_DAT] = data; u_sleep(10); for (i = 0; i < HT6542_MAX_RESENDS; i++) { if(!check_tx()) { check_obf(); temp = pucPtr[HT6542_DAT]; if (temp == 0x30) { check_obf(); temp = pucPtr[HT6542_DAT]; } if( temp == KBD_STAT_RESEND) { pucPtr[HT6542_DAT] = data; } else // if not re-send, then see if it's ack { if(temp == KBD_STAT_ACK) { return temp; } else // not re-send or ack so return with error { xxcprintf(g_e, "No Resend or ACK, data %x\n", temp); return temp; } } } // if !check_tx else { xxcprintf(g_e, "TX Timeout\n"); return 1; } } // while 1 xxcprintf(g_e, "Too many resends\n"); return 1; } // main
/* * This implements the state machine defined in the IPMI manual, see * that for details on how this works. Divide that flowchart into * sections delimited by "Wait for IBF" and this will become clear. */ static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) { unsigned char status; unsigned char state; status = read_status(kcs); if (kcs_debug & KCS_DEBUG_STATES) printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status); /* All states wait for ibf, so just do it here. */ if (!check_ibf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; /* Just about everything looks at the KCS state, so grab that, too. */ state = GET_STATUS_STATE(status); switch (kcs->state) { case KCS_IDLE: /* If there's and interrupt source, turn it off. */ clear_obf(kcs, status); if (GET_STATUS_ATN(status)) return SI_SM_ATTN; else return SI_SM_IDLE; case KCS_START_OP: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, "State machine not idle at start"); break; } clear_obf(kcs, status); write_cmd(kcs, KCS_WRITE_START); kcs->state = KCS_WAIT_WRITE_START; break; case KCS_WAIT_WRITE_START: if (state != KCS_WRITE_STATE) { start_error_recovery( kcs, "Not in write state at write start"); break; } read_data(kcs); if (kcs->write_count == 1) { write_cmd(kcs, KCS_WRITE_END); kcs->state = KCS_WAIT_WRITE_END; } else { write_next_byte(kcs); kcs->state = KCS_WAIT_WRITE; } break; case KCS_WAIT_WRITE: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, "Not in write state for write"); break; } clear_obf(kcs, status); if (kcs->write_count == 1) { write_cmd(kcs, KCS_WRITE_END); kcs->state = KCS_WAIT_WRITE_END; } else { write_next_byte(kcs); } break; case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, "Not in write state" " for write end"); break; } clear_obf(kcs, status); write_next_byte(kcs); kcs->state = KCS_WAIT_READ; break; case KCS_WAIT_READ: if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) { start_error_recovery( kcs, "Not in read or idle in read state"); break; } if (state == KCS_READ_STATE) { if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { /* * We don't implement this exactly like the state * machine in the spec. Some broken hardware * does not write the final dummy byte to the * read register. Thus obf will never go high * here. We just go straight to idle, and we * handle clearing out obf in idle state if it * happens to come in. */ clear_obf(kcs, status); kcs->orig_write_count = 0; kcs->state = KCS_IDLE; return SI_SM_TRANSACTION_COMPLETE; } break; case KCS_ERROR0: clear_obf(kcs, status); status = read_status(kcs); if (GET_STATUS_OBF(status)) /* controller isn't responding */ if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); kcs->state = KCS_ERROR1; break; case KCS_ERROR1: clear_obf(kcs, status); write_data(kcs, 0); kcs->state = KCS_ERROR2; break; case KCS_ERROR2: if (state != KCS_READ_STATE) { start_error_recovery(kcs, "Not in read state for error2"); break; } if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); write_data(kcs, KCS_READ_BYTE); kcs->state = KCS_ERROR3; break; case KCS_ERROR3: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, "Not in idle state for error3"); break; } if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); if (kcs->orig_write_count) { restart_kcs_transaction(kcs); } else { kcs->state = KCS_IDLE; return SI_SM_TRANSACTION_COMPLETE; } break; case KCS_HOSED: break; } if (kcs->state == KCS_HOSED) { init_kcs_data(kcs, kcs->io); return SI_SM_HOSED; } return SI_SM_CALL_WITHOUT_DELAY; }
int test_keyboard() { unsigned char data; volatile unsigned char test, test1; unsigned long testl; // set up CS4 for 8-bits, 4 wait states // start by clearing the CS4 field pulPtr[HwMemConfig2 >> 2] &= 0xffffff00; // now get the boot width and set CS4 accordingly testl = (pulPtr[HwStatus >> 2] >> 27) & 0x3; // boot width is in bits 27 and 28 of HwStatus switch(testl) { case 0: // we booted in 32-bit mode pulPtr[HwMemConfig2 >> 2] |= (0x00000090 | 2); break; case 1: // we booted in 8-bit mode pulPtr[HwMemConfig2 >> 2] |= (0x00000090 | 0); break; case 2: // we booted in 16-bit mode pulPtr[HwMemConfig2 >> 2] |= (0x00000090 | 3); break; } // flush any pending data flush_obf(); // see if we can run the controller self test xxcprintf(g_e, "Starting 6542 Internal Diagnostic Test\n"); pucPtr[HT6542_CMD] = HT6542_CMD_DIAG; // check the status for completion // wait until the ibf flag goes false check_ibf(); // now see if we have output data check_obf(); data = pucPtr[HT6542_DAT]; if(data == KBD_STAT_DIAG_OK) { xxcprintf(g_e, "HT6542B Internal Diagnostic Test Passed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); } else { xxcprintf(g_e, "HT6542B Internal Diagnostic Test Failed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); return -1; } // next we test the keyboard and mouse ports xxcprintf(g_e, "Starting HT6542B Keyboard Port Test\n"); check_ibf(); pucPtr[HT6542_CMD] = HT6542_CMD_KBD_TEST; // check the status for completion // wait until the ibf flag goes false check_ibf(); // now see if we have output data check_obf(); data = pucPtr[HT6542_DAT]; if(data == 0) // anything but zero is a failure { xxcprintf(g_e, "HT6542B Keyboard Port Test Passed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); } else { xxcprintf(g_e, "HT6542B Keyboard Port Test Failed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); } xxcprintf(g_e, "Starting HT6542B Mouse Port Test\n"); check_ibf(); pucPtr[HT6542_CMD] = HT6542_CMD_AUX_TEST; // check the status for completion // wait until the ibf flag goes false check_ibf(); // now see if we have output data check_obf(); data = pucPtr[HT6542_DAT]; if(data == 0) // anything but zero is a failure { xxcprintf(g_e, "HT6542B Mouse Port Test Passed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); } else { xxcprintf(g_e, "HT6542B Mouse Port Test Failed\n"); xxcprintf(g_e, "Data Port = 0x%02x\n",data); } // next enable interrupts xxcprintf(g_e, "Enable Interrupts\n"); check_ibf(); pucPtr[HT6542_CMD] = HT6542_CMD_SET_BYTE; check_ibf(); // send the interrupt enable byte pucPtr[HT6542_CMD] = (HT6542_CMD_BYTE_AUX_INT | HT6542_CMD_BYTE_KBD_INT); check_ibf(); // get it back to check it pucPtr[HT6542_CMD] = HT6542_CMD_GET_BYTE; check_ibf(); // now see if we have output data check_obf(); data = pucPtr[HT6542_DAT]; xxcprintf(g_e, "Enable Interrupts Status = %02x\n", data); // next we see if we have a keyboard attached. if we don't // we will get a tx timeout status. if we do, we will get // an 0xFA followed by 0xAA. xxcprintf(g_e, "Detecting Keyboard Presence\n"); test = send_kbd_cmd(KBD_CMD_RST); if(test != KBD_STAT_ACK) { xxcprintf(g_e, "No ACK from Keyboard, Received 0x%02x\n", test); return 0; } check_obf(); test = pucPtr[HT6542_DAT]; xxcprintf(g_e, "Got %x\n", test); if (test != KBD_STAT_RST_OK) { xxcprintf(g_e, "Keyboard Reset Failed\n"); return 0; } xxcprintf(g_e, "Keyboard Detected\n"); // get the ID of the keyboard xxcprintf(g_e, "Detecting Keyboard ID\n"); test = send_kbd_cmd(KBD_CMD_ID); if(test != KBD_STAT_ACK) { xxcprintf(g_e, "No ACK from Keyboard, Received 0x%02x\n", test); return 0; } check_obf(); test = pucPtr[HT6542_DAT]; if(test == KBD_CMD_ID_1ST) // 1st byte of ID? { xxcprintf(g_e, "Received Valid ID\n"); check_obf(); test1 = pucPtr[HT6542_DAT]; xxcprintf(g_e, "Keyboard ID = 0x%02x%02x\n",test,test1); } else { xxcprintf(g_e, "Bad ID Received, 0x%02x\n", test); } return 1; } // main
static enum si_sm_result kcs_event(struct si_sm_data *kcs, long time) { unsigned char status; unsigned char state; status = read_status(kcs); if (kcs_debug & KCS_DEBUG_STATES) printk(KERN_DEBUG "KCS: State = %d, %x\n", kcs->state, status); if (!check_ibf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; state = GET_STATUS_STATE(status); switch (kcs->state) { case KCS_IDLE: clear_obf(kcs, status); if (GET_STATUS_ATN(status)) return SI_SM_ATTN; else return SI_SM_IDLE; case KCS_START_OP: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, "State machine not idle at start"); break; } clear_obf(kcs, status); write_cmd(kcs, KCS_WRITE_START); kcs->state = KCS_WAIT_WRITE_START; break; case KCS_WAIT_WRITE_START: if (state != KCS_WRITE_STATE) { start_error_recovery( kcs, "Not in write state at write start"); break; } read_data(kcs); if (kcs->write_count == 1) { write_cmd(kcs, KCS_WRITE_END); kcs->state = KCS_WAIT_WRITE_END; } else { write_next_byte(kcs); kcs->state = KCS_WAIT_WRITE; } break; case KCS_WAIT_WRITE: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, "Not in write state for write"); break; } clear_obf(kcs, status); if (kcs->write_count == 1) { write_cmd(kcs, KCS_WRITE_END); kcs->state = KCS_WAIT_WRITE_END; } else { write_next_byte(kcs); } break; case KCS_WAIT_WRITE_END: if (state != KCS_WRITE_STATE) { start_error_recovery(kcs, "Not in write state" " for write end"); break; } clear_obf(kcs, status); write_next_byte(kcs); kcs->state = KCS_WAIT_READ; break; case KCS_WAIT_READ: if ((state != KCS_READ_STATE) && (state != KCS_IDLE_STATE)) { start_error_recovery( kcs, "Not in read or idle in read state"); break; } if (state == KCS_READ_STATE) { if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; read_next_byte(kcs); } else { clear_obf(kcs, status); kcs->orig_write_count = 0; kcs->state = KCS_IDLE; return SI_SM_TRANSACTION_COMPLETE; } break; case KCS_ERROR0: clear_obf(kcs, status); status = read_status(kcs); if (GET_STATUS_OBF(status)) if (time_before(jiffies, kcs->error0_timeout)) return SI_SM_CALL_WITH_TICK_DELAY; write_cmd(kcs, KCS_GET_STATUS_ABORT); kcs->state = KCS_ERROR1; break; case KCS_ERROR1: clear_obf(kcs, status); write_data(kcs, 0); kcs->state = KCS_ERROR2; break; case KCS_ERROR2: if (state != KCS_READ_STATE) { start_error_recovery(kcs, "Not in read state for error2"); break; } if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); write_data(kcs, KCS_READ_BYTE); kcs->state = KCS_ERROR3; break; case KCS_ERROR3: if (state != KCS_IDLE_STATE) { start_error_recovery(kcs, "Not in idle state for error3"); break; } if (!check_obf(kcs, status, time)) return SI_SM_CALL_WITH_DELAY; clear_obf(kcs, status); if (kcs->orig_write_count) { restart_kcs_transaction(kcs); } else { kcs->state = KCS_IDLE; return SI_SM_TRANSACTION_COMPLETE; } break; case KCS_HOSED: break; } if (kcs->state == KCS_HOSED) { init_kcs_data(kcs, kcs->io); return SI_SM_HOSED; } return SI_SM_CALL_WITHOUT_DELAY; }