USB Device Driver Programming 작성 : 송지호 (DevGuru 대표 ) songjiho@devguru.co.kr
목 차 1. USB 개요 2. USB 장치의구성 3. Pipe 특성 4. 개발에필요한기타정보 5. USB driver 구조 6. 실제적인 I/O 방법 7. bulkusb 소스분석 8. 실제동작하는소스분석 9. 드라이버설치와제거
1.USB 개요 1.1 개발배경 1) 제한된 IRQ 해결방안필요 2) 고속의디바이스필요 (Parallel의단점극복 ) 3) 손쉬운디바이스접속및설치 4) 다양한하드웨어가접속가능한버스필요 5) 작은크기의커넥터필요
1.2 USB 의특징 (1) 거의무제한의확장능력 1) 127 개까지의디바이스를 daisy-chain 방식으로연결가능 2) 최대 5m 까지의케이블사용가능 3) 파워공급 (+5v, 총 500mA 지원 ) PnP 지원 1) Jumper Setting 없이하드웨어설치가능 Hot Plug In 지원 2) 동작도중하드웨어착탈가능작은커넥터 3) 이동에용이
1.2 USB 의특징 (2) 다양한주변기기지원 1) 지원하는전송대역폭이수 Kbps 에서 480Mpbs 까지다양 (1.1 규격의경우 12Mbps 까지지원 ) 2) 모뎀, 프린터, 저장장치등을지원사용자의사용편이성 1) 통일된케이블과커넥터사용 2) 버스자체에서파워지원 3) Hot Plug In 지원 4) PnP 지원 5) Daisy-Chain 형식의하드웨어
1.2 USB 의특징 (3) 데이터보장 1) 하드웨어적인 Data error recovery 제작가격이저렴 다양한기능의 ChipSet 제공 다양한클래스의드라이버가이미존재 ( 예 : Mouse,Keyboard,MassStroage ) 다양한전송속도및전송방법제공
1.2 USB 의특징 (3) - 구성도 Host Host hub : Hub ports Device Device Hub Device Device Hub Device Device
1.3 IEEE1394 vs USB(1) IEEE1394 란? 1) 고속의시리얼버스 2) 100/200/400Mbps(1394.1995) 3) 800/1600Mbps(1394a.2000) 4) 최대 63nodes/bus, 최대 1023buss 5) Hot Plugging 6) 4또는 6pin connector 7) Bus Power 제공
1.3 IEEE1394 vs USB(2) Data-Strob Encoding Data Strob Data^Strob 1. Strob 신호를함께보내준다 2. Strob 신호를사용해서클럭을만들수있다. 3. 이는클럭보다파형변화가적어상대적으로노이즈요소를감소시키고고속의전송이가능하게된다.
1.4 USB Class(1) Class 란? - USB Org 에서만든 USB 표준규격 - 데이터전송표준규격 - 이미만들어진규격을사용하므로하드웨어의구성과상관없이드라이버제작가능 - 하드웨어와소프트웨어모두표준을준수해야함 Class 의종류 Class 사용예 Audio Speaker Communication Modem HID Mouse Display Monitor Hub Class Feed back Power Printer Mass strorage 사용예 Joystick
2. USB 장치의구성 Host Host hub : Hub ports Device Device Hub Device Device Hub Device Device
2.1 USB 의 H/W 적인구성 (1) USB Host 1) 버스상에는단하나의 Host 가존재 2) Device 에필요한드라이버와전송대역폭을관리 3) 주로 OHCI(Open Host Controller Interface) 사용 4) Host controller 는버스에 token 을보내고이를받은 Device 가응답하는방식으로동작한다. 5) 버스파워관리 6) 개념적으로 PC 라고생각하면된다.
2.1 USB 의 H/W 적인구성 (2) USB HUB 1) Device 가접속가능한하향접속포트를제공 2) Host 쪽으로의상향접속기능을가짐 3) 하향접속의디바이스착탈을감지 4) 접속된디바이스에전원공급기능 Device (Function, Node) 1) 실제적인기능을수행 2) Host 의요청에의한응답방식으로동작 3) Keyboard,Mouse,Joystick,Modem 4) USB Class 디바이스의경우 Class 에서정의한프로토콜을준수해야함
2.1 USB 의 H/W 적인구성 (3) 케이블의종류와구성
2.2 USB 장치의논리적구성 (1) Device Interface0 Endpoint 0 (Pipe0) Endpoint 1 (Pipe1) Configuration0 Interface1 Other Endpoints. Endpoints Other Interfaces Configuration1 Other Configurations Interfaces
2.2 USB 장치의논리적구성 (2) Configuration 1) 하나이상존재가능 2) 각각의 Configuration 은하나이상의 Inferface 를가진다. 3) 가장큰논리적구성단위이다. 4) 다른논리적요소를찾는데필요한시작지점이된다.
2.2 USB 장치의논리적구성 (3) Interface 1) Endpoint 의모음 2) 소프트웨어에서하드웨어로접근하는규정을기술한다. 3) 하나이상의 Interface 가있어야한다. 4) 하나이상의 Endpoint 를가지고있어야한다.
2.2 USB 장치의논리적구성 (4) Endpoint 1) Pipe와매칭 2) Pipe를통해연결된디바이스쪽의끝단 3) Endpoint 0 는 control pipe 로예약 4) 최소한하나이상의 Endpoint가있어야한다. 5) 논리적인단위이다. 6) 전송Byte수등의정보가들어있다.
2.2 USB 장치의논리적구성 (5) Usbcheck 에서본디바이스의논리구조
2.3 기타 Usbdriver 개발에필요한용어정리 1) 하드웨어관련 Host, Device, Hub, Pid, Vid 2) 소프트웨어관련 Pipe, Descriptor, Configuration, Interface, Endpoint
3. Pipe 특성 (1) Control Pipe(1) 1) 용도 PnP,Vendor command 전송 2) 전송속도 - LowSpeed 3) 특징 저속파이프, 어떠한 Device 도반듯이가지고있어야함, 데이타무결성보장, 4) 사용예 마우스, 키보드, CBI 저장장치등 5) Data 전송 Size : 8,16,32,64 Byte
3. Pipe 특성 - Control Pipe(2) Offset Field Size Value Description 0 bmrequesttype 1 Bitmap Characteristics of request: D7: Data transfer direction 0 = Host-to-device, 1 = Device-to-host D6...5: Type 0 = Standard, 1 = Class, 2 = Vendor, 3 = Reserved, D4...0: Recipient 0 = Device, 1 = Interface,2 = Endpoint, 3 = Other, 4...31 = Reserved 1 brequest 1 Value Specific request (refer to Table 9-3) 2 wvalue 2 Value Word-sized field that varies according to request 4 windex 2 Index or Offset Word-sized field that varies according to request; typically used to pass an index or Offset 6 wlength 2 Count Number of bytes to transfer if there is a Data stage
3. Pipe 특성 (2) BulkPipe 1) 용도 대용량의데이터전송 2) 전송속도 FullSpeed 3) 특징 고속파이프, 데이터무결성보장 4) 사용예 CBI 저장장치 5) Data 전송 Size : 8,16,32,64 Byte
3. Pipe 특성 (3) Interrupt Pipe 1) 용도 Device 의상태를알리는데사용 2) 전송속도 LowSpeed 3) 특징 데이타무결성보장, 가장넓은전송대역폭, 제한된전송량 4) 사용예 HID( 마우스 ) 5) Data 전송 Size : 64Byte
3. Pipe 특성 (4) Isochoronous Pipe 1) 용도 : 대용량의데이터전송 2) 전송속도 : FullSpeed 3) 특징 : 실시간전송보장, 인터럽트파이프다음으로많은대역폭, 데이터무결성을보장받지못함 4) 사용예 : 모뎀, 네트워크카드 5) Data 전송 Size : 1023 Byte
3. Pipe 특성 (5) Bulk Pipe 전송속도계산방법
4. 개발에필요한기타정보 (1) USB 드라이버의계층구조 USB Driver Interface HIDClass.sys HIDUSB.sys USBHUB.sys Our Drivers USBD.sys UHCD.sys PCI Enumerator OpenHCI.sys USB Drive Stack USB Bus
4. 개발에필요한기타정보 (2) 사용툴들과스팩소개 1) Usb.org usb 스팩을얻을수있다. 2) NTDDK src wdm usb usbview 3) 98DDK src usb bin usbcheck 4) 98DDK src usb bin usbdiag 5) 98DDK src usb bin hidview
4. 개발에필요한기타정보 (3) DDK 소스위치와소개 1) NTDDK src wdm usb bulkusb 2) NTDDK src wdm usb isousb 3) NTDDK src wdm hid 4) 98DDK src usb 5) 98DDK src hid
5. USB driver 구조 (1) urb 의구조 typedef struct _URB { union { struct _URB_HEADER UrbHeader; struct _URB_SELECT_INTERFACE UrbSelectInterface; struct _URB_SELECT_CONFIGURATION UrbSelectConfiguration; struct _URB_PIPE_REQUEST UrbPipeRequest; struct _URB_FRAME_LENGTH_CONTROL UrbFrameLengthControl; struct _URB_GET_FRAME_LENGTH UrbGetFrameLength; struct _URB_SET_FRAME_LENGTH UrbSetFrameLength; struct _URB_GET_CURRENT_FRAME_NUMBER UrbGetCurrentFrameNumber; struct _URB_CONTROL_TRANSFER UrbControlTransfer; struct _URB_BULK_OR_INTERRUPT_TRANSFER UrbBulkOrInterruptTransfer; struct _URB_ISOCH_TRANSFER UrbIsochronousTransfer;
5. USB driver 구조 (2) struct _URB_CONTROL_DESCRIPTOR_REQUEST UrbControlDescriptorRequest; struct _URB_CONTROL_GET_STATUS_REQUEST UrbControlGetStatusRequest; struct _URB_CONTROL_FEATURE_REQUEST UrbControlFeatureRequest; struct _URB_CONTROL_SYNC_FRAME_REQUEST UrbControlSyncFrameRequest; struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST UrbControlVendorClassRequest; struct _URB_CONTROL_GET_INTERFACE_REQUEST UrbControlGetInterfaceRequest; struct _URB_CONTROL_GET_CONFIGURATION_REQUEST UrbControlGetConfigurationRequest; } } URB, *PURB ;
5. USB driver 구조 (3) urb 의사용시주의점 1) 정확한공용체사용 2) Direction 과 Pipe 가일치하도록 3) Firmware 와약속된데로 In/Out size 설정 4) Vendor Command 의경우 Direction 과 bmrequest 의일치 5) Data size 와 Buffer size 의크기일치 6) 정확한 Pipe 설정
5. USB driver 구조 (4) 전체드라이버구조 1) DriverEntry() : CallBack 루틴등록 2) AddDevice() : DriverObject 생성, Symbolic linkname 등록, TopOfStackObject 얻기 3) PnP 처리 : Power/Pnp 관련사항처리, USB Descriptor 얻기, Pipe 정보얻기, Device 제거루틴, 4) 사용자 I/O 요청처리 : CreateFile(),CloseHandle(),ReadFile(),WriteFile(),DeviceIoCo ntrol() 등의 Wind32 함수호출에대한처리
5. USB driver 구조 (5)-AddDevice ntstatus = IoRegisterDeviceInterface(DeviceObject, (LPGUID)&GUID_WDM_TESTUSB, NULL, devicelinkunicodestring); ntstatus = IoSetDeviceInterfaceState(deviceLinkUnicodeString, TRUE); ntstatus = IoCreateDevice (DriverObject, sizeof (DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, DeviceObject); pdx = (_DEVICE_EXTENSION *)deviceobject->deviceextension; pdx ->Flags &= ~DO_DEVICE_INITIALIZING; pdx ->Flags = DO_BUFFERED_IO; pdx ->Flags = DO_POWER_PAGABLE; pdx ->StackDeviceObject =IoAttachDeviceToDeviceStack( deviceobject,physicaldeviceobject);
5. USB driver 구조 (6) 일반적인 PnP 부분 IRP_MN_START_DEVICE: IRP_MN_STOP_DEVICE: IRP_MN_REMOVE_DEVICE: IRP_MN_QUERY_DEVICE_RELATIONS: IRP_MN_QUERY_CAPABILITIES: IRP_MN_QUERY_ID: IRP_MN_QUERY_PNP_DEVICE_STATE: default:
5. USB driver 구조 (7) IRP_MN_START_DEVICE: - XX_StartDevice() IRP_MN_START_DEVICE 처리후호출 USB_DEVICE_DESCRIPTOR 를얻는다. - XX_ConfigureDevice() USB_CONFIGURATION_DESCRIPTOR 를얻는다 USB_CONFIGURATION_DESCRIPTOR 의정확한크기를얻는다. USB_CONFIGURATION_DESCRIPTOR 를정확히얻는다 -XX_SelectInterface() 정확한 Interface를얻는다. Interface에서 Pipe handle를얻는다
5. USB driver 구조 (8) XX_StartDevice urb _URB_CONTROL_DESCRIPTOR_REQUEST siz sizeof ( USB_DEVICE_DESCRIPTOR ); UsbBuildGetDescriptorRequest(urb,sizeof ( struct _URB_CONTROL_DESCRIPTOR_REQUEST ), ) USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, devicedescriptor, NULL, siz, NULL
5. USB driver 구조 (9) XX_ConfigureDevice() urb _URB_CONTROL_DESCRIPTOR_REQUEST* siz sizeof ( USB_CONFIGURATION_DESCRIPTOR ) + dummy configurationdescriptor _USB_CONFIGURATION_DESCRIPTOR* UsbBuildGetDescriptorRequest (urb, ( USHORT ) sizeof ( struct _URB_CONTROL_DESCRIPTOR_REQUEST ), USB_CONFIGURATION_DESCRIPTOR_TYPE, 0, 0,configurationDescriptor, NULL, sizeof (USB_CONFIGURATION_DESCRIPTOR),NULL); siz configurationdescriptor->wtotallength + dummy configurationdescriptor struct _USB_CONFIGURATION_DESCRIPTOR * UsbBuildGetDescriptorRequest (urb,(ushort) sizeof (struct _URB_CONTROL_DESCRIPTOR_REQUEST), USB_CONFIGURATION_DESCRIPTOR_TYPE,0,0,configurationDescriptor, NULL, siz,null);
5. USB driver 구조 (10) XX_SelectInterface () interfacelist (struct _USBD_INTERFACE_LIST_ENTRY *(sizeof(usbd_interface_list_entry) * 2) interfacedescriptor USBD_ParseConfigurationDescriptorEx() urb = USBD_CreateConfigurationRequestEx(ConfigurationDescriptor, interfacelist) Interface = &urb->urbselectconfiguration.interface; for ( i = 0 ; i < Interface->NumberOfPipes ; i++ ) { switch (i) { case DGUSB_BULKOUT_PIPE: Interface->Pipes[i].MaximumTransferSize = XX; break; - 생략 - } } IoCallDriver() ( 이후 Interface 안에모든파이프정보가들어있다.)
5. USB driver 구조 (11) usb 드라이버의 I/O 절차 1) IRP생성 2) URB 생성 / Setting 3) NextStackLoaction에 URB 첨부 4) IoCallDriver() 5) Pending이면 Wait 6) 결과확인후 return
5. USB driver 구조 (12) Irp 생성 / 전달 pdx->vendorirp = IoAllocateIrp( (CCHAR)(pDx->StackDeviceObject->StackSize+1), FALSE); IoInitializeIrp(pDx->VendorIrp,IoSizeOfIrp( (pdx->stackdeviceobject->stacksize+1)), (pdx->stackdeviceobject->stacksize+1)); 또는 irp = IoBuildDeviceIoControlRequest( IOCTL_INTERNAL_USB_SUBMIT_URB, deviceextension->topofstackdeviceobject,null,0,null, 0, TRUE,IRP_MJ_INTERNAL_DEVICE_CONTROL or IRP_MJ_SCSI &event, &iostatus); urb 전달 nextstack->parameters.others.argument1 = Urb;
5. USB driver 구조 (13) Irp / Urb 생성 register Completion Routine KeSetEvent NextStackLoaction setting return STATUS_MORE_PROCESSING_REQUIRED IoSetCompletionRoutine IoCallDriver() call Pending? no return yes wait Wait 해제
6. 실제적인 I/O 방법 (1) Bulk Data I/O ULONG siz = sizeof(struct _URB_BULK_OR_INTERRUPT_TRANSFER); RtlZeroMemory(urb, siz); urb->urbbulkorinterrupttransfer.hdr.length = (USHORT) siz; urb->urbbulkorinterrupttransfer.hdr.function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER; urb->urbbulkorinterrupttransfer.pipehandle = pipe->pipeinfo->pipehandle; urb->urbbulkorinterrupttransfer.transferflags = USBD_TRANSFER_DIRECTION_IN; urb->urbbulkorinterrupttransfer.transferflags = USBD_TRANSFER_DIRECTION_OUT; urb->urbbulkorinterrupttransfer.transferbuffermdl = NULL; urb->urbbulkorinterrupttransfer.transferbuffer = Buffer; urb->urbbulkorinterrupttransfer.transferbufferlength = Length; urb->urbbulkorinterrupttransfer.urblink = 0;
6. 실제적인 I/O 방법 (2) Vendor Command I/O siz = sizeof ( _URB_CONTROL_VENDOR_OR_CLASS_REQUEST ); urb = (struct _URB *)ExAllocatePool(NonPagedPool,siz); RtlZeroMemory(urb,siz); urb->urbcontrolvendorclassrequest.hdr.length = siz; urb->urbcontrolvendorclassrequest.hdr.function = URB_FUNCTION_VENDOR_DEVICE; urb->urbcontrolvendorclassrequest.transferflags = TransferFlags; 전송방향을표시하는필드이다. urb->urbcontrolvendorclassrequest.urblink = NULL;
6. 실제적인 I/O 방법 (3) Vendor Command I/O 계속 urb->urbcontrolvendorclassrequest.requesttypereservedbits = RequestTypeReservedBits; 0 번필드 urb->urbcontrolvendorclassrequest.request = Request; 1 번필드 urb->urbcontrolvendorclassrequest.value = Value; 2~3 번필드 urb->urbcontrolvendorclassrequest.index = Index; 4~5 번필드 urb->urbcontrolvendorclassrequest.transferbufferlength = TransferBufferLength; 6~7 번필드 urb->urbcontrolvendorclassrequest.transferbuffer = TransferBuffer; urb->urbcontrolvendorclassrequest.transferbuffermdl = TransferBufferMDL;
6. 실제적인 I/O 방법 (4) Interrupt Data I/O VOID UsbBuildGetInterruptOrBulkTransferRequest( IN OUT PURB Urb, IN USHORT Length, IN USBD_PIPE_HANDLE PipeHandle, IN PVOID TransferBuffer, IN PMDL TransferBufferMDL, IN ULONG TransferBufferLength, IN ULONG TransferFlags, IN PURB Link ); 이함수로 URB 초기화
6. 실제적인 I/O 방법 (5) Interrupt Data I/O StartInterruptUrb(){ } urb 생성 / 초기화 IoSetCompletionRoutine() 으로 OnInterrupt() 함수등록 IoCallDriver() 호출후 pending 확인없이 return OnInterrupt(){ } Interrupt 상태확인 StartInterruptUrb() 호출 만약더이상인터럽트를체크하지않아도되면 StartInterrupt() 함수를호출하지않는다.
7. bulkusb 소스분석 DDK 소스분석 디버거상에서실제동작상태확인
8. 실제동작하는소스분석 Bulk, Interrupt, Control pipe 를사용하는디바이스를통해실제동작하는모습을 Debugger 에서확인
9. 드라이버설치와제거 (1) 설치순서 1) 최초 PnP 시 OS 에서는디바이스의 VID,PID,Class type 등을읽는다. 2) 해당 PID,VID 에해당되는드라이버가있는지레지스트리에서찿는다. 3) 해당되는드라이버를발견하면로딩하고발견하지못하면새하드웨어설치마법사가실행된다. 4) 설치마법사는.inf 파일에서해당되는 PID 와 VID 를발견하면 inf 파일에기술된데로설치작업을수행한다. 5) 설치작업은레지스트리수정, 드라이버파일복사,inf 파일복사,inf 파일백업본작성등이다.
9. 드라이버설치와제거 (2)
9. 드라이버설치와제거 (3) Hardware Enumerator 레지스트리설정
9. 드라이버설치와제거 (4) Service key 설정
9. 드라이버설치와제거 (5) 제거순서 1) 레지스트리제거 Wind98 과 2000 은각각상이한레지스트리키를사용한다. Win2000 에서키값을삭제하기위해서는삭제권한을가져야한다. (Administrator 도마음대로삭제할수없다.) 2) Inf 파일제거 win2000 은 oemx.inf 라는이름으로존재한다.(X 는가변 ) 3) Inf 파일복사본제거 wind98 의경우 회사명 + inf 명.inf 형태로존재한다. 4) 드라이버제거
9. 드라이버설치와제거 (6) 지워야할레지스트리키의위치 win98 HKEY_LOCAL_MACHINE Enum USB 에서브키로 vid 와 pid 로만들어진키와서브키를삭제 HKEY_LOCAL_MACHINE Software Microsoft Windows Curr entversion Setup SetupX INF OEMName 에서관련된 INF 파일에대한내용을삭제 ( 여기에서지워야할 inf 파일과위치를알수있다 ) win2000 HKEY_LOCAL_MACHINE SYSTEM ControlSet Enum USB 에서브키로 vid 와 pid 로만들어진키와서브키를삭제 HKEY_LOCAL_MACHINE SOFTWARE Microsoft Windows C urrentversion Setup 에서관련된 INF 파일에대한내용을삭제 ( 여기에서지워야할 inf 파일과위치를알수있다 )