21#include <winpr/assert.h>
27#include <winpr/pool.h>
28#include <winpr/print.h>
31#include <winpr/synch.h>
32#include <winpr/string.h>
33#include <winpr/cmdline.h>
35#include <freerdp/dvc.h>
36#include <freerdp/addin.h>
37#include <freerdp/channels/log.h>
38#include <freerdp/channels/urbdrc.h>
40#include "urbdrc_types.h"
41#include "urbdrc_main.h"
42#include "data_transfer.h"
44#include <urbdrc_helpers.h>
53static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman)
58 return idevman->controlChannel;
61static int func_container_id_generate(IUDEVICE* pdev,
char* strContainerId)
63 const char* p =
nullptr;
64 UINT8 containerId[17] = WINPR_C_ARRAY_INIT;
67 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
68 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
69 const char* path = pdev->getPath(pdev);
71 const size_t plen = strlen(path);
77 (void)sprintf_s((
char*)containerId,
sizeof(containerId),
"%04" PRIX16
"%04" PRIX16
"%s",
78 idVendor, idProduct, p);
80 (void)sprintf_s(strContainerId, DEVICE_CONTAINER_STR_SIZE,
81 "{%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
82 "-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
83 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"}",
84 containerId[0], containerId[1], containerId[2], containerId[3], containerId[4],
85 containerId[5], containerId[6], containerId[7], containerId[8], containerId[9],
86 containerId[10], containerId[11], containerId[12], containerId[13],
87 containerId[14], containerId[15]);
91static int func_instance_id_generate(IUDEVICE* pdev,
char* strInstanceId,
size_t len)
93 char instanceId[17] = WINPR_C_ARRAY_INIT;
94 (void)sprintf_s(instanceId,
sizeof(instanceId),
"\\%s", pdev->getPath(pdev));
96 (void)sprintf_s(strInstanceId, len,
97 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
98 "-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
99 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"",
100 instanceId[0], instanceId[1], instanceId[2], instanceId[3], instanceId[4],
101 instanceId[5], instanceId[6], instanceId[7], instanceId[8], instanceId[9],
102 instanceId[10], instanceId[11], instanceId[12], instanceId[13], instanceId[14],
112 const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
113 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
116 return ERROR_OUTOFMEMORY;
118 Stream_Write_UINT32(out, 0x00000000);
119 return stream_write_and_free(callback->plugin, callback->channel, out);
130 WINPR_ASSERT(callback);
132 WINPR_ASSERT(urbdrc);
135 return ERROR_INVALID_PARAMETER;
137 if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
138 return ERROR_INVALID_DATA;
140 UINT32 Version = Stream_Get_UINT32(s);
142 if (Version > RIM_CAPABILITY_VERSION_01)
144 WLog_Print(urbdrc->log, WLOG_WARN,
"Unknown capability version %" PRIu32
", expected %d",
145 Version, RIM_CAPABILITY_VERSION_01);
146 Version = RIM_CAPABILITY_VERSION_01;
149 return urbdrc_send_capability_response(callback, MessageId, Version);
154 UINT32 MajorVersion, UINT32 MinorVersion,
157 WINPR_ASSERT(callback);
159 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
161 create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
164 return ERROR_OUTOFMEMORY;
166 Stream_Write_UINT32(out, MajorVersion);
167 Stream_Write_UINT32(out, MinorVersion);
168 Stream_Write_UINT32(out, Capabilities);
169 return stream_write_and_free(callback->plugin, callback->channel, out);
180 UINT32 MajorVersion = 0;
181 UINT32 MinorVersion = 0;
182 UINT32 Capabilities = 0;
185 if (!callback || !s || !callback->plugin)
186 return ERROR_INVALID_PARAMETER;
190 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
191 return ERROR_INVALID_DATA;
193 Stream_Read_UINT32(s, MajorVersion);
194 Stream_Read_UINT32(s, MinorVersion);
195 Stream_Read_UINT32(s, Capabilities);
198 if ((MajorVersion != 1) || (MinorVersion != 0))
200 WLog_Print(urbdrc->log, WLOG_WARN,
201 "server supports USB channel version %" PRIu32
".%" PRIu32, MajorVersion,
203 WLog_Print(urbdrc->log, WLOG_WARN,
"we only support channel version 1.0");
207 if (Capabilities != 0)
209 WLog_Print(urbdrc->log, WLOG_WARN,
210 "[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states "
211 "Capabilities must be 0, got %" PRIu32,
216 return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
220static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
223 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
224 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
225 ADD_VIRTUAL_CHANNEL, 0);
228 return ERROR_OUTOFMEMORY;
230 return stream_write_and_free(plugin, channel, out);
233static BOOL write_string_block(
wStream* s,
size_t count,
const char** strings,
const size_t* length,
237 for (
size_t x = 0; x < count; x++)
239 const SSIZE_T wlen = ConvertUtf8NToWChar(strings[x], length[x],
nullptr, 0);
242 len += WINPR_ASSERTING_INT_CAST(
size_t, wlen) + 1ULL;
248 if (!Stream_EnsureRemainingCapacity(s, len *
sizeof(WCHAR) +
sizeof(UINT32)))
252 Stream_Write_UINT32(s, WINPR_ASSERTING_INT_CAST(UINT32, len));
255 for (
size_t x = 0; x < count; x++)
257 size_t clength = length[x];
258 const char* str = strings[x];
259 const SSIZE_T wlen = ConvertUtf8NToWChar(str, clength,
nullptr, 0);
262 const size_t wlength = WINPR_ASSERTING_INT_CAST(
size_t, wlen);
264 const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, wlength, str, clength, TRUE);
265 if ((w < 0) || ((
size_t)w != wlength))
267 Stream_Write_UINT16(s, 0);
271 Stream_Write_UINT16(s, 0);
277 UINT32 bcdUSB,
enum device_speed deviceSpeed,
278 const char* strInstanceId,
size_t InstanceIdLen,
size_t nrHwIds,
279 const char* HardwareIds[],
const size_t HardwareIdsLen[],
280 size_t nrCompatIds,
const char* CompatibilityIds[],
281 const size_t CompatibilityIdsLen[],
const char* strContainerId,
282 size_t ContainerIdLen)
284 WINPR_ASSERT(callback);
285 WINPR_ASSERT(HardwareIds);
286 WINPR_ASSERT(HardwareIdsLen);
287 WINPR_ASSERT(CompatibilityIds);
288 WINPR_ASSERT(CompatibilityIdsLen);
290 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
291 wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
293 return ERROR_OUTOFMEMORY;
295 Stream_Write_UINT32(out, 0x00000001);
296 Stream_Write_UINT32(out, UsbDevice);
298 if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
301 if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
304 if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
307 if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
311 if (!Stream_EnsureRemainingCapacity(out, 28))
314 Stream_Write_UINT32(out, 0x0000001c);
315 Stream_Write_UINT32(out, 2);
316 Stream_Write_UINT32(out, 0x600);
318 Stream_Write_UINT32(out, bcdUSB);
319 Stream_Write_UINT32(out, 0x00000000);
323 UINT32 DeviceIsHighSpeed = 0;
326 case DEVICE_SPEED_LOW:
327 case DEVICE_SPEED_FULL:
328 DeviceIsHighSpeed = 0x00000000;
331 case DEVICE_SPEED_UNKNOWN:
335 DeviceIsHighSpeed = (bcdUSB < 0x200) ? 0x00000000 : 0x00000001;
339 DeviceIsHighSpeed = 0x00000001;
343 Stream_Write_UINT32(out, DeviceIsHighSpeed);
345 Stream_Write_UINT32(out, 0x50);
346 return stream_write_and_free(callback->plugin, callback->channel, out);
349 Stream_Free(out, TRUE);
350 return ERROR_INTERNAL_ERROR;
360 char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { WINPR_C_ARRAY_INIT };
361 const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
362 char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { WINPR_C_ARRAY_INIT };
363 const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
364 CompatibilityIds[2], CompatibilityIds[3] };
365 char strContainerId[DEVICE_CONTAINER_STR_SIZE] = WINPR_C_ARRAY_INIT;
366 char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = WINPR_C_ARRAY_INIT;
367 size_t CompatibilityIdLen[4] = WINPR_C_ARRAY_INIT;
368 size_t HardwareIdsLen[2] = WINPR_C_ARRAY_INIT;
369 const size_t nrHwIds = ARRAYSIZE(HardwareIds);
370 size_t nrCompatIds = 3;
373 if (!pdev->detach_kernel_driver(pdev))
374 return ERROR_INTERNAL_ERROR;
377 const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
378 const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
379 const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE);
380 (void)sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE,
381 "USB\\VID_%04" PRIX16
"&PID_%04" PRIX16
"", idVendor, idProduct);
382 (void)sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE,
383 "USB\\VID_%04" PRIX16
"&PID_%04" PRIX16
"&REV_%04" PRIX16
"", idVendor,
384 idProduct, bcdDevice);
387 const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS);
388 const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS);
389 const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL);
391 if (!(pdev->isCompositeDevice(pdev)))
393 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
394 "USB\\Class_%02" PRIX8
"", bDeviceClass);
395 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
396 "USB\\Class_%02" PRIX8
"&SubClass_%02" PRIX8
"", bDeviceClass,
398 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
399 "USB\\Class_%02" PRIX8
"&SubClass_%02" PRIX8
"&Prot_%02" PRIX8
"",
400 bDeviceClass, bDeviceSubClass, bDeviceProtocol);
404 (void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE,
"USB\\COMPOSITE");
405 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
"USB\\DevClass_00");
406 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
407 "USB\\DevClass_00&SubClass_00");
408 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
409 "USB\\DevClass_00&SubClass_00&Prot_00");
413 func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
414 func_container_id_generate(pdev, strContainerId);
416 for (
size_t x = 0; x < nrHwIds; x++)
418 HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
421 for (
size_t x = 0; x < nrCompatIds; x++)
423 CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
426 const size_t InstanceIdLen = strnlen(strInstanceId,
sizeof(strInstanceId));
427 const size_t ContainerIdLen = strnlen(strContainerId,
sizeof(strContainerId));
429 const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
430 const UINT32 bcdUSB =
431 WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
432 const enum device_speed deviceSpeed = pdev->query_device_speed(pdev);
433 return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, deviceSpeed, strInstanceId,
434 InstanceIdLen, nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
435 CCompatibilityIds, CompatibilityIdLen, strContainerId,
446 UINT32 MessageId = 0;
447 UINT32 FunctionId = 0;
448 UINT32 InterfaceId = 0;
449 UINT error = CHANNEL_RC_OK;
452 return ERROR_INVALID_PARAMETER;
454 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
455 return ERROR_INVALID_DATA;
457 Stream_Rewind_UINT32(data);
458 Stream_Read_UINT32(data, InterfaceId);
459 Stream_Read_UINT32(data, MessageId);
460 Stream_Read_UINT32(data, FunctionId);
464 case RIM_EXCHANGE_CAPABILITY_REQUEST:
465 if (InterfaceId != 0)
469 "[MS-RDPEUSB] 2.2.3.1 Interface Manipulation Exchange Capabilities Request "
470 "(RIM_EXCHANGE_CAPABILITY_REQUEST))::InterfaceId expected 0, got %" PRIu32,
472 return ERROR_INVALID_DATA;
474 error = urbdrc_process_capability_request(callback, data, MessageId);
477 case RIMCALL_RELEASE:
481 error = ERROR_NOT_FOUND;
488static BOOL urbdrc_announce_devices(IUDEVMAN* udevman)
490 UINT error = ERROR_SUCCESS;
492 udevman->loading_lock(udevman);
493 udevman->rewind(udevman);
495 while (udevman->has_next(udevman))
497 IUDEVICE* pdev = udevman->get_next(udevman);
499 if (!pdev->isAlreadySend(pdev))
501 UINT cerror = ERROR_SUCCESS;
502 const UINT32 deviceId = pdev->get_UsbDevice(pdev);
503 udevman->loading_lock(udevman);
504 if (!pdev->isChannelClosed(pdev))
506 IWTSVirtualChannel* channel = get_channel(udevman);
508 cerror = urdbrc_send_virtual_channel_add(udevman->plugin, channel, deviceId);
510 udevman->loading_unlock(udevman);
511 if (cerror != ERROR_SUCCESS)
516 udevman->loading_unlock(udevman);
518 return error == ERROR_SUCCESS;
525 IUDEVMAN* udevman = urbdrc->udevman;
526 IWTSVirtualChannel* channel = callback->channel;
527 IUDEVICE* pdev =
nullptr;
529 UINT error = ERROR_INTERNAL_ERROR;
530 UINT32 channelId = callback->channel_mgr->GetChannelId(channel);
532 switch (urbdrc->vchannel_status)
534 case INIT_CHANNEL_IN:
536 error = ERROR_SUCCESS;
537 if (!udevman->initialize(udevman, channelId))
540 udevman->loading_lock(udevman);
541 udevman->controlChannel = channel;
542 udevman->loading_unlock(udevman);
544 if (!urbdrc_announce_devices(udevman))
547 urbdrc->vchannel_status = INIT_CHANNEL_OUT;
550 case INIT_CHANNEL_OUT:
553 udevman->loading_lock(udevman);
554 udevman->rewind(udevman);
556 while (udevman->has_next(udevman))
558 pdev = udevman->get_next(udevman);
560 if (!pdev->isAlreadySend(pdev))
562 const UINT32 channelID = callback->channel_mgr->GetChannelId(channel);
564 pdev->setAlreadySend(pdev);
565 pdev->set_channelManager(pdev, callback->channel_mgr);
566 pdev->set_channelID(pdev, channelID);
571 udevman->loading_unlock(udevman);
572 error = ERROR_SUCCESS;
574 if (found && pdev->isAlreadySend(pdev))
575 error = urdbrc_send_usb_device_add(callback, pdev);
580 WLog_Print(urbdrc->log, WLOG_ERROR,
"vchannel_status unknown value %" PRIu32
"",
581 urbdrc->vchannel_status);
596 UINT32 MessageId = 0;
597 UINT32 FunctionId = 0;
598 UINT32 InterfaceId = 0;
599 UINT error = CHANNEL_RC_OK;
602 if (!callback || !data)
603 return ERROR_INVALID_PARAMETER;
608 return ERROR_INVALID_PARAMETER;
610 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
611 return ERROR_INVALID_DATA;
613 Stream_Rewind(data, 4);
614 Stream_Read_UINT32(data, InterfaceId);
615 Stream_Read_UINT32(data, MessageId);
616 Stream_Read_UINT32(data, FunctionId);
617 WLog_Print(urbdrc->log, WLOG_TRACE,
"%s [%" PRIu32
"]",
618 call_to_string(FALSE, InterfaceId, FunctionId), FunctionId);
622 case CHANNEL_CREATED:
623 error = urbdrc_process_channel_create(callback, data, MessageId);
626 case RIMCALL_RELEASE:
627 error = urbdrc_device_control_channel(callback, data);
631 WLog_Print(urbdrc->log, WLOG_TRACE,
"unknown FunctionId 0x%" PRIX32
"", FunctionId);
644static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
648 IUDEVMAN* udevman =
nullptr;
649 UINT32 InterfaceId = 0;
650 UINT error = ERROR_INTERNAL_ERROR;
652 if (callback ==
nullptr)
653 return ERROR_INVALID_PARAMETER;
655 if (callback->plugin ==
nullptr)
660 if (urbdrc->udevman ==
nullptr)
663 udevman = urbdrc->udevman;
665 if (!Stream_CheckAndLogRequiredLength(TAG, data, 12))
666 return ERROR_INVALID_DATA;
668 urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data);
669 Stream_Read_UINT32(data, InterfaceId);
674 case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30):
675 error = urbdrc_exchange_capabilities(callback, data);
678 case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30):
679 error = urbdrc_process_channel_notification(callback, data);
683 error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data);
684 WLog_DBG(TAG,
"urbdrc_process_udev_data_transfer returned 0x%08" PRIx32, error);
685 error = ERROR_SUCCESS;
697static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
705 IUDEVMAN* udevman = urbdrc->udevman;
706 if (udevman && callback->channel_mgr)
708 udevman->loading_lock(udevman);
709 if (udevman->controlChannel == callback->channel)
711 udevman->controlChannel =
nullptr;
712 udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
713 udevman->controlChannelId = 0;
715 UINT32 control = callback->channel_mgr->GetChannelId(callback->channel);
716 IUDEVICE* pdev = udevman->get_udevice_by_ChannelID(udevman, control);
717 if (pdev && !pdev->isChannelClosed(pdev))
719 if (udevman->controlChannelId == control)
721 udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
722 udevman->controlChannelId = 0;
728 pdev->markChannelClosed(pdev);
731 udevman->loading_unlock(udevman);
736 return CHANNEL_RC_OK;
744static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
745 IWTSVirtualChannel* pChannel,
746 WINPR_ATTR_UNUSED BYTE* pData,
747 WINPR_ATTR_UNUSED BOOL* pbAccept,
748 IWTSVirtualChannelCallback** ppCallback)
754 return ERROR_INVALID_PARAMETER;
759 return ERROR_OUTOFMEMORY;
761 callback->iface.OnDataReceived = urbdrc_on_data_received;
762 callback->iface.OnClose = urbdrc_on_close;
763 callback->plugin = listener_callback->plugin;
764 callback->channel_mgr = listener_callback->channel_mgr;
765 callback->channel = pChannel;
766 *ppCallback = (IWTSVirtualChannelCallback*)callback;
767 return CHANNEL_RC_OK;
775static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
779 IUDEVMAN* udevman =
nullptr;
780 char channelName[
sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME };
782 if (!urbdrc || !urbdrc->udevman)
783 return ERROR_INVALID_PARAMETER;
785 if (urbdrc->initialized)
787 WLog_ERR(TAG,
"[%s] channel initialized twice, aborting", URBDRC_CHANNEL_NAME);
788 return ERROR_INVALID_DATA;
790 udevman = urbdrc->udevman;
791 urbdrc->listener_callback =
794 if (!urbdrc->listener_callback)
795 return CHANNEL_RC_NO_MEMORY;
797 urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection;
798 urbdrc->listener_callback->plugin = pPlugin;
799 urbdrc->listener_callback->channel_mgr = pChannelMgr;
802 CharUpperA(channelName);
803 status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0,
804 &urbdrc->listener_callback->iface, &urbdrc->listener);
805 if (status != CHANNEL_RC_OK)
808 status = CHANNEL_RC_OK;
809 if (udevman->listener_created_callback)
810 status = udevman->listener_created_callback(udevman);
812 urbdrc->initialized = status == CHANNEL_RC_OK;
821static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin)
824 IUDEVMAN* udevman =
nullptr;
827 return ERROR_INVALID_DATA;
828 if (urbdrc->listener_callback)
830 IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr;
832 IFCALL(mgr->DestroyListener, mgr, urbdrc->listener);
834 udevman = urbdrc->udevman;
838 udevman->free(udevman);
842 free(urbdrc->subsystem);
843 free(urbdrc->listener_callback);
845 return CHANNEL_RC_OK;
848static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman)
854 WLog_Print(urbdrc->log, WLOG_ERROR,
"existing device, abort.");
858 DEBUG_DVC(
"device registered.");
859 urbdrc->udevman = udevman;
868static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name,
const ADDIN_ARGV* args)
873 PVIRTUALCHANNELENTRY pvce =
874 freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, name,
nullptr, 0);
875 PFREERDP_URBDRC_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_URBDRC_DEVICE_ENTRY);
878 return ERROR_INVALID_OPERATION;
880 entryPoints.plugin = pPlugin;
881 entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_addin;
882 entryPoints.args = args;
884 const UINT error = entry(&entryPoints);
887 WLog_Print(urbdrc->log, WLOG_ERROR,
"%s entry returns error.", name);
891 return CHANNEL_RC_OK;
894static BOOL urbdrc_set_subsystem(
URBDRC_PLUGIN* urbdrc,
const char* subsystem)
896 free(urbdrc->subsystem);
897 urbdrc->subsystem = _strdup(subsystem);
898 return (urbdrc->subsystem !=
nullptr);
910 {
"dbg", COMMAND_LINE_VALUE_FLAG,
"",
nullptr, BoolValueFalse, -1,
nullptr,
"debug" },
911 {
"sys", COMMAND_LINE_VALUE_REQUIRED,
"<subsystem>",
nullptr,
nullptr, -1,
nullptr,
913 {
"dev", COMMAND_LINE_VALUE_REQUIRED,
"<device list>",
nullptr,
nullptr, -1,
nullptr,
915 {
"encode", COMMAND_LINE_VALUE_FLAG,
"",
nullptr,
nullptr, -1,
nullptr,
"encode" },
916 {
"quality", COMMAND_LINE_VALUE_REQUIRED,
"<[0-2] -> [high-medium-low]>",
nullptr,
nullptr,
917 -1,
nullptr,
"quality" },
918 {
nullptr, 0,
nullptr,
nullptr,
nullptr, -1,
nullptr,
nullptr }
922 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
924 status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc,
nullptr,
928 return ERROR_INVALID_DATA;
934 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
937 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"dbg")
939 if (!WLog_SetLogLevel(urbdrc->log, WLOG_TRACE))
940 return ERROR_INTERNAL_ERROR;
942 CommandLineSwitchCase(arg,
"sys")
944 if (!urbdrc_set_subsystem(urbdrc, arg->Value))
945 return ERROR_OUTOFMEMORY;
947 CommandLineSwitchDefault(arg)
950 CommandLineSwitchEnd(arg)
951 }
while ((arg = CommandLineFindNextArgumentA(arg)) !=
nullptr);
953 return CHANNEL_RC_OK;
956BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
966 if (!urbdrc || !urbdrc->listener_callback)
969 UINT32 mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT);
970 if ((flags & mask) == mask)
971 regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID;
972 mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV);
973 if ((flags & mask) == mask)
974 regflags |= UDEVMAN_FLAG_ADD_BY_ADDR;
976 const size_t success =
977 idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags);
979 if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER))
981 if (!urbdrc_announce_devices(idevman))
988BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
991 IUDEVICE* pdev =
nullptr;
999 if (!urbdrc || !urbdrc->listener_callback)
1002 idevman->loading_lock(idevman);
1003 idevman->rewind(idevman);
1005 while (idevman->has_next(idevman))
1008 IUDEVICE* dev = idevman->get_next(idevman);
1010 if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR |
1011 DEVICE_ADD_FLAG_PRODUCT)) == 0)
1013 if (flags & DEVICE_ADD_FLAG_BUS)
1015 if (dev->get_bus_number(dev) != busnum)
1018 if (flags & DEVICE_ADD_FLAG_DEV)
1020 if (dev->get_dev_number(dev) != devnum)
1023 if (flags & DEVICE_ADD_FLAG_VENDOR)
1025 int vid = dev->query_device_descriptor(dev, ID_VENDOR);
1026 if (vid != idVendor)
1029 if (flags & DEVICE_ADD_FLAG_PRODUCT)
1031 int pid = dev->query_device_descriptor(dev, ID_PRODUCT);
1032 if (pid != idProduct)
1044 pdev->setChannelClosed(pdev);
1046 idevman->loading_unlock(idevman);
1055FREERDP_ENTRY_POINT(UINT VCAPITYPE urbdrc_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1060 urbdrc = (
URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME);
1061 args = pEntryPoints->GetPluginData(pEntryPoints);
1063 if (urbdrc ==
nullptr)
1068 return CHANNEL_RC_NO_MEMORY;
1070 urbdrc->iface.Initialize = urbdrc_plugin_initialize;
1071 urbdrc->iface.Terminated = urbdrc_plugin_terminated;
1072 urbdrc->vchannel_status = INIT_CHANNEL_IN;
1073 status = pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, &urbdrc->iface);
1076 if (status != CHANNEL_RC_OK)
1082 urbdrc->log = WLog_Get(TAG);
1088 status = urbdrc_process_addin_args(urbdrc, args);
1090 if (status != CHANNEL_RC_OK)
1093 if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc,
"libusb"))
1096 return urbdrc_load_udevman_addin(&urbdrc->iface, urbdrc->subsystem, args);
1101UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
wStream* out)
1106 return ERROR_INVALID_PARAMETER;
1108 if (!channel || !out || !urbdrc)
1110 Stream_Free(out, TRUE);
1111 return ERROR_INVALID_PARAMETER;
1114 if (!channel->Write)
1116 Stream_Free(out, TRUE);
1117 return ERROR_INTERNAL_ERROR;
1120 urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out);
1121 const size_t len = Stream_GetPosition(out);
1122 UINT rc = ERROR_INTERNAL_ERROR;
1123 if (len <= UINT32_MAX)
1124 rc = channel->Write(channel, (UINT32)len, Stream_Buffer(out),
nullptr);
1125 Stream_Free(out, TRUE);