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>
46static IWTSVirtualChannel* get_channel(IUDEVMAN* idevman)
48 IWTSVirtualChannelManager* channel_mgr = NULL;
56 if (!urbdrc || !urbdrc->listener_callback)
59 channel_mgr = urbdrc->listener_callback->channel_mgr;
64 return channel_mgr->FindChannelById(channel_mgr, idevman->controlChannelId);
67static int func_container_id_generate(IUDEVICE* pdev,
char* strContainerId)
71 UINT8 containerId[17] = { 0 };
74 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
75 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
76 path = pdev->getPath(pdev);
79 p = (path + strlen(path)) - 8;
83 (void)sprintf_s((
char*)containerId,
sizeof(containerId),
"%04" PRIX16
"%04" PRIX16
"%s",
84 idVendor, idProduct, p);
86 (void)sprintf_s(strContainerId, DEVICE_CONTAINER_STR_SIZE,
87 "{%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
88 "-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
89 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"}",
90 containerId[0], containerId[1], containerId[2], containerId[3], containerId[4],
91 containerId[5], containerId[6], containerId[7], containerId[8], containerId[9],
92 containerId[10], containerId[11], containerId[12], containerId[13],
93 containerId[14], containerId[15]);
97static int func_instance_id_generate(IUDEVICE* pdev,
char* strInstanceId,
size_t len)
99 char instanceId[17] = { 0 };
100 (void)sprintf_s(instanceId,
sizeof(instanceId),
"\\%s", pdev->getPath(pdev));
102 (void)sprintf_s(strInstanceId, len,
103 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
104 "-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
"-%02" PRIx8
"%02" PRIx8
105 "%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"%02" PRIx8
"",
106 instanceId[0], instanceId[1], instanceId[2], instanceId[3], instanceId[4],
107 instanceId[5], instanceId[6], instanceId[7], instanceId[8], instanceId[9],
108 instanceId[10], instanceId[11], instanceId[12], instanceId[13], instanceId[14],
118 const UINT32 InterfaceId = ((STREAM_ID_NONE << 30) | CAPABILITIES_NEGOTIATOR);
119 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId, Version, 4);
122 return ERROR_OUTOFMEMORY;
124 Stream_Write_UINT32(out, 0x00000000);
125 return stream_write_and_free(callback->plugin, callback->channel, out);
136 WINPR_ASSERT(callback);
138 WINPR_ASSERT(urbdrc);
141 return ERROR_INVALID_PARAMETER;
143 if (!Stream_CheckAndLogRequiredLengthWLog(urbdrc->log, s, 4))
144 return ERROR_INVALID_DATA;
146 UINT32 Version = Stream_Get_UINT32(s);
148 if (Version > RIM_CAPABILITY_VERSION_01)
150 WLog_Print(urbdrc->log, WLOG_WARN,
"Unknown capability version %" PRIu32
", expected %d",
151 Version, RIM_CAPABILITY_VERSION_01);
152 Version = RIM_CAPABILITY_VERSION_01;
155 return urbdrc_send_capability_response(callback, MessageId, Version);
160 UINT32 MajorVersion, UINT32 MinorVersion,
163 WINPR_ASSERT(callback);
165 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_CHANNEL_NOTIFICATION);
167 create_shared_message_header_with_functionid(InterfaceId, MessageId, CHANNEL_CREATED, 12);
170 return ERROR_OUTOFMEMORY;
172 Stream_Write_UINT32(out, MajorVersion);
173 Stream_Write_UINT32(out, MinorVersion);
174 Stream_Write_UINT32(out, Capabilities);
175 return stream_write_and_free(callback->plugin, callback->channel, out);
186 UINT32 MajorVersion = 0;
187 UINT32 MinorVersion = 0;
188 UINT32 Capabilities = 0;
191 if (!callback || !s || !callback->plugin)
192 return ERROR_INVALID_PARAMETER;
196 if (!Stream_CheckAndLogRequiredLength(TAG, s, 12))
197 return ERROR_INVALID_DATA;
199 Stream_Read_UINT32(s, MajorVersion);
200 Stream_Read_UINT32(s, MinorVersion);
201 Stream_Read_UINT32(s, Capabilities);
204 if ((MajorVersion != 1) || (MinorVersion != 0))
206 WLog_Print(urbdrc->log, WLOG_WARN,
207 "server supports USB channel version %" PRIu32
".%" PRIu32, MajorVersion,
209 WLog_Print(urbdrc->log, WLOG_WARN,
"we only support channel version 1.0");
213 if (Capabilities != 0)
215 WLog_Print(urbdrc->log, WLOG_WARN,
216 "[MS-RDPEUSB] 2.2.5.1 Channel Created Message (CHANNEL_CREATED) states "
217 "Capabilities must be 0, got %" PRIu32,
222 return urbdrc_send_channel_created(callback, MessageId, MajorVersion, MinorVersion,
226static UINT urdbrc_send_virtual_channel_add(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
229 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
230 wStream* out = create_shared_message_header_with_functionid(InterfaceId, MessageId,
231 ADD_VIRTUAL_CHANNEL, 0);
234 return ERROR_OUTOFMEMORY;
236 return stream_write_and_free(plugin, channel, out);
239static BOOL write_string_block(
wStream* s,
size_t count,
const char** strings,
const size_t* length,
243 for (
size_t x = 0; x < count; x++)
245 len += length[x] + 1ULL;
251 if (!Stream_EnsureRemainingCapacity(s, len *
sizeof(WCHAR) +
sizeof(UINT32)))
255 Stream_Write_UINT32(s, (UINT32)len);
258 for (
size_t x = 0; x < count; x++)
260 size_t clength = length[x];
261 const char* str = strings[x];
263 const SSIZE_T w = Stream_Write_UTF16_String_From_UTF8(s, clength, str, clength, TRUE);
264 if ((w < 0) || ((
size_t)w != clength))
266 Stream_Write_UINT16(s, 0);
270 Stream_Write_UINT16(s, 0);
276 UINT32 bcdUSB,
const char* strInstanceId,
size_t InstanceIdLen,
277 size_t nrHwIds,
const char* HardwareIds[],
278 const size_t HardwareIdsLen[],
size_t nrCompatIds,
279 const char* CompatibilityIds[],
280 const size_t CompatibilityIdsLen[],
const char* strContainerId,
281 size_t ContainerIdLen)
283 WINPR_ASSERT(callback);
284 WINPR_ASSERT(HardwareIds);
285 WINPR_ASSERT(HardwareIdsLen);
286 WINPR_ASSERT(CompatibilityIds);
287 WINPR_ASSERT(CompatibilityIdsLen);
289 const UINT32 InterfaceId = ((STREAM_ID_PROXY << 30) | CLIENT_DEVICE_SINK);
290 wStream* out = create_shared_message_header_with_functionid(InterfaceId, 0, ADD_DEVICE, 8);
292 return ERROR_OUTOFMEMORY;
294 Stream_Write_UINT32(out, 0x00000001);
295 Stream_Write_UINT32(out, UsbDevice);
297 if (!write_string_block(out, 1, &strInstanceId, &InstanceIdLen, FALSE))
300 if (!write_string_block(out, nrHwIds, HardwareIds, HardwareIdsLen, TRUE))
303 if (!write_string_block(out, nrCompatIds, CompatibilityIds, CompatibilityIdsLen, TRUE))
306 if (!write_string_block(out, 1, &strContainerId, &ContainerIdLen, FALSE))
310 if (!Stream_EnsureRemainingCapacity(out, 28))
313 Stream_Write_UINT32(out, 0x0000001c);
314 Stream_Write_UINT32(out, 2);
315 Stream_Write_UINT32(out, 0x600);
317 Stream_Write_UINT32(out, bcdUSB);
318 Stream_Write_UINT32(out, 0x00000000);
321 Stream_Write_UINT32(out, 0x00000000);
323 Stream_Write_UINT32(out, 0x00000001);
325 Stream_Write_UINT32(out, 0x50);
326 return stream_write_and_free(callback->plugin, callback->channel, out);
329 Stream_Free(out, TRUE);
330 return ERROR_INTERNAL_ERROR;
340 char HardwareIds[2][DEVICE_HARDWARE_ID_SIZE] = { { 0 } };
341 const char* CHardwareIds[2] = { HardwareIds[0], HardwareIds[1] };
342 char CompatibilityIds[4][DEVICE_COMPATIBILITY_ID_SIZE] = { { 0 } };
343 const char* CCompatibilityIds[4] = { CompatibilityIds[0], CompatibilityIds[1],
344 CompatibilityIds[2], CompatibilityIds[3] };
345 char strContainerId[DEVICE_CONTAINER_STR_SIZE] = { 0 };
346 char strInstanceId[DEVICE_INSTANCE_STR_SIZE] = { 0 };
347 size_t CompatibilityIdLen[4] = { 0 };
348 size_t HardwareIdsLen[2] = { 0 };
349 const size_t nrHwIds = ARRAYSIZE(HardwareIds);
350 size_t nrCompatIds = 3;
353 pdev->detach_kernel_driver(pdev);
355 const UINT16 idVendor = (UINT16)pdev->query_device_descriptor(pdev, ID_VENDOR);
356 const UINT16 idProduct = (UINT16)pdev->query_device_descriptor(pdev, ID_PRODUCT);
357 const UINT16 bcdDevice = (UINT16)pdev->query_device_descriptor(pdev, BCD_DEVICE);
358 (void)sprintf_s(HardwareIds[1], DEVICE_HARDWARE_ID_SIZE,
359 "USB\\VID_%04" PRIX16
"&PID_%04" PRIX16
"", idVendor, idProduct);
360 (void)sprintf_s(HardwareIds[0], DEVICE_HARDWARE_ID_SIZE,
361 "USB\\VID_%04" PRIX16
"&PID_%04" PRIX16
"&REV_%04" PRIX16
"", idVendor,
362 idProduct, bcdDevice);
365 const UINT8 bDeviceClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_CLASS);
366 const UINT8 bDeviceSubClass = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_SUBCLASS);
367 const UINT8 bDeviceProtocol = (UINT8)pdev->query_device_descriptor(pdev, B_DEVICE_PROTOCOL);
369 if (!(pdev->isCompositeDevice(pdev)))
371 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
372 "USB\\Class_%02" PRIX8
"", bDeviceClass);
373 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
374 "USB\\Class_%02" PRIX8
"&SubClass_%02" PRIX8
"", bDeviceClass,
376 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
377 "USB\\Class_%02" PRIX8
"&SubClass_%02" PRIX8
"&Prot_%02" PRIX8
"",
378 bDeviceClass, bDeviceSubClass, bDeviceProtocol);
382 (void)sprintf_s(CompatibilityIds[3], DEVICE_COMPATIBILITY_ID_SIZE,
"USB\\COMPOSITE");
383 (void)sprintf_s(CompatibilityIds[2], DEVICE_COMPATIBILITY_ID_SIZE,
"USB\\DevClass_00");
384 (void)sprintf_s(CompatibilityIds[1], DEVICE_COMPATIBILITY_ID_SIZE,
385 "USB\\DevClass_00&SubClass_00");
386 (void)sprintf_s(CompatibilityIds[0], DEVICE_COMPATIBILITY_ID_SIZE,
387 "USB\\DevClass_00&SubClass_00&Prot_00");
391 func_instance_id_generate(pdev, strInstanceId, DEVICE_INSTANCE_STR_SIZE);
392 func_container_id_generate(pdev, strContainerId);
394 for (
size_t x = 0; x < nrHwIds; x++)
396 HardwareIdsLen[x] = strnlen(HardwareIds[x], DEVICE_HARDWARE_ID_SIZE);
399 for (
size_t x = 0; x < nrCompatIds; x++)
401 CompatibilityIdLen[x] = strnlen(CompatibilityIds[x], DEVICE_COMPATIBILITY_ID_SIZE);
404 const size_t InstanceIdLen = strnlen(strInstanceId,
sizeof(strInstanceId));
405 const size_t ContainerIdLen = strnlen(strContainerId,
sizeof(strContainerId));
407 const UINT32 UsbDevice = pdev->get_UsbDevice(pdev);
408 const UINT32 bcdUSB =
409 WINPR_ASSERTING_INT_CAST(uint32_t, pdev->query_device_descriptor(pdev, BCD_USB));
410 return urbdrc_send_add_device(callback, UsbDevice, bcdUSB, strInstanceId, InstanceIdLen,
411 nrHwIds, CHardwareIds, HardwareIdsLen, nrCompatIds,
412 CCompatibilityIds, CompatibilityIdLen, strContainerId,
423 UINT32 MessageId = 0;
424 UINT32 FunctionId = 0;
425 UINT32 InterfaceId = 0;
426 UINT error = CHANNEL_RC_OK;
429 return ERROR_INVALID_PARAMETER;
431 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
432 return ERROR_INVALID_DATA;
434 Stream_Rewind_UINT32(data);
435 Stream_Read_UINT32(data, InterfaceId);
436 Stream_Read_UINT32(data, MessageId);
437 Stream_Read_UINT32(data, FunctionId);
441 case RIM_EXCHANGE_CAPABILITY_REQUEST:
442 if (InterfaceId != 0)
446 "[MS-RDPEUSB] 2.2.3.1 Interface Manipulation Exchange Capabilities Request "
447 "(RIM_EXCHANGE_CAPABILITY_REQUEST))::InterfaceId expected 0, got %" PRIu32,
449 return ERROR_INVALID_DATA;
451 error = urbdrc_process_capability_request(callback, data, MessageId);
454 case RIMCALL_RELEASE:
458 error = ERROR_NOT_FOUND;
465static BOOL urbdrc_announce_devices(IUDEVMAN* udevman)
467 UINT error = ERROR_SUCCESS;
469 udevman->loading_lock(udevman);
470 udevman->rewind(udevman);
472 while (udevman->has_next(udevman))
474 IUDEVICE* pdev = udevman->get_next(udevman);
476 if (!pdev->isAlreadySend(pdev))
478 const UINT32 deviceId = pdev->get_UsbDevice(pdev);
480 urdbrc_send_virtual_channel_add(udevman->plugin, get_channel(udevman), deviceId);
482 if (cerror != ERROR_SUCCESS)
487 udevman->loading_unlock(udevman);
489 return error == ERROR_SUCCESS;
496 IUDEVMAN* udevman = urbdrc->udevman;
497 IWTSVirtualChannel* channel = callback->channel;
498 IUDEVICE* pdev = NULL;
500 UINT error = ERROR_INTERNAL_ERROR;
501 UINT32 channelId = callback->channel_mgr->GetChannelId(channel);
503 switch (urbdrc->vchannel_status)
505 case INIT_CHANNEL_IN:
507 error = ERROR_SUCCESS;
508 udevman->initialize(udevman, channelId);
510 if (!urbdrc_announce_devices(udevman))
513 urbdrc->vchannel_status = INIT_CHANNEL_OUT;
516 case INIT_CHANNEL_OUT:
519 udevman->loading_lock(udevman);
520 udevman->rewind(udevman);
522 while (udevman->has_next(udevman))
524 pdev = udevman->get_next(udevman);
526 if (!pdev->isAlreadySend(pdev))
528 const UINT32 channelID = callback->channel_mgr->GetChannelId(channel);
530 pdev->setAlreadySend(pdev);
531 pdev->set_channelManager(pdev, callback->channel_mgr);
532 pdev->set_channelID(pdev, channelID);
537 udevman->loading_unlock(udevman);
538 error = ERROR_SUCCESS;
540 if (found && pdev->isAlreadySend(pdev))
541 error = urdbrc_send_usb_device_add(callback, pdev);
546 WLog_Print(urbdrc->log, WLOG_ERROR,
"vchannel_status unknown value %" PRIu32
"",
547 urbdrc->vchannel_status);
562 UINT32 MessageId = 0;
563 UINT32 FunctionId = 0;
564 UINT32 InterfaceId = 0;
565 UINT error = CHANNEL_RC_OK;
568 if (!callback || !data)
569 return ERROR_INVALID_PARAMETER;
574 return ERROR_INVALID_PARAMETER;
576 if (!Stream_CheckAndLogRequiredLength(TAG, data, 8))
577 return ERROR_INVALID_DATA;
579 Stream_Rewind(data, 4);
580 Stream_Read_UINT32(data, InterfaceId);
581 Stream_Read_UINT32(data, MessageId);
582 Stream_Read_UINT32(data, FunctionId);
583 WLog_Print(urbdrc->log, WLOG_TRACE,
"%s [%" PRIu32
"]",
584 call_to_string(FALSE, InterfaceId, FunctionId), FunctionId);
588 case CHANNEL_CREATED:
589 error = urbdrc_process_channel_create(callback, data, MessageId);
592 case RIMCALL_RELEASE:
593 error = urbdrc_device_control_channel(callback, data);
597 WLog_Print(urbdrc->log, WLOG_TRACE,
"unknown FunctionId 0x%" PRIX32
"", FunctionId);
610static UINT urbdrc_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
wStream* data)
614 IUDEVMAN* udevman = NULL;
615 UINT32 InterfaceId = 0;
616 UINT error = ERROR_INTERNAL_ERROR;
618 if (callback == NULL)
619 return ERROR_INVALID_PARAMETER;
621 if (callback->plugin == NULL)
626 if (urbdrc->udevman == NULL)
629 udevman = urbdrc->udevman;
631 if (!Stream_CheckAndLogRequiredLength(TAG, data, 12))
632 return ERROR_INVALID_DATA;
634 urbdrc_dump_message(urbdrc->log, FALSE, FALSE, data);
635 Stream_Read_UINT32(data, InterfaceId);
640 case CAPABILITIES_NEGOTIATOR | (STREAM_ID_NONE << 30):
641 error = urbdrc_exchange_capabilities(callback, data);
644 case SERVER_CHANNEL_NOTIFICATION | (STREAM_ID_PROXY << 30):
645 error = urbdrc_process_channel_notification(callback, data);
649 error = urbdrc_process_udev_data_transfer(callback, urbdrc, udevman, data);
650 WLog_DBG(TAG,
"urbdrc_process_udev_data_transfer returned 0x%08" PRIx32, error);
651 error = ERROR_SUCCESS;
663static UINT urbdrc_on_close(IWTSVirtualChannelCallback* pChannelCallback)
671 IUDEVMAN* udevman = urbdrc->udevman;
672 if (udevman && callback->channel_mgr)
674 UINT32 control = callback->channel_mgr->GetChannelId(callback->channel);
675 if (udevman->controlChannelId == control)
676 udevman->status |= URBDRC_DEVICE_CHANNEL_CLOSED;
679 IUDEVICE* pdev = udevman->get_udevice_by_ChannelID(udevman, control);
681 pdev->markChannelClosed(pdev);
687 return CHANNEL_RC_OK;
695static UINT urbdrc_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
696 IWTSVirtualChannel* pChannel,
697 WINPR_ATTR_UNUSED BYTE* pData,
698 WINPR_ATTR_UNUSED BOOL* pbAccept,
699 IWTSVirtualChannelCallback** ppCallback)
705 return ERROR_INVALID_PARAMETER;
710 return ERROR_OUTOFMEMORY;
712 callback->iface.OnDataReceived = urbdrc_on_data_received;
713 callback->iface.OnClose = urbdrc_on_close;
714 callback->plugin = listener_callback->plugin;
715 callback->channel_mgr = listener_callback->channel_mgr;
716 callback->channel = pChannel;
717 *ppCallback = (IWTSVirtualChannelCallback*)callback;
718 return CHANNEL_RC_OK;
726static UINT urbdrc_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
730 IUDEVMAN* udevman = NULL;
731 char channelName[
sizeof(URBDRC_CHANNEL_NAME)] = { URBDRC_CHANNEL_NAME };
733 if (!urbdrc || !urbdrc->udevman)
734 return ERROR_INVALID_PARAMETER;
736 if (urbdrc->initialized)
738 WLog_ERR(TAG,
"[%s] channel initialized twice, aborting", URBDRC_CHANNEL_NAME);
739 return ERROR_INVALID_DATA;
741 udevman = urbdrc->udevman;
742 urbdrc->listener_callback =
745 if (!urbdrc->listener_callback)
746 return CHANNEL_RC_NO_MEMORY;
748 urbdrc->listener_callback->iface.OnNewChannelConnection = urbdrc_on_new_channel_connection;
749 urbdrc->listener_callback->plugin = pPlugin;
750 urbdrc->listener_callback->channel_mgr = pChannelMgr;
753 CharUpperA(channelName);
754 status = pChannelMgr->CreateListener(pChannelMgr, channelName, 0,
755 &urbdrc->listener_callback->iface, &urbdrc->listener);
756 if (status != CHANNEL_RC_OK)
759 status = CHANNEL_RC_OK;
760 if (udevman->listener_created_callback)
761 status = udevman->listener_created_callback(udevman);
763 urbdrc->initialized = status == CHANNEL_RC_OK;
772static UINT urbdrc_plugin_terminated(IWTSPlugin* pPlugin)
775 IUDEVMAN* udevman = NULL;
778 return ERROR_INVALID_DATA;
779 if (urbdrc->listener_callback)
781 IWTSVirtualChannelManager* mgr = urbdrc->listener_callback->channel_mgr;
783 IFCALL(mgr->DestroyListener, mgr, urbdrc->listener);
785 udevman = urbdrc->udevman;
789 udevman->free(udevman);
793 free(urbdrc->subsystem);
794 free(urbdrc->listener_callback);
796 return CHANNEL_RC_OK;
799static BOOL urbdrc_register_udevman_addin(IWTSPlugin* pPlugin, IUDEVMAN* udevman)
805 WLog_Print(urbdrc->log, WLOG_ERROR,
"existing device, abort.");
809 DEBUG_DVC(
"device registered.");
810 urbdrc->udevman = udevman;
819static UINT urbdrc_load_udevman_addin(IWTSPlugin* pPlugin, LPCSTR name,
const ADDIN_ARGV* args)
824 PVIRTUALCHANNELENTRY pvce =
825 freerdp_load_channel_addin_entry(URBDRC_CHANNEL_NAME, name, NULL, 0);
826 PFREERDP_URBDRC_DEVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PFREERDP_URBDRC_DEVICE_ENTRY);
829 return ERROR_INVALID_OPERATION;
831 entryPoints.plugin = pPlugin;
832 entryPoints.pRegisterUDEVMAN = urbdrc_register_udevman_addin;
833 entryPoints.args = args;
835 const UINT error = entry(&entryPoints);
838 WLog_Print(urbdrc->log, WLOG_ERROR,
"%s entry returns error.", name);
842 return CHANNEL_RC_OK;
845static BOOL urbdrc_set_subsystem(
URBDRC_PLUGIN* urbdrc,
const char* subsystem)
847 free(urbdrc->subsystem);
848 urbdrc->subsystem = _strdup(subsystem);
849 return (urbdrc->subsystem != NULL);
861 {
"dbg", COMMAND_LINE_VALUE_FLAG,
"", NULL, BoolValueFalse, -1, NULL,
"debug" },
862 {
"sys", COMMAND_LINE_VALUE_REQUIRED,
"<subsystem>", NULL, NULL, -1, NULL,
"subsystem" },
863 {
"dev", COMMAND_LINE_VALUE_REQUIRED,
"<device list>", NULL, NULL, -1, NULL,
"devices" },
864 {
"encode", COMMAND_LINE_VALUE_FLAG,
"", NULL, NULL, -1, NULL,
"encode" },
865 {
"quality", COMMAND_LINE_VALUE_REQUIRED,
"<[0-2] -> [high-medium-low]>", NULL, NULL, -1,
867 { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
871 COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD;
874 CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_args, flags, urbdrc, NULL, NULL);
877 return ERROR_INVALID_DATA;
883 if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
886 CommandLineSwitchStart(arg) CommandLineSwitchCase(arg,
"dbg")
888 WLog_SetLogLevel(urbdrc->log, WLOG_TRACE);
890 CommandLineSwitchCase(arg,
"sys")
892 if (!urbdrc_set_subsystem(urbdrc, arg->Value))
893 return ERROR_OUTOFMEMORY;
895 CommandLineSwitchDefault(arg)
898 CommandLineSwitchEnd(arg)
899 }
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
901 return CHANNEL_RC_OK;
904BOOL add_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
914 if (!urbdrc || !urbdrc->listener_callback)
917 UINT32 mask = (DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT);
918 if ((flags & mask) == mask)
919 regflags |= UDEVMAN_FLAG_ADD_BY_VID_PID;
920 mask = (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV);
921 if ((flags & mask) == mask)
922 regflags |= UDEVMAN_FLAG_ADD_BY_ADDR;
924 const size_t success =
925 idevman->register_udevice(idevman, busnum, devnum, idVendor, idProduct, regflags);
927 if ((success > 0) && (flags & DEVICE_ADD_FLAG_REGISTER))
929 if (!urbdrc_announce_devices(idevman))
936BOOL del_device(IUDEVMAN* idevman, UINT32 flags, BYTE busnum, BYTE devnum, UINT16 idVendor,
939 IUDEVICE* pdev = NULL;
947 if (!urbdrc || !urbdrc->listener_callback)
950 idevman->loading_lock(idevman);
951 idevman->rewind(idevman);
953 while (idevman->has_next(idevman))
956 IUDEVICE* dev = idevman->get_next(idevman);
958 if ((flags & (DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV | DEVICE_ADD_FLAG_VENDOR |
959 DEVICE_ADD_FLAG_PRODUCT)) == 0)
961 if (flags & DEVICE_ADD_FLAG_BUS)
963 if (dev->get_bus_number(dev) != busnum)
966 if (flags & DEVICE_ADD_FLAG_DEV)
968 if (dev->get_dev_number(dev) != devnum)
971 if (flags & DEVICE_ADD_FLAG_VENDOR)
973 int vid = dev->query_device_descriptor(dev, ID_VENDOR);
977 if (flags & DEVICE_ADD_FLAG_PRODUCT)
979 int pid = dev->query_device_descriptor(dev, ID_PRODUCT);
980 if (pid != idProduct)
992 pdev->setChannelClosed(pdev);
994 idevman->loading_unlock(idevman);
1003FREERDP_ENTRY_POINT(UINT VCAPITYPE urbdrc_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints))
1008 urbdrc = (
URBDRC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, URBDRC_CHANNEL_NAME);
1009 args = pEntryPoints->GetPluginData(pEntryPoints);
1016 return CHANNEL_RC_NO_MEMORY;
1018 urbdrc->iface.Initialize = urbdrc_plugin_initialize;
1019 urbdrc->iface.Terminated = urbdrc_plugin_terminated;
1020 urbdrc->vchannel_status = INIT_CHANNEL_IN;
1021 status = pEntryPoints->RegisterPlugin(pEntryPoints, URBDRC_CHANNEL_NAME, &urbdrc->iface);
1024 if (status != CHANNEL_RC_OK)
1030 urbdrc->log = WLog_Get(TAG);
1036 status = urbdrc_process_addin_args(urbdrc, args);
1038 if (status != CHANNEL_RC_OK)
1041 if (!urbdrc->subsystem && !urbdrc_set_subsystem(urbdrc,
"libusb"))
1044 return urbdrc_load_udevman_addin(&urbdrc->iface, urbdrc->subsystem, args);
1049UINT stream_write_and_free(IWTSPlugin* plugin, IWTSVirtualChannel* channel,
wStream* out)
1054 return ERROR_INVALID_PARAMETER;
1056 if (!channel || !out || !urbdrc)
1058 Stream_Free(out, TRUE);
1059 return ERROR_INVALID_PARAMETER;
1062 if (!channel->Write)
1064 Stream_Free(out, TRUE);
1065 return ERROR_INTERNAL_ERROR;
1068 urbdrc_dump_message(urbdrc->log, TRUE, TRUE, out);
1069 const size_t len = Stream_GetPosition(out);
1070 UINT rc = ERROR_INTERNAL_ERROR;
1071 if (len <= UINT32_MAX)
1072 rc = channel->Write(channel, (UINT32)len, Stream_Buffer(out), NULL);
1073 Stream_Free(out, TRUE);