/** * ACK를 기다림 * ACK가 아닌 다른 스캔 코드는 변환해서 큐에 삽입 */ BOOL kWaitForACKAndPutOtherScanCode( void ) { int i, j; BYTE bData; BOOL bResult = FALSE; // ACK가 오기 전에 키보드 출력 버퍼(포트 0x60)에 키 데이터가 저장되어 있을 수 있으므로 // 키보드에서 전달된 데이터를 최대 100개까지 수신하여 ACK를 확인 for( j = 0 ; j < 100 ; j++ ) { // 0xFFFF만큼 루프를 수행할 시간이면 충분히 커맨드의 응답이 올 수 있음 // 0xFFFF 루프를 수행한 이후에도 출력 버퍼(포트 0x60)가 차 있지 않으면 무시하고 읽음 for( i = 0 ; i < 0xFFFF ; i++ ) { // 출력 버퍼(포트 0x60)가 차있으면 데이터를 읽을 수 있음 if( kIsOutputBufferFull() == TRUE ) { break; } } // 출력 버퍼(포트 0x60)에서 읽은 데이터가 ACK(0xFA)이면 성공 bData = kInPortByte( 0x60 ); if( bData == 0xFA ) { bResult = TRUE; break; } // ACK(0xFA)가 아니면 키보드 큐에 삽입 else { kConvertScanCodeAndPutQueue( bData ); } } return bResult; }
void kEnableA20Gate( void ) { BYTE bOutputPortData; int i; // 키보드 컨트롤러 정보를 읽거나 쓰려면 미리 D0, D1 커맨드 신호를 보내야 한다. kOutPortByte( 0x64, 0xD0 ); // 키보드 컨트롤러의 출력 포트 값을 읽는 함수 for( i = 0 ; i < 0xFFFF ; i++ ) { if( kIsOutputBufferFull()) // 출력값이 있으면 { break; } } bOutputPortData = kInPortByte(0x60); // 출력값을 읽어냄 bOutputPortData |= 0x01; // 1인경우 A20Gate, 0인경우 리붓 for( i = 0 ; i < 0xFFFF ; i++ ) { if ( kIsInputBufferFull() == FALSE ) // 입력 버퍼에 데이터가 비어있으면 { break; } } kOutPortByte(0x64, 0xD1); // 키보드 컨트롤러의 출력 포트 값을 보내는 커맨드 kOutPortByte(0x60, bOutputPortData); // A20 Gate On }
// 키보드 인터럽트 핸들러 void kKeyboardHandler(int iVectorNumber) { char vcBuffer[] = "[INT: , ]"; static int g_iKeyboardInterruptCount = 0; BYTE bTemp; //============================================================ // Interrupt 발생 메시지 출력 // Interrupt Vector 출력 vcBuffer[5] = '0' + iVectorNumber / 10; vcBuffer[6] = '0' + iVectorNumber % 10; // Interrupt 발생 횟수 출력 vcBuffer[8] = '0' + g_iKeyboardInterruptCount; g_iKeyboardInterruptCount = (g_iKeyboardInterruptCount + 1) % 10; kPrintString(0, 0, vcBuffer); //============================================================ // 키보드 컨트롤러에서 데이터를 읽어서 ASCII로 변환하여 큐에 삽입 if(kIsOutputBufferFull() == TRUE) { bTemp = kGetKeyboardScanCode(); kConvertScanCodeAndPutQueue(bTemp); } // Send EOI. kSendEOIToPIC(iVectorNumber - PIC_IRQSTARTVECTOR); }
BOOL kWaitForACKAndPutOtherScanCode( void ) { int i, j; BYTE bData; BOOL bResult = FALSE; // 100번 꺼내본다. (이전에 들어온 키보드 신호때문에) for( j = 0 ; j < 100 ; j++ ) { // 올때까지 0xFFFF번 실행 for( i = 0 ; i < 0xFFFF ; i++ ) { if( kIsOutputBufferFull() ) // outputbuffer에 ACK 신호가 있으면 데이터 읽어내야 함 { break; } } bData = kInPortByte(0x60); if( bData == 0xFA ) { bResult = TRUE; break; } else { kConvertScanCodeAndPutQueue( bData ); } } return bResult; }
/** * 키보드 인터럽트의 핸들러 */ void kKeyboardHandler( int iVectorNumber ) { char vcBuffer[] = "[INT: , ]"; static int g_iKeyboardInterruptCount = 0; BYTE bTemp; //========================================================================= // 인터럽트가 발생했음을 알리려고 메시지를 출력하는 부분 // 인터럽트 벡터를 화면 왼쪽 위에 2자리 정수로 출력 vcBuffer[ 5 ] = '0' + iVectorNumber / 10; vcBuffer[ 6 ] = '0' + iVectorNumber % 10; // 발생한 횟수 출력 vcBuffer[ 8 ] = '0' + g_iKeyboardInterruptCount; g_iKeyboardInterruptCount = ( g_iKeyboardInterruptCount + 1 ) % 10; kPrintStringXY( 0, 0, vcBuffer ); //========================================================================= // 키보드 컨트롤러에서 데이터를 읽어서 ASCII로 변환하여 큐에 삽입 if( kIsOutputBufferFull() == TRUE ) { bTemp = kGetKeyboardScanCode(); kConvertScanCodeAndPutQueue( bTemp ); } // EOI 전송 kSendEOIToPIC( iVectorNumber - PIC_IRQSTARTVECTOR ); }
/** * 출력 버퍼(포트 0x60)에서 키를 읽음 */ BYTE kGetKeyboardScanCode( void ) { // 출력 버퍼(포트 0x60)에 데이터가 있을 때까지 대기 while( kIsOutputBufferFull() == FALSE ) { ; } return kInPortByte( 0x60 ); }
BYTE kGetKeyboardScanCode( void ) { while( !kIsOutputBufferFull() ) { // 출력 버퍼에 아무것도 없으면 무한루프 } return kInPortByte(0x60); }
/// Read a key from the output buffer (port 0x60). BYTE kKeyboard::kGetKeyboardScanCode(void) { // Wait until the output buffer (port 0x60) is full. while (kIsOutputBufferFull() == false) { ; } return a_pclPort->kInPortByte(0x60); }
/** * 마우스 인터럽트의 핸들러 */ void kMouseHandler( int iVectorNumber ) { char vcBuffer[] = "[INT: , ]"; static int g_iMouseInterruptCount = 0; BYTE bTemp; int iIRQ; //========================================================================= // 인터럽트가 발생했음을 알리려고 메시지를 출력하는 부분 // 인터럽트 벡터를 화면 왼쪽 위에 2자리 정수로 출력 vcBuffer[ 5 ] = '0' + iVectorNumber / 10; vcBuffer[ 6 ] = '0' + iVectorNumber % 10; // 발생한 횟수 출력 vcBuffer[ 8 ] = '0' + g_iMouseInterruptCount; g_iMouseInterruptCount = ( g_iMouseInterruptCount + 1 ) % 10; kPrintStringXY( 0, 0, vcBuffer ); //========================================================================= // 출력 버퍼(포트 0x60)에 수신된 데이터가 있는지 여부를 확인하여 읽은 데이터를 // 키 큐 또는 마우스 큐에 삽입 if( kIsOutputBufferFull() == TRUE ) { // 마우스 데이터가 아니면 키 큐에 삽입 if( kIsMouseDataInOutputBuffer() == FALSE ) { // 출력 버퍼(포트 0x60)에서 키 스캔 코드를 읽는 용도의 함수지만 키보드와 마우스 // 데이터는 출력 버퍼를 공통으로 사용하므로 마우스 데이터를 읽는데도 사용 가능 bTemp = kGetKeyboardScanCode(); // 키 큐에 삽입 kConvertScanCodeAndPutQueue( bTemp ); } // 마우스 데이터이면 마우스 큐에 삽입 else { // 출력 버퍼(포트 0x60)에서 키 스캔 코드를 읽는 용도의 함수지만 키보드와 마우스 // 데이터는 출력 버퍼를 공통으로 사용하므로 마우스 데이터를 읽는데도 사용 가능 bTemp = kGetKeyboardScanCode(); // 마우스 큐에 삽입 kAccumulateMouseDataAndPutQueue( bTemp ); } } // 인터럽트 벡터에서 IRQ 번호 추출 iIRQ = iVectorNumber - PIC_IRQSTARTVECTOR; // EOI 전송 kSendEOI( iIRQ ); // 인터럽트 발생 횟수를 업데이트 kIncreaseInterruptCount( iIRQ ); // 부하 분산(Load Balancing) 처리 kProcessLoadBalancing( iIRQ ); }
/// Activate A20 gate. void kKeyboard::kEnableA20Gate(void) { BYTE bOutputPortData; // Send a command which read the output port value // of the keyboard controller to the control register (port 0x64). a_pclPort->kOutPortByte(0x64, 0xD0); // Wait data of the output port and read. for (int i = 0; i < 0xFFFF; i++) { // If the output buffer (port 0x60) is full, // kOdin can read data. if (kIsOutputBufferFull() == true) { break; } } // Read the output port value of the keyboard controller // from the output port (0x60). bOutputPortData = a_pclPort->kInPortByte(0x60); // Set A20 gate activating bit bOutputPortData |= 0x01; // Send a command which write a data to the output port // and the output port data, if the input buffer (port 0x60) is empty. for (int i = 0; i < 0xFFFF; i++) { // If the input buffer (port 0x60) is empty, // it is available to send. if (kIsInputBufferFull() == false) { break; } } // Send the output port setting command (0xD1) // to the command register (0x64). a_pclPort->kOutPortByte(0x64, 0xD1); // Send setting value for A20 gate to the input buffer (port 0x60). a_pclPort->kOutPortByte(0x60, bOutputPortData); return; }
/** * A20 게이트를 활성화 */ void kEnableA20Gate( void ) { BYTE bOutputPortData; int i; // 컨트롤 레지스터(포트 0x64)에 키보드 컨트롤러의 출력 포트 값을 읽는 커맨드(0xD0) 전송 kOutPortByte( 0x64, 0xD0 ); // 출력 포트의 데이터를 기다렸다가 읽음 for( i = 0 ; i < 0xFFFF ; i++ ) { // 출력 버퍼(포트 0x60)가 차있으면 데이터를 읽을 수 있음 if( kIsOutputBufferFull() == TRUE ) { break; } } // 출력 포트(포트 0x60)에 수신된 키보드 컨트롤러의 출력 포트 값을 읽음 bOutputPortData = kInPortByte( 0x60 ); // A20 게이트 비트 설정 bOutputPortData |= 0x01; // 입력 버퍼(포트 0x60)에 데이터가 비어있으면 출력 포트에 값을 쓰는 커맨드와 출력 포트 데이터 전송 for( i = 0 ; i < 0xFFFF ; i++ ) { // 입력 버퍼(포트 0x60)가 비었으면 커맨드 전송 가능 if( kIsInputBufferFull() == FALSE ) { break; } } // 커맨드 레지스터(0x64)에 출력 포트 설정 커맨드(0xD1)을 전달 kOutPortByte( 0x64, 0xD1 ); // 입력 버퍼(0x60)에 A20 게이트 비트가 1로 설정된 값을 전달 kOutPortByte( 0x60, bOutputPortData ); }
/** * Wait for the ACK signal * If a received signal is not the ACK signal, * translate Scan Code and push it **/ bool kKeyboard::kWaitForACKAndPushOtherScanCode(void) { bool bResult = false; BYTE bData; // It is possible to receive key data before the ACK signal // "kOdin" receives 100 data, and find the ACK signal among them for (int j = 0; j < 100; j++) { // The time to count from 0 to 0xFFF is enough // If the ACK signal is not shown, skip this step for (int i = 0; i < 0xFFFF; i++) { // If the output buffer(port 0x60) is full, it is readable if (kIsOutputBufferFull() == true) { break; } } // If the data from the output buffer(port 0x60) is // the ACK signal (0xFA), it returns true bData = _kInPortByte(0x60); if(bData == 0xFA) { bResult = true; break; } // If it is not 0xFA, translate it to ASCII code and push it else { kConvertScanCodeAndPushQueue(bData); } } return bResult; }