2012년 5월 8일 화요일

libusb 가이드

출처 : http://wiki.tcltk.co.kr/wiki.php/libusb


이 문서는 libusb를 사용하고자 하는 분들을 위한 초보자 가이드입니다.

1 시작하기 

libusb는 커널 레벨이 아닌 유저 영역에서 USB 드라이버를 개발시 사용되는 오픈소스 라이브러리입니다. libusb는 USB 호스트가 동작하지 않는다면 무용지물인 라이브러리입니다. 이 글은 윈도우즈를 기준으로 설명합니다.

2 inf 생성하기 

이 글을 작성 하기 위해 이나릿 시스템의 iNCITE 하드웨어를 이용하였습니다. iNCITE는 USB 2.0 인터페이스를 제공하는, FPGA 디자인을 검증하기 위한 Xilinx사의 Spratan과 그외 다양한 장치를 지원하는 디자인 검증 플랫폼입니다. 우선 위의 싸이트에서 libusb-win32-device-bin-xxx.tar.gz 와 libusb-win32-filter-bin-xxx.exe 를 다운 받습니다. libusb-win32-filter-bin-xxx.exe 를 설치하고, Test Program 을 수행하면 현재 사용가능한 USB 장치가 나열됩니다.

1.png

다음 libusb-win32-device-bin-xxx.tar.gz 압축을 풀어, bin 디렉토리내의 inf-wizard.exe 를 수행합니다. 이 단계에서 *.inf 파일을 생성합니다. 우선 제작할 드라이버의 하드웨어를 켜주시기 바랍니다.

2.png

위의 화면에서 보시는바와 같이 새로운 하드웨어(iNCITE) 가 보여질겁니다. 선택후 다음 버튼을 눌러 Manfacture Name과 Device Name을 지정합니다.

3.png

다음을 누르시면 화면의 보여지는 정보로 지정한 위치로 *.inf 파일이 생성됩니다. 여기서는 D:\iVORY 로 지정하였습니다.

4.png

이제 생성된 *.inf 파일을 로딩해봅니다. 하드웨어를 리셋합니다. 그러면 새로운 USB 장치를 로딩하기위한  하드웨어 검색 마법사 화면이 나타납니다.

5.png

다음 색 안함. 설치할 드라이버를 직접 선택 합니다.

6.png

다음 스크 있음 을 누르시고, *.inf 파일이 저장된 위치를 선택합니다.

7.png

설치치 libusb0.sys 파일을 요구합니다. libusb-win32-device-bin-xxx\bin 내의 libusb0.sys 파일을 지정합니다.

8.png

설치가 완료됩니다. 이제 처음 수행했던 Test Program을 다시 실행합니다.

9.png

치 관리자 에서도 인식이 됨을 알 수 있습니다.

10.png

하드웨어가 인식되고, USB 통신을 코드를 작성 하기 위한 준비 단계는 완료되었습니다.

3 유저 프로그램 작성 

libusb-win32-device-bin-xxx\examples 를 보면 기본 예제가 있습니다. 우선 작업 디렉토리인 D:\iVORY 로 위의 예제 파일인 bulk.c 를 복사합니다. 다음 bulk.c 파일의 MY_VID와 MY_PIC 를 수정합니다. 참고로 MY_VID는 Vendor ID, MY_PID는 Product ID 입니다. 그외 usb_bulk_write, usb_bulk_read, usb_control_msg 를 사용하여 데이타를 송/수신합니다. 아래의 예는 bulk.c 를 수정한 파일로 iNCITE의 카드 아이디(CID) 정보를 읽어냅니다.

#include <usb.h>
#include <stdio.h>

/* the device's vendor and product id */
#define MY_VID      0x1A89  // iNCITE
#define MY_PID      0x3000  // iNCITE

/* the device's endpoints */
#define EP_IN      0x81
#define EP_OUT      0x01

#define BUF_SIZE     64

#define USB_DIR_IN    0x80
#define USB_DIR_OUT    0x00

#define VENDOR_REQUEST_IVORY  0x54  // iNCITE

usb_dev_handle *open_dev(void);

usb_dev_handle *open_dev(void)
{
 struct usb_bus *bus;
 struct usb_device *dev;

 for(bus = usb_get_busses(); bus; bus = bus->next)
 {
  for(dev = bus->devices; dev; dev = dev->next)
  {
   if(dev->descriptor.idVendor == MY_VID
    && dev->descriptor.idProduct == MY_PID)
   {
    fprintf(stdout, "Found device: 0x%x:0x%x\n", MY_VID, MY_PID);
    fprintf(stdout, "Device filename: %s\n", dev->filename);
    fprintf(stdout, "Bus dirname: %s\n", bus->dirname);

    usb_dev_handle *fdev;
    fdev = usb_open(dev);

    char string[50];
    usb_get_string_simple(fdev, dev->descriptor.iManufacturer, string, sizeof(string));
    fprintf(stdout, "Device Manfucaturer : %s\n" ,string);
    usb_get_string_simple(fdev, dev->descriptor.iProduct, string, sizeof(string));
    fprintf(stdout, "Product Name : %s\n", string);
    usb_get_string_simple(fdev, dev->descriptor.iSerialNumber, string, sizeof(string));
    fprintf(stdout, "Device Serial Number: %s\n", string);

    return fdev;
   }
  }
 }

 return NULL;
}

// Device I/O control
int ivory_get_cid(usb_dev_handle *dev)  // iNCITE
{
 #define HIU_CID     0x054

 int ret = 0;
 unsigned char buf[BUF_SIZE];

 ret = usb_control_msg(dev,
  USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,  // __u8 requesttype
  VENDOR_REQUEST_IVORY,         // __u8 request
  HIU_CID,            // __u16 value
  0,              // __u16 index
  buf,             // void *data
  sizeof(int),           // __u16 size
  5000             // int timeout
 );

 return *buf;
}

int main(void)
{
 usb_dev_handle *dev = NULL; /* the device handle */

 usb_init(); /* initialize the library */
 usb_find_busses(); /* find all busses */
 usb_find_devices(); /* find all connected devices */

 if(!(dev = open_dev()))
 {
  printf("error: device not found!\n");
  return 0;
 }

 if(usb_set_configuration(dev, 1) < 0)
 {
  printf("error: setting config 1 failed\n");
  usb_close(dev);
  return 0;
 }

 if(usb_claim_interface(dev, 0) < 0)
 {
  printf("error: claiming interface 0 failed\n");
  usb_close(dev);
  return 0;
 }

 // ---------------------------------------
 int cid;
 cid = ivory_get_cid(dev);

 fprintf(stdout, "CID: %d\n", cid);
 // ---------------------------------------

 usb_release_interface(dev, 0);
 usb_close(dev);

 return 0;
}

4 빌드 및 테스트 

Makefile을 아래와 같이 간단히 작성합니다.
all:
 gcc -g -o bulk.exe -I../libusb-win32-device-bin-0.1.12.1/include bulk.c ../libusb-win32-device-bin-0.1.12.1/lib/gcc/libusb.a

clean:
 rm -rf *.o *.exe
컴파일후 생성된 bulk.exe를 수행하면 iNCITE의 현재 CID 정보를 리턴합니다.
[Administrator@MYMAIN /d/ivory]$ ./bulk.exe
Found device: 0x1a89:0x3000
Device filename: \\.\libusb0-0003--0x1a89-0x3000
Bus dirname: bus-0
Device Manfucaturer : Dynalith
Product Name : iVORY
Device Serial Number: ?
CID: 1
이 코드를 컴파일한 환경은 다음과 같습니다.
gcc.exe (GCC) 3.4.5 (mingw-vista special r3)
Copyright (C) 2004 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

5 libusb의 한계 

  • USB 장치의 insert/remove 처리가 까다로울 수 있다.
  • libusb는 유저 레벨에서 제어하므로, 실시간 처리와 관계되는 isochronous transfer, interrupt transfer를 지원하기는 어려움이 있다. 즉, kernel module 없이 간단한 USB 장치를 제어하는데 좋다.

댓글 없음:

댓글 쓰기