📄 dcampkt.c
字号:
Routine Description:
Returns the information of all streams that are supported by the driver
Arguments:
Srb - Pointer to Stream request block
Return Value:
Nothing
--*/
{
//
// pick up the pointer to the stream information data structure
//
PIRB pIrb;
PHW_STREAM_HEADER StreamHeader = &(Srb->CommandData.StreamBuffer->StreamHeader);
PDCAM_EXTENSION pDevExt = (PDCAM_EXTENSION) Srb->HwDeviceExtension;
PHW_STREAM_INFORMATION StreamInfo = &(Srb->CommandData.StreamBuffer->StreamInfo);
PAGED_CODE();
pIrb = (PIRB) Srb->SRBExtension;
//
// set number of streams
//
ASSERT (Srb->NumberOfBytesToTransfer >=
sizeof (HW_STREAM_HEADER) +
sizeof (HW_STREAM_INFORMATION));
//
// initialize stream header
//
RtlZeroMemory(StreamHeader,
sizeof (HW_STREAM_HEADER) +
sizeof (HW_STREAM_INFORMATION));
//
// initialize the number of streams supported
//
StreamHeader->NumberOfStreams = 1;
StreamHeader->SizeOfHwStreamInformation = sizeof(HW_STREAM_INFORMATION);
//
// set the device property info
//
StreamHeader->NumDevPropArrayEntries = pDevExt->ulPropSetSupported;
StreamHeader->DevicePropertiesArray = &pDevExt->VideoProcAmpSet;
//
// Initialize the stream structure.
//
// Number of instances field indicates the number of concurrent streams
// of this type the device can support.
//
StreamInfo->NumberOfPossibleInstances = 1;
//
// indicates the direction of data flow for this stream, relative to
// the driver
//
StreamInfo->DataFlow = KSPIN_DATAFLOW_OUT;
//
// dataAccessible - Indicates whether the data is "seen" by the host
// processor.
//
StreamInfo->DataAccessible = TRUE;
//
// Return number of formats and the table.
// These information is collected dynamically.
//
StreamInfo->NumberOfFormatArrayEntries = pDevExt->ModeSupported;
StreamInfo->StreamFormatsArray = &pDevExt->DCamStrmModes[0];
//
// set the property information for the video stream
//
StreamInfo->NumStreamPropArrayEntries = NUMBER_VIDEO_STREAM_PROPERTIES;
StreamInfo->StreamPropertiesArray = (PKSPROPERTY_SET) VideoStreamProperties;
//
// set the pin name and category
//
StreamInfo->Name = (GUID *) &PINNAME_VIDEO_CAPTURE;
StreamInfo->Category = (GUID *) &PINNAME_VIDEO_CAPTURE;
//
// store a pointer to the topology for the device
//
Srb->CommandData.StreamBuffer->StreamHeader.Topology = &Topology;
//
// indicate success
//
Srb->Status = STATUS_SUCCESS;
DbgMsg2(("\'DCamGetStreamInfo: NumFormat %d, StreamFormatArray %x\n",
StreamInfo->NumberOfFormatArrayEntries, StreamInfo->StreamFormatsArray));
}
#define TIME_ROUNDING 1000 // Give it some rounding error of 100microsec
#define TIME_0750FPS (1333333+TIME_ROUNDING) // 1/7.50 * 10,000,000 (unit=100ns)
#define TIME_1500FPS (666666+TIME_ROUNDING) // 1/15.0 * 10,000,000 (unit=100ns) do not round to 666667
#define TIME_3000FPS (333333+TIME_ROUNDING) // 1/30.0 * 10,000,000 (unit=100ns)
NTSTATUS
DCamAllocateIsochResource(
PDCAM_EXTENSION pDevExt,
PIRB Irb,
BOOL bAllocateResource
)
{
PIRP Irp;
CCHAR StackSize;
ULONG ModeIndex;
PSTREAMEX pStrmEx;
DWORD dwAvgTimePerFrame, dwCompression;
ULONG fulSpeed;
NTSTATUS Status = STATUS_SUCCESS;
ASSERT(pDevExt);
pStrmEx = (PSTREAMEX) pDevExt->pStrmEx;
ASSERT(pStrmEx);
DbgMsg2(("\'DCamAllocateIsochResource: enter; pStrmEx %x; pVideoInfo %x\n", pStrmEx, pStrmEx->pVideoInfoHeader));
//
// Now if they're on a YUV4:2:2 format, we've gotta check what
// resolution they want it at, since we support this format
// but in two different resolutions (modes on the camera).
//
// This is the INDEX to the frame rate and resource allocation; see IsochInfoTable.
// 0 : reserved
// 1 : 3.75
// 2 : 7.5
// 3 : 15 (DEFAULT_FRAME_RATE)
// 4 : 30
// 5 : 60 (Not supported for Mode 1 & 3)
dwAvgTimePerFrame = (DWORD) pStrmEx->pVideoInfoHeader->AvgTimePerFrame;
dwCompression = (DWORD) pStrmEx->pVideoInfoHeader->bmiHeader.biCompression;
// Determine the Frame rate
if (dwAvgTimePerFrame > TIME_0750FPS)
pDevExt->FrameRate = 1; // 3.75FPS
else if (dwAvgTimePerFrame > TIME_1500FPS)
pDevExt->FrameRate = 2; // 7.5FPS
else if (dwAvgTimePerFrame > TIME_3000FPS)
pDevExt->FrameRate = 3; // 15 FPS
else
pDevExt->FrameRate = 4; // 30 FPS
DbgMsg2(("\'DCamAllocateIsochResource: FrameRate: %d FPS\n", (1 << (pDevExt->FrameRate-1)) * 15 / 4));
// Determine the Video Mode
switch(dwCompression) {
#ifdef SUPPORT_YUV444
case FOURCC_Y444: // Mode 0
ModeIndex = VMODE0_YUV444;
break;
#endif
case FOURCC_UYVY: // Mode 1 or 3
if (pStrmEx->pVideoInfoHeader->bmiHeader.biWidth == 640 &&
(pStrmEx->pVideoInfoHeader->bmiHeader.biHeight == 480 ||
pStrmEx->pVideoInfoHeader->bmiHeader.biHeight == -480)) {
ModeIndex = VMODE3_YUV422;
// Max frame rate is 15
if(pDevExt->FrameRate > 3)
pDevExt->FrameRate = 3;
} else
ModeIndex = VMODE1_YUV422;
break;
#ifdef SUPPORT_YUV411
case FOURCC_Y411: // Mode 2
ModeIndex = VMODE2_YUV411;
break;
#endif
#ifdef SUPPORT_RGB24
case KS_BI_RGB: // = 0
ModeIndex = VMODE4_RGB24;
// Max frame rate is 15
if(pDevExt->FrameRate > 3)
pDevExt->FrameRate = 3;
break;
#endif
#ifdef SUPPORT_YUV800
case FOURCC_Y800:
ModeIndex = VMODE5_YUV800;
break;
#endif
default:
Status = STATUS_NOT_IMPLEMENTED;;
return Status;;
}
DbgMsg1(("\'DCamAllocateIsochResource: ModeIndex=%d, AvgTimePerFrame=%d, FrameRate=%d\n",
ModeIndex, dwAvgTimePerFrame, pDevExt->FrameRate));
//
// Get an Irp so we can send some allocation commands down
//
StackSize = pDevExt->BusDeviceObject->StackSize;
Irp = IoAllocateIrp(StackSize, FALSE);
if (!Irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Calculate the index to use to reference the ISOCH table
//
pStrmEx->idxIsochTable = ModeIndex * NUM_POSSIBLE_RATES + pDevExt->FrameRate;
ASSERT(pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage == IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize);
DbgMsg2(("\'DCamAllocateIsochResource: ModeIndex=%d, idxIsochTable=%d, biSizeImage=%d, CompletePictureSize=%d\n",
ModeIndex, pStrmEx->idxIsochTable, pStrmEx->pVideoInfoHeader->bmiHeader.biSizeImage, IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize));
//
// 0. Determine the MAX_SPEED and not use the speed defined in the static table.
//
Irb->FunctionNumber = REQUEST_GET_SPEED_BETWEEN_DEVICES;
Irb->Flags = 0;
Irb->u.GetMaxSpeedBetweenDevices.fulFlags = USE_LOCAL_NODE;
Irb->u.GetMaxSpeedBetweenDevices.ulNumberOfDestinations = 0;
Status = DCamSubmitIrpSynch(pDevExt, Irp, Irb);
if(Status) {
ERROR_LOG(("\'DCamAllocateIsochResource: Error %x while trying to get maximun speed between devices.\n", Status));
IoFreeIrp(Irp);
return STATUS_INSUFFICIENT_RESOURCES;
}
fulSpeed = Irb->u.GetMaxSpeedBetweenDevices.fulSpeed;
//
// The max speed between devices should be within supported speed range, and
// must be equal or greater than the required speed for the chosen format.
//
if(
( fulSpeed != SPEED_FLAGS_100
&& fulSpeed != SPEED_FLAGS_200
&& fulSpeed != SPEED_FLAGS_400
)
|| fulSpeed < IsochInfoTable[pStrmEx->idxIsochTable].SpeedRequired
) {
ASSERT(fulSpeed == SPEED_FLAGS_100 || fulSpeed == SPEED_FLAGS_200 || fulSpeed == SPEED_FLAGS_400);
ASSERT(fulSpeed >= IsochInfoTable[pStrmEx->idxIsochTable].SpeedRequired);
IoFreeIrp(Irp);
return STATUS_UNSUCCESSFUL;
}
pDevExt->SpeedCode = fulSpeed >> 1; // Safe for S100, 200 and 400 (is checked above).
DbgMsg2(("\'GetMaxSpeedBetweenDevices.fulSpeed=%x; SpeedCode:%x\n", fulSpeed, pDevExt->SpeedCode));
//
// 1. Allocate CHANNEL
// First try to re-allocate the same channel
// If it is used, try to get any channel. 1394DCam can only be on channel 0..15
//
Irb->FunctionNumber = REQUEST_ISOCH_ALLOCATE_CHANNEL;
Irb->Flags = 0;
//
// ULONG nRequestedChannel; // Need a specific channel
// ULONG Channel; // Returned channel
// LARGE_INTEGER ChannelsAvailable; // Channels available
// Instead of hardcoded '0'; use -1 to ask the bus driver to get the next available channel for us.
// -1 (any channel) or an existing channel
Irb->u.IsochAllocateChannel.nRequestedChannel = pDevExt->IsochChannel;
Status = DCamSubmitIrpSynch(pDevExt, Irp, Irb);
if(Status) {
//
// Due to channel change,
// all Pending read will be either resubmitted,
// or cancelled (if out of resource).
//
pDevExt->bStopIsochCallback = TRUE; // Set back to FALSE after pending buffer are attached.
//
// If this is an initial request and no channel available,
// free all resource and abort.
//
if(pDevExt->IsochChannel == ISOCH_ANY_CHANNEL)
goto NoResource_abort;
DbgMsg1(("DCamAllocateIsochResource: last allocated channel %d is not available; pending count %d.\n",
pDevExt->IsochChannel, pDevExt->PendingReadCount));
// Try gettting any channel.
Irb->FunctionNumber = REQUEST_ISOCH_ALLOCATE_CHANNEL;
Irb->Flags = 0;
Irb->u.IsochAllocateChannel.nRequestedChannel = ISOCH_ANY_CHANNEL;
Status = DCamSubmitIrpSynch(pDevExt, Irp, Irb);
if(Status) {
ERROR_LOG(("DCamAllocateIsochResource: allocate any channel failed, status %x!\n", Status));
goto NoResource_abort;
}
//
// Channel changed, we MUST reallocate resource.
// The "stale" resrouce will be free later when
// pending packet are detached.
//
bAllocateResource = TRUE;
}
DbgMsg1(("**IsochAlloc: Channel(Old) %d, requested %d, got %d, HiLo(0x%x:%x), PendingRead %d\n",
pDevExt->IsochChannel,
Irb->u.IsochAllocateChannel.nRequestedChannel,
Irb->u.IsochAllocateChannel.Channel,
Irb->u.IsochAllocateChannel.ChannelsAvailable.u.HighPart,
Irb->u.IsochAllocateChannel.ChannelsAvailable.u.LowPart,
pDevExt->PendingReadCount));
// New channel
pDevExt->IsochChannel = Irb->u.IsochAllocateChannel.Channel; // Used in allocating iso. resource and reallocation
//
// 2. Allocate BANDWIDTH
//
Irb->FunctionNumber = REQUEST_ISOCH_ALLOCATE_BANDWIDTH;
Irb->Flags = 0;
Irb->u.IsochAllocateBandwidth.nMaxBytesPerFrameRequested = IsochInfoTable[pStrmEx->idxIsochTable].QuadletPayloadPerPacket << 2;
Irb->u.IsochAllocateBandwidth.fulSpeed = fulSpeed;
Irb->u.IsochAllocateBandwidth.hBandwidth = 0;
Status = DCamSubmitIrpSynch(pDevExt, Irp, Irb);
if(Status) {
ERROR_LOG(("DCamAllocateIsochResource: Error %x while trying to allocate Isoch bandwidth\n", Status));
goto NoResource_abort;
}
pDevExt->hBandwidth = Irb->u.IsochAllocateBandwidth.hBandwidth;
DbgMsg2(("**IsochAlloc: nMaxBytesPerFrameRequested %d, fulSpeed %d; hBandWidth 0x%x\n",
IsochInfoTable[pStrmEx->idxIsochTable].QuadletPayloadPerPacket << 2, fulSpeed, pDevExt->hBandwidth));
//
// 3. Allocate RESOURCES
// Note: after a bus reset, we need not free and re-allocate this resoruce again.
//
if(bAllocateResource) {
Irb->FunctionNumber = REQUEST_ISOCH_ALLOCATE_RESOURCES;
Irb->Flags = 0;
Irb->u.IsochAllocateResources.fulSpeed = fulSpeed;
Irb->u.IsochAllocateResources.nChannel = pDevExt->IsochChannel;
Irb->u.IsochAllocateResources.nMaxBytesPerFrame = IsochInfoTable[pStrmEx->idxIsochTable].QuadletPayloadPerPacket << 2;
// For slower frame rate use smaller quadlets
// smaller frame size will use more packet to fill the same amount of data
// this is why smaller frame rate actually demand more resource !!
Irb->u.IsochAllocateResources.nNumberOfBuffers = MAX_BUFFERS_SUPPLIED + 1; // "+1" as a "safety"
Irb->u.IsochAllocateResources.nMaxBufferSize = IsochInfoTable[pStrmEx->idxIsochTable].CompletePictureSize;
if (pDevExt->HostControllerInfomation.HostCapabilities & HOST_INFO_SUPPORTS_RETURNING_ISO_HDR) {
Irb->u.IsochAllocateResources.nQuadletsToStrip = 1;
Irb->u.IsochAllocateResources.fulFlags = RESOURCE_USED_IN_LISTENING | RESOURCE_STRIP_ADDITIONAL_QUADLETS;
} else {
Irb->u.IsochAllocateResources.nQuadletsToStrip = 0;
Irb->u.IsochAllocateResources.fulFlags = RESOURCE_USED_IN_LISTENING;
}
Irb->u.IsochAllocateResources.hResource = 0;
DbgMsg2(("\'DCamAllocateIsochResource: fullSpeed(%d), nMaxBytesPerFrame(%d), nMaxBufferSize(%d)\n",
Irb->u.IsochAllocateResources.fulSpeed,
Irb->u.IsochAllocateResources.nMaxBytesPerFrame,
Irb->u.IsochAllocateResources.nMaxBufferSize));
Status = DCamSubmitIrpSynch(pDevExt, Irp, Irb);
if(Status) {
ERROR_LOG(("DCamAllocateIsochResource: Error %x while trying to allocate Isoch resources\n", Status));
goto NoResource_abort;
}
pDevExt->hResource = Irb->u.IsochAllocateResources.hResource;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -