/* * mckernel.h * * 32-bit Motion Control Device Driver * * Definition of interface between hardware-specific portions of * kernel driver and the helper library mckernel.lib * * The hardware-specific portion of a motion control driver will * have an NT-specific DriverEntry function that will call Init() * to initialise the helper library after performing hardware detect and * initialise. All NT interaction will then be done by the library mckernel.lib * calling back to the hardware-specific code only through the dispatch * table below. * * All h/w specific functions are given a pointer to a PDEVICE_INFO structure * which they can pass to Inp(), Outp(). GetHWInfo() will return a * pointer to the hardware-specific data structure requested from Init(). * */ #ifndef _MCKERNEL_ #define _MCKERNEL_ /* include necessary headers so that hardware-specific callers do not * explicitly reference NT-specific headers. */ #if defined(_NT) #include #else typedef long NTSTATUS; #endif #include #include #include #ifdef _OLD_DLL #define PT_PMAC1 1 #define PT_PMAC2 2 #define PT_PMACUL 3 #define PT_PMAC 4 #define PT_PMAC1T 5 #define PT_PMAC2T 6 #define PT_PMACUT 7 #define PT_UMAC 8 #endif /***************************************************************************** * hardware-independent device-extension data structure - opaque to * h/w specific functions. *****************************************************************************/ typedef struct _DEVICE_INFO DEVICE_INFO, *PDEVICE_INFO; /***************************************************************************** Callbacks to h/w specific code These are the hardware-specific functions called from the dispatcher *****************************************************************************/ typedef struct __CALLBACK { // called on device open/close - optional routines BOOLEAN (*DeviceOpenFunc)(PDEVICE_INFO); BOOLEAN (*DeviceCloseFunc)(PDEVICE_INFO); BOOLEAN (*InterruptInitFunc)(PDEVICE_INFO pDevInfo, ULONG interruptMask); BOOLEAN (*InterruptTermFunc)(PDEVICE_INFO); // returns TRUE if Interrupt needs Service ULONG (*InterruptAcknowledge)(PDEVICE_INFO); // called on driver-unload BOOLEAN (*CleanupFunc)(PDEVICE_INFO); } _CALLBACK, * P_CALLBACK; /***************************************************************************** Support functions for NT *****************************************************************************/ #if defined(_NT) /* * PmacCreateDevice * * Create the device object, and any necessary related setup, and * allocate device extension data. The device extension data is * a DEVICE_INFO struct plus however much data the caller wants for * hardware-specific data. * * parameters: * pDriverObject - pointer to driver object (arg to DriverEntry) * RegistryPathName - entry for this driver in registry (arg to DriverEntry) * HWInfoSize - amount of data to allocate at end of DeviceExtension * DeviceNumber - the nth Pmac to create a device object for * * returns pointer to device extension data as DEVICE_INFO struct. */ PDEVICE_OBJECT PmacCreateDevice( PDRIVER_OBJECT pDriverObject, PUNICODE_STRING RegistryPathName, ULONG HWInfoSize, UCHAR DeviceNumber); PDEVICE_INFO PmacDeleteDevice(PDRIVER_OBJECT pDriverObject,PDEVICE_INFO pDevInfo); /* * GetResources * * map port and frame buffer into system address space or i/o space, and * report resource usage of the ports, interrupt and physical memory * address used. * * Note: We do not connect the interrupt: this is not done until * a subsequent call to ConnectInterrupt(). We do, however, report * usage of the interrupt. * * we return TRUE if success, or FALSE if we couldn't get the resources. */ BOOLEAN GetResources( PDEVICE_INFO pDevInfo, PDRIVER_OBJECT pDriverObject, DWORD PortBase, ULONG NrOfPorts, ULONG Interrupt, BOOLEAN bLatched, DWORD FrameBuffer); // the dispatch routine to which all IRPs go NTSTATUS Dispatch( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ); // cancel routine - set as cancel routine for pending irps (wait-error // or add-buffer). Called to de-queue and complete them if cancelled. VOID Cancel( IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp ); // call to unload or abort load of the driver VOID Cleanup(PDRIVER_OBJECT pDriverObject); /* 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 InterruptService( IN PKINTERRUPT pInterruptObject, IN PVOID Context ); /* * DPC routine scheduled in MC_InterruptService. */ VOID Deferred( PKDPC pDpc, PDEVICE_OBJECT pDeviceObject, PIRP pIrpNotUsed, PVOID Context ); /* * extract the next item from a cancellable queue of irps * if bCancelHeld is true, then we already hold the cancel spinlock so we * should not try to get it */ PIRP ExtractNextIrp( PLIST_ENTRY pQueueHead, BOOLEAN bCancelHeld ); /* * extract a specific IRP from the given queue, while possibly holding the * cancel spinlock already. */ PIRP ExtractThisIrp( PLIST_ENTRY pHead, PIRP pIrpToFind, BOOLEAN bCancelHeld ); /* * interlocked queue access functions */ /* * QueueRequest * * Add an irp to a cancellable queue. * Check the cancel flag and return FALSE if cancelled. * otherwise set the cancel routine and add to queue. * */ BOOLEAN QueueRequest( PIRP pIrp, PLIST_ENTRY pQueueHead, PDRIVER_CANCEL pCancelFunc ); /* * ReplaceRequest * * return a request to the head of a cancellable queue * */ BOOLEAN ReplaceRequest( PIRP pIrp, PLIST_ENTRY pQueueHead, PDRIVER_CANCEL pCancelFunc ); /* * increment the skipcount, and complete a wait-error irp if there * is one waiting. */ VOID ReportSkip( PDEVICE_INFO pDevInfo ); /* * queue a wait-error request to the queue of cancellable wait-error requests, * and return the irp's status (pending, cancelled, etc); * * When queuing, check the cancel flag and insert the correct cancel routine. * * If there is a skip-count to report, then: * --- if there is another irp on the q already complete that and leave * the current irp pending. * -- otherwise return STATUS_SUCCESSFUL for this IRP, having written out * the result data. * * Even if cancelled or complete, IoCompleteRequest will NOT have been called * for this request. */ NTSTATUS QueueWaitError( PDEVICE_INFO pDevInfo, PIRP pIrp ); /***************************************************************************** *****************************************************************************/ #endif // _NT /* * ConnectInterrupt * * This assumes that GetResources() has already been called to report the * resource usage, and that the _CALLBACK table has been set up * to handle interrupts. * * returns TRUE if success. */ BOOLEAN ConnectInterrupt( PDEVICE_INFO pDevInfo, BOOLEAN bLatched); // get the hardware specific portion of the device extension PVOID GetHWInfo(PDEVICE_INFO); // get card information stored for user retrieval LONG atol(PCHAR s,PCHAR *ep); // like strtol int GetRomDate(PDEVICE_INFO pDevInfo); int GetRomVersion(PDEVICE_INFO pDevInfo); BOOL GetLinkList(PDEVICE_INFO pDevInfo); BOOL GetLDSList(PDEVICE_INFO pDevInfo); int GetIVariableStr(PDEVICE_INFO pDevInfo,PCHAR str,UINT maxchar,UINT num); int GetPmacType(PDEVICE_INFO pDevInfo); DWORD SetMaxMotors(PDEVICE_INFO pDevInfo); LONG GetIVariableLong(PDEVICE_INFO pDevInfo,ULONG num,LONG def); BOOL SetIVariableLong(PDEVICE_INFO pDevInfo,ULONG num,LONG val); BOOL GetScales(PDEVICE_INFO pDevInfo); int GetDPRAMAddress(PDEVICE_INFO pDevInfo,PDWORD adr); BOOL ConfigureDPRAM(PDEVICE_INFO pDevInfo); int SaveConfiguration(PDEVICE_INFO pDevInfo); //============================================================================ // PORT Related macro,defines and functions #define PORT_STALL_USEC 5 // usec stall per retry period // determine if PMAC card can be found on this port address BOOL CardOnPort(PDEVICE_INFO pDevInfo); //---------------------------------------------------------------------------------- // Specialized flush, determines if PMAC is in the bus. // THEORY: If no card exists in bus at the specified i/o address then it // will appear that there is an infinite amount of characters of type // 0xFF to be stripped. This function is useful to initiate communication // on the bus since a deadlock situation may occur otherwise. //---------------------------------------------------------------------------------- BOOL PmacPingAndClean(PDEVICE_INFO pDevInfo); // output one byte from the port at bOffset offset from the port base address VOID Outp(PDEVICE_INFO pDevInfo, BYTE bOffset, BYTE bData); // input one byte from the port at bOffset offset from the port base address BYTE Inp(PDEVICE_INFO pDevInfo, BYTE bOffset); // flush bus port void FlushPort(PDEVICE_INFO pDevInfo); // write a character to PMAC bus port int WriteCharPort(PDEVICE_INFO pDevInfo, UCHAR outchar); // write buffer to bus port int WriteLinePort(PDEVICE_INFO pDevInfo,PUCHAR str); // see if port has a read ready BOOL PortIsReadReady(PDEVICE_INFO pDevInfo); // read bus port into buffer until eol with wait int ReadLinePort(PDEVICE_INFO pDevInfo,PUCHAR str,UINT maxchar); // send a command then read bus port into buffer until eot or err or timeout int GetResponsePort(PDEVICE_INFO pDevInfo,PUCHAR s,UINT maxchar, PUCHAR outstr); // Get response to control characters int GetControlResponse(PDEVICE_INFO pDevInfo ,CHAR inChar, PCHAR outStr,DWORD maxChars); //============================================================================ // MEMORY Related macro,defines and functions #define MEM_STALL_USEC 5 // usec stall per retry period /* The macros below are based on this PMAC DPRAM ASCII structure struct ascii { unsigned short sendready:1; // Y:$D18B output control word 0x62C unsigned short pad:15; unsigned short ctrlchar; // X:$D18B control character char outstr[MAXAOUT]; // $D18C - $D1B3 output string buffer unsigned short instatus; // Y:$D1B4 input control word 0x6D0 unsigned short charcount; // X:$D1B4 input character count char instr[MAXAIN]; // $D1B5 - $D1F4 input string buffer }; */ // Turbo ASCII memory port macros --------------------------------------------- // Base = 0x0E9C #define SENDREADY_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xE9C)) == 0) #define NOT_SENDREADY_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xE9C)) > 0) #define SET_SENDREADY_T (WRITE_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xE9C),1)) #define CTRL_CHAR_T (PUCHAR)(pDevInfo->FrameBase + 0xE9E) #define READREADY_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) > 0) #define NOT_READREADY_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) == 0) #define FLUSH_ACK_READY_T ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) & 0x001F) == 0x0018) #define SET_READREADY_T (WRITE_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40),0)) #define ERROR_SET_T ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) & 0x8000) > 0) #define ERROR_T (((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40))) & 0x0F) + \ (((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40))) >> 4) & 0x0F) * 10) #define NUM_CHARS_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF42)) - 1) #define MEM_ACK_T ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) & 0x000F) == 0x0006) #define MEM_CR_T ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) & 0x000F) == 0x000D) #define MEM_PMACREADY_T (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40))) #define MEM_USR_T ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0xF40)) & 0x0300) != 0) // Pmac1/2 ASCII memory port macros --------------------------------------------- // Base = 0x062C #define SENDREADY (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x62C)) == 0) #define NOT_SENDREADY (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x62C)) > 0) #define SET_SENDREADY (WRITE_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x62C),1)) #define CTRL_CHAR (PUCHAR)(pDevInfo->FrameBase + 0x62E) #define READREADY (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) > 0) #define NOT_READREADY (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) == 0) #define FLUSH_ACK_READY ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) & 0x001F) == 0x0018) #define SET_READREADY (WRITE_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0),0)) #define ERROR_SET ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) & 0x8000) > 0) #define ERROR2 (((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0))) & 0x0F) + \ (((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0))) >> 4) & 0x0F) * 10) #define NUM_CHARS (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D2)) - 1) #define MEM_ACK ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) & 0x000F) == 0x0006) #define MEM_CR ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) & 0x000F) == 0x000D) #define MEM_PMACREADY (READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0))) #define MEM_USR ((READ_REGISTER_USHORT((PUSHORT)(pDevInfo->FrameBase + 0x6D0)) & 0x0300) != 0) // determine if PMAC card has DPRAM and can communicate through it BOOL CardHasMem(PDEVICE_INFO pDevInfo); // configure card memory address void ConfigureMem(PDEVICE_INFO pDevInfo); // Get a portion of DPRAM UINT GetMem(PDEVICE_INFO pDevInfo,PBYTE pbData,WORD wDprOffset,WORD wLength); // Set a portion of DPRAM UINT SetMem(PDEVICE_INFO pDevInfo,PBYTE pbData,WORD wDprOffset,WORD wLength); // Get a bit from DPRAM DWORD UINT GetMemBit(PDEVICE_INFO pDevInfo,PMEM_BUFFER_BIT pMemBufferBits); // Set a bit DPRAM DWORD UINT SetMemBit(PDEVICE_INFO pDevInfo,PMEM_BUFFER_BIT pMemBufferBits); // Get a bit range of DPRAM DWORD UINT GetMemBits(PDEVICE_INFO pDevInfo,PMEM_BUFFER_BITS pMemBufferBits); // Set a bit range of DPRAM DWORD UINT SetMemBits(PDEVICE_INFO pDevInfo,PMEM_BUFFER_BITS pMemBufferBits); // flush mem port void FlushMem(PDEVICE_INFO pDevInfo); // write a character to pmac dpram ascii port (ie. 'ch' + '\0') UINT WriteCharMem(PDEVICE_INFO pDevInfo,UCHAR outchar); // write a control character to pmac dpram ascii port UINT WriteCtrlCharMem(PDEVICE_INFO pDevInfo,UCHAR outchar); // write a character to frame ASCII buffer UINT WriteLineMem(PDEVICE_INFO pDevInfo,PUCHAR str); // see if dpram port has a read ready BOOL MemIsReadReady(PDEVICE_INFO pDevInfo); //---------------------------------------------------------------------------- // see what DPRAM is ready with, send,cmd,ack,err //---------------------------------------------------------------------------- WORD MemIsReadReadyEx(PDEVICE_INFO pDevInfo); // read frame memory into buffer until eol with wait int ReadLineMem(PDEVICE_INFO pDevInfo,PUCHAR str); //---------------------------------------------------------------------------------- // This function sends the requested control character between 1 - 26 to the // PMAC. If the request is known not to return any characters it sets the EOT // status bit then exits immediately to avoid any timeout. If the request is known // to return "1" line of data the function grabs the data then returns with EOT set. // If the funtion returns "n" lines of data the function doesn't attempt to grab // any data and doesn't set the EOT status so it is up to the caller to grab the data //----------------------------------------------------------------------------------- int GetControlResponseMem(PDEVICE_INFO pDevInfo ,CHAR inChar,PCHAR outStr,DWORD maxChars); /* * i/o memory on adapter cards such as the frame buffer memory cannot * be accessed like ordinary memory on all processors (especially alpha). * You must read and write this memory using the following macros. These are * wrappers for the appropriate NT macros. */ // return one ULONG from the frame buffer at p #ifdef i386 #define ReadIOMemoryULONG(p) ( * (DWORD volatile *)p) // return a word from the frame buffer at p #define ReadIOMemoryUSHORT(p) ( * (USHORT volatile *)p) // return a byte from the frame buffer at p #define ReadIOMemoryBYTE(p) ( * (unsigned char volatile *) p) #else #define ReadIOMemoryULONG(p) READ_REGISTER_ULONG((PUCHAR)p) // return a word from the frame buffer at p #define ReadIOMemoryUSHORT(p) READ_REGISTER_USHORT((PUCHAR)p) // return a byte from the frame buffer at p #define ReadIOMemoryBYTE(p) READ_REGISTER_UCHAR(p) #endif // read a block of c bytes from the frame buffer at s to memory at d #define ReadIOMemoryUCHAR(d, s, c) READ_REGISTER_BUFFER_UCHAR(s, d, c) // write a byte b to the frame buffer at p #define WriteIOMemoryBYTE(p, b) WRITE_REGISTER_UCHAR(p, b) // write a word w to the frame buffer at p #define WriteIOMemoryUSHORT(p, w) WRITE_REGISTER_USHORT((PUSHORT)p, w) // write a ULONG l to the frame buffer at p #define WriteIOMemoryULONG(p, l) WRITE_REGISTER_ULONG((PULONG)p, l) // write a block of c bytes to the frame buffer d from memory at s #define WriteIOMemoryUCHAR(d, s, c) WRITE_REGISTER_BUFFER_UCHAR(d, s, c) P_CALLBACK GetCallbackTable(PDEVICE_INFO); /* get a pointer to the frame buffer mapped into system memory */ PUCHAR GetFrameBuffer(PDEVICE_INFO); /* this function is a wrapper for KeSynchronizeExecution (at least in the NT * version). It will call back the function specified with the context * argument specified, having first disabled the video interrupt in * a multi-processor safe way. */ typedef BOOLEAN (*PSYNC_ROUTINE)(PVOID); BOOLEAN SynchronizeExecution(PDEVICE_INFO, PSYNC_ROUTINE, PVOID); /* * This function can be used like 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 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 SynchronizeDPC(PDEVICE_INFO, PSYNC_ROUTINE, PVOID); /* * 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. * * This function cannot be called from the InterruptAcknowledge or * ServiceCapture call back functions - it must be running in the * context of the calling thread (in kernel mode). */ typedef BOOLEAN (*PACCESS_ROUTINE)(PDEVICE_INFO, PUCHAR, ULONG, PVOID); BOOLEAN AccessData(PDEVICE_INFO, PUCHAR, ULONG, PACCESS_ROUTINE, PVOID); /* these functions allocate and free non-paged memory for use * in kernel mode, including at interrupt time. */ PVOID AllocMem(PDEVICE_INFO, ULONG); VOID FreeMem(PDEVICE_INFO, PVOID, ULONG); /* * delay for a number of milliseconds. This is accurate only to * +- 15msecs at best. */ VOID Delay(int nMillisecs); /* block for given number of microseconds by polling. Not recommended * for more than 25 usecs. */ VOID Stall(int nMicrosecs); #endif // _MCKERNEL_