/*++ 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