/*M*
//                    INTEL CORPORATION PROPRIETARY INFORMATION
//      This software is supplied under the terms of a license agreement or
//      nondisclosure agreement with Intel Corporation and may not be copied
//      or disclosed except in accordance with the terms of that agreement.
//            Copyright (c) 1995-2000 Intel Corporation.  All Rights Reserved.
//
//  PVCS:
//      $Workfile:   imbapi.c  $
//      $Revision:   1.13  $
//      $Modtime:   27 Dec 1999 10:09:14  $
//      $Author:   jpaiasno  $
//
//  Purpose:    This file contains the main dll entry point that opens the MISMIC device in
//              order to issue the  MISMIC driver API related IOCTLs.
//              This file implements the MISMIC driver API for the Server Management Agents
//              (only read/write register functions in this file).  
//
//  
*M*/

/*
 * $Log:   //cospublic004/SharedData/ISC/ISC2x/ntwork/src/imbapi/imbapi.c.v  $
 * 
 *    Rev 1.13   27 Dec 1999 16:10:02   jpaiasno
 * Refined the logic related to creation of DPC 
 * named event object
 * 
 * 
 *    Rev 1.12   02 Sep 1999 11:03:16   jpaiasno
 * Fixed logic problem related to copying 
 * i2c response
 * 
 *    Rev 1.11   19 Aug 1999 11:38:20   sganeshx
 * 1. modified function 'UnRegisterForImbAsyncMessageNotification'
 *     to accept second parameter.
 * 
 *    Rev 1.10   27 Jul 1999 09:52:34   jpaiasno
 * Changed the size of BMC  communication buffer
 * to 64. This change was done to support all
 * IPMI 1.0 based commands.
 * 
 * 
 *    Rev 1.9   Jun 14 1999 11:07:22   sganeshx
 * 1. added  check for BMC in 'SendTimedImbpRequest'
 *     
 * 
 *    Rev 1.8   May 26 1999 18:30:12   sganeshx
 * 1. eliminate syntax error due to missing
 *     semicolon (only in Unix section).
 * 
 *    Rev 1.7   May 26 1999 17:22:56   sganeshx
 * 1. modified function 'open_mismic' to fix
 *     compilation errors because local variables
 *     were not defined
 * 
 *    Rev 1.6   May 07 1999 12:04:34   sganeshx
 * 1. added new constant for response length
 *     from Get Device ID command (IPMI v1.0)
 *     IPMI10_GET_DEVICE_ID_RESP_LENGTH
 * 
 * 2. use (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1)
 *     to check for IPMI version.
 * 
 *    Rev 1.5   04 May 1999 15:47:52   jpaiasno
 * Added IPMI 1.0 code to 'ImbGetAsyncMessage'
 * 
 *    Rev 1.4   28 Apr 1999 17:09:46   jpaiasno
 * Fixed the problem for NT as well as UnixWare
 * (response  length check to be >1 to account for completion code)
 * 
 *    Rev 1.3   28 Apr 1999 17:00:26   jpaiasno
 * fixed response data length check logic
 * in 'SendDataTimedImbp' function
 * 
 *    Rev 1.2   27 Apr 1999 14:15:16   jpaiasno
 * Added code to support IPMI 1.0 for IPMB
 * requests.
 * 
 *    Rev 1.1   08 Dec 1998 11:15:40   jpaiasno
 * Added code to support DPC related
 * Async. events from the EMP console
 */




#ifndef UNIX
#include <windows.h>
#endif

#define IMB_API

#ifndef UNIX
#include "..\imb\imb_if.h"
#include "..\imb\imb_log.h"
#endif  // not UNIX

#ifdef UNIX

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <synch.h>

#include "../ntio/inc/windows.h"
#include "../ntio/inc/smi.h"
#include "../ntio/driver/imb/imb_if.h"
#include "../ntio/driver/imb/imb_log.h"
#endif  // UNIX

#include "imbapi.h"

#ifndef UNIX
#include "..\imb\memIf.h"
#else   // UNIX
#include "../ntio/driver/imb/memif.h"
#endif  // UNIX

//keep it simple. use global varibles for event objects and handles
//pai 10/8

// UnixWare should eventually have its own source code file. Right now
// new code has been added based on the exsisting policy of using
// pre-processor directives to separate os-specific code (pai 11/21)

HANDLE  AsyncEventHandle = 0;
static void *  AsyncEventObject = 0; 
static  IpmiVersion;

/////////////////////////////////////////////////////////////////////////////////////////
//  GLOBAL VARIABLES
/////////////////////////////////////////////////////////////////////////////////////////

#ifdef UNIX

IO_STATUS_BLOCK NTstatus;
static HANDLE   hDevice1;
//mutex_t deviceMutex;

#endif  // UNIX

static HANDLE hDevice;

#ifndef UNIX

//////////////////////////////////////////////////////////////////////////////////////////////
// DllMain
//////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       DllMain 
//  Purpose:    To establish a link to the mismic device for each process that intends to use it.
//  Context:    Called when a process/thread attaches/detaches to this library.
//  Returns:    TRUE on success, FALSE on failure
//  Parameters: 
//      hDLL        handle of DLL
//      dwReason    indicates why DLL called
//      lpReserved  reserved
//  Notes:      none
*F*/                                                                                                                                                                    
BOOL WINAPI
DllMain (
		HINSTANCE hDLL,
		DWORD dwReason,
		LPVOID lpReserved
	)
{

	IMBPREQUESTDATA                requestData;
	BYTE						   respBuffer[16];
	DWORD						   respLength;
	BYTE						   completionCode;



	switch (dwReason) {
	case DLL_PROCESS_ATTACH:
		//
		// Open IMB driver device
		//
		hDevice = CreateFile(   "\\\\.\\Imb",
								GENERIC_READ | GENERIC_WRITE,
								FILE_SHARE_READ | FILE_SHARE_WRITE,
								NULL,
								OPEN_EXISTING,
								FILE_ATTRIBUTE_NORMAL,
								NULL
							);
		if (hDevice == NULL)
			return FALSE;

		//detect the IPMI version for processing requests later.
		// This is a crude but most reliable method to differentiate
		// between old IPMI versions and the 1.0 version. If we had used the
		// version field instead then we would have had to revalidate all the
		// older platforms (pai 4/27/99)
		
		requestData.cmdType            = GET_DEVICE_ID;
		requestData.rsSa               = BMC_SA;
		requestData.rsLun              = BMC_LUN;
		requestData.netFn              = APP_NETFN ;
		requestData.busType            = PUBLIC_BUS;
		requestData.data               = NULL; 
		requestData.dataLength			= 0;
		respLength					    = 16;

		if (
				 (SendTimedImbpRequest (
						&requestData,                
						(DWORD)400,
						 respBuffer, 
					     &respLength,    
						  &completionCode  
						)  != ACCESN_OK ) || ( completionCode != 0)
			)
		{
					CloseHandle(hDevice);
					return FALSE;
		}

		if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1))
			IpmiVersion = IPMI_09_VERSION;
		else
			IpmiVersion = IPMI_10_VERSION;

		break;

	case DLL_THREAD_ATTACH:
	  break;

	case DLL_THREAD_DETACH:
	  break;

	case DLL_PROCESS_DETACH:
		//
		// Close the IMB device
		//
		if(hDevice != INVALID_HANDLE_VALUE) 
			CloseHandle(hDevice);
		
		break;
	}
	return TRUE;
}

#else   // UNIX

////////////////////////////////////////////////////////////////////////////////
/////////////////
// open_mismic
////////////////////////////////////////////////////////////////////////////////
/////////////////
/*F*
//  Name:       open_mismic
//  Purpose:    To open mismic device
//  Context:    Called from each routine to make sure that open is done.
//  Returns:    returns 0 for Fail and 1 for Success, sets hDevice to open
//              handle.
//  Parameters: none
//  Notes:      none
*F*/

int open_mismic()
{
/* This routine will be called from all other routineds before doing any
   interfacing with mismic driver. It will open only once. */
	IMBPREQUESTDATA                requestData;
	BYTE						   respBuffer[16];
	DWORD						   respLength;
	BYTE						   completionCode;

  if(hDevice1 == 0)
  {


		    if ((hDevice1 = open("/dev/instru/mismic",O_RDWR|O_NDELAY)) <0) 
			{
				hDevice1  = 0;
				//   perror("mismic driver open failed\n");
				return (0);
			}	
			
			//detect the IPMI version for processing requests later.
			// This is a crude but most reliable method to differentiate
			// between old IPMI versions and the 1.0 version. If we had used the
			// version field instead then we would have had to revalidate all the
			// older platforms (pai 4/27/99)
		
			requestData.cmdType            = GET_DEVICE_ID;
			requestData.rsSa               = BMC_SA;
			requestData.rsLun              = BMC_LUN;
			requestData.netFn              = APP_NETFN ;
			requestData.busType            = PUBLIC_BUS;
			requestData.data               = NULL; 
			requestData.dataLength			= 0;
			respLength					    = 16;

			if (
				 (SendTimedImbpRequest (
						&requestData,                
						(DWORD)400,
						 respBuffer, 
					     &respLength,    
						  &completionCode  
						)  != ACCESN_OK ) || ( completionCode != 0)
			)
			{
					hDevice1 = 0;
					return (0);
			}

			if (respLength < (IPMI10_GET_DEVICE_ID_RESP_LENGTH-1))
				IpmiVersion = IPMI_09_VERSION;
			else
				IpmiVersion = IPMI_10_VERSION;


			
		
/*
//initialise a mutex
		if(mutex_init(&deviceMutex , USYNC_THREAD, NULL) != 0)
		{
			return(0);
		}

*/

	}
    

	return (1);
}


/////////////////////////////////////////////////////////////////////////////////////////////////
// DeviceIoControl 
/////////////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       DeviceIoControl 
//  Purpose:    Simulate NT DeviceIoControl using unix calls and structures.
//  Context:    called for every NT DeviceIoControl
//  Returns:    FALSE for fail and TRUE for success. Same as standarad NTOS call
//              as it also sets Ntstatus.status.
//  Parameters: Standard NT call parameters, see below.
//  Notes:      none
*F*/
static BOOL
DeviceIoControl(HANDLE dummey_hDevice, /* handle of device */
		DWORD dwIoControlCode, /* control code of operation to perform*/
		LPVOID lpvInBuffer, /* address of buffer for input data */
		DWORD cbInBuffer, /* size of input buffer */
		LPVOID lpvOutBuffer, /* address of output buffer */
		DWORD cbOutBuffer, /* size of output buffer */
		LPDWORD lpcbBytesReturned, /* address of actual bytes of output */
		LPOVERLAPPED lpoOverlapped) /* address of overlapped struct */
{
struct smi s;
int rc;

  rc = open_mismic();
  if (rc == 0) 
    {
    return FALSE;
    }

/*
//lock the mutex, before making the request....
	if(mutex_lock(&deviceMutex) != 0)
	{
		return(FALSE);
	}
*/
#ifdef UWDEBUG
	//printf("in deviceiocontrol\n");
#endif
  s.lpvInBuffer = lpvInBuffer;
  s.cbInBuffer = cbInBuffer;
  s.lpvOutBuffer = lpvOutBuffer;
  s.cbOutBuffer = cbOutBuffer;
  s.lpcbBytesReturned = lpcbBytesReturned;
  s.lpoOverlapped = lpoOverlapped;
  s.ntstatus = (LPVOID)&NTstatus;

  if (ioctl(hDevice1, dwIoControlCode,&s)<0) {
 //   perror("dismic Driver ioctl failed");
//      mutex_unlock(&deviceMutex);
    return FALSE;
    }
#ifdef UWDEBUG
//      printf("in deviceiocontrol 1\n");
#endif
//      mutex_unlock(&deviceMutex);
#ifdef UNIX
//       printf("msmcapi.c, address of parameters IN sendTimedImbRequest is %p \n", lpcbBytesReturned);
//       printf("msmcapi.c, NTstatus.Information is %d  \n", NTstatus.Information);
#endif  // UNIX
  *lpcbBytesReturned = NTstatus.Information;
  
  if (NTstatus.Status == STATUS_SUCCESS)
     {
#ifdef UNIX
//      printf("deviceiocontrol returning true\n");
#endif  // UNIX
     return (TRUE);
     }
  else
     {
#ifdef UNIX
//      printf("deviceiocontrol returning false\n");
#endif  // UNIX
     return (FALSE);
     }
}

ACCESN_STATUS
StartAsyncMesgPoll()
{

	DWORD   retLength;
	BOOL    status;
   
	status = DeviceIoControl (      hDevice,
								IOCTL_IMB_POLL_ASYNC,
								NULL,
								0,
								NULL,
								0,
								& retLength,
								0
							);
 
	if( status == TRUE ) {
		return ACCESN_OK;
	} else {
		return ACCESN_ERROR;
	}

}
#endif  // UNIX

/////////////////////////////////////////////////////////////////////////////////////////////////
// SendTimedI2cRequest
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       SendTimedI2cRequest 
//  Purpose:    This function sends a request to a I2C device
//  Context:    Used by Upper level agents (sis modules) to access dumb I2c devices 
//  Returns:    ACCESN_OK  else error status code
//  Parameters: 
//     reqPtr
//     timeOut
//     respDataPtr
//     respLen
//  Notes:      none
*F*/

ACCESN_STATUS
SendTimedI2cRequest (
		I2CREQUESTDATA *        reqPtr,                 // I2C request
		int                                     timeOut,                // how long to wait, mSec units
		BYTE *                          respDataPtr,    // where to put response data
		int *                           respDataLen,    // size of response buffer/size of returned data
		BYTE *                          completionCode  // request status from BMC
	)
{
	BOOL                            status;


	#ifndef UNIX

	HANDLE hEvt ;
	OVERLAPPED ovl ;

	#endif
   

	
    BYTE                                responseData[MAX_IMB_RESP_SIZE];
	ImbResponseBuffer *     resp = (ImbResponseBuffer *) responseData;
	DWORD                           respLength = sizeof( responseData );

    BYTE                                requestData[MAX_IMB_RESP_SIZE];
	ImbRequestBuffer *      req = (ImbRequestBuffer *) requestData;

	struct WriteReadI2C {                           // format of a write/read I2C request
		BYTE    busType;
		BYTE    rsSa;
		BYTE    count;
		BYTE    data[1];
	} * wrReq = (struct WriteReadI2C *) req->req.data;

#define MIN_WRI2C_SIZE  3       // size of write/read request minus any data
	//
	// If the Imb driver is not present return AccessFailed
	//
#ifndef UNIX
	if( hDevice == INVALID_HANDLE_VALUE )
		return ACCESN_ERROR;


	hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
	if (!hEvt) {
		return ACCESN_ERROR;
	}

	ovl.hEvent = hEvt ;
	ResetEvent (hEvt) ;

#endif  // UNIX





	req->req.rsSa           = BMC_SA;
	req->req.cmd            = WRITE_READ_I2C;
	req->req.netFn          = APP_NETFN;
	req->req.rsLun          = BMC_LUN;
	req->req.dataLength     = reqPtr->dataLength + MIN_WRI2C_SIZE;

	wrReq->busType          = reqPtr->busType;
	wrReq->rsSa                     = reqPtr->rsSa;
	wrReq->count            = reqPtr->numberOfBytesToRead;
	
	memcpy( wrReq->data, reqPtr->data, reqPtr->dataLength );

	req->flags      = 0;
	req->timeOut    = timeOut * 1000;       // convert to uSec units

#ifndef UNIX

	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );



		if (!status && (GetLastError() == ERROR_IO_PENDING)) {
					WaitForSingleObject (hEvt, INFINITE) ;
					ResetEvent (hEvt) ;
		} else {

			    if (!status && (GetLastError() != ERROR_IO_PENDING))
				   {
					   CloseHandle(hEvt);
						return ACCESN_ERROR;
					}


		}



	if ( ( GetOverlappedResult(hDevice,      
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength <= 0)
		)
	{

		CloseHandle(hEvt);
		return ACCESN_ERROR;

	}
		
	
	//
	// give the caller his response
	//
	*completionCode = resp->cCode;
	*respDataLen    = respLength - 1;

	if(( *respDataLen > 0) && (respDataPtr))
		memcpy( respDataPtr, resp->data, *respDataLen);

	CloseHandle(hEvt);

	return ACCESN_OK;
#endif

#ifdef UNIX



		status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								NULL
							  );

	if( status != TRUE ) {
		DWORD error = GetLastError();
		return ACCESN_ERROR;
	}
	if( respLength == 0 ) {
		return ACCESN_ERROR;
	}
	//
	// give the caller his response
	//
	*completionCode = resp->cCode;
	*respDataLen    = respLength - 1;

	if(( *respDataLen ) && (respDataPtr))
		memcpy( respDataPtr, resp->data, *respDataLen);

	return ACCESN_OK;


#endif

}

//This is not a  API exported by the driver in stricter sense. It is added to support
// EMP functionality. Upper level software could have implemented this function.(pai 5/4/99)
/////////////////////////////////////////////////////////////////////////////////////////////////
// SendTimedEmpMessageResponse
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       SendTimedEmpMessageResponse 
//  Purpose:    This function sends a response message to the EMP port
//  Context:     
//  Returns:    OK  else error status code
//  Parameters: 
//  
//  Notes:      none
*F*/



ACCESN_STATUS
SendTimedEmpMessageResponse (

		ImbPacket *      ptr,           // pointer to the original request from EMP
		char      *responseDataBuf,
		int        responseDataLen,
		int         timeOut         // how long to wait, in mSec units
	)
{
	BOOL                            status;

	#ifndef UNIX

	HANDLE hEvt ;
	OVERLAPPED ovl ;
	#endif  // not UNIX

   


    BYTE                                responseData[MAX_IMB_RESP_SIZE];
	ImbResponseBuffer *     resp = (ImbResponseBuffer *) responseData;
	DWORD                           respLength = sizeof( responseData );

    BYTE                                requestData[MAX_IMB_RESP_SIZE];
	ImbRequestBuffer *      req = (ImbRequestBuffer *) requestData;
	int i,j;
	//
	// If the Imb driver is not present return AccessFailed
	//

#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;

	hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
	if (!hEvt) {
		return ACCESN_ERROR;
	}

	ovl.hEvent = hEvt ;
	ResetEvent (hEvt) ;

#endif


	//form the response packet first



	req->req.rsSa           =  BMC_SA;
	if (IpmiVersion ==	IPMI_09_VERSION)
	req->req.cmd            =  WRITE_EMP_BUFFER;
	else 
	req->req.cmd            =  SEND_MESSAGE;	
	req->req.netFn          =  APP_NETFN;
	req->req.rsLun          =  0;

	i = 0;
	if (IpmiVersion !=	IPMI_09_VERSION)
		req->req.data[i++] 	= EMP_CHANNEL;
		
	req->req.data[i++]    =  ptr->rqSa;
	req->req.data[i++]      =  (((ptr->nfLn & 0xfc) | 0x4) | ((ptr->seqLn) & 0x3));
	if (IpmiVersion ==	IPMI_09_VERSION)
		req->req.data[i++]    = ((~(req->req.data[0] +  req->req.data[1])) +1);
	else
		req->req.data[i++]    = ((~(req->req.data[1] +  req->req.data[2])) +1);

	req->req.data[i++]      =  BMC_SA; //though software is responding, we have to
								   //provide BMC's slave address as responder
								   //address.
	
	req->req.data[i++]      = ( (ptr->seqLn & 0xfc) | (ptr->nfLn & 0x3) );

	req->req.data[i++]      = ptr->cmd;
	for ( j = 0 ; j < responseDataLen ; ++j,++i)
	   req->req.data[i] = responseDataBuf[j];

	 req->req.data[i] = 0;
	 if (IpmiVersion ==	IPMI_09_VERSION)
		 j = 0;
	 else 
		 j = 1;
	for ( ; j < ( i -3); ++j)
		 req->req.data[i] += req->req.data[j+3];
	req->req.data[i]  = ~(req->req.data[i]) +1;
	++i;
	req->req.dataLength     = i;

	req->flags      = 0;
	req->timeOut    = timeOut * 1000;       // convert to uSec units

#ifndef UNIX


	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof(requestData),
								responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );


		if (!status && (GetLastError() == ERROR_IO_PENDING)) {
					WaitForSingleObject (hEvt, INFINITE) ;
					ResetEvent (hEvt) ;
		} else {

				    if (!status && (GetLastError() != ERROR_IO_PENDING))
					   {
						   CloseHandle(hEvt);
							return ACCESN_ERROR;
						}


		}



	

	if ( ( GetOverlappedResult(hDevice,      
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength != 1) || (responseData[0] != 0)
					
		)

		{

			CloseHandle(hEvt);
			return ACCESN_ERROR;

		}



		
	CloseHandle(hEvt);

	return ACCESN_OK;







#else


	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof(requestData),
								responseData,
								sizeof( responseData ),
								& respLength,
								NULL
							  );



	if ( (status != TRUE) || (respLength != 1) || (responseData[0] != 0) )
					
			{

			
			return ACCESN_ERROR;

		}



		
	return ACCESN_OK;


#endif









}












/////////////////////////////////////////////////////////////////////////////////////////////////
// SendTimedImbpRequest
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       SendTimedImbpRequest 
//  Purpose:    This function sends a request for BMC implemented function
//  Context:    Used by Upper level agents (sis modules) to access BMC implemented functionality. 
//  Returns:    OK  else error status code
//  Parameters: 
//     reqPtr
//     timeOut
//     respDataPtr
//     respLen
//  Notes:      none
*F*/
ACCESN_STATUS
SendTimedImbpRequest (
		IMBPREQUESTDATA *reqPtr,                // request info and data
		int                             timeOut,                // how long to wait, in mSec units
		BYTE *                  respDataPtr,    // where to put response data
		int *                   respDataLen,    // how much response data there is
		BYTE *                  completionCode  // request status from dest controller
	)
{
	BOOL                            status;


   #ifndef UNIX
    HANDLE hEvt;
	OVERLAPPED ovl ;
   #endif


    BYTE                                responseData[MAX_BUFFER_SIZE];
	ImbResponseBuffer *     resp = (ImbResponseBuffer *) responseData;
	DWORD                           respLength = sizeof( responseData );

    BYTE                                requestData[MAX_BUFFER_SIZE];
	ImbRequestBuffer *      req = (ImbRequestBuffer *) requestData;
	//
	// If the Imb driver is not present return AccessFailed
	//

#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;



	hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
	if (!hEvt) {
		return ACCESN_ERROR;
	}

	ovl.hEvent = hEvt ;
	ResetEvent (hEvt) ;

#endif



	req->req.rsSa           = reqPtr->rsSa;
	req->req.cmd            = reqPtr->cmdType;
	req->req.netFn          = reqPtr->netFn;
	req->req.rsLun          = reqPtr->rsLun;
	req->req.dataLength     = reqPtr->dataLength;

	memcpy( req->req.data, reqPtr->data, reqPtr->dataLength );

	req->flags              = 0;
	req->timeOut    = timeOut * 1000;       // convert to uSec units


#ifndef UNIX


	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );




	if (!status && (GetLastError() == ERROR_IO_PENDING)) {
					WaitForSingleObject (hEvt, INFINITE) ;
					ResetEvent (hEvt) ;
		} else {

				    if (!status && (GetLastError() != ERROR_IO_PENDING))
					   {
						   CloseHandle(hEvt);
							return ACCESN_ERROR;
						}


		}



	

	if ( ( GetOverlappedResult(hDevice,      
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength <= 0)
		)

		{

			CloseHandle(hEvt);
			return ACCESN_ERROR;

		}



	//
	// give the caller  response
	//
	*completionCode = resp->cCode;
	*respDataLen = 0;

    if(( respLength > 1) && ( respDataPtr))
	{
		*respDataLen    = respLength - 1;
		memcpy( respDataPtr, resp->data, *respDataLen);
			
	}

	CloseHandle(hEvt);


	return ACCESN_OK;

#endif


#ifdef UNIX

	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								NULL
							  );

	if( status != TRUE ) {
		DWORD error = GetLastError();
		return ACCESN_ERROR;
	}
	if( respLength == 0 ) {
		return ACCESN_ERROR;
	}
	//
	// give the caller his response
	//
  


	*completionCode = resp->cCode;
	*respDataLen    = 0;

        if(( respLength > 1 ) && ( respDataPtr))
		{
			*respDataLen    = respLength - 1;
			memcpy( respDataPtr, resp->data, *respDataLen);
		}

	return ACCESN_OK;
#endif


}


/////////////////////////////////////////////////////////////////////////////////////////
//SendAsyncImbpRequest
/////////////////////////////////////////////////////////////////////////////////////////
//
// Send an IMB request that we don't expect to get a response to
//
/////////////////////////////////////////////////////////////////////////////////////////////////
// SendAsyncImbpRequest
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       SendAsyncImbpRequest
//  Purpose:    This function sends a request for Asynchronous IMB implemented function
//  Context:    Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. 
//  Returns:    OK  else error status code
//  Parameters: 
//     reqPtr  Pointer to Async IMB request
//     seqNo   Sequence Munber
//  Notes:      none
*F*/
ACCESN_STATUS
SendAsyncImbpRequest (
		IMBPREQUESTDATA *reqPtr,                // request info and data
		BYTE *                  seqNo                   // IMB sequence number used when creating IMB msg
	)
{

	#ifndef UNIX

		HANDLE hEvt ;
		OVERLAPPED ovl ;
	#endif
   


	BOOL                            status;

    BYTE                                responseData[MAX_IMB_RESP_SIZE];
	ImbResponseBuffer *     resp = (ImbResponseBuffer *) responseData;
	DWORD                           respLength = sizeof( responseData );

    BYTE                                requestData[MAX_IMB_RESP_SIZE];
	ImbRequestBuffer *      req = (ImbRequestBuffer *) requestData;
	//
	// If the Imb driver is not present return AccessFailed
	//
#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;
#endif  // not UNIX

	req->req.rsSa           = reqPtr->rsSa;
	req->req.cmd            = reqPtr->cmdType;
	req->req.netFn          = reqPtr->netFn;
	req->req.rsLun          = reqPtr->rsLun;
	req->req.dataLength     = reqPtr->dataLength;

	memcpy( req->req.data, reqPtr->data, reqPtr->dataLength );

	req->flags              = NO_RESPONSE_EXPECTED;
	req->timeOut    = 0;    // no timeouts for async sends

#ifndef UNIX

	hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
	if (!hEvt) {
		return ACCESN_ERROR;
	}

	ovl.hEvent = hEvt ;
	ResetEvent (hEvt) ;



	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );



	if (!status && (GetLastError() == ERROR_IO_PENDING)) {
					WaitForSingleObject (hEvt, INFINITE) ;
					ResetEvent (hEvt) ;
		} else {

				    if (!status && (GetLastError() != ERROR_IO_PENDING))
					   {
						   CloseHandle(hEvt);
							return ACCESN_ERROR;
						}


		}



	

	if ( 
		( GetOverlappedResult(hDevice,   
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength <= 0)
		)

		{

			CloseHandle(hEvt);
			return ACCESN_ERROR;

		}



	if( respLength != 2 ) {
		CloseHandle(hEvt);
		return ACCESN_ERROR;
	}
	//
	// give the caller his sequence number
	//
	*seqNo = resp->data[0];
	CloseHandle(hEvt);

	return ACCESN_OK;


#else


	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SEND_MESSAGE,
								requestData,
								sizeof( requestData ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								NULL
							  );

	if( status != TRUE ) {
		DWORD error = GetLastError();
		return ACCESN_ERROR;
	}
	if( respLength != 2 ) {
		return ACCESN_ERROR;
	}
	//
	// give the caller his sequence number
	//
	*seqNo = resp->data[0];

	return ACCESN_OK;

#endif



}

/////////////////////////////////////////////////////////////////////////////////////////
//GetAsyncImbpMessage
/////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       GetAsyncImbpMessage
//  Purpose:    This function gets the next available async message with a message id
//                              greater than SeqNo. The message looks like an IMB packet
//                              and the length and Sequence number is returned
//  Context:    Used by Upper level agents (sis modules) to access Asynchronous IMB implemented functionality. 
//  Returns:    OK  else error status code
//  Parameters: 
//     msgPtr  Pointer to Async IMB request
//     msgLen  Length 
//     timeOut Time to wait 
//     seqNo   Sequence Munber
//  Notes:      none
*F*/

ACCESN_STATUS
GetAsyncImbpMessage (
		ImbPacket *             msgPtr,         // request info and data
		DWORD *                 msgLen,         // IN - length of buffer, OUT - msg len
		DWORD                   timeOut,        // how long to wait for the message
		ImbAsyncSeq *			 seqNo,           // previously returned seq number (or ASYNC_SEQ_START)
		DWORD					channelNumber
	)
{

#ifndef UNIX


	HANDLE hEvt ;
	OVERLAPPED ovl ;

#endif


   

	BOOL                            status;

    BYTE                   responseData[MAX_ASYNC_RESP_SIZE], lun;
	ImbAsyncResponse *      resp = (ImbAsyncResponse *) responseData;
	DWORD                           respLength = sizeof( responseData );

	ImbAsyncRequest         req;

	while(1)
	{
		//
		// If the Imb driver is not present return AccessFailed
		//


		#ifndef UNIX
			if(hDevice == INVALID_HANDLE_VALUE)
				return ACCESN_ERROR;
		#endif // not UNIX

		if( (msgPtr == NULL) || (msgLen == NULL) || ( seqNo == NULL) )
				return ACCESN_ERROR;

				req.timeOut             = timeOut * 1000;       // convert to uSec units
				req.lastSeq             = *seqNo;


		#ifndef UNIX
				hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
				if (!hEvt) {
					return ACCESN_ERROR;
				}

				ovl.hEvent = hEvt ;
				ResetEvent (hEvt) ;



				status = DeviceIoControl(       hDevice,
								IOCTL_IMB_GET_ASYNC_MSG,
								& req,
								sizeof( req ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );

				if( status != TRUE ) {
						DWORD error = GetLastError();
					//
					// handle "msg not available" specially. it's different from
					// a random old error.
					//
					//
									if (!status)
										{
											switch (error )
												{
													case ERROR_IO_PENDING:
			
														WaitForSingleObject (hEvt, INFINITE) ;
														ResetEvent (hEvt) ;
														break;

													case IMB_MSG_NOT_AVAILABLE:

															CloseHandle(hEvt);
															return ACCESN_END_OF_DATA;

													default:
															CloseHandle(hEvt);
															return ACCESN_ERROR;
								
												}
										}


					}
					if ( 
						( GetOverlappedResult(hDevice,   
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength <= 0)
					)

					{
		
							CloseHandle(hEvt);
							return ACCESN_ERROR;

					}



	
				if( respLength < MIN_ASYNC_RESP_SIZE ) {
					CloseHandle(hEvt);
				return ACCESN_ERROR;
			}

		respLength -= MIN_ASYNC_RESP_SIZE;

		if( *msgLen < respLength ) {

					// The following code should have been just return ACCESN_OUT_OF_RANGE
					SetLastError( IMB_RESPONSE_DATA_OVERFLOW );

					CloseHandle(hEvt);
					return ACCESN_ERROR;
		}

	

		if ( IpmiVersion == IPMI_09_VERSION)
			{

				switch( channelNumber) {

							case IPMB_CHANNEL:

								lun = IPMB_LUN;
								 break;

							case  EMP_CHANNEL:
								lun = EMP_LUN;
								  break;

							default:
								
								lun = RESERVED_LUN;
								 break;


				}

				if ( (lun == RESERVED_LUN) || (lun !=  ((((ImbPacket *)(resp->data))->nfLn) & 0x3 )) )
							{
									*seqNo = resp->thisSeq;
									continue;
									
							}


							memcpy( msgPtr, resp->data, respLength );
							*msgLen = respLength;
				
			
			}	else {
			//it's a 1.0 or  above version 	

						if (resp->data[0] != (BYTE)channelNumber)
							{
								*seqNo = resp->thisSeq;
								continue;
							}

							memcpy( msgPtr, &(resp->data[1]), respLength-1 );
							*msgLen = respLength-1;
						

		}

	
		//
		// give the caller his sequence number
		//
		*seqNo = resp->thisSeq;

		CloseHandle(hEvt);


		return ACCESN_OK;

		#else

			status = DeviceIoControl(       hDevice,
								IOCTL_IMB_GET_ASYNC_MSG,
								& req,
								sizeof( req ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								NULL
							  );

			if( status != TRUE ) {
								DWORD error = GetLastError();
								//
								// handle "msg not available" specially. it's different from
								// a random old error.
								//
									switch( error ) {
													case IMB_MSG_NOT_AVAILABLE:
																return ACCESN_END_OF_DATA;
													default:
																return ACCESN_ERROR;
									}
								return ACCESN_ERROR;
			}
			if( respLength < MIN_ASYNC_RESP_SIZE ) {
					return ACCESN_ERROR;
			}
			respLength -= MIN_ASYNC_RESP_SIZE;

			if( *msgLen < respLength ) {
					return ACCESN_ERROR;
		}


			//same code as in NT section
			if ( IpmiVersion == IPMI_09_VERSION)
			{

				switch( channelNumber) {

							case IPMB_CHANNEL:

								lun = IPMB_LUN;
								 break;

							case  EMP_CHANNEL:
								lun = EMP_LUN;
								  break;

							default:
								
								lun = RESERVED_LUN;
								 break;


				}

				if ( (lun == RESERVED_LUN) || (lun !=  ((((ImbPacket *)(resp->data))->nfLn) & 0x3 )) )
							{
									*seqNo = resp->thisSeq;
									continue;
									
							}


							memcpy( msgPtr, resp->data, respLength );
							*msgLen = respLength;
				
			
			}	else {
			//it's a 1.0 or  above version 	

						if (resp->data[0] != (BYTE)channelNumber)
							{
								*seqNo = resp->thisSeq;
								continue;
							}

							memcpy( msgPtr, &(resp->data[1]), respLength-1 );
							*msgLen = respLength-1;
						

		}

	
		


	
		//
		// give the caller his sequence number
		//
		*seqNo = resp->thisSeq;

		return ACCESN_OK;

	#endif


	} //while (1) 



}

  



/////////////////////////////////////////////////////////////////////////////////////////
//IsAsyncMessageAvailable
/////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       IsMessageAvailable
//  Purpose:    This function waits for an Async Message  
//
//  Context:    Used by Upper level agents access Asynchronous IMB based
//              messages   
//  Returns:    OK  else error status code
//  Parameters: 
//               eventId
//    
//  Notes:     This call will block the calling thread if no Async events are 
//                              are available in the queue.
//
*F*/
ACCESN_STATUS
IsAsyncMessageAvailable (unsigned int   eventId )
{


    int dummy;
    int respLength = 0;
      BOOL  status;

 // confirm that       app is not using a bad Id


if (  AsyncEventHandle  != (HANDLE) eventId)
	  return ACCESN_ERROR;

#ifndef UNIX
 
  WaitForSingleObject (AsyncEventHandle, INFINITE) ;
  ResetEvent (AsyncEventHandle) ;
  return ACCESN_OK;


#else
status = DeviceIoControl(hDevice,
				   IOCTL_IMB_CHECK_EVENT,
				   &AsyncEventHandle,
				    sizeof(HANDLE ),
				    &dummy,
					sizeof(int),
					(LPDWORD) & respLength,
					NULL
				  );

		if( status != TRUE )
			return  ACCESN_ERROR;

	
return ACCESN_OK;

#endif





}


//I have retained this commented code because later we may want to use DPC message specific
//Processing (pai 11/21)

/////////////////////////////////////////////////////////////////////////////////////////
//GetAsyncDpcMessage
/////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       GetAsyncDpcMessage
//  Purpose:    This function gets the next available async message from
//                              the DPC client. 
//
//  Context:    Used by Upper level agents access Asynchronous IMB based
//              messages sent by the DPC client.  
//  Returns:    OK  else error status code
//  Parameters: 
//     msgPtr  Pointer to Async IMB request
//         msgLen  Length 
//         timeOut Time to wait 
//     seqNo   Sequence Munber
//  Notes:     This call will block the calling thread if no Async events are 
//                              are available in the queue.
//
*F*/

/*
ACCESN_STATUS
GetAsyncDpcMessage (
		ImbPacket *             msgPtr,         // request info and data
		DWORD *                 msgLen,         // IN - length of buffer, OUT - msg len
		DWORD                   timeOut,        // how long to wait for the message
		ImbAsyncSeq *   seqNo,          // previously returned seq number (or ASYNC_SEQ_START)
	)
{

	HANDLE hEvt ;
	OVERLAPPED ovl ;
   

	BOOL                            status;

    BYTE                                responseData[MAX_ASYNC_RESP_SIZE];
	ImbAsyncResponse *      resp = (ImbAsyncResponse *) responseData;
	DWORD                           respLength = sizeof( responseData );

	ImbAsyncRequest         req;
	//
	// If the Imb driver is not present return AccessFailed
	//
#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;
#endif // not UNIX

	if( msgPtr == NULL || msgLen == NULL || seqNo == NULL )
		return ACCESN_ERROR;

	req.lastSeq             = *seqNo;


	hEvt = CreateEvent (NULL, TRUE, FALSE, NULL) ;
	if (!hEvt) {
		return ACCESN_ERROR;
	}

	ovl.hEvent = hEvt ;
	ResetEvent (hEvt) ;



	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_GET_DPC_MSG,
								& req,
								sizeof( req ),
								& responseData,
								sizeof( responseData ),
								& respLength,
								&ovl
							  );

	if( status != TRUE ) {
		DWORD error = GetLastError();
		//
		// handle "msg not available" specially. it's different from
		// a random old error.
		//
		//
	if (!status)
	{
			switch (error )
				{
						case ERROR_IO_PENDING:

								WaitForSingleObject (hEvt, INFINITE) ;
								ResetEvent (hEvt) ;
								break;

						case IMB_MSG_NOT_AVAILABLE:

							    CloseHandle(hEvt);
								return ACCESN_END_OF_DATA;

						default:
								CloseHandle(hEvt);
								return ACCESN_ERROR;
								
			}
	}



		if ( 
		( GetOverlappedResult(hDevice,   
							&ovl,    
							(LPDWORD)&respLength, 
							TRUE 
					) == 0 ) || (respLength <= 0)
		)

		{

			CloseHandle(hEvt);
			return ACCESN_ERROR;

		}



	
	if( respLength < MIN_ASYNC_RESP_SIZE ) {
		CloseHandle(hEvt);
		return ACCESN_ERROR;
	}

	respLength -= MIN_ASYNC_RESP_SIZE;

	if( *msgLen < respLength ) {

		// The following code should have been just return ACCESN_out_of_range
#ifndef UNIX
		SetLastError( IMB_RESPONSE_DATA_OVERFLOW );
#endif
		CloseHandle(hEvt);
		return ACCESN_ERROR;
	}

	memcpy( msgPtr, resp->data, respLength );

	*msgLen = respLength;
	//
	// give the caller his sequence number
	//
	*seqNo = resp->thisSeq;

	CloseHandle(hEvt);


	return ACCESN_OK;
}

*/


/////////////////////////////////////////////////////////////////////////////////////////
//RegisterForImbAsyncMessageNotification
/////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       RegisterForImbAsyncMessageNotification
//  Purpose:    This function Registers the calling application  
//                              for Asynchronous notification when a sms message
//                              is available with the IMB driver.                       
//
//  Context:    Used by Upper level agents to know that an async
//                              SMS message is available with the driver.  
//  Returns:    OK  else error status code
//  Parameters: 
//    handleId  pointer to the registration handle
//
//  Notes:      The calling application should use the returned handle to 
//              get the Async messages..
*F*/
ACCESN_STATUS
RegisterForImbAsyncMessageNotification (unsigned int *handleId)

{

	
  
	BOOL                            status;

	DWORD                           respLength ;

	int                                     dummy;

	


		//allow  only one app to register 

	if( (handleId  == NULL ) || (AsyncEventHandle) )
		return ACCESN_ERROR;



	//
	// If the Imb driver is not present return AccessFailed
	//
#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;
	// Originaly I thought of using Win32 based sync . object. 
    // Though it is supported in 3.51, it has a serious problem with
    // baseboard service getting killed abruptly  and leaving the kernel reference
	// intact. In that case any signaling from kernel side can lead to
	// a blue screen . A named kernel object is a better choice
	// as we do not have to support NT 3.51 (pai 12/07)



	AsyncEventHandle = OpenEvent (SYNCHRONIZE, FALSE, "AsyncSignalEvt") ;

	if (AsyncEventHandle == NULL)
	{
		//Problem related to creation of  named kernel event object 
		//observed in WIN2000 environment (during initialization of driver)
		//So we check if it can be created here (pai 12/26/99)

		status = DeviceIoControl(hDevice,
								IOCTL_IMB_REGISTER_ASYNC_OBJ,
								&dummy,
								sizeof( int ),
								&AsyncEventHandle,
								(DWORD)sizeof(HANDLE ),
								(LPDWORD) & respLength,
								NULL
							  );

		if( status != TRUE )
			return  ACCESN_ERROR;

		// success, so again we try to create the ring3 equivelent 
		AsyncEventHandle = OpenEvent (SYNCHRONIZE, FALSE, "AsyncSignalEvt") ;

		if (AsyncEventHandle == NULL)
				return ACCESN_ERROR;
	}


    


	*handleId = (unsigned int) AsyncEventHandle;
	

	return ACCESN_OK;

#else

		status = DeviceIoControl(hDevice,
								IOCTL_IMB_REGISTER_ASYNC_OBJ,
								&dummy,
								sizeof( int ),
								&AsyncEventHandle,
								(DWORD)sizeof(HANDLE ),
								(LPDWORD) & respLength,
								NULL
							  );

		if( (respLength != sizeof(int))  || (status != TRUE ))
			return  ACCESN_ERROR;

		*handleId = (unsigned int) AsyncEventHandle;
	
		return ACCESN_OK;


#endif




}





/////////////////////////////////////////////////////////////////////////////////////////
//UnRegisterForImbAsyncMessageNotification
/////////////////////////////////////////////////////////////////////////////////////////
/*F*
//  Name:       UnRegisterForImbAsyncMessageNotification
//  Purpose:    This function un-registers the calling application  
//                              for Asynchronous notification when a sms message
//                              is available with the IMB driver.                       
//
//  Context:    Used by Upper level agents to un-register
//                              for  async. notification of sms messages  
//  Returns:    OK  else error status code
//  Parameters: 
//    handleId  pointer to the registration handle
//	  iFlag		value used to determine where this function was called from
//				_it is used currently on in NetWare environment_
//
//  Notes:      
*F*/
ACCESN_STATUS
UnRegisterForImbAsyncMessageNotification (unsigned int handleId, int iFlag)

{

	

	BOOL                            status;
	DWORD                           respLength ;
	int								dummy;


	iFlag = iFlag;	/* to keep compiler happy */

	if (  AsyncEventHandle  != (HANDLE) handleId)
	  return ACCESN_ERROR;

#ifndef UNIX
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;
 // not UNIX

	//allow the app to register once only
/*
	if( handleId != (unsigned int)AsyncEventHandle ) 
		return ACCESN_ERROR;

 
	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_DEREGISTER_ASYNC_OBJ,
								&AsyncEventObject,
								(DWORD)sizeof( void * ),
								&AsyncEventObject,
								(DWORD)sizeof( void * ),
								(LPDWORD) & respLength,
								NULL
							  );


	
	if (status != TRUE)
		return ACCESN_ERROR;
  */
    if (AsyncEventHandle == 0)
		return ACCESN_ERROR;

	CloseHandle(AsyncEventHandle);
	AsyncEventHandle = 0;
	AsyncEventObject = 0;

	/*

	status = DeviceIoControl(hDevice,
								IOCTL_IMB_DEREGISTER_ASYNC_OBJ,
								&AsyncEventHandle,
								(DWORD)sizeof(HANDLE ),
								&dummy,
								(DWORD)sizeof(int ),
								(LPDWORD) & respLength,
								NULL
							  );

		if( status != TRUE )
			return  ACCESN_ERROR;

	
		return ACCESN_OK;

    */

#else
		status = DeviceIoControl(hDevice,
								IOCTL_IMB_DEREGISTER_ASYNC_OBJ,
								&AsyncEventHandle,
								(DWORD)sizeof(HANDLE ),
								&dummy,
								(DWORD)sizeof(int ),
								(LPDWORD) & respLength,
								NULL
							  );

		if( status != TRUE )
			return  ACCESN_ERROR;


	#endif


	
		return ACCESN_OK;


	
}






/////////////////////////////////////////////////////////////////////////////////////////
// SetShutDownCode
/////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       SetShutDownCode
//  Purpose:    To set the shutdown  action code
//  Context:    Called by the System Control Subsystem
//  Returns:    none
//  Parameters: 
//              code  shutdown action code which can be either
//                    SD_NO_ACTION, SD_RESET, SD_POWER_OFF as defined in imb_if.h

*F*/
		
ACCESN_STATUS 
SetShutDownCode (
		int delayTime,  // time to delay in 100ms units
		int code                // what to do when time expires
	)
{   
	DWORD                           retLength;
	BOOL                            status;
	ShutdownCmdBuffer       cmd;

	//
	// If Imb driver is not present return AccessFailed
	//
	if(hDevice == INVALID_HANDLE_VALUE)
		return ACCESN_ERROR;

	cmd.code                = code;
	cmd.delayTime   = delayTime;

	status = DeviceIoControl(       hDevice,
								IOCTL_IMB_SHUTDOWN_CODE,
								& cmd,
								sizeof( cmd ),
								NULL,
								0,
								& retLength,
								NULL
							  );

	if(status == TRUE)
		return ACCESN_OK;
	else
		return ACCESN_ERROR;
}


#ifndef UNIX

/////////////////////////////////////////////////////////////////////////////////////////////////
// MapPhysicalMemory 
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       MapPhysicalMemory 
//  Purpose:    This function maps specified range of physical memory in calling 
//              pocesse's address space
//  Context:    Used by Upper level agents (sis modules) to access system physical memory 
//  Returns:    ACCESN_OK  else error status code
//  Parameters: 
//     
//     startAddress   starting physical address of the  memory to be mapped 
//     addressLength  length of the physical memory to be mapped
//     virtualAddress pointer to the mapped virtual address
//  Notes:      none
*F*/
ACCESN_STATUS
MapPhysicalMemory (
		int startAddress,       // physical address to map in
		int addressLength,      // how much to map
		int *virtualAddress     // where it got mapped to
	)
{
	PHYSICAL_MEMORY_INFO pmi;
	DWORD                retLength;
	BOOL                 status;
   
	if ( startAddress == (int) NULL || addressLength <= 0 )
		return ACCESN_OUT_OF_RANGE;

	pmi.InterfaceType       = Internal;
	pmi.BusNumber           = 0;
	pmi.BusAddress.HighPart = (LONG)0x0;
	pmi.BusAddress.LowPart  = (LONG)startAddress;
	pmi.AddressSpace        = (LONG) 0;
	pmi.Length              = addressLength;

	status = DeviceIoControl (      hDevice,
								IOCTL_IMB_MAP_MEMORY,
								& pmi,
								sizeof(PHYSICAL_MEMORY_INFO),
								virtualAddress,
								sizeof(PVOID),
								& retLength,
								0
							);
	if( status == TRUE ) {
		return ACCESN_OK;
	} else {
		return ACCESN_ERROR;
	}
}

/////////////////////////////////////////////////////////////////////////////////////////////////
// UnmapPhysicalMemory 
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       UnMapPhysicalMemory 
//  Purpose:    This function unmaps the previously mapped physical memory
//  Context:    Used by Upper level agents (sis modules)  
//  Returns:    ACCESN_OK  else error status code
//  Parameters: 
//     
//     virtualAddress pointer to the mapped virtual address
//  Notes:      none
*F*/
ACCESN_STATUS
UnmapPhysicalMemory (
		int virtualAddress      // what memory to unmap
	)
{
	DWORD   retLength;
	BOOL    status;
   
	status = DeviceIoControl (      hDevice,
								IOCTL_IMB_UNMAP_MEMORY,
								& virtualAddress,
								sizeof(PVOID),
								NULL,
								0,
								& retLength,
								0
							);
 
	if( status == TRUE ) {
		return ACCESN_OK;
	} else {
		return ACCESN_ERROR;
	}
}

#else   // not UNIX
/////////////////////////////////////////////////////////////////////////////////////////////////
// MapPhysicalMemory 
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       MapPhysicalMemory 
//  Purpose:    This function maps specified range of physical memory in calling 
//              pocesse's address space
//  Context:    Used by Upper level agents (sis modules) to access system physical memory 
//  Returns:    ACCESN_OK  else error status code
//  Parameters: 
//     
//     startAddress   starting physical address of the  memory to be mapped 
//     addressLength  length of the physical memory to be mapped
//     virtualAddress pointer to the mapped virtual address
//  Notes:      none
*F*/
ACCESN_STATUS
MapPhysicalMemory(int startAddress,int addressLength, int *virtualAddress )

{
   
	int fd,i;
	unsigned int length = addressLength;
	caddr_t startpAddress = startAddress;
	unsigned int diff;
	caddr_t startvAddress;

	if ((startAddress == (int) NULL) || (addressLength <= 0))
		return ACCESN_ERROR;

	fd = open("/dev/mem", O_RDONLY);
	if(fd < 0 )
	{
		//perror("could not open file\n");
		return ACCESN_ERROR ;

	}

	/* aliging the offset to a page boundary and adjusting the length */
	diff = (int)startpAddress % PAGESIZE;
	startpAddress -= diff;
	length += diff;


	startvAddress = mmap((caddr_t)0, length, PROT_READ, MAP_SHARED, fd, startpAddress);
	if(startvAddress == -1)
	{
#ifdef UWDEBUG
		//perror("mmap failed \n");
#endif
		close(fd);
		return ACCESN_ERROR;
	}
/*
	for(i=0; i < length; i++)
	{

	{

		printf("%x\n", (startvAddress[i]));
		if(isascii(startvAddress[i]))
		{
		printf("%c\n", (startvAddress[i]));
		}
	}
	} */

	*virtualAddress = startvAddress + diff;
	return ACCESN_OK;

}
/////////////////////////////////////////////////////////////////////////////////////////////////
// UnmapPhysicalMemory 
/////////////////////////////////////////////////////////////////////////////////////////////////

/*F*
//  Name:       UnMapPhysicalMemory 
//  Purpose:    This function unmaps the previously mapped physical memory
//  Context:    Used by Upper level agents (sis modules)  
//  Returns:    ACCESN_OK  else error status code
//  Parameters: 
//     
//     addressLength  length of the physical memory to be mapped
//     virtualAddress pointer to the mapped virtual address
//  Notes:      none
*F*/
ACCESN_STATUS
UnmapPhysicalMemory( int virtualAddress, int Length )
{

	unsigned int diff = 0;

/* page align the virtual address and adjust length accordingly */

	
	diff =((unsigned int) virtualAddress) % PAGESIZE;
	virtualAddress -= diff;
	Length += diff;

#ifdef UWDEBUG
	printf("in unmapphysicalmemory, just before callinf munmap\n");
#endif
	if(munmap((caddr_t)virtualAddress, Length) != 0)
	{
		//perror("unmap failed!!!!!!!!!!!\n");
		return ACCESN_ERROR;

	}

	return ACCESN_OK;

}

#endif  // UNIX
