UniHigh Application v2.0 소스분석 - 어플리케이션과 드라이버간의 인터페이스
오늘은 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 파일 역시
프로젝트 내에서 호출하는 함수들을 위한 라이브러리 이다.


빨간 선으로 표시한 부분이 본좌처럼 “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” 버튼을 클릭하면 낼롬 이 함수로 뛰어들어온다.



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

이게 줄거리의 전부다.

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


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프로그램 작성하듯 해도 된다.
더 자세한 것들은 책 사서 보시라.




by 바람처럼날다 | 2005/05/25 23:27 | FX2 펌웨어 강좌 | 트랙백 | 덧글(2)
트랙백 주소 : http://muosys.egloos.com/tb/178949
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by 냥냥이 at 2005/06/07 18:12
USB라는걸 보게될줄 몰랐는데 어찌어찌해서 하게생겼습니다.
데브피아 따라왔다가 그나마 안심이 되네요 ^^;
앞으로도 많이 도와주세요 ㅠㅠ
Commented by 방상운 at 2016/07/04 16:54
안녕하세요 지금도 이 사이트를 보시는지는 모르겠으나, CreateFile에서 문제가 되어 연락드립니다.
TCHAR *pcCommPort = TEXT("\\.\COM17");
TCHAR *pcCommPort = TEXT("\\?\ide#cdromtsstcorp_cddvdw_sh-216db________________sc00____#5&2934420d&0&5.0.0#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}");
등처럼 COM이나, CDROM을 쓸경우 Handler정상적으로 return되지만, 유독 SOUND CARD를 CreateFile하면, File Not Found의 에러가 발생합니다.
TCHAR *pcCommPort = TEXT("\\?\hdaudio#func_01&ven_10de&dev_0051&subsys_144d80a8&rev_1001#5&19d61ee4&0&0001#{4d36e96c-e325-11ce-bfc1-08002be10318}"); 로 선언을 하였는데, CString으로 해도 안되고..막히니 답이 안나오네요..도움 부탁드립니다.

:         :

:

비공개 덧글

< 이전페이지 다음페이지 >