Stop! 윈도우 임베디드 CE 시스템 개발! ⑤



디바이스 드라이버라는 것은 윈도우 임베디드 CE 운영체제를 탑재한 임베디드 시스템에 있는 각종 장치들을 제어하는 소프트웨어를 의미하며 장치에 따라서 장치의 역할에 따라서 다양한 디바이스 드라이버가 존재하게 된다. 디바이스 드라이버는 윈도우 임베디드 CE를 개발하는데 있어 많은 영역을 차지하는 부분이다. 가장 좋은 디바이스 드라이버는 사용자를 위한 드라이버라는 것을 명심하기를 바라며 이에 대해 자세히 알아본다.
글 : 라영호  / ratharn@naver.com

연재 차례

1. 윈도우 임베디드 시스템 테스팅
2. 부트로더를 통한 개발 준비  
3. 빌드이야기
4. 윈도우 임베디드 CE 6.0 커널 이야기 
5. 디바이스 드라이버 개발
 6. 디스플레이 디바이스 드라이버
 7. 원도우 임베디드 시스템, 3D의 세계로...
 8. 플래시 메모리를 저장 장치로
 9. GPS 디바이스 드라이버의 개발
 10. 선 없는 세상으로
 11. 멀티미디어 세상속으로-I
 12. 멀티미디어 세상속으로-II

/필/자/소/개/

필자는 윈도우 모바일 관련 스마트폰 개발과 윈도우CE 관련 장치를 개발하고 있다. 개인적으로 운영하고 있는 윈도우CE에 관한 블로그(www.embeddedce.com)를 통해 윈도우CE 개발에 대한 다양한 생각과 방법론을 함께 생각해 보고자 노력 중이다. 아울러 윈도우CE의 포팅 뿐만 아니라 개발에서부터 최종 제품이 나오기까지 거쳐야 할 다양한 테스트 및 신뢰성 문제에도 관심을 가지고 있다.

 

디바이스 드라이버(Device Driver)란?

윈도우 임베디드 CE 시스템을 개발하는데 있어 많은 부분을 차지하는 부분은 디바이스 드라이버를 개발하거나 수정하는 작업일 것이다. 개발하는 제품에 따라, 개발하는 목적에 따라 사용하는 부품이나 시스템의 구조가 달라지고 이에 따라 디바이스 드라이버를 수정하게 된다. 다른 LCD 모듈을 장착한다고 해도 이 LCD 모듈의 제어 방법에 따라 디바이스 드라이버가 수정되어야 한다는 것이다. 불과 2~3년 전과는 달리 윈도우 임베디드 CE 운영체제의 위상 및 지원 개념이 많이 달라져 많은 장치들에 대해서 디바이스 드라이버를 손쉽게 얻고 개발할 수 있다. 또한 한 회사에서 자체적으로 모든 드라이버를 다 개발하고 제품을 만든다는 개념보다는 잘 만들어진 제품과 디바이스 드라이버를 탑재하여 잘 돌아가는 윈도우 임베디드 CE 운영체제를 탑재한 제품을 만드는 것이라고 봐야 하겠다.
'윈도우 임베디드 CE를 탑재한 제품 개발에 있어 디바이스 드라이버는 어떻게 보면 개발 작업의 많은 부분을 차지하는 부분이다.'
다시 정리하면 디바이스 드라이버라는 것은 윈도우 임베디드 CE 운영체제를 탑재한 임베디드 시스템에 있는 각종 장치들을 제어하는 소프트웨어를 의미하며 장치에 따라서 장치의 역할에 따라서 다양한 디바이스 드라이버가 존재하게 된다.

내비게이션 시스템을 개발한다고 가정해 보자.
(1)화면 표시를 위한 LCD 드라이버가 있어야 하며,
(2)소리 출력을 위한 사운드 드라이버 혹은 오디오 디바이스 드라이버
(3)지도 저장을 위해 사용하는 SD/MMC 저장 장치를 위한 SD/MMC 디바이스 드라이버
(4)GPS 모듈과 연결을 하여 위치 추적을 위한 GPS 드라이버(시리얼 드라이버라는 것이 옳지만 문맥상 GPS 드라이버라고 한다) 등 다양한 종류의 디바이스 드라이버가 있다.
이같은 디바이스 드라이버들이 네비게이션 시스템을 구성하고 있다.

카메라, 오디오, 디스플레이, CDMA 모듈과 같은 통신 장치와 연결 및 동작시키는 복잡한 드라이버에서부터 장치에 있는 LED를 키고 끄는 기능을 하는 간단한 기능의 LED 디바이스 드라이버도 있다.
윈도우 임베디드 CE 운영체제가 마이크로프로세서를 동작시키기 위해 존재한다면 디바이스 드라이버는 마이크로프로세서와 연결된 장치들을 다루는 소프트웨어라고 생각하면 된다. 윈도우 임베디드CE 운영체제 개발 이전에도 PC에 USB 랜 카드나 비디오 카드를 변경했을 때 디바이스 드라이버를 설치하였던 경험이 있을 것이다. 물론 이 경우에는 인터넷이나 첨부된 CD에서 장치용 디바이스 드라이버를 매뉴얼에서 알려 준 것처럼 설치하면 되는 것이다. 일반 PC용 디바이스 드라이버는 주변 장치 제조업체에서 제공해 준다는 것은 당연히 알고 있는 사실이다. 이와 다르게 윈도우 임베디드 CE에서는 윈도우 임베디드 CE를 개발하는 업체에서 만드는 장치에 맞게 만들어야 한다는 차이점이 있는 것이다. 물론 어느 정도의 소스 코드는 제공해 준다. PC와는 다르게 독립된 제품으로 판매되는 것이 아니고 칩 단위로 제품이 판매가 되기 때문에 디바이스 드라이버도 대표되는 제품에 대한 소스 코드(대부분의 업체가 참고용 디바이스 드라이버 소스나 실행 파일을 제공하기는 하지만 제공 안 되는 경우도 많이 있음)나 참고 드라이버가 형태로 제공이 되고, 이 드라이버 소스를 개발하는 제품이 맞게 포팅 하는 작업을 거쳐 해당 디바이스 드라이버로 만들어 지는 것이다. 따라서 제조업체에서 제공해주는 드라이버를 설치하는 드라이버 개념에서 개발하는 장치의 드라이버를 만들어야 한다는 것으로 바꿔야 하는 것이다. <그림 1>는 임베디드 시스템에서 드라이버의 역할을 설명해 주는 그림이다.

윈도우 임베디드 CE 그리고 디바이스 드라이버 

<표 1>은 디바이스 드라이버의 구조 및 기능에 따라 분류한 표이다. 표에 있는 것처럼 구분하기 모호한 디바이스 드라이버도 있다. 대부분의 디바이스 드라이버는 표에서 정의한 분류에 속한다고 생각하면 된다. 디바이스 드라이버는 마이크로프로세서에 부착된 장치만큼이나 디바이스 드라이버도 많다는 것이다. USB를 통하여 연결된 장치이지만 실제 USB 장치의 본연의 역할인 외장 메모리나 마우스와 같은 입력장치의 역할뿐만 아니라 USB를 통하여 시리얼 장치의 기능을 하고 네트워크 카드, 통신장치와 같은 역할을 하는 복합 장치 기능을 제공하고 있다. 그만큼 윈도우 임베디드 CE 에서 디바이스 드라이버의 범위도 확대 되었고 그 의미도 점점 달라지고 있다는 것을 의미한다. 하지만 디바이스 드라이버의 주 목적은 '윈도우 임베디드 CE가 설계한 디바이스 드라이버 구조에 맞게 부착된 장치를 효율적으로 사용하게 하는데 있다.'라는 것을 명심해야 한다.

PC와 통신을 하는 USB 디바이스 드라이버라면
▶PC 와의 데이터 전송 속도가 빨라야 할 것이며,
▶PC에 연결 했을 때는 USB 장치로써 제대로 인식이 되어야 하면,
▶PC에서 연결 해제 시에는 안정적으로 PC의 장치 목록에서 제거 되어야 한다.
이와 같이 디바이스 드라이버로써 갖추어야 할 기본 동작이 잘 구현되어야 한다.

윈도우 임베디드 CE의 디바이스 드라이버 종류

디바이스 드라이버 종류는 시스템에 부착된 장치만큼이나 많이 있고 다양하다. 또한 시스템이 복잡해짐에 따라 더 다양한 디바이스 드라이버들이 존재한다. 다음 <표 1>는 대표적인 디바이스 드라이버들의 기능 및 사용 방법에 따라 분류한 것이다. 사실 이외에도 더 많은 디바이스 드라이버들이 존재한다. 따라서 아래와 같은 구분이 명확히 되지 않기도 한다. 하지만 윈도우 임베디드 CE 운영체제에 사용되는 대표적인 디바이스 드라이버에 대한 분류 이해를 통해 어떠한 드라이버를 어떻게 분석하고 구현할 지에 대한 정책을 세워보는 것도 좋은 방법일 것이라 생각한다.

디바이스 드라이버 분류  디바이스 드라이버 내용

드라이버 로드 방법  * 네이티브 드라이버 - GWES에 의해 로드 됨
   * 스트림 인터페이스 드라이버 - Device.dll에 의해 로드됨.

드라이버 동작 모드  * 유저 모드 드라이버- 사용자 모드로 동작하는 디바이스 드라이버
   * 커널 모드 드라이버 - 커널 모드로 동작하는 디바이스 드라이버
드라이버 구조  * Monolithic 드라이버 - 단일 구조 디바이스 드라이버
   * Layered 드라이버(MDD/PDD) - MS에서 제공한MDD(Model Device Driver) 라이브러리와 PDD(Platform Dependent Driver) 라이브러리 형태로 구성된 드라이버, 시리얼 드라이버, 오디오 드라이버

드라이버 설치 방법  * 빌트인 드라이버 - OS가 부팅 중에 로드 되는 디바이스 드라이버
   * Dynamic/Installable 드라이버 - OS가 부팅 후에 로드 되거나 설치 가능한 디바이스 드라이버
 
드라이버 종류  * 호스트 드라이버 - USB Host, PCMCIA, SD/MMC Host 드라이버 등
   * 클라이언트 드라이버 - Host Driver내에 동작하는 디바이스 드라이버
   * 단일 드라이버 - 일반적인 단일 기능(단일 장치를 위한)을 하는 드라이버
   * 에뮬레이션(복합) 드라이버 - 다른 디바이스 드라이버나 기능을 에뮬레이션하는 디바이스 드라이버, USB 시리얼 드라이버 등

표 1. 디바이스 드라이버의 구조 및 기능

 

Serial MDD: COM_Write()
Serial MDD: DoTxData()
Serial PDD: PDD_SerTxIntrEx()
Serial PDD: PDD_SerialDispatch Thread()
USB Client: IssueBulkTransfer() lplssueBulkTransfer with BulkOut pipe

그림 2. MDD-PDD

MDD/PDD란

디바이스 드라이버는 종류에 따라 복잡도가 많이 다르다. LED를 제어하거나 진동 모터와 같은 기능을 제어하는 드라이버의 경우 적은 수의 코딩을 통해서도 작성할 수 있다. 하지만 디스플레이 드라이버나 오디오, 시리얼 드라이버의 경우 매우 복잡하다. 이러한 복잡한 디바이스 드라이버를 손쉽게 개발할 수 있도록 고안된 것이 MDD/PDD 모델의 디바이스 드라이버 구조이다. 디바이스 드라이버의 상위 레벨의 복잡한 부분은 마이크로소프트사에서 제공한 MDD라는 형태의 라이브러리를 이용하고 하드웨어 설정에 관련된 PDD 부분만 수정하고 개발하는 형태로 개발하는 디바이스 드라이버 형태이다. <그림 2>는 대표적인 MDD/PDD 형태의 디바이스 드라이버인 시리얼 드라이버의 구조를 보여주는 것이다. 녹색 부분은 윈도우 임베디드 CE가 제공하는 MDD부분이고, 노란색 부분은 하드웨어에 맞추어 수정해야 하는 PDD 부분을 표시한다.

▶ MDD : Model Device Driver, MS가 제공하는 드라이버 라이브러리
▶ PDD : Platform-Dependent Driver, 하드웨어따라 수정해야 하는 드라이버 부분
이 디바이스 드라이버 형태의 장점은 특별한 노력 없이도 디바이스 드라이버를 구현할 수 있다는 점이다. 물론 MDD/PDD 형태의 구조를 더 잘 이해한다면 좀더 효율적인 디바이스 드라이버를 구현할 수 있다.

윈도우 임베디드 CE에서 디바이스 드라이버 개발

사실 디바이스 드라이버를 개발한다고 하면 장치 자체에 대한 지식뿐만 아니라 윈도우 임베디드 CE 운영체제에서 어떻게 디바이스 드라이버가 동작하고 어떻게 구성해야 하는지 알아야 하는 것이 순서일 것이다. 그 후에 디바이스 드라이버를 동작시키기 위해 윈도우 임베디드 CE 운영체제를 어떻게 설정하고 인터럽트는 어떻게 처리하는지 알면 디바이스 드라이버에 대한 기초적인 개념을 잡을 수 있다. 윈도우 임베디드 CE 운영체제가 임베디드용 중요한 운영체제로 인식되고 있는 지금은 대부분 업체에서 참조용 디바이스 드라이버 소스를 제공하고 있거나 없다면 참고할 수 있는 자료를 제공하고 있다. 따라서 디바이스 드라이버를 개발하는 작업은 점점 용이해지는 상황이다. 하지만 아무것도 없는 상태에서 개발을 하거나 특정 드라이버를 제품화 할 수 있는 상태까지 만드는 문제는 기본적인 드라이버 구현과는 또 다른 문제다.
오디오나 카메라 드라이버와 같이 복잡한 드라이버의 경우 최소 2개월 이상의 개발 기간이 소요되는 드라이버도 있고 간단히 며칠 안에 작성할 수 있는 드라이버도 있다. 단 주의할 점은 디바이스 드라이버는 운영체제와 같이 동작하는 소프트웨어기 때문에 운영체제와 정상적인 동작을 할 수 있도록 최적화 작업이 이루어져야 한다는 것이다. 대부분 각 드라이버 마다 담당자가 있고 개발 능력의 차이나 개발 방법의 차이가 있기 때문에 어떻게 융화시켜 안정적인 시스템을 만드는가가 중요한 문제일 것이다. 이 문제에 대한 정답은 될 수 있으면 빠른 시간 내에 통합 작업을 하여 지속적인 테스트를 하는 수밖에 없다고 본다.

디바이스 드라이버 제작 단계

 디바이스 드라이버는 아래 <표 2>와 같이 간략하게 디바이스 드라이버 개발 단계를 정리할 수 있다. 윈도우 임베디드 CE용 디바이스 드라이버는 PC 운영체제와 비슷한 구조 및 개발 방법을 따른다. PC 디바이스 드라이버보다는 보다 간략한 구조로 되어 있다.
인터럽트를 이용하여 외부 장치에 대한 요구 사항, 데이터 전송 등을 효과적으로 처리한다. 인터럽트 처리를 위해선 윈도우 임베디드 CE의 커널 영역에서 전달된 인터럽트를 디바이스 드라이버에서 받아 처리하는 부분을 디바이스 드라이버 내에 쓰레드(Thread) 형태로 구현하여 처리할 수 있도록 해야 한다. 운영체제를 담당하는 담당자는 OAL 포팅시 인터럽트에 대한 정보를 먼저 수집하고 인터럽트를 다른 드라이버에서 사용할 수 있도록 SYSINTR_KEY_INT와 같은 형태로 인터럽트를 등록하여 해당 인터럽트를 처리 할 수 있도록 등록한다. 그 후 디바이스 드라이버 개발자는 인터럽트 처리 쓰레드에서 인터럽트를 처리할 수 있도록 디바이스 드라이버에 구현하게 된다. 디바이스 드라이버 내에서의 인터럽트 처리 방법에 대해 이해했다면 어느정도 디바이스 드라이버 구현에 대한 개념을 이해한 단계로 판단하면 된다.

 

단 계    내 용

디바이스 드라이버 구조 참조  디바이스 드라이버 개발 시 제일 필요한 점은 참조할 수 있는 정보를 입수하는 것이다. 디바이스 드라이버 소스, 디바이스 데이터시트가 있어야 한다.

인터럽트 처리 방법 설정  OAL영역과 디바이스 드라이버 간의 인터럽트 처리 방법을 설정한다. 

XXX_ 형태의 드라이버 명 결정 SAM_ 형태의 드라이버 Prefix를 결정한다. 향후 디바이스 드라이버에 대한 함수 명, 로드 관리 등에 사용된다.

드라이버 골격 만들기  디바이스 드라이버의 기본 함수를 구현한다.
    * XXX_Close
    * XXX_Deinit
    * XXX_IOControl
    * XXX_Open
    * XXX_Read

 

드라이버 인터페이스  IOCTL 형태의 디바이스 드라이버 인터페이스 구현, 디바이스 드라이버와 다른 디바이스 드라이버 혹은 응용 프로그램과의 통신을 할 수 있게 한다.

DEF 파일 작성   DLL 생성을 위한 .DEF 파일을 작성한다.

레지스터리에 등록   생성된 디바이스 드라이버가 로드 될 수 있도록 레지스터리에 등록한다.

BIB 파일에 등록   디바이스 드라이버가 OS 이미지에 포함될 수 있도록 BIB 파일에 등록한다.

OS 이미지 빌드    전체 운영체제 이미지에 디바이스 드라이버를 포함시켜 이미지를 만든다.
  
디버깅    DLL이 제대로 동작하는지 디버깅 테스트를 한다.
PM 관련 구현및 디버깅  PM(Power Management) 기능을 제공 할 수 있도록 디바이스 드라이버 내에 전원 관리 루틴을 추가한다.

드라이버 최적화   윈도우 임베디드 CE 운영체제에서 효율적으로 동작하도록 디바이스 드라이버를 최적화한다.

표 2. 디바이스 드라이버 제작 순서

 

디바이스 드라이버와 레지스터리

윈도우 임베디드 CE용 디바이스 드라이버는 대부분 운영체제에 포함되어 로드되는 형태이다. .REG 파일과 .BIB 파일에 디바이스 드라이버에 대한 등록 정보를 등록해 두면 부팅 시 그 디바이스 드라이버를 로드하게 된다. 디바이스 드라이버는 XXX_ 형태의 함수로서 디바이스 드라이버 내의 함수를 구성한다. LED를 제어하는 드라이버라면 "LED_" 형태의 구성 함수 이름을 가진다. 이 디바이스 드라이버가 운영체제에 의해 로드된 후에는 "LED0:"와 같은 고유 ID를 통해 디바이스 드라이버에 대한 관리 및 제어를 할 수 있다. 윈도우 임베디드 CE에서 디바이스 드라이버는 DLL 형태의 실행 파일이다. PC에서 DLL을 만드는 것처럼 윈도우 임베디드 CE에서도 .DEF 파일을 만들어 DLL을 생성하여야 한다. 개발된 드라이버는 레지스터리에 등록하여서 운영체제가 부팅 작업 도중 로드될 수 있도록 해야 한다. 다음은 레지스터리에 등록된 드라이버의 예이다. wavedev.dll이라는 디바이스 드라이버는 WAV라는 디바이스 드라이버관리용 Prefix를 가지며, Order와 같은 레지스터리 설정값에 의해 윈도우 임베디드 CE에 의해 언제 로딩될 지 지정할 수 있다.

[HKEY_LOCAL_MACHINEDriversBuiltInWaveDev]
   "Prefix"="WAV"
   "Dll"="wavedev.dll"
   "Index"=dword:1
   "Order"=dword:0
   "Priority256"=dword:95
   "Sysintr"=dword:19
   "IClass"="{A32942B7-920C-486b-B0E6-92A702A99B35}"
; power managed device

디바이스 드라이버 그리고 데이터 시트

디바이스 드라이버를 제대로 만들기 위해서는 위의 표와 같은 순서로 제작하면 된다. 생각보다 간단하군! 하고 생각하면 오산이다. 디바이스 드라이버의 구조나 개발 자체는 사실 어려운 문제는 아니다. 어려운 문제는 마이크로프로세서와 디바이스(오디오의 경우 코덱 칩)와의 인터페이스를 제대로 설정하고, 디바이스의 On/Off, 초기화, 동작을 위한 명령을 잘 전달할 것인가 하는데 있다
디바이스 자체에 대한 정보는 샘플로 제공하는 소스나 데이터 시트가 전부이기 때문에 실제 장치를 자유자제로 프로그래밍 하기가 쉽지는 않을 것이다. 필자는 펌웨어라는 개념의 마이크로프로세서 프로그래밍을 먼저 시작했었다. 운영체제라고 하기는 뭐한 마이크로프로세서에서 동작하는 프로그램을 작성하는 개발이다. main() 함수 속에 순차적으로 프로세서 동작 시에 필요한 작업들에 대해 프로그래밍해야 했다. 디바이스 드라이버라는 개념도 운영체제라는 개념도 없는 상태였기 때문에 PC에서 프로그래밍 하듯이 작성하면 되었다. 사실 마이크로프로세서에 연결된 디바이스도 지금처럼 복잡하지 않기 때문에 명령을 위한 레지스터만 잘 이해하고 프로그래밍하면 됐다. 사실 쉽게 보이는 과정이지만 이 과정에서 마이크로프로세서의 하드웨어를 제대로 이해하고 프로세서와 장치간의 관계를 정확히 이해했기 때문에 가능했던 작업이다. 이후에 윈도우 임베디드 CE 운영체제에서 디바이스 드라이버를 개발하게 되었다. 윈도우 임베디드 CE용 드라이버 개발 시에는 윈도우 임베디드 CE라는 운영체제 자체에 대한 개념이 부족했기 때문에 윈도우 임베디드 CE라는 운영체제를 이해하는 것이 어려웠고 실제 드라이버 자체를 코딩하는 일은 그다지 어려웠던 일은 아니었다. 따라서 윈도우 임베디드 CE에 대한 구조 및 동작 방식을 이해한 후에는 드라이버 작성이 그다지 어려운 작업은 아니었다. 이와 비교해서 지금의 디바이스 드라이버 개발자들은 필자와 같은 펌웨어(혹은 로우레벨) 단계의 개발 경험이 없기 때문에 윈도우 임베디드 CE 운영체제에서 드라이버 작성은 쉽게 하는데 디바이스 자체를 다루는 데는 부족한 점을 보여준다. PC상에서 윈도 프로그래밍에 대한 경험이 많고 윈도우 임베디드 CE에 대한 구조적인 이해는 빠르지만 정작 디바이스를 다룰 때는 어려움을 호소하는 것을 종종 보게 된다. 사실 데이터시트만 가지고 디바이스 드라이버를 작성할 수 있는 엔지니어가 적다는 것이다. 그나마 제공해주는 드라이버 소스나 인터넷상에서 찾을 수 있는 정보가 많기 때문에 이런 어려움을 극복할 수 있다. 임베디드 시스템을 다루는 디바이스 드라이버 엔지니어에게는 하드웨어에 대한 지식은 기본적으로 필요한 지식이다.

디바이스 드라이버 개발 시 주의할 점

윈도우 임베디드 CE 디바이스 드라이버 개발 시 "₩PUB-LIC₩COMMON₩OAK₩DRIVERS"라는 경로명은 반드시 알아야 하는 경로중의 하나다. MSDN도 좋고 매뉴얼도 좋지만 소스를 참조한다는 것이 개발의 어떤 것보다 장점이기 때문에 참고할 수 있는 각종 디바이스 드라이버를 제공하고 있다. 분야별 다양한 종류의 소스가 있기 때문에 필요한 디바이스 드라이버 소스를 찾아서 거기서부터 개발의 시작으로 생각하면 된다. 소스가 생각보다 많기 때문에 일일이 살펴보는 것은 사실상 불가능한 일이다. 하지만 소스에 대한 세부적인 설명이 없기 때문에 MSDN에서 소스에 대한 대략적인 내용을 파악한 후 소스를 찾는 노하우가 필요하다. 디바이스 드라이버는 기술적으로 난이도가 있는 분야 중에 하나다. 윈도우 임베디드 CE라는 운영체제가 원하는 기술적인 스펙을 따르게 구현해야 하는 점이 첫 번째 어려움이며, 드라이버는 운영체제에 속해 동작해야 한다는 점이 또 하나의 어려움이다. 단독으로 동작하는 소프트웨어는 개발하기 쉽다. 하지만 운영체제 밑에서 운영체제의 제어를 받으며 다른 디바이스 드라이버와 조화로움을 이루면서 동작하게 구현하려면 고민을 하면서 개발을 진행해 나가야 한다.

디바이스 드라이버와 가상메모리? 

디바이스 드라이버를 처음 개발 할 때 초보자들이 헷갈리는 점 중의 하나를 꼽아 본다면 가상 주소(Virtual Address)에 관련된 사항이다. 마이크로프로세서나 주변장치의 레지스터를 접근할 때 VirtualAlloc()이나 VirtualCopy()와 같은 함수를 사용하여 가상 메모리를 할당해서 사용해서 제어할 수 있다. 그 이유는 드라이버는 운영체제가 관리하는 주소 체계 안에서 동작해야 한다. 모든 주소는 마이크로프로세서가 제공하는 실제 주소가 아닌 윈도우 임베디드 CE가 관리하는 가상 주소로 변환되기 때문이다. 따라서 원래 마이크로프로세서에서 제공하는 레지스터의 주소가 아닌 윈도우 임베디드 CE가 관리하는 가상 주소를 통해 제어할 수 있는 것이다. 이러한 가상 주소의 개념을 드라이버 처음 개발 시 이해하고 있어야 한다.  보통 g_oalAddressTable이라고 하여 BSP 내에 물리적인 메모리와 가상 메모리를 설정하는 테이블을 관리하게 된다. 이 테이블을 통해 윈도우 임베디드 CE 운영체제가 사용하는 가상 주소 공간을 관리하게 되고 하드웨어 영역을 제어하게 된다. 따라서 이러한 가상 주소 관리에 대한 기본적인 개념을 이해하고 있어야 한다.

g_oalAddressTable

     DCD     0x90000000, 0x70000000,  4      ; SROM SFR
     DCD     0x90400000, 0x71000000,  4      ; TZIC0
     ;DCD     0x90500000, 0x71100000,  1      ; TZIC1
     ;DCD     0x90600000, 0x71200000,  1      ; INTC0
     ;DCD     0x90700000, 0x71300000,  1      ; INTC1
     DCD      0x90800000, 0x72000000,  1    ; FIMG-3DSE SFR
     ;DCD     0x90800000, 0x73000000,  2      ; ETB Memory
     ;DCD     0x90900000, 0x73100000,  1      ; ETB Registers

디바이스 드라이버는 하드웨어를 제어하는 것

디바이스 드라이버의 목적은 주변 장치를 제어하는 것이다. LCD 드라이버는 LCD 컨트롤러와 TFT LCD 모듈을 제어하는 것이다. 제어를 하기 위해서는 우선 LCD 컨트롤러와 어떻게 통신을 하는지 우선 알아야 한다. 대부분의 주변 장치들이 메모리와 같이 주소로 지정할 수 있는 메모리 주소 형태의 레지스터(Memory Mapped Register)를 가지고 있다. 이런 연결 형태는 마이크로프로세서에서 주변 장치를 설정한 후 일반적인 메모리를 읽고 쓰는 것 같이 동작된다. 우선은 마이크로프로세서의 인터페이스를 설정한 후 레지스터의 모든 내용을 읽어서 제대로 레지스터의 값은 읽는지 장치에 대한 고유 ID(장치에 따라 제조사와 제품 ID를 읽을 수 있게 지원하기도 한다)는 제대로 읽히는지 검사하도록 한다. 그 후 장치에 대한 전원 On/Off를 어떻게 하는지, 설정은 어떻게 읽고 변경하는지, 초기화는 어떻게 하는지 설정하게 된다.
이러한 기본적인 테스트가 끝나면 비로소 윈도우 임베디드 CE의 디바이스 드라이버 구조에 맞게 디바이스 드라이버 소스를 포팅하거나 개발한다. 필자는 디바이스 드라이버를 개발할 때 Eboot(부트로더)에서 장치에 대한 모든 테스트를 마치고 디바이스 드라이버를 개발하는 과정을 가진다. 그 이유는 하드웨어 팀과 소프트웨어 팀은 개발 일정에 따라서 각자 진행할 일이 많다.
하드웨어 팀은 우선 하드웨어가 정상적으로 설계가 되었는지 검증이 필요하다. 검증 과정은 소프트웨어 팀의 도움이 없이는 불가능한 일이기 때문에 빠른 시간 내에 하드웨어를 검증하기 위한 작업에 들어가야 한다. 모든 하드웨어에 대한 기능 테스트를 다 할 수 없겠지만 마이크로프로세서와 장치간의 인터페이스가 제대로 되는지? GPIO 포트에 대한 제어는 제대로 되는지? 등의 설계된 하드웨어에 대한 검증 작업은 빠른 시간 내에 진행되어야 한다. 윈도우 임베디드 CE 개발 작업의 초기에는 이러한 하드웨어 검증 작업에 대한 개념이나 경험이 없기 때문에 간과하는 경우가 많았다. 윈도우 임베디드 CE 운영체제가 제대로 동작되어야 LCD가 동작되어 화면에 표시하는 테스트도 할 수 있었고 시리얼 통신도 테스트 했었다. 그러다 보니 하드웨어에 대한 테스트가 미흡하여 정작 하드웨어 설계상의 문제를 나중에 발견하는 시행착오를 많이 겪었다. 그래서 요즘에는 아에 부트로더 단계에서 하드웨어에 대한 테스트 작업을 강화하여 하드웨어에 대한 모든 테스트를 할 수 있도록 기능을 구현하는 방법을 시도하여 진행하고 있다. 하드웨어에 대한 테스트 작업을 하드웨어가 나왔을 때 바로 검증할 수 있도록 하고 하드웨어 팀은 다음 하드웨어 수정 작업이나 디버깅 작업을 진행할 수 있게 한 후 드라이버를 개발하는 단계를 진행할 수 있게 했다. 하드웨어에 대한 검증 작업만 끝나면 다음 단계의 하드웨어가 나오기 까지는 어느 정도 여유가 있기 때문에 좀 여유를 부리며 드라이버를 개발할 수 있었다. 하드웨어에 대한 검증작업만 완벽히 한다면 디바이스 드라이버 구현은 문제가 없다.

디바이스 드라이버와 PM(파워 매니지먼트)

PDA와 같은 휴대형 장치는 전원 관리가 중요한 기술 이슈중의 하나다. 한번 충전을 해서 최소한 며칠 사용할 수 있어야 하기 때문이다. 물론 배터리의 용량을 크게 해서 동작시간을 늘릴 수도 있지만 무한정 용량을 늘일 수는 없는 것이다. 따라서 한정된 용량을 최대한 이용할 수 있도록 시스템을 구현하여야 한다. 제품에 따라 전원 관리에 대한 정책이 다를 수 있다. 휴대형 장치의 경우 전원 관리에 대해 주의하여 구현하여야 하지만 POS 단말기와 같이 전원을 계속 공급 받으면서 동작되는 장치의 경우에는 좀 더 전원 관리에 대한 자유로운 구현이 가능하다. 사실 장치에 대한 On/Off 가 제대로 되도록 구현하여도 크게 문제가 되지는 않는다. 개발하는 장치이 용도와 사용 환경에 따라 전원 관리 방침을 설계해야 한다. 사용자가 어떻게 사용할지 사용자 시나리오에 따른 사용량 예측 후 구현하는 것도 좋은 방법이다. 물론 사용자 시나리오라는 것이 다양한 사용 변수가 있기 때문에 하루아침에 만들어질 수 있는 것은 아니다. 전원 관리는 개발 제품에 있어 중요한 문제이기 때문에 초기 개발시부터 계획적인 구현이 필요하다. 윈도우 임베디드 CE운영체제는 운영체제 커널 내에 전원 관리 기능이 있으며 세부적인 전원 관리는 파워 매니저인 PM.DLL에 의해서 이루어진다. 전체적인 관리는 커널 및 PM.DLL에 의해 이루어지지만 각각의 디바이스 드라이버는 전원 관리를 할 수 있는 구조로 만들어져야 한다. 윈도우 임베디드 CE의 전원 관리의 큰 방침은 전원관리에 대한 큰 골격은 제공하지만 세부적인 구현은 구현하는 개발자의 자율에 맡기는 것이다. 어떻게 보면 자유로움을 준다는 것도 있지만 초기 전원관리에 대한 개념을 잡는데 어려움이나 시행착오를 겪을 수 있는 사항이다.
다음은 디바이스 드라이버 구현에 있어 기본이 되는 소스를 통해 어떻게 디바이스 드라이버를 만드는 것인지 알아보도록 하겠다. 우선 디바이스 드라이버의 기본이 되는 .DEF 형태의 디바이스 드라이버 기본 파일을 생성한다.

LIBRARY DemoDriver

EXPORTS
   DEM_Init
   DEM_Deinit
   DEM_Open
   DEM_Close
   DEM_IOControl
   DEM_PowerUp
   DEM_PowerDown
   DEM_Read
   DEM_Write
   DEM_Seek
   CustomFunction
   CustomFunctionEx

위 디바이스 드라이버 파일을 바탕으로 디바이스 드라이버의 기본 함수들을 구현하게 된다. 다음은 초기화 및 디바이스 드라이버 시작에 관련된 DEM_Init(), DEM_Open() 등의 함수 소스이다.

// Driver Init...

DWORD DEM_Init( LPCTSTR pContext, LPCVOID lpvBusContext)

{

  OutputDebugString(L"Demo - DEM_Init - Context: ");

  OutputDebugString(pContext);

  OutputDebugString(L"n");

  hMem=LocalAlloc(LPTR,0x2000);   // 0x1000 Unicode Characters

 

  OutputDebugString(L"DemoDriver - ~ DEM_Initn");

  return 0x1234;

}

 

BOOL DEM_Deinit( DWORD hDeviceContext )

{

OutputDebugString(L"Demo - DEM_Deinitn");

 

OutputDebugString(L"Demo - ~ DEM_Deinitn");

return TRUE;

}

 

// Driver Open

DWORD DEM_Open( DWORD hDeviceContext, DWORD AccessCode, DWORD ShareMode )

{

  OutputDebugString(L"DemoDriver - DEM_Openn");

  OutputDebugString(L"hDeviceContext - ");

  DBGOut(hDeviceContext);

  OutputDebugString(L"n");

  OutputDebugString(L"DemoDriver - ~ DEM_Openn");

return 0x5678;

}

BOOL DEM_Close( DWORD hOpenContext )

{

  OutputDebugString(L"Demo - DEM_Closen");

  OutputDebugString(L"hOpenContext - ");

  DBGOut(hOpenContext);

  OutputDebugString(L"n");

  OutputDebugString(L"Demo - ~ DEM_Closen");

return TRUE;

}

여기에 다른 디바이스 드라이버나 응용 프로그램과의 통신에 사용되는 DEM_IOControl() 함수 및 전원 관련 함수들을 추가하게 된다.

 

BOOL DEM_IOControl( DWORD hOpenContext, DWORD dwCode, PBYTE pBufIn, DWORD dwLenIn, PBYTE pBufOut, DWORD dwLenOut, PDWORD pdwActualOut )

{

  OutputDebugString(L"Demo - DEM_IOControln");

  OutputDebugString(L"hOpenContext - ");

  DBGOut(hOpenContext);

  OutputDebugString(L"n");

  switch (dwCode) {

    case IOCTL_DRIVER_REVSTR:

    {

       OutputDebugString(L"DRIVER REVSTR IOCTL...n");

       // reverse the string...

       HANDLE hTemp=LocalAlloc(LPTR,dwLenIn+sizeof
(TCHAR));

       memset(hTemp,0x00,dwLenIn+1);

       TCHAR *tcOut=(TCHAR*)hTemp;

       TCHAR *tcIn=(TCHAR*)pBufIn;

       DWORD dwChars=dwLenIn/2;

       for (DWORD x=0;x < dwChars;x++) {

          tcOut[x]=tcIn[dwChars-x-1];

       }

       memcpy(pBufOut,hTemp,dwLenIn);

       LocalFree(hTemp);

       *pdwActualOut=dwLenIn;

    }

    break;

    default:

       OutputDebugString(L"Unknown IOCTLn");

    break;

}

OutputDebugString(L"Demo - ~ DEM_IOControln");

return TRUE;

}

void DEM_PowerUp( DWORD hDeviceContext )

{

  OutputDebugString(L"Demo - DEM_PowerUpn");

  OutputDebugString(L"hDeviceContext - ");

  DBGOut(hDeviceContext);

  OutputDebugString(L"n");

 

  OutputDebugString(L"Demo - ~ DEM_PowerUpn");

}

 

void DEM_PowerDown( DWORD hDeviceContext )

{

  OutputDebugString(L"Demo - DEM_PowerDownn");

  OutputDebugString(L"hDeviceContext - ");

  DBGOut(hDeviceContext);

  OutputDebugString(L"n");

 

  OutputDebugString(L"Demo - ~ DEM_PowerDownn");

}

 

이러한 기본 디바이스 드라이버 함수들을 통해 디바이스드라이버가 구현되고 .REG 및 .BIB에 디바이스 드라이버를 등록하여 윈도우 임베디드 CE 운영체제에 사용할 수 있는 것이다.

 

[HKEY_LOCAL_MACHINEDriversBuiltInDemo]

    "Dll" = "Demo.Dll"

    "Prefix" = "DEM"

    "Order" = dword:0

    "FriendlyName" = "Demo Driver"

    "Ioctl" = dword:0

Platform.reg에 디바이스 드라이버 등록 항목

 

Demo.dll      $(_FLATRELEASEDIR)Demo.dll                NK  SH

Platform.bib의 디바이스 드라이버 등록 항목

끝으로

지금까지 디바이스 드라이버에 관하여 간단히 알아 봤다. 디바이스 드라이버는 윈도우 임베디드 CE를 개발하는데 있어 많은 영역을 차지하는 부분이다. 가장 좋은 디바이스 드라이버는 사용자를 위한 드라이버라는 것을 명심하기를 바라며 마치겠다.
회원가입 후 이용바랍니다.
개의 댓글
0 / 400
댓글 정렬
BEST댓글
BEST 댓글 답글과 추천수를 합산하여 자동으로 노출됩니다.
댓글삭제
삭제한 댓글은 다시 복구할 수 없습니다.
그래도 삭제하시겠습니까?
댓글수정
댓글 수정은 작성 후 1분내에만 가능합니다.
/ 400
내 댓글 모음
저작권자 © 테크월드뉴스 무단전재 및 재배포 금지