/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Minimalistic keyboard driver
*
*/
//#define DEBUG
#include "syborg_keyboard.h"
LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2)
{
DKeyboardPs2Soc* pH=(DKeyboardPs2Soc*)aPtr;
return pH->HalFunction(aFunction,a1,a2);
}
void rxMsg(TAny* aPtr)
{
DKeyboardPs2Soc& h=*(DKeyboardPs2Soc*)aPtr;
TMessageBase* pM=h.iMsgQ.iMessage;
if (pM)
h.HandleMsg(pM);
}
TInt DKeyboardPs2Soc::FifoPop(void)
{
TInt val = iKeyFifo[iFifoPos];
iFifoPos++;
iFifoCount--;
if (iFifoPos == FIFO_SIZE)
iFifoPos = 0;
return val;
}
void DKeyboardPs2Soc::FifoPush(TInt val)
{
TInt slot;
if (iFifoCount == FIFO_SIZE)
return;
slot = iFifoPos + iFifoCount;
if (slot >= FIFO_SIZE)
slot -= FIFO_SIZE;
iKeyFifo[slot] = val;
iFifoCount++;
}
void DKeyboardPs2Soc::Isr(TAny* aPtr)
{
__DEBUG_PRINT("DKeyboardPs2Soc::Isr");
DKeyboardPs2Soc& k = *(DKeyboardPs2Soc*)aPtr;
// Is now auto-clearing
while(ReadReg(KHwBaseKmiKeyboard, KBD_FIFO_COUNT)!=0)
k.FifoPush(ReadReg(KHwBaseKmiKeyboard, KBD_DATA));
//WriteReg(KHwBaseKmiKeyboard,KBD_CLEAR_INT, 0);
Interrupt::Clear(EIntKeyboard);
k.iRxDfc.Add();
}
DKeyboardPs2Soc::DKeyboardPs2Soc()
: DPowerHandler(KLitKeyboard),
iRxDfc(RxDfc,this,Kern::DfcQue0(),1),
iMsgQ(rxMsg,this,NULL,1)
{
iKeyboardOn = ETrue;
iFifoPos = 0;
iFifoCount = 0;
}
TInt DKeyboardPs2Soc::Create()
{
__DEBUG_PRINT("DKeyboardPs2Soc::Create");
TInt r=KErrNone;
iDfcQ=Kern::DfcQue0();
iFifoPos = iFifoCount = 0;
r=Kern::AddHalEntry(EHalGroupKeyboard,halFunction,this);
if (r!=KErrNone)
return r;
iMsgQ.SetDfcQ(iDfcQ);
iMsgQ.Receive();
r=Interrupt::Bind(EIntKeyboard,Isr,this);
if (r==KErrNone) {
Add();
KeyboardOn();
}
return r;
}
void DKeyboardPs2Soc::PowerUp()
{
PowerUpDone();
}
void DKeyboardPs2Soc::PowerDown(TPowerState)
{
PowerDownDone();
}
void DKeyboardPs2Soc::KeyboardOn()
{
__DEBUG_PRINT("DKeyboardPs2Soc::KeyboardOn");
TInt reg = ReadReg(KHwBaseKmiKeyboard,KBD_ID);
Interrupt::Enable(EIntKeyboard);
WriteReg(KHwBaseKmiKeyboard,KBD_INT_ENABLE,1);
}
void DKeyboardPs2Soc::KeyboardOff()
{
__DEBUG_PRINT("DKeyboardPs2Soc::KeyboardOff");
Interrupt::Disable(EIntKeyboard);
WriteReg(KHwBaseKmiKeyboard,KBD_INT_ENABLE,0);
}
void DKeyboardPs2Soc::HandleMsg(TMessageBase* aMsg)
{
__DEBUG_PRINT("DKeyboardPs2Soc::HandleMsg");
if (aMsg->iValue)
KeyboardOn();
else
KeyboardOff();
aMsg->Complete(KErrNone,ETrue);
}
void DKeyboardPs2Soc::KeyboardInfo(TKeyboardInfoV01& aInfo)
{
aInfo.iKeyboardType=KConfigKeyboardType;
aInfo.iDeviceKeys=KConfigKeyboardDeviceKeys;
aInfo.iAppsKeys=KConfigKeyboardAppsKeys;
}
TInt DKeyboardPs2Soc::HalFunction(TInt aFunction, TAny* a1, TAny* a2)
{
TInt r=KErrNone;
__DEBUG_PRINT("DKeyboardPs2Soc::HalFunction");
switch(aFunction)
{
case EKeyboardHalKeyboardInfo:
{
TPckgBuf<TKeyboardInfoV01> kPckg;
KeyboardInfo(kPckg());
Kern::InfoCopy(*(TDes8*)a1,kPckg);
break;
}
// UIKLAF Silent running/power management
case EKeyboardHalSetKeyboardState:
{
if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EKeyboardHalSetKeyboardState")))
return KErrPermissionDenied;
if ((TBool)a1)
{
TThreadMessage& m=Kern::Message();
m.iValue = ETrue;
m.SendReceive(&iMsgQ);
}
else
{
TThreadMessage& m=Kern::Message();
m.iValue = EFalse;
m.SendReceive(&iMsgQ);
}
}
break;
case EKeyboardHalKeyboardState:
kumemput32(a1, &iKeyboardOn, sizeof(TBool));
break;
default:
r=KErrNotSupported;
break;
}
return r;
}
void DKeyboardPs2Soc::RxDfc(TAny* aPtr)
{
TRawEvent e;
DKeyboardPs2Soc& k = *(DKeyboardPs2Soc*)aPtr;
while(k.iFifoCount>0) {
int keycode = k.FifoPop();
int dwn = (keycode & 0x80000000) ? 0 : 1;
__DEBUG_PRINT("DKeyboardPs2Soc::RxDfc %d %d", keycode, dwn);
keycode &= ~(0x80000000);
if (dwn) {
__DEBUG_PRINT("kbd EKeyDown:%d",keycode);
e.Set(TRawEvent::EKeyDown,KConvertCode[keycode],0);
}
else {
__DEBUG_PRINT("kbd EKeyUp:%d",keycode);
e.Set(TRawEvent::EKeyUp,KConvertCode[keycode],0);
}
Kern::AddEvent(e);
}
}
DECLARE_STANDARD_EXTENSION()
{
TInt r=KErrNoMemory;
DKeyboardPs2Soc* pK=new DKeyboardPs2Soc;
if (pK)
r=pK->Create();
__KTRACE_OPT(KEXTENSION,__DEBUG_PRINT("Returns %d",r));
return r;
}