sl@0: // Copyright (c) 1998-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32\drivers\pbus\spbus.cpp sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "OstTraceDefinitions.h" sl@0: #ifdef OST_TRACE_COMPILER_IN_USE sl@0: #include "locmedia_ost.h" sl@0: #ifdef __VC32__ sl@0: #pragma warning(disable: 4127) // disabling warning "conditional expression is constant" sl@0: #endif sl@0: #include "spbusTraces.h" sl@0: #endif sl@0: sl@0: sl@0: const TInt KPBusSocketThreadPriority=26; sl@0: sl@0: GLDEF_D DMediaChangeBase* TheMediaChanges[KMaxMediaChanges]; sl@0: GLDEF_D DPBusSocket* TheSockets[KMaxPBusSockets]; sl@0: GLDEF_D DPBusPsuBase* TheVccs[KMaxPBusVccs]; sl@0: GLDEF_D DPBusPsuBase* TheVccCores[KMaxPBusVccs]; sl@0: sl@0: /******************************************** sl@0: * Peripheral bus callback sl@0: ********************************************/ sl@0: EXPORT_C TPBusCallBack::TPBusCallBack() sl@0: : iSocket(NULL), iFunction(NULL), iIntMask(0), iPtr(NULL) sl@0: { sl@0: OstTraceFunctionEntry0( TPBUSCALLBACK_TPBUSCALLBACK1_ENTRY ); sl@0: iNext=NULL; sl@0: OstTraceFunctionExit0( TPBUSCALLBACK_TPBUSCALLBACK1_EXIT ); sl@0: } sl@0: sl@0: EXPORT_C TPBusCallBack::TPBusCallBack(TPBusCallBackFn aFunction, TAny* aPtr) sl@0: : iSocket(NULL), iFunction(aFunction), iIntMask(0), iPtr(aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( TPBUSCALLBACK_TPBUSCALLBACK2_ENTRY ); sl@0: iNext=NULL; sl@0: OstTraceFunctionExit0( TPBUSCALLBACK_TPBUSCALLBACK2_EXIT ); sl@0: } sl@0: sl@0: EXPORT_C TPBusCallBack::TPBusCallBack(TPBusIsr anIsr, TAny* aPtr, TUint anIntMask) sl@0: : iSocket(NULL), iFunction(NULL), iIntMask(anIntMask), iIsr(anIsr), iPtr(aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( TPBUSCALLBACK_TPBUSCALLBACK3_ENTRY ); sl@0: iNext=NULL; sl@0: OstTraceFunctionExit0( TPBUSCALLBACK_TPBUSCALLBACK3_EXIT ); sl@0: } sl@0: sl@0: EXPORT_C void TPBusCallBack::Remove() sl@0: { sl@0: OstTraceFunctionEntry0( TPBUSCALLBACK_REMOVE_ENTRY ); sl@0: TInt irq=NKern::DisableAllInterrupts(); sl@0: if (iNext) sl@0: Deque(); sl@0: iNext=NULL; sl@0: NKern::RestoreInterrupts(irq); sl@0: OstTraceFunctionExit0( TPBUSCALLBACK_REMOVE_EXIT ); sl@0: } sl@0: sl@0: EXPORT_C void TPBusCallBack::SetSocket(TInt aSocket) sl@0: { sl@0: OstTraceFunctionEntryExt( TPBUSCALLBACK_SETSOCKET_ENTRY, this ); sl@0: iSocket=TheSockets[aSocket]; sl@0: OstTraceFunctionExit1( TPBUSCALLBACK_SETSOCKET_EXIT, this ); sl@0: } sl@0: sl@0: /******************************************** sl@0: * Media change base class sl@0: ********************************************/ sl@0: sl@0: /** sl@0: * Constructor for a DMediaChangeBase object. sl@0: * sl@0: * @param aMediaChangeNum The media change number sl@0: */ sl@0: EXPORT_C DMediaChangeBase::DMediaChangeBase(TInt aMediaChangeNum) sl@0: : iMediaChangeNum(aMediaChangeNum), sl@0: iReplyCount(0), sl@0: iDoorOpenDfc(DoorOpenDfcFn,this,Kern::DfcQue1(),1) sl@0: { sl@0: OstTraceFunctionEntryExt( DMEDIACHANGEBASE_DMEDIACHANGEBASE_ENTRY, this ); sl@0: } sl@0: sl@0: sl@0: /** sl@0: * Creates a DMediaChangeBase object. sl@0: * This should be overridden at the media and variant layer to allow sl@0: * interrupts and other media/variant-specific parameters to be initialised. sl@0: * sl@0: * Method should be called post object creation, although could be used to sl@0: * re-initialise parameters. sl@0: * sl@0: * @return KErrNone Default sl@0: */ sl@0: EXPORT_C TInt DMediaChangeBase::Create() sl@0: { sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: * Called from ISR triggered by media change or from sl@0: * the Peripheral Bus Controller Media Driver context sl@0: * if a media change is being forced. sl@0: * sl@0: * Method adds/enques a media change event on to the door sl@0: * open DFC queue. If called by PBUS thread then DFC queue sl@0: * is by-passed and change event is dealt with synchronously. sl@0: * sl@0: * Media change events are platform specific although are sl@0: * generally related to a media door or slot being opened. sl@0: */ sl@0: EXPORT_C void DMediaChangeBase::DoorOpenService() sl@0: { sl@0: if (NKern::CurrentContext()==NKern::EInterrupt) sl@0: { sl@0: OstTrace0(TRACE_INTERNALS, DMEDIACHANGEBASE_DOOROPENSERVICE, "Interrupt driven asynchronous media change event"); sl@0: iDoorOpenDfc.Add(); sl@0: } sl@0: else sl@0: { sl@0: if (Kern::DfcQue1()->iThread==(NThreadBase *)NKern::CurrentThread()) // check if this is being called from PBUS thread sl@0: { sl@0: OstTrace0(TRACE_INTERNALS, DMEDIACHANGEBASE_DOOROPENSERVICE2, "Synchronous media change event"); sl@0: MediaChangeEvent(ETrue); sl@0: } sl@0: else sl@0: { sl@0: OstTrace0(TRACE_INTERNALS, DMEDIACHANGEBASE_DOOROPENSERVICE3, "Different thread is queueing request, asynchronous media change event"); sl@0: iDoorOpenDfc.Enque(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: * High priority DFC triggered by media change interrupt. sl@0: * sl@0: * Media changes events are added/enqued by DMediaChangeBase::DoorOpenService(). sl@0: * sl@0: * @param aPtr Pointer to an instantiated class which enqued/added this DFC event sl@0: */ sl@0: void DMediaChangeBase::DoorOpenDfcFn(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( DMEDIACHANGEBASE_DOOROPENDFCFN_ENTRY ); sl@0: DMediaChangeBase* pM=(DMediaChangeBase*)aPtr; sl@0: pM->MediaChangeEvent(ETrue); sl@0: OstTraceFunctionExit0( DMEDIACHANGEBASE_DOOROPENDFCFN_EXIT ); sl@0: } sl@0: sl@0: /** sl@0: * sl@0: * Notifies sockets of door close event. sl@0: * sl@0: * This function must be called by variant when door close has been detected. sl@0: */ sl@0: EXPORT_C void DMediaChangeBase::DoorClosedService() sl@0: { sl@0: OstTraceFunctionEntry1( DMEDIACHANGEBASE_DOORCLOSEDSERVICE_ENTRY, this ); sl@0: MediaChangeEvent(EFalse); sl@0: OstTraceFunctionExit1( DMEDIACHANGEBASE_DOORCLOSEDSERVICE_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: * Notifies relevant peripheral bus sockets of door open or close events. sl@0: * sl@0: * @param aDoorOpened ETrue if door is opened sl@0: * sl@0: * @see DPBusSocket::DPBusSocket sl@0: */ sl@0: void DMediaChangeBase::MediaChangeEvent(TBool aDoorOpened) sl@0: { sl@0: OstTraceFunctionEntry1( DMEDIACHANGEBASE_MEDIACHANGEEVENT_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DMediaChangeBase(%d)::MediaChangeEvent(%d)",iMediaChangeNum,aDoorOpened)); sl@0: OstTraceExt2(TRACE_INTERNALS, DMEDIACHANGEBASE_DMEDIACHANGEBASE, "iMediaChangeNum=%d; aDoorOpened=%d", iMediaChangeNum,aDoorOpened); sl@0: TInt i; sl@0: sl@0: // notify all sockets affected sl@0: for (i=0; iiMediaChange==this) sl@0: { sl@0: // Only increment base reply count if actually adding a DFC sl@0: if (!pS->iMediaChangeDfc.Queued()) sl@0: __e32_atomic_add_ord32(&iReplyCount, 1); sl@0: pS->MediaChangeEvent(aDoorOpened); sl@0: } sl@0: } sl@0: OstTraceFunctionExit1( DMEDIACHANGEBASE_MEDIACHANGEEVENT_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: * To be called by peripheral bus socket derived classes when sl@0: * door open/close event has been processed. sl@0: * sl@0: * @param aDoorOpened ETrue door opened event processed, sl@0: * EFalse door closed event processed sl@0: * sl@0: * @see DPBusSocket::DoorOpenEvent() sl@0: * @see DPBusSocket::DoorCloseEvent() sl@0: */ sl@0: void DMediaChangeBase::AcknowledgeEvent(TBool aDoorOpened) sl@0: { sl@0: OstTraceFunctionEntryExt( DMEDIACHANGEBASE_ACKNOWLEDGEEVENT_ENTRY, this ); sl@0: TInt c = __e32_atomic_tas_ord32(&iReplyCount, 1, -1, 0); sl@0: if (c==1) sl@0: { sl@0: if (aDoorOpened) sl@0: DoDoorOpen(); sl@0: else sl@0: DoDoorClosed(); sl@0: } sl@0: OstTraceFunctionExit1( DMEDIACHANGEBASE_ACKNOWLEDGEEVENT_EXIT, this ); sl@0: } sl@0: sl@0: /******************************************** sl@0: * Power supply base class sl@0: ********************************************/ sl@0: void psuTick(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( _PSUTICK_ENTRY ); sl@0: DPBusPsuBase* pP=(DPBusPsuBase*)aPtr; sl@0: pP->iPsuDfc.Enque(); sl@0: OstTraceFunctionExit0( _PSUTICK_EXIT ); sl@0: } sl@0: sl@0: void psuDfc(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( _PSUDFC_ENTRY ); sl@0: DPBusPsuBase* pP=(DPBusPsuBase*)aPtr; sl@0: pP->DoTickService(); sl@0: OstTraceFunctionExit0( _PSUDFC_EXIT ); sl@0: } sl@0: sl@0: /** sl@0: Constructor for a DPBusPsuBase object. sl@0: sl@0: @param aPsuNum Unique power supply identification number sl@0: @param aMediaChangedNum Unique media change identification number sl@0: */ sl@0: DPBusPsuBase::DPBusPsuBase(TInt aPsuNum, TInt aMediaChangeNum) sl@0: : iPsuNum(aPsuNum), iMediaChangeNum(aMediaChangeNum), iVoltCheckMethod(EPsuChkComparator), iState(EPsuOff), sl@0: iPsuDfc(psuDfc, this, 4), sl@0: iPwrDownCheckFn(DoPwrDownCheck) sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSPSUBASE_DPBUSPSUBASE_ENTRY, this ); sl@0: // iCurrLimited=EFalse; sl@0: // iVoltageSupported=0; sl@0: // iMaxCurrentInMicroAmps=0; sl@0: // iVoltCheckInterval=0; sl@0: // iInactivityCount=0; sl@0: // iNotLockedCount=0; sl@0: // iInactivityTimeout=0; sl@0: // iNotLockedTimeout=0; sl@0: } sl@0: sl@0: void DPBusPsuBase::DoPwrDownCheck(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( DPBUSPSUBASE_DOPWRDOWNCHECK_ENTRY ); sl@0: DPBusPsuBase& self = *static_cast(aPtr); sl@0: self.PwrDownCheck(); sl@0: OstTraceFunctionExit0( DPBUSPSUBASE_DOPWRDOWNCHECK_EXIT ); sl@0: } sl@0: sl@0: /** sl@0: Initialises a DPBusPsuBase object. sl@0: sl@0: Sets object information based on hardware variant PSU inforamtion. sl@0: Calls DoCreate to initialise the PSU. sl@0: sl@0: @return Standard Symbian OS error code. sl@0: sl@0: @see DPBusPsuBase::PsuInfo() sl@0: @see DPBusPsuBase::DoCreate() sl@0: */ sl@0: TInt DPBusPsuBase::Create() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_CREATE_ENTRY, this ); sl@0: sl@0: TPBusPsuInfo pi; sl@0: PsuInfo(pi); sl@0: iVoltageSupported=pi.iVoltageSupported; sl@0: iMaxCurrentInMicroAmps=pi.iMaxCurrentInMicroAmps; sl@0: iVoltCheckInterval=pi.iVoltCheckInterval; sl@0: iVoltCheckMethod=pi.iVoltCheckMethod; sl@0: iInactivityTimeout=pi.iInactivityTimeOut; sl@0: iNotLockedTimeout=pi.iNotLockedTimeOut; sl@0: sl@0: TInt r=DoCreate(); sl@0: if (r!=KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DPBUSPSUBASE_CREATE_EXIT1, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: iPsuDfc.SetDfcQ(&iSocket->iDfcQ); sl@0: sl@0: OstTraceFunctionExitExt( DPBUSPSUBASE_CREATE_EXIT2, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Initialises the power supply unit. sl@0: sl@0: The function is provided by the hardware variant layer, and needs to initialise sl@0: interrupts and other variant-specific parameters. sl@0: sl@0: The default implementation returns KErrNone. sl@0: sl@0: @return KErrNone sl@0: */ sl@0: EXPORT_C TInt DPBusPsuBase::DoCreate() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_DOCREATE_ENTRY, this ); sl@0: TInt r = KErrNone; sl@0: OstTraceFunctionExitExt( DPBUSPSUBASE_DOCREATE_EXIT, this, r ); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Reset (turn off) the power supply unit. sl@0: Sets PSU state to EPsuOff. sl@0: */ sl@0: void DPBusPsuBase::Reset() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_RESET_ENTRY, this ); sl@0: SetState(EPsuOff); sl@0: iCurrLimited=EFalse; sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_RESET_EXIT, this ); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Checks whether this PSU is powering a bus containing sl@0: a locked device, i.e. one that is recognised and in use by a client. sl@0: sl@0: The function is provided at the media layer, could be used to ensure power is not sl@0: removed whilst media is locked or some other media specific power management activatity. sl@0: sl@0: The default implementation just returns EFalse. sl@0: sl@0: @return EFalse sl@0: */ sl@0: EXPORT_C TBool DPBusPsuBase::IsLocked() sl@0: { sl@0: return EFalse; sl@0: } sl@0: sl@0: /** sl@0: Controls the power supply state. sl@0: sl@0: @param aState A TPBusPsuState enumeration specifying the required state sl@0: (EPsuOnFull, EPsuOff, EPsuOnCurLimit) sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: sl@0: @see TPBusPsuState sl@0: @see DPBusPsuBase::DoSetState() sl@0: */ sl@0: EXPORT_C TInt DPBusPsuBase::SetState(TPBusPsuState aState) sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_SETSTATE_ENTRY, this ); sl@0: sl@0: TInt r=KErrGeneral; sl@0: if (aState==EPsuOff) sl@0: { sl@0: iTickLink.Cancel(); // No point in having the 1 second tick running while the PSU is off sl@0: } sl@0: else sl@0: { sl@0: // Start the 1 second tick to monitor for inactivity, not in use and PSU level checking sl@0: iTickLink.Cancel(); sl@0: iTickLink.Periodic(KPBusPsuTickInterval,psuTick,this); sl@0: } sl@0: sl@0: // Don't turn the PSU back on if it has current limited since the last reset event sl@0: iInactivityCount=0; sl@0: iNotLockedCount=0; sl@0: if (aState==EPsuOff || !iCurrLimited) sl@0: { sl@0: DoSetState(aState); sl@0: iState=aState; sl@0: r=KErrNone; sl@0: } sl@0: __KTRACE_OPT(KPBUS2,Kern::Printf("PsuFault(KErrCorrupt); sl@0: } sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_RECEIVEVOLTAGECHECKRESULT_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: Get the current power supply unit status sl@0: sl@0: @return PSU status. sl@0: sl@0: @see TPBusPsuStatus sl@0: */ sl@0: TPBusPsuStatus DPBusPsuBase::Status() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_STATUS_ENTRY, this ); sl@0: if (iCurrLimited) sl@0: { sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_STATUS_EXIT1, this ); sl@0: return(EPsuStatError); sl@0: } sl@0: else sl@0: { sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_STATUS_EXIT2, this ); sl@0: return( (iState==EPsuOff) ? EPsuStatOff : EPsuStatOn ); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** sl@0: Checks if power supply unit can be turned off. sl@0: sl@0: @see DPBusPsuBase::DoTickService() sl@0: */ sl@0: void DPBusPsuBase::PwrDownCheck() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_PWRDOWNCHECK_ENTRY, this ); sl@0: if ( sl@0: (iNotLockedTimeout&&!IsLocked()&&++iNotLockedCount>iNotLockedTimeout) || sl@0: (iInactivityTimeout&&++iInactivityCount>iInactivityTimeout) sl@0: ) sl@0: iSocket->PsuTimeout(); sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_PWRDOWNCHECK_EXIT, this ); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Services the Pc Card Tick (called in timer thread). sl@0: */ sl@0: EXPORT_C void DPBusPsuBase::DoTickService() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPSUBASE_DOTICKSERVICE_ENTRY, this ); sl@0: if (iPwrDownCheckFn) sl@0: (*iPwrDownCheckFn)(this); sl@0: CheckVoltage(KPsuChkWhileOn); // Check voltage level sl@0: OstTraceFunctionExit1( DPBUSPSUBASE_DOTICKSERVICE_EXIT, this ); sl@0: } sl@0: sl@0: sl@0: /******************************************** sl@0: * Peripheral bus power handler sl@0: ********************************************/ sl@0: DPBusPowerHandler::DPBusPowerHandler(DPBusSocket* aSocket) sl@0: : DPowerHandler(*aSocket->iName), sl@0: iSocket(aSocket) sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSPOWERHANDLER_DPBUSPOWERHANDLER_ENTRY, this ); sl@0: } sl@0: sl@0: void DPBusPowerHandler::PowerUp() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPOWERHANDLER_POWERUP_ENTRY, this ); sl@0: iSocket->iPowerUpDfc.Enque(); sl@0: OstTraceFunctionExit1( DPBUSPOWERHANDLER_POWERUP_EXIT, this ); sl@0: } sl@0: sl@0: void DPBusPowerHandler::PowerDown(TPowerState) sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSPOWERHANDLER_POWERDOWN_ENTRY, this ); sl@0: iSocket->iPowerDownDfc.Enque(); sl@0: OstTraceFunctionExit1( DPBUSPOWERHANDLER_POWERDOWN_EXIT, this ); sl@0: } sl@0: sl@0: /******************************************** sl@0: * Peripheral bus socket base class sl@0: ********************************************/ sl@0: void mediaChangeDfc(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( _MEDIACHANGEDFC_ENTRY ); sl@0: DPBusSocket* pS=(DPBusSocket*)aPtr; sl@0: if (pS->iDoorOpened) sl@0: pS->DoorOpenEvent(); sl@0: else sl@0: pS->DoorCloseEvent(); sl@0: OstTraceFunctionExit0( _MEDIACHANGEDFC_EXIT ); sl@0: } sl@0: sl@0: void powerUpDfc(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( _POWERUPDFC_ENTRY ); sl@0: DPBusSocket* pS=(DPBusSocket*)aPtr; sl@0: pS->DoPowerUp(); sl@0: OstTraceFunctionExit0( _POWERUPDFC_EXIT ); sl@0: } sl@0: sl@0: void powerDownDfc(TAny* aPtr) sl@0: { sl@0: OstTraceFunctionEntry0( _POWERDOWNDFC_ENTRY ); sl@0: DPBusSocket* pS=(DPBusSocket*)aPtr; sl@0: pS->DoPowerDown(); sl@0: OstTraceFunctionExit0( _POWERDOWNDFC_EXIT ); sl@0: } sl@0: sl@0: /** sl@0: PBus Socket panics. Faults the system. sl@0: This will start the Crash Debugger if it is present, otherwise the system is rebooted by calling Kern::Restart(0) sl@0: @param aPanic The panic to be raised sl@0: @see DPBusSocket::TPanic sl@0: */ sl@0: EXPORT_C void DPBusSocket::Panic(DPBusSocket::TPanic aPanic) sl@0: { sl@0: Kern::Fault("PBUS",aPanic); sl@0: } sl@0: sl@0: /** sl@0: Flags the media driver as entering a critical part of its processing. sl@0: In this context, critical means that the driver must be allowed to complete its current activity. sl@0: sl@0: @return KErrNone if successful, sl@0: KErrNotReady if there is any postponed events outstanding. sl@0: @see DPBusSocket::EndInCritical() sl@0: */ sl@0: EXPORT_C TInt DPBusSocket::InCritical() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_INCRITICAL_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::InCritical",iSocketNumber)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_INCRITICAL, "iSocketNumber=%d",iSocketNumber ); sl@0: if (iPostponeCount==0 && iPostponedEvents!=0) sl@0: { sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_INCRITICAL_EXIT1, this, KErrNotReady ); sl@0: return KErrNotReady; // we are about to do media change/power down sl@0: } sl@0: ++iPostponeCount; sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_INCRITICAL_EXIT2, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Flags the media driver as leaving a critical part of its processing. sl@0: This function enque the media change DFC or power down DFC depending on the event DPBusSocket::iPostponedEvents. sl@0: @see TPostponedEvent sl@0: @see DPBusSocket::InCritical() sl@0: */ sl@0: EXPORT_C void DPBusSocket::EndInCritical() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_ENDINCRITICAL_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::EndInCritical",iSocketNumber)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_ENDINCRITICAL1, "iSocketNumber=%d",iSocketNumber); sl@0: if (iPostponeCount && --iPostponeCount==0) sl@0: { sl@0: if (iPostponedEvents & EMediaChange) sl@0: { sl@0: iMediaChangeDfc.Enque(); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("Media change - done postponed")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_ENDINCRITICAL2, "Media change - done postponed"); sl@0: } sl@0: if (iPostponedEvents & EPowerDown) sl@0: { sl@0: iPowerDownDfc.Enque(); sl@0: __KTRACE_OPT2(KPBUS1,KPOWER,Kern::Printf("Power down - done postponed")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_ENDINCRITICAL3, "Power down - done postponed"); sl@0: } sl@0: } sl@0: OstTraceFunctionExit1( DPBUSSOCKET_ENDINCRITICAL_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: Sets the incremental value of current consumption to aCurrent. sl@0: @param aCurrent Delta Current in Milliamps sl@0: @see DPowerHandler::DeltaCurrentConsumption() sl@0: */ sl@0: EXPORT_C void DPBusSocket::DeltaCurrentConsumption(TInt aDelta) sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSSOCKET_DELTACURRENTCONSUMPTION_ENTRY, this ); sl@0: iPowerHandler->DeltaCurrentConsumption(aDelta); sl@0: OstTraceFunctionExit1( DPBUSSOCKET_DELTACURRENTCONSUMPTION_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: Constructor for DPBusSocket. sl@0: Sets the iSocketNumber and initializes the DFC queue for Media Change Dfc, PowerUp Dfc, PowerDown Dfc and PSU Dfc queue. sl@0: @param aSocketNumber Pbus socket number sl@0: */ sl@0: DPBusSocket::DPBusSocket(TInt aSocketNumber) sl@0: : iSocketNumber(aSocketNumber), sl@0: iMediaChangeDfc(mediaChangeDfc, this, 6), sl@0: iPowerUpDfc(powerUpDfc, this, 4), sl@0: iPowerDownDfc(powerDownDfc, this, 4), sl@0: iPsuDfc(psuDfc, this, 4) sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSSOCKET_DPBUSSOCKET_ENTRY, this ); sl@0: // iPowerGroup=0; sl@0: // iName=NULL; sl@0: // iState=EPBusCardAbsent; sl@0: // iPostponeCount=0; sl@0: // iPostponedEvents=0; sl@0: // iPowerHandler=NULL; sl@0: } sl@0: sl@0: /** sl@0: Creates a new Socket. sl@0: This method sets the DFC Queue for the driver associated, sl@0: Constructs power handler and registers it with the Power Manager. sl@0: @param aName Assigns aName to the PBus socket. sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: @see DPBusPowerHandler sl@0: @see iMediaChangeDfc sl@0: @see iPowerUpDfc sl@0: @see iPowerDownDfc sl@0: @see iPsuDfc sl@0: */ sl@0: TInt DPBusSocket::Create(const TDesC* aName) sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_CREATE_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::Create %lS",iSocketNumber,aName)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_CREATE, "iSocketNumber=%d",iSocketNumber); sl@0: iName=aName; sl@0: DPBusPowerHandler* pH=new DPBusPowerHandler(this); sl@0: if (!pH) sl@0: { sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_CREATE_EXIT1, this, KErrNoMemory ); sl@0: return KErrNoMemory; sl@0: } sl@0: iPowerHandler=pH; sl@0: pH->Add(); // register power handler sl@0: TInt r=Kern::DfcQInit(&iDfcQ, KPBusSocketThreadPriority, iName); sl@0: if (r!=KErrNone) sl@0: { sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_CREATE_EXIT2, this, r ); sl@0: return r; sl@0: } sl@0: iMediaChangeDfc.SetDfcQ(&iDfcQ); sl@0: iPowerUpDfc.SetDfcQ(&iDfcQ); sl@0: iPowerDownDfc.SetDfcQ(&iDfcQ); sl@0: sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_CREATE_EXIT3, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Initializes the PBus socket by changing its state to EPBusOff. sl@0: @return KErrNone if successful, sl@0: otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DPBusSocket::Init() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_INIT_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::Init",iSocketNumber)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_INIT, "iSocketNumber=%d",iSocketNumber); sl@0: __PM_ASSERT(iState == EPBusCardAbsent); sl@0: if (MediaState()==EDoorClosed && CardIsPresent()) sl@0: ChangeState(EPBusOff,KErrNotReady); sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_INIT_EXIT, this, KErrNone ); sl@0: return KErrNone; sl@0: } sl@0: sl@0: void DPBusSocket::ResetSocket(TBool aFullReset) sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSSOCKET_RESETSOCKET_ENTRY, this ); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_RESETSOCKET, "iSocketNumber=%d; aFullReset=%d", iSocketNumber, aFullReset); sl@0: Reset1(); sl@0: iVcc->Reset(); sl@0: if (aFullReset) sl@0: Reset2(); sl@0: OstTraceFunctionExit1( DPBUSSOCKET_RESETSOCKET_EXIT, this ); sl@0: } sl@0: sl@0: void DPBusSocket::ChangeState(TInt aState, TInt anError) sl@0: // sl@0: // Change state, notifying all clients sl@0: // sl@0: { sl@0: OstTraceFunctionEntryExt( DPBUSSOCKET_CHANGESTATE_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("Socket %d ChangeState %d to %d, err %d",iSocketNumber,iState,aState,anError)); sl@0: OstTraceExt4(TRACE_INTERNALS, DPBUSSOCKET_CHANGESTATE , "iSocketNumber=%d; ChangeState %d to %d; anError=%d",iSocketNumber,iState,aState,anError); sl@0: if (iState!=aState) sl@0: { sl@0: if(iState == EPBusCardAbsent && aState == EPBusOff && anError == KErrTimedOut) sl@0: { sl@0: // Maintain the internal state to EPBusCardAbsent when PSU sl@0: // times out to prevent the media from being powered back up. sl@0: } sl@0: else sl@0: { sl@0: iState=aState; sl@0: } sl@0: sl@0: // notify all clients of state change sl@0: SDblQueLink* pC=iCallBackQ.iA.iNext; sl@0: while (pC && pC!=&iCallBackQ.iA) sl@0: { sl@0: ((TPBusCallBack*)pC)->NotifyPBusStateChange(aState,anError); sl@0: pC=pC->iNext; sl@0: } sl@0: } sl@0: OstTraceFunctionExit1( DPBUSSOCKET_CHANGESTATE_EXIT, this ); sl@0: } sl@0: sl@0: void DPBusSocket::Isr(TInt anId) sl@0: // sl@0: // Service a card interrupt sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_ISR_ENTRY, this ); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_ISR, "iSocketNumber=%d; anId=%d", iSocketNumber, anId ); sl@0: // notify all interested clients of interrupt sl@0: SDblQueLink* pC=iCallBackQ.iA.iNext; sl@0: #ifdef _DEBUG sl@0: TInt n=0; sl@0: #endif sl@0: while (pC!=&iCallBackQ.iA) sl@0: { sl@0: #ifdef _DEBUG sl@0: n++; sl@0: #endif sl@0: ((TPBusCallBack*)pC)->Isr(anId); sl@0: pC=pC->iNext; sl@0: } sl@0: #ifdef _DEBUG sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("!%d",n)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_ISR2, "!%d", n); sl@0: #endif sl@0: OstTraceFunctionExit1( DPBUSSOCKET_ISR_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: This function adds a callback function to the socket. sl@0: @param aCallBack is a pointer to PBus callback function for event notification. sl@0: @see TPBusCallBack sl@0: */ sl@0: EXPORT_C void DPBusSocket::Add(TPBusCallBack* aCallBack) sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_ADD_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("DPBusSocket(%d)::Add(%08x) next %08x",iSocketNumber,aCallBack,aCallBack->iNext)); sl@0: OstTraceExt3(TRACE_INTERNALS, DPBUSSOCKET_ADD, "iSocketNumber=%d; aCallBack=0x%08x; aCallBack->iNext=0x%08x",iSocketNumber, (TUint) aCallBack, (TUint) aCallBack->iNext); sl@0: TInt irq=NKern::DisableAllInterrupts(); sl@0: if (!aCallBack->iNext) sl@0: iCallBackQ.Add(aCallBack); sl@0: NKern::RestoreInterrupts(irq); sl@0: OstTraceFunctionExit1( DPBUSSOCKET_ADD_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: Called by clients to power up the socket. sl@0: @return KErrNone if successful, otherwise one of the other system-wide error codes including: sl@0: KErrNotReady if card absent or media change has occurred, sl@0: KErrServerBusy if already powering up, sl@0: KErrCompletion if already powered up, sl@0: KErrCorrupt if PSU fault occurs. sl@0: sl@0: @panic PBUS 1, if PBUS state is invalid. sl@0: @see TPBusState sl@0: */ sl@0: EXPORT_C TInt DPBusSocket::PowerUp() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_POWERUP_ENTRY, this ); sl@0: __KTRACE_OPT2(KPBUS1,KPOWER,Kern::Printf(">DPBusSocket(%d)::PowerUp state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_POWERUP1, "iSocketNumber=%d; iState=%d",iSocketNumber,iState); sl@0: TInt r=KErrNone; sl@0: switch (iState) sl@0: { sl@0: case EPBusCardAbsent: // card absent or media change has occurred sl@0: r=KErrNotReady; sl@0: break; sl@0: case EPBusOff: sl@0: break; sl@0: case EPBusPoweringUp: // already powering up sl@0: case EPBusPowerUpPending: sl@0: r=KErrServerBusy; sl@0: break; sl@0: case EPBusOn: // already powered up sl@0: r=KErrCompletion; sl@0: break; sl@0: case EPBusPsuFault: sl@0: r=KErrCorrupt; sl@0: break; sl@0: default: sl@0: Panic(EPowerUpInvalidState); sl@0: } sl@0: if (r==KErrNone) sl@0: { sl@0: if (iStandby) sl@0: { sl@0: // machine is powering down, so delay client until machine powers back up sl@0: // remember to power up when machine powers back up sl@0: ChangeState(EPBusPowerUpPending,KErrNone); sl@0: } sl@0: else sl@0: { sl@0: ChangeState(EPBusPoweringUp,KErrNone); sl@0: InitiatePowerUpSequence(); sl@0: } sl@0: } sl@0: __KTRACE_OPT2(KPBUS1,KPOWER,Kern::Printf("DPBusSocket(%d)::PsuFault state %d error %d",iSocketNumber,iState,anError)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_PSUFAULT, "iSocketNumber=%d; iState=%d",iSocketNumber,iState ); sl@0: ResetSocket(ETrue); sl@0: ChangeState(EPBusPsuFault,anError); sl@0: } sl@0: sl@0: void DPBusSocket::PsuTimeout() sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::PsuTimeout state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_PSUTIMEOUT, "iSocketNumber=%d; iState=%d",iSocketNumber,iState ); sl@0: ResetSocket(EFalse); sl@0: ChangeState(EPBusOff,KErrTimedOut); sl@0: } sl@0: sl@0: void DPBusSocket::DoPowerUp() sl@0: // sl@0: // Called on transition from standby sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_DOPOWERUP_ENTRY, this ); sl@0: sl@0: __KTRACE_OPT2(KPBUS1,KPOWER,Kern::Printf("DPBusSocket(%d)::DoPowerUp state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_DOPOWERUP, "iSocketNumber=%d; iState=%d",iSocketNumber,iState ); sl@0: __PM_ASSERT(iStandby); sl@0: if (iState!=EPBusCardAbsent && iState!=EPBusOff && iState!=EPBusPowerUpPending) sl@0: Panic(EMcPowerUpInvalidState); sl@0: sl@0: // when we power up, check whether the door is closed and a card is present sl@0: // if so we should start in state Off otherwise in state CardAbsent sl@0: sl@0: TMediaState doorState = MediaState(); sl@0: TBool cardIsPresent = CardIsPresent(); sl@0: sl@0: #ifdef __ENABLE_SIMULATED_MEDIA_CHANGE sl@0: // Override the default media state is we are simulating media change sl@0: if(iSimulatedMediaState != DPBusSocket::EPeriphBusMediaNormal) sl@0: { sl@0: doorState = (iSimulatedMediaState == DPBusSocket::EPeriphBusDoorOpen) ? EDoorOpen : EDoorClosed; sl@0: cardIsPresent = (iSimulatedMediaState == DPBusSocket::EPeriphBusMediaPresent); sl@0: } sl@0: #endif sl@0: sl@0: if (!(doorState==EDoorClosed && cardIsPresent)) sl@0: ChangeState(EPBusCardAbsent,KErrNotReady); sl@0: else if (iState==EPBusPowerUpPending) sl@0: { sl@0: // if a power-up request is pending, process it now sl@0: ChangeState(EPBusPoweringUp,KErrNone); sl@0: InitiatePowerUpSequence(); sl@0: } sl@0: else sl@0: ChangeState(EPBusOff,KErrNotReady); sl@0: iStandby = EFalse; sl@0: iPowerHandler->PowerUpDone(); sl@0: OstTraceFunctionExit1( DPBUSSOCKET_DOPOWERUP_EXIT, this ); sl@0: } sl@0: sl@0: void DPBusSocket::DoPowerDown() sl@0: // sl@0: // Called by DPowerManager on transition to standby sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_DOPOWERDOWN_ENTRY, this ); sl@0: __KTRACE_OPT2(KPBUS1,KPOWER,Kern::Printf("DPBusSocket(%d)::DoPowerDown state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_DOPOWERDOWN1, "iSocketNumber=%d; iState=%d",iSocketNumber,iState ); sl@0: __PM_ASSERT(!iStandby); sl@0: if (iPostponeCount) sl@0: { sl@0: iPostponedEvents |= EPowerDown; sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("Power down postponed")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_DOPOWERDOWN2, "Power down postponed"); sl@0: return; sl@0: } sl@0: iPostponedEvents &= ~EPowerDown; sl@0: switch (iState) sl@0: { sl@0: case EPBusPoweringUp: sl@0: case EPBusOn: sl@0: case EPBusPsuFault: sl@0: ChangeState(EPBusOff,KErrNone); sl@0: case EPBusCardAbsent: sl@0: case EPBusOff: sl@0: case EPBusPowerUpPending: sl@0: break; sl@0: default: sl@0: Panic(EEmergencyPowerDownInvalidState); sl@0: } sl@0: sl@0: if(iRequestPowerDownCount == 0) sl@0: { sl@0: ResetSocket(EFalse); sl@0: iStandby = ETrue; sl@0: iPowerHandler->PowerDownDone(); sl@0: } sl@0: OstTraceFunctionExit1( DUP1_DPBUSSOCKET_DOPOWERDOWN_EXIT, this ); sl@0: } sl@0: sl@0: /** sl@0: Notifies the socket that we are deferring this power down event. sl@0: The function increments the iRequestPowerDownCount reference count sl@0: @see DPBusSocket::PowerDownComplete() sl@0: */ sl@0: EXPORT_C void DPBusSocket::RequestAsyncPowerDown() sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("DPBusSocket::RequestAsyncPowerDown")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_REQUESTASYNCPOWERDOWN1, "DPBusSocket::RequestAsyncPowerDown"); sl@0: __e32_atomic_add_ord32(&iRequestPowerDownCount, 1); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" >> count=%d", iRequestPowerDownCount)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_REQUESTASYNCPOWERDOWN2, "iRequestPowerDownCount=%d", iRequestPowerDownCount); sl@0: } sl@0: sl@0: /** sl@0: This function power down the PBus. Powers down the PBus if iRequestPowerDownCount is equal to 1. sl@0: @see DPBusSocket::RequestAsyncPowerDown() sl@0: @see iRequestPowerDownCount sl@0: */ sl@0: EXPORT_C void DPBusSocket::PowerDownComplete() sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("DPBusSocket::PowerDownComplete")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_POWERDOWNCOMPLETE, "DPBusSocket::PowerDownComplete"); sl@0: if (__e32_atomic_tas_ord32(&iRequestPowerDownCount, 1, -1, 0) == 1) sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" > Signalling Power Down (deferred)")); sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_POWERDOWNCOMPLETE2, "Signalling Power Down (deferred)"); sl@0: DoPowerDown(); sl@0: } sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(" >> count=%d", iRequestPowerDownCount)); sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_POWERDOWNCOMPLETE3, "iRequestPowerDownCount=%d", iRequestPowerDownCount); sl@0: } sl@0: sl@0: /** sl@0: This function is called by the local media device driver to force a remount of the media device. sl@0: @see DMediaChangeBase::ForceMediaChange() sl@0: */ sl@0: EXPORT_C void DPBusSocket::ForceMediaChange() sl@0: { sl@0: OstTrace1(TRACE_INTERNALS, DPBUSSOCKET_FORCEMEDIACHANGE, "iSocketNumber=%d", iSocketNumber); sl@0: iMediaChange->ForceMediaChange(); sl@0: } sl@0: sl@0: void DPBusSocket::MediaChangeEvent(TBool aDoorOpened) sl@0: // sl@0: // Called in high-priority DFC sl@0: // sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::MediaChangeEvent %d state %d",iSocketNumber,aDoorOpened,iState)); sl@0: OstTraceExt3(TRACE_INTERNALS, DPBUSSOCKET_MEDIACHANGEEVENT, "iSocketNumber=%d; aDoorOpened=%d; iState=%d",iSocketNumber,aDoorOpened,iState); sl@0: iDoorOpened=aDoorOpened; sl@0: iMediaChangeDfc.Enque(); sl@0: } sl@0: sl@0: void DPBusSocket::DoorOpenEvent() sl@0: // sl@0: // Called in socket thread sl@0: // sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_DOOROPENEVENT_ENTRY, this ); sl@0: sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::DoorOpenEvent state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_DOOROPENEVENT1, "iSocketNumber=%d; iState=%d",iSocketNumber,iState); sl@0: sl@0: if (iPostponeCount) sl@0: { sl@0: iPostponedEvents |= EMediaChange; sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("Media change postponed")); sl@0: OstTraceFunctionExit1( DPBUSSOCKET_DOOROPENEVENT_EXIT1, this ); sl@0: return; sl@0: } sl@0: iPostponedEvents &= ~EMediaChange; sl@0: sl@0: // notify all clients of media change sl@0: ChangeState(EPBusCardAbsent,KErrNotReady); sl@0: sl@0: // power down the socket sl@0: ResetSocket(ETrue); sl@0: sl@0: // get the media state befor calling AcknowledgeEvent() as the PSL may start a debounce sl@0: // timer on this call and return EDoorOpen while the timer is active.... sl@0: TMediaState mediaState = MediaState(); sl@0: sl@0: #ifdef __ENABLE_SIMULATED_MEDIA_CHANGE sl@0: // Only acknowledge the media change to the PSL if we are running in normal mode sl@0: if(iSimulatedMediaState == EPeriphBusMediaNormal) sl@0: iMediaChange->AcknowledgeEvent(ETrue); sl@0: #else sl@0: iMediaChange->AcknowledgeEvent(ETrue); sl@0: #endif sl@0: sl@0: // If there are multiple doors, then it is assumed that : sl@0: // - DMediaChangeBase::MediaState() will return EDoorClosed if ANY door is closed, and sl@0: // - DPBusSocket::CardIsPresent() will return ETrue if ANY card is present sl@0: // so that if, for example, one door is open and one door closed, then the bus will sl@0: // power down and then up again when one of the cards is next accessed. sl@0: // NB This doesn't worrk for a simulated media change since this doesn't affect the sl@0: // PSL's door state sl@0: #ifdef __ENABLE_SIMULATED_MEDIA_CHANGE sl@0: if ((iSimulatedMediaState == EPeriphBusMediaNormal) && sl@0: (mediaState == EDoorClosed && CardIsPresent())) sl@0: #else sl@0: if (mediaState == EDoorClosed && CardIsPresent()) sl@0: #endif sl@0: { sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf("At least 1 door still closed"));; sl@0: OstTrace0(TRACE_INTERNALS, DPBUSSOCKET_DOOROPENEVENT2 , "At least 1 door still closed"); sl@0: ChangeState(EPBusOff,KErrNotReady); sl@0: } sl@0: sl@0: OstTraceFunctionExit1( DPBUSSOCKET_DOOROPENEVENT_EXIT2, this ); sl@0: } sl@0: sl@0: void DPBusSocket::DoorCloseEvent() sl@0: { sl@0: OstTraceFunctionEntry1( DPBUSSOCKET_DOORCLOSEEVENT_ENTRY, this ); sl@0: __KTRACE_OPT(KPBUS1,Kern::Printf(">DPBusSocket(%d)::DoorCloseEvent state %d",iSocketNumber,iState)); sl@0: OstTraceExt2(TRACE_INTERNALS, DPBUSSOCKET_DOORCLOSEEVENT , "iSocketNumber=%d; iState=%d",iSocketNumber,iState); sl@0: sl@0: // NB If there are multiple doors then the bus may already be powererd up, sl@0: // so it's not possible to determine the bus state. sl@0: //if (iState!=EPBusCardAbsent) sl@0: // Panic(EDoorCloseInvalidState); sl@0: sl@0: // door has been closed - check for a card sl@0: sl@0: TBool cardIsPresent = CardIsPresent(); sl@0: sl@0: #ifdef __ENABLE_SIMULATED_MEDIA_CHANGE sl@0: // Override the default drive state if we are simulating the media state sl@0: if((iSimulatedMediaState == EPeriphBusDoorOpen) || (iSimulatedMediaState == EPeriphBusMediaRemoved)) sl@0: cardIsPresent = EFalse; sl@0: #endif sl@0: sl@0: sl@0: if (cardIsPresent) sl@0: { sl@0: if (iState == EPBusCardAbsent) sl@0: { sl@0: // Notifies clients of a media change sl@0: ChangeState(EPBusOff,KErrNotReady); sl@0: } sl@0: else // if there's already a card present (iState != EPBusCardAbsent), power the bus off and on sl@0: { sl@0: // Notify clients of a media change, cancel any outstanding requests, close media driver(s) sl@0: // and set the DPrimaryMediaBase's state to EClosed to force a subsequent power-up sl@0: ChangeState(EPBusCardAbsent,KErrNotReady); sl@0: ChangeState(EPBusOff,KErrNotReady); sl@0: // NB Don't power down the socket when iState == EPBusCardAbsent as this can take a small amount of time sl@0: // and will cause DPBusPrimaryMedia::QuickCheckStatus() to return KErrNotReady in the meantime: this will sl@0: // result in any requests to the DPrimaryMediaBase being completed IMMEDIATELY with KErrNotReady, i.e. the sl@0: // requests won't be queued until the power up completes. sl@0: ResetSocket(ETrue); sl@0: } sl@0: } sl@0: sl@0: #ifdef __ENABLE_SIMULATED_MEDIA_CHANGE sl@0: // Only acknowledge the media change to the PSL if we are running in normal mode sl@0: if(iSimulatedMediaState == EPeriphBusMediaNormal) sl@0: iMediaChange->AcknowledgeEvent(EFalse); sl@0: #else sl@0: iMediaChange->AcknowledgeEvent(EFalse); sl@0: #endif sl@0: OstTraceFunctionExit1( DPBUSSOCKET_DOORCLOSEEVENT_EXIT, this ); sl@0: } sl@0: /** sl@0: Gets pointer to the PBus Socket corresponding to the opened logical unit. sl@0: @param anId logical id of the PBus Socket. sl@0: @return Pointer to the PBusSocket for valid anId, else NULL. sl@0: */ sl@0: EXPORT_C DPBusSocket* DPBusSocket::SocketFromId(TInt anId) sl@0: { sl@0: OstTraceFunctionEntry0( DPBUSSOCKET_SOCKETFROMID_ENTRY ); sl@0: if (anId>=0 && anIdMediaChangeEvent(ETrue); sl@0: break; sl@0: sl@0: case EPeriphBusDoorOpen: sl@0: // sl@0: // Simulated door open or back to normal state. sl@0: // - Signal that the door is open and generate a media change. sl@0: // sl@0: MediaChangeEvent(ETrue); sl@0: break; sl@0: sl@0: case EPeriphBusMediaRemoved: sl@0: case EPeriphBusMediaPresent: sl@0: // sl@0: // Simulated door close with media present or absent sl@0: // - Signal that the door is closed. sl@0: // sl@0: MediaChangeEvent(EFalse); sl@0: break; sl@0: sl@0: case EPeriphBusMediaDoubleDoorOpen: sl@0: // simulate 2 door open interrupts sl@0: iSimulatedMediaState = EPeriphBusMediaNormal; sl@0: iMediaChange->MediaChangeEvent(ETrue); sl@0: iMediaChange->MediaChangeEvent(ETrue); sl@0: break; sl@0: sl@0: default: sl@0: // sl@0: // Unsupported media state sl@0: // sl@0: err = KErrArgument; sl@0: break; sl@0: } sl@0: } sl@0: #else sl@0: aParam1 = aParam1; sl@0: err = KErrNotSupported; sl@0: #endif sl@0: break; sl@0: } sl@0: sl@0: default: sl@0: err = KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: OstTraceFunctionExitExt( DPBUSSOCKET_CONTROLIO_EXIT, this, err ); sl@0: return err; sl@0: } sl@0: sl@0: /******************************************** sl@0: * Extension entry point sl@0: ********************************************/ sl@0: sl@0: GLDEF_C TInt KernelModuleEntry(TInt aReason) sl@0: { sl@0: if (aReason==KModuleEntryReasonExtensionInit0 || aReason==KModuleEntryReasonExtensionInit1) sl@0: return KErrNone; sl@0: return KErrArgument; sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: