Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1956 lines
62 KiB

/*++
Copyright (c) 1997 1998 PHILIPS I&C
Module Name: mcamdrv.c.c
Abstract: driver for the philips camera.
Author: Paul Oosterhof
Environment: Kernel mode only
Revision History:
Date Reason
Sept.22, 98 Optimized for NT5
Nov.30 , Frozen video frame for corrupted usb frames
Nov.30 , properties added to deliver VID/PID actual used camera to app
--*/
#include "mwarn.h"
#include "wdm.h"
#include "mcamdrv.h"
#include "strmini.h"
#include "mprpobj.h"
#include "mprpobjx.h"
#include "mprpftn.h"
#include "mcodec.h"
#include "mstreams.h"
#include "mssidef.h"
/*
* Local function definitions
*/
static USHORT
MapFrPeriodFrRate(LONGLONG llFramePeriod);
static NTSTATUS
PHILIPSCAM_SetFrRate_AltInterface(IN PVOID DeviceContext);
/*
Here the mapping is defined to alternate interfaces dependent from
picture format and framerate
*/
UCHAR InterfaceMap[9][10] = {
// Size
//Framerate // CIF, QCIF, SQCIF, QQCIF, VGA, SIF, SSIF, QSIF, SQSIF, SCIF
/* VGA */ { 0 , 0 , 0 , 0, 1, 0 , 0 , 0 , 0 , 0 },
/* 3.75 */ { 4 , 0 , 0 , 0, 0, 4 , 4 , 0 , 0 , 4 },
/* 5 */ { 7 , 8 , 8 , 8, 0, 7 , 7 , 8 , 8 , 7 },
/* 7.5 */ { 6 , 7 , 7 , 7, 0, 6 , 6 , 7 , 7 , 6 },
/* 10 */ { 4 , 6 , 7 , 7, 0, 4 , 4 , 6 , 7 , 4 },
/* 12 */ { 3 , 5 , 6 , 6, 0, 3 , 3 , 5 , 6 , 3 },
/* 15 */ { 2 , 4 , 5 , 5, 0, 2 , 2 , 4 , 5 , 2 },
/* 20 */ { 0 , 1 , 3 , 3, 0, 0 , 0 , 1 , 3 , 0 },
/* 24 */ { 0 , 1 , 3 , 3, 0, 0 , 0 , 1 , 3 , 0 },
};
//QCIF20 alt.intfc. 2 is sufficient, however 20Fr/sec is asked as default by PM;
//to enable the user to select as well 24Fr/sec, also alt.intfc. 1 is selected
//SQCIF20 alt.intfc. 4 is sufficient, however 20Fr/sec is asked as default by PM;
//to enable the user to select as well 24Fr/sec, also alt.intfc. 3 is selected
ULONG PHILIPSCAM_DebugTraceLevel
#ifdef MAX_DEBUG
= MAX_TRACE;
#else
= MIN_TRACE;
#endif
#ifndef mmioFOURCC
#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
( (DWORD)(BYTE)(ch0) | ( (DWORD)(BYTE)(ch1) << 8 ) | \
( (DWORD)(BYTE)(ch2) << 16 ) | ( (DWORD)(BYTE)(ch3) << 24 ) )
#endif
KSPIN_MEDIUM StandardMedium =
{
STATIC_KSMEDIUMSETID_Standard,
0, 0
};
// ------------------------------------------------------------------------
// Property sets for all video capture streams
// ------------------------------------------------------------------------
DEFINE_KSPROPERTY_TABLE(VideoStreamConnectionProperties)
{
DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_CONNECTION_ALLOCATORFRAMING,
TRUE, // GetSupported or Handler
sizeof(KSPROPERTY), // MinProperty
sizeof(KSALLOCATOR_FRAMING), // MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
sizeof(ULONG) // SerializedSize
),
};
DEFINE_KSPROPERTY_TABLE(VideoStreamDroppedFramesProperties)
{
DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_DROPPEDFRAMES_CURRENT,
TRUE, // GetSupported or Handler
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinProperty
sizeof(KSPROPERTY_DROPPEDFRAMES_CURRENT_S),// MinData
FALSE, // SetSupported or Handler
NULL, // Values
0, // RelationsCount
NULL, // Relations
NULL, // SupportHandler
0 // SerializedSize
),
};
// ------------------------------------------------------------------------
// Array of all of the property sets supported by video streams
// ------------------------------------------------------------------------
DEFINE_KSPROPERTY_SET_TABLE(VideoStreamProperties)
{
DEFINE_KSPROPERTY_SET
(
&KSPROPSETID_Connection, // Set
SIZEOF_ARRAY(VideoStreamConnectionProperties), // PropertiesCount
VideoStreamConnectionProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
),
DEFINE_KSPROPERTY_SET
(
&PROPSETID_VIDCAP_DROPPEDFRAMES, // Set
SIZEOF_ARRAY(VideoStreamDroppedFramesProperties), // PropertiesCount
VideoStreamDroppedFramesProperties, // PropertyItem
0, // FastIoCount
NULL // FastIoTable
),
};
#define NUMBER_VIDEO_STREAM_PROPERTIES (SIZEOF_ARRAY(VideoStreamProperties))
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QCIF_I420 = STREAMFORMAT_QCIF_I420 ;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_CIF_I420 = STREAMFORMAT_CIF_I420;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SQCIF_I420 = STREAMFORMAT_SQCIF_I420;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QQCIF_I420 = STREAMFORMAT_QQCIF_I420;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SIF_I420 = STREAMFORMAT_SIF_I420 ;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SSIF_I420 = STREAMFORMAT_SSIF_I420 ;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_QSIF_I420 = STREAMFORMAT_QSIF_I420 ;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SQSIF_I420 = STREAMFORMAT_SQSIF_I420 ;
KS_DATARANGE_VIDEO PHILIPSCAM_StreamFormat_SCIF_I420 = STREAMFORMAT_SCIF_I420 ;
static PKSDATAFORMAT PHILIPSCAM_MovingStreamFormats[]={
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QCIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_CIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SQCIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QQCIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SSIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_QSIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SQSIF_I420,
(PKSDATAFORMAT) &PHILIPSCAM_StreamFormat_SCIF_I420
};
#define NUM_PHILIPSCAM_STREAM_FORMATS (SIZEOF_ARRAY(PHILIPSCAM_MovingStreamFormats))
//---------------------------------------------------------------------------
// Create an array that holds the list of all of the streams supported
//---------------------------------------------------------------------------
HW_STREAM_INFORMATION Streams [] = {
// -----------------------------------------------------------------
// PHILIPSCAM_Moving_Stream
// -----------------------------------------------------------------
// HW_STREAM_INFORMATION -------------------------------------------
1, // NumberOfPossibleInstances
KSPIN_DATAFLOW_OUT, // DataFlow
TRUE, // DataAccessible
NUM_PHILIPSCAM_STREAM_FORMATS, // NumberOfFormatArrayEntries
PHILIPSCAM_MovingStreamFormats, // StreamFormatsArray
NULL, // ClassReserved[0]
NULL, // ClassReserved[1]
NULL, // ClassReserved[2]
NULL, // ClassReserved[3]
NUMBER_VIDEO_STREAM_PROPERTIES, // NumStreamPropArrayEntries
(PKSPROPERTY_SET) VideoStreamProperties,// StreamPropertiesArray
0, // NumStreamEventArrayEntries;
0, // StreamEventsArray;
(GUID *)&PINNAME_VIDEO_CAPTURE, // Category;
(GUID *)&PINNAME_VIDEO_CAPTURE, // Name;
0, // MediumsCount
&StandardMedium, // Mediums
FALSE, // BridgeStream
0, // Reserved[0]
0 // Reserved[1]
};
/*****************************************************************************/
/*****************************************************************************/
/************ Start of Function Blocks **********************/
/*****************************************************************************/
/*****************************************************************************/
/*
// This function searches the maximal framerate for a given picture format
// dependent from the USB bus load and selects the belonging alternate interface.
//
*/
NTSTATUS
PHILIPSCAM_SetFrRate_AltInterface(IN PVOID DeviceContext){
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
NTSTATUS ntStatus = STATUS_SUCCESS;
USHORT PhFormat = deviceContext->CamStatus.PictureFormat;
USHORT PhFrameRate = deviceContext->CamStatus.PictureFrameRate;
USHORT j;
// reset permitted framerates
for (j = FRRATEVGA; j <= FRRATE24; j++){
deviceContext->FrrSupported[j] = FALSE;
}
// set permitted framerates dependent on selected format and sensortype
switch (PhFormat) {
case FORMATCIF:
for ( j = FRRATE375 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATQCIF:
for ( j = FRRATE5 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATSQCIF:
for ( j = FRRATE5 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATQQCIF:
for ( j = FRRATE5 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATSIF:
for ( j = FRRATE375 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATSSIF:
for ( j = FRRATE375 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATQSIF:
for ( j = FRRATE5 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATSQSIF:
for ( j = FRRATE5 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
break;
case FORMATSCIF:
for ( j = FRRATE375 ; j <= PhFrameRate; j++){
deviceContext->FrrSupported[j] = TRUE;
}
default:
; // no permitted framerates;
}
// select framerate dependent on available USB bandwidth
ntStatus = STATUS_NOT_FOUND;
for ( PhFrameRate ;
(!NT_SUCCESS(ntStatus) && (PhFrameRate != FRRATEVGA));
PhFrameRate --) {
if (deviceContext->FrrSupported[PhFrameRate]){
if ( InterfaceMap[PhFrameRate][PhFormat] != 0 ){
deviceContext->Interface->AlternateSetting =
InterfaceMap[PhFrameRate][PhFormat];
ntStatus = USBCAMD_SelectAlternateInterface(
deviceContext,
deviceContext->Interface);
}
if (!NT_SUCCESS(ntStatus)){
deviceContext->FrrSupported[PhFrameRate]= FALSE;
}else{
PHILIPSCAM_KdPrint (MIN_TRACE, ("Alt Setting # %d, Max.allowed FPS %s\n",
InterfaceMap[PhFrameRate][PhFormat] , FRString(PhFrameRate)));
deviceContext->CamStatus.PictureFrameRate = PhFrameRate ;
}
}
}
return ntStatus;
}
/*
** AdapterCompareGUIDsAndFormatSize()
**
** Checks for a match on the three GUIDs and FormatSize
**
** Arguments:
**
** IN DataRange1
** IN DataRange2
**
** Returns:
**
** TRUE if all elements match
** FALSE if any are different
**
** Side Effects: none
*/
BOOLEAN
AdapterCompareGUIDsAndFormatSize(
IN PKSDATARANGE DataRange1,
IN PKSDATARANGE DataRange2)
{
return (
IsEqualGUID (
&DataRange1->MajorFormat,
&DataRange2->MajorFormat) &&
IsEqualGUID (
&DataRange1->SubFormat,
&DataRange2->SubFormat) &&
IsEqualGUID (
&DataRange1->Specifier,
&DataRange2->Specifier) &&
(DataRange1->FormatSize == DataRange2->FormatSize));
}
/*
** AdapterFormatFromRange()
**
** Returns a DATAFORMAT from a DATARANGE
**
** Arguments:
**
** IN PHW_STREAM_REQUEST_BLOCK pSrb
**
** Returns:
**
** STATUS_SUCCESS if format is supported
**
** Side Effects: none
*/
NTSTATUS
AdapterFormatFromRange(
IN PHW_STREAM_REQUEST_BLOCK Srb)
{
PSTREAM_DATA_INTERSECT_INFO intersectInfo;
PKSDATARANGE dataRange;
BOOL onlyWantsSize;
ULONG formatSize = 0;
ULONG streamNumber;
ULONG j;
ULONG numberOfFormatArrayEntries;
PKSDATAFORMAT *availableFormats;
NTSTATUS ntStatus = STATUS_NOT_FOUND;
intersectInfo = Srb->CommandData.IntersectInfo;
streamNumber = intersectInfo->StreamNumber;
dataRange = intersectInfo->DataRange;
//
// Check that the stream number is valid
//
// ASSERT(streamNumber == 0);
numberOfFormatArrayEntries = Streams[0].NumberOfFormatArrayEntries;
//
// Get the pointer to the array of available formats
//
availableFormats = Streams[0].StreamFormatsArray;
//
// Is the caller trying to get the format, or the size of the format?
//
onlyWantsSize =
(intersectInfo->SizeOfDataFormatBuffer == sizeof(ULONG));
//
// Walk the formats supported by the stream searching for a match
// of the three GUIDs which together define a DATARANGE
//
for (j = 0; j < numberOfFormatArrayEntries; j++, availableFormats++) {
if (!AdapterCompareGUIDsAndFormatSize(dataRange,
*availableFormats)) {
// not the format we want
continue;
}
//
// Now that the three GUIDs match, switch on the Specifier
// to do a further type specific check
//
// -------------------------------------------------------------------
// Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
// -------------------------------------------------------------------
if (IsEqualGUID (&dataRange->Specifier,
&KSDATAFORMAT_SPECIFIER_VIDEOINFO)) {
PKS_DATARANGE_VIDEO dataRangeVideoToVerify =
(PKS_DATARANGE_VIDEO) dataRange;
PKS_DATARANGE_VIDEO dataRangeVideo =
(PKS_DATARANGE_VIDEO) *availableFormats;
PKS_DATAFORMAT_VIDEOINFOHEADER DataFormatVideoInfoHeaderOut;
ULONG videoHeaderSize;
ULONG rangeSize;
//
// Check that the other fields match
//
if ((dataRangeVideoToVerify->bFixedSizeSamples !=
dataRangeVideo->bFixedSizeSamples) ||
(dataRangeVideoToVerify->bTemporalCompression !=
dataRangeVideo->bTemporalCompression) ||
(dataRangeVideoToVerify->StreamDescriptionFlags !=
dataRangeVideo->StreamDescriptionFlags) ||
(dataRangeVideoToVerify->MemoryAllocationFlags !=
dataRangeVideo->MemoryAllocationFlags) ||
(RtlCompareMemory (&dataRangeVideoToVerify->ConfigCaps,
&dataRangeVideo->ConfigCaps,
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS)) !=
sizeof (KS_VIDEO_STREAM_CONFIG_CAPS))) {
// not the format want
continue;
}
if ((dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biWidth !=
dataRangeVideo->VideoInfoHeader.bmiHeader.biWidth ) ||
(dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biHeight !=
dataRangeVideo->VideoInfoHeader.bmiHeader.biHeight )) {
continue;
}
// Validate each step of the size calculations for arithmetic overflow,
// and verify that the specified sizes correlate
// (with unsigned math, a+b < b iff an arithmetic overflow occured)
videoHeaderSize = dataRangeVideoToVerify->VideoInfoHeader.bmiHeader.biSize +
FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader);
rangeSize = videoHeaderSize +
FIELD_OFFSET(KS_DATARANGE_VIDEO,VideoInfoHeader);
if (videoHeaderSize < FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader) ||
rangeSize < FIELD_OFFSET(KS_DATARANGE_VIDEO,VideoInfoHeader) ||
rangeSize > dataRangeVideoToVerify->DataRange.FormatSize) {
Srb->Status = ntStatus = STATUS_INVALID_PARAMETER;
break;
}
formatSize = sizeof(KSDATAFORMAT) + videoHeaderSize;
if (onlyWantsSize) {
break;
}
// Is the return buffer size = 0 ?
if(intersectInfo->SizeOfDataFormatBuffer == 0) {
ntStatus = Srb->Status = STATUS_BUFFER_OVERFLOW;
// the proxy wants to know the actual buffer size to allocate.
Srb->ActualBytesTransferred = formatSize;
break;
}
// Caller wants the full data format, make sure we have room
if (intersectInfo->SizeOfDataFormatBuffer < formatSize) {
Srb->Status = ntStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
DataFormatVideoInfoHeaderOut =
(PKS_DATAFORMAT_VIDEOINFOHEADER) intersectInfo->DataFormatBuffer;
// Copy over the KSDATAFORMAT, followed by the
// actual VideoInfoHeader
RtlCopyMemory(
&DataFormatVideoInfoHeaderOut->DataFormat,
&dataRangeVideoToVerify->DataRange,
sizeof (KSDATARANGE));
DataFormatVideoInfoHeaderOut->DataFormat.FormatSize = formatSize;
RtlCopyMemory(
&DataFormatVideoInfoHeaderOut->VideoInfoHeader,
&dataRangeVideoToVerify->VideoInfoHeader,
videoHeaderSize);
// Calculate biSizeImage for this request, and put the result in both
// the biSizeImage field of the bmiHeader AND in the SampleSize field
// of the DataFormat.
//
// Note that for compressed sizes, this calculation will probably not
// be just width * height * bitdepth
DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader.biSizeImage =
DataFormatVideoInfoHeaderOut->DataFormat.SampleSize =
KS_DIBSIZE(DataFormatVideoInfoHeaderOut->VideoInfoHeader.bmiHeader);
//
// Perform other validation such as cropping and scaling checks
//
// we will not allow setting FPS below our minimum FPS.
if ((DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame >
dataRangeVideo->ConfigCaps.MaxFrameInterval) ) {
DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame =
dataRangeVideo->ConfigCaps.MaxFrameInterval;
DataFormatVideoInfoHeaderOut->VideoInfoHeader.dwBitRate =
dataRangeVideo->ConfigCaps.MinBitsPerSecond;
}
// we will not allow setting FPS above our maximum FPS.
if ((DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame <
dataRangeVideo->ConfigCaps.MinFrameInterval) ) {
DataFormatVideoInfoHeaderOut->VideoInfoHeader.AvgTimePerFrame =
dataRangeVideo->ConfigCaps.MinFrameInterval;
DataFormatVideoInfoHeaderOut->VideoInfoHeader.dwBitRate =
dataRangeVideo->ConfigCaps.MaxBitsPerSecond;
}
Srb->Status = ntStatus = STATUS_SUCCESS;
break;
}
} // End of loop on all formats for this stream
if (NT_SUCCESS(ntStatus)) {
if (onlyWantsSize) {
*(PULONG) intersectInfo->DataFormatBuffer = formatSize;
Srb->ActualBytesTransferred = sizeof(ULONG);
}else {
Srb->ActualBytesTransferred = formatSize;
}
}
return ntStatus;
}
/*
** AdapterVerifyFormat()
**
** Checks the validity of a format request by walking through the
** array of supported KSDATA_RANGEs for a given stream.
**
** Arguments:
**
** pKSDataFormat - pointer of a KS_DATAFORMAT_VIDEOINFOHEADER structure.
** StreamNumber - index of the stream being queried / opened.
**
** Returns:
**
** TRUE if the format is supported
** FALSE if the format cannot be suppored
**
** Side Effects: none
*/
BOOL
AdapterVerifyFormat(
PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormatToVerify,
int StreamNumber
)
{
PKSDATAFORMAT *pAvailableFormats;
int NumberOfFormatArrayEntries;
int j;
// Make sure a format has been specified
if (!pKSDataFormatToVerify)
{
return FALSE;
}
//
// Make sure the stream index is valid
//
if (StreamNumber >= 2 || StreamNumber < 0) {
return FALSE;
}
//
// How many formats does this stream support?
//
NumberOfFormatArrayEntries =
Streams[StreamNumber].NumberOfFormatArrayEntries;
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: Stream=%d\n",
StreamNumber));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: FormatSize=%d\n",
pKSDataFormatToVerify->DataFormat.FormatSize));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: MajorFormat=%x\n",
pKSDataFormatToVerify->DataFormat.MajorFormat));
//
// Get the pointer to the array of available formats
//
pAvailableFormats = Streams[StreamNumber].StreamFormatsArray;
//
// Walk the array, searching for a match
//
for (j = 0; j < NumberOfFormatArrayEntries; j++, pAvailableFormats++) {
PKS_DATARANGE_VIDEO pKSDataRange = (PKS_DATARANGE_VIDEO) *pAvailableFormats;
PKS_VIDEOINFOHEADER pVideoInfoHdr = &pKSDataRange->VideoInfoHeader;
KS_VIDEO_STREAM_CONFIG_CAPS *pConfigCaps = &pKSDataRange->ConfigCaps;
//
// Check for matching size, Major Type, Sub Type, and Specifier
//
if (!IsEqualGUID (&pKSDataRange->DataRange.MajorFormat,
&pKSDataFormatToVerify->DataFormat.MajorFormat)) {
continue;
}
if (!IsEqualGUID (&pKSDataRange->DataRange.SubFormat,
&pKSDataFormatToVerify->DataFormat.SubFormat)) {
continue;
}
if (!IsEqualGUID (&pKSDataRange->DataRange.Specifier,
&pKSDataFormatToVerify->DataFormat.Specifier)) {
continue;
}
// -------------------------------------------------------------------
// Specifier FORMAT_VideoInfo for VIDEOINFOHEADER
// -------------------------------------------------------------------
if (IsEqualGUID(&pKSDataRange->DataRange.Specifier, &KSDATAFORMAT_SPECIFIER_VIDEOINFO))
{
PKS_VIDEOINFOHEADER pVideoInfoHdrToVerify;
if (pKSDataFormatToVerify->DataFormat.FormatSize < sizeof(KS_DATAFORMAT_VIDEOINFOHEADER))
{
break; // considered a fatal error for this format
}
pVideoInfoHdrToVerify = &pKSDataFormatToVerify->VideoInfoHeader;
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: pVideoInfoHdrToVerify=%x\n",
pVideoInfoHdrToVerify));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: Width=%d Height=%d biBitCount=%d\n",
pVideoInfoHdrToVerify->bmiHeader.biWidth,
pVideoInfoHdrToVerify->bmiHeader.biHeight,
pVideoInfoHdrToVerify->bmiHeader.biBitCount));
PHILIPSCAM_KdPrint (MAX_TRACE, ("AdapterVerifyFormat: biSizeImage =%d\n",
pVideoInfoHdrToVerify->bmiHeader.biSizeImage));
// Calculate the actual format buffer size (includes bmiHeader.biSize).
// Validate each step of the size calculations for arithmetic overflow,
// and verify that the specified sizes correlate
// (with unsigned math, a+b < b iff an arithmetic overflow occured).
{
ULONG VideoHeaderSize = pVideoInfoHdrToVerify->bmiHeader.biSize +
FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader);
ULONG FormatSize = VideoHeaderSize +
FIELD_OFFSET(KS_DATAFORMAT_VIDEOINFOHEADER,VideoInfoHeader);
if (VideoHeaderSize < FIELD_OFFSET(KS_VIDEOINFOHEADER,bmiHeader) ||
FormatSize < FIELD_OFFSET(KS_DATAFORMAT_VIDEOINFOHEADER,VideoInfoHeader) ||
FormatSize > pKSDataFormatToVerify->DataFormat.FormatSize) {
break; // considered a fatal error for this format
}
}
if ((pVideoInfoHdrToVerify->bmiHeader.biWidth !=
pVideoInfoHdr->bmiHeader.biWidth ) ||
(pVideoInfoHdrToVerify->bmiHeader.biHeight !=
pVideoInfoHdr->bmiHeader.biHeight )) {
continue;
}
if ( pVideoInfoHdrToVerify->bmiHeader.biSizeImage !=
pVideoInfoHdr->bmiHeader.biSizeImage ||
pVideoInfoHdrToVerify->bmiHeader.biSizeImage >
pKSDataFormatToVerify->DataFormat.SampleSize) {
PHILIPSCAM_KdPrint (MIN_TRACE, ("***Error**:Format mismatch Width=%d Height=%d image size=%d\n",
pVideoInfoHdrToVerify->bmiHeader.biWidth,
pVideoInfoHdrToVerify->bmiHeader.biHeight,
pVideoInfoHdrToVerify->bmiHeader.biSizeImage));
continue;
}
//
// HOORAY, the format passed all of the tests, so we support it
//
return TRUE;
}
}
//
// The format requested didn't match any of our listed ranges,
// so refuse the connection.
//
return FALSE;
}
//
// hooks for stream SRBs
//
VOID STREAMAPI
PHILIPSCAM_ReceiveDataPacket(
IN PHW_STREAM_REQUEST_BLOCK Srb,
IN PVOID DeviceContext,
IN PBOOLEAN Completed
)
{
// PHILIPSCAM_KdPrint (MAX_TRACE, ("P*_ReceiveDataPacket\n"));
}
VOID STREAMAPI
PHILIPSCAM_ReceiveCtrlPacket(
IN PHW_STREAM_REQUEST_BLOCK Srb,
IN PVOID DeviceContext,
IN PBOOLEAN Completed
)
{
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("'PHILIPSCAM: Receive Ctrl SRB %x\n", Srb->Command));
*Completed = TRUE;
Srb->Status = STATUS_SUCCESS;
switch (Srb->Command) {
case SRB_PROPOSE_DATA_FORMAT:
PHILIPSCAM_KdPrint(MIN_TRACE, ("'Receiving SRB_PROPOSE_DATA_FORMAT SRB \n"));
if ( !(AdapterVerifyFormat (
(PKS_DATAFORMAT_VIDEOINFOHEADER)Srb->CommandData.OpenFormat,
Srb->StreamObject->StreamNumber))) {
Srb->Status = STATUS_NO_MATCH;
PHILIPSCAM_KdPrint(MIN_TRACE,("SRB_PROPOSE_DATA_FORMAT FAILED\n"));
}
break;
case SRB_SET_DATA_FORMAT:
{
PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormat =
(PKS_DATAFORMAT_VIDEOINFOHEADER) Srb->CommandData.OpenFormat;
PKS_VIDEOINFOHEADER pVideoInfoHdrRequested =
&pKSDataFormat->VideoInfoHeader;
PHILIPSCAM_KdPrint(MIN_TRACE, ("'SRB_SET_DATA_FORMAT\n"));
if ((AdapterVerifyFormat(pKSDataFormat,Srb->StreamObject->StreamNumber))) {
// if (deviceContext->UsbcamdInterface.USBCAMD_SetVideoFormat(DeviceContext,Srb)) {
// deviceContext->CurrentProperty.Format.lWidth =
// pVideoInfoHdrRequested->bmiHeader.biWidth;
// deviceContext->CurrentProperty.Format.lHeight =
// pVideoInfoHdrRequested->bmiHeader.biHeight;
// }
}else {
Srb->Status = STATUS_NO_MATCH;
PHILIPSCAM_KdPrint(MIN_TRACE,(" SRB_SET_DATA_FORMAT FAILED\n"));
}
}
break;
case SRB_GET_DATA_FORMAT:
PHILIPSCAM_KdPrint(MIN_TRACE, ("' SRB_GET_DATA_FORMAT\n"));
Srb->Status = STATUS_NOT_IMPLEMENTED;
break;
case SRB_SET_STREAM_STATE:
case SRB_GET_STREAM_STATE:
case SRB_GET_STREAM_PROPERTY:
case SRB_SET_STREAM_PROPERTY:
case SRB_INDICATE_MASTER_CLOCK:
default:
*Completed = FALSE; // let USBCAMD handle these control SRBs
}
if (*Completed == TRUE) {
StreamClassStreamNotification(StreamRequestComplete,Srb->StreamObject,Srb);
}
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_ReceiveCtrlPacket\n"));
}
// **
// Describe the camera
//
USBCAMD_DEVICE_DATA PHILIPSCAM_DeviceData = {
0,
PHILIPSCAM_Initialize,
PHILIPSCAM_UnInitialize,
PHILIPSCAM_ProcessUSBPacket,
PHILIPSCAM_NewFrame,
PHILIPSCAM_ProcessRawVideoFrame,
PHILIPSCAM_StartVideoCapture,
PHILIPSCAM_StopVideoCapture,
PHILIPSCAM_Configure,
PHILIPSCAM_SaveState,
PHILIPSCAM_RestoreState,
PHILIPSCAM_AllocateBandwidth,
PHILIPSCAM_FreeBandwidth
};
/* Function Caller
PHILIPSCAM_Initialize, USBCAMD.c : USBCAMD_ConfigureDevice()
PHILIPSCAM_UnInitialize, USBCAMD.c : USBCAMD_RemoveDevice
PHILIPSCAM_ProcessUSBPacket, iso.c : USBCAMD_TransferComplete()
PHILIPSCAM_NewFrame, iso.c : USBCAMD_TransferComplete()
PHILIPSCAM_ProcessRawVideoFrame, iso.c : USBCAMD_ProcessWorkItem()
PHILIPSCAM_StartVideoCapture, USBCAMD.c : USBCAMD_PrepareChannel()
reset.c USBCAMD_ResetPipes()
PHILIPSCAM_StopVideoCapture, USBCAMD.c : USBCAMD_UnPrepareChannel()
reset.c: USBCAMD_ResetPipes()
PHILIPSCAM_Configure, USBCAMD.c : USBCAMD_SelectConfiguration()
PHILIPSCAM_SaveState,
PHILIPSCAM_RestoreState,
PHILIPSCAM_AllocateBandwidth, <--+
USBCAMD.c : USBCAMD_PrepareChannel() -+ <--+
STREAM.c : AdapterOpenStream() -+ <--+
USBCAMD_AdapterReceivePacket(SRB = SRB_OPEN_STREAM) -+
PHILIPSCAM_FreeBandwidth USBCAMD.c : USBCAMD_UnPrepareChannel()
*/
VOID
PHILIPSCAM_AdapterReceivePacket( IN PHW_STREAM_REQUEST_BLOCK Srb ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext;
PHW_STREAM_INFORMATION streamInformation =
&(Srb->CommandData.StreamBuffer->StreamInfo);
PHW_STREAM_HEADER streamHeader =
&(Srb->CommandData.StreamBuffer->StreamHeader);
PDEVICE_OBJECT deviceObject;
switch (Srb->Command) {
case SRB_GET_STREAM_INFO:
//
// this is a request for the driver to enumerate requested streams
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_GET_STREAM_INFO\n"));
// get our device ext. from USBCAMD.
deviceContext =
USBCAMD_AdapterReceivePacket(Srb, NULL, NULL, FALSE);
//
// we support one stream
//
streamHeader->NumberOfStreams = 1;
streamInformation->StreamFormatsArray =
&PHILIPSCAM_MovingStreamFormats[0];
streamInformation->NumberOfFormatArrayEntries =
Streams[0].NumberOfFormatArrayEntries;
//
// set the property information for the video stream
//
streamHeader->DevicePropertiesArray =
PHILIPSCAM_GetAdapterPropertyTable(&streamHeader->
NumDevPropArrayEntries) ;
// pass to usbcamd to finish the job
deviceContext =
USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData, NULL, TRUE);
ASSERT_DEVICE_CONTEXT(deviceContext);
break;
case SRB_GET_DEVICE_PROPERTY:
//
// we handle all the property stuff
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_GET_DEVICE_PROPERTY\n"));
deviceContext =
USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData,
&deviceObject, FALSE);
ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("SRB_GET_STREAM_INFO\n"));
PHILIPSCAM_PropertyRequest( FALSE, deviceObject, deviceContext, Srb);
StreamClassDeviceNotification(DeviceRequestComplete,
Srb->HwDeviceExtension,
Srb);
break;
case SRB_SET_DEVICE_PROPERTY:
//
// we handle all the property stuff
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_SET_DEVICE_PROPERTY\n"));
deviceContext =
USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData,
&deviceObject, FALSE);
ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("SRB_GET_STREAM_INFO\n"));
PHILIPSCAM_PropertyRequest( TRUE, deviceObject, deviceContext, Srb);
StreamClassDeviceNotification(DeviceRequestComplete,
Srb->HwDeviceExtension,
Srb);
break;
case SRB_OPEN_STREAM: {
PKS_DATAFORMAT_VIDEOINFOHEADER pKSDataFormat =
(PKS_DATAFORMAT_VIDEOINFOHEADER) Srb->CommandData.OpenFormat;
PKS_VIDEOINFOHEADER pVideoInfoHdrRequested =
&pKSDataFormat->VideoInfoHeader;
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_OPEN_STREAM\n"));
// pass to usbcamd to finish the job
Srb->StreamObject->ReceiveDataPacket =
(PVOID) PHILIPSCAM_ReceiveDataPacket;
Srb->StreamObject->ReceiveControlPacket =
(PVOID) PHILIPSCAM_ReceiveCtrlPacket;
if (AdapterVerifyFormat(pKSDataFormat,
Srb->StreamObject->StreamNumber)) {
deviceContext =
USBCAMD_AdapterReceivePacket(Srb, &PHILIPSCAM_DeviceData,
NULL, TRUE);
// deviceContext->StreamOpen = TRUE;
}else{
Srb->Status = STATUS_INVALID_PARAMETER;
StreamClassDeviceNotification(DeviceRequestComplete,
Srb->HwDeviceExtension,
Srb);
}
}
break;
case SRB_GET_DATA_INTERSECTION:
//
// Return a format, given a range
//
//deviceContext =
// USBCAMD_AdapterReceivePacket(Srb,
// &PHILIPSCAM_DeviceData,
// &deviceObject,
// FALSE);
PHILIPSCAM_KdPrint (MAX_TRACE, ("P*_AdapterReceivePacket: SRB_GET_DATA_INTERSECTION\n"));
Srb->Status = AdapterFormatFromRange(Srb);
StreamClassDeviceNotification(DeviceRequestComplete,
Srb->HwDeviceExtension,
Srb);
break;
case SRB_CLOSE_STREAM: // close the specified stream
case SRB_CHANGE_POWER_STATE: // change power state
case SRB_SET_STREAM_RATE: // set the rate at which the stream should run
default:
//
// let usbcamd handle it
//
PHILIPSCAM_KdPrint (ULTRA_TRACE, ("P*_AdapterReceivePacket: SRB_HANDLED BY USBCAMD\n"));
deviceContext =
USBCAMD_AdapterReceivePacket(Srb,
&PHILIPSCAM_DeviceData, NULL, TRUE);
ASSERT_DEVICE_CONTEXT(deviceContext);
}
}
/*
** DriverEntry()
**
** This routine is called when the mini driver is first loaded. The driver
** should then call the StreamClassRegisterAdapter function to register with
** the stream class driver
**
** Arguments:
**
** Context1: The context arguments are private plug and play structures
** used by the stream class driver to find the resources for this
** adapter
** Context2:
**
** Returns:
**
** This routine returns an NT_STATUS value indicating the result of the
** registration attempt. If a value other than STATUS_SUCCESS is returned, the
** minidriver will be unloaded.
**
** Side Effects: none
*/
ULONG
DriverEntry(
PVOID Context1,
PVOID Context2 ){
PHILIPSCAM_KdPrint (MAX_TRACE, ("'Driver Entry\n"));
return USBCAMD_DriverEntry(Context1,
Context2,
sizeof(PHILIPSCAM_DEVICE_CONTEXT),
sizeof(PHILIPSCAM_FRAME_CONTEXT),
PHILIPSCAM_AdapterReceivePacket);
}
/*
** PHILIPSCAM_Initialize()
**
** On entry the device has been configured and the initial alt
** interface selected -- this is where we may send additional
** vendor commands to enable the device.
**
** Philips actions:
** 1. Find out what type of camera is available, VGA or medium-Res
** This has consequences for the available streamformats.
**
** Arguments:
**
** BusDeviceObject - pdo associated with this device
**
** DeviceContext - driver specific context
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_Initialize( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext=DeviceContext;
NTSTATUS ntStatus = STATUS_SUCCESS;
ASSERT_DEVICE_CONTEXT(deviceContext);
//
// perform any hardware specific
// initialization
//
ntStatus = PHILIPSCAM_GetSensorType(deviceContext);
if (NT_SUCCESS(ntStatus)) {
ntStatus = PHILIPSCAM_GetReleaseNumber(deviceContext);
}
deviceContext->EmptyPacketCounter = 0; // (Initialize this counter)
if (NT_SUCCESS(ntStatus)) {
ntStatus = PHILIPSCAM_InitPrpObj(deviceContext);
}
PHILIPSCAM_KdPrint (MIN_TRACE, ("'X P*_Initialize 0x%x\n", ntStatus));
ILOGENTRY("inHW", 0, 0, ntStatus);
return ntStatus;
}
/*
** PHILIPSCAM_UnInitialize()
**
** Assume the device hardware is gone -- all that needs to be done is to
** free any allocated resources (like memory).
**
** Arguments:
**
** BusDeviceObject - pdo associated with this device
**
** DeviceContext - driver specific context
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_UnInitialize( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext;
NTSTATUS ntStatus = STATUS_SUCCESS;
deviceContext = DeviceContext;
ASSERT_DEVICE_CONTEXT(deviceContext);
if ( deviceContext->Interface) {
ExFreePool(deviceContext->Interface);
deviceContext->Interface = NULL;
}
PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_UnInitialize 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_Configure()
**
** Configure the iso streaming Interface:
**
** Called just before the device is configured, this is where we tell
** usbcamd which interface and alternate setting to use for the idle state.
**
** NOTE: The assumption here is that the device will have a single interface
** with multiple alt settings and each alt setting has the same number of
** pipes.
**
** Arguments:
**
** BusDeviceObject - device object created by the hub whe can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** Interface - USBD interface structure initialized with the proper values
** for select_configuration. This Interface structure corresponds
** a single iso interafce on the device. This is the drivers
** chance to pick a particular alternate setting and pipe
** parameters.
**
**
** ConfigurationDescriptor - USB configuration Descriptor for
** this device.
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_Configure(IN PDEVICE_OBJECT BusDeviceObject,
IN PVOID DeviceContext,
IN OUT PUSBD_INTERFACE_INFORMATION Interface,
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN OUT PLONG DataPipeIndex,
IN OUT PLONG SyncPipeIndex ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext;
NTSTATUS ntStatus = STATUS_SUCCESS;
deviceContext = DeviceContext;
deviceContext->Sig = PHILIPSCAM_DEVICE_SIG;
//
// initilialize any other context stuff
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_Configure \n"));
if ( Interface == NULL) {
//
// this is a signal from usbcamd that I need to free my previousely
// allocated space for interface descriptor due to error conditions
// during IRP_MN_START_DEVICE processing and driver will be unloaded soon.
//
if (deviceContext->Interface) {
ExFreePool(deviceContext->Interface);
deviceContext->Interface = NULL;
}
return ntStatus;
}
deviceContext->Interface = ExAllocatePool(NonPagedPool,
Interface->Length);
*DataPipeIndex = 1;
*SyncPipeIndex = -1; // no sync pipe
if (deviceContext->Interface) {
Interface->AlternateSetting = ALT_INTERFACE_0 ;
// This interface has two pipes,
// initialize input parameters to USBD for both pipes.
// The MaximumTransferSize is the size of the largest
// buffer we want to submit for a single iso urb
// request.
//
Interface->Pipes[PHILIPSCAM_SYNC_PIPE].MaximumTransferSize =
USBD_DEFAULT_MAXIMUM_TRANSFER_SIZE; // = PAGE SIZE ??
Interface->Pipes[PHILIPSCAM_DATA_PIPE].MaximumTransferSize =
// 1024*32; // 32k transfer per urb ??
1024*198; // CIF: 352x288x16/8
RtlCopyMemory(deviceContext->Interface,
Interface,
Interface->Length);
PHILIPSCAM_KdPrint (MAX_TRACE, ("'size of interface request = %d\n",
Interface->Length));
}else{
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
}
//
// return interface number and alternate setting
//
PHILIPSCAM_KdPrint (MIN_TRACE, ("'X P*_Configure 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_StartVideoCapture()
**
** Arguments:
**
** BusDeviceObject - device object created by the hub we can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_StartVideoCapture( IN PDEVICE_OBJECT BusDeviceObject,
IN PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
NTSTATUS ntStatus= STATUS_SUCCESS;
ASSERT_DEVICE_CONTEXT(deviceContext);
//
// This is where we select the interface we need and send
// commands to start capturing
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_StartVideoCapture \n"));
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_StartVideocapture 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_AllocateBandwidth()
**
** Called just before the iso video capture stream is
** started, here is where we select the appropriate
** alternate interface and set up the device to stream.
**
** Called in connection with the stream class RUN command
**
** Arguments:
**
** BusDeviceObject - device object created by the hub we can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** RawFrameLength - pointer to be filled in with size of buffer needed to
** receive the raw frame data from the packet stream.
**
** Format - pointer to PKS_DATAFORMAT_VIDEOINFOHEADER associated with this
** stream.
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_AllocateBandwidth( IN PDEVICE_OBJECT BusDeviceObject,
IN PVOID DeviceContext,
OUT PULONG RawFrameLength,
IN PVOID Format ){
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
NTSTATUS ntStatus = STATUS_SUCCESS;
PKS_DATAFORMAT_VIDEOINFOHEADER pdataFormatHeader;
PKS_BITMAPINFOHEADER bmInfoHeader;
LONGLONG llDefaultFramePeriod ;
USHORT usReqFrRate;
ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_AllocateBandwidth \n"));
//
// This is where we select the interface we need and send
// commands to start capturing
//
*RawFrameLength = 0;
pdataFormatHeader = Format;
bmInfoHeader = &pdataFormatHeader->VideoInfoHeader.bmiHeader;
// deviceContext->pSelectedStreamFormat = &pdataFormatHeader->DataFormat; // removed RMR
RtlCopyMemory (&deviceContext->CamStatus.PictureSubFormat, // added RMR
&pdataFormatHeader->DataFormat.SubFormat,
sizeof (GUID));
PHILIPSCAM_KdPrint (MIN_TRACE,
("'req.format %d x %d\n", bmInfoHeader->biWidth,
bmInfoHeader->biHeight));
switch (bmInfoHeader->biWidth) {
case QQCIF_X:
deviceContext->CamStatus.PictureFormat = FORMATQQCIF;
*RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8;
break;
case SQCIF_X:
deviceContext->CamStatus.PictureFormat = FORMATSQCIF;
*RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8;
break;
case QCIF_X:
deviceContext->CamStatus.PictureFormat = FORMATQCIF;
*RawFrameLength = (QCIF_X * QCIF_Y * 12)/8;
break;
case CIF_X:
deviceContext->CamStatus.PictureFormat = FORMATCIF;
*RawFrameLength = (CIF_X * CIF_Y * 12)/8;
break;
case SQSIF_X:
deviceContext->CamStatus.PictureFormat = FORMATSQSIF;
*RawFrameLength = (SQCIF_X * SQCIF_Y * 12)/8;
break;
case QSIF_X:
deviceContext->CamStatus.PictureFormat = FORMATQSIF;
*RawFrameLength = (QCIF_X * QCIF_Y * 12)/8;
break;
case SSIF_X:
if (bmInfoHeader->biHeight == SSIF_Y){
deviceContext->CamStatus.PictureFormat = FORMATSSIF;
}else{
deviceContext->CamStatus.PictureFormat = FORMATSCIF;
}
*RawFrameLength = (CIF_X * CIF_Y * 12)/8;
break;
case SIF_X:
deviceContext->CamStatus.PictureFormat = FORMATSIF;
*RawFrameLength = (CIF_X * CIF_Y * 12)/8;
break;
default:
deviceContext->CamStatus.PictureFormat = FORMATQCIF;
*RawFrameLength = (QCIF_X * QCIF_Y * 12)/8;
}
llDefaultFramePeriod = pdataFormatHeader->VideoInfoHeader.AvgTimePerFrame; // [100nS]
usReqFrRate = MapFrPeriodFrRate(llDefaultFramePeriod);
deviceContext->CamStatus.PictureFrameRate = usReqFrRate;
PHILIPSCAM_KdPrint (MIN_TRACE,("Req.frperiod: %d us \n",
llDefaultFramePeriod / 10));
PHILIPSCAM_KdPrint (MIN_TRACE,("Req.frperiod index: %d = %s fps\n",
usReqFrRate, FRString(usReqFrRate)));
// Define framerate based on available USB=bandwidth
// if not suff.BW, frame rate is decreased.
ntStatus = PHILIPSCAM_SetFrRate_AltInterface(deviceContext);
// Send from here the format/framerate to the camera hardware:
if (NT_SUCCESS(ntStatus)) {
ntStatus = PHILIPSCAM_SetFormatFramerate( deviceContext );
}
if (NT_SUCCESS(ntStatus)) {
ntStatus = PHILIPSCAM_StartCodec( deviceContext );
}
if (NT_SUCCESS(ntStatus)) {
deviceContext->FrameLength = *RawFrameLength;
}
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_AllocateBandwidth 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_FreeBandwidth()
**
** Called after the iso video stream is stopped, this is where we
** select an alternate interface that uses no bandwidth.
**
** Arguments:
**
** BusDeviceObject - device object created by the hub we can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_FreeBandwidth(
PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ){
NTSTATUS ntStatus;
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
// turn off streaming on the device
ASSERT_DEVICE_CONTEXT(deviceContext);
ntStatus = PHILIPSCAM_StopCodec(deviceContext);
deviceContext->Interface->AlternateSetting = ALT_INTERFACE_0 ;
ntStatus = USBCAMD_SelectAlternateInterface(
deviceContext,
deviceContext->Interface);
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_FreeBandWidth 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_StopVideoCapture()
**
** Called after the iso video stream is stopped, this is where we
** select an alternate interface that uses no bandwidth.
**
** Arguments:
**
** BusDeviceObject - device object created by the hub we can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_StopVideoCapture( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
NTSTATUS ntStatus = STATUS_SUCCESS;
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
// turn off streaming on the device
ASSERT_DEVICE_CONTEXT(deviceContext);
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_StopVideoCapture 0x%x\n", ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_NewFrame()
**
** called at DPC level to allow driver to initialize a new video frame
** context structure
**
** Arguments:
**
** DeviceContext - minidriver device context
**
** FrameContext - frame context to be initialized
**
** Returns:
**
** NTSTATUS code
**
** Side Effects: none
*/
VOID
PHILIPSCAM_NewFrame( PVOID DeviceContext,
PVOID FrameContext ){
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
PPHILIPSCAM_FRAME_CONTEXT pFrameContext = FrameContext;
pFrameContext->USBByteCounter = 0;
// PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_NewFrame\n"));
ASSERT_DEVICE_CONTEXT(deviceContext);
}
/*
** PHILIPSCAM_ProcessUSBPacket()
**
** called at DPC level to allow driver to determine if this packet is part
** of the current video frame or a new video frame.
**
** This function should complete as quickly as possible, any image processing
** should be deferred to the ProcessRawFrame routine.
**
** Arguments:
**
** BusDeviceObject - device object created by the hub we can submit
** urbs to our device through this deviceObject
**
** DeviceContext - minidriver device context
**
** CurrentFrameContext - some context for this particular frame
**
** SyncPacket - iso packet descriptor from sync pipe, not used if the interface
** has only one pipe.
**
** SyncBuffer - pointer to data for the sync packet
**
** DataPacket - iso packet descriptor from data pipe
**
** DataBuffer - pointer to data for the data packet
**
** FrameComplete - indicates to usbcamd that this is the first data packet
** for a new video frame
**
** Returns:
**
** number of bytes that should be copied in to the rawFrameBuffer of FrameBuffer.
**
** Side Effects: none
*/
ULONG
PHILIPSCAM_ProcessUSBPacket(
PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext,
PVOID CurrentFrameContext,
PUSBD_ISO_PACKET_DESCRIPTOR SyncPacket,
PVOID SyncBuffer,
PUSBD_ISO_PACKET_DESCRIPTOR DataPacket,
PVOID DataBuffer,
PBOOLEAN FrameComplete,
PBOOLEAN NextFrameIsStill ) {
static BOOLEAN EndOfFrameFound = FALSE;
static BOOLEAN StartOfFrameFound = FALSE;
static ULONG previous_packetSize= 0;
static ULONG ActualBytesReceived = 0 ;
#if DBG
#if DBGHARD
typedef struct {
ULONG PSize;
ULONG DeltaT;
} PACKETINFO;
#define MAXI 2048
static ULONG ulRcvdFrameSize[MAXI];
static ULONG ulPHistory[MAXI][2];
static ULONG ulPcktCntr = 0;
static ULONG ulFrSCntr = 0;
static LARGE_INTEGER liCurTicks, liPrevTicks;
static ULONG ElapsedTicks;
static ULONG TickPeriod ;
#endif
#endif
PUSBD_ISO_PACKET_DESCRIPTOR dataPacket = DataPacket;
PPHILIPSCAM_FRAME_CONTEXT pFrameContext = CurrentFrameContext;
ULONG packetSize;
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
*NextFrameIsStill = FALSE;
// PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_ProcessPacket\n"));
ASSERT_DEVICE_CONTEXT(deviceContext);
packetSize = dataPacket->Length ;
// Synchronization:
// ----------------
if (packetSize != previous_packetSize){
//end or start of frame
if (packetSize < previous_packetSize) {
EndOfFrameFound = TRUE;
}else{
StartOfFrameFound = TRUE;
}
}
if ( StartOfFrameFound == TRUE ){
*FrameComplete = TRUE;
EndOfFrameFound = FALSE;
StartOfFrameFound = FALSE;
#if DBG
#if DBGHARD
ulRcvdFrameSize[ulFrSCntr] = ActualBytesReceived;
if (ulFrSCntr==MAXI) ulFrSCntr = 0;
#endif
#endif
if (pFrameContext)
pFrameContext->USBByteCounter = ActualBytesReceived;
ActualBytesReceived = 0;
}
ActualBytesReceived += packetSize;
#if DBG
#if DBGHARD
// KeQueryTickCount(&liCurTicks);
ElapsedTicks = (ULONG)( liCurTicks.QuadPart - liPrevTicks.QuadPart);
ulPHistory[ulPcktCntr][0] = packetSize;
ulPHistory[ulPcktCntr][1] = ElapsedTicks ;
liPrevTicks.QuadPart = liCurTicks.QuadPart;
ulPcktCntr++;
if (ulPcktCntr==MAXI) ulPcktCntr = 0;
#endif
#endif
// Added to improve robustness
if ( ActualBytesReceived > deviceContext->FrameLength){
*FrameComplete = TRUE;
ActualBytesReceived = 0;
}
previous_packetSize = packetSize;
return packetSize;
}
/*
** PHILIPSCAM_ProcessRawVideoFrame()
**
** Called at PASSIVE level to allow driver to perform any decoding of the
** raw video frame.
**
** This routine will convert the packetized data in to the fromat
** the CODEC expects, ie y,u,v
**
** data is always of the form 256y 64u 64v (384 byte chunks) regardless of USB
** packet size.
**
**
** Arguments:
**
** DeviceContext - driver context
**
** FrameContext - driver context for this frame
**
** FrameBuffer - pointer to the buffer that should receive the final
** processed video frame.
**
** FrameLength - length of the Frame buffer (from the original read
** request)
**
** RawFrameBuffer - pointer to buffer containing the received USB packets
**
** RawFrameLength - length of the raw frame.
**
** NumberOfPackets - number of USB packets received in to the RawFrameBuffer
**
** BytesReturned - pointer to value to return for number of bytes read.
**
** Returns:
**
** NT status completion code for the read irp
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_ProcessRawVideoFrame( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext,
PVOID FrameContext,
PVOID FrameBuffer,
ULONG FrameLength,
PVOID RawFrameBuffer,
ULONG RawFrameLength,
ULONG NumberOfPackets,
PULONG BytesReturned ) {
NTSTATUS ntStatus = STATUS_SUCCESS;
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
PPHILIPSCAM_FRAME_CONTEXT frameContext = FrameContext;
ULONG rawDataLength, processedDataLength;
PUCHAR frameBuffer = FrameBuffer;
PUCHAR rawFrameBuffer = RawFrameBuffer;
ULONG rawFrameLength = RawFrameLength;
ULONG frameLength = FrameLength;
ULONG ExpectedNumberOfBytes;
//TEST_TRAP();
ASSERT_DEVICE_CONTEXT(deviceContext);
switch (deviceContext->CamStatus.PictureFormat){
case FORMATCIF:
if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){
ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ;
}else{
ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ;
}
break;
case FORMATQCIF:
ExpectedNumberOfBytes = QCIF_X * QCIF_Y * 3/2 ;
break;
case FORMATSQCIF:
ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ;
break;
case FORMATQQCIF:
ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ;
break;
case FORMATVGA:
ExpectedNumberOfBytes = VGA_X * VGA_Y * 3/2 ;
break;
case FORMATSIF:
if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){
ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ;
}else{
ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ;
}
break;
case FORMATSSIF:
if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){
ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ;
}else{
ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ;
}
break;
case FORMATSCIF:
if ( deviceContext->CamStatus.PictureCompressing == COMPRESSION0 ){
ExpectedNumberOfBytes = CIF_X * CIF_Y * 3/2 ;
}else{
ExpectedNumberOfBytes = CIF_X * CIF_Y / 2 ;
}
break;
case FORMATQSIF:
ExpectedNumberOfBytes = QCIF_X * QCIF_Y * 3/2 ;
break;
case FORMATSQSIF:
ExpectedNumberOfBytes = SQCIF_X * SQCIF_Y * 3/2 ;
break;
default:
ExpectedNumberOfBytes = 0;
}
if (ExpectedNumberOfBytes == frameContext->USBByteCounter ) {
ntStatus = PHILIPSCAM_DecodeUsbData(deviceContext,
frameBuffer,
frameLength,
rawFrameBuffer,
rawFrameLength);
*BytesReturned = frameLength ;
}else{
PHILIPSCAM_KdPrint (MIN_TRACE, ("Actual (%d) < Expected (%d) \n",
frameContext->USBByteCounter,ExpectedNumberOfBytes));
// Green screen complaints bug fix : At the moment USBCAMD delivers a frame for
// processing, we check whether the size of that frame is correct.
// If not we return to USBCAMD a framelength to be copied of zero and we won't
// process the frame.
// The workaround is to let USBCAMD copy the buffer with the actual buffer length
// and not to process the frame. Apparantly, returning a bufferlength zero has as
// consequence that USB packets gets lost.
// This causes subsequent frames to be incorrect, returning again bufferlength
// zero. And so on. Not processing buffers has as consequence that the renderer
// sees empty buffers resulting in a green screen.
// Sometimes, if this happens during streaming, old buffers are being rerendered.
*BytesReturned = 0 ;
// 2001/01/29: This workaround was causing the first few frames
// captured to remain uninitialized due to insufficient framelength.
// Returning 0 to indicate a dropped frame is the correct behavior.
//*BytesReturned = frameLength ;
}
return ntStatus;
}
/*
** PHILIPSCAM_PropertyRequest()
**
** Arguments:
**
** DeviceContext - driver context
**
** Returns:
**
** NT status completion code for the read irp
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_PropertyRequest( BOOLEAN SetProperty,
PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext,
PVOID PropertyContext ) {
NTSTATUS ntStatus = STATUS_SUCCESS;
PHW_STREAM_REQUEST_BLOCK srb = (PHW_STREAM_REQUEST_BLOCK)PropertyContext;
PSTREAM_PROPERTY_DESCRIPTOR propertyDescriptor;
propertyDescriptor = srb->CommandData.PropertyInfo;
//
// identify the property to set
//
PHILIPSCAM_KdPrint (MAX_TRACE, ("'E P*_PropertyRequest\n"));
if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOPROCAMP, &propertyDescriptor->Property->Set))
if (SetProperty)
ntStatus = PHILIPSCAM_SetCameraProperty(DeviceContext, srb);
else
ntStatus = PHILIPSCAM_GetCameraProperty(DeviceContext, srb);
else if (IsEqualGUID(&PROPSETID_PHILIPS_CUSTOM_PROP, &propertyDescriptor->Property->Set))
if (SetProperty)
ntStatus = PHILIPSCAM_SetCustomProperty(DeviceContext, srb);
else
ntStatus = PHILIPSCAM_GetCustomProperty(DeviceContext, srb);
else if (IsEqualGUID(&PROPSETID_PHILIPS_FACTORY_PROP, &propertyDescriptor->Property->Set))
if (SetProperty)
ntStatus = PHILIPSCAM_SetFactoryProperty(DeviceContext, srb);
else
ntStatus = PHILIPSCAM_GetFactoryProperty(DeviceContext, srb);
else if (IsEqualGUID(&PROPSETID_VIDCAP_VIDEOCONTROL, &propertyDescriptor->Property->Set))
{
if (SetProperty)
ntStatus = PHILIPSCAM_SetVideoControlProperty(DeviceContext, srb);
else
ntStatus = PHILIPSCAM_GetVideoControlProperty(DeviceContext, srb);
}
else
ntStatus = STATUS_NOT_SUPPORTED;
PHILIPSCAM_KdPrint (MAX_TRACE, ("'X P*_PropertyRequest 0x%x\n",ntStatus));
return ntStatus;
}
/*
** PHILIPSCAM_SaveState()
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_SaveState( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
PHILIPSCAM_KdPrint (MAX_TRACE, ("'P*_SaveState\n"));
return STATUS_SUCCESS;
}
/*
** PHILIPSCAM_RestoreState()
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_RestoreState( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
PHILIPSCAM_KdPrint (MAX_TRACE, ("'RestoreState\n"));
return STATUS_SUCCESS;
}
/*
** PHILIPSCAM_ReadRegistry()
**
** Arguments:
**
** Returns:
**
** Side Effects: none
*/
NTSTATUS
PHILIPSCAM_ReadRegistry( PDEVICE_OBJECT BusDeviceObject,
PVOID DeviceContext ) {
PPHILIPSCAM_DEVICE_CONTEXT deviceContext = DeviceContext;
NTSTATUS ntStatus=STATUS_SUCCESS;
HANDLE handle;
return ntStatus;
}
USHORT
MapFrPeriodFrRate(LONGLONG llFramePeriod)
{
USHORT FrameRate;
if (llFramePeriod <= 420000 ){ // 41.6 rounded to 42 ms
FrameRate = FRRATE24;
}else if (llFramePeriod <= 510000 ){ // 50.0 rounded to 51 ma
FrameRate = FRRATE20;
}else if (llFramePeriod <= 670000 ){ // 66.6 rounded to 67 ms
FrameRate = FRRATE15;
}else if (llFramePeriod <= 840000 ){ // 83.3 rounded to 84 ms
FrameRate = FRRATE12;
}else if (llFramePeriod <= 1010000 ){ // 100.0 rounded to 101 ms
FrameRate = FRRATE10;
// HR: changed from 134 to 143ms.
}else if (llFramePeriod <= 1430000 ){ // 133.3 rounded to 134 ms
FrameRate = FRRATE75;
}else if (llFramePeriod <= 2010000 ){ // 200 rounded to 201 ms
FrameRate = FRRATE5;
}else {
FrameRate = FRRATE375;
}
// rounding was necessary as the OS returns e.g. #667.111 for 15 fps
return FrameRate;
}
#if DBG
PCHAR
FRString (
USHORT index
)
{
switch (index)
{
case FRRATEVGA: return "VGA";
case FRRATE375: return "3.75";
case FRRATE5: return "5";
case FRRATE75: return "7.5";
case FRRATE10: return "10";
case FRRATE12: return "12";
case FRRATE15: return "15";
case FRRATE20: return "20";
case FRRATE24:return "24";
default:
return "";break;
}
}
#endif