Blame channels/urbdrc/client/libusb/libusb_udevman.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * RemoteFX USB Redirection
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2012 Atrust corp.
Packit 1fb8d4
 * Copyright 2012 Alfred Liu <alfred.liu@atruscorp.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit Service 5a9772
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/cmdline.h>
Packit Service 5a9772
#include <winpr/collections.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/addin.h>
Packit 1fb8d4
Packit 1fb8d4
#include "urbdrc_types.h"
Packit 1fb8d4
#include "urbdrc_main.h"
Packit 1fb8d4
Packit 1fb8d4
#include "libusb_udevice.h"
Packit 1fb8d4
Packit Service 5a9772
#include <libusb.h>
Packit Service 5a9772
Packit Service 5a9772
#if !defined(LIBUSB_HOTPLUG_NO_FLAGS)
Packit Service 5a9772
#define LIBUSB_HOTPLUG_NO_FLAGS 0
Packit Service 5a9772
#endif
Packit Service 5a9772
Packit Service 5a9772
#define BASIC_STATE_FUNC_DEFINED(_arg, _type)                   \
Packit Service 5a9772
	static _type udevman_get_##_arg(IUDEVMAN* idevman)          \
Packit Service 5a9772
	{                                                           \
Packit Service 5a9772
		UDEVMAN* udevman = (UDEVMAN*)idevman;                   \
Packit Service 5a9772
		return udevman->_arg;                                   \
Packit Service 5a9772
	}                                                           \
Packit Service 5a9772
	static void udevman_set_##_arg(IUDEVMAN* idevman, _type _t) \
Packit Service 5a9772
	{                                                           \
Packit Service 5a9772
		UDEVMAN* udevman = (UDEVMAN*)idevman;                   \
Packit Service 5a9772
		udevman->_arg = _t;                                     \
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
#define BASIC_STATE_FUNC_REGISTER(_arg, _man)    \
Packit 1fb8d4
	_man->iface.get_##_arg = udevman_get_##_arg; \
Packit 1fb8d4
	_man->iface.set_##_arg = udevman_set_##_arg
Packit 1fb8d4
Packit Service 5a9772
typedef struct _VID_PID_PAIR VID_PID_PAIR;
Packit Service 5a9772
Packit Service 5a9772
struct _VID_PID_PAIR
Packit Service 5a9772
{
Packit Service 5a9772
	UINT16 vid;
Packit Service 5a9772
	UINT16 pid;
Packit Service 5a9772
};
Packit Service 5a9772
Packit 1fb8d4
typedef struct _UDEVMAN UDEVMAN;
Packit 1fb8d4
Packit 1fb8d4
struct _UDEVMAN
Packit 1fb8d4
{
Packit 1fb8d4
	IUDEVMAN iface;
Packit 1fb8d4
Packit 1fb8d4
	IUDEVICE* idev; /* iterator device */
Packit 1fb8d4
	IUDEVICE* head; /* head device in linked list */
Packit 1fb8d4
	IUDEVICE* tail; /* tail device in linked list */
Packit 1fb8d4
Packit Service 5a9772
	LPSTR devices_vid_pid;
Packit Service 5a9772
	LPSTR devices_addr;
Packit Service 5a9772
	wArrayList* hotplug_vid_pids;
Packit 1fb8d4
	UINT16 flags;
Packit Service 5a9772
	UINT32 device_num;
Packit Service 5a9772
	UINT32 next_device_id;
Packit Service 5a9772
	UINT32 channel_id;
Packit Service 5a9772
Packit Service 5a9772
	HANDLE devman_loading;
Packit Service 5a9772
	libusb_context* context;
Packit Service 5a9772
	HANDLE thread;
Packit Service 5a9772
	BOOL running;
Packit 1fb8d4
};
Packit 1fb8d4
typedef UDEVMAN* PUDEVMAN;
Packit 1fb8d4
Packit Service 5a9772
static BOOL poll_libusb_events(UDEVMAN* udevman);
Packit Service 5a9772
Packit 1fb8d4
static void udevman_rewind(IUDEVMAN* idevman)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
	udevman->idev = udevman->head;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_has_next(IUDEVMAN* idevman)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
Packit Service 5a9772
	if (!udevman || !udevman->idev)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
	else
Packit Service 5a9772
		return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static IUDEVICE* udevman_get_next(IUDEVMAN* idevman)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
	IUDEVICE* pdev;
Packit 1fb8d4
	pdev = udevman->idev;
Packit Service 5a9772
	udevman->idev = (IUDEVICE*)((UDEVICE*)udevman->idev)->next;
Packit 1fb8d4
	return pdev;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static IUDEVICE* udevman_get_udevice_by_addr(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
Packit 1fb8d4
{
Packit Service 5a9772
	IUDEVICE* dev = NULL;
Packit Service 5a9772
Packit Service 5a9772
	if (!idevman)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit 1fb8d4
	idevman->loading_lock(idevman);
Packit 1fb8d4
	idevman->rewind(idevman);
Packit 1fb8d4
Packit 1fb8d4
	while (idevman->has_next(idevman))
Packit 1fb8d4
	{
Packit Service 5a9772
		IUDEVICE* pdev = idevman->get_next(idevman);
Packit 1fb8d4
Packit Service 5a9772
		if ((pdev->get_bus_number(pdev) == bus_number) &&
Packit Service 5a9772
		    (pdev->get_dev_number(pdev) == dev_number))
Packit 1fb8d4
		{
Packit Service 5a9772
			dev = pdev;
Packit Service 5a9772
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	idevman->loading_unlock(idevman);
Packit Service 5a9772
	return dev;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number,
Packit Service 5a9772
                                       UINT16 idVendor, UINT16 idProduct, UINT32 flag)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
	IUDEVICE* pdev = NULL;
Packit 1fb8d4
	IUDEVICE** devArray;
Packit Service 5a9772
	URBDRC_PLUGIN* urbdrc;
Packit Service 5a9772
	size_t i, num, addnum = 0;
Packit Service 5a9772
Packit Service 5a9772
	if (!idevman || !idevman->plugin)
Packit Service 5a9772
		return 0;
Packit Service 5a9772
Packit Service 5a9772
	urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
Packit Service 5a9772
	pdev = (IUDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
Packit 1fb8d4
Packit 1fb8d4
	if (pdev != NULL)
Packit 1fb8d4
		return 0;
Packit 1fb8d4
Packit Service 5a9772
	if (flag & UDEVMAN_FLAG_ADD_BY_ADDR)
Packit 1fb8d4
	{
Packit Service 5a9772
		UINT32 id;
Packit Service 5a9772
		IUDEVICE* tdev = udev_new_by_addr(urbdrc, udevman->context, bus_number, dev_number);
Packit 1fb8d4
Packit Service 5a9772
		if (tdev == NULL)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
Packit Service 5a9772
		id = idevman->get_next_device_id(idevman);
Packit Service 5a9772
		tdev->set_UsbDevice(tdev, id);
Packit 1fb8d4
		idevman->loading_lock(idevman);
Packit 1fb8d4
Packit 1fb8d4
		if (udevman->head == NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* linked list is empty */
Packit Service 5a9772
			udevman->head = tdev;
Packit Service 5a9772
			udevman->tail = tdev;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			/* append device to the end of the linked list */
Packit Service 5a9772
			udevman->tail->set_p_next(udevman->tail, tdev);
Packit Service 5a9772
			tdev->set_p_prev(tdev, udevman->tail);
Packit Service 5a9772
			udevman->tail = tdev;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		udevman->device_num += 1;
Packit 1fb8d4
		idevman->loading_unlock(idevman);
Packit 1fb8d4
	}
Packit Service 5a9772
	else if (flag & UDEVMAN_FLAG_ADD_BY_VID_PID)
Packit 1fb8d4
	{
Packit 1fb8d4
		addnum = 0;
Packit 1fb8d4
		/* register all device that match pid vid */
Packit Service 5a9772
		num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray);
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < num; i++)
Packit 1fb8d4
		{
Packit Service 5a9772
			UINT32 id;
Packit Service 5a9772
			IUDEVICE* tdev = devArray[i];
Packit 1fb8d4
Packit Service 5a9772
			if (udevman_get_udevice_by_addr(idevman, tdev->get_bus_number(tdev),
Packit Service 5a9772
			                                tdev->get_dev_number(tdev)) != NULL)
Packit 1fb8d4
			{
Packit Service 5a9772
				tdev->free(tdev);
Packit Service 5a9772
				devArray[i] = NULL;
Packit 1fb8d4
				continue;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit Service 5a9772
			id = idevman->get_next_device_id(idevman);
Packit Service 5a9772
			tdev->set_UsbDevice(tdev, id);
Packit 1fb8d4
			idevman->loading_lock(idevman);
Packit 1fb8d4
Packit 1fb8d4
			if (udevman->head == NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* linked list is empty */
Packit Service 5a9772
				udevman->head = tdev;
Packit Service 5a9772
				udevman->tail = tdev;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* append device to the end of the linked list */
Packit Service 5a9772
				udevman->tail->set_p_next(udevman->tail, tdev);
Packit Service 5a9772
				tdev->set_p_prev(tdev, udevman->tail);
Packit Service 5a9772
				udevman->tail = tdev;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			udevman->device_num += 1;
Packit 1fb8d4
			idevman->loading_unlock(idevman);
Packit 1fb8d4
			addnum++;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		free(devArray);
Packit 1fb8d4
		return addnum;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_Print(urbdrc->log, WLOG_ERROR, "udevman_register_udevice: Invalid flag=%08 " PRIx32,
Packit Service 5a9772
		           flag);
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_unregister_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE dev_number)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
	UDEVICE* pdev;
Packit Service 5a9772
	UDEVICE* dev = (UDEVICE*)udevman_get_udevice_by_addr(idevman, bus_number, dev_number);
Packit Service 5a9772
Packit Service 5a9772
	if (!dev || !idevman)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit 1fb8d4
	idevman->loading_lock(idevman);
Packit 1fb8d4
	idevman->rewind(idevman);
Packit 1fb8d4
Packit Service 5a9772
	while (idevman->has_next(idevman))
Packit 1fb8d4
	{
Packit Service 5a9772
		pdev = (UDEVICE*)idevman->get_next(idevman);
Packit 1fb8d4
Packit 1fb8d4
		if (pdev == dev) /* device exists */
Packit 1fb8d4
		{
Packit 1fb8d4
			/* set previous device to point to next device */
Packit 1fb8d4
			if (dev->prev != NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* unregistered device is not the head */
Packit 1fb8d4
				pdev = dev->prev;
Packit 1fb8d4
				pdev->next = dev->next;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* unregistered device is the head, update head */
Packit 1fb8d4
				udevman->head = (IUDEVICE*)dev->next;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			/* set next device to point to previous device */
Packit 1fb8d4
Packit 1fb8d4
			if (dev->next != NULL)
Packit 1fb8d4
			{
Packit 1fb8d4
				/* unregistered device is not the tail */
Packit 1fb8d4
				pdev = (UDEVICE*)dev->next;
Packit 1fb8d4
				pdev->prev = dev->prev;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				/* unregistered device is the tail, update tail */
Packit 1fb8d4
				udevman->tail = (IUDEVICE*)dev->prev;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			udevman->device_num--;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	idevman->loading_unlock(idevman);
Packit 1fb8d4
Packit 1fb8d4
	if (dev)
Packit 1fb8d4
	{
Packit Service 5a9772
		dev->iface.free(&dev->iface);
Packit Service 5a9772
		return TRUE; /* unregistration successful */
Packit Service 5a9772
	}
Packit 1fb8d4
Packit Service 5a9772
	/* if we reach this point, the device wasn't found */
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_unregister_all_udevices(IUDEVMAN* idevman)
Packit Service 5a9772
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
Packit Service 5a9772
	if (!idevman)
Packit Service 5a9772
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	if (!udevman->head)
Packit Service 5a9772
		return TRUE;
Packit 1fb8d4
Packit Service 5a9772
	idevman->loading_lock(idevman);
Packit Service 5a9772
	idevman->rewind(idevman);
Packit 1fb8d4
Packit Service 5a9772
	while (idevman->has_next(idevman))
Packit Service 5a9772
	{
Packit Service 5a9772
		UDEVICE* dev = (UDEVICE*)idevman->get_next(idevman);
Packit 1fb8d4
Packit Service 5a9772
		if (!dev)
Packit Service 5a9772
			continue;
Packit 1fb8d4
Packit Service 5a9772
		/* set previous device to point to next device */
Packit Service 5a9772
		if (dev->prev != NULL)
Packit Service 5a9772
		{
Packit Service 5a9772
			/* unregistered device is not the head */
Packit Service 5a9772
			UDEVICE* pdev = dev->prev;
Packit Service 5a9772
			pdev->next = dev->next;
Packit Service 5a9772
		}
Packit Service 5a9772
		else
Packit Service 5a9772
		{
Packit Service 5a9772
			/* unregistered device is the head, update head */
Packit Service 5a9772
			udevman->head = (IUDEVICE*)dev->next;
Packit Service 5a9772
		}
Packit 1fb8d4
Packit Service 5a9772
		/* set next device to point to previous device */
Packit 1fb8d4
Packit Service 5a9772
		if (dev->next != NULL)
Packit Service 5a9772
		{
Packit Service 5a9772
			/* unregistered device is not the tail */
Packit Service 5a9772
			UDEVICE* pdev = (UDEVICE*)dev->next;
Packit Service 5a9772
			pdev->prev = dev->prev;
Packit Service 5a9772
		}
Packit Service 5a9772
		else
Packit Service 5a9772
		{
Packit Service 5a9772
			/* unregistered device is the tail, update tail */
Packit Service 5a9772
			udevman->tail = (IUDEVICE*)dev->prev;
Packit Service 5a9772
		}
Packit 1fb8d4
Packit Service 5a9772
		dev->iface.free(&dev->iface);
Packit Service 5a9772
		udevman->device_num--;
Packit Service 5a9772
	}
Packit 1fb8d4
Packit Service 5a9772
	idevman->loading_unlock(idevman);
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int udevman_is_auto_add(IUDEVMAN* idevman)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
	return (udevman->flags & UDEVMAN_FLAG_ADD_BY_AUTO) ? 1 : 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static IUDEVICE* udevman_get_udevice_by_UsbDevice(IUDEVMAN* idevman, UINT32 UsbDevice)
Packit 1fb8d4
{
Packit 1fb8d4
	UDEVICE* pdev;
Packit Service 5a9772
	URBDRC_PLUGIN* urbdrc;
Packit Service 5a9772
Packit Service 5a9772
	if (!idevman || !idevman->plugin)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	/* Mask highest 2 bits, must be ignored */
Packit Service 5a9772
	UsbDevice = UsbDevice & INTERFACE_ID_MASK;
Packit Service 5a9772
	urbdrc = (URBDRC_PLUGIN*)idevman->plugin;
Packit 1fb8d4
	idevman->loading_lock(idevman);
Packit 1fb8d4
	idevman->rewind(idevman);
Packit 1fb8d4
Packit 1fb8d4
	while (idevman->has_next(idevman))
Packit 1fb8d4
	{
Packit Service 5a9772
		pdev = (UDEVICE*)idevman->get_next(idevman);
Packit 1fb8d4
Packit 1fb8d4
		if (pdev->UsbDevice == UsbDevice)
Packit 1fb8d4
		{
Packit 1fb8d4
			idevman->loading_unlock(idevman);
Packit Service 5a9772
			return (IUDEVICE*)pdev;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	idevman->loading_unlock(idevman);
Packit Service 5a9772
	WLog_Print(urbdrc->log, WLOG_WARN, "Failed to find a USB device mapped to deviceId=%08" PRIx32,
Packit Service 5a9772
	           UsbDevice);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void udevman_loading_lock(IUDEVMAN* idevman)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
	WaitForSingleObject(udevman->devman_loading, INFINITE);
Packit Service 5a9772
}
Packit 1fb8d4
Packit Service 5a9772
static void udevman_loading_unlock(IUDEVMAN* idevman)
Packit Service 5a9772
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
	ReleaseMutex(udevman->devman_loading);
Packit Service 5a9772
}
Packit 1fb8d4
Packit Service 5a9772
BASIC_STATE_FUNC_DEFINED(device_num, UINT32)
Packit 1fb8d4
Packit Service 5a9772
static UINT32 udevman_get_next_device_id(IUDEVMAN* idevman)
Packit Service 5a9772
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
	return udevman->next_device_id++;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void udevman_set_next_device_id(IUDEVMAN* idevman, UINT32 _t)
Packit Service 5a9772
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
	udevman->next_device_id = _t;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void udevman_free(IUDEVMAN* idevman)
Packit Service 5a9772
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit 1fb8d4
Packit Service 5a9772
	if (!udevman)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	udevman->running = FALSE;
Packit Service 5a9772
	if (udevman->thread)
Packit 1fb8d4
	{
Packit Service 5a9772
		WaitForSingleObject(udevman->thread, INFINITE);
Packit Service 5a9772
		CloseHandle(udevman->thread);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	udevman_unregister_all_udevices(idevman);
Packit Service 5a9772
Packit Service 5a9772
	if (udevman->devman_loading)
Packit Service 5a9772
		CloseHandle(udevman->devman_loading);
Packit Service 5a9772
Packit Service 5a9772
	libusb_exit(udevman->context);
Packit Service 5a9772
Packit Service 5a9772
	ArrayList_Free(udevman->hotplug_vid_pids);
Packit Service 5a9772
	free(udevman);
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL filter_by_class(uint8_t bDeviceClass, uint8_t bDeviceSubClass)
Packit 1fb8d4
{
Packit Service 5a9772
	switch (bDeviceClass)
Packit Service 5a9772
	{
Packit Service 5a9772
		case LIBUSB_CLASS_AUDIO:
Packit Service 5a9772
		case LIBUSB_CLASS_HID:
Packit Service 5a9772
		case LIBUSB_CLASS_MASS_STORAGE:
Packit Service 5a9772
		case LIBUSB_CLASS_HUB:
Packit Service 5a9772
		case LIBUSB_CLASS_SMART_CARD:
Packit Service 5a9772
			return TRUE;
Packit Service 5a9772
		default:
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	switch (bDeviceSubClass)
Packit Service 5a9772
	{
Packit Service 5a9772
		default:
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL append(char* dst, size_t length, const char* src)
Packit 1fb8d4
{
Packit Service 5a9772
	size_t slen = strlen(src);
Packit Service 5a9772
	size_t dlen = strnlen(dst, length);
Packit Service 5a9772
	if (dlen + slen >= length)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
	strcat(dst, src);
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL device_is_filtered(struct libusb_device* dev,
Packit Service 5a9772
                               const struct libusb_device_descriptor* desc,
Packit Service 5a9772
                               libusb_hotplug_event event)
Packit 1fb8d4
{
Packit Service 5a9772
	char buffer[8192] = { 0 };
Packit Service 5a9772
	char* what;
Packit Service 5a9772
	BOOL filtered = FALSE;
Packit Service 5a9772
	append(buffer, sizeof(buffer), usb_interface_class_to_string(desc->bDeviceClass));
Packit Service 5a9772
	if (filter_by_class(desc->bDeviceClass, desc->bDeviceSubClass))
Packit Service 5a9772
		filtered = TRUE;
Packit Service 5a9772
Packit Service 5a9772
	switch (desc->bDeviceClass)
Packit Service 5a9772
	{
Packit Service 5a9772
		case LIBUSB_CLASS_PER_INTERFACE:
Packit Service 5a9772
		{
Packit Service 5a9772
			struct libusb_config_descriptor* config = NULL;
Packit Service 5a9772
			int rc = libusb_get_active_config_descriptor(dev, &config);
Packit Service 5a9772
			if (rc == LIBUSB_SUCCESS)
Packit Service 5a9772
			{
Packit Service 5a9772
				uint8_t x;
Packit Service 5a9772
Packit Service 5a9772
				for (x = 0; x < config->bNumInterfaces; x++)
Packit Service 5a9772
				{
Packit Service 5a9772
					uint8_t y;
Packit Service 5a9772
					const struct libusb_interface* ifc = &config->interface[x];
Packit Service 5a9772
					for (y = 0; y < ifc->num_altsetting; y++)
Packit Service 5a9772
					{
Packit Service 5a9772
						const struct libusb_interface_descriptor* const alt = &ifc->altsetting[y];
Packit Service 5a9772
						if (filter_by_class(alt->bInterfaceClass, alt->bInterfaceSubClass))
Packit Service 5a9772
							filtered = TRUE;
Packit Service 5a9772
Packit Service 5a9772
						append(buffer, sizeof(buffer), "|");
Packit Service 5a9772
						append(buffer, sizeof(buffer),
Packit Service 5a9772
						       usb_interface_class_to_string(alt->bInterfaceClass));
Packit Service 5a9772
					}
Packit Service 5a9772
				}
Packit Service 5a9772
			}
Packit Service 5a9772
			libusb_free_config_descriptor(config);
Packit Service 5a9772
		}
Packit Service 5a9772
		break;
Packit Service 5a9772
		default:
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (filtered)
Packit Service 5a9772
		what = "Filtered";
Packit Service 5a9772
	else
Packit Service 5a9772
	{
Packit Service 5a9772
		switch (event)
Packit Service 5a9772
		{
Packit Service 5a9772
			case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
Packit Service 5a9772
				what = "Hotplug remove";
Packit Service 5a9772
				break;
Packit Service 5a9772
			case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
Packit Service 5a9772
				what = "Hotplug add";
Packit Service 5a9772
				break;
Packit Service 5a9772
			default:
Packit Service 5a9772
				what = "Hotplug unknown";
Packit Service 5a9772
				break;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	WLog_DBG(TAG, "%s device VID=0x%04X,PID=0x%04X class %s", what, desc->idVendor, desc->idProduct,
Packit Service 5a9772
	         buffer);
Packit Service 5a9772
	return filtered;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev,
Packit Service 5a9772
                            libusb_hotplug_event event, void* user_data)
Packit 1fb8d4
{
Packit Service 5a9772
	VID_PID_PAIR pair;
Packit Service 5a9772
	struct libusb_device_descriptor desc;
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)user_data;
Packit Service 5a9772
	const uint8_t bus = libusb_get_bus_number(dev);
Packit Service 5a9772
	const uint8_t addr = libusb_get_device_address(dev);
Packit Service 5a9772
	int rc = libusb_get_device_descriptor(dev, &desc);
Packit 1fb8d4
Packit Service 5a9772
	WINPR_UNUSED(ctx);
Packit 1fb8d4
Packit Service 5a9772
	if (rc != LIBUSB_SUCCESS)
Packit Service 5a9772
		return rc;
Packit 1fb8d4
Packit Service 5a9772
	switch (event)
Packit Service 5a9772
	{
Packit Service 5a9772
		case LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED:
Packit Service 5a9772
			pair.vid = desc.idVendor;
Packit Service 5a9772
			pair.pid = desc.idProduct;
Packit Service 5a9772
			if ((ArrayList_Contains(udevman->hotplug_vid_pids, &pair)) ||
Packit Service 5a9772
			    (udevman->iface.isAutoAdd(&udevman->iface) &&
Packit Service 5a9772
			     !device_is_filtered(dev, &desc, event)))
Packit Service 5a9772
			{
Packit Service 5a9772
				add_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
Packit Service 5a9772
				           desc.idProduct);
Packit Service 5a9772
			}
Packit Service 5a9772
			break;
Packit Service 5a9772
Packit Service 5a9772
		case LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT:
Packit Service 5a9772
			del_device(&udevman->iface, DEVICE_ADD_FLAG_ALL, bus, addr, desc.idVendor,
Packit Service 5a9772
			           desc.idProduct);
Packit Service 5a9772
			break;
Packit 1fb8d4
Packit Service 5a9772
		default:
Packit Service 5a9772
			break;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_initialize(IUDEVMAN* idevman, UINT32 channelId)
Packit 1fb8d4
{
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)idevman;
Packit Service 5a9772
Packit Service 5a9772
	if (!udevman)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	idevman->status &= ~URBDRC_DEVICE_CHANNEL_CLOSED;
Packit Service 5a9772
	idevman->controlChannelId = channelId;
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_vid_pid_pair_equals(const void* objA, const void* objB)
Packit 1fb8d4
{
Packit Service 5a9772
	const VID_PID_PAIR* a = objA;
Packit Service 5a9772
	const VID_PID_PAIR* b = objB;
Packit Service 5a9772
Packit Service 5a9772
	return (a->vid == b->vid) && (a->pid == b->pid);
Packit Service 5a9772
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL udevman_parse_device_id_addr(const char** str, UINT16* id1, UINT16* id2, UINT16 max,
Packit Service 5a9772
                                         char split_sign, char delimiter)
Packit 1fb8d4
{
Packit Service 5a9772
	char* mid;
Packit Service 5a9772
	char* end;
Packit Service 5a9772
	unsigned long rc;
Packit Service 5a9772
Packit Service 5a9772
	rc = strtoul(*str, &mid, 16);
Packit Service 5a9772
Packit Service 5a9772
	if ((mid == *str) || (*mid != split_sign) || (rc > max))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	*id1 = (UINT16)rc;
Packit Service 5a9772
	rc = strtoul(++mid, &end, 16);
Packit Service 5a9772
Packit Service 5a9772
	if ((end == mid) || (rc > max))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	*id2 = (UINT16)rc;
Packit Service 5a9772
Packit Service 5a9772
	*str += end - *str;
Packit Service 5a9772
	if (*end == '\0')
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
	if (*end == delimiter)
Packit 1fb8d4
	{
Packit Service 5a9772
		(*str)++;
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
	}
Packit 1fb8d4
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL urbdrc_udevman_register_devices(UDEVMAN* udevman, const char* devices, BOOL add_by_addr)
Packit Service 5a9772
{
Packit Service 5a9772
	const char* pos = devices;
Packit Service 5a9772
	VID_PID_PAIR* idpair;
Packit Service 5a9772
	UINT16 id1, id2;
Packit Service 5a9772
Packit Service 5a9772
	while (*pos != '\0')
Packit Service 5a9772
	{
Packit Service 5a9772
		if (!udevman_parse_device_id_addr(&pos, &id1, &id2, (add_by_addr) ? UINT8_MAX : UINT16_MAX,
Packit Service 5a9772
		                                  ':', '#'))
Packit 1fb8d4
		{
Packit Service 5a9772
			WLog_ERR(TAG, "Invalid device argument: \"%s\"", devices);
Packit Service 5a9772
			return COMMAND_LINE_ERROR_UNEXPECTED_VALUE;
Packit 1fb8d4
		}
Packit Service 5a9772
Packit Service 5a9772
		if (add_by_addr)
Packit 1fb8d4
		{
Packit Service 5a9772
			add_device(&udevman->iface, DEVICE_ADD_FLAG_BUS | DEVICE_ADD_FLAG_DEV, (UINT8)id1,
Packit Service 5a9772
			           (UINT8)id2, 0, 0);
Packit 1fb8d4
		}
Packit Service 5a9772
		else
Packit Service 5a9772
		{
Packit Service 5a9772
			idpair = malloc(sizeof(VID_PID_PAIR));
Packit Service 5a9772
			if (!idpair)
Packit Service 5a9772
				return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
			idpair->vid = id1;
Packit Service 5a9772
			idpair->pid = id2;
Packit Service 5a9772
			if (ArrayList_Add(udevman->hotplug_vid_pids, idpair) == -1)
Packit Service 5a9772
			{
Packit Service 5a9772
				free(idpair);
Packit Service 5a9772
				return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
			}
Packit 1fb8d4
Packit Service 5a9772
			add_device(&udevman->iface, DEVICE_ADD_FLAG_VENDOR | DEVICE_ADD_FLAG_PRODUCT, 0, 0, id1,
Packit Service 5a9772
			           id2);
Packit Service 5a9772
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static UINT urbdrc_udevman_parse_addin_args(UDEVMAN* udevman, ADDIN_ARGV* args)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit Service 5a9772
	LPSTR devices = NULL;
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* arg;
Packit Service 5a9772
	COMMAND_LINE_ARGUMENT_A urbdrc_udevman_args[] = {
Packit Service 5a9772
		{ "dbg", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "debug" },
Packit Service 5a9772
		{ "dev", COMMAND_LINE_VALUE_REQUIRED, "<devices>", NULL, NULL, -1, NULL, "device list" },
Packit Service 5a9772
		{ "id", COMMAND_LINE_VALUE_OPTIONAL, "", NULL, BoolValueFalse, -1, NULL,
Packit Service 5a9772
		  "FLAG_ADD_BY_VID_PID" },
Packit Service 5a9772
		{ "addr", COMMAND_LINE_VALUE_OPTIONAL, "", NULL, BoolValueFalse, -1, NULL,
Packit Service 5a9772
		  "FLAG_ADD_BY_ADDR" },
Packit Service 5a9772
		{ "auto", COMMAND_LINE_VALUE_FLAG, "", NULL, BoolValueFalse, -1, NULL, "FLAG_ADD_BY_AUTO" },
Packit Service 5a9772
		{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
Packit Service 5a9772
	};
Packit Service 5a9772
Packit Service 5a9772
	status = CommandLineParseArgumentsA(args->argc, args->argv, urbdrc_udevman_args,
Packit Service 5a9772
	                                    COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON,
Packit Service 5a9772
	                                    udevman, NULL, NULL);
Packit Service 5a9772
Packit Service 5a9772
	if (status != CHANNEL_RC_OK)
Packit Service 5a9772
		return status;
Packit Service 5a9772
Packit 1fb8d4
	arg = urbdrc_udevman_args;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit Service 5a9772
		if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit Service 5a9772
		CommandLineSwitchStart(arg) CommandLineSwitchCase(arg, "dbg")
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_SetLogLevel(WLog_Get(TAG), WLOG_TRACE);
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "dev")
Packit 1fb8d4
		{
Packit Service 5a9772
			devices = arg->Value;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "id")
Packit 1fb8d4
		{
Packit Service 5a9772
			if (arg->Value)
Packit Service 5a9772
				udevman->devices_vid_pid = arg->Value;
Packit Service 5a9772
			else
Packit Service 5a9772
				udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "addr")
Packit 1fb8d4
		{
Packit Service 5a9772
			if (arg->Value)
Packit Service 5a9772
				udevman->devices_addr = arg->Value;
Packit Service 5a9772
			else
Packit Service 5a9772
				udevman->flags = UDEVMAN_FLAG_ADD_BY_ADDR;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "auto")
Packit 1fb8d4
		{
Packit 1fb8d4
			udevman->flags |= UDEVMAN_FLAG_ADD_BY_AUTO;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchDefault(arg)
Packit 1fb8d4
		{
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchEnd(arg)
Packit Service 5a9772
	} while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit Service 5a9772
Packit Service 5a9772
	if (devices)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (udevman->flags & UDEVMAN_FLAG_ADD_BY_VID_PID)
Packit Service 5a9772
			udevman->devices_vid_pid = devices;
Packit Service 5a9772
		else if (udevman->flags & UDEVMAN_FLAG_ADD_BY_ADDR)
Packit Service 5a9772
			udevman->devices_addr = devices;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT udevman_listener_created_callback(IUDEVMAN* iudevman)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT status;
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)iudevman;
Packit Service 5a9772
Packit Service 5a9772
	if (udevman->devices_vid_pid)
Packit Service 5a9772
	{
Packit Service 5a9772
		status = urbdrc_udevman_register_devices(udevman, udevman->devices_vid_pid, FALSE);
Packit Service 5a9772
		if (status != CHANNEL_RC_OK)
Packit Service 5a9772
			return status;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (udevman->devices_addr)
Packit Service 5a9772
		return urbdrc_udevman_register_devices(udevman, udevman->devices_addr, TRUE);
Packit Service 5a9772
Packit Service 5a9772
	return CHANNEL_RC_OK;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void udevman_load_interface(UDEVMAN* udevman)
Packit Service 5a9772
{
Packit Service 5a9772
	/* standard */
Packit Service 5a9772
	udevman->iface.free = udevman_free;
Packit Service 5a9772
	/* manage devices */
Packit Service 5a9772
	udevman->iface.rewind = udevman_rewind;
Packit Service 5a9772
	udevman->iface.get_next = udevman_get_next;
Packit Service 5a9772
	udevman->iface.has_next = udevman_has_next;
Packit Service 5a9772
	udevman->iface.register_udevice = udevman_register_udevice;
Packit Service 5a9772
	udevman->iface.unregister_udevice = udevman_unregister_udevice;
Packit Service 5a9772
	udevman->iface.get_udevice_by_UsbDevice = udevman_get_udevice_by_UsbDevice;
Packit Service 5a9772
	/* Extension */
Packit Service 5a9772
	udevman->iface.isAutoAdd = udevman_is_auto_add;
Packit Service 5a9772
	/* Basic state */
Packit Service 5a9772
	BASIC_STATE_FUNC_REGISTER(device_num, udevman);
Packit Service 5a9772
	BASIC_STATE_FUNC_REGISTER(next_device_id, udevman);
Packit Service 5a9772
Packit Service 5a9772
	/* control semaphore or mutex lock */
Packit Service 5a9772
	udevman->iface.loading_lock = udevman_loading_lock;
Packit Service 5a9772
	udevman->iface.loading_unlock = udevman_loading_unlock;
Packit Service 5a9772
	udevman->iface.initialize = udevman_initialize;
Packit Service 5a9772
	udevman->iface.listener_created_callback = udevman_listener_created_callback;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL poll_libusb_events(UDEVMAN* udevman)
Packit Service 5a9772
{
Packit Service 5a9772
	int rc = LIBUSB_SUCCESS;
Packit Service 5a9772
	struct timeval tv = { 0, 500 };
Packit Service 5a9772
	if (libusb_try_lock_events(udevman->context))
Packit Service 5a9772
	{
Packit Service 5a9772
		if (libusb_event_handling_ok(udevman->context))
Packit Service 5a9772
		{
Packit Service 5a9772
			rc = libusb_handle_events_locked(udevman->context, &tv;;
Packit Service 5a9772
			if (rc != LIBUSB_SUCCESS)
Packit Service 5a9772
				WLog_WARN(TAG, "libusb_handle_events_locked %d", rc);
Packit Service 5a9772
		}
Packit Service 5a9772
		libusb_unlock_events(udevman->context);
Packit Service 5a9772
	}
Packit Service 5a9772
	else
Packit Service 5a9772
	{
Packit Service 5a9772
		libusb_lock_event_waiters(udevman->context);
Packit Service 5a9772
		if (libusb_event_handler_active(udevman->context))
Packit Service 5a9772
		{
Packit Service 5a9772
			rc = libusb_wait_for_event(udevman->context, &tv;;
Packit Service 5a9772
			if (rc < LIBUSB_SUCCESS)
Packit Service 5a9772
				WLog_WARN(TAG, "libusb_wait_for_event %d", rc);
Packit Service 5a9772
		}
Packit Service 5a9772
		libusb_unlock_event_waiters(udevman->context);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return rc > 0;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static DWORD poll_thread(LPVOID lpThreadParameter)
Packit Service 5a9772
{
Packit Service 5a9772
	libusb_hotplug_callback_handle handle;
Packit Service 5a9772
	UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter;
Packit Service 5a9772
	BOOL hasHotplug = libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG);
Packit Service 5a9772
Packit Service 5a9772
	if (hasHotplug)
Packit Service 5a9772
	{
Packit Service 5a9772
		int rc = libusb_hotplug_register_callback(
Packit Service 5a9772
		    udevman->context,
Packit Service 5a9772
		    LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
Packit Service 5a9772
		    LIBUSB_HOTPLUG_NO_FLAGS, LIBUSB_HOTPLUG_MATCH_ANY, LIBUSB_HOTPLUG_MATCH_ANY,
Packit Service 5a9772
		    LIBUSB_HOTPLUG_MATCH_ANY, hotplug_callback, udevman, &handle);
Packit Service 5a9772
Packit Service 5a9772
		if (rc != LIBUSB_SUCCESS)
Packit Service 5a9772
			udevman->running = FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
	else
Packit Service 5a9772
		WLog_WARN(TAG, "Platform does not support libusb hotplug. USB devices plugged in later "
Packit Service 5a9772
		               "will not be detected.");
Packit Service 5a9772
Packit Service 5a9772
	while (udevman->running)
Packit Service 5a9772
	{
Packit Service 5a9772
		poll_libusb_events(udevman);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	if (hasHotplug)
Packit Service 5a9772
		libusb_hotplug_deregister_callback(udevman->context, handle);
Packit Service 5a9772
Packit Service 5a9772
	/* Process remaining usb events */
Packit Service 5a9772
	while (poll_libusb_events(udevman))
Packit Service 5a9772
		;
Packit Service 5a9772
Packit Service 5a9772
	ExitThread(0);
Packit Service 5a9772
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#ifdef BUILTIN_CHANNELS
Packit Service 5a9772
#define freerdp_urbdrc_client_subsystem_entry libusb_freerdp_urbdrc_client_subsystem_entry
Packit 1fb8d4
#else
Packit Service 5a9772
#define freerdp_urbdrc_client_subsystem_entry FREERDP_API freerdp_urbdrc_client_subsystem_entry
Packit 1fb8d4
#endif
Packit Service 5a9772
UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS pEntryPoints)
Packit 1fb8d4
{
Packit Service 5a9772
	UINT rc;
Packit Service 5a9772
	UINT status;
Packit 1fb8d4
	UDEVMAN* udevman;
Packit 1fb8d4
	ADDIN_ARGV* args = pEntryPoints->args;
Packit Service 5a9772
	udevman = (PUDEVMAN)calloc(1, sizeof(UDEVMAN));
Packit 1fb8d4
Packit 1fb8d4
	if (!udevman)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
	udevman->hotplug_vid_pids = ArrayList_New(TRUE);
Packit Service 5a9772
	if (!udevman->hotplug_vid_pids)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
	ArrayList_Object(udevman->hotplug_vid_pids)->fnObjectFree = free;
Packit Service 5a9772
	ArrayList_Object(udevman->hotplug_vid_pids)->fnObjectEquals = udevman_vid_pid_pair_equals;
Packit Service 5a9772
Packit Service 5a9772
	udevman->next_device_id = BASE_USBDEVICE_NUM;
Packit Service 5a9772
	udevman->iface.plugin = pEntryPoints->plugin;
Packit Service 5a9772
	rc = libusb_init(&udevman->context);
Packit Service 5a9772
Packit Service 5a9772
	if (rc != LIBUSB_SUCCESS)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
#ifdef _WIN32
Packit Service 5a9772
#if LIBUSB_API_VERSION >= 0x01000106
Packit Service 5a9772
	/* Prefer usbDK backend on windows. Not supported on other platforms. */
Packit Service 5a9772
	rc = libusb_set_option(udevman->context, LIBUSB_OPTION_USE_USBDK);
Packit Service 5a9772
	switch (rc)
Packit Service 5a9772
	{
Packit Service 5a9772
		case LIBUSB_SUCCESS:
Packit Service 5a9772
			break;
Packit Service 5a9772
		case LIBUSB_ERROR_NOT_FOUND:
Packit Service 5a9772
		case LIBUSB_ERROR_NOT_SUPPORTED:
Packit Service 5a9772
			WLog_WARN(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
Packit Service 5a9772
			break;
Packit Service 5a9772
		default:
Packit Service 5a9772
			WLog_ERR(TAG, "LIBUSB_OPTION_USE_USBDK %s [%d]", libusb_strerror(rc), rc);
Packit Service 5a9772
			goto fail;
Packit Service 5a9772
	}
Packit Service 5a9772
#endif
Packit Service 5a9772
#endif
Packit 1fb8d4
Packit 1fb8d4
	udevman->flags = UDEVMAN_FLAG_ADD_BY_VID_PID;
Packit Service 5a9772
	udevman->devman_loading = CreateMutexA(NULL, FALSE, "devman_loading");
Packit Service 5a9772
Packit Service 5a9772
	if (!udevman->devman_loading)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit 1fb8d4
	/* load usb device service management */
Packit 1fb8d4
	udevman_load_interface(udevman);
Packit Service 5a9772
	status = urbdrc_udevman_parse_addin_args(udevman, args);
Packit Service 5a9772
Packit Service 5a9772
	if (status != CHANNEL_RC_OK)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
	udevman->running = TRUE;
Packit Service 5a9772
	udevman->thread = CreateThread(NULL, 0, poll_thread, udevman, 0, NULL);
Packit Service 5a9772
Packit Service 5a9772
	if (!udevman->thread)
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
	if (!pEntryPoints->pRegisterUDEVMAN(pEntryPoints->plugin, (IUDEVMAN*)udevman))
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit 1fb8d4
	WLog_DBG(TAG, "UDEVMAN device registered.");
Packit 1fb8d4
	return 0;
Packit Service 5a9772
fail:
Packit Service 5a9772
	udevman_free(&udevman->iface);
Packit Service 5a9772
	return ERROR_INTERNAL_ERROR;
Packit 1fb8d4
}