/************************************************************
**
**  HA_USBDeviceObject.cpp
**
**  History :
**     2013.08.01 K.Takagi     新規作成
**
**  Description
**  -----------
**  RASP-LCシリーズからのデータ読み出し
**
**     Copyright (c) 2013
**     System In Frontier,Inc.
**     All rights reserved. 
**
**     当社の許可なしに複製および転載を禁ず
**
*/

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <poll.h>

#include "HA_log.h"
#include "HA_USBDeviceObject.h"

namespace HARKAndroid {

// You can use any device, but will be first detected device
int USBDeviceObject::InitDevice()
{
    return InitDevice(0x0000, 0x0000, 0xffff);
}

// You can use specified vid/pid device only
int USBDeviceObject::InitDevice(int vid, int pid, int pid_mask)
{
    int ret;
    ret = FindUSBDeviceAndSet(vid, pid, pid_mask, 1);
    //ret = FindUSBDeviceAndSet(0x23a7, 0xf100, 0xff00, 1); // RASP-ZX (dynamic PID by mic module counts)
    //ret = FindUSBDeviceAndSet(0x1415, 0x2000, 0xffff, 1); // Sony PS3 PS-Eye
    //ret = FindUSBDeviceAndSet(0x0458, 0x708c, 0xffff, 1); // iBuffalo BSW20KM11 (NG)
    //ret = FindUSBDeviceAndSet(0x2212, 0x0001, 0xffff, 1); // micro cone (NG)
    printf("FindUSBDeviceAndSet : %d\n", ret);
    //ret = SetConfiguration(0);
    //printf("SetConfiguration(0) : %d\n", ret);
    //ret = SetConfiguration(1);
    //printf("SetConfiguration(1) : %d\n", ret);
    //usb_device_info.interface_no = 1;
    //usb_device_info.address = 0x81;
    //usb_device_info.max_packet_size = 459;
    ret = USBClaimInterface(usb_device_info.interface_no, 1); // force mode
    printf("USBClaimInterface : %d\n", ret);
    ret = SetInterface(usb_device_info.interface_no, 1);
    printf("SetInterface : %d\n", ret);
    return 0;
}

int USBDeviceObject::ReleaseDevice()
{
    ReleaseInterface(1);
    USBDeviceClose();
    return 0;
}

int USBDeviceObject::CreateUSBDeviceList()
{
    char busdirname[32], devdirname[32]; // maybe correct case's max size is 20 chars.
    DIR *busdir, *devdir;
    struct dirent *dir_entry;
    int list_index = 0; // USB device counts must be less than 127. (exclude host)
    int skip;
    char *name_p;
    busdir = opendir("/dev/bus/usb");
    if(!busdir){ return -1; } // /dev/bus/usb not found.
    while((dir_entry = readdir(busdir)) && list_index < 128){
        skip = 0;
        name_p = dir_entry->d_name;
        while(*name_p){ // bus dir name must be digits.
            if(*name_p < 0x30 && *name_p > 0x39){ skip = 1; break; }
            name_p++;
        }
        if(skip){ continue; }
        snprintf(busdirname, sizeof(busdirname), "/dev/bus/usb/%s", dir_entry->d_name);
        devdir = opendir(busdirname);
        while((dir_entry = readdir(devdir)) && list_index < 128){
            skip = 0;
            name_p = dir_entry->d_name;
            while(*name_p){ // dev dir name must be digits.
                if(*name_p < 0x30 && *name_p > 0x39){ skip = 1; break; }
                name_p++;
            }
            if(skip){ continue; }
            snprintf(devdirname, sizeof(devdirname), "%s/%s", busdirname, dir_entry->d_name);
            strcpy(device_list[list_index], devdirname);
            list_index++;
        }
        closedir(devdir);
    }
    closedir(busdir);
    device_count = list_index;
    return list_index; // return found device count. if return was negative value, it error occured.
}

// pid_mask for same vendor's product id checking. example) pid=0x1234, pid_mask=0xff00 => pid=0x12?? ?? is don't care.
int USBDeviceObject::FindUSBDeviceAndSet(unsigned int vid, unsigned int pid, unsigned int pid_mask, int create_list)
{
    int ret;
    unsigned int get_vid, get_pid;
    if(create_list){ CreateUSBDeviceList(); }
    if(device_count <= 0 || device_count > 128){ return -1; } // usb device not found.
    for(int i = device_count - 1; i >= 0; i--){
        ret = USBDeviceOpen(device_list[i]);
        if(ret < 0){ continue; }
        get_vid = GetVendorID();
        get_pid = GetProductID();
        printf("FoundDevice(VID, PID) : (%04x, %04x)\n", get_vid, get_pid);
        if((!vid && !pid && inf_ok && ep_ok) || vid == get_vid && (pid & pid_mask) == (get_pid & pid_mask)){
            if(usb_device_info.is_writeable){ return 0; }
            else{
                if(TryEnableWriteMode() == 0){ return 0; } // success, changed from read only to writeable.
                //else{ return -1; } // if comment-out this line, try search other device. if comment-in this line, return fail code.
            }
        } // target vid/pid device found.
        USBDeviceClose();
    }
    return -1; // target vid/pid device not found.
}

int USBDeviceObject::USBDeviceOpen(const char *dev_name)
{
    int ret, fd, is_writeable;
    for(int max_retry = 1; max_retry >= 0; max_retry--){
        //printf("Try writeable mode\n");
        is_writeable = 1;
        fd = ::open(dev_name, O_RDWR);
        if(fd < 0){
            //printf("Try read only mode\n");
            is_writeable = 0;
            fd = ::open(dev_name, O_RDONLY);
            if(fd < 0){ sleep(1); }
        }
    }
    if(fd < 0){ return -1; }
    usb_device_info.fd = fd;
    usb_device_info.is_writeable = is_writeable;
    ret = USBDeviceNew(dev_name);
    printf("USB device opened.\n");
    return ret; // ret == 0 is success, ret == -1 is failed and fd was already closed.
}

int USBDeviceObject::USBDeviceClose()
{
    ::close(usb_device_info.fd);
    usb_device_info.fd = -1;
    usb_device_info.is_writeable = 0;
    usb_device_info.dev_name[0] = 0;
    usb_device_info.desc[0] = 0;
    usb_device_info.desc_length = 0;
    printf("USB device closed.\n");
    return 0;
}

int USBDeviceObject::USBDeviceNew(const char *dev_name)
{
    int length;
    if(lseek(usb_device_info.fd, 0, SEEK_SET) != 0){
        printf("SEEK_SET error\n");
        USBDeviceClose();
        return -1;
    }
    if((length = read(usb_device_info.fd, usb_device_info.desc, 4096)) < 0){
        printf("4096 Bytes read error : %d\n", length);
        USBDeviceClose();
        return -1;
    }
    printf("read success : %d\n", length);
    inf_ok = 0; ep_ok = 0;

    int debug_msg = 1;
    int continue_loop = 1;
    int remain_size = length;
    char *cur_p = (char *) usb_device_info.desc;
    struct usb_descriptor_header* header_desc;
    struct usb_device_descriptor* dev_desc;
    struct usb_config_descriptor* conf_desc;
    struct usb_interface_descriptor* inf_desc;
    struct usb_endpoint_descriptor* ep_desc;
    struct usb_qualifier_descriptor* qual_desc;
    struct usb_otg_descriptor* otg_desc;
    struct usb_debug_descriptor* debug_desc;
    struct usb_interface_assoc_descriptor* infassoc_desc;
    int interface_class = 0, interface_sub_class = 0;
    while(continue_loop && remain_size > 0){
        header_desc = (usb_descriptor_header*) cur_p;
        ////printf("- usb_descriptor_header (for Check)\n");
        ////printf("  bLength            : %d\n", header_desc->bLength);
        ////printf("  bDescriptorType    : 0x%02x\n", header_desc->bDescriptorType);
        // Descriptor types
        // 0x01 - 0x08 :: from Table 9.5 by USB 2.0 specifications
        // 0x09 - 0x0b :: from minor USB 2.0 revision ECN (Engineering Change Notice)
        // 0x21 - 0x25 :: conventional codes for ClassSpecific descriptors
        switch(header_desc->bDescriptorType){
        case 0x01: // USB_DT_DEVICE Device Descriptor
            dev_desc = (struct usb_device_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_device_descriptor\n");
                printf("    bLength            : %d\n", dev_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", dev_desc->bDescriptorType);
                printf("    bcdUSB             : %x.%02x\n", (dev_desc->bcdUSB & 0xff00) >> 8, dev_desc->bcdUSB & 0x00ff);
                printf("    bDeviceClass       : 0x%02x\n", dev_desc->bDeviceClass);
                printf("    bDeviceSubClass    : 0x%02x\n", dev_desc->bDeviceSubClass);
                printf("    bDeviceProtocol    : 0x%02x\n", dev_desc->bDeviceProtocol);
                printf("    bMaxPacketSize0    : %d\n", dev_desc->bMaxPacketSize0);
                printf("    idVendor           : 0x%04x\n", dev_desc->idVendor);
                printf("    idProduct          : 0x%04x\n", dev_desc->idProduct);
                printf("    bcdDevice          : %x.%02x\n", (dev_desc->bcdDevice & 0xff00) >> 8, dev_desc->bcdDevice & 0x00ff);
                printf("    iManufacturer      : 0x%02x\n", dev_desc->iManufacturer);
                printf("    iProduct           : 0x%02x\n", dev_desc->iProduct);
                printf("    iSerialNumber      : 0x%02x\n", dev_desc->iSerialNumber);
                printf("    bNumConfigurations : %d\n", dev_desc->bNumConfigurations);
            }
            break;
        case 0x02: // USB_DT_CONFIG Config Descriptor
            conf_desc = (struct usb_config_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_config_descriptor\n");
                printf("    bLength            : %d\n", conf_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", conf_desc->bDescriptorType);
                printf("    wTotalLength       : %d\n", conf_desc->wTotalLength);
                printf("    bNumInterfaces     : %d\n", conf_desc->bNumInterfaces);
                printf("    bConfigurationValue: %d\n", conf_desc->bConfigurationValue);
                printf("    iConfiguration     : %d\n", conf_desc->iConfiguration);
                printf("    bmAttributes       : 0x%02x\n", conf_desc->bmAttributes);
                printf("    MaxPower           : %d [mA]\n", (conf_desc->bMaxPower << 0x1)); // bMaxPower * 2 [mA]
            }
            break;
        case 0x03: // USB_DT_STRING String Descriptor
            break;
        case 0x04: // USB_DT_INTERFACE Interface Descriptor
            inf_desc = (struct usb_interface_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_interface_descriptor\n");
                printf("    bLength            : %d\n", inf_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", inf_desc->bDescriptorType);
                printf("    bInterfaceNumber   : 0x%02x\n", inf_desc->bInterfaceNumber);
                printf("    bAlternateSetting  : 0x%02x\n", inf_desc->bAlternateSetting);
                printf("    bNumEndpoints      : 0x%02x\n", inf_desc->bNumEndpoints);
                printf("    bInterfaceClass    : 0x%02x\n", inf_desc->bInterfaceClass);
                printf("    bInterfaceSubClass : 0x%02x\n", inf_desc->bInterfaceSubClass);
                printf("    bInterfaceProtocol : 0x%02x\n", inf_desc->bInterfaceProtocol);
                printf("    iInterface         : 0x%02x\n", inf_desc->iInterface);
            }
            if(inf_desc->bInterfaceSubClass == 0x02){ // Streaming Interface
                usb_device_info.interface_no = inf_desc->bInterfaceNumber; // 1
                inf_ok = 1;
            }
            interface_class = (int) inf_desc->bInterfaceClass;
            interface_sub_class = (int) inf_desc->bInterfaceSubClass;
            break;
        case 0x05: // USB_DT_ENDPOINT Endpoint Descriptor
            ep_desc = (struct usb_endpoint_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_endpoint_descriptor\n");
                printf("    bLength            : %d\n", ep_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", ep_desc->bDescriptorType);
                printf("    bEndpointAddress   : 0x%02x\n", ep_desc->bEndpointAddress);
                printf("      %s endpoint (Endpoint Number : %d)\n", (ep_desc->bEndpointAddress & 0x80) ? "IN" : "OUT", (ep_desc->bEndpointAddress & 0x0f));
                printf("    bmAttributes       : 0x%02x\n", ep_desc->bmAttributes);
                switch(ep_desc->bmAttributes & 0x03){ // Transfer Type
                case 0x0: // Control
                    printf("      Transfer Type        : Control\n");
                    break;
                case 0x1: // Isochronous
                    printf("      Transfer Type        : Isochronous\n");
                    switch((ep_desc->bmAttributes & 0x0c) >> 2){ // Synchronization Type
                    case 0x0: // No Synchronization
                        printf("      Synchronization Type : No Synchronization\n");
                        break;
                    case 0x1: // Asynchronous
                        printf("      Synchronization Type : Asynchronous\n");
                        break;
                    case 0x2: // Adaptive
                        printf("      Synchronization Type : Adaptive\n");
                        break;
                    case 0x3: // Synchronous
                        printf("      Synchronization Type : Synchronous\n");
                        break;
                    default: // Unreachable
                        break;
                    }
                    switch((ep_desc->bmAttributes & 0x30) >> 4){ // Usage Type
                    case 0x0: // Data endpoint
                        printf("      Usage Type           : Data endpoint\n");
                        break;
                    case 0x1: // Feedback endpoint
                        printf("      Usage Type           : Feedback endpoint\n");
                        break;
                    case 0x2: // Implicit feedback encpoint
                        printf("      Usage Type           : Implicit feedback encpoint\n");
                        break;
                    case 0x3: // Reserved
                        printf("      Usage Type           : Reserved\n");
                        break;
                    default: // Unreachable
                        break;
                    }
                    break;
                case 0x2: // Bulk
                    printf("      Transfer Type        : Bulk\n");
                    break;
                case 0x3: // Interrupt
                    printf("      Transfer Type        : Interrupt\n");
                    switch((ep_desc->bmAttributes & 0x0c) >> 2){ // Reserved
                    default: // Reserved
                        break;
                    }
                    switch((ep_desc->bmAttributes & 0x30) >> 4){ // Usage Type
                    case 0x0: // Periodic
                        printf("      Usage Type           : Periodic\n");
                        break;
                    case 0x1: // Notification
                        printf("      Usage Type           : Notification\n");
                        break;
                    default: // Reserved
                        printf("      Usage Type           : Reserved\n");
                        break;
                    }
                    break;
                default: // Unreachable
                    break;
                }
                printf("    wMaxPacketSize     : 0x%04x\n", ep_desc->wMaxPacketSize);
                switch((ep_desc->wMaxPacketSize & 0x1800) >> 11){ // lsusb specific
                case 0x0:
                    printf("      1x %d\n", ep_desc->wMaxPacketSize & 0x07ff);
                    break;
                case 0x1:
                    printf("      2x %d\n", ep_desc->wMaxPacketSize & 0x07ff);
                    break;
                case 0x2:
                    printf("      3x %d\n", ep_desc->wMaxPacketSize & 0x07ff);
                    break;
                case 0x3:
                    printf("      (?\?) %d\n", ep_desc->wMaxPacketSize & 0x07ff);
                    break;
                default:
                    break;
                }
                printf("    bInterval          : 0x%02x\n", ep_desc->bInterval);
                if(((int) ep_desc->bLength) == 9){ // is Audio
                    printf("   (Audio)\n");
                    printf("    bRefresh           : 0x%02x\n", ep_desc->bRefresh);
                    printf("    bSynchAddress      : 0x%02x\n", ep_desc->bSynchAddress);
                }
            }
            if(ep_desc->bEndpointAddress & 0x80){ // In Endpoint
                if((ep_desc->bmAttributes & 0x33) == 0x01){ // Isochronous, Data Endpoint
                    usb_device_info.address = ep_desc->bEndpointAddress; // 0x81
                    usb_device_info.max_packet_size = ep_desc->wMaxPacketSize & 0x07ff; // 459
                    ep_ok = 1;
                }
            }
            break;
        case 0x06: // USB_DT_DEVICE_QUALIFIER Device Qualifier Descriptor
            qual_desc = (struct usb_qualifier_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_qualifier_descriptor\n");
                printf("    bLength            : %d\n", qual_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", qual_desc->bDescriptorType);
                printf("    bcdUSB             : %x.%02x\n", (qual_desc->bcdUSB & 0xff00) >> 8, qual_desc->bcdUSB & 0x00ff);
                printf("    bDeviceClass       : 0x%02x\n", qual_desc->bDeviceClass);
                printf("    bDeviceSubClass    : 0x%02x\n", qual_desc->bDeviceSubClass);
                printf("    bDeviceProtocol    : 0x%02x\n", qual_desc->bDeviceProtocol);
                printf("    bMaxPacketSize0    : %d\n", qual_desc->bMaxPacketSize0);
                printf("    bNumConfigurations : %d\n", qual_desc->bNumConfigurations);
                printf("    bRESERVED          : 0x%02x\n", qual_desc->bRESERVED);
            }
            break;
        case 0x07: // USB_DT_OTHER_SPEED_CONFIG Other Speed Descriptor
            break;
        case 0x08: // USB_DT_INTERFACE_POWER Interface Power Descriptor
            break;
        case 0x09: // USB_DT_OTG OTG (On The Go) Descriptor
            otg_desc = (struct usb_otg_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_otg_descriptor\n");
                printf("    bLength            : %d\n", otg_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", otg_desc->bDescriptorType);
                printf("    bmAttributes       : 0x%02x\n", otg_desc->bmAttributes);
                printf("      SRP (Session Request Protocol) %s\n", (otg_desc->bmAttributes & 0x01) ? "enabled" : "disabled");
                printf("      HNP (Host Negotiation Protocol) %s\n", (otg_desc->bmAttributes & 0x02) ? "enabled" : "disabled");
            }
            break;
        case 0x0a: // USB_DT_DEBUG Debug Descriptor
            debug_desc = (struct usb_debug_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_otg_descriptor\n");
                printf("    bLength            : %d\n", debug_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", debug_desc->bDescriptorType);
                printf("    bDebugInEndpoint   : 0x%02x\n", debug_desc->bDebugInEndpoint);
                printf("    bDebugOutEndpoint  : 0x%02x\n", debug_desc->bDebugOutEndpoint);
            }
            break;
        case 0x0b: // USB_DT_INTERFACE_ASSOCIATION Interface Association Descriptor
            infassoc_desc = (struct usb_interface_assoc_descriptor*) cur_p;
            if(debug_msg){
                printf("  - usb_interface_assoc_descriptor\n");
                printf("    bLength            : %d\n", infassoc_desc->bLength);
                printf("    bDescriptorType    : 0x%02x\n", infassoc_desc->bDescriptorType);
                printf("    bFirstInterface    : 0x%02x\n", infassoc_desc->bFirstInterface);
                printf("    bInterfaceCount    : %d\n", infassoc_desc->bInterfaceCount);
                printf("    bFunctionClass     : 0x%02x\n", infassoc_desc->bFunctionClass);
                printf("    bFunctionSubClass  : 0x%02x\n", infassoc_desc->bFunctionSubClass);
                printf("    bFunctionProtocol  : 0x%02x\n", infassoc_desc->bFunctionProtocol);
                printf("    iFunction          : 0x%02x\n", infassoc_desc->iFunction);
            }
            break;
        case 0x21: // USB_DT_CS_DEVICE Class Specific Device Descriptor
            break;
        case 0x22: // USB_DT_CS_CONFIG Class Specific Config Descriptor
            break;
        case 0x23: // USB_DT_CS_STRING Class Specific String Descriptor
            break;
        case 0x24: // USB_DT_CS_INTERFACE Class Specific Interface Descriptor
            switch(interface_class){
            case 0x01: // Audio Class
                switch(interface_sub_class){
                case 0x01: // Control Device
                    switch( *((unsigned char*) (cur_p + 2)) ){ // bDescriptorSubtype
                    case 0x01: // Header
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Control Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      Header\n");
                            printf("    bcdADC             : %x.%02x\n", ((*((unsigned short*) (cur_p + 3))) & 0xff00) >> 8,(*((unsigned short*) (cur_p + 3))) & 0x00ff);
                            printf("    wTotalLength       : %d\n", *((unsigned short*) (cur_p + 5)));
                            printf("    bInCollection      : 0x%02x\n", *((unsigned char*) (cur_p + 7)));
                            printf("    baInterfaceNr(1)   : %d\n", *((unsigned char*) (cur_p + 8)));
                        }
                        break;
                    case 0x02: // Input Terminal
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Control Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      Input Terminal\n");
                            printf("    bTerminalID        : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    wTerminalType      : 0x%04x\n", *((unsigned short*) (cur_p + 4)));
                            printf("    bAssocTerminal     : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            printf("    bNrChannels        : %d\n", *((unsigned char*) (cur_p + 7)));
                            printf("    wChannelConfig     : 0x%04x\n", *((unsigned short*) (cur_p + 8)));
                            printf("    iChannelNames      : 0x%02x\n", *((unsigned char*) (cur_p + 10)));
                            printf("    iTerminal          : 0x%02x\n", *((unsigned char*) (cur_p + 11)));
                        }
                        break;
                    case 0x03: // Output Terminal
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Control Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      Output Terminal\n");
                            printf("    bTerminalID        : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    wTerminalType      : 0x%04x\n", *((unsigned short*) (cur_p + 4)));
                            printf("    bAssocTerminal     : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            printf("    bSourceID          : 0x%02x\n", *((unsigned char*) (cur_p + 7)));
                            printf("    iTerminal          : 0x%02x\n", *((unsigned char*) (cur_p + 8)));
                        }
                        break;
                    default: // Unknown Descriptor
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Control Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                        }
                        break;
                    }
                    break;
                case 0x02: // Streaming
                    switch( *((unsigned char*) (cur_p + 2)) ){ // bDescriptorSubtype
                    case 0x01: // AS General
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Streaming Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      AS General\n");
                            printf("    bTerminalLink      : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    bDelay             : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            printf("    wFormatTag         : 0x%04x\n", *((unsigned short*) (cur_p + 5)));
                        }
                        break;
                    case 0x02: // Format Type
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Streaming Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      Format Type\n");
                            printf("    bFormatType        : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    bNrChannels        : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            printf("    bSubFrameSize      : 0x%02x\n", *((unsigned char*) (cur_p + 5)));
                            printf("    bBitResolution     : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            printf("    bSamFreqType       : 0x%02x\n", *((unsigned char*) (cur_p + 7)));
                            printf("    tSamFreq           : 0x%02x%02x%02x (%d [Hz])\n", *((unsigned char*) (cur_p + 10)), *((unsigned char*) (cur_p + 9)), *((unsigned char*) (cur_p + 8)), (*((unsigned char*) (cur_p + 10)) << 16) + (*((unsigned char*) (cur_p + 9)) << 8) + (*((unsigned char*) (cur_p + 8))));
                        }
                        usb_device_info.channels = *((unsigned char*) (cur_p + 4));
                        usb_device_info.bits = *((unsigned char*) (cur_p + 6));
                        break;
                    case 0x03:
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Streaming Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      ??\n");
                            printf("    bFormatType        : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    bNrChannels        : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            printf("    bSubFrameSize      : 0x%02x\n", *((unsigned char*) (cur_p + 5)));
                            printf("    bBitResolution     : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            printf("    bSamFreqType       : 0x%02x\n", *((unsigned char*) (cur_p + 7)));
                            printf("    tSamFreq           : 0x%02x%02x%02x (%d [Hz])\n", *((unsigned char*) (cur_p + 10)), *((unsigned char*) (cur_p + 9)), *((unsigned char*) (cur_p + 8)), (*((unsigned char*) (cur_p + 10)) << 16) + (*((unsigned char*) (cur_p + 9)) << 8) + (*((unsigned char*) (cur_p + 8))));
                        }
                        break;
                    default: // Unknown Descriptor
                        if(debug_msg){
                            printf("  - Audio Class Specific (Audio Streaming Interface Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("      Unsupported (skip)\n");
                        }
                        break;
                    }
                    break;
                default: // Unknown Sub Class
                    break;
                }
                break;
            case 0xdc: // Debug Class
                switch(interface_sub_class){
                case 0x80: // Debug Control
                    switch( *((unsigned char*) (cur_p + 2)) ){ // bDescriptorSubtype
                    case 0x01: // Input Connection Descriptor
                        if(debug_msg){
                            printf("  - USB Debug Class Specific (Input Connection Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("    bConnectionID      : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            switch(*((unsigned char*) (cur_p + 3))){
                            case 0:
                                printf("      USB OUT endpoint\n");
                                break;
                            case 1:
                                printf("      Debug Port input pin (Control, e.g., JTAG)\n");
                                break;
                            case 2:
                                printf("      Debug Port input pin (Data)\n");
                                break;
                            case 3:
                                printf("      Debug Port input pin (Data or Control)\n");
                                break;
                            default:
                                printf("      Reserved\n");
                                break;
                            }
                            printf("    bConnectionType    : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            printf("    bAssocConnection   : 0x%02x\n", *((unsigned char*) (cur_p + 5)));
                            printf("    iConnection        : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            if(header_desc->bLength == 11){ // Optional Field
                                printf("    dTraceFormat       : 0x%08x\n", *((unsigned int*) (cur_p + 7)));
                                //printf("    dStreamID          : 0x%08x\n", *((unsigned int*) (cur_p + 11)));
                            }
                        }
                        break;
                    case 0x02: // Output Connection Descriptor
                        if(debug_msg){
                            printf("  - USB Debug Class Specific (Output Connection Descriptor)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            printf("    bConnectionID      : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            printf("    bConnectionType    : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            switch(*((unsigned char*) (cur_p + 3))){
                            case 0:
                                printf("      USB IN endpoint\n");
                                break;
                            case 1:
                                printf("      Debug Port output pin (Control)\n");
                                break;
                            case 2:
                                printf("      Debug Port output pin (Data)\n");
                                break;
                            case 3:
                                printf("      Debug Port output pin (Data or Control)\n");
                                break;
                            default:
                                printf("      Reserved\n");
                                break;
                            }
                            printf("    bAssocConnection   : 0x%02x\n", *((unsigned char*) (cur_p + 5)));
                            printf("    wSourceID          : 0x%04x\n", *((unsigned short*) (cur_p + 6)));
                            printf("    iConnection        : 0x%02x\n", *((unsigned char*) (cur_p + 8)));
                        }
                        break;
                    case 0x03: // Debug Unit Descriptor
                        if(debug_msg){
                            printf("  - USB Debug Class Specific (Debug Unit Descriptro)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                            //if(0){ // written by USB Debug Class Rev1.0 Final, but buggy? (overwraped address)
                            //    printf("    bcdDC              : %x.%02x\n", ((*((unsigned short*) (cur_p + 3))) & 0xff00) >> 8,(*((unsigned short*) (cur_p + 3))) & 0x00ff);
                            //    printf("    bUnitID            : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
                            //    printf("    bDebugUnitType     : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
                            //    printf("    bDebugSubUnitType  : 0x%02x\n", *((unsigned char*) (cur_p + 5)));
                            //    printf("    bAliasUnitID       : 0x%02x\n", *((unsigned char*) (cur_p + 6)));
                            //    printf("    bNrInPins          : 0x%02x\n", *((unsigned char*) (cur_p + 7)));
                            //    int i, i_max;
                            //    i = 0; i_max = *((unsigned char*) (cur_p + 7));
                            //    while(i < i_max){
                            //        printf("    wSourceID(%d)       : %d\n", i, *((unsigned short*) (cur_p + 8 + i * 2)));
                            //        i++;
                            //    }
                            //    printf("    bNrOutPins         : 0x%02x\n", *((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2))));
                            //    i = 0; i_imax = *((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2)));
                            //    while(i < i_max){
                            //        printf("    dTraceFormat(%d)    : 0x%08x\n", i, *((unsigned int*) (cur_p + 9 + (*((unsigned char*) (cur_p + 7)) * 2) + i * 8)));
                            //        printf("    dStreamID(%d)       : %d\n", i, *((unsigned int*) (cur_p + 13 + (*((unsigned char*) (cur_p + 7)) * 2) + i * 8)));
                            //    }
                            //    printf("    bControlSize       : 0x%02x\n", *((unsigned char*) (cur_p + 17 + (*((unsigned char*) (cur_p + 7)) * 2) + (*((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2)))) * 8)));
                            //    printf("    bmControl          : %s\n", ((unsigned char*) (cur_p + 18 + (*((unsigned char*) (cur_p + 7)) * 2) + (*((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2)))) * 8)));
                            //    printf("    bAuxDataSize       : 0x%02x\n", *((unsigned char*) (cur_p + 18 + (*((unsigned char*) (cur_p + 7)) * 2) + (*((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2)))) * 8 + (*((unsigned char*) (cur_p + 17 + (*((unsigned char*) (cur_p + 7)) * 2) + (*((unsigned char*) (cur_p + 8 + (*((unsigned char*) (cur_p + 7)) * 2)))) * 8))))));
                            //    //qBaseAddress(8[Byte]), hGUID(16[Byte]), wStandardsDataSize(2[Byte]), bStarndardsID(1[Byte]), StandardData(bNrInPins-1[Byte]), wVendorDataSize(2[Byte]), VendorData(bNrOutPins[Byte]), iDebugUnitType(1[Byte])
                            //}
                        }
                        break;
                    case 0x04: // Debug Attributes Descriptor
                        if(debug_msg){
                            printf("  - USB Debug Class Specific (Debug Attributes Descriptro)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                        }
                        break;
                    default: // Unknown Descriptor
                        if(debug_msg){
                            printf("  - USB Debug Class Specific (Descriptro)\n");
                            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
                            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
                            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
                        }
                        break;
                    }
                    break;
                default: // Unknown Sub Class
                    break;
                }
                break;
            default: // Unknown Class
                break;
            }
            break;
        case 0x25: // USB_DT_CS_ENDPOINT
            printf("  - Audio Class (Audio Data Endpoint Descriptor)\n");
            printf("    bLength            : %d\n", *((unsigned char*) cur_p));
            printf("    bDescriptorType    : 0x%02x\n", *((unsigned char*) (cur_p + 1)));
            printf("    bDescriptorSubType : 0x%02x\n", *((unsigned char*) (cur_p + 2)));
            printf("    bmAttributes       : 0x%02x\n", *((unsigned char*) (cur_p + 3)));
            printf("    bLockDelayUnits    : 0x%02x\n", *((unsigned char*) (cur_p + 4)));
            printf("    wLockDelay         : 0x%04x\n", *((unsigned short*) (cur_p + 5)));
            break;
        default:
            //remain_size = 0;
            break;
        }
        remain_size -= (int) header_desc->bLength;
        cur_p += (int) header_desc->bLength;
    } // while loop end

    strncpy(usb_device_info.dev_name, dev_name, sizeof(dev_name));
    usb_device_info.desc_length = length;
    return 0;
}

int USBDeviceObject::TryEnableWriteMode()
{
    if(usb_device_info.is_writeable){ return 0; } // already writeable.
    int fd = ::open(usb_device_info.dev_name, O_RDWR);
    if(fd < 0){ return -1; } // cannot enable write mode. (keep read only mode.)
    ::close(usb_device_info.fd);
    usb_device_info.fd = fd;
    usb_device_info.is_writeable = 1;
    return 0;
}

int USBDeviceObject::GetFD()
{
    return usb_device_info.fd;
}

const char* USBDeviceObject::GetDeviceName()
{
    return usb_device_info.dev_name;
}

int USBDeviceObject::GetUniqueID(const char *dev_name)
{
    int bus, dev;
    bus = 0; dev = 0;
    if(dev_name == NULL){
        sscanf(usb_device_info.dev_name, "/dev/bus/usb/%d/%d", &bus, &dev);
    }
    else{
        sscanf(dev_name, "/dev/bus/usb/%d/%d", &bus, &dev);
    }
    return ((bus << 8) | dev);
}

int USBDeviceObject::GetDeviceNameFromUniqueID(int id, char *dev_name)
{
    int bus, dev;
    bus = (id & 0xff00) >> 8; dev = id & 0x00ff;
    snprintf(dev_name, 20, "/dev/bus/usb/%03d/%03d", bus, dev);
    return 0;
}

unsigned int USBDeviceObject::GetVendorID()
{
    struct usb_device_descriptor* desc = (struct usb_device_descriptor*) usb_device_info.desc;
    return (unsigned int) desc->idVendor; // this code is little endian only, type is __le16.
}

unsigned int USBDeviceObject::GetProductID()
{
    struct usb_device_descriptor* desc = (struct usb_device_descriptor*) usb_device_info.desc;
    return (unsigned int) desc->idProduct; // this code is little endian only, type is __le16.
}

int USBDeviceObject::GetString(int index, char *ret_string)
{
    char string[256];
    unsigned short int buf[128];
    unsigned short int langs[128];
    int result, langcount;
    struct usbdevfs_ctrltransfer control;
    string[0] = 0;
    memset(langs, 0, sizeof(langs));
    langcount = 0;
    if(!TryEnableWriteMode()){ return -1; } // fd is read only.
    memset(&control, 0, sizeof(control));
    control.bRequestType = (int) USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
    control.bRequest = (int) USB_REQ_GET_DESCRIPTOR;
    control.wValue = (int) (USB_DT_STRING << 8); // (USB_DT_STRING << 8) | 0;
    control.wIndex = (int) 0;
    control.wLength = (int) sizeof(langs);
    control.data = (void*) langs;
    control.timeout = (unsigned int) 0;
    result = ioctl(usb_device_info.fd, USBDEVFS_CONTROL, &control);
    if(result > 0){ langcount = (result - 2) / 2; }
    control.wValue |= index;
    control.wLength = (int) sizeof(buf);
    control.data = (void*) buf;
    for(int i = 1; i <= langcount; i++){
        memset(buf, 0, sizeof(buf));
        //memset(&control, 0, sizeof(control));
        //control.bRequestType = (int) USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
        //control.bRequest = (int) USB_REQ_GET_DESCRIPTOR;
        //control.wValue = (int) (USB_DT_STRING << 8) | index;
        control.wIndex = (int) langs[i];
        //control.wLength = (int) sizeof(buf);
        //control.data = (void*) buf;
        //control.timeout = (unsigned int) 0;
        result = ioctl(usb_device_info.fd, USBDEVFS_CONTROL, &control);
        if(result > 0){
            result /= 2;
            for(int j = 1; j < result; j++){ string[j-1] = buf[j]; }
            string[result] = 0;
            strcpy(ret_string, string);
            return 0;
        }
    }
    ret_string = NULL;
    return -1;
}

int USBDeviceObject::GetManufacturerName(int index, char *ret_string)
{
    struct usb_device_descriptor *desc = (struct usb_device_descriptor*) usb_device_info.desc;
    if(desc->iManufacturer){
        GetString(desc->iManufacturer, ret_string);
        if(ret_string != NULL){ return 0; }
    }
    ret_string = NULL;
    return -1;
}

int USBDeviceObject::GetProductName(int index, char *ret_string)
{
    struct usb_device_descriptor *desc = (struct usb_device_descriptor*) usb_device_info.desc;
    if(desc->iProduct){
        GetString(desc->iProduct, ret_string);
        if(ret_string != NULL){ return 0; }
    }
    ret_string = NULL;
    return -1;
}

int USBDeviceObject::GetSerialNumber(int index, char *ret_string)
{
    struct usb_device_descriptor *desc = (struct usb_device_descriptor*) usb_device_info.desc;
    if(desc->iSerialNumber){
        GetString(desc->iSerialNumber, ret_string);
        if(ret_string != NULL){ return 0; }
    }
    ret_string = NULL;
    return -1;
}


// force is 0(false) or 1(true).
int USBDeviceObject::USBClaimInterface(unsigned int interface, int force)
{
    struct usbdevfs_ioctl control;
    int ret = ioctl(usb_device_info.fd, USBDEVFS_CLAIMINTERFACE, &interface);
    printf("ClaimInterface : %d\n", ret);
    if(ret && force /*&& error_no == EBUSY*/){
        control.ifno = interface;
        control.ioctl_code = USBDEVFS_DISCONNECT;
        control.data = NULL;
        int x = ioctl(usb_device_info.fd, USBDEVFS_IOCTL, &control);
        printf("IOCTL(disconnect) : %d\n", x);
        ret = ioctl(usb_device_info.fd, USBDEVFS_CLAIMINTERFACE, &interface);
        printf("ClaimInterface(force) : %d\n", ret);
    }
    return ret; // ret == 0 is success.
}

// force is 0(false) or 1(true).
int USBDeviceObject::ReleaseInterface(unsigned int interface)
{
    struct usbdevfs_ioctl control;
    int ret = ioctl(usb_device_info.fd, USBDEVFS_RELEASEINTERFACE, &interface);
    printf("ReleaseInterface : %d\n", ret);
    if(!ret){ // ret == 0
        control.ifno = interface;
        control.ioctl_code = USBDEVFS_CONNECT;
        control.data = NULL;
        int x = ioctl(usb_device_info.fd, USBDEVFS_IOCTL, &control);
        printf("IOCTL(connect) : %d\n", x);
    }
    return ret; // ret == 0 is success.
}



/// maybe not used
int USBDeviceObject::ConnectKernelDriver(unsigned int interface, int connect)
{
    struct usbdevfs_ioctl control;
    control.ifno = interface;
    control.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
    control.data = NULL;
    return ioctl(usb_device_info.fd, USBDEVFS_RELEASEINTERFACE, &control);
}

int USBDeviceObject::SetConfiguration(unsigned int configuration)
{
    return ioctl(usb_device_info.fd, USBDEVFS_SETCONFIGURATION, &configuration);
}

int USBDeviceObject::SetInterface(unsigned int interface, unsigned int altsetting)
{
    struct usbdevfs_setinterface setinterface;
    setinterface.interface = interface;
    setinterface.altsetting = altsetting;
    return ioctl(usb_device_info.fd, USBDEVFS_SETINTERFACE, &setinterface);
}

// USB Audio Class check (for Not USB audio class USB microphone array)
/* !!CAUTION!! this is cording image. not actual code.
int USBDeviceObject::GetAudioDeviceInformation()
{
  if("If AudioClass"){
    for (int i = 0, i < EndpointNum, i++){
      // Check Endpoint information (Please check "Isochronous IN" here.)
    }
  }
  else{ // If you need supports not UAC microphone (e.g. SHT microphone)
    for (int i = 0, i < EndpointNum, i++){
      // Check Endpoint information (Please search "Bulk IN" here.)：
    }
  }
}
*/

void USBDeviceObject::FreeUrbs()
{
    int i;
    for(i=0; i<NUM_URBS; i++){
        if(urbs[i] != NULL){ free(urbs[i]); }
        urbs[i] = NULL;
    }
}

int USBDeviceObject::SubmitUrb(int index)
{
    int stat;
    int j;
    if(index >= NUM_URBS){ return -1; }
    if(urbs[index] == NULL){ return -1; }

    bzero(urbs[index], urb_size);
    bzero(iso_buffer[index], MAX_PACKET_SIZE * NUM_PACKETS);

    urbs[index]->type              = USBDEVFS_URB_TYPE_ISO;
    urbs[index]->endpoint          = usb_device_info.address;
    //printf("urbs[%d]->endpoint : %d\n", index, usb_device_info.address);
    urbs[index]->flags             = USBDEVFS_URB_ISO_ASAP;
    urbs[index]->buffer            = (void *)&iso_buffer[index][0];
    //urbs[index]->buffer_length     = MAX_PACKET_SIZE * NUM_PACKETS;
    urbs[index]->number_of_packets = NUM_PACKETS;
    //printf("urbs[%d]->number_of_packets : %d\n", index, NUM_PACKETS);
    urbs[index]->usercontext       = (void *)index;

    for(j=0; j<NUM_PACKETS; j++){
        urbs[index]->iso_frame_desc[j].length = usb_device_info.max_packet_size;
        //printf("urbs[%d]->iso_frame_desc[%d] : %d\n", index, j, usb_device_info.max_packet_size);
    }

    stat = ioctl(usb_device_info.fd, USBDEVFS_SUBMITURB, urbs[index]);

    return stat;
}

int USBDeviceObject::RecStart()
{
    int i;
    int stat;
    struct usbdevfs_setinterface setinterface;

    if(usb_device_info.fd < 0){ return -1; }
    /* alternateを切り替えてRASP-LCの録音開始 */
    setinterface.interface  = usb_device_info.interface_no;
    setinterface.altsetting = 1;
    stat = ioctl(usb_device_info.fd, USBDEVFS_SETINTERFACE, &setinterface);
    printf("RecStart SetInterface : %d\n", stat);
    /* URB登録（録音を開始していないと登録できない） */
    urb_submit_count = 0;
    for(i=0; i<NUM_URBS; i++){
        stat = SubmitUrb(i);
        if(stat != 0){ LOGE("SubmitUrb[%d] Error : %d", i, stat); break; }
        urb_submit_count++;
    }
    if(i != NUM_URBS){
        /* エラーが起きたので停止 */
        setinterface.interface  = usb_device_info.interface_no;
        setinterface.altsetting = 0;
        ioctl(usb_device_info.fd, USBDEVFS_SETINTERFACE, &setinterface);
    }
    return stat;
}

int USBDeviceObject::RecStop()
{
    int i;

    int stat;
    struct usbdevfs_setinterface setinterface;
    struct usbdevfs_urb *urb;

    if(usb_device_info.fd < 0){ return -1; }
    // 登録済みのURBをすべて受け取る
    //for(i=0; i<urb_submit_count; i++)
    for(i=0; i<NUM_URBS; i++){ ioctl(usb_device_info.fd, USBDEVFS_REAPURB, &urb); }
    // alternateを切り替えてRASP-LCの録音停止
    setinterface.interface  = usb_device_info.interface_no;
    setinterface.altsetting = 0;
    stat = ioctl(usb_device_info.fd, USBDEVFS_SETINTERFACE, &setinterface);
    return 0;
}

int USBDeviceObject::ReadData(unsigned char *data, int buf_size)
{
    int stat;
    struct usbdevfs_urb *urb;
    int i;
    int index;
    int read_size;

    //LOGI("buf_size = %d, read_size = %d * %d", buf_size, usb_device_info.max_packet_size, NUM_PACKETS);
    if(buf_size < usb_device_info.max_packet_size * NUM_PACKETS){ return -1; } // バッファサイズをチェック
    if(usb_device_info.fd < 0){ return -1; }
    stat = ioctl(usb_device_info.fd, USBDEVFS_REAPURB, &urb); // データ受信
    if(stat < 0){ return -1; }
    urb_submit_count--;

    index = (int)urb->usercontext;
//64bit
//    long tm = (long)urb->usercontext; index = tm;
//    //index = (int)urb->usercontext;

    // 受信データをバッファにコピー
    read_size = 0;
    for(i=0; i<urb->number_of_packets; i++){
        if(urb->iso_frame_desc[i].status == 0){
            memcpy(&data[read_size], //&work_buffer[read_size],
                   &iso_buffer[index][i * usb_device_info.max_packet_size],
                   urb->iso_frame_desc[i].actual_length);
            read_size += urb->iso_frame_desc[i].actual_length;
        }
    }
    SubmitUrb(index); // 再登録
    return read_size;
}


USBDeviceObject::USBDeviceObject() : thread_id(0),
    BeingStopped(false)
{
    int ret = ::pthread_mutex_init(&Being_Stopped_mutex, NULL);
    if(ret != 0){ LOGE("pthread_mutex_init error"); }
    usb_device_info.fd = -1;
}

USBDeviceObject::~USBDeviceObject()
{
    ::pthread_mutex_destroy(&Being_Stopped_mutex);
}

int USBDeviceObject::SetBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    BeingStopped = true;
    return 0;
}

int USBDeviceObject::ResetBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    BeingStopped = false;
    return 0;
}

bool USBDeviceObject::isBeingStopped()
{
    lockobject lock(&Being_Stopped_mutex);
    const bool val = BeingStopped;
    return val;
}

int USBDeviceObject::open()
{
    int i;
	// USB接続されたデバイス情報をチェック
    if(usb_device_info.fd < 0){ return -1; }
#ifdef IS_APPLE_IOS // if #define ENABLE_NEON
    if(usb_device_info.bits != 24){ return -1; }
    if((usb_device_info.channels != 4) && (usb_device_info.channels != 8)){ return -1; }
#else // IS_APPLE_IOS // if #undef ENABLE_NEON
/*
// This code no need on Linux, because device informations get from usb device.
// This code for only used by Android.
    switch(usb_device_info.device_type){
    case DEVICE_SINGLE_MIC:
        if((usb_device_info.bits != 16) && (usb_device_info.bits != 24)){ return -1; }
        if(usb_device_info.channels != 1){ return -1; }
        break;
    case DEVICE_RASP_LC:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 8){ return -1; }
        break;
    case DEVICE_RASP_LC4:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 4){ return -1; }
        break;
    case DEVICE_RASP_ZX:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 8){ return -1; }
        break;
    case DEVICE_RASP_ZX8:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 8){ return -1; }
        break;
    case DEVICE_RASP_24:
        if(usb_device_info.bits != 24){ return -1; }
        if((usb_device_info.channels != 8) && (usb_device_info.channels != 16) && (usb_device_info.channels != 24) && (usb_device_info.channels != 32) && (usb_device_info.channels != 48)){ return -1; }
        break;
    case DEVICE_PS_EYE:
        if(usb_device_info.bits != 16){ return -1; }
        if(usb_device_info.channels != 4){ return -1; }
        break;
    case DEVICE_KINECT:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 4){ return -1; }
        break;
    case DEVICE_MICROCONE:
        if(usb_device_info.bits != 24){ return -1; }
        if(usb_device_info.channels != 7){ return -1; }
        break;
    case DEVICE_HRI_SP_KM:
        if(usb_device_info.bits != 16){ return -1; }
        if(usb_device_info.channels != 4){ return -1; }
        break;
    default:
        LOGI("Unsupported device type found. [bits = %d, channel = %d]", usb_device_info.bits, usb_device_info.channels);
        return -1;
        break;
    }
*/
#endif // IS_APPLE_IOS
    // URB(USB Request Block)バッファを作成
    FreeUrbs();
    urb_size = sizeof(struct usbdevfs_urb) + sizeof(struct usbdevfs_iso_packet_desc) * NUM_PACKETS;
    for(i=0; i<NUM_URBS; i++){
        urbs[i] = (usbdevfs_urb *)malloc(urb_size);
        if(urbs[i] == NULL){ FreeUrbs(); return -1; }
    }
    // デバック表示
    LOGI("fd = %d", usb_device_info.fd);
    LOGI("ch = %d, bits = %d", usb_device_info.channels, usb_device_info.bits);
    LOGI("ifno = %d, addr = 0x%02x, max packet size = %d", usb_device_info.interface_no, usb_device_info.address, usb_device_info.max_packet_size);
    return 0;
}


static void *_usb_device_loop(void *arg)
{
    USBDeviceObject *thiz = reinterpret_cast<USBDeviceObject *>(arg);
    const int buffer_size = MAX_PACKET_SIZE * NUM_PACKETS;
    unsigned char work_buffer[MAX_PACKET_SIZE * NUM_PACKETS];
    
    int ret;
    int ct = 0;
    
    /*
     * vdatのサイズについて
     *   USB Iso転送は 1ms　間隔
     *   RASP-LCのサンプリング周波数は　16kHz
     *
     *   上記より1パケットあたり16サンプルが含まれる
     *   実際は1ms間隔にずれが生じるので16±αとなる（RASP-LCでは最大20サンプル）
     *
     *   ioctlを使ってのデータ取り出しはNUM_PACKETS単位
     *
     *   上記より　16サンプル×NUM_PACKETS　の2倍を確保
     *
     */
    std::vector<floatx8> vdat( (16 * NUM_PACKETS * 2) );

    if(thiz->RecStart() != 0){ LOGE("Start Failure!"); thiz->close(); return 0; }

    int sample_bits;
    int sample_byte;
    int sample_size;
    int channels;
    int max_packet_size;
    int max_sample_num;
    int blocks;

    channels    = thiz->GetChannels();               // チャネル数
    sample_bits = thiz->GetBits();                   // チャネルごとのデータのビット数
    sample_byte = thiz->GetBits() / 8;               // チャネルごとのデータのバイト数
    sample_size = sample_byte * channels;            // 1サンプルあたりのバイト数
    max_packet_size = thiz->GetMaxPacketSize();      // 1パケットあたりの最大バイト数
    max_sample_num  = max_packet_size / sample_size; // 1パケットあたりの最大サンプル数

    // デバック表示
    LOGI("channels        = %d", channels);
    LOGI("sample_bits     = %d", sample_bits);
    LOGI("sample_byte     = %d", sample_byte);
    LOGI("sample_size     = %d", sample_size);
    LOGI("max_packet_size = %d", max_packet_size);
    LOGI("max_sample_num  = %d", max_sample_num);

    int read_size;

    while (!thiz->isBeingStopped()){
    	read_size = thiz->ReadData(work_buffer, buffer_size);
        if (read_size > 0){
            ct = 0;
            
            /* 受信したサンプル数にvector要素数を変更 */
        	blocks = read_size / sample_size;
        	vdat.resize(blocks);

            for(int i = 0; i < blocks; i++){ vdat[i].convert(&work_buffer[i * sample_size], channels, sample_bits); }

        retry:
            if(thiz->isBeingStopped()){ goto loopend; }
            ret = thiz->buffer->writeWithTimeout(vdat, 250); // 250ms
            if(ret == 0){
                // OK
            }
            else if(ret == ETIMEDOUT){
                ct++;
                //LOGI("retrying %d", ct);
                //LOGD("buf in use (%d / %d)", thiz->buffer->getdatnum(), thiz->buffer->getlen());
                goto retry;
            }
            else{ LOGE("usb_device_loop Write Error %d", ret); goto loopend; }
        }
        else{ LOGE("usb_device_loop DataRead Error"); break; }
        //LOGD("record count %d", ct);
        //LOGD("buf in use (%d / %d)", thiz->buffer->getdatnum(), thiz->buffer->getlen());
        //::sleep(90);
    }
    
loopend:
    if(thiz->RecStop() != 0){ LOGE("Stop Failure!"); thiz->close(); return 0; }
    return 0;
}
    
int USBDeviceObject::start(BufferObject& buf)
{
    ResetBeingStopped();
    buffer = &buf;
    int rr = ::pthread_create(&thread_id, NULL, _usb_device_loop, reinterpret_cast<void *>(this));
    if(rr != 0){ LOGE("pthread_create error"); return -1; }
    return 0;
}

int USBDeviceObject::stop()
{
    SetBeingStopped();
    void *ret;
    int retval = ::pthread_join(thread_id, &ret);
    return retval;
}

int USBDeviceObject::close()
{
    ReleaseDevice();
    usb_device_info.fd = -1;
    FreeUrbs(); // URBバッファを開放
    return 0;
}
    
} // end of namespace
