구리의 창고

USB 개념 본문

Window Driver

USB 개념

구리z 2010. 2. 18. 19:25

USB(Universal Serial Bus)의 개념

1. USB logical structure
ㆍEndpoint
- 각각의 device가 가지고 있는 하나 이상의 논리적인 connection point.
- 모든 device는 device의 제어와 확인에 사용되는 전송을 위한 Endpoint0를 가지고 있음.
- pipe : host와 device의 endpoint 사이의 connection.
- Default pipe : host USB system software와 device의 endpoint0 사이의 연결.
ㆍInterface
- 어떻게 software들이 hardware들을 접근할 것인가를 설명.
- host를 위해 device가 가지고 있는 일련의 endpoint들의 집합
- composite device : 하나 이상의 interface를 가지고 있는 device
ㆍConfiguration
- driver가 어떻게 동작할 것인가를 결정
- 하나 이상의 interface의 집합
- 오직 하나의 configuration이 한번에 active나 이 configuration에 속한 모든 interface나 endpoint들은 같은 시간에 active 됨.


2. Windows USB Driver Interface
ㆍUSB device는 kernel과 user application request에 응답하고 device와 통신하기 위하여 새로운 driver를 필요로 한다.
ㆍkernel level에서 명령어는 내부 IOCTL들을 사용하여 USB system에게 client driver에 의해 이슈화된다.
ㆍ대부분들의 IOCTL은 system USB driver에게 USB Request Blocks (URBs)를 이슈화하는 것을 허락한다.

3. Transfer Types
ㆍControl transfer
- 데이터의 비교적 적은 양을 받거나 보내기 위해 USB system과 client에 의해 사용되다.
- 데이터의 최대 전송 크기는 8, 16, 32, 64 bytes이다.
- USB에서 가장 높은 우선순위를 가진다.
- 각 device는 입출력 control transaction에 대한 응답으로서 endpoint0를 가지고 있다.
- endpoint0 가 모든 control request를 처리하기 때문에 이외의 endpoint는 필요로 하지 않는다.
- 데이터의 손실이 거의 없다. error가 발생했을 때 전송을 포기하기 전 3번까지 재전송을 시도하기 때문이다.
- 데이터의 전송은 SETUP packet을 가지고 시작
ㆍ Interrupt transfer
- device로부터 PC에게 input event를 신호한다.
- PC는 어떤 활용 가능한 interrupt data를 얻기 위해 규칙적으로 device를 조사한다.
- 데이터의 사이즈는 64bytes 이하의 값을 취한다.
- 1 ~ 255 milliseconds의 범위 안에서 polling interval을 정의한다.
- host는 bus bandwidth의 최대 90%까지 예약을 한다.
ㆍBulk transfer
- 양방향으로 많은 양의 데이터를 위해 사용된다.
- 데이터의 최대 전송 크기는 8, 16, 32, 64bytes 이하의 값을 취한다.
- 데이터의 손실이 거의 없다.
- 데이터의 전송은 지정된 address나 device에 IN or OUT packet을 가지고 시작
ㆍIsochronous transfer
- 규칙적으로 발생하고, 대개 시간에 민감하다. (음성통신과 같은 경우 사용)
- 활용 가능한 bandwidth를 1ms의 길이의 frame들로 나눈다.
- device는 각 frame 마다 하나의 isochronous transfer를 행할 수 있다.
- millisecond 마다 error의 수정 없이 고정된 양의 data의 전송.
- 데이터의 사이즈는 1023bytes 이하의 값을 취한다.
- 데이터는 약간의 손실을 감수 할 수 있다.
- 데이터 전송은 IN or OUT token과 바로 data phase 가 뒤따른다. 이것은 handshake phase는 존재하지 않는다.
- host는 bus bandwidth의 최대 90%까지 예약을 한다.

※ Endpoint의 특징
- endpoint가 제공할 수 있거나 단일 transaction에서 소비할 수 있는 data의 최대 수.
   : Control, bulk endpoint - 몇 개의 분리된 값들 중의 하나로 정의된다.
   : interrupt, isochronous endpoint - 총체적인 최대값 이하의 어떤 값을 정의.
- 어느 쪽이 Input(정보가 device로부터 host로 이동)이고 Output(정보는 host로부터 device로 이동)인가를 정의하는 방향이다.
   : 각각의 endpoint는 endpoint의 주소로서 입출력 방향의 지시자와 함께 하는 function의 수를 가진다.

4. USB Low Level Structure
ㆍPacket
- serial line 상에서 전송된 data의 가장 작은 block.
- Packet ID (pid), some data, some CRC check byte들로 구성
- Packet ID들은 다음의 표와 같이 분리한다.
ㆍTransactions
- 하나 이상의 packet들을 사용하여 하나의 device와 host 사이에 interaction을 하는 장치.
- host는 항상 하나의 Token type pids를 가지고 transaction을 시작하고, Data packet이나 다른 packet들이 어느 방향으로든 따르게 된다.
- Handshake는 data 전송과는 반대 방향으로 되돌아온다.
- IN, OUT, SETUP packet
   : 응답해야 하는 device와 endpoint를 지정하기 위해서 USB address와 endpoint를 지정하기 위해 사용되는 packet이다.
   : 128개의 address와 default address로 0을 가지고 있다.
- SETUP packet
   : 어떤 transaction이 발생했는가를 지적하기 위해 eight data bytes를 포함한다.
- DATA pids
   : complete data packet을 miss했을 때 발견하기 쉽게 만들어 준다.
- ACK Handshake packet
   : 전송이 성공적으로 완료되었다는 것을 지적한다.
- NAK Handshake packet
   : 전송이 성공적으로 완료되지 못했다는 것을 지적
- STALL Handshake packet
   : 약간의 심각한 error가 device나 endpoint에서 발생했다는 의미로 되돌려짐.
   : host는 다른 파이프들의 사용을 clear 시킴.
- 하나의 transaction은 따라 하나 이상의 phase로 구성되는데, 기본적으로 packet에 따라 token phase, optional data phase, optional handshake phase로 구성
?Token Phase
: token phase 동안 host는 모든 현재 확인된 device들에게 data packet을 전송한다.
: device address와 endpoint number를 포함한다.
: 언급된 device 만이 transaction을 처리하고, device는 다른 device에게 언급된 transaction이 지속되는 동안 bus 상에서 data를 읽지도 쓰지도 않는다.
?Data Phase
: data phase 동안 데이터는 bus 상에 위치
: output transaction을 위해 host는 data를 bus상에 놓고 언급된 device가 이것을 처리한다.
: input transaction을 위해 device는 host에 의해서 소비될 것을 위해 bus상에 data를 놓는다.
?Handshake Phase
: handshake phase 동안 device이든 host이든 상태정보를 제공하는 bus 상에 packet을 놓는다.
: ACK packet - 정보가 성공적으로 처리되었다는 것을 지적.
: NAK packet - device가 busy 상태이고 정보를 받기 위해 다시 시도하지 않는 것을 지적
: STALL packet - transaction이 옳게 받아졌지만 논리적으로 어떤 방법에서 유효하지 안는 것을 지적
: handshake를 제공하는 host는 오직 ACK packet만을 보냄.
ㆍStates of an Endpoint
- Idle state
   : host에 의해 초기화된 새로운 transaction을 처리하기 위하여 준비한다
- Busy state
   : transaction을 처리하기에 바쁘고 새로운 것을 처리할 수 없다.
- Stalled state
   : device가 자신의 기능성에서 발견한 error는 device가 현재의 transaction을 위해 STALL handshake packet을 보내고 stalled state 상태로 진입한다

5. Descriptors
ㆍdescriptor types
- 각각의 descriptor는 전체 descriptor의 byte의 수와 type code를 포함하는 2 byte의 header를 가지고 시작
- 다음의 표는 descriptor의 종류를 나열한 것이다.

ㆍDevice Descriptors
- host는 이 descriptor를 읽기 위해 endpoint0에 지시되어지는 GET_DESCRIPTOR  control transaction을 사용한다.
- device descriptor의 길이(18)와 descriptor의 type(1), USB specification의 version code, device의 종류(audio, human interface, monitor등)에 대한 class, subclass, protocol, data packet의 최대 크기, device를 위한 vendor code와 vendor-specific 제품 식별자, release number, string descriptor에 정의된 manufacturer, product, unit serial number, 수용 가능한 configuration의 수를 포함한다.

ㆍConfiguration Descriptors
- system software는 endpoint0에 언급된 GET_DESCRIPTOR control transaction을 구현함으로 인해 configuration descriptor를 읽음.
- configuration descriptor의 크기(9)와 descriptor의 type(2), interface와 endpoint descriptors의 길이를 추가한 총 크기, configuration에 있는 interface의 수, configuration의 인증 index, optional string descriptor index, power와 다른 특성을 기술한 bit mask를 포함한다.

ㆍInterface Descriptors
- GET_DESCRIPTOR control request로 interface descriptor를 패치 함.
- interface descriptor의 크기(9)와 descriptor의 type(4), interface를 활성화시키기 위하여 SET_INTERFACE control transaction에서 사용되는 interface number와 alternate setting, endpoint의 개수, interface에서 제공하는 기능들을 기술한 class, subclass, protocol, string descriptor의 index 들을 포함한다.

ㆍEndpoint Descriptors
- GET_DESCRIPTOR control request로 endpoint descriptor를 패치 함.
- endpoint descriptor의 크기(7)와 descriptor(5)의 type, endpoint의 수와 방향, endpoint가 하나의 transaction 동안 전송이 가능한 최대 데이터의 크기, Interrupt와 isochronous endpoint에서 polling interval measure을 정하는 field를 포함한다.
- bEndpointAddress
   : endpoint의 수와 방향을 encode 한다.
   : 예를 들어 주소값이 0x82 이면 endpoint 2에서 IN transaction을, 0x02이면 endpoint 2에서 OUT transaction을 나타냄

- bmAttributes
   : endpoint의 type을 정의

ㆍString Descriptors
- endpoint 0에 GET_DESCRIPTOR control request를 처리함으로서 읽음.
- data의 길이, descriptor의 type(3), string data로 구성된다.


SPUSB 드라이버 설명

1. Headers and Libraries
ㆍusb100.h   - 다양한 USB 상수들과 structures
ㆍusbioctl.h - IOCTL 정의들
ㆍusbdlib.h  - URB building 과 관련 있는 routine들
ㆍusbdi.h    -  URB structure들을 포함한 USBDI routine들

2. USBDI IOCTLs

※ 위의 내부 IOCTL은 kernel mode에서만 사용 가능하다
※ 가장 중요한 IOCTL은 IOCTL_INTERNAL_USB_SUBMIT_URB로서 URB를 USB class driver가 처리할 수 있도록 보내는 역할을 한다.

3. URBs
ㆍ16개의 다른 _URB_* 구조체를 가지고 있는 공용체이다. 
ㆍ모든 URB structure는 보통 _URB_HEADER 구조체의 헤더를 가지고 시작한다.
ㆍ헤더의 Length와 Function 필드는 USB Device Interface가 호출되기 전에 값이 저장되어야 한다.
ㆍ URB 처리의 결과 값은 Status field에 저장


typedef struct _URB {
    union {
      struct _URB_HEADER                UrbHeader;
      struct _URB_SELECT_INTERFACE      UrbSelectInterface;
      struct _URB_SELECT_CONFIGURATION  UrbSelectConfiguration;
      // ...
    };
} URB, *PURB;

struct _URB_HEADER {
    USHORT  Length;
    USHORT  Function;
    USBD_STATUS   Status;
    // ...
};

ㆍStatus field는 어떻게 그 요청이 완료되었는가를 지적하는 사위 2 bit를 포함.

4. Calling USBDI
ㆍ모든 Internal IOCTL을 USB system class driver에게 이슈화하는데 사용
ㆍC++ 코드에서는 마지막 parameter를 default parameter로 지정 가능하다.
ㆍInternal IOCTL을 위한 새로운 IRP를 생성하고, IRP에 기입하고, USB system driver에게 device stack의 아래로 IRP를 보낸다.
ㆍ다음으로 IRP가 완료될 때까지 기다린다.
ㆍ오직 PASSIVE_LEVEL에서만 호출된다.
ㆍUSB Internal IOCTL은 표준 입출력 IRP stack location을 사용하지 않으며, 스택의 Parameters.Others.Argument1 field를 URB 포인터로 설정하고, Parameters.Others.Argument2 field는 USB IOCTL들 중의 하나를 위해 사용한다.

1) Allocating IRPs : CallUSBDI(...) 함수
ㆍIOCTL IRP를 building하고 issuing하는 것은 IOBuildDeviceIoControlRequest를 호출함으로서 쉽게 만들어진다. 
Irp = IoBuildDeviceIoControlRequest(
IoControlCode, dx->NextStackDevice,
NULL, 0,// Input buffer
NULL, 0,// Output buffer
TRUE, &event, &IoStatus);

ㆍIoBuildDeviceIoControlRequest는 IOCTL과 Internal IOCTL IRP를 만들기 위해서 사용. 즉 6번째 parameter인 InternalDeviceIoControl의 값이 TRUE이면 Internal IOCTL을, FALSE 이면 IOCTL을 사용.
ㆍ개발자가 event를 초기화했을 때, event가 signalled 될 때까지 기다림으로서 IRP의 완료를 기다려야 하는데, 이때는 completion routine을 설정 할 필요가 없다.
KeInitializeEvent(&event, NotificationEvent, FALSE);
KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL);

ㆍUSB Internal IOCTL은 표준 입출력 버퍼를 사용하지 못한다. 즉, IoSkipCurrentIrpStackLocation과 IoCopyCurrentIrpStackLocation routine를 사용하지 못한다. 왜냐하면 current stack location인 아직 set up 되지 않았기 때문이다. ClIsa driver을 보면 Win32 application이 DeviceIoControl() 함수를 통하여 driver를 호출 할 때, 모든 정보가 stack에 저장되나, CallUSBDI() 함수는 내부 IOCTL IRP를 사용하기 때문에 필요한 정보를 직접 스택에 저장해야 한다. 그래서 IoBuildDeviceIoControlRequest() routine을 통해서 stack location에 필요한 올바른 값들을 set up 한다.
ㆍ요구된 IRP stack location의 포인터를 얻기 위해 IoGetNextIrpStackLocation을 호출하고, 필요한 값들을 Parameters.Others.Argument1 field등에 저장한다.
NextIrpStack = IoGetNextIrpStackLocation(Irp);

NextIrpStack->Parameters.Others.Argument1 = UrbEtc;
NextIrpStack->Parameters.Others.Argument2 = (PVOID)Arg2;

ㆍ마지막으로 next driver를 호출하고 만약 pending이 있을 시 적절한 조치를 취한다.
status = IoCallDriver( dx->NextStackDevice, Irp);

if (status == STATUS_PENDING)
{
  KeWaitForSingleObject( &event, Suspended, KernelMode, FALSE, NULL);
  status = IoStatus.Status;
}

ㆍCallUSBDI() routine이 행하는 작업을 요약하면 다음과 같다.
- IRP completion event를 초기화 한다.
- Internal IOCTL을 생성한다.
- URB 포인터 등을 저장한다.
- next driver를 호출한다.
- 요청이 여전히 pending 상태라면 completion event가 signalled 될 때까지 기다린다.
※ CallUSBDI() 함수는 PASSIVE_LEVEL에서만 호출되기 때문에 DISPATCH_LEVEL에서 실행되는 StartIo routine에서는 호출 할 수 가 없다.

2) Other IRP Alloctions
ㆍIoBuildSynchronousFsdRequest
- IoBuildDeviceIoControlRequest와 같은 방법으로 signal completion을 위해 event를 사용하는 Read, Write, Flush, Shutdown IRP를 생성한다.
- PASSIVE_LEVEL IRQL에서 호출된다.
ㆍIoBuildAsynchronousFsdRequest
- signal completion을 위해 event를 사용하지 않은 것처럼, 비동기적으로 동작한다.
- DISPATCH_LEVEL IRQL 이하에서 호출된다.
ㆍIoFreeIrp
- IRP를 해제하기 위하여 호출
- 대부분 completion routine를 첨가시키는데, 여기서 이 함수를 호출하고 return 값으로 STATUS_MORE_PROCESSING_REQUIRED를 반환한다.
ㆍIRP를 할당하는 마지막 두 방법
- IoAllocateIrp : IRP를 할당한다.
- IoInitializeIrp : 어떤 driver에 할당되어진 memory의 외부에 IRP를 만든다.
- 위 두 방법은 개발자가 IRP stack size의 크기를 정의해야 한다.

5. Talking USB
1) Initializing a USB Device
ㆍ대부분 Start Device Plug and Play IRP를 처리할 때 driver를 초기화한다.
ㆍStartDevice 함수에서 처리과정은 다음과 같다.
- device를 위한 configuration을 선택한다.
- configuration의 일부분인 하나 이상의 interface를 선택한다.
- 선택된 configuration URB를 bus driver에게 보낸다.
- bus driver는 선택된 interface에 있는 endpoint를 가지고 device와 상호 통신할 수 있도록 pipe들을 생성하고, pipe들을 액세스 할 수 있도록 핸들을 제공한다. 또한 configuration과 interface를 위한 핸들을 생성한다.
- 완료된 URB로부터 핸들을 뽑아내고, 나중에 사용하기 위하여 필요한 값들을 저장한다.


2) Device reset
ㆍUsbGetPortStatus(...)
- port 상태 비트를 얻기 위해 IOCTL_INTERNAL_USB_GET_PORT_STATUS를 이슈화한다.
status = CallUSBDI (dx, &PortStatus,
               IOCTL_INTERNAL_USB_GET_PORT_STATUS, 0);

ㆍUsbResetDevice(...)
- USBD_PORT_CONNECTED와 USBD_PORT_ENABLED bit를 체크하고 필요한 경우 UsbResetPort를 호출한다.
if( !(PortStatus & USBD_PORT_CONNECTED))
return STATUS_NO_SUCH_DEVICE;

if( PortStatus & USBD_PORT_ENABLED)
return status;

status = UsbResetPort (dx);

if( !NT_SUCCESS(status))
return status;

ㆍUsbResetPort(...)
- IOCTL_INTERNAL_USB_RESET_PORT을 USB class driver에게 이슈화한다.
status = CallUSBDI (dx, NULL, IOCTL_INTERNAL_USB_RESET_PORT, 0);

ㆍUsbResetPipe(...)
- ENDPOINT)HALT 기능을 클리어 시킨다. 즉, endpoint가 stalled 되면, 다음 전송을 위한 준비 작업을 한다.

3) Issuing URBs
ㆍGetting a USB descriptor : UsbGetDeviceDescriptor(...)
- 어떤 종류의 device가 장착되었는가를 결정하기 위해 Device Descriptor를 읽는다.
- URB를 위한 nonpaged memory를 할당한다.
- Get Descriptor URB function은 URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE function code를 사용하는데, 이 코드를 위해 _URB_CONTROL_DESCRIPTOR_REQUEST structure를 사용한다.
UrbSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST);
urb     = (PURB)ExAllocatePool(NonPagedPool, UrbSize);

if( urb==NULL)
return STATUS_INSUFFICIENT_RESOURCES;

- device descriptor를 위한 메모리를 할당한다. 메모리 할당이 실패할 경우 URB를 위해 할당한 메모리를 해제하고 적절한 상태코드 값을 되돌려 준다.
sizeDescriptor   = sizeof(USB_DEVICE_DESCRIPTOR);
deviceDescriptor = (PUSB_DEVICE_DESCRIPTOR) ExAllocatePool
                   (NonPagedPool, sizeDescriptor);

if( deviceDescriptor == NULL)
{
FreeIfAllocated (urb);
return STATUS_INSUFFICIENT_RESOURCES;
}
- URB formatting의 작업을 하기 위하여 UsbBuildGetDescriptorRequest를 호출한다. 첫 번째와 두 번째 파라미터는 URB의 포인터와 크기를 나타내며, 세 번째 파라미터는 descriptor type을 나타낸다. 네 번째와 다섯 번째 parameter인 Index와 LanguageId 필드는 configuration과 string descriptor 요청이 있을 때 사용한다. 다음으로는 descriptor buffer와 길이를 나타낸다. 만약 direct I/O 방식을 사용할 경우에는 descriptor buffer 대신에 MDL을 사용한다. 마지막 parameter인 UrbLink는 URB에 따르는 optional link이다.
UsbBuildGetDescriptorRequest (urb, UrbSize, 
              USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, deviceDescriptor,
              NULL, sizeDescriptor, NULL);

- CallUSBDI() 함수를 사용하여 생성된 URB를 보낸다. 그리고 CallUSBDI이 반환한  return status와 URB의 completion status를 체크한다.
status = CallUSBDI (dx, urb, IOCTL_INTERNAL_USB_SUBMIT_URB, 0);
if( !NT_SUCCESS(status) || !USBD_SUCCESS( urb->UrbHeader.Status))
{
ExFreePool (deviceDescriptor);
status = STATUS_UNSUCCESSFUL;
}

- 마지막 작업으로 deviceDescriptor의 값을 저장하고 할당된 메모리를 해제한다.
dx->UsbDeviceDescriptor = deviceDescriptor;
ExFreePool (deviceDescriptor);
ExFreePool (urb);

4) Selecting an Interface
ㆍ전체적인 step은 다음과 같다.
- configuration, interface, endpoint descriptor 등을 얻는다.
- 적절한 interface descriptor를 찾는다.
- 선택된 configuration URB를 이슈화한다.
- configuration 핸들과 개발자가 사용하는 어떤 pipe의 핸들을 저장한다.

ㆍUsbGetConfigurationDescriptor(...)
- 필요한 모든 descriptor를 얻는데 사용
- Get Descriptor 요청을 두 번 이슈화한다.
- 첫 번째 호출은 basic configuration descriptor를 읽기 위한 것이다. 여기서 configuration, interface, endpoint를 포함하는 전체 구조체의 길이를 저장한다. 이 길이는 다음의 URB의 이슈화에 사용한다.
DescriptorsSize = dx->UsbConfigurationDescriptor->wTotalLength;
- 두 번째 호출은 전제 descriptor를 읽기 위해 URB를 이슈화한다.

ㆍUsbSelectionConfiguration(...)
- USBD_ParseConfigurationDescriptorEx()
   : interface를 찾는데 사용한다.
   : 여기서 사용하는 파라미터는 일치해야 하는 기준을 정해야 하는데, 우리의 USB 제품은 사용자 정의용을 사용하였기 때문에 일치하는 값이 없다. 그래서 모든 값은 -1이다. 
   : matching된 interface를 찾아내고, interface descriptor pointer를 돌려준다.
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
      Descriptors, Descriptors, -1, -1, -1, -1, -1);
- 두 번째로 처리해야 할 작업은 적당한 Select configuration URB를 생성하는 것이다. USBD_CreateConfigurationRequestEX()는 이 URB를 할당하고 system USB class driver에게 제출한다.
- USBD_CreateConfigurationRequestEx()의 입력으로 USBD_INTERFACE_LIST_ENTRY structure를 사용하며, 이 리스트의 끝을 나타내기 위하여 InterfaceDescriptor field는 NULL 값이다.
ilist[0].InterfaceDescriptor = InterfaceDescriptor;
ilist[0].Interface           = NULL;
ilist[1].InterfaceDescriptor = NULL;
ilist[1].Interface           = NULL;

urb = USBD_CreateConfigurationRequestEx (Descriptors, ilist);

- 선택된 interface descriptor에서 endpoint의 수를 체크한다. 본 제품은 총 4개의 endpoint를 설정하였다.
if (InterfaceDescriptor->bNumEndpoints != 4)
return STATUS_DEVICE_CONFIGURATION_ERROR;

- Select Configuration URB를 driver에게 보낸다.
status = CallUSBDI( dx, urb, IOCTL_INTERNAL_USB_SUBMIT_URB, 0);

- 하드웨어와의 입출력에 사용하기 위해서 버퍼 사이즈, 입출력 핸들 등, 필요한 값들을 저장한다.
dx->UsbConfigurationHandle =
          urb->UrbSelectConfiguration.ConfigurationHandle;

InterfaceInfo = &urb->UrbSelectConfiguration.Interface;

if( InterfaceInfo->NumberOfPipes > 0)
{
for (i=0; i< InterfaceInfo->NumberOfPipes; i++)
{
pi = &InterfaceInfo->Pipes[i];

pi->MaximumTransferSize = dx->MaximumTransferSize;
pi->PipeFlags = 0;
}

dx->UsbInPipeHandle  = InterfaceInfo->Pipes[2].PipeHandle;
dx->UsbOutPipeHandle = InterfaceInfo->Pipes[1].PipeHandle;
}

if( dx->UsbInPipeHandle == NULL && dx->UsbOutPipeHandle == NULL)
status = STATUS_UNSUCCESSFUL;
※ 참고로 데이터의 입력 pipe handle은 0x82 이며 interfaceInfo->Pipes[2]에 저장되어 있으며, 출력 pipe handle은 0x01 이며 interfaceInfo->Pipes[1]에 저장되어 있다. 그 외에 0x81과 0x02는 사용하지 않는다.

- 마지막 작업으로서 interface를 선택하기 위하여 할당했던 메모리를 해제한다.
ExFreePool (Descriptors);
ExFreePool (urb);

5) Other Initialize
ㆍUsbGetSpecifiedDescriptor(...)
- Device가 지원하는 language ID를 반환한다.
- 각각의 String Descriptor를 얻기 위해 Get Descriptor 요청을 이슈화한다.
UsbBuildGetDescriptorRequest (urb, UrbSize, DescriptorType,
 0, 0, dx->StringsDescriptor, NULL, (ULONG)Size, NULL);

ㆍUsbGetUsbInfo(...)
- host controller device 이름과 사용된 bandwidth의 양과 같은 USB bud에 관한 일반적인 정보를 얻기 위해 사용
- 요구된 Internal IOCTL들은 Win 2000에서만 구현]
- preprocessor 지시어는 Win98에서 이 작업을 행하는 함수의 몸체를 제거하기 위해 사용
#if _WIN32_WINNT>=0x0500
       ~
#else
       ~
#endif
※ 위의 두 함수의 사용여부는 불투명하다. 두 함수를 사용하지 않아도 크게 무리는 없을 듯 보인다. 그리고 descriptor를 초기화하는 부분(메모리의 할당과 해제, URB 제출 등)은 거의 비슷함으로 설명은 하지 않았다.
6) Deselecting a configuration : UsbDeselectDescription(...)
ㆍdriver가 device의 접근을 그만두기 원할 때 device의 configuration 선택을 해제해야 한다.
ㆍ이 작업은 STOP_DEVICE PnP IRP를 처리할 때 호출된다.
ㆍSelect configuration URB를 생성하기 위해 NULL 값인 configuration descriptor를 가지고 UsbBuildSelectionConfigurationRequest를 호출한다.
UsbBuildSelectConfigurationRequest (urb, UrbSize, NULL);

ㆍ메모리의 할당과 해제, USB system class driver에 URB를 보내는 것은 초기화 함수와 같다.



출처 : http://tong.nate.com/thisbe71/29386832

'Window Driver' 카테고리의 다른 글

CLASS GUID  (0) 2010.02.24
Writing Windows WDM Device Drivers (CHRIS CANT) CD  (0) 2010.02.23
URB  (0) 2010.02.18
USB 관련 헤더파일  (0) 2010.02.18
USB 구조  (0) 2010.02.18
Comments