FreeRDP/channels/urbdrc/client/libusb/libusb_udevice.c
2019-04-05 09:13:24 +02:00

2007 lines
52 KiB
C

/**
* FreeRDP: A Remote Desktop Protocol Implementation
* RemoteFX USB Redirection
*
* Copyright 2012 Atrust corp.
* Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if defined(__linux__)
#include <libudev.h>
#endif
#include <errno.h>
#include <winpr/crt.h>
#include "libusb_udevice.h"
#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \
static _type udev_get_##_arg (IUDEVICE* idev) \
{ \
UDEVICE* pdev = (UDEVICE*) idev; \
return pdev->_arg; \
} \
static void udev_set_##_arg (IUDEVICE* idev, _type _t) \
{ \
UDEVICE* pdev = (UDEVICE*) idev; \
pdev->_arg = _t; \
}
#define BASIC_POINT_FUNC_DEFINED(_arg, _type) \
static _type udev_get_p_##_arg (IUDEVICE* idev) \
{ \
UDEVICE* pdev = (UDEVICE*) idev; \
return pdev->_arg; \
} \
static void udev_set_p_##_arg (IUDEVICE* idev, _type _t) \
{ \
UDEVICE* pdev = (UDEVICE*) idev; \
pdev->_arg = _t; \
}
#define BASIC_STATE_FUNC_REGISTER(_arg, _dev) \
_dev->iface.get_##_arg = udev_get_##_arg; \
_dev->iface.set_##_arg = udev_set_##_arg
typedef struct _ISO_USER_DATA ISO_USER_DATA;
struct _ISO_USER_DATA
{
BYTE* IsoPacket;
BYTE* output_data;
int iso_status;
int completed;
UINT32 error_count;
int noack;
UINT32 start_frame;
};
static int get_next_timeout(libusb_context* ctx, struct timeval* tv, struct timeval* out)
{
int r;
struct timeval timeout;
r = libusb_get_next_timeout(ctx, &timeout);
if (r)
{
/* timeout already expired? */
if (!timerisset(&timeout))
return 1;
/* choose the smallest of next URB timeout or user specified timeout */
if (timercmp(&timeout, tv, <))
*out = timeout;
else
*out = *tv;
}
else
{
*out = *tv;
}
return 0;
}
/*
* a simple wrapper to implement libusb_handle_events_timeout_completed
* function in libusb library git tree (1.0.9 later) */
static int handle_events_completed(libusb_context* ctx, int* completed)
{
struct timeval tv;
tv.tv_sec = 60;
tv.tv_usec = 0;
#ifdef HAVE_NEW_LIBUSB
return libusb_handle_events_timeout_completed(ctx, &tv, completed);
#else
int r;
struct timeval poll_timeout;
r = get_next_timeout(ctx, &tv, &poll_timeout);
retry:
if (libusb_try_lock_events(ctx) == 0)
{
if (completed == NULL || !*completed)
{
/* we obtained the event lock: do our own event handling */
WLog_DBG(TAG, "doing our own event handling");
r = libusb_handle_events_locked(ctx, &tv);
}
libusb_unlock_events(ctx);
return r;
}
/* another thread is doing event handling. wait for thread events that
* notify event completion. */
libusb_lock_event_waiters(ctx);
if (completed && *completed)
goto already_done;
if (!libusb_event_handler_active(ctx))
{
/* we hit a race: whoever was event handling earlier finished in the
* time it took us to reach this point. try the cycle again. */
libusb_unlock_event_waiters(ctx);
WLog_DBG(TAG, "event handler was active but went away, retrying");
goto retry;
}
WLog_DBG(TAG, "another thread is doing event handling");
r = libusb_wait_for_event(ctx, &poll_timeout);
already_done:
libusb_unlock_event_waiters(ctx);
if (r < 0)
{
return r;
}
else if (r == 1)
{
return libusb_handle_events_timeout(ctx, &tv);
}
else
{
return 0;
}
#endif /* HAVE_NEW_LIBUSE */
}
static void func_iso_callback(struct libusb_transfer* transfer)
{
ISO_USER_DATA* iso_user_data = (ISO_USER_DATA*) transfer->user_data;
BYTE* data = iso_user_data->IsoPacket;
int* completed = &iso_user_data->completed;
UINT32 offset = 0;
INT32 index = 0;
INT32 i, act_len;
BYTE* b;
*completed = 1;
/* Fixme: currently fill the dummy frame number, tt needs to be
* filled a real frame number */
// urbdrc_get_mstime(iso_user_data->start_frame);
if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (!iso_user_data->noack))
{
for (i = 0; i < transfer->num_iso_packets; i++)
{
act_len = transfer->iso_packet_desc[i].actual_length;
data_write_UINT32(data + offset, index);
data_write_UINT32(data + offset + 4, act_len);
data_write_UINT32(data + offset + 8,
transfer->iso_packet_desc[i].status);
offset += 12;
if (transfer->iso_packet_desc[i].status == USBD_STATUS_SUCCESS)
{
b = libusb_get_iso_packet_buffer_simple(transfer, i);
if (act_len > 0)
{
if (iso_user_data->output_data + index != b)
memcpy(iso_user_data->output_data + index, b, act_len);
index += act_len;
}
else
{
//WLog_ERR(TAG, "actual length %"PRIu32"", act_len);
//exit(EXIT_FAILURE);
}
}
else
{
iso_user_data->error_count++;
//print_transfer_status(transfer->iso_packet_desc[i].status);
}
}
transfer->actual_length = index;
iso_user_data->iso_status = 1;
}
else if ((transfer->status == LIBUSB_TRANSFER_COMPLETED) && (iso_user_data->noack))
{
/* This situation occurs when we do not need to
* return any packet */
iso_user_data->iso_status = 1;
}
else
{
//print_status(transfer->status);
iso_user_data->iso_status = -1;
}
}
static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig,
MSUSB_CONFIG_DESCRIPTOR* MsConfig, UINT32 EndpointAddress)
{
BYTE alt;
UINT32 inum, pnum;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
const LIBUSB_INTERFACE* interface;
const LIBUSB_ENDPOINT_DESCEIPTOR* endpoint;
MsInterfaces = MsConfig->MsInterfaces;
interface = LibusbConfig->interface;
for (inum = 0; inum < MsConfig->NumInterfaces; inum++)
{
alt = MsInterfaces[inum]->AlternateSetting;
endpoint = interface[inum].altsetting[alt].endpoint;
for (pnum = 0; pnum < MsInterfaces[inum]->NumberOfPipes; pnum++)
{
if (endpoint[pnum].bEndpointAddress == EndpointAddress)
{
return &endpoint[pnum];
}
}
}
return NULL;
}
static void func_bulk_transfer_cb(struct libusb_transfer* transfer)
{
int* completed = transfer->user_data;
*completed = 1;
/* caller interprets results and frees transfer */
}
static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result)
{
switch (err_result)
{
case LIBUSB_SUCCESS:
*status = USBD_STATUS_SUCCESS;
break;
case LIBUSB_ERROR_IO:
*status = USBD_STATUS_STALL_PID;
WLog_ERR(TAG, "LIBUSB_ERROR_IO!!");
break;
case LIBUSB_ERROR_INVALID_PARAM:
*status = USBD_STATUS_INVALID_PARAMETER;
break;
case LIBUSB_ERROR_ACCESS:
*status = USBD_STATUS_NOT_ACCESSED;
break;
case LIBUSB_ERROR_NO_DEVICE:
*status = USBD_STATUS_DEVICE_GONE;
if (pdev)
{
if (!(pdev->status & URBDRC_DEVICE_NOT_FOUND))
{
pdev->status |= URBDRC_DEVICE_NOT_FOUND;
WLog_WARN(TAG, "LIBUSB_ERROR_NO_DEVICE!!");
}
}
break;
case LIBUSB_ERROR_NOT_FOUND:
*status = USBD_STATUS_STALL_PID;
break;
case LIBUSB_ERROR_BUSY:
*status = USBD_STATUS_STALL_PID;
break;
case LIBUSB_ERROR_TIMEOUT:
*status = USBD_STATUS_TIMEOUT;
break;
case LIBUSB_ERROR_OVERFLOW:
*status = USBD_STATUS_STALL_PID;
break;
case LIBUSB_ERROR_PIPE:
*status = USBD_STATUS_STALL_PID;
break;
case LIBUSB_ERROR_INTERRUPTED:
*status = USBD_STATUS_STALL_PID;
break;
case LIBUSB_ERROR_NO_MEM:
*status = USBD_STATUS_NO_MEMORY;
break;
case LIBUSB_ERROR_NOT_SUPPORTED:
*status = USBD_STATUS_NOT_SUPPORTED;
break;
case LIBUSB_ERROR_OTHER:
*status = USBD_STATUS_STALL_PID;
break;
default:
*status = USBD_STATUS_SUCCESS;
break;
}
return 0;
}
static void func_iso_data_init(ISO_USER_DATA* iso_user_data, UINT32 numPacket, UINT32 buffsize,
UINT32 noAck, BYTE* isoPacket, BYTE* buffer)
{
/* init struct iso_user_data */
iso_user_data->IsoPacket = isoPacket;
iso_user_data->output_data = buffer;
iso_user_data->error_count = 0;
iso_user_data->completed = 0;
iso_user_data->noack = noAck;
urbdrc_get_mstime(iso_user_data->start_frame);
}
static int func_config_release_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle,
UINT32 NumInterfaces)
{
UINT32 i;
int ret;
for (i = 0; i < NumInterfaces; i++)
{
ret = libusb_release_interface(libusb_handle, i);
if (ret < 0)
{
WLog_ERR(TAG, "config_release_all_interface: error num %d", ret);
return -1;
}
}
return 0;
}
static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int NumInterfaces)
{
int i, ret;
for (i = 0; i < NumInterfaces; i++)
{
ret = libusb_claim_interface(libusb_handle, i);
if (ret < 0)
{
WLog_ERR(TAG, "claim_all_interface: error num %d", ret);
return -1;
}
}
return 0;
}
/*
static void* print_transfer_status(enum libusb_transfer_status status)
{
switch (status)
{
case LIBUSB_TRANSFER_COMPLETED:
//WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_COMPLETED");
break;
case LIBUSB_TRANSFER_ERROR:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_ERROR");
break;
case LIBUSB_TRANSFER_TIMED_OUT:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_TIMED_OUT");
break;
case LIBUSB_TRANSFER_CANCELLED:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_CANCELLED");
break;
case LIBUSB_TRANSFER_STALL:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_STALL");
break;
case LIBUSB_TRANSFER_NO_DEVICE:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_NO_DEVICE");
break;
case LIBUSB_TRANSFER_OVERFLOW:
WLog_ERR(TAG, "Transfer Status: LIBUSB_TRANSFER_OVERFLOW");
break;
default:
WLog_ERR(TAG, "Transfer Status: Get unknow error num %d (0x%x)",
status, status);
}
return 0;
}
static void print_status(enum libusb_transfer_status status)
{
switch (status)
{
case LIBUSB_TRANSFER_COMPLETED:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_COMPLETED");
break;
case LIBUSB_TRANSFER_ERROR:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_ERROR");
break;
case LIBUSB_TRANSFER_TIMED_OUT:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_TIMED_OUT");
break;
case LIBUSB_TRANSFER_CANCELLED:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_CANCELLED");
break;
case LIBUSB_TRANSFER_STALL:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_STALL");
break;
case LIBUSB_TRANSFER_NO_DEVICE:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_NO_DEVICE");
break;
case LIBUSB_TRANSFER_OVERFLOW:
WLog_ERR(TAG, "Transfer status: LIBUSB_TRANSFER_OVERFLOW");
break;
default:
WLog_ERR(TAG, "Transfer status: unknow status %d(0x%x)", status, status);
break;
}
}
*/
static LIBUSB_DEVICE* udev_get_libusb_dev(int bus_number, int dev_number)
{
ssize_t i, total_device;
LIBUSB_DEVICE** libusb_list;
total_device = libusb_get_device_list(NULL, &libusb_list);
for (i = 0; i < total_device; i++)
{
if ((bus_number == libusb_get_bus_number(libusb_list[i])) &&
(dev_number == libusb_get_device_address(libusb_list[i])))
return libusb_list[i];
}
libusb_free_device_list(libusb_list, 1);
return NULL;
}
static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev)
{
int ret;
LIBUSB_DEVICE_DESCRIPTOR* descriptor;
descriptor = (LIBUSB_DEVICE_DESCRIPTOR*) malloc(sizeof(LIBUSB_DEVICE_DESCRIPTOR));
ret = libusb_get_device_descriptor(libusb_dev, descriptor);
if (ret < 0)
{
WLog_ERR(TAG, "libusb_get_device_descriptor: ERROR!!");
free(descriptor);
return NULL;
}
return descriptor;
}
/* Get HUB handle */
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number)
{
int error;
ssize_t i, total_device, ports_cnt;
uint8_t port_numbers[16];
LIBUSB_DEVICE** libusb_list;
total_device = libusb_get_device_list(NULL, &libusb_list);
/* Look for device. */
error = -1;
for (i = 0; i < total_device; i ++)
{
if ((bus_number != libusb_get_bus_number(libusb_list[i])) ||
(dev_number != libusb_get_device_address(libusb_list[i])))
continue;
error = libusb_open(libusb_list[i], &pdev->hub_handle);
if (error < 0)
{
WLog_ERR(TAG, "libusb_open error: %i - %s", error, libusb_strerror(error));
break;
}
/* get port number */
error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers));
libusb_close(pdev->hub_handle);
if (error < 1)
{
/* Prevent open hub, treat as error. */
WLog_ERR(TAG, "libusb_get_port_numbers error: %i - %s", error, libusb_strerror(error));
break;
}
pdev->port_number = port_numbers[(error - 1)];
error = 0;
WLog_DBG(TAG, " Port: %d", pdev->port_number);
/* gen device path */
sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "ugen%"PRIu16".%"PRIu16"", bus_number, dev_number);
WLog_DBG(TAG, " DevPath: %s", pdev->path);
break;
}
/* Look for device hub. */
if (error == 0)
{
error = -1;
for (i = 0; i < total_device; i ++)
{
if ((bus_number != libusb_get_bus_number(libusb_list[i])) ||
(1 != libusb_get_device_address(libusb_list[i]))) /* Root hub allways first on bus. */
continue;
WLog_DBG(TAG, " Open hub: %"PRIu16"", bus_number);
error = libusb_open(libusb_list[i], &pdev->hub_handle);
if (error < 0)
WLog_ERR(TAG, "libusb_open error: %i - %s", error, libusb_strerror(error));
break;
}
}
libusb_free_device_list(libusb_list, 1);
if (error < 0)
return -1;
WLog_DBG(TAG, "libusb_open success!");
return 0;
}
#endif
#if defined(__linux__)
static int udev_get_hub_handle(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number)
{
struct udev* udev;
struct udev_enumerate* enumerate;
struct udev_list_entry* devices;
struct udev_list_entry* dev_list_entry;
struct udev_device* dev;
LIBUSB_DEVICE* libusb_dev;
int hub_found = 0;
unsigned long hub_bus = 0;
unsigned long hub_dev = 0;
int error = 0;
udev = udev_new();
if (!udev)
{
WLog_ERR(TAG, "Can't create udev");
return -1;
}
enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "usb");
udev_enumerate_add_match_property(enumerate, "DEVTYPE", "usb_device");
udev_enumerate_scan_devices(enumerate);
devices = udev_enumerate_get_list_entry(enumerate);
udev_list_entry_foreach(dev_list_entry, devices)
{
const char* path;
errno = 0;
path = udev_list_entry_get_name(dev_list_entry);
dev = udev_device_new_from_syspath(udev, path);
if (!dev)
continue;
unsigned long tmp_b, tmp_d;
tmp_b = strtoul(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0);
if (errno != 0)
continue;
tmp_d = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0);
if (errno != 0)
continue;
if (bus_number == tmp_b && dev_number == tmp_d)
{
/* get port number */
char* p1, *p2;
const char* sysfs_path =
udev_device_get_property_value(dev, "DEVPATH");
p1 = (char*) sysfs_path;
do
{
p2 = p1 + 1;
p1 = strchr(p2, '.');
}
while (p1 != NULL);
if ((p2 - sysfs_path) < (strlen(sysfs_path) - 2U))
{
p1 = (char*) sysfs_path;
do
{
p2 = p1 + 1;
p1 = strchr(p2, '-');
}
while (p1 != NULL);
}
errno = 0;
{
unsigned long val = strtoul(p2, NULL, 0);
if ((errno != 0) || (val == 0) || (val > UINT16_MAX))
continue;
pdev->port_number = val;
}
WLog_DBG(TAG, " Port: %d", pdev->port_number);
/* get device path */
p1 = (char*) sysfs_path;
do
{
p2 = p1 + 1;
p1 = strchr(p2, '/');
}
while (p1 != NULL);
sprintf_s(pdev->path, ARRAYSIZE(pdev->path), "%s", p2);
WLog_DBG(TAG, " DevPath: %s", pdev->path);
/* query parent hub info */
dev = udev_device_get_parent(dev);
if (dev != NULL)
{
hub_found = 1;
hub_bus = strtoul(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0);
hub_dev = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0);
WLog_DBG(TAG, " Hub BUS/DEV: %d %d", hub_bus, hub_dev);
}
udev_device_unref(dev);
break;
}
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
udev_unref(udev);
if (!hub_found)
{
WLog_WARN(TAG, "hub was not found!");
return -1;
}
/* Get libusb hub handle */
libusb_dev = udev_get_libusb_dev(hub_bus, hub_dev);
if (libusb_dev == NULL)
{
WLog_DBG(TAG, "get hub libusb_dev fail!");
return -1;
}
error = libusb_open(libusb_dev, &pdev->hub_handle);
if (error < 0)
{
WLog_DBG(TAG, "libusb_open error!");
return -1;
}
WLog_DBG(TAG, "libusb_open success!");
/* Success! */
return 0;
}
#endif
static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting)
{
int error = 0, diff = 1;
UDEVICE* pdev = (UDEVICE*) idev;
MSUSB_CONFIG_DESCRIPTOR* MsConfig;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
MsConfig = pdev->MsConfig;
if (MsConfig)
{
MsInterfaces = MsConfig->MsInterfaces;
if ((MsInterfaces) && (MsInterfaces[InterfaceNumber]->AlternateSetting == AlternateSetting))
{
diff = 0;
}
}
if (diff)
{
error = libusb_set_interface_alt_setting(pdev->libusb_handle,
InterfaceNumber, AlternateSetting);
if (error < 0)
{
WLog_ERR(TAG, "Set interface altsetting get error num %d",
error);
}
}
return error;
}
static MSUSB_CONFIG_DESCRIPTOR* libusb_udev_complete_msconfig_setup(IUDEVICE* idev,
MSUSB_CONFIG_DESCRIPTOR* MsConfig)
{
UDEVICE* pdev = (UDEVICE*) idev;
MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces;
MSUSB_INTERFACE_DESCRIPTOR* MsInterface;
MSUSB_PIPE_DESCRIPTOR** MsPipes;
MSUSB_PIPE_DESCRIPTOR* MsPipe;
MSUSB_PIPE_DESCRIPTOR** t_MsPipes;
MSUSB_PIPE_DESCRIPTOR* t_MsPipe;
LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig;
const LIBUSB_INTERFACE* LibusbInterface;
const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting;
const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint;
BYTE LibusbNumEndpoint;
UINT32 inum = 0, pnum = 0, MsOutSize = 0;
LibusbConfig = pdev->LibusbConfig;
if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces)
{
WLog_ERR(TAG, "Select Configuration: Libusb NumberInterfaces(%"PRIu8") is different "
"with MsConfig NumberInterfaces(%"PRIu32")",
LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces);
}
/* replace MsPipes for libusb */
MsInterfaces = MsConfig->MsInterfaces;
for (inum = 0; inum < MsConfig->NumInterfaces; inum++)
{
MsInterface = MsInterfaces[inum];
/* get libusb's number of endpoints */
LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber];
LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting];
LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints;
t_MsPipes = (MSUSB_PIPE_DESCRIPTOR**) calloc(LibusbNumEndpoint, sizeof(MSUSB_PIPE_DESCRIPTOR*));
for (pnum = 0; pnum < LibusbNumEndpoint; pnum++)
{
t_MsPipe = (MSUSB_PIPE_DESCRIPTOR*) malloc(sizeof(MSUSB_PIPE_DESCRIPTOR));
memset(t_MsPipe, 0, sizeof(MSUSB_PIPE_DESCRIPTOR));
if (pnum < MsInterface->NumberOfPipes && MsInterface->MsPipes)
{
MsPipe = MsInterface->MsPipes[pnum];
t_MsPipe->MaximumPacketSize = MsPipe->MaximumPacketSize;
t_MsPipe->MaximumTransferSize = MsPipe->MaximumTransferSize;
t_MsPipe->PipeFlags = MsPipe->PipeFlags;
}
else
{
t_MsPipe->MaximumPacketSize = 0;
t_MsPipe->MaximumTransferSize = 0xffffffff;
t_MsPipe->PipeFlags = 0;
}
t_MsPipe->PipeHandle = 0;
t_MsPipe->bEndpointAddress = 0;
t_MsPipe->bInterval = 0;
t_MsPipe->PipeType = 0;
t_MsPipe->InitCompleted = 0;
t_MsPipes[pnum] = t_MsPipe;
}
msusb_mspipes_replace(MsInterface, t_MsPipes, LibusbNumEndpoint);
}
/* setup configuration */
MsOutSize = 8;
/* ConfigurationHandle: 4 bytes
* ---------------------------------------------------------------
* ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>||
* || bus_number | dev_number | bConfigurationValue ||
* ---------------------------------------------------------------
* ***********************/
MsConfig->ConfigurationHandle = MsConfig->bConfigurationValue |
(pdev->bus_number << 24) |
(pdev->dev_number << 16);
MsInterfaces = MsConfig->MsInterfaces;
for (inum = 0; inum < MsConfig->NumInterfaces; inum++)
{
MsOutSize += 16;
MsInterface = MsInterfaces[inum];
/* get libusb's interface */
LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber];
LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting];
/* InterfaceHandle: 4 bytes
* ---------------------------------------------------------------
* ||<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>||
* || bus_number | dev_number | altsetting | interfaceNum ||
* ---------------------------------------------------------------
* ***********************/
MsInterface->InterfaceHandle = LibusbAltsetting->bInterfaceNumber
| (LibusbAltsetting->bAlternateSetting << 8)
| (pdev->dev_number << 16)
| (pdev->bus_number << 24);
MsInterface->Length = 16 + (MsInterface->NumberOfPipes * 20);
MsInterface->bInterfaceClass = LibusbAltsetting->bInterfaceClass;
MsInterface->bInterfaceSubClass = LibusbAltsetting->bInterfaceSubClass;
MsInterface->bInterfaceProtocol = LibusbAltsetting->bInterfaceProtocol;
MsInterface->InitCompleted = 1;
MsPipes = MsInterface->MsPipes;
LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints;
for (pnum = 0; pnum < LibusbNumEndpoint; pnum++)
{
MsOutSize += 20;
MsPipe = MsPipes[pnum];
/* get libusb's endpoint */
LibusbEndpoint = &LibusbAltsetting->endpoint[pnum];
/* PipeHandle: 4 bytes
* ---------------------------------------------------------------
* ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>||
* || bus_number | dev_number | bEndpointAddress ||
* ---------------------------------------------------------------
* ***********************/
MsPipe->PipeHandle = LibusbEndpoint->bEndpointAddress
| (pdev->dev_number << 16)
| (pdev->bus_number << 24);
/* count endpoint max packet size */
int max = LibusbEndpoint->wMaxPacketSize & 0x07ff;
BYTE attr = LibusbEndpoint->bmAttributes;
if ((attr & 0x3) == 1 || (attr & 0x3) == 3)
{
max *= (1 + ((LibusbEndpoint->wMaxPacketSize >> 11) & 3));
}
MsPipe->MaximumPacketSize = max;
MsPipe->bEndpointAddress = LibusbEndpoint->bEndpointAddress;
MsPipe->bInterval = LibusbEndpoint->bInterval;
MsPipe->PipeType = attr & 0x3;
MsPipe->InitCompleted = 1;
}
}
MsConfig->MsOutSize = MsOutSize;
MsConfig->InitCompleted = 1;
/* replace device's MsConfig */
if (!(MsConfig == pdev->MsConfig))
{
msusb_msconfig_free(pdev->MsConfig);
pdev->MsConfig = MsConfig;
}
return MsConfig;
}
static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfigurationValue)
{
UDEVICE* pdev = (UDEVICE*) idev;
MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->MsConfig;
LIBUSB_DEVICE_HANDLE* libusb_handle = pdev->libusb_handle;
LIBUSB_DEVICE* libusb_dev = pdev->libusb_dev;
LIBUSB_CONFIG_DESCRIPTOR** LibusbConfig = &pdev->LibusbConfig;
int ret = 0;
if (MsConfig->InitCompleted)
{
func_config_release_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces);
}
/* The configuration value -1 is mean to put the device in unconfigured state. */
if (bConfigurationValue == 0)
ret = libusb_set_configuration(libusb_handle, -1);
else
ret = libusb_set_configuration(libusb_handle, bConfigurationValue);
if (ret < 0)
{
WLog_ERR(TAG, "libusb_set_configuration: ERROR number %d!!", ret);
func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces);
return -1;
}
else
{
ret = libusb_get_active_config_descriptor(libusb_dev, LibusbConfig);
if (ret < 0)
{
WLog_ERR(TAG, "libusb_get_config_descriptor_by_value: ERROR number %d!!", ret);
func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces);
return -1;
}
}
func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces);
return 0;
}
static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId,
UINT32 EndpointAddress, UINT32* UsbdStatus, int command)
{
int error = 0;
UDEVICE* pdev = (UDEVICE*) idev;
/*
pdev->request_queue->register_request(pdev->request_queue, RequestId, NULL, 0);
*/
switch (command)
{
case PIPE_CANCEL:
/** cancel bulk or int transfer */
idev->cancel_all_transfer_request(idev);
//dummy_wait_s_obj(1);
/** set feature to ep (set halt)*/
error = libusb_control_transfer(pdev->libusb_handle,
LIBUSB_ENDPOINT_OUT | LIBUSB_RECIPIENT_ENDPOINT,
LIBUSB_REQUEST_SET_FEATURE,
ENDPOINT_HALT,
EndpointAddress,
NULL,
0,
1000);
break;
case PIPE_RESET:
idev->cancel_all_transfer_request(idev);
error = libusb_clear_halt(pdev->libusb_handle, EndpointAddress);
//func_set_usbd_status(pdev, UsbdStatus, error);
break;
default:
error = -0xff;
break;
}
*UsbdStatus = 0;
/*
if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId))
WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId);
*/
return error;
}
static int libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType,
UINT32 LocaleId,
UINT32* BufferSize,
BYTE* Buffer)
{
UDEVICE* pdev = (UDEVICE*) idev;
LIBUSB_DEVICE_DESCRIPTOR* devDescriptor = pdev->devDescriptor;
char* strDesc = "Generic Usb String";
char deviceLocation[25];
BYTE bus_number;
BYTE device_address;
int ret = 0;
size_t i = 0;
switch (TextType)
{
case DeviceTextDescription:
ret = libusb_get_string_descriptor(pdev->libusb_handle,
devDescriptor->iProduct,
LocaleId,
Buffer,
*BufferSize);
for (i = 0; (ret > 0) && (i < (size_t)ret); i++)
{
Buffer[i] = Buffer[i + 2];
}
ret -= 2;
if (ret <= 0 || ret < 4)
{
WLog_DBG(TAG, "libusb_get_string_descriptor: "
"ERROR num %d, iProduct: %"PRIu8"!", ret, devDescriptor->iProduct);
memcpy(Buffer, strDesc, strlen(strDesc));
Buffer[strlen(strDesc)] = '\0';
*BufferSize = (strlen((char*)Buffer)) * 2;
for (i = strlen((char*)Buffer); i > 0; i--)
{
Buffer[i * 2] = Buffer[i];
Buffer[(i * 2) - 1] = 0;
}
}
else
{
*BufferSize = ret;
}
break;
case DeviceTextLocationInformation:
bus_number = libusb_get_bus_number(pdev->libusb_dev);
device_address = libusb_get_device_address(pdev->libusb_dev);
sprintf_s(deviceLocation, ARRAYSIZE(deviceLocation), "Port_#%04"PRIu8".Hub_#%04"PRIu8"",
device_address, bus_number);
for (i = 0; i < strlen(deviceLocation); i++)
{
Buffer[i * 2] = (BYTE)deviceLocation[i];
Buffer[(i * 2) + 1] = 0;
}
*BufferSize = (i * 2);
break;
default:
WLog_DBG(TAG, "Query Text: unknown TextType %"PRIu32"", TextType);
break;
}
return 0;
}
static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 RequestId,
BYTE Recipient,
BYTE InterfaceNumber,
BYTE Ms_PageIndex,
UINT16 Ms_featureDescIndex,
UINT32* UsbdStatus,
UINT32* BufferSize,
BYTE* Buffer,
int Timeout)
{
UDEVICE* pdev = (UDEVICE*) idev;
BYTE ms_string_desc[0x13];
int error = 0;
/*
pdev->request_queue->register_request(pdev->request_queue, RequestId, NULL, 0);
*/
memset(ms_string_desc, 0, 0x13);
error = libusb_control_transfer(pdev->libusb_handle,
LIBUSB_ENDPOINT_IN | Recipient,
LIBUSB_REQUEST_GET_DESCRIPTOR,
0x03ee,
0,
ms_string_desc,
0x12,
Timeout);
//WLog_ERR(TAG, "Get ms string: result number %d", error);
if (error > 0)
{
BYTE bMS_Vendorcode;
data_read_BYTE(ms_string_desc + 16, bMS_Vendorcode);
//WLog_ERR(TAG, "bMS_Vendorcode:0x%x", bMS_Vendorcode);
/** get os descriptor */
error = libusb_control_transfer(pdev->libusb_handle,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | Recipient,
bMS_Vendorcode,
(InterfaceNumber << 8) | Ms_PageIndex,
Ms_featureDescIndex,
Buffer,
*BufferSize,
Timeout);
*BufferSize = error;
}
if (error < 0)
*UsbdStatus = USBD_STATUS_STALL_PID;
else
*UsbdStatus = USBD_STATUS_SUCCESS;
/*
if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId))
WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%x", RequestId);
*/
return error;
}
static int libusb_udev_query_device_descriptor(IUDEVICE* idev, int offset)
{
UDEVICE* pdev = (UDEVICE*) idev;
switch (offset)
{
case B_LENGTH:
return pdev->devDescriptor->bLength;
case B_DESCRIPTOR_TYPE:
return pdev->devDescriptor->bDescriptorType;
case BCD_USB:
return pdev->devDescriptor->bcdUSB;
case B_DEVICE_CLASS:
return pdev->devDescriptor->bDeviceClass;
case B_DEVICE_SUBCLASS:
return pdev->devDescriptor->bDeviceSubClass;
case B_DEVICE_PROTOCOL:
return pdev->devDescriptor->bDeviceProtocol;
case B_MAX_PACKET_SIZE0:
return pdev->devDescriptor->bMaxPacketSize0;
case ID_VENDOR:
return pdev->devDescriptor->idVendor;
case ID_PRODUCT:
return pdev->devDescriptor->idProduct;
case BCD_DEVICE:
return pdev->devDescriptor->bcdDevice;
case I_MANUFACTURER:
return pdev->devDescriptor->iManufacturer;
case I_PRODUCT:
return pdev->devDescriptor->iProduct;
case I_SERIAL_NUMBER:
return pdev->devDescriptor->iSerialNumber;
case B_NUM_CONFIGURATIONS:
return pdev->devDescriptor->bNumConfigurations;
default:
return 0;
}
return 0;
}
static void libusb_udev_detach_kernel_driver(IUDEVICE* idev)
{
int i, err = 0;
UDEVICE* pdev = (UDEVICE*) idev;
if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0)
{
for (i = 0; i < pdev->LibusbConfig->bNumInterfaces; i++)
{
err = libusb_kernel_driver_active(pdev->libusb_handle, i);
WLog_DBG(TAG, "libusb_kernel_driver_active = %d", err);
if (err)
{
err = libusb_detach_kernel_driver(pdev->libusb_handle, i);
WLog_DBG(TAG, "libusb_detach_kernel_driver = %d", err);
}
}
pdev->status |= URBDRC_DEVICE_DETACH_KERNEL;
}
}
static void libusb_udev_attach_kernel_driver(IUDEVICE* idev)
{
int i, err = 0;
UDEVICE* pdev = (UDEVICE*) idev;
for (i = 0; i < pdev->LibusbConfig->bNumInterfaces && err != LIBUSB_ERROR_NO_DEVICE; i++)
{
err = libusb_release_interface(pdev->libusb_handle, i);
if (err < 0)
{
WLog_DBG(TAG, "libusb_release_interface: error num %d = %d", i, err);
}
if (err != LIBUSB_ERROR_NO_DEVICE)
{
err = libusb_attach_kernel_driver(pdev->libusb_handle, i);
WLog_DBG(TAG, "libusb_attach_kernel_driver if%d = %d", i, err);
}
}
}
static int libusb_udev_is_composite_device(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return pdev->isCompositeDevice;
}
static int libusb_udev_is_signal_end(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return (pdev->status & URBDRC_DEVICE_SIGNAL_END) ? 1 : 0;
}
static int libusb_udev_is_exist(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return (pdev->status & URBDRC_DEVICE_NOT_FOUND) ? 0 : 1;
}
static int libusb_udev_is_channel_closed(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) ? 1 : 0;
}
static int libusb_udev_is_already_send(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return (pdev->status & URBDRC_DEVICE_ALREADY_SEND) ? 1 : 0;
}
static void libusb_udev_signal_end(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
pdev->status |= URBDRC_DEVICE_SIGNAL_END;
}
static void libusb_udev_channel_closed(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
}
static void libusb_udev_set_already_send(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
pdev->status |= URBDRC_DEVICE_ALREADY_SEND;
}
static char* libusb_udev_get_path(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
return pdev->path;
}
static int libusb_udev_wait_action_completion(IUDEVICE* idev)
{
int error, sval;
UDEVICE* pdev = (UDEVICE*) idev;
while (1)
{
usleep(500000);
error = sem_getvalue(&pdev->sem_id, &sval);
if (sval == 0)
break;
}
return error;
}
static void libusb_udev_push_action(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
sem_post(&pdev->sem_id);
}
static void libusb_udev_complete_action(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
sem_trywait(&pdev->sem_id);
}
static int libusb_udev_wait_for_detach(IUDEVICE* idev)
{
int error = 0;
int times = 0;
UDEVICE* pdev = (UDEVICE*) idev;
while (times < 25)
{
if (pdev->status & URBDRC_DEVICE_SIGNAL_END)
{
error = -1;
break;
}
usleep(200000);
times++;
}
return error;
}
static void libusb_udev_lock_fifo_isoch(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
pthread_mutex_lock(&pdev->mutex_isoch);
}
static void libusb_udev_unlock_fifo_isoch(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
pthread_mutex_unlock(&pdev->mutex_isoch);
}
static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStatus,
UINT32* BufferSize, BYTE* Buffer)
{
UDEVICE* pdev = (UDEVICE*) idev;
int success = 0, ret;
WLog_DBG(TAG, "...");
if (pdev->hub_handle != NULL)
{
ret = idev->control_transfer(idev, 0xffff, 0, 0,
LIBUSB_ENDPOINT_IN
| LIBUSB_REQUEST_TYPE_CLASS
| LIBUSB_RECIPIENT_OTHER,
LIBUSB_REQUEST_GET_STATUS,
0, pdev->port_number, UsbdStatus, BufferSize, Buffer, 1000);
if (ret < 0)
{
WLog_DBG(TAG, "libusb_control_transfer: error num %d", ret);
*BufferSize = 0;
}
else
{
WLog_DBG(TAG, "PORT STATUS:0x%02"PRIx8"%02"PRIx8"%02"PRIx8"%02"PRIx8"",
Buffer[3], Buffer[2], Buffer[1], Buffer[0]);
success = 1;
}
}
return success;
}
static int libusb_udev_request_queue_is_none(IUDEVICE* idev)
{
UDEVICE* pdev = (UDEVICE*) idev;
if (pdev->request_queue->request_num == 0)
return 1;
return 0;
}
static int libusb_udev_isoch_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, int NoAck, UINT32* ErrorCount,
UINT32* UrbdStatus, UINT32* StartFrame, UINT32 NumberOfPackets,
BYTE* IsoPacket, UINT32* BufferSize, BYTE* Buffer, int Timeout)
{
UINT32 iso_packet_size;
UDEVICE* pdev = (UDEVICE*) idev;
ISO_USER_DATA iso_user_data;
struct libusb_transfer* iso_transfer = NULL;
int status = 0, ret = 0, submit = 0;
iso_packet_size = *BufferSize / NumberOfPackets;
iso_transfer = libusb_alloc_transfer(NumberOfPackets);
if (iso_transfer == NULL)
{
WLog_ERR(TAG, "Error: libusb_alloc_transfer.");
return -1;
}
/** process URB_FUNCTION_IOSCH_TRANSFER */
func_iso_data_init(&iso_user_data, NumberOfPackets, *BufferSize, NoAck, IsoPacket, Buffer);
/** fill setting */
libusb_fill_iso_transfer(iso_transfer,
pdev->libusb_handle, EndpointAddress, Buffer, *BufferSize,
NumberOfPackets, func_iso_callback, &iso_user_data, 2000);
libusb_set_iso_packet_lengths(iso_transfer, iso_packet_size);
if (pdev->status & (URBDRC_DEVICE_SIGNAL_END | URBDRC_DEVICE_NOT_FOUND))
status = -1;
iso_user_data.iso_status = 0;
if (!(status < 0))
{
submit = libusb_submit_transfer(iso_transfer);
if (submit < 0)
{
WLog_DBG(TAG, "Error: Failed to submit transfer (ret = %d).", submit);
status = -1;
func_set_usbd_status(pdev, UrbdStatus, ret);
}
}
#if ISOCH_FIFO
if (!NoAck)
{
idev->unlock_fifo_isoch(idev);
}
#endif
while (pdev && iso_user_data.iso_status == 0 && status >= 0 && submit >= 0)
{
if (pdev->status & URBDRC_DEVICE_NOT_FOUND)
{
status = -1;
break;
}
ret = handle_events_completed(NULL, &iso_user_data.completed);
if (ret < 0)
{
WLog_DBG(TAG, "Error: libusb_handle_events (ret = %d).", ret);
status = -1;
break;
}
#if WAIT_COMPLETE_SLEEP
if (iso_user_data.iso_status == 0)
{
usleep(WAIT_COMPLETE_SLEEP);
}
#endif
}
if (iso_user_data.iso_status < 0)
status = -1;
*ErrorCount = iso_user_data.error_count;
*StartFrame = iso_user_data.start_frame;
*BufferSize = iso_transfer->actual_length;
libusb_free_transfer(iso_transfer);
return status;
}
static int libusb_udev_control_transfer(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress,
UINT32 TransferFlags, BYTE bmRequestType, BYTE Request, UINT16 Value, UINT16 Index,
UINT32* UrbdStatus, UINT32* BufferSize, BYTE* Buffer, UINT32 Timeout)
{
int status = 0;
UDEVICE* pdev = (UDEVICE*) idev;
status = libusb_control_transfer(pdev->libusb_handle,
bmRequestType, Request, Value, Index, Buffer, *BufferSize, Timeout);
if (!(status < 0))
*BufferSize = status;
func_set_usbd_status(pdev, UrbdStatus, status);
return status;
}
static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 RequestId,
UINT32 EndpointAddress, UINT32 TransferFlags, UINT32* UsbdStatus, UINT32* BufferSize, BYTE* Buffer,
UINT32 Timeout)
{
UINT32 transfer_type;
UDEVICE* pdev = (UDEVICE*) idev;
const LIBUSB_ENDPOINT_DESCEIPTOR* ep_desc;
struct libusb_transfer* transfer = NULL;
TRANSFER_REQUEST* request = NULL;
int completed = 0, status = 0, submit = 0;
int transferDir = EndpointAddress & 0x80;
/* alloc memory for urb transfer */
transfer = libusb_alloc_transfer(0);
ep_desc = func_get_ep_desc(pdev->LibusbConfig, pdev->MsConfig, EndpointAddress);
if (!ep_desc)
{
WLog_ERR(TAG, "func_get_ep_desc: endpoint 0x%"PRIx32" is not found!!", EndpointAddress);
return -1;
}
transfer_type = (ep_desc->bmAttributes) & 0x3;
WLog_DBG(TAG, "urb_bulk_or_interrupt_transfer: ep:0x%"PRIx32" "
"transfer_type %"PRIu32" flag:%"PRIu32" OutputBufferSize:0x%"PRIx32"",
EndpointAddress, transfer_type, TransferFlags, *BufferSize);
switch (transfer_type)
{
case BULK_TRANSFER:
/** Bulk Transfer */
//Timeout = 10000;
break;
case INTERRUPT_TRANSFER:
/** Interrupt Transfer */
/** Sometime, we may have receive a oversized transfer request,
* it make submit urb return error, so we set the length of
* request to wMaxPacketSize */
if (*BufferSize != (ep_desc->wMaxPacketSize))
{
WLog_DBG(TAG, "Interrupt Transfer(%s): "
"BufferSize is different than maxPacketsize(0x%x)",
((transferDir) ? "IN" : "OUT"), ep_desc->wMaxPacketSize);
if ((*BufferSize) > (ep_desc->wMaxPacketSize) &&
transferDir == USBD_TRANSFER_DIRECTION_IN)
(*BufferSize) = ep_desc->wMaxPacketSize;
}
Timeout = 0;
break;
default:
WLog_DBG(TAG, "urb_bulk_or_interrupt_transfer:"
" other transfer type 0x%"PRIX32"", transfer_type);
return -1;
break;
}
libusb_fill_bulk_transfer(transfer, pdev->libusb_handle, EndpointAddress,
Buffer, *BufferSize, func_bulk_transfer_cb, &completed, Timeout);
transfer->type = (unsigned char) transfer_type;
/** Bug fixed in libusb-1.0-8 later: issue of memory crash */
submit = libusb_submit_transfer(transfer);
if (submit < 0)
{
WLog_DBG(TAG, "libusb_bulk_transfer: error num %d", status);
func_set_usbd_status(pdev, UsbdStatus, status);
*BufferSize = 0;
}
else
{
request = pdev->request_queue->register_request(
pdev->request_queue, RequestId, transfer, EndpointAddress);
request->submit = 1;
}
if ((pdev && *UsbdStatus == 0) && (submit >= 0) &&
(pdev->iface.isSigToEnd((IUDEVICE*) pdev) == 0))
{
while (!completed)
{
status = handle_events_completed(NULL, &completed);
if (status < 0)
{
if (status == LIBUSB_ERROR_INTERRUPTED)
continue;
libusb_cancel_transfer(transfer);
while (!completed)
{
if (handle_events_completed(NULL, &completed) < 0)
break;
#if WAIT_COMPLETE_SLEEP
if (!completed)
usleep(WAIT_COMPLETE_SLEEP);
#endif
}
break;
}
#if WAIT_COMPLETE_SLEEP
if (!completed)
usleep(WAIT_COMPLETE_SLEEP);
#endif
}
switch (transfer->status)
{
case LIBUSB_TRANSFER_COMPLETED:
func_set_usbd_status(pdev, UsbdStatus, 0);
break;
case LIBUSB_TRANSFER_TIMED_OUT:
func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_TIMEOUT);
break;
case LIBUSB_TRANSFER_STALL:
func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_PIPE);
break;
case LIBUSB_TRANSFER_OVERFLOW:
func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_OVERFLOW);
break;
case LIBUSB_TRANSFER_NO_DEVICE:
func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_NO_DEVICE);
break;
default:
func_set_usbd_status(pdev, UsbdStatus, LIBUSB_ERROR_OTHER);
break;
}
*BufferSize = transfer->actual_length;
}
WLog_DBG(TAG, "bulk or interrupt Transfer data size : 0x%"PRIx32"", *BufferSize);
if (request)
{
if (pdev->request_queue->unregister_request(pdev->request_queue, RequestId))
WLog_ERR(TAG, "request_queue_unregister_request: not fount request 0x%"PRIx32"", RequestId);
}
libusb_free_transfer(transfer);
return 0;
}
static void libusb_udev_cancel_all_transfer_request(IUDEVICE* idev)
{
int status;
UDEVICE* pdev = (UDEVICE*) idev;
REQUEST_QUEUE* request_queue = pdev->request_queue;
TRANSFER_REQUEST* request = NULL;
pthread_mutex_lock(&request_queue->request_loading);
request_queue->rewind(request_queue);
while (request_queue->has_next(request_queue))
{
request = request_queue->get_next(request_queue);
if ((!request) || (!request->transfer) ||
(request->endpoint != request->transfer->endpoint) ||
(request->transfer->endpoint == 0) || (request->submit != 1))
{
continue;
}
status = libusb_cancel_transfer(request->transfer);
if (status < 0)
{
WLog_DBG(TAG, "libusb_cancel_transfer: error num %d!!", status);
}
else
{
request->submit = -1;
}
}
pthread_mutex_unlock(&request_queue->request_loading);
}
static int func_cancel_xact_request(TRANSFER_REQUEST* request)
{
int status;
if (!request)
return -1;
if ((!request->transfer) || (request->endpoint != request->transfer->endpoint) ||
(request->transfer->endpoint == 0) || (request->submit != 1))
{
return 0;
}
status = libusb_cancel_transfer(request->transfer);
if (status < 0)
{
WLog_DBG(TAG, "libusb_cancel_transfer: error num %d!!", status);
if (status == LIBUSB_ERROR_NOT_FOUND)
return -1;
}
else
{
WLog_DBG(TAG, "libusb_cancel_transfer: Success num:0x%x!!", request->RequestId);
request->submit = -1;
return 1;
}
return 0;
}
static int libusb_udev_cancel_transfer_request(IUDEVICE* idev, UINT32 RequestId)
{
UDEVICE* pdev = (UDEVICE*) idev;
REQUEST_QUEUE* request_queue = pdev->request_queue;
TRANSFER_REQUEST* request = NULL;
int status = 0, retry_times = 0;
cancel_retry:
pthread_mutex_lock(&request_queue->request_loading);
request_queue->rewind(request_queue);
while (request_queue->has_next(request_queue))
{
request = request_queue->get_next(request_queue);
if (!request)
continue;
WLog_DBG(TAG, "CancelId:0x%"PRIx32" RequestId:0x%x endpoint 0x%x!!",
RequestId, request->RequestId, request->endpoint);
if (request->RequestId == (RequestId && retry_times <= 10))
{
status = func_cancel_xact_request(request);
break;
}
else if ((request->transfer) && (retry_times > 10))
{
status = -1;
break;
}
}
pthread_mutex_unlock(&request_queue->request_loading);
if ((status == 0) && (retry_times < 10))
{
retry_times++;
usleep(100000);
WLog_DBG(TAG, "urbdrc_process_cancel_request: go retry!!");
goto cancel_retry;
}
else if ((status < 0) || (retry_times >= 10))
{
/** END */
WLog_DBG(TAG, "urbdrc_process_cancel_request: error go exit!!");
return -1;
}
WLog_DBG(TAG, "urbdrc_process_cancel_request: success!!");
return 0;
}
BASIC_STATE_FUNC_DEFINED(channel_id, UINT32)
BASIC_STATE_FUNC_DEFINED(UsbDevice, UINT32)
BASIC_STATE_FUNC_DEFINED(ReqCompletion, UINT32)
BASIC_STATE_FUNC_DEFINED(bus_number, UINT16)
BASIC_STATE_FUNC_DEFINED(dev_number, UINT16)
BASIC_STATE_FUNC_DEFINED(port_number, int)
BASIC_STATE_FUNC_DEFINED(isoch_queue, void*)
BASIC_STATE_FUNC_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*)
BASIC_POINT_FUNC_DEFINED(udev, void*)
BASIC_POINT_FUNC_DEFINED(prev, void*)
BASIC_POINT_FUNC_DEFINED(next, void*)
static void udev_load_interface(UDEVICE* pdev)
{
/* load interface */
/* Basic */
BASIC_STATE_FUNC_REGISTER(channel_id, pdev);
BASIC_STATE_FUNC_REGISTER(UsbDevice, pdev);
BASIC_STATE_FUNC_REGISTER(ReqCompletion, pdev);
BASIC_STATE_FUNC_REGISTER(bus_number, pdev);
BASIC_STATE_FUNC_REGISTER(dev_number, pdev);
BASIC_STATE_FUNC_REGISTER(port_number, pdev);
BASIC_STATE_FUNC_REGISTER(isoch_queue, pdev);
BASIC_STATE_FUNC_REGISTER(MsConfig, pdev);
BASIC_STATE_FUNC_REGISTER(p_udev, pdev);
BASIC_STATE_FUNC_REGISTER(p_prev, pdev);
BASIC_STATE_FUNC_REGISTER(p_next, pdev);
pdev->iface.isCompositeDevice = libusb_udev_is_composite_device;
pdev->iface.isSigToEnd = libusb_udev_is_signal_end;
pdev->iface.isExist = libusb_udev_is_exist;
pdev->iface.isAlreadySend = libusb_udev_is_already_send;
pdev->iface.isChannelClosed = libusb_udev_is_channel_closed;
pdev->iface.SigToEnd = libusb_udev_signal_end;
pdev->iface.setAlreadySend = libusb_udev_set_already_send;
pdev->iface.setChannelClosed = libusb_udev_channel_closed;
pdev->iface.getPath = libusb_udev_get_path;
/* Transfer */
pdev->iface.isoch_transfer = libusb_udev_isoch_transfer;
pdev->iface.control_transfer = libusb_udev_control_transfer;
pdev->iface.bulk_or_interrupt_transfer = libusb_udev_bulk_or_interrupt_transfer;
pdev->iface.select_interface = libusb_udev_select_interface;
pdev->iface.select_configuration = libusb_udev_select_configuration;
pdev->iface.complete_msconfig_setup = libusb_udev_complete_msconfig_setup;
pdev->iface.control_pipe_request = libusb_udev_control_pipe_request;
pdev->iface.control_query_device_text = libusb_udev_control_query_device_text;
pdev->iface.os_feature_descriptor_request = libusb_udev_os_feature_descriptor_request;
pdev->iface.cancel_all_transfer_request = libusb_udev_cancel_all_transfer_request;
pdev->iface.cancel_transfer_request = libusb_udev_cancel_transfer_request;
pdev->iface.query_device_descriptor = libusb_udev_query_device_descriptor;
pdev->iface.detach_kernel_driver = libusb_udev_detach_kernel_driver;
pdev->iface.attach_kernel_driver = libusb_udev_attach_kernel_driver;
pdev->iface.wait_action_completion = libusb_udev_wait_action_completion;
pdev->iface.push_action = libusb_udev_push_action;
pdev->iface.complete_action = libusb_udev_complete_action;
pdev->iface.lock_fifo_isoch = libusb_udev_lock_fifo_isoch;
pdev->iface.unlock_fifo_isoch = libusb_udev_unlock_fifo_isoch;
pdev->iface.query_device_port_status = libusb_udev_query_device_port_status;
pdev->iface.request_queue_is_none = libusb_udev_request_queue_is_none;
pdev->iface.wait_for_detach = libusb_udev_wait_for_detach;
}
static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number)
{
int status, num;
LIBUSB_DEVICE_DESCRIPTOR* devDescriptor;
LIBUSB_CONFIG_DESCRIPTOR* config_temp;
LIBUSB_INTERFACE_DESCRIPTOR interface_temp;
/* Get HUB handle */
status = udev_get_hub_handle(pdev, bus_number, dev_number);
if (status < 0)
{
WLog_ERR(TAG, "USB init: Error to get HUB handle!!");
pdev->hub_handle = NULL;
}
pdev->devDescriptor = udev_new_descript(pdev->libusb_dev);
if (!pdev->devDescriptor)
{
WLog_ERR(TAG, "USB init: Error to get device descriptor!!");
zfree(pdev);
return NULL;
}
num = pdev->devDescriptor->bNumConfigurations;
status = libusb_get_active_config_descriptor(pdev->libusb_dev, &pdev->LibusbConfig);
if (status < 0)
{
WLog_ERR(TAG, "libusb_get_descriptor: ERROR!!ret:%d", status);
zfree(pdev);
return NULL;
}
config_temp = pdev->LibusbConfig;
/* get the first interface and first altsetting */
interface_temp = config_temp->interface[0].altsetting[0];
WLog_DBG(TAG, "Registered Device: Vid: 0x%04"PRIX16" Pid: 0x%04"PRIX16""
" InterfaceClass = 0x%02"PRIX8"",
pdev->devDescriptor->idVendor,
pdev->devDescriptor->idProduct,
interface_temp.bInterfaceClass);
/* Denied list */
switch (interface_temp.bInterfaceClass)
{
case CLASS_RESERVE:
//case CLASS_COMMUNICATION_IF:
//case CLASS_HID:
//case CLASS_PHYSICAL:
case CLASS_MASS_STORAGE:
case CLASS_HUB:
//case CLASS_COMMUNICATION_DATA_IF:
case CLASS_SMART_CARD:
case CLASS_CONTENT_SECURITY:
//case CLASS_WIRELESS_CONTROLLER:
//case CLASS_ELSE_DEVICE:
WLog_ERR(TAG, " Device is not supported!!");
zfree(pdev);
return NULL;
default:
break;
}
/* Check composite device */
devDescriptor = pdev->devDescriptor;
if ((devDescriptor->bNumConfigurations == 1) &&
(config_temp->bNumInterfaces > 1) &&
(devDescriptor->bDeviceClass == 0x0))
{
pdev->isCompositeDevice = 1;
}
else if ((devDescriptor->bDeviceClass == 0xef) &&
(devDescriptor->bDeviceSubClass == 0x02) &&
(devDescriptor->bDeviceProtocol == 0x01))
{
pdev->isCompositeDevice = 1;
}
else
{
pdev->isCompositeDevice = 0;
}
/* set device class to first interface class */
devDescriptor->bDeviceClass = interface_temp.bInterfaceClass;
devDescriptor->bDeviceSubClass = interface_temp.bInterfaceSubClass;
devDescriptor->bDeviceProtocol = interface_temp.bInterfaceProtocol;
/* initialize pdev */
pdev->prev = NULL;
pdev->next = NULL;
pdev->bus_number = bus_number;
pdev->dev_number = dev_number;
pdev->status = 0;
pdev->ReqCompletion = 0;
pdev->channel_id = 0xffff;
pdev->request_queue = request_queue_new();
pdev->isoch_queue = NULL;
sem_init(&pdev->sem_id, 0, 0);
/* set config of windows */
pdev->MsConfig = msusb_msconfig_new();
pthread_mutex_init(&pdev->mutex_isoch, NULL);
//deb_config_msg(pdev->libusb_dev, config_temp, devDescriptor->bNumConfigurations);
udev_load_interface(pdev);
return (IUDEVICE*) pdev;
}
int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE** * devArray)
{
LIBUSB_DEVICE_DESCRIPTOR* descriptor;
LIBUSB_DEVICE** libusb_list;
UDEVICE** array;
UINT16 bus_number;
UINT16 dev_number;
ssize_t i, total_device;
int status, num = 0;
WLog_INFO(TAG, "VID: 0x%04"PRIX16", PID: 0x%04"PRIX16"", idVendor, idProduct);
array = (UDEVICE**) malloc(16 * sizeof(UDEVICE*));
total_device = libusb_get_device_list(NULL, &libusb_list);
for (i = 0; i < total_device; i++)
{
descriptor = udev_new_descript(libusb_list[i]);
if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct))
{
bus_number = 0;
dev_number = 0;
array[num] = (PUDEVICE) malloc(sizeof(UDEVICE));
array[num]->libusb_dev = libusb_list[i];
status = libusb_open(libusb_list[i], &array[num]->libusb_handle);
if (status < 0)
{
WLog_ERR(TAG, "libusb_open: (by id) error: 0x%08X (%d)", status, status);
zfree(descriptor);
zfree(array[num]);
continue;
}
bus_number = libusb_get_bus_number(libusb_list[i]);
dev_number = libusb_get_device_address(libusb_list[i]);
array[num] = (PUDEVICE) udev_init(array[num], bus_number, dev_number);
if (array[num] != NULL)
num++;
}
zfree(descriptor);
}
libusb_free_device_list(libusb_list, 1);
*devArray = (IUDEVICE**) array;
return num;
}
IUDEVICE* udev_new_by_addr(int bus_number, int dev_number)
{
int status;
UDEVICE* pDev;
WLog_DBG(TAG, "bus:%d dev:%d", bus_number, dev_number);
pDev = (PUDEVICE) malloc(sizeof(UDEVICE));
pDev->libusb_dev = udev_get_libusb_dev(bus_number, dev_number);
if (pDev->libusb_dev == NULL)
{
WLog_ERR(TAG, "libusb_device_new: ERROR!!");
zfree(pDev);
return NULL;
}
status = libusb_open(pDev->libusb_dev, &pDev->libusb_handle);
if (status < 0)
{
WLog_ERR(TAG, "libusb_open: (by addr) ERROR!!");
zfree(pDev);
return NULL;
}
return udev_init(pDev, bus_number, dev_number);
}