UniHigh 2.0 펌웨어, 드라이버, 어플리케이션

출처 : http://muosys.egloos.com/176088

 

오늘은 이전 강좌의 펌웨어 예제 UniHigh v1.0을 본좌가 만든 WDM USB 드라이버인 unihigh.sys를 써서 우리가 만들 어플리케이션에서 동작시키는 연습을 해 보자.

우선 기존의 펌웨어 예제를 살짝 바꿔주어야 한다.
바꿀 부분은 디바이스 디스크립터의 Vendor ID와 Product ID이다.
USB 디바이스가 포트에 꽂히면 운영체제(USB 호스트)는 디바이스 디스크립터 중에 Vendor ID와 Product ID를 읽어, 그에 해당하는 드라이버를 찾아 로딩하고 사용할 준비를 한다.
그 ID들에 해당하는 기존에 깔려있는 드라이버를 찾지 못하면 운영체제는 새 드라이버를 요구하는 대화상자를 띄우게 된다.

물론 UniHigh v1.0에서 사용하는 기존의 VID(Vendor ID), PID(Product ID)를 그냥 써서 unihigh.sys 드라이버를 로딩하게 할수도 있지만, 그렇게 하면 EZ-USB Control Panel을 사용할 수 없게 되므로, 일부러 다른 VID, PID를 사용했다.

다음은 UniHigh v1.0에서 VID, PID를 바꾼 펌웨어 예제이다.
UniHigh Firmware v2.0
(바꾸는 김에 bulkloop.c란 파일 이름도 unihigh.c로 변경했다.)

그리고 다음은 드라이버 예제이다. 다운받아서 적당한 위치에 압축을 풀어 놓으시라.
(c: 같이 ASCII문자로만 구성되며, 공백이 없는 디렉토리에 풀어 놓는게 안전하다.)
UniHigh Driver v2.0

이 UniHigh Firmware v2.0 예제를 EZ-USB Control Panel을 통해 UniHigh모듈로 다운로드 하면, 드라이버 설치를 요구하는 대화창이 뜰 것이다.

clip_image001

그럼 미리 UniHigh Driver v2.0를 다운받아 풀어 놓았던 폴더로 가서 unihigh.inf파일을 지정해 주어라.

이제 드라이버도 깔렸으니 어플리케이션을 실행해서 UniHigh 보드의 LED를 키고, 꺼보자.

UniHigh App v2.0 소스
UniHigh App v2.0 실행프로그램

당근 보드 세팅은 이전처럼 되어 있어야 한다.

어플리케이션 소스에 대한 설명은 내일 계속
*드라이버는 컴터 재부팅시키기 귀찮아서 98se, xp에서는 테스트를 안 해 봤다. -.-; 이상 있으면 얼렁 연락 주시라.

오늘은 UniHigh Application v2.0의 소스를 분석하여 어플리케이션에서 어떻게 드라이버를 통해 디바이스와 통신하는지를 디벼보자.

기본적으로 UniHigh App v2.0은 MFC로 생성한 Dialog Base의 MFC 골격을 만든 후에 리소스 에디터에서 메인 Dialog에 버튼 하나를 추가하고, 그 버튼의 Handling function을 추가한 것이다.

아직 MFC를 모르는 행자들 미리부터 너무 쫄지 마시라.
본좌가 MFC 프로그래밍을 어떻게 하는지 가르쳐 줄 수는 없지만, 그걸 몰라도 전체적인 흐름을 따라잡고, 나중에 필요한 부분의 코드를 손 댈 수 있을 정도는 설명해 준다. 그까이꺼 뭐 대충~.

소스코드를 담고 있는 프로젝트 폴더를 열어보면 MFC 위저드가 생성한 파일들 외에 본좌가 따로 추가해준 파일들이 있다.
usb100.h
usbdi.h
usbioctl.h
usbiodef.h
wdm.h
그리고 unihighusr.h

맨 아래 파일은 본좌가 만들어 추가해준 헤더파일이고, 그 이외 5개의 헤더파일들은 이 프로젝트 내에서 호출하는 함수들을 위한 헤더파일 들이다.
(DDK에서 복사해 왔다. DDK가 뭔지는 나중에 알려주마.)

그 외에 행자들이 스스로 프로젝트를 생성해서 코딩을 할 때 해주어야 할 것이 하나 있는데, Visual Studio 메뉴의 “Project”->”Settings”->”Link” 탭을 클릭해서, “Object/Library Modules”항목에 “setupapi.lib”를 추가해 주어야 한다.
이 setupapi.lib 파일 역시 프로젝트 내에서 호출하는 함수들을 위한 라이브러리 이다.

clip_image001[4]

빨간 선으로 표시한 부분이 본좌처럼 “Win32 Debug”로 되어 있다면, 이 것을 “Win32 Release” 또는 “All Configurations”로 바꾸어 준 뒤 “Object/Library Modules”항목에 “setupapi.lib”를 추가해 주는 정도의 센.스.는 있어야 하겠다.
안 그럼 릴리즈 버전의 EXE파일을 생성할 때, 링크에러가 떵 하니 나타나버리고 말 것이기 때문이다.

변죽 울리기(I탄)은 끝났고, 본격적으로 코드를 들여다 보자.

딴 파일들은 손댄 것이 없고, UniHighDlg.cpp만 보면 된다.

본좌가 이 파일에 한 짓거리를 연대기 순으로 나열 하면, (이 부분부터 벌써 지겹다고 진저리를 치는 행자들은 반성하시라. 나중에 스스로 프로젝트를 만들려고 하면 이 설명이 필요할 것이다. 본좌가 다 애정이 있어서 그런 거다.)

맨 위에 헤더파일 include문 추가
#include “unihighusr.h”
#include “usbdi.h”
#include

고 밑에 define 문 추가
#define DEFAULT_CONTROL_PIPE NULL
#define MESSAGE_PIPE (“PIPE00”) <- 쓸데 없는 넘

고 밑에 함수 원형 정의
HANDLE OpenFile(…);
BOOL GetUsbDeviceFileName(…);
HANDLE OpenUsbDevice(…);
HANDLE OpenOneDevice(…);

거기다가 전역변수
CHAR szCompleteDeviceName[256];
추가.

그리고 마우스를 쭉 끌어 맨 밑으로 가 보면 위에 선언한 함수원형에 해당하는 함수 본체들이 블라~블라~블라~ 있다.

그리고 오늘의 하이라이뚜
void OnButtonLED() 멤버함수 <-“LED ON/OFF 버튼의 핸들링 함수”
가 있다.

맨 마지막 OnButtonLED() 멤버함수를 제외하고 include문을 추가하는 것부터 시작하는 이 일련의 절차들은 행자들이 디바이스를 제어하는 어플리케이션을 작성하기 위해서는 기계적으로 Copy&Paste 신공을 구사해야 하는 대상이다.
이해? 이런 거 필요 없다.
딱 5초 준다. 존내 클릭하는 거다.

그래서 본좌가 같다 붙이기 쉬우라고 szCompleteDeviceName 전역변수와 네 개의 함수들을 멤버변수와 멤버함수로 안 만들고 기냥 같다 붙인 것이다.

본좌는 위의 변수와 함수들을 하나로 묶어 하나의 클래스로 만들어 쓰지만 클래스가 뭐시어라? 하는 행자들도 분명히 있을 것이기에 기냥 평범한 함수로 같다 붙였다.
(이러나 저러나 모냥만 다를 뿐, 하는 일은 같으므로 신경 쓰지 말자.)

여기까지가 변죽 울리기 II탄 이다.

행자들의 이해력을 필요로 하는 부분은 오직 OnButtonLED() 함수 하나 뿐이다.

앞서 말했지만,  “LED ON/OFF” 버튼을 클릭하면 낼롬 이 함수로 뛰어들어온다.

clip_image002

OpenFile함수에서 우리가 접근하고자 하는 디바이스의 핸들을 얻고, DeviceIoControl로 디바이스에 어떤 일을 시키며, 할 일이 다 끝났다면 CloseHandle로 핸들을 반환한다.

이게 줄거리의 전부다.

어라? 저번에는 CreateFile로 핸들을 얻는다며?
또 구라치기냐?
하는 행자들에게는 박수를. 짝짝짝.
나머지는 업드려!
호이짜~ 호이짜~

clip_image003

OpenFile함수를 따라 들어가 보면 거기 CreateFile이 있다.

h = CreateFile ( szCompleteDeviceName,
                         GENERIC_WRITE | GENERIC_READ,
                         FILE_SHARE_WRITE | FILE_SHARE_READ,
                         NULL,
                         OPEN_EXISTING,
                         0,
                         NULL );

시리얼 통신을 하는 프로그램을 한번이라도 작성해 본 행자들은 CreateFile의 맨 처음 인자에 “\\.\COM1” 이라고 준 것을 기억할 것이다.
근데 이건 뭐 생뚱맞게 szCompleteDeviceName 냥?

디바이스를 오픈할 때, 그 이름을 “\\.\COM1”, “\\.\ezusb-0” 처럼 주는 것을 Symbolic Link를 사용한다고 하고, 본좌처럼 GUID_CLASS_UNIHIGH_TEST (unihighusr.h에 선언돼 있음)같은 GUID를 사용하여 디바이스를 오픈할 수도 있다.

두 가지 방법 다 어플리케이션에서 운영체제에다가 “야! 나는 여기에 명시된 디바이스랑 통신 할 꺼니까 그 다바이스의 Handle을 나한테 넘겨.” 라고 말하는 방법이다.

어느 방법을 사용하느냐 하는 것은 어플리케이션 프로그래머와 디바이스 프로그래머가 상의하기 나름이다.
하지만, ezusb.sys의 사용법처럼 Symbolic Link를 사용하는 것은 다른 장치와 그 이름이 중복될 가능성 때문에 될수록 피하는게 좋다.

씨바. 난 열라 독창적인 이름을 만들어내고 말테야!
라고 우기는 행자들은 말리지 않겠다. 지금 시간 햇빛도 안 나니 말릴 수 가 없다.
근데, 가끔 Symbolic Link가 중복되어 문제가 발생하는 경우가 있다.

따라서 MS에서는 GUIDGEN.exe라 하는 GUID(Globally Unique Identifier)를 만드는 프로그램을 제공한다.
이 프로그램은 확률적으로 중복의 우려가 없는 32bit짜리 GUID를 생성해 내고, 이렇게 생성한 GUID를 사용해 디바이스를 오픈하면

CreateFile할 때에 운영체제가 대략 중복! KIN! 하는 경우는 막을 수 있다.

뭐 이래저래 장황한 설명이 되었지만
HANDLE OpenFile(…);
BOOL GetUsbDeviceFileName(…);
HANDLE OpenUsbDevice(…);
HANDLE OpenOneDevice(…);
이 네 함수는 CreateFile의 맨 처음 인자를 얻기 위해 필요한 함수들이고, 우리가 손댈 필요가 없다.

요 함수들 땜에
usb100.h, usbdi.h, usbioctl.h, usbiodef.h, wdm.h
헤더 파일들과 setupapi.lib를 추가해 준 것이다.

본좌도 예전에 위 함수들이 어떤 동작을 하는지 한번 분석해 보고 난 뒤, 그 이후부터는 그냥 기계적으로 복사해서 쓴다.
이젠 이 함수들이 어떤 짓을 하는지 기억조차 안난다.

관심과 시간이 있는 행자들은 MSDN Library를 참조해 함 디벼 보시라.

이제 파일(디바이스) 핸들을 얻었으니, 그 핸들을 가지고 디바이스와 통신할 차례이다.

bRet = DeviceIoControl( hFile, lLed, NULL, 0, NULL, 0, &dwBytesReturned, NULL );
가 그 코드이다.

이 함수에 대한 설명은 여기를 참조하시라. 꼭 한번 볼 것을 권한다.

다른 인자들은 이 예에서는 사용을 안하고, 두 번째 인자 ( DWORD dwIoControlCode)가 우리가 디바이스에게 이 일을 햐쇼. 라고 명령하는 부분이 되겠다.

이 코드는 unihighusr.h에 선언되어 있는데, IOCTL_UNIHIGH_xxxxx하는 것들이 다 그것들이다.
이 코드들도 어플리케이션 프로그래머와 드라이버 프로그래머가 상의해서 내가 이런 코드 날리면 니가 그런 일 해야되… 라고 입을 맞추면 된다.(동성끼리면 대략 난감. -.-;)

여기까지가 UniHigh Application v2.0의 소스에 대한 설명이다.
정리하자면 변죽울리기 I탄과 II탄은 앞으로도 그냥 따라 Copy&Paste하면 되고, 디바이스를 컨트롤 하기 위해서는 OnButtonLED() 처럼 하면 된다. 이다.

MFC에 익숙하지 않은 행자들은 C 콘솔프로그램에서 프로그램을 시작하면 main()문으로 들어가듯이 버튼을 누르면 OnButtonLED()로 들어온다. 라는 정도만 알고, 그 버튼이 눌렸을 때 처리해야 하는 일은 그 함수 내에서 처리해 주면 되겠다.
변수 및 함수 선언들은 본좌가 했듯이 그냥 C프로그램 작성하듯 해도 된다.
더 자세한 것들은 책 사서 보시라.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: