/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Copyright (c) 2001. Samsung Electronics, co. ltd  All rights reserved.

Module Name:  

   socket.c
   
Abstract:  

Rev:
	2002.04.22	: add S3C2410 specific initialization codes (by Seung-han, Lim)
	2001.12.21	: Bug Fixup (kwangyoon LEE, kwangyoon@samsung.com)
	2001.12.12	: add S3C2400 Specific codes (kwangyoon LEE, kwangyoon@samsung.com)
		
Notes: 
--*/

#include <windows.h>
#include <types.h>
#include <cardserv.h>
#include <sockserv.h>
#include <sockpd.h>
#include <memory.h>
//#include <pc.h>

#include "S2440.H"
#include "pd6710.h"


//#define FORCE_POLLING 1

//
// CEPC PCMCIA Socket Services Socket APIs:
//    PDCardInquireSocket
//    PDCardGetSocket
//    PDCardSetSocket
//    PDCardInquireAdapter
//

#define NUM_SOCKETS 1
#define NUM_POWER_ENTRIES 4
#define VCC_DEFAULT_INDEX 2



//
// @doc DRIVERS
//

PDCARD_ADAPTER_INFO v_AdapterInfo = {
	1,				// memory granularity (for production platforms, this should be 1)
	0,				// adapter capabilities
	8,				// cache line size in 32-bit words
	NUM_POWER_ENTRIES
};

PDCARD_POWER_ENTRY v_PowerEntries[NUM_POWER_ENTRIES] = {
	{ 0,    PWR_SUPPLY_VCC | PWR_SUPPLY_VPP1 | PWR_SUPPLY_VPP2 },
	{ 33,   PWR_SUPPLY_VCC },
	{ 50,   PWR_SUPPLY_VCC | PWR_SUPPLY_VPP1 | PWR_SUPPLY_VPP2 },
	{ 120,  PWR_SUPPLY_VPP1 | PWR_SUPPLY_VPP2 }
};

PDCARD_SOCKET_STATE v_SockState[NUM_SOCKETS] = {
{
	SOCK_CAP_IO,
#ifdef FORCE_POLLING
	EVENT_MASK_BATTERY_DEAD|EVENT_MASK_BATTERY_LOW|
#else
	EVENT_MASK_BATTERY_DEAD|EVENT_MASK_BATTERY_LOW|EVENT_MASK_CARD_DETECT|
#endif
        EVENT_MASK_WRITE_PROTECT,	// status change interrupt mask
	0,				// present socket state
	0,				// control and indicators
	0,				// interface type
	0,				// Vcc
	0,				// Vpp1
	0				// Vpp2
},
};

//volatile PUCHAR g_PCICIndex;
//volatile PUCHAR g_PCICData;
//CRITICAL_SECTION g_PCIC_Crit;
extern volatile PUCHAR g_PCICIndex;
extern volatile PUCHAR g_PCICData;
extern CRITICAL_SECTION g_PCIC_Crit;

extern DWORD g_Irq;			// PCMCIA IRQ set in init.c

//extern volatile int BackupFlag;
//extern void PD_DataBackup();
extern void PD_DataRestore();

//
// Set the socket controller registers to initial state with no card inserted.
//
VOID InitSocketNoCard(UINT32 uSocket, BOOL bUserMode)
{
	UCHAR tmp;
	UINT32 status; 
	UINT32 i; 
	UINT32 first, last;
	PDCARD_WINDOW_STATE WinState;

	DEBUGMSG (1,(TEXT("++InitSocketNoCard #%x\n\r"), uSocket));
	//RETAILMSG(1, (TEXT("PDD:SOCKET.C:InitSocketNoCard()\r\n")));

	PCICIndex(uSocket, REG_POWER_CONTROL);
	PCICDataWrite(PWR_AUTO_POWER);

	// PD6710 specific code to enable management interrupt(routed to -INTR)

	tmp = CFG_CARD_DETECT_ENABLE;
	PCICIndex(uSocket, REG_STATUS_CHANGE_INT_CONFIG);
	PCICDataWrite(tmp);

	// Enable Manage Interrupt
	PCICIndex(0, REG_INTERRUPT_AND_GENERAL_CONTROL);
	tmp = PCICDataRead();
	tmp |= INT_ENABLE_MANAGE_INT;
	PCICDataWrite(tmp);

	//
	// Disable the I/O windows
	//
	first = (uSocket == 0) ? SOCKET0_FIRST_IO_WINDOW : SOCKET1_FIRST_IO_WINDOW;
	last = first + 2;
	for (i = first; i < last; i++) 
	{
		status = PDCardGetWindow(i, &WinState);
		if (status == CERR_SUCCESS) 
		{
			WinState.fState &= ~WIN_STATE_ENABLED;
			WinState.uOffset = 0;
			// set the high bit in the window index if we are in kernel-mode
			PDCardSetWindow(bUserMode ? i : (i|ADP_STATE_KERNEL_MODE), &WinState);
		}
	}
	DEBUGMSG (1,(TEXT("--InitSocketNoCard\n\r")));
}

//
// PDCardGetSocket
//
// @func    STATUS | PDCardGetSocket | Get the socket state of the specified socket.
// @rdesc   Returns one of the CERR_* return codes in cardserv.h.
//
// @comm    This function reads the specified socket's state and returns it in
//          the PDCARD_SOCKET_STATE structure.
//
STATUS
PDCardGetSocket(UINT32 uSocket,			// @parm Socket number (first socket is 0)
		PPDCARD_SOCKET_STATE pState)	// @parm Pointer to PDCARD_SOCKET_STATE structure
{	
	UINT8 tmp;
	PPDCARD_SOCKET_STATE pPDDState;

	DEBUGMSG(1,(TEXT("+++PDCardGetSocket\r\n")));
	if (uSocket >= NUM_SOCKETS) 
	{
		return CERR_BAD_SOCKET;
	}

	pPDDState = &v_SockState[uSocket];
    
	EnterCriticalSection(&g_PCIC_Crit);

	pPDDState->fNotifyEvents = 0;        // Start off with nothing

	//
	// First acknowledge any status change interrupts
	//
	PCICIndex(uSocket, REG_CARD_STATUS_CHANGE);
	tmp = PCICDataRead();

	DEBUGMSG(ZONE_PDD, (TEXT("PDCardGetSocket(%d) REG_CARD_STATUS_CHANGE(0x%x) = 0x%x\r\n"),
    	uSocket, REG_CARD_STATUS_CHANGE, tmp));

	//
	// Figure out the socket state
	//
	PCICIndex(uSocket, REG_INTERFACE_STATUS);
	tmp = PCICDataRead();

	if ((tmp & (STS_CD1|STS_CD2)) == (STS_CD1|STS_CD2)) 
	{
		pPDDState->fNotifyEvents |= EVENT_MASK_CARD_DETECT;
	} else {
		InitSocketNoCard(uSocket, FALSE);
		goto pcgs_exit;
	}

#ifdef NOT_IMPLEMENTED
	switch (tmp & (STS_BVD1|STS_BVD2)) 
	{
		case STS_BVD1:
			pPDDState->fNotifyEvents |= EVENT_MASK_BATTERY_LOW;
			DEBUGMSG(ZONE_PDD, (TEXT("PDCardGetSocket(%d) BATTERY_LOW\r\n"), uSocket));
			break;

		case STS_BVD2:
		case 0:
			DEBUGMSG(ZONE_PDD, (TEXT("PDCardGetSocket(%d) BATTERY_DEAD\r\n"), uSocket));
			pPDDState->fNotifyEvents |= EVENT_MASK_BATTERY_DEAD;
			break;
	}
#endif NOT_IMPLEMENTED

	if (tmp & STS_WRITE_PROTECT) 
	{
		DEBUGMSG(ZONE_PDD, (TEXT("PDCardGetSocket(%d) WRITE_PROTECT\r\n"), uSocket));
		pPDDState->fNotifyEvents |= EVENT_MASK_WRITE_PROTECT;
	}


	if (tmp & STS_CARD_READY) 
	{
		DEBUGMSG(ZONE_PDD, (TEXT("PDCardGetSocket(%d) CARD_READY\r\n"), uSocket));
		pPDDState->fNotifyEvents |= EVENT_MASK_CARD_READY;
	}

	DEBUGMSG(1,(TEXT("---PDCardGetSocket\r\n")));

pcgs_exit:
	memcpy(pState, pPDDState, sizeof(PDCARD_SOCKET_STATE));
	LeaveCriticalSection(&g_PCIC_Crit);
	return CERR_SUCCESS;
}   // PDDCardGetSocket


//
// PDCardSetSocket
//
// @func    STATUS | PDCardSetSocket | Set the socket state of the specified socket.
// @rdesc   Returns one of the CERR_* return codes in cardserv.h.
//
// @comm    This function sets the specified socket's state and adjusts the socket
//          controller appropriately.
//          PDCardGetSocketState will usually be called first and adjustments will
//          be made to the PDCARD_SOCKET_STATE structure before PDCardSetSocketState
//          is called.  This avoids duplicated socket state on different layers and
//          it avoids unintentionally setting socket parameters.
//
// @xref <f PDCardGetSocketState>
//
STATUS
PDCardSetSocket(UINT32 uSocket,			// @parm Socket number (first socket is 0)
		PPDCARD_SOCKET_STATE pState)	// @parm Pointer to PDCARD_SOCKET_STATE structure
{
	UINT8 tmp, intctl;
	PPDCARD_SOCKET_STATE pPDDState;
	STATUS ret;
	int t;

	DEBUGMSG(1, (TEXT("PDCardSetSocket(%d) entered\r\n"), uSocket));

	if (uSocket >= NUM_SOCKETS) 
	{
		ret = CERR_BAD_SOCKET;
		goto pcss_fail;
	}

	//
	// Check socket power level indexes
	//
	if ((pState->fVcc & SOCK_VCC_LEVEL_MASK) >= NUM_POWER_ENTRIES ||
		!(v_PowerEntries[pState->fVcc & SOCK_VCC_LEVEL_MASK].fSupply & PWR_SUPPLY_VCC)) 
	{
		ret = CERR_BAD_VCC;
		goto pcss_fail;
	}
	if (pState->uVpp1 >= NUM_POWER_ENTRIES || pState->uVpp2 >= NUM_POWER_ENTRIES ||
		!(v_PowerEntries[pState->uVpp1].fSupply & PWR_SUPPLY_VPP1) ||
		!(v_PowerEntries[pState->uVpp2].fSupply & PWR_SUPPLY_VPP2)) 
	{
		ret = CERR_BAD_VPP;
		goto pcss_fail;
	}

	EnterCriticalSection(&g_PCIC_Crit);

	PCICIndex(uSocket, REG_INTERFACE_STATUS);
	tmp = PCICDataRead();

	if ((tmp & (STS_CD1|STS_CD2)) != (STS_CD1|STS_CD2)) 
	{
		DEBUGMSG(ZONE_PDD, (TEXT("PDCardSetSocket(%d) No card inserted\r\n"), uSocket));
		InitSocketNoCard(uSocket, FALSE);
		goto pcss_exit;
	}

	pPDDState = &v_SockState[uSocket];

	//
	// Set the status change interrupt sources
	//
#if 1
	tmp = (UCHAR)(g_Irq << 4); // CFG_MANAGEMENT_IRQ_BIT* bits will be set
#else
	tmp =0;
#endif	

	if (pState->fInterruptEvents & EVENT_MASK_CARD_DETECT) 
	{
		tmp |= CFG_CARD_DETECT_ENABLE;
	}
	if (pState->fInterruptEvents & EVENT_MASK_BATTERY_DEAD) 
	{
		tmp |= CFG_BATTERY_DEAD_ENABLE;
	}
	if (pState->fInterruptEvents & EVENT_MASK_BATTERY_LOW) 
	{
		tmp |= CFG_BATTERY_WARNING_ENABLE;
	}
	if (pState->fIREQRouting & SOCK_IREQ_ENABLE) 
	{
		// tmp |= CFG_READY_ENABLE;
	} 
	PCICIndex(uSocket, REG_STATUS_CHANGE_INT_CONFIG);
	PCICDataWrite(tmp);
	DEBUGMSG(ZONE_PDD, (TEXT("PDCardSetSocket(%d) REG_STATUS_CHANGE_INT_CONFIG(0x%x) = 0x%x\r\n"),
				uSocket, REG_STATUS_CHANGE_INT_CONFIG, tmp));

#if 1
	// PD6710 specific code to enable management interrupt(routed to -INTR)
	PCICIndex(0, REG_INTERRUPT_AND_GENERAL_CONTROL);
	tmp = PCICDataRead();
	tmp |= INT_ENABLE_MANAGE_INT;
	PCICDataWrite(tmp);
#endif

	//
	// Enable or disable IREQ interrupts
	//
	PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
	tmp = PCICDataRead();
	tmp &= (UCHAR)~g_Irq; // Turn off INT_IRQ_BIT* bits
	if (pState->fIREQRouting & SOCK_IREQ_ENABLE) 
	{
		DEBUGMSG(1, (TEXT("Enable IREQ interrupts #%x\r\n"), g_Irq));
		tmp |= ((UCHAR)g_Irq)|INT_CARD_NOT_RESET; // Turn on INT_IRQ_BIT* bits
	} else {
		tmp |= INT_CARD_NOT_RESET;
	}
	PCICDataWrite(tmp);

	DEBUGMSG(1, (TEXT("PDCardSetSocket voltage = %d\r\n"),
			v_PowerEntries[pState->fVcc & SOCK_VCC_LEVEL_MASK].uPowerLevel));
	// ignore Vpp 
	if ((pState->fVcc & SOCK_VCC_LEVEL_MASK) != (pPDDState->fVcc & SOCK_VCC_LEVEL_MASK)) 
	{
		//
		// Set socket power as requested.
		//
		switch (v_PowerEntries[pState->fVcc & SOCK_VCC_LEVEL_MASK].uPowerLevel) 
		{
			case 0:
				PCICIndex(uSocket, REG_POWER_CONTROL);
				PCICDataWrite(0);
				goto pcss_exit; // this is what it used to do so I won't change it
			case 33:
				PCICIndex(uSocket, 0x16);//REG_MISC_CONTROL_1);
				PCICDataWrite(0x02);  // enable 3.3V
				DEBUGMSG(1, (TEXT("set to 3.3V\r\n")));
				break;
			case 50:
				PCICIndex(uSocket, 0x16);//REG_MISC_CONTROL_1);
				if (PCICDataRead() & 0x01) // i.e., if we detect a 5V card:
				{
					PCICDataWrite(0x00);  // disable 3.3V (i.e., use 5V)
					DEBUGMSG(1, (TEXT("set to 5V\r\n")));
				}
				else
				{
					// this is a 3.3V ONLY card and mustn't be powered at 5V
					// so ignore the command; we'd assert here save that card
					// services will attempt to apply 5V to read the CIS.
					PCICDataWrite(0x02);  // enable 3.3V
 					DEBUGMSG(1, (TEXT("set to 3.3V[5V]\r\n")));
				}
				break;
			default:
				ASSERT(0); // this ought to have been caught above
		}

		// LKY 2001.12
		Sleep(100);

		//
		// Assert RESET
		//
		PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
		intctl = PCICDataRead();
		PCICDataWrite((UINT8)(intctl & ~ INT_CARD_NOT_RESET));

		Sleep(20);

		PCICIndex(uSocket, REG_POWER_CONTROL);

		PCICDataWrite(PWR_OUTPUT_ENABLE | PWR_AUTO_POWER | PWR_VPP2_BIT0 | PWR_VPP1_BIT0);
		//
		// Power the socket
		//
		PCICIndex(uSocket, REG_POWER_CONTROL);
		PCICDataWrite(PWR_OUTPUT_ENABLE | PWR_AUTO_POWER | PWR_VCC_POWER | PWR_VPP2_BIT0 | PWR_VPP1_BIT0);

		Sleep(20);

		//
		// Deassert RESET
		//
		PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
		intctl = PCICDataRead();
		PCICDataWrite((UINT8)(intctl | INT_CARD_NOT_RESET));

		Sleep(20);
    
		//
		// Allow the card 2 seconds to assert RDY
		//
		PCICIndex(uSocket, REG_INTERFACE_STATUS);
		for (t = 0; t < PCMCIA_MAX_RDY_WAIT_TIME; t += PCMCIA_RDY_POLL_INT) 
		{
			tmp = PCICDataRead();
			if (tmp & STS_CARD_READY) 
			{
				DEBUGMSG(ZONE_PDD, (TEXT("PDCardSetSocket: Card in socket %d RDY after %dms\r\n"),
							uSocket, t));
				break;
			}
			Sleep(PCMCIA_RDY_POLL_INT);
		}

		if (t >= PCMCIA_MAX_RDY_WAIT_TIME) 
		{
			DEBUGMSG(ZONE_PDD, (TEXT("PDCardSetSocket: CARD IN SOCKET %d NOT RDY AFTER %dms\r\n"),
						uSocket, t));
		}

		// LKY 2001.12    
		Sleep(300); // necessary for CF cards?

	}

	if (pState->fIREQRouting & SOCK_IREQ_ENABLE) 
		DumpSocketRegisters(uSocket);

	*pPDDState = *pState;

pcss_exit:
#ifdef DEBUG
	DeltaSocketRegisters(uSocket);
#endif
	LeaveCriticalSection(&g_PCIC_Crit);
	return CERR_SUCCESS;

pcss_fail:
	DEBUGMSG(ZONE_PDD, (TEXT("PDCardSetSocket(%d) returning %d\r\n"), uSocket, ret));
	return ret;
}   // PDCardSetSocket


//
// PDCardInquireAdapter
//
// @func    STATUS | PDCardInquireAdapter | Returns the socket controller's characteristics
//                                          and capabilities.
// @rdesc   Returns one of the CERR_* return codes in cardserv.h.
//
STATUS
PDCardInquireAdapter( PPDCARD_ADAPTER_INFO pAdapterInfo )	// @parm Pointer to PDCARD_ADAPTER_INFO structure.
{
	if (pAdapterInfo->uPowerEntries < NUM_POWER_ENTRIES) 
	{
		pAdapterInfo->uPowerEntries = NUM_POWER_ENTRIES;
		return CERR_BAD_ARG_LENGTH;
	}

	// Copy the adapter info
	memcpy(pAdapterInfo, &v_AdapterInfo, sizeof(PDCARD_ADAPTER_INFO));
	pAdapterInfo = (PPDCARD_ADAPTER_INFO)(((UINT)pAdapterInfo) + sizeof(PDCARD_ADAPTER_INFO));

	// Copy the power entries at the end
	memcpy(pAdapterInfo, &v_PowerEntries, sizeof(v_PowerEntries));
	return CERR_SUCCESS;
}

//
// Set up socket's initial window registers and interrupts
//
VOID
InitSocket( UINT32 uSocket )
{
	PDCARD_WINDOW_STATE WinState;
	PDCARD_SOCKET_STATE SockState;
	UINT32 status; 
	UINT32 i; 
	UINT32 first, last;

	DEBUGMSG(1, (TEXT(":::PCMCIA:InitSocket\r\n")));

	//
	// Set the socket to detect status change events
	//
	SockState = v_SockState[uSocket];
	SockState.fInterruptEvents = EVENT_MASK_CARD_DETECT|
                                 EVENT_MASK_CARD_LOCK|
                                 EVENT_MASK_BATTERY_LOW|
                                 EVENT_MASK_BATTERY_DEAD|
                                 EVENT_MASK_WRITE_PROTECT;
#if 0
	SockState.fInterfaceType = CFG_IFACE_MEMORY;
	SockState.fIREQRouting = 0;
#else
	SockState.fInterfaceType = CFG_IFACE_MEMORY_IO;		// IO/MEM Interface, 2000.4.26, LKY
	SockState.fIREQRouting = 1; 				// IRQRouting enabled, 2000.4.26, LKY
#endif

	SockState.fVcc = VCC_DEFAULT_INDEX;
	PDCardSetSocket(uSocket, &SockState);

	//
	// Initially enable only the memory windows
	//
	first = (uSocket == 0) ? 0 : SOCKET1_FIRST_MEMORY_WINDOW;
	last = first + SOCKET1_FIRST_MEMORY_WINDOW;
	for (i = first; i < last; i++) 
	{
		status = PDCardGetWindow(i, &WinState);
		if (status == CERR_SUCCESS) 
		{
			WinState.fState |= WIN_STATE_ATTRIBUTE|WIN_STATE_ENABLED;
			PDCardSetWindow(i, &WinState);
		}
	}
}   // InitSocket

//
// PDCardResetSocket
//
// @func    STATUS | PDCardResetSocket | Resets the specified socket.
// @rdesc   Returns one of the CERR_* return codes in cardserv.h.
//
STATUS
PDCardResetSocket( UINT32 uSocket )	// @parm Socket number (first socket is 0)
{
	UINT8 tmp;
	UINT8 intctl;
	UINT32 t; 

	DEBUGMSG(1, (TEXT("++PDCardResetSocket\r\n")));

	if (uSocket >= NUM_SOCKETS) 
	{
		return CERR_BAD_SOCKET;
	}

	EnterCriticalSection(&g_PCIC_Crit);

	PCICIndex(uSocket, REG_INTERFACE_STATUS);
	tmp = PCICDataRead();

	//
	// Power off the socket
	//
	PCICIndex(uSocket, REG_POWER_CONTROL);
	PCICDataWrite(0);

	if ((tmp & (STS_CD1|STS_CD2)) != (STS_CD1|STS_CD2)) 
	{
		//
		// Leave it powered off if no card in it.
		//
		InitSocketNoCard(uSocket, FALSE);
		LeaveCriticalSection(&g_PCIC_Crit);
		return CERR_NO_CARD;
	}

	//
	// Tri-state outputs for 310ms
	//
	Sleep(310);

	//
	// Assert RESET
	//
	PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
	intctl = PCICDataRead();
	PCICDataWrite(0);

	//
	// Power the socket
	//
	PCICIndex(uSocket, REG_POWER_CONTROL);
	PCICDataWrite(PWR_OUTPUT_ENABLE|PWR_AUTO_POWER|PWR_VCC_POWER);

	Sleep(20);

	//
	// Deassert RESET
	//
	PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
	PCICDataWrite(INT_CARD_NOT_RESET);

	//
	// Allow 20ms for card to assert RDY
	//
	Sleep(20);

	//
	// Allow the card 2 seconds to assert RDY
	//
	PCICIndex(uSocket, REG_INTERFACE_STATUS);
	for (t = 0; t < PCMCIA_MAX_RDY_WAIT_TIME; t += PCMCIA_RDY_POLL_INT) 
	{
		tmp = PCICDataRead();
		if (tmp & STS_CARD_READY) 
		{
			DEBUGMSG(ZONE_PDD, (TEXT("PDCardResetSocket: Card in socket %d RDY after %dms\r\n"),uSocket, t));
			break;
		}
		Sleep(PCMCIA_RDY_POLL_INT);
	}

	if (t >= PCMCIA_MAX_RDY_WAIT_TIME) 
	{
		DEBUGMSG(ZONE_PDD, (TEXT("PDCardResetSocket: CARD IN SOCKET %d NOT RDY AFTER %dms\r\n"),uSocket, t));
	}

	InitSocket(uSocket);

	// LKY 2001.12
	Sleep(20);

	PCICIndex(uSocket, REG_INTERRUPT_AND_GENERAL_CONTROL);
	intctl |= INT_CARD_NOT_RESET;
	PCICDataWrite(intctl);

	// LKY 2001.12
	Sleep(20);

#if 0
	// Enable Manage Interrupt
	PCICIndex(0, REG_INTERRUPT_AND_GENERAL_CONTROL);
	intctl = PCICDataRead();
	intctl |= INT_ENABLE_MANAGE_INT;
	PCICDataWrite(intctl);
#endif

	LeaveCriticalSection(&g_PCIC_Crit);
    
	DEBUGMSG(1, (TEXT("--PDCardResetSocket\r\n")));
    
	return CERR_SUCCESS;
}   // PDCardResetSocket

//
// PDCardGetAdapter
//
// @func    STATUS | PDCardGetAdapter | Returns power save mode status and capabilities
// @rdesc   Returns one of the CERR_* return codes in cardserv.h
//

STATUS
PDCardGetAdapter(	UINT32 uSocket,
			PPDCARD_ADAPTER_STATE pState     )
{

	UINT8 tmp;
	BOOL bUserMode;

	if (uSocket >= NUM_SOCKETS) 
	{
		return CERR_BAD_SOCKET;
	}

	if (pState == NULL) 
	{
		return CERR_BAD_ARGS;
	}

	bUserMode = (*pState & ADP_STATE_KERNEL_MODE) ? FALSE : TRUE;

	DEBUGMSG(1, (TEXT("PDCardGetAdapter entered\r\n")));
	
	*pState = 0;
	if (bUserMode) 
	{
		EnterCriticalSection(&g_PCIC_Crit);
	}

	PCICIndex(uSocket, REG_POWER_CONTROL);
	tmp = PCICDataRead();
	if (!(tmp & PWR_OUTPUT_ENABLE)) 
	{
		*pState |= ADP_STATE_POWERDOWN;
	}

	if (bUserMode) 
	{
		LeaveCriticalSection(&g_PCIC_Crit);
	}

	DEBUGMSG(1, (TEXT("PDCardGetAdapter done\r\n")));
	return CERR_SUCCESS;

}


//
// PDCardSetAdapter
//
// @func    STATUS | PDCardSetAdapter | Sets power save mode status and capabilities
// @rdesc   Returns one of the CERR_* return codes in cardserv.h
//
STATUS
PDCardSetAdapter(	UINT32 uSocket,
			PPDCARD_ADAPTER_STATE pState )
{
	BOOL bUserMode;
	// UINT32 bSoc;

	if (uSocket >= NUM_SOCKETS) 
	{
		return CERR_BAD_SOCKET;
	}

	if (pState == NULL) 
	{
		return CERR_BAD_ARGS;
	}

	bUserMode = (*pState & ADP_STATE_KERNEL_MODE) ? FALSE : TRUE;
	
	DEBUGMSG(1, (TEXT("PDCardSetAdapter entered\r\n")));

	if (bUserMode) 
	{
		EnterCriticalSection(&g_PCIC_Crit);
	}

	//
	// The socket controller will automatically power up when a card is inserted
	// by shlim
	// if (*pState & (ADP_STATE_POWERDOWN|ADP_STATE_POWEROFF)) 
	if (*pState & (ADP_STATE_POWEROFF | ADP_STATE_POWERDOWN)) 
	{
		//RETAILMSG(1, (TEXT("---- (ADP_STATE_POWEROFF | ADP_STATE_POWERDOWN)\r\n")));	
		// Power down the socket
		//RETAILMSG(1, (TEXT("PD_DataRestore()\r\n")));
		PD_DataRestore();				
		InitSocketNoCard(uSocket, bUserMode);
	}else {
		//RETAILMSG(1, (TEXT("---! (ADP_STATE_POWEROFF | ADP_STATE_POWERDOWN)\r\n")));	
		//
		// Power up the socket
		//
		//RETAILMSG(1, (TEXT("PD_DataBackup()\r\n")));
		//PD_DataBackup();
		//InitSocketNoCard(uSocket, bUserMode);		
	}

	if (bUserMode) 
	{
		LeaveCriticalSection(&g_PCIC_Crit);
	}

	return CERR_SUCCESS;
}
