Hey guys,
I am having a hell of a time handling a pretty simple task. I have a HID kmdf driver and an user-mode application that I want to use to write and read from the chip on my device. I have a continuous reader set up to handle reading and that is working fine. It is the write requests that I’m having trouble with. When I call my write function in the user app, my driver’s HidEvtInternalDeviceControl function gets called with IOCTL_HID_WRITE_REPORT as the ioctl code but the input buffer is always zeroes and the InputBufferLength is 16 when it should be 64. I’ve tried creating a queue for write requests but that leads to another unexpected error in that the device fails to start so now I’m just trying to figure out what’s going on. Any help or nudges in the right direction would be hugely appreciated. Here’s the code I have now:
USER MODE WRITE FUNCTION:
BOOL WriteToDevice(PROPRIETARY_DEVICE *pDevice, DWORD dwCollIndex, LPCVOID pMessage, DWORD dwNumBytes, DWORD *pdwBytesWritten)
{
if(dwCollIndex >= pDevice->bCollectionNum)
{//collection does not exist for this device
return FALSE;
}
if(dwNumBytes > pDevice->Collection[dwCollIndex].dwOutReportByteLength)
{//not enough space in buffer
return FALSE;
}
BOOL bWriteStatus = WriteFile(pDevice->Collection[dwCollIndex].hHidDevice,
pMessage,
dwNumBytes,
pdwBytesWritten,
&pDevice->Collection[dwCollIndex].OverlappedWrite);
if((bWriteStatus == FALSE) || (*pdwBytesWritten != pDevice->Collection[dwCollIndex].dwOutReportByteLength))
{
DWORD dwErrorCode = GetLastError();
if(dwErrorCode == ERROR_IO_PENDING)
{
//use WaitForSingleObject to time out, then call GetOverlappedResult
WaitForSingleObject(pDevice->Collection[dwCollIndex].OverlappedWrite.hEvent, TIMEOUT_WRITE);
BOOL bSuccess = GetOverlappedResult(pDevice->Collection[dwCollIndex].hHidDevice,
&pDevice->Collection[dwCollIndex].OverlappedWrite,
pdwBytesWritten,
FALSE);
if(bSuccess)
{
bWriteStatus = TRUE;
}
}
}
ResetEvent(pDevice->Collection[dwCollIndex].OverlappedWrite.hEvent);
return(bWriteStatus);
}
KERNEL MODE IOCTL_HID_WRITE CASE:
VOID My_HidEvtInternalDeviceControl(
IN WDFQUEUE Queue,
IN WDFREQUEST Request,
IN size_t OutputBufferLength,
IN size_t InputBufferLength,
IN ULONG IoControlCode
)
{
NTSTATUS status = STATUS_SUCCESS;
PIRP pIrp = NULL;
WDFDEVICE device;
PDEVICE_EXTENSION devContext = NULL;
WDFMEMORY wdfInMem;
WDFMEMORY wdfOutMem;
UCHAR inBuf[128];
UCHAR outBuf[100];
size_t length = 0;
int i;
UNREFERENCED_PARAMETER(InputBufferLength);
UNREFERENCED_PARAMETER(OutputBufferLength);
device = WdfIoQueueGetDevice(Queue);
devContext = GetDeviceContext(device);
TraceEvents(TRACE_LEVEL_INFORMATION, DBG_IOCTL,
“%s, Queue:0x%p, Request:0x%p\n”,
DbgHidInternalIoctlString(IoControlCode),
Queue,
Request);
//
// Please note that HIDCLASS provides the buffer in the Irp->UserBuffer
// field irrespective of the ioctl buffer type. However, framework is very
// strict about type checking. You cannot get Irp->UserBuffer by using
// WdfRequestRetrieveOutputMemory if the ioctl is not a METHOD_NEITHER
// internal ioctl. So depending on the ioctl code, we will either
// use retreive function or escape to WDM to get the UserBuffer.
//
switch(IoControlCode){
…
…
…
case IOCTL_HID_WRITE_REPORT:
//
//Transmits a class driver-supplied report to the device.
//
DbgPrint(“IOCTL_HID_WRITE_REPORT. InBufLength: %d, OutBufLength: %d”, InputBufferLength, OutputBufferLength);
status = WdfRequestRetrieveInputMemory(Request, &wdfInMem);
if(!NT_SUCCESS(status)){
DbgPrint(“Retrieve Input Memory failed! Error: %d\r\n”, status);
WdfRequestComplete(Request, status);
return;
}
status = WdfRequestRetrieveInputBuffer(Request, 8, inBuf, &length);
if(!NT_SUCCESS(status)){
DbgPrint(“Retrieve Input Buffer failed! Error: %d\r\n”, status);
WdfRequestComplete(Request, status);
return;
}
DbgPrint(“Retrieve Input Buffer succeeded! Length: %d\r\n”, length);
for (i = 0; i < 8; i++)
DbgPrint(“Buf[%d]: %d”, i, (UCHAR)inBuf[i]);
break;
…
…
…
default:
status = STATUS_NOT_SUPPORTED;
KdPrint((“get an NOT_SUPPORTED request \n”));
DbgPrint(“Unsupported IOCTL: 0x%x”,IoControlCode);
break;
}
WdfRequestComplete(Request, status);
return;
}
I know this is not code that will actually handle the write request, I am just trying to get a better idea of what’s going on so I can proceed correctly. When I print the buffer it is all zeros. Once I successfully obtain the actual write buffer data then I will call another function to actually copy the data to the device. That function is shown below:
NTSTATUS SendDataToDevice(
IN WDFMEMORY requestMem,
IN PDEVICE_EXTENSION devContext,
IN WDFREQUEST Request
)
{
NTSTATUS status;
status = WdfUsbTargetPipeFormatRequestForWrite(
devContext->OutPipe,
Request,
requestMem,
NULL);
if(!NT_SUCCESS(status)){
DbgPrint(“Failed to format pipe for write. Error: %d\r\n”, status);
WdfRequestComplete(Request, status);
return status;
}
WdfRequestSetCompletionRoutine(Request,
EvtIoWriteComplete,
devContext->OutPipe);
if(FALSE == WdfRequestSend(Request,
WdfUsbTargetPipeGetIoTarget(devContext->OutPipe),
NULL))
{
DbgPrint(“Failed to send Request. Error: %d”, status);
status = WdfRequestGetStatus(Request);
}
return status;
}
Can anyone point me in the right direction here? I’m not sure what I’m doing wrong…