일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 나르왈프레오
- 패턴인식
- 갤럭시탭S8울트라
- 고려대학교
- 삼성전자 소프트웨어멤버십 SSM
- hopfield network
- 삼성소프트웨어멤버십
- 가상화
- 신경망
- Bidirectional Associative Memory
- Neural Network
- 구글 앱 엔진
- BAM
- NarwalFreo
- 물걸레자동세척로봇청소기
- SSM
- 패턴 인식
- 물걸레로봇청소기추천
- 멤버십
- 신경회로망
- 하이퍼바이저
- 빅데이터
- 파이썬
- Python
- 인공지능
- 삼성
- Friendship
- 증강현실
- 동아리
- Google App Engine
- Today
- Total
정보공간_1
[3기 강남 정준호] KeyBoard & Monitor Device Driver 본문
[3기 강남 정준호] KeyBoard & Monitor Device Driver
알 수 없는 사용자 2013. 4. 5. 12:25
주제: 키보드와 모니터 디바이스 드라이버
안녕하세요 강남 멤버십 19-2 정 준호 입니다. 밤과 낮의 일교차가 커요.감기 조심하세요!!! 그래도 요센 낮에는 따듯해서 좋네요^^
이전 포스팅에선 Scheduler의 동작 괴정과 Work-Queu에에 대하여 기술하였습니다.
이번 포스팅에서는 사용자와 Communication을 위하여 키보드와 모니터를 추가하는 작업을 기술하도록 하겠습니다.
* SMP 와 MP Boot
* Scheduler
* Work Queue 동작 과정
* 키보드와 모니터 디바이스 드라이버
* Console & Shell
* Testing
* 키보드 디바이스 드라이버
키보드 컨트롤러는 PC내부버스와 PortI/O방식으로 연결되어 있으며, Portaddress는 0x60와 0x64를 사용한다.
실제 할당된 port는 두 개나 데이터를 읽고 쓸대 접근 레지스터가 다르므로 실 제로는 네 개의 레지스터와 연결된 것과 같다.
크기는 모두 1Byte이며 그 중 상태레지스터가 가장 중요 하다. 키보드 컨트롤러의 상태를 표시하기 때문에 킷값을 읽거나 쓰려면 반드시 체크해 야 하는 비트를 포함하기 때문이다.
Port Mapping | |||
Port |
Read/Write |
Register |
Description |
0x60 |
Read |
Output Buffer |
Read Input Buffer |
0x60 |
Write |
Input Buffer |
Write Output Buffer |
0x64 |
Read |
Status Register |
Read Status Register |
0x64 |
Write |
Control Register |
Send Command to Controller |
Keyboard Register는Control Register, Status Register, Input Buffer, Output Buffer 네 개가 있으며 크기는 모두 1Byte이다.
이 중에서 Status Register가 가장 중요한 기능을 담당하는데 Keyboard Controller의 상태를 표시하는 레지스터이기 때문에 키 값을 읽거나 쓰려면 반드시 체크해야 하는 Bit를 포함한다.
Status Register | ||
Bit |
Field |
Description |
0 |
OUTB(Output Buffer Status) |
- 0: Output buffer empty, don’tread yet / 1: Output buffer full, please read me |
1 |
INPB(Input Buffer Status) |
- 0: Input buffer empty, can be written / 1: Input buffer full, don’t write yet |
2 |
SYSF (System Flag) |
- 0: Set after power on reset - 1: Set after successful completion of the keyboard controllers self-test (Basic Assurance Test, BAT) |
3 |
C/D (Command Data) |
- 0: Last write to input buffer was data (via port 0x60) - 1: Last write to input buffer was a command (via port 0x64) |
4 |
KEYL(Keyboard Locked) |
- 0: Locked / 1: Not locked |
5 |
AUXB (Auxiliary Output buffer full) |
- PS/2 Systems: 0: Determines if read from port 0x60 is valid If valid, 0=Keyboard data 1: Mouse data, only if you can read from port 0x60 - AT Systems: 0: OK flag 1: Timeout on transmission from keyboard controller to keyboard. This may indicate no keyboard is present. |
6 |
TIM (Timeout) |
- 0: OK flag / 1: Timeout - PS/2: General Timeout - AT: Timeout on transmission from keyboard to keyboard controller. Possibly parity error (In which case both bits 6 and 7 are set) |
7 |
PARE(Parity error) |
- 0: OK flag, no error / 1: Parity error with last byte |
그 외 참고할만한 Keyboard Controller Command는 다음과 같다.
Keyboard Controller Commands | |
Keyboard Controller Command |
Description |
0x20 |
Read Keyboard Controller Command Byte |
0x60 |
Write Keyboard Controller Command Byte |
0xAA |
Self Test |
0xAB |
Interface Test |
0xAD |
Disable Keyboard Device |
0xAE |
Enable Keyboard Device |
0xC0 |
Read Input Port |
0xD0 |
Read Output Port |
0xD1 |
Write Output Port |
0xDD |
Enable A20 Address Line |
0xDF |
Disable A20 Address Line |
0xE0 |
Read Test Inputs |
0xFE |
System Reset |
Keyboard와 기타 시스템 제어에 관련된 Keyboard Controller Command
일반적으로Bootloader가 실행되기 전에 Keyboard는 이미 BIOS에 의해 활성화된 상태이다. 따라서 Keyboard를 활성화하는 단계를 굳이 수행하지 않아도 Keyboard에서 키 값을 읽는데 아무런 문제가 없지만, 만약을 대비하여 Keyboard를 직접 활성화할 필요성이 있다.
Keyboard Controller에서 Keyboard Device를 사용 가능하게 하려면, 커맨드 Port로Keyboard Device 활성화 커맨드인 0xAE를 보내면 된다.
하지만 이것은 엄밀히 말하면 Keyboard Controller에서 활성화된 것이지 실제 Keyboard가 활성화된 것은 아니다.
Keyboard Controller와 Keyboard는 PS/2 방식의 케이블로 연결되어 있으며 PC의 외부에 존재한다. 그래서 Keyboard에도 활성화 커맨드를 보내줄 필요가 있다. Keyboard에 직접 데이터를 보내는 방법은 커맨드를 전송하지 않고, Input Buffer에 Keyboard로 보낼 커맨드를 직접 쓰면 된다.
Keyboard는 keyboard Controller와 달리 커맨드나 데이터에 대한 응답이 전송되며, 정상적으로 처리한 경우 ACK(0xFA)를 전송한다. 만일 ACK가 수신되지 않으면 수행 도중 에러가 발생한 것이므로, 재시도하거나 작업을 포기해야 한다.
Keyboard Command | |
Keyboard Command |
Description |
0xED |
Write LEDs |
0xEE |
Diagnostic echo |
0xF0 |
Set/Get scancode set |
0xF2 |
Read Keyboard ID |
0xF3 |
Set repeat rate and delay |
0xF4 |
Keyboard enable |
0xF5 |
Set defaults and disable keyboard |
0xF6 |
Set defaults |
0xF7 |
Set all keys to repeat |
0xF8 |
Set all keys to give make/break codes |
0xF9 |
Set all keys to give make codes only |
0xFA |
Set all keys to give repeat and give make/break codes |
0xFB |
Set a single key to repeat |
0xFC |
Set a single key to give make/break codes |
0xFD |
Set a single key to give make codes only |
0xFE |
Resend |
0xFF |
Keyboard reset |
LED와 Keyboard 활성화에 관련된 Keyboard Command
앞서 언급했듯이 Keyboard Controller의 Keyboard 활성화는 커맨드 Port에0xAE를 보내는 것으로 가능하다.
Keyboard Controller에 커맨드를 보냈다면 남은 것은 Keyboard에 직접 커맨드 를 보내는 일이다. Keyboard로 커맨드를 보내려면 Input Buffer의 상태 처리와 Keyboard의 응답 처리를 해야 한다.
Keyboard와Keyboard Controller는 프로세서와 비교하면 아주 느리게 동작하므로 프로세서가 커맨드를 전송하고 한참을 기다려야 수행이 완료된다.
여기서 다루어야 할 문제는 커맨드가 완료될 때까지 얼마나 기다려야 하는 것인가 이다 커맨드를 처리하는 시간은 Keyboard와Keyboard Controller의 상태에 따라 가변적인 부분이기에 Keyboard Controller의 상태를 확인할 수 있는 무언가가 필요하게 된다.
이때 사용하는 것이 Keyboard Controller의Status Register(Port 0x64)이다. 위 표에서 알 수 있듯이, Status Register는 Input Buffer 상태 를 표시하는 Bit(Bit 1)와 Output Buffer의 상태를 표시하는 Bit(Bit 0)가 있다.
입력 버터 상태 Bit(Bit 1)를 통해 Input Buffer가 비어있는지 확인 후 Keyboard 커맨드를 송신하고, Output Buffer 상태 Bit(Bit 0)을 통해 Output Buffer에 데이터가 있는지 확인한 후 실행 결과를 읽어 들여 보다 효율적으로 처리할 수 있다.
일반적인 경우에는 키보드는 이미BIOS에 의해 활성화된 상태이다. 따라서 키보드 활성화를 하는 단계를 굳이 수행하지 않아도 키보드에서 킷값을 읽는데 문제가 없다. 만약을 대비해 키보드를 활성 하다록 했다. 일단 부팅을 하고나면 바로 키보드컨트롤러를 활성화 시켜 준다.
아래의 블록다이어그램 처럼 처음에 0x64(쓰기모드)를 이용하여 0xAE(키보드디바이스활성화)데 이터를 전송한다. 이렇게 전송을 하면 키보드활성화를 시켜주고 0xFA를 통해 키보드를 동작 시 켜 주므로써 초기화를 할 수 있다.
|
어셈블리어를 이용하여 포트I/O 레지스터를 읽고 쓰기를 한다.
어셈블리어 함수를 만들어서 In과 Out을 한다. In명령어는 포트I/O어드레스를 지정하는데 DX레지스터를 사용하며 포트에서 값을 읽어 AX레지스터에 저장 한다.
Out명령어는 반대로 포트I/O어드레스에 데이터를 출력하는 역할을 한다.
기능은 반대지만 포트I/O어드레스에는 DX레지스터를 사용하며 값을 보내는 레지스터로는 AX레지스터를 사용한다.
kInPortByte: pushrdx ;함수에서임시로사용하는레지스터를스택에저장 ;함수의마지막부분에서스택에사입된값을꺼내복원
movrdx,rdi ;RDX레지스터에파라메터1를저장 movrax,0 ;RAX레지스터를초기화 inal,dx ;DX레지스터에저장된포트어드레스에서한바이트를읽어 ;AL레지스터에저장
poprdx ;함수에서사용이끝난레지스터를복원 ret ;함수를호출한다음코드의위치로.
kOutPortByte: pushrdx ;함수에서임시로사용하는레지스터를스택에저장 pushrax ;함수의마지막부분에서스택에삽입된값을꺼내복원
movrdx,rdi ;RDX레지스터에파라미터1(포트번호)를저장 movrax,rsi ;RAX레지스터에파라미터2(데이터)를저장 outdx,al ;DX레지스터에저장된포트어드레스에AL레지스터에저장된 ;한바이트를씀
poprax ;함수에서사용이끝난레지스터를복원 poprdx ret ;함수를호출한다음코드의위치로복귀 |
(2) 키보드 컨트롤러에서 키 값읽기
키보드는 키가 눌리거나 떨어질때 마다 키 별로 할당된 값을 키보드컨트롤러로 전달하며, 이 값 을 스캔코드라고 한다.
키보드 컨트롤러의 출력버퍼에는 키보드 또는 마우스에서 수신된 데이터가 저장된다. 따라서 상태레지스터를 읽어서 출력버퍼에 데이터가 있는지 확인 후, 데이터가 있다면 출력버퍼를 읽어서 저장하면 된다.
if(kInPortByte(0x64)& 0x01) //키데이터가있다면, { returnkInPortByte(0x60); //그값을리턴한다. } return0; //값이없다면0으로
|
다음과 같이 어셈블러를 이용하여 해당 상태레지스터를 보고 그 데이터를 리턴 받아서 출력 하도록 한다.
while(1) { key_value=KeyScancode(); if(key_value!=0){ //키가눌러졌으면키의ASCII코드값을화면에출력 kPrintStirng(0,15,key_value); } } |
다음과 같이 간단히 폴링 상태로키보드에서 입력을 받아 key데이터 즉 아스키 값을 출력을 할수 있다.
이렇게 만들어진 키 데이터는 가장 기본적인 방식으로 while루프안에서 폴링방식으로 체크를 한다.
이런방식은 키가 지속적으로 걸리면 다른 테스크에 무리를 준다.
따라서 중간 발표 때에는 가장 간단하게 테스크 하나를 통해서 지속적으로 Key값을 받아서 출력을 하였다.
하지만 이런 방식은 너무 비효율적 이므로 Keyboard인터럽트를 통해서 킷값을 받도록 한다.
Keyboard는 키가 눌리거나 떨어질 때마다 해당 키에 대한 고유 코드를 전송하며, 키 이벤트에 대한 고유코드를 Scan Code라고 한다.
Scan Code | |||||
Key Name |
Down Code |
Up Code |
Key Name |
Down Code |
Up Code |
Esc |
0x01 |
0x81 |
, < |
0x33 |
0xB3 |
1 ! |
0x02 |
0x82 |
. > |
0x34 |
0xB4 |
2 @ |
0x03 |
0x83 |
/ ? |
0x35 |
0xB5 |
3 # |
0x04 |
0x84 |
Right Shift |
0x36 |
0xB6 |
4 $ |
0x05 |
0x85 |
Print Screen |
0x37 |
0xB7 |
5 % |
0x06 |
0x86 |
Alt |
0x38 |
0xB8 |
6 ^ |
0x07 |
0x87 |
Space |
0x39 |
0xB9 |
7 & |
0x08 |
0x88 |
CAPS Lock |
0x3A |
0xBA |
8 * |
0x09 |
0x89 |
F1 |
0x3B |
0xBB |
9 ( |
0x0A |
0x8A |
F2 |
0x3C |
0xBC |
0 ) |
0x0B |
0x8B |
F3 |
0x3D |
0xBD |
- _ |
0x0C |
0x8C |
F4 |
0x3E |
0xBE |
= + |
0x0D |
0x8D |
F5 |
0x3F |
0xBF |
BACK Space |
0x0E |
0x8E |
F6 |
0x40 |
0xC0 |
Tab |
0x0F |
0x8F |
F7 |
0x41 |
0xC1 |
Q |
0x10 |
0x90 |
F8 |
0x42 |
0xC2 |
W |
0x11 |
0x91 |
F9 |
0x43 |
0xC3 |
E |
0x12 |
0x92 |
F10 |
0x44 |
0xC4 |
R |
0x13 |
0x93 |
NUM Lock |
0x45 |
0xC5 |
T |
0x14 |
0x94 |
Scroll Lock |
0x46 |
0xC6 |
Y |
0x15 |
0x95 |
Home |
0x47 |
0xC7 |
U |
0x16 |
0x96 |
Up |
0x48 |
0xC8 |
I |
0x17 |
0x97 |
Page Up |
0x49 |
0xC9 |
O |
0x18 |
0x98 |
- |
0x4A |
0xCA |
P |
0x19 |
0x99 |
Left |
0x4B |
0xCB |
[ { |
0x1A |
0x9A |
Center |
0x4C |
0xCC |
] } |
0x1B |
0x9B |
Right |
0x4D |
0xCD |
Enter |
0x1C |
0x9C |
+ |
0x4E |
0xCE |
Ctrl |
0x1D |
0x9D |
End |
0x4F |
0xCF |
A |
0x1E |
0x9E |
Down |
0x50 |
0xD0 |
S |
0x1F |
0x9F |
Page Down |
0x51 |
0xD1 |
D |
0x20 |
0xA0 |
Insert |
0x52 |
0xD2 |
F |
0x21 |
0xA1 |
Delete |
0x53 |
0xD3 |
G |
0x22 |
0xA2 |
F11 |
0x57 |
0xD7 |
H |
0x23 |
0xA3 |
F12 |
0x58 |
0xD8 |
J |
0x24 |
0xA4 |
Enter |
0xE0 0x1C |
0x9C |
K |
0x25 |
0xA5 |
Right Ctrl |
0xE0 0x1D |
0x9D |
L |
0x26 |
0xA6 |
/ |
0xE0 0x35 |
0xB5 |
: |
0x27 |
0xA7 |
Right Alt |
0xE0 0x38 |
0xB8 |
‘ ““ |
0x28 |
0xA8 |
Home |
0xE0 0x47 |
0xC7 |
` ~ |
0x29 |
0xA9 |
Up |
0xE0 0x48 |
0xC8 |
Left Shift |
0x2A |
0xAA |
Page Up |
0xE0 0x49 |
0xC9 |
\ | |
0x2B |
0xAB |
Left |
0xE0 0x4B |
0xCB |
Z |
0x2C |
0xAC |
Right |
0xE0 0x4D |
0xCD |
X |
0x2D |
0xAD |
End |
0xE0 0x4F |
0xCF |
C |
0x2E |
0xAE |
Down |
0xE0 0x50 |
0xD0 |
V |
0x2F |
0xAF |
Page Down |
0xE0 0x51 |
0xD1 |
B |
0x30 |
0xB0 |
Insert |
0xE0 0x52 |
0xD2 |
N |
0x31 |
0xB1 |
Delete |
0xE0 0x53 |
0xD3 |
M |
0x32 |
0xB2 |
Pause |
0xE1 0x1D 0x45 |
- |
Keyboard의 Scan Code Table
위 표와 같이 Keyboard의 모든 키는 각자의 고유 코드를 가지고 있으며, Keyboard는 키가 눌리거나 떨어질 때마다 그 상태에 해당하는 키 값을 Keyboard Controller로 전송한다.
Scan Code는 키가 눌렸을 때(Down)와 떨어졌을 때(Up)의 값이 다르며, 일반적으로 떨어졌을 때의 키 값은 눌러졌을 때의 값에 최상위 Bit(Bit 7)을 1로 설정한 값과 같다.
최상위 Bit를 1로 설정하는 것은 0x80을 더하는 것과 같으므로, 눌러졌을 때의 키 값에 0x80을 더하는 방식으로 처리하면 떨어졌을 때의 키 값을 가지고 있지 않아도 된다.
위 표에서 음영으로 표시한 부분은 확장 키 (Extended Key)의 Scan Code를 표시한 것이다. 확장 키는 AT PC 시절에 사용되었던 Keyboard 이후에 추가된 키를 의미한다. 확장 키는 일반적으로 QWERTY 키 영역과 숫자 패드 사이에 있다. 확장 키는 일반 키와 달리 2개 이상의 Code로 구성되므로 처리할 때 주의해야 한다.
확장 키는 다른 키와 달리 0xE0이나 0xE1로 시작한다는 공통점이 있으므로, 0xE0이나 0xE1에 해당하는 Scan Code가 수신되었을 때 이를 판단해서 처리하면 된다.
Scan Code에서 ASCII Code로의 변환을 용이하게 하기 위해 Scan Code의 값을 Table Index로 사용하여 ASCII값을 구하는 변환 테이블을 만들어 사용하였다.
변환과정에서 주의해야 할 사항은 조합 키의 상 태에 따라 영향을 받는 지의 여부와 확장 키를 처리하는 것이다.
Scan Code를 ASCII Code로변환하는 알고리즘은 다음과 같다.
if( 마지막 키가 Pause여서 나머지 Scan Code 2개를 무시해야 하는가? ) { Scan Code를 무시 종료 } if( Scan Code가 Pause의 첫 번째 코드(0xE1)인가? ) { 나머지 Scan Code 2개를 무시하도록 설정하고 Pause 코드를 반환 종료 } else if( Scan Code가 확장 키의 첫 번째 코드(0xE0)인가? ) { 다음에 수신될 키가 확장 코드임을 저장 종료 }
if( Scan Code와 관계된 조함 키(Shift, Caps Lock, Num Lock)가 눌러졌는가? ) { Scan Code에 해당하는 ASCII 테이블의 조합 코드를 반환 } else { Scan Code에 해당하는 ASCII 테이블의 일반 코드를 반환 } if( 마지막 Scan Code가 확장 키의 첫 번째 코드(0xE0)였는가? ) { 속성 값에 확장 키 옵션 반환 } 조합 키(Shift, Caps Lock, Num Lock, Scroll Lock)의 눌림, 떨어짐 상태, LED 상태 갱신 종료 |
(4) Keyboard Interrupt Handler
Keyboard Interrupt가 발생하면, I/O APIC Redirection Table Entry 1에 설정한 Vector값에 해당하는 IRQ(Interrupt Request)가 수행된다.
IRQ는 Interrupt가 수행되는 동안 다른 Interrupt가 방해하지 않도록 Timer Interrupt를 Disable한다. 이후, Keyboard IRQ Handler 함수를 호출하여 필요한 작업을 수행한 뒤, EOI를 전달, Timer Interrupt를 Enable하고 IRQ를 종료한다.
Keyboard의 입력 값은 포트 0x60의 출력 버퍼에 저장된다.
이 값은 Keyboard 각 자판의 Scan Code값이다. 이 버퍼의 값을 읽어 ASCII Code로 변환하여 OS 내에 있는 Keyboard Queue에 삽입한다.
* 모니터 드라이버
화면에 문자를 출력하려면 현재 동작중인 화면모드와 관련된 비디오메모리의 어드레스를 알아야 한다.
비디오 메모리는 화면출력과 관계된 메모리로 모드 별로 정해진 형식에 따라 데이터를 채우면 화면에원하는 문자나 그림을 출력하는 구조로 구성되어 있다.
PC부팅 후 기본으로 설정되는 화면모드는 텍스트모드로 화면크기는 가로80, 세로25 문자이며 비디오메모리어드레스는 0xB8000에서 시작한다.
또한, 화면에 표시하는 한 문자는 문자값 1바이트와 속성값1바이트로 구성되어 있다. 따라서 화면크기를 곱한 크기는 80*25*2=4000바이트이다.
|
속성값은 하위4비트 전경색과 상위4비트 배경식으로 구별 된다. 각전경색과 배경색은 다시 최상위의 특수기능비트와 하위3비트의 색상으로 구분 된다. 전경색은 강조효과만 지원 하지만, 배경색은 강조와 깜빡임 두기능을 한다.
전경색과 배경색의 최상위 비트를 모두 강조기능으로 사용하면 16가지 색상으로 표현할 수 있으므로 이를 이용하면 그럴듯 한 텍스트화면을 표현할 수 있으므로 사용하면 사용하도록 한다.
BIT |
값 |
배경색(상위4비트) |
전경색(하위4비트) |
0~2 |
0x00 |
검은색 | |
0x01 |
파란색 | ||
0x02 |
녹색 | ||
0x03 |
청색 | ||
0x04 |
빨간색 | ||
0x05 |
자홍색 | ||
0x06 |
노란색 | ||
0x07 |
흰색 |
3 |
0x00 |
효과없음 | |
0x01 |
하위3비트색상에 깜빡임 효과를 주거나 강조 효과 추가 |
하위3비트색상에 깜빡임 효과를 주거나 강조 효과 추가 | |
이제 화면에 문자를 표시하려면 0xB8000어드레스에 문자와 속성 순서대로 지정하면 된다. 이를 이용하여 맨위에 ‘A’을 빨간색 배경에 밝은녹색으로 출력해 본다.
mov ax, 0xB800 ;AX레지스터에0xB800복사 mov ds, ax ;DS세그먼트레지스터에AX레지스터의값(0xB800)을복사
DS세그먼트레지스터에0xB800의값을설정했으니각가‘A’,0x4A를입력시켜준다.
mov byte[0x00], 'A' mov byte[0x01], 0x4A |
커서는 모니터에 깜빡이는 ‘_’ 문자료 표시되며 입력된 텍스트가 출력될 위치를 표시하기 위해 사 용한다. 커서는 직접 ‘_’ 문자를 출력하여 표현하는 것이 아니라 모니터 출력을 담당하는 VGA 컨트롤러가 담당한다.
그 중 CRTC Controller Address Register와 CRTC Controller Data Register가 담당하며 각 I/O Port 0x3D4와 0x3D5를 사용한다.
CRTC 컨트롤러 어드레스 레지 스터(0x3D4)는 CRTC의 내부 레지스터를 지정한다. 커서의 위치를 제어하려면 0xE와 0xF를 전달하여 상위 커서 위치 레지스터와 하위 커서 레지스터를 먼저 선택하고 CRTC 컨트롤러의 데이 터 레지스터(0x3D5)에 상위, 하위 바이트로 나누어 커서 위치를 전달하면 해당 위치로 커서가 이동하게 된다.
이때 CRT 컨트롤러는 컬럼과 라인 좌표가 아닌 비디오 메모리 내 오프셋을 사용한다.
void SetCursor( int iX, int iY )
{ int iLinearValue;
iLinearValue = iY * CONSOLE_WIDTH + iX; // Calculate Offset
// Send 0x0E to CRTC(0x3D4), Select upperbyte outportb( VGA_PORT_INDEX, VGA_INDEX_UPPERCURSOR ); outportb( VGA_PORT_DATA, iLinearValue >> 8 );
// Send 0x0F to CRTC(0x3D4), select lowwerbyte outportb( VGA_PORT_INDEX, VGA_INDEX_LOWERCURSOR ); outportb( VGA_PORT_DATA, iLinearValue & 0xFF ); gs_stConsoleManager.iCurrentPrintOffset = iLinearValue; // update offset }
void GetCursor( int *piX, int *piY ) { *piX = gs_stConsoleManager.iCurrentPrintOffset % CONSOLE_WIDTH; *piY = gs_stConsoleManager.iCurrentPrintOffset / CONSOLE_WIDTH; } // CONSOLE_WIDTH == 80 |
필요성 : 폴링 방식은 프로세서가 키보드 컨트롤러를 주기적으로 확인하므로 프로세서의 소모가 심하고 확인하는 주기에 비례하여 데이터가 수신되는 시간이 길어지는 문제점이 있다.
인터럽트 방식은 컨트롤러에 데이터가 있거나 데이터를 전송할 수 있을 때 인터럽트를 통해 이를 알려주므 로 상대적으로 프로세서를 덜 사용하게 된다.
이런 차이는 멀티태스킹 환경에서 더욱 확연히 드러날 것이다. 그래서 최종적으로 키보드 디바이스를 인터럽트 방식으로 변경하려면 버퍼는 필수적으로 필요하게 된다.
왜냐하면 인터럽트는 발생 시점을 예측할 수가 없어 수신된 키 값을 온전히 전달하기가 어렵기 때문이다.
'IT 놀이터 > Elite Member Tech & Talk' 카테고리의 다른 글
[3기 전주 전환규] Place & Route Part.2 (0) | 2013.05.05 |
---|---|
[3기 강남 백정의] 플래시의 비트맵을 활용한 영상을 재생시키고 레이어 추가 (0) | 2013.04.06 |
[3기 강남 정준호] Work-Queue Working Flow (0) | 2013.04.05 |
[3기 대전 김재원] Linux Kernel - Data Structure (1) (0) | 2013.04.03 |
[3기 전주 전환규] Place & Route Part.1 (0) | 2013.04.02 |