Скачиваний:
20
Добавлен:
11.10.2020
Размер:
19.15 Кб
Скачать
/*
Copyright by 3S Smart Software Solutions GmbH, 87439 Kempten, Germany
Author: A. Fauter
*/

/*
This file is ready to use, but does nothing. 
The most important points in the code, that must be changed to create an own RTIOdriver are
marked with //TODO: 
*/


#include "ntddk.h"
#include "IOdrvInterface.h"
#include "CardFunctions.h"
#include "RTIOdrv.h"
#include "IODrvFunctions.h"
#include "Utils.h"

#define MAXIMUM_STRING_BUFFER 80

//globals to export
void* g_pDefaultDispatch = NULL;
RtsApiInterface g_rtsapi;
unsigned long g_ulShmLength = 0x1000;
PHYSICAL_ADDRESS g_paShmBuffer;
char* g_pcBufferAddrInAppl = NULL;
char* g_pcShmBuffer = NULL;

//forward decls
NTSTATUS ntDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
NTSTATUS ntCreateFile(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);
VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject);
NTSTATUS ntShutdown(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp);

// This is the definition for the routine, that will be called by the RT-PLC as a callback.
unsigned long ntCallback(CallbackInfo* pcbi, void* pPar)
{
	if(pcbi->ulSecurityId1 != 0x436F4465 || pcbi->ulSecurityId2 != 0x53797320)
	 	return STATUS_SUCCESS; /*This is not a CoDeSys-related programm, that calls the function.*/

	switch(pcbi->ulCommand)
	{
		case DRV_CMD_GET_FUNCTION_POINTER_LIST:
		{	//fill the functionpointerlist by using the defined indexes from enum FctIndices.
			void** ppfFctTable = pcbi->pAdditionalCmdData;
            void** ppfApiFctTable = (void*)pcbi->ulCmdParam;
            //fill the rtsapi-structure, believing that ulCmdParam points to an initialized list of functions.
            //doing this everytime the function is called is not necessary, but doing it once is too less,
            //because the PLC may be unloaded, while the IOdriver keeps running.....
            g_rtsapi.ulVersion = (unsigned long)ppfApiFctTable[API_FCT_ULVERSION];
            g_rtsapi.pfRtsStopAllTasks = ppfApiFctTable[API_FCT_STOP_ALL_TASKS];
            g_rtsapi.pfRtsStartAllTasks = ppfApiFctTable[API_FCT_START_ALL_TASKS];
            g_rtsapi.pfRtsGetPlcState = ppfApiFctTable[API_FCT_GET_PLC_STATE];
            g_rtsapi.pfRtsProgramLoaded = ppfApiFctTable[API_FCT_PROGRAM_LOADED];
            g_rtsapi.pfRtsGetInputMemory = ppfApiFctTable[API_FCT_GET_INPUT_MEMORY];
            g_rtsapi.pfRtsGetOutputMemory = ppfApiFctTable[API_FCT_GET_OUTPUT_MEMORY];
            g_rtsapi.pfRtsGetInputSize = ppfApiFctTable[API_FCT_GET_INPUTSIZE];
            g_rtsapi.pfRtsGetOutputSize = ppfApiFctTable[API_FCT_GET_OUTPUTSIZE];
            if((g_rtsapi.ulVersion & 0xffff) >= 1000)
            {
                g_rtsapi.pfRtsCreateTask = ppfApiFctTable[API_FCT_CREATE_TASK];
                g_rtsapi.pfRtsDeleteTask = ppfApiFctTable[API_FCT_DELETE_TASK];
                g_rtsapi.pfRtsWaitForObject = ppfApiFctTable[API_FCT_WAIT_FOR_OBJECT];
                g_rtsapi.pfRtsSetObject = ppfApiFctTable[API_FCT_SET_OBJECT];
                g_rtsapi.pfRtsSleep = ppfApiFctTable[API_FCT_SLEEP];
                g_rtsapi.pfAsynchFileOpen = ppfApiFctTable[API_FCT_OPENFILE];
                g_rtsapi.pfAsynchFileClose = ppfApiFctTable[API_FCT_CLOSEFILE];
                g_rtsapi.pfAsynchFileRead = ppfApiFctTable[API_FCT_READFILE];
                g_rtsapi.pfAsynchFileWrite = ppfApiFctTable[API_FCT_WRITEFILE];
                g_rtsapi.pfRtsResume = ppfApiFctTable[API_FCT_RESUME];
                g_rtsapi.pfRtsSuspend = ppfApiFctTable[API_FCT_SUSPEND];
                g_rtsapi.pfRtsProgramReset = ppfApiFctTable[API_FCT_PRGRESET];
                g_rtsapi.pfRtsDataManipulation = ppfApiFctTable[API_FCT_DATAMANIPULATION];
                g_rtsapi.pfRtsGetProjectInfo = ppfApiFctTable[API_FCT_GETPROJECTINFO];
                g_rtsapi.pfSrvComputeService = ppfApiFctTable[API_FCT_PFSRVCOMPUTESERVICE];
                g_rtsapi.pfSrvAddClient = ppfApiFctTable[API_FCT_PFSRVADDCLIENT];
                g_rtsapi.pfSrvDeleteClient = ppfApiFctTable[API_FCT_PFSRVDELETECLIENT];
                g_rtsapi.pfCsEnter = ppfApiFctTable[API_FCT_PFCSENTER];
                g_rtsapi.pfCsLeave = ppfApiFctTable[API_FCT_PFCSLEAVE];
                g_rtsapi.pfCsCreate = ppfApiFctTable[API_FCT_PFCSCREATE];
                g_rtsapi.pfCsDelete = ppfApiFctTable[API_FCT_PFCSDELETE];

            }


            //TODO: Insert the functions that should be called from the PLC instead of NULL.
            //Insert functions beginning with IODrv....
            //This is the layer that does the driver-specific work and calls the device-specific functions (IODev...)
			ppfFctTable[DRV_FCT_INIT] = IODrvInitIO;
			ppfFctTable[DRV_FCT_EXIT] = NULL;
			ppfFctTable[DRV_FCT_GET_ID] = IODrvGetId; //TODO:remember to change this function or minimum look at it!
			ppfFctTable[DRV_FCT_GET_FLAGS] = NULL;
			ppfFctTable[DRV_FCT_GET_IORANGE] = NULL;
			ppfFctTable[DRV_FCT_CONFIGURE_IONET] = NULL;
			ppfFctTable[DRV_FCT_CONFIGURE_MODULE] = NULL;
			ppfFctTable[DRV_FCT_CONFIGURE_DEVICE] = NULL;
			ppfFctTable[DRV_FCT_START_WRITE_OUTPUTS] = NULL;
			ppfFctTable[DRV_FCT_WRITE_OUTPUTS] = NULL;
			ppfFctTable[DRV_FCT_DONE_WRITE_OUTPUTS] = NULL;
			ppfFctTable[DRV_FCT_START_READ_INPUTS] = NULL;
			ppfFctTable[DRV_FCT_READ_INPUTS] = NULL;
			ppfFctTable[DRV_FCT_DONE_READ_INPUTS] = NULL;
			ppfFctTable[DRV_FCT_PLC_STATUS_CHANGES] = NULL;
			ppfFctTable[DRV_FCT_START_CONFIGURE_IONET] = NULL;
			ppfFctTable[DRV_FCT_DONE_CONFIGURE_IONET] = NULL;
            ppfFctTable[DRV_FCT_CYCLIC_CALL] = NULL;
            ppfFctTable[DRV_GET_EXTREFTABLE] = NULL;
            ppfFctTable[DRV_FCT_BUSDIAG_GETBUSSTATE] = NULL;
            ppfFctTable[DRV_FCT_BUSDIAG_GETSTATE] = NULL;
            ppfFctTable[DRV_FCT_BUSDIAG_SETBUSSTATE] = NULL;
            ppfFctTable[DRV_FCT_BUSDIAG_SETSTATE] = NULL;
            ppfFctTable[DRV_FCT_AFTERDOWNLOAD] = NULL;
            ppfFctTable[DRV_FCT_PLCRESETHOOK] = NULL; //Unused, just backward-compatibility, now use: CST_PROCESSHOOK
            ppfFctTable[DRV_FCT_PRECOMPUTE_SERVICE] = NULL;
            ppfFctTable[DRV_FCT_POSTCOMPUTE_SERVICE] = NULL;
            ppfFctTable[DRV_FCT_SRV_BROWSERCMD] = IODrvSrvBrowserCmds;
            ppfFctTable[DRV_FCT_ADD_BROWSERHELP] = IODrvAddBrowserhelp;
            ppfFctTable[DRV_FCT_CST_PROCESSHOOK] = NULL;
            ppfFctTable[DRV_FCT_GETTARGETIDS] = NULL; //IODrvGetTargetIds if you want to overwrite targetID.
                                                        //In this case, you must provide your own .trg-file!!
			break;
		}
        case DRV_CMD_VERSIONCHECK:
        {
            unsigned short us = (unsigned short)DRV_FCT_MAXINDEX;
            *(unsigned long*)pcbi->pAdditionalCmdData = (us << 16) | 2000; //pAdditionalCmdData points to a dword where the driver inserts its version.
                                                        //The HIWORD is the number of functionpointers, the driver will insert.
            break;    
        }
		case DRV_CMD_INVALID_CMD:
		default:
			return STATUS_SUCCESS; //what's that for a call?
	}

	return 1;
}


NTSTATUS ntCreateDevice(	IN	PDRIVER_OBJECT		pDriverObject,
							OUT	PDEVICE_OBJECT*		ppDeviceObject,
							OUT	void**	ppsExtension )
// PURPOSE
//	creates the device object for the driver
// ADDITIONAL INFORMATION
//	As I don't know what NTSTATUS values "IoCreateSymbolicLink" can return, I also don't know what
//	NTSTATUS values can be returned by this function.
// PARAMETERS
//	pDriverObject:	the driver's object
//	ppDeviceObject:	pointer to driver's device object - returned by this function, if successfull
//	ppsExtension:	the driver's device extension     - returned by this function, if successfull
// RETURN VALUE
//	STATUS_SUCCESS:	device object was successfully created
//	If the routine wasn't successfull then another NTSTATUS value is returned. Probably one of these:
//		STATUS_INSUFFICIENT_RESOURCES
//		STATUS_OBJECT_NAME_EXISTS
//		STATUS_OBJECT_NAME_COLLISION
{

    WCHAR          deviceNameBuffer[] = L"\\Device\\RTIOdrv"; //TODO: change to own drivername
                                                            //TODO: change #define MY_IODRV_NAME XXXXXX in IOdrvInterface.h also! 
    UNICODE_STRING deviceNameUnicodeString;
    WCHAR          deviceLinkBuffer[] = L"\\DosDevices\\RTIOdrv"; //TODO: change to own drivername
    UNICODE_STRING deviceLinkUnicodeString;
	NTSTATUS		ntStatus;		// return value / error code
	BOOLEAN	bHalRes = FALSE;
	unsigned long zero = 0;
	unsigned long ulBaseAddress = 0x0;
	unsigned long ulLength = 0;
	NTSTATUS ntsQueryRegRes = -1;
	
	// create device name and win32 device name strings
	RtlInitUnicodeString(&deviceNameUnicodeString, deviceNameBuffer);
	RtlInitUnicodeString(&deviceLinkUnicodeString, deviceLinkBuffer);

	// Create the device object:
	ntStatus = IoCreateDevice(
		pDriverObject,				// DriverObject created by IO Manager when driver was loaded
		20,	// DeviceExtensionSize  //TODO: change to your own device-extension-size
		&deviceNameUnicodeString,	// DeviceName
		FILE_DEVICE_RTIODRIVERthis,		// DeviceType
		0,							// DeviceCharacteristics
		FALSE,						// Exclusive
		ppDeviceObject );			// DeviceObject returned by the function

	if (!NT_SUCCESS(ntStatus))
	{
		// Creating device object failed.
		KdPrint(("IoCreateDevice failed."));
		return ntStatus;
	}


	// Create a link from our device name to a name in the Win32 namespace.
    ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,
                                         &deviceNameUnicodeString);
	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("IoCreateSymLink failed."));
		// Creating a symbolic link failed.
		IoDeleteDevice(*ppDeviceObject);
		*ppDeviceObject = NULL;
		return ntStatus;
	}

	// Fill in the device extension.
	*ppsExtension = (void*)((*ppDeviceObject)->DeviceExtension);

	return ntStatus;
} // ntCreateDevice


NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING ustrRegistryPath)
// PURPOSE
//	This routine is called, when the driver is loaded by the system.
// PARAMETERS
//	pDriverObject:		Pointer to the driver's object, that was created by the system.
//	ustrRegistryPath:	Path to the driver's registry entry.
// RETURN VALUE
//	STATUS_SUCCESS:	Everything upon driver initialization went fine and the driver is ready for IO.
{

	NTSTATUS			ntStatus;				// return value, also gets return values of calls to other functions
    PDEVICE_OBJECT		pDeviceObject	= NULL;	// pointer to device object
	void*	psExtension		= NULL;	// pointer to device extension

	KdPrint(("Entering DriverEntry.\r\n"));

	// initialize dispatch routines
	g_pDefaultDispatch = (void*)pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL];
	pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ntDeviceControl;
	pDriverObject->MajorFunction[IRP_MJ_CREATE        ] = ntCreateFile;
	pDriverObject->MajorFunction[IRP_MJ_SHUTDOWN      ] = ntShutdown;
#pragma warning(disable : 4028)
	pDriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ntCallback;
#pragma warning(default : 4028)
	pDriverObject->DriverUnload = DriverUnload;

	//initialize the functionpointers to the PLC with NULL, so it's sure, they're not called.
    memset((char*)&g_rtsapi,0,sizeof(g_rtsapi));

	// create device
	ntStatus = ntCreateDevice(pDriverObject, &pDeviceObject, &psExtension);
	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("Creating a symbolic link failed"));
		// Creating a symbolic link failed.
		return ntStatus;
	}

    g_paShmBuffer.u.HighPart = 0;
    g_paShmBuffer.u.LowPart = 0xffffffff;
    g_pcShmBuffer = MmAllocateContiguousMemory(g_ulShmLength,g_paShmBuffer);
    g_paShmBuffer = MmGetPhysicalAddress(g_pcShmBuffer);

	return STATUS_SUCCESS;
} // DriverEntry



NTSTATUS ntCreateFile(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
// PURPOSE
//	This routine is called, when a user mode app opens a handle to the driver by calling CreateFile.
//	It does all specific initializations for this opening process.
// PARAMETERS
//	pDriverObject:	pointer to the driver's object
//	pIrp:			pointer to the IRP for the IO call
// RETURN VALUE
//	STATUS_SUCCESS:	at the current state of development this is the only return value
{

	return STATUS_SUCCESS;
} 



VOID DriverUnload(IN PDRIVER_OBJECT pDriverObject)
// PURPOSE
//	This routine is called when the driver is unloaded (e.g. at system shutdown). It frees all
//	resources that the driver has locked.
// PARAMETERS
//	pDriverObject:	pointer to the driver's object, that was created by the system
{

    WCHAR          deviceLinkBuffer[] = L"\\DosDevices\\RTIOdrv"; //TODO: change to own driver name.
    UNICODE_STRING deviceLinkUnicodeString;
    BOOLEAN				bConflictDetected;		// needed for IoReportResourceUsage, set to true, if
												// resources have already been claimed by another device

    if(g_pcShmBuffer != NULL)
        MmFreeContiguousMemory(g_pcShmBuffer);

	// We don't need our resources anymore (ports and interrupt).
	IoReportResourceUsage(NULL, pDriverObject, NULL, 0, NULL, NULL, 0, FALSE, &bConflictDetected);

	// Delete the link from our device name to a name in the Win32 namespace.
	RtlInitUnicodeString(&deviceLinkUnicodeString, deviceLinkBuffer);
	IoDeleteSymbolicLink(&deviceLinkUnicodeString);

	// Finally delete our device object
	IoDeleteDevice(pDriverObject->DeviceObject);
} // DriverUnload


NTSTATUS ntDeviceControl(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
// PURPOSE
//	This routine is called, if a user mode app makes a call to DeviceIoControl.
// PARAMETERS
//	pDriverObject:	pointer to the driver's object
//	pIrp:			pointer to the IRP for the IO call
// RETURN VALUE
//	Returns a NTSTATUS value.
{

	NTSTATUS			ntStatus	= STATUS_SUCCESS;										// return value / get's return values from function calls
	void*	psExtension	= (void*)pDeviceObject->DeviceExtension;	// pointer to driver's device extension
	PIO_STACK_LOCATION	pIrpStack	= IoGetCurrentIrpStackLocation(pIrp);					// pointer to IRP's stack


	switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode)
	{
		//process a direct command, send by a call to DeviceIOControl from an application.
		case IOCTL_DIRECT_COMMAND:
            switch(((DirectCommand*)(pIrp->AssociatedIrp.SystemBuffer))->Cmd)
            {
                case RTS_CUSTOM_SERVICES:
                {
                    switch(((DirectCommand*)(pIrp->AssociatedIrp.SystemBuffer))->SubCmd)
        			{
                        case SUBCMD_GETSHMPOINTER:
                        {   
                            OBJECT_ATTRIBUTES objectAttributes;  
                            UNICODE_STRING physicalMemoryUnicodeString;
                            HANDLE physicalMemoryHandle;
                            NTSTATUS ntStatus;
                            PVOID virtualAddress = NULL;
                            LARGE_INTEGER laOffset;
                            unsigned long ulLength = g_ulShmLength;

                            if(ulLength)
                            {
                                laOffset.u.LowPart = g_paShmBuffer.u.LowPart;
                                laOffset.u.HighPart = 0;
                            
                                RtlInitUnicodeString (&physicalMemoryUnicodeString,
                                                      L"\\Device\\PhysicalMemory");

                                InitializeObjectAttributes (&objectAttributes,
                                                            &physicalMemoryUnicodeString,
                                                            OBJ_CASE_INSENSITIVE,
                                                            (HANDLE) NULL,
                                                            (PSECURITY_DESCRIPTOR) NULL);

                                ntStatus = ZwOpenSection (&physicalMemoryHandle,
                                                          SECTION_MAP_WRITE | SECTION_MAP_READ,
                                                          &objectAttributes);
                                if(NT_SUCCESS(ntStatus))
                                {
                                    ntStatus = ZwMapViewOfSection (physicalMemoryHandle,
                                                                   (HANDLE)-1,
                                                                   &virtualAddress,
                                                                   0L,
                                                                   ulLength,
                                                                   &laOffset,
                                                                   &ulLength,
                                                                   ViewShare,
                                                                   0,
                                                                   PAGE_READWRITE | PAGE_NOCACHE);
                                    ZwClose(physicalMemoryHandle);
                                
                                }
                            }
                            ((DirectCommand*)(pIrp->UserBuffer))->adpar.ulPar1 = (unsigned long)virtualAddress;
                            ((DirectCommand*)(pIrp->UserBuffer))->adpar.ulPar2 = g_ulShmLength = ulLength;
                            g_pcBufferAddrInAppl = virtualAddress;
                            pIrp->IoStatus.Information = 1;
                            break;
                        }
                        case SUBCMD_RELEASESHMPOINTER:
                        {
                            if(g_pcBufferAddrInAppl != NULL)
                                ZwUnmapViewOfSection((HANDLE)-1,g_pcBufferAddrInAppl);
                            pIrp->IoStatus.Information = 1;
                            break;   
                        }
                        default:
                            pIrp->IoStatus.Information = 0;
                            break;
                    }
                    break;
                }
		        default:
            	    pIrp->IoStatus.Information = 0;
                    break;
            }
			break;		 
		// unknown IOCTL code
		default:
		{
            ntStatus = STATUS_INVALID_PARAMETER;
			pIrp->IoStatus.Information = 0;
	 	}
	}

	pIrp->IoStatus.Status = ntStatus;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return ntStatus;
} // ntDeviceControl


NTSTATUS ntShutdown(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp)
// PURPOSE
//	Handles shutdown. Is called by the system before going down.
//		but only if a shutdownnotification has been registered.
// PARAMETERS
//	pDriverObject:	pointer to the driver's object
//	pIrp:			pointer to the IRP for the IO call
// RETURN VALUE
//	Returns a NTSTATUS value.
{		    

	
	return STATUS_SUCCESS;
}
Соседние файлы в папке IODriver ToolKit