Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

475 lines
10 KiB

/*
* Copyright (c) Microsoft 1993. All Rights Reserved.
*/
/*
* vclib.c
*
*
* 32-bit Video Capture driver
* kernel-mode support library - wrapper/helper functions
*
* Geraint Davies, Feb 93
*/
#include <vckernel.h>
#include "vckpriv.h"
#include <ntddvdeo.h> // support for VC_GetVideoMode
#include <stdio.h>
#include <stdarg.h>
#if DBG
ULONG VCDebugLevel = 0;
#endif
/* -- utility functions (to hide NT dependencies) -----------------------*/
/*
* get the hardware specific portion of the device extension
*/
PVOID
VC_GetHWInfo(PDEVICE_INFO pDevInfo)
{
if (pDevInfo == NULL) {
dprintf(("NULL devinfo pointer"));
return NULL;
} else {
return( (PVOID) ( ((PUCHAR)pDevInfo) + sizeof(DEVICE_INFO)));
}
}
#if 0
/*
* this does not work, since only the windows server has permission
* to open the video device and make this call. The only way to find
* this info out is for the user-mode driver to call GetDeviceCaps
* and write it to the registry.
*/
/*
* find out the current video mode. Build an ioctl irp and
* send it to the video driver
*/
BOOL
VC_GetVideoMode(
PDEVICE_INFO pDevInfo,
int * pWidth,
int * pHeight,
int * pDepth)
{
UNICODE_STRING us;
PDEVICE_OBJECT pDevObj;
PFILE_OBJECT pFile;
VIDEO_MODE_INFORMATION ModeInfo;
PIRP pIrp;
IO_STATUS_BLOCK IoStatus;
PIO_STACK_LOCATION pIoStack;
NTSTATUS Status;
/*
* get a handle to the video device - assume we are running
* on video device 0
*/
RtlInitUnicodeString(&us, L"\\Device\\Video0");
Status = IoGetDeviceObjectPointer(&us, FILE_READ_DATA, &pFile, &pDevObj);
if (!NT_SUCCESS(Status)) {
dprintf1(("GetDeviceObjectPointer failed 0x%x", Status));
return(FALSE);
}
/*
* build an irp we can use to send the IOCTL to the device
*/
pIrp = IoBuildDeviceIoControlRequest(
IRP_MJ_DEVICE_CONTROL,
pDevObj,
NULL,
0,
&ModeInfo,
sizeof(VIDEO_MODE_INFORMATION),
FALSE,
NULL,
&IoStatus);
if (pIrp == NULL) {
dprintf1(("build ioctl failed"));
return(FALSE);
}
/*
* we still need to put the ioctl code into the irp, and set up the
* buffer pointer.
*/
pIoStack = IoGetNextIrpStackLocation(pIrp);
pIoStack->Parameters.DeviceIoControl.IoControlCode =
IOCTL_VIDEO_QUERY_CURRENT_MODE;
pIrp->AssociatedIrp.SystemBuffer = (PVOID) &ModeInfo;
/* send the irp to the driver */
Status = IoCallDriver(pDevObj, pIrp);
if (!NT_SUCCESS(Status)) {
dprintf1(("video ioctl failed %x", Status));
return(FALSE);
}
if (IoStatus.Information != sizeof(VIDEO_MODE_INFORMATION)) {
dprintf1(("bad size returned from video mode ioctl "));
return(FALSE);
} else {
dprintf2(("got video mode ok"));
}
*pWidth = ModeInfo.VisScreenWidth;
*pHeight = ModeInfo.VisScreenHeight;
*pDepth = ModeInfo.NumberOfPlanes * ModeInfo.BitsPerPlane;
return(TRUE);
}
#endif
/*
* output one BYTE to the port. bOffset is the offset from
* the port base address.
*/
VOID
VC_Out(PDEVICE_INFO pDevInfo, BYTE bOffset, BYTE bData)
{
WRITE_PORT_UCHAR( (PUCHAR) pDevInfo->PortBase + bOffset, bData);
}
/*
* input one byte from the port at bOffset offset from the port base address
*/
BYTE
VC_In(PDEVICE_INFO pDevInfo, BYTE bOffset)
{
return (BYTE) READ_PORT_UCHAR( (PUCHAR) pDevInfo->PortBase + bOffset);
}
/*
* get the callback table into which we can insert functions we support */
PVC_CALLBACK
VC_GetCallbackTable(PDEVICE_INFO pDevInfo)
{
return ( &pDevInfo->Callback );
}
/*
* get the system-mode address of the frame buffer
*/
PUCHAR
VC_GetFrameBuffer(PDEVICE_INFO pDevInfo)
{
return(pDevInfo->FrameBase);
}
/*
* set the minimum size for queued buffers
*/
VOID
VC_SetImageSize(PDEVICE_INFO pDevInfo, int ImageSize)
{
/*
* if the image size changes, free up the system buffer
*/
pDevInfo->SysBufInUse = 0;
if (pDevInfo->pSystemBuffer != NULL) {
ExFreePool(pDevInfo->pSystemBuffer);
pDevInfo->pSystemBuffer = NULL;
}
pDevInfo->ImageSize = ImageSize;
}
/*
* this function synchronizes with the device interrupt in
* a multiprocessor-safe way. It disables the interrupt, and also
* holds an interrupt spinlock to prevent contention on other
* processors.
*/
BOOLEAN
VC_SynchronizeExecution(
PDEVICE_INFO pDevInfo,
PSYNC_ROUTINE SyncFunc,
PVOID pContext
)
{
/* if the interrupt hasn't yet been set up, then
* just call the callback function
*
* If we are at interrupt time, then just call the callback. if
* we are at ipl > dpc level, we must already hold the spinlock.
*/
if ((KeGetCurrentIrql() <= DISPATCH_LEVEL) && (pDevInfo->InterruptObject)) {
return(KeSynchronizeExecution(
pDevInfo->InterruptObject,
(PKSYNCHRONIZE_ROUTINE)SyncFunc,
pContext));
} else {
return(SyncFunc(pContext));
}
}
/*
* This function can be used like VC_SynchronizeExecution, to sync
* between the captureservice routine and the passive-level requests. This
* will not necessarily disable interrupts. On win-16, this function may be
* the same as VC_SynchronizeExecution. On NT, the CaptureService func
* runs as a DPC, at a lower interrupt priority than the isr itself, and
* so can be protected using this (spinlock-based) function without having
* to disable all interrupts.
*/
BOOLEAN
VC_SynchronizeDPC(
PDEVICE_INFO pDevInfo,
PSYNC_ROUTINE SyncFunc,
PVOID pContext
)
{
KIRQL OldIrql;
BOOL bRet;
KeAcquireSpinLock(&pDevInfo->DeviceSpinLock, &OldIrql);
bRet = SyncFunc(pContext);
KeReleaseSpinLock(&pDevInfo->DeviceSpinLock, OldIrql);
return((BOOLEAN)bRet);
}
/*
* VC_AccessData gives access to the data in kernel mode in a safe way.
* It calls the given function with the address and size of the buffer
* after any necessary mapping, and wrapped in exception handlers
* as necessary. It must be called in the context of the original requesting
* thread.
*
* This implementation assumes that in kernel mode we can see the data,
* with no mapping necessary, and just wraps the function in an
* exception handler.
*/
BOOLEAN
VC_AccessData(
PDEVICE_INFO pDevInfo,
PUCHAR pData,
ULONG Length,
PACCESS_ROUTINE AccessFunc,
PVOID pContext
)
{
BOOLEAN retval;
try {
retval = AccessFunc(pDevInfo, pData, Length, pContext);
} except (EXCEPTION_EXECUTE_HANDLER) {
dprintf(("data access exception"));
retval = FALSE;
}
return(retval);
}
/* these functions allocate and free non-paged memory for use
* in kernel mode, including at interrupt time.
*/
PVOID
VC_AllocMem(PDEVICE_INFO pDevInfo, ULONG Length)
{
return ExAllocatePool(NonPagedPool, Length);
}
VOID
VC_FreeMem(PDEVICE_INFO pDevInfo, PVOID pData, ULONG Length)
{
ExFreePool(pData);
}
/*
* delay for a number of milliseconds. This is accurate only to
* +- 15msecs at best.
*/
VOID
VC_Delay(int nMillisecs)
{
LARGE_INTEGER Delay;
/*
* relative times are negative, in units of 100 nanosecs
*/
// first wait for the minimum length of time - this ensures that
// our wait is never less than nMillisecs.
Delay = RtlConvertLongToLargeInteger(-1);
KeDelayExecutionThread(KernelMode,
FALSE, //non-alertable
&Delay);
// now wait for the requested time.
Delay = RtlConvertLongToLargeInteger(-(nMillisecs * 10000));
KeDelayExecutionThread(KernelMode,
FALSE, //non-alertable
&Delay);
}
/*
* Block by polling for a number of microseconds
*/
VOID
VC_Stall(int nMicrosecs)
{
KeStallExecutionProcessor(nMicrosecs);
}
/*
* callback routine called back from RtlQueryRegistryValues from
* VC_ReadProfile. This function is called if the value named is in
* the registry. The context pointer is a pointer to the DWORD containing
* the default: overwrite this with the actual value.
*/
NTSTATUS VC_RegistryQueryCallback(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
{
ASSERT(ValueType == REG_DWORD);
*(PULONG)Context = *(PULONG)ValueData;
return (STATUS_SUCCESS);
}
/*
* read a given registry entry and return the value data or the
* default if not present.
*
* The value will be held in the parameters key for the current
* device.
*/
DWORD
VC_ReadProfile(PDEVICE_INFO pDevInfo, PWCHAR ValueName, DWORD Default)
{
RTL_QUERY_REGISTRY_TABLE Table[2];
/*
* first entry is filled out to the name we want: second is left empty
* to indicate the end of the table.
*/
RtlZeroMemory(&Table, sizeof(Table));
Table[0].QueryRoutine = VC_RegistryQueryCallback;
Table[0].Name = ValueName;
/*
* The callback routine will write the value data to Default (passed
* as its context argument)
*/
RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE,
pDevInfo->ParametersKey,
Table,
&Default,
NULL);
/*
* whether or not the callback was called, Default now contains the
* correct value to return
*/
return(Default);
}
/*
* write a dword value to this device's section of the registry or profile.
* ValueName is a unicode string representing the registry value name or
* profile key, and ValueData is the dword data written. Returns TRUE if
* successfully written.
*/
BOOL
VC_WriteProfile(PDEVICE_INFO pDevInfo, PWCHAR ValueName, DWORD ValueData)
{
NTSTATUS Status;
if ((pDevInfo == NULL) || (pDevInfo->ParametersKey == NULL)) {
dprintf(("null devinfo - no registry path"));
return(FALSE);
}
Status = RtlWriteRegistryValue(
RTL_REGISTRY_ABSOLUTE,
pDevInfo->ParametersKey,
ValueName,
REG_DWORD,
&ValueData,
sizeof(DWORD));
if (!NT_SUCCESS(Status)) {
dprintf(("error 0x%x writing to registry", Status));
}
return(NT_SUCCESS(Status));
}
#if DBG
void
dbgPrintf(char * szFormat, ...)
{
char buf[256];
va_list va;
va_start(va, szFormat);
vsprintf(buf, szFormat, va);
va_end(va);
DbgPrint("VIDCAP: %s\n", buf);
}
#endif