Example #1
0
VOID
OnIoDeviceControl(
    _In_  WDFQUEUE    FxQueue,
    _In_  WDFREQUEST  FxRequest,
    _In_  size_t      OutputBufferLength,
    _In_  size_t      InputBufferLength,
    _In_  ULONG       IoControlCode
    )
/*++
Routine Description:

    This event is called when the framework receives IRP_MJ_DEVICE_CONTROL
    requests from the system.

Arguments:

    FxQueue - Handle to the framework queue object that is associated
        with the I/O request.
    FxRequest - Handle to a framework request object.
    OutputBufferLength - length of the request's output buffer,
        if an output buffer is available.
    InputBufferLength - length of the request's input buffer,
        if an input buffer is available.
    IoControlCode - the driver-defined or system-defined I/O control code
        (IOCTL) that is associated with the request.

Return Value:

   VOID

--*/
{
    FuncEntry(TRACE_FLAG_SPBAPI);

    WDFDEVICE device;
    PDEVICE_CONTEXT pDevice;
    BOOLEAN fSync = FALSE;
    NTSTATUS status = STATUS_SUCCESS;
    UNREFERENCED_PARAMETER(OutputBufferLength);
    UNREFERENCED_PARAMETER(InputBufferLength);

	device = WdfIoQueueGetDevice(FxQueue);
	pDevice = GetDeviceContext(device);

	CyapaPrint(
		DEBUG_LEVEL_INFO, DBG_IOCTL,
        "DeviceIoControl request %p received with IOCTL=%lu",
        FxRequest,
        IoControlCode);
	CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL,
		"%s, Queue:0x%p, Request:0x%p\n",
		DbgHidInternalIoctlString(IoControlCode),
		FxQueue,
		FxRequest
		);

    //
    // Translate the test IOCTL into the appropriate 
    // SPB API method.  Open and close are completed 
    // synchronously.
    //

    switch (IoControlCode)
    {
	case IOCTL_HID_GET_DEVICE_DESCRIPTOR:
		//
		// Retrieves the device's HID descriptor.
		//
		status = CyapaGetHidDescriptor(device, FxRequest);
		fSync = TRUE;
		break;

	case IOCTL_HID_GET_DEVICE_ATTRIBUTES:
		//
		//Retrieves a device's attributes in a HID_DEVICE_ATTRIBUTES structure.
		//
		status = CyapaGetDeviceAttributes(FxRequest);
		fSync = TRUE;
		break;

	case IOCTL_HID_GET_REPORT_DESCRIPTOR:
		//
		//Obtains the report descriptor for the HID device.
		//
		status = CyapaGetReportDescriptor(device, FxRequest);
		fSync = TRUE;
		break;

	case IOCTL_HID_GET_STRING:
		//
		// Requests that the HID minidriver retrieve a human-readable string
		// for either the manufacturer ID, the product ID, or the serial number
		// from the string descriptor of the device. The minidriver must send
		// a Get String Descriptor request to the device, in order to retrieve
		// the string descriptor, then it must extract the string at the
		// appropriate index from the string descriptor and return it in the
		// output buffer indicated by the IRP. Before sending the Get String
		// Descriptor request, the minidriver must retrieve the appropriate
		// index for the manufacturer ID, the product ID or the serial number
		// from the device extension of a top level collection associated with
		// the device.
		//
		status = CyapaGetString(FxRequest);
		fSync = TRUE;
		break;

	case IOCTL_HID_WRITE_REPORT:
	case IOCTL_HID_SET_OUTPUT_REPORT:
		//
		//Transmits a class driver-supplied report to the device.
		//
		status = CyapaWriteReport(pDevice, FxRequest);
		fSync = TRUE;
		break;

	case IOCTL_HID_READ_REPORT:
	case IOCTL_HID_GET_INPUT_REPORT:
		//
		// Returns a report from the device into a class driver-supplied buffer.
		// 
		status = CyapaReadReport(pDevice, FxRequest, &fSync);
		break;

	case IOCTL_HID_GET_FEATURE:
		//
		// returns a feature report associated with a top-level collection
		//
		status = CyapaGetFeature(pDevice, FxRequest, &fSync);
		break;
	case IOCTL_HID_ACTIVATE_DEVICE:
		//
		// Makes the device ready for I/O operations.
		//
	case IOCTL_HID_DEACTIVATE_DEVICE:
		//
		// Causes the device to cease operations and terminate all outstanding
		// I/O requests.
		//
    default:
        fSync = TRUE;
		status = STATUS_NOT_SUPPORTED;
		CyapaPrint(
			DEBUG_LEVEL_INFO, DBG_IOCTL,
            "Request %p received with unexpected IOCTL=%lu",
            FxRequest,
            IoControlCode);
    }

    //
    // Complete the request if necessary.
    //

    if (fSync)
    {
		CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL,
			"%s completed, Queue:0x%p, Request:0x%p\n",
			DbgHidInternalIoctlString(IoControlCode),
			FxQueue,
			FxRequest
			);

        WdfRequestComplete(FxRequest, status);
	}
	else {
		CyapaPrint(DEBUG_LEVEL_INFO, DBG_IOCTL,
			"%s deferred, Queue:0x%p, Request:0x%p\n",
			DbgHidInternalIoctlString(IoControlCode),
			FxQueue,
			FxRequest
			);
	}

    FuncExit(TRACE_FLAG_SPBAPI);
}
Example #2
0
NTSTATUS
HidUmdfInternalIoctlWorker(
    _In_ PDEVICE_OBJECT DeviceObject,
    _Inout_ PIRP Irp
    )
/*++

Routine Description:

    IOCTL handler.


Arguments:

   DeviceObject - pointer to a device object.

   Irp - pointer to an I/O Request Packet.

Return Value:

      NT status code

--*/
{
    PIO_STACK_LOCATION currStack, nextStack;
    ULONG ioctlCode, newIoctlCode;
    BOOLEAN setCompletionRoutine = FALSE;
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN modeChanged = FALSE;
    PULONG temp = NULL;
    
    currStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // Copy current stack to next instead of skipping. We do this to preserve 
    // current stack information provided by hidclass driver to the minidriver
    //
    IoCopyCurrentIrpStackLocationToNext(Irp);

    //
    // HIDclass uses INTERNAL_IOCTL but since UMDF doesn't yet have support for
    // internal IOCTLS we change the IOCTL type to DEVICE_CONTROL for next stack
    // so that UMDF stack can handle it as normal IOCTL.
    // Note that user mode apps cannot open a handle to minidriver since 
    // HIDClass doesn't allow that (it own's minidriver's dispatch table),
    // and therefore they can't send these IOCTLs to UMDF minidriver by calling 
    // win32 API.
    //
    nextStack = IoGetNextIrpStackLocation(Irp);
    nextStack->MajorFunction = IRP_MJ_DEVICE_CONTROL;

    //
    // Some IOCTLs are not of type METHOD_NEITHER and are forwarded by 
    // HIDClass to minidriver. We modify those IOCTLs to use METHOD_NEITHER
    // and send it down to UMDF driver.
    //
    ioctlCode = nextStack->Parameters.DeviceIoControl.IoControlCode;

    newIoctlCode = ioctlCode;
    
    switch(ioctlCode) {
    case IOCTL_HID_GET_DEVICE_DESCRIPTOR:           // METHOD_NEITHER, KM
    case IOCTL_HID_GET_REPORT_DESCRIPTOR:           // METHOD_NEITHER, KM
    case IOCTL_HID_READ_REPORT:                     // METHOD_NEITHER, KM
    case IOCTL_HID_ACTIVATE_DEVICE:                 // METHOD_NEITHER, KM
    case IOCTL_HID_DEACTIVATE_DEVICE:               // METHOD_NEITHER, KM
    case IOCTL_HID_GET_DEVICE_ATTRIBUTES:           // METHOD_NEITHER, KM
    case IOCTL_HID_SEND_IDLE_NOTIFICATION_REQUEST:  // METHOD_NEITHER, KM
        //
        // Nothing to do. These IOCTLs have been listed for completeness.
        //
        break;
    case IOCTL_HID_WRITE_REPORT:                    // METHOD_NEITHER, KM
    case IOCTL_HID_SET_FEATURE:                     // METHOD_IN_DIRECT, KM/UM
    case IOCTL_HID_GET_FEATURE:                     // METHOD_OUT_DIRECT, KM/UM
    case IOCTL_HID_GET_INPUT_REPORT:                // METHOD_OUT_DIRECT, KM/UM
    case IOCTL_HID_SET_OUTPUT_REPORT:               // METHOD_IN_DIRECT, KM/UM
        //
        // These IOCTLs use HID_XFER_PACKET. They need their buffer location 
        // updated. See comments in function for IOCTL specific updates.
        //
        status = UpdateBufferLocationAndIoctl(Irp, &newIoctlCode);
        if (!NT_SUCCESS(status)) {
            KdPrint(("HidUmdf: Ioctl %s failed status 0x%x\n", 
                DbgHidInternalIoctlString(ioctlCode), status));
            Irp->IoStatus.Status = status;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return status;
        }

        //
        // set completion routine
        //
        setCompletionRoutine = TRUE;
        break;

    case IOCTL_GET_PHYSICAL_DESCRIPTOR:             // METHOD_OUT_DIRECT, KM/UM 
        //
        // These IOCTLs are not METHOD_NEITHER but hidclass places buffers at
        // locations that are standard locations for METHOD_NEITHER 
        // (Type3InputBuffer and Irp->UserBuffer), so we modify the IOCTL type
        // to use METHOD_NEITHER so that UMDF can provide the buffers from 
        // standard METHOD_NEITHER buffer locations.
        // 
        newIoctlCode = IOCTL_UMDF_GET_PHYSICAL_DESCRIPTOR;
        break;

    case IOCTL_HID_GET_STRING:                      // METHOD_NEITHER, KM     
        //
        // This is a METHOD_NEITHER IOCTL. Hidclass places an input
        // ULONG value, and not a buffer, at Type3inputBuffer location. 
        // We store the input value in Irp->AssocatedIrp.SystemBuffer location
        // and store pointer to Irp->AssocatedIrp.SystemBuffer at 
        // Type3InputBuffer so that lower driver can access it as input buffer. 
        // 

        //
        // swap current SystemBuffer content with Type3inputBuffer
        //
        temp = Irp->AssociatedIrp.SystemBuffer;
        Irp->AssociatedIrp.SystemBuffer = 
            currStack->Parameters.DeviceIoControl.Type3InputBuffer;
        currStack->Parameters.DeviceIoControl.Type3InputBuffer = temp;

        //
        // store the address of SystemBuffer in next stack's Type3InputBuffer
        // and set buffer size
        //
        nextStack->Parameters.DeviceIoControl.Type3InputBuffer = 
            &Irp->AssociatedIrp.SystemBuffer;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);

        setCompletionRoutine = TRUE;
        break;
    
    case IOCTL_HID_GET_INDEXED_STRING:              // METHOD_OUT_DIRECT, KM/UM
        //
        // This is a METHOD_OUT_DIRECT IOCTL however hidclass places buffer/value
        // in a mix of locations (Type3InputBuffer for input instead of 
        // Irp->AssociatedIrp.SystemBuffer and Irp->MdlAddress for output). 
        // Also, the input is not a buffer but a ULONG value.
        // 
        // We store the address of next stack's Type3InputBuffer that contains 
        // the input value at Irp->AssiciatedIrp.SystemBuffer 
        // (standard location for METHOD_OUT_DIRECT), and keep the output buffer
        // location (Irp->UserBuffer) unchanged  since it's already at standard
        // location. The input buffer location is reverted back to original in 
        // completion routine.
        // 

        //
        // store SystemBuffer in curr stack's Type3inputBuffer so we 
        // can get it back in completion routine.
        //
        currStack->Parameters.DeviceIoControl.Type3InputBuffer = 
            Irp->AssociatedIrp.SystemBuffer;

        //
        // store the address of next stack's Type3InputBuffer in  SystemBuffer
        // and set buffer size.
        //
        Irp->AssociatedIrp.SystemBuffer = 
            &nextStack->Parameters.DeviceIoControl.Type3InputBuffer;
        nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(ULONG);

        setCompletionRoutine = TRUE;
        break;

    default:
        NT_ASSERTMSG("Unexpected IOCTL", FALSE);
        break;
    }

    //
    // update ioctl code for next stack location
    //
    nextStack->Parameters.DeviceIoControl.IoControlCode = newIoctlCode;

    if (Irp->RequestorMode == UserMode) {
        Irp->RequestorMode = KernelMode;
        setCompletionRoutine = TRUE;
        modeChanged = TRUE;
    }

    if (setCompletionRoutine) {
        IoSetCompletionRoutine(Irp,
                       UserIoctlCompletion,
                       (modeChanged ? (PVOID)Irp : NULL),  // context
                       TRUE,                       
                       TRUE,
                       TRUE );
    }

    return IoCallDriver(GET_NEXT_DEVICE_OBJECT(DeviceObject), Irp);
}