📄 io.c
字号:
//
// Remember our position in the byte so we
// can properly process the next sample
//
bitPos += numSamplesThisPacket;
break;
} else {
//
// We're finishing off a byte. May be leftover
// bits from a previous pass, so subtract our
// position from the total number of possible
// bits.
//
numSamplesThisPacket -= (8-bitPos);
//
// Put this byte in the FIFO.
//
txFifoData->FifoBuffer[bytesInFifo++] = fifoByte;
//
// Used all bits. Restart the position,
//
bitPos = 0;
if (bytesInFifo > fifoBufferSize) {
//
// This shouldn't happen: we've exhausted our
// previous overallocation of the user buffer.
//
// The only reason for this would be the user
// data buffer changing out from underneath us,
// so this is a user mode app problem.
//
ExFreePool(txFifoData);
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmitBuildFifoData: User data changed while "
"processing. Aborting TX"));
return STATUS_DATA_NOT_ACCEPTED;
}
}
}
}
if (bitPos) {
//
// If bit position isn't zero, then the last packet
// was short on filling up the byte. imagine ON for 8,
// OFF for 2 being the last two samples...We now have
// a partially empty packet that needs to have the upper
// bits stuffed.
//
// We'll deal with that here by padding the last byte with
// silence
//
fifoByte |= (0xFF << bitPos);
txFifoData->FifoBuffer[bytesInFifo++] = fifoByte;
}
//
// Add whatever silence we need at the end to make
// this SMSCIR_FIFO_SIZE aligned
//
paddingRequired
= (SMSCIR_FIFO_SIZE - (bytesInFifo & (SMSCIR_FIFO_SIZE-1)));
for (i = 0; i < paddingRequired; i++) {
txFifoData->FifoBuffer[bytesInFifo++] = 0xFF;
}
ASSERT((bytesInFifo % SMSCIR_FIFO_SIZE) == 0);
txFifoData->FifoBufferLength = bytesInFifo;
//
// Done building the buffer.
//
*TxFifoData = txFifoData;
return STATUS_SUCCESS;
}
VOID
IrGetDevCaps(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request,
SIZE_T OutputBufferLength
) {
/*++
Routine Description.
Returns device capabilities.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_GET_DEV_CAPS request
OutputBufferLength - sizeof(IR_DEV_CAPS)
--*/
PIR_DEV_CAPS devCaps;
NTSTATUS status;
UNREFERENCED_PARAMETER(DeviceData);
if (OutputBufferLength < sizeof(IR_DEV_CAPS)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrGetDevCaps: Buffer size must be at least 0x%x",
sizeof(IR_DEV_CAPS)));
WdfRequestWdmGetIrp(Request)->IoStatus.Status
= STATUS_BUFFER_TOO_SMALL;
WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_TOO_SMALL,
sizeof(IR_DEV_CAPS));
return;
}
status = WdfRequestRetrieveOutputBuffer(Request,
sizeof(IR_DEV_CAPS),
&devCaps,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("WdfRequestRetrieveOutputBuffer failed with Status code 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
//
// Fill in the capabilities based on what we just happen to "know"
// about out device
//
devCaps->ProtocolVersion = DEV_CAPS_PROTOCOL_VERSION;
devCaps->DevCapsFlags = 0;
devCaps->NumReceivePorts = DEVCAPS_NUM_RECEIVE_PORTS;
devCaps->LearningReceiverMask = DEVCAPS_LEARNING_MASK;
devCaps->NumTransmitPorts = DEVCAPS_TRANSMIT_PORTS;
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("IrGetDevCaps: Returning capabilities:"));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("\tProtocolVersion = %Id", devCaps->ProtocolVersion));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("\tDevCapsFlags = 0x%Ix", devCaps->DevCapsFlags));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("\tNumReceivePorts = %Id", devCaps->NumReceivePorts));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("\tLearningReceiverMask = 0x%Ix", devCaps->LearningReceiverMask));
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("\tNumTransmitPorts = %Id", devCaps->NumTransmitPorts));
WdfRequestCompleteWithInformation(Request, STATUS_SUCCESS,
sizeof(IR_DEV_CAPS));
}
VOID
IrUserOpen(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request
) {
/*++
Routine Description.
Called here by IRCLASS when our port FDO is indirectly
opened by a user opening the IRCLASS FDO.
This IOCTL is simply informational, IRCLASS will not
reject the open if this is failed.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_USER_OPEN request
--*/
UNREFERENCED_PARAMETER(DeviceData);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrUserOpen: Entered"));
//
// Just complete the request.
//
WdfRequestComplete(Request, STATUS_SUCCESS);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrUserOpen: Exited"));
return;
}
VOID
IrUserClose(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request
) {
/*++
Routine Description.
Called here by IRCLASS when our port FDO is indirectly
closed by a user closing its handle to the IRCLASS FDO.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_USER_CLOSE request
--*/
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrUserClose: Entered"));
//
// For closes, make sure that the user did us
// right and exited priority mode if he entered it.
// If he didn't, fix it for him...
//
if (DeviceData->InPriorityMode) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrUserClose: The application exited without exiting priority "\
"mode! Cleaning up"));
IrExitPriorityMode(DeviceData,
Request);
return;
}
//
// Otherwise just complete it...
//
WdfRequestComplete(Request, STATUS_SUCCESS);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrUserOpen: Exited"));
return;
}
VOID
IrEnterPriorityMode(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request,
SIZE_T InputBufferLength
) {
/*++
Routine Description.
This request is sent from a user mode application to prepare the port to
return priority IR data. While the device is in priority mode, all
IOCTL_IR_RECEIVE requests should be starved and IOCTL_IR_PRIORITY_RECEIVE
requests should be completed with RLC IR data.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_ENTER_PRIORITY_RECEIVE request
InputBufferLength - sizeof(IOCTL_IR_ENTER_PRIORITY_RECEIVE_PARAMS)
--*/
NTSTATUS status = STATUS_SUCCESS;
PIOCTL_IR_ENTER_PRIORITY_RECEIVE_PARAMS priorityModeParams = NULL;
ULONG numFFs;
ULONG localTimeoutInUSec;
MASTER_BLOCK_CONTROL mbc;
SCE_CONFIG_B configB;
LINE_CONTROL_B lcb;
LINE_CONTROL_A lca;
CONSUMER_IR_CTRL irCtrl;
KIRQL oldIrql;
WDFREQUEST successfulRequest = NULL;
WDFREQUEST failedRequest = NULL;
NTSTATUS failureStatus;
ULONG minusOne;
CARRIER_CAPTURE_CONTROL captureControl;
ULONG receiver;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: Entered"));
//
// Sorry buddy, can't help you if we're already in priority mode...
//
if (DeviceData->InPriorityMode) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: Device is already in priority mode. "\
"Failing ENTER_PRIORITY_RECEIVE"));
WdfRequestComplete(Request, STATUS_INVALID_DEVICE_STATE);
return;
}
if (InputBufferLength < sizeof(IOCTL_IR_ENTER_PRIORITY_RECEIVE_PARAMS)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: Buffer size must be at least 0x%x",
sizeof(IOCTL_IR_ENTER_PRIORITY_RECEIVE_PARAMS)));
WdfRequestWdmGetIrp(Request)->IoStatus.Status
= STATUS_BUFFER_TOO_SMALL;
WdfRequestCompleteWithInformation(
Request,
STATUS_BUFFER_TOO_SMALL,
sizeof(IOCTL_IR_ENTER_PRIORITY_RECEIVE_PARAMS));
return;
}
status = WdfRequestRetrieveInputBuffer(Request,
InputBufferLength,
&priorityModeParams,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: WdfRequestRetrieveInputBuffer failed "\
"with Status code 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
ASSERT(priorityModeParams);
//
// Get the receiver the caller wants to use
//
receiver = (ULONG)priorityModeParams->Receiver;
if (receiver > DEVCAPS_NUM_RECEIVE_PORTS) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: Receiver #%d invalid. Device only has %d "\
"receivers ", receiver, DEVCAPS_NUM_RECEIVE_PORTS));
WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
return;
}
//
// Figure out the number of FFs we need to see for a timeout.
// Any timeout less than 8 * 50usecs will be rounded up, but it
// prevents us from having to calculate RLC from within the ISR
// (which isn't an option anyway)
//
//
// Timeout is given in milliseconds....
//
localTimeoutInUSec = (ULONG)priorityModeParams->TimeOut * 1000;
if (!localTimeoutInUSec) {
//
// Invalid to not give some sort of timeout
//
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_IOCTL_INFO,
("IrEnterPriorityMode: Zero timeout supplied. Invalid."));
WdfRequestComplete(Request, STATUS_INVALID_PARAMETER);
return;
}
//
// Round it up to the next 50usec unit...
//
numFFs = (localTimeoutInUSec + (IR_SAMPLE_PERIOD-1)) & ~(IR_SAMPLE_PERIOD-1);
//
// And divide by 50usec...
//
numFFs = numFFs / IR_SAMPLE_PERIOD;
//
// Divide into number of FF bytes required for a data end...
//
numFFs = (numFFs/8);
if (numFFs != DeviceData->NumFFsForDataEnd) {
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -