📄 io.c
字号:
// Setup the caller's buffer...
//
callersBuffer = (PUCHAR)&receiveParams->Data[0];
KeAcquireSpinLock(&DeviceData->PriorityReceiver.ListSpinLock, &oldIrql);
//
// If we don't have a current PRIORITY IR receive, set this up
// to be it...
//
if (DeviceData->PriorityReceiver.CurrentIrReceiveRequest == NULL) {
//
// Any data out there?
//
amountData = SmscIrDequeueRLCData(&DeviceData->PriorityReceiver,
callersBuffer,
capturedByteCount,
&dataEnd);
if (dataEnd ||
(amountData == capturedByteCount)){
//
// Filled the user's buffer already or we copied up to
// a data end event. Complete the request.
//
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: Data was waiting. Completing request."));
KeReleaseSpinLock(&DeviceData->PriorityReceiver.ListSpinLock,
oldIrql);
//
// Get the IO_STATUS_BLOCK for the underlying IRP. This is
// ehere we'll be filling in the number of bytes
// transferred.
//
ioStatus = &WdfRequestWdmGetIrp(Request)->IoStatus;
ioStatus->Information
= FIELD_OFFSET(IR_PRIORITY_RECEIVE_PARAMS, Data) + amountData;
receiveParams->DataEnd = dataEnd;
WdfRequestComplete(Request, STATUS_SUCCESS);
return;
}
//
// Otherwise we're out of here, we'll complete the
// request when we see all of the data.
//
DeviceData->PriorityReceiver.CurrentIrReceiveRequest = Request;
DeviceData->PriorityReceiver.ReceiveBuffer = callersBuffer;
DeviceData->PriorityReceiver.ReceiveBufferSize = capturedByteCount;
DeviceData->PriorityReceiver.ReceiveCurrentOffset = amountData;
DeviceData->PriorityReceiver.PriorityReceiveParams = receiveParams;
//
// This request is going to hang out there, and may stay
// there indefinitely. We need to be able to cancel this
// request if the user wants to disable the device,
// so we need a cancel routine...
//
WdfRequestMarkCancelable(Request, IrPriorityReceiveInProgressCancel);
} else {
//
// Put the request in the queue.
//
status = WdfRequestForwardToIoQueue(
Request,
DeviceData->PriorityReceiver.PendingReceiveQueue);
if(!NT_SUCCESS(status)) {
KeReleaseSpinLock(&DeviceData->PriorityReceiver.ListSpinLock,
oldIrql);
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceive: WdfRequestForwardToIoQueue failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
}
KeReleaseSpinLock(&DeviceData->PriorityReceiver.ListSpinLock, oldIrql);
return;
}
VOID
IrPriorityReceiveInProgressCancel(
IN WDFREQUEST Request
) {
/*++
Routine Description.
Cancel routine set for the in progress
PRIORITY receive request.
Arguments:
Request - An IOCTL_IR_PRIORITY_RECEIVE request
--*/
PSMSCIR_DATA deviceData;
WDFQUEUE ioQueue;
KIRQL oldIrql;
BOOLEAN completeRequest;
WDFREQUEST failedRequest = NULL;
NTSTATUS status;
NTSTATUS failureStatus;
ioQueue = WdfRequestGetIoQueue(Request);
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrReceiveInProgressCancel: Entered"));
deviceData = (PSMSCIR_DATA)GetIrData(WdfIoQueueGetDevice(ioQueue));
KeAcquireSpinLock(&deviceData->PriorityReceiver.ListSpinLock, &oldIrql);
//
// We're here first. NULL out the current request
// in the extension - the completion side will never
// see this request.
//
deviceData->PriorityReceiver.CurrentIrReceiveRequest = NULL;
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceiveInProgressCancel: Priority Request 0x%p is "\
"the currently active receive request.",
Request));
//
// Need to get the next request active.
//
status = IrSetupNextRequest(&deviceData->PriorityReceiver,
&failedRequest,
&failureStatus);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_RECEIVE_INFO,
("IrPriorityReceiveInProgressCancel: IrSetupNextRequest "\
"failed - 0x%x", status));
}
KeReleaseSpinLock(&deviceData->PriorityReceiver.ListSpinLock, oldIrql);
WdfRequestComplete(Request, STATUS_CANCELLED);
if (failedRequest) {
WdfRequestComplete(failedRequest, failureStatus);
}
SmscIrTracePrint(
TRACE_LEVEL_VERBOSE,
SMSCDBG_IOCTL_INFO,
("IrReceiveInProgressCancel: Exited"));
}
VOID
IrTransmit(
PSMSCIR_DATA DeviceData,
WDFREQUEST Request,
SIZE_T OutputBufferLength,
SIZE_T InputBufferLength
) {
/*++
Routine Description.
Transmits the given IR stream on the given port(s) at the given
carrier frequency.
On legacy devices, this maintains the pre-existing carrier
frequency, port masks, and sample period values. (ie. it gets the old
values, changes them, transmits, and then changes them back)
This IOCTL is synchronous. It does not return until the IR has actually
been transmitted.
Arguments:
DeviceData - Our device extension
Request - An IOCTL_IR_TRANSMIT request
OutputBufferLength - Size of a variable length IR_TRANSMIT_CHUNK structure
InputBufferLength - Size of an IR_TRANSMIT_PARAMS structure
--*/
NTSTATUS status = STATUS_SUCCESS;
KIRQL oldIrql;
PIR_TRANSMIT_PARAMS transmitParams;
PIR_TRANSMIT_CHUNK transmitChunk;
ULONG_PTR transmitMaxAddress;
ULONG frequencyKHz;
ULONG carrierDivider = 0;
ULONG capturedCarrierPeriod;
ULONG capturedRepeatCount;
ULONG_PTR capturedNextOffset;
ULONG capturedByteCount;
UCHAR capturedTxPorts;
BIRCC2_TX_CHANNEL_ENABLES txEnables;
BIRCC2_LINE_CONTROL lineControl;
BIRCC2_MASTER_BLOCK_CONTROL mbc;
PSMSCIR_TX_FIFO_DATA txFifoData = NULL;
WDFREQUEST requestToComplete;
NTSTATUS requestStatus;
UNREFERENCED_PARAMETER(InputBufferLength);
if (OutputBufferLength < sizeof(IR_TRANSMIT_CHUNK)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: Output buffer too small, must be at least "\
"0x%x bytes", sizeof(IR_TRANSMIT_CHUNK)));
WdfRequestWdmGetIrp(Request)->IoStatus.Status
= STATUS_BUFFER_TOO_SMALL;
WdfRequestCompleteWithInformation(Request, STATUS_BUFFER_TOO_SMALL,
sizeof(IR_TRANSMIT_CHUNK));
return;
}
status = WdfRequestRetrieveOutputBuffer(Request,
OutputBufferLength,
&transmitChunk,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: WdfRequestRetrieveOutputBuffer failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
//
// The data structure contains byte counts and offsets.
// Calculate the largest possible address that we can
// use when walking this data structure to ensure
// we don't walk all over memory we don't have access
// too
//
transmitMaxAddress = ((ULONG_PTR)transmitChunk + OutputBufferLength);
status = WdfRequestRetrieveInputBuffer(Request,
sizeof(IR_TRANSMIT_PARAMS),
&transmitParams,
NULL);
if (!NT_SUCCESS(status)) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: WdfRequestRetrieveInputBuffer failed - 0x%x",
status));
WdfRequestComplete(Request, status);
return;
}
capturedCarrierPeriod = (ULONG)transmitParams->CarrierPeriod;
if (capturedCarrierPeriod == 0) {
if (transmitParams->Flags & TRANSMIT_FLAGS_DC_MODE) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: Device does not support DC mode"));
WdfRequestComplete(Request, STATUS_INVALID_DEVICE_REQUEST);
return;
}
ASSERT(transmitParams->Flags & TRANSMIT_FLAGS_PULSE_MODE);
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("IrTransmit: Pulse mode support not available"));
WdfRequestComplete(Request, STATUS_NOT_IMPLEMENTED);
return;
} else {
//
// We've been given the carrier period for the device
// in usecs.
//
//
// Calculate the frequency in Hz to keep things integral
//
frequencyKHz
= SMSCIR_USEC_P_TO_KHZ_F(capturedCarrierPeriod);
//
// And turn the value into something for our CFD register (see
// section 2.1.1 in the CIRCC2 data book)
//
//
// Beware an obscenely large period from an unsavory user.
//
if (frequencyKHz != 0) {
carrierDivider = SMSCIR_KHZ_TO_CFD(frequencyKHz);
}
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("IrTransmit: Blasting will occur at %dKHz",
frequencyKHz));
if (carrierDivider == 0 ||
carrierDivider > UCHAR_MAX) {
SmscIrTracePrint(
TRACE_LEVEL_ERROR,
SMSCDBG_TRANSMIT_INFO,
("Frequency divider result out of range (%d), "\
"Defaulting to %d",
carrierDivider, SMSCIR_RC6_CARRIER_DIVIDER));
}
}
//
// Figure out which emitters this request is going
// out on.
//
// Note that we only have 4 emitter jacks, so only
// look at the botton four bits
//
capturedTxPorts = (UCHAR)(transmitParams->TransmitPortMask & 0xF);
//
// Write out the emitters we're using
//
SmscIrTracePrint(
TRACE_LEVEL_INFORMATION,
SMSCDBG_IOCTL_INFO,
("IrTransmit: Blasting on port mask 0x%x", capturedTxPorts));
//
// Need to modify registers, so we need the lock.
// The registers on this device use a windowing
// scheme, so we always need the lock to avoid
// banging into someone else.
//
WdfInterruptAcquireLock(DeviceData->Interrupt);
//
// Disable interrupts.
//
mbc.AsUChar = 0;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MASTER_BLOCK_CONTROL_ADDR,
mbc.AsUChar);
//
// Reset the fifo
//
lineControl.AsUChar = 0;
lineControl.FifoReset = 1;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_LINE_CONTROL_ADDR,
lineControl.AsUChar);
//
// Write it out to the blaster mask
//
txEnables.AsUChar = capturedTxPorts;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_TX_CHANNEL_ENABLES_ADDR,
txEnables.AsUChar);
//
// Figure out if we need to modify the carrier settings
//
if (SMSCIR_RC6_CARRIER_DIVIDER != carrierDivider) {
//
// Indeed we do. Update it...
//
mbc.AsUChar = 0;
mbc.RegisterBlockSelect = 1;
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_MASTER_BLOCK_CONTROL_ADDR,
mbc.AsUChar);
WRITE_TRANSMIT_UCHAR(DeviceData,
BIRCC2_CONSUMER_IR_CARRIER,
(UCHAR)carrierDivider);
}
//
// Re-enable interrupts on the device (this also puts
// us back to register block 0).
//
mbc.AsUChar = 0;
mbc.RegisterBlockSelect = 0;
mbc.MasterInterruptEnable = TRUE;
WRITE_TRANSMIT_UCHAR(DeviceData,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -