2023-01-03 05:35:53 +01:00
|
|
|
#include <windows.h>
|
|
|
|
#include <cfgmgr32.h>
|
2023-01-07 06:52:08 +01:00
|
|
|
#include <usbioctl.h>
|
2023-01-03 05:35:53 +01:00
|
|
|
|
2023-01-07 06:52:08 +01:00
|
|
|
#include "hook/table.h"
|
|
|
|
#include "hook/iohook.h"
|
|
|
|
#include "hooklib/setupapi.h"
|
|
|
|
|
|
|
|
#include "util/dprintf.h"
|
|
|
|
#include "util/str.h"
|
|
|
|
#include "es3sec.h"
|
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
static const wchar_t DEVNAME_HUB[] = L"$hub";
|
|
|
|
static const wchar_t DEVNAME_HUB_[] = L"\\\\.\\$hub";
|
|
|
|
static const wchar_t DEVNAME_DONGLE[] = L"$dongle";
|
|
|
|
static const wchar_t HUB_DRIVER_KEY[] = L"{36fc9e60-c465-11cf-8056-444553540000}\\0001";
|
|
|
|
static const wchar_t root_hub_name[] = L"Fake Root Hub";
|
|
|
|
static const DEVINST HUB_DEVINST = 573;
|
|
|
|
static const DEVINST DONGLE_DEVINST = 5730;
|
2023-01-07 06:52:08 +01:00
|
|
|
static struct es3sec_config config;
|
|
|
|
static HANDLE dongle_fd;
|
|
|
|
static HANDLE hub_fd;
|
|
|
|
static IID hubs_iid;
|
2023-01-26 03:09:38 +01:00
|
|
|
static DEVINST root_dev_inst;
|
|
|
|
static USHORT dongle_vid;
|
|
|
|
static USHORT dongle_pid;
|
2023-01-07 06:52:08 +01:00
|
|
|
|
|
|
|
static HRESULT es3sec_handle_hub_irp(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_hub_open(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_hub_close(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_hub_ioctl(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_dongle_irp(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_dongle_open(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_dongle_close(struct irp *irp);
|
|
|
|
static HRESULT es3sec_handle_dongle_ioctl(struct irp *irp);
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_handle_driverkey(struct irp *irp);
|
2023-01-26 03:09:38 +01:00
|
|
|
static HRESULT es3sec_hub_handle_roothub(struct irp *irp);
|
|
|
|
static HRESULT es3sec_hub_handle_nodeinfo(struct irp *irp);
|
|
|
|
static HRESULT es3sec_hub_connection_info_ex(struct irp *irp);
|
|
|
|
static HRESULT es3sec_hub_descriptor_from_node(struct irp *irp);
|
2023-01-07 06:52:08 +01:00
|
|
|
|
|
|
|
static CONFIGRET my_CM_Get_Child(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
|
|
|
|
static CONFIGRET (*next_CM_Get_Child)(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
|
|
|
|
|
|
|
|
static CONFIGRET my_CM_Get_DevNode_Registry_PropertyW(
|
|
|
|
DEVINST dnDevInst,
|
|
|
|
ULONG ulProperty,
|
|
|
|
PULONG pulRegDataType,
|
|
|
|
PVOID Buffer,
|
|
|
|
PULONG pulLength,
|
|
|
|
ULONG ulFlags
|
|
|
|
);
|
|
|
|
static CONFIGRET (*next_CM_Get_DevNode_Registry_PropertyW)(
|
|
|
|
DEVINST dnDevInst,
|
|
|
|
ULONG ulProperty,
|
|
|
|
PULONG pulRegDataType,
|
|
|
|
PVOID Buffer,
|
|
|
|
PULONG pulLength,
|
|
|
|
ULONG ulFlags
|
|
|
|
);
|
|
|
|
|
|
|
|
static const struct hook_symbol cm_syms[] = {
|
|
|
|
{
|
|
|
|
.name = "CM_Get_DevNode_Registry_PropertyW",
|
|
|
|
.patch = my_CM_Get_DevNode_Registry_PropertyW,
|
|
|
|
.link = (void **) &next_CM_Get_DevNode_Registry_PropertyW
|
|
|
|
},
|
|
|
|
{
|
|
|
|
.name = "CM_Get_Child",
|
|
|
|
.patch = my_CM_Get_Child,
|
|
|
|
.link = (void **) &next_CM_Get_Child
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
HRESULT es3sec_hook_init(const struct es3sec_config *cfg, USHORT vid, USHORT pid)
|
2023-01-07 06:52:08 +01:00
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
assert(cfg != NULL);
|
|
|
|
|
|
|
|
if (!cfg->enable) {
|
|
|
|
return S_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IIDFromString(L"{3ABF6F2D-71C4-462a-8A92-1E6861E6AF27}", &hubs_iid);
|
|
|
|
setupapi_add_phantom_dev(&hubs_iid, DEVNAME_HUB);
|
|
|
|
|
|
|
|
hr = iohook_open_nul_fd(&dongle_fd);
|
|
|
|
hr = iohook_open_nul_fd(&hub_fd);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = iohook_push_handler(es3sec_handle_hub_irp);
|
|
|
|
hr = iohook_push_handler(es3sec_handle_dongle_irp);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
hook_table_apply(NULL, "setupapi.dll", cm_syms, _countof(cm_syms));
|
|
|
|
|
|
|
|
CM_Locate_DevNodeW(&root_dev_inst, NULL, CM_LOCATE_DEVNODE_NORMAL);
|
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
dprintf("ES3 Dongle: init with VID %d PID %d\n", vid, pid);
|
|
|
|
dongle_vid = vid;
|
|
|
|
dongle_pid = pid;
|
2023-01-07 06:52:08 +01:00
|
|
|
|
|
|
|
memcpy(&config, cfg, sizeof(*cfg));
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_hub_irp(struct irp *irp)
|
|
|
|
{
|
|
|
|
assert(irp != NULL);
|
|
|
|
if (irp->op != IRP_OP_OPEN && irp->fd != hub_fd) {
|
|
|
|
return iohook_invoke_next(irp);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (irp->op) {
|
|
|
|
case IRP_OP_OPEN: return es3sec_handle_hub_open(irp);
|
|
|
|
case IRP_OP_CLOSE: return es3sec_handle_hub_close(irp);
|
|
|
|
case IRP_OP_IOCTL: return es3sec_handle_hub_ioctl(irp);
|
|
|
|
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_hub_open(struct irp *irp)
|
|
|
|
{
|
2023-01-26 03:09:38 +01:00
|
|
|
if (!wstr_ieq(irp->open_filename, DEVNAME_HUB) && !wstr_ieq(irp->open_filename, DEVNAME_HUB_)) {
|
2023-01-07 06:52:08 +01:00
|
|
|
return iohook_invoke_next(irp);
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Open USB Hub\n");
|
|
|
|
irp->fd = hub_fd;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_hub_close(struct irp *irp)
|
|
|
|
{
|
|
|
|
dprintf("ES3 Dongle: Close Hub\n");
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_hub_ioctl(struct irp *irp)
|
|
|
|
{
|
|
|
|
switch (irp->ioctl) {
|
|
|
|
case 0x220424: return es3sec_hub_handle_driverkey(irp);
|
2023-01-26 03:09:38 +01:00
|
|
|
case 0x220448: return es3sec_hub_connection_info_ex(irp);
|
|
|
|
case 0x220410: return es3sec_hub_descriptor_from_node(irp);
|
|
|
|
case 0x220408:
|
|
|
|
if (irp->read.nbytes == sizeof(USB_NODE_INFORMATION))
|
|
|
|
return es3sec_hub_handle_nodeinfo(irp);
|
|
|
|
|
|
|
|
else if (irp->read.nbytes >= sizeof(USB_ROOT_HUB_NAME))
|
|
|
|
return es3sec_hub_handle_roothub(irp);
|
|
|
|
|
|
|
|
else {
|
|
|
|
dprintf("ES3 Dongle: Bad size for IOCTL %X\n", irp->ioctl);
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
|
|
|
|
2023-01-07 06:52:08 +01:00
|
|
|
default: dprintf("ES3 Dongle: Unknown hub IOCTL %X\n", irp->ioctl); return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_handle_driverkey(struct irp *irp)
|
2023-01-26 03:09:38 +01:00
|
|
|
{
|
|
|
|
size_t size_of_driver_key = sizeof(HUB_DRIVER_KEY);
|
|
|
|
ULONG actual_length = size_of_driver_key + sizeof(USB_ROOT_HUB_NAME);
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (irp->write.nbytes == sizeof(USB_HCD_DRIVERKEY_NAME)) {
|
|
|
|
dprintf("ES3 Dongle: Get Hub Driver Key size\n");
|
|
|
|
USB_HCD_DRIVERKEY_NAME usb_hcd_driver_key_name;
|
|
|
|
usb_hcd_driver_key_name.ActualLength = actual_length;
|
|
|
|
hr = iobuf_write(&irp->read, &usb_hcd_driver_key_name, sizeof(usb_hcd_driver_key_name));
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: iobuf_write failed! %lx\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Get Hub Driver Key\n");
|
2023-01-07 06:52:08 +01:00
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
PUSB_HCD_DRIVERKEY_NAME usb_hcd_driver_key_name = (PUSB_HCD_DRIVERKEY_NAME)malloc(sizeof(USB_HCD_DRIVERKEY_NAME) + actual_length);
|
2023-01-07 06:52:08 +01:00
|
|
|
usb_hcd_driver_key_name->ActualLength = actual_length;
|
2023-01-26 03:09:38 +01:00
|
|
|
|
2023-01-07 06:52:08 +01:00
|
|
|
errno_t err = wcscpy_s(
|
|
|
|
usb_hcd_driver_key_name->DriverKeyName,
|
|
|
|
_countof(HUB_DRIVER_KEY),
|
|
|
|
HUB_DRIVER_KEY
|
|
|
|
);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_handle_driverkey wcscpy_s failed with %X", err);
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
hr = iobuf_write(&irp->read, usb_hcd_driver_key_name, actual_length);
|
2023-01-07 06:52:08 +01:00
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: iobuf_write failed! %lx\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_handle_roothub(struct irp *irp)
|
|
|
|
{
|
|
|
|
size_t size_of_hub_name = sizeof(DEVNAME_HUB);
|
|
|
|
ULONG actual_length = size_of_hub_name + sizeof(USB_ROOT_HUB_NAME);
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
|
|
if (irp->read.nbytes == sizeof(USB_ROOT_HUB_NAME)) {
|
|
|
|
dprintf("ES3 Dongle: Get Hub Root Hub Name size\n");
|
|
|
|
USB_ROOT_HUB_NAME rhub;
|
|
|
|
rhub.ActualLength = actual_length;
|
|
|
|
hr = iobuf_write(&irp->read, &rhub, sizeof(rhub));
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: iobuf_write failed! %lx\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Get Hub Root Hub Name\n");
|
|
|
|
PUSB_ROOT_HUB_NAME rhub = (PUSB_ROOT_HUB_NAME)malloc(actual_length);
|
|
|
|
rhub->ActualLength = actual_length;
|
|
|
|
|
|
|
|
errno_t err = wcscpy_s(
|
|
|
|
rhub->RootHubName,
|
|
|
|
_countof(DEVNAME_HUB),
|
|
|
|
DEVNAME_HUB
|
|
|
|
);
|
|
|
|
|
|
|
|
if (err) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_handle_roothub wcscpy_s failed with %X", err);
|
|
|
|
return E_FAIL;
|
|
|
|
}
|
|
|
|
|
|
|
|
hr = iobuf_write(&irp->read, rhub, sizeof(USB_ROOT_HUB_NAME) + size_of_hub_name);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: iobuf_write failed! %lx\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_handle_nodeinfo(struct irp *irp)
|
|
|
|
{
|
|
|
|
dprintf("ES3 Dongle: Get Hub Node Information\n");
|
|
|
|
USB_NODE_INFORMATION node_info;
|
|
|
|
node_info.NodeType = UsbHub;
|
|
|
|
node_info.u.HubInformation.HubDescriptor.bNumberOfPorts = 1;
|
|
|
|
HRESULT hr = iobuf_write(&irp->read, &node_info, sizeof(node_info));
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_handle_nodeinfo iobuf_write failed! 0x%lX\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_connection_info_ex(struct irp *irp)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
PUSB_NODE_CONNECTION_INFORMATION_EX conn_info = (PUSB_NODE_CONNECTION_INFORMATION_EX) malloc(irp->write.nbytes);
|
|
|
|
hr = iobuf_read(&irp->write, conn_info, irp->write.nbytes);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_connection_info_ex Failed to read IRP %lx\n", hr);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Get Hub Connection Info EX\tConnectionIndex %ld\n", conn_info->ConnectionIndex);
|
|
|
|
conn_info->ConnectionStatus = DeviceConnected;
|
|
|
|
conn_info->DeviceIsHub = false;
|
|
|
|
|
|
|
|
conn_info->DeviceDescriptor.idVendor = dongle_vid;
|
|
|
|
conn_info->DeviceDescriptor.idProduct = dongle_pid;
|
|
|
|
conn_info->DeviceDescriptor.bLength = sizeof(conn_info->DeviceDescriptor);
|
|
|
|
|
|
|
|
hr = iobuf_write(&irp->read, conn_info, irp->read.nbytes);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_connection_info_ex Failed to write IRP %lx\n", hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_hub_descriptor_from_node(struct irp *irp)
|
|
|
|
{
|
|
|
|
HRESULT hr;
|
|
|
|
UCHAR req_type;
|
|
|
|
UCHAR req_data_requested;
|
|
|
|
PUSB_DESCRIPTOR_REQUEST req = (PUSB_DESCRIPTOR_REQUEST) malloc(irp->write.nbytes);
|
|
|
|
hr = iobuf_read(&irp->write, req, irp->write.nbytes);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_descriptor_from_node Failed to read IRP %lx\n", hr);
|
|
|
|
return hr;
|
|
|
|
}
|
|
|
|
|
|
|
|
req_type = req->SetupPacket.wValue >> 8;
|
|
|
|
req_data_requested = req->SetupPacket.wValue & 0xFF;
|
|
|
|
dprintf("ES3 Dongle: Get Hub Descriptor from Node Connection\treq_type %02X req_data_requested %02X\n", req_type, req_data_requested);
|
|
|
|
switch (req_type) {
|
|
|
|
case USB_CONFIGURATION_DESCRIPTOR_TYPE: req->Data[2] = irp->write.nbytes - 12; break;
|
|
|
|
case USB_STRING_DESCRIPTOR_TYPE: break;
|
|
|
|
default:
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_descriptor_from_node Unknown request type %x\n", req_type);
|
|
|
|
return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
|
|
|
hr = iobuf_write(&irp->read, req, irp->read.nbytes);
|
|
|
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
dprintf("ES3 Dongle: es3sec_hub_descriptor_from_node Failed to write IRP %lx\n", hr);
|
|
|
|
}
|
|
|
|
return hr;
|
2023-01-07 06:52:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_dongle_irp(struct irp *irp)
|
|
|
|
{
|
|
|
|
assert(irp != NULL);
|
|
|
|
if (irp->op != IRP_OP_OPEN && irp->fd != dongle_fd) {
|
|
|
|
return iohook_invoke_next(irp);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (irp->op) {
|
|
|
|
case IRP_OP_OPEN: return es3sec_handle_dongle_open(irp);
|
|
|
|
case IRP_OP_CLOSE: return es3sec_handle_dongle_close(irp);
|
|
|
|
case IRP_OP_IOCTL: return es3sec_handle_dongle_ioctl(irp);
|
|
|
|
default: return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_dongle_open(struct irp *irp)
|
|
|
|
{
|
|
|
|
if (!wstr_ieq(irp->open_filename, DEVNAME_DONGLE)) {
|
|
|
|
return iohook_invoke_next(irp);
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Open dongle\n");
|
|
|
|
irp->fd = dongle_fd;
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_dongle_close(struct irp *irp)
|
|
|
|
{
|
|
|
|
dprintf("ES3 Dongle: Close dongle\n");
|
|
|
|
return S_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static HRESULT es3sec_handle_dongle_ioctl(struct irp *irp)
|
|
|
|
{
|
2023-01-26 03:09:38 +01:00
|
|
|
switch (irp->ioctl) {
|
|
|
|
default: dprintf("ES3 Dongle: Unknown dongle IOCTL %X\n", irp->ioctl); return HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION);
|
|
|
|
}
|
2023-01-07 06:52:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static CONFIGRET my_CM_Get_DevNode_Registry_PropertyW(
|
|
|
|
DEVINST dnDevInst,
|
|
|
|
ULONG ulProperty,
|
|
|
|
PULONG pulRegDataType,
|
|
|
|
PVOID Buffer,
|
|
|
|
PULONG pulLength,
|
|
|
|
ULONG ulFlags
|
|
|
|
)
|
|
|
|
{
|
|
|
|
CONFIGRET cr = next_CM_Get_DevNode_Registry_PropertyW(dnDevInst, ulProperty, pulRegDataType, Buffer, pulLength, ulFlags);
|
|
|
|
if (dnDevInst != HUB_DEVINST) {
|
|
|
|
return cr;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (ulProperty) {
|
2023-01-26 03:09:38 +01:00
|
|
|
case CM_DRP_DEVICEDESC:
|
|
|
|
dprintf("ES3 Dongle: Get hub device description\n");
|
|
|
|
// wcscpy_s(Buffer, _countof(L"Disk drive"), L"Disk drive");
|
|
|
|
wcscpy_s(Buffer, _countof(L"Fake USB Hub"), L"Fake USB Hub");
|
|
|
|
break;
|
2023-01-07 06:52:08 +01:00
|
|
|
|
2023-01-26 03:09:38 +01:00
|
|
|
case CM_DRP_DRIVER:
|
|
|
|
dprintf("ES3 Dongle: Get hub driver\n");
|
|
|
|
wcscpy_s(Buffer, _countof(HUB_DRIVER_KEY), HUB_DRIVER_KEY);
|
|
|
|
break;
|
2023-01-07 06:52:08 +01:00
|
|
|
|
|
|
|
default:
|
2023-01-26 03:09:38 +01:00
|
|
|
dprintf("ES3 Dongle: my_CM_Get_DevNode_Registry_PropertyW Unhandled property 0x%lX\n", ulProperty);
|
2023-01-07 06:52:08 +01:00
|
|
|
return CR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static CONFIGRET my_CM_Get_Child(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags)
|
|
|
|
{
|
|
|
|
if (dnDevInst != root_dev_inst) {
|
|
|
|
return next_CM_Get_Child(pdnDevInst, dnDevInst, ulFlags);
|
|
|
|
}
|
|
|
|
|
|
|
|
dprintf("ES3 Dongle: Adding fake hub to root node\n");
|
|
|
|
*pdnDevInst = HUB_DEVINST;
|
|
|
|
return CR_SUCCESS;
|
|
|
|
}
|