/*
 * usbshare - internal declarations
 */

#pragma once

#include <ntddk.h>
#include <wdf.h>
#include <usb.h>
#include <usbdlib.h>
#include <wdfusb.h>

#include "public.h"

#define USBSHARE_POOL_TAG 'hsBU'

/*
 * Per-device context.
 *
 * One instance per filtered device. Claimed and ClaimOwner together decide
 * whether the class driver's requests are passed down or swallowed.
 */
typedef struct _DEVICE_CONTEXT {
    /* The device we are filtering, as a USB target. */
    WDFUSBDEVICE UsbDevice;

    /* The interface whose pipes we use. Only the first is handled today. */
    WDFUSBINTERFACE UsbInterface;

    /*
     * Pipe handles indexed by endpoint address (0x00-0xFF).
     *
     * Indexing by full address rather than endpoint number matters: a device
     * can have endpoint 1 as both interrupt IN (0x81) and bulk OUT (0x01),
     * and conflating them submits transfers of the wrong type.
     */
    WDFUSBPIPE Pipes[256];

    /*
     * Non-zero while user mode holds the device. Guarded by ClaimLock; read
     * on the request path, so it must stay cheap.
     */
    BOOLEAN Claimed;

    /*
     * The file object that claimed it. Used to release automatically when
     * that handle closes, including when its process dies.
     */
    WDFFILEOBJECT ClaimOwner;

    WDFSPINLOCK ClaimLock;

    /* Outstanding user mode transfers, so cancellation can find them. */
    WDFCOLLECTION PendingTransfers;
    WDFSPINLOCK PendingLock;

    /* Cached descriptor blob, built once on first request. */
    PUCHAR Descriptors;
    ULONG DescriptorsLength;

    /* Device info reported on claim. */
    USBSHARE_DEVICE_INFO Info;
} DEVICE_CONTEXT, *PDEVICE_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DEVICE_CONTEXT, GetDeviceContext)

/*
 * Per-request context, kept so a cancel can locate the WDFREQUEST that
 * belongs to a transfer ID.
 */
typedef struct _REQUEST_CONTEXT {
    ULONG64 TransferId;
    WDFMEMORY UrbMemory;
    PURB Urb;
    /* Bytes of payload the caller expects back, for IN transfers. */
    ULONG ExpectedLength;
} REQUEST_CONTEXT, *PREQUEST_CONTEXT;

WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(REQUEST_CONTEXT, GetRequestContext)

/* driver.c */
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD UsbShareEvtDeviceAdd;
EVT_WDF_DEVICE_PREPARE_HARDWARE UsbShareEvtDevicePrepareHardware;
EVT_WDF_DEVICE_FILE_CREATE UsbShareEvtDeviceFileCreate;
EVT_WDF_FILE_CLOSE UsbShareEvtFileClose;

/* queue.c */
EVT_WDF_IO_QUEUE_IO_DEVICE_CONTROL UsbShareEvtIoDeviceControl;

/* filter.c */
EVT_WDF_IO_QUEUE_IO_DEFAULT UsbShareEvtIoDefault;
EVT_WDF_IO_QUEUE_IO_INTERNAL_DEVICE_CONTROL UsbShareEvtIoInternalDeviceControl;

/* Helpers shared between translation units. */
NTSTATUS UsbShareBuildDescriptorBlob(_In_ PDEVICE_CONTEXT Context);
BOOLEAN UsbShareIsClaimed(_In_ PDEVICE_CONTEXT Context);
VOID UsbShareReleaseClaim(_In_ PDEVICE_CONTEXT Context, _In_opt_ WDFFILEOBJECT Owner);
