📄 driver.cpp
字号:
ExFreePool(pDevExt->deviceBuffer);
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
}
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0; // no bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS;
}
//++
// Function: DispatchCancel
//
// Description:
// Handles canceled IRP
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
VOID DispatchCancel (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG==1
DbgPrint("PPORT: IRP Canceled\n");
#endif
// Just complete the IRP
pIrp->IoStatus.Status = STATUS_CANCELLED;
pIrp->IoStatus.Information = 0; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, TRUE );
}
//++
// Function: DispatchWrite
//
// Description:
// Handles call from Win32 WriteFile request
// For PPort driver, "starts" the device by
// indirectly calling StartIo.
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
NTSTATUS DispatchWrite (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG==1
DbgPrint("PPORT: Write Operation requested (DispatchWrite)\n");
#endif
// Start the I/O
IoMarkIrpPending( pIrp );
IoStartPacket( pDevObj, pIrp, 0, DispatchCancel);
return STATUS_PENDING;
}
//++
// Function: DispatchRead
//
// Description:
// Handles call from Win32 ReadFile request
// For PPort driver, xfers pool buffer to user
//
// Arguments:
// pDevObj - Passed from I/O Manager
// pIrp - Passed from I/O Manager
//
// Return value:
// NTSTATUS - success or failuer code
//--
NTSTATUS DispatchRead (
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp ) {
#if DBG==1
DbgPrint("PPORT: Read Operation requested (DispatchRead)\n");
#endif
NTSTATUS status = STATUS_SUCCESS;
PVOID userBuffer;
ULONG xferSize;
// The stack location contains the user buffer info
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation( pIrp );
// Dig out the Device Extension from the Device object
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
// Determine the length of the request
xferSize = pIrpStack->Parameters.Read.Length;
// Obtain user buffer pointer
userBuffer = pIrp->AssociatedIrp.SystemBuffer;
// Don't transfer more than the user's request
xferSize = (xferSize < pDevExt->deviceBufferSize) ?
xferSize : pDevExt->deviceBufferSize;
// Now copy the pool buffer into user space
RtlCopyMemory( userBuffer, pDevExt->deviceBuffer,
xferSize );
// Free the temporary pool buffer
ExFreePool( pDevExt->deviceBuffer );
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
// Now complete the IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = xferSize; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status;
}
BOOLEAN Isr (
IN PKINTERRUPT pIntObj,
IN PVOID pServiceContext ) {
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pServiceContext;
PDEVICE_OBJECT pDevObj = pDevExt->pDevice;
PIRP pIrp = pDevObj->CurrentIrp;
#if dbg==1
DbgPrint("PPORT: Interrupt Service Routine\n");
#endif
UCHAR status = ReadStatus( pDevExt );
if ((status & STS_NOT_IRQ))
return FALSE;
// its our interrupt, deal with it
WriteControl( pDevExt, CTL_DEFAULT);
// transmit another character
if (!TransmitByte( pDevExt ))
// if no more bytes, complete the request
IoRequestDpc( pDevObj, pIrp, (PVOID)pDevExt );
return TRUE;
}
//++
// Function:
// TransmitByte
//
// Description:
// This function sends one character to the device
// An interrupt is then forced from the port.
// If no characters remain to be transmitted, return FALSE.
//
// Arguments:
// Pointer to the Device Extension
//
// Return Value:
// TRUE - one more byte transmitted
// FALSE - no more bytes remain to be transmitted
//--
BOOLEAN TransmitByte(
IN PVOID pArg ) {
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pArg;
// If all the bytes have been sent, just quit
if( pDevExt->xferCount >= pDevExt->maxXferCount)
return FALSE;
// A transfer is happening.
PDEVICE_OBJECT pDevObj =
pDevExt->pDevice;
PIRP pIrp = pDevObj->CurrentIrp;
// Obtain user buffer pointer
PUCHAR userBuffer = (PUCHAR)
pIrp->AssociatedIrp.SystemBuffer;
UCHAR nextByte =
userBuffer[pDevExt->xferCount];
// Now send it...
#if DBG==1
DbgPrint("PPORT: TransmitByte: Sending 0x%02X (%c) to port %X\n",
nextByte, nextByte, pDevExt->portBase);
#endif
// The loopback connector requires us to do
// some bizzare work.
// Bit 0 of the data is sent as bit 0 of Port data.
WriteData( pDevExt, nextByte & 1);
// It will be read in Status bit 3
// Bits 1-3 of the data are sent as bits 0,1, & 3
// of the Control register.
// Control bits 0 & 1 are inverted.
UCHAR bits = (nextByte & 0x8) +
((nextByte & 0x6)>>1);
bits ^= 0x3; // Invert the 2 control bits (0 & 1)
// These bits will be read in Status bits 4,5, & 7
WriteControl( pDevExt, bits | CTL_DEFAULT);
#if DBG==1
DbgPrint("PPORT: Wrote to Control: 0x%02X\n", bits);
#endif
// Now read the data from the loopback
UCHAR status =
ReadStatus( pDevExt );
#if DBG==1
DbgPrint("PPORT: Read From Status: 0x%03X\n", status);
#endif
// Format the nibble into the upper half of the byte
UCHAR readByte =
((status & 0x8)<< 1) |
((status & 0x30)<<1) |
(status & 0x80);
pDevExt->deviceBuffer[pDevExt->xferCount++] =
readByte;
#if DBG==1
DbgPrint("PPORT: TransmitByte read character: 0x%03X (%c)\n",
readByte, readByte);
#endif
// Force an interrupt
#if DBG==1
DbgPrint("PPORT: TransmitByte: generating interrupt.\n");
#endif
// Enable interrupts, raise BUSY
WriteControl( pDevExt, CTL_INTENB | CTL_SELECT | CTL_DEFAULT );
// Lower BUSY
WriteControl( pDevExt, CTL_INTENB | CTL_DEFAULT );
// Pulse ACK#
WriteControl( pDevExt, CTL_INTENB | CTL_NOT_RST | CTL_DEFAULT);
// hold it for about 50 uS
KeStallExecutionProcessor(50);
WriteControl( pDevExt, CTL_INTENB | CTL_DEFAULT );
return TRUE;
}
//++
// Function:
// StartIo
//
// Description:
// This function is responsible initiating the
// actual data transfer. The ultimate result
// should be an interrupt from the device.
//
// Arguments:
// Pointer to the Device object
// Pointer to the IRP for this request
//
// Return Value:
// (None)
//--
VOID
StartIo(
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp
) {
#if DBG==1
DbgPrint("PPORT: Start I/O Operation\n");
#endif
PIO_STACK_LOCATION pIrpStack =
IoGetCurrentIrpStackLocation( pIrp );
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pDevObj->DeviceExtension;
PUCHAR userBuffer;
ULONG xferSize;
switch( pIrpStack->MajorFunction ) {
// Use a SynchCritSection routine to
// start the write operation...
case IRP_MJ_WRITE:
// Set up counts and byte pointer
pDevExt->maxXferCount =
pIrpStack->Parameters.Write.Length;
pDevExt->xferCount = 0;
// Since we processing a new Write request,
// free up any old buffer
if (pDevExt->deviceBuffer != NULL) {
ExFreePool(pDevExt->deviceBuffer);
pDevExt->deviceBuffer = NULL;
pDevExt->deviceBufferSize = 0;
}
// Determine the length of the request
xferSize =
pIrpStack->Parameters.Write.Length;
// Obtain user buffer pointer
userBuffer = (PUCHAR)
pIrp->AssociatedIrp.SystemBuffer;
// Allocate the new buffer
pDevExt->deviceBuffer = (PUCHAR)
ExAllocatePool( PagedPool, xferSize );
if (pDevExt->deviceBuffer == NULL) {
// buffer didn't allocate???
// fail the IRP
pIrp->IoStatus.Status =
STATUS_INSUFFICIENT_RESOURCES;
pIrp->IoStatus.Information = 0;
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, FALSE );
}
pDevExt->deviceBufferSize = xferSize;
//
// Try to send the first byte of data.
// If there's a problem, use
// the DPC routine to fail the IRP.
//
#if DBG==1
DbgPrint("PPORT: StartIO: Transmitting first byte of %d\n", pDevExt->deviceBufferSize);
#endif
if( !KeSynchronizeExecution(
pDevExt->pIntObj,
TransmitByte,
pDevExt ))
{
DpcForIsr(
NULL,
pDevObj,
pIrp,
pDevExt );
}
break;
//
// Should never get here -- just get rid
// of the packet...
//
default:
pIrp->IoStatus.Status =
STATUS_NOT_SUPPORTED;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(
pIrp,
IO_NO_INCREMENT );
IoStartNextPacket( pDevObj, FALSE );
break;
}
}
//++
// Function:
// DpcForIsr
//
// Description:
// This function performs the low-IRQL
// post-processing of I/O requests
//
// Arguments:
// Pointer to a DPC object
// Pointer to the Device object
// Pointer to the IRP for this request
// Pointer to the Device Extension
//
// Return Value:
// (None)
//--
VOID
DpcForIsr(
IN PKDPC pDpc,
IN PDEVICE_OBJECT pDevObj,
IN PIRP pIrp,
IN PVOID pContext
)
{
PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
pContext;
#if DBG==1
DbgPrint("PPORT: DpcForIsr, xferCount = %d\n",
pDevExt->xferCount);
#endif
pIrp->IoStatus.Information =
pDevExt->xferCount;
// This loopback device always works
pIrp->IoStatus.Status =
STATUS_SUCCESS;
//
// If we're being called directly from Start I/O,
// don't give the user any priority boost.
//
if( pDpc == NULL )
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
else
IoCompleteRequest( pIrp, IO_PARALLEL_INCREMENT );
//
// This one's done. Begin working on the next
//
IoStartNextPacket( pDevObj, FALSE );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -