RtlAnsiStringToUnicodeString()과 메모리 해제

윈도우 드라이버를 개발하다 보면 UNICODE_STRING을 사용하는 경우가 많습니다. 유저모드에서 커널모드로 문자열을 보내왔을 때나, 드라이버 내에서 문자열을 주고 받고 조작하는 경우 보통 NULL로 끝나는 char * 문자열을 이용하는 경우가 많습니다.

이 char * 문자열은 윈도우 커널모드 함수에서 받아주지 않기 때문에 UNICODE_STRING으로 변환해서 사용합니다. 보통 char *에서 ANSI_STRING으로 만들고 다시 RtlAnsiStringToUnicodeString()을 사용해서 UNICODE_STRING으로 변환합니다.

RtlAnsiStringToUnicodeString()의 매개변수는 대상 UNICODE_STRING과 원본 ANSI_STRING, 그리고 대상 UNICODE_STRING의 버퍼를 메모리에 자동 할당 할 것인지 아닌지를 지정하는 것입니다.

그런데 이 RtlAnsiStringToUnicodeString()의 세번째 매개 변수와 대상 UNICODE_STRING 상태에 따라 RtlFreeUnicodeString()의 사용 여부가 결정됩니다.

RtlAnsiStringToUnicodeString()에서 TRUE로 설정하여 버퍼 메모리를 자동으로 할당한 경우.

VOID
SampleFunction(char *Str)
{
    ANSI_STRING     ansiStr;
    UNICODE_STRING  uniStr;

    RtlInitAnsiString(&ansiStr, Str);
    RtlAnsiStringToUnicodeString(&uniStr, &ansiStr, TRUE);
    (...)
    RtlFreeUnicodeString(&uniStr);
}


당연한 것이겠지만 uniStr의 버퍼를 자동으로 할당했으므로 RtlFreeUnicodeString()을 사용하여 버퍼를 해제해줘야 합니다.

RtlAnsiStringToUnicodeString()에서 FALSE로 설정하여 버퍼 메모리를 자동으로 할당하지 않고 지역 변수 배열을 사용하는 경우.

VOID
SampleFunction(char *Str)
{
    ANSI_STRING     ansiStr;
    UNICODE_STRING  uniStr;
    WCHAR           buffer[100];

    RtlInitAnsiString(&ansiStr, Str);
    uniStr.Buffer = &buffer[0];
    uniStr.Length = 0;
    uniStr.MaximumLength = sizeof(buffer);
    RtlAnsiStringToUnicodeString(&uniStr, &ansiStr, FALSE);
    (...)
}


이 경우에서는 지역 변수 배열을 사용하였기 때문에 당연히 RtlFreeUnicodeString()을 사용하면 안되겠죠.

RtlAnsiStringToUnicodeString()에서 FALSE로 설정하여 버퍼 메모리를 자동으로 할당하지 않았지만 버퍼는 동적으로 할당한 경우.

VOID
SampleFunction(char *Str)
{
    ANSI_STRING     ansiStr;
    UNICODE_STRING  uniStr;
    PWCHAR          buffer = ExAllocatePool(PagedPool, 100);

    RtlInitAnsiString(&ansiStr, Str);
    uniStr.Buffer = buffer;
    uniStr.Length = 0;
    uniStr.MaximumLength = 100;
    RtlAnsiStringToUnicodeString(&uniStr, &ansiStr, FALSE);
    (...)
    RtlFreeUnicodeString(&uniStr);
}


이미 ExAllocatePool()로 uniStr의 버퍼에 메모리를 할당했습니다. 그래서 RtlAnsiStringToUnicodeString()에서는 FALSE를 줘서 자동으로 메모리를 할당하지 않도록 했습니다. ExAllocatePool()로 메모리를 할당했기 때문에 RtlFreeUnicodeString()로 해제를 해줘야 합니다. ExFreePool()로 해제를 해줘도 상관은 없습니다.

RtlAnsiStringToUnicodeString()과 마찬가지로 RtlUnicodeStringToAnsiString()도 대상 ANSI_STRING을 동적으로 할당할 것인지 아닌지를 지정할 수 있습니다. 물론 위의 예제에 나온 상황에 맞게 RtlFreeAnsiString()을 사용해 주면 됩니다.


이번에는 RtlInitUnicodeString()으로 만든 유니코드 문자열에 대해서는 어떤지 알아보겠습니다.

VOID
SampleFunction()
{
    UNICODE_STRING  uniStr;

    RtlInitUnicodeString(&uniStr, L"Hello World");
    (...)
}


코드상에서 직접 문자열 상수로 지정해줬기 때문에 L"Hello World" 부분은 데이터 영역에 들어가 있습니다. 그러므로 RtlFreeUnicodeString()로 해제할 필요가 없습니다.

VOID
SampleFunction()
{
    UNICODE_STRING  uniStr;
    PWCHAR          wStr = ExAllocatePool(PagedPool, 100);

    swprintf(wStr, L"Hello %s", L"World");
    RtlInitUnicodeString(&uniStr, wStr);
    (...)
    RtlFreeUnicodeString(&uniStr);
}


동적으로 메모리를 할당한 뒤 UNICODE_STRING으로 만들었습니다. 그래서 RtlFreeUnicodeString()으로 메모리를 해제해줘야 합니다. (예제에서는 간단하게 보이기 위해서 swprintf()를 사용하였지만 실제로 이런 함수를 써서는 안되겠죠.)

마찬가지로 RtlInitUnicodeString()과 같이 RtlInitAnsiString()도 위의 예제와 같은 방식으로 RtlFreeAnsiString()을 사용하면 됩니다.

이런 저런 코드를 예로 들었지만 핵심은 동적 메모리를 할당하였는가 아닌가 입니다.

Posted by 혁쌈

2008/02/15 01:10 2008/02/15 01:10
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/358

IRQL(CPU 우선권 레벨)

커널모드 프로그램밍에서 중요한 개념인 하드웨어 인터럽트 우선권에 대해서 알아보겠습니다. 윈도우 2000이상 커널에서는 HAL 개념을 이용해서 모든 플랫폼에 적용시키기 위한 추상적인 스키마를 제공합니다.

이러한 우선권 추상화에 대한 기본이 되는 것이 바로 인터럽트 요청 레벨(IRQL)이다. IRQL은 단순하게 우선순위를 정의한 값입니다. 그러나 가장 중요한 법칙이 하나 있습니다.

[주어진 IRQL에서 수행되는 코드는 그 보다 낮은 IRQL의 코드나 동일한 IRQL 코드에 의해 인터럽트 될 수 없다]


< IRQL 운선순위>

인터럽트 처리 과정

위 표와 같이 인터럽트가 CPU에 도달하면 프로세서는 요청된 인터럽트의 IRQL값을 현재 CPU를 점유하고 있는 IRQL값과 비교해서 요청한 IRQL이 현재의 IRQL보다 낮거나 같다면 요청에 대한 처리가 거부되고, IRQL 레벨이 보다 낮은 값으로 떨어질 때까지 지연된 상태로 남아 있는다.

반대로 요청된 IRQL이 현재 CPU가 사용하고 있는 CPU IRQL보다 크다면 프로세서는 아래와 같은 과정에 따라 수행됩니다.

1.       현재의 명령의 수행을 중지한다.

2.       인터럽트 된 코드를 나중에 수행하기 위해서 스택에 충분한 상태정보를 저장한다.

3.       요청된 IRQL값과 같도록 CPU IRQL을 상승시키고, 현재보다 낮은 권한의 인터럽트가 일어나지 않도록 한다.

4.       요청된 인터럽트에 적절한 인터럽트 서비스 루틴으로 제어권을 넘긴다.

아래 그림은 위 동작과정을 나타낸 것 입니다

<IRQL 작동 방식 그림>

위와 같은 IRQL의 동작방식은 보다 높은 IRQL의 요청이 낮은 IRQL의 코드를 인터럽트 요청 할 수 있도록 한다.” 입니다. (인터럽트의 인터럽트) 이러한 매커니즘은 스택에 기반한 동작이기 때문에 동작에 혼동될 염려가 없는 장점이 있습니다. 그러나 동기화를 사용하는 쪽에서 처리해야 한다라는 조건이 있습니다.

소프트웨어 인터럽트

IRQL 운선순위에서 하단 부분에 있는 3가지 값(DISPATCH_LEVEL, APC_LEVEL, PASSIVE_LEVEL)은 소프트웨어 인터럽트입니다. 글자 뜻대로 하드웨어가 아니 소프트웨어 레벨에서 인터럽트가 발생합니다. 윈도우 2000에서는 이러한 소프트웨어 인터럽트를 스레드 스케줄링을 포함하여 인터럽트 우선권을 할당하는데 사용합니다. 소프트웨어 인터럽트는 한 스레드의 IRQL을 임의적으로 상승시켜 다른 스레드에 의해 인터럽트 되는 것을 막음으로써, 활성화된 스레드간의 동기화를 하는데 이용할 수 있습니다.
출처 : windows2000 디바이스 드라이버

Posted by 혁쌈

2008/01/19 19:43 2008/01/19 19:43
,
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/342

윈도우 부팅시 Break Point걸기

부팅시에 로드되는 드라이버의 driverentry에 브레이크포인트를
걸기위해 고생하신적있나요?.... 간단하지만
알아두면 유용합니다. 메뉴에서 아래부분을 찾아보세요....

DEBUG->Kernel Connection->Cycle Initial Break[Ctrl+Alt+K]

한번 누를때마다 아래와 같은 메세지가 나타나면서
기능이 설정됩니다.

Will breakin on first symbol load at next boot. -> 다음 부팅시 심볼이 처음로드될때 break 를 겁니다.
Will NOT breakin at next boot. -> 부팅시 break point 걸기를 해제합니다.
Will request initial breakpoint at next boot. -> 다음 부팅시 윈도우가 시작하자마자 break 를 겁니다.

즉.. 부팅시 로드되는 드라이버의 driverentry에 bp를 걸기위해서는(start=0인 드라이버인경우특히
이기능이 필요) 부팅후 초기화시 자동으로 브레이크 포인트를 걸게하고요(위와 같은 방법으로요)
브레이크 포인트가 걸렸을때, 자기가 원하는 드라이버에 bp를 걸어주시면
됩니다...

전 이거 몰라서 꽤나 고생했네요..^^


출처 : 드라이버 온라인

Posted by 혁쌈

2007/12/22 19:42 2007/12/22 19:42
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/327

Windows Driver Foundation(WDF) - 한국어

출처 : http://www.microsoft.com/whdc/driver/wdf/default.mspx


Windows Driver Foundation(WDF)


WDF를 사용하면 OS가 아닌 디바이스 장치에 중점을 두고 개발할 수 있다.

WDF는 몇가지 드라이버 검증 툴을 통해서 커널 모드와 사용자 모드 드라이버의 개발을 위한 프레임워크를 포함하고 있다.


Kernel-Mode Driver Framework(KMDF)


KMDF는 커널 모드 드라이버에 필요한 기본적인 기능을 구현하고 있다. 다음을 포함한다:


. PnP와 전원 관리

. I/O 큐

. Direct memory access (DMA)

. Windows management instrumentation (WMI)

. Synchronization


각 윈도우즈 버전에 적합한 프레임워크에 대부분의 소스 코드가 있기 때문에, KMDF 드라이버는 최소한의 소스 코드만을 필요로 한다. 드라이버는 다음을 지원하기 위한 코드가 있다:


. 디바이스가 response해야하는 이벤트

. 디바이스에 고유한 기능


User-Mode Driver Framework(UMDF)

UMDF는 프로토콜 기반 디바이스 혹은 시리얼 버스 기반 디바이스를 지원하는 user-mode 드라이버의 작성을 지원한다. 이런 드라이버는 커널 모드 드라이버와 동일한 타입의 I/O를 처리하고 커널 모드 드라이버와 동일하게 INF 파일로 설치된다.


사용자 모드에서 작동하는 드라이버는 사용자 주소 영역에 대한 접근 권한만을 가진다 따라서 커널 모드 드라이버 보다 시스템 보안과 안정성에 대한 낮은 리스크를 가진다. 사용자 모드 드라이버는 커멀 모드 드라이버와 거의 동일한 성능을 가지며 여러가지의 장점이 있다:


. 쉬운 드라이버 환경

. 높은 안정성과 보안성

. Win32 API 사용

. 사용자 모드 디버거를 이용한 디버깅

. C++ 프로그래밍

. 빠른 코드 생성


사용자 모드 드라이버가 할 수 없는 일:

. 인터럽트 처리

. 하드웨어 직접 접근

. 정확한 타이밍 루프 사용

. 커널 모드 리소스 사용


Architecture of the Windows Driver Foundation


이 글의 목적은 윈도우즈 OS 패밀리를 위한 차세대 드라이버 모델인 WDF에 대한 정보를 제공하는 것이다. WDF에 대한 전체적인 아키텍처를 기술하고 드라이버 개발 시간을 줄이고, 시스템 안정성을 높이고 드라이버 진단성과 서비스 능력을 개선할 수 있는 방법을 설명한다. WDF에 생소한 기술 관리자, 아키텍처, 드라이버 설계자를 위해 작성되었다.


다음의 OS에 적용된다:

MS Vista

MS Server 2003

MS XP

MS 2000


이 문서에 있는 정보:

. WDF의 디자인 목적

. WDF에서의 디바이스와 드라이버 지원

. WDF 드라이버 모델

. WDF 객체 모델

. PnP와 전원 관리 지원

. I/O 모델

. 드라이버 프레임워크

. 개발과 테스팅 툴

. serviceability and versioning

. 다음 단계



Windows Driver Foundation (WDF)

WDF defines a single driver model that supports the creation of object-oriented, event-driven drivers for either kernel mode or user mode. It simplifies driver development and maintenance by:

Implementing common features.

Providing intelligent defaults.

Managing most interactions with the operating system.

With WDF, driver writers can focus on their device hardware, rather than on the operating system.

WDF includes frameworks for the development of kernel-mode and user-mode drivers along with several driver verification tools.

Download the KMDF. KMDF 1.1 is now available for download. More

Tip: See the video presentations from Driver DevCon and other tips & tricks at Notes from Windows Development Teams.

Kernel-Mode Driver Framework (KMDF)
KMDF implements the fundamental features required for kernel-mode drivers.

User-Mode Driver Framework (UMDF)
UMDF supports the development of user-mode drivers for device classes such as cameras and portable music players that are based on protocol or serial buses.

WDF Driver Verification Tools
WDF includes a built-in verifier along with two rule-based static verification tools: PREfast and Static Driver Verifier (SDV).

WDF Overview

White PaperArchitecture of the Windows Driver Foundation/
White PaperFAQ: Questions from Driver Developers about Windows Driver Foundation/
White PaperIntroduction to the Windows Driver Foundation/
White PaperWindows Driver Foundation Facts/
Microsoft Powerpoint (.ppt)Windows Driver Foundation: An Introduction [WinHEC 2005; 689 KB]/

WDF Beta Program

White PaperWindows Driver Foundation Beta Program Invitation/

Windows Driver Foundation Notes

Microsoft Powerpoint (.ppt)How to Develop a KMDF Driver [517 KB]/
Microsoft Powerpoint (.ppt)How to Develop a UMDF Driver [1.4 MB]/
Microsoft Powerpoint (.ppt)How to Port WDM Drivers to KMDF [749 KB]/
Microsoft Powerpoint (.ppt)Introduction to User-Mode Driver Framework [536 KB]/
Windows MultimediaHow to Develop a KMDF Driver: Part 2/
Windows MultimediaHow to Port a WDM Driver to the KMDF: Part 1/
Windows MultimediaHow to Port a WDM Driver to the KMDF: Part 2/

Articles on WDF

This link leaves the Microsoft.com siteDefensive Drivers - DevSource by Ziff Davis Media/
This link leaves the Microsoft.com siteNT Insider Interviews Jake Oshins on WDF PnP/Power (subscription required)/

Posted by 혁쌈

2007/09/29 04:40 2007/09/29 04:40
,
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/309

USB 드라이버 이렇게 구성한다.(1)

1. USBDI / USBDI IOCTL / URB

USBDI
USB를 지원하는 클래스 드라이버는 uhcd.sys, usbd.sys, usbhub.sys, usbui.sys로 구성되어 있으며 작성된 USB 드라이버와 가장 깊은 관계를 가진 드라이버는 usbd.sys이다. 이 드라이버가 USB 디바이스와 통신하는 기본 코드를 갖고 있다. 간단히 생각하면 USB 디바이스는 엔드포인트(endpoint)라는 다수의 논리적인 포트를 갖고 있으며 최하위 클래스 드라이버는 실제 포트와 맞물려 C 언어의 inp()나 outp()와 같은 최소 기능만 가진 라이브러리와 비슷하다.

USBDI IOCTL
드라이버 간에 내부 데이터 교환은 클래스 드라이버에 정의된 IOCTL을 사용한다. 이를 잊지 말기 바란다. USB 뿐만 아니라 다른 디바이스 관련 드라이버도 마찬가지이다. 제일 먼저 도움말에서 찾을 내용은 클래스 드라이버가 제공하는 IOCTL과 해당 IOCTL이 하는 일에 관련된 것으로, <표 1>에서 USB 클래스 드라이버가 제공하는 IOCTL을 살펴보기 바란다.

<표 1> USBDI 내부 IOCTL

IOCTL

설명

IOCTL_INTERNAL_USB_SUBMIT_URB

클래스 드라이버에 작업을 요청하고 결과를 기다린다.

IOCTL_INTERNAL_USB_RESET_PORTUSB

포트 재초기화

IOCTL_INTERNAL_USB_GET_PORT_STATUS

현재 포트의 상태를 얻어온다. 리턴값은 다음과 같다.
USBD_PORT_ENABLED
USBD_PORT_CONNECTED

IOCTL_INTERNAL_USB_ENABLE_PORT

포트를 활성화한다.

IOCTL_INTERNAL_USB_GET_HUB_NAME

USB 허브의 이름을 얻는다.

IOCTL_INTERNAL_USB_GET_BUS_INFO

USB 버스 정보를 얻는다. 버스 정보는 USB_BUS_NOTIFICATION 구조체에 채워진다.

URB
찾아낸 IOCTL을 다음 드라이버에 어떻게 전송할 것인가? 또한 <표 1>에 다뤄진 IOCTL만으로도 USB 드라이버와 모든 일을 처리할 수 있는가? 사실 <표 1>의 IOCTL을 전부 사용하지 않으며 주로 IOCTL_INTERNAL_USB_SUBMIT_URB를 IRP로 포장해 하위 드라이버에 전송한다.

USB 클래스 드라이버에 전달하기 위해 필요한 것은 다음과 같다.

① IRP를 생성한다. 상위 계층에서 내려오는 것이 아니며 현재 드라이버에서 하위 드라이버에 요청하므로 새로운 IRP를 생성해 전달시켜야 한다.
② 새로 생성한 IRP에는 하위 드라이버가 처리 가능한 정보를 담아야 한다. 다시 말해 IRP 형태가 하위 드라이버의 요구 형태에 맞춰져야 한다는 의미이다.

하위 드라이버가 처리할 수 있는 데이터 포맷은 미리 정의되어 있으며 각 디바이스마다 별개로 존재한다.

URB(USB Request Packet)는 USB 클래스 드라이버가 처리하는 패킷 포맷이다(DDK에서 패킷이라고 강조하므로 같은 말을 사용했다). 데이터 입출력과 상태 확인, 디스크립터 처리를 위한 많은 구조체를 유니언 형태로 내포하며 적당히 캐스팅해 사용하면 된다. 이와 비슷한 경우로 IEEE 1394에는 하위 드라이버에 작업 요청을 하기 위해 IRB를 사용한다. IRB에 대해 자세히 알고 싶으면 DDK 도움말을 참조하도록 하자.

디바이스에 직접 명령을 내리는 방법은 IRP를 새로 만들어 DriverObject를 생성할 때 저장한 하위 DriverObject에 IRP를 전달하고 처리 결과를 기다리는 것이다. 다만, 처리를 맡기는 대신 응답이 오지 않을 때에 대비해 이벤트를 설정하고 응답이 없을 경우 작업을 취소할 수 있도록 해야 한다.

IRP는 용도에 따라 생성하는 커널 모드 함수가 많다. 그 중 IOCTL을 기반으로 요구 패킷을 생성하는 IoBuildDeviceIoControlRequest()를 사용해 IRP를 만들어야 한다. 이 함수는 IOCTL, 하위 드라이버 포인터, 입출력 버퍼 인자 등을 받아들이지만 입출력 버퍼 인자는 사용할 필요가 없으니 값을 null로 넘겨준다. 그리고 하위 드라이버에 전달할 URB를 어딘가에 넣어야 하는데 USB의 내부 IOCTL은 STACK LOCATION의 입출력 버퍼를 사용하지 않는 대신 Paramters.Others.Argument1 멤버에 URB 포인터를 넣도록 되어있다. 주의하기 바란다.

<리스트 1>의 call_usbd()는 USB 드라이버에서 가장 많이 사용되는 함수이다. 이 함수는 URB를 다음 드라이버에 전송하고 그 결과가 나올 때까지 기다렸다가 결과값을 리턴하는 역할을 한다.

<리스트 1> call_usbd()의 예
NTSTATUS call_usbd (IN PDEVICE_OBJECT fdo, IN PURB p_urb)
{
  NTSTATUS status = STATUS_SUCCESS;
  PDEVICE_EXTENSION p_dev_ext;
  PIRP irp;
  c_event event;

  IO_STATUS_BLOCK io_status;
  PIO_STACK_LOCATION next_stack;

  p_dev_ext = get_device_extension (fdo);

  event.init ();

  // 1) IRP 생성
  irp =
     IoBuildDeviceIoControlRequest (
        IOCTL_INTERNAL_USB_SUBMIT_URB,
        p_dev_ext->next_stack_driver,
        NULL,
        0,
        NULL,
        0,
        TRUE,
        event,
        &io_status );

  next_stack = IoGetNextIrpStackLocation (irp);
  ASSERT (next_stack != NULL);

  // 2) IRP에 URB 포함시킨다.
  next_stack->Parameters.Others.Argument1 = p_urb;

  // 3) 다음 드라이버에 IRP를 전달한다.
  status = IoCallDriver (p_dev_ext->next_stack_driver, irp);

  // 결과를 기다린다.
  if (status == STATUS_PENDING)
     status = event.wait (Suspended, KernelMode, FALSE);
  else
     io_status.Status = status; // 완료

  status = io_status.Status;

  // 4) 결과값 리턴
  return status;
}

2. USB 디바이스의 설정

첫회에서 디바이스의 실제 제어는 메이저 IRP, IRP_MJ_PNP에서 처리한다고 설명했다. 드라이버 동작 후 실제 디바이스 인식은 IRP_MJ_PNP 메이저의 IRP_MN_START_DEVICE에서 처리하며, 이것이 보통 NT 드라이버와 다른 점이기도 하다.

디바이스의 설정, 무엇을 해야 하는가?
먼저 작성할 소스 코드를 차례대로 정리해 보겠다. 미리 이야기하는 것이지만 윈도우의 공통 컨트롤에서 값을 얻어와서 이를 다시 설정하는 과정과 흡사하다.

① USB 클래스 드라이버를 통해 디바이스 디스크립터를 얻어온다. 성공하면 DEVICE_EXTENSION에 디스크립터의 포인터를 저장한다.
② 컨피규레이션(configuration) 디스크립터를 요청해 얻어온다.
③ 컨피규레이션 디스크립터를 사용해 인터페이스 리스트를 가져온다. 이 인터페이스 리스트를 다시 재해석하도록 요청해 사용 가능한 인터페이스 리스트를 구한다.
④ 정해진 스펙 이외의 지정할 내용, 예를 들어 최대 전송량을 설정해야 한다면 이때 인터페이스를 차례로 검색하면서 값을 설정한다.
⑤ 재설정된 디스크립터를 디바이스에 적용하도록 요청한다.
⑥ DEVICE_EXTENSION에 값을 저장한다.

④ 과정에서 디스크립터에 값을 설정하는 것을 제외하면 하위 드라이버에 요청해 디스크립터를 얻어다 다시 디바이스에 설정하는 것을 반복했을 뿐이다. ④ 과정에서 인터페이스에 값을 다시 넣지만 보통의 디바이스에서는 생략해도 무방하며, 앞서 반복해 이야기했지만 USB는 실제 뭔가를 설정하는 것이 아니며 확인하는 것이 초기화 과정의 전부이다.

사용하는 함수는?
DDK가 제공하는 USB 관련 함수는 주로 어떤 일을 할까? 보통 클래스 드라이버에 작업을 요청하기 위해 필요한 IRP를 생성하는 것이 전부이다. <표 2>의 함수 이름을 눈여겨보기 바란다. 모든 함수 이름에 'Build'와 'Request'가 포함되어 있는데, 이는 특정 작업을 요청하기 위한 IRP를 생성해 달라는 의미이다. 강조하지만 NT 드라이버는 직접 값을 읽어오지 않는다. 대신 디바이스와 직접 통신하는 클래스 드라이버에게 뭔가를 요청하고 그 결과를 받아 사용한다.

<표 2> USB 주요 함수

함수명

설명

UsbBuildGetDescriptorRequest

디스크립터를 얻는 Request 패킷 생성

UsbBuildGetInterruptOrBulkTransferRequest

데이터 전송 Request 패킷 생성

UsbBuildGetSelectConfigurationRequest

컨피규레이션 디스크립터 선택 Request 패킷 생성

UsbBuildSelectInterfaceRequest

인터페이스 선택 Request 패킷 생성

UsbBuildVenderRequest

OEM 작업 Request 패킷 생성

DDK의 USB 예제에는 디바이스 시작/초기화 과정을 3개 함수, 즉 StartDevice(), ConfigureDevice(), SelectInterface()로 나눠 실행한다. 한 함수에 묶는 것도 상관없지만 3가지로 나누도록 작성하는 것이 무리없을 듯 하다.

<리스트 2>는 일반적인 USB라면 전부 실행 가능한 초기화 코드를 나타냈다. 앞에서 설명한 내용과 비교하기 바란다. <리스트 2>의 내용이 이해되면 DDK의 USB 예제 중 bulk와 isochronous 예제에서의 디바이스 초기화 부분도 꼭 한 번 볼 것을 권한다.

<리스트 2> USB 디바이스 설정때 사용하는 함수
//
// IRP_MJ_PNP - IRP_MN_START_DEVICE에서 호출되며 USB 디바이스를 초기화한다.
//
NTSTATUS start_device (IN PDEVICE_OBJECT fdo)
{
  PDEVICE_EXTENSION dev_ext;
  PUSB_DEVICE_DESCRIPTOR p_usb_dev_desc = NULL;
  PURB p_urb = NULL;

  NTSTATUS nt_status;
  ULONG siz;

  trace ("ENTER start_device\n");

  dev_ext = get_device_extension (fdo);

  // 디스크립터를 얻기 위한 URB를 생성한다.
  p_urb =
     (PURB) new (NonPagedPool) struct _URB_CONTROL_DESCRIPTOR_REQUEST;

  if (p_urb)
  {
     siz = sizeof(USB_DEVICE_DESCRIPTOR);

     p_usb_dev_desc =
        (PUSB_DEVICE_DESCRIPTOR) new (NonPagedPool) USB_DEVICE_DESCRIPTOR;

     if (p_usb_dev_desc)
     {
        UsbBuildGetDescriptorRequest (
           p_urb,
           (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
           USB_DEVICE_DESCRIPTOR_TYPE,
           0,
           0,
           p_usb_dev_desc,
           NULL,
           siz,
           NULL );

       
// USB 클래스 드라이버에게 디스크립터를 얻어줄 것을 요청했다.
        nt_status = call_usbd(fdo, p_urb);
     }
     else
     {
        nt_status = STATUS_INSUFFICIENT_RESOURCES;
     }

     // 성공했으므로 정보를 저장한다

     if (NT_SUCCESS(nt_status))
        dev_ext->usb_device_descriptor = p_usb_dev_desc;
     else
        delete p_usb_dev_desc;

      delete p_urb;
  }
  else
     nt_status = STATUS_INSUFFICIENT_RESOURCES;

  // 디바이스 설정에 나선다
 
 
if (NT_SUCCESS(nt_status))
     nt_status = configure_device (fdo);

  if (NT_SUCCESS(nt_status))
  {
     dev_ext->f_device_started = TRUE;
     dev_ext->f_device_removed = FALSE;
  }

  return nt_status;
}

//
// 디바이스 설정보다는 설정값을 얻어내는 것이 하는 일의 전부다.
//

NTSTATUS configure_device (IN PDEVICE_OBJECT fdo)
{
  NTSTATUS nt_status  = STATUS_SUCCESS;
  PURB p_urb          = NULL;

  PDEVICE_EXTENSION dev_ext;
  ULONG siz;

  trace ("----------------------\n");
  trace ("ENTER configure_device\n");

  dev_ext = get_device_extension (fdo);
 
 
p_urb =
     (PURB) new (NonPagedPool) struct _URB_CONTROL_DESCRIPTOR_REQUEST;
  if (! p_urb)
     return STATUS_INSUFFICIENT_RESOURCES;
 
 
siz = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 512;  
 
 
while( 1 )
  {
     dev_ext->usb_conf_desc =
        (USB_CONFIGURATION_DESCRIPTOR*) new (NonPagedPool) CHAR[siz];
   
    
if (! dev_ext->usb_conf_desc)
     {
        delete p_urb;
        return STATUS_INSUFFICIENT_RESOURCES;
     }
   
    
UsbBuildGetDescriptorRequest (
        p_urb,
        (USHORT) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST),
        USB_CONFIGURATION_DESCRIPTOR_TYPE,
        0,
        0,
        dev_ext->usb_conf_desc,
        NULL,
        siz,
        NULL );
   
    
nt_status = call_usbd (fdo, p_urb);
   
    
if (p_urb->UrbControlDescriptorRequest.TransferBufferLength > 0 &&
        dev_ext->usb_conf_desc->wTotalLength > siz)
     {
        siz = dev_ext->usb_conf_desc->wTotalLength;
        delete dev_ext->usb_conf_desc;
        dev_ext->usb_conf_desc = NULL;
     }
     else
        break;  // we got it on the first try
   
 
} // while(retry loop)
 
 
delete p_urb;
 
 
//
  // 인터페이스 설정
  //
 
 
nt_status = select_interface (fdo, dev_ext->usb_conf_desc );
 
 
return nt_status;
}

//
// 인터페이스를 얻어내고 필요한 설정을 변경하고 다시 디바이스에 설정한다.
// 그러나 변경이 거의 없다.
//

NTSTATUS
select_interface (
  IN PDEVICE_OBJECT fdo,
  IN PUSB_CONFIGURATION_DESCRIPTOR conf_desc
)
{
  NTSTATUS nt_status = STATUS_SUCCESS;

  PURB p_urb = NULL;
  PUSB_INTERFACE_DESCRIPTOR interface_desc = NULL;
  PUSBD_INTERFACE_INFORMATION interface = NULL;

  PDEVICE_EXTENSION dev_ext;
  ULONG i;
  USHORT siz;
 
 
trace ("ENTER select_interface\n");
 
 
dev_ext = get_device_extension (fdo);

  p_urb = USBD_CreateConfigurationRequest(conf_desc, &siz);

 
if (p_urb)
  {
     interface_desc =
        USBD_ParseConfigurationDescriptorEx (
           conf_desc,
           conf_desc,
           -1,        
          
-1,        
          
-1,        
          
-1,        
          
-1 );      
   
    
if (! interface_desc)
     {
        delete p_urb;
        return STATUS_INSUFFICIENT_RESOURCES;
     }
   
    
interface = &p_urb->UrbSelectConfiguration.Interface;
       
    
for (i=0; i< interface->NumberOfPipes; i++)
     {
        //
        // 인터페이스를 변경하고 싶다면 이곳에서 한다. 그러나 생략해도 무방
        //
     }

     UsbBuildSelectConfigurationRequest (
        p_urb,
        (USHORT) siz,
        conf_desc );

     nt_status = call_usbd (fdo, p_urb);

     dev_ext->usb_conf_handle =
        p_urb->UrbSelectConfiguration.ConfigurationHandle;

  }
  else
  {
     nt_status = STATUS_INSUFFICIENT_RESOURCES;
  }

  if (NT_SUCCESS(nt_status))
  {

     //
     // configuration handle을 보관한다.
     //
   
    
dev_ext->usb_conf_handle =
        p_urb->UrbSelectConfiguration.ConfigurationHandle;

     dev_ext->usb_interface =
        (USBD_INTERFACE_INFORMATION*) new (NonPagedPool)
        unsigned char[interface->Length];

     if (dev_ext->usb_interface)
     {
        ULONG j;
     
       
//
        // DEVICE_EXTENSION에 인터페이스를 보관한 후에 입출력할 때 사용한다.
        //
        RtlCopyMemory (
           dev_ext->usb_interface,
           interface,
           interface->Length);
     }
  }
 
 
if (p_urb) delete p_urb;

  return nt_status;
}

3. INF 구성과 작성

INF는 설치에 관련된 모든 정보를 담고 있는 배치 파일이다. 설치할 파일, 위치, 변경 혹은 추가할 레지스트리까지 하나의 파일에 모두 담는다. 또한 드라이버뿐만 아니라 일반 애플리케이션도 간단히 설치할 수 있도록 구성할 수 있다. 공개 프로그램인 ezpad는 INF 파일로 설치할 수 있도록 구성되어 있는 것으로 알고 있다. INF는 INI와 마찬가지로 섹션과 하부 엔트리 설정값으로 구성되어 있다. 섹션 문자열은 '[', ']'에 들어있고 하부 설정값은 항목 이름에 값을 대입하는 형식을 취한다. 주석은 INI와 마찬가지로 ';'를 사용한다.

INF는 최소한 16개 섹션을 갖게 된다. 설치 정보를 윈도우 95/98과 윈도우 NT/2000에 대해 별도로 갖고 있어야 하므로 별로 복잡하지도 않다. 자세한 내용을 알고 싶은 독자는 MSDN에서 INF 키워드로 검색하거나 비주얼 C++ 도움말에서 검색해 읽어보기 바란다. 한 페이지에 전부 설명되어 있지 않고 여러 갈래로 나눠져 설명되어 있다. 여기에서는 드라이버 설치에 필요한 것만 알아보고 넘어가겠다.

Strings 섹션
INF에서 사용할 문자열을 미리 정의한 부분으로, 별도로 문자열 섹션을 둔 이유는 한 가지 언어에 제한되지 않도록 하기 위함이다. 엔트리 이름에는 '.'이나 공백을 넣을 수 있으므로 이름을 지을 때 무척 자유롭다. DDK 예제에서는 제품명이나 제작사 이름, 문자열 이름 사이에 점을 넣어 구분해 사용한다. 이 섹션은 보통 INF의 제일 마지막에 위치한다.

[Strings]
WdmFrame.DeviceDesc="WDM Frame Device"
WdmFrame.ClassName="WDM Frame Device"
; ···

"WdmFrame.ClassName"이 엔트리명이며 그 뒤의 문자열이 정의할 값이다. 정의된 문자열을 "%문자열정의명%" 형식으로 사용한다. 문자열 "WDM frame Device"를 사용하려면 다음부터는 %WdmFrame.ClassName%을 적어주면 된다.

Version 섹션
모든 INF 파일에 공통으로 들어가는 섹션으로, 다음과 같은 하부 엔트리로 구성되어 있다.

◆ Signature : 설치할 운영체제를 명시한다. $Windows NT$, $Chicago$, $Windows 95$ 중에 하나만 적어야 한다. 대소문자를 가리므로 틀리지 않도록 하자. 윈도우 95/98과 2000에서 모두 사용하기 위해서는 어느 하나만 적기 곤란한데 $Windows NT$만 사용해도 별 문제가 없었다.
◆ Class : 드라이버 종류를 써줘야 하며 여기에서는 USB라고 적었다. 다른 값은 DDK 도움말에서 찾을 수 있다.
◆ ClassGUID : GuidGen.exe로 생성한 guid를 기록한다.
◆ Provider : INF 파일 작성자 이름이나 드라이버 제작사의 이름을 적어준다. String 섹션에 미리 정의하고 해당 엔트리로 대체한다.

Manufacturer 섹션
하위 섹션에 영향을 주는 섹션이다. 잠시 후에 참조 관계를 다루니 이 정도만 알고 넘어가자. 여기부터 설치 정보가 시작된다.

%WdmFrame.Manufacturer%=WdmFrame

SourceDisksNames 섹션
설치할 때 사용할 타이틀과 파일 위치를 기록한다. 파일 위치는 어디나 명시할 수 있지만 굳이 정하지 않아도 문제가 없다. 따라서 타이틀만 기록하고 나머지는 생략한다. 사용한 엔트리 이름은 다음 섹션인 SourceDisksFiles 섹션에서 참조한다. 엔트리 이름은 설치할 디스켓의 번호로, 작성자가 임의로 결정할 수 있다.

[SourceDisksNames]
1="WDM frame driver installation diskette","",,

SourceDisksFiles 섹션
복사할 파일을 적는다. 엔트리명은 해당 디스켓에 들어있어야 할 파일명이고 엔트리값은 SourceDisksNames 섹션에서 사용한 엔트리명이다. 다음 예와 앞의 예를 눈여겨보기 바란다.

[SourceDisksFiles]
WdmFrame.sys=1

DestinationDirs 섹션
파일이 복사될 위치를 정한다.

[DestinationDirs]
파일 리스트 섹션 = drid [,subdir]

이 섹션의 엔트리도 다른 섹션이 참조하는데 파일 리스트 섹션의 이름으로는 Copy Files, Rename Files, Delete Files 중 하나가 올 수 있다. 해당 섹션이 처리할 파일을 여기에 기록하는 것이다. drid에는 미리 정의된 위치값을 적으며 <표 3>에 나오는 값 중 하나를 사용한다. 많지는 않지만 전부 필요없을 것 같아 중요한 몇 가지만 적었다. 목록 전부를 보기 위해서는 MSDN에서 DestinationDirs로 정리된 도움말을 참조하자.

<표 3> DestinationDirs 섹션의 값

해당 위치

0xFFFF

INF가 위치한 현재 디렉토리

10

Windows 디렉토리

11

Windows 시스템 디렉토리(윈도우 95/98에서 %windir%\system, 윈도우 NT에서 %windir%\system32)

12

드라이버 디렉토리(윈도우 NT의 %windir%\system32\drivers)

30

부팅 파티션의 루트

INF 참조 관계
INF를 이해하려면 어디서 무엇을 참조해야 할까? 무엇이 어디에 포함되는지 이해하면 된다. 다음은 INF 섹션 간에 참조 관계에 포함되는 순서대로 적어놓았다. Manufacturer가 시작되며 참조 문자열의 시작이다. 참조의 기본 원칙은 상위 섹션의 엔트리값이 다음 하위 섹션의 이름이 된다는 것이다.

[Version]
[Strings]
[SourceDisksNames]
[SourceDisksFiles]
[DestinationDirs]

[Manufacturer]
                  Nobody Make=Nobody.Make
                                     [Nobody.Make]
                                     Driver 1=Driver1.Install,ID
                                                        [Driver1.Install]
                                                        CopyFiles=Driver1.CopyFiles
                                                        AddReg=Driver1.AddReg
                                                                           [Driver1.CopyFiles]
                                                                           ; ···
                                                                           [Driver1.AddReg]
                                                                           ; ···

INF 간단히 작성하기
윈도우 2000의 DDK에는 INF 작성을 도와주는 유틸리티인 GetInf.exe가 들어있지만 필자는 이 유틸리티를 사용하는 것보다는 예제 INF를 복사해 편집하는 것이 편했다. 사람마다 다를 수 있으니 자세한 것은 직접 실행해 확인하도록 한다. 이 유틸리티는 위저드 방식으로 실행되므로 차례대로 요구하는 값을 입력하면 INF를 생성해준다. <리스트 3>은 완전한 형태의 INF 예제이다. 앞과 뒤의 참조 관계를 확인하면서 읽어보기 바란다.

<리스트 3> INF의 예
; ---------------------------------------------------------------
; WDMFrame.sys를 설치하기 위해 작성한 INF
; ---------------------------------------------------------------

[Version]
Signature="$Windows NT$"
Class=USB
ClassGUID={A0401445-5366-11d3-AC7C-00A0C93E77E4}
Provider=%WdmFrame.Provider%

[Manufacturer]
%WdmFrame.Manufacturer%=WdmFrame

[ClassInstall32]
AddReg=WdmFrame.AddClassReg

[WdmFrame]
%WdmFrame.DeviceDesc%=WdmFrame.Install, USB\VID_04B4&PID_0002

[SourceDisksNames]
1=%WdmFrame.DriverDiskName%,"",,

[SourceDisksFiles]
WdmFrame.sys=1

[PreCopySection]
HKR,,NoSetupUI,,1

[DestinationDirs]
WdmFrame.CopyFiles = 10,system32\drivers

[WdmFrame.Install]
CopyFiles=WdmFrame.CopyFiles
AddReg=WdmFrame.AddReg

[WdmFrame.AddClassReg]
HKR,,,,%WdmFrame.ClassName%

[WdmFrame.AddReg]
HKR,,DevLoader,,*ntkern
HKR,,NTMPDriver,,WdmFrame.sys

[WdmFrame.CopyFiles]
WdmFrame.sys

;
; WinNT area
;

[WdmFrame.Install.NT]
CopyFiles= WdmFrame.CopyFiles
AddReg = WdmFrame.AddReg

[WdmFrame.AddReg.NT]

[WdmFrame.Install.NT.Services]
AddService = WdmFrame,0x00000002,WDM_Frame_Service_Inst,

[WDM_Frame_Service_Inst]
ServiceType = 1 ;%SERVICE_KERNEL_DRIVER%
StartType = 3 ;%SERVICE_AUTO_START%
ErrorControl = 1 ;%SERVICE_ERROR_NORMAL%
ServiceBinary = %12%\WdmFrame.sys
DisplayName = %WdmFrame.DeviceDesc%

;---------------------------------------------------------------
; INF에서 사용할 문자열이 정의되어 있다
;---------------------------------------------------------------

[Strings]
WdmFrame.Provider="nobody"
WdmFrame.Manufacturer="nobody"
WdmFrame.DeviceDesc="WDM Frame Device"
WdmFrame.ClassName="WDM Frame Device"
WdmFrame.DriverDiskName="WDM frame driver installation diskette"

드라이버 설치
드라이버 설치 화면은 윈도우 NT/2000과 윈도우 95/98이 서로 다르지만 내용은 거의 같으므로 여기에서는 윈도우 95/98을 기준으로 설명한다. 윈도우 NT/2000에서 드라이버를 동작시키기 위해서는 인내심이 필요한데 설치할 때마다 레지스트리를 검사하는 시간이 점점 늘어나기 때문이다. USB 디바이스를 PC에 연결하면 '새로운 디바이스 발견'했다는 메시지가 나타나고 이어 하드웨어 추가 마법사가 시작된다. <화면 1>에서 '알 수 없는 디바이스'라고 나타난 이유는 USB 컨트롤러에 디바이스 이름이나 회사에 관한 정보를 넣지 않았기 때문이다.


<화면 1> USB 디바이스 검색

지금 사용하는 USB 디바이스는 윈도우 95/98의 기본 목록에 없는 것이므로 직접 검색한다. '검색할 위치 지정'을 선택하고 드라이버가 있는 위치를 선택한다. 이후부터는 '다음'을 선택하는 것으로 드라이버 설치를 마칠 수 있다. 설치를 마치면 <화면 2>와 같이 INF에 적힌 문자열을 참조해 다이얼로그박스에 나타내 주었다.


<화면 2> USB 디바이스 설치 완료

4. 드라이버 제거 / 무뎌지면 편하다

드라이버 제거
드라이버는 레지스트리의 드라이버 정보와 설치할 때 시스템 폴더에 복사된 INF 파일, 해당 드라이버 파일을 삭제해야 한다. 개발 시에는 약간 번거롭지만 한 번 설치해 놓고 드라이버 파일만 교체해 사용할 수도 있다.

윈도우 95/98에서 드라이버 제거
정상적으로 설치된 레지스트리의 드라이버 정보는 HKEY_LOCAL_MACHINE\Enum\USB\ 아래에 서브키로 vid와 pid로 만들어진 문자열을 갖고 있다. 삭제하려면 해당 디바이스의 서브키를 삭제한다. 그리고 HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Setup\SetupX \INF\OEMName에는 설치된 드라이버에 관련된 INF 목록이 있다. 여기에서 해당되는 INF 파일을 삭제하면 된다. 또한 %WINDOWS%\INF\OTHER에 있는 INF 파일도 같이 삭제해야 한다. 만약 이 파일을 삭제하지 않으면 다음 디바이스가 인식될 때 드라이버를 자동으로 설치하므로 잊지 말아야 한다. INF의 파일명은 '회사명 + 원래이름.INF' 형태로 구성되어 있다.

윈도우 2000에서의 드라이버 제거
윈도우 2000에서는 사용자마다 레지스트리 접근 권한이 다르므로 administrator 계정으로 로그인해야 하며 regedit.exe 대신 regedt32.exe를 실행해 불필요한 레지스트리 정보를 삭제해야 한다. 그런데 administrator라 해도 레지스트리의 서브키를 함부로 삭제할 수 없다. 따라서 regedt32.exe의 security 메뉴를 통해 삭제하려는 레지스트리 키에 읽고 쓸 수 있는 권한을 준 다음 삭제해야 한다. 삭제할 위치는 HKEY_LOCAL_MACHINE\SYSTEM\ControlSet\Enum\USB이며 하위 키 중에서 자신의 드라이버를 찾을 수 있을 것이다.

INF를 삭제하려면 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup에서 드라이버의 INF 항목을 삭제한 다음 시스템 폴더인 %WINDOWS%\INF에서 설치할 때 사용한 INF를 지워야 한다. 그런데 여기에는 이름이 다르게 저장되어 있을 것이다. 많은 INF 중에서 oem?.inf가 있는데 이것을 하나씩 열어보고 자신이 사용한 INF를 찾아 지워줘야 한다. 마지막으로 당연히 sys 드라이버 파일도 삭제해야 한다.

무뎌지면 편하다
의의로 간단한 것에 놀라는 독자도 있을 것 같다. WDM은 기존 드라이버와 달리 쉽게 작성할 수 있도록 구성되었다. 다만 NT 드라이버에 대해 문외한이라면 익숙하지 않을 것인데, 이는 앞에서 말했듯이 무뎌지면 편해진다. USB 디바이스 인식과 설치 파일인 INF 작성에 대해 한회로 끝내기에는 아쉬움이 남는다. 다음호에는 USB로부터 값을 읽고 쓰는 방법에 대해 설명하도록 하겠다.d

Posted by 혁쌈

2007/06/05 03:26 2007/06/05 03:26
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/281

WinDbg 사용법

우선 Symbol File Path를 해당 드라이버에 맞는 경로를 지정해 주어야 합니다. Reload를 해주셔야 되고요.
그 후에 디버깅 중에 Break를 겁니다. 그럼 Break가 걸려서 멈추겠죠. 그때 Source File을 엽니다. Source Line중에서 브레이크 포인트 잡을 곳에 가서 F9(Break Point)를 잡습니다. 물론 bp 명령을 사용하셔도 됩니다. 그러면 뭐라고 알림창이 뜬 후에
Break Point 잡은 곳에 빨간 줄(?)이 그어집니다.
그 후에 F5(Go)를 하시거나 Trace(t 명령어나 F11)나 Step(p 명령어나 F10)등을 사용하시면 됩니다.
그러면서 Call Stack창을 띄워서 보시던지, Local View나 Watch View를 띄우시면 변수 값 변화및 스택(함수)변화 등을 보실 수 있습니다.

Posted by 혁쌈

2007/05/29 02:02 2007/05/29 02:02
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/279

USB(Universal Serial Bus)

저번 강의에 이어 PDIUSBD12의 내부를 들여다보기에 앞서 우리가 익숙해져야 할 USB에 관련된 용어들이 몇 개 있어서, 오늘은 그것들 먼저 좀 짚고 넘어가 보자.

먼저 Host(호스트).

한국말로 주인(장, 님,…),

단순 무식하게 말해서 PC를 말한다.

왜냐하면 PC의 메인보드(또는 PCI슬롯에 꽂혀있는 USB 컨트롤러 카드)에 USB HOST Controller가 있기 때문이다. 이 Host가 USB포트에 꽂혀 동작하는 모든 디바이스, 허브 등을 컨트롤 한다. 앞으로 USB로 데이터가 왔다 갔다 할 때, 그 전송방향을 말해야 한다면, 항상 호스트를 기준으로 말한다. 즉, 데이터가 디바이스에서 호스트로 전송된다면, 호스트 입장에서는 데이터가 들어오는 것이 되므로 “IN” Transaction(트렌젝션), 그 반대로 호스트가 데이터를 디바이스에게 전송할 때는 “OUT” Transaction, 요렇게 말한다.


Transaction이 뭐냐고?

USB Spec.을 보시라. 거기 자세히 설명되어 있다.

설마 USB 디바이스를 만들려고 하면서 USB 스펙 한번 들여다 볼 생각을 안하고 있는 행자는 없으리라 생각한다.


두번째, Endpoint(엔드포인트)

이 Endpoint가 우리가 실제로 데이터를 주고 받는 통로가 된다.

다른 말로 Pipe(파이프)라고도 한다.

(펌웨어 프로그래머들은 엔드포인트라 많이 부르고, 드라이버 프로그래머들은 파이프라고들 부르더라. 관점의 차이일 뿐, 같은 말이다.)

하나의 USB 디바이스는 여러 개의 Endpoint를 가질 수 있는데, 그렇다고 USB 케이블을 잘라보면 하나의 Endpoint(Pipe)에 대응하는 선들이 한 가닥씩 있느냐 하면, 그건 아니라고 봐요. 잘라봐라 네 가닥 밖에 없다. 전원선 두 가닥. 데이터선 두 가닥. 데이터 선이 두 가닥이니 Endpoint도 두 개까지 가질 수 있을까?

천만의 말씀 만만의 콩떡이다.

그 데이터 선 두 가닥도 사실은 위상이 반전된 동일한 신호를 전송하므로 사실상 데이터를 전송하는 통로는 하나뿐이다. (데이터를 외부 노이즈로부터 보호하기 위해 요렇게 한다. 유식한 사람들은 요렇게 위상이 반전된 신호를 보고 Deferential Signal 이라고 하더라.)

앞전에, USB 디바이스는 여러 개의 Endpoint를 가질 수 있다고 해 놓구서, 이제와서 데이터를 전송할 통로는 하나 뿐이라고 하니 헷갈린가? 그럴만하다. Endpoint는 약간 추상적인 개념이 들어가 있는 용어이다. 추상적이라고 하니 벌써 머리에 쥐난 행자들. 반갑다. 본좌도 “추상”자만 들으면 머리에 쥐날라 그런다.

우리가 USB 디바이스를 만들어 궁극적으로 하고자 하는 일이 뭔가? 이것 저것 종류는 많아도 결국은 바로 (윈도우) 어플리케이션과 통신을 하고자 함이다.

어떻게? ReadFile, WriteFile을 써서. 그 API들을 호출하기 전에 뭘 할까?

바로 CreatFile을 써서 File Handle을 먼저 얻어와야, 그 파일 핸들을 인자(Parameter)로 주어서 ReadFile등등을 호출해 써먹을 수 있다. 이 때 CreatFile을 호출해서 얻어오는 File Handle이 바로 Endpoint(Pipe)에 대한 핸들이다.


(대부분의 경우에…)



(그럴 일을 거의 없겠지만)

어플리케이션에서 한꺼번에 세 개의 File Handle에 읽고 쓰기를 동시에 해 버린다면? 그때는 데이터가 얽히고 설키는 게 아니라, USB 호스트 컨트롤더가 먼저 보낼 놈, 다음에 보낼 놈, 마지막에 보낼 놈, 등등 교통정리를 해서 보내면,

SIE(Serial Interface Engine)에서 차례차례로 들어오는 신호들을 받아서 각각의 Endpoint에 데이터가 도착했고, 또는 데이터가 보내졌음을 알린다.

정리하면,

엔드포인트(파이프)를 통해 데이터를 주고 받으며, 각각의 엔드포인트를 오가는 신호들은 시간대별로 쪼개져서 왔다 갔다 하기 때문에, USB 케이블의 데이터 선이 한 가닥만 있어도 되는 것이다. Endpoint는 이 통로를 통해 오가는 데이터의 성질에 따라 네가지 중 하나의 것으로 세팅할 수 있는데, 그것들이 각각

1. Control Endpoint

2. Interrupt Endpoint

3. Bulk Endpoint

4. Isochronous Endpoint 이다.

(물론 하드웨어의 설계에 따라 설정할 수 있는 엔드포인트가 제한된다. )

오늘은 그 중에서 Control Endpoint를 잠깐 언급하고 넘어가자.

Control Endpint는 주로 USB 디바이스에 간단한 명령을 하달하고 그 결과를 받기 위해 주로 사용한다. USB디바이스라면 Control Endpoint 중에서도 특별히 “Default” Control Endpoint(Endpoint “0”)만은 꼭 가지고 있어야 하는데, 이 Endpoint를 통해 호스트가 디바이스를 인식하고, 설정하기 때문이다. 그리고 이 Endpoint를 쓰면 간단한 데이터 전송 정도는 쉽게 할 수 있기 때문에 Endpoint 0만을 가지고 있는 디바이스들도 가끔 있다. 예를 들면, 단순히 LED를 키고,끄는 장치를 만드는 데는 다른 Endpoint가 필요가 없다.


Interrupt Endpoint는 일정한 시간 간격으로 전송되어야 할 비교적 소량의 데이터를 위한 것이고,


Bulk Endpoint는 많은 데이터를 오류 없이, 그리고 전송시간에도 구애 받지 않고 보내고자 할 때 쓴다.


Isochronous Endpoint는 전송시간이 중요한 데이터가 있다면 약간의 삑사리가 있더라도 감수하고 보내고자 할 때 쓴다. 즉 데이터 전송의 대역폭은 보장되지만, 데이터의 무결성은 보장하지 않는다

Posted by 혁쌈

2007/05/11 21:30 2007/05/11 21:30
,
Response
No Trackback , 3 Comments
RSS :
http://trlight.cafe24.com/tc/rss/response/273

Windows Driver Foundation (WDF)

 

Windows Driver Foundation (WDF)

WDF defines a single driver model that supports the creation of object-oriented, event-driven drivers for either kernel mode or user mode. It simplifies driver development and maintenance by:

Implementing common features.

Providing intelligent defaults.

Managing most interactions with the operating system.


With WDF, driver writers can focus on their device hardware, rather than on the operating system.

WDF includes frameworks for the development of kernel-mode and user-mode drivers along with several driver verification tools.

Tip: See the video presentations from Driver DevCon and other tips & tricks at Notes from Windows Development Teams.

Kernel-Mode Driver Framework (KMDF)
KMDF implements the fundamental features required for kernel-mode drivers. The KMDF 1.5 is provided as part of the current release of the Windows Driver Kit (WDK).

User-Mode Driver Framework (UMDF)
UMDF supports the development of user-mode drivers for device classes such as cameras and portable music players that are based on protocol or serial buses.

WDF Driver Verification Tools
WDF includes a built-in verifier along with two rule-based static verification tools: PREfast and Static Driver Verifier (SDV).

WDF Overview

Architecture of the Windows Driver Foundation

FAQ: Questions from Driver Developers about Windows Driver Foundation

Introduction to the Windows Driver Foundation

Versioning in the Windows Driver Foundation

Windows Driver Foundation Facts

Windows Driver Foundation: An Introduction [WinHEC 2005; 689 KB]

Windows Driver Foundation: A Syllabus [175 KB Word document]
A study guide for KMDF, UMDF, and Windows device driver concepts


WDF Beta Program

Windows Driver Foundation Beta Program Invitation


Windows Driver Foundation Notes

How to Develop a KMDF Driver [517 KB]

How to Develop a UMDF Driver [1.4 MB]

How to Port WDM Drivers to KMDF [749 KB]

Introduction to User-Mode Driver Framework [536 KB]

How to Develop a KMDF Driver: Part 2

How to Port a WDM Driver to the KMDF: Part 1

How to Port a WDM Driver to the KMDF: Part 2


Articles on WDF

Defensive Drivers - DevSource by Ziff Davis Media

NT Insider Interviews Jake Oshins on WDF PnP/Power (subscription required)

관련 링크 : http://www.microsoft.com/whdc/driver/wdf/default.mspx

Posted by 혁쌈

2007/04/02 18:30 2007/04/02 18:30
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/264

커널 디버거 설치

http://blog.naver.com/hellolee73?Redirect=Log&logNo=6288486

좋은내용.

Posted by 혁쌈

2007/03/31 17:52 2007/03/31 17:52
,
Response
No Trackback , No Comment
RSS :
http://trlight.cafe24.com/tc/rss/response/263


블로그 이미지

No pains, No gains.

- 혁쌈

Archives

Authors

  1. 혁쌈

Recent Trackbacks

  1. rjixambb rjixambb 10/30

Calendar

«   2009/11   »
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          

Site Stats

Total hits:
80138
Today:
7
Yesterday:
52