sl@0: // Copyright (c) 2007-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: // template\template_variant\specific\keyboard.cpp sl@0: // Access to Template polled keyboard sl@0: // The code here implements a simple polled keyboard driver. sl@0: // This is an alternative to the interrupt-driven driver in keyboard_interrupt.cpp. sl@0: // This example assumes that we have a non-intelligent keyboard sl@0: // consisting of a number of i/o lines arranged in a grid. sl@0: // You can use this code as a starting point and modify it to suit sl@0: // your hardware. sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include "platform.h" sl@0: #include sl@0: #include sl@0: sl@0: sl@0: sl@0: // The TKeyboardState class is used to encapsulate the state of sl@0: // the keyboard. i.e which keys are currently being pressed. sl@0: // To determine which keys are being pressed, typically a voltage sl@0: // is applied to each row in turn (or column, depending on the hardware) sl@0: // and the output is read resulting in a bitmask for each row. sl@0: // sl@0: // For example, the keys could be arranged as follows (where a '1' indicates sl@0: // that a key is currently being pressed : sl@0: // EXAMPLE ONLY sl@0: // sl@0: // Translated sl@0: // Column# 0 1 2 3 4 5 6 7 8 9 A B C D E F KeyCode sl@0: // Row# sl@0: // 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 60 to 6F sl@0: // 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50 to 5F sl@0: // 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 to 4F sl@0: // 3 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 30 to 3F sl@0: // Input-> 2 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 20 to 2F sl@0: // 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 10 to 1F sl@0: // 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 00 to 0F sl@0: // sl@0: // output-> 0 0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 sl@0: // sl@0: // TO DO: (mandadory) sl@0: // Modify TKeyboardState (or provide an alternative) to model the sl@0: // real keyboard state sl@0: // sl@0: // EXAMPLE ONLY sl@0: class TKeyboardState sl@0: { sl@0: public: sl@0: sl@0: enum TDimensions sl@0: { sl@0: KRows = 7, sl@0: KColumns = 16 sl@0: }; sl@0: sl@0: public: sl@0: TKeyboardState(); sl@0: void Clear(); sl@0: TBool IsKeyReady(); sl@0: TUint32 GetKeyCode(); sl@0: TKeyboardState operator&(const TKeyboardState& aState); sl@0: TKeyboardState operator|(const TKeyboardState& aState); sl@0: TKeyboardState operator~(); sl@0: sl@0: public: sl@0: TUint32 iKeyBitMask[KRows]; sl@0: }; sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: TKeyboardState::TKeyboardState() sl@0: { sl@0: Clear(); sl@0: } sl@0: sl@0: /** sl@0: Clears the array of bitmasks sl@0: */ sl@0: void TKeyboardState::Clear() sl@0: { sl@0: for (TInt row=0; rowPoll(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Reads scan codes from the keyboard until there are none left sl@0: Called from the keyboard-polling timer's DFC sl@0: */ sl@0: void DKeyboardTemplate::Poll() sl@0: { sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("DKeyboardTemplate::EventDfc")); sl@0: sl@0: sl@0: TKeyboardState keyState; sl@0: sl@0: // sl@0: // TO DO: (mandatory) sl@0: // Read new key state into the array of bitmasks in keyState sl@0: // This typically involves applying a voltage to each row from 0 to KRows-1, sl@0: // reading the output state of the i/o lines at every step sl@0: // - this represents the keys that are pressed on each row - sl@0: // and storing the output of each row as a bitmask into keyState.iKeyBitMask[n], sl@0: // where n = the row being accessed sl@0: // sl@0: sl@0: // To enable a simple de-bouncing algorithm, sl@0: // work out which keys have been pressed down for at least two timer sl@0: // ticks by AND-ing together the last bitmask with the current bitmask sl@0: TKeyboardState keysStillDown = keyState & iKeyStateLast; sl@0: sl@0: sl@0: // Similarly, work out which keys have been "un-pressed" for at least two timer sl@0: // ticks by AND-ing together the one's complement of the last bitmask with the sl@0: // one's complement of the current bitmask and sl@0: // then AND-ing this with the set of keys for which we have sent an EKeyDown sl@0: // event to give the set of keys for which we need to send an EKeyUp event sl@0: TKeyboardState keysStillUp = (~keyState & ~iKeyStateLast) & iKeysDown; sl@0: sl@0: // save the current state for next time sl@0: iKeyStateLast = keyState; sl@0: sl@0: // update the set of keys for which we have sent an EKeyDown event sl@0: iKeysDown = iKeysDown | keysStillDown; sl@0: iKeysDown = iKeysDown & ~keysStillUp; sl@0: sl@0: // process all the key-down events sl@0: while (keysStillDown.IsKeyReady()) // while there are keys we haven't processed sl@0: { sl@0: TRawEvent e; sl@0: TUint keyCode = keysStillDown.GetKeyCode(); // Read keycodes from bitmask sl@0: sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("EKeyDown: #%02x\n",keyCode)); sl@0: sl@0: // sl@0: // TO DO: (mandatory) sl@0: // sl@0: // Convert from hardware scancode to EPOC scancode and send the scancode as an event (key pressed or released) sl@0: // as per below EXAMPLE ONLY: sl@0: // sl@0: __ASSERT_DEBUG(keyCode < (sizeof(convertCode) / sizeof(TUint8)), Kern::Fault("Keyboard", __LINE__)); sl@0: TUint8 stdKey = convertCode[keyCode]; sl@0: sl@0: e.Set(TRawEvent::EKeyDown, stdKey, 0); sl@0: Kern::AddEvent(e); sl@0: } sl@0: sl@0: // process all the key-up events sl@0: while (keysStillUp.IsKeyReady()) // while there are keys we haven't processed sl@0: { sl@0: TRawEvent e; sl@0: TUint keyCode = keysStillUp.GetKeyCode(); // Read keycodes from bitmask sl@0: sl@0: __KTRACE_OPT(KHARDWARE,Kern::Printf("EKeyUp: #%02x\n",keyCode)); sl@0: sl@0: // sl@0: // TO DO: (mandatory) sl@0: // sl@0: // Convert from hardware scancode to EPOC scancode and send the scancode as an event (key pressed or released) sl@0: // as per below EXAMPLE ONLY: sl@0: // sl@0: __ASSERT_DEBUG(keyCode < (sizeof(convertCode) / sizeof(TUint8)), Kern::Fault("Keyboard", __LINE__)); sl@0: TUint8 stdKey = convertCode[keyCode]; sl@0: sl@0: e.Set(TRawEvent::EKeyUp, stdKey, 0); sl@0: Kern::AddEvent(e); sl@0: } sl@0: sl@0: // start the timer again sl@0: iTimer.OneShot(iTimerTicks); sl@0: } sl@0: sl@0: sl@0: sl@0: /** sl@0: Notifies the peripheral of system power up. sl@0: Called by the power manager during a transition from standby. sl@0: Schedules a DFC to handle the power up. sl@0: */ sl@0: void DKeyboardTemplate::PowerUp() sl@0: { sl@0: iPowerUpDfc.Enque(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: static DFC to handle powering up the keyboard sl@0: sl@0: @param aPtr A pointer to an instance of DKeyboardTemplate sl@0: */ sl@0: void DKeyboardTemplate::PowerUpDfcFn(TAny* aPtr) sl@0: { sl@0: ((DKeyboardTemplate*)aPtr)->PowerUpDfc(); sl@0: } sl@0: sl@0: sl@0: /** sl@0: DFC to handle powering up the keyboard sl@0: */ sl@0: void DKeyboardTemplate::PowerUpDfc() sl@0: { sl@0: __KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerUpDfc()")); sl@0: KeyboardOn(); sl@0: sl@0: // Indicate to power handle that powered up is complete sl@0: PowerUpDone(); sl@0: } sl@0: sl@0: /** sl@0: Powers up the keyboard sl@0: May be called as a result of a power transition or from the HAL sl@0: */ sl@0: void DKeyboardTemplate::KeyboardOn() sl@0: { sl@0: __KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOn() iKeyboardOn=%d", iKeyboardOn)); sl@0: sl@0: if (!iKeyboardOn) // make sure we don't initialize more than once sl@0: KeyboardPowerUp(); sl@0: } sl@0: sl@0: /** sl@0: Powers up the keyboard sl@0: Assumes that the keyboard is currently powered off sl@0: */ sl@0: void DKeyboardTemplate::KeyboardPowerUp() sl@0: { sl@0: __KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardPowerUp()")); sl@0: sl@0: iKeyboardOn = ETrue; sl@0: sl@0: iKeyStateLast.Clear(); sl@0: iKeysDown.Clear(); sl@0: sl@0: // Send key up events for EStdKeyOff (Fn+Esc) event sl@0: TRawEvent e; sl@0: e.Set(TRawEvent::EKeyUp,EStdKeyEscape,0); sl@0: Kern::AddEvent(e); sl@0: e.Set(TRawEvent::EKeyUp,EStdKeyLeftFunc,0); sl@0: Kern::AddEvent(e); sl@0: sl@0: // Start the periodic tick for the selected rate. sl@0: // This will call TimerCallback() in the context of an ISR sl@0: iTimer.OneShot(iTimerTicks); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Requests keyboard to power down. sl@0: Called by the power manager during a transition to standby or power off sl@0: Schedules a DFC to handle the power up. sl@0: sl@0: @param aPowerState the current power state sl@0: */ sl@0: void DKeyboardTemplate::PowerDown(TPowerState) sl@0: { sl@0: iPowerDownDfc.Enque(); sl@0: } sl@0: sl@0: /** sl@0: static DFC to handle powering down the keyboard sl@0: sl@0: @param aPtr A pointer to an instance of DKeyboardTemplate sl@0: */ sl@0: void DKeyboardTemplate::PowerDownDfcFn(TAny* aPtr) sl@0: { sl@0: ((DKeyboardTemplate*)aPtr)->PowerDownDfc(); sl@0: } sl@0: sl@0: /** sl@0: DFC to handle powering down the keyboard sl@0: */ sl@0: void DKeyboardTemplate::PowerDownDfc() sl@0: { sl@0: __KTRACE_OPT(KPOWER, Kern::Printf("DKeyboardTemplate::PowerDownDfc()")); sl@0: KeyboardOff(); sl@0: PowerDownDone(); sl@0: } sl@0: sl@0: /** sl@0: Powers down the keyboard sl@0: May be called as a result of a power transition or from the HAL sl@0: */ sl@0: void DKeyboardTemplate::KeyboardOff() sl@0: { sl@0: __KTRACE_OPT(KPOWER,Kern::Printf("DKeyboardTemplate::KeyboardOff() iKeyboardOn=%d", iKeyboardOn)); sl@0: sl@0: // cancel the keyboard-polling timer sl@0: iTimerDfc.Cancel(); sl@0: iTimer.Cancel(); sl@0: sl@0: iKeyboardOn = EFalse; sl@0: } sl@0: sl@0: sl@0: /** sl@0: static message handler for processing power up/down messages sl@0: posted internally from HalFunction() sl@0: sl@0: @param aPtr A pointer to an instance of DKeyboardTemplate sl@0: */ sl@0: void DKeyboardTemplate::HandleMessage(TAny* aPtr) sl@0: { sl@0: DKeyboardTemplate& h=*(DKeyboardTemplate*)aPtr; sl@0: TMessageBase* pM=h.iMsgQ.iMessage; sl@0: if (pM) sl@0: h.HandleMsg(pM); sl@0: } sl@0: sl@0: /** sl@0: Message handler for processing power up/down messages sl@0: posted internally from HalFunction() sl@0: sl@0: param aMsg A message indicating whether to power the keyboard on or off sl@0: */ sl@0: void DKeyboardTemplate::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: if (aMsg->iValue) sl@0: KeyboardOn(); sl@0: else sl@0: KeyboardOff(); sl@0: aMsg->Complete(KErrNone,ETrue); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Retrieves information about the keyboard sl@0: Called from HalFunction() sl@0: sl@0: @param aInfo a caller-supplied class which on return contains information about the keyboard sl@0: */ sl@0: void DKeyboardTemplate::KeyboardInfo(TKeyboardInfoV01& aInfo) sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("DKeyboardTemplate::KeyboardInfo")); sl@0: aInfo.iKeyboardType=KConfigKeyboardType; sl@0: aInfo.iDeviceKeys=KConfigKeyboardDeviceKeys; sl@0: aInfo.iAppsKeys=KConfigKeyboardAppsKeys; sl@0: } sl@0: sl@0: sl@0: /** sl@0: HAL handler function sl@0: sl@0: @param aPtr a pointer to an instance of DLcdPowerHandler sl@0: @param aFunction the function number sl@0: @param a1 an arbitrary parameter sl@0: @param a2 an arbitrary parameter sl@0: */ sl@0: TInt DKeyboardTemplate::HalFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: DKeyboardTemplate* pH=(DKeyboardTemplate*)aPtr; sl@0: return pH->HalFunction(aFunction,a1,a2); sl@0: } sl@0: sl@0: sl@0: /** sl@0: a HAL entry handling function for HAL group attribute EHalGroupKeyboard sl@0: sl@0: @param a1 an arbitrary argument sl@0: @param a2 an arbitrary argument sl@0: @return KErrNone if successful sl@0: */ sl@0: TInt DKeyboardTemplate::HalFunction(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt r=KErrNone; sl@0: sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("DKeyboardTemplate::HalFunction %d", aFunction)); sl@0: sl@0: switch(aFunction) sl@0: { sl@0: case EKeyboardHalKeyboardInfo: sl@0: { sl@0: TPckgBuf kPckg; sl@0: KeyboardInfo(kPckg()); sl@0: Kern::InfoCopy(*(TDes8*)a1,kPckg); sl@0: break; sl@0: } sl@0: sl@0: case EKeyboardHalSetKeyboardState: sl@0: { sl@0: if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EKeyboardHalSetKeyboardState"))) sl@0: return KErrPermissionDenied; sl@0: if ((TBool)a1) sl@0: { sl@0: TThreadMessage& m=Kern::Message(); sl@0: m.iValue = ETrue; sl@0: m.SendReceive(&iMsgQ); // send a message and block Client thread until keyboard has been powered up sl@0: } sl@0: else sl@0: { sl@0: TThreadMessage& m=Kern::Message(); sl@0: m.iValue = EFalse; sl@0: m.SendReceive(&iMsgQ); // send a message and block Client thread until keyboard has been powered down sl@0: } sl@0: } sl@0: break; sl@0: sl@0: case EKeyboardHalKeyboardState: sl@0: kumemput32(a1, &iKeyboardOn, sizeof(TBool)); sl@0: break; sl@0: sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: sl@0: DECLARE_STANDARD_EXTENSION() sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("Starting keyboard driver")); sl@0: sl@0: // create keyboard driver sl@0: TInt r=KErrNoMemory; sl@0: DKeyboardTemplate* pK=new DKeyboardTemplate; sl@0: if (pK) sl@0: r=pK->Create(); sl@0: sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("Returns %d",r)); sl@0: return r; sl@0: }