CentOS 에서 USB 하드 마운트 시키기

우선 USB 하드를 꼽고, fdisk -l을 입력함.

% fdisk -l
...
Disk /dev/sdb: 1000.2 GB, 1000204886016 bytes
255 heads, 63 sectors/track, 121601 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x03f92b08

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1   *           1      121602   976762528    7  HPFS/NTFS
...

다음 마운트해본다.

% mount /dev/sdb1 /home/usb
mount: unknown filesystem type

ntfs 파일 시스템을 인식못함.

% yum install -y yum-priorities 
% vim /etc/yum/pluginconf.d/priorities.conf
[main]
enabled = 1
check_obsoletes = 1 <-- 추가
priority = 2 <-- 추가

다음 아래 싸이트에 가서 내 시스템에 맞는 rpm을 설치한다.
http://pkgs.repoforge.org/rpmforge-release/

% rpm -ivh http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el6.rf.x86_64.rpm
% yum check-update
% yum install fuse fuse-ntfs-3g dkms dkms-fuse

이제 마운트해본다.

% mount /dev/sdb1 /home/usb

USB to Parallel

요즘PC는 Parallel 포트가 없다.
포트가 있다 하더라도 땜이 안되어 있을것이다.
제목처럼 굳이 이렇게 라도 하고 싶은 이유는 JTAG 디버깅시 Parallel 포트가 필수적이기 때문이다. ㅠ
그래서 일단 USB to Parallel 케이블을 하나 구입한다.

usb_to_parallel

시중에서 9천원 정도면 구입할 수 있다.
다음 PC에 꼽으면 드라이버를 자동 인식하는데, 이는 Windows에 기본으로 내장된 usbprint.sys 를 사용하기 때문.
문제없이 자동 인식 되었다면 우린 아래의 코드를 작성하고 USB를 통해서 Parallel 케이블로 데이타를 내보낸다 혹은 읽는다.

아래의 코드는 물론 테스트 되었고, 코드는 급조한거라 정리가 안되어있다.

// ----------------------------------------
// USB to Parallel example
// by inhak.min@gmail.com
// ----------------------------------------

// How to compile
// c:\> cl usbtoparallel.c setupapi.lib 
//
#include <windows.h>
#include <initguid.h>
#include <winioctl.h>
#include <setupapi.h>
#include <stdlib.h>
#include <stdio.h>

#define USBPRINT_IOCTL_INDEX  0x0000

#define IOCTL_USBPRINT_GET_LPT_STATUS \
	CTL_CODE(FILE_DEVICE_UNKNOWN,  \
	USBPRINT_IOCTL_INDEX+12,\
	METHOD_BUFFERED,  \
	FILE_ANY_ACCESS)                                                           

#define IOCTL_USBPRINT_GET_1284_ID \
	CTL_CODE(FILE_DEVICE_UNKNOWN,  \
	USBPRINT_IOCTL_INDEX+13,\
	METHOD_BUFFERED,  \
	FILE_ANY_ACCESS)                                                           

#define IOCTL_USBPRINT_VENDOR_SET_COMMAND \
	CTL_CODE(FILE_DEVICE_UNKNOWN,  \
	USBPRINT_IOCTL_INDEX+14,\
	METHOD_BUFFERED,  \
	FILE_ANY_ACCESS)                                                           

#define IOCTL_USBPRINT_VENDOR_GET_COMMAND \
	CTL_CODE(FILE_DEVICE_UNKNOWN,  \
	USBPRINT_IOCTL_INDEX+15,\
	METHOD_BUFFERED,  \
	FILE_ANY_ACCESS)                                                           

#define IOCTL_USBPRINT_SOFT_RESET \
	CTL_CODE(FILE_DEVICE_UNKNOWN,  \
	USBPRINT_IOCTL_INDEX+16,\
	METHOD_BUFFERED,  \
	FILE_ANY_ACCESS)                                                           

const GUID GUID_USBPRINT = 
		{ 0x28d78fad, 0x5a12, 0x11D1, 0xae, 0x5b, 
			0x00, 0x00, 0xf8, 0x03, 0xa8, 0xc2};

void main(void)
{	
	unsigned int dataType;
	HANDLE handle;

	HDEVINFO devs;
	DWORD devCount;
	SP_DEVINFO_DATA devInfo;
	SP_DEVICE_INTERFACE_DATA devInterface;
	DWORD size;
	PSP_DEVICE_INTERFACE_DETAIL_DATA interfaceDetail;

	devs = SetupDiGetClassDevs(&GUID_USBPRINT, 0, 0, 
			DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if (devs == INVALID_HANDLE_VALUE) {
		return;
	}

	devCount = 0;
	devInterface.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
	while (SetupDiEnumDeviceInterfaces(devs, 0, &GUID_USBPRINT, 
				devCount, &devInterface)) 
	{
		char driverkey[2048];
		char interfaceName[2048];
		char location[2048];
		char description[2048];

		devCount++;
		size = 0;

		SetupDiGetDeviceInterfaceDetail(devs, &devInterface, 0, 0, &size, 0);
		devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
		interfaceDetail = calloc(1, size);
		if (interfaceDetail) {
			interfaceDetail->cbSize = sizeof (SP_DEVICE_INTERFACE_DETAIL_DATA);
			devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
			if (!SetupDiGetDeviceInterfaceDetail(devs, &devInterface, 
						interfaceDetail, size, 0, &devInfo)) 
			{
				free(interfaceDetail);
				SetupDiDestroyDeviceInfoList(devs);
				return;
			}
			strcpy(interfaceName, interfaceDetail->DevicePath);
			free(interfaceDetail);

			fprintf(stdout, "Parallel port name: %s\n", interfaceName);

			size = sizeof(driverkey);
			driverkey[0] = 0;
			if (!SetupDiGetDeviceRegistryProperty(devs, &devInfo, 
						SPDRP_DRIVER, &dataType, (LPBYTE)driverkey, size, 0)) 
			{
				SetupDiDestroyDeviceInfoList(devs);
				return;
			}
			fprintf(stdout, "Driver key: %s\n", driverkey);

			size = sizeof(location);
			location[0] = 0;
			if (!SetupDiGetDeviceRegistryProperty(devs, &devInfo, 
						SPDRP_LOCATION_INFORMATION, &dataType, 
						(LPBYTE)location, size, 0)) 
			{
				SetupDiDestroyDeviceInfoList(devs);
				return;
			}
			fprintf(stdout, "Location: %s\n", location);

			handle = CreateFile(interfaceName, 
					GENERIC_WRITE|GENERIC_READ, 
					NULL, NULL, OPEN_EXISTING, 0, NULL);
			if (handle != INVALID_HANDLE_VALUE) 
			{
				// 1000번을 쓴다.
				int i;
				for(i=0; i<1000; i++)
				{
					LPWSTR pBuffer;
					SetupDiDestroyDeviceInfoList(devs);
					pBuffer=(LPWSTR)HeapAlloc(GetProcessHeap (), HEAP_ZERO_MEMORY,50);
					pBuffer=L"\n12345678912345678912345678912345678912345/n";
					
					{
						DWORD pcbWritten=0;
						DWORD  cbBuf=49;
						long ret=0;
						ret=WriteFile(handle, pBuffer, cbBuf, &pcbWritten, 0);
						if(ret) printf("\n %d Value Printed", i);
					}

					// http://msdn.microsoft.com/en-us/library/aa506818.aspx
					{
						DWORD numread;
						int return_value;
						return_value = DeviceIoControl(
							(HANDLE)  handle, 
							IOCTL_USBPRINT_SOFT_RESET, // dwIoControlCode
							NULL, // lpInBuffer
							0,  // nInBufferSize
							NULL, // lpOutBuffer
							0, // nOutBufferSize
							&numread, 0);
						if(return_value==0){
							printf("error....\n");
						}
					}
				}

				if(CloseHandle(handle))
					printf("\nPort Closed");
			}
		}
	}

	SetupDiDestroyDeviceInfoList(devs);
}

libusb 초보자 가이드

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

시작하기

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

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

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

2

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

3

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

4

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

5

다음 검색 안 함. 설치할 드라이버를 직접 선택을 선택한다.

6

다음 디스크 있음 을 선택하고, *.inf 파일이 저장된 위치를 선택한다.

7

설치치 libusb0.sys 파일을 요구하는데 libusb-win32-device-bin-xxx\bin 내의 libusb0.sys 파일을 지정한다.

8

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

9

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

10

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

유저 프로그램 작성

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;
}

빌드 및 테스트

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.

libusb의 한계

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