From 0927d7aa50c76b671b55c33e0f06c950d1f08e9a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 22 Nov 2019 10:42:05 +0100 Subject: [PATCH] Rewrite of urbdrc channel. * Fix command line parsing * Properly handle channel creation/destruction * Use wStream API for parsing --- channels/urbdrc/CMakeLists.txt | 38 +- channels/urbdrc/client/CMakeLists.txt | 11 +- channels/urbdrc/client/data_transfer.c | 2702 ++++++++--------- channels/urbdrc/client/data_transfer.h | 5 +- channels/urbdrc/client/isoch_queue.c | 184 -- channels/urbdrc/client/isoch_queue.h | 60 - channels/urbdrc/client/libusb/CMakeLists.txt | 6 +- .../urbdrc/client/libusb/libusb_udevice.c | 1735 +++++------ .../urbdrc/client/libusb/libusb_udevice.h | 27 +- .../urbdrc/client/libusb/libusb_udevman.c | 588 ++-- channels/urbdrc/client/libusb/request_queue.c | 179 -- channels/urbdrc/client/libusb/request_queue.h | 62 - channels/urbdrc/client/searchman.c | 83 +- channels/urbdrc/client/searchman.h | 9 - channels/urbdrc/client/urbdrc_main.c | 1598 +++------- channels/urbdrc/client/urbdrc_main.h | 116 +- channels/urbdrc/common/CMakeLists.txt | 26 + channels/urbdrc/common/msusb.c | 402 +++ channels/urbdrc/common/msusb.h | 97 + channels/urbdrc/common/urbdrc_helpers.c | 408 +++ channels/urbdrc/common/urbdrc_helpers.h | 45 + .../urbdrc/{client => common}/urbdrc_types.h | 156 +- include/freerdp/channels/urbdrc.h | 30 + 23 files changed, 3954 insertions(+), 4613 deletions(-) delete mode 100644 channels/urbdrc/client/isoch_queue.c delete mode 100644 channels/urbdrc/client/isoch_queue.h delete mode 100644 channels/urbdrc/client/libusb/request_queue.c delete mode 100644 channels/urbdrc/client/libusb/request_queue.h create mode 100644 channels/urbdrc/common/CMakeLists.txt create mode 100644 channels/urbdrc/common/msusb.c create mode 100644 channels/urbdrc/common/msusb.h create mode 100644 channels/urbdrc/common/urbdrc_helpers.c create mode 100644 channels/urbdrc/common/urbdrc_helpers.h rename channels/urbdrc/{client => common}/urbdrc_types.h (66%) create mode 100644 include/freerdp/channels/urbdrc.h diff --git a/channels/urbdrc/CMakeLists.txt b/channels/urbdrc/CMakeLists.txt index c7e546fcb..356e612f4 100644 --- a/channels/urbdrc/CMakeLists.txt +++ b/channels/urbdrc/CMakeLists.txt @@ -17,38 +17,12 @@ define_channel("urbdrc") -if(NOT WIN32) - find_package(DevD) - find_package(UDev) - find_package(UUID) - find_package(DbusGlib) - find_package(libusb-1.0) -endif() - -if(DEVD_FOUND OR UDEV_FOUND) - include_directories(${UDEV_INCLUDE_DIR}) - if(UUID_FOUND AND DBUS_GLIB_FOUND AND LIBUSB_1_FOUND) - include_directories(${UUID_INCLUDE_DIRS}) - include_directories(${LIBUSB_1_INCLUDE_DIRS}) - include_directories(${DBUS_GLIB_INCLUDE_DIRS}) - - set(URBDRC_DEPENDENCIES_FOUND TRUE) - message(STATUS "Found all URBDRC dependencies") - else() - if(NOT UUID_FOUND) - message(STATUS "URBDRC dependencie not found: UUID") - endif() - if(NOT DBUS_GLIB_FOUND) - message(STATUS "URBDRC dependencie not found: DBUS_GLIB") - endif() - if(NOT LIBUSB_1_FOUND) - message(STATUS "URBDRC dependencie not found: LIBUSB_1") - endif() - endif() -endif() +include_directories(common) +add_subdirectory(common) if(WITH_CLIENT_CHANNELS) - if(URBDRC_DEPENDENCIES_FOUND) - add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) - endif() + find_package(libusb-1.0 REQUIRED) + include_directories(${LIBUSB_1_INCLUDE_DIRS}) + + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) endif() diff --git a/channels/urbdrc/client/CMakeLists.txt b/channels/urbdrc/client/CMakeLists.txt index 24c7ee94b..a9ada7fbf 100644 --- a/channels/urbdrc/client/CMakeLists.txt +++ b/channels/urbdrc/client/CMakeLists.txt @@ -21,22 +21,15 @@ define_channel_client("urbdrc") set(${MODULE_PREFIX}_SRCS searchman.c searchman.h - isoch_queue.c - isoch_queue.h data_transfer.c data_transfer.h urbdrc_main.c urbdrc_main.h - urbdrc_types.h) - -include_directories(..) + $ + ) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") - - -#set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} libusb-devman) - set(${MODULE_PREFIX}_LIBS) if (UDEV_FOUND AND UDEV_LIBRARIES) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${UDEV_LIBRARIES}) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 5b4b00e6a..806d989d8 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -21,419 +21,361 @@ #include #include #include -#include -#include -#include -#include +#include + +#include #include "urbdrc_types.h" #include "data_transfer.h" -static void usb_process_get_port_status(IUDEVICE* pdev, BYTE* OutputBuffer) +static void usb_process_get_port_status(IUDEVICE* pdev, wStream* out) { int bcdUSB = pdev->query_device_descriptor(pdev, BCD_USB); switch (bcdUSB) { case USB_v1_0: - data_write_UINT32(OutputBuffer, 0x303); + Stream_Write_UINT32(out, 0x303); break; case USB_v1_1: - data_write_UINT32(OutputBuffer, 0x103); + Stream_Write_UINT32(out, 0x103); break; case USB_v2_0: - data_write_UINT32(OutputBuffer, 0x503); + Stream_Write_UINT32(out, 0x503); break; default: - data_write_UINT32(OutputBuffer, 0x503); + Stream_Write_UINT32(out, 0x503); break; } } -#if ISOCH_FIFO - -static int func_check_isochronous_fds(IUDEVICE* pdev) +static UINT urb_write_completion(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, BOOL noAck, + wStream* out, UINT32 InterfaceId, UINT32 MessageId, + UINT32 RequestId, UINT32 usbd_status, UINT32 OutputBufferSize) { - int ret = 0; - BYTE* data_temp; - UINT32 size_temp, process_times = 2; - ISOCH_CALLBACK_QUEUE* isoch_queue = NULL; - ISOCH_CALLBACK_DATA* isoch = NULL; - URBDRC_CHANNEL_CALLBACK* callback; + if (!out) + return ERROR_INVALID_PARAMETER; - isoch_queue = (ISOCH_CALLBACK_QUEUE*)pdev->get_isoch_queue(pdev); - - while (process_times) + if (Stream_Capacity(out) < OutputBufferSize + 36) { - process_times--; - - if (isoch_queue == NULL || !pdev) - return -1; - - pthread_mutex_lock(&isoch_queue->isoch_loading); - - if (isoch_queue->head == NULL) - { - pthread_mutex_unlock(&isoch_queue->isoch_loading); - continue; - } - else - { - isoch = isoch_queue->head; - } - - if (!isoch || !isoch->out_data) - { - pthread_mutex_unlock(&isoch_queue->isoch_loading); - continue; - } - else - { - callback = (URBDRC_CHANNEL_CALLBACK*)isoch->callback; - size_temp = isoch->out_size; - data_temp = isoch->out_data; - - ret = isoch_queue->unregister_data(isoch_queue, isoch); - - if (!ret) - WLog_DBG(TAG, "isoch_queue_unregister_data: Not found isoch data!!"); - - pthread_mutex_unlock(&isoch_queue->isoch_loading); - - if (pdev && !pdev->isSigToEnd(pdev)) - { - callback->channel->Write(callback->channel, size_temp, data_temp, NULL); - zfree(data_temp); - } - } + Stream_Free(out, TRUE); + return ERROR_INVALID_PARAMETER; } - return 0; + Stream_SetPosition(out, 0); + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + + if (OutputBufferSize != 0) + Stream_Write_UINT32(out, URB_COMPLETION); + else + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); + + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 8); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + Stream_Write_UINT16(out, 8); /** Size */ + Stream_Write_UINT16(out, 0); /* Padding */ + Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */ + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + Stream_Seek(out, OutputBufferSize); + + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); + + return ERROR_SUCCESS; } -#endif - -static int urbdrc_process_register_request_callback(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, IUDEVMAN* udevman, - UINT32 UsbDevice) +static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId, UINT32 RequestId, + UINT32 OutputBufferSize) +{ + const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF); + wStream* out = Stream_New(NULL, OutputBufferSize + 28); + + if (!out) + return NULL; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, IOCONTROL_COMPLETION); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** Information */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + return out; +} + +static UINT urbdrc_process_register_request_callback(IUDEVICE* pdev, + URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 NumRequestCompletion = 0; UINT32 RequestCompletion = 0; + URBDRC_PLUGIN* urbdrc; - WLog_DBG(TAG, "urbdrc_process_register_request_callback"); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - if (pdev == NULL) - return 0; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - if (data_sizem >= 8) + WLog_Print(urbdrc->log, WLOG_DEBUG, "urbdrc_process_register_request_callback"); + + if (Stream_GetRemainingCapacity(s) >= 8) { - data_read_UINT32(data + 0, NumRequestCompletion); /** must be 1 */ + Stream_Read_UINT32(s, NumRequestCompletion); /** must be 1 */ /** RequestCompletion: * unique Request Completion interface for the client to use */ - data_read_UINT32(data + 4, RequestCompletion); + Stream_Read_UINT32(s, RequestCompletion); pdev->set_ReqCompletion(pdev, RequestCompletion); } - else /** Unregister the device */ + else if (Stream_GetRemainingCapacity(s) >= 4) /** Unregister the device */ { - data_read_UINT32(data + 0, RequestCompletion); + Stream_Read_UINT32(s, RequestCompletion); - if (1) //(pdev->get_ReqCompletion(pdev) == RequestCompletion) - { - /** The wrong driver may also receive this message, So we - * need some time(default 3s) to check the driver or delete - * it */ - sleep(3); - callback->channel->Write(callback->channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } + if (pdev->get_ReqCompletion(pdev) == RequestCompletion) + pdev->setChannelClosed(pdev); } + else + return ERROR_INVALID_DATA; - return 0; + return ERROR_SUCCESS; } -static int urbdrc_process_cancel_request(BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, - UINT32 UsbDevice) +static UINT urbdrc_process_cancel_request(IUDEVICE* pdev, wStream* s, IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 CancelId; - int error = 0; + URBDRC_PLUGIN* urbdrc; - data_read_UINT32(data + 0, CancelId); /** RequestId */ + if (!s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - WLog_DBG(TAG, "urbdrc_process_cancel_request: id 0x%" PRIx32 "", CancelId); + urbdrc = (URBDRC_PLUGIN*)udevman->plugin; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; - if (pdev == NULL) - return 0; + Stream_Read_UINT32(s, CancelId); + WLog_Print(urbdrc->log, WLOG_DEBUG, "CANCEL_REQUEST: CancelId=%08" PRIx32 "", CancelId); - error = pdev->cancel_transfer_request(pdev, CancelId); + if (pdev->cancel_transfer_request(pdev, CancelId) < 0) + return ERROR_INTERNAL_ERROR; - return error; + return ERROR_SUCCESS; } -static int urbdrc_process_retract_device_request(BYTE* data, UINT32 data_sizem, IUDEVMAN* udevman, - UINT32 UsbDevice) +static UINT urbdrc_process_retract_device_request(IUDEVICE* pdev, wStream* s, IUDEVMAN* udevman) { UINT32 Reason; - WLog_DBG(TAG, "urbdrc_process_retract_device_request"); + URBDRC_PLUGIN* urbdrc; - data_read_UINT32(data + 0, Reason); /** Reason */ + if (!s || !udevman) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)udevman->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Reason); /** Reason */ switch (Reason) { case UsbRetractReason_BlockedByPolicy: - WLog_DBG(TAG, "UsbRetractReason_BlockedByPolicy: now it is not support"); - return -1; - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "UsbRetractReason_BlockedByPolicy: now it is not support"); + return ERROR_ACCESS_DENIED; default: - WLog_DBG(TAG, "urbdrc_process_retract_device_request: Unknown Reason %" PRIu32 "", - Reason); - return -1; - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urbdrc_process_retract_device_request: Unknown Reason %" PRIu32 "", Reason); + return ERROR_ACCESS_DENIED; } - return 0; + return ERROR_SUCCESS; } -static int urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice) +static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; - UINT32 out_size; UINT32 InterfaceId; UINT32 IoControlCode; UINT32 InputBufferSize; UINT32 OutputBufferSize; UINT32 RequestId; UINT32 usbd_status = USBD_STATUS_SUCCESS; - BYTE* OutputBuffer; - BYTE* out_data; - UINT32 i; - int offset, success = 0; + wStream* out; + int success = 0; + URBDRC_PLUGIN* urbdrc; - WLog_DBG(TAG, "urbdrc_process__io_control"); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, IoControlCode); - data_read_UINT32(data + 4, InputBufferSize); - data_read_UINT32(data + 8 + InputBufferSize, OutputBufferSize); - data_read_UINT32(data + 12 + InputBufferSize, RequestId); + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, IoControlCode); + Stream_Read_UINT32(s, InputBufferSize); + + if (Stream_GetRemainingCapacity(s) < InputBufferSize + 8) + return ERROR_INVALID_DATA; + + Stream_Seek(s, InputBufferSize); + Stream_Read_UINT32(s, OutputBufferSize); + Stream_Read_UINT32(s, RequestId); InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize); - /** process */ - OutputBuffer = (BYTE*)calloc(1, OutputBufferSize); - if (!OutputBuffer) + if (!out) return ERROR_OUTOFMEMORY; switch (IoControlCode) { case IOCTL_INTERNAL_USB_SUBMIT_URB: /** 0x00220003 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked"); + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked"); break; case IOCTL_INTERNAL_USB_RESET_PORT: /** 0x00220007 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_RESET_PORT"); + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_RESET_PORT"); break; case IOCTL_INTERNAL_USB_GET_PORT_STATUS: /** 0x00220013 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS"); - - success = - pdev->query_device_port_status(pdev, &usbd_status, &OutputBufferSize, OutputBuffer); + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS"); + success = pdev->query_device_port_status(pdev, &usbd_status, &OutputBufferSize, + Stream_Pointer(out)); if (success) { - if (pdev->isExist(pdev) == 0) - { - data_write_UINT32(OutputBuffer, 0); - } - else - { - usb_process_get_port_status(pdev, OutputBuffer); - OutputBufferSize = 4; - } + Stream_Seek(out, OutputBufferSize); - WLog_DBG(TAG, - "PORT STATUS(fake!):0x%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "", - OutputBuffer[3], OutputBuffer[2], OutputBuffer[1], OutputBuffer[0]); + if (pdev->isExist(pdev) == 0) + Stream_Write_UINT32(out, 0); + else + usb_process_get_port_status(pdev, out); } break; case IOCTL_INTERNAL_USB_CYCLE_PORT: /** 0x0022001F */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked"); + WLog_Print(urbdrc->log, WLOG_DEBUG, "ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked"); break; case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: /** 0x00220027 */ - WLog_DBG(TAG, "ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); - WLog_ERR(TAG, " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked"); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION"); + WLog_Print(urbdrc->log, WLOG_ERROR, + " Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked"); break; default: - WLog_DBG(TAG, "urbdrc_process_io_control: unknown IoControlCode 0x%" PRIX32 "", - IoControlCode); - zfree(OutputBuffer); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urbdrc_process_io_control: unknown IoControlCode 0x%" PRIX32 "", + IoControlCode); + Stream_Free(out, TRUE); return ERROR_INVALID_OPERATION; - break; } - offset = 28; - out_size = offset + OutputBufferSize; - out_data = (BYTE*)calloc(1, out_size); - if (!out_data) - { - zfree(OutputBuffer); - return ERROR_OUTOFMEMORY; - } - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, IOCONTROL_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, USBD_STATUS_SUCCESS); /** HResult */ - data_write_UINT32(out_data + 20, OutputBufferSize); /** Information */ - data_write_UINT32(out_data + 24, OutputBufferSize); /** OutputBufferSize */ - - for (i = 0; i < OutputBufferSize; i++) - { - data_write_BYTE(out_data + offset, OutputBuffer[i]); /** OutputBuffer */ - offset += 1; - } - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - zfree(OutputBuffer); - - return CHANNEL_RC_OK; + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urbdrc_process_internal_io_control(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, - IUDEVMAN* udevman, UINT32 UsbDevice) +static UINT urbdrc_process_internal_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; - BYTE* out_data; - UINT32 out_size, IoControlCode, InterfaceId, InputBufferSize; + wStream* out; + UINT32 IoControlCode, InterfaceId, InputBufferSize; UINT32 OutputBufferSize, RequestId, frames; - data_read_UINT32(data + 0, IoControlCode); + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; - WLog_DBG(TAG, "urbdrc_process_internal_io_control:0x%" PRIx32 "", IoControlCode); + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; - data_read_UINT32(data + 4, InputBufferSize); - data_read_UINT32(data + 8, OutputBufferSize); - data_read_UINT32(data + 12, RequestId); + Stream_Read_UINT32(s, IoControlCode); + Stream_Read_UINT32(s, InputBufferSize); - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; + if (Stream_GetRemainingCapacity(s) < InputBufferSize + 8) + return ERROR_INVALID_DATA; + Stream_Seek(s, InputBufferSize); + Stream_Read_UINT32(s, OutputBufferSize); + Stream_Read_UINT32(s, RequestId); InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - + // TODO: Implement control code. /** Fixme: Currently this is a FALSE bustime... */ - urbdrc_get_mstime(frames); + frames = GetTickCount(); + out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, 4); - out_size = 32; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, IOCONTROL_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0); /** HResult */ - data_write_UINT32(out_data + 20, 4); /** Information */ - data_write_UINT32(out_data + 24, 4); /** OutputBufferSize */ - data_write_UINT32(out_data + 28, frames); /** OutputBuffer */ + if (!out) + return ERROR_OUTOFMEMORY; - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + Stream_Write_UINT32(out, frames); /** OutputBuffer */ + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urbdrc_process_query_device_text(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice) +static UINT urbdrc_process_query_device_text(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman) { - IUDEVICE* pdev; UINT32 out_size; - UINT32 InterfaceId; UINT32 TextType; UINT32 LocaleId; - UINT32 bufferSize = 1024; - BYTE* out_data; - BYTE DeviceDescription[bufferSize]; - int out_offset; + UINT32 InterfaceId; + UINT8 bufferSize = 0xFF; + UINT32 hr; + wStream* out; + BYTE DeviceDescription[0x100] = { 0 }; - WLog_DBG(TAG, "urbdrc_process_query_device_text"); + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, TextType); - data_read_UINT32(data + 4, LocaleId); + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + Stream_Read_UINT32(s, TextType); + Stream_Read_UINT32(s, LocaleId); + if (LocaleId > UINT16_MAX) + return ERROR_INVALID_DATA; - if (pdev == NULL) - return 0; - - pdev->control_query_device_text(pdev, TextType, LocaleId, &bufferSize, DeviceDescription); - - InterfaceId = ((STREAM_ID_STUB << 30) | UsbDevice); - - out_offset = 16; - out_size = out_offset + bufferSize; + hr = pdev->control_query_device_text(pdev, TextType, (UINT16)LocaleId, &bufferSize, + DeviceDescription); + InterfaceId = ((STREAM_ID_STUB << 30) | pdev->get_UsbDevice(pdev)); + out_size = 16 + bufferSize; if (bufferSize != 0) out_size += 2; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + if (!out) + return ERROR_OUTOFMEMORY; - if (bufferSize != 0) - { - data_write_UINT32(out_data + 8, (bufferSize / 2) + 1); /** cchDeviceDescription */ - out_offset = 12; - memcpy(out_data + out_offset, DeviceDescription, bufferSize); - out_offset += bufferSize; - data_write_UINT16(out_data + out_offset, 0x0000); - out_offset += 2; - } - else - { - data_write_UINT32(out_data + 8, 0); /** cchDeviceDescription */ - out_offset = 12; - } - - data_write_UINT32(out_data + out_offset, 0); /** HResult */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, bufferSize / 2); /** cchDeviceDescription in WCHAR */ + Stream_Write(out, DeviceDescription, bufferSize); /* '\0' terminated unicode */ + Stream_Write_UINT32(out, hr); /** HResult */ + return stream_write_and_free(callback->plugin, callback->channel, out); } static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, @@ -452,45 +394,60 @@ static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, } } -static int urb_select_configuration(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static UINT urb_select_configuration(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { MSUSB_CONFIG_DESCRIPTOR* MsConfig = NULL; - IUDEVICE* pdev = NULL; - UINT32 out_size, InterfaceId, RequestId, NumInterfaces, usbd_status = 0; + UINT32 out_size, InterfaceId, NumInterfaces, usbd_status = 0; BYTE ConfigurationDescriptorIsValid; - BYTE* out_data; - int MsOutSize = 0, offset = 0; + wStream* out; + int MsOutSize = 0; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_ERR(TAG, "urb_select_configuration: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_select_configuration: unsupported transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, ConfigurationDescriptorIsValid); - data_read_UINT32(data + 8, NumInterfaces); - offset = 12; + Stream_Read_UINT8(s, ConfigurationDescriptorIsValid); + Stream_Seek(s, 3); /* Padding */ + Stream_Read_UINT32(s, NumInterfaces); /** if ConfigurationDescriptorIsValid is zero, then just do nothing.*/ if (ConfigurationDescriptorIsValid) { /* parser data for struct config */ - MsConfig = msusb_msconfig_read(data + offset, data_sizem - offset, NumInterfaces); + MsConfig = msusb_msconfig_read(s, NumInterfaces); + + if (!MsConfig) + return ERROR_INVALID_DATA; + /* select config */ pdev->select_configuration(pdev, MsConfig->bConfigurationValue); /* select all interface */ func_select_all_interface_for_msconfig(pdev, MsConfig); /* complete configuration setup */ - MsConfig = pdev->complete_msconfig_setup(pdev, MsConfig); + if (!pdev->complete_msconfig_setup(pdev, MsConfig)) + { + msusb_msconfig_free(MsConfig); + MsConfig = NULL; + } } if (MsConfig) @@ -500,676 +457,541 @@ static int urb_select_configuration(URBDRC_CHANNEL_CALLBACK* callback, BYTE* dat out_size = 36 + MsOutSize; else out_size = 44; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ + + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + if (MsOutSize > 0) { /** CbTsUrbResult */ - data_write_UINT32(out_data + 16, 8 + MsOutSize); + Stream_Write_UINT32(out, 8 + MsOutSize); /** TS_URB_RESULT_HEADER Size*/ - data_write_UINT16(out_data + 20, 8 + MsOutSize); + Stream_Write_UINT16(out, 8 + MsOutSize); } else { - data_write_UINT32(out_data + 16, 16); - data_write_UINT16(out_data + 20, 16); + Stream_Write_UINT32(out, 16); + Stream_Write_UINT16(out, 16); } /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SELECT_CONFIGURATION); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - offset = 28; + Stream_Write_UINT16(out, TS_URB_SELECT_CONFIGURATION); + Stream_Write_UINT32(out, usbd_status); /** UsbdStatus */ + /** TS_URB_SELECT_CONFIGURATION_RESULT */ if (MsOutSize > 0) - { - msusb_msconfig_write(MsConfig, out_data, &offset); - } + msusb_msconfig_write(MsConfig, out); else { - data_write_UINT32(out_data + offset, 0); /** ConfigurationHandle */ - data_write_UINT32(out_data + offset + 4, NumInterfaces); /** NumInterfaces */ - offset += 8; + Stream_Write_UINT32(out, 0); /** ConfigurationHandle */ + Stream_Write_UINT32(out, NumInterfaces); /** NumInterfaces */ } - data_write_UINT32(out_data + offset, 0); /** HResult */ - data_write_UINT32(out_data + offset + 4, 0); /** OutputBufferSize */ - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ + + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); + + return ERROR_SUCCESS; } -static int urb_select_interface(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, UINT32 data_sizem, - UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, - int transferDir) +static UINT urb_select_interface(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { MSUSB_CONFIG_DESCRIPTOR* MsConfig; MSUSB_INTERFACE_DESCRIPTOR* MsInterface; - IUDEVICE* pdev; - UINT32 out_size, InterfaceId, RequestId, ConfigurationHandle; + UINT32 out_size, InterfaceId, ConfigurationHandle; UINT32 OutputBufferSize; BYTE InterfaceNumber; - BYTE* out_data; - int out_offset, interface_size; + wStream* out; + UINT32 interface_size; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_ERR(TAG, "urb_select_interface: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_select_interface: not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, ConfigurationHandle); + MsInterface = msusb_msinterface_read(s); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, ConfigurationHandle); - out_offset = 8; - - MsInterface = msusb_msinterface_read(data + out_offset, data_sizem - out_offset, &out_offset); - - data_read_UINT32(data + out_offset, OutputBufferSize); + if ((Stream_GetRemainingCapacity(s) < 4) || !MsInterface) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, OutputBufferSize); pdev->select_interface(pdev, MsInterface->InterfaceNumber, MsInterface->AlternateSetting); - /* replace device's MsInterface */ MsConfig = pdev->get_MsConfig(pdev); InterfaceNumber = MsInterface->InterfaceNumber; - msusb_msinterface_replace(MsConfig, InterfaceNumber, MsInterface); - + if (!msusb_msinterface_replace(MsConfig, InterfaceNumber, MsInterface)) + { + msusb_msconfig_free(MsConfig); + return ERROR_BAD_CONFIGURATION; + } /* complete configuration setup */ - MsConfig = pdev->complete_msconfig_setup(pdev, MsConfig); + if (!pdev->complete_msconfig_setup(pdev, MsConfig)) + { + msusb_msconfig_free(MsConfig); + return ERROR_BAD_CONFIGURATION; + } MsInterface = MsConfig->MsInterfaces[InterfaceNumber]; interface_size = 16 + (MsInterface->NumberOfPipes * 20); - out_size = 36 + interface_size; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8 + interface_size); /** CbTsUrbResult */ + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 8 + interface_size); /** CbTsUrbResult */ /** TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8 + interface_size); /** Size */ + Stream_Write_UINT16(out, 8 + interface_size); /** Size */ /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SELECT_INTERFACE); - data_write_UINT32(out_data + 24, USBD_STATUS_SUCCESS); /** UsbdStatus */ - out_offset = 28; - + Stream_Write_UINT16(out, TS_URB_SELECT_INTERFACE); + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */ /** TS_URB_SELECT_INTERFACE_RESULT */ - msusb_msinterface_write(MsInterface, out_data + out_offset, &out_offset); + msusb_msinterface_write(MsInterface, out); + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ - data_write_UINT32(out_data + out_offset, 0); /** HResult */ - data_write_UINT32(out_data + out_offset + 4, OutputBufferSize); /** OutputBufferSize */ + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + return ERROR_SUCCESS; } -static int urb_control_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, UINT32 data_sizem, - UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, - int transferDir, int External) +static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir, int External) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; + UINT32 out_size, InterfaceId, EndpointAddress, PipeHandle; UINT32 TransferFlags, OutputBufferSize, usbd_status, Timeout; BYTE bmRequestType, Request; UINT16 Value, Index, length; BYTE* buffer; - BYTE* out_data; - int offset, ret; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ - + Stream_Read_UINT32(s, PipeHandle); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ EndpointAddress = (PipeHandle & 0x000000ff); - offset = 12; Timeout = 2000; switch (External) { case URB_CONTROL_TRANSFER_EXTERNAL: - data_read_UINT32(data + offset, Timeout); /** TransferFlags */ - offset += 4; + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Timeout); /** TransferFlags */ break; + case URB_CONTROL_TRANSFER_NONEXTERNAL: break; } /** SetupPacket 8 bytes */ - data_read_BYTE(data + offset, bmRequestType); - data_read_BYTE(data + offset + 1, Request); - data_read_UINT16(data + offset + 2, Value); - data_read_UINT16(data + offset + 4, Index); - data_read_UINT16(data + offset + 6, length); - data_read_UINT32(data + offset + 8, OutputBufferSize); - offset += 12; + if (Stream_GetRemainingCapacity(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT8(s, bmRequestType); + Stream_Read_UINT8(s, Request); + Stream_Read_UINT16(s, Value); + Stream_Read_UINT16(s, Index); + Stream_Read_UINT16(s, length); + Stream_Read_UINT32(s, OutputBufferSize); if (length != OutputBufferSize) { - WLog_ERR(TAG, "urb_control_transfer ERROR: buf != length"); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, "urb_control_transfer ERROR: buf != length"); + return ERROR_INVALID_DATA; } out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); /** Get Buffer Data */ + buffer = Stream_Pointer(out); + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - memcpy(buffer, data + offset, OutputBufferSize); + Stream_Copy(s, out, OutputBufferSize); - /** process URB_FUNCTION_CONTROL_TRANSFER */ - ret = pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, - Request, Value, Index, &usbd_status, &OutputBufferSize, buffer, - Timeout); - - if (ret < 0) + /** process TS_URB_CONTROL_TRANSFER */ + if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, + Request, Value, Index, &usbd_status, &OutputBufferSize, buffer, + Timeout)) { - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - /** send data */ - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_CONTROL_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_bulk_or_interrupt_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static void urb_bulk_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, UINT32 RequestId, + UINT32 NumberOfPackets, UINT32 status, UINT32 StartFrame, + UINT32 ErrorCount, UINT32 OutputBufferSize) { - int offset; - BYTE* Buffer; - IUDEVICE* pdev; - BYTE* out_data; - UINT32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; - UINT32 TransferFlags, OutputBufferSize, usbd_status = 0; - - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; - - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ - data_read_UINT32(data + 12, OutputBufferSize); - offset = 16; - EndpointAddress = (PipeHandle & 0x000000ff); - - if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - out_size = 36; + if (!pdev->isChannelClosed(pdev)) + urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, status, + OutputBufferSize); else - out_size = 36 + OutputBufferSize; - - Buffer = NULL; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - - switch (transferDir) - { - case USBD_TRANSFER_DIRECTION_OUT: - Buffer = data + offset; - break; - - case USBD_TRANSFER_DIRECTION_IN: - Buffer = out_data + 36; - break; - } - - /** process URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER */ - pdev->bulk_or_interrupt_transfer(pdev, RequestId, EndpointAddress, TransferFlags, &usbd_status, - &OutputBufferSize, Buffer, 10000); - - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if (transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (pdev && !pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + Stream_Free(out, TRUE); } -static int urb_isoch_transfer(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, UINT32 data_sizem, - UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, - int transferDir) +static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 RequestId, InterfaceId, EndpointAddress; - UINT32 PipeHandle, TransferFlags, StartFrame, NumberOfPackets; - UINT32 ErrorCount, OutputBufferSize, usbd_status = 0; - UINT32 RequestField, noAck = 0; - UINT32 out_size = 0; - BYTE* iso_buffer = NULL; - BYTE* iso_packets = NULL; - BYTE* out_data = NULL; - int offset, nullBuffer = 0, iso_status; + UINT32 EndpointAddress, PipeHandle; + UINT32 TransferFlags, OutputBufferSize; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - if (pdev->isSigToEnd(pdev)) - return 0; + if (!pdev || !callback || !s || !udevman) + return ERROR_INVALID_PARAMETER; - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestField); - RequestId = RequestField & 0x7fffffff; - noAck = (RequestField & 0x80000000) >> 31; - data_read_UINT32(data + 4, PipeHandle); + if (Stream_GetRemainingCapacity(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, PipeHandle); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT32(s, OutputBufferSize); EndpointAddress = (PipeHandle & 0x000000ff); - data_read_UINT32(data + 8, TransferFlags); /** TransferFlags */ - data_read_UINT32(data + 12, StartFrame); /** StartFrame */ - data_read_UINT32(data + 16, NumberOfPackets); /** NumberOfPackets */ - data_read_UINT32(data + 20, ErrorCount); /** ErrorCount */ - offset = 24 + (NumberOfPackets * 12); - data_read_UINT32(data + offset, OutputBufferSize); - offset += 4; + /** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */ + return pdev->bulk_or_interrupt_transfer(pdev, callback, MessageId, RequestId, EndpointAddress, + TransferFlags, noAck, OutputBufferSize, + urb_bulk_transfer_cb, 10000); +} - /** send data memory alloc */ - if (transferDir == USBD_TRANSFER_DIRECTION_OUT) +static void urb_isoch_transfer_cb(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, + UINT32 RequestId, UINT32 NumberOfPackets, UINT32 status, + UINT32 StartFrame, UINT32 ErrorCount, UINT32 OutputBufferSize) +{ + if (!noAck) { - if (!noAck) + UINT32 packetSize = (status == 0) ? NumberOfPackets * 12 : 0; + Stream_SetPosition(out, 0); + /* fill the send data */ + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + + if (OutputBufferSize == 0) + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); /** function id */ + else + Stream_Write_UINT32(out, URB_COMPLETION); /** function id */ + + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 20 + packetSize); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + Stream_Write_UINT16(out, 20 + packetSize); /** Size */ + Stream_Write_UINT16(out, 0); /* Padding */ + Stream_Write_UINT32(out, status); /** UsbdStatus */ + Stream_Write_UINT32(out, StartFrame); /** StartFrame */ + + if (status == 0) { - out_size = 48 + (NumberOfPackets * 12); - out_data = (BYTE*)malloc(out_size); - iso_packets = out_data + 40; + /** NumberOfPackets */ + Stream_Write_UINT32(out, NumberOfPackets); + Stream_Write_UINT32(out, ErrorCount); /** ErrorCount */ + Stream_Seek(out, packetSize); } - } - else - { - out_size = 48 + OutputBufferSize + (NumberOfPackets * 12); - out_data = (BYTE*)malloc(out_size); - iso_packets = out_data + 40; + else + { + Stream_Write_UINT32(out, 0); /** NumberOfPackets */ + Stream_Write_UINT32(out, ErrorCount); /** ErrorCount */ + } + + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, OutputBufferSize); /** OutputBufferSize */ + Stream_Seek(out, OutputBufferSize); + + if (!pdev->isChannelClosed(pdev)) + callback->channel->Write(callback->channel, Stream_GetPosition(out), Stream_Buffer(out), + NULL); } - if (out_size) - memset(out_data, 0, out_size); - - switch (transferDir) - { - case USBD_TRANSFER_DIRECTION_OUT: - /** Get Buffer Data */ - // memcpy(iso_buffer, data + offset, OutputBufferSize); - iso_buffer = data + offset; - break; - case USBD_TRANSFER_DIRECTION_IN: - iso_buffer = out_data + 48 + (NumberOfPackets * 12); - break; - } - - WLog_DBG(TAG, - "urb_isoch_transfer: EndpointAddress: 0x%" PRIx32 ", " - "TransferFlags: 0x%" PRIx32 ", " - "StartFrame: 0x%" PRIx32 ", " - "NumberOfPackets: 0x%" PRIx32 ", " - "OutputBufferSize: 0x%" PRIx32 " " - "RequestId: 0x%" PRIx32 "", - EndpointAddress, TransferFlags, StartFrame, NumberOfPackets, OutputBufferSize, - RequestId); - -#if ISOCH_FIFO - ISOCH_CALLBACK_QUEUE* isoch_queue = NULL; - ISOCH_CALLBACK_DATA* isoch = NULL; - if (!noAck) - { - isoch_queue = (ISOCH_CALLBACK_QUEUE*)pdev->get_isoch_queue(pdev); - isoch = isoch_queue->register_data(isoch_queue, callback, pdev); - } -#endif - - iso_status = pdev->isoch_transfer(pdev, RequestId, EndpointAddress, TransferFlags, noAck, - &ErrorCount, &usbd_status, &StartFrame, NumberOfPackets, - iso_packets, &OutputBufferSize, iso_buffer, 2000); - - if (noAck) - { - zfree(out_data); - return 0; - } - - if (iso_status < 0) - nullBuffer = 1; - - out_size = 48; - if (nullBuffer) - OutputBufferSize = 0; - else - out_size += OutputBufferSize + (NumberOfPackets * 12); - /* fill the send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if (OutputBufferSize != 0 && !nullBuffer) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 20 + (NumberOfPackets * 12)); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 20 + (NumberOfPackets * 12)); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_ISOCH_TRANSFER); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, StartFrame); /** StartFrame */ - if (!nullBuffer) - { - /** NumberOfPackets */ - data_write_UINT32(out_data + 32, NumberOfPackets); - data_write_UINT32(out_data + 36, ErrorCount); /** ErrorCount */ - offset = 40 + (NumberOfPackets * 12); - } - else - { - data_write_UINT32(out_data + 32, 0); /** NumberOfPackets */ - data_write_UINT32(out_data + 36, NumberOfPackets); /** ErrorCount */ - offset = 40; - } - - data_write_UINT32(out_data + offset, 0); /** HResult */ - data_write_UINT32(out_data + offset + 4, OutputBufferSize); /** OutputBufferSize */ - -#if ISOCH_FIFO - if (!noAck) - { - pthread_mutex_lock(&isoch_queue->isoch_loading); - isoch->out_data = out_data; - isoch->out_size = out_size; - pthread_mutex_unlock(&isoch_queue->isoch_loading); - } -#else - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); -#endif - - if (nullBuffer) - return -1; - - return 0; + Stream_Free(out, TRUE); } -static int urb_control_descriptor_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, BYTE func_recipient, int transferDir) +static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, InterfaceId, RequestId, OutputBufferSize, usbd_status; + UINT32 EndpointAddress; + UINT32 PipeHandle, TransferFlags, StartFrame, NumberOfPackets; + UINT32 ErrorCount, OutputBufferSize; + BYTE* packetDescriptorData; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!pdev || !callback || !udevman) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 20) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, PipeHandle); + EndpointAddress = (PipeHandle & 0x000000ff); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT32(s, StartFrame); /** StartFrame */ + Stream_Read_UINT32(s, NumberOfPackets); /** NumberOfPackets */ + Stream_Read_UINT32(s, ErrorCount); /** ErrorCount */ + + if (Stream_GetRemainingCapacity(s) < NumberOfPackets * 12 + 4) + return ERROR_INVALID_DATA; + + packetDescriptorData = Stream_Pointer(s); + Stream_Seek(s, NumberOfPackets * 12); + Stream_Read_UINT32(s, OutputBufferSize); + return pdev->isoch_transfer( + pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame, + ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize, + (transferDir == USBD_TRANSFER_DIRECTION_OUT) ? Stream_Pointer(s) : NULL, + urb_isoch_transfer_cb, 2000); +} + +static UINT urb_control_descriptor_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, int transferDir) +{ + UINT32 out_size, InterfaceId, OutputBufferSize, usbd_status; BYTE bmRequestType, desc_index, desc_type; UINT16 langId; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, desc_index); - data_read_BYTE(data + 5, desc_type); - data_read_UINT16(data + 6, langId); - data_read_UINT32(data + 8, OutputBufferSize); + Stream_Read_UINT8(s, desc_index); + Stream_Read_UINT8(s, desc_type); + Stream_Read_UINT16(s, langId); + Stream_Read_UINT32(s, OutputBufferSize); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (Stream_GetRemainingCapacity(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + } out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); bmRequestType = func_recipient; + switch (transferDir) { case USBD_TRANSFER_DIRECTION_IN: bmRequestType |= 0x80; break; + case USBD_TRANSFER_DIRECTION_OUT: bmRequestType |= 0x00; - offset = 12; - memcpy(buffer, data + offset, OutputBufferSize); + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); break; + default: - WLog_DBG(TAG, "get error transferDir"); + WLog_Print(urbdrc->log, WLOG_DEBUG, "get error transferDir"); OutputBufferSize = 0; usbd_status = USBD_STATUS_STALL_PID; break; } /** process get usb device descriptor */ - - ret = pdev->control_transfer( - pdev, RequestId, 0, 0, bmRequestType, 0x06, /* REQUEST_GET_DESCRIPTOR */ - (desc_type << 8) | desc_index, langId, &usbd_status, &OutputBufferSize, buffer, 1000); - - if (ret < 0) + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, + 0x06, /* REQUEST_GET_DESCRIPTOR */ + (desc_type << 8) | desc_index, langId, &usbd_status, + &OutputBufferSize, Stream_Pointer(out), 1000)) { - WLog_DBG(TAG, "get_descriptor: error num %d", ret); - OutputBufferSize = 0; + WLog_Print(urbdrc->log, WLOG_ERROR, "get_descriptor failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_control_get_status_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, BYTE func_recipient, int transferDir) +static UINT urb_control_get_status_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + UINT32 out_size, InterfaceId, OutputBufferSize, usbd_status; UINT16 Index; BYTE bmRequestType; - BYTE* buffer; - BYTE* out_data; - int offset, ret; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_DBG(TAG, "urb_control_get_status_request: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_status_request: transfer out not supported"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, Index); /** Index */ - data_read_UINT32(data + 8, OutputBufferSize); - + Stream_Read_UINT16(s, Index); /** Index */ + Stream_Seek(s, 2); + Stream_Read_UINT32(s, OutputBufferSize); out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; + Stream_Seek(out, 36); bmRequestType = func_recipient | 0x80; - ret = - pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, 0x00, /* REQUEST_GET_STATUS */ - 0, Index, &usbd_status, &OutputBufferSize, buffer, 1000); - - if (ret < 0) + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, 0x00, /* REQUEST_GET_STATUS */ + 0, Index, &usbd_status, &OutputBufferSize, Stream_Pointer(out), + 1000)) { - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; - usbd_status = USBD_STATUS_STALL_PID; - } - else - { - usbd_status = USBD_STATUS_SUCCESS; + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - /** send data */ - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - - data_write_UINT32(out_data + 12, RequestId); /** RequestId, include NoAck*/ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_VENDOR_DEVICE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, - IUDEVMAN* udevman, UINT32 UsbDevice, BYTE func_type, - BYTE func_recipient, int transferDir) +static UINT urb_control_vendor_or_class_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_type, + BYTE func_recipient, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, TransferFlags, usbd_status; + UINT32 out_size, InterfaceId, TransferFlags, usbd_status; UINT32 OutputBufferSize; BYTE ReqTypeReservedBits, Request, bmRequestType; UINT16 Value, Index, Padding; - BYTE* buffer; - BYTE* out_data; - int offset, ret; - /** control by vendor command */ + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 16) + return ERROR_INVALID_DATA; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT8(s, ReqTypeReservedBits); /** ReqTypeReservedBids */ + Stream_Read_UINT8(s, Request); /** Request */ + Stream_Read_UINT16(s, Value); /** value */ + Stream_Read_UINT16(s, Index); /** index */ + Stream_Read_UINT16(s, Padding); /** Padding */ + Stream_Read_UINT32(s, OutputBufferSize); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, TransferFlags); /** TransferFlags */ - data_read_BYTE(data + 8, ReqTypeReservedBits); /** ReqTypeReservedBids */ - data_read_BYTE(data + 9, Request); /** Request */ - data_read_UINT16(data + 10, Value); /** value */ - data_read_UINT16(data + 12, Index); /** index */ - data_read_UINT16(data + 14, Padding); /** Padding */ - data_read_UINT32(data + 16, OutputBufferSize); - offset = 20; + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (Stream_GetRemainingCapacity(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + } out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Seek(out, 36); /** Get Buffer */ if (transferDir == USBD_TRANSFER_DIRECTION_OUT) - memcpy(buffer, data + offset, OutputBufferSize); + { + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); + } /** vendor or class command */ bmRequestType = func_type | func_recipient; @@ -1177,468 +999,415 @@ static int urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK* callback if (TransferFlags & USBD_TRANSFER_DIRECTION) bmRequestType |= 0x80; - WLog_DBG(TAG, - "urb_control_vendor_or_class_request: " - "RequestId 0x%" PRIx32 " TransferFlags: 0x%" PRIx32 " ReqTypeReservedBits: 0x%" PRIx8 - " " - "Request:0x%" PRIx8 " Value: 0x%" PRIx16 " Index: 0x%" PRIx16 - " OutputBufferSize: 0x%" PRIx32 " bmRequestType: 0x%" PRIx8 "!!", - RequestId, TransferFlags, ReqTypeReservedBits, Request, Value, Index, OutputBufferSize, - bmRequestType); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "RequestId 0x%" PRIx32 " TransferFlags: 0x%" PRIx32 " ReqTypeReservedBits: 0x%" PRIx8 + " " + "Request:0x%" PRIx8 " Value: 0x%" PRIx16 " Index: 0x%" PRIx16 + " OutputBufferSize: 0x%" PRIx32 " bmRequestType: 0x%" PRIx8, + RequestId, TransferFlags, ReqTypeReservedBits, Request, Value, Index, + OutputBufferSize, bmRequestType); - ret = pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, Request, Value, Index, - &usbd_status, &OutputBufferSize, buffer, 2000); - - if (ret < 0) + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, Request, Value, Index, + &usbd_status, &OutputBufferSize, Stream_Pointer(out), 2000)) { - WLog_DBG(TAG, "control_transfer: error num %d!!", ret); - OutputBufferSize = 0; - usbd_status = USBD_STATUS_STALL_PID; - } - else - { - usbd_status = USBD_STATUS_SUCCESS; + WLog_Print(urbdrc->log, WLOG_ERROR, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - if (transferDir == USBD_TRANSFER_DIRECTION_IN) - out_size = offset + OutputBufferSize; - else - out_size = offset; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (transferDir == USBD_TRANSFER_DIRECTION_IN && OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - - data_write_UINT32(out_data + 12, RequestId); /** RequestId, include NoAck*/ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - data_write_UINT16(out_data + 22, - URB_FUNCTION_VENDOR_DEVICE); /** Padding, MUST be ignored upon receipt */ - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_os_feature_descriptor_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static UINT urb_os_feature_descriptor_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + UINT32 out_size, InterfaceId, OutputBufferSize, usbd_status; BYTE Recipient, InterfaceNumber, Ms_PageIndex; UINT16 Ms_featureDescIndex; - BYTE* out_data; - BYTE* buffer; - int offset, ret; + wStream* out; + int ret; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + if (!urbdrc) + return ERROR_INVALID_PARAMETER; - data_read_UINT32(data + 0, RequestId); - data_read_BYTE(data + 4, Recipient); /** Recipient */ - Recipient = (Recipient & 0x1f); /* XXX: origin: Recipient && 0x1f !? */ - data_read_BYTE(data + 5, InterfaceNumber); /** InterfaceNumber */ - data_read_BYTE(data + 6, Ms_PageIndex); /** Ms_PageIndex */ - data_read_UINT16(data + 7, Ms_featureDescIndex); /** Ms_featureDescIndex */ - data_read_UINT32(data + 12, OutputBufferSize); - offset = 16; + if (Stream_GetRemainingCapacity(s) < 12) + return ERROR_INVALID_DATA; - out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - - buffer = out_data + 36; + /* 2.2.9.15 TS_URB_OS_FEATURE_DESCRIPTOR_REQUEST */ + Stream_Read_UINT8(s, Recipient); /** Recipient */ + Recipient = (Recipient & 0x1f); /* Mask out Padding1 */ + Stream_Read_UINT8(s, InterfaceNumber); /** InterfaceNumber */ + Stream_Read_UINT8(s, Ms_PageIndex); /** Ms_PageIndex */ + Stream_Read_UINT16(s, Ms_featureDescIndex); /** Ms_featureDescIndex */ + Stream_Seek(s, 3); /* Padding 2 */ + Stream_Read_UINT32(s, OutputBufferSize); switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - WLog_ERR(TAG, "Function urb_os_feature_descriptor_request: OUT Unchecked"); - memcpy(buffer, data + offset, OutputBufferSize); + if (Stream_GetRemainingCapacity(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + break; + + default: + break; + } + + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + out_size = 36 + OutputBufferSize; + out = Stream_New(NULL, out_size); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Seek(out, 36); + + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); + break; + case USBD_TRANSFER_DIRECTION_IN: break; } - WLog_DBG(TAG, - "Ms descriptor arg: Recipient:0x%" PRIx8 ", " - "InterfaceNumber:0x%" PRIx8 ", Ms_PageIndex:0x%" PRIx8 ", " - "Ms_featureDescIndex:0x%" PRIx16 ", OutputBufferSize:0x%" PRIx32 "", - Recipient, InterfaceNumber, Ms_PageIndex, Ms_featureDescIndex, OutputBufferSize); - + WLog_Print(urbdrc->log, WLOG_DEBUG, + "Ms descriptor arg: Recipient:0x%" PRIx8 ", " + "InterfaceNumber:0x%" PRIx8 ", Ms_PageIndex:0x%" PRIx8 ", " + "Ms_featureDescIndex:0x%" PRIx16 ", OutputBufferSize:0x%" PRIx32 "", + Recipient, InterfaceNumber, Ms_PageIndex, Ms_featureDescIndex, OutputBufferSize); /** get ms string */ ret = pdev->os_feature_descriptor_request(pdev, RequestId, Recipient, InterfaceNumber, Ms_PageIndex, Ms_featureDescIndex, &usbd_status, - &OutputBufferSize, buffer, 1000); + &OutputBufferSize, Stream_Pointer(out), 1000); if (ret < 0) - WLog_DBG(TAG, "os_feature_descriptor_request: error num %d", ret); + WLog_Print(urbdrc->log, WLOG_DEBUG, "os_feature_descriptor_request: error num %d", ret); - offset = 36; - out_size = offset + OutputBufferSize; - /** send data */ - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); /** function id */ - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - - zfree(out_data); - - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_pipe_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, UINT32 data_sizem, - UINT32 MessageId, IUDEVMAN* udevman, UINT32 UsbDevice, int transferDir, - int action) +static UINT urb_pipe_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 RequestField, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir, int action) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, PipeHandle, EndpointAddress; + UINT32 out_size, InterfaceId, PipeHandle, EndpointAddress; UINT32 OutputBufferSize, usbd_status = 0; - BYTE* out_data; - int out_offset, ret; + wStream* out; + UINT32 ret = USBD_STATUS_REQUEST_FAILED; + int rc; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; if (transferDir == 0) { - WLog_DBG(TAG, "urb_pipe_request: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request: not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - - if (pdev == NULL) - return 0; - InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, PipeHandle); /** PipeHandle */ - data_read_UINT32(data + 8, OutputBufferSize); + Stream_Read_UINT32(s, PipeHandle); /** PipeHandle */ + Stream_Read_UINT32(s, OutputBufferSize); EndpointAddress = (PipeHandle & 0x000000ff); switch (action) { case PIPE_CANCEL: - WLog_DBG(TAG, "urb_pipe_request: PIPE_CANCEL 0x%" PRIx32 "", EndpointAddress); + rc = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, + PIPE_CANCEL); - ret = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, - PIPE_CANCEL); - - if (ret < 0) - { - WLog_DBG(TAG, "PIPE SET HALT: error num %d", ret); - } + if (rc < 0) + WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE SET HALT: error %d", ret); + else + ret = USBD_STATUS_SUCCESS; break; + case PIPE_RESET: - WLog_DBG(TAG, "urb_pipe_request: PIPE_RESET ep 0x%" PRIx32 "", EndpointAddress); + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request: PIPE_RESET ep 0x%" PRIx32 "", + EndpointAddress); + rc = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, + PIPE_RESET); - ret = pdev->control_pipe_request(pdev, RequestId, EndpointAddress, &usbd_status, - PIPE_RESET); - - if (ret < 0) - WLog_DBG(TAG, "PIPE RESET: error num %d!!", ret); + if (rc < 0) + WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE RESET: error %d", ret); + else + ret = USBD_STATUS_SUCCESS; break; + default: - WLog_DBG(TAG, "urb_pipe_request action: %d is not support!", action); + WLog_Print(urbdrc->log, WLOG_DEBUG, "urb_pipe_request action: %d not supported", + action); + ret = USBD_STATUS_INVALID_URB_FUNCTION; break; } /** send data */ - out_offset = 36; - out_size = out_offset + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + out_size = 36; + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 0x00000008); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 0x0008); /** Size */ + if (!out) + return ERROR_OUTOFMEMORY; - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, 0); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, ret, + 0); } -static int urb_get_current_frame_number(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static UINT urb_get_current_frame_number(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize; + UINT32 out_size, InterfaceId, OutputBufferSize; UINT32 dummy_frames; - BYTE* out_data; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; if (transferDir == 0) { - WLog_DBG(TAG, "urb_get_current_frame_number: not support transfer out"); - // exit(1); - return -1; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_get_current_frame_number: not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, OutputBufferSize); - + Stream_Read_UINT32(s, OutputBufferSize); /** Fixme: Need to fill actual frame number!!*/ - urbdrc_get_mstime(dummy_frames); - + dummy_frames = GetTickCount(); out_size = 40; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ + out = Stream_New(NULL, out_size); - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 12); /** CbTsUrbResult */ + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /** interface */ + Stream_Write_UINT32(out, MessageId); /** message id */ + Stream_Write_UINT32(out, URB_COMPLETION_NO_DATA); + Stream_Write_UINT32(out, RequestId); /** RequestId */ + Stream_Write_UINT32(out, 12); /** CbTsUrbResult */ /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 12); /** Size */ - + Stream_Write_UINT16(out, 12); /** Size */ /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_CURRENT_FRAME_NUMBER); - data_write_UINT32(out_data + 24, USBD_STATUS_SUCCESS); /** UsbdStatus */ - data_write_UINT32(out_data + 28, dummy_frames); /** FrameNumber */ + Stream_Write_UINT16(out, TS_URB_GET_CURRENT_FRAME_NUMBER); + Stream_Write_UINT32(out, USBD_STATUS_SUCCESS); /** UsbdStatus */ + Stream_Write_UINT32(out, dummy_frames); /** FrameNumber */ + Stream_Write_UINT32(out, 0); /** HResult */ + Stream_Write_UINT32(out, 0); /** OutputBufferSize */ - data_write_UINT32(out_data + 32, 0); /** HResult */ - data_write_UINT32(out_data + 36, 0); /** OutputBufferSize */ + if (!noAck) + return stream_write_and_free(callback->plugin, callback->channel, out); + else + Stream_Free(out, TRUE); - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return ERROR_SUCCESS; } /* Unused function for current server */ -static int urb_control_get_configuration_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, - IUDEVMAN* udevman, UINT32 UsbDevice, - int transferDir) +static UINT urb_control_get_configuration_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + UINT32 out_size, InterfaceId, OutputBufferSize, usbd_status; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; if (transferDir == 0) { - WLog_DBG(TAG, "urb_control_get_configuration_request:" - " not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_configuration_request:" + " not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (Stream_GetRemainingCapacity(s) < 4) + return ERROR_INVALID_DATA; - if (pdev == NULL) - return 0; + Stream_Read_UINT32(s, OutputBufferSize); + out_size = 36 + OutputBufferSize; + out = Stream_New(NULL, out_size); + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Seek(out, 36); InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - data_read_UINT32(data + 0, RequestId); - data_read_UINT32(data + 4, OutputBufferSize); - - out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - - buffer = out_data + 36; - - ret = pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x00, - 0x08, /* REQUEST_GET_CONFIGURATION */ - 0, 0, &usbd_status, &OutputBufferSize, buffer, 1000); - - if (ret < 0) + if (!pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x00, + 0x08, /* REQUEST_GET_CONFIGURATION */ + 0, 0, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) { - WLog_DBG(TAG, "control_transfer: error num %d", ret); - OutputBufferSize = 0; + WLog_Print(urbdrc->log, WLOG_DEBUG, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_CONFIGURATION); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } /* Unused function for current server */ -static int urb_control_get_interface_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static UINT urb_control_get_interface_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + UINT32 out_size, InterfaceId, OutputBufferSize, usbd_status; UINT16 interface; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; + + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; if (transferDir == 0) { - WLog_DBG(TAG, "urb_control_get_interface_request: not support transfer out"); - return -1; + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_control_get_interface_request: not support transfer out"); + return ERROR_INVALID_PARAMETER; } - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); - - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, interface); - data_read_UINT32(data + 8, OutputBufferSize); - + Stream_Read_UINT16(s, interface); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, OutputBufferSize); out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); + out = Stream_New(NULL, out_size); - buffer = out_data + 36; + if (!out) + return ERROR_OUTOFMEMORY; - ret = - pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x01, 0x0A, /* REQUEST_GET_INTERFACE */ - 0, interface, &usbd_status, &OutputBufferSize, buffer, 1000); + Stream_Seek(out, 36); - if (ret < 0) + if (!pdev->control_transfer( + pdev, RequestId, 0, 0, 0x80 | 0x01, 0x0A, /* REQUEST_GET_INTERFACE */ + 0, interface, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) { - WLog_DBG(TAG, "control_transfer: error num %d", ret); - OutputBufferSize = 0; + WLog_Print(urbdrc->log, WLOG_DEBUG, "control_transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_INTERFACE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, BYTE func_recipient, BYTE command, - int transferDir) +static UINT urb_control_feature_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 RequestField, UINT32 MessageId, + IUDEVMAN* udevman, BYTE func_recipient, BYTE command, + int transferDir) { - IUDEVICE* pdev; - UINT32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + UINT32 InterfaceId, OutputBufferSize, usbd_status; UINT16 FeatureSelector, Index; BYTE bmRequestType, bmRequest; - BYTE* buffer; - BYTE* out_data; - int ret, offset; + wStream* out; + URBDRC_PLUGIN* urbdrc; + const BOOL noAck = (RequestField & 0x80000000U) != 0; + const UINT32 RequestId = RequestField & 0x7FFFFFFF; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; - if (pdev == NULL) - return 0; + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 8) + return ERROR_INVALID_DATA; InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + Stream_Read_UINT16(s, FeatureSelector); + Stream_Read_UINT16(s, Index); + Stream_Read_UINT32(s, OutputBufferSize); - data_read_UINT32(data + 0, RequestId); - data_read_UINT16(data + 4, FeatureSelector); - data_read_UINT16(data + 6, Index); - data_read_UINT32(data + 8, OutputBufferSize); - offset = 12; - - out_size = 36 + OutputBufferSize; - out_data = (BYTE*)malloc(out_size); - memset(out_data, 0, out_size); - - buffer = out_data + 36; - - bmRequestType = func_recipient; switch (transferDir) { case USBD_TRANSFER_DIRECTION_OUT: - WLog_ERR(TAG, "Function urb_control_feature_request: OUT Unchecked"); - memcpy(buffer, data + offset, OutputBufferSize); + if (Stream_GetRemainingCapacity(s) < OutputBufferSize) + return ERROR_INVALID_DATA; + + break; + + default: + break; + } + + out = Stream_New(NULL, 36 + OutputBufferSize); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Seek(out, 36); + bmRequestType = func_recipient; + + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + WLog_Print(urbdrc->log, WLOG_ERROR, + "Function urb_control_feature_request: OUT Unchecked"); + Stream_Copy(s, out, OutputBufferSize); + Stream_Rewind(out, OutputBufferSize); bmRequestType |= 0x00; break; + case USBD_TRANSFER_DIRECTION_IN: bmRequestType |= 0x80; break; @@ -1649,484 +1418,403 @@ static int urb_control_feature_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* case URB_SET_FEATURE: bmRequest = 0x03; /* REQUEST_SET_FEATURE */ break; + case URB_CLEAR_FEATURE: bmRequest = 0x01; /* REQUEST_CLEAR_FEATURE */ break; + default: - WLog_ERR(TAG, "urb_control_feature_request: Error Command 0x%02" PRIx8 "", command); - zfree(out_data); - return -1; + WLog_Print(urbdrc->log, WLOG_ERROR, + "urb_control_feature_request: Error Command 0x%02" PRIx8 "", command); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - ret = pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, bmRequest, FeatureSelector, - Index, &usbd_status, &OutputBufferSize, buffer, 1000); - - if (ret < 0) + if (!pdev->control_transfer(pdev, RequestId, 0, 0, bmRequestType, bmRequest, FeatureSelector, + Index, &usbd_status, &OutputBufferSize, Stream_Pointer(out), 1000)) { - WLog_DBG(TAG, "feature control transfer: error num %d", ret); - OutputBufferSize = 0; + WLog_Print(urbdrc->log, WLOG_DEBUG, "feature control transfer failed"); + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; } - offset = 36; - out_size = offset + OutputBufferSize; - data_write_UINT32(out_data + 0, InterfaceId); /** interface */ - data_write_UINT32(out_data + 4, MessageId); /** message id */ - - if (OutputBufferSize != 0) - data_write_UINT32(out_data + 8, URB_COMPLETION); - else - data_write_UINT32(out_data + 8, URB_COMPLETION_NO_DATA); - data_write_UINT32(out_data + 12, RequestId); /** RequestId */ - data_write_UINT32(out_data + 16, 8); /** CbTsUrbResult */ - /** TsUrbResult TS_URB_RESULT_HEADER */ - data_write_UINT16(out_data + 20, 8); /** Size */ - - /** Padding, MUST be ignored upon receipt */ - data_write_UINT16(out_data + 22, URB_FUNCTION_GET_INTERFACE); - data_write_UINT32(out_data + 24, usbd_status); /** UsbdStatus */ - - data_write_UINT32(out_data + 28, 0); /** HResult */ - data_write_UINT32(out_data + 32, OutputBufferSize); /** OutputBufferSize */ - - if (!pdev->isSigToEnd(pdev)) - callback->channel->Write(callback->channel, out_size, out_data, NULL); - zfree(out_data); - return 0; + return urb_write_completion(pdev, callback, noAck, out, InterfaceId, MessageId, RequestId, + usbd_status, OutputBufferSize); } -static int urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK* callback, BYTE* data, - UINT32 data_sizem, UINT32 MessageId, IUDEVMAN* udevman, - UINT32 UsbDevice, int transferDir) +static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback, + wStream* s, UINT32 MessageId, IUDEVMAN* udevman, + int transferDir) { - IUDEVICE* pdev; UINT32 CbTsUrb; UINT16 Size; UINT16 URB_Function; - UINT32 OutputBufferSize; - int error = 0; + UINT32 RequestId; + UINT error = ERROR_INTERNAL_ERROR; + URBDRC_PLUGIN* urbdrc; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL) - return 0; - data_read_UINT32(data + 0, CbTsUrb); /** CbTsUrb */ - data_read_UINT16(data + 4, Size); /** size */ - data_read_UINT16(data + 6, URB_Function); - data_read_UINT32(data + 4 + CbTsUrb, OutputBufferSize); + if (!callback || !s || !udevman || !pdev) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingCapacity(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, CbTsUrb); /** CbTsUrb */ + Stream_Read_UINT16(s, Size); /** size */ + Stream_Read_UINT16(s, URB_Function); + Stream_Read_UINT32(s, RequestId); + WLog_Print(urbdrc->log, WLOG_DEBUG, "URB %s[" PRIu16 "]", urb_function_string(URB_Function), + URB_Function); switch (URB_Function) { - case URB_FUNCTION_SELECT_CONFIGURATION: /** 0x0000 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_CONFIGURATION"); - error = urb_select_configuration(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir); + case TS_URB_SELECT_CONFIGURATION: /** 0x0000 */ + error = urb_select_configuration(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); break; - case URB_FUNCTION_SELECT_INTERFACE: /** 0x0001 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SELECT_INTERFACE"); - error = urb_select_interface(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir); - break; - case URB_FUNCTION_ABORT_PIPE: /** 0x0002 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ABORT_PIPE"); - error = urb_pipe_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, PIPE_CANCEL); - break; - case URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL: /** 0x0003 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL: /** 0x0004 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_GET_FRAME_LENGTH: /** 0x0005 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_FRAME_LENGTH"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_SET_FRAME_LENGTH: /** 0x0006 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FRAME_LENGTH"); - error = -1; /** This URB function is obsolete in Windows 2000 - * and later operating systems - * and is not supported by Microsoft. */ - break; - case URB_FUNCTION_GET_CURRENT_FRAME_NUMBER: /** 0x0007 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CURRENT_FRAME_NUMBER"); - error = urb_get_current_frame_number(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, transferDir); - break; - case URB_FUNCTION_CONTROL_TRANSFER: /** 0x0008 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER"); - error = urb_control_transfer(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, URB_CONTROL_TRANSFER_NONEXTERNAL); - break; - case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER: /** 0x0009 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER"); - error = urb_bulk_or_interrupt_transfer(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, transferDir); - break; - case URB_FUNCTION_ISOCH_TRANSFER: /** 0x000A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_ISOCH_TRANSFER"); - error = urb_isoch_transfer(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir); - break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE: /** 0x000B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x00, transferDir); - break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE: /** 0x000C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x00, transferDir); - break; - case URB_FUNCTION_SET_FEATURE_TO_DEVICE: /** 0x000D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_DEVICE"); + + case TS_URB_SELECT_INTERFACE: /** 0x0001 */ error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x00, URB_SET_FEATURE, transferDir); + urb_select_interface(pdev, callback, s, RequestId, MessageId, udevman, transferDir); break; - case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: /** 0x000E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_INTERFACE"); + + case TS_URB_PIPE_REQUEST: /** 0x0002 */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_CANCEL); + break; + + case TS_URB_TAKE_FRAME_LENGTH_CONTROL: /** 0x0003 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_RELEASE_FRAME_LENGTH_CONTROL: /** 0x0004 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_GET_FRAME_LENGTH: /** 0x0005 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_SET_FRAME_LENGTH: /** 0x0006 */ + /** This URB function is obsolete in Windows 2000 + * and later operating systems + * and is not supported by Microsoft. */ + break; + + case TS_URB_GET_CURRENT_FRAME_NUMBER: /** 0x0007 */ + error = urb_get_current_frame_number(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); + break; + + case TS_URB_CONTROL_TRANSFER: /** 0x0008 */ + error = urb_control_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir, URB_CONTROL_TRANSFER_NONEXTERNAL); + break; + + case TS_URB_BULK_OR_INTERRUPT_TRANSFER: /** 0x0009 */ + error = urb_bulk_or_interrupt_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir); + break; + + case TS_URB_ISOCH_TRANSFER: /** 0x000A */ error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x01, URB_SET_FEATURE, transferDir); + urb_isoch_transfer(pdev, callback, s, RequestId, MessageId, udevman, transferDir); break; - case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_ENDPOINT"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x02, URB_SET_FEATURE, transferDir); + + case TS_URB_GET_DESCRIPTOR_FROM_DEVICE: /** 0x000B */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); break; - case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x00, URB_CLEAR_FEATURE, transferDir); + + case TS_URB_SET_DESCRIPTOR_TO_DEVICE: /** 0x000C */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); break; - case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x01, URB_CLEAR_FEATURE, transferDir); + + case TS_URB_SET_FEATURE_TO_DEVICE: /** 0x000D */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, URB_SET_FEATURE, transferDir); break; - case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x02, URB_CLEAR_FEATURE, transferDir); + + case TS_URB_SET_FEATURE_TO_INTERFACE: /** 0x000E */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, URB_SET_FEATURE, transferDir); break; - case URB_FUNCTION_GET_STATUS_FROM_DEVICE: /** 0x0013 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_DEVICE"); - error = urb_control_get_status_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x00, transferDir); + + case TS_URB_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, URB_SET_FEATURE, transferDir); break; - case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_INTERFACE"); - error = urb_control_get_status_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x01, transferDir); + + case TS_URB_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, URB_CLEAR_FEATURE, transferDir); break; - case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_ENDPOINT"); - error = urb_control_get_status_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x02, transferDir); + + case TS_URB_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, URB_CLEAR_FEATURE, transferDir); break; - case URB_FUNCTION_RESERVED_0X0016: /** 0x0016 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVED_0X0016"); - error = -1; + + case TS_URB_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, URB_CLEAR_FEATURE, transferDir); break; - case URB_FUNCTION_VENDOR_DEVICE: /** 0x0017 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_DEVICE"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x02 << 5), /* vendor type */ + + case TS_URB_GET_STATUS_FROM_DEVICE: /** 0x0013 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x00, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); + break; + + case TS_URB_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); + break; + + case TS_URB_RESERVED_0X0016: /** 0x0016 */ + break; + + case TS_URB_VENDOR_DEVICE: /** 0x0017 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ 0x00, transferDir); break; - case URB_FUNCTION_VENDOR_INTERFACE: /** 0x0018 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_INTERFACE"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x02 << 5), /* vendor type */ + + case TS_URB_VENDOR_INTERFACE: /** 0x0018 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ 0x01, transferDir); break; - case URB_FUNCTION_VENDOR_ENDPOINT: /** 0x0019 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_ENDPOINT"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x02 << 5), /* vendor type */ + + case TS_URB_VENDOR_ENDPOINT: /** 0x0019 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ 0x02, transferDir); break; - case URB_FUNCTION_CLASS_DEVICE: /** 0x001A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_DEVICE"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x01 << 5), /* class type */ + + case TS_URB_CLASS_DEVICE: /** 0x001A */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ 0x00, transferDir); break; - case URB_FUNCTION_CLASS_INTERFACE: /** 0x001B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_INTERFACE"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x01 << 5), /* class type */ + + case TS_URB_CLASS_INTERFACE: /** 0x001B */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ 0x01, transferDir); break; - case URB_FUNCTION_CLASS_ENDPOINT: /** 0x001C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_ENDPOINT"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x01 << 5), /* class type */ + + case TS_URB_CLASS_ENDPOINT: /** 0x001C */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ 0x02, transferDir); break; - case URB_FUNCTION_RESERVE_0X001D: /** 0x001D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X001D"); - error = -1; + + case TS_URB_RESERVE_0X001D: /** 0x001D */ break; - case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL"); - error = urb_pipe_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, PIPE_RESET); + + case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); break; - case URB_FUNCTION_CLASS_OTHER: /** 0x001F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLASS_OTHER"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x01 << 5), /* class type */ + + case TS_URB_CLASS_OTHER: /** 0x001F */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x01 << 5), /* class type */ 0x03, transferDir); break; - case URB_FUNCTION_VENDOR_OTHER: /** 0x0020 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_VENDOR_OTHER"); - error = urb_control_vendor_or_class_request(callback, data + 8, data_sizem - 8, - MessageId, udevman, UsbDevice, - (0x02 << 5), /* vendor type */ + + case TS_URB_VENDOR_OTHER: /** 0x0020 */ + error = urb_control_vendor_or_class_request(pdev, callback, s, RequestId, MessageId, + udevman, (0x02 << 5), /* vendor type */ 0x03, transferDir); break; - case URB_FUNCTION_GET_STATUS_FROM_OTHER: /** 0x0021 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_STATUS_FROM_OTHER"); - error = urb_control_get_status_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x03, transferDir); + + case TS_URB_GET_STATUS_FROM_OTHER: /** 0x0021 */ + error = urb_control_get_status_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, transferDir); break; - case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CLEAR_FEATURE_TO_OTHER"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x03, URB_CLEAR_FEATURE, transferDir); + + case TS_URB_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, URB_CLEAR_FEATURE, transferDir); break; - case URB_FUNCTION_SET_FEATURE_TO_OTHER: /** 0x0023 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_FEATURE_TO_OTHER"); - error = - urb_control_feature_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, 0x03, URB_SET_FEATURE, transferDir); + + case TS_URB_SET_FEATURE_TO_OTHER: /** 0x0023 */ + error = urb_control_feature_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x03, URB_SET_FEATURE, transferDir); break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x02, transferDir); + + case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x02, transferDir); + + case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x02, transferDir); break; - case URB_FUNCTION_GET_CONFIGURATION: /** 0x0026 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_CONFIGURATION"); - error = urb_control_get_configuration_request( - callback, data + 8, data_sizem - 8, MessageId, udevman, UsbDevice, transferDir); + + case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST: /** 0x0026 */ + error = urb_control_get_configuration_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); break; - case URB_FUNCTION_GET_INTERFACE: /** 0x0027 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_INTERFACE"); - error = urb_control_get_interface_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, transferDir); + + case TS_URB_CONTROL_GET_INTERFACE_REQUEST: /** 0x0027 */ + error = urb_control_get_interface_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); break; - case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x01, transferDir); + + case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); break; - case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE"); - error = urb_control_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, 0x01, transferDir); + + case TS_URB_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ + error = urb_control_descriptor_request(pdev, callback, s, RequestId, MessageId, udevman, + 0x01, transferDir); break; - case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: /** 0x002A */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR"); - error = urb_os_feature_descriptor_request(callback, data + 8, data_sizem - 8, MessageId, - udevman, UsbDevice, transferDir); + + case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST: /** 0x002A */ + error = urb_os_feature_descriptor_request(pdev, callback, s, RequestId, MessageId, + udevman, transferDir); break; - case URB_FUNCTION_RESERVE_0X002B: /** 0x002B */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002B"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002C: /** 0x002C */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002C"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002D: /** 0x002D */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002D"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002E: /** 0x002E */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002E"); - error = -1; - break; - case URB_FUNCTION_RESERVE_0X002F: /** 0x002F */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_RESERVE_0X002F"); - error = -1; + + case TS_URB_RESERVE_0X002B: /** 0x002B */ + case TS_URB_RESERVE_0X002C: /** 0x002C */ + case TS_URB_RESERVE_0X002D: /** 0x002D */ + case TS_URB_RESERVE_0X002E: /** 0x002E */ + case TS_URB_RESERVE_0X002F: /** 0x002F */ break; + /** USB 2.0 calls start at 0x0030 */ - case URB_FUNCTION_SYNC_RESET_PIPE: /** 0x0030 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_RESET_PIPE"); - error = urb_pipe_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, PIPE_RESET); - error = -9; /** function not support */ + case TS_URB_SYNC_RESET_PIPE: /** 0x0030 */ + error = urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); break; - case URB_FUNCTION_SYNC_CLEAR_STALL: /** 0x0031 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_SYNC_CLEAR_STALL"); - error = urb_pipe_request(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, PIPE_RESET); - error = -9; + + case TS_URB_SYNC_CLEAR_STALL: /** 0x0031 */ + urb_pipe_request(pdev, callback, s, RequestId, MessageId, udevman, transferDir, + PIPE_RESET); break; - case URB_FUNCTION_CONTROL_TRANSFER_EX: /** 0x0032 */ - WLog_DBG(TAG, "URB_Func: URB_FUNCTION_CONTROL_TRANSFER_EX"); - error = urb_control_transfer(callback, data + 8, data_sizem - 8, MessageId, udevman, - UsbDevice, transferDir, URB_CONTROL_TRANSFER_EXTERNAL); + + case TS_URB_CONTROL_TRANSFER_EX: /** 0x0032 */ + error = urb_control_transfer(pdev, callback, s, RequestId, MessageId, udevman, + transferDir, URB_CONTROL_TRANSFER_EXTERNAL); break; + default: - WLog_DBG(TAG, "URB_Func: %" PRIx16 " is not found!", URB_Function); + WLog_Print(urbdrc->log, WLOG_DEBUG, "URB_Func: %" PRIx16 " is not found!", + URB_Function); break; } return error; } -void* urbdrc_process_udev_data_transfer(void* arg) +UINT urbdrc_process_udev_data_transfer(URBDRC_CHANNEL_CALLBACK* callback, URBDRC_PLUGIN* urbdrc, + IUDEVMAN* udevman, wStream* data) { - TRANSFER_DATA* transfer_data = (TRANSFER_DATA*)arg; - URBDRC_CHANNEL_CALLBACK* callback = transfer_data->callback; - BYTE* pBuffer = transfer_data->pBuffer; - UINT32 cbSize = transfer_data->cbSize; - UINT32 UsbDevice = transfer_data->UsbDevice; - IUDEVMAN* udevman = transfer_data->udevman; + UINT32 InterfaceId; UINT32 MessageId; UINT32 FunctionId; IUDEVICE* pdev; - int error = 0; - pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); - if (pdev == NULL || pdev->isSigToEnd(pdev)) + UINT error = ERROR_INTERNAL_ERROR; + size_t len; + + if (!urbdrc || !data || !callback || !udevman) + goto fail; + + len = Stream_GetRemainingLength(data); + + if (Stream_GetRemainingCapacity(data) < 8) + goto fail; + + Stream_Rewind_UINT32(data); + + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, InterfaceId); + + /* Device does not exist, ignore this request. */ + if (pdev == NULL) { - if (transfer_data->pBuffer) - zfree(transfer_data->pBuffer); - zfree(transfer_data); - return 0; + error = ERROR_SUCCESS; + goto fail; } - pdev->push_action(pdev); + /* Device has been removed, ignore this request. */ + if (pdev->isChannelClosed(pdev)) + { + error = ERROR_SUCCESS; + goto fail; + } /* USB kernel driver detach!! */ pdev->detach_kernel_driver(pdev); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); switch (FunctionId) { case CANCEL_REQUEST: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>CANCEL_REQUEST<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_cancel_request(pBuffer + 8, cbSize - 8, udevman, UsbDevice); + error = urbdrc_process_cancel_request(pdev, data, udevman); break; + case REGISTER_REQUEST_CALLBACK: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>REGISTER_REQUEST_CALLBACK<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_register_request_callback(callback, pBuffer + 8, cbSize - 8, - udevman, UsbDevice); + error = urbdrc_process_register_request_callback(pdev, callback, data, udevman); break; + case IO_CONTROL: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>IO_CONTROL<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_io_control(callback, pBuffer + 8, cbSize - 8, MessageId, udevman, - UsbDevice); + error = urbdrc_process_io_control(pdev, callback, data, MessageId, udevman); break; + case INTERNAL_IO_CONTROL: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>INTERNAL_IO_CONTROL<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_internal_io_control(callback, pBuffer + 8, cbSize - 8, MessageId, - udevman, UsbDevice); + error = urbdrc_process_internal_io_control(pdev, callback, data, MessageId, udevman); break; + case QUERY_DEVICE_TEXT: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>QUERY_DEVICE_TEXT<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_query_device_text(callback, pBuffer + 8, cbSize - 8, MessageId, - udevman, UsbDevice); + error = urbdrc_process_query_device_text(pdev, callback, data, MessageId, udevman); break; + case TRANSFER_IN_REQUEST: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>TRANSFER_IN_REQUEST<<0x%" PRIX32 "", - FunctionId); - error = urbdrc_process_transfer_request(callback, pBuffer + 8, cbSize - 8, MessageId, - udevman, UsbDevice, USBD_TRANSFER_DIRECTION_IN); + error = urbdrc_process_transfer_request(pdev, callback, data, MessageId, udevman, + USBD_TRANSFER_DIRECTION_IN); break; + case TRANSFER_OUT_REQUEST: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>TRANSFER_OUT_REQUEST<<0x%" PRIX32 "", - FunctionId); - error = - urbdrc_process_transfer_request(callback, pBuffer + 8, cbSize - 8, MessageId, - udevman, UsbDevice, USBD_TRANSFER_DIRECTION_OUT); + error = urbdrc_process_transfer_request(pdev, callback, data, MessageId, udevman, + USBD_TRANSFER_DIRECTION_OUT); break; + case RETRACT_DEVICE: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " >>RETRACT_DEVICE<<0x%" PRIX32 "", - FunctionId); - error = - urbdrc_process_retract_device_request(pBuffer + 8, cbSize - 8, udevman, UsbDevice); + error = urbdrc_process_retract_device_request(pdev, data, udevman); break; + default: - WLog_DBG(TAG, - "urbdrc_process_udev_data_transfer:" - " unknown FunctionId 0x%" PRIX32 "", - FunctionId); - error = -1; + WLog_Print(urbdrc->log, WLOG_WARN, + "urbdrc_process_udev_data_transfer:" + " unknown FunctionId 0x%" PRIX32 "", + FunctionId); break; } - if (transfer_data) - { - if (transfer_data->pBuffer) - zfree(transfer_data->pBuffer); - zfree(transfer_data); - } - - if (pdev) - { -#if ISOCH_FIFO - /* check isochronous fds */ - func_check_isochronous_fds(pdev); -#endif - /* close this channel, if device is not found. */ - pdev->complete_action(pdev); - } - else - { - udevman->push_urb(udevman); - return 0; - } - - udevman->push_urb(udevman); - return 0; +fail: + return error; } diff --git a/channels/urbdrc/client/data_transfer.h b/channels/urbdrc/client/data_transfer.h index 5e47e2de5..d63f82ec7 100644 --- a/channels/urbdrc/client/data_transfer.h +++ b/channels/urbdrc/client/data_transfer.h @@ -21,6 +21,8 @@ #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H #define FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H +#include + #include "urbdrc_main.h" #define DEVICE_CTX(dev) ((dev)->ctx) @@ -28,6 +30,7 @@ #define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) #define ITRANSFER_CTX(transfer) (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) -void* urbdrc_process_udev_data_transfer(void* arg); +UINT urbdrc_process_udev_data_transfer(URBDRC_CHANNEL_CALLBACK* callback, URBDRC_PLUGIN* urbdrc, + IUDEVMAN* udevman, wStream* data); #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_DATA_TRANSFER_H */ diff --git a/channels/urbdrc/client/isoch_queue.c b/channels/urbdrc/client/isoch_queue.c deleted file mode 100644 index eff5fbeab..000000000 --- a/channels/urbdrc/client/isoch_queue.c +++ /dev/null @@ -1,184 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * RemoteFX USB Redirection - * - * Copyright 2012 Atrust corp. - * Copyright 2012 Alfred Liu - * - * 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 -#include -#include -#include -#include "isoch_queue.h" - -static void isoch_queue_rewind(ISOCH_CALLBACK_QUEUE* queue) -{ - queue->curr = queue->head; -} - -static BOOL isoch_queue_has_next(ISOCH_CALLBACK_QUEUE* queue) -{ - return (queue->curr != NULL); -} - -static ISOCH_CALLBACK_DATA* isoch_queue_get_next(ISOCH_CALLBACK_QUEUE* queue) -{ - ISOCH_CALLBACK_DATA* isoch; - - isoch = queue->curr; - queue->curr = (ISOCH_CALLBACK_DATA*)queue->curr->next; - - return isoch; -} - -static ISOCH_CALLBACK_DATA* isoch_queue_register_data(ISOCH_CALLBACK_QUEUE* queue, void* callback, - void* dev) -{ - ISOCH_CALLBACK_DATA* isoch; - - isoch = (ISOCH_CALLBACK_DATA*)calloc(1, sizeof(ISOCH_CALLBACK_DATA)); - if (!isoch) - return NULL; - - isoch->device = dev; - isoch->callback = callback; - - pthread_mutex_lock(&queue->isoch_loading); - - if (queue->head == NULL) - { - /* linked queue is empty */ - queue->head = isoch; - queue->tail = isoch; - } - else - { - /* append data to the end of the linked queue */ - queue->tail->next = (void*)isoch; - isoch->prev = (void*)queue->tail; - queue->tail = isoch; - } - queue->isoch_num += 1; - - pthread_mutex_unlock(&queue->isoch_loading); - - return isoch; -} - -static int isoch_queue_unregister_data(ISOCH_CALLBACK_QUEUE* queue, ISOCH_CALLBACK_DATA* isoch) -{ - ISOCH_CALLBACK_DATA* p; - - queue->rewind(queue); - - while (queue->has_next(queue)) - { - p = queue->get_next(queue); - - if (p != isoch) - continue; - - /* data exists */ - /* set previous data to point to next data */ - - if (isoch->prev != NULL) - { - /* unregistered data is not the head */ - p = (ISOCH_CALLBACK_DATA*)isoch->prev; - p->next = isoch->next; - } - else - { - /* unregistered data is the head, update head */ - queue->head = (ISOCH_CALLBACK_DATA*)isoch->next; - } - - /* set next data to point to previous data */ - - if (isoch->next != NULL) - { - /* unregistered data is not the tail */ - p = (ISOCH_CALLBACK_DATA*)isoch->next; - p->prev = isoch->prev; - } - else - { - /* unregistered data is the tail, update tail */ - queue->tail = (ISOCH_CALLBACK_DATA*)isoch->prev; - } - queue->isoch_num--; - - if (isoch) - { - /* free data info */ - isoch->out_data = NULL; - - zfree(isoch); - } - - return 1; /* unregistration successful */ - } - - /* if we reach this point, the isoch wasn't found */ - return 0; -} - -void isoch_queue_free(ISOCH_CALLBACK_QUEUE* queue) -{ - ISOCH_CALLBACK_DATA* isoch; - - pthread_mutex_lock(&queue->isoch_loading); - - /** unregister all isochronous data*/ - queue->rewind(queue); - - while (queue->has_next(queue)) - { - isoch = queue->get_next(queue); - - if (isoch != NULL) - queue->unregister_data(queue, isoch); - } - - pthread_mutex_unlock(&queue->isoch_loading); - - pthread_mutex_destroy(&queue->isoch_loading); - - /* free queue */ - if (queue) - zfree(queue); -} - -ISOCH_CALLBACK_QUEUE* isoch_queue_new() -{ - ISOCH_CALLBACK_QUEUE* queue; - - queue = (ISOCH_CALLBACK_QUEUE*)calloc(1, sizeof(ISOCH_CALLBACK_QUEUE)); - if (!queue) - return NULL; - - pthread_mutex_init(&queue->isoch_loading, NULL); - - /* load service */ - queue->get_next = isoch_queue_get_next; - queue->has_next = isoch_queue_has_next; - queue->rewind = isoch_queue_rewind; - queue->register_data = isoch_queue_register_data; - queue->unregister_data = isoch_queue_unregister_data; - queue->free = isoch_queue_free; - - return queue; -} diff --git a/channels/urbdrc/client/isoch_queue.h b/channels/urbdrc/client/isoch_queue.h deleted file mode 100644 index a58078816..000000000 --- a/channels/urbdrc/client/isoch_queue.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * RemoteFX USB Redirection - * - * Copyright 2012 Atrust corp. - * Copyright 2012 Alfred Liu - * - * 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. - */ - -#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H -#define FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H - -#include "urbdrc_types.h" - -typedef struct _ISOCH_CALLBACK_DATA ISOCH_CALLBACK_DATA; -typedef struct _ISOCH_CALLBACK_QUEUE ISOCH_CALLBACK_QUEUE; - -struct _ISOCH_CALLBACK_DATA -{ - void* inode; - void* prev; - void* next; - void* device; - BYTE* out_data; - UINT32 out_size; - void* callback; -}; - -struct _ISOCH_CALLBACK_QUEUE -{ - int isoch_num; - ISOCH_CALLBACK_DATA* curr; /* current point */ - ISOCH_CALLBACK_DATA* head; /* head point in linked list */ - ISOCH_CALLBACK_DATA* tail; /* tail point in linked list */ - - pthread_mutex_t isoch_loading; - - /* Isochronous queue service */ - void (*rewind)(ISOCH_CALLBACK_QUEUE* queue); - BOOL (*has_next)(ISOCH_CALLBACK_QUEUE* queue); - int (*unregister_data)(ISOCH_CALLBACK_QUEUE* queue, ISOCH_CALLBACK_DATA* isoch); - ISOCH_CALLBACK_DATA* (*get_next)(ISOCH_CALLBACK_QUEUE* queue); - ISOCH_CALLBACK_DATA* (*register_data)(ISOCH_CALLBACK_QUEUE* queue, void* callback, void* dev); - void (*free)(ISOCH_CALLBACK_QUEUE* queue); -}; - -ISOCH_CALLBACK_QUEUE* isoch_queue_new(void); - -#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_ISOCH_QUEUE_H */ diff --git a/channels/urbdrc/client/libusb/CMakeLists.txt b/channels/urbdrc/client/libusb/CMakeLists.txt index abb435637..c5e9b7087 100644 --- a/channels/urbdrc/client/libusb/CMakeLists.txt +++ b/channels/urbdrc/client/libusb/CMakeLists.txt @@ -21,9 +21,7 @@ define_channel_client_subsystem("urbdrc" "libusb" "") set(${MODULE_PREFIX}_SRCS libusb_udevman.c libusb_udevice.c - libusb_udevice.h - request_queue.c - request_queue.h) + libusb_udevice.h) include_directories(..) @@ -38,7 +36,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} ${LIBUSB_1_LIBRARIES}) -set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) +set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr urbdrc-client) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 084108a92..69352e6cf 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -21,16 +21,16 @@ #include #include #include -#include -#if defined(__linux__) -#include -#endif + +#include #include -#include #include "libusb_udevice.h" +#define SEM_MAX_COUNT 2 + +#define HAVE_NEW_LIBUSB #define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ static _type udev_get_##_arg(IUDEVICE* idev) \ { \ @@ -59,172 +59,129 @@ _dev->iface.get_##_arg = udev_get_##_arg; \ _dev->iface.set_##_arg = udev_set_##_arg -typedef struct _ISO_USER_DATA ISO_USER_DATA; +typedef struct _ASYNC_TRANSFER_USER_DATA ASYNC_TRANSFER_USER_DATA; -struct _ISO_USER_DATA +struct _ASYNC_TRANSFER_USER_DATA { - BYTE* IsoPacket; - BYTE* output_data; - int iso_status; - int completed; - UINT32 error_count; - int noack; - UINT32 start_frame; + wStream* data; + BOOL noack; + UINT32 MessageId; + UINT32 StartFrame; + UINT32 ErrorCount; + IUDEVICE* idev; + UINT32 OutputBufferSize; + URBDRC_CHANNEL_CALLBACK* callback; + t_isoch_transfer_cb cb; + wHashTable* queue; }; -static int get_next_timeout(libusb_context* ctx, struct timeval* tv, struct timeval* out) +static ASYNC_TRANSFER_USER_DATA* async_transfer_user_data_new(IUDEVICE* idev, UINT32 MessageId, + size_t offset, size_t BufferSize, + size_t packetSize, BOOL NoAck, + t_isoch_transfer_cb cb, + URBDRC_CHANNEL_CALLBACK* callback) { - int r; - struct timeval timeout; - r = libusb_get_next_timeout(ctx, &timeout); + ASYNC_TRANSFER_USER_DATA* user_data = calloc(1, sizeof(ASYNC_TRANSFER_USER_DATA)); + UDEVICE* pdev = (UDEVICE*)idev; - if (r) + if (!user_data) + return NULL; + + user_data->data = Stream_New(NULL, offset + BufferSize + packetSize); + + if (!user_data->data) { - /* 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; + free(user_data); + return NULL; } + Stream_Seek(user_data->data, offset); /* Skip header offset */ - return 0; + user_data->noack = NoAck; + user_data->cb = cb; + user_data->callback = callback; + user_data->idev = idev; + user_data->MessageId = MessageId; + user_data->OutputBufferSize = BufferSize; + user_data->queue = pdev->request_queue; + + return user_data; } -/* - * 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) +static void async_transfer_user_data_free(ASYNC_TRANSFER_USER_DATA* user_data) { - 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 (user_data) { - 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; + Stream_Free(user_data->data, TRUE); + free(user_data); } - - /* 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; + ASYNC_TRANSFER_USER_DATA* user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; + const UINT32 streamID = libusb_transfer_get_stream_id(transfer); - /* 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)) + switch (transfer->status) { - for (i = 0; i < transfer->num_iso_packets; i++) + + case LIBUSB_TRANSFER_COMPLETED: { - 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; + int i; + UINT32 index = 0; + BYTE* dataStart = Stream_Pointer(user_data->data); + Stream_SetPosition(user_data->data, + 40); /* TS_URB_ISOCH_TRANSFER_RESULT IsoPacket offset */ - if (transfer->iso_packet_desc[i].status == USBD_STATUS_SUCCESS) + for (i = 0; i < transfer->num_iso_packets; i++) { - b = libusb_get_iso_packet_buffer_simple(transfer, i); + const UINT32 act_len = transfer->iso_packet_desc[i].actual_length; + Stream_Write_UINT32(user_data->data, index); + Stream_Write_UINT32(user_data->data, act_len); + Stream_Write_UINT32(user_data->data, transfer->iso_packet_desc[i].status); - if (act_len > 0) + if (transfer->iso_packet_desc[i].status != USBD_STATUS_SUCCESS) + user_data->ErrorCount++; + else { - if (iso_user_data->output_data + index != b) - memcpy(iso_user_data->output_data + index, b, act_len); + const unsigned char* packetBuffer = + libusb_get_iso_packet_buffer_simple(transfer, i); + BYTE* data = dataStart + index; + + if (data != packetBuffer) + memmove(data, packetBuffer, 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); } } + /* fallthrough */ - 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; + case LIBUSB_TRANSFER_CANCELLED: + case LIBUSB_TRANSFER_TIMED_OUT: + case LIBUSB_TRANSFER_ERROR: + { + const UINT32 InterfaceId = + ((STREAM_ID_PROXY << 30) | user_data->idev->get_ReqCompletion(user_data->idev)); + + if (HashTable_Contains(user_data->queue, (void*)(size_t)streamID)) + { + if (!user_data->noack) + { + const UINT32 RequestID = streamID & INTERFACE_ID_MASK; + user_data->cb(user_data->idev, user_data->callback, user_data->data, + InterfaceId, user_data->noack, user_data->MessageId, RequestID, + transfer->num_iso_packets, transfer->status, + user_data->StartFrame, user_data->ErrorCount, + user_data->OutputBufferSize); + user_data->data = NULL; + } + HashTable_Remove(user_data->queue, (void*)(size_t)streamID); + } + } + break; + default: + break; } } @@ -259,13 +216,39 @@ static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPT static void func_bulk_transfer_cb(struct libusb_transfer* transfer) { - int* completed = transfer->user_data; - *completed = 1; - /* caller interprets results and frees transfer */ + ASYNC_TRANSFER_USER_DATA* user_data; + uint32_t streamID; + + user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; + if (!user_data) + { + WLog_ERR(TAG, "[%s]: Invalid transfer->user_data!"); + return; + } + + streamID = libusb_transfer_get_stream_id(transfer); + + if (HashTable_Contains(user_data->queue, (void*)(size_t)streamID)) + { + const UINT32 InterfaceId = + ((STREAM_ID_PROXY << 30) | user_data->idev->get_ReqCompletion(user_data->idev)); + const UINT32 RequestID = streamID & INTERFACE_ID_MASK; + + user_data->cb(user_data->idev, user_data->callback, user_data->data, InterfaceId, + user_data->noack, user_data->MessageId, RequestID, transfer->num_iso_packets, + transfer->status, user_data->StartFrame, user_data->ErrorCount, + user_data->OutputBufferSize); + user_data->data = NULL; + HashTable_Remove(user_data->queue, (void*)(size_t)streamID); + } } -static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) +static BOOL func_set_usbd_status(URBDRC_PLUGIN* urbdrc, UDEVICE* pdev, UINT32* status, + int err_result) { + if (!urbdrc || !status) + return FALSE; + switch (err_result) { case LIBUSB_SUCCESS: @@ -274,7 +257,6 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) case LIBUSB_ERROR_IO: *status = USBD_STATUS_STALL_PID; - WLog_ERR(TAG, "LIBUSB_ERROR_IO!!"); break; case LIBUSB_ERROR_INVALID_PARAM: @@ -291,10 +273,7 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) if (pdev) { if (!(pdev->status & URBDRC_DEVICE_NOT_FOUND)) - { pdev->status |= URBDRC_DEVICE_NOT_FOUND; - WLog_WARN(TAG, "LIBUSB_ERROR_NO_DEVICE!!"); - } } break; @@ -340,34 +319,22 @@ static int func_set_usbd_status(UDEVICE* pdev, UINT32* status, int err_result) break; } - return 0; + return TRUE; } -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, +static int func_config_release_all_interface(URBDRC_PLUGIN* urbdrc, + LIBUSB_DEVICE_HANDLE* libusb_handle, UINT32 NumInterfaces) { UINT32 i; - int ret; for (i = 0; i < NumInterfaces; i++) { - ret = libusb_release_interface(libusb_handle, i); + int ret = libusb_release_interface(libusb_handle, i); if (ret < 0) { - WLog_ERR(TAG, "config_release_all_interface: error num %d", ret); + WLog_Print(urbdrc->log, WLOG_ERROR, "config_release_all_interface: error num %d", ret); return -1; } } @@ -375,7 +342,8 @@ static int func_config_release_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle return 0; } -static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int NumInterfaces) +static int func_claim_all_interface(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE_HANDLE* libusb_handle, + int NumInterfaces) { int i, ret; @@ -385,7 +353,7 @@ static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int Num if (ret < 0) { - WLog_ERR(TAG, "claim_all_interface: error num %d", ret); + WLog_Print(urbdrc->log, WLOG_ERROR, "claim_all_interface: error num %d", ret); return -1; } } @@ -393,71 +361,6 @@ static int func_claim_all_interface(LIBUSB_DEVICE_HANDLE* libusb_handle, int Num 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; @@ -475,7 +378,7 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(int bus_number, int dev_number) return NULL; } -static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) +static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE* libusb_dev) { int ret; LIBUSB_DEVICE_DESCRIPTOR* descriptor; @@ -484,7 +387,8 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) if (ret < 0) { - WLog_ERR(TAG, "libusb_get_device_descriptor: ERROR!!"); + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_get_device_descriptor: error %s [%d]", + libusb_error_name(ret), ret); free(descriptor); return NULL; } @@ -492,231 +396,19 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(LIBUSB_DEVICE* libusb_dev) 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, 10); - - if (errno != 0) - continue; - - tmp_d = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 10); - - 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 ((size_t)((p2 - sysfs_path) + 2U) < strlen(sysfs_path)) - { - 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, 10); - hub_dev = strtoul(udev_device_get_property_value(dev, "DEVNUM"), NULL, 10); - 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; + URBDRC_PLUGIN* urbdrc; MSUSB_CONFIG_DESCRIPTOR* MsConfig; MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + + if (!pdev || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; MsConfig = pdev->MsConfig; if (MsConfig) @@ -736,7 +428,7 @@ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BY if (error < 0) { - WLog_ERR(TAG, "Set interface altsetting get error num %d", error); + WLog_Print(urbdrc->log, WLOG_ERROR, "Set interface altsetting get error num %d", error); } } @@ -758,15 +450,21 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting; const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint; BYTE LibusbNumEndpoint; + URBDRC_PLUGIN* urbdrc; UINT32 inum = 0, pnum = 0, MsOutSize = 0; + + if (!pdev || !pdev->LibusbConfig || !pdev->urbdrc || !MsConfig) + return NULL; + + urbdrc = pdev->urbdrc; 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); + WLog_Print(urbdrc->log, WLOG_ERROR, + "Select Configuration: Libusb NumberInterfaces(%" PRIu8 ") is different " + "with MsConfig NumberInterfaces(%" PRIu32 ")", + LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); } /* replace MsPipes for libusb */ @@ -883,7 +581,7 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC MsConfig->InitCompleted = 1; /* replace device's MsConfig */ - if (!(MsConfig == pdev->MsConfig)) + if (MsConfig != pdev->MsConfig) { msusb_msconfig_free(pdev->MsConfig); pdev->MsConfig = MsConfig; @@ -895,15 +593,26 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC 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; + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + LIBUSB_DEVICE_HANDLE* libusb_handle; + LIBUSB_DEVICE* libusb_dev; + URBDRC_PLUGIN* urbdrc; + LIBUSB_CONFIG_DESCRIPTOR** LibusbConfig; int ret = 0; + if (!pdev || !pdev->MsConfig || !pdev->LibusbConfig || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + MsConfig = pdev->MsConfig; + libusb_handle = pdev->libusb_handle; + libusb_dev = pdev->libusb_dev; + LibusbConfig = &pdev->LibusbConfig; + if (MsConfig->InitCompleted) { - func_config_release_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_config_release_all_interface(pdev->urbdrc, libusb_handle, + (*LibusbConfig)->bNumInterfaces); } /* The configuration value -1 is mean to put the device in unconfigured state. */ @@ -914,8 +623,9 @@ static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfiguratio if (ret < 0) { - WLog_ERR(TAG, "libusb_set_configuration: ERROR number %d!!", ret); - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_set_configuration: error %s [%d]", + libusb_error_name(ret), ret); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } else @@ -924,13 +634,14 @@ static int libusb_udev_select_configuration(IUDEVICE* idev, UINT32 bConfiguratio if (ret < 0) { - WLog_ERR(TAG, "libusb_get_config_descriptor_by_value: ERROR number %d!!", ret); - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_set_configuration: error %s [%d]", + libusb_error_name(ret), ret); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return -1; } } - func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + func_claim_all_interface(urbdrc, libusb_handle, (*LibusbConfig)->bNumInterfaces); return 0; } @@ -967,82 +678,104 @@ static int libusb_udev_control_pipe_request(IUDEVICE* idev, UINT32 RequestId, } *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) +static UINT32 libusb_udev_control_query_device_text(IUDEVICE* idev, UINT32 TextType, + UINT16 LocaleId, UINT8* BufferSize, + BYTE* Buffer) { UDEVICE* pdev = (UDEVICE*)idev; - LIBUSB_DEVICE_DESCRIPTOR* devDescriptor = pdev->devDescriptor; - char* strDesc = "Generic Usb String"; - char deviceLocation[25]; + LIBUSB_DEVICE_DESCRIPTOR* devDescriptor; + const char* strDesc = "Generic Usb String"; + char deviceLocation[25] = { 0 }; BYTE bus_number; BYTE device_address; int ret = 0; - size_t i = 0; + size_t i, len; + URBDRC_PLUGIN* urbdrc; + WCHAR* text = (WCHAR*)Buffer; + BYTE slen, locale; + const UINT8 inSize = *BufferSize; + + *BufferSize = 0; + if (!pdev || !pdev->devDescriptor || !pdev->urbdrc) + return ERROR_INVALID_DATA; + + urbdrc = pdev->urbdrc; + devDescriptor = pdev->devDescriptor; switch (TextType) { case DeviceTextDescription: + { + BYTE data[0x100] = { 0 }; ret = libusb_get_string_descriptor(pdev->libusb_handle, devDescriptor->iProduct, - LocaleId, Buffer, *BufferSize); + LocaleId, data, 0xFF); + /* The returned data in the buffer is: + * 1 byte length of following data + * 1 byte descriptor type, must be 0x03 for strings + * n WCHAR unicode string (of length / 2 characters) including '\0' + */ + slen = data[0]; + locale = data[1]; - for (i = 0; (ret > 0) && (i < (size_t)ret); i++) + if ((ret <= 0) || (ret < 4) || (slen < 4) || (locale != LIBUSB_DT_STRING) || + (ret > UINT8_MAX)) { - Buffer[i] = Buffer[i + 2]; - } + WLog_Print(urbdrc->log, WLOG_DEBUG, + "libusb_get_string_descriptor: " + "ERROR num %d, iProduct: %" PRIu8 "!", + ret, devDescriptor->iProduct); - ret -= 2; + len = MIN(sizeof(strDesc), inSize); + for (i = 0; i < len; i++) + text[i] = (WCHAR)strDesc[i]; - 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; - } + *BufferSize = (BYTE)(len * 2); } else { - *BufferSize = ret; - } + /* ret and slen should be equals, but you never know creativity + * of device manufacturers... + * So also check the string length returned as server side does + * not honor strings with multi '\0' characters well. + */ + const size_t rchar = _wcsnlen((WCHAR*)&data[2], sizeof(data) / 2); + len = MIN((BYTE)ret, slen); + len = MIN(len, inSize); + len = MIN(len, rchar * 2 + sizeof(WCHAR)); + memcpy(Buffer, &data[2], len); - break; + /* Just as above, the returned WCHAR string should be '\0' + * terminated, but never trust hardware to conform to specs... */ + Buffer[len - 2] = '\0'; + Buffer[len - 1] = '\0'; + *BufferSize = (BYTE)len; + } + } + 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), + sprintf_s(deviceLocation, sizeof(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); + len = strnlen(deviceLocation, MIN(sizeof(deviceLocation), inSize - 1)); + for (i = 0; i < len; i++) + text[i] = (WCHAR)deviceLocation[i]; + text[len++] = '\0'; + *BufferSize = (UINT8)(len * sizeof(WCHAR)); break; default: - WLog_DBG(TAG, "Query Text: unknown TextType %" PRIu32 "", TextType); - break; + WLog_Print(urbdrc->log, WLOG_DEBUG, "Query Text: unknown TextType %" PRIu32 "", + TextType); + return ERROR_INVALID_DATA; } - return 0; + return S_OK; } static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 RequestId, @@ -1062,12 +795,11 @@ static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 Requ LIBUSB_REQUEST_GET_DESCRIPTOR, 0x03ee, 0, ms_string_desc, 0x12, Timeout); - // WLog_ERR(TAG, "Get ms string: result number %d", error); + // WLog_Print(urbdrc->log, WLOG_ERROR, "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); + const BYTE bMS_Vendorcode = ms_string_desc[16]; + // WLog_Print(urbdrc->log, WLOG_ERROR, "bMS_Vendorcode:0x%x", bMS_Vendorcode); /** get os descriptor */ error = libusb_control_transfer(pdev->libusb_handle, LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | Recipient, @@ -1081,11 +813,7 @@ static int libusb_udev_os_feature_descriptor_request(IUDEVICE* idev, UINT32 Requ 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; + return ERROR_SUCCESS; } static int libusb_udev_query_device_descriptor(IUDEVICE* idev, int offset) @@ -1143,49 +871,64 @@ static int libusb_udev_query_device_descriptor(IUDEVICE* idev, int offset) return 0; } -static void libusb_udev_detach_kernel_driver(IUDEVICE* idev) +static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) { int i, err = 0; UDEVICE* pdev = (UDEVICE*)idev; + URBDRC_PLUGIN* urbdrc; + + if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) + return FALSE; + + urbdrc = pdev->urbdrc; 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); + WLog_Print(urbdrc->log, WLOG_DEBUG, "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); + WLog_Print(urbdrc->log, WLOG_DEBUG, "libusb_detach_kernel_driver = %d", err); } } pdev->status |= URBDRC_DEVICE_DETACH_KERNEL; } + + return TRUE; } -static void libusb_udev_attach_kernel_driver(IUDEVICE* idev) +static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) { int i, err = 0; UDEVICE* pdev = (UDEVICE*)idev; + if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) + return FALSE; + 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); + WLog_Print(pdev->urbdrc->log, WLOG_DEBUG, "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); + WLog_Print(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if%d = %d", i, + err); } } + + return TRUE; } static int libusb_udev_is_composite_device(IUDEVICE* idev) @@ -1194,12 +937,6 @@ static int libusb_udev_is_composite_device(IUDEVICE* 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; @@ -1209,7 +946,16 @@ static int libusb_udev_is_exist(IUDEVICE* idev) static int libusb_udev_is_channel_closed(IUDEVICE* idev) { UDEVICE* pdev = (UDEVICE*)idev; - return (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) ? 1 : 0; + if (!pdev || !pdev->urbdrc) + return 1; + + if (pdev->urbdrc->status & URBDRC_DEVICE_CHANNEL_CLOSED) + return 1; + + if (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) + return 1; + + return 0; } static int libusb_udev_is_already_send(IUDEVICE* idev) @@ -1218,16 +964,27 @@ static int libusb_udev_is_already_send(IUDEVICE* 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; + const UINT16 idVendor = (UINT16)idev->query_device_descriptor(idev, ID_VENDOR); + const UINT16 idProduct = (UINT16)idev->query_device_descriptor(idev, ID_PRODUCT); + const uint8_t busNr = idev->get_bus_number(idev); + const uint8_t devNr = idev->get_dev_number(idev); + IWTSVirtualChannel* channel = + pdev->channelManager->FindChannelById(pdev->channelManager, pdev->channelID); pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; + + if (channel) + { + URBDRC_PLUGIN* urbdrc = pdev->urbdrc; + USB_SEARCHMAN* searchman = urbdrc->searchman; + + /* Notify the server the device is no longer available. */ + channel->Write(channel, 0, NULL, NULL); + urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr); + searchman->add(searchman, idVendor, idProduct); + } } static void libusb_udev_set_already_send(IUDEVICE* idev) @@ -1242,66 +999,9 @@ static char* libusb_udev_get_path(IUDEVICE* idev) return pdev->path; } -static int libusb_udev_wait_action_completion(IUDEVICE* idev) +static BOOL libusb_udev_wait_for_detach(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); + return TRUE; } static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStatus, @@ -1309,7 +1009,13 @@ static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStat { UDEVICE* pdev = (UDEVICE*)idev; int success = 0, ret; - WLog_DBG(TAG, "..."); + URBDRC_PLUGIN* urbdrc; + + if (!pdev || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + WLog_Print(urbdrc->log, WLOG_DEBUG, "..."); if (pdev->hub_handle != NULL) { @@ -1320,13 +1026,14 @@ static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStat if (ret < 0) { - WLog_DBG(TAG, "libusb_control_transfer: error num %d", ret); + WLog_Print(urbdrc->log, WLOG_DEBUG, "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]); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "PORT STATUS:0x%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "", Buffer[3], + Buffer[2], Buffer[1], Buffer[0]); success = 1; } } @@ -1334,441 +1041,328 @@ static int libusb_udev_query_device_port_status(IUDEVICE* idev, UINT32* UsbdStat 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) +static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress, + UINT32 TransferFlags, UINT32 StartFrame, UINT32 ErrorCount, + BOOL NoAck, const BYTE* packetDescriptorData, + UINT32 NumberOfPackets, UINT32 BufferSize, const BYTE* Buffer, + t_isoch_transfer_cb cb, UINT32 Timeout) { UINT32 iso_packet_size; UDEVICE* pdev = (UDEVICE*)idev; - ISO_USER_DATA iso_user_data; + ASYNC_TRANSFER_USER_DATA* user_data; struct libusb_transfer* iso_transfer = NULL; - int status = 0, ret = 0, submit = 0; - iso_packet_size = *BufferSize / NumberOfPackets; + URBDRC_PLUGIN* urbdrc; + size_t outSize = (NumberOfPackets * 12); + uint32_t streamID = 0x40000000 | RequestId; + + if (!pdev || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + user_data = async_transfer_user_data_new(idev, MessageId, 48, BufferSize, outSize + 1024, NoAck, + cb, callback); + + if (!user_data) + return -1; + + user_data->ErrorCount = ErrorCount; + user_data->StartFrame = StartFrame; + + if (Buffer) /* We read data, prepare a bufffer */ + { + user_data->OutputBufferSize = 0; + memmove(Stream_Pointer(user_data->data), Buffer, BufferSize); + } + else + Stream_Seek(user_data->data, (NumberOfPackets * 12)); + + iso_packet_size = BufferSize / NumberOfPackets; iso_transfer = libusb_alloc_transfer(NumberOfPackets); if (iso_transfer == NULL) { - WLog_ERR(TAG, "Error: libusb_alloc_transfer."); + WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer."); + async_transfer_user_data_free(user_data); return -1; } + iso_transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; /** 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_fill_iso_transfer(iso_transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, NumberOfPackets, + func_iso_callback, user_data, Timeout); + libusb_transfer_set_stream_id(iso_transfer, streamID); 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; + HashTable_Add(pdev->request_queue, (void*)(size_t)streamID, iso_transfer); + return libusb_submit_transfer(iso_transfer); } -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) +static BOOL 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; + + if (!pdev || !pdev->urbdrc) + return FALSE; + status = libusb_control_transfer(pdev->libusb_handle, bmRequestType, Request, Value, Index, Buffer, *BufferSize, Timeout); - if (!(status < 0)) - *BufferSize = status; + if (status >= 0) + *BufferSize = (UINT32)status; + else + WLog_Print(pdev->urbdrc->log, WLOG_ERROR, "libusb_control_transfer %s [%d]", + libusb_error_name(status), status); - func_set_usbd_status(pdev, UrbdStatus, status); - return status; + if (!func_set_usbd_status(pdev->urbdrc, pdev, UrbdStatus, status)) + return FALSE; + + return TRUE; } -static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, UINT32 RequestId, +static int libusb_udev_bulk_or_interrupt_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags, - UINT32* UsbdStatus, UINT32* BufferSize, - BYTE* Buffer, UINT32 Timeout) + BOOL NoAck, UINT32 BufferSize, + t_isoch_transfer_cb cb, 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; + URBDRC_PLUGIN* urbdrc; + ASYNC_TRANSFER_USER_DATA* user_data; + uint32_t streamID = 0x80000000 | RequestId; + + if (!pdev || !pdev->LibusbConfig || !pdev->urbdrc) + return -1; + + urbdrc = pdev->urbdrc; + user_data = + async_transfer_user_data_new(idev, MessageId, 36, BufferSize, 0, NoAck, cb, callback); + + if (!user_data) + return -1; + /* alloc memory for urb transfer */ transfer = libusb_alloc_transfer(0); + if (!transfer) + { + async_transfer_user_data_free(user_data); + return -1; + } + transfer->flags = LIBUSB_TRANSFER_FREE_TRANSFER; + 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); + WLog_Print(urbdrc->log, WLOG_ERROR, "func_get_ep_desc: endpoint 0x%" PRIx32 " not found", + EndpointAddress); + libusb_free_transfer(transfer); + async_transfer_user_data_free(user_data); 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); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "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; + libusb_fill_bulk_transfer(transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, + func_bulk_transfer_cb, user_data, Timeout); 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; + libusb_fill_interrupt_transfer(transfer, pdev->libusb_handle, EndpointAddress, + Stream_Pointer(user_data->data), BufferSize, + func_bulk_transfer_cb, user_data, Timeout); break; default: - WLog_DBG(TAG, - "urb_bulk_or_interrupt_transfer:" - " other transfer type 0x%" PRIX32 "", - transfer_type); + WLog_Print(urbdrc->log, WLOG_DEBUG, + "urb_bulk_or_interrupt_transfer:" + " other transfer type 0x%" PRIX32 "", + transfer_type); + async_transfer_user_data_free(user_data); + libusb_free_transfer(transfer); 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; + libusb_transfer_set_stream_id(transfer, streamID); + HashTable_Add(pdev->request_queue, (void*)(size_t)streamID, transfer); + return libusb_submit_transfer(transfer); } -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) +static int func_cancel_xact_request(URBDRC_PLUGIN* urbdrc, wHashTable* queue, uint32_t streamID, + struct libusb_transfer* transfer) { int status; - if (!request) + if (!urbdrc || !queue || !transfer) 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); + status = libusb_cancel_transfer(transfer); + HashTable_Remove(queue, (void*)(size_t)streamID); if (status < 0) { - WLog_DBG(TAG, "libusb_cancel_transfer: error num %d!!", status); + WLog_Print(urbdrc->log, WLOG_WARN, "libusb_cancel_transfer: error num %s [%d]", + libusb_error_name(status), 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 void libusb_udev_cancel_all_transfer_request(IUDEVICE* idev) +{ + UDEVICE* pdev = (UDEVICE*)idev; + ULONG_PTR* keys; + int count, x; + + if (!pdev || !pdev->request_queue || !pdev->urbdrc) + return; + + count = HashTable_GetKeys(pdev->request_queue, &keys); + + for (x = 0; x < count; x++) + { + struct libusb_transfer* transfer = + HashTable_GetItemValue(pdev->request_queue, (void*)keys[x]); + func_cancel_xact_request(pdev->urbdrc, pdev->request_queue, (uint32_t)keys[x], transfer); + } + + free(keys); +} 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); + struct libusb_transfer* transfer; + URBDRC_PLUGIN* urbdrc; + BOOL id1; + uint32_t cancelID; + uint32_t cancelID1 = 0x40000000 | RequestId; + uint32_t cancelID2 = 0x80000000 | RequestId; - 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!!"); + if (!idev || !pdev->urbdrc || !pdev->request_queue) return -1; - } - WLog_DBG(TAG, "urbdrc_process_cancel_request: success!!"); - return 0; + id1 = HashTable_Contains(pdev->request_queue, (void*)(size_t)cancelID1); + + if (!id1) + return -1; + + urbdrc = (URBDRC_PLUGIN*)pdev->urbdrc; + cancelID = (id1) ? cancelID1 : cancelID2; + transfer = HashTable_GetItemValue(pdev->request_queue, (void*)(size_t)cancelID); + return func_cancel_xact_request(urbdrc, pdev->request_queue, cancelID, transfer); } -BASIC_STATE_FUNC_DEFINED(channel_id, UINT32) -BASIC_STATE_FUNC_DEFINED(UsbDevice, UINT32) +BASIC_STATE_FUNC_DEFINED(channelManager, IWTSVirtualChannelManager*) +BASIC_STATE_FUNC_DEFINED(channelID, 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(bus_number, BYTE) +BASIC_STATE_FUNC_DEFINED(dev_number, BYTE) 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 UINT32 udev_get_UsbDevice(IUDEVICE* idev) +{ + UDEVICE* pdev = (UDEVICE*)idev; + + if (!pdev) + return 0; + + return pdev->UsbDevice; +} + +static void udev_set_UsbDevice(IUDEVICE* idev, UINT32 val) +{ + UDEVICE* pdev = (UDEVICE*)idev; + + if (!pdev) + return; + + val = 0x10 + val; + + if (val < 0x10) + val += 0x10; + + pdev->UsbDevice = val; +} + +static void udev_free(IUDEVICE* idev) +{ + int rc; + UDEVICE* udev = (UDEVICE*)idev; + URBDRC_PLUGIN* urbdrc; + + if (!idev || !udev->urbdrc) + return; + + urbdrc = udev->urbdrc; + + if (udev->libusb_handle) + { + rc = libusb_reset_device(udev->libusb_handle); + + if (rc != LIBUSB_SUCCESS) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_reset_device: error %s [%d[", + libusb_error_name(rc), rc); + } + } + + /* release all interface and attach kernel driver */ + udev->iface.attach_kernel_driver(idev); + HashTable_Free(udev->request_queue); + /* free the config descriptor that send from windows */ + msusb_msconfig_free(udev->MsConfig); + libusb_close(udev->libusb_handle); + libusb_close(udev->hub_handle); + free(udev->devDescriptor); + free(idev); +} + static void udev_load_interface(UDEVICE* pdev) { /* load interface */ /* Basic */ - BASIC_STATE_FUNC_REGISTER(channel_id, pdev); + BASIC_STATE_FUNC_REGISTER(channelManager, pdev); + BASIC_STATE_FUNC_REGISTER(channelID, 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; @@ -1787,83 +1381,166 @@ static void udev_load_interface(UDEVICE* pdev) 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; + pdev->iface.free = udev_free; } -static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) +static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, UDEVICE* pdev, UINT16 bus_number, + UINT16 dev_number) { - int status, num; + int error; + ssize_t i, total_device; + 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++) + { + LIBUSB_DEVICE_HANDLE* handle; + + 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], &handle); + + if (error < 0) + { + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_open error: %i - %s", error, + libusb_error_name(error)); + break; + } + + /* get port number */ + error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); + libusb_close(handle); + + if (error < 1) + { + /* Prevent open hub, treat as error. */ + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_get_port_numbers error: %i - %s", error, + libusb_error_name(error)); + break; + } + + pdev->port_number = port_numbers[(error - 1)]; + error = 0; + WLog_Print(urbdrc->log, WLOG_DEBUG, " Port: %d", pdev->port_number); + /* gen device path */ + sprintf(pdev->path, "ugen%" PRIu16 ".%" PRIu16 "", bus_number, dev_number); + WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path); + break; + } + + /* Look for device hub. */ + if (error == 0) + { + error = -1; + + for (i = 0; i < total_device; i++) + { + LIBUSB_DEVICE_HANDLE* handle; + + 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_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); + error = libusb_open(libusb_list[i], &handle); + + if (error < 0) + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_open error: %i - %s", error, + libusb_error_name(error)); + else + pdev->hub_handle = handle; + + break; + } + } + + libusb_free_device_list(libusb_list, 1); + + if (error < 0) + return -1; + + return 0; +} + +static void request_free(void* value) +{ + ASYNC_TRANSFER_USER_DATA* user_data; + struct libusb_transfer* transfer = (struct libusb_transfer*)value; + if (!transfer) + return; + + user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; + async_transfer_user_data_free(user_data); +} + +static IUDEVICE* udev_init(URBDRC_PLUGIN* urbdrc, LIBUSB_DEVICE* device, BYTE bus_number, + BYTE dev_number) +{ + UDEVICE* pdev; + int status; 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); + pdev = (PUDEVICE)calloc(1, sizeof(UDEVICE)); + + if (!pdev) + return NULL; + + pdev->urbdrc = urbdrc; + udev_load_interface(pdev); + + if (device) + pdev->libusb_dev = device; + else + pdev->libusb_dev = udev_get_libusb_dev(bus_number, dev_number); + + if (pdev->libusb_dev == NULL) + goto fail; + + status = libusb_open(pdev->libusb_dev, &pdev->libusb_handle); if (status < 0) { - WLog_ERR(TAG, "USB init: Error to get HUB handle!!"); - pdev->hub_handle = NULL; + WLog_Print(urbdrc->log, WLOG_ERROR, "libusb_open error: %i - %s", status, + libusb_error_name(status)); + goto fail; } - pdev->devDescriptor = udev_new_descript(pdev->libusb_dev); + /* Get HUB handle */ + status = udev_get_hub_handle(urbdrc, pdev, bus_number, dev_number); + + if (status < 0) + pdev->hub_handle = NULL; + + pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev); if (!pdev->devDescriptor) - { - WLog_ERR(TAG, "USB init: Error to get device descriptor!!"); - zfree(pdev); - return NULL; - } + goto fail; - num = pdev->devDescriptor->bNumConfigurations; status = libusb_get_active_config_descriptor(pdev->libusb_dev, &pdev->LibusbConfig); + if (status == LIBUSB_ERROR_NOT_FOUND) + status = libusb_get_config_descriptor(pdev->libusb_dev, 0, &pdev->LibusbConfig); + if (status < 0) - { - WLog_ERR(TAG, "libusb_get_descriptor: ERROR!!ret:%d", status); - zfree(pdev); - return NULL; - } + goto fail; 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; - } - + WLog_Print(urbdrc->log, WLOG_DEBUG, + "Registered Device: Vid: 0x%04" PRIX16 " Pid: 0x%04" PRIX16 "" + " InterfaceClass = 0x%02" PRIX8 "", + pdev->devDescriptor->idVendor, pdev->devDescriptor->idProduct, + interface_temp.bInterfaceClass); /* Check composite device */ devDescriptor = pdev->devDescriptor; @@ -1878,75 +1555,72 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number) 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); + pdev->request_queue = HashTable_New(TRUE); + + if (!pdev->request_queue) + goto fail; + + pdev->request_queue->valueFree = request_free; + /* set config of windows */ pdev->MsConfig = msusb_msconfig_new(); - pthread_mutex_init(&pdev->mutex_isoch, NULL); + + if (!pdev->MsConfig) + goto fail; + // deb_config_msg(pdev->libusb_dev, config_temp, devDescriptor->bNumConfigurations); - udev_load_interface(pdev); return (IUDEVICE*)pdev; +fail: + pdev->iface.free((IUDEVICE*)pdev); + return NULL; } -int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray) +size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, 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*)); + size_t num = 0; + + if (!urbdrc || !devArray) + return 0; + + WLog_Print(urbdrc->log, WLOG_INFO, "VID: 0x%04" PRIX16 ", PID: 0x%04" PRIX16 "", idVendor, + idProduct); + array = (UDEVICE**)calloc(16, sizeof(UDEVICE*)); + + if (!array) + return 0; + total_device = libusb_get_device_list(NULL, &libusb_list); for (i = 0; i < total_device; i++) { - descriptor = udev_new_descript(libusb_list[i]); + LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, 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); + array[num] = (PUDEVICE)udev_init(urbdrc, libusb_list[i], bus_number, dev_number); if (array[num] != NULL) num++; } - zfree(descriptor); + free(descriptor); } libusb_free_device_list(libusb_list, 1); @@ -1954,29 +1628,8 @@ int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray) return num; } -IUDEVICE* udev_new_by_addr(int bus_number, int dev_number) +IUDEVICE* udev_new_by_addr(URBDRC_PLUGIN* urbdrc, BYTE bus_number, BYTE 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); + WLog_Print(urbdrc->log, WLOG_DEBUG, "bus:%d dev:%d", bus_number, dev_number); + return udev_init(urbdrc, NULL, bus_number, dev_number); } diff --git a/channels/urbdrc/client/libusb/libusb_udevice.h b/channels/urbdrc/client/libusb/libusb_udevice.h index f08f24b07..246f1e09c 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.h +++ b/channels/urbdrc/client/libusb/libusb_udevice.h @@ -21,14 +21,10 @@ #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H #define FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) #include -#else -#include -#endif +#include #include "urbdrc_types.h" -#include "request_queue.h" #include "urbdrc_main.h" typedef struct libusb_device LIBUSB_DEVICE; @@ -51,10 +47,11 @@ struct _UDEVICE UINT32 UsbDevice; /* An unique interface ID */ UINT32 ReqCompletion; /* An unique interface ID */ - UINT32 channel_id; + IWTSVirtualChannelManager* channelManager; + UINT32 channelID; UINT16 status; - UINT16 bus_number; - UINT16 dev_number; + BYTE bus_number; + BYTE dev_number; char path[17]; int port_number; int isCompositeDevice; @@ -66,18 +63,14 @@ struct _UDEVICE MSUSB_CONFIG_DESCRIPTOR* MsConfig; LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig; - REQUEST_QUEUE* request_queue; - /* Used in isochronous transfer */ - void* isoch_queue; + wHashTable* request_queue; - pthread_mutex_t mutex_isoch; - sem_t sem_id; + URBDRC_PLUGIN* urbdrc; }; typedef UDEVICE* PUDEVICE; -int udev_new_by_id(UINT16 idVendor, UINT16 idProduct, IUDEVICE*** devArray); -IUDEVICE* udev_new_by_addr(int bus_number, int dev_number); - -extern int libusb_debug; +size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, UINT16 idVendor, UINT16 idProduct, + IUDEVICE*** devArray); +IUDEVICE* udev_new_by_addr(URBDRC_PLUGIN* urbdrc, BYTE bus_number, BYTE dev_number); #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_UDEVICE_H */ diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 035c2d0de..8f4f8cc9f 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -21,7 +21,9 @@ #include #include #include +#include +#include #include #include @@ -32,8 +34,6 @@ #include "libusb_udevice.h" -int libusb_debug; - #define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ static _type udevman_get_##_arg(IUDEVMAN* idevman) \ { \ @@ -62,28 +62,33 @@ struct _UDEVMAN UINT32 defUsbDevice; UINT16 flags; - int device_num; + UINT32 device_num; int sem_timeout; - pthread_mutex_t devman_loading; - sem_t sem_urb_lock; + HANDLE devman_loading; + libusb_context* context; + libusb_hotplug_callback_handle handle; + HANDLE thread; + BOOL running; }; typedef UDEVMAN* PUDEVMAN; +static BOOL poll_libusb_events(UDEVMAN* udevman); + static void udevman_rewind(IUDEVMAN* idevman) { UDEVMAN* udevman = (UDEVMAN*)idevman; udevman->idev = udevman->head; } -static int udevman_has_next(IUDEVMAN* idevman) +static BOOL udevman_has_next(IUDEVMAN* idevman) { UDEVMAN* udevman = (UDEVMAN*)idevman; - if (udevman->idev == NULL) - return 0; + if (!udevman || !udevman->idev) + return FALSE; else - return 1; + return TRUE; } static IUDEVICE* udevman_get_next(IUDEVMAN* idevman) @@ -95,36 +100,46 @@ static IUDEVICE* udevman_get_next(IUDEVMAN* idevman) return pdev; } -static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, int bus_number, int dev_number) +static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number) { - IUDEVICE* pdev; + IUDEVICE* dev = NULL; + + if (!idevman) + return NULL; + idevman->loading_lock(idevman); idevman->rewind(idevman); while (idevman->has_next(idevman)) { - pdev = idevman->get_next(idevman); + IUDEVICE* pdev = idevman->get_next(idevman); if ((pdev->get_bus_number(pdev) == bus_number) && (pdev->get_dev_number(pdev) == dev_number)) { - idevman->loading_unlock(idevman); - return pdev; + dev = pdev; + break; } } idevman->loading_unlock(idevman); - WLog_WARN(TAG, "bus:%d dev:%d not exist in udevman", bus_number, dev_number); - return NULL; + return dev; } -static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_number, - int UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag) +static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number, + UINT32 UsbDevice, UINT16 idVendor, UINT16 idProduct, + int flag) { UDEVMAN* udevman = (UDEVMAN*)idevman; IUDEVICE* pdev = NULL; IUDEVICE** devArray; - int i, num, addnum = 0; + URBDRC_PLUGIN* urbdrc; + size_t i, num, addnum = 0; + + if (!idevman || !idevman->plugin) + return 0; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; pdev = (IUDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); if (pdev != NULL) @@ -132,26 +147,26 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n if (flag == UDEVMAN_FLAG_ADD_BY_ADDR) { - pdev = udev_new_by_addr(bus_number, dev_number); + IUDEVICE* tdev = udev_new_by_addr(urbdrc, bus_number, dev_number); - if (pdev == NULL) + if (tdev == NULL) return 0; - pdev->set_UsbDevice(pdev, UsbDevice); + tdev->set_UsbDevice(tdev, UsbDevice); idevman->loading_lock(idevman); if (udevman->head == NULL) { /* linked list is empty */ - udevman->head = pdev; - udevman->tail = pdev; + udevman->head = tdev; + udevman->tail = tdev; } else { /* append device to the end of the linked list */ - udevman->tail->set_p_next(udevman->tail, pdev); - pdev->set_p_prev(pdev, udevman->tail); - udevman->tail = pdev; + udevman->tail->set_p_next(udevman->tail, tdev); + tdev->set_p_prev(tdev, udevman->tail); + udevman->tail = tdev; } udevman->device_num += 1; @@ -161,34 +176,35 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n { addnum = 0; /* register all device that match pid vid */ - num = udev_new_by_id(idVendor, idProduct, &devArray); + num = udev_new_by_id(urbdrc, idVendor, idProduct, &devArray); for (i = 0; i < num; i++) { - pdev = devArray[i]; + IUDEVICE* tdev = devArray[i]; - if (udevman_get_udevice_by_addr(idevman, pdev->get_bus_number(pdev), - pdev->get_dev_number(pdev)) != NULL) + if (udevman_get_udevice_by_addr(idevman, tdev->get_bus_number(tdev), + tdev->get_dev_number(tdev)) != NULL) { - zfree(pdev); + tdev->free(tdev); + devArray[i] = NULL; continue; } - pdev->set_UsbDevice(pdev, UsbDevice); + tdev->set_UsbDevice(tdev, UsbDevice); idevman->loading_lock(idevman); if (udevman->head == NULL) { /* linked list is empty */ - udevman->head = pdev; - udevman->tail = pdev; + udevman->head = tdev; + udevman->tail = tdev; } else { /* append device to the end of the linked list */ - udevman->tail->set_p_next(udevman->tail, pdev); - pdev->set_p_prev(pdev, udevman->tail); - udevman->tail = pdev; + udevman->tail->set_p_next(udevman->tail, tdev); + tdev->set_p_prev(tdev, udevman->tail); + udevman->tail = tdev; } udevman->device_num += 1; @@ -196,28 +212,32 @@ static int udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_n addnum++; } - zfree(devArray); + free(devArray); return addnum; } else { - WLog_ERR(TAG, "udevman_register_udevice: function error!!"); + WLog_Print(urbdrc->log, WLOG_ERROR, "udevman_register_udevice: Invalid flag=%08 " PRIx32, + flag); return 0; } return 1; } -static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev_number) +static BOOL udevman_unregister_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number) { UDEVMAN* udevman = (UDEVMAN*)idevman; - UDEVICE *pdev, *dev; - int ret = 0, err = 0; - dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + UDEVICE* pdev; + UDEVICE* dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + + if (!dev || !idevman) + return FALSE; + idevman->loading_lock(idevman); idevman->rewind(idevman); - while (idevman->has_next(idevman) != 0) + while (idevman->has_next(idevman)) { pdev = (UDEVICE*)idevman->get_next(idevman); @@ -259,63 +279,158 @@ static int udevman_unregister_udevice(IUDEVMAN* idevman, int bus_number, int dev if (dev) { - /* reset device */ - if (err != LIBUSB_ERROR_NO_DEVICE) - { - ret = libusb_reset_device(dev->libusb_handle); - - if (ret < 0) - { - WLog_ERR(TAG, "libusb_reset_device: ERROR!!ret:%d", ret); - } - } - - /* release all interface and attach kernel driver */ - dev->iface.attach_kernel_driver((IUDEVICE*)dev); - - if (dev->request_queue) - zfree(dev->request_queue); - - /* free the config descriptor that send from windows */ - msusb_msconfig_free(dev->MsConfig); - libusb_close(dev->libusb_handle); - libusb_close(dev->hub_handle); - sem_destroy(&dev->sem_id); - - /* free device info */ - if (dev->devDescriptor) - zfree(dev->devDescriptor); - - if (dev) - zfree(dev); - - return 1; /* unregistration successful */ + dev->iface.free(&dev->iface); + return TRUE; /* unregistration successful */ } /* if we reach this point, the device wasn't found */ - return 0; + return FALSE; } -static void udevman_parse_device_addr(char* str, int* id1, int* id2, char sign) +static BOOL udevman_cancel_all_device_requests(IUDEVMAN* idevman) { - char s1[8]; - char* s2; - ZeroMemory(s1, sizeof(s1)); - s2 = (strchr(str, sign)) + 1; - strncpy(s1, str, strlen(str) - (strlen(s2) + 1)); - *id1 = strtol(s1, NULL, 0); - *id2 = strtol(s2, NULL, 0); + UDEVMAN* udevman = (UDEVMAN*)idevman; + + if (!idevman) + return FALSE; + + idevman->loading_lock(idevman); + idevman->rewind(idevman); + + while (idevman->has_next(idevman)) + { + UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman); + + if (!dev) + continue; + dev->iface.cancel_all_transfer_request(&dev->iface); + } + + idevman->loading_unlock(idevman); + + return TRUE; } -static void udevman_parse_device_pid_vid(char* str, int* id1, int* id2, char sign) +static BOOL udevman_unregister_all_udevices(IUDEVMAN* idevman) { - char s1[8]; + UDEVMAN* udevman = (UDEVMAN*)idevman; + + if (!idevman) + return FALSE; + + idevman->loading_lock(idevman); + idevman->rewind(idevman); + + while (idevman->has_next(idevman)) + { + UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman); + + if (!dev) + continue; + + /* set previous device to point to next device */ + if (dev->prev != NULL) + { + /* unregistered device is not the head */ + UDEVICE* pdev = dev->prev; + pdev->next = dev->next; + } + else + { + /* unregistered device is the head, update head */ + udevman->head = (IUDEVICE*)dev->next; + } + + /* set next device to point to previous device */ + + if (dev->next != NULL) + { + /* unregistered device is not the tail */ + UDEVICE* pdev = (UDEVICE*)dev->next; + pdev->prev = dev->prev; + } + else + { + /* unregistered device is the tail, update tail */ + udevman->tail = (IUDEVICE*)dev->prev; + } + + dev->iface.free(&dev->iface); + udevman->device_num--; + } + + idevman->loading_unlock(idevman); + + return TRUE; +} + +static BOOL udevman_parse_device_addr(const char* str, size_t maxLen, UINT16* id1, UINT16* id2, + char sign) +{ + unsigned long rc; + char s1[8] = { 0 }; char* s2; - ZeroMemory(s1, sizeof(s1)); + size_t len = strnlen(str, maxLen); + size_t cpLen; s2 = (strchr(str, sign)) + 1; - strncpy(s1, str, strlen(str) - (strlen(s2) + 1)); - *id1 = strtol(s1, NULL, 16); - *id2 = strtol(s2, NULL, 16); + + if (!s2) + return FALSE; + + cpLen = len - (strnlen(s2, len) + 1); + + if (cpLen >= sizeof(s1)) + cpLen = sizeof(s1) - 1; + + strncpy(s1, str, cpLen); + rc = strtoul(s1, NULL, 16); + + if ((rc > UINT16_MAX) || (errno != 0)) + return FALSE; + + *id1 = rc; + rc = strtoul(s2, NULL, 16); + + if ((rc > UINT16_MAX) || (errno != 0)) + return FALSE; + + *id2 = rc; + return TRUE; +} + +static BOOL udevman_parse_device_pid_vid(const char* str, size_t maxLen, UINT16* id1, UINT16* id2, + char sign) +{ + unsigned long rc; + char s1[8] = { 0 }; + char* s2; + size_t len = strnlen(str, maxLen); + size_t cpLen; + s2 = (strchr(str, sign)) + 1; + + if (!s2) + return FALSE; + + cpLen = len - (strnlen(s2, len) + 1); + + if (cpLen >= sizeof(s1)) + cpLen = sizeof(s1) - 1; + + strncpy(s1, str, cpLen); + errno = 0; + rc = strtoul(s1, NULL, 16); + + if ((rc > UINT16_MAX) || (errno != 0)) + return FALSE; + + *id1 = rc; + rc = strtoul(s2, NULL, 16); + + if ((rc > UINT16_MAX) || (errno != 0)) + return FALSE; + + *id2 = rc; + return TRUE; } static int udevman_check_device_exist_by_id(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct) @@ -332,30 +447,17 @@ static int udevman_is_auto_add(IUDEVMAN* idevman) return (udevman->flags & UDEVMAN_FLAG_ADD_BY_AUTO) ? 1 : 0; } -static IUDEVICE* udevman_get_udevice_by_UsbDevice_try_again(IUDEVMAN* idevman, UINT32 UsbDevice) -{ - UDEVICE* pdev; - idevman->loading_lock(idevman); - idevman->rewind(idevman); - - while (idevman->has_next(idevman)) - { - pdev = (UDEVICE*)idevman->get_next(idevman); - - if (pdev->UsbDevice == UsbDevice) - { - idevman->loading_unlock(idevman); - return (IUDEVICE*)pdev; - } - } - - idevman->loading_unlock(idevman); - return NULL; -} - static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice) { UDEVICE* pdev; + URBDRC_PLUGIN* urbdrc; + + if (!idevman || !idevman->plugin) + return NULL; + + /* Mask highest 2 bits, must be ignored */ + UsbDevice = UsbDevice & INTERFACE_ID_MASK; + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; idevman->loading_lock(idevman); idevman->rewind(idevman); @@ -371,57 +473,90 @@ static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbD } idevman->loading_unlock(idevman); - /* try again */ - pdev = (UDEVICE*)idevman->get_udevice_by_UsbDevice_try_again(idevman, UsbDevice); - - if (pdev) - { - return (IUDEVICE*)pdev; - } - - WLog_ERR(TAG, "0x%" PRIx32 " ERROR!!", UsbDevice); + WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to deviceId=%08" PRIx32, + UsbDevice); return NULL; } static void udevman_loading_lock(IUDEVMAN* idevman) { UDEVMAN* udevman = (UDEVMAN*)idevman; - pthread_mutex_lock(&udevman->devman_loading); + WaitForSingleObject(udevman->devman_loading, INFINITE); } static void udevman_loading_unlock(IUDEVMAN* idevman) { UDEVMAN* udevman = (UDEVMAN*)idevman; - pthread_mutex_unlock(&udevman->devman_loading); -} - -static void udevman_wait_urb(IUDEVMAN* idevman) -{ - UDEVMAN* udevman = (UDEVMAN*)idevman; - sem_wait(&udevman->sem_urb_lock); -} - -static void udevman_push_urb(IUDEVMAN* idevman) -{ - UDEVMAN* udevman = (UDEVMAN*)idevman; - sem_post(&udevman->sem_urb_lock); + ReleaseMutex(udevman->devman_loading); } BASIC_STATE_FUNC_DEFINED(defUsbDevice, UINT32) -BASIC_STATE_FUNC_DEFINED(device_num, int) +BASIC_STATE_FUNC_DEFINED(device_num, UINT32) BASIC_STATE_FUNC_DEFINED(sem_timeout, int) static void udevman_free(IUDEVMAN* idevman) { UDEVMAN* udevman = (UDEVMAN*)idevman; - pthread_mutex_destroy(&udevman->devman_loading); - sem_destroy(&udevman->sem_urb_lock); - libusb_exit(NULL); - /* free udevman */ + if (!udevman) + return; - if (udevman) - zfree(udevman); + libusb_hotplug_deregister_callback(udevman->context, udevman->handle); + + udevman->running = FALSE; + WaitForSingleObject(udevman->thread, INFINITE); + + /* Process remaining usb events */ + while (poll_libusb_events(udevman)) + ; + + udevman_unregister_all_udevices(idevman); + CloseHandle(udevman->devman_loading); + CloseHandle(udevman->thread); + libusb_exit(udevman->context); + + free(udevman); +} + +static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev, + libusb_hotplug_event event, void* user_data) +{ + int rc; + struct libusb_device_descriptor desc; + IUDEVMAN* idevman = (IUDEVMAN*)user_data; + const uint8_t bus = libusb_get_bus_number(dev); + const uint8_t addr = libusb_get_device_address(dev); + rc = libusb_get_device_descriptor(dev, &desc); + + if (rc != LIBUSB_SUCCESS) + return rc; + + switch (event) + { + case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED: + add_device(idevman, bus, addr, desc.iManufacturer, desc.iProduct); + break; + + case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT: + del_device(idevman, bus, addr, desc.iManufacturer, desc.iProduct); + break; + + default: + break; + } + + return 0; +} + +static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId) +{ + UDEVMAN* udevman = (UDEVMAN*)idevman; + + if (!udevman) + return FALSE; + + idevman->controlChannelId = channelId; + return TRUE; } static void udevman_load_interface(UDEVMAN* udevman) @@ -435,7 +570,6 @@ static void udevman_load_interface(UDEVMAN* udevman) udevman->iface.register_udevice = udevman_register_udevice; udevman->iface.unregister_udevice = udevman_unregister_udevice; udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice; - udevman->iface.get_udevice_by_UsbDevice_try_again = udevman_get_udevice_by_UsbDevice_try_again; /* Extension */ udevman->iface.check_device_exist_by_id = udevman_check_device_exist_by_id; udevman->iface.isAutoAdd = udevman_is_auto_add; @@ -446,47 +580,51 @@ static void udevman_load_interface(UDEVMAN* udevman) /* control semaphore or mutex lock */ udevman->iface.loading_lock = udevman_loading_lock; udevman->iface.loading_unlock = udevman_loading_unlock; - udevman->iface.push_urb = udevman_push_urb; - udevman->iface.wait_urb = udevman_wait_urb; + udevman->iface.initialize = udevman_initialize; } -static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices) +static BOOL urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices) { + BOOL rc = FALSE; char* token; - int idVendor; - int idProduct; - int bus_number; - int dev_number; int success = 0; + char* tmp; char hardware_id[16]; - char* default_devices = "id"; + const char* default_devices = "id"; UINT32 UsbDevice = BASE_USBDEVICE_NUM; if (!devices) - devices = default_devices; + tmp = _strdup(default_devices); + else + tmp = _strdup(devices); /* register all usb devices */ - token = strtok(devices, "#"); + token = strtok(tmp, "#"); while (token) { - bus_number = 0; - dev_number = 0; - idVendor = 0; - idProduct = 0; - sprintf_s(hardware_id, ARRAYSIZE(hardware_id), "%s", token); + strcpy(hardware_id, token); token = strtok(NULL, "#"); if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID) { - udevman_parse_device_pid_vid(hardware_id, &idVendor, &idProduct, ':'); - success = udevman->iface.register_udevice((IUDEVMAN*)udevman, 0, 0, UsbDevice, - (UINT16)idVendor, (UINT16)idProduct, - UDEVMAN_FLAG_ADD_BY_VID_PID); + UINT16 idVendor, idProduct; + + if (!udevman_parse_device_pid_vid(hardware_id, sizeof(hardware_id), &idVendor, + &idProduct, ':')) + goto fail; + + success = udevman->iface.register_udevice((IUDEVMAN*)udevman, 0, 0, UsbDevice, idVendor, + idProduct, UDEVMAN_FLAG_ADD_BY_VID_PID); } else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR) { - udevman_parse_device_addr(hardware_id, &bus_number, &dev_number, ':'); + UINT16 bus_number, dev_number; + + if (!udevman_parse_device_addr(hardware_id, sizeof(hardware_id), &bus_number, + &dev_number, ':')) + goto fail; + success = udevman->iface.register_udevice((IUDEVMAN*)udevman, bus_number, dev_number, UsbDevice, 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR); } @@ -496,12 +634,18 @@ static void urbdrc_udevman_register_devices(UDEVMAN* udevman, char* devices) } udevman->defUsbDevice = UsbDevice; + rc = TRUE; +fail: + free(tmp); + return rc; } -static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) +static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) { int status; DWORD flags; + LPSTR devices = NULL; + const UINT16 mask = UDEVMAN_FLAG_ADD_BY_VID_PID | UDEVMAN_FLAG_ADD_BY_ADDR; COMMAND_LINE_ARGUMENT_A* arg; COMMAND_LINE_ARGUMENT_A urbdrc_udevman_args[] = { { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, @@ -512,9 +656,14 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) { "auto", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_AUTO" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_udevman_args, flags, udevman, NULL, NULL); + + if (status != CHANNEL_RC_OK) + return status; + arg = urbdrc_udevman_args; do @@ -528,7 +677,7 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) } CommandLineSwitchCase(arg, "dev") { - urbdrc_udevman_register_devices(udevman, arg->Value); + devices = arg->Value; } CommandLineSwitchCase(arg, "id") { @@ -547,6 +696,60 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) } CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); + + /* Can not add devices by address and VID/PID */ + if ((udevman->flags & mask) == mask) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + + /* Add listed devices after we know the format of addressing */ + if (devices) + { + if (!urbdrc_udevman_register_devices(udevman, devices)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } + + return CHANNEL_RC_OK; +} + +static BOOL poll_libusb_events(UDEVMAN* udevman) +{ + int rc = LIBUSB_SUCCESS; + struct timeval tv = { 0, 500 }; + if (libusb_try_lock_events(udevman->context)) + { + if (libusb_event_handling_ok(udevman->context)) + { + rc = libusb_handle_events_locked(udevman->context, &tv); + if (rc != LIBUSB_SUCCESS) + WLog_WARN(TAG, "libusb_handle_events_locked %d", rc); + } + libusb_unlock_events(udevman->context); + } + else + { + libusb_lock_event_waiters(udevman->context); + if (libusb_event_handler_active(udevman->context)) + { + rc = libusb_wait_for_event(udevman->context, &tv); + if (rc < LIBUSB_SUCCESS) + WLog_WARN(TAG, "libusb_wait_for_event %d", rc); + } + libusb_unlock_event_waiters(udevman->context); + } + + return rc > 0; +} + +static DWORD poll_thread(LPVOID lpThreadParameter) +{ + UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter; + + while (udevman->running) + { + poll_libusb_events(udevman); + } + + return 0; } #ifdef BUILTIN_CHANNELS @@ -554,31 +757,56 @@ static void urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args) #else #define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry #endif - int freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) { + int rc; + UINT status; UDEVMAN* udevman; ADDIN_ARGV* args = pEntryPoints->args; - libusb_init(NULL); - udevman = (PUDEVMAN)malloc(sizeof(UDEVMAN)); + udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN)); if (!udevman) - return -1; + goto fail; + + udevman->iface.plugin = pEntryPoints->plugin; + rc = libusb_init(&udevman->context); + + if (rc != LIBUSB_SUCCESS) + goto fail; - udevman->device_num = 0; - udevman->idev = NULL; - udevman->head = NULL; - udevman->tail = NULL; - udevman->sem_timeout = 0; udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID; - pthread_mutex_init(&udevman->devman_loading, NULL); - sem_init(&udevman->sem_urb_lock, 0, MAX_URB_REQUSET_NUM); + udevman->devman_loading = CreateMutexA(NULL, FALSE, "devman_loading"); + + if (!udevman->devman_loading) + goto fail; + /* load usb device service management */ udevman_load_interface(udevman); - /* set debug flag, to enable Debug message for usb data transfer */ - libusb_debug = 10; - urbdrc_udevman_parse_addin_args(udevman, args); - pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman); + status = urbdrc_udevman_parse_addin_args(udevman, args); + + if (status != CHANNEL_RC_OK) + goto fail; + + udevman->running = TRUE; + udevman->thread = CreateThread(NULL, 0, poll_thread, udevman, 0, NULL); + + if (!udevman->thread) + goto fail; + + rc = libusb_hotplug_register_callback( + udevman->context, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT, + LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY, + LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &udevman->handle); + + if (rc != LIBUSB_SUCCESS) + goto fail; + + if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman)) + goto fail; + WLog_DBG(TAG, "UDEVMAN device registered."); return 0; +fail: + udevman_free(&udevman->iface); + return -1; } diff --git a/channels/urbdrc/client/libusb/request_queue.c b/channels/urbdrc/client/libusb/request_queue.c deleted file mode 100644 index 9492cddcb..000000000 --- a/channels/urbdrc/client/libusb/request_queue.c +++ /dev/null @@ -1,179 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * RemoteFX USB Redirection - * - * Copyright 2012 Atrust corp. - * Copyright 2012 Alfred Liu - * - * 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 -#include -#include -#include -#include "request_queue.h" - -TRANSFER_REQUEST* request_queue_get_next(REQUEST_QUEUE* queue) -{ - TRANSFER_REQUEST* request; - - request = queue->ireq; - queue->ireq = (TRANSFER_REQUEST*)queue->ireq->next; - - return request; -} - -int request_queue_has_next(REQUEST_QUEUE* queue) -{ - if (queue->ireq == NULL) - return 0; - else - return 1; -} - -TRANSFER_REQUEST* request_queue_register_request(REQUEST_QUEUE* queue, UINT32 RequestId, - struct libusb_transfer* transfer, BYTE endpoint) -{ - TRANSFER_REQUEST* request; - - request = (TRANSFER_REQUEST*)malloc(sizeof(TRANSFER_REQUEST)); - - request->prev = NULL; - request->next = NULL; - - request->RequestId = RequestId; - request->transfer = transfer; - request->endpoint = endpoint; - request->submit = 0; - - pthread_mutex_lock(&queue->request_loading); - - if (queue->head == NULL) - { - /* linked queue is empty */ - queue->head = request; - queue->tail = request; - } - else - { - /* append data to the end of the linked queue */ - queue->tail->next = (void*)request; - request->prev = (void*)queue->tail; - queue->tail = request; - } - - queue->request_num += 1; - pthread_mutex_unlock(&queue->request_loading); - - return request; -} - -void request_queue_rewind(REQUEST_QUEUE* queue) -{ - queue->ireq = queue->head; -} - -/* Get first*/ -TRANSFER_REQUEST* request_queue_get_request_by_endpoint(REQUEST_QUEUE* queue, BYTE ep) -{ - TRANSFER_REQUEST* request; - pthread_mutex_lock(&queue->request_loading); - queue->rewind(queue); - while (queue->has_next(queue)) - { - request = queue->get_next(queue); - if (request->endpoint == ep) - { - pthread_mutex_unlock(&queue->request_loading); - return request; - } - } - pthread_mutex_unlock(&queue->request_loading); - WLog_ERR(TAG, "request_queue_get_request_by_id: ERROR!!"); - return NULL; -} - -int request_queue_unregister_request(REQUEST_QUEUE* queue, UINT32 RequestId) -{ - TRANSFER_REQUEST *request, *request_temp; - pthread_mutex_lock(&queue->request_loading); - queue->rewind(queue); - - while (queue->has_next(queue) != 0) - { - request = queue->get_next(queue); - - if (request->RequestId == RequestId) - { - - if (request->prev != NULL) - { - request_temp = (TRANSFER_REQUEST*)request->prev; - request_temp->next = (TRANSFER_REQUEST*)request->next; - } - else - { - queue->head = (TRANSFER_REQUEST*)request->next; - } - - if (request->next != NULL) - { - request_temp = (TRANSFER_REQUEST*)request->next; - request_temp->prev = (TRANSFER_REQUEST*)request->prev; - } - else - { - queue->tail = (TRANSFER_REQUEST*)request->prev; - } - - queue->request_num--; - - if (request) - { - request->transfer = NULL; - zfree(request); - } - - pthread_mutex_unlock(&queue->request_loading); - - return 0; - } - } - pthread_mutex_unlock(&queue->request_loading); - /* it wasn't found */ - return 1; -} - -REQUEST_QUEUE* request_queue_new() -{ - REQUEST_QUEUE* queue; - - queue = (REQUEST_QUEUE*)malloc(sizeof(REQUEST_QUEUE)); - queue->request_num = 0; - queue->ireq = NULL; - queue->head = NULL; - queue->tail = NULL; - - pthread_mutex_init(&queue->request_loading, NULL); - - /* load service */ - queue->get_next = request_queue_get_next; - queue->has_next = request_queue_has_next; - queue->rewind = request_queue_rewind; - queue->register_request = request_queue_register_request; - queue->unregister_request = request_queue_unregister_request; - queue->get_request_by_ep = request_queue_get_request_by_endpoint; - - return queue; -} diff --git a/channels/urbdrc/client/libusb/request_queue.h b/channels/urbdrc/client/libusb/request_queue.h deleted file mode 100644 index bafe6716a..000000000 --- a/channels/urbdrc/client/libusb/request_queue.h +++ /dev/null @@ -1,62 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * RemoteFX USB Redirection - * - * Copyright 2012 Atrust corp. - * Copyright 2012 Alfred Liu - * - * 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. - */ - -#ifndef FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H -#define FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H - -#include "urbdrc_types.h" - -typedef struct _TRANSFER_REQUEST TRANSFER_REQUEST; -typedef struct _REQUEST_QUEUE REQUEST_QUEUE; - -struct _TRANSFER_REQUEST -{ - void* request; - void* prev; - void* next; - - UINT32 RequestId; - BYTE endpoint; - struct libusb_transfer* transfer; - int submit; -}; - -struct _REQUEST_QUEUE -{ - int request_num; - TRANSFER_REQUEST* ireq; /* iterator request */ - TRANSFER_REQUEST* head; /* head request in linked queue */ - TRANSFER_REQUEST* tail; /* tail request in linked queue */ - - pthread_mutex_t request_loading; - - /* request queue manager service */ - void (*rewind)(REQUEST_QUEUE* queue); - int (*has_next)(REQUEST_QUEUE* queue); - int (*unregister_request)(REQUEST_QUEUE* queue, UINT32 RequestId); - TRANSFER_REQUEST* (*get_next)(REQUEST_QUEUE* queue); - TRANSFER_REQUEST* (*get_request_by_ep)(REQUEST_QUEUE* queue, BYTE ep); - TRANSFER_REQUEST* (*register_request)(REQUEST_QUEUE* queue, UINT32 RequestId, - struct libusb_transfer* transfer, BYTE endpoint); -}; - -REQUEST_QUEUE* request_queue_new(void); - -#endif /* FREERDP_CHANNEL_URBDRC_CLIENT_LIBUSB_REQUEST_QUEUE_H */ diff --git a/channels/urbdrc/client/searchman.c b/channels/urbdrc/client/searchman.c index a1a587d5b..6d109f213 100644 --- a/channels/urbdrc/client/searchman.c +++ b/channels/urbdrc/client/searchman.c @@ -21,12 +21,12 @@ #include #include #include -#include #include #include #include "searchman.h" +#include "urbdrc_main.h" static void searchman_rewind(USB_SEARCHMAN* searchman) { @@ -44,18 +44,16 @@ static int searchman_has_next(USB_SEARCHMAN* searchman) static USB_SEARCHDEV* searchman_get_next(USB_SEARCHMAN* searchman) { USB_SEARCHDEV* search; - search = searchman->idev; searchman->idev = (USB_SEARCHDEV*)searchman->idev->next; - return search; } static BOOL searchman_list_add(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT16 idProduct) { USB_SEARCHDEV* search; - search = (USB_SEARCHDEV*)calloc(1, sizeof(USB_SEARCHDEV)); + if (!search) return FALSE; @@ -75,8 +73,8 @@ static BOOL searchman_list_add(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT16 search->prev = (void*)searchman->tail; searchman->tail = search; } - searchman->usb_numbers += 1; + searchman->usb_numbers += 1; return TRUE; } @@ -84,7 +82,6 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT { USB_SEARCHDEV* search; USB_SEARCHDEV* point; - searchman_rewind(searchman); while (searchman_has_next(searchman) != 0) @@ -94,8 +91,8 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT if (point->idVendor == idVendor && point->idProduct == idProduct) { /* set previous device to point to next device */ - search = point; + if (search->prev != NULL) { /* unregistered device is not the head */ @@ -121,10 +118,9 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT /* unregistered device is the tail, update tail */ searchman->tail = (USB_SEARCHDEV*)search->prev; } + searchman->usb_numbers--; - free(search); - return 1; /* unregistration successful */ } } @@ -133,42 +129,29 @@ static int searchman_list_remove(USB_SEARCHMAN* searchman, UINT16 idVendor, UINT return 0; } -static BOOL searchman_start(USB_SEARCHMAN* self, void* (*func)(void*)) -{ - pthread_t thread; - - /* create search thread */ - if (pthread_create(&thread, 0, func, self) != 0) - return FALSE; - - if (pthread_detach(thread) != 0) - return FALSE; - - self->started = 1; - return TRUE; -} - -/* close thread */ -static void searchman_close(USB_SEARCHMAN* self) -{ - SetEvent(self->term_event); -} static void searchman_list_show(USB_SEARCHMAN* self) { int num = 0; USB_SEARCHDEV* usb; - WLog_DBG(TAG, "=========== Usb Search List ========="); + URBDRC_PLUGIN* urbdrc; + + if (!self || !self->urbdrc) + return; + + urbdrc = self->urbdrc; + WLog_Print(urbdrc->log, WLOG_DEBUG, "=========== Usb Search List ========="); self->rewind(self); + while (self->has_next(self)) { usb = self->get_next(self); - WLog_DBG(TAG, " USB %d: ", num++); - WLog_DBG(TAG, " idVendor: 0x%04" PRIX16 "", usb->idVendor); - WLog_DBG(TAG, " idProduct: 0x%04" PRIX16 "", usb->idProduct); + WLog_Print(urbdrc->log, WLOG_DEBUG, " USB %d: ", num++); + WLog_Print(urbdrc->log, WLOG_DEBUG, " idVendor: 0x%04" PRIX16 "", usb->idVendor); + WLog_Print(urbdrc->log, WLOG_DEBUG, " idProduct: 0x%04" PRIX16 "", usb->idProduct); } - WLog_DBG(TAG, "================= END ==============="); + WLog_Print(urbdrc->log, WLOG_DEBUG, "================= END ==============="); } void searchman_free(USB_SEARCHMAN* self) @@ -182,30 +165,19 @@ void searchman_free(USB_SEARCHMAN* self) } /* free searchman */ - sem_destroy(&self->sem_term); - CloseHandle(self->term_event); free(self); } USB_SEARCHMAN* searchman_new(void* urbdrc, UINT32 UsbDevice) { - int ret; USB_SEARCHMAN* searchman; - searchman = (USB_SEARCHMAN*)calloc(1, sizeof(USB_SEARCHMAN)); + if (!searchman) return NULL; searchman->urbdrc = urbdrc; searchman->UsbDevice = UsbDevice; - - ret = pthread_mutex_init(&searchman->mutex, NULL); - if (ret != 0) - { - WLog_ERR(TAG, "searchman mutex initialization: searchman->mutex failed"); - goto out_error_mutex; - } - /* load service */ searchman->add = searchman_list_add; searchman->remove = searchman_list_remove; @@ -213,25 +185,6 @@ USB_SEARCHMAN* searchman_new(void* urbdrc, UINT32 UsbDevice) searchman->get_next = searchman_get_next; searchman->has_next = searchman_has_next; searchman->show = searchman_list_show; - searchman->start = searchman_start; - searchman->close = searchman_close; searchman->free = searchman_free; - - searchman->started = 0; - searchman->term_event = CreateEvent(NULL, TRUE, FALSE, NULL); - if (!searchman->term_event) - goto out_error_event; - - if (sem_init(&searchman->sem_term, 0, 0) < 0) - goto out_error_sem; - return searchman; - -out_error_sem: - CloseHandle(searchman->term_event); -out_error_event: - pthread_mutex_destroy(&searchman->mutex); -out_error_mutex: - free(searchman); - return NULL; } diff --git a/channels/urbdrc/client/searchman.h b/channels/urbdrc/client/searchman.h index 8e5562819..4e29f0d41 100644 --- a/channels/urbdrc/client/searchman.h +++ b/channels/urbdrc/client/searchman.h @@ -44,11 +44,6 @@ struct _USB_SEARCHMAN USB_SEARCHDEV* head; /* head device in linked list */ USB_SEARCHDEV* tail; /* tail device in linked list */ - pthread_mutex_t mutex; - HANDLE term_event; - sem_t sem_term; - int started; - /* for urbdrc channel call back */ void* urbdrc; @@ -56,10 +51,6 @@ struct _USB_SEARCHMAN void (*rewind)(USB_SEARCHMAN* seachman); /* show all device in the list */ void (*show)(USB_SEARCHMAN* self); - /* start searchman */ - BOOL (*start)(USB_SEARCHMAN* self, void* (*func)(void*)); - /* close searchman */ - void (*close)(USB_SEARCHMAN* self); /* add a new usb device for search */ BOOL (*add)(USB_SEARCHMAN* seachman, UINT16 idVendor, UINT16 idProduct); /* remove a usb device from list */ diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c index 6694521d2..64bf79efd 100644 --- a/channels/urbdrc/client/urbdrc_main.c +++ b/channels/urbdrc/client/urbdrc_main.c @@ -22,20 +22,10 @@ #include #include #include -#include -#include #include -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -#include -#include -#include -#include -#include -#endif -#if defined(__linux__) -#include -#endif +#include +#include #include #include @@ -45,97 +35,52 @@ #include #include #include +#include #include "urbdrc_types.h" #include "urbdrc_main.h" #include "data_transfer.h" #include "searchman.h" +#include -static int func_hardware_id_format(IUDEVICE* pdev, char (*HardwareIds)[DEVICE_HARDWARE_ID_SIZE]) +static BOOL Stream_Write_UTF16_String_From_Utf8(wStream* s, const char* utf8, size_t len) { - char str[DEVICE_HARDWARE_ID_SIZE]; - UINT16 idVendor, idProduct, bcdDevice; - idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR); - idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); - bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE); - sprintf_s(str, sizeof(str), "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "", idVendor, idProduct); - strncpy(HardwareIds[1], str, DEVICE_HARDWARE_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&REV_%04" PRIX16 "", HardwareIds[1], bcdDevice); - strncpy(HardwareIds[0], str, DEVICE_HARDWARE_ID_SIZE); - return 0; + BOOL ret; + WCHAR* utf16; + int rc; + + if (len > INT_MAX) + return FALSE; + + rc = ConvertToUnicode(CP_UTF8, 0, utf8, (int)len, &utf16, 0); + + if (rc < 0) + return FALSE; + + ret = Stream_Write_UTF16_String(s, utf16, (size_t)rc); + free(utf16); + return ret; } -static int func_compat_id_format(IUDEVICE* pdev, - char (*CompatibilityIds)[DEVICE_COMPATIBILITY_ID_SIZE]) +static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman) { - char str[DEVICE_COMPATIBILITY_ID_SIZE]; - UINT8 bDeviceClass, bDeviceSubClass, bDeviceProtocol; - bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS); - bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS); - bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL); + IWTSVirtualChannelManager* channel_mgr; + URBDRC_PLUGIN* urbdrc; - if (!(pdev->isCompositeDevice(pdev))) - { - sprintf_s(str, sizeof(str), "USB\\Class_%02" PRIX8 "", bDeviceClass); - strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&SubClass_%02" PRIX8 "", CompatibilityIds[2], - bDeviceSubClass); - strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&Prot_%02" PRIX8 "", CompatibilityIds[1], bDeviceProtocol); - strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); - } - else - { - sprintf_s(str, sizeof(str), "USB\\DevClass_00"); - strncpy(CompatibilityIds[2], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&SubClass_00", CompatibilityIds[2]); - strncpy(CompatibilityIds[1], str, DEVICE_COMPATIBILITY_ID_SIZE); - sprintf_s(str, sizeof(str), "%s&Prot_00", CompatibilityIds[1]); - strncpy(CompatibilityIds[0], str, DEVICE_COMPATIBILITY_ID_SIZE); - } + if (!idevman) + return NULL; - return 0; -} + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; -static void func_close_udevice(USB_SEARCHMAN* searchman, IUDEVICE* pdev) -{ - int idVendor = 0; - int idProduct = 0; - URBDRC_PLUGIN* urbdrc = searchman->urbdrc; - pdev->SigToEnd(pdev); - idVendor = pdev->query_device_descriptor(pdev, ID_VENDOR); - idProduct = pdev->query_device_descriptor(pdev, ID_PRODUCT); - searchman->add(searchman, (UINT16)idVendor, (UINT16)idProduct); - pdev->cancel_all_transfer_request(pdev); - pdev->wait_action_completion(pdev); -#if ISOCH_FIFO - { - /* free isoch queue */ - ISOCH_CALLBACK_QUEUE* isoch_queue = pdev->get_isoch_queue(pdev); + if (!urbdrc || !urbdrc->listener_callback) + return NULL; - if (isoch_queue) - isoch_queue->free(isoch_queue); - } -#endif - urbdrc->udevman->unregister_udevice(urbdrc->udevman, pdev->get_bus_number(pdev), - pdev->get_dev_number(pdev)); -} + channel_mgr = urbdrc->listener_callback->channel_mgr; -static int fun_device_string_send_set(char* out_data, int out_offset, char* str) -{ - int i = 0; - int offset = 0; + if (!channel_mgr) + return NULL; - while (str[i]) - { - data_write_UINT16(out_data + out_offset + offset, str[i]); /* str */ - i++; - offset += 2; - } - - data_write_UINT16(out_data + out_offset + offset, 0x0000); /* add "\0" */ - offset += 2; - return offset + out_offset; + return channel_mgr->FindChannelById(channel_mgr, idevman->controlChannelId); } static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId) @@ -167,13 +112,12 @@ static int func_container_id_generate(IUDEVICE* pdev, char* strContainerId) return 0; } -static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId) +static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId, size_t len) { - UINT8 instanceId[17]; - ZeroMemory(instanceId, sizeof(instanceId)); - sprintf_s((char*)instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev)); + char instanceId[17]; + sprintf_s(instanceId, sizeof(instanceId), "\\%s", pdev->getPath(pdev)); /* format */ - sprintf_s(strInstanceId, DEVICE_INSTANCE_STR_SIZE, + sprintf_s(strInstanceId, len, "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "-%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "", @@ -184,72 +128,42 @@ static int func_instance_id_generate(IUDEVICE* pdev, char* strInstanceId) return 0; } -#if ISOCH_FIFO - -static void func_lock_isoch_mutex(TRANSFER_DATA* transfer_data) -{ - int noAck = 0; - IUDEVICE* pdev; - UINT32 FunctionId; - UINT32 RequestField; - UINT16 URB_Function; - IUDEVMAN* udevman = transfer_data->udevman; - - if (transfer_data->cbSize >= 8) - { - data_read_UINT32(transfer_data->pBuffer + 4, FunctionId); - - if ((FunctionId == TRANSFER_IN_REQUEST || FunctionId == TRANSFER_OUT_REQUEST) && - transfer_data->cbSize >= 16) - { - data_read_UINT16(transfer_data->pBuffer + 14, URB_Function); - - if (URB_Function == URB_FUNCTION_ISOCH_TRANSFER && transfer_data->cbSize >= 20) - { - data_read_UINT32(transfer_data->pBuffer + 16, RequestField); - noAck = (RequestField & 0x80000000) >> 31; - - if (!noAck) - { - pdev = udevman->get_udevice_by_UsbDevice(udevman, transfer_data->UsbDevice); - pdev->lock_fifo_isoch(pdev); - } - } - } - } -} - -#endif - /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, char* data, - UINT32 data_sizem, UINT32 MessageId) +static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId) { UINT32 InterfaceId; UINT32 Version; UINT32 out_size; - char* out_data; - UINT ret; - WLog_VRB(TAG, ""); - data_read_UINT32(data + 0, Version); + wStream* out; + + if (!callback || !s) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(s) < 4) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, Version); + + if (Version > RIM_CAPABILITY_VERSION_01) + Version = RIM_CAPABILITY_VERSION_01; + InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR); out_size = 16; - out_data = (char*)calloc(1, out_size); + out = Stream_New(NULL, out_size); - if (!out_data) + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface id */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, Version); /* usb protocol version */ - data_write_UINT32(out_data + 12, 0x00000000); /* HRESULT */ - ret = callback->channel->Write(callback->channel, out_size, (BYTE*)out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, InterfaceId); /* interface id */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, Version); /* usb protocol version */ + Stream_Write_UINT32(out, 0x00000000); /* HRESULT */ + return stream_write_and_free(callback->plugin, callback->channel, out); } /** @@ -257,56 +171,68 @@ static UINT urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK* callback, * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK* callback, char* data, - UINT32 data_sizem, UINT32 MessageId) +static UINT urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK* callback, wStream* s, + UINT32 MessageId) { UINT32 InterfaceId; UINT32 out_size; UINT32 MajorVersion; UINT32 MinorVersion; UINT32 Capabilities; - char* out_data; - UINT ret; - WLog_VRB(TAG, ""); - data_read_UINT32(data + 0, MajorVersion); - data_read_UINT32(data + 4, MinorVersion); - data_read_UINT32(data + 8, Capabilities); + wStream* out; + URBDRC_PLUGIN* urbdrc; + + if (!callback || !s || !callback->plugin) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (Stream_GetRemainingLength(s) < 12) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, MajorVersion); + Stream_Read_UINT32(s, MinorVersion); + Stream_Read_UINT32(s, Capabilities); + + /* Version check, we only support version 1.0 */ + if ((MajorVersion != 1) || (MinorVersion != 0)) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "server supports USB channel version %" PRIu32 ".%" PRIu32); + WLog_Print(urbdrc->log, WLOG_WARN, "we only support channel version 1.0"); + MajorVersion = 1; + MinorVersion = 0; + } + InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION); out_size = 24; - out_data = (char*)calloc(1, out_size); + out = Stream_New(NULL, out_size); - if (!out_data) + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface id */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, CHANNEL_CREATED); /* function id */ - data_write_UINT32(out_data + 12, MajorVersion); - data_write_UINT32(out_data + 16, MinorVersion); - data_write_UINT32(out_data + 20, Capabilities); /* capabilities version */ - ret = callback->channel->Write(callback->channel, out_size, (BYTE*)out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, InterfaceId); /* interface id */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, CHANNEL_CREATED); /* function id */ + Stream_Write_UINT32(out, MajorVersion); + Stream_Write_UINT32(out, MinorVersion); + Stream_Write_UINT32(out, Capabilities); /* capabilities version */ + return stream_write_and_free(callback->plugin, callback->channel, out); } -static int urdbrc_send_virtual_channel_add(IWTSVirtualChannel* channel, UINT32 MessageId) +static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel, + UINT32 MessageId) { - UINT32 out_size; - UINT32 InterfaceId; - char* out_data; - WLog_VRB(TAG, ""); - assert(NULL != channel); - assert(NULL != channel->Write); - InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); - out_size = 12; - out_data = (char*)malloc(out_size); - memset(out_data, 0, out_size); - data_write_UINT32(out_data + 0, InterfaceId); /* interface */ - data_write_UINT32(out_data + 4, MessageId); /* message id */ - data_write_UINT32(out_data + 8, ADD_VIRTUAL_CHANNEL); /* function id */ - channel->Write(channel, out_size, (BYTE*)out_data, NULL); - zfree(out_data); - return 0; + const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); + wStream* out = Stream_New(NULL, 12); + + if (!out) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT32(out, InterfaceId); /* interface */ + Stream_Write_UINT32(out, MessageId); /* message id */ + Stream_Write_UINT32(out, ADD_VIRTUAL_CHANNEL); /* function id */ + return stream_write_and_free(plugin, channel, out); } /** @@ -316,103 +242,130 @@ static int urdbrc_send_virtual_channel_add(IWTSVirtualChannel* channel, UINT32 M */ static UINT urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK* callback, IUDEVICE* pdev) { - char* out_data; + wStream* out; UINT32 InterfaceId; - char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE]; - char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE]; - char strContainerId[DEVICE_CONTAINER_STR_SIZE]; - char strInstanceId[DEVICE_INSTANCE_STR_SIZE]; - char* composite_str = "USB\\COMPOSITE"; - int size, out_offset, cchCompatIds, bcdUSB; - ISOCH_CALLBACK_QUEUE* cb_queue; - UINT ret; - WLog_VRB(TAG, ""); + char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } }; + char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } }; + char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 }; + char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 }; + const char* composite_str = "USB\\COMPOSITE"; + const size_t composite_len = 13; + size_t size; + size_t CompatibilityIdLen[3]; + size_t HardwareIdsLen[2]; + size_t ContainerIdLen, InstanceIdLen; + size_t cchCompatIds; + UINT32 bcdUSB; InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK); /* USB kernel driver detach!! */ pdev->detach_kernel_driver(pdev); -#if ISOCH_FIFO - /* create/initial isoch queue */ - cb_queue = isoch_queue_new(); + { + const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR); + const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT); + const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE); + sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE, + "USB\\VID_%04" PRIX16 "&PID_%04" PRIX16 "", idVendor, idProduct); + sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE, "%s&REV_%04" PRIX16 "", HardwareIds[1], + bcdDevice); + } + { + const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS); + const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS); + const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL); - if (!cb_queue) - return ERROR_OUTOFMEMORY; - - pdev->set_isoch_queue(pdev, (void*)cb_queue); -#endif - func_hardware_id_format(pdev, HardwareIds); - func_compat_id_format(pdev, CompatibilityIds); - func_instance_id_generate(pdev, strInstanceId); + if (!(pdev->isCompositeDevice(pdev))) + { + sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\Class_%02" PRIX8 "", + bDeviceClass); + sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE, "%s&SubClass_%02" PRIX8 "", + CompatibilityIds[2], bDeviceSubClass); + sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE, "%s&Prot_%02" PRIX8 "", + CompatibilityIds[1], bDeviceProtocol); + } + else + { + sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE, "USB\\DevClass_00"); + sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE, "%s&SubClass_00", + CompatibilityIds[2]); + sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE, "%s&Prot_00", + CompatibilityIds[1]); + } + } + func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE); func_container_id_generate(pdev, strContainerId); - cchCompatIds = strlen(CompatibilityIds[0]) + 1 + strlen(CompatibilityIds[1]) + 1 + - strlen(CompatibilityIds[2]) + 2; + CompatibilityIdLen[0] = strnlen(CompatibilityIds[0], sizeof(CompatibilityIds[0])); + CompatibilityIdLen[1] = strnlen(CompatibilityIds[1], sizeof(CompatibilityIds[1])); + CompatibilityIdLen[2] = strnlen(CompatibilityIds[2], sizeof(CompatibilityIds[2])); + HardwareIdsLen[0] = strnlen(HardwareIds[0], sizeof(HardwareIds[0])); + HardwareIdsLen[1] = strnlen(HardwareIds[1], sizeof(HardwareIds[1])); + cchCompatIds = + CompatibilityIdLen[0] + 1 + CompatibilityIdLen[1] + 1 + CompatibilityIdLen[2] + 2; + InstanceIdLen = strnlen(strInstanceId, sizeof(strInstanceId)); + ContainerIdLen = strnlen(strContainerId, sizeof(strContainerId)); if (pdev->isCompositeDevice(pdev)) - cchCompatIds += strlen(composite_str) + 1; + cchCompatIds += composite_len + 1; - out_offset = 24; size = 24; - size += (strlen(strInstanceId) + 1) * 2 + (strlen(HardwareIds[0]) + 1) * 2 + 4 + - (strlen(HardwareIds[1]) + 1) * 2 + 2 + 4 + (cchCompatIds)*2 + - (strlen(strContainerId) + 1) * 2 + 4 + 28; - out_data = (char*)calloc(1, size); + size += (InstanceIdLen + 1) * 2 + (HardwareIdsLen[0] + 1) * 2 + 4 + + (HardwareIdsLen[1] + 1) * 2 + 2 + 4 + (cchCompatIds)*2 + (ContainerIdLen + 1) * 2 + 4 + + 28; + out = Stream_New(NULL, size); - if (!out_data) + if (!out) return ERROR_OUTOFMEMORY; - data_write_UINT32(out_data + 0, InterfaceId); /* interface */ - /* data_write_UINT32(out_data + 4, 0);*/ /* message id */ - data_write_UINT32(out_data + 8, ADD_DEVICE); /* function id */ - data_write_UINT32(out_data + 12, 0x00000001); /* NumUsbDevice */ - data_write_UINT32(out_data + 16, pdev->get_UsbDevice(pdev)); /* UsbDevice */ - data_write_UINT32(out_data + 20, 0x00000025); /* cchDeviceInstanceId */ - out_offset = fun_device_string_send_set(out_data, out_offset, strInstanceId); - data_write_UINT32(out_data + out_offset, 0x00000036); /* cchHwIds */ - out_offset += 4; + Stream_Write_UINT32(out, InterfaceId); /* interface */ + Stream_Write_UINT32(out, 0); + Stream_Write_UINT32(out, ADD_DEVICE); /* function id */ + Stream_Write_UINT32(out, 0x00000001); /* NumUsbDevice */ + Stream_Write_UINT32(out, pdev->get_UsbDevice(pdev)); /* UsbDevice */ + Stream_Write_UINT32(out, (UINT32)InstanceIdLen + 1); /* cchDeviceInstanceId */ + Stream_Write_UTF16_String_From_Utf8(out, strInstanceId, InstanceIdLen); + Stream_Write_UINT16(out, 0); + Stream_Write_UINT32(out, HardwareIdsLen[0] + HardwareIdsLen[1] + 3); /* cchHwIds */ /* HardwareIds 1 */ - out_offset = fun_device_string_send_set(out_data, out_offset, HardwareIds[0]); - /* HardwareIds 2 */ - out_offset = fun_device_string_send_set(out_data, out_offset, HardwareIds[1]); - /*data_write_UINT16(out_data + out_offset, 0x0000);*/ /* add "\0" */ - out_offset += 2; - data_write_UINT32(out_data + out_offset, cchCompatIds); /* cchCompatIds */ - out_offset += 4; - /* CompatibilityIds 1 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[0]); - /* CompatibilityIds 2 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[1]); - /* CompatibilityIds 3 */ - out_offset = fun_device_string_send_set(out_data, out_offset, CompatibilityIds[2]); + Stream_Write_UTF16_String_From_Utf8(out, HardwareIds[0], HardwareIdsLen[0]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, HardwareIds[1], HardwareIdsLen[1]); + Stream_Write_UINT16(out, 0); + Stream_Write_UINT16(out, 0); /* add "\0" */ + Stream_Write_UINT32(out, (UINT32)cchCompatIds); /* cchCompatIds */ + /* CompatibilityIds */ + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[0], CompatibilityIdLen[0]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[1], CompatibilityIdLen[1]); + Stream_Write_UINT16(out, 0); + Stream_Write_UTF16_String_From_Utf8(out, CompatibilityIds[2], CompatibilityIdLen[2]); + Stream_Write_UINT16(out, 0); if (pdev->isCompositeDevice(pdev)) - out_offset = fun_device_string_send_set(out_data, out_offset, composite_str); + { + Stream_Write_UTF16_String_From_Utf8(out, composite_str, composite_len); + Stream_Write_UINT16(out, 0); + } - /*data_write_UINT16(out_data + out_offset, 0x0000);*/ /* add "\0" */ - out_offset += 2; - data_write_UINT32(out_data + out_offset, 0x00000027); /* cchContainerId */ - out_offset += 4; + Stream_Write_UINT16(out, 0x0000); /* add "\0" */ + Stream_Write_UINT32(out, (UINT32)ContainerIdLen + 1); /* cchContainerId */ /* ContainerId */ - out_offset = fun_device_string_send_set(out_data, out_offset, strContainerId); + Stream_Write_UTF16_String_From_Utf8(out, strContainerId, ContainerIdLen); + Stream_Write_UINT16(out, 0); /* USB_DEVICE_CAPABILITIES 28 bytes */ - data_write_UINT32(out_data + out_offset, 0x0000001c); /* CbSize */ - data_write_UINT32(out_data + out_offset + 4, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ - data_write_UINT32(out_data + out_offset + 8, 0x600); /* USBDI_Version, 0x500 or 0x600 */ + Stream_Write_UINT32(out, 0x0000001c); /* CbSize */ + Stream_Write_UINT32(out, 2); /* UsbBusInterfaceVersion, 0 ,1 or 2 */ // TODO: Get from libusb + Stream_Write_UINT32(out, 0x600); /* USBDI_Version, 0x500 or 0x600 */ // TODO: Get from libusb /* Supported_USB_Version, 0x110,0x110 or 0x200(usb2.0) */ bcdUSB = pdev->query_device_descriptor(pdev, BCD_USB); - data_write_UINT32(out_data + out_offset + 12, bcdUSB); - data_write_UINT32(out_data + out_offset + 16, - 0x00000000); /* HcdCapabilities, MUST always be zero */ + Stream_Write_UINT32(out, bcdUSB); + Stream_Write_UINT32(out, 0x00000000); /* HcdCapabilities, MUST always be zero */ if (bcdUSB < 0x200) - data_write_UINT32(out_data + out_offset + 20, 0x00000000); /* DeviceIsHighSpeed */ + Stream_Write_UINT32(out, 0x00000000); /* DeviceIsHighSpeed */ else - data_write_UINT32(out_data + out_offset + 20, 0x00000001); /* DeviceIsHighSpeed */ + Stream_Write_UINT32(out, 0x00000001); /* DeviceIsHighSpeed */ - data_write_UINT32(out_data + out_offset + 24, - 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */ - out_offset += 28; - ret = callback->channel->Write(callback->channel, out_offset, (BYTE*)out_data, NULL); - zfree(out_data); - return ret; + Stream_Write_UINT32(out, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */ + return stream_write_and_free(callback->plugin, callback->channel, out); } /** @@ -420,23 +373,37 @@ static UINT urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK* callback, IUDEVI * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char* pBuffer, - UINT32 cbSize) +static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, wStream* data) { UINT32 MessageId; UINT32 FunctionId; + UINT32 InterfaceId; UINT error = CHANNEL_RC_OK; - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); + URBDRC_PLUGIN* urbdrc; + + if (!callback || !data || !callback->plugin) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (Stream_GetRemainingLength(data) < 8) + return ERROR_INVALID_DATA; + + Stream_Rewind_UINT32(data); + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); switch (FunctionId) { case RIM_EXCHANGE_CAPABILITY_REQUEST: - error = urbdrc_process_capability_request(callback, pBuffer + 8, cbSize - 8, MessageId); + error = urbdrc_process_capability_request(callback, data, MessageId); + break; + + case RIMCALL_RELEASE: break; default: - WLog_ERR(TAG, "%s: unknown FunctionId 0x%" PRIX32 "", __FUNCTION__, FunctionId); error = ERROR_NOT_FOUND; break; } @@ -444,676 +411,38 @@ static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char return error; } -#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) -static char* devd_get_val(char* buf, size_t buf_size, const char* val_name, size_t val_name_size, - size_t* val_size) +static UINT urbdrc_device_control_channel(URBDRC_CHANNEL_CALLBACK* callback, wStream* s) { - char *ret, *buf_end, *ptr; - buf_end = (buf + buf_size); - - for (ret = buf; ret != NULL && ret < buf_end;) - { - ret = memmem(ret, (buf_end - ret), val_name, val_name_size); - - if (ret == NULL) - return NULL; - - /* Found. */ - /* Check: space before or buf+1. */ - if ((buf + 1) < ret && ret[-1] != ' ') - { - ret += val_name_size; - continue; - } - - /* Check: = after name and size for value. */ - ret += val_name_size; - - if ((ret + 1) >= buf_end) - return NULL; - - if (ret[0] != '=') - continue; - - ret++; - break; - } - - if (ret == NULL || val_size == NULL) - return ret; - - /* Calc value data size. */ - ptr = memchr(ret, ' ', (buf_end - ret)); - - if (ptr == NULL) /* End of string/last value. */ - ptr = buf_end; - - (*val_size) = (ptr - ret); - return ret; -} - -static void* urbdrc_search_usb_device(void* arg) -{ - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*)arg; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)searchman->urbdrc; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; IUDEVMAN* udevman = urbdrc->udevman; - IWTSVirtualChannelManager* channel_mgr = urbdrc->listener_callback->channel_mgr; - IWTSVirtualChannel* dvc_channel; - USB_SEARCHDEV* sdev; - IUDEVICE* pdev; - HANDLE listobj[2]; - HANDLE mon_fd; - int devd_skt; - char buf[4096], *val, *ptr, *end_val; - ssize_t data_size; - size_t val_size, tm; - long idVendor, idProduct; - long busnum, devnum; - int action, success, found, on_close; - struct sockaddr_un sun; - DWORD status; - UINT32 error; - WLog_DBG(TAG, "urbdrc_search_usb_device - devd: start"); - devd_skt = socket(PF_LOCAL, SOCK_SEQPACKET, 0); - - if (devd_skt == -1) - { - WLog_ERR(TAG, "Can't create devd socket: error = %i", errno); - goto err_out; - } - - memset(&sun, 0, sizeof(sun)); - sun.sun_family = PF_LOCAL; - sun.sun_len = sizeof(sun); - strlcpy(sun.sun_path, "/var/run/devd.seqpacket.pipe", sizeof(sun.sun_path)); - - if (-1 == connect(devd_skt, (struct sockaddr*)&sun, sizeof(sun))) - { - WLog_ERR(TAG, "Can't connect devd socket: error = %i - %s", errno, strerror(errno)); - goto err_out; - } - - /* Get the file descriptor (fd) for the monitor. - This fd will get passed to select() */ - mon_fd = CreateFileDescriptorEvent(NULL, TRUE, FALSE, devd_skt, WINPR_FD_READ); - listobj[0] = searchman->term_event; - listobj[1] = mon_fd; - - while (WaitForMultipleObjects(2, listobj, FALSE, INFINITE) != WAIT_OBJECT_0) - { - status = WaitForMultipleObjects(2, listobj, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); - return 0; - } - - if (status == WAIT_OBJECT_0) - break; - - errno = 0; - WLog_DBG(TAG, "======= SEARCH ======= "); - /* !system=USB subsystem=DEVICE type=ATTACH ugen=ugen3.3 cdev=ugen3.3 vendor=0x046d - * product=0x082d devclass=0xef devsubclass=0x02 sernum="6E7D726F" release=0x0011 mode=host - * port=4 parent=ugen3.1 */ - /* !system=USB subsystem=DEVICE type=DETACH ugen=ugen3.3 cdev=ugen3.3 vendor=0x046d - * product=0x082d devclass=0xef devsubclass=0x02 sernum="6E7D726F" release=0x0011 mode=host - * port=4 parent=ugen3.1 */ - data_size = read(devd_skt, buf, (sizeof(buf) - 1)); - - if (data_size == -1) - { - WLog_ERR(TAG, "devd socket read: error = %i", errno); - break; - } - - buf[data_size] = 0; - WLog_DBG(TAG, "devd event: %s", buf); - - if (buf[0] != '!') /* Skeep non notify events. */ - continue; - - /* Check: system=USB */ - val = devd_get_val(buf, data_size, "system", 6, &val_size); - - if (val == NULL || val_size != 3 || memcmp(val, "USB", 3) != 0) - continue; - - /* Check: subsystem=DEVICE */ - val = devd_get_val(buf, data_size, "subsystem", 9, &val_size); - - if (val == NULL || val_size != 6 || memcmp(val, "DEVICE", 6) != 0) - continue; - - /* Get event type. */ - val = devd_get_val(buf, data_size, "type", 4, &val_size); - - if (val == NULL || val_size != 6) - continue; - - action = -1; - - if (memcmp(val, "ATTACH", 6) == 0) - action = 0; - - if (memcmp(val, "DETACH", 6) == 0) - action = 1; - - if (action == -1) - continue; /* Skeep other actions. */ - - /* Get bus and dev num. */ - /* ugen=ugen3.3 */ - val = devd_get_val(buf, data_size, "ugen", 4, &val_size); - - if (val == NULL || val_size < 7 || memcmp(val, "ugen", 4) != 0) - continue; - - val += 4; - val_size -= 4; - ptr = memchr(val, '.', val_size); - - if (ptr == NULL) - continue; - - /* Prepare strings. */ - ptr[0] = 0; - ptr++; - val[val_size] = 0; - /* Extract numbers. */ - busnum = strtol(val, NULL, 0); - - if (errno != 0) - continue; - - devnum = strtol(ptr, NULL, 0); - - if (errno != 0) - continue; - - /* Restore spaces. */ - ptr[-1] = ' '; - val[val_size] = ' '; - /* Handle event. */ - dvc_channel = NULL; - - switch (action) - { - case 0: /* ATTACH */ - sdev = NULL; - success = 0; - found = 0; - /* vendor=0x046d */ - val = devd_get_val(buf, data_size, "vendor", 6, &val_size); - - if (val == NULL || val_size < 1) - continue; - - val[val_size] = 0; - idVendor = strtol(val, NULL, 16); - - if (errno != 0) - continue; - - val[val_size] = ' '; - /* product=0x082d */ - val = devd_get_val(buf, data_size, "product", 7, &val_size); - - if (val == NULL || val_size < 1) - continue; - - val[val_size] = 0; - idProduct = strtol(val, NULL, 16); - - if (errno != 0) - continue; - - val[val_size] = ' '; - WLog_DBG(TAG, "ATTACH: bus: %i, dev: %i, ven: %i, prod: %i", busnum, devnum, - idVendor, idProduct); - dvc_channel = channel_mgr->FindChannelById(channel_mgr, urbdrc->first_channel_id); - searchman->rewind(searchman); - - while (dvc_channel && searchman->has_next(searchman)) - { - sdev = searchman->get_next(searchman); - - if (sdev->idVendor == idVendor && sdev->idProduct == idProduct) - { - WLog_VRB(TAG, "Searchman Found Device: %04" PRIx16 ":%04" PRIx16 "", - sdev->idVendor, sdev->idProduct); - found = 1; - break; - } - } - - if (!found && udevman->isAutoAdd(udevman)) - { - WLog_VRB(TAG, "Auto Find Device: %04x:%04x ", idVendor, idProduct); - found = 2; - } - - if (found) - { - success = - udevman->register_udevice(udevman, busnum, devnum, searchman->UsbDevice, 0, - 0, UDEVMAN_FLAG_ADD_BY_ADDR); - } - - if (success) - { - searchman->UsbDevice++; - usleep(400000); - error = urdbrc_send_virtual_channel_add(dvc_channel, 0); - - if (found == 1) - searchman->remove(searchman, sdev->idVendor, sdev->idProduct); - } - - break; - - case 1: /* DETACH */ - pdev = NULL; - on_close = 0; - WLog_DBG(TAG, "DETACH: bus: %i, dev: %i", busnum, devnum); - usleep(500000); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) - { - pdev = udevman->get_next(udevman); - - if (pdev->get_bus_number(pdev) == busnum && - pdev->get_dev_number(pdev) == devnum) - { - dvc_channel = - channel_mgr->FindChannelById(channel_mgr, pdev->get_channel_id(pdev)); - - if (dvc_channel == NULL) - { - WLog_ERR(TAG, "SEARCH: dvc_channel %d is NULL!!", - pdev->get_channel_id(pdev)); - func_close_udevice(searchman, pdev); - break; - } - - if (!pdev->isSigToEnd(pdev)) - { - dvc_channel->Write(dvc_channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } - - on_close = 1; - break; - } - } - - udevman->loading_unlock(udevman); - usleep(300000); - - if (pdev && on_close && dvc_channel && pdev->isSigToEnd(pdev) && - !(pdev->isChannelClosed(pdev))) - { - dvc_channel->Close(dvc_channel); - } - - break; - } - } - - CloseHandle(mon_fd); -err_out: - close(devd_skt); - sem_post(&searchman->sem_term); - WLog_DBG(TAG, "urbdrc_search_usb_device - devd: end"); - return 0; -} -#endif -#if defined(__linux__) -static void* urbdrc_search_usb_device(void* arg) -{ - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*)arg; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)searchman->urbdrc; - IUDEVMAN* udevman = urbdrc->udevman; - IWTSVirtualChannelManager* channel_mgr; - IWTSVirtualChannel* dvc_channel; - USB_SEARCHDEV* sdev; + IWTSVirtualChannel* channel = callback->channel; IUDEVICE* pdev = NULL; - HANDLE listobj[2]; - HANDLE mon_fd; - int numobj, timeout; - long busnum, devnum; - int success = 0, on_close = 0, found = 0; - WLog_VRB(TAG, ""); - channel_mgr = urbdrc->listener_callback->channel_mgr; - DWORD status; - DWORD dwError; - /* init usb monitor */ - struct udev* udev; - struct udev_device* dev; - struct udev_monitor* mon; - udev = udev_new(); - - if (!udev) - { - WLog_ERR(TAG, "Can't create udev"); - return 0; - } - - /* Set up a monitor to monitor usb devices */ - mon = udev_monitor_new_from_netlink(udev, "udev"); - udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", "usb_device"); - udev_monitor_enable_receiving(mon); - /* Get the file descriptor (fd) for the monitor. - This fd will get passed to select() */ - mon_fd = CreateFileDescriptorEvent(NULL, TRUE, FALSE, udev_monitor_get_fd(mon), WINPR_FD_READ); - - if (!mon_fd) - goto fail_create_monfd_event; - - while (1) - { - WLog_VRB(TAG, "======= SEARCH ======= "); - busnum = 0; - devnum = 0; - sdev = NULL; - pdev = NULL; - dvc_channel = NULL; - on_close = 0; - listobj[0] = searchman->term_event; - listobj[1] = mon_fd; - numobj = 2; - status = WaitForMultipleObjects(numobj, listobj, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - sem_post(&searchman->sem_term); - goto out; - } - - status = WaitForSingleObject(mon_fd, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - dev = udev_monitor_receive_device(mon); - - if (dev) - { - const char* action = udev_device_get_action(dev); - - if (strcmp(action, "add") == 0) - { - long idVendor, idProduct; - success = 0; - found = 0; - idVendor = strtol(udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16); - - if (errno != 0) - continue; - - idProduct = strtol(udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16); - - if (errno != 0) - continue; - - if (idVendor < 0 || idProduct < 0) - { - udev_device_unref(dev); - continue; - } - - busnum = strtol(udev_device_get_property_value(dev, "BUSNUM"), NULL, 10); - - if (errno != 0) - continue; - - devnum = strtol(udev_device_get_property_value(dev, "DEVNUM"), NULL, 10); - - if (errno != 0) - continue; - - dvc_channel = - channel_mgr->FindChannelById(channel_mgr, urbdrc->first_channel_id); - searchman->rewind(searchman); - - while (dvc_channel && searchman->has_next(searchman)) - { - sdev = searchman->get_next(searchman); - - if (sdev->idVendor == idVendor && sdev->idProduct == idProduct) - { - WLog_VRB(TAG, "Searchman Find Device: %04" PRIx16 ":%04" PRIx16 "", - sdev->idVendor, sdev->idProduct); - found = 1; - break; - } - } - - if (!found && udevman->isAutoAdd(udevman)) - { - WLog_VRB(TAG, "Auto Find Device: %04x:%04x ", idVendor, idProduct); - found = 2; - } - - if (found) - { - success = - udevman->register_udevice(udevman, busnum, devnum, searchman->UsbDevice, - 0, 0, UDEVMAN_FLAG_ADD_BY_ADDR); - } - - if (success) - { - searchman->UsbDevice++; - /* when we send the usb device add request, - * we will detach the device driver at same - * time. But, if the time of detach the - * driver and attach driver is too close, - * the system will crash. workaround: we - * wait it for some time to avoid system - * crash. */ - listobj[0] = searchman->term_event; - numobj = 1; - timeout = 4000; /* milliseconds */ - status = WaitForMultipleObjects(numobj, listobj, FALSE, timeout); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", - dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", - dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - CloseHandle(mon_fd); - sem_post(&searchman->sem_term); - return 0; - } - - urdbrc_send_virtual_channel_add(dvc_channel, 0); - - if (found == 1) - searchman->remove(searchman, sdev->idVendor, sdev->idProduct); - } - } - else if (strcmp(action, "remove") == 0) - { - busnum = strtol(udev_device_get_property_value(dev, "BUSNUM"), NULL, 0); - - if (errno != 0) - goto out; - - devnum = strtol(udev_device_get_property_value(dev, "DEVNUM"), NULL, 0); - - if (errno != 0) - goto out; - - usleep(500000); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) - { - pdev = udevman->get_next(udevman); - - if (pdev->get_bus_number(pdev) == busnum && - pdev->get_dev_number(pdev) == devnum) - { - dvc_channel = channel_mgr->FindChannelById(channel_mgr, - pdev->get_channel_id(pdev)); - - if (dvc_channel == NULL) - { - WLog_ERR(TAG, "SEARCH: dvc_channel %d is NULL!!", - pdev->get_channel_id(pdev)); - func_close_udevice(searchman, pdev); - break; - } - - if (!pdev->isSigToEnd(pdev)) - { - dvc_channel->Write(dvc_channel, 0, NULL, NULL); - pdev->SigToEnd(pdev); - } - - on_close = 1; - break; - } - } - - udevman->loading_unlock(udevman); - listobj[0] = searchman->term_event; - numobj = 1; - timeout = 3000; /* milliseconds */ - status = WaitForMultipleObjects(numobj, listobj, FALSE, timeout); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", - dwError); - goto out; - } - - status = WaitForSingleObject(searchman->term_event, 0); - - if (status == WAIT_FAILED) - { - dwError = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", - dwError); - goto out; - } - - if (status == WAIT_OBJECT_0) - { - CloseHandle(mon_fd); - sem_post(&searchman->sem_term); - return 0; - } - - if (pdev && on_close && dvc_channel && pdev->isSigToEnd(pdev) && - !(pdev->isChannelClosed(pdev))) - { - on_close = 0; - dvc_channel->Close(dvc_channel); - } - } - - udev_device_unref(dev); - } - else - { - WLog_ERR(TAG, "No Device from receive_device(). An error occurred."); - } - } - } - -out: - CloseHandle(mon_fd); -fail_create_monfd_event: - sem_post(&searchman->sem_term); - return 0; -} -#endif - -void* urbdrc_new_device_create(void* arg) -{ - TRANSFER_DATA* transfer_data = (TRANSFER_DATA*)arg; - URBDRC_CHANNEL_CALLBACK* callback = transfer_data->callback; - IWTSVirtualChannelManager* channel_mgr; - URBDRC_PLUGIN* urbdrc = transfer_data->urbdrc; - USB_SEARCHMAN* searchman = urbdrc->searchman; - BYTE* pBuffer = transfer_data->pBuffer; - IUDEVMAN* udevman = transfer_data->udevman; - IUDEVICE* pdev = NULL; - UINT32 ChannelId = 0; - UINT32 MessageId; - UINT32 FunctionId; - int i = 0, found = 0; - WLog_DBG(TAG, "..."); - channel_mgr = urbdrc->listener_callback->channel_mgr; - ChannelId = channel_mgr->GetChannelId(callback->channel); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); - int error = 0; + UINT32 i = 0; + BOOL found = FALSE; + UINT error = ERROR_INTERNAL_ERROR; + UINT32 channelId = callback->channel_mgr->GetChannelId(channel); switch (urbdrc->vchannel_status) { case INIT_CHANNEL_IN: - urbdrc->first_channel_id = ChannelId; - - if (!searchman->start(searchman, urbdrc_search_usb_device)) - { - WLog_ERR(TAG, "unable to start searchman thread"); - return 0; - } + /* Control channel was established */ + error = ERROR_SUCCESS; + udevman->initialize(udevman, channelId); for (i = 0; i < udevman->get_device_num(udevman); i++) - error = urdbrc_send_virtual_channel_add(callback->channel, MessageId); + { + error = urdbrc_send_virtual_channel_add(callback->plugin, callback->channel, i); + + if (error != ERROR_SUCCESS) + goto fail; + } urbdrc->vchannel_status = INIT_CHANNEL_OUT; break; case INIT_CHANNEL_OUT: + /* A new device channel was created, add the channel + * to the device */ udevman->loading_lock(udevman); udevman->rewind(udevman); @@ -1123,35 +452,31 @@ void* urbdrc_new_device_create(void* arg) if (!pdev->isAlreadySend(pdev)) { - found = 1; + const UINT32 channelID = callback->channel_mgr->GetChannelId(channel); + found = TRUE; pdev->setAlreadySend(pdev); - pdev->set_channel_id(pdev, ChannelId); + pdev->set_channelManager(pdev, callback->channel_mgr); + pdev->set_channelID(pdev, channelID); break; } } udevman->loading_unlock(udevman); + error = ERROR_SUCCESS; if (found && pdev->isAlreadySend(pdev)) - { - /* when we send the usb device add request, we will detach - * the device driver at same time. But, if the time of detach the - * driver and attach driver is too close, the system will crash. - * workaround: we wait it for some time to avoid system crash. */ - error = pdev->wait_for_detach(pdev); - - if (error >= 0) - urdbrc_send_usb_device_add(callback, pdev); - } + error = urdbrc_send_usb_device_add(callback, pdev); break; default: - WLog_ERR(TAG, "vchannel_status unknown value %" PRIu32 "", urbdrc->vchannel_status); + WLog_Print(urbdrc->log, WLOG_ERROR, "vchannel_status unknown value %" PRIu32 "", + urbdrc->vchannel_status); break; } - return 0; +fail: + return error; } /** @@ -1159,63 +484,45 @@ void* urbdrc_new_device_create(void* arg) * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback, char* pBuffer, - UINT32 cbSize) +static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callback, wStream* data) { - UINT32 i; UINT32 MessageId; UINT32 FunctionId; + UINT32 InterfaceId; UINT error = CHANNEL_RC_OK; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; - WLog_DBG(TAG, "..."); - data_read_UINT32(pBuffer + 0, MessageId); - data_read_UINT32(pBuffer + 4, FunctionId); + URBDRC_PLUGIN* urbdrc; + + if (!callback || !data) + return ERROR_INVALID_PARAMETER; + + urbdrc = (URBDRC_PLUGIN*)callback->plugin; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + + if (Stream_GetRemainingLength(data) < 8) + return ERROR_INVALID_DATA; + + Stream_Rewind(data, 4); + Stream_Read_UINT32(data, InterfaceId); + Stream_Read_UINT32(data, MessageId); + Stream_Read_UINT32(data, FunctionId); + WLog_Print(urbdrc->log, WLOG_TRACE, "%s [%" PRIu32 "]", + call_to_string(FALSE, InterfaceId, FunctionId), FunctionId); switch (FunctionId) { case CHANNEL_CREATED: - error = urbdrc_process_channel_create(callback, pBuffer + 8, cbSize - 8, MessageId); + error = urbdrc_process_channel_create(callback, data, MessageId); break; case RIMCALL_RELEASE: - WLog_VRB(TAG, "recv RIMCALL_RELEASE"); - pthread_t thread; - TRANSFER_DATA* transfer_data; - transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); - - if (!transfer_data) - return ERROR_OUTOFMEMORY; - - transfer_data->callback = callback; - transfer_data->urbdrc = urbdrc; - transfer_data->udevman = urbdrc->udevman; - transfer_data->urbdrc = urbdrc; - transfer_data->cbSize = cbSize; - transfer_data->pBuffer = (BYTE*)malloc((cbSize)); - - if (!transfer_data->pBuffer) - { - free(transfer_data); - return ERROR_OUTOFMEMORY; - } - - for (i = 0; i < (cbSize); i++) - { - transfer_data->pBuffer[i] = pBuffer[i]; - } - - if (pthread_create(&thread, 0, urbdrc_new_device_create, transfer_data) != 0) - { - free(transfer_data->pBuffer); - free(transfer_data); - return ERROR_INVALID_OPERATION; - } - - pthread_detach(thread); + error = urbdrc_device_control_channel(callback, data); break; default: - WLog_VRB(TAG, "%s: unknown FunctionId 0x%" PRIX32 "", __FUNCTION__, FunctionId); + WLog_Print(urbdrc->log, WLOG_TRACE, "%s: unknown FunctionId 0x%" PRIX32 "", + __FUNCTION__, FunctionId); error = 1; break; } @@ -1233,88 +540,46 @@ static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*)pChannelCallback; URBDRC_PLUGIN* urbdrc; IUDEVMAN* udevman; - UINT32 InterfaceTemp; UINT32 InterfaceId; - UINT32 Mask; - UINT error = CHANNEL_RC_OK; - char* pBuffer = (char*)Stream_Pointer(data); - UINT32 cbSize = Stream_GetRemainingLength(data); + UINT error = ERROR_INTERNAL_ERROR; if (callback == NULL) - return 0; + return ERROR_INVALID_PARAMETER; if (callback->plugin == NULL) - return 0; + return error; urbdrc = (URBDRC_PLUGIN*)callback->plugin; if (urbdrc->udevman == NULL) - return 0; + return error; udevman = (IUDEVMAN*)urbdrc->udevman; - data_read_UINT32(pBuffer + 0, InterfaceTemp); - InterfaceId = (InterfaceTemp & 0x0fffffff); - Mask = ((InterfaceTemp & 0xf0000000) >> 30); - WLog_VRB(TAG, "Size=%" PRIu32 " InterfaceId=0x%" PRIX32 " Mask=0x%" PRIX32 "", cbSize, - InterfaceId, Mask); + if (Stream_GetRemainingLength(data) < 12) + return ERROR_INVALID_DATA; + + urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data); + Stream_Read_UINT32(data, InterfaceId); + + /* Need to check InterfaceId and mask values */ switch (InterfaceId) { - case CAPABILITIES_NEGOTIATOR: - error = urbdrc_exchange_capabilities(callback, pBuffer + 4, cbSize - 4); + case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30): + error = urbdrc_exchange_capabilities(callback, data); break; - case SERVER_CHANNEL_NOTIFICATION: - error = urbdrc_process_channel_notification(callback, pBuffer + 4, cbSize - 4); + case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30): + error = urbdrc_process_channel_notification(callback, data); break; default: - WLog_VRB(TAG, "InterfaceId 0x%" PRIX32 " Start matching devices list", InterfaceId); - pthread_t thread; - TRANSFER_DATA* transfer_data; - transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); - - if (!transfer_data) - { - WLog_ERR(TAG, "transfer_data is NULL!!"); - return ERROR_OUTOFMEMORY; - } - - transfer_data->callback = callback; - transfer_data->urbdrc = urbdrc; - transfer_data->udevman = udevman; - transfer_data->cbSize = cbSize - 4; - transfer_data->UsbDevice = InterfaceId; - transfer_data->pBuffer = (BYTE*)malloc((cbSize - 4)); - - if (!transfer_data->pBuffer) - { - free(transfer_data); - return ERROR_OUTOFMEMORY; - } - - memcpy(transfer_data->pBuffer, pBuffer + 4, (cbSize - 4)); - /* To ensure that not too many urb requests at the same time */ - udevman->wait_urb(udevman); -#if ISOCH_FIFO - /* lock isoch mutex */ - func_lock_isoch_mutex(transfer_data); -#endif - error = pthread_create(&thread, 0, urbdrc_process_udev_data_transfer, transfer_data); - - if (error != 0) - { - WLog_ERR(TAG, "Create Data Transfer Thread got error = %" PRIu32 "", error); - free(transfer_data->pBuffer); - free(transfer_data); - return ERROR_INVALID_OPERATION; - } - - pthread_detach(thread); + error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data); + error = ERROR_SUCCESS; /* Ignore errors, the device may have been unplugged. */ break; } - return 0; + return error; } /** @@ -1325,38 +590,13 @@ static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback) { URBDRC_CHANNEL_CALLBACK* callback = (URBDRC_CHANNEL_CALLBACK*)pChannelCallback; - URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; - IUDEVMAN* udevman = (IUDEVMAN*)urbdrc->udevman; - USB_SEARCHMAN* searchman = (USB_SEARCHMAN*)urbdrc->searchman; - IUDEVICE* pdev = NULL; - UINT32 ChannelId = 0; - int found = 0; - ChannelId = callback->channel_mgr->GetChannelId(callback->channel); - WLog_INFO(TAG, "urbdrc_on_close: channel id %" PRIu32 "", ChannelId); - udevman->loading_lock(udevman); - udevman->rewind(udevman); - - while (udevman->has_next(udevman)) + if (callback) { - pdev = udevman->get_next(udevman); - - if (pdev->get_channel_id(pdev) == ChannelId) - { - found = 1; - break; - } + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)callback->plugin; + if (urbdrc) + urbdrc->status |= URBDRC_DEVICE_CHANNEL_CLOSED; } - - udevman->loading_unlock(udevman); - - if (found && pdev && !(pdev->isChannelClosed(pdev))) - { - pdev->setChannelClosed(pdev); - func_close_udevice(searchman, pdev); - } - - zfree(callback); - WLog_DBG(TAG, "success"); + free(callback); return CHANNEL_RC_OK; } @@ -1372,7 +612,10 @@ static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCall { URBDRC_LISTENER_CALLBACK* listener_callback = (URBDRC_LISTENER_CALLBACK*)pListenerCallback; URBDRC_CHANNEL_CALLBACK* callback; - WLog_VRB(TAG, ""); + + if (!ppCallback) + return ERROR_INVALID_PARAMETER; + callback = (URBDRC_CHANNEL_CALLBACK*)calloc(1, sizeof(URBDRC_CHANNEL_CALLBACK)); if (!callback) @@ -1397,7 +640,11 @@ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; IUDEVMAN* udevman = NULL; USB_SEARCHMAN* searchman = NULL; - WLog_VRB(TAG, ""); + char channelName[sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME }; + + if (!urbdrc) + return ERROR_INVALID_PARAMETER; + urbdrc->listener_callback = (URBDRC_LISTENER_CALLBACK*)calloc(1, sizeof(URBDRC_LISTENER_CALLBACK)); @@ -1419,8 +666,10 @@ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana } urbdrc->searchman = searchman; - return pChannelMgr->CreateListener(pChannelMgr, "URBDRC", 0, - (IWTSListenerCallback*)urbdrc->listener_callback, NULL); + /* [MS-RDPEUSB] 2.1 Transport defines the channel name in uppercase letters */ + CharUpperA(channelName); + return pChannelMgr->CreateListener(pChannelMgr, channelName, 0, + &urbdrc->listener_callback->iface, NULL); } /** @@ -1431,24 +680,18 @@ static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelMana static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin) { URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; - IUDEVMAN* udevman = urbdrc->udevman; - USB_SEARCHMAN* searchman = urbdrc->searchman; - WLog_VRB(TAG, ""); + IUDEVMAN* udevman; + USB_SEARCHMAN* searchman; + + if (!urbdrc) + return ERROR_INVALID_DATA; + + udevman = urbdrc->udevman; + searchman = urbdrc->searchman; if (searchman) { /* close searchman */ - searchman->close(searchman); - - /* free searchman */ - if (searchman->started) - { - struct timespec ts; - ts.tv_sec = time(NULL) + 10; - ts.tv_nsec = 0; - sem_timedwait(&searchman->sem_term, &ts); - } - searchman->free(searchman); searchman = NULL; } @@ -1459,27 +702,25 @@ static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin) udevman = NULL; } - if (urbdrc->listener_callback) - zfree(urbdrc->listener_callback); - - if (urbdrc) - zfree(urbdrc); - + free(urbdrc->subsystem); + free(urbdrc->listener_callback); + free(urbdrc); return CHANNEL_RC_OK; } -static void urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman) +static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman) { URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; if (urbdrc->udevman) { - WLog_ERR(TAG, "existing device, abort."); - return; + WLog_Print(urbdrc->log, WLOG_ERROR, "existing device, abort."); + return FALSE; } DEBUG_DVC("device registered."); urbdrc->udevman = udevman; + return TRUE; } /** @@ -1487,12 +728,13 @@ static void urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, const char* name, ADDIN_ARGV* args) +static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name, ADDIN_ARGV* args) { + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)pPlugin; PFREERDP_URBDRC_DEVICE_ENTRY entry; FREERDP_URBDRC_SERVICE_ENTRY_POINTS entryPoints; - entry = (PFREERDP_URBDRC_DEVICE_ENTRY)freerdp_load_channel_addin_entry("urbdrc", (LPSTR)name, - NULL, 0); + entry = (PFREERDP_URBDRC_DEVICE_ENTRY)freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, + name, NULL, 0); if (!entry) return ERROR_INVALID_OPERATION; @@ -1503,14 +745,14 @@ static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, const char* name, ADD if (entry(&entryPoints) != 0) { - WLog_ERR(TAG, "%s entry returns error.", name); + WLog_Print(urbdrc->log, WLOG_ERROR, "%s entry returns error.", name); return ERROR_INVALID_OPERATION; } return CHANNEL_RC_OK; } -BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, char* subsystem) +static BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, const char* subsystem) { free(urbdrc->subsystem); urbdrc->subsystem = _strdup(subsystem); @@ -1522,17 +764,18 @@ BOOL urbdrc_set_subsystem(URBDRC_PLUGIN* urbdrc, char* subsystem) * * @return 0 on success, otherwise a Win32 error code */ -static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) +static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, const ADDIN_ARGV* args) { int status; - DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; COMMAND_LINE_ARGUMENT_A urbdrc_args[] = { { "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" }, { "sys", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "subsystem" }, { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; - flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON; + + const DWORD flags = + COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + COMMAND_LINE_ARGUMENT_A* arg; status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL); @@ -1548,7 +791,7 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg") { - WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE); + WLog_SetLogLevel(urbdrc->log, WLOG_TRACE); } CommandLineSwitchCase(arg, "sys") { @@ -1564,6 +807,108 @@ static UINT urbdrc_process_addin_args(URBDRC_PLUGIN* urbdrc, ADDIN_ARGV* args) return CHANNEL_RC_OK; } +BOOL add_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct) +{ + USB_SEARCHDEV* sdev = NULL; + size_t success = 0; + BOOL found = FALSE; + URBDRC_PLUGIN* urbdrc; + USB_SEARCHMAN* searchman; + + if (!idevman) + return FALSE; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; + + if (!urbdrc || !urbdrc->listener_callback) + return FALSE; + + searchman = urbdrc->searchman; + + if (!searchman) + return FALSE; + + searchman->rewind(searchman); + + while (searchman->has_next(searchman)) + { + USB_SEARCHDEV* dev = searchman->get_next(searchman); + + if (dev->idVendor == idVendor && dev->idProduct == idProduct) + { + WLog_Print(urbdrc->log, WLOG_TRACE, + "Searchman Find Device: %04" PRIx16 ":%04" PRIx16 "", dev->idVendor, + dev->idProduct); + found = TRUE; + sdev = dev; + break; + } + } + + if (!found && idevman->isAutoAdd(idevman)) + { + WLog_Print(urbdrc->log, WLOG_TRACE, "Auto Find Device: %04x:%04x ", idVendor, idProduct); + found = TRUE; + } + + if (found) + { + success = idevman->register_udevice(idevman, busnum, devnum, searchman->UsbDevice, 0, 0, + UDEVMAN_FLAG_ADD_BY_ADDR); + } + + if (success) + { + searchman->UsbDevice++; + urdbrc_send_virtual_channel_add(idevman->plugin, get_channel(idevman), + 5 + searchman->UsbDevice); + + if (found && sdev) + searchman->remove(searchman, sdev->idVendor, sdev->idProduct); + } + + return TRUE; +} + +BOOL del_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct) +{ + IUDEVICE* pdev = NULL; + URBDRC_PLUGIN* urbdrc; + USB_SEARCHMAN* searchman; + + if (!idevman) + return FALSE; + + urbdrc = (URBDRC_PLUGIN*)idevman->plugin; + + if (!urbdrc || !urbdrc->listener_callback) + return FALSE; + + searchman = urbdrc->searchman; + + if (!searchman) + return FALSE; + + idevman->loading_lock(idevman); + idevman->rewind(idevman); + + while (idevman->has_next(idevman)) + { + IUDEVICE* dev = idevman->get_next(idevman); + + if (dev->get_bus_number(dev) == busnum && dev->get_dev_number(dev) == devnum) + { + pdev = dev; + break; + } + } + + if (pdev) + pdev->setChannelClosed(pdev); + + idevman->loading_unlock(idevman); + return TRUE; +} #ifdef BUILTIN_CHANNELS #define DVCPluginEntry urbdrc_DVCPluginEntry #else @@ -1580,7 +925,7 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) UINT status = 0; ADDIN_ARGV* args; URBDRC_PLUGIN* urbdrc; - urbdrc = (URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "urbdrc"); + urbdrc = (URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME); args = pEntryPoints->GetPluginData(pEntryPoints); if (urbdrc == NULL) @@ -1591,35 +936,56 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_NO_MEMORY; urbdrc->iface.Initialize = urbdrc_plugin_initialize; - urbdrc->iface.Connected = NULL; - urbdrc->iface.Disconnected = NULL; urbdrc->iface.Terminated = urbdrc_plugin_terminated; - urbdrc->searchman = NULL; urbdrc->vchannel_status = INIT_CHANNEL_IN; - status = pEntryPoints->RegisterPlugin(pEntryPoints, "urbdrc", (IWTSPlugin*)urbdrc); + status = + pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, (IWTSPlugin*)urbdrc); if (status != CHANNEL_RC_OK) - goto error_register; + goto fail; + + urbdrc->log = WLog_Get(TAG); + + if (!urbdrc->log) + goto fail; } status = urbdrc_process_addin_args(urbdrc, args); if (status != CHANNEL_RC_OK) - { - /* TODO: we should unregister the plugin ? */ - WLog_ERR(TAG, "error processing arguments"); - // return status; - } + goto fail; if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc, "libusb")) - { - /* TODO: we should unregister the plugin ? */ - WLog_ERR(TAG, "error setting subsystem"); - return ERROR_OUTOFMEMORY; - } + goto fail; return urbdrc_load_udevman_addin((IWTSPlugin*)urbdrc, urbdrc->subsystem, args); -error_register: - free(urbdrc); +fail: + urbdrc_plugin_terminated(&urbdrc->iface); return status; } + +UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* out) +{ + UINT rc; + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*)plugin; + + if (!out) + return ERROR_INVALID_PARAMETER; + + if (!channel || !out || !urbdrc) + { + Stream_Free(out, TRUE); + return ERROR_INVALID_PARAMETER; + } + + if (!channel->Write) + { + Stream_Free(out, TRUE); + return ERROR_INTERNAL_ERROR; + } + + urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out); + rc = channel->Write(channel, Stream_GetPosition(out), Stream_Buffer(out), NULL); + Stream_Free(out, TRUE); + return rc; +} diff --git a/channels/urbdrc/client/urbdrc_main.h b/channels/urbdrc/client/urbdrc_main.h index e76ef4024..1ffc8f739 100644 --- a/channels/urbdrc/client/urbdrc_main.h +++ b/channels/urbdrc/client/urbdrc_main.h @@ -21,14 +21,26 @@ #ifndef FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H #define FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H +#include +#include + #include "searchman.h" -#include "isoch_queue.h" #define DEVICE_HARDWARE_ID_SIZE 32 #define DEVICE_COMPATIBILITY_ID_SIZE 36 #define DEVICE_INSTANCE_STR_SIZE 37 #define DEVICE_CONTAINER_STR_SIZE 39 +#define TAG CHANNELS_TAG("urbdrc.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif + typedef struct _IUDEVICE IUDEVICE; typedef struct _IUDEVMAN IUDEVMAN; @@ -71,13 +83,14 @@ struct _URBDRC_PLUGIN IUDEVMAN* udevman; USB_SEARCHMAN* searchman; - UINT32 first_channel_id; UINT32 vchannel_status; char* subsystem; + + UINT32 status; + wLog* log; }; -typedef void (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman); - +typedef BOOL (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman); struct _FREERDP_URBDRC_SERVICE_ENTRY_POINTS { IWTSPlugin* plugin; @@ -96,27 +109,34 @@ struct _TRANSFER_DATA URBDRC_CHANNEL_CALLBACK* callback; URBDRC_PLUGIN* urbdrc; IUDEVMAN* udevman; - BYTE* pBuffer; - UINT32 cbSize; - UINT32 UsbDevice; + IWTSVirtualChannel* channel; + wStream* s; }; +typedef void (*t_isoch_transfer_cb)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, wStream* out, + UINT32 InterfaceId, BOOL noAck, UINT32 MessageId, + UINT32 RequestId, UINT32 NumberOfPackets, UINT32 status, + UINT32 StartFrame, UINT32 ErrorCount, UINT32 OutputBufferSize); + struct _IUDEVICE { /* Transfer */ - int (*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); + int (*isoch_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, UINT32 MessageId, + UINT32 RequestId, UINT32 EndpointAddress, UINT32 TransferFlags, + UINT32 StartFrame, UINT32 ErrorCount, BOOL NoAck, + const BYTE* packetDescriptorData, UINT32 NumberOfPackets, + UINT32 BufferSize, const BYTE* Buffer, t_isoch_transfer_cb cb, + UINT32 Timeout); - int (*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); + BOOL(*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 (*bulk_or_interrupt_transfer)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, - UINT32 TransferFlags, UINT32* UsbdStatus, UINT32* BufferSize, - BYTE* Buffer, UINT32 Timeout); + int (*bulk_or_interrupt_transfer)(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* callback, + UINT32 MessageId, UINT32 RequestId, UINT32 EndpointAddress, + UINT32 TransferFlags, BOOL NoAck, UINT32 BufferSize, + t_isoch_transfer_cb cb, UINT32 Timeout); int (*select_configuration)(IUDEVICE* idev, UINT32 bConfigurationValue); @@ -125,8 +145,8 @@ struct _IUDEVICE int (*control_pipe_request)(IUDEVICE* idev, UINT32 RequestId, UINT32 EndpointAddress, UINT32* UsbdStatus, int command); - int (*control_query_device_text)(IUDEVICE* idev, UINT32 TextType, UINT32 LocaleId, - UINT32* BufferSize, BYTE* Buffer); + UINT32(*control_query_device_text) + (IUDEVICE* idev, UINT32 TextType, UINT16 LocaleId, UINT8* BufferSize, BYTE* Buffer); int (*os_feature_descriptor_request)(IUDEVICE* idev, UINT32 RequestId, BYTE Recipient, BYTE InterfaceNumber, BYTE Ms_PageIndex, @@ -139,56 +159,43 @@ struct _IUDEVICE int (*query_device_descriptor)(IUDEVICE* idev, int offset); - void (*detach_kernel_driver)(IUDEVICE* idev); + BOOL (*detach_kernel_driver)(IUDEVICE* idev); - void (*attach_kernel_driver)(IUDEVICE* idev); - - int (*wait_action_completion)(IUDEVICE* idev); - - void (*push_action)(IUDEVICE* idev); - - void (*complete_action)(IUDEVICE* idev); + BOOL (*attach_kernel_driver)(IUDEVICE* idev); /* Wait for 5 sec */ - int (*wait_for_detach)(IUDEVICE* idev); - - /* FIXME: Currently this is a way of stupid, SHOULD to improve it. - * Isochronous transfer must to FIFO */ - void (*lock_fifo_isoch)(IUDEVICE* idev); - void (*unlock_fifo_isoch)(IUDEVICE* idev); + BOOL (*wait_for_detach)(IUDEVICE* idev); int (*query_device_port_status)(IUDEVICE* idev, UINT32* UsbdStatus, UINT32* BufferSize, BYTE* Buffer); - int (*request_queue_is_none)(IUDEVICE* idev); - MSUSB_CONFIG_DESCRIPTOR* (*complete_msconfig_setup)(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsConfig); /* Basic state */ int (*isCompositeDevice)(IUDEVICE* idev); - int (*isSigToEnd)(IUDEVICE* idev); + int (*isExist)(IUDEVICE* idev); int (*isAlreadySend)(IUDEVICE* idev); int (*isChannelClosed)(IUDEVICE* idev); - void (*SigToEnd)(IUDEVICE* idev); + void (*setAlreadySend)(IUDEVICE* idev); void (*setChannelClosed)(IUDEVICE* idev); char* (*getPath)(IUDEVICE* idev); - BASIC_DEV_STATE_DEFINED(channel_id, UINT32); + void (*free)(IUDEVICE* idev); + + BASIC_DEV_STATE_DEFINED(channelManager, IWTSVirtualChannelManager*); + BASIC_DEV_STATE_DEFINED(channelID, UINT32); BASIC_DEV_STATE_DEFINED(UsbDevice, UINT32); BASIC_DEV_STATE_DEFINED(ReqCompletion, UINT32); - BASIC_DEV_STATE_DEFINED(bus_number, UINT16); - BASIC_DEV_STATE_DEFINED(dev_number, UINT16); + BASIC_DEV_STATE_DEFINED(bus_number, BYTE); + BASIC_DEV_STATE_DEFINED(dev_number, BYTE); BASIC_DEV_STATE_DEFINED(port_number, int); - BASIC_DEV_STATE_DEFINED(isoch_queue, void*); BASIC_DEV_STATE_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR*); BASIC_DEV_STATE_DEFINED(p_udev, void*); BASIC_DEV_STATE_DEFINED(p_prev, void*); BASIC_DEV_STATE_DEFINED(p_next, void*); - - /* Control semaphore or mutex lock */ }; struct _IUDEVMAN @@ -198,13 +205,12 @@ struct _IUDEVMAN /* Manage devices */ void (*rewind)(IUDEVMAN* idevman); - int (*has_next)(IUDEVMAN* idevman); - int (*unregister_udevice)(IUDEVMAN* idevman, int bus_number, int dev_number); - int (*register_udevice)(IUDEVMAN* idevman, int bus_number, int dev_number, int UsbDevice, - UINT16 idVendor, UINT16 idProduct, int flag); + BOOL (*has_next)(IUDEVMAN* idevman); + BOOL (*unregister_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number); + size_t (*register_udevice)(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number, + UINT32 UsbDevice, UINT16 idVendor, UINT16 idProduct, int flag); IUDEVICE* (*get_next)(IUDEVMAN* idevman); IUDEVICE* (*get_udevice_by_UsbDevice)(IUDEVMAN* idevman, UINT32 UsbDevice); - IUDEVICE* (*get_udevice_by_UsbDevice_try_again)(IUDEVMAN* idevman, UINT32 UsbDevice); /* Extension */ int (*check_device_exist_by_id)(IUDEVMAN* idevman, UINT16 idVendor, UINT16 idProduct); @@ -212,14 +218,20 @@ struct _IUDEVMAN /* Basic state */ BASIC_DEVMAN_STATE_DEFINED(defUsbDevice, UINT32); - BASIC_DEVMAN_STATE_DEFINED(device_num, int); + BASIC_DEVMAN_STATE_DEFINED(device_num, UINT32); BASIC_DEVMAN_STATE_DEFINED(sem_timeout, int); /* control semaphore or mutex lock */ void (*loading_lock)(IUDEVMAN* idevman); void (*loading_unlock)(IUDEVMAN* idevman); - void (*push_urb)(IUDEVMAN* idevman); - void (*wait_urb)(IUDEVMAN* idevman); + BOOL (*initialize)(IUDEVMAN* idevman, UINT32 channelId); + + IWTSPlugin* plugin; + UINT32 controlChannelId; }; +BOOL add_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct); +BOOL del_device(IUDEVMAN* idevman, BYTE busnum, BYTE devnum, UINT16 idVendor, UINT16 idProduct); + +UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel, wStream* s); #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_MAIN_H */ diff --git a/channels/urbdrc/common/CMakeLists.txt b/channels/urbdrc/common/CMakeLists.txt new file mode 100644 index 000000000..0e7b448be --- /dev/null +++ b/channels/urbdrc/common/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2019 Armin Novak +# Copyright 2019 Thincast Technologies GmbH +# +# 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. + +set(SRCS + urbdrc_types.h + urbdrc_helpers.h + urbdrc_helpers.c + msusb.h + msusb.c) + +add_library(urbdrc-common OBJECT ${SRCS}) diff --git a/channels/urbdrc/common/msusb.c b/channels/urbdrc/common/msusb.c new file mode 100644 index 000000000..45c677370 --- /dev/null +++ b/channels/urbdrc/common/msusb.c @@ -0,0 +1,402 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX USB Redirection + * + * Copyright 2012 Atrust corp. + * Copyright 2012 Alfred Liu + * + * 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 +#include +#include + +#include +#include + +#define TAG FREERDP_TAG("utils") + +static MSUSB_PIPE_DESCRIPTOR* msusb_mspipe_new() +{ + return (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR)); +} + +static void msusb_mspipes_free(MSUSB_PIPE_DESCRIPTOR** MsPipes, UINT32 NumberOfPipes) +{ + UINT32 pnum = 0; + + if (MsPipes) + { + for (pnum = 0; pnum < NumberOfPipes && MsPipes[pnum]; pnum++) + free(MsPipes[pnum]); + + free(MsPipes); + } +} + +BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, + MSUSB_PIPE_DESCRIPTOR** NewMsPipes, UINT32 NewNumberOfPipes) +{ + if (!MsInterface || !NewMsPipes) + return FALSE; + + /* free orignal MsPipes */ + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + /* And replace it */ + MsInterface->MsPipes = NewMsPipes; + MsInterface->NumberOfPipes = NewNumberOfPipes; + return TRUE; +} + +static MSUSB_PIPE_DESCRIPTOR** msusb_mspipes_read(wStream* s, UINT32 NumberOfPipes) +{ + UINT32 pnum; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + + if (Stream_GetRemainingCapacity(s) < 12 * NumberOfPipes) + return NULL; + + MsPipes = (MSUSB_PIPE_DESCRIPTOR**)calloc(NumberOfPipes, sizeof(MSUSB_PIPE_DESCRIPTOR*)); + + if (!MsPipes) + return NULL; + + for (pnum = 0; pnum < NumberOfPipes; pnum++) + { + MSUSB_PIPE_DESCRIPTOR* MsPipe = msusb_mspipe_new(); + + if (!MsPipe) + goto out_error; + + Stream_Read_UINT16(s, MsPipe->MaximumPacketSize); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, MsPipe->MaximumTransferSize); + Stream_Read_UINT32(s, MsPipe->PipeFlags); + /* Already set to zero by memset + MsPipe->PipeHandle = 0; + MsPipe->bEndpointAddress = 0; + MsPipe->bInterval = 0; + MsPipe->PipeType = 0; + MsPipe->InitCompleted = 0; + */ + MsPipes[pnum] = MsPipe; + } + + return MsPipes; +out_error: + + for (pnum = 0; pnum < NumberOfPipes; pnum++) + free(MsPipes[pnum]); + + free(MsPipes); + return NULL; +} + +static MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_new() +{ + return (MSUSB_INTERFACE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_INTERFACE_DESCRIPTOR)); +} + +static void msusb_msinterface_free(MSUSB_INTERFACE_DESCRIPTOR* MsInterface) +{ + if (MsInterface) + { + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + MsInterface->MsPipes = NULL; + free(MsInterface); + } +} + +static void msusb_msinterface_free_list(MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces, + UINT32 NumInterfaces) +{ + UINT32 inum = 0; + + if (MsInterfaces) + { + for (inum = 0; inum < NumInterfaces; inum++) + { + msusb_msinterface_free(MsInterfaces[inum]); + } + + free(MsInterfaces); + } +} + +BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, BYTE InterfaceNumber, + MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface) +{ + if (!MsConfig || !MsConfig->MsInterfaces) + return FALSE; + + msusb_msinterface_free(MsConfig->MsInterfaces[InterfaceNumber]); + MsConfig->MsInterfaces[InterfaceNumber] = NewMsInterface; + return TRUE; +} + +MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* s) +{ + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + + if (Stream_GetRemainingCapacity(s) < 12) + return NULL; + + MsInterface = msusb_msinterface_new(); + + if (!MsInterface) + return NULL; + + Stream_Read_UINT16(s, MsInterface->Length); + Stream_Read_UINT16(s, MsInterface->NumberOfPipesExpected); + Stream_Read_UINT8(s, MsInterface->InterfaceNumber); + Stream_Read_UINT8(s, MsInterface->AlternateSetting); + Stream_Seek(s, 2); + Stream_Read_UINT32(s, MsInterface->NumberOfPipes); + MsInterface->InterfaceHandle = 0; + MsInterface->bInterfaceClass = 0; + MsInterface->bInterfaceSubClass = 0; + MsInterface->bInterfaceProtocol = 0; + MsInterface->InitCompleted = 0; + MsInterface->MsPipes = NULL; + + if (MsInterface->NumberOfPipes > 0) + { + MsInterface->MsPipes = msusb_mspipes_read(s, MsInterface->NumberOfPipes); + + if (!MsInterface->MsPipes) + goto out_error; + } + + return MsInterface; +out_error: + msusb_msinterface_free(MsInterface); + return NULL; +} + +BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out) +{ + MSUSB_PIPE_DESCRIPTOR** MsPipes; + MSUSB_PIPE_DESCRIPTOR* MsPipe; + UINT32 pnum = 0; + + if (!MsInterface) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, 16 + MsInterface->NumberOfPipes * 20)) + return FALSE; + + /* Length */ + Stream_Write_UINT16(out, MsInterface->Length); + /* InterfaceNumber */ + Stream_Write_UINT8(out, MsInterface->InterfaceNumber); + /* AlternateSetting */ + Stream_Write_UINT8(out, MsInterface->AlternateSetting); + /* bInterfaceClass */ + Stream_Write_UINT8(out, MsInterface->bInterfaceClass); + /* bInterfaceSubClass */ + Stream_Write_UINT8(out, MsInterface->bInterfaceSubClass); + /* bInterfaceProtocol */ + Stream_Write_UINT8(out, MsInterface->bInterfaceProtocol); + /* Padding */ + Stream_Write_UINT8(out, 0); + /* InterfaceHandle */ + Stream_Write_UINT32(out, MsInterface->InterfaceHandle); + /* NumberOfPipes */ + Stream_Write_UINT32(out, MsInterface->NumberOfPipes); + /* Pipes */ + MsPipes = MsInterface->MsPipes; + + for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + /* MaximumPacketSize */ + Stream_Write_UINT16(out, MsPipe->MaximumPacketSize); + /* EndpointAddress */ + Stream_Write_UINT8(out, MsPipe->bEndpointAddress); + /* Interval */ + Stream_Write_UINT8(out, MsPipe->bInterval); + /* PipeType */ + Stream_Write_UINT32(out, MsPipe->PipeType); + /* PipeHandle */ + Stream_Write_UINT32(out, MsPipe->PipeHandle); + /* MaximumTransferSize */ + Stream_Write_UINT32(out, MsPipe->MaximumTransferSize); + /* PipeFlags */ + Stream_Write_UINT32(out, MsPipe->PipeFlags); + } + + return TRUE; +} + +static MSUSB_INTERFACE_DESCRIPTOR** msusb_msinterface_read_list(wStream* s, UINT32 NumInterfaces) +{ + UINT32 inum; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MsInterfaces = + (MSUSB_INTERFACE_DESCRIPTOR**)calloc(NumInterfaces, sizeof(MSUSB_INTERFACE_DESCRIPTOR*)); + + if (!MsInterfaces) + return NULL; + + for (inum = 0; inum < NumInterfaces; inum++) + { + MsInterfaces[inum] = msusb_msinterface_read(s); + + if (!MsInterfaces[inum]) + goto fail; + } + + return MsInterfaces; +fail: + + for (inum = 0; inum < NumInterfaces; inum++) + msusb_msinterface_free(MsInterfaces[inum]); + + free(MsInterfaces); + return NULL; +} + +BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out) +{ + UINT32 inum = 0; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + + if (!MsConfg) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(out, 8)) + return FALSE; + + /* ConfigurationHandle*/ + Stream_Write_UINT32(out, MsConfg->ConfigurationHandle); + /* NumInterfaces*/ + Stream_Write_UINT32(out, MsConfg->NumInterfaces); + /* Interfaces */ + MsInterfaces = MsConfg->MsInterfaces; + + for (inum = 0; inum < MsConfg->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + + if (!msusb_msinterface_write(MsInterface, out)) + return FALSE; + } + + return TRUE; +} + +MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void) +{ + return (MSUSB_CONFIG_DESCRIPTOR*)calloc(1, sizeof(MSUSB_CONFIG_DESCRIPTOR)); +} + +void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig) +{ + if (MsConfig) + { + msusb_msinterface_free_list(MsConfig->MsInterfaces, MsConfig->NumInterfaces); + MsConfig->MsInterfaces = NULL; + free(MsConfig); + } +} + +MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces) +{ + MSUSB_CONFIG_DESCRIPTOR* MsConfig; + BYTE lenConfiguration, typeConfiguration; + + if (Stream_GetRemainingCapacity(s) < 6 + NumInterfaces * 2) + return NULL; + + MsConfig = msusb_msconfig_new(); + + if (!MsConfig) + goto fail; + + MsConfig->MsInterfaces = msusb_msinterface_read_list(s, NumInterfaces); + + if (!MsConfig->MsInterfaces) + goto fail; + + Stream_Read_UINT8(s, lenConfiguration); + Stream_Read_UINT8(s, typeConfiguration); + + if (lenConfiguration != 0x9 || typeConfiguration != 0x2) + { + WLog_ERR(TAG, "len and type must be 0x9 and 0x2 , but it is 0x%" PRIx8 " and 0x%" PRIx8 "", + lenConfiguration, typeConfiguration); + goto fail; + } + + Stream_Read_UINT16(s, MsConfig->wTotalLength); + Stream_Seek(s, 1); + Stream_Read_UINT8(s, MsConfig->bConfigurationValue); + MsConfig->NumInterfaces = NumInterfaces; + return MsConfig; +fail: + msusb_msconfig_free(MsConfig); + return NULL; +} + +void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfig) +{ + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR* MsInterface; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + MSUSB_PIPE_DESCRIPTOR* MsPipe; + UINT32 inum = 0, pnum = 0; + WLog_INFO(TAG, "=================MsConfig:========================"); + WLog_INFO(TAG, "wTotalLength:%" PRIu16 "", MsConfig->wTotalLength); + WLog_INFO(TAG, "bConfigurationValue:%" PRIu8 "", MsConfig->bConfigurationValue); + WLog_INFO(TAG, "ConfigurationHandle:0x%08" PRIx32 "", MsConfig->ConfigurationHandle); + WLog_INFO(TAG, "InitCompleted:%d", MsConfig->InitCompleted); + WLog_INFO(TAG, "MsOutSize:%d", MsConfig->MsOutSize); + WLog_INFO(TAG, "NumInterfaces:%" PRIu32 "", MsConfig->NumInterfaces); + MsInterfaces = MsConfig->MsInterfaces; + + for (inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + WLog_INFO(TAG, " Interface: %" PRIu8 "", MsInterface->InterfaceNumber); + WLog_INFO(TAG, " Length: %" PRIu16 "", MsInterface->Length); + WLog_INFO(TAG, " NumberOfPipesExpected: %" PRIu16 "", + MsInterface->NumberOfPipesExpected); + WLog_INFO(TAG, " AlternateSetting: %" PRIu8 "", MsInterface->AlternateSetting); + WLog_INFO(TAG, " NumberOfPipes: %" PRIu32 "", MsInterface->NumberOfPipes); + WLog_INFO(TAG, " InterfaceHandle: 0x%08" PRIx32 "", MsInterface->InterfaceHandle); + WLog_INFO(TAG, " bInterfaceClass: 0x%02" PRIx8 "", MsInterface->bInterfaceClass); + WLog_INFO(TAG, " bInterfaceSubClass: 0x%02" PRIx8 "", MsInterface->bInterfaceSubClass); + WLog_INFO(TAG, " bInterfaceProtocol: 0x%02" PRIx8 "", MsInterface->bInterfaceProtocol); + WLog_INFO(TAG, " InitCompleted: %d", MsInterface->InitCompleted); + MsPipes = MsInterface->MsPipes; + + for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + WLog_INFO(TAG, " Pipe: %d", pnum); + WLog_INFO(TAG, " MaximumPacketSize: 0x%04" PRIx16 "", MsPipe->MaximumPacketSize); + WLog_INFO(TAG, " MaximumTransferSize: 0x%08" PRIx32 "", + MsPipe->MaximumTransferSize); + WLog_INFO(TAG, " PipeFlags: 0x%08" PRIx32 "", MsPipe->PipeFlags); + WLog_INFO(TAG, " PipeHandle: 0x%08" PRIx32 "", MsPipe->PipeHandle); + WLog_INFO(TAG, " bEndpointAddress: 0x%02" PRIx8 "", MsPipe->bEndpointAddress); + WLog_INFO(TAG, " bInterval: %" PRIu8 "", MsPipe->bInterval); + WLog_INFO(TAG, " PipeType: 0x%02" PRIx8 "", MsPipe->PipeType); + WLog_INFO(TAG, " InitCompleted: %d", MsPipe->InitCompleted); + } + } + + WLog_INFO(TAG, "=================================================="); +} diff --git a/channels/urbdrc/common/msusb.h b/channels/urbdrc/common/msusb.h new file mode 100644 index 000000000..89f1a2bde --- /dev/null +++ b/channels/urbdrc/common/msusb.h @@ -0,0 +1,97 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RemoteFX USB Redirection + * + * Copyright 2012 Atrust corp. + * Copyright 2012 Alfred Liu + * + * 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. + */ + +#ifndef FREERDP_UTILS_MSCONFIG_H +#define FREERDP_UTILS_MSCONFIG_H + +#include +#include + +typedef struct _MSUSB_INTERFACE_DESCRIPTOR MSUSB_INTERFACE_DESCRIPTOR; +typedef struct _MSUSB_PIPE_DESCRIPTOR MSUSB_PIPE_DESCRIPTOR; +typedef struct _MSUSB_CONFIG_DESCRIPTOR MSUSB_CONFIG_DESCRIPTOR; + +struct _MSUSB_PIPE_DESCRIPTOR +{ + UINT16 MaximumPacketSize; + UINT32 MaximumTransferSize; + UINT32 PipeFlags; + UINT32 PipeHandle; + BYTE bEndpointAddress; + BYTE bInterval; + BYTE PipeType; + int InitCompleted; +}; + +struct _MSUSB_INTERFACE_DESCRIPTOR +{ + UINT16 Length; + UINT16 NumberOfPipesExpected; + BYTE InterfaceNumber; + BYTE AlternateSetting; + UINT32 NumberOfPipes; + UINT32 InterfaceHandle; + BYTE bInterfaceClass; + BYTE bInterfaceSubClass; + BYTE bInterfaceProtocol; + MSUSB_PIPE_DESCRIPTOR** MsPipes; + int InitCompleted; +}; + +struct _MSUSB_CONFIG_DESCRIPTOR +{ + UINT16 wTotalLength; + BYTE bConfigurationValue; + UINT32 ConfigurationHandle; + UINT32 NumInterfaces; + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; + int InitCompleted; + int MsOutSize; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + /* MSUSB_PIPE exported functions */ + FREERDP_API BOOL msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, + MSUSB_PIPE_DESCRIPTOR** NewMsPipes, + UINT32 NewNumberOfPipes); + + /* MSUSB_INTERFACE exported functions */ + FREERDP_API BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, + BYTE InterfaceNumber, + MSUSB_INTERFACE_DESCRIPTOR* NewMsInterface); + FREERDP_API MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* out); + FREERDP_API BOOL msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR* MsInterface, wStream* out); + + /* MSUSB_CONFIG exported functions */ + FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_new(void); + FREERDP_API void msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR* MsConfig); + FREERDP_API MSUSB_CONFIG_DESCRIPTOR* msusb_msconfig_read(wStream* s, UINT32 NumInterfaces); + FREERDP_API BOOL msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR* MsConfg, wStream* out); + FREERDP_API void msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR* MsConfg); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_UTILS_MSCONFIG_H */ diff --git a/channels/urbdrc/common/urbdrc_helpers.c b/channels/urbdrc/common/urbdrc_helpers.c new file mode 100644 index 000000000..4088527d1 --- /dev/null +++ b/channels/urbdrc/common/urbdrc_helpers.c @@ -0,0 +1,408 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server USB redirection channel - helper functions + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * + * 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 "urbdrc_helpers.h" +#include "urbdrc_types.h" + +const char* mask_to_string(UINT32 mask) +{ + switch (mask) + { + case STREAM_ID_NONE: + return "STREAM_ID_NONE"; + + case STREAM_ID_PROXY: + return "STREAM_ID_PROXY"; + + case STREAM_ID_STUB: + return "STREAM_ID_STUB"; + + default: + return "UNKNOWN"; + } +} +const char* interface_to_string(UINT32 id) +{ + switch (id) + { + case CAPABILITIES_NEGOTIATOR: + return "CAPABILITIES_NEGOTIATOR"; + + case SERVER_CHANNEL_NOTIFICATION: + return "SERVER_CHANNEL_NOTIFICATION"; + + case CLIENT_CHANNEL_NOTIFICATION: + return "CLIENT_CHANNEL_NOTIFICATION"; + + default: + return "DEVICE_MESSAGE"; + } +} + +static const char* call_to_string_none(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + WINPR_UNUSED(interfaceId); + + if (client) + return "RIM_EXCHANGE_CAPABILITY_RESPONSE [none |client]"; + else + { + switch (functionId) + { + case RIM_EXCHANGE_CAPABILITY_REQUEST: + return "RIM_EXCHANGE_CAPABILITY_REQUEST [none |server]"; + + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [none |server]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [none |server]"; + + default: + return "UNKNOWN [none |server]"; + } + } +} + +static const char* call_to_string_proxy_server(UINT32 functionId) +{ + switch (functionId) + { + case QUERY_DEVICE_TEXT: + return "QUERY_DEVICE_TEXT [proxy|server]"; + + case INTERNAL_IO_CONTROL: + return "INTERNAL_IO_CONTROL [proxy|server]"; + + case IO_CONTROL: + return "IO_CONTROL [proxy|server]"; + + case REGISTER_REQUEST_CALLBACK: + return "REGISTER_REQUEST_CALLBACK [proxy|server]"; + + case CANCEL_REQUEST: + return "CANCEL_REQUEST [proxy|server]"; + + case RETRACT_DEVICE: + return "RETRACT_DEVICE [proxy|server]"; + + case TRANSFER_IN_REQUEST: + return "TRANSFER_IN_REQUEST [proxy|server]"; + + default: + return "UNKNOWN [proxy|server]"; + } +} + +static const char* call_to_string_proxy_client(UINT32 functionId) +{ + switch (functionId) + { + case URB_COMPLETION_NO_DATA: + return "URB_COMPLETION_NO_DATA [proxy|client]"; + + case URB_COMPLETION: + return "URB_COMPLETION [proxy|client]"; + + case IOCONTROL_COMPLETION: + return "IOCONTROL_COMPLETION [proxy|client]"; + + case TRANSFER_OUT_REQUEST: + return "TRANSFER_OUT_REQUEST [proxy|client]"; + + default: + return "UNKNOWN [proxy|client]"; + } +} + +static const char* call_to_string_proxy(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + switch (interfaceId & INTERFACE_ID_MASK) + { + case CLIENT_DEVICE_SINK: + switch (functionId) + { + case ADD_VIRTUAL_CHANNEL: + return "ADD_VIRTUAL_CHANNEL [proxy|sink ]"; + + case ADD_DEVICE: + return "ADD_DEVICE [proxy|sink ]"; + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|sink ]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|sink ]"; + default: + return "UNKNOWN [proxy|sink ]"; + } + + case SERVER_CHANNEL_NOTIFICATION: + switch (functionId) + { + case CHANNEL_CREATED: + return "CHANNEL_CREATED [proxy|server]"; + + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|server]"; + + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|server]"; + + default: + return "UNKNOWN [proxy|server]"; + } + + case CLIENT_CHANNEL_NOTIFICATION: + switch (functionId) + { + case CHANNEL_CREATED: + return "CHANNEL_CREATED [proxy|client]"; + case RIMCALL_RELEASE: + return "RIMCALL_RELEASE [proxy|client]"; + case RIMCALL_QUERYINTERFACE: + return "RIMCALL_QUERYINTERFACE [proxy|client]"; + default: + return "UNKNOWN [proxy|client]"; + } + + default: + if (client) + return call_to_string_proxy_client(functionId); + else + return call_to_string_proxy_server(functionId); + } +} + +static const char* call_to_string_stub(BOOL client, UINT32 interfaceId, UINT32 functionId) +{ + return "QUERY_DEVICE_TEXT_RSP [stub |client]"; +} + +const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId) +{ + const UINT32 mask = (interface & STREAM_ID_MASK) >> 30; + const UINT32 interfaceId = interface & INTERFACE_ID_MASK; + + switch (mask) + { + case STREAM_ID_NONE: + return call_to_string_none(client, interfaceId, functionId); + + case STREAM_ID_PROXY: + return call_to_string_proxy(client, interfaceId, functionId); + + case STREAM_ID_STUB: + return call_to_string_stub(client, interfaceId, functionId); + + default: + return "UNKNOWN[mask]"; + } +} + +const char* urb_function_string(UINT16 urb) +{ + switch (urb) + { + case TS_URB_SELECT_CONFIGURATION: + return "TS_URB_SELECT_CONFIGURATION"; + + case TS_URB_SELECT_INTERFACE: + return "TS_URB_SELECT_INTERFACE"; + + case TS_URB_PIPE_REQUEST: + return "TS_URB_PIPE_REQUEST"; + + case TS_URB_TAKE_FRAME_LENGTH_CONTROL: + return "TS_URB_TAKE_FRAME_LENGTH_CONTROL"; + + case TS_URB_RELEASE_FRAME_LENGTH_CONTROL: + return "TS_URB_RELEASE_FRAME_LENGTH_CONTROL"; + + case TS_URB_GET_FRAME_LENGTH: + return "TS_URB_GET_FRAME_LENGTH"; + + case TS_URB_SET_FRAME_LENGTH: + return "TS_URB_SET_FRAME_LENGTH"; + + case TS_URB_GET_CURRENT_FRAME_NUMBER: + return "TS_URB_GET_CURRENT_FRAME_NUMBER"; + + case TS_URB_CONTROL_TRANSFER: + return "TS_URB_CONTROL_TRANSFER"; + + case TS_URB_BULK_OR_INTERRUPT_TRANSFER: + return "TS_URB_BULK_OR_INTERRUPT_TRANSFER"; + + case TS_URB_ISOCH_TRANSFER: + return "TS_URB_ISOCH_TRANSFER"; + + case TS_URB_GET_DESCRIPTOR_FROM_DEVICE: + return "TS_URB_GET_DESCRIPTOR_FROM_DEVICE"; + + case TS_URB_SET_DESCRIPTOR_TO_DEVICE: + return "TS_URB_SET_DESCRIPTOR_TO_DEVICE"; + + case TS_URB_SET_FEATURE_TO_DEVICE: + return "TS_URB_SET_FEATURE_TO_DEVICE"; + + case TS_URB_SET_FEATURE_TO_INTERFACE: + return "TS_URB_SET_FEATURE_TO_INTERFACE"; + + case TS_URB_SET_FEATURE_TO_ENDPOINT: + return "TS_URB_SET_FEATURE_TO_ENDPOINT"; + + case TS_URB_CLEAR_FEATURE_TO_DEVICE: + return "TS_URB_CLEAR_FEATURE_TO_DEVICE"; + + case TS_URB_CLEAR_FEATURE_TO_INTERFACE: + return "TS_URB_CLEAR_FEATURE_TO_INTERFACE"; + + case TS_URB_CLEAR_FEATURE_TO_ENDPOINT: + return "TS_URB_CLEAR_FEATURE_TO_ENDPOINT"; + + case TS_URB_GET_STATUS_FROM_DEVICE: + return "TS_URB_GET_STATUS_FROM_DEVICE"; + + case TS_URB_GET_STATUS_FROM_INTERFACE: + return "TS_URB_GET_STATUS_FROM_INTERFACE"; + + case TS_URB_GET_STATUS_FROM_ENDPOINT: + return "TS_URB_GET_STATUS_FROM_ENDPOINT"; + + case TS_URB_RESERVED_0X0016: + return "TS_URB_RESERVED_0X0016"; + + case TS_URB_VENDOR_DEVICE: + return "TS_URB_VENDOR_DEVICE"; + + case TS_URB_VENDOR_INTERFACE: + return "TS_URB_VENDOR_INTERFACE"; + + case TS_URB_VENDOR_ENDPOINT: + return "TS_URB_VENDOR_ENDPOINT"; + + case TS_URB_CLASS_DEVICE: + return "TS_URB_CLASS_DEVICE"; + + case TS_URB_CLASS_INTERFACE: + return "TS_URB_CLASS_INTERFACE"; + + case TS_URB_CLASS_ENDPOINT: + return "TS_URB_CLASS_ENDPOINT"; + + case TS_URB_RESERVE_0X001D: + return "TS_URB_RESERVE_0X001D"; + + case TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL: + return "TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL"; + + case TS_URB_CLASS_OTHER: + return "TS_URB_CLASS_OTHER"; + + case TS_URB_VENDOR_OTHER: + return "TS_URB_VENDOR_OTHER"; + + case TS_URB_GET_STATUS_FROM_OTHER: + return "TS_URB_GET_STATUS_FROM_OTHER"; + + case TS_URB_CLEAR_FEATURE_TO_OTHER: + return "TS_URB_CLEAR_FEATURE_TO_OTHER"; + + case TS_URB_SET_FEATURE_TO_OTHER: + return "TS_URB_SET_FEATURE_TO_OTHER"; + + case TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT: + return "TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT"; + + case TS_URB_SET_DESCRIPTOR_TO_ENDPOINT: + return "TS_URB_SET_DESCRIPTOR_TO_ENDPOINT"; + + case TS_URB_CONTROL_GET_CONFIGURATION_REQUEST: + return "TS_URB_CONTROL_GET_CONFIGURATION_REQUEST"; + + case TS_URB_CONTROL_GET_INTERFACE_REQUEST: + return "TS_URB_CONTROL_GET_INTERFACE_REQUEST"; + + case TS_URB_GET_DESCRIPTOR_FROM_INTERFACE: + return "TS_URB_GET_DESCRIPTOR_FROM_INTERFACE"; + + case TS_URB_SET_DESCRIPTOR_TO_INTERFACE: + return "TS_URB_SET_DESCRIPTOR_TO_INTERFACE"; + + case TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST: + return "TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST"; + + case TS_URB_RESERVE_0X002B: + return "TS_URB_RESERVE_0X002B"; + + case TS_URB_RESERVE_0X002C: + return "TS_URB_RESERVE_0X002C"; + + case TS_URB_RESERVE_0X002D: + return "TS_URB_RESERVE_0X002D"; + + case TS_URB_RESERVE_0X002E: + return "TS_URB_RESERVE_0X002E"; + + case TS_URB_RESERVE_0X002F: + return "TS_URB_RESERVE_0X002F"; + + case TS_URB_SYNC_RESET_PIPE: + return "TS_URB_SYNC_RESET_PIPE"; + + case TS_URB_SYNC_CLEAR_STALL: + return "TS_URB_SYNC_CLEAR_STALL"; + + case TS_URB_CONTROL_TRANSFER_EX: + return "TS_URB_CONTROL_TRANSFER_EX"; + + default: + return "UNKNOWN"; + } +} + +void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s) +{ + const char* type = write ? "WRITE" : "READ"; + UINT32 InterfaceId, MessageId, FunctionId; + size_t length, pos; + + pos = Stream_GetPosition(s); + if (write) + { + length = Stream_GetPosition(s); + Stream_SetPosition(s, 0); + } + else + length = Stream_GetRemainingLength(s); + + if (length < 12) + return; + + Stream_Read_UINT32(s, InterfaceId); + Stream_Read_UINT32(s, MessageId); + Stream_Read_UINT32(s, FunctionId); + Stream_SetPosition(s, pos); + + WLog_Print(log, WLOG_DEBUG, + "[%-5s] %s [%08" PRIx32 "] InterfaceId=%08" PRIx32 ", MessageId=%08" PRIx32 + ", FunctionId=%08" PRIx32 ", length=%" PRIdz, + type, call_to_string(client, InterfaceId, FunctionId), FunctionId, InterfaceId, + MessageId, FunctionId, length); +} diff --git a/channels/urbdrc/common/urbdrc_helpers.h b/channels/urbdrc/common/urbdrc_helpers.h new file mode 100644 index 000000000..e9e25af3a --- /dev/null +++ b/channels/urbdrc/common/urbdrc_helpers.h @@ -0,0 +1,45 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server USB redirection channel - helper functions + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_URBDRC_HELPERS_H +#define FREERDP_CHANNEL_URBDRC_HELPERS_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include + + const char* urb_function_string(UINT16 urb); + const char* mask_to_string(UINT32 mask); + const char* interface_to_string(UINT32 id); + const char* call_to_string(BOOL client, UINT32 interface, UINT32 functionId); + + void urbdrc_dump_message(wLog* log, BOOL client, BOOL write, wStream* s); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_URBDRC_HELPERS_H */ diff --git a/channels/urbdrc/client/urbdrc_types.h b/channels/urbdrc/common/urbdrc_types.h similarity index 66% rename from channels/urbdrc/client/urbdrc_types.h rename to channels/urbdrc/common/urbdrc_types.h index 57555b47e..c120715d8 100644 --- a/channels/urbdrc/client/urbdrc_types.h +++ b/channels/urbdrc/common/urbdrc_types.h @@ -27,24 +27,12 @@ #include #include -#include -#include -#include -#include -#include +#include #include -#define TAG CHANNELS_TAG("urbdrc.client") -#ifdef WITH_DEBUG_DVC -#define DEBUG_DVC(...) WLog_DBG(TAG, __VA_ARGS__) -#else -#define DEBUG_DVC(...) \ - do \ - { \ - } while (0) -#endif +#define RIM_CAPABILITY_VERSION_01 0x00000001 #define CAPABILITIES_NEGOTIATOR 0x00000000 #define CLIENT_DEVICE_SINK 0x00000001 @@ -53,6 +41,7 @@ #define BASE_USBDEVICE_NUM 0x00000005 #define RIMCALL_RELEASE 0x00000001 +#define RIMCALL_QUERYINTERFACE 0x00000002 #define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100 #define CHANNEL_CREATED 0x00000100 #define ADD_VIRTUAL_CHANNEL 0x00000100 @@ -88,15 +77,18 @@ #define USB_v2_0 0x200 #define USB_v3_0 0x300 -#define STREAM_ID_NONE 0x0 -#define STREAM_ID_PROXY 0x1 -#define STREAM_ID_STUB 0x2 +#define STREAM_ID_NONE 0x0UL +#define STREAM_ID_PROXY 0x1UL +#define STREAM_ID_STUB 0x2UL +#define STREAM_ID_MASK 0xC0000000 +#define INTERFACE_ID_MASK 0x3FFFFFFF #define CANCEL_REQUEST 0x00000100 #define REGISTER_REQUEST_CALLBACK 0x00000101 #define IO_CONTROL 0x00000102 #define INTERNAL_IO_CONTROL 0x00000103 #define QUERY_DEVICE_TEXT 0x00000104 + #define TRANSFER_IN_REQUEST 0x00000105 #define TRANSFER_OUT_REQUEST 0x00000106 #define RETRACT_DEVICE 0x00000107 @@ -142,63 +134,64 @@ enum device_descriptor_table #define IOCTL_INTERNAL_USB_CYCLE_PORT 0x0022001F #define IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION 0x00220027 -#define URB_FUNCTION_SELECT_CONFIGURATION 0x0000 -#define URB_FUNCTION_SELECT_INTERFACE 0x0001 -#define URB_FUNCTION_ABORT_PIPE 0x0002 -#define URB_FUNCTION_TAKE_FRAME_LENGTH_CONTROL 0x0003 -#define URB_FUNCTION_RELEASE_FRAME_LENGTH_CONTROL 0x0004 -#define URB_FUNCTION_GET_FRAME_LENGTH 0x0005 -#define URB_FUNCTION_SET_FRAME_LENGTH 0x0006 -#define URB_FUNCTION_GET_CURRENT_FRAME_NUMBER 0x0007 -#define URB_FUNCTION_CONTROL_TRANSFER 0x0008 -#define URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER 0x0009 -#define URB_FUNCTION_ISOCH_TRANSFER 0x000A -#define URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE 0x000B -#define URB_FUNCTION_SET_DESCRIPTOR_TO_DEVICE 0x000C -#define URB_FUNCTION_SET_FEATURE_TO_DEVICE 0x000D -#define URB_FUNCTION_SET_FEATURE_TO_INTERFACE 0x000E -#define URB_FUNCTION_SET_FEATURE_TO_ENDPOINT 0x000F -#define URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE 0x0010 -#define URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE 0x0011 -#define URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT 0x0012 -#define URB_FUNCTION_GET_STATUS_FROM_DEVICE 0x0013 -#define URB_FUNCTION_GET_STATUS_FROM_INTERFACE 0x0014 -#define URB_FUNCTION_GET_STATUS_FROM_ENDPOINT 0x0015 -#define URB_FUNCTION_RESERVED_0X0016 0x0016 -#define URB_FUNCTION_VENDOR_DEVICE 0x0017 -#define URB_FUNCTION_VENDOR_INTERFACE 0x0018 -#define URB_FUNCTION_VENDOR_ENDPOINT 0x0019 -#define URB_FUNCTION_CLASS_DEVICE 0x001A -#define URB_FUNCTION_CLASS_INTERFACE 0x001B -#define URB_FUNCTION_CLASS_ENDPOINT 0x001C -#define URB_FUNCTION_RESERVE_0X001D 0x001D -#define URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E -#define URB_FUNCTION_CLASS_OTHER 0x001F -#define URB_FUNCTION_VENDOR_OTHER 0x0020 -#define URB_FUNCTION_GET_STATUS_FROM_OTHER 0x0021 -#define URB_FUNCTION_CLEAR_FEATURE_TO_OTHER 0x0022 -#define URB_FUNCTION_SET_FEATURE_TO_OTHER 0x0023 -#define URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 -#define URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 -#define URB_FUNCTION_GET_CONFIGURATION 0x0026 -#define URB_FUNCTION_GET_INTERFACE 0x0027 -#define URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 -#define URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE 0x0029 -#define URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR 0x002A -#define URB_FUNCTION_RESERVE_0X002B 0x002B -#define URB_FUNCTION_RESERVE_0X002C 0x002C -#define URB_FUNCTION_RESERVE_0X002D 0x002D -#define URB_FUNCTION_RESERVE_0X002E 0x002E -#define URB_FUNCTION_RESERVE_0X002F 0x002F +#define TS_URB_SELECT_CONFIGURATION 0x0000 +#define TS_URB_SELECT_INTERFACE 0x0001 +#define TS_URB_PIPE_REQUEST 0x0002 +#define TS_URB_TAKE_FRAME_LENGTH_CONTROL 0x0003 +#define TS_URB_RELEASE_FRAME_LENGTH_CONTROL 0x0004 +#define TS_URB_GET_FRAME_LENGTH 0x0005 +#define TS_URB_SET_FRAME_LENGTH 0x0006 +#define TS_URB_GET_CURRENT_FRAME_NUMBER 0x0007 +#define TS_URB_CONTROL_TRANSFER 0x0008 +#define TS_URB_BULK_OR_INTERRUPT_TRANSFER 0x0009 +#define TS_URB_ISOCH_TRANSFER 0x000A +#define TS_URB_GET_DESCRIPTOR_FROM_DEVICE 0x000B +#define TS_URB_SET_DESCRIPTOR_TO_DEVICE 0x000C +#define TS_URB_SET_FEATURE_TO_DEVICE 0x000D +#define TS_URB_SET_FEATURE_TO_INTERFACE 0x000E +#define TS_URB_SET_FEATURE_TO_ENDPOINT 0x000F +#define TS_URB_CLEAR_FEATURE_TO_DEVICE 0x0010 +#define TS_URB_CLEAR_FEATURE_TO_INTERFACE 0x0011 +#define TS_URB_CLEAR_FEATURE_TO_ENDPOINT 0x0012 +#define TS_URB_GET_STATUS_FROM_DEVICE 0x0013 +#define TS_URB_GET_STATUS_FROM_INTERFACE 0x0014 +#define TS_URB_GET_STATUS_FROM_ENDPOINT 0x0015 +#define TS_URB_RESERVED_0X0016 0x0016 +#define TS_URB_VENDOR_DEVICE 0x0017 +#define TS_URB_VENDOR_INTERFACE 0x0018 +#define TS_URB_VENDOR_ENDPOINT 0x0019 +#define TS_URB_CLASS_DEVICE 0x001A +#define TS_URB_CLASS_INTERFACE 0x001B +#define TS_URB_CLASS_ENDPOINT 0x001C +#define TS_URB_RESERVE_0X001D 0x001D +#define TS_URB_SYNC_RESET_PIPE_AND_CLEAR_STALL 0x001E +#define TS_URB_CLASS_OTHER 0x001F +#define TS_URB_VENDOR_OTHER 0x0020 +#define TS_URB_GET_STATUS_FROM_OTHER 0x0021 +#define TS_URB_CLEAR_FEATURE_TO_OTHER 0x0022 +#define TS_URB_SET_FEATURE_TO_OTHER 0x0023 +#define TS_URB_GET_DESCRIPTOR_FROM_ENDPOINT 0x0024 +#define TS_URB_SET_DESCRIPTOR_TO_ENDPOINT 0x0025 +#define TS_URB_CONTROL_GET_CONFIGURATION_REQUEST 0x0026 +#define TS_URB_CONTROL_GET_INTERFACE_REQUEST 0x0027 +#define TS_URB_GET_DESCRIPTOR_FROM_INTERFACE 0x0028 +#define TS_URB_SET_DESCRIPTOR_TO_INTERFACE 0x0029 +#define TS_URB_GET_OS_FEATURE_DESCRIPTOR_REQUEST 0x002A +#define TS_URB_RESERVE_0X002B 0x002B +#define TS_URB_RESERVE_0X002C 0x002C +#define TS_URB_RESERVE_0X002D 0x002D +#define TS_URB_RESERVE_0X002E 0x002E +#define TS_URB_RESERVE_0X002F 0x002F // USB 2.0 calls start at 0x0030 -#define URB_FUNCTION_SYNC_RESET_PIPE 0x0030 -#define URB_FUNCTION_SYNC_CLEAR_STALL 0x0031 -#define URB_FUNCTION_CONTROL_TRANSFER_EX 0x0032 +#define TS_URB_SYNC_RESET_PIPE 0x0030 +#define TS_URB_SYNC_CLEAR_STALL 0x0031 +#define TS_URB_CONTROL_TRANSFER_EX 0x0032 #define USBD_STATUS_SUCCESS 0x0 #define USBD_STATUS_PENDING 0x40000000 #define USBD_STATUS_CANCELED 0xC0010000 +#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 #define USBD_STATUS_CRC 0xC0000001 #define USBD_STATUS_BTSTUFF 0xC0000002 #define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 @@ -303,7 +296,6 @@ enum device_descriptor_table #define URBDRC_DEVICE_INITIALIZED 0x01 #define URBDRC_DEVICE_NOT_FOUND 0x02 -#define URBDRC_DEVICE_SIGNAL_END 0x04 #define URBDRC_DEVICE_CHANNEL_CLOSED 0x08 #define URBDRC_DEVICE_ALREADY_SEND 0x10 #define URBDRC_DEVICE_DETACH_KERNEL 0x20 @@ -313,30 +305,4 @@ enum device_descriptor_table #define UDEVMAN_FLAG_ADD_BY_AUTO 0x04 #define UDEVMAN_FLAG_DEBUG 0x08 -#define MAX_URB_REQUSET_NUM 0x80 - -#define LOG_LEVEL 1 - -#define dummy_wait_obj(void) \ - do \ - { \ - sleep(5); \ - } while (0) -#define dummy_wait_s_obj(_s) \ - do \ - { \ - sleep(_s); \ - } while (0) - -#define ISOCH_FIFO 1 -#define WAIT_COMPLETE_SLEEP 10000 /* for cpu high loading */ - -#define urbdrc_get_mstime(_t) \ - do \ - { \ - struct timeval _tp; \ - gettimeofday(&_tp, 0); \ - _t = (_tp.tv_sec * 1000) + (_tp.tv_usec / 1000); \ - } while (0) - #endif /* FREERDP_CHANNEL_URBDRC_CLIENT_TYPES_H */ diff --git a/include/freerdp/channels/urbdrc.h b/include/freerdp/channels/urbdrc.h new file mode 100644 index 000000000..a0035169a --- /dev/null +++ b/include/freerdp/channels/urbdrc.h @@ -0,0 +1,30 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Server USB redirection Virtual Channel + * + * Copyright 2019 Armin Novak + * Copyright 2019 Thincast Technologies GmbH + * + * 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. + */ + +#ifndef FREERDP_CHANNEL_URBDRC_H +#define FREERDP_CHANNEL_URBDRC_H + +#include +#include +#include + +#define URBDRC_CHANNEL_NAME "urbdrc" + +#endif /* FREERDP_CHANNEL_URBDRC_H */