2011년 6월 21일 화요일

Cypress FX2LP USB 인터페이스 Binder

현재 사용중인 환경은 Visual C++ 6.0이지만 아마도 상위 버전에서도 호환 될 것으로 예상된다. Binder는 Cypress 사가 제공하는 Development Suit의 드라이버와 Libusb-win32의 드라이버 모두에서 선택적으로 사용할 수 있도록 제작 되었다. Development Suit에서 제공하는 드라이버는 속도를 위해서 DeviceIOControl을 이용해 구현하였다. 테스트시 Hang On 상태일때 FX2LP 보드를 리셋 시켜야 테스트 프로그램이 정상적으로 종료 되기 때문에 여간 불편한게 아니다. 정상적으로 검증된 응용프로그램이라도 문제가 될 것같아. Libusb-win32를 사용하였다. Libusb-win32를 사용하면 다소 체감 속도는 감소하지만 Hang On 상태에서도 정상적으로 프로그램이 종료되고 다시 실행하면 초기 상태로 되돌아 간다. 이 문제는 USB 통신을 담당하는 thread가 정상적으로 종료되지 않아서 생기는 문제로 속도를 조금 손해 보더라도 테스트 환경을 위해서 libusb-win32를 사용할 것을 권한다.

간단한 사용방법은

int usb_binder::connectDevice(USHORT vid, USHORT pid)

위의 함수를 이용해서 vendor ID와 Product ID에 해당하는 디바이스와 연결하고 나머지 데이터의 통로는 FIFO를 통한 함수로 제공한다.

FX2LP의 포트와 I2C를 제어하기 위한 함수도 제공한다. 물론 FX2LP의 펌웨어 단에서 VRQ_???에 해당하는 command를 구현해주어야 한다. 이 부분은 다음 기회에 정리해서 올리도록 하겠다.

int controlPortA?(BOOL value, BOOL blink);

위의 포트 제어 함수는 value로 On/Off을 제어하고 blink로 1ms단위의 깜빡거림 제어하기 위한 매개변수이다.

int putI2C(UCHAR addr, UCHAR val);
int getI2C(UCHAR addr, UCHAR *val);
int getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val);
int setI2CReg(UCHAR addr, UCHAR reg, UCHAR val);

위의 네 함수는 I2C전송을 위한 함수이다. putI2C와 getI2C는 일반적인 I2C 전송을 목적으로 사용하는 것이고, 나머지 두 함수는 I2C로 디바이스의 내부 제어 레지스터를 읽고 쓸 목적으로 제공하는 함수이다.

가장 근본적인 데이타 전송은 Thread함수 내에 구현 되어 있다. 데이터 전송은 EP2만 사용가능하게 되어있지만 얼마든지 쉽게 수정가능하다. 주의 해야할 것은 NR_BUF와 BUF_SIZE를 적절하게 설정하는 것이다. BUF_SIZE는 한번에 non-EP0를 통해서 통신한 데이터의 크기이다. 최소 크기 512로 설정해 놓으면 모든 곳에서 작동하지만 데이터 처리속도와 효율성 면에서 가능한한 가장 큰 데이터 전송 단위로 설정할 것을 추천한다. 그리고 NR_BUF는 내부 FIFO의 저장 공간을 확보 할때 사용한다. 그 저장 공간은 NR_BUF*BUF_SIZE만큼 할당한다.

********************************** command.h *************************************

#ifndef __COMMANDS_H__
#define __COMMANDS_H__

#define MAX_EP0_PKTSIZE       64 // max size of EP0 packet on FX2

// ----------------------------------------------------------------
// Vendor bmRequestType's
// ----------------------------------------------------------------

#define VRT_VENDOR_IN 0xC0
#define VRT_VENDOR_OUT 0x40

// ----------------------------------------------------------------
//  USRP Vendor Requests
//
// Note that Cypress reserves [0xA0,0xAF].
// 0xA0 is the firmware load function.
// ----------------------------------------------------------------


// IN commands
#define VRQ_GET_STATUS 0x80
//#define VRQ_I2C_READ 0x81 // wIndexL: i2c id

// OUT commands
#define VRQ_PA0_CTRL    0xD0 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA1_CTRL 0xD1 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA3_CTRL 0xD2 // wValueL off/on {0,1}; wIndexL: Auto off/manual off {0, 1}; mLength = 0;
#define VRQ_PA7_CTRL            0xD3
#define VRQ_PE1_CTRL 0xD4
#define VRQ_I2C_WRITE 0xD5 // mValue = 0
// mIndex = addr;
// mLength = 0;
#define VRQ_I2C_READ 0xD6 // mValue = 0
// mIndex = addr;
// mLength = 4;
#define VRQ_I2C_WRITE_REG 0xD7 // mValue = ((USHORT)reg << 8) | (USHORT)val;
// mIndex = addr;
// mLength = 0;
#define VRQ_I2C_READ_REG 0xD8 // mValue = ((USHORT)reg << 8);
// mIndex = addr;
// mLength = 4;

#endif /* _COMMANDS_H_ */


********************************** usb_binder.h *************************************

/* USB Binder for libusb-win32

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/


// usb_binder.h: interface for the usb_binder class.
//
//////////////////////////////////////////////////////////////////////

#ifndef __USB_BINDER_H__
#define __USB_BINDER_H__

#include "../../commands.h"
//#include "../config.h"
//#undef USE_LIBUSB
//#define USE_CYAPI
#define USE_LIBUSB

#if defined(USE_LIBUSB)
# include
#elif defined(USE_CYAPI)
# include
# include
# include
#endif

#include "fifo.h"

class usb_binder
{
public:
void setDataEnable(BOOL enable);
ULONG readBuffer(UCHAR *buf, ULONG bufsize);
ULONG glimpseBuffer(UCHAR *buf, ULONG bufsize);
//void setSize(ULONG bufsize);
ULONG getSize(void);
int controlPortA0(BOOL value, BOOL blink);
int controlPortA1(BOOL value, BOOL blink);
int controlPortA3(BOOL value, BOOL blink);
int controlPortA7(BOOL value, BOOL blink);
//int controlPortE1(BOOL value, BOOL blink);

int putI2C(UCHAR addr, UCHAR val);
int getI2C(UCHAR addr, UCHAR *val);
int getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val);
int setI2CReg(UCHAR addr, UCHAR reg, UCHAR val);

int connectDevice(USHORT vid, USHORT pid);
usb_binder();
virtual ~usb_binder();
private:
fifo_t *mFifo;
int waitPortCtrlDone(void);
int waitI2CDone(void);
UCHAR mCommand;
USHORT mRequest, mValue, mIndex, mLength;
#ifdef USE_LIBUSB
usb_dev_handle *mDevice; /* the device handle */
#elif defined(USE_CYAPI)
HANDLE mDevice;
#endif
BOOL mThreadLooping;
CWinThread *mWinThread;
USHORT mPid;
USHORT mVid;
static UINT Thread(LPVOID params);
UCHAR *mXmitBuf;
HANDLE mMutex;
};

#endif /* __USB_BINDER_H__ */


********************************** usb_binder.cpp *************************************
/* USB Binder for libusb-win32

 Copyright 2011 Hoyoung Yi.

 This program is free software; you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published by 
 the Free Software Foundation; either version 2 of the License, or 
 (at your option) any later version.

 This program is distributed in the hope that it will be useful, but 
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 License for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program; if not, please visit www.gnu.org.
*/

// usb_binder.cpp: implementation of the usb_binder class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "usb_binder.h"
#include

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//#define TEST_ASYNC

#define NR_BUF   (3)
#define BUF_SIZE (1280*1024)

#define CMD_READ_I2C 0x01
#define CMD_WRITE_I2C 0x02
#define CMD_PORT_CTRL 0x04
#define CMD_READ_DATA 0x08

#define USB_ENDP_IN   (0x82)

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

usb_binder::usb_binder()
{
mDevice = NULL;
mWinThread = NULL;
mThreadLooping = TRUE;
mVid = 0;
mPid = 0;
mCommand = 0;
mFifo = NULL;
mXmitBuf = (UCHAR *)malloc(64);
mMutex = CreateMutex(NULL, FALSE, NULL);
}

usb_binder::~usb_binder()
{
DWORD dwBytes;

mThreadLooping = FALSE;

#ifdef USE_CYAPI
if (mDevice) 
DeviceIoControl(mDevice, IOCTL_ADAPT_RESET_PARENT_PORT, NULL, 0, NULL, 0, &dwBytes, NULL);
#endif

Sleep(10);

if (mWinThread) {
CloseHandle(mWinThread->m_hThread);
mWinThread->m_hThread = NULL;
}

if (mFifo) fifo_delete(mFifo);

CloseHandle(mMutex);

free(mXmitBuf);

if (mDevice) CloseHandle(mDevice);
}

static UCHAR portal_buffer[512];
static UCHAR RecvBuff[BUF_SIZE];
static int RecvBuffSize = BUF_SIZE;

#ifdef USE_LIBUSB
/*
* Read/Write using async transfer functions.
*
* NOTE: This function waits for the transfer to complete essentially making
* it a sync transfer function so it only serves as an example of how one might
* implement async transfers into thier own code.
*/
static int transfer_bulk_async(usb_dev_handle *dev,
                               int ep,
                               char *bytes,
                               int size,
                               int timeout)
{
    // Each async transfer requires it's own context. A transfer
    // context can be re-used.  When no longer needed they must be
    // freed with usb_free_async().
    //
    void* async_context = NULL;
    int ret;

    // Setup the async transfer.  This only needs to be done once
    // for multiple submit/reaps. (more below)
    //
    ret = usb_bulk_setup_async(dev, &async_context, ep);
    if (ret < 0)
    {
        printf("error usb_bulk_setup_async:\n%s\n", usb_strerror());
        goto Done;
    }

    // Submit this transfer.  This function returns immediately and the
    // transfer is on it's way to the device.
    //
    ret = usb_submit_async(async_context, bytes, size);
    if (ret < 0)
    {
        printf("error usb_submit_async:\n%s\n", usb_strerror());
        usb_free_async(&async_context);
        goto Done;
    }

    // Wait for the transfer to complete.  If it doesn't complete in the
    // specified time it is cancelled.  see also usb_reap_async_nocancel().
    //
    ret = usb_reap_async(async_context, timeout);

    // Free the context.
    usb_free_async(&async_context);

Done:
    return ret;
}
#endif

UINT usb_binder::Thread(LPVOID params)
{
usb_binder *dlg;
int RecvCount = 0;
int byte_count = 0;
BOOL bPrevContinuous = FALSE;

int success;
int i; 
DWORD dwReturnBytes;

dlg = (usb_binder *)params;

#if defined(USE_LIBUSB)
printf("hello thread\n");
int ret;

for (;dlg->mThreadLooping;) {
if (dlg->mCommand & CMD_READ_I2C) { // send command to read i2c data
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 
dlg->mRequest,
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);

if (ret < 0) {
// error
} else {
for (i = 0; i < dlg->mLength; i++) {
dlg->mXmitBuf[i] = RecvBuff[i];
//printf("%02x ", pExtraData[i]);
}
//putchar('R');

//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_READ_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_WRITE_I2C) { // send command to write i2c data
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, 
dlg->mRequest,
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);
if (ret < 0) {
// error;
} else {
//putchar('W');
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_WRITE_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_PORT_CTRL) { // send command to reset CPLD chip
ret = usb_control_msg(dlg->mDevice,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, 
dlg->mRequest, //VRQ_PA0_CTRL
dlg->mValue,
dlg->mIndex,
(char *)RecvBuff,
dlg->mLength,
100);
if (ret < 0) {
// error
printf("CMD_PORT_CTRL error");
} else {
putchar('P');

//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /* retval == WAIT_OBJECT_0 */) {
dlg->mCommand &= ~CMD_PORT_CTRL;
}
//ReleaseMutex(dlg->m_hMutex[i]);
Sleep(0);
}
}
if (dlg->mCommand & CMD_READ_DATA) {
RecvBuffSize = BUF_SIZE;
#ifdef TEST_ASYNC
// Running an async read test
ret = transfer_bulk_async(dlg->mDevice, USB_ENDP_IN, (char *)RecvBuff, RecvBuffSize, 100);
#else
// Running a sync read test
ret = usb_bulk_read(dlg->mDevice, USB_ENDP_IN, (char *)RecvBuff, RecvBuffSize, 100);
#endif
if (ret < 0) {
//printf("error reading:\n%s\n", usb_strerror());
} else {
byte_count += ret;
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /*retval == WAIT_OBJECT_0*/) {
fifo_fill(dlg->mFifo, RecvBuff, ret);
}
//ReleaseMutex(dlg->m_hMutex[i]);
putchar('D');
}
}
//Sleep(0);
}
#elif defined(USE_CYAPI)

union  {
struct {
UCHAR Recipient:5; 
UCHAR Type:2; 
UCHAR Direction:1; 
} bmRequest; 
UCHAR bmReq; 
};
SINGLE_TRANSFER *pSingleTransfer;
UCHAR *pExtraData;
OVERLAPPED ov;

//pSingleTransfer = (SINGLE_TRANSFER *)malloc(sizeof(SINGLE_TRANSFER)+64);
pSingleTransfer = (SINGLE_TRANSFER *)portal_buffer;

/*
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 
*/
printf("hello thread\n");

for (;dlg->mThreadLooping;) {
//printf(".");

if (dlg->mCommand & CMD_READ_I2C) { // send command to read i2c data
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_FROM_DEVICE; // IN command (from  Device to Host) 
memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER)+dlg->mLength);
pSingleTransfer->SetupPacket.bmRequest = bmReq;
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest; //VRQ_I2C_READ;
pSingleTransfer->SetupPacket.wValue = dlg->mValue;
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex;
pSingleTransfer->SetupPacket.wLength = dlg->mLength;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER); //+dlg->mLength;
pSingleTransfer->BufferLength = dlg->mLength; 
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
if (!DeviceIoControl(dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER)+dlg->mLength,
pSingleTransfer, sizeof(SINGLE_TRANSFER)+dlg->mLength,
&dwReturnBytes,  NULL)) {
printf("VRQ_I2C_READ error\n");
//printf("dwReturnBytes%c, 0x%04x \n", dwReturnBytes, pSingleTransfer->SetupPacket.wValue);
} else {
//printf("VRQ_I2C_READ complete\n");
pExtraData = (UCHAR *)(pSingleTransfer+1);
for (i = 0; i < dlg->mLength; i++) {
dlg->mXmitBuf[i] = pExtraData[i];
//printf("%02x ", pExtraData[i]);
}
//printf("R");
}
dlg->mCommand &= ~CMD_READ_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_WRITE_I2C) { // send command to write i2c data
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->SetupPacket.bmRequest = bmReq; 
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest; //VRQ_I2C_WRITE;
pSingleTransfer->SetupPacket.wValue = dlg->mValue;
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex;
pSingleTransfer->SetupPacket.wLength = dlg->mLength;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER); 
pSingleTransfer->BufferLength = dlg->mLength;
//printf("VRQ_I2C_WRITE: wValue(%04x), wIndex(0x%04x), wLength(0x%04x)\n", dlg->mValue, dlg->mIndex, dlg->mLength);
if (!DeviceIoControl(dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER),
pSingleTransfer, sizeof(SINGLE_TRANSFER),
&dwReturnBytes,  NULL)) {
printf("VRQ_I2C_WRITE error\n");
} else {
// printf("VRQ_I2C_WRITE complete\n");
//printf("W");
}
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
dlg->mCommand &= ~CMD_WRITE_I2C;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_PORT_CTRL) { // send command to reset CPLD chip
bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->SetupPacket.bmRequest = bmReq; 
pSingleTransfer->SetupPacket.bRequest = dlg->mRequest;//VRQ_PA0_CTRL;
pSingleTransfer->SetupPacket.wValue = dlg->mValue; // port on
pSingleTransfer->SetupPacket.wIndex = dlg->mIndex; // auto inv
pSingleTransfer->SetupPacket.wLength = 0;
pSingleTransfer->SetupPacket.ulTimeOut = 2;
pSingleTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pSingleTransfer->IsoPacketLength = 0; 
pSingleTransfer->BufferOffset = sizeof(SINGLE_TRANSFER);
pSingleTransfer->BufferLength = 0; 
if (!DeviceIoControl (dlg->mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pSingleTransfer, sizeof(SINGLE_TRANSFER),
pSingleTransfer, sizeof(SINGLE_TRANSFER),
&dwReturnBytes,  NULL)) {
printf("VRQ_SEND_RESET error\n");
} else {
// printf("VRQ_SEND_RESET complete\n");
printf("P");
}
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1/*retval == WAIT_OBJECT_0*/) {
dlg->mCommand &= ~CMD_PORT_CTRL;
}
//ReleaseMutex(dlg->m_hMutex[i]);
}

if (!(dlg->mThreadLooping)) break;

if (dlg->mCommand & CMD_READ_DATA) {
RecvBuffSize = 512; //BUF_SIZE;
memset(pSingleTransfer, 0, sizeof(SINGLE_TRANSFER));
pSingleTransfer->ucEndpointAddress = USB_ENDP_IN;
pSingleTransfer->IsoPacketLength = 0;
pSingleTransfer->BufferOffset = 0;
pSingleTransfer->BufferLength = 0;

success = DeviceIoControl(dlg->mDevice,
IOCTL_ADAPT_SEND_NON_EP0_DIRECT,
pSingleTransfer, sizeof(SINGLE_TRANSFER),
RecvBuff, RecvBuffSize,
&dwReturnBytes, NULL); 
//printf("red %d ", dwReturnBytes);
if (success && dwReturnBytes > 0) {
byte_count += RecvBuffSize;
//DWORD retval = WaitForSingleObject(dlg->m_hMutex[i], 0);
if (1 /*retval == WAIT_OBJECT_0*/) {
fifo_fill(dlg->mFifo, RecvBuff, RecvBuffSize);
}
//ReleaseMutex(dlg->m_hMutex[i]);
printf("D");
}
//if (!dlg->mThreadLooping) break;
}
}

// free(pSingleTransfer);
printf("exit thread\n");
dlg->mWinThread = NULL;

#endif

return TRUE;
}

#define MAX_DEVICE_NUMBER 10

int usb_binder::connectDevice(USHORT vid, USHORT pid)
{
if (mDevice) {
AfxMessageBox("Already connected device !!!", MB_ICONINFORMATION|MB_OK);
return -1;
}

#if defined(USE_LIBUSB)
int i, j, l, k;
// USB interface setting
struct usb_bus *bus;
struct usb_device *dev;
int udev_config = 1;
int udev_interface = 0;
usb_init(); /* initialize the library */
usb_find_busses(); /* find all busses */
usb_find_devices(); /* find all connected devices */

printf("Hello Libusb-win32\n");
for (bus = usb_get_busses(); bus; bus = bus->next) {
for (dev = bus->devices; dev; dev = dev->next) {
printf("VID_%04X, PID_%04X\r\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
if (dev->descriptor.idVendor == vid && dev->descriptor.idProduct == pid) {
printf("\"%s\"\r\n", dev->filename);
printf("Descriptor\r\n");
printf("VID_%04X, PID_%04X\r\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
printf("%d Configuration\r\n", i);
for (j = 0; j < dev->config[i].bNumInterfaces; j++) {
printf(" %d Interface\r\n", j);
for (l = 0; l < dev->config[i].interface[j].num_altsetting; l++) {
printf("  %d altsetting\r\n", l);
for (k = 0; k < dev->config[i].interface[j].altsetting[l].bNumEndpoints; k++) {
printf("   %d Endpoint\r\n", k);
printf("    Address : 0x%0X\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].bEndpointAddress);
printf("    Attribute : 0x%0X\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].bmAttributes);
printf("    MaxPacketSize : %d\r\n", dev->config[i].interface[j].altsetting[l].endpoint[k].wMaxPacketSize);
}
}
}
}
mDevice = usb_open(dev);
// goto __next_step;
}
}
}

//__next_step:;

if (mDevice) {
if (!(usb_set_configuration(mDevice, udev_config) < 0)) {
printf("Setting config %d\r\n", udev_config);
if (!(usb_claim_interface(mDevice, udev_interface) < 0)) {
printf("Claiming interface %d\r\n", udev_interface);
} else {
printf("error: claiming interface %d failed\r\n", udev_interface);
usb_close(mDevice);
mDevice = NULL;
}
} else {
printf("error: setting config %d failed\r\n", udev_config);
usb_close(mDevice);
mDevice = NULL;
}

if (mDevice) {
// need reset fifo
//usb_reset(mDevice);
usb_resetep(mDevice, USB_ENDP_IN);
//usb_clear_halt(mDevice, USB_ENDP_IN);

mVid = vid;
mPid = pid;

mFifo = fifo_create(BUF_SIZE*NR_BUF);

mWinThread = AfxBeginThread(Thread, this, THREAD_PRIORITY_NORMAL /* THREAD_PRIORITY_ABOVE_NORMAL,  THREAD_PRIORITY_HIGHEST */);
return 0;
}
// Syncronize tick
} else {
printf("error: device not found!\r\n");
}

#elif defined(USE_CYAPI)

char devPath[80];

sprintf(devPath, "\\\\?\\usb#vid_%04x&pid_%04x#", vid, pid);

HDEVINFO hwDeviceInfo = SetupDiGetClassDevs((LPGUID) &CYUSBDRV_GUID, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE); 
if (hwDeviceInfo != INVALID_HANDLE_VALUE) {
SP_DEVICE_INTERFACE_DATA devInterfaceData; 
devInterfaceData.cbSize = sizeof(devInterfaceData);

for (int devNumber = 0; devNumber < MAX_DEVICE_NUMBER; devNumber++) {
if (!SetupDiEnumDeviceInterfaces(hwDeviceInfo, 0, (LPGUID) &CYUSBDRV_GUID, devNumber, &devInterfaceData))
break;

SP_DEVINFO_DATA deviceInfoData; 
memset(&deviceInfoData, 0, sizeof(SP_DEVINFO_DATA)); 
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

PSP_DEVICE_INTERFACE_DETAIL_DATA deviceInterfaceDetailData; 
ULONG requiredLength = 0, reservedLength = 0, realLength = 0; 

if (!SetupDiGetDeviceInterfaceDetail(hwDeviceInfo, &devInterfaceData, NULL, 0, &requiredLength, NULL)) { 
int errorCode = GetLastError();
if (errorCode != ERROR_INSUFFICIENT_BUFFER) {
printf("SetupDiGetDeviceInterfaceDetail() failed.\n");
//AfxMessageBox("ERROR CODE %d (0x%X)\r\n", errorCode, errorCode);
break;
}
}
reservedLength = requiredLength; 
deviceInterfaceDetailData = (PSP_INTERFACE_DEVICE_DETAIL_DATA) new char[reservedLength]; 
memset(deviceInterfaceDetailData, 0, reservedLength); 
deviceInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
realLength = reservedLength; 
if (SetupDiGetDeviceInterfaceDetail(hwDeviceInfo, &devInterfaceData, deviceInterfaceDetailData, reservedLength, &realLength, &deviceInfoData)) { 
if (!memcmp(deviceInterfaceDetailData->DevicePath, devPath, strlen(devPath))) {
mDevice = CreateFile(deviceInterfaceDetailData->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); 
}
} else { 
int error = ::GetLastError(); 
printf("SetupDiGetDeviceInterfaceDetail() is failed.\n");
break;

delete deviceInterfaceDetailData; 
deviceInterfaceDetailData = NULL;
if (mDevice) break;
}
SetupDiDestroyDeviceInfoList(hwDeviceInfo);

if (mDevice) {
DWORD dwBytes = 0; 
ULONG driver_version;
ULONG usdi_version;
UCHAR device_address;
UCHAR intfc = 0; 
UCHAR alt; 
UCHAR device_name[256], device_friendly_name[256]; 
ULONG device_speed;
UCHAR endPts; 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DRIVER_VERSION, 
&driver_version, sizeof (driver_version),      
&driver_version, sizeof (driver_version), 
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_USBDI_VERSION, 
&usdi_version, sizeof (usdi_version),      
&usdi_version, sizeof (usdi_version), 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DEVICE_NAME, 
device_name, 256, 
device_name, 256, 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_FRIENDLY_NAME,
device_friendly_name, 256,
device_friendly_name, 256,
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_ADDRESS, 
&device_address, sizeof (UCHAR),      
&device_address, sizeof (UCHAR), 
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_DEVICE_SPEED,
&device_speed, sizeof (ULONG),
&device_speed, sizeof (ULONG),
&dwBytes, NULL);

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_ALT_INTERFACE_SETTING, 
&intfc, sizeof (intfc), 
&alt, sizeof (alt), 
&dwBytes, NULL); 

DeviceIoControl(mDevice, IOCTL_ADAPT_GET_NUMBER_ENDPOINTS, 
NULL, 0,
&endPts, sizeof (endPts),
&dwBytes, NULL);

assert(endPts > 0);
printf("driver version: %x\n", driver_version);
printf("usdi version: %x\n", usdi_version);
printf("device name: %s\n", device_name);
printf("device friendly name: %s\n", device_friendly_name);
printf("device speed: %d\n", device_speed);
printf("device address: %d\n", device_address);
printf("intfc: %d, alt: %d\n", intfc, alt);
  printf("endpoint number: %d\n", endPts);

DWORD BytesXfered;
// Define Transfer Size
SET_TRANSFER_SIZE_INFO SetTransferInfo; 
SetTransferInfo.EndpointAddress = USB_ENDP_IN;
//SetTransferInfo.TransferSize = 3*m_FrameSize;
SetTransferInfo.TransferSize = 0x2000;

DeviceIoControl(mDevice, IOCTL_ADAPT_SET_TRANSFER_SIZE,
&SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
&SetTransferInfo, sizeof(SET_TRANSFER_SIZE_INFO),
&BytesXfered,  NULL); 

DeviceIoControl(mDevice,  IOCTL_ADAPT_GET_TRANSFER_SIZE, 
&SetTransferInfo,  sizeof (SET_TRANSFER_SIZE_INFO), 
&SetTransferInfo,  sizeof (SET_TRANSFER_SIZE_INFO), 
&BytesXfered,  NULL); 

LONG transferSz = SetTransferInfo.TransferSize; 
printf("transfer size: %d\n", transferSz);

#if 0
// send reset signal
union  { 
struct   { 
UCHAR Recipient:5; 
UCHAR  Type:2; 
CHAR Direction:1; 
} bmRequest; 
UCHAR bmReq; 
}; 

bmRequest.Recipient = TGT_DEVICE; //  Device 
bmRequest.Type      = REQ_VENDOR; //  Vendor 
bmRequest.Direction = DIR_TO_DEVICE; // IN command (from  Device to Host) 

int iXmitBufSize = sizeof(SINGLE_TRANSFER);  //  The size of the two-part structure 
UCHAR *pXmitBuf = new UCHAR[iXmitBufSize];            //  Allocate the memory 
ZeroMemory(pXmitBuf, iXmitBufSize); 

PSINGLE_TRANSFER pTransfer = (PSINGLE_TRANSFER)pXmitBuf;  //  The SINGLE_TRANSFER comes first 

pTransfer->SetupPacket.bmRequest = bmReq; 
pTransfer->SetupPacket.bRequest = VRQ_SEND_RESET;
pTransfer->SetupPacket.wValue = 0; 
pTransfer->SetupPacket.wIndex = 0; 
pTransfer->SetupPacket.wLength = 0; 
pTransfer->SetupPacket.ulTimeOut = 100;
pTransfer->ucEndpointAddress = 0x00;     //  Control pipe 
pTransfer->IsoPacketLength = 0; 
pTransfer->BufferOffset = sizeof (SINGLE_TRANSFER); 
pTransfer->BufferLength = 0; 
DWORD dwReturnBytes; 

DeviceIoControl (mDevice, IOCTL_ADAPT_SEND_EP0_CONTROL_TRANSFER, 
pXmitBuf,  iXmitBufSize, 
pXmitBuf,  iXmitBufSize, 
&dwReturnBytes,  NULL); 
delete [] pXmitBuf;
Sleep(10);
#endif
DeviceIoControl(mDevice, IOCTL_ADAPT_RESET_PARENT_PORT, NULL, 0, NULL, 0, &dwBytes, NULL);

mVid = vid;
mPid = pid;

mFifo = fifo_create(BUF_SIZE*NR_BUF);

mWinThread = AfxBeginThread(Thread, this, THREAD_PRIORITY_NORMAL);

return 0;
} else {
printf("Device connection failed!!!\n");
}
}
#else
# error "unknown device driver!"
#endif

return -1;
}

int usb_binder::putI2C(UCHAR addr, UCHAR val)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_I2C_WRITE;
mValue = val;
mIndex = addr;
mLength = 0;
mCommand |= CMD_WRITE_I2C;
Sleep(1);
while (mCommand & CMD_WRITE_I2C); // putchar('c');
return 0;
}

int usb_binder::getI2C(UCHAR addr, UCHAR *val)
{
if (!(mDevice && mWinThread)) {
*val = 0;
return -1;
}
mRequest = VRQ_I2C_READ;
mValue = 0;
mIndex = addr;
mLength = 2; // the number of returned bytes
mCommand |= CMD_READ_I2C;
Sleep(1);
while (mCommand & CMD_READ_I2C);
if ((addr == mXmitBuf[0])) {
*val = mXmitBuf[1];
return 0;
}
printf("receiveI2C error\n");
*val = 0;
return -1;
}

int usb_binder::setI2CReg(UCHAR addr, UCHAR reg, UCHAR val)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_I2C_WRITE_REG;
mValue = ((USHORT)reg << 8) | (USHORT)val;
mIndex = addr;
mLength = 0;
mCommand |= CMD_WRITE_I2C;
Sleep(1);
while (mCommand & CMD_WRITE_I2C);
return 0;
}

int usb_binder::getI2CReg(UCHAR addr, UCHAR reg, UCHAR *val)
{
if (!(mDevice && mWinThread)) {
*val = 0;
return -1;
}
mRequest = VRQ_I2C_READ_REG;
mValue = ((USHORT)reg << 8);
mIndex = addr;
mLength = 4; // the number of returned bytes
mCommand |= CMD_READ_I2C;
Sleep(1);
while (mCommand & CMD_READ_I2C);
/*
if ((reg == mXmitBuf[1]) && (addr == mXmitBuf[0])) {
*val = mXmitBuf[2];
return 0;
}
printf("receiveI2C error\n");
*/
*val = mXmitBuf[2];
return -1;
}

int usb_binder::controlPortA0(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA0_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA0");
return 0;
}

int usb_binder::controlPortA1(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA1_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA1 error");
return 0;
}

int usb_binder::controlPortA3(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA3_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA3 error");
return 0;
}

int usb_binder::controlPortA7(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PA7_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortA7 error");
return 0;
}

#if 0
int usb_binder::controlPortE1(BOOL value, BOOL blink)
{
if (!(mDevice && mWinThread)) return -1;
mRequest = VRQ_PE1_CTRL;
if (value) mValue = 1;
else mValue = 0;
if (blink) mIndex = 0;
else mIndex = 1;
mLength = 0;
mCommand |= CMD_PORT_CTRL;
Sleep(1);
while (mCommand & CMD_PORT_CTRL);
//puts("controlPortE1 error");
return 0;
}
#endif

int usb_binder::waitI2CDone() 
{
while (mCommand & (CMD_READ_I2C | CMD_WRITE_I2C));
return 0;
}

int usb_binder::waitPortCtrlDone()
{
while (mCommand & (CMD_PORT_CTRL));
return 0;
}

ULONG usb_binder::getSize(void)
{
if (!(mDevice && mWinThread)) return 0;
return fifo_filled_bytes(mFifo);
}

ULONG usb_binder::readBuffer(UCHAR *buf, ULONG bufsize)
{
ULONG fifo_len;

if (!(mDevice && mWinThread)) return 0;

fifo_len = fifo_filled_bytes(mFifo);
if (fifo_len >= bufsize) {
fifo_bring(buf, bufsize, mFifo);
return bufsize;
}
return 0;
}

ULONG usb_binder::glimpseBuffer(UCHAR *buf, ULONG bufsize)
{
ULONG fifo_len;

if (!(mDevice && mWinThread)) return 0;

fifo_len = fifo_filled_bytes(mFifo);
if (fifo_len >= bufsize) {
fifo_copy(buf, bufsize, mFifo);
return bufsize;
}
return 0;

}

void usb_binder::setDataEnable(BOOL enable)
{
if (!(mDevice && mWinThread)) return;
if (enable) mCommand |= CMD_READ_DATA;
else mCommand &= ~CMD_READ_DATA;
}

댓글 없음:

댓글 쓰기