📄 io.c
字号:
CIRCC2_MASTER_BLOCK_CONTROL,
mbc.AsUChar);
WdfInterruptReleaseLock(DeviceData->Interrupt);
//
// The user has given us a data buffer in RLC format:
//
// 500, -1000, 200, -500
// ON for 10 OFF for 20 ON for 5 OFF for 10
//
// Our job is to now convert this into something that
// is appropriate for our device, which in our case
// is one bit per sample, and transmit it
//
// We're going to do this by looping over all of the
// user data, converting it to our native format,
// then begin blasting. Each time a piece is done our
// device will interrupt, we'll queue a DPC, and then
// continue the blasting from within the DPC. Once the
// blasting is complete we'll complete this transmit
// request
//
//
// We shouldn't have anything outstanding
//
ASSERT(IsListEmpty(&DeviceData->TxFifoDataList));
while (TRUE) {
//
// transmitChunk is mapped via an MDL. Make sure we
// capture anything important before validating,
// the user has the ability to modifiy the contents
// while we work on it.
//
capturedByteCount = (ULONG)transmitChunk->ByteCount;
capturedNextOffset = transmitChunk->OffsetToNextChunk;
capturedRepeatCount = (ULONG)transmitChunk->RepeatCount;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: Transmit chunk 0x%p: Byte Count 0x%x, "\
"Repeat Count 0x%x",
transmitChunk, capturedByteCount,
capturedRepeatCount));
//
// Watch out for a malformed ByteCount...
//
if (capturedByteCount >
(transmitMaxAddress - (ULONG_PTR)transmitChunk->Data)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: ByteCount of 0x%x is invalid - passes end "\
"of allocation",
capturedByteCount));
status = STATUS_INVALID_BUFFER_SIZE;
break;
}
//
// Convert this transmit chunk into data that works for
// our device.
//
status = IrTransmitBuildFifoData(transmitChunk,
capturedByteCount,
&txFifoData);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: IrTransmitBuildFifoData failed - 0x%x", status));
break;
}
//
// Insert this (now converted) chunk onto the tail of
// our "to be blasted" list. No need to lock, we'll only
// ever have one TX request active
//
InsertTailList(&DeviceData->TxFifoDataList,
&txFifoData->ListEntry);
if (capturedNextOffset == 0) {
//
// We ran out of things to process...Get out...
//
break;
}
//
// Watch out for a malformed Offset...Life would be easy
// if it wasn't for users...
//
if (capturedNextOffset >
(transmitMaxAddress - (ULONG_PTR)transmitChunk->Data)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: OffsetToNextChunk of 0x%Ix is invalid - passes "\
"end of allocation",
capturedNextOffset));
status = STATUS_INVALID_USER_BUFFER;
break;
}
if (capturedNextOffset <
(sizeof(IR_TRANSMIT_CHUNK) + capturedByteCount)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: OffsetToNextChunk of 0x%Ix is invalid - too "\
"small based on prev chunk",
capturedNextOffset));
status = STATUS_INVALID_USER_BUFFER;
break;
}
//
// Next!
//
transmitChunk
= (PIR_TRANSMIT_CHUNK)((ULONG_PTR)transmitChunk
+ capturedNextOffset);
//
// Make sure that the user followed best practices
// and aligned the next offset properly...
//
ASSERT(((ULONG_PTR)transmitChunk % sizeof(ULONG_PTR)) == 0);
}
//
// If we encountered an error it's time to cleanup
//
if (!NT_SUCCESS(status)) {
while (!IsListEmpty(&DeviceData->TxFifoDataList)) {
txFifoData
= (PSMSCIR_TX_FIFO_DATA)
RemoveHeadList(&DeviceData->TxFifoDataList);
ExFreePool(txFifoData);
}
WdfRequestComplete(Request, status);
return;
}
//
// We've preprocessed the data, let's get the transfer going...
//
KeAcquireSpinLock(&DeviceData->TxFifoDataLock, &oldIrql);
txFifoData = (PSMSCIR_TX_FIFO_DATA)DeviceData->TxFifoDataList.Flink;
DeviceData->CurrentTxFifoData = txFifoData;
DeviceData->CurrentTxRequest = Request;
DeviceData->BytesTransmitted = 0;
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: Beginning blasting"));
//
// Call the helper to kick off the blasting (even though
// it's called "Continue Blasting" it will do the right thing).
//
SmscIrContinueBlasting(DeviceData,
&requestToComplete,
&requestStatus);
KeReleaseSpinLock(&DeviceData->TxFifoDataLock, oldIrql);
if (requestToComplete) {
//
// This would only happen on incredibly small transfers (like,
// < 32 bytes) or requests that were cancelled while we were
// preprocessing the data.
//
WdfRequestComplete(requestToComplete, requestStatus);
} else {
//
// Start the deadman. If the system is under much stress
// there's a chance for the TX FIFO to underrun, so we
// need to keep a deadman out there on the watch (we won't
// necessarily get an interrupt for the underrun, and
// the TX FIFO interrupt stopping also stops the RX FIFO
// interrupt)
//
WdfTimerStart(DeviceData->DeadManTimer,
WDF_REL_TIMEOUT_IN_MS(SMSCIR_DEADMAN_TIMER_PERIOD));
}
return;
}
NTSTATUS
IrTransmitBuildFifoData(
PIR_TRANSMIT_CHUNK TransmitChunk,
ULONG CapturedByteCount,
PSMSCIR_TX_FIFO_DATA *TxFifoData
) {
/*++
Routine Description.
This routine takes the RLC data that is sent from the user
mode app and turns it into data that can be pushed out to
our TX FIFO
Arguments:
DeviceData - Our device extension
TxFifoData - On successful return contains a PSMSCIR_TX_FIFO_DATA
that describes the RLC data in TransmitChunk in terms
of the CIR device
--*/
ULONG_PTR i;
ULONG_PTR rlcPackets;
LONG numSamplesThisPacket;
LONG rlcSample;
UCHAR fifoByte = 0;
ULONG bitPos = 0;
ULONG bytesInFifo = 0;
UCHAR on;
PLONG rlcDataPtr;
ULONG fifoBufferSize;
PSMSCIR_TX_FIFO_DATA txFifoData;
ULONG paddingRequired;
if (CapturedByteCount < sizeof(LONG)) {
//
// Bad buffer.
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmitBuildFifoData: Invalid byte count."));
return STATUS_BUFFER_TOO_SMALL;
}
//
// RLC samples are stored in LONGs by the caller.
//
rlcPackets = CapturedByteCount / sizeof(LONG);
//
// Need a LONG pointer to the data...
//
rlcDataPtr = (PLONG)&TransmitChunk->Data[0];
//
// First loop through and compute the required
// FIFO buffer size...This is suboptimal, but
// is rquired in order to figure out how many
// FIFO bytes this transfer is going to require
// (and we're choosing to convert the entire buffer
// up front instead of in pieces as we process in
// order to spend less time at IRQL > PASSIVE_LEVEL -
// if we didn't do this now we'd be doing it in our
// DPC or ISR as we blast)
//
fifoBufferSize = 0;
for (i = 0; i < rlcPackets; i++) {
//
// Get the RLC sample...
//
rlcSample = rlcDataPtr[i];
if (rlcSample < 0) {
//
// Get the sign right.
//
rlcSample = -rlcSample;
}
//
// Now add it to the overall buffer size. We'll
// div this total by IR_SAMPLE_PERIOD when we're done
//
fifoBufferSize += rlcSample;
}
if (fifoBufferSize < IR_SAMPLE_PERIOD) {
//
// Bad data buffer...
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmitBuildFifoData: User buffer contained no samples."));
return STATUS_INVALID_USER_BUFFER;
}
//
// fifoBufferSize now contains the number of individual samples
// * IR_SAMPLE_PERIOD, so div it out. Note that we won't
// need all of this buffer since we'll be packing the bits in
// as we go. However, we're going to take the hit of overallocating
// instead of the perf hit of calculating the exact size twice (once
// to figure out how big it needs to be, then again to build it)
//
fifoBufferSize = (fifoBufferSize / IR_SAMPLE_PERIOD);
//
// Due to the way we configure the device, We always
// need to blast in multiples of SMSCIR_FIFO_SIZE
// pieces. Pad this buffer so we can round up later
//
txFifoData = (PSMSCIR_TX_FIFO_DATA)
ExAllocatePoolWithTag(
NonPagedPool,
fifoBufferSize+sizeof(SMSCIR_TX_FIFO_DATA)+SMSCIR_FIFO_SIZE,
'DFxT');
if (!txFifoData) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmitBuildFifoData: Cannot allocate %d bytes of memory.",
fifoBufferSize+sizeof(SMSCIR_TX_FIFO_DATA)+SMSCIR_FIFO_SIZE));
return STATUS_INSUFFICIENT_RESOURCES;
}
txFifoData->CurrentOffset = 0;
txFifoData->RepeatCount = (ULONG)TransmitChunk->RepeatCount;
txFifoData->TimesRepeated = 0;
//
// *****NOTE*****
//
// We have to be extra careful here because the user
// could have already changed the data buffer supplied
// with the transfer (the TransmitChunk is described
// via DIRECT_IO).
//
// All we're going to do is build the FIFO buffer
// with the data as it is at this moment up to
// fifoBufferSize bytes.
//
// *****NOTE*****
//
//
// Now go through and REALLY build the buffer. We'll need
// one bit per sample, and the LSBit of one byte is the
// continuation of the MSBit of the previous byte
//
for (i = 0; i < rlcPackets; i++) {
//
// Get the number of samples in the RLC packet.
//
numSamplesThisPacket = rlcDataPtr[i];
if (numSamplesThisPacket < 0) {
//
// Indicates an off, or "dark", period in the sample,
//
//
// Get the sign right.
//
numSamplesThisPacket = -numSamplesThisPacket;
on = FALSE;
} else {
//
// Indicates an on, or "light", period in the sample,
//
on = TRUE;
}
//
// We now have a positive number of 50usec RLC samples.
// We div by 50 to get the number of samples,
// and then we need to build UCHARs containing
// one bit per 50usc sample to send to the transmit
// FIFO on the device
//
numSamplesThisPacket /= IR_SAMPLE_PERIOD;
while (numSamplesThisPacket > 0) {
//
// Fill in as many of the high bits as possible,
// starting at whatever position we are in the
// overall byte
//
if (on) {
fifoByte &= ~(0xFF << bitPos);
} else {
fifoByte |= (0xFF << bitPos);
}
if ((numSamplesThisPacket + bitPos) < 8) {
//
// We didn't completely fill this
// byte yet but we're done with the
// sample (e.g. this was the first piece
// of the sample and it was ON for 1, so
// we have 7 bits remaining in the byte)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -