|
|
/*
* vcisr.c * * * 32-bit Video Capture driver * kernel-mode support library - interrupt dispatch * * Geraint Davies, Feb 93 */
#include <vckernel.h>
#include "vckpriv.h"
#include "profile.h"
#if DBG
extern profiling looptime; #endif
/* interrupt service routine - returns TRUE if interrupt handled.
* all interrupts come in here and are then dispatched to hw ack routine * the Context pointer is a pointer to DEVICE_INFO. */ BOOLEAN VC_InterruptService( IN PKINTERRUPT pInterruptObject, IN PVOID Context ) { PDEVICE_INFO pDevInfo;
pDevInfo = (PDEVICE_INFO)Context;
/*
* make sure that the hardware-specific code has installed * an ack routine */ if (pDevInfo->Callback.InterruptAcknowledge == NULL) {
/* no isr - and yet we are getting interrupts -
* we should disconnect the interrupt */ dprintf(("interrupt occured without h/w isr"));
//IoDisconnectInterrupt(pDevInfo->InterruptObject);
return(FALSE); }
/*
* call the acknowledge. this will not do any service, but will * return TRUE if the service routine is to be called. */ if (!pDevInfo->Callback.InterruptAcknowledge(pDevInfo)) { return(FALSE); }
/* the isr reckons that it is time to schedule the service
* routine. This is done on a DPC. */
if (pDevInfo->DpcRequested) { //dprintf5(("dpc overrun"));
} else { pDevInfo->DpcRequested = TRUE; IoRequestDpc(pDevInfo->pDeviceObject, NULL, pDevInfo); }
/* everything else is done in dpc routine */
return(TRUE); }
/*
* DPC routine to do work for interrupt service. Scheduled because * hardware acknowledge routine said that it was time to call its * service routine. * * If there is an outstanding buffer, pass this to the h/w service * routine to fill, and then complete the irp. * * if there is no buffer, then we have to miss a frame. if there is an * outstanding wait-error request, then we can complete that to report * the overrun. If not, we just count one more unreported overrun * to save up for the next wait-error. * * If we have no buffer, we must still call the hardware capture routine, * with a NULL buffer pointer, so it can discard any data and re-arm for * capture. * * Note that the pIrpNotUsed is an arg passed from the IoRequestDpc call. * We don't work out which Irp to complete until this function, so * we ignore that. The context argument is a PDEVICE_INFO. * * The buffered parameter to the add-buffer irp is the CAPTUREBUFFER structure. * We need to store the bytes written, and the timestamp there. The * virtual address for the buffer has been locked down and is * represented by the Irp->MdlAddress. We mapped this ourselves but * we don't need to free it ourselves since we added it to the irp. the i/o * subsystem will unlock and free it when freeing the irp. * * Contention: see comment at top of vcdisp.c. We use the cancel spinlock * to protect accesses to the irp queues against contention from * passive-level requests, but we do not hold it for the entire * service routine. */ VOID VC_Deferred( PKDPC pDpc, PDEVICE_OBJECT pDeviceObject, PIRP pIrpNotUsed, PVOID Context ) { PDEVICE_INFO pDevInfo; PIRP pIrp = NULL; PUCHAR pData; ULONG ulLength; PCAPTUREBUFFER pCapBuf;
pDevInfo = (PDEVICE_INFO)Context;
pDevInfo->DpcRequested = FALSE;
/*
* check that the h/w specific code has installed a service handler * some kind of internal error otherwise. */ if (pDevInfo->Callback.CaptureService == NULL) { dprintf(("dpc requested but no service routine")); return; }
/*
* if there is a system buffer and it is in use, then * we should fail to capture anything else */ if ((pDevInfo->pSystemBuffer != NULL) && (pDevInfo->SysBufInUse != 0)) {
/* report overrun, same as for no-buffer cases */
/*
* notify the hardware portion that there is no buffer, so * he must throw away everything and re-arm. */ pDevInfo->Callback.CaptureService(pDevInfo, NULL, NULL, 0);
/*
* access to the skip count needs to be locked together * with access to the queue of wait-error requests. This function * increments the skip-count and completes a wait-error request * if there is one. */ VC_ReportSkip(pDevInfo);
}
/*
* We need to interlock access to the queue using the Cancel * spinlock (see vcqueue.c) - but we don't need to interlock * the whole of this function. * * Any further contention between this code and the * passive-level code will be resolved by the h/wspecific code. */
/*
* get the next irp from the queue */ pIrp = VC_ExtractNextIrp(&pDevInfo->BufferHead, FALSE); if (pIrp) {
PIO_STACK_LOCATION pIoStack; ULONG IoCode;
/*
* is this cap_to_sysbuf or a real one ? */ pIoStack = IoGetCurrentIrpStackLocation(pIrp); IoCode = pIoStack->Parameters.DeviceIoControl.IoControlCode; if(IoCode == IOCTL_VIDC_ADD_BUFFER) {
/* get the address of the callers buffer, mapped into
* system memory */ pData = (PUCHAR) MmGetSystemAddressForMdl(pIrp->MdlAddress);
if (pData == NULL) { dprintf(("MmGetSystemAddressforMdl failed in dpc"));
pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_NO_MEMORY;
} else {
/* get a pointer to the (buffered) CAPTUREBUFFER header */ pCapBuf = (PCAPTUREBUFFER) pIrp->AssociatedIrp.SystemBuffer;
/*
* find the length of the data buffer */ ulLength = pCapBuf->BufferLength;
//profile this call
START_PROFILING(&looptime);
pCapBuf->BytesUsed = (DWORD) pDevInfo->Callback.CaptureService(pDevInfo, pData, (PULONG) &pCapBuf->TimeCaptured, ulLength); STOP_PROFILING(&looptime);
/* if a capture service routine returns 0, it means
* that it has not completed this capture, and would like * the same buffer back for the next field if possible * - in this case, return the buffer to the start of the * queue */ if (pCapBuf->BytesUsed == 0) { if (VC_ReplaceRequest(pIrp, &pDevInfo->BufferHead, VC_Cancel)) {
// nothing more to do till he gets another crack
return; } else { // this irp has been cancelled
pIrp->IoStatus.Status = STATUS_CANCELLED; pIrp->IoStatus.Information = 0; } } else { /* we copy back the CAPTUREBUFFER struct */ pIrp->IoStatus.Information = sizeof(CAPTUREBUFFER); pIrp->IoStatus.Status = STATUS_SUCCESS; } }
} else if (IoCode == IOCTL_VIDC_CAP_TO_SYSBUF) { if (pDevInfo->pSystemBuffer == NULL) { pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE; } else {
/*
* capture to system buffer and complete request */ pDevInfo->SysBufInUse = 1; if (pDevInfo->Callback.CaptureService( pDevInfo, pDevInfo->pSystemBuffer, &pDevInfo->SysBufTimeStamp, pDevInfo->ImageSize) == 0) {
// 0 return means please give me another go at this request
if (VC_ReplaceRequest(pIrp, &pDevInfo->BufferHead, VC_Cancel)) {
// nothing more to do till he gets another crack
return; } else { // this irp has been cancelled
pIrp->IoStatus.Status = STATUS_CANCELLED; } } else { pIrp->IoStatus.Status = STATUS_SUCCESS; }
pIrp->IoStatus.Information = 0; } } else { /* unexpected irp */ pIrp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR; }
IoCompleteRequest(pIrp, IO_SOUND_INCREMENT); } else {
/*
* notify the hardware portion that there is no buffer, so * he must throw away everything and re-arm. */ pDevInfo->Callback.CaptureService(pDevInfo, NULL, NULL, 0);
/*
* access to the skip count needs to be locked together * with access to the queue of wait-error requests. This function * increments the skip-count and completes a wait-error request * if there is one. */ VC_ReportSkip(pDevInfo);
}
}
|