From fa4d8fca1be797b03504fd1f53a4c861066e591b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 25 Apr 2012 14:26:35 -0400 Subject: [PATCH] urbrdc: initial USB redirection support, contributed by Atrust --- channels/drdynvc/CMakeLists.txt | 1 + channels/drdynvc/drdynvc_main.c | 10 +- channels/drdynvc/drdynvc_types.h | 1 + channels/drdynvc/dvcman.c | 55 +- channels/drdynvc/urbdrc/CMakeLists.txt | 45 + channels/drdynvc/urbdrc/data_transfer.c | 2475 +++++++++++++++++ channels/drdynvc/urbdrc/data_transfer.h | 41 + channels/drdynvc/urbdrc/isoch_queue.c | 195 ++ channels/drdynvc/urbdrc/isoch_queue.h | 69 + channels/drdynvc/urbdrc/libusb/CMakeLists.txt | 38 + .../drdynvc/urbdrc/libusb/libusb_udevice.c | 1903 +++++++++++++ .../drdynvc/urbdrc/libusb/libusb_udevice.h | 86 + .../drdynvc/urbdrc/libusb/libusb_udevman.c | 567 ++++ .../drdynvc/urbdrc/libusb/request_queue.c | 188 ++ .../drdynvc/urbdrc/libusb/request_queue.h | 65 + channels/drdynvc/urbdrc/searchman.c | 237 ++ channels/drdynvc/urbdrc/searchman.h | 77 + channels/drdynvc/urbdrc/urbdrc_main.c | 1073 +++++++ channels/drdynvc/urbdrc/urbdrc_main.h | 269 ++ channels/drdynvc/urbdrc/urbdrc_types.h | 355 +++ include/freerdp/dvc.h | 4 + include/freerdp/utils/msusb.h | 148 + libfreerdp-utils/CMakeLists.txt | 3 +- libfreerdp-utils/msusb.c | 368 +++ 24 files changed, 8252 insertions(+), 21 deletions(-) create mode 100644 channels/drdynvc/urbdrc/CMakeLists.txt create mode 100644 channels/drdynvc/urbdrc/data_transfer.c create mode 100644 channels/drdynvc/urbdrc/data_transfer.h create mode 100644 channels/drdynvc/urbdrc/isoch_queue.c create mode 100644 channels/drdynvc/urbdrc/isoch_queue.h create mode 100644 channels/drdynvc/urbdrc/libusb/CMakeLists.txt create mode 100644 channels/drdynvc/urbdrc/libusb/libusb_udevice.c create mode 100644 channels/drdynvc/urbdrc/libusb/libusb_udevice.h create mode 100644 channels/drdynvc/urbdrc/libusb/libusb_udevman.c create mode 100644 channels/drdynvc/urbdrc/libusb/request_queue.c create mode 100644 channels/drdynvc/urbdrc/libusb/request_queue.h create mode 100644 channels/drdynvc/urbdrc/searchman.c create mode 100644 channels/drdynvc/urbdrc/searchman.h create mode 100644 channels/drdynvc/urbdrc/urbdrc_main.c create mode 100644 channels/drdynvc/urbdrc/urbdrc_main.h create mode 100644 channels/drdynvc/urbdrc/urbdrc_types.h create mode 100644 include/freerdp/utils/msusb.h create mode 100644 libfreerdp-utils/msusb.c diff --git a/channels/drdynvc/CMakeLists.txt b/channels/drdynvc/CMakeLists.txt index 1e3cc13f3..e41f6b3bf 100644 --- a/channels/drdynvc/CMakeLists.txt +++ b/channels/drdynvc/CMakeLists.txt @@ -34,4 +34,5 @@ install(TARGETS drdynvc DESTINATION ${FREERDP_PLUGIN_PATH}) add_subdirectory(tsmf) add_subdirectory(audin) +add_subdirectory(urbdrc) diff --git a/channels/drdynvc/drdynvc_main.c b/channels/drdynvc/drdynvc_main.c index 27ad531b7..42d422d25 100644 --- a/channels/drdynvc/drdynvc_main.c +++ b/channels/drdynvc/drdynvc_main.c @@ -86,7 +86,15 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, uint32 ChannelId, uint8* data, ui stream_set_pos(data_out, 1); cbChId = drdynvc_write_variable_uint(data_out, ChannelId); - if (data_size <= CHANNEL_CHUNK_LENGTH - pos) + if(data_size == 0) + { + pos = stream_get_pos(data_out); + stream_set_pos(data_out, 0); + stream_write_uint8(data_out, 0x40 | cbChId); + stream_set_pos(data_out, pos); + error = svc_plugin_send((rdpSvcPlugin*)drdynvc, data_out); + } + else if (data_size <= CHANNEL_CHUNK_LENGTH - pos) { pos = stream_get_pos(data_out); stream_set_pos(data_out, 0); diff --git a/channels/drdynvc/drdynvc_types.h b/channels/drdynvc/drdynvc_types.h index a08a60523..8af592071 100644 --- a/channels/drdynvc/drdynvc_types.h +++ b/channels/drdynvc/drdynvc_types.h @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef WITH_DEBUG_DVC #define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__) diff --git a/channels/drdynvc/dvcman.c b/channels/drdynvc/dvcman.c index d24b11489..3aee4ce83 100644 --- a/channels/drdynvc/dvcman.c +++ b/channels/drdynvc/dvcman.c @@ -78,6 +78,8 @@ struct _DVCMAN_CHANNEL IWTSVirtualChannelCallback* channel_callback; STREAM* dvc_data; + + pthread_mutex_t dvc_chan_mutex; }; static int dvcman_get_configuration(IWTSListener* pListener, void** ppPropertyBag) @@ -174,6 +176,28 @@ RDP_PLUGIN_DATA* dvcman_get_plugin_data(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return ((DVCMAN_ENTRY_POINTS*) pEntryPoints)->plugin_data; } +uint32 dvcman_get_channel_id(IWTSVirtualChannel * channel) +{ + return ((DVCMAN_CHANNEL*)channel)->channel_id; +} + +IWTSVirtualChannel* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId) +{ + LIST_ITEM* curr; + DVCMAN* dvcman = (DVCMAN*) pChannelMgr; + + for (curr = dvcman->channels->head; curr; curr = curr->next) + { + if (((DVCMAN_CHANNEL*) curr->data)->channel_id == ChannelId) + { + return (IWTSVirtualChannel*)curr->data; + } + } + + return NULL; +} + + IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) { DVCMAN* dvcman; @@ -181,6 +205,8 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin) dvcman = xnew(DVCMAN); dvcman->iface.CreateListener = dvcman_create_listener; dvcman->iface.PushEvent = dvcman_push_event; + dvcman->iface.FindChannelById = dvcman_find_channel_by_id; + dvcman->iface.GetChannelId = dvcman_get_channel_id; dvcman->drdynvc = plugin; dvcman->channels = list_new(); @@ -271,8 +297,13 @@ int dvcman_init(IWTSVirtualChannelManager* pChannelMgr) static int dvcman_write_channel(IWTSVirtualChannel* pChannel, uint32 cbSize, uint8* pBuffer, void* pReserved) { DVCMAN_CHANNEL* channel = (DVCMAN_CHANNEL*) pChannel; + int error; - return drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize); + pthread_mutex_lock(&channel->dvc_chan_mutex); + error = drdynvc_write_data(channel->dvcman->drdynvc, channel->channel_id, pBuffer, cbSize); + pthread_mutex_unlock(&channel->dvc_chan_mutex); + + return error; } static int dvcman_close_channel_iface(IWTSVirtualChannel* pChannel) @@ -310,6 +341,7 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 Channel channel->iface.Close = dvcman_close_channel_iface; channel->dvcman = dvcman; channel->channel_id = ChannelId; + pthread_mutex_init(&channel->dvc_chan_mutex, NULL); bAccept = 1; pCallback = NULL; @@ -336,28 +368,13 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 Channel return 1; } -static DVCMAN_CHANNEL* dvcman_find_channel_by_id(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId) -{ - LIST_ITEM* curr; - DVCMAN* dvcman = (DVCMAN*) pChannelMgr; - - for (curr = dvcman->channels->head; curr; curr = curr->next) - { - if (((DVCMAN_CHANNEL*) curr->data)->channel_id == ChannelId) - { - return (DVCMAN_CHANNEL*)curr->data; - } - } - - return NULL; -} int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, uint32 ChannelId) { DVCMAN_CHANNEL* channel; IWTSVirtualChannel* ichannel; - channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (channel == NULL) { @@ -382,7 +399,7 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, ui { DVCMAN_CHANNEL* channel; - channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (channel == NULL) { @@ -403,7 +420,7 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, uint32 C int error = 0; DVCMAN_CHANNEL* channel; - channel = dvcman_find_channel_by_id(pChannelMgr, ChannelId); + channel = (DVCMAN_CHANNEL*)dvcman_find_channel_by_id(pChannelMgr, ChannelId); if (channel == NULL) { diff --git a/channels/drdynvc/urbdrc/CMakeLists.txt b/channels/drdynvc/urbdrc/CMakeLists.txt new file mode 100644 index 000000000..627bf8704 --- /dev/null +++ b/channels/drdynvc/urbdrc/CMakeLists.txt @@ -0,0 +1,45 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP cmake build script +# +# 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. + +set(URBDRC_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_library(urbdrc ${URBDRC_SRCS}) +set_target_properties(urbdrc PROPERTIES PREFIX "") + +target_link_libraries(urbdrc udev) +target_link_libraries(urbdrc dbus-glib-1) +target_link_libraries(urbdrc pthread) +target_link_libraries(urbdrc uuid) +target_link_libraries(urbdrc freerdp-utils) + +install(TARGETS urbdrc DESTINATION ${FREERDP_PLUGIN_PATH}) + +add_subdirectory(libusb) + diff --git a/channels/drdynvc/urbdrc/data_transfer.c b/channels/drdynvc/urbdrc/data_transfer.c new file mode 100644 index 000000000..c00c504d0 --- /dev/null +++ b/channels/drdynvc/urbdrc/data_transfer.c @@ -0,0 +1,2475 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 +#include +#include + +#include "urbdrc_types.h" +#include "data_transfer.h" + + +static void +usb_process_get_port_status(IUDEVICE * pdev, uint8 * OutputBuffer) +{ + int bcdUSB = pdev->query_device_descriptor(pdev, BCD_USB); + switch (bcdUSB){ + case USB_v1_0: + data_write_uint32(OutputBuffer, 0x303); + break; + case USB_v1_1: + data_write_uint32(OutputBuffer, 0x103); + break; + case USB_v2_0: + data_write_uint32(OutputBuffer, 0x503); + break; + default: + data_write_uint32(OutputBuffer, 0x503); + break; + } +} + + +#if ISOCH_FIFO +static int +func_check_isochronous_fds(IUDEVICE * pdev) +{ + ISOCH_CALLBACK_QUEUE * isoch_queue = NULL; + ISOCH_CALLBACK_DATA * isoch = NULL; + URBDRC_CHANNEL_CALLBACK * callback; + uint32 size_temp, process_times = 2; + uint8 * data_temp; + int ret = 0; + + isoch_queue = (ISOCH_CALLBACK_QUEUE *)pdev->get_isoch_queue(pdev); + + while (process_times) + { + 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) + LLOGLN(0, ("isoch_queue_unregister_data: Not found isoch data!!\n")); + 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); + } + + } + + } + return 0; +} +#endif + +static int +urbdrc_process_register_request_callback(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + IUDEVICE * pdev; + uint32 NumRequestCompletion = 0; + uint32 RequestCompletion = 0; + + LLOGLN(urbdrc_debug, ("urbdrc_process_register_request_callback")); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL) + return 0; + + if (data_sizem >= 8) + { + data_read_uint32(data + 0, NumRequestCompletion); /** must be 1 */ + /** RequestCompletion: + * unique Request Completion interface for the client to use */ + data_read_uint32(data + 4, RequestCompletion); + pdev->set_ReqCompletion(pdev, RequestCompletion); + } + else /** Unregister the device */ + { + data_read_uint32(data + 0, 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); + } + } + + return 0; +} + +static int +urbdrc_process_cancel_request(uint8 * data, uint32 data_sizem, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + IUDEVICE* pdev; + uint32 CancelId; + int error = 0; + + data_read_uint32(data + 0, CancelId); /** RequestId */ + + LLOGLN(urbdrc_debug, ("urbdrc_process_cancel_request: id 0x%x", CancelId)); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL) + return 0; + + error = pdev->cancel_transfer_request(pdev, CancelId); + + return error; +} + +static int +urbdrc_process_retract_device_request(uint8 * data, uint32 data_sizem, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + uint32 Reason; + LLOGLN(urbdrc_debug, ("urbdrc_process_retract_device_request")); + + data_read_uint32(data + 0, Reason); /** Reason */ + + switch (Reason) + { + case UsbRetractReason_BlockedByPolicy: + LLOGLN(urbdrc_debug, ("UsbRetractReason_BlockedByPolicy: now it is not support")); + return -1; + break; + default: + LLOGLN(urbdrc_debug, ("urbdrc_process_retract_device_request: Unknown Reason %d", Reason)); + return -1; + break; + } + + return 0; +} + +static int +urbdrc_process_io_control(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + IUDEVICE * pdev; + uint32 out_size; + uint32 InterfaceId; + uint32 IoControlCode; + uint32 InputBufferSize; + uint32 OutputBufferSize; + uint32 RequestId; + uint32 usbd_status = USBD_STATUS_SUCCESS; + uint8 * OutputBuffer; + uint8 * out_data; + int i, offset, success = 0; + + LLOGLN(urbdrc_debug, ("urbdrc_process__io_control")); + + 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); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL) + return 0; + + InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + + + /** process */ + OutputBuffer = (uint8 *)malloc(OutputBufferSize); + memset(OutputBuffer, 0, OutputBufferSize); + + switch (IoControlCode){ + case IOCTL_INTERNAL_USB_SUBMIT_URB: /** 0x00220003 */ + LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_SUBMIT_URB")); + printf(" Function IOCTL_INTERNAL_USB_SUBMIT_URB: Unchecked\n"); + break; + case IOCTL_INTERNAL_USB_RESET_PORT: /** 0x00220007 */ + LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_RESET_PORT")); + break; + case IOCTL_INTERNAL_USB_GET_PORT_STATUS: /** 0x00220013 */ + LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_GET_PORT_STATUS")); + + success = pdev->query_device_port_status(pdev, &usbd_status, + &OutputBufferSize, + OutputBuffer); + + if (success) + { + if (pdev->isExist(pdev) == 0) + { + data_write_uint32(OutputBuffer, 0); + } + else + { + usb_process_get_port_status(pdev, OutputBuffer); + OutputBufferSize = 4; + } + LLOGLN(urbdrc_debug, ("PORT STATUS(fake!):0x%02x%02x%02x%02x", + OutputBuffer[3], OutputBuffer[2], OutputBuffer[1], OutputBuffer[0])); + } + + break; + case IOCTL_INTERNAL_USB_CYCLE_PORT: /** 0x0022001F */ + LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_CYCLE_PORT")); + printf(" Function IOCTL_INTERNAL_USB_CYCLE_PORT: Unchecked\n"); + break; + case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: /** 0x00220027 */ + LLOGLN(urbdrc_debug, ("ioctl: IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION")); + printf(" Function IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION: Unchecked\n"); + break; + default: + LLOGLN(urbdrc_debug, ("urbdrc_process_io_control: unknown IoControlCode 0x%X", IoControlCode)); + return -1; + break; + } + + + offset = 28; + out_size = offset + OutputBufferSize; + out_data = (uint8 *) 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, USBD_STATUS_SUCCESS); /** HResult */ + data_write_uint32(out_data + 20, OutputBufferSize); /** Information */ + data_write_uint32(out_data + 24, OutputBufferSize); /** OutputBufferSize */ + + for (i=0;iisSigToEnd(pdev)) + callback->channel->Write(callback->channel, out_size, out_data, NULL); + + zfree(out_data); + zfree(OutputBuffer); + + return 0; +} + +static int +urbdrc_process_internal_io_control(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + IUDEVICE* pdev; + uint32 out_size, IoControlCode, InterfaceId, InputBufferSize; + uint32 OutputBufferSize, RequestId, frames; + uint8 * out_data; + + data_read_uint32(data + 0, IoControlCode); + + LLOGLN(urbdrc_debug, ("urbdrc_process_internal_io_control:0x%x", IoControlCode)); + + data_read_uint32(data + 4, InputBufferSize); + data_read_uint32(data + 8, OutputBufferSize); + data_read_uint32(data + 12, RequestId); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL) + return 0; + InterfaceId = ((STREAM_ID_PROXY<<30) | pdev->get_ReqCompletion(pdev)); + + /** Fixme: Currently this is a false bustime... */ + urbdrc_get_mstime(frames); + + out_size = 32; + out_data = (uint8 *) 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 (!pdev->isSigToEnd(pdev)) + callback->channel->Write(callback->channel, out_size, out_data, NULL); + + zfree(out_data); + + return 0; +} + +static int +urbdrc_process_query_device_text(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice) +{ + IUDEVICE * pdev; + uint32 out_size; + uint32 InterfaceId; + uint32 TextType; + uint32 LocaleId; + uint32 bufferSize = 1024; + uint8 * out_data; + uint8 DeviceDescription[bufferSize]; + int out_offset; + + LLOGLN(urbdrc_debug, ("urbdrc_process_query_device_text")); + + data_read_uint32(data + 0, TextType); + data_read_uint32(data + 4, LocaleId); + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + 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; + if(bufferSize != 0) + out_size += 2; + out_data = (uint8 *) 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 */ + 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; +} + + + +static void +func_select_all_interface_for_msconfig(IUDEVICE * pdev, MSUSB_CONFIG_DESCRIPTOR * MsConfig) +{ + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces = MsConfig->MsInterfaces; + uint8 InterfaceNumber, AlternateSetting; + uint32 NumInterfaces = MsConfig->NumInterfaces; + int inum; + + for (inum = 0; inum < NumInterfaces; inum++) + { + InterfaceNumber = MsInterfaces[inum]->InterfaceNumber; + AlternateSetting = MsInterfaces[inum]->AlternateSetting; + pdev->select_interface(pdev, InterfaceNumber, AlternateSetting); + } +} + + + +static int +urb_select_configuration(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + MSUSB_CONFIG_DESCRIPTOR * MsConfig = NULL; + IUDEVICE * pdev = NULL; + uint32 out_size, InterfaceId, RequestId, NumInterfaces, usbd_status = 0; + uint8 ConfigurationDescriptorIsValid; + uint8 * out_data; + int MsOutSize = 0, offset = 0; + + if (transferDir == 0){ + printf("urb_select_configuration: not support transfer out\n"); + return -1; + } + + 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_uint8(data + 4, ConfigurationDescriptorIsValid); + data_read_uint32(data + 8, NumInterfaces); + offset = 12; + + /** 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); + /* 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 (MsConfig) + MsOutSize = MsConfig->MsOutSize; + + if (MsOutSize > 0) + out_size = 36 + MsOutSize; + else + out_size = 44; + out_data = (uint8 *) 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 */ + if (MsOutSize > 0) + { + /** CbTsUrbResult */ + data_write_uint32(out_data + 16, 8 + MsOutSize); + /** TS_URB_RESULT_HEADER Size*/ + data_write_uint16(out_data + 20, 8 + MsOutSize); + } + else + { + data_write_uint32(out_data + 16, 16); + data_write_uint16(out_data + 20, 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; + /** TS_URB_SELECT_CONFIGURATION_RESULT */ + if (MsOutSize > 0) + { + msusb_msconfig_write(MsConfig, out_data, &offset); + } + else + { + data_write_uint32(out_data + offset, 0); /** ConfigurationHandle */ + data_write_uint32(out_data + offset + 4, NumInterfaces); /** NumInterfaces */ + offset += 8; + } + 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; +} + + +static int +urb_select_interface(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + MSUSB_CONFIG_DESCRIPTOR * MsConfig; + MSUSB_INTERFACE_DESCRIPTOR * MsInterface; + IUDEVICE * pdev; + uint32 out_size, InterfaceId, RequestId, ConfigurationHandle; + uint32 OutputBufferSize; + uint8 InterfaceNumber; + uint8 * out_data; + int out_offset, interface_size; + + if (transferDir == 0){ + printf("urb_select_interface: not support transfer out\n"); + return -1; + } + + 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, ConfigurationHandle); + out_offset = 8; + + MsInterface = msusb_msinterface_read(data + out_offset, data_sizem - out_offset, &out_offset); + + data_read_uint32(data + out_offset, 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); + + /* complete configuration setup */ + MsConfig = pdev->complete_msconfig_setup(pdev, MsConfig); + MsInterface = MsConfig->MsInterfaces[InterfaceNumber]; + interface_size = 16 + (MsInterface->NumberOfPipes * 20); + + out_size = 36 + interface_size ; + out_data = (uint8 *) 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 */ + data_write_uint32(out_data + 16, 8 + interface_size); /** CbTsUrbResult */ + /** TS_URB_RESULT_HEADER */ + data_write_uint16(out_data + 20, 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; + + /** TS_URB_SELECT_INTERFACE_RESULT */ + msusb_msinterface_write(MsInterface, out_data + out_offset, &out_offset); + + data_write_uint32(out_data + out_offset, 0); /** HResult */ + data_write_uint32(out_data + out_offset + 4, OutputBufferSize); /** OutputBufferSize */ + + if (!pdev->isSigToEnd(pdev)) + callback->channel->Write(callback->channel, out_size, out_data, NULL); + + zfree(out_data); + return 0; +} + + + +static int +urb_control_transfer(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir, + int External) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; + uint32 TransferFlags, OutputBufferSize, usbd_status, Timeout; + uint8 bmRequestType, Request; + uint16 Value, Index, length; + uint8 * buffer; + uint8 * out_data; + int offset, ret; + + 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 */ + + EndpointAddress = (PipeHandle & 0x000000ff); + offset = 12; + Timeout = 2000; + switch (External) + { + case URB_CONTROL_TRANSFER_EXTERNAL: + data_read_uint32(data + offset, Timeout); /** TransferFlags */ + offset += 4; + break; + case URB_CONTROL_TRANSFER_NONEXTERNAL: + break; + } + /** SetupPacket 8 bytes */ + data_read_uint8(data + offset, bmRequestType); + data_read_uint8(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 (length != OutputBufferSize){ + LLOGLN(urbdrc_debug, ("urb_control_transfer ERROR: buf != length")); + return -1; + } + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 36; + + /** Get Buffer Data */ + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + memcpy(buffer, data + offset, 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){ + LLOGLN(urbdrc_debug, ("control_transfer: error num %d!!\n", ret)); + OutputBufferSize = 0; + } + + /** 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; +} + + +static int +urb_bulk_or_interrupt_transfer(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, EndpointAddress, PipeHandle; + uint32 TransferFlags, OutputBufferSize, usbd_status = 0; + uint8 * Buffer; + uint8 * out_data; + int offset; + + 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; + else + out_size = 36 + OutputBufferSize; + + out_data = (uint8 *) 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; +} + + +static int +urb_isoch_transfer(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + 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; + uint8 * iso_buffer = NULL; + uint8 * iso_packets = NULL; + uint8 * out_data = NULL; + int offset, nullBuffer = 0, iso_status; + + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL) + return 0; + if (pdev->isSigToEnd(pdev)) + return 0; + + 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); + 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; + + /** send data memory alloc */ + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) { + if (!noAck) { + out_size = 48 + (NumberOfPackets * 12); + out_data = (uint8 *) malloc(out_size); + iso_packets = out_data + 40; + } + } + else { + out_size = 48 + OutputBufferSize + (NumberOfPackets * 12); + out_data = (uint8 *) malloc(out_size); + iso_packets = out_data + 40; + } + + 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; + } + + LLOGLN(urbdrc_debug, ("urb_isoch_transfer: EndpointAddress: 0x%x, " + "TransferFlags: 0x%x, " "StartFrame: 0x%x, " + "NumberOfPackets: 0x%x, " "OutputBufferSize: 0x%x " + "RequestId: 0x%x", + 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; +} + +static int +urb_control_descriptor_request(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + uint8 func_recipient, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, InterfaceId, RequestId, OutputBufferSize, usbd_status; + uint8 bmRequestType, desc_index, desc_type; + uint16 langId; + uint8 * buffer; + uint8 * out_data; + int ret, offset; + + 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_uint8(data + 4, desc_index); + data_read_uint8(data + 5, desc_type); + data_read_uint16(data + 6, langId); + data_read_uint32(data + 8, OutputBufferSize); + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 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); + break; + default: + LLOGLN(urbdrc_debug, ("%s: get error transferDir", __func__)); + 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) { + LLOGLN(urbdrc_debug, ("%s:get_descriptor: error num %d", __func__, ret)); + OutputBufferSize = 0; + } + + 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; +} + + + + +static int +urb_control_get_status_request(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + uint8 func_recipient, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + uint16 Index; + uint8 bmRequestType; + uint8 * buffer; + uint8 * out_data; + int offset, ret; + + if (transferDir == 0){ + LLOGLN(urbdrc_debug, ("urb_control_get_status_request: not support transfer out\n")); + return -1; + } + + 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, Index); /** Index */ + data_read_uint32(data + 8, OutputBufferSize); + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 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){ + LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d!!\n", __func__, ret)); + OutputBufferSize = 0; + usbd_status = USBD_STATUS_STALL_PID; + } + else{ + usbd_status = USBD_STATUS_SUCCESS; + } + + /** 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; +} + +static int +urb_control_vendor_or_class_request(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + uint8 func_type, + uint8 func_recipient, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, TransferFlags, usbd_status; + uint32 OutputBufferSize; + uint8 ReqTypeReservedBits, Request, bmRequestType; + uint16 Value, Index, Padding; + uint8 * buffer; + uint8 * out_data; + int offset, ret; + /** control by vendor command */ + + 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, TransferFlags); /** TransferFlags */ + data_read_uint8(data + 8, ReqTypeReservedBits); /** ReqTypeReservedBids */ + data_read_uint8(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; + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 36; + + /** Get Buffer */ + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + memcpy(buffer, data + offset, OutputBufferSize); + + /** vendor or class command */ + bmRequestType = func_type | func_recipient; + + if (TransferFlags & USBD_TRANSFER_DIRECTION) + bmRequestType |= 0x80; + + LLOGLN(urbdrc_debug, ("urb_control_vendor_or_class_request: " + "RequestId 0x%x TransferFlags: 0x%x ReqTypeReservedBits: 0x%x " + "Request:0x%x Value: 0x%x Index: 0x%x OutputBufferSize: 0x%x bmRequestType: 0x%x!!", + 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){ + LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d!!", __func__, ret)); + OutputBufferSize = 0; + usbd_status = USBD_STATUS_STALL_PID; + } + else{ + usbd_status = USBD_STATUS_SUCCESS; + } + + 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; +} + + + +static int +urb_os_feature_descriptor_request(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + uint8 Recipient, InterfaceNumber, Ms_PageIndex; + uint16 Ms_featureDescIndex; + uint8 * out_data; + uint8 * buffer; + int offset, ret; + + 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_uint8(data + 4, Recipient); /** Recipient */ + Recipient = Recipient && 0x1f; + data_read_uint8(data + 5, InterfaceNumber); /** InterfaceNumber */ + data_read_uint8(data + 6, Ms_PageIndex); /** Ms_PageIndex */ + data_read_uint16(data + 7, Ms_featureDescIndex); /** Ms_featureDescIndex */ + data_read_uint32(data + 12, OutputBufferSize); + offset = 16; + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 36; + + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + printf("Function urb_os_feature_descriptor_request: OUT Unchecked\n"); + memcpy(buffer, data + offset, OutputBufferSize); + break; + case USBD_TRANSFER_DIRECTION_IN: + break; + } + + LLOGLN(urbdrc_debug, ("Ms descriptor arg: Recipient:0x%x, " + "InterfaceNumber:0x%x, Ms_PageIndex:0x%x, " + "Ms_featureDescIndex:0x%x, OutputBufferSize:0x%x", + 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); + + if (ret < 0) + LLOGLN(urbdrc_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; +} + + + + +static int +urb_pipe_request(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir, + int action) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, PipeHandle, EndpointAddress; + uint32 OutputBufferSize, usbd_status = 0; + uint8 * out_data; + int out_offset, ret; + + if (transferDir == 0){ + LLOGLN(urbdrc_debug, ("urb_pipe_request: not support transfer out\n")); + return -1; + } + + 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); + EndpointAddress = (PipeHandle & 0x000000ff); + + + switch (action){ + case PIPE_CANCEL: + LLOGLN(urbdrc_debug, ("urb_pipe_request: PIPE_CANCEL 0x%x ", EndpointAddress)); + + ret = pdev->control_pipe_request( + pdev, RequestId, EndpointAddress, + &usbd_status, + PIPE_CANCEL); + + if (ret < 0) { + LLOGLN(urbdrc_debug, ("PIPE SET HALT: error num %d", ret)); + } + + + break; + case PIPE_RESET: + LLOGLN(urbdrc_debug, ("urb_pipe_request: PIPE_RESET ep 0x%x ", EndpointAddress)); + + ret = pdev->control_pipe_request( + pdev, RequestId, EndpointAddress, + &usbd_status, + PIPE_RESET); + + if (ret < 0) + LLOGLN(urbdrc_debug, ("PIPE RESET: error num %d!!\n", ret)); + + break; + default: + LLOGLN(urbdrc_debug, ("urb_pipe_request action: %d is not support!\n", action)); + break; + } + + + /** send data */ + out_offset = 36; + out_size = out_offset + OutputBufferSize; + out_data = (uint8 *) 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); + 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_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; +} + + + + +static int +urb_get_current_frame_number(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize; + uint32 dummy_frames; + uint8 * out_data; + + if (transferDir == 0){ + LLOGLN(urbdrc_debug, ("urb_get_current_frame_number: not support transfer out\n")); + //exit(1); + return -1; + } + + 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); + + /** Fixme: Need to fill actual frame number!!*/ + urbdrc_get_mstime(dummy_frames); + + out_size = 40; + out_data = (uint8 *) 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); + data_write_uint32(out_data + 12, RequestId); /** RequestId */ + data_write_uint32(out_data + 16, 12); /** CbTsUrbResult */ + /** TsUrbResult TS_URB_RESULT_HEADER */ + data_write_uint16(out_data + 20, 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 */ + + data_write_uint32(out_data + 32, 0); /** HResult */ + data_write_uint32(out_data + 36, 0); /** OutputBufferSize */ + + if (!pdev->isSigToEnd(pdev)) + callback->channel->Write(callback->channel, out_size, out_data, NULL); + zfree(out_data); + return 0; +} + + +/* Unused function for current server */ +static int +urb_control_get_configuration_request(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + uint8 * buffer; + uint8 * out_data; + int ret, offset; + + if (transferDir == 0){ + LLOGLN(urbdrc_debug, ("urb_control_get_configuration_request:" + " not support transfer out\n")); + return -1; + } + + 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); + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) 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){ + LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d\n", __func__, ret)); + OutputBufferSize = 0; + } + + + 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; +} + +/* Unused function for current server */ +static int +urb_control_get_interface_request(URBDRC_CHANNEL_CALLBACK * callback, + uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + uint16 interface; + uint8 * buffer; + uint8 * out_data; + int ret, offset; + + if (transferDir == 0){ + LLOGLN(urbdrc_debug, ("urb_control_get_interface_request: not support transfer out\n")); + return -1; + } + + 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); + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 36; + + ret = pdev->control_transfer(pdev, RequestId, 0, 0, 0x80 | 0x01, + 0x0A, /* REQUEST_GET_INTERFACE */ + 0, + interface, + &usbd_status, + &OutputBufferSize, + buffer, + 1000); + + if (ret < 0){ + LLOGLN(urbdrc_debug, ("%s:control_transfer: error num %d\n", __func__, ret)); + OutputBufferSize = 0; + } + + 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; +} + +static int +urb_control_feature_request(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + uint8 func_recipient, + uint8 command, + int transferDir) +{ + IUDEVICE * pdev; + uint32 out_size, RequestId, InterfaceId, OutputBufferSize, usbd_status; + uint16 FeatureSelector, Index; + uint8 bmRequestType, bmRequest; + uint8 * buffer; + uint8 * out_data; + int ret, offset; + + 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, FeatureSelector); + data_read_uint16(data + 6, Index); + data_read_uint32(data + 8, OutputBufferSize); + offset = 12; + + out_size = 36 + OutputBufferSize; + out_data = (uint8 *) malloc(out_size); + memset(out_data, 0, out_size); + + buffer = out_data + 36; + + bmRequestType = func_recipient; + switch (transferDir) + { + case USBD_TRANSFER_DIRECTION_OUT: + printf("Function urb_control_feature_request: OUT Unchecked\n"); + memcpy(buffer, data + offset, OutputBufferSize); + bmRequestType |= 0x00; + break; + case USBD_TRANSFER_DIRECTION_IN: + bmRequestType |= 0x80; + break; + } + + switch (command) + { + case URB_SET_FEATURE: + bmRequest = 0x03; /* REQUEST_SET_FEATURE */ + break; + case URB_CLEAR_FEATURE: + bmRequest = 0x01; /* REQUEST_CLEAR_FEATURE */ + break; + default: + printf("urb_control_feature_request: Error Command %x\n", command); + return -1; + } + + ret = pdev->control_transfer( + pdev, RequestId, 0, 0, bmRequestType, bmRequest, + FeatureSelector, + Index, + &usbd_status, + &OutputBufferSize, + buffer, + 1000); + + if (ret < 0){ + LLOGLN(urbdrc_debug, ("feature control transfer: error num %d", ret)); + OutputBufferSize = 0; + } + + 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; +} + +static int +urbdrc_process_transfer_request(URBDRC_CHANNEL_CALLBACK * callback, uint8 * data, + uint32 data_sizem, + uint32 MessageId, + IUDEVMAN * udevman, + uint32 UsbDevice, + int transferDir) +{ + IUDEVICE * pdev; + uint32 CbTsUrb; + uint16 Size; + uint16 URB_Function; + uint32 OutputBufferSize; + int error = 0; + + 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); + + switch (URB_Function) + { + case URB_FUNCTION_SELECT_CONFIGURATION: /** 0x0000 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SELECT_CONFIGURATION")); + error = urb_select_configuration( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + transferDir); + break; + case URB_FUNCTION_SELECT_INTERFACE: /** 0x0001 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("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 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_DEVICE")); + error = urb_control_feature_request(callback, + data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x00, + URB_SET_FEATURE, + transferDir); + break; + case URB_FUNCTION_SET_FEATURE_TO_INTERFACE: /** 0x000E */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_FEATURE_TO_INTERFACE")); + error = urb_control_feature_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x01, + URB_SET_FEATURE, + transferDir); + break; + case URB_FUNCTION_SET_FEATURE_TO_ENDPOINT: /** 0x000F */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_DEVICE: /** 0x0010 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_INTERFACE: /** 0x0011 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_ENDPOINT: /** 0x0012 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_GET_STATUS_FROM_DEVICE: /** 0x0013 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_GET_STATUS_FROM_INTERFACE: /** 0x0014 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_GET_STATUS_FROM_ENDPOINT: /** 0x0015 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_RESERVED_0X0016: /** 0x0016 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVED_0X0016")); + error = -1; + break; + case URB_FUNCTION_VENDOR_DEVICE: /** 0x0017 */ + LLOGLN(urbdrc_debug, ("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 */ + 0x00, + transferDir); + break; + case URB_FUNCTION_VENDOR_INTERFACE: /** 0x0018 */ + LLOGLN(urbdrc_debug, ("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 */ + 0x01, + transferDir); + break; + case URB_FUNCTION_VENDOR_ENDPOINT: /** 0x0019 */ + LLOGLN(urbdrc_debug, ("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 */ + 0x02, + transferDir); + break; + case URB_FUNCTION_CLASS_DEVICE: /** 0x001A */ + LLOGLN(urbdrc_debug, ("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 */ + 0x00, + transferDir); + break; + case URB_FUNCTION_CLASS_INTERFACE: /** 0x001B */ + LLOGLN(urbdrc_debug, ("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 */ + 0x01, + transferDir); + break; + case URB_FUNCTION_CLASS_ENDPOINT: /** 0x001C */ + LLOGLN(urbdrc_debug, ("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 */ + 0x02, + transferDir); + break; + case URB_FUNCTION_RESERVE_0X001D: /** 0x001D */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X001D")); + error = -1; + break; + case URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL: /** 0x001E */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_CLASS_OTHER: /** 0x001F */ + LLOGLN(urbdrc_debug, ("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 */ + 0x03, + transferDir); + break; + case URB_FUNCTION_VENDOR_OTHER: /** 0x0020 */ + LLOGLN(urbdrc_debug, ("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 */ + 0x03, + transferDir); + break; + case URB_FUNCTION_GET_STATUS_FROM_OTHER: /** 0x0021 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_CLEAR_FEATURE_TO_OTHER: /** 0x0022 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_SET_FEATURE_TO_OTHER: /** 0x0023 */ + LLOGLN(urbdrc_debug, ("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); + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT: /** 0x0024 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_ENDPOINT")); + error = urb_control_descriptor_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x02, + transferDir); + break; + case URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT: /** 0x0025 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_ENDPOINT")); + error = urb_control_descriptor_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x02, + transferDir); + break; + case URB_FUNCTION_GET_CONFIGURATION: /** 0x0026 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_CONFIGURATION")); + error = urb_control_get_configuration_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + transferDir); + break; + case URB_FUNCTION_GET_INTERFACE: /** 0x0027 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_INTERFACE")); + error = urb_control_get_interface_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + transferDir); + break; + case URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE: /** 0x0028 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_DESCRIPTOR_FROM_INTERFACE")); + error = urb_control_descriptor_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x01, + transferDir); + break; + case URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE: /** 0x0029 */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_SET_DESCRIPTOR_TO_INTERFACE")); + error = urb_control_descriptor_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + 0x01, + transferDir); + break; + case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR: /** 0x002A */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR")); + error = urb_os_feature_descriptor_request( + callback, data + 8, + data_sizem - 8, + MessageId, + udevman, + UsbDevice, + transferDir); + break; + case URB_FUNCTION_RESERVE_0X002B: /** 0x002B */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002B")); + error = -1; + break; + case URB_FUNCTION_RESERVE_0X002C: /** 0x002C */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002C")); + error = -1; + break; + case URB_FUNCTION_RESERVE_0X002D: /** 0x002D */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002D")); + error = -1; + break; + case URB_FUNCTION_RESERVE_0X002E: /** 0x002E */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002E")); + error = -1; + break; + case URB_FUNCTION_RESERVE_0X002F: /** 0x002F */ + LLOGLN(urbdrc_debug, ("URB_Func: URB_FUNCTION_RESERVE_0X002F")); + error = -1; + break; + /** USB 2.0 calls start at 0x0030 */ + case URB_FUNCTION_SYNC_RESET_PIPE: /** 0x0030 */ + LLOGLN(urbdrc_debug, ("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 */ + break; + case URB_FUNCTION_SYNC_CLEAR_STALL: /** 0x0031 */ + LLOGLN(urbdrc_debug, ("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; + break; + case URB_FUNCTION_CONTROL_TRANSFER_EX: /** 0x0032 */ + LLOGLN(urbdrc_debug, ("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); + break; + default: + LLOGLN(urbdrc_debug, ("URB_Func: %x is not found!", URB_Function)); + } + + return error; +} + +void* +urbdrc_process_udev_data_transfer(void* arg) +{ + TRANSFER_DATA* transfer_data = (TRANSFER_DATA*) arg; + URBDRC_CHANNEL_CALLBACK * callback = transfer_data->callback; + uint8 * pBuffer = transfer_data->pBuffer; + uint32 cbSize = transfer_data->cbSize; + uint32 UsbDevice = transfer_data->UsbDevice; + IUDEVMAN * udevman = transfer_data->udevman; + uint32 MessageId; + uint32 FunctionId; + IUDEVICE* pdev; + int error = 0; + pdev = udevman->get_udevice_by_UsbDevice(udevman, UsbDevice); + if (pdev == NULL || pdev->isSigToEnd(pdev)) + { + if (transfer_data) + { + if (transfer_data->pBuffer) + zfree(transfer_data->pBuffer); + zfree(transfer_data); + } + return 0; + } + + pdev->push_action(pdev); + + /* 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: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>CANCEL_REQUEST<<0x%X", FunctionId)); + error = urbdrc_process_cancel_request( + pBuffer + 8, + cbSize - 8, + udevman, + UsbDevice); + break; + case REGISTER_REQUEST_CALLBACK: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>REGISTER_REQUEST_CALLBACK<<0x%X", FunctionId)); + error = urbdrc_process_register_request_callback( + callback, + pBuffer + 8, + cbSize - 8, + udevman, + UsbDevice); + break; + case IO_CONTROL: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>IO_CONTROL<<0x%X", FunctionId)); + error = urbdrc_process_io_control( + callback, + pBuffer + 8, + cbSize - 8, + MessageId, + udevman, UsbDevice); + break; + case INTERNAL_IO_CONTROL: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>INTERNAL_IO_CONTROL<<0x%X", FunctionId)); + error = urbdrc_process_internal_io_control( + callback, + pBuffer + 8, + cbSize - 8, + MessageId, + udevman, UsbDevice); + break; + case QUERY_DEVICE_TEXT: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>QUERY_DEVICE_TEXT<<0x%X", FunctionId)); + error = urbdrc_process_query_device_text( + callback, + pBuffer + 8, + cbSize - 8, + MessageId, + udevman, + UsbDevice); + break; + case TRANSFER_IN_REQUEST: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>TRANSFER_IN_REQUEST<<0x%X", FunctionId)); + error = urbdrc_process_transfer_request( + callback, + pBuffer + 8, + cbSize - 8, + MessageId, + udevman, + UsbDevice, + USBD_TRANSFER_DIRECTION_IN); + break; + case TRANSFER_OUT_REQUEST: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>TRANSFER_OUT_REQUEST<<0x%X", FunctionId)); + error = urbdrc_process_transfer_request( + callback, + pBuffer + 8, + cbSize - 8, + MessageId, + udevman, + UsbDevice, + USBD_TRANSFER_DIRECTION_OUT); + break; + case RETRACT_DEVICE: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " >>RETRACT_DEVICE<<0x%X", FunctionId)); + error = urbdrc_process_retract_device_request( + pBuffer + 8, + cbSize - 8, + udevman, + UsbDevice); + break; + default: + LLOGLN(urbdrc_debug, ("urbdrc_process_udev_data_transfer:" + " unknown FunctionId 0x%X", FunctionId)); + error = -1; + 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; +} + + diff --git a/channels/drdynvc/urbdrc/data_transfer.h b/channels/drdynvc/urbdrc/data_transfer.h new file mode 100644 index 000000000..eb6af0a93 --- /dev/null +++ b/channels/drdynvc/urbdrc/data_transfer.h @@ -0,0 +1,41 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __DATA_TRANSFER_H +#define __DATA_TRANSFER_H + + +#include "urbdrc_main.h" + + +#define DEVICE_CTX(dev) ((dev)->ctx) +#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) +#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); + + +#endif + diff --git a/channels/drdynvc/urbdrc/isoch_queue.c b/channels/drdynvc/urbdrc/isoch_queue.c new file mode 100644 index 000000000..fe77739d1 --- /dev/null +++ b/channels/drdynvc/urbdrc/isoch_queue.c @@ -0,0 +1,195 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 int +isoch_queue_has_next(ISOCH_CALLBACK_QUEUE * queue) +{ + if (queue->curr == NULL) + return 0; + else + return 1; +} + +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*)malloc(sizeof(ISOCH_CALLBACK_DATA)); + + isoch->prev = NULL; + isoch->next = NULL; + + isoch->out_data = NULL; + isoch->out_size = 0; + 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) != 0) + { + p = queue->get_next(queue); + + if (p == isoch) /* 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--; + + /* free data info */ + isoch->out_data = NULL; + + if (isoch) 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 *)malloc(sizeof(ISOCH_CALLBACK_QUEUE)); + queue->isoch_num = 0; + queue->curr = NULL; + queue->head = NULL; + queue->tail = 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/drdynvc/urbdrc/isoch_queue.h b/channels/drdynvc/urbdrc/isoch_queue.h new file mode 100644 index 000000000..94b077375 --- /dev/null +++ b/channels/drdynvc/urbdrc/isoch_queue.h @@ -0,0 +1,69 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __ISOCH_QUEUE_H +#define __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; + uint8 * 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); + int (*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(); + + + +#endif /* __ISOCH_QUEUE_H */ diff --git a/channels/drdynvc/urbdrc/libusb/CMakeLists.txt b/channels/drdynvc/urbdrc/libusb/CMakeLists.txt new file mode 100644 index 000000000..f3ba9c242 --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/CMakeLists.txt @@ -0,0 +1,38 @@ +# FreeRDP: A Remote Desktop Protocol Client +# FreeRDP cmake build script +# +# 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. + +set(LIBUSB_UDEVMAN_SRCS + libusb_udevman.c + libusb_udevice.c + libusb_udevice.h + request_queue.c + request_queue.h +) + +include_directories(..) + +add_library(libusb_udevman ${LIBUSB_UDEVMAN_SRCS}) +set_target_properties(libusb_udevman PROPERTIES PREFIX "") + +target_link_libraries(libusb_udevman udev) +target_link_libraries(libusb_udevman dbus-glib-1) +target_link_libraries(libusb_udevman pthread) +target_link_libraries(libusb_udevman usb-1.0) +target_link_libraries(libusb_udevman freerdp-utils) + +install(TARGETS libusb_udevman DESTINATION ${FREERDP_PLUGIN_PATH}) diff --git a/channels/drdynvc/urbdrc/libusb/libusb_udevice.c b/channels/drdynvc/urbdrc/libusb/libusb_udevice.c new file mode 100644 index 000000000..9b70e9d1d --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/libusb_udevice.c @@ -0,0 +1,1903 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 + +#include "libusb_udevice.h" + +#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ +static _type udev_get_##_arg (IUDEVICE * idev) \ +{ \ + UDEVICE * pdev = (UDEVICE *) idev; \ + return pdev->_arg; \ +} \ +static void udev_set_##_arg (IUDEVICE * idev, _type _t) \ +{ \ + UDEVICE * pdev = (UDEVICE *) idev; \ + pdev->_arg = _t; \ +} + +#define BASIC_POINT_FUNC_DEFINED(_arg, _type) \ +static _type udev_get_p_##_arg (IUDEVICE * idev) \ +{ \ + UDEVICE * pdev = (UDEVICE *) idev; \ + return pdev->_arg; \ +} \ +static void udev_set_p_##_arg (IUDEVICE * idev, _type _t) \ +{ \ + UDEVICE * pdev = (UDEVICE *) idev; \ + pdev->_arg = _t; \ +} + +#define BASIC_STATE_FUNC_REGISTER(_arg, _dev) \ + _dev->iface.get_##_arg = udev_get_##_arg; \ + _dev->iface.set_##_arg = udev_set_##_arg + + +typedef struct _ISO_USER_DATA ISO_USER_DATA; +struct _ISO_USER_DATA +{ + uint8 * IsoPacket; + uint8 * output_data; + int iso_status; + int completed; + uint32 error_count; + int noack; + uint32 start_frame; +}; + +static int +get_next_timeout(libusb_context *ctx, struct timeval *tv, struct timeval *out) +{ + struct timeval timeout; + int r = libusb_get_next_timeout(ctx, &timeout); + if (r) { + /* timeout already expired? */ + if (!timerisset(&timeout)) + return 1; + + /* choose the smallest of next URB timeout or user specified timeout */ + if (timercmp(&timeout, tv, <)) + *out = timeout; + else + *out = *tv; + } else { + *out = *tv; + } + return 0; +} + +/* + * a simple wrapper to implement libusb_handle_events_timeout_completed + * function in libusb library git tree (1.0.9 later) */ +static int +handle_events_completed(libusb_context *ctx, int *completed) +{ + struct timeval tv; + tv.tv_sec = 60; + tv.tv_usec = 0; + +#ifdef HAVE_NEW_LIBUSB + return libusb_handle_events_timeout_completed(ctx, &tv, completed); +#else + int r; + struct timeval poll_timeout; + + r = get_next_timeout(ctx, &tv, &poll_timeout); + +retry: + if (libusb_try_lock_events(ctx) == 0) { + if (completed == NULL || !*completed) { + /* we obtained the event lock: do our own event handling */ + LLOGLN(10, ("doing our own event handling")); + r = libusb_handle_events_locked(ctx, &tv); + } + libusb_unlock_events(ctx); + return r; + } + + /* another thread is doing event handling. wait for thread events that + * notify event completion. */ + libusb_lock_event_waiters(ctx); + + if (completed && *completed) + goto already_done; + + if (!libusb_event_handler_active(ctx)) { + /* we hit a race: whoever was event handling earlier finished in the + * time it took us to reach this point. try the cycle again. */ + libusb_unlock_event_waiters(ctx); + LLOGLN(10, ("event handler was active but went away, retrying")); + goto retry; + } + + LLOGLN(10, ("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; + uint8 * data = iso_user_data->IsoPacket; + int * completed = &iso_user_data->completed; + uint32 offset = 0; + uint32 index = 0; + uint32 i, act_len; + uint8 *b; + + *completed = 1; + /* Fixme: currently fill the dummy frame number, tt needs to be + * filled a real frame number */ + // urbdrc_get_mstime(iso_user_data->start_frame); + if(transfer->status == LIBUSB_TRANSFER_COMPLETED && + !iso_user_data->noack) + { + for (i = 0; i < transfer->num_iso_packets; i++) + { + act_len = transfer->iso_packet_desc[i].actual_length; + data_write_uint32(data + offset, index); + data_write_uint32(data + offset + 4, act_len); + data_write_uint32(data + offset + 8, + transfer->iso_packet_desc[i].status); + offset += 12; + if (transfer->iso_packet_desc[i].status == USBD_STATUS_SUCCESS) + { + b = libusb_get_iso_packet_buffer_simple(transfer, i); + if (act_len > 0) + { + if (iso_user_data->output_data + index != b) + memcpy(iso_user_data->output_data + index, b, act_len); + index += act_len; + } + else{ + //printf("actual length %d \n", act_len); + //exit(EXIT_FAILURE); + } + } + else + { + iso_user_data->error_count++; + //print_transfer_status(transfer->iso_packet_desc[i].status); + } + } + transfer->actual_length = index; + iso_user_data->iso_status = 1; + } + else if(transfer->status == LIBUSB_TRANSFER_COMPLETED && + iso_user_data->noack) + { + /* This situation occurs when we do not need to + * return any packet */ + iso_user_data->iso_status = 1; + } + else{ + //print_status(transfer->status); + iso_user_data->iso_status = -1; + } +} + + +static const LIBUSB_ENDPOINT_DESCEIPTOR* +func_get_ep_desc(LIBUSB_CONFIG_DESCRIPTOR * LibusbConfig, + MSUSB_CONFIG_DESCRIPTOR * MsConfig, + uint32 EndpointAddress) +{ + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + const LIBUSB_INTERFACE * interface; + const LIBUSB_ENDPOINT_DESCEIPTOR * endpoint; + uint8 alt; + int inum, pnum; + + MsInterfaces = MsConfig->MsInterfaces; + interface = LibusbConfig->interface; + for(inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + alt = MsInterfaces[inum]->AlternateSetting; + endpoint = interface[inum].altsetting[alt].endpoint; + + for(pnum = 0; pnum < MsInterfaces[inum]->NumberOfPipes; pnum++) + { + if (endpoint[pnum].bEndpointAddress == EndpointAddress) + { + return &endpoint[pnum]; + } + } + } + return NULL; +} + + + +static void +func_bulk_transfer_cb(struct libusb_transfer *transfer) +{ + int *completed = transfer->user_data; + *completed = 1; + /* caller interprets results and frees transfer */ +} + + + + +static int +func_set_usbd_status(UDEVICE* pdev, uint32* status, int err_result) +{ + switch (err_result) + { + case LIBUSB_SUCCESS: + *status = USBD_STATUS_SUCCESS; + break; + case LIBUSB_ERROR_IO: + *status = USBD_STATUS_STALL_PID; + LLOGLN(10, ("urb_status: LIBUSB_ERROR_IO!!\n")); + break; + case LIBUSB_ERROR_INVALID_PARAM: + *status = USBD_STATUS_INVALID_PARAMETER; + break; + case LIBUSB_ERROR_ACCESS: + *status = USBD_STATUS_NOT_ACCESSED; + break; + case LIBUSB_ERROR_NO_DEVICE: + *status = USBD_STATUS_DEVICE_GONE; + if (pdev){ + if(!(pdev->status & URBDRC_DEVICE_NOT_FOUND)) + { + pdev->status |= URBDRC_DEVICE_NOT_FOUND; + LLOGLN(libusb_debug, ("urb_status: LIBUSB_ERROR_NO_DEVICE!!\n")); + } + } + break; + case LIBUSB_ERROR_NOT_FOUND: + *status = USBD_STATUS_STALL_PID; + break; + case LIBUSB_ERROR_BUSY: + *status = USBD_STATUS_STALL_PID; + break; + case LIBUSB_ERROR_TIMEOUT: + *status = USBD_STATUS_TIMEOUT; + break; + case LIBUSB_ERROR_OVERFLOW: + *status = USBD_STATUS_STALL_PID; + break; + case LIBUSB_ERROR_PIPE: + *status = USBD_STATUS_STALL_PID; + break; + case LIBUSB_ERROR_INTERRUPTED: + *status = USBD_STATUS_STALL_PID; + break; + case LIBUSB_ERROR_NO_MEM: + *status = USBD_STATUS_NO_MEMORY; + break; + case LIBUSB_ERROR_NOT_SUPPORTED: + *status = USBD_STATUS_NOT_SUPPORTED; + break; + case LIBUSB_ERROR_OTHER: + *status = USBD_STATUS_STALL_PID; + break; + default: + *status = USBD_STATUS_SUCCESS; + break; + } + return 0; +} + + + +static void +func_iso_data_init(ISO_USER_DATA * iso_user_data, uint32 numPacket, uint32 buffsize, + uint32 noAck, uint8 * isoPacket, uint8 * buffer) +{ + /* init struct iso_user_data */ + iso_user_data->IsoPacket = isoPacket; + iso_user_data->output_data = buffer; + iso_user_data->error_count = 0; + iso_user_data->completed = 0; + iso_user_data->noack = noAck; + urbdrc_get_mstime(iso_user_data->start_frame); +} + + + +static int +func_config_release_all_interface(LIBUSB_DEVICE_HANDLE *libusb_handle, uint32_t NumInterfaces) +{ + int i, ret; + for (i = 0; i < NumInterfaces; i++) + { + ret = libusb_release_interface (libusb_handle, i); + if (ret < 0){ + printf("config_release_all_interface: error num %d\n", ret); + return -1; + } + } + return 0; +} + + +static int +func_claim_all_interface(LIBUSB_DEVICE_HANDLE *libusb_handle, int NumInterfaces) +{ + int i, ret; + for (i = 0; i < NumInterfaces; i++) + { + ret = libusb_claim_interface (libusb_handle, i); + if (ret < 0){ + printf("claim_all_interface: error num %d\n", ret); + return -1; + } + } + return 0; +} + + + + +/* +static void* +print_transfer_status(enum libusb_transfer_status status) +{ + switch(status) + { + case LIBUSB_TRANSFER_COMPLETED: + //printf("Transfer Status: LIBUSB_TRANSFER_COMPLETED\n"); + break; + case LIBUSB_TRANSFER_ERROR: + printf("Transfer Status: LIBUSB_TRANSFER_ERROR\n"); + break; + case LIBUSB_TRANSFER_TIMED_OUT: + printf("Transfer Status: LIBUSB_TRANSFER_TIMED_OUT\n"); + break; + case LIBUSB_TRANSFER_CANCELLED: + printf("Transfer Status: LIBUSB_TRANSFER_CANCELLED\n"); + break; + case LIBUSB_TRANSFER_STALL: + printf("Transfer Status: LIBUSB_TRANSFER_STALL\n"); + break; + case LIBUSB_TRANSFER_NO_DEVICE: + printf("Transfer Status: LIBUSB_TRANSFER_NO_DEVICE\n"); + break; + case LIBUSB_TRANSFER_OVERFLOW: + printf("Transfer Status: LIBUSB_TRANSFER_OVERFLOW\n"); + break; + default: + printf("Transfer Status: Get unknow error num %d (0x%x)\n", + status, status); + } + return 0; +} + + +static void +print_status(enum libusb_transfer_status status) +{ + switch(status) + { + case LIBUSB_TRANSFER_COMPLETED: + printf("Transfer status: LIBUSB_TRANSFER_COMPLETED\n"); + break; + case LIBUSB_TRANSFER_ERROR: + printf("Transfer status: LIBUSB_TRANSFER_ERROR\n"); + break; + case LIBUSB_TRANSFER_TIMED_OUT: + printf("Transfer status: LIBUSB_TRANSFER_TIMED_OUT\n"); + break; + case LIBUSB_TRANSFER_CANCELLED: + printf("Transfer status: LIBUSB_TRANSFER_CANCELLED\n"); + break; + case LIBUSB_TRANSFER_STALL: + printf("Transfer status: LIBUSB_TRANSFER_STALL\n"); + break; + case LIBUSB_TRANSFER_NO_DEVICE: + printf("Transfer status: LIBUSB_TRANSFER_NO_DEVICE\n"); + break; + case LIBUSB_TRANSFER_OVERFLOW: + printf("Transfer status: LIBUSB_TRANSFER_OVERFLOW\n"); + break; + default: + printf("Transfer status: unknow status %d(0x%x)\n", status, status); + break; + } +} +*/ + + +static LIBUSB_DEVICE* +udev_get_libusb_dev(int bus_number, int dev_number) +{ + ssize_t total_device; + LIBUSB_DEVICE ** libusb_list; + int i; + + total_device = libusb_get_device_list(NULL, &libusb_list); + for (i = 0; i < total_device; i++) + { + if((bus_number == libusb_get_bus_number(libusb_list[i])) && + (dev_number == libusb_get_device_address(libusb_list[i]))) + return libusb_list[i]; + } + libusb_free_device_list(libusb_list, 1); + + return NULL; +} + + + +static LIBUSB_DEVICE_DESCRIPTOR* +udev_new_descript(LIBUSB_DEVICE* libusb_dev) +{ + LIBUSB_DEVICE_DESCRIPTOR* descriptor; + int ret; + + descriptor = (LIBUSB_DEVICE_DESCRIPTOR*)malloc(sizeof(LIBUSB_DEVICE_DESCRIPTOR)); + + ret = libusb_get_device_descriptor(libusb_dev, descriptor); + if (ret<0){ + printf("libusb_get_device_descriptor: ERROR!!\n"); + return NULL; + } + + return descriptor; +} + + + + /* Get HUB handle */ +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, *dev_list_entry; + struct udev_device *dev; + LIBUSB_DEVICE* libusb_dev; + int hub_found = 0; + int hub_bus = 0; + int hub_dev = 0; + int error = 0; + + udev = udev_new(); + if (!udev) { + LLOGLN(0, ("%s: Can't create udev", __func__)); + 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; + + path = udev_list_entry_get_name(dev_list_entry); + dev = udev_device_new_from_syspath(udev, path); + if (!dev) continue; + int tmp_b = atoi(udev_device_get_property_value(dev,"BUSNUM")); + int tmp_d = atoi(udev_device_get_property_value(dev,"DEVNUM")); + if (bus_number == tmp_b && dev_number == tmp_d) + { + /* get port number */ + char *p1, *p2; + const char * sysfs_path = + udev_device_get_property_value(dev,"DEVPATH"); + + p1 = (char *)sysfs_path; + do{ + p2 = p1 + 1; + p1 = strchr(p2, '.'); + }while(p1 != NULL); + + if ((p2 - sysfs_path) < (strlen(sysfs_path) - 2)) + { + p1 = (char *)sysfs_path; + do{ + + p2 = p1 + 1; + p1 = strchr(p2, '-'); + }while(p1 != NULL); + } + pdev->port_number = atoi(p2); + LLOGLN(libusb_debug, (" Port: %d", pdev->port_number)); + + /* get device path */ + p1 = (char *)sysfs_path; + do{ + p2 = p1 + 1; + p1 = strchr(p2, '/'); + }while(p1 != NULL); + memset(pdev->path, 0, 17); + strcpy(pdev->path, p2); + LLOGLN(libusb_debug, (" DevPath: %s", pdev->path)); + + /* query parent hub info */ + dev = udev_device_get_parent(dev); + if (dev != NULL) + { + hub_found = 1; + hub_bus = atoi(udev_device_get_property_value(dev,"BUSNUM")); + hub_dev = atoi(udev_device_get_property_value(dev,"DEVNUM")); + LLOGLN(libusb_debug, (" 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) + { + LLOGLN(0, ("%s: hub was not found!", __func__)); + return -1; + } + /* Get libusb hub handle */ + libusb_dev = udev_get_libusb_dev(hub_bus, hub_dev); + if (libusb_dev == NULL) + { + LLOGLN(0, ("%s: get hub libusb_dev fail!", __func__)); + return -1; + } + error = libusb_open (libusb_dev, &pdev->hub_handle); + if (error < 0) + { + LLOGLN(0, ("%s: libusb_open error!", __func__)); + return -1; + } + LLOGLN(libusb_debug, ("%s: libusb_open success!", __func__)); + /* Success! */ + return 0; +} + + + + +static int +libusb_udev_select_interface(IUDEVICE * idev, uint8 InterfaceNumber, uint8 AlternateSetting) +{ + MSUSB_CONFIG_DESCRIPTOR * MsConfig; + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + UDEVICE * pdev = (UDEVICE *) idev; + int error = 0, diff = 1; + + MsConfig = pdev->MsConfig; + if (MsConfig) + { + MsInterfaces = MsConfig->MsInterfaces; + if (MsInterfaces && + MsInterfaces[InterfaceNumber]->AlternateSetting == AlternateSetting) + { + diff = 0; + } + } + + if (diff) + { + error = libusb_set_interface_alt_setting (pdev->libusb_handle, + InterfaceNumber, AlternateSetting); + if (error < 0){ + printf("%s: Set interface altsetting get error num %d\n", + __func__, error); + } + } + + return error; +} + + + + +static MSUSB_CONFIG_DESCRIPTOR * +libusb_udev_complete_msconfig_setup(IUDEVICE * idev, MSUSB_CONFIG_DESCRIPTOR * MsConfig) +{ + UDEVICE * pdev = (UDEVICE *) idev; + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR * MsInterface; + MSUSB_PIPE_DESCRIPTOR ** MsPipes; + MSUSB_PIPE_DESCRIPTOR * MsPipe; + MSUSB_PIPE_DESCRIPTOR ** t_MsPipes; + MSUSB_PIPE_DESCRIPTOR * t_MsPipe; + LIBUSB_CONFIG_DESCRIPTOR * LibusbConfig; + const LIBUSB_INTERFACE * LibusbInterface; + const LIBUSB_INTERFACE_DESCRIPTOR * LibusbAltsetting; + const LIBUSB_ENDPOINT_DESCEIPTOR * LibusbEndpoint; + uint8 LibusbNumEndpoint; + int inum = 0, pnum = 0, MsOutSize = 0; + + LibusbConfig = pdev->LibusbConfig; + if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces) + { + printf("Select Configuration: Libusb NumberInterfaces(%d) is different " + "with MsConfig NumberInterfaces(%d)\n", + LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); + } + + /* replace MsPipes for libusb */ + MsInterfaces = MsConfig->MsInterfaces; + for (inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + /* get libusb's number of endpoints */ + LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; + LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; + LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; + t_MsPipes = (MSUSB_PIPE_DESCRIPTOR **) malloc ( LibusbNumEndpoint * + sizeof(MSUSB_PIPE_DESCRIPTOR *)); + + for (pnum = 0; pnum < LibusbNumEndpoint; pnum++) + { + t_MsPipe = (MSUSB_PIPE_DESCRIPTOR *) malloc (sizeof(MSUSB_PIPE_DESCRIPTOR)); + memset(t_MsPipe, 0, sizeof(MSUSB_PIPE_DESCRIPTOR)); + + if (pnum < MsInterface->NumberOfPipes && MsInterface->MsPipes) + { + MsPipe = MsInterface->MsPipes[pnum]; + t_MsPipe->MaximumPacketSize = MsPipe->MaximumPacketSize; + t_MsPipe->MaximumTransferSize = MsPipe->MaximumTransferSize; + t_MsPipe->PipeFlags = MsPipe->PipeFlags; + } + else + { + t_MsPipe->MaximumPacketSize = 0; + t_MsPipe->MaximumTransferSize = 0xffffffff; + t_MsPipe->PipeFlags = 0; + } + t_MsPipe->PipeHandle = 0; + t_MsPipe->bEndpointAddress = 0; + t_MsPipe->bInterval = 0; + t_MsPipe->PipeType = 0; + t_MsPipe->InitCompleted = 0; + + t_MsPipes[pnum] = t_MsPipe; + } + + msusb_mspipes_replace(MsInterface, t_MsPipes, LibusbNumEndpoint); + } + /* setup configuration */ + MsOutSize = 8; + /* ConfigurationHandle: 4 bytes + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>|| + * || bus_number | dev_number | bConfigurationValue || + * --------------------------------------------------------------- + * ***********************/ + MsConfig->ConfigurationHandle = MsConfig->bConfigurationValue | + (pdev->bus_number << 24) | + (pdev->dev_number << 16); + + MsInterfaces = MsConfig->MsInterfaces; + for (inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsOutSize += 16; + MsInterface = MsInterfaces[inum]; + /* get libusb's interface */ + LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; + LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; + /* InterfaceHandle: 4 bytes + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>|| + * || bus_number | dev_number | altsetting | interfaceNum || + * --------------------------------------------------------------- + * ***********************/ + MsInterface->InterfaceHandle = LibusbAltsetting->bInterfaceNumber + | (LibusbAltsetting->bAlternateSetting << 8) + | (pdev->dev_number << 16) + | (pdev->bus_number << 24); + + MsInterface->Length = 16 + (MsInterface->NumberOfPipes * 20); + MsInterface->bInterfaceClass = LibusbAltsetting->bInterfaceClass; + MsInterface->bInterfaceSubClass = LibusbAltsetting->bInterfaceSubClass; + MsInterface->bInterfaceProtocol = LibusbAltsetting->bInterfaceProtocol; + MsInterface->InitCompleted = 1; + + MsPipes = MsInterface->MsPipes; + LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; + for (pnum = 0; pnum < LibusbNumEndpoint; pnum++) + { + MsOutSize += 20; + MsPipe = MsPipes[pnum]; + /* get libusb's endpoint */ + LibusbEndpoint = &LibusbAltsetting->endpoint[pnum]; + /* PipeHandle: 4 bytes + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>|| + * || bus_number | dev_number | bEndpointAddress || + * --------------------------------------------------------------- + * ***********************/ + MsPipe->PipeHandle = LibusbEndpoint->bEndpointAddress + | (pdev->dev_number << 16) + | (pdev->bus_number << 24); + /* count endpoint max packet size */ + int max = LibusbEndpoint->wMaxPacketSize & 0x07ff; + uint8 attr = LibusbEndpoint->bmAttributes; + if ((attr & 0x3) == 1 || (attr & 0x3) == 3) + { + max *= (1 + ((LibusbEndpoint->wMaxPacketSize >> 11) & 3)); + } + MsPipe->MaximumPacketSize = max; + MsPipe->bEndpointAddress = LibusbEndpoint->bEndpointAddress; + MsPipe->bInterval = LibusbEndpoint->bInterval; + MsPipe->PipeType = attr & 0x3; + MsPipe->InitCompleted = 1; + } + } + MsConfig->MsOutSize = MsOutSize; + MsConfig->InitCompleted = 1; + + /* replace device's MsConfig */ + if (!(MsConfig == pdev->MsConfig)) + { + msusb_msconfig_free(pdev->MsConfig); + pdev->MsConfig = MsConfig; + } + + return MsConfig; +} + + + +static int +libusb_udev_select_configuration(IUDEVICE * idev, uint32 bConfigurationValue) +{ + UDEVICE * pdev = (UDEVICE *) idev; + MSUSB_CONFIG_DESCRIPTOR * MsConfig = pdev->MsConfig; + LIBUSB_DEVICE_HANDLE * libusb_handle = pdev->libusb_handle; + LIBUSB_DEVICE * libusb_dev = pdev->libusb_dev; + LIBUSB_CONFIG_DESCRIPTOR ** LibusbConfig = &pdev->LibusbConfig; + int ret = 0; + + if (MsConfig->InitCompleted){ + func_config_release_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + } + /* The configuration value -1 is mean to put the device in unconfigured state. */ + if (bConfigurationValue == 0) + ret = libusb_set_configuration(libusb_handle, -1); + else + ret = libusb_set_configuration(libusb_handle, bConfigurationValue); + + if (ret < 0){ + printf("libusb_set_configuration: ERROR number %d!!\n", ret); + func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + return -1; + } + else + { + ret = libusb_get_active_config_descriptor (libusb_dev, LibusbConfig); + if (ret < 0){ + printf("libusb_get_config_descriptor_by_value: ERROR number %d!!\n", ret); + func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + return -1; + } + } + + func_claim_all_interface(libusb_handle, (*LibusbConfig)->bNumInterfaces); + + return 0; +} + + + +static int +libusb_udev_control_pipe_request(IUDEVICE * idev, uint32 RequestId, + uint32 EndpointAddress, + uint32 *UsbdStatus, + int command) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int error = 0; + /* + pdev->request_queue->register_request(pdev->request_queue, RequestId, NULL, 0); + */ + switch (command){ + case PIPE_CANCEL: + /** cancel bulk or int transfer */ + idev->cancel_all_transfer_request(idev); + + //dummy_wait_s_obj(1); + /** set feature to ep (set halt)*/ + error = libusb_control_transfer(pdev->libusb_handle, + LIBUSB_ENDPOINT_OUT | LIBUSB_RECIPIENT_ENDPOINT, + LIBUSB_REQUEST_SET_FEATURE, + ENDPOINT_HALT, + EndpointAddress, + NULL, + 0, + 1000); + break; + case PIPE_RESET: + idev->cancel_all_transfer_request(idev); + + error = libusb_clear_halt(pdev->libusb_handle, EndpointAddress); + + //func_set_usbd_status(pdev, UsbdStatus, error); + break; + default: + error = -0xff; + break; + } + + *UsbdStatus = 0; + /* + if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) + printf("request_queue_unregister_request: not fount request 0x%x\n", RequestId); + */ + return error; +} + + +static int +libusb_udev_control_query_device_text(IUDEVICE * idev, uint32 TextType, + uint32 LocaleId, + uint32 * BufferSize, + uint8 * Buffer) +{ + UDEVICE * pdev = (UDEVICE *) idev; + LIBUSB_DEVICE_DESCRIPTOR * devDescriptor = pdev->devDescriptor; + char * strDesc = "Generic Usb String"; + char deviceLocation[25]; + uint8 bus_number; + uint8 device_address; + int ret = 0, i = 0; + + switch (TextType){ + case DeviceTextDescription: + ret = libusb_get_string_descriptor (pdev->libusb_handle, + devDescriptor->iProduct, + LocaleId, + Buffer, + *BufferSize); + + for(i = 0; i < ret; i++) + { + Buffer[i] = Buffer[i+2]; + } + ret -= 2; + + if (ret <= 0 || ret < 4){ + LLOGLN(libusb_debug, ("libusb_get_string_descriptor: " + "ERROR num %d, iProduct: %d!", ret, devDescriptor->iProduct)); + memcpy(Buffer, strDesc, strlen(strDesc)); + Buffer[strlen(strDesc)] = '\0'; + *BufferSize = (strlen((char *)Buffer)) * 2; + for (i = strlen((char *)Buffer); i > 0; i--) + { + Buffer[i*2] = Buffer[i]; + Buffer[(i*2)-1] = 0; + } + } + else + { + *BufferSize = ret; + } + + break; + case DeviceTextLocationInformation: + bus_number = libusb_get_bus_number(pdev->libusb_dev); + device_address = libusb_get_device_address(pdev->libusb_dev); + sprintf(deviceLocation, "Port_#%04d.Hub_#%04d", device_address, bus_number); + + for(i=0;irequest_queue->register_request(pdev->request_queue, RequestId, NULL, 0); + */ + memset(ms_string_desc, 0, 0x13); + error = libusb_control_transfer(pdev->libusb_handle, + LIBUSB_ENDPOINT_IN | Recipient, + LIBUSB_REQUEST_GET_DESCRIPTOR, + 0x03ee, + 0, + ms_string_desc, + 0x12, + Timeout); + //printf("Get ms string: result number %d", error); + if (error > 0) + { + uint8 bMS_Vendorcode; + data_read_uint8(ms_string_desc + 16, bMS_Vendorcode); + //printf("bMS_Vendorcode:0x%x", bMS_Vendorcode); + /** get os descriptor */ + error = libusb_control_transfer(pdev->libusb_handle, + LIBUSB_ENDPOINT_IN |LIBUSB_REQUEST_TYPE_VENDOR | Recipient, + bMS_Vendorcode, + (InterfaceNumber << 8) | Ms_PageIndex, + Ms_featureDescIndex, + Buffer, + *BufferSize, + Timeout); + *BufferSize = error; + } + + if (error < 0) + *UsbdStatus = USBD_STATUS_STALL_PID; + else + *UsbdStatus = USBD_STATUS_SUCCESS; + /* + if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) + printf("request_queue_unregister_request: not fount request 0x%x\n", RequestId); + */ + return error; +} + + + +static int +libusb_udev_query_device_descriptor(IUDEVICE * idev, int offset) +{ + UDEVICE * pdev = (UDEVICE *) idev; + switch (offset) + { + case B_LENGTH: + return pdev->devDescriptor->bLength; + case B_DESCRIPTOR_TYPE: + return pdev->devDescriptor->bDescriptorType; + case BCD_USB: + return pdev->devDescriptor->bcdUSB; + case B_DEVICE_CLASS: + return pdev->devDescriptor->bDeviceClass; + case B_DEVICE_SUBCLASS: + return pdev->devDescriptor->bDeviceSubClass; + case B_DEVICE_PROTOCOL: + return pdev->devDescriptor->bDeviceProtocol; + case B_MAX_PACKET_SIZE0: + return pdev->devDescriptor->bMaxPacketSize0; + case ID_VENDOR: + return pdev->devDescriptor->idVendor; + case ID_PRODUCT: + return pdev->devDescriptor->idProduct; + case BCD_DEVICE: + return pdev->devDescriptor->bcdDevice; + case I_MANUFACTURER: + return pdev->devDescriptor->iManufacturer; + case I_PRODUCT: + return pdev->devDescriptor->iProduct; + case I_SERIAL_NUMBER: + return pdev->devDescriptor->iSerialNumber; + case B_NUM_CONFIGURATIONS: + return pdev->devDescriptor->bNumConfigurations; + default: + return 0; + } + return 0; +} + + +static void +libusb_udev_detach_kernel_driver(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int i, err = 0; + 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); + LLOGLN(libusb_debug, ("libusb_kernel_driver_active = %d\n", err)); + if (err){ + err = libusb_detach_kernel_driver(pdev->libusb_handle , i); + LLOGLN(libusb_debug, ("libusb_detach_kernel_driver = %d\n", err)); + } + } + + pdev->status |= URBDRC_DEVICE_DETACH_KERNEL; + } +} + + +static void +libusb_udev_attach_kernel_driver(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int i, err = 0; + for (i = 0; i < pdev->LibusbConfig->bNumInterfaces && err != LIBUSB_ERROR_NO_DEVICE; i++) + { + err = libusb_release_interface (pdev->libusb_handle, i); + if (err < 0){ + LLOGLN(libusb_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); + LLOGLN(libusb_debug, ("libusb_attach_kernel_driver if%d = %d", i, err)); + } + } +} + + +static int +libusb_udev_is_composite_device(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return pdev->isCompositeDevice; +} + + +static int +libusb_udev_is_signal_end(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return (pdev->status & URBDRC_DEVICE_SIGNAL_END) ? 1 : 0; +} + +static int +libusb_udev_is_exist(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return (pdev->status & URBDRC_DEVICE_NOT_FOUND) ? 0 : 1; +} + + +static int +libusb_udev_is_channel_closed(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return (pdev->status & URBDRC_DEVICE_CHANNEL_CLOSED) ? 1 : 0; +} + + +static int +libusb_udev_is_already_send(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return (pdev->status & URBDRC_DEVICE_ALREADY_SEND) ? 1 : 0; +} + + +static void +libusb_udev_signal_end(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + pdev->status |= URBDRC_DEVICE_SIGNAL_END; +} + +static void +libusb_udev_channel_closed(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; +} + + +static void +libusb_udev_set_already_send(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + pdev->status |= URBDRC_DEVICE_ALREADY_SEND; +} + +static char * +libusb_udev_get_path(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + return pdev->path; +} + +static int +libusb_udev_wait_action_completion(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int error, sval; + 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) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int error = 0; + int times = 0; + + while(times < 25) + { + if(pdev->status & URBDRC_DEVICE_SIGNAL_END) + { + error = -1; + break; + } + usleep(200000); + times++; + } + + return error; +} + + +static void +libusb_udev_lock_fifo_isoch(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + pthread_mutex_lock(&pdev->mutex_isoch); +} + +static void +libusb_udev_unlock_fifo_isoch(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + pthread_mutex_unlock(&pdev->mutex_isoch); +} + + +static int +libusb_udev_query_device_port_status(IUDEVICE * idev, uint32 *UsbdStatus, + uint32 * BufferSize, + uint8 * Buffer) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int success = 0, ret; + + if (pdev->hub_handle != NULL) + { + ret = idev->control_transfer(idev, 0xffff, 0, 0, + LIBUSB_ENDPOINT_IN + | LIBUSB_REQUEST_TYPE_CLASS + | LIBUSB_RECIPIENT_OTHER, + LIBUSB_REQUEST_GET_STATUS, + 0, + pdev->port_number, + UsbdStatus, + BufferSize, + Buffer, + 1000); + + if (ret < 0){ + LLOGLN(libusb_debug, ("libusb_control_transfer: error num %d", ret)); + *BufferSize = 0; + } + else{ + LLOGLN(libusb_debug, ("PORT STATUS:0x%02x%02x%02x%02x", + Buffer[3], Buffer[2], Buffer[1], Buffer[0])); + success = 1; + } + } + return success; +} + + +static int +libusb_udev_request_queue_is_none(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + if (pdev->request_queue->request_num == 0) + return 1; + return 0; +} + + +static int +libusb_udev_isoch_transfer(IUDEVICE * idev, uint32 RequestId, uint32 EndpointAddress, + uint32 TransferFlags, + int NoAck, + uint32 *ErrorCount, + uint32 *UrbdStatus, + uint32 *StartFrame, + uint32 NumberOfPackets, + uint8 *IsoPacket, + uint32 *BufferSize, + uint8 *Buffer, + int Timeout) +{ + UDEVICE * pdev = (UDEVICE *) idev; + ISO_USER_DATA iso_user_data; + struct libusb_transfer * iso_transfer = NULL; + uint32 iso_packet_size; + int error = 0, ret = 0, submit = 0; + + + iso_packet_size = *BufferSize / NumberOfPackets; + + iso_transfer = libusb_alloc_transfer(NumberOfPackets); + if (iso_transfer == NULL) { + printf("Error: libusb_alloc_transfer.\n"); + error = -1; + } + + /** process URB_FUNCTION_IOSCH_TRANSFER */ + func_iso_data_init(&iso_user_data, NumberOfPackets, *BufferSize, + NoAck, IsoPacket, Buffer); + /** fill setting */ + libusb_fill_iso_transfer(iso_transfer, + pdev->libusb_handle, + EndpointAddress, + Buffer, + *BufferSize, + NumberOfPackets, + func_iso_callback, + &iso_user_data, + TransferFlags, + 2000); + + libusb_set_iso_packet_lengths(iso_transfer, iso_packet_size); + + if(pdev->status & (URBDRC_DEVICE_SIGNAL_END | URBDRC_DEVICE_NOT_FOUND)) + error = -1; + iso_user_data.iso_status = 0; + if (!(error < 0)) + { + submit = libusb_submit_transfer(iso_transfer); + if (submit < 0) { + LLOGLN(libusb_debug, ("Error: Failed to submit transfer (ret = %d).", submit)); + error = -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 && error >= 0 && submit >= 0) + { + if (pdev->status & URBDRC_DEVICE_NOT_FOUND){ + error = -1; + break; + } + ret = handle_events_completed(NULL, &iso_user_data.completed); + if (ret < 0) { + LLOGLN(libusb_debug, ("Error: libusb_handle_events (ret = %d).", ret)); + error = -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) + error = -1; + + *ErrorCount = iso_user_data.error_count; + *StartFrame = iso_user_data.start_frame; + *BufferSize = iso_transfer->actual_length; + libusb_free_transfer(iso_transfer); + + return error; +} + + +static int +libusb_udev_control_transfer(IUDEVICE * idev, uint32 RequestId, uint32 EndpointAddress, + uint32 TransferFlags, + uint8 bmRequestType, + uint8 Request, + uint16 Value, + uint16 Index, + uint32 *UrbdStatus, + uint32 *BufferSize, + uint8 *Buffer, + uint32 Timeout) +{ + UDEVICE * pdev = (UDEVICE *) idev; + int error = 0; + /* + pdev->request_queue->register_request(pdev->request_queue, + RequestId, NULL, 0); + */ + error = libusb_control_transfer(pdev->libusb_handle, + bmRequestType, + Request, + Value, + Index, + Buffer, + *BufferSize, + Timeout); + if (!(error < 0)) + *BufferSize = error; + func_set_usbd_status(pdev, UrbdStatus, error); + /* + if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) + printf("request_queue_unregister_request: not fount request 0x%x\n", RequestId); + */ + return error; +} + + +static int +libusb_udev_bulk_or_interrupt_transfer(IUDEVICE * idev, uint32 RequestId, + uint32 EndpointAddress, + uint32 TransferFlags, + uint32 *UsbdStatus, + uint32 *BufferSize, + uint8 *Buffer, + uint32 Timeout) +{ + UDEVICE * pdev = (UDEVICE *) idev; + const LIBUSB_ENDPOINT_DESCEIPTOR * ep_desc; + struct libusb_transfer * transfer = NULL; + TRANSFER_REQUEST * request = NULL; + uint32 transfer_type; + int completed = 0, ret = 0, submit = 0; + int transferDir = EndpointAddress & 0x80; + + /** alloc memory for urb transfer */ + transfer = libusb_alloc_transfer(0); + + ep_desc = func_get_ep_desc(pdev->LibusbConfig, pdev->MsConfig, EndpointAddress); + + if(!ep_desc){ + printf("func_get_ep_desc: endpoint 0x%x is not found!!\n", EndpointAddress); + return -1; + } + transfer_type = (ep_desc->bmAttributes) & 0x3; + + LLOGLN(libusb_debug, ("urb_bulk_or_interrupt_transfer: ep:0x%x " + "transfer_type %d flag:%d OutputBufferSize:0x%x", + EndpointAddress, transfer_type, TransferFlags, *BufferSize)); + + switch (transfer_type){ + case BULK_TRANSFER: + /** Bulk Transfer */ + //Timeout = 10000; + break; + case INTERRUPT_TRANSFER: + /** Interrupt Transfer */ + /** Sometime, we may have receive a oversized transfer request, + * it make submit urb return error, so we set the length of + * request to wMaxPacketSize */ + if (*BufferSize != (ep_desc->wMaxPacketSize)) + { + LLOGLN(libusb_debug, ("Interrupt Transfer(%s): " + "BufferSize is different than maxPacketsize(0x%x)", + ((transferDir)?"IN":"OUT"), ep_desc->wMaxPacketSize)); + if((*BufferSize) > (ep_desc->wMaxPacketSize) && + transferDir == USBD_TRANSFER_DIRECTION_IN) + (*BufferSize) = ep_desc->wMaxPacketSize; + } + Timeout = 0; + break; + default: + LLOGLN(0, ("urb_bulk_or_interrupt_transfer:" + " other transfer type 0x%X", transfer_type)); + return -1; + break; + } + + + libusb_fill_bulk_transfer(transfer, + pdev->libusb_handle, + EndpointAddress, + Buffer, + *BufferSize, + func_bulk_transfer_cb, + &completed, + TransferFlags, + 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) { + LLOGLN(libusb_debug, ("libusb_bulk_transfer: error num %d", ret)); + func_set_usbd_status(pdev, UsbdStatus, ret); + *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) { + //ret = libusb_handle_events_check(NULL, &completed); + ret = handle_events_completed(NULL, &completed); + if (ret < 0) { + if (ret == 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); + } + + *BufferSize = transfer->actual_length; + } + LLOGLN(libusb_debug, ("bulk or interrupt Transfer data size : 0x%x", *BufferSize)); + + if (request) + { + if(pdev->request_queue->unregister_request(pdev->request_queue, RequestId)) + printf("request_queue_unregister_request: not fount request 0x%x\n", RequestId); + } + + libusb_free_transfer(transfer); + + return 0; +} + + + +static void +libusb_udev_cancel_all_transfer_request(IUDEVICE * idev) +{ + UDEVICE * pdev = (UDEVICE *) idev; + REQUEST_QUEUE * request_queue = pdev->request_queue; + TRANSFER_REQUEST * request = NULL; + int ret; + 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; + } + + ret = libusb_cancel_transfer(request->transfer); + if (ret < 0){ + LLOGLN(libusb_debug, ("libusb_cancel_transfer: error num %d!!\n", ret)); + } + else + { + request->submit = -1; + } + + } + pthread_mutex_unlock(&request_queue->request_loading); +} + + +static int +func_cancel_xact_request(TRANSFER_REQUEST *request) +{ + int ret; + + if (!request->transfer || + request->endpoint != request->transfer->endpoint || + request->transfer->endpoint == 0 || + request->submit != 1) + { + return 0; + } + + ret = libusb_cancel_transfer(request->transfer); + if (ret < 0){ + LLOGLN(0, ("libusb_cancel_transfer: error num %d!!", ret)); + if(ret == LIBUSB_ERROR_NOT_FOUND) + return -1; + } + else + { + LLOGLN(libusb_debug, ("libusb_cancel_transfer: Success num:0x%x!!", + request->RequestId)); + request->submit = -1; + return 1; + } + return 0; +} + + +static int +libusb_udev_cancel_transfer_request(IUDEVICE * idev, uint32 RequestId) +{ + UDEVICE * pdev = (UDEVICE *) idev; + REQUEST_QUEUE * request_queue = pdev->request_queue; + TRANSFER_REQUEST * request = NULL; + int success = 0, retry_times = 0; + +cancel_retry: + pthread_mutex_lock(&request_queue->request_loading); + + request_queue->rewind (request_queue); + while (request_queue->has_next (request_queue)) + { + request = request_queue->get_next (request_queue); + LLOGLN(libusb_debug, ("%s: CancelId:0x%x RequestId:0x%x endpoint 0x%x!!", + __func__, RequestId, request->RequestId, request->endpoint)); + if (request && request->RequestId == RequestId && retry_times <= 10 ) + { + success = func_cancel_xact_request(request); + break; + } + else if(request->transfer && retry_times > 10){ + success = -1; + break; + } + } + pthread_mutex_unlock(&request_queue->request_loading); + if (success == 0 && retry_times < 10){ + retry_times++; + usleep(100000); + LLOGLN(10, ("urbdrc_process_cancel_request: go retry!!")); + goto cancel_retry; + } + else if(success < 0 || retry_times >= 10){ + /** END */ + LLOGLN(libusb_debug, ("urbdrc_process_cancel_request: error go exit!!")); + return -1; + } + LLOGLN(libusb_debug, ("urbdrc_process_cancel_request: success!!")); + + return 0; +} + +BASIC_STATE_FUNC_DEFINED(channel_id, uint32) +BASIC_STATE_FUNC_DEFINED(UsbDevice, uint32) +BASIC_STATE_FUNC_DEFINED(ReqCompletion, uint32) +BASIC_STATE_FUNC_DEFINED(bus_number, uint16) +BASIC_STATE_FUNC_DEFINED(dev_number, uint16) +BASIC_STATE_FUNC_DEFINED(port_number, int) +BASIC_STATE_FUNC_DEFINED(isoch_queue, void *) +BASIC_STATE_FUNC_DEFINED(MsConfig, MSUSB_CONFIG_DESCRIPTOR *) + +BASIC_POINT_FUNC_DEFINED(udev, void *) +BASIC_POINT_FUNC_DEFINED(prev, void *) +BASIC_POINT_FUNC_DEFINED(next, void *) + + + +static void +udev_load_interface(UDEVICE * pdev) +{ + /* load interface */ + + /* Basic */ + BASIC_STATE_FUNC_REGISTER(channel_id, pdev); + BASIC_STATE_FUNC_REGISTER(UsbDevice, pdev); + BASIC_STATE_FUNC_REGISTER(ReqCompletion, pdev); + BASIC_STATE_FUNC_REGISTER(bus_number, pdev); + BASIC_STATE_FUNC_REGISTER(dev_number, pdev); + BASIC_STATE_FUNC_REGISTER(port_number, pdev); + BASIC_STATE_FUNC_REGISTER(isoch_queue, pdev); + BASIC_STATE_FUNC_REGISTER(MsConfig, pdev); + + BASIC_STATE_FUNC_REGISTER(p_udev, pdev); + BASIC_STATE_FUNC_REGISTER(p_prev, pdev); + BASIC_STATE_FUNC_REGISTER(p_next, pdev); + + pdev->iface.isCompositeDevice = libusb_udev_is_composite_device; + pdev->iface.isSigToEnd = libusb_udev_is_signal_end; + pdev->iface.isExist = libusb_udev_is_exist; + pdev->iface.isAlreadySend = libusb_udev_is_already_send; + pdev->iface.isChannelClosed = libusb_udev_is_channel_closed; + pdev->iface.SigToEnd = libusb_udev_signal_end; + pdev->iface.setAlreadySend = libusb_udev_set_already_send; + pdev->iface.setChannelClosed = libusb_udev_channel_closed; + pdev->iface.getPath = libusb_udev_get_path; + + /* Transfer */ + pdev->iface.isoch_transfer = libusb_udev_isoch_transfer; + pdev->iface.control_transfer = libusb_udev_control_transfer; + pdev->iface.bulk_or_interrupt_transfer = libusb_udev_bulk_or_interrupt_transfer; + + pdev->iface.select_interface = libusb_udev_select_interface; + pdev->iface.select_configuration = libusb_udev_select_configuration; + pdev->iface.complete_msconfig_setup = libusb_udev_complete_msconfig_setup; + pdev->iface.control_pipe_request = libusb_udev_control_pipe_request; + pdev->iface.control_query_device_text = libusb_udev_control_query_device_text; + pdev->iface.os_feature_descriptor_request = libusb_udev_os_feature_descriptor_request; + pdev->iface.cancel_all_transfer_request = libusb_udev_cancel_all_transfer_request; + pdev->iface.cancel_transfer_request = libusb_udev_cancel_transfer_request; + pdev->iface.query_device_descriptor = libusb_udev_query_device_descriptor; + pdev->iface.detach_kernel_driver = libusb_udev_detach_kernel_driver; + pdev->iface.attach_kernel_driver = libusb_udev_attach_kernel_driver; + pdev->iface.wait_action_completion = libusb_udev_wait_action_completion; + pdev->iface.push_action = libusb_udev_push_action; + pdev->iface.complete_action = libusb_udev_complete_action; + pdev->iface.lock_fifo_isoch = libusb_udev_lock_fifo_isoch; + pdev->iface.unlock_fifo_isoch = libusb_udev_unlock_fifo_isoch; + pdev->iface.query_device_port_status = libusb_udev_query_device_port_status; + pdev->iface.request_queue_is_none = libusb_udev_request_queue_is_none; + pdev->iface.wait_for_detach = libusb_udev_wait_for_detach; +} + + + + +static IUDEVICE* +udev_init(UDEVICE* pdev, uint16 bus_number, uint16 dev_number) +{ + LIBUSB_DEVICE_DESCRIPTOR* devDescriptor; + LIBUSB_CONFIG_DESCRIPTOR* config_temp; + LIBUSB_INTERFACE_DESCRIPTOR interface_temp; + int ret, num; + + /* Get HUB handle */ + ret = udev_get_hub_handle(pdev, bus_number, dev_number); + if (ret < 0) + { + printf("USB init: Error to get HUB handle!!\n"); + pdev->hub_handle = NULL; + } + + pdev->devDescriptor = udev_new_descript(pdev->libusb_dev); + if (!pdev->devDescriptor) + { + printf("USB init: Error to get device descriptor!!\n"); + zfree(pdev); + return NULL; + } + + num = pdev->devDescriptor->bNumConfigurations; + + ret = libusb_get_active_config_descriptor (pdev->libusb_dev, &pdev->LibusbConfig); + if (ret<0){ + printf("libusb_get_descriptor: ERROR!!ret:%d\n", ret); + zfree(pdev); + return NULL; + } + config_temp = pdev->LibusbConfig; + /* get the first interface and first altsetting */ + interface_temp = config_temp->interface[0].altsetting[0]; + + LLOGLN(0, ("Regist Device: Vid: 0x%04X Pid: 0x%04X" + " InterfaceClass = 0x%X", + 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: + printf(" Device is not support!!\n"); + zfree(pdev); + return NULL; + default: + break; + } + + /* Check composite device */ + devDescriptor = pdev->devDescriptor; + if(devDescriptor->bNumConfigurations == 1 && + config_temp->bNumInterfaces > 1 && + devDescriptor->bDeviceClass == 0x0) + { + pdev->isCompositeDevice = 1; + } + else if(devDescriptor->bDeviceClass == 0xef && + devDescriptor->bDeviceSubClass == 0x02 && + devDescriptor->bDeviceProtocol == 0x01 ) + { + pdev->isCompositeDevice = 1; + } + else + { + pdev->isCompositeDevice = 0; + } + + /* set device class to first interface class */ + devDescriptor->bDeviceClass = interface_temp.bInterfaceClass; + devDescriptor->bDeviceSubClass = interface_temp.bInterfaceSubClass; + devDescriptor->bDeviceProtocol = interface_temp.bInterfaceProtocol; + + /* initialize pdev */ + pdev->prev = NULL; + pdev->next = NULL; + pdev->bus_number = bus_number; + pdev->dev_number = dev_number; + pdev->status = 0; + pdev->ReqCompletion = 0; + pdev->channel_id = 0xffff; + pdev->request_queue = request_queue_new(); + pdev->isoch_queue = NULL; + sem_init(&pdev->sem_id, 0, 0); + /* set config of windows */ + pdev->MsConfig = msusb_msconfig_new(); + + pthread_mutex_init(&pdev->mutex_isoch, NULL); + + //deb_config_msg(pdev->libusb_dev, config_temp, devDescriptor->bNumConfigurations); + + udev_load_interface(pdev); + + return (IUDEVICE *)pdev; +} + + + +int +udev_new_by_id(uint16 idVendor, uint16 idProduct, IUDEVICE *** devArray) +{ + LIBUSB_DEVICE_DESCRIPTOR * descriptor; + LIBUSB_DEVICE ** libusb_list; + UDEVICE ** array; + uint16 bus_number; + uint16 dev_number; + ssize_t total_device; + int i, ret, num = 0; + + array = (UDEVICE **) malloc (16 * sizeof (UDEVICE *)); + + total_device = libusb_get_device_list(NULL, &libusb_list); + for (i = 0; i < total_device; i++) + { + descriptor = udev_new_descript(libusb_list[i]); + if(descriptor->idVendor == idVendor && + descriptor->idProduct == idProduct) + { + bus_number = 0; + dev_number = 0; + array[num] = (PUDEVICE)malloc(sizeof(UDEVICE)); + array[num]->libusb_dev = libusb_list[i]; + ret = libusb_open (libusb_list[i], &array[num]->libusb_handle); + if (ret < 0){ + printf("libusb_open: ERROR!!\n"); + zfree(descriptor); + zfree(array[num]); + continue; + } + bus_number = libusb_get_bus_number (libusb_list[i]); + dev_number = libusb_get_device_address (libusb_list[i]); + array[num] = (PUDEVICE)udev_init(array[num], bus_number, dev_number); + if (array[num] != NULL) + num++; + } + zfree(descriptor); + } + libusb_free_device_list(libusb_list, 1); + + *devArray = (IUDEVICE **)array; + return num; +} + +IUDEVICE * +udev_new_by_addr(int bus_number, int dev_number) +{ + UDEVICE* pDev; + int ret; + + LLOGLN(10, ("bus:%d dev:%d\n", 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){ + printf("libusb_device_new: ERROR!!\n"); + zfree(pDev); + return NULL; + } + + ret = libusb_open (pDev->libusb_dev, &pDev->libusb_handle); + if (ret < 0){ + printf("libusb_open: ERROR!!\n"); + zfree(pDev); + return NULL; + } + + return udev_init(pDev, bus_number, dev_number); +} diff --git a/channels/drdynvc/urbdrc/libusb/libusb_udevice.h b/channels/drdynvc/urbdrc/libusb/libusb_udevice.h new file mode 100644 index 000000000..e75dc18f1 --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/libusb_udevice.h @@ -0,0 +1,86 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __LIBUSB_UDEVICE_H +#define __LIBUSB_UDEVICE_H + +#include + +#include "urbdrc_types.h" +#include "request_queue.h" +#include "urbdrc_main.h" + + + +typedef struct libusb_device LIBUSB_DEVICE; +typedef struct libusb_device_handle LIBUSB_DEVICE_HANDLE; +typedef struct libusb_device_descriptor LIBUSB_DEVICE_DESCRIPTOR; +typedef struct libusb_config_descriptor LIBUSB_CONFIG_DESCRIPTOR; +typedef struct libusb_interface LIBUSB_INTERFACE; +typedef struct libusb_interface_descriptor LIBUSB_INTERFACE_DESCRIPTOR; +typedef struct libusb_endpoint_descriptor LIBUSB_ENDPOINT_DESCEIPTOR; + + +typedef struct _UDEVICE UDEVICE; +struct _UDEVICE +{ + IUDEVICE iface; + + void * udev; + void * prev; + void * next; + + uint32 UsbDevice; /* An unique interface ID */ + uint32 ReqCompletion; /* An unique interface ID */ + uint32 channel_id; + uint16 status; + uint16 bus_number; + uint16 dev_number; + char path[17]; + int port_number; + int isCompositeDevice; + + LIBUSB_DEVICE_HANDLE * libusb_handle; + LIBUSB_DEVICE_HANDLE * hub_handle; + LIBUSB_DEVICE * libusb_dev; + LIBUSB_DEVICE_DESCRIPTOR * devDescriptor; + MSUSB_CONFIG_DESCRIPTOR * MsConfig; + LIBUSB_CONFIG_DESCRIPTOR * LibusbConfig; + + REQUEST_QUEUE * request_queue; + /* Used in isochronous transfer */ + void * isoch_queue; + + pthread_mutex_t mutex_isoch; + sem_t sem_id; +}; +typedef UDEVICE * PUDEVICE; + + +int +udev_new_by_id(uint16_t idVendor, uint16_t idProduct, IUDEVICE ***devArray); +IUDEVICE* +udev_new_by_addr(int bus_number, int dev_number); + +extern int libusb_debug; + +#endif /* __LIBUSB_UDEVICE_H */ diff --git a/channels/drdynvc/urbdrc/libusb/libusb_udevman.c b/channels/drdynvc/urbdrc/libusb/libusb_udevman.c new file mode 100644 index 000000000..5e31fb66a --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/libusb_udevman.c @@ -0,0 +1,567 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 "urbdrc_types.h" +#include "urbdrc_main.h" +#include "libusb_udevice.h" + +int libusb_debug; + +#define BASIC_STATE_FUNC_DEFINED(_arg, _type) \ +static _type udevman_get_##_arg (IUDEVMAN * idevman) \ +{ \ + UDEVMAN * udevman = (UDEVMAN *) idevman; \ + return udevman->_arg; \ +} \ +static void udevman_set_##_arg (IUDEVMAN * idevman, _type _t) \ +{ \ + UDEVMAN * udevman = (UDEVMAN *) idevman; \ + udevman->_arg = _t; \ +} + +#define BASIC_STATE_FUNC_REGISTER(_arg, _man) \ + _man->iface.get_##_arg = udevman_get_##_arg; \ + _man->iface.set_##_arg = udevman_set_##_arg + + +typedef struct _UDEVMAN UDEVMAN; +struct _UDEVMAN +{ + IUDEVMAN iface; + + IUDEVICE* idev; /* iterator device */ + IUDEVICE* head; /* head device in linked list */ + IUDEVICE* tail; /* tail device in linked list */ + + uint32 defUsbDevice; + uint16 flags; + int device_num; + int sem_timeout; + + pthread_mutex_t devman_loading; + sem_t sem_urb_lock; +}; +typedef UDEVMAN * PUDEVMAN; + + + +static void +udevman_rewind(IUDEVMAN * idevman) +{ + UDEVMAN * udevman = (UDEVMAN *) idevman; + udevman->idev = udevman->head; +} + +static int +udevman_has_next(IUDEVMAN * idevman) +{ + UDEVMAN * udevman = (UDEVMAN *) idevman; + if (udevman->idev == NULL) + return 0; + else + return 1; +} + +static IUDEVICE* +udevman_get_next(IUDEVMAN * idevman) +{ + UDEVMAN * udevman = (UDEVMAN *) idevman; + IUDEVICE* pdev; + + pdev = udevman->idev; + udevman->idev = (IUDEVICE*) ((UDEVICE*)udevman->idev)->next; + + return pdev; +} + + +static IUDEVICE* +udevman_get_udevice_by_addr(IUDEVMAN * idevman, int bus_number, int dev_number) +{ + IUDEVICE * pdev; + + idevman->loading_lock(idevman); + idevman->rewind (idevman); + while (idevman->has_next (idevman)) + { + 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; + } + } + idevman->loading_unlock(idevman); + LLOGLN(libusb_debug, ("%s: bus:%d dev:%d not exist in udevman", + __func__, bus_number, dev_number)); + return NULL; +} + + + +static int +udevman_register_udevice(IUDEVMAN* idevman, int bus_number, int dev_number, + int UsbDevice, + uint16 idVendor, + uint16 idProduct, + int flag) +{ + UDEVMAN * udevman = (UDEVMAN *) idevman; + IUDEVICE * pdev = NULL; + IUDEVICE ** devArray; + int i, num, addnum = 0; + + pdev = (IUDEVICE *)udevman_get_udevice_by_addr(idevman, bus_number, dev_number); + if (pdev != NULL) + return 0; + + if (flag == UDEVMAN_FLAG_ADD_BY_ADDR) + { + pdev = udev_new_by_addr(bus_number, dev_number); + if (pdev == NULL) + return 0; + + pdev->set_UsbDevice(pdev, UsbDevice); + idevman->loading_lock(idevman); + if (udevman->head == NULL) + { + /* linked list is empty */ + udevman->head = pdev; + udevman->tail = pdev; + } + 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->device_num += 1; + idevman->loading_unlock(idevman); + } + else if (flag == UDEVMAN_FLAG_ADD_BY_VID_PID) + { + addnum = 0; + /* register all device that match pid vid */ + num = udev_new_by_id(idVendor, idProduct, &devArray); + for (i = 0; i < num; i++) + { + pdev = devArray[i]; + if (udevman_get_udevice_by_addr(idevman, + pdev->get_bus_number(pdev), + pdev->get_dev_number(pdev)) + != NULL) + { + zfree(pdev); + continue; + } + + pdev->set_UsbDevice(pdev, UsbDevice); + idevman->loading_lock(idevman); + if (udevman->head == NULL) + { + /* linked list is empty */ + udevman->head = pdev; + udevman->tail = pdev; + } + 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->device_num += 1; + idevman->loading_unlock(idevman); + addnum++; + } + zfree(devArray); + return addnum; + } + else + { + printf("udevman_register_udevice: function error!!"); + return 0; + } + return 1; +} + + +static int +udevman_unregister_udevice(IUDEVMAN * idevman, int bus_number, int 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); + + idevman->loading_lock(idevman); + idevman->rewind(idevman); + while (idevman->has_next(idevman) != 0) + { + pdev = (UDEVICE *)idevman->get_next(idevman); + + if (pdev == dev) /* device exists */ + { + /* set previous device to point to next device */ + + if (dev->prev != NULL) + { + /* unregistered device is not the head */ + 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 */ + pdev = (UDEVICE *)dev->next; + pdev->prev = dev->prev; + } + else + { + /* unregistered device is the tail, update tail */ + udevman->tail = (IUDEVICE*)dev->prev; + } + udevman->device_num--; + + break; + } + } + idevman->loading_unlock(idevman); + + if (dev) + { + /* reset device */ + if (err != LIBUSB_ERROR_NO_DEVICE) + { + ret = libusb_reset_device(dev->libusb_handle); + if (ret<0){ + LLOGLN(10, ("libusb_reset_device: ERROR!!ret:%d\n", 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 */ + } + + + /* if we reach this point, the device wasn't found */ + return 0; +} + +static void +udevman_parse_device_addr (char *str, int *id1, int *id2, char sign) +{ + char s1[8], *s2; + memset(s1, 0, sizeof(s1)); + + s2 = (strchr(str, sign)) + 1; + strncpy(s1, str, strlen(str) - (strlen(s2)+1)); + + *id1 = atoi(s1); + *id2 = atoi(s2); +} + +static void +udevman_parse_device_pid_vid (char *str, int *id1, int *id2, char sign) +{ + char s1[8], *s2; + memset(s1, 0, sizeof(s1)); + + s2 = (strchr(str, sign)) + 1; + strncpy(s1, str, strlen(str) - (strlen(s2)+1)); + + *id1 = (int) strtol(s1, NULL, 16); + *id2 = (int) strtol(s2, NULL, 16); +} + + +static int +udevman_check_device_exist_by_id(IUDEVMAN * idevman, uint16 idVendor, uint16 idProduct) +{ + if (libusb_open_device_with_vid_pid (NULL, idVendor, idProduct)) + return 1; + + return 0; +} + + +static int +udevman_is_auto_add(IUDEVMAN * idevman) +{ + UDEVMAN * udevman = (UDEVMAN *) 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; + 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); + /* try again */ + pdev = (UDEVICE *)idevman->get_udevice_by_UsbDevice_try_again(idevman, UsbDevice); + if (pdev) + { + return (IUDEVICE *)pdev; + } + + LLOGLN(libusb_debug, ("udevman_get_udevice_by_UsbDevice: 0x%x ERROR!!\n", + UsbDevice)); + return NULL; +} + + +static void +udevman_loading_lock(IUDEVMAN * idevman) +{ + UDEVMAN * udevman = (UDEVMAN *) idevman; + pthread_mutex_lock(&udevman->devman_loading); +} + +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); +} + + +BASIC_STATE_FUNC_DEFINED(defUsbDevice, uint32) +BASIC_STATE_FUNC_DEFINED(device_num, int) +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) + zfree(udevman); +} + + +static void +udevman_load_interface(UDEVMAN * udevman) +{ + /* standard */ + udevman->iface.free = udevman_free; + /* manage devices */ + udevman->iface.rewind = udevman_rewind; + udevman->iface.get_next = udevman_get_next; + udevman->iface.has_next = udevman_has_next; + 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; + /* Basic state */ + BASIC_STATE_FUNC_REGISTER(defUsbDevice, udevman); + BASIC_STATE_FUNC_REGISTER(device_num, udevman); + BASIC_STATE_FUNC_REGISTER(sem_timeout, 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; +} + + + +int FreeRDPUDEVMANEntry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints) +{ + UDEVMAN* udevman; + RDP_PLUGIN_DATA * plugin_data = pEntryPoints->plugin_data; + uint32 UsbDevice = BASE_USBDEVICE_NUM; + char * token; + char * message = "id"; + char hardware_id[16]; + int idVendor; + int idProduct; + int bus_number; + int dev_number; + int success = 0; + + libusb_init(NULL); + + udevman = (PUDEVMAN)malloc(sizeof(UDEVMAN)); + 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); + + /* load usb device service management */ + udevman_load_interface(udevman); + + /* set debug flag, to enable Debug message for usb data transfer*/ + if (plugin_data->data[2]) + message = (char *)plugin_data->data[2]; + + if (strstr(message, "id")) + udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID; + else if (strstr(message, "addr")) + udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR; + + if (strstr(message, "auto")) + udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO; + libusb_debug = 10; + if (strstr(message, "debug")) + { + libusb_debug = 0; + udevman->flags |= UDEVMAN_FLAG_DEBUG; + } + /* register all usb device */ + token = strtok((char *)plugin_data->data[1], "#"); + while (token) + { + bus_number = 0; + dev_number = 0; + idVendor = 0; + idProduct = 0; + + 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); + } + else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR) + { + udevman_parse_device_addr(hardware_id, &bus_number, + &dev_number, + '_'); + success = udevman->iface.register_udevice((IUDEVMAN *)udevman, + bus_number, + dev_number, + UsbDevice, + 0, + 0, + UDEVMAN_FLAG_ADD_BY_ADDR); + } + + if (success) + UsbDevice++; + } + + udevman->defUsbDevice = UsbDevice; + + pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*) udevman); + + return 0; +} diff --git a/channels/drdynvc/urbdrc/libusb/request_queue.c b/channels/drdynvc/urbdrc/libusb/request_queue.c new file mode 100644 index 000000000..e7f897864 --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/request_queue.c @@ -0,0 +1,188 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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, + uint8 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, uint8 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); + printf("request_queue_get_request_by_id: ERROR!!\n"); + 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/drdynvc/urbdrc/libusb/request_queue.h b/channels/drdynvc/urbdrc/libusb/request_queue.h new file mode 100644 index 000000000..0ea275263 --- /dev/null +++ b/channels/drdynvc/urbdrc/libusb/request_queue.h @@ -0,0 +1,65 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __REQUEST_QUEUE_H +#define __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; + uint8 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, uint8 ep); + TRANSFER_REQUEST *(*register_request) (REQUEST_QUEUE* queue, + uint32 RequestId, struct libusb_transfer * transfer, uint8 endpoint); +}; + + +REQUEST_QUEUE* request_queue_new(); + + +#endif /* __REQUEST_QUEUE_H */ diff --git a/channels/drdynvc/urbdrc/searchman.c b/channels/drdynvc/urbdrc/searchman.c new file mode 100644 index 000000000..bfb4d56ce --- /dev/null +++ b/channels/drdynvc/urbdrc/searchman.c @@ -0,0 +1,237 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 "searchman.h" + +static void +searchman_rewind(USB_SEARCHMAN* searchman) +{ + searchman->idev = searchman->head; +} + +static int +searchman_has_next(USB_SEARCHMAN* searchman) +{ + if (searchman->idev == NULL) + return 0; + else + return 1; +} + +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 int +searchman_list_add(USB_SEARCHMAN* searchman, uint16 idVendor, uint16 idProduct) +{ + USB_SEARCHDEV* search; + + search = (USB_SEARCHDEV*)malloc(sizeof(USB_SEARCHDEV)); + + search->prev = NULL; + search->next = NULL; + search->idVendor = idVendor; + search->idProduct = idProduct; + + if (searchman->head == NULL) + { + /* linked list is empty */ + searchman->head = search; + searchman->tail = search; + } + else + { + /* append device to the end of the linked list */ + searchman->tail->next = (void*)search; + search->prev = (void*)searchman->tail; + searchman->tail = search; + } + searchman->usb_numbers += 1; + + return 1; +} + + +static int +searchman_list_remove(USB_SEARCHMAN* searchman, uint16 idVendor, + uint16 idProduct) +{ + USB_SEARCHDEV* search; + USB_SEARCHDEV* point; + + searchman_rewind(searchman); + while (searchman_has_next(searchman) != 0) + { + point = searchman_get_next(searchman); + + 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 */ + point = (USB_SEARCHDEV*)search->prev; + point->next = search->next; + } + else + { + /* unregistered device is the head, update head */ + searchman->head = (USB_SEARCHDEV*)search->next; + } + + /* set next device to point to previous device */ + + if (search->next != NULL) + { + /* unregistered device is not the tail */ + point = (USB_SEARCHDEV*)search->next; + point->prev = search->prev; + } + else + { + /* unregistered device is the tail, update tail */ + searchman->tail = (USB_SEARCHDEV*)search->prev; + } + searchman->usb_numbers--; + + free(search); + + return 1; /* unregistration successful */ + } + } + + /* if we reach this point, the device wasn't found */ + return 0; +} + + + +static void +searchman_start(USB_SEARCHMAN* self, void * func) +{ + pthread_t thread; + + /* create search thread */ + pthread_create(&thread, 0, func, self); + pthread_detach(thread); + self->strated = 1; +} + +/* close thread */ +static void +searchman_close(USB_SEARCHMAN* self) +{ + wait_obj_set(self->term_event); +} + + +static void +searchman_list_show(USB_SEARCHMAN* self) +{ + USB_SEARCHDEV* usb; + int num = 0; + + printf("=========== Usb Search List ========= \n"); + self->rewind(self); + while (self->has_next(self)) + { + usb = self->get_next(self); + printf(" USB %d: \n", num++); + printf(" idVendor: 0x%04X \n", usb->idVendor); + printf(" idProduct: 0x%04X \n", usb->idProduct); + } + printf("================= END =============== \n"); +} + + +void +searchman_free(USB_SEARCHMAN* self) +{ + USB_SEARCHDEV * dev; + + while (self->head != NULL) + { + dev = (USB_SEARCHDEV *)self->head; + self->remove (self, dev->idVendor, dev->idProduct); + } + + /* free searchman */ + sem_destroy(&self->sem_term); + wait_obj_free(self->term_event); + free(self); +} + + +USB_SEARCHMAN* +searchman_new(void * urbdrc, uint32 UsbDevice) +{ + USB_SEARCHMAN* searchman; + int ret; + searchman = (USB_SEARCHMAN*)malloc(sizeof(USB_SEARCHMAN)); + + searchman->idev = NULL; + searchman->head = NULL; + searchman->tail = NULL; + searchman->usb_numbers = 0; + searchman->urbdrc = urbdrc; + searchman->UsbDevice = UsbDevice; + + ret = pthread_mutex_init(&searchman->mutex, NULL); + if (ret != 0) + { + printf("searchman mutex initialization: searchman->mutex failed"); + exit(EXIT_FAILURE); + } + + /* load service */ + searchman->add = searchman_list_add; + searchman->remove = searchman_list_remove; + searchman->rewind = searchman_rewind; + 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->strated = 0; + searchman->term_event = wait_obj_new(); + sem_init(&searchman->sem_term, 0, 0); + + return searchman; +} diff --git a/channels/drdynvc/urbdrc/searchman.h b/channels/drdynvc/urbdrc/searchman.h new file mode 100644 index 000000000..0a690d1b8 --- /dev/null +++ b/channels/drdynvc/urbdrc/searchman.h @@ -0,0 +1,77 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __SEACH_MAN_H +#define __SEACH_MAN_H + +#include "urbdrc_types.h" +#include + +typedef struct _USB_SEARCHDEV USB_SEARCHDEV; +struct _USB_SEARCHDEV +{ + void * inode; + void * prev; + void * next; + uint16 idVendor; + uint16 idProduct; +}; + +typedef struct _USB_SEARCHMAN USB_SEARCHMAN; +struct _USB_SEARCHMAN +{ + int usb_numbers; + uint32 UsbDevice; + USB_SEARCHDEV * idev; /* iterator device */ + USB_SEARCHDEV * head; /* head device in linked list */ + USB_SEARCHDEV * tail; /* tail device in linked list */ + + pthread_mutex_t mutex; + struct wait_obj * term_event; + sem_t sem_term; + int strated; + + /* for urbdrc channel call back */ + void * urbdrc; + + /* load service */ + void (*rewind) (USB_SEARCHMAN* seachman); + /* show all device in the list */ + void (*show) (USB_SEARCHMAN* self); + /* start searchman */ + void (*start) (USB_SEARCHMAN* self, void * func); + /* close searchman */ + void (*close) (USB_SEARCHMAN* self); + /* add a new usb device for search */ + int (*add) (USB_SEARCHMAN* seachman, uint16 idVendor, uint16 idProduct); + /* remove a usb device from list */ + int (*remove) (USB_SEARCHMAN* searchman, uint16 idVendor, uint16 idProduct); + /* check list has next device*/ + int (*has_next) (USB_SEARCHMAN* seachman); + /* get the device from list*/ + USB_SEARCHDEV* (*get_next) (USB_SEARCHMAN* seachman); + /* free! */ + void (*free) (USB_SEARCHMAN* searchman); +}; + +USB_SEARCHMAN * searchman_new(void * urbdrc, uint32 UsbDevice); + +#endif + diff --git a/channels/drdynvc/urbdrc/urbdrc_main.c b/channels/drdynvc/urbdrc/urbdrc_main.c new file mode 100644 index 000000000..e2e1e8efb --- /dev/null +++ b/channels/drdynvc/urbdrc/urbdrc_main.c @@ -0,0 +1,1073 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 +#include + +#include + +#include "urbdrc_types.h" +#include "dvcman.h" +#include "urbdrc_main.h" +#include "data_transfer.h" +#include "searchman.h" + +int urbdrc_debug = 0; + +static int +func_hardware_id_format(IUDEVICE * pdev, char (*HardwareIds)[DEVICE_HARDWARE_ID_SIZE]) +{ + char str[DEVICE_HARDWARE_ID_SIZE]; + int idVendor, idProduct, bcdDevice; + + memset(str, 0, DEVICE_HARDWARE_ID_SIZE); + + idVendor = pdev->query_device_descriptor(pdev, ID_VENDOR); + idProduct = pdev->query_device_descriptor(pdev, ID_PRODUCT); + bcdDevice = pdev->query_device_descriptor(pdev, BCD_DEVICE); + + sprintf(str, "USB\\VID_%04X&PID_%04X", idVendor, idProduct); + strcpy(HardwareIds[1], str); + sprintf(str, "%s&REV_%04X", str, bcdDevice); + strcpy(HardwareIds[0], str); + + return 0; +} + + +static int +func_compat_id_format(IUDEVICE *pdev, char (*CompatibilityIds)[DEVICE_COMPATIBILITY_ID_SIZE]) +{ + char str[DEVICE_COMPATIBILITY_ID_SIZE]; + int bDeviceClass, bDeviceSubClass, bDeviceProtocol; + + bDeviceClass = pdev->query_device_descriptor(pdev, B_DEVICE_CLASS); + bDeviceSubClass = pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS); + bDeviceProtocol = pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL); + + if(!(pdev->isCompositeDevice(pdev))){ + sprintf(str, "USB\\Class_%02X", bDeviceClass); + strcpy(CompatibilityIds[2], str); + sprintf(str, "%s&SubClass_%02X", str, bDeviceSubClass); + strcpy(CompatibilityIds[1], str); + sprintf(str, "%s&Prot_%02X", str, bDeviceProtocol); + strcpy(CompatibilityIds[0], str); + } + else{ + sprintf(str, "USB\\DevClass_00"); + strcpy(CompatibilityIds[2], str); + sprintf(str, "%s&SubClass_00", str); + strcpy(CompatibilityIds[1], str); + sprintf(str, "%s&Prot_00", str); + strcpy(CompatibilityIds[0], str); + } + + return 0; +} + + +static void +func_close_udevice(USB_SEARCHMAN * searchman, IUDEVICE * pdev) +{ + URBDRC_PLUGIN * urbdrc = searchman->urbdrc; + int idVendor = 0; + int idProduct = 0; + + 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 (isoch_queue) + isoch_queue->free(isoch_queue); +#endif + + urbdrc->udevman->unregister_udevice(urbdrc->udevman, + pdev->get_bus_number(pdev), + pdev->get_dev_number(pdev)); + //searchman->show(searchman); +} + + +static int +fun_device_string_send_set(char * out_data, int out_offset, char * str) +{ + int i = 0; + int offset = 0; + + 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; +} + + +static int +func_container_id_generate(IUDEVICE * pdev, char * strContainerId) +{ + char containerId[17]; + char *p, *path; + int idVendor, idProduct; + + idVendor = pdev->query_device_descriptor(pdev, ID_VENDOR); + idProduct = pdev->query_device_descriptor(pdev, ID_PRODUCT); + path = pdev->getPath(pdev); + if (strlen(path) > 8) + p = (path + strlen(path)) - 8; + else + p = path; + + sprintf(containerId, "%04X%04X%s", idVendor, idProduct, p); + /* format */ + sprintf(strContainerId, + "{%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x}", + containerId[0], containerId[1],containerId[2], containerId[3], + containerId[4], containerId[5], containerId[6], containerId[7], + containerId[8], containerId[9], containerId[10], containerId[11], + containerId[12], containerId[13], containerId[14], containerId[15]); + + return 0; +} + + +static int +func_instance_id_generate(IUDEVICE * pdev, char *strInstanceId) +{ + char instanceId[17]; + + memset(instanceId, 0, 17); + sprintf(instanceId, "\\%s", pdev->getPath(pdev)); + /* format */ + sprintf(strInstanceId, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + instanceId[0], instanceId[1],instanceId[2], instanceId[3], + instanceId[4], instanceId[5], instanceId[6], instanceId[7], + instanceId[8], instanceId[9], instanceId[10], instanceId[11], + instanceId[12], instanceId[13], instanceId[14], instanceId[15]); + + return 0; +} + + +#if ISOCH_FIFO +static void +func_lock_isoch_mutex(TRANSFER_DATA* transfer_data) +{ + IUDEVMAN * udevman = transfer_data->udevman; + IUDEVICE* pdev; + uint32 FunctionId; + uint32 RequestField; + uint16 URB_Function; + int noAck = 0; + + 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 + + +static int +urbdrc_process_capability_request(URBDRC_CHANNEL_CALLBACK * callback, + char * data, uint32 data_sizem, uint32 MessageId) +{ + uint32 InterfaceId; + uint32 Version; + uint32 out_size; + char * out_data; + + LLOGLN(10, ("urbdrc_process_capability_request")); + data_read_uint32(data + 0, Version); + + InterfaceId = ((STREAM_ID_NONE<<30) | CAPABILITIES_NEGOTIATOR); + + out_size = 16; + out_data = (char *) malloc(out_size); + memset(out_data, 0, out_size); + 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 */ + callback->channel->Write(callback->channel, out_size, (uint8 *)out_data, NULL); + zfree(out_data); + + return 0; +} + +static int +urbdrc_process_channel_create(URBDRC_CHANNEL_CALLBACK * callback, char * data, + uint32 data_sizem, + uint32 MessageId) +{ + uint32 InterfaceId; + uint32 out_size; + uint32 MajorVersion; + uint32 MinorVersion; + uint32 Capabilities; + char * out_data; + + LLOGLN(10, ("urbdrc_process_channel_create")); + data_read_uint32(data + 0, MajorVersion); + data_read_uint32(data + 4, MinorVersion); + data_read_uint32(data + 8, Capabilities); + + InterfaceId = ((STREAM_ID_PROXY<<30) | CLIENT_CHANNEL_NOTIFICATION); + + out_size = 24; + out_data = (char *) malloc(out_size); + memset(out_data, 0, out_size); + 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 */ + callback->channel->Write(callback->channel, out_size, (uint8 *)out_data, NULL); + zfree(out_data); + + return 0; +} + + +static int +urdbrc_send_virtual_channel_add(IWTSVirtualChannel * channel, uint32 MessageId) +{ + uint32 out_size; + uint32 InterfaceId; + char * out_data; + + LLOGLN(10, ("urdbrc_send_virtual_channel_add")); + + 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, (uint8 *)out_data, NULL); + zfree(out_data); + + return 0; +} + + + +static int +urdbrc_send_usb_device_add(URBDRC_CHANNEL_CALLBACK * callback, IUDEVICE* pdev) +{ + uint32 InterfaceId; + char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE]; + char CompatibilityIds[3][DEVICE_COMPATIBILITY_ID_SIZE]; + char * out_data; + char strContainerId[DEVICE_CONTAINER_STR_SIZE]; + char strInstanceId[DEVICE_INSTANCE_STR_SIZE]; + char * composite_str = "USB\\COMPOSITE"; + int size, out_offset, cchCompatIds, bcdUSB; + + LLOGLN(10, ("urdbrc_send_usb_device_add")); + InterfaceId = ((STREAM_ID_PROXY<<30) | CLIENT_DEVICE_SINK); + + /* USB kernel driver detach!! */ + pdev->detach_kernel_driver(pdev); +#if ISOCH_FIFO + /* create/initial isoch queue */ + pdev->set_isoch_queue(pdev, (void *)isoch_queue_new()); +#endif + + func_hardware_id_format(pdev, HardwareIds); + func_compat_id_format(pdev, CompatibilityIds); + func_instance_id_generate(pdev, strInstanceId); + func_container_id_generate(pdev, strContainerId); + + cchCompatIds = strlen(CompatibilityIds[0])+1 + + strlen(CompatibilityIds[1])+1 + + strlen(CompatibilityIds[2])+2; + + if(pdev->isCompositeDevice(pdev)) + cchCompatIds += strlen(composite_str)+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 *) malloc(size); + memset(out_data, 0, size); + 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; + /* 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]); + + if(pdev->isCompositeDevice(pdev)) + out_offset = fun_device_string_send_set(out_data, out_offset, composite_str); + + 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; + /* ContainerId */ + out_offset = fun_device_string_send_set(out_data, out_offset, strContainerId); + + /* 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 */ + /* 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 */ + if (bcdUSB < 0x200) + data_write_uint32(out_data + out_offset + 20, 0x00000000); /* DeviceIsHighSpeed */ + else + data_write_uint32(out_data + out_offset + 20, 0x00000001); /* DeviceIsHighSpeed */ + data_write_uint32(out_data + out_offset + 24, 0x50); /* NoAckIsochWriteJitterBufferSizeInMs, >=10 or <=512 */ + out_offset += 28; + + callback->channel->Write(callback->channel, out_offset, (uint8 *)out_data, NULL); + zfree(out_data); + + return 0; +} + + +static int +urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK * callback, + char * pBuffer, + uint32 cbSize) +{ + uint32 MessageId; + uint32 FunctionId; + + int error = 0; + + data_read_uint32(pBuffer + 0, MessageId); + data_read_uint32(pBuffer + 4, FunctionId); + + switch (FunctionId) + { + case RIM_EXCHANGE_CAPABILITY_REQUEST: + error = urbdrc_process_capability_request(callback, + pBuffer + 8, + cbSize - 8, + MessageId); + break; + default: + LLOGLN(10, ("urbdrc_exchange_capabilities: unknown FunctionId 0x%X", FunctionId)); + error = 1; + break; + } + return error; +} + + + +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; + IUDEVICE * pdev = NULL; + struct wait_obj * listobj[2]; + struct wait_obj * mon_fd; + int numobj, timeout; + int busnum, devnum; + int success = 0, error, on_close = 0, found = 0; + + LLOGLN(10, ("urbdrc_search_usb_device: ")); + + channel_mgr = urbdrc->listener_callback->channel_mgr; + + /* init usb monitor */ + struct udev *udev; + struct udev_device *dev; + struct udev_monitor *mon; + + udev = udev_new(); + if (!udev) { + printf("Can't create udev\n"); + 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 = wait_obj_new_with_fd((void *)udev_monitor_get_fd(mon)); + + while (1) + { + LLOGLN(10, ("======= 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; + wait_obj_select(listobj, numobj, -1); + if (wait_obj_is_set(searchman->term_event)) + { + sem_post(&searchman->sem_term); + return 0; + } + + if (wait_obj_is_set(mon_fd)) + { + dev = udev_monitor_receive_device(mon); + if (dev) { + const char * action = udev_device_get_action(dev); + if (strcmp(action, "add") == 0) + { + int idVendor, idProduct; + success = 0; + found = 0; + idVendor = strtol( + udev_device_get_sysattr_value(dev, "idVendor"), NULL, 16); + idProduct = strtol( + udev_device_get_sysattr_value(dev, "idProduct"), NULL, 16); + if (idVendor < 0 || idProduct < 0) + { + udev_device_unref(dev); + continue; + } + + busnum = atoi(udev_device_get_property_value(dev,"BUSNUM")); + devnum = atoi(udev_device_get_property_value(dev,"DEVNUM")); + + 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) + { + LLOGLN(10, ("Searchman Find Device: %04x:%04x ", + sdev->idVendor, sdev->idProduct)); + found = 1; + break; + } + } + + if (!found && udevman->isAutoAdd(udevman)) + { + LLOGLN(10, ("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 */ + wait_obj_select(listobj, numobj, timeout); + if (wait_obj_is_set(searchman->term_event)) + { + wait_obj_free(mon_fd); + sem_post(&searchman->sem_term); + return 0; + } + error = 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 = atoi(udev_device_get_property_value(dev,"BUSNUM")); + devnum = atoi(udev_device_get_property_value(dev,"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){ + LLOGLN(0, ("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 */ + wait_obj_select(listobj, numobj, timeout); + if (wait_obj_is_set(searchman->term_event)) + { + wait_obj_free(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 { + printf("No Device from receive_device(). An error occured.\n"); + } + } + } + + wait_obj_free(mon_fd); + sem_post(&searchman->sem_term); + + return 0; +} + + +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; + uint8 * pBuffer = transfer_data->pBuffer; + //uint32 cbSize = transfer_data->cbSize; + IUDEVMAN * udevman = transfer_data->udevman; + IUDEVICE * pdev = NULL; + uint32 ChannelId = 0; + uint32 MessageId; + uint32 FunctionId; + int i = 0, found = 0; + + 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; + switch (urbdrc->vchannel_status){ + case INIT_CHANNEL_IN: + urbdrc->first_channel_id = ChannelId; + searchman->start(searchman, urbdrc_search_usb_device); + + for(i=0; i < udevman->get_device_num(udevman); i++) + { + error = urdbrc_send_virtual_channel_add(callback->channel, MessageId); + } + urbdrc->vchannel_status = INIT_CHANNEL_OUT; + break; + case INIT_CHANNEL_OUT: + udevman->loading_lock(udevman); + udevman->rewind(udevman); + while(udevman->has_next(udevman)){ + pdev = udevman->get_next(udevman); + if (!pdev->isAlreadySend(pdev)) + { + found = 1; + pdev->setAlreadySend(pdev); + pdev->set_channel_id(pdev, ChannelId); + break; + } + } + udevman->loading_unlock(udevman); + + 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); + } + + break; + default: + LLOGLN(0, ("urbdrc_new_device_create: vchannel_status unknown value %d", + urbdrc->vchannel_status)); + break; + } + + return 0; +} + + + +static int +urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK * callback, + char * pBuffer, uint32 cbSize) +{ + URBDRC_PLUGIN * urbdrc = (URBDRC_PLUGIN *) callback->plugin; + uint32 MessageId; + uint32 FunctionId; + int i, error = 0; + + data_read_uint32(pBuffer + 0, MessageId); + data_read_uint32(pBuffer + 4, FunctionId); + + switch (FunctionId) + { + case CHANNEL_CREATED: + error = urbdrc_process_channel_create(callback, pBuffer + 8, cbSize - 8, MessageId); + break; + case RIMCALL_RELEASE: + LLOGLN(10, ("urbdrc_process_channel_notification: recv RIMCALL_RELEASE")); + pthread_t thread; + + TRANSFER_DATA* transfer_data; + + transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); + transfer_data->callback = callback; + transfer_data->urbdrc = urbdrc; + transfer_data->udevman = urbdrc->udevman; + transfer_data->urbdrc = urbdrc; + transfer_data->cbSize = cbSize; + transfer_data->pBuffer = (uint8 *)malloc((cbSize)); + for (i = 0; i < (cbSize); i++) + { + transfer_data->pBuffer[i] = pBuffer[i]; + } + + pthread_create(&thread, 0, urbdrc_new_device_create, transfer_data); + pthread_detach(thread); + break; + default: + LLOGLN(10, ("urbdrc_process_channel_notification: unknown FunctionId 0x%X", FunctionId)); + error = 1; + break; + } + return error; +} + + + + +static int +urbdrc_on_data_received(IWTSVirtualChannelCallback * pChannelCallback, + uint32 cbSize, + uint8 * Buffer) +{ + URBDRC_CHANNEL_CALLBACK * callback = (URBDRC_CHANNEL_CALLBACK *) pChannelCallback; + URBDRC_PLUGIN * urbdrc; + IUDEVMAN * udevman; + uint32 InterfaceTemp; + uint32 InterfaceId; + uint32 Mask; + int error = 0; + char * pBuffer = (char *) Buffer; + + if (callback == NULL) return 0; + if (callback->plugin == NULL) return 0; + urbdrc = (URBDRC_PLUGIN *) callback->plugin; + if (urbdrc->udevman == NULL) return 0; + udevman = (IUDEVMAN *) urbdrc->udevman; + + data_read_uint32(pBuffer + 0, InterfaceTemp); + InterfaceId = (InterfaceTemp & 0x0fffffff); + Mask = ((InterfaceTemp & 0xf0000000)>>30); + LLOGLN(10, ("urbdrc_on_data_received: Size=%d InterfaceId=0x%X Mask=0x%X", cbSize, InterfaceId, Mask)); + + switch (InterfaceId) + { + case CAPABILITIES_NEGOTIATOR: + error = urbdrc_exchange_capabilities(callback, pBuffer + 4, cbSize - 4); + break; + case SERVER_CHANNEL_NOTIFICATION: + error = urbdrc_process_channel_notification(callback, pBuffer + 4, cbSize - 4); + break; + default: + LLOGLN(10, ("urbdrc_on_data_received: InterfaceId 0x%X Start matching devices list", InterfaceId)); + pthread_t thread; + TRANSFER_DATA* transfer_data; + + transfer_data = (TRANSFER_DATA*)malloc(sizeof(TRANSFER_DATA)); + if (transfer_data == NULL) + printf("transfer_data is NULL!!"); + transfer_data->callback = callback; + transfer_data->urbdrc = urbdrc; + transfer_data->udevman = udevman; + transfer_data->cbSize = cbSize - 4; + transfer_data->UsbDevice = InterfaceId; + transfer_data->pBuffer = (uint8 *)malloc((cbSize - 4)); + + 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) + LLOGLN(0, ("Create Data Transfer Thread got error = %d", error)); + else + pthread_detach(thread); + + //urbdrc_process_udev_data_transfer(transfer_data); + + break; + } + + return 0; +} + +static int +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); + + LLOGLN(0, ("urbdrc_on_close: channel id %d", ChannelId)); + + udevman->loading_lock(udevman); + udevman->rewind(udevman); + while(udevman->has_next(udevman)) + { + pdev = udevman->get_next(udevman); + if (pdev->get_channel_id(pdev) == ChannelId) + { + found = 1; + break; + } + } + udevman->loading_unlock(udevman); + if (found && pdev && !(pdev->isChannelClosed(pdev))) + { + pdev->setChannelClosed(pdev); + func_close_udevice(searchman, pdev); + } + + zfree(callback); + + LLOGLN(urbdrc_debug, ("urbdrc_on_close: success")); + + return 0; +} + +static int +urbdrc_on_new_channel_connection(IWTSListenerCallback * pListenerCallback, + IWTSVirtualChannel * pChannel, + uint8 * pData, + int * pbAccept, + IWTSVirtualChannelCallback ** ppCallback) +{ + URBDRC_LISTENER_CALLBACK * listener_callback = (URBDRC_LISTENER_CALLBACK *) pListenerCallback; + URBDRC_CHANNEL_CALLBACK * callback; + + LLOGLN(10, ("urbdrc_on_new_channel_connection:")); + callback = (URBDRC_CHANNEL_CALLBACK *) malloc(sizeof(URBDRC_CHANNEL_CALLBACK)); + callback->iface.OnDataReceived = urbdrc_on_data_received; + callback->iface.OnClose = urbdrc_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + *ppCallback = (IWTSVirtualChannelCallback *) callback; + return 0; +} + +static int +urbdrc_plugin_initialize(IWTSPlugin * pPlugin, IWTSVirtualChannelManager * pChannelMgr) +{ + URBDRC_PLUGIN * urbdrc = (URBDRC_PLUGIN *) pPlugin; + IUDEVMAN * udevman = NULL; + USB_SEARCHMAN * searchman = NULL; + + LLOGLN(10, ("urbdrc_plugin_initialize:")); + urbdrc->listener_callback = (URBDRC_LISTENER_CALLBACK *) malloc(sizeof(URBDRC_LISTENER_CALLBACK)); + memset(urbdrc->listener_callback, 0, sizeof(URBDRC_LISTENER_CALLBACK)); + + urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection; + urbdrc->listener_callback->plugin = pPlugin; + urbdrc->listener_callback->channel_mgr = pChannelMgr; + + /* Init searchman */ + udevman = urbdrc->udevman; + searchman = searchman_new((void *)urbdrc, udevman->get_defUsbDevice(udevman)); + urbdrc->searchman = searchman; + + return pChannelMgr->CreateListener(pChannelMgr, "URBDRC", 0, + (IWTSListenerCallback *) urbdrc->listener_callback, NULL); +} + +static int +urbdrc_plugin_terminated(IWTSPlugin * pPlugin) +{ + URBDRC_PLUGIN * urbdrc = (URBDRC_PLUGIN *) pPlugin; + IUDEVMAN* udevman = urbdrc->udevman; + USB_SEARCHMAN* searchman = urbdrc->searchman; + + LLOGLN(10, ("urbdrc_plugin_terminated:")); + + if (searchman) + { + /* close searchman */ + searchman->close(searchman); + /* free searchman */ + if (searchman->strated) + { + struct timespec ts; + ts.tv_sec = time(NULL)+10; + ts.tv_nsec = 0; + sem_timedwait(&searchman->sem_term, &ts); + } + searchman->free(searchman); + searchman = NULL; + } + + if (udevman) + { + udevman->free(udevman); + udevman = NULL; + } + + if (urbdrc->listener_callback) + zfree(urbdrc->listener_callback); + if(urbdrc) + zfree(urbdrc); + return 0; +} + + +static void +urbdrc_register_udevman_plugin(IWTSPlugin* pPlugin, IUDEVMAN* udevman) +{ + URBDRC_PLUGIN* urbdrc = (URBDRC_PLUGIN*) pPlugin; + + if (urbdrc->udevman) + { + DEBUG_WARN("existing device, abort."); + return; + } + + DEBUG_DVC("device registered."); + + urbdrc->udevman = udevman; +} + + + +static int +urbdrc_load_udevman_plugin(IWTSPlugin* pPlugin, const char* name, RDP_PLUGIN_DATA* data) +{ + char* fullname; + PFREERDP_URBDRC_DEVICE_ENTRY entry; + FREERDP_URBDRC_SERVICE_ENTRY_POINTS entryPoints; + + if (strrchr(name, '.') != NULL) + { + entry = (PFREERDP_URBDRC_DEVICE_ENTRY) freerdp_load_plugin(name, URBDRC_UDEVMAN_EXPORT_FUNC_NAME); + } + else + { + fullname = xzalloc(strlen(name) + 8); + strcpy(fullname, name); + strcat(fullname, "_udevman"); + entry = (PFREERDP_URBDRC_DEVICE_ENTRY) freerdp_load_plugin(fullname, URBDRC_UDEVMAN_EXPORT_FUNC_NAME); + xfree(fullname); + } + + if (entry == NULL) + return false; + + entryPoints.plugin = pPlugin; + entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_plugin; + entryPoints.plugin_data = data; + + if (entry(&entryPoints) != 0) + { + DEBUG_WARN("%s entry returns error.", name); + return false; + } + + return true; +} + + + + +static int +urbdrc_process_plugin_data(IWTSPlugin* pPlugin, RDP_PLUGIN_DATA* data) +{ + boolean ret; + + if (data->data[0] && (strcmp((char*)data->data[0], "urbdrc") == 0 || strstr((char*) data->data[0], "/urbdrc.") != NULL)) + { + ret = urbdrc_load_udevman_plugin(pPlugin, "libusb", data); + return ret; + } + + return true; +} + + +int +DVCPluginEntry(IDRDYNVC_ENTRY_POINTS * pEntryPoints) +{ + int error = 0; + URBDRC_PLUGIN* urbdrc; + RDP_PLUGIN_DATA* data; + + urbdrc = (URBDRC_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "urbdrc"); + data = pEntryPoints->GetPluginData(pEntryPoints); + + if (urbdrc == NULL) + { + urbdrc = xnew(URBDRC_PLUGIN); + + 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; + + urbdrc_debug = 10; + if (data->data[2] && strstr((char *)data->data[2], "debug")) + urbdrc_debug = 0; + + error = pEntryPoints->RegisterPlugin(pEntryPoints, "urbdrc", (IWTSPlugin *) urbdrc); + } + + if (error == 0) + urbdrc_process_plugin_data((IWTSPlugin*) urbdrc, data); + + return error; +} + diff --git a/channels/drdynvc/urbdrc/urbdrc_main.h b/channels/drdynvc/urbdrc/urbdrc_main.h new file mode 100644 index 000000000..146e8a4fe --- /dev/null +++ b/channels/drdynvc/urbdrc/urbdrc_main.h @@ -0,0 +1,269 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __URBDRC_MAIN_H +#define __URBDRC_MAIN_H + +#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 + + +typedef struct _IUDEVICE IUDEVICE; +typedef struct _IUDEVMAN IUDEVMAN; + +#define BASIC_DEV_STATE_DEFINED(_arg, _type) \ + _type (*get_##_arg) (IUDEVICE *pdev); \ + void (*set_##_arg) (IUDEVICE *pdev, _type _arg) +#define BASIC_DEVMAN_STATE_DEFINED(_arg, _type) \ + _type (*get_##_arg) (IUDEVMAN *udevman); \ + void (*set_##_arg) (IUDEVMAN *udevman, _type _arg) + + +typedef struct _URBDRC_LISTENER_CALLBACK URBDRC_LISTENER_CALLBACK; +struct _URBDRC_LISTENER_CALLBACK +{ + IWTSListenerCallback iface; + + IWTSPlugin * plugin; + IWTSVirtualChannelManager * channel_mgr; +}; + +typedef struct _URBDRC_CHANNEL_CALLBACK URBDRC_CHANNEL_CALLBACK; +struct _URBDRC_CHANNEL_CALLBACK +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin * plugin; + IWTSVirtualChannelManager * channel_mgr; + IWTSVirtualChannel * channel; +}; + +typedef struct _URBDRC_PLUGIN URBDRC_PLUGIN; +struct _URBDRC_PLUGIN +{ + IWTSPlugin iface; + + URBDRC_LISTENER_CALLBACK * listener_callback; + + IUDEVMAN * udevman; + USB_SEARCHMAN * searchman; + uint32 first_channel_id; + uint32 vchannel_status; +}; + + +#define URBDRC_UDEVMAN_EXPORT_FUNC_NAME "FreeRDPUDEVMANEntry" + +typedef void (*PREGISTERURBDRCSERVICE)(IWTSPlugin* plugin, IUDEVMAN* udevman); + +struct _FREERDP_URBDRC_SERVICE_ENTRY_POINTS +{ + IWTSPlugin* plugin; + PREGISTERURBDRCSERVICE pRegisterUDEVMAN; + RDP_PLUGIN_DATA* plugin_data; +}; +typedef struct _FREERDP_URBDRC_SERVICE_ENTRY_POINTS FREERDP_URBDRC_SERVICE_ENTRY_POINTS; +typedef FREERDP_URBDRC_SERVICE_ENTRY_POINTS* PFREERDP_URBDRC_SERVICE_ENTRY_POINTS; + +typedef int (*PFREERDP_URBDRC_DEVICE_ENTRY)(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints); + + + + +typedef struct _TRANSFER_DATA TRANSFER_DATA; +struct _TRANSFER_DATA +{ + URBDRC_CHANNEL_CALLBACK * callback; + URBDRC_PLUGIN * urbdrc; + IUDEVMAN * udevman; + uint8 * pBuffer; + uint32 cbSize; + uint32 UsbDevice; +}; + + +struct _IUDEVICE +{ + /* Transfer */ + int (*isoch_transfer) (IUDEVICE * idev, uint32 RequestId, + uint32 EndpointAddress, + uint32 TransferFlags, + int NoAck, + uint32 *ErrorCount, + uint32 *UrbdStatus, + uint32 *StartFrame, + uint32 NumberOfPackets, + uint8 *IsoPacket, + uint32 *BufferSize, + uint8 *Buffer, + int Timeout); + + int (*control_transfer) (IUDEVICE * idev, uint32 RequestId, + uint32 EndpointAddress, + uint32 TransferFlags, + uint8 bmRequestType, + uint8 Request, + uint16 Value, + uint16 Index, + uint32 *UrbdStatus, + uint32 *BufferSize, + uint8 *Buffer, + uint32 Timeout); + + int (*bulk_or_interrupt_transfer) (IUDEVICE * idev, uint32 RequestId, + uint32 EndpointAddress, + uint32 TransferFlags, + uint32 *UsbdStatus, + uint32 *BufferSize, + uint8 *Buffer, + uint32 Timeout); + + + int (*select_configuration) (IUDEVICE * idev, uint32 bConfigurationValue); + + int (*select_interface) (IUDEVICE * idev, uint8 InterfaceNumber, + uint8 AlternateSetting); + + 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, + uint8 * Buffer); + + int (*os_feature_descriptor_request) (IUDEVICE * idev, uint32 RequestId, + uint8 Recipient, + uint8 InterfaceNumber, + uint8 Ms_PageIndex, + uint16 Ms_featureDescIndex, + uint32 * UsbdStatus, + uint32 * BufferSize, + uint8* Buffer, + int Timeout); + + void (*cancel_all_transfer_request) (IUDEVICE * idev); + + int (*cancel_transfer_request) (IUDEVICE * idev, uint32 RequestId); + + int (*query_device_descriptor) (IUDEVICE * idev, int offset); + + void (*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); + + /* 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); + + int (*query_device_port_status) (IUDEVICE * idev, uint32 *UsbdStatus, + uint32 * BufferSize, + uint8 * 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); + 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(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 +{ + /* Standard */ + void (*free) (IUDEVMAN *idevman); + /* 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); + 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); + int (*isAutoAdd) (IUDEVMAN * idevman); + /* Basic state */ + BASIC_DEVMAN_STATE_DEFINED(defUsbDevice, uint32); + BASIC_DEVMAN_STATE_DEFINED(device_num, int); + 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); +}; + + +#endif /* __URBDRC_MAIN_H */ diff --git a/channels/drdynvc/urbdrc/urbdrc_types.h b/channels/drdynvc/urbdrc/urbdrc_types.h new file mode 100644 index 000000000..38fbb4e1a --- /dev/null +++ b/channels/drdynvc/urbdrc/urbdrc_types.h @@ -0,0 +1,355 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __URBDRC_TYPES_H +#define __URBDRC_TYPES_H + + +#include "config.h" +#include +#include +#include +#include +#include +#include "drdynvc_types.h" + +#include +#include +#include + +#define CAPABILITIES_NEGOTIATOR 0x00000000 +#define CLIENT_DEVICE_SINK 0x00000001 +#define SERVER_CHANNEL_NOTIFICATION 0x00000002 +#define CLIENT_CHANNEL_NOTIFICATION 0x00000003 +#define BASE_USBDEVICE_NUM 0x00000005 + +#define RIMCALL_RELEASE 0x00000001 +#define RIM_EXCHANGE_CAPABILITY_REQUEST 0x00000100 +#define CHANNEL_CREATED 0x00000100 +#define ADD_VIRTUAL_CHANNEL 0x00000100 +#define ADD_DEVICE 0x00000101 + + +#define INIT_CHANNEL_IN 1 +#define INIT_CHANNEL_OUT 0 + + +/* InterfaceClass */ +#define CLASS_RESERVE 0x00 +#define CLASS_AUDIO 0x01 +#define CLASS_COMMUNICATION_IF 0x02 +#define CLASS_HID 0x03 +#define CLASS_PHYSICAL 0x05 +#define CLASS_IMAGE 0x06 +#define CLASS_PRINTER 0x07 +#define CLASS_MASS_STORAGE 0x08 +#define CLASS_HUB 0x09 +#define CLASS_COMMUNICATION_DATA_IF 0x0a +#define CLASS_SMART_CARD 0x0b +#define CLASS_CONTENT_SECURITY 0x0d +#define CLASS_VIDEO 0x0e +#define CLASS_PERSONAL_HEALTHCARE 0x0f +#define CLASS_DIAGNOSTIC 0xdc +#define CLASS_WIRELESS_CONTROLLER 0xe0 +#define CLASS_ELSE_DEVICE 0xef +#define CLASS_DEPENDENCE 0xfe +#define CLASS_VENDOR_DEPENDENCE 0xff + + +/* usb version */ +#define USB_v1_0 0x100 +#define USB_v1_1 0x110 +#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 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 + + +#define IOCONTROL_COMPLETION 0x00000100 +#define URB_COMPLETION 0x00000101 +#define URB_COMPLETION_NO_DATA 0x00000102 + +/* The USB device is to be stopped from being redirected because the + * device is blocked by the server's policy. */ +#define UsbRetractReason_BlockedByPolicy 0x00000001 + + + +enum device_text_type { + DeviceTextDescription = 0, + DeviceTextLocationInformation = 1, +}; + +enum device_descriptor_table { + B_LENGTH = 0, + B_DESCRIPTOR_TYPE = 1, + BCD_USB = 2, + B_DEVICE_CLASS = 4, + B_DEVICE_SUBCLASS = 5, + B_DEVICE_PROTOCOL = 6, + B_MAX_PACKET_SIZE0 = 7, + ID_VENDOR = 8, + ID_PRODUCT = 10, + BCD_DEVICE = 12, + I_MANUFACTURER = 14, + I_PRODUCT = 15, + I_SERIAL_NUMBER = 16, + B_NUM_CONFIGURATIONS = 17 +}; + + +#define PIPE_CANCEL 0 +#define PIPE_RESET 1 + +#define IOCTL_INTERNAL_USB_SUBMIT_URB 0x00220003 +#define IOCTL_INTERNAL_USB_RESET_PORT 0x00220007 +#define IOCTL_INTERNAL_USB_GET_PORT_STATUS 0x00220013 +#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 +// 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 USBD_STATUS_SUCCESS 0x0 +#define USBD_STATUS_PENDING 0x40000000 +#define USBD_STATUS_CANCELED 0xC0010000 + +#define USBD_STATUS_CRC 0xC0000001 +#define USBD_STATUS_BTSTUFF 0xC0000002 +#define USBD_STATUS_DATA_TOGGLE_MISMATCH 0xC0000003 +#define USBD_STATUS_STALL_PID 0xC0000004 +#define USBD_STATUS_DEV_NOT_RESPONDING 0xC0000005 +#define USBD_STATUS_PID_CHECK_FAILURE 0xC0000006 +#define USBD_STATUS_UNEXPECTED_PID 0xC0000007 +#define USBD_STATUS_DATA_OVERRUN 0xC0000008 +#define USBD_STATUS_DATA_UNDERRUN 0xC0000009 +#define USBD_STATUS_RESERVED1 0xC000000A +#define USBD_STATUS_RESERVED2 0xC000000B +#define USBD_STATUS_BUFFER_OVERRUN 0xC000000C +#define USBD_STATUS_BUFFER_UNDERRUN 0xC000000D + +/* unknow */ +#define USBD_STATUS_NO_DATA 0xC000000E + +#define USBD_STATUS_NOT_ACCESSED 0xC000000F +#define USBD_STATUS_FIFO 0xC0000010 +#define USBD_STATUS_XACT_ERROR 0xC0000011 +#define USBD_STATUS_BABBLE_DETECTED 0xC0000012 +#define USBD_STATUS_DATA_BUFFER_ERROR 0xC0000013 + +#define USBD_STATUS_NOT_SUPPORTED 0xC0000E00 +#define USBD_STATUS_BUFFER_TOO_SMALL 0xC0003000 +#define USBD_STATUS_TIMEOUT 0xC0006000 +#define USBD_STATUS_DEVICE_GONE 0xC0007000 + +#define USBD_STATUS_NO_MEMORY 0x80000100 +#define USBD_STATUS_INVALID_URB_FUNCTION 0x80000200 +#define USBD_STATUS_INVALID_PARAMETER 0x80000300 +#define USBD_STATUS_REQUEST_FAILED 0x80000500 +#define USBD_STATUS_INVALID_PIPE_HANDLE 0x80000600 +#define USBD_STATUS_ERROR_SHORT_TRANSFER 0x80000900 + +// Values for URB TransferFlags Field +// + +/* + Set if data moves device->host +*/ +#define USBD_TRANSFER_DIRECTION 0x00000001 +/* + This bit if not set indicates that a short packet, and hence, + a short transfer is an error condition +*/ +#define USBD_SHORT_TRANSFER_OK 0x00000002 +/* + Subit the iso transfer on the next frame +*/ +#define USBD_START_ISO_TRANSFER_ASAP 0x00000004 +#define USBD_DEFAULT_PIPE_TRANSFER 0x00000008 + + +#define USBD_TRANSFER_DIRECTION_FLAG(flags) ((flags) & USBD_TRANSFER_DIRECTION) + +#define USBD_TRANSFER_DIRECTION_OUT 0 +#define USBD_TRANSFER_DIRECTION_IN 1 + +#define VALID_TRANSFER_FLAGS_MASK USBD_SHORT_TRANSFER_OK | \ + USBD_TRANSFER_DIRECTION | \ + USBD_START_ISO_TRANSFER_ASAP | \ + USBD_DEFAULT_PIPE_TRANSFER) + + + + +#define ENDPOINT_HALT 0x00 +#define DEVICE_REMOTE_WAKEUP 0x01 + + +/* transfer type */ +#define CONTROL_TRANSFER 0x00 +#define ISOCHRONOUS_TRANSFER 0x01 +#define BULK_TRANSFER 0x02 +#define INTERRUPT_TRANSFER 0x03 + + + +#define ClearHubFeature (0x2000 | LIBUSB_REQUEST_CLEAR_FEATURE) +#define ClearPortFeature (0x2300 | LIBUSB_REQUEST_CLEAR_FEATURE) +#define GetHubDescriptor (0xa000 | LIBUSB_REQUEST_GET_DESCRIPTOR) +#define GetHubStatus (0xa000 | LIBUSB_REQUEST_GET_STATUS) +#define GetPortStatus (0xa300 | LIBUSB_REQUEST_GET_STATUS) +#define SetHubFeature (0x2000 | LIBUSB_REQUEST_SET_FEATURE) +#define SetPortFeature (0x2300 | LIBUSB_REQUEST_SET_FEATURE) + + + +#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 +#define USBD_PF_SHORT_PACKET_OPT 0x00000002 +#define USBD_PF_ENABLE_RT_THREAD_ACCESS 0x00000004 +#define USBD_PF_MAP_ADD_TRANSFERS 0x00000008 + +/* feature request */ +#define URB_SET_FEATURE 0x00 +#define URB_CLEAR_FEATURE 0x01 + +#define USBD_PF_CHANGE_MAX_PACKET 0x00000001 +#define USBD_PF_SHORT_PACKET_OPT 0x00000002 +#define USBD_PF_ENABLE_RT_THREAD_ACCESS 0x00000004 +#define USBD_PF_MAP_ADD_TRANSFERS 0x00000008 + + +#define URB_CONTROL_TRANSFER_EXTERNAL 0x1 +#define URB_CONTROL_TRANSFER_NONEXTERNAL 0x0 + + +#define USBFS_URB_SHORT_NOT_OK 0x01 +#define USBFS_URB_ISO_ASAP 0x02 +#define USBFS_URB_BULK_CONTINUATION 0x04 +#define USBFS_URB_QUEUE_BULK 0x10 + + +#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 + + +#define UDEVMAN_FLAG_ADD_BY_VID_PID 0x01 +#define UDEVMAN_FLAG_ADD_BY_ADDR 0x02 +#define UDEVMAN_FLAG_ADD_BY_AUTO 0x04 +#define UDEVMAN_FLAG_DEBUG 0x08 + + +#define MAX_URB_REQUSET_NUM 0x80 + + +#define LOG_LEVEL 1 +#define LLOG(_level, _args) \ + do { if (_level < LOG_LEVEL) { printf _args ; } } while (0) +#define LLOGLN(_level, _args) \ + do { if (_level < LOG_LEVEL) { printf _args ; printf("\n"); } } while (0) + + +#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) + + +extern int urbdrc_debug; + +#endif /* __URBDRC_TYPES_H */ diff --git a/include/freerdp/dvc.h b/include/freerdp/dvc.h index dfa487c28..98a382ae7 100644 --- a/include/freerdp/dvc.h +++ b/include/freerdp/dvc.h @@ -92,6 +92,10 @@ struct _IWTSVirtualChannelManager This is a FreeRDP extension to standard MS API. */ int (*PushEvent) (IWTSVirtualChannelManager* pChannelMgr, RDP_EVENT* pEvent); + /* Find the channel or ID to send data to a specific endpoint. */ + uint32 (*GetChannelId) (IWTSVirtualChannel * channel); + IWTSVirtualChannel* (*FindChannelById) (IWTSVirtualChannelManager* pChannelMgr, + uint32 ChannelId); }; struct _IWTSPlugin diff --git a/include/freerdp/utils/msusb.h b/include/freerdp/utils/msusb.h new file mode 100644 index 000000000..f2ef6beaa --- /dev/null +++ b/include/freerdp/utils/msusb.h @@ -0,0 +1,148 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 __MSCONFIG_H +#define __MSCONFIG_H + +#include +#include +#include + +/* a safer free helper */ +#define zfree(p) do { if (p != NULL) {free(p); p = NULL;} } while (0) + +/* Data maintenance helper only used in URBDRC */ +#define data_read_uint8(_p, _v) do { _v = \ + *((uint8 *) (_p)); \ + } while (0) +#define data_read_uint16(_p, _v) do { _v = \ + ((uint16) (*((uint8 *) (_p)))) + \ + ((uint16) (*(((uint8 *) (_p)) + 1)) << 8); \ + } while (0) +#define data_read_uint32(_p, _v) do { _v = \ + (uint32) (*((uint8 *) (_p))) + \ + ((uint32) (*(((uint8 *) (_p)) + 1)) << 8) + \ + ((uint32) (*(((uint8 *) (_p)) + 2)) << 16) + \ + ((uint32) (*(((uint8 *) (_p)) + 3)) << 24); \ + } while (0) +#define data_read_uint64(_p, _v) do { _v = \ + (uint64) (*((uint8 *) (_p))) + \ + ((uint64) (*(((uint8 *) (_p)) + 1)) << 8) + \ + ((uint64) (*(((uint8 *) (_p)) + 2)) << 16) + \ + ((uint64) (*(((uint8 *) (_p)) + 3)) << 24) + \ + ((uint64) (*(((uint8 *) (_p)) + 4)) << 32) + \ + ((uint64) (*(((uint8 *) (_p)) + 5)) << 40) + \ + ((uint64) (*(((uint8 *) (_p)) + 6)) << 48) + \ + ((uint64) (*(((uint8 *) (_p)) + 7)) << 56); \ + } while (0) + +#define data_write_uint8(_p, _v) do { \ + *((uint8 *) _p) = (uint8) (_v); \ + } while (0) +#define data_write_uint16(_p, _v) do { \ + *((uint8 *) _p) = (uint8) (((uint16) (_v)) & 0xff); \ + *(((uint8 *) _p) + 1) = (uint8) ((((uint16) (_v)) >> 8) & 0xff); \ + } while (0) +#define data_write_uint32(_p, _v) do { \ + *((uint8 *) _p) = (uint8) (((uint32) (_v)) & 0xff); \ + *(((uint8 *) _p) + 1) = (uint8) ((((uint32) (_v)) >> 8) & 0xff); \ + *(((uint8 *) _p) + 2) = (uint8) ((((uint32) (_v)) >> 16) & 0xff); \ + *(((uint8 *) _p) + 3) = (uint8) ((((uint32) (_v)) >> 24) & 0xff); \ + } while (0) +#define data_write_uint64(_p, _v) do { \ + *((uint8 *) _p) = (uint8) (((uint64) (_v)) & 0xff); \ + *(((uint8 *) _p) + 1) = (uint8) ((((uint64) (_v)) >> 8) & 0xff); \ + *(((uint8 *) _p) + 2) = (uint8) ((((uint64) (_v)) >> 16) & 0xff); \ + *(((uint8 *) _p) + 3) = (uint8) ((((uint64) (_v)) >> 24) & 0xff); \ + *(((uint8 *) _p) + 4) = (uint8) ((((uint64) (_v)) >> 32) & 0xff); \ + *(((uint8 *) _p) + 5) = (uint8) ((((uint64) (_v)) >> 40) & 0xff); \ + *(((uint8 *) _p) + 6) = (uint8) ((((uint64) (_v)) >> 48) & 0xff); \ + *(((uint8 *) _p) + 7) = (uint8) ((((uint64) (_v)) >> 56) & 0xff); \ + } while (0) + +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; + uint8 bEndpointAddress; + uint8 bInterval; + uint8 PipeType; + int InitCompleted; +} __attribute__((packed)); + + +struct _MSUSB_INTERFACE_DESCRIPTOR +{ + uint16 Length; + uint16 NumberOfPipesExpected; + uint8 InterfaceNumber; + uint8 AlternateSetting; + uint32 NumberOfPipes; + uint32 InterfaceHandle; + uint8 bInterfaceClass; + uint8 bInterfaceSubClass; + uint8 bInterfaceProtocol; + MSUSB_PIPE_DESCRIPTOR ** MsPipes; + int InitCompleted; +} __attribute__((packed)); + +struct _MSUSB_CONFIG_DESCRIPTOR +{ + uint16 wTotalLength; + uint8 bConfigurationValue; + uint32 ConfigurationHandle; + uint32 NumInterfaces; + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + int InitCompleted; + int MsOutSize; +} __attribute__((packed)); + + +/* MSUSB_PIPE exported functions */ +void +msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR * MsInterface, MSUSB_PIPE_DESCRIPTOR ** NewMsPipes, uint32 NewNumberOfPipes); + +/* MSUSB_INTERFACE exported functions */ +void +msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR * MsConfig, uint8 InterfaceNumber, MSUSB_INTERFACE_DESCRIPTOR * NewMsInterface); +MSUSB_INTERFACE_DESCRIPTOR * +msusb_msinterface_read(uint8 * data, uint32 data_size, int * offset); +int +msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR * MsInterface, uint8 * data, int * offset); + +/* MSUSB_CONFIG exported functions */ +MSUSB_CONFIG_DESCRIPTOR * +msusb_msconfig_new(); +void +msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR * MsConfig); +MSUSB_CONFIG_DESCRIPTOR * +msusb_msconfig_read(uint8 * data, uint32 data_size, uint32 NumInterfaces); +int +msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR * MsConfg, uint8 * data, int * offset); +void +msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR * MsConfg); + +#endif diff --git a/libfreerdp-utils/CMakeLists.txt b/libfreerdp-utils/CMakeLists.txt index a12b5ce2b..1eb5745cd 100644 --- a/libfreerdp-utils/CMakeLists.txt +++ b/libfreerdp-utils/CMakeLists.txt @@ -49,7 +49,8 @@ set(FREERDP_UTILS_SRCS thread.c time.c unicode.c - wait_obj.c) + wait_obj.c + msusb.c) add_library(freerdp-utils ${FREERDP_UTILS_SRCS}) diff --git a/libfreerdp-utils/msusb.c b/libfreerdp-utils/msusb.c new file mode 100644 index 000000000..0c918b8ca --- /dev/null +++ b/libfreerdp-utils/msusb.c @@ -0,0 +1,368 @@ +/** + * FreeRDP: A Remote Desktop Protocol client. + * 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 + +static MSUSB_PIPE_DESCRIPTOR * +msusb_mspipe_new() +{ + MSUSB_PIPE_DESCRIPTOR * MsPipe = (MSUSB_PIPE_DESCRIPTOR *)malloc(sizeof(MSUSB_PIPE_DESCRIPTOR)); + memset(MsPipe, 0, sizeof(MSUSB_PIPE_DESCRIPTOR)); + return MsPipe; +} + +static void +msusb_mspipes_free(MSUSB_PIPE_DESCRIPTOR ** MsPipes, uint32 NumberOfPipes) +{ + int pnum = 0; + if (MsPipes) + { + for (pnum = 0; pnum < NumberOfPipes && MsPipes[pnum]; pnum++) + { + zfree(MsPipes[pnum]); + } + zfree(MsPipes); + } +} + +void +msusb_mspipes_replace(MSUSB_INTERFACE_DESCRIPTOR * MsInterface, MSUSB_PIPE_DESCRIPTOR ** NewMsPipes, uint32 NewNumberOfPipes) +{ + /* free orignal MsPipes */ + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + /* And replace it */ + MsInterface->MsPipes = NewMsPipes; + MsInterface->NumberOfPipes = NewNumberOfPipes; + +} + +static MSUSB_PIPE_DESCRIPTOR ** +msusb_mspipes_read(uint8 * data, uint32 data_size, uint32 NumberOfPipes, int * offset) +{ + MSUSB_PIPE_DESCRIPTOR ** MsPipes; + int pnum, move = 0; + + MsPipes = (MSUSB_PIPE_DESCRIPTOR **)malloc(NumberOfPipes * + sizeof(MSUSB_PIPE_DESCRIPTOR *)); + + for(pnum = 0;pnum < NumberOfPipes; pnum++) + { + MSUSB_PIPE_DESCRIPTOR * MsPipe = msusb_mspipe_new(); + + data_read_uint16(data + move, MsPipe->MaximumPacketSize); + data_read_uint32(data + move + 4, MsPipe->MaximumTransferSize); + data_read_uint32(data + move + 8, MsPipe->PipeFlags); + move += 12; +/* Already set to zero by memset + MsPipe->PipeHandle = 0; + MsPipe->bEndpointAddress = 0; + MsPipe->bInterval = 0; + MsPipe->PipeType = 0; + MsPipe->InitCompleted = 0; +*/ + + MsPipes[pnum] = MsPipe; + } + *offset += move; + + return MsPipes; +} + +static MSUSB_INTERFACE_DESCRIPTOR * +msusb_msinterface_new() +{ + MSUSB_INTERFACE_DESCRIPTOR * MsInterface = (MSUSB_INTERFACE_DESCRIPTOR *)malloc(sizeof(MSUSB_INTERFACE_DESCRIPTOR)); + memset(MsInterface, 0, sizeof(MSUSB_INTERFACE_DESCRIPTOR)); + return MsInterface; +} + +static void +msusb_msinterface_free(MSUSB_INTERFACE_DESCRIPTOR * MsInterface) +{ + if (MsInterface) + { + msusb_mspipes_free(MsInterface->MsPipes, MsInterface->NumberOfPipes); + MsInterface->MsPipes = NULL; + zfree(MsInterface); + } +} + +static void +msusb_msinterface_free_list(MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces, uint32 NumInterfaces) +{ + int inum = 0; + + if (MsInterfaces) + { + for (inum = 0; inum < NumInterfaces; inum++) + { + msusb_msinterface_free(MsInterfaces[inum]); + } + zfree(MsInterfaces); + } +} + +void +msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR * MsConfig, uint8 InterfaceNumber, MSUSB_INTERFACE_DESCRIPTOR * NewMsInterface) +{ + msusb_msinterface_free(MsConfig->MsInterfaces[InterfaceNumber]); + MsConfig->MsInterfaces[InterfaceNumber] = NewMsInterface; +} + +MSUSB_INTERFACE_DESCRIPTOR * +msusb_msinterface_read(uint8 * data, uint32 data_size, int * offset) +{ + MSUSB_INTERFACE_DESCRIPTOR * MsInterface; + + MsInterface = msusb_msinterface_new(); + + data_read_uint16(data, MsInterface->Length); + data_read_uint16(data + 2, MsInterface->NumberOfPipesExpected); + data_read_uint8(data + 4, MsInterface->InterfaceNumber); + data_read_uint8(data + 5, MsInterface->AlternateSetting); + data_read_uint32(data + 8, MsInterface->NumberOfPipes); + *offset += 12; + + 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(data+(*offset), data_size-(*offset), MsInterface->NumberOfPipes, offset); + } + + return MsInterface; +} + +int +msusb_msinterface_write(MSUSB_INTERFACE_DESCRIPTOR * MsInterface, uint8 * data, int * offset) +{ + MSUSB_PIPE_DESCRIPTOR ** MsPipes; + MSUSB_PIPE_DESCRIPTOR * MsPipe; + int pnum = 0, move = 0; + + /* Length */ + data_write_uint16(data, MsInterface->Length); + /* InterfaceNumber */ + data_write_uint8(data + 2, MsInterface->InterfaceNumber); + /* AlternateSetting */ + data_write_uint8(data + 3, MsInterface->AlternateSetting); + /* bInterfaceClass */ + data_write_uint8(data + 4, MsInterface->bInterfaceClass); + /* bInterfaceSubClass */ + data_write_uint8(data + 5, MsInterface->bInterfaceSubClass); + /* bInterfaceProtocol */ + data_write_uint8(data + 6, MsInterface->bInterfaceProtocol); + /* Padding */ + data_write_uint8(data + 7, 0); + /* InterfaceHandle */ + data_write_uint32(data + 8, MsInterface->InterfaceHandle); + /* NumberOfPipes */ + data_write_uint32(data + 12, MsInterface->NumberOfPipes); + move += 16; + /* Pipes */ + MsPipes = MsInterface->MsPipes; + for(pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + /* MaximumPacketSize */ + data_write_uint16(data + move, MsPipe->MaximumPacketSize); + /* EndpointAddress */ + data_write_uint8(data + move + 2, MsPipe->bEndpointAddress); + /* Interval */ + data_write_uint8(data + move + 3, MsPipe->bInterval); + /* PipeType */ + data_write_uint32(data + move + 4, MsPipe->PipeType); + /* PipeHandle */ + data_write_uint32(data + move + 8, MsPipe->PipeHandle); + /* MaximumTransferSize */ + data_write_uint32(data + move + 12, MsPipe->MaximumTransferSize); + /* PipeFlags */ + data_write_uint32(data + move + 16, MsPipe->PipeFlags); + + move += 20; + } + + *offset += move; + + return 0; +} + +static MSUSB_INTERFACE_DESCRIPTOR ** +msusb_msinterface_read_list(uint8 * data, uint32 data_size, uint32 NumInterfaces) +{ + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + int inum, offset = 0; + + MsInterfaces = (MSUSB_INTERFACE_DESCRIPTOR **)malloc(NumInterfaces * + sizeof(MSUSB_INTERFACE_DESCRIPTOR *)); + + for(inum = 0; inum < NumInterfaces; inum++) + { + MsInterfaces[inum] = msusb_msinterface_read(data + offset, data_size - offset, &offset); + } + + + return MsInterfaces; +} + +int +msusb_msconfig_write(MSUSB_CONFIG_DESCRIPTOR * MsConfg, uint8 * data, int * offset) +{ + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR * MsInterface; + int inum = 0; + + /* ConfigurationHandle*/ + data_write_uint32(data + *offset, MsConfg->ConfigurationHandle); + /* NumInterfaces*/ + data_write_uint32(data + *offset + 4, MsConfg->NumInterfaces); + *offset += 8; + /* Interfaces */ + MsInterfaces = MsConfg->MsInterfaces; + for(inum = 0; inum < MsConfg->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + msusb_msinterface_write(MsInterface, data + (*offset), offset); + } + + return 0; +} + +MSUSB_CONFIG_DESCRIPTOR * +msusb_msconfig_new() +{ + MSUSB_CONFIG_DESCRIPTOR * MsConfig = NULL; + MsConfig = (MSUSB_CONFIG_DESCRIPTOR *)malloc(sizeof(MSUSB_CONFIG_DESCRIPTOR)); + memset(MsConfig, 0, sizeof(MSUSB_CONFIG_DESCRIPTOR)); + + return MsConfig; +} + +void +msusb_msconfig_free(MSUSB_CONFIG_DESCRIPTOR * MsConfig) +{ + if (MsConfig) + { + msusb_msinterface_free_list(MsConfig->MsInterfaces, MsConfig->NumInterfaces); + MsConfig->MsInterfaces = NULL; + zfree(MsConfig); + } +} + +MSUSB_CONFIG_DESCRIPTOR * +msusb_msconfig_read(uint8 * data, uint32 data_size, uint32 NumInterfaces) +{ + MSUSB_CONFIG_DESCRIPTOR * MsConfig; + uint8 lenConfiguration, typeConfiguration; + uint16 lenInterface; + int i, offset = 0; + + MsConfig = msusb_msconfig_new(); + + for(i = 0; i < NumInterfaces; i++) + { + data_read_uint16(data + offset, lenInterface); + offset += lenInterface; + } + data_read_uint8(data + offset, lenConfiguration); + data_read_uint8(data + offset + 1, typeConfiguration); + if (lenConfiguration != 0x9 || typeConfiguration != 0x2) + { + DEBUG("%s: len and type must be 0x9 and 0x2 , but it is 0x%x and 0x%x", + lenConfiguration, typeConfiguration); + } + data_read_uint16(data + offset + 2, MsConfig->wTotalLength); + data_read_uint8(data + offset + 5, MsConfig->bConfigurationValue); + MsConfig->NumInterfaces = NumInterfaces; + MsConfig->ConfigurationHandle = 0; + MsConfig->InitCompleted = 0; + MsConfig->MsOutSize = 0; + MsConfig->MsInterfaces = NULL; + offset = 0; + + if (NumInterfaces > 0) + { + MsConfig->MsInterfaces = + msusb_msinterface_read_list(data, data_size, NumInterfaces); + } + + return MsConfig; + +} + +void +msusb_msconfig_dump(MSUSB_CONFIG_DESCRIPTOR * MsConfig) +{ + MSUSB_INTERFACE_DESCRIPTOR ** MsInterfaces; + MSUSB_INTERFACE_DESCRIPTOR * MsInterface; + MSUSB_PIPE_DESCRIPTOR ** MsPipes; + MSUSB_PIPE_DESCRIPTOR * MsPipe; + int inum = 0, pnum = 0; + + printf("=================MsConfig:========================\n"); + printf("wTotalLength:%d\n", MsConfig->wTotalLength); + printf("bConfigurationValue:%d\n", MsConfig->bConfigurationValue); + printf("ConfigurationHandle:0x%x\n", MsConfig->ConfigurationHandle); + printf("InitCompleted:%d\n", MsConfig->InitCompleted); + printf("MsOutSize:%d\n", MsConfig->MsOutSize); + printf("NumInterfaces:%d\n\n", MsConfig->NumInterfaces); + MsInterfaces = MsConfig->MsInterfaces; + for(inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsInterface = MsInterfaces[inum]; + printf(" Interfase: %d\n", MsInterface->InterfaceNumber); + printf(" Length: %d\n", MsInterface->Length); + printf(" NumberOfPipesExpected: %d\n", MsInterface->NumberOfPipesExpected); + printf(" AlternateSetting: %d\n", MsInterface->AlternateSetting); + printf(" NumberOfPipes: %d\n", MsInterface->NumberOfPipes); + printf(" InterfaceHandle: 0x%x\n", MsInterface->InterfaceHandle); + printf(" bInterfaceClass: 0x%x\n", MsInterface->bInterfaceClass); + printf(" bInterfaceSubClass: 0x%x\n", MsInterface->bInterfaceSubClass); + printf(" bInterfaceProtocol: 0x%x\n", MsInterface->bInterfaceProtocol); + printf(" InitCompleted: %d\n\n", MsInterface->InitCompleted); + MsPipes = MsInterface->MsPipes; + for (pnum = 0; pnum < MsInterface->NumberOfPipes; pnum++) + { + MsPipe = MsPipes[pnum]; + printf(" Pipe: %d\n", pnum); + printf(" MaximumPacketSize: 0x%x\n", MsPipe->MaximumPacketSize); + printf(" MaximumTransferSize: 0x%x\n", MsPipe->MaximumTransferSize); + printf(" PipeFlags: 0x%x\n", MsPipe->PipeFlags); + printf(" PipeHandle: 0x%x\n", MsPipe->PipeHandle); + printf(" bEndpointAddress: 0x%x\n", MsPipe->bEndpointAddress); + printf(" bInterval: %d\n", MsPipe->bInterval); + printf(" PipeType: 0x%x\n", MsPipe->PipeType); + printf(" InitCompleted: %d\n\n", MsPipe->InitCompleted); + } + } + printf("==================================================\n"); +}