omap3530/shared/serialkeyb/serialkeyboard.cpp
changeset 0 6663340f3fc9
child 21 524118fd998f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omap3530/shared/serialkeyb/serialkeyboard.cpp	Thu Oct 15 12:59:54 2009 +0100
@@ -0,0 +1,414 @@
+// Copyright (c) 2007-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:
+// omap3530/shared/serialkeyb/serialkeyboard.mmp
+// Simple serial keyboard implementation for Beagle baseport
+//
+
+#include <platform.h>
+#include <e32keys.h>
+#include <assp/omap3530_assp/omap3530_assp_priv.h>
+#include <assp/omap3530_assp/omap3530_uart.h>
+//#include <drivers/resourceman.h>
+
+const TInt KMagicCrashValue = 15;
+
+
+#define SHIFTED(x)   (0x8000|(x))
+#define ISSHIFTED(x) (0x8000&(x))
+#define CTRLED(x)    (0x2000|(x))
+#define ISCTRL(x)  (0x2000&(x))
+#define FUNCED(x)    (0x4000|(x))
+#define ISFUNC(x)  (0x4000&(x))
+#define STDKEY(x)    (0x1FFF&(x))
+
+static const TUint16 KScanCode[] =
+	{
+	/*00*/	EStdKeyNull,
+	/*01*/	EStdKeyHome,				// ^A
+	/*02*/	EStdKeyLeftArrow,			// ^B
+	/*03*/	EStdKeyEscape,				// ^C
+	/*04*/	SHIFTED(EStdKeyDownArrow),	// ^D - move window down
+	/*05*/	EStdKeyEnd,					// ^E
+	/*06*/	EStdKeyRightArrow,			// ^F
+	/*07*/	EStdKeyNull,
+	/*08*/	EStdKeyBackspace,			// ^H - Reserved!
+	/*09*/	EStdKeyTab,					// ^I - Reserved!
+	/*0a*/	EStdKeyNull,
+	/*0b*/	EStdKeyIncContrast,			// ^K
+	/*0c*/	EStdKeyDecContrast,			// ^L
+	/*0d*/	EStdKeyEnter,				// ^M - Reserved!
+	/*0e*/	EStdKeyDownArrow,			// ^N
+	/*0f*/	EStdKeyNull,				// ^O = instant death
+	/*10*/	EStdKeyUpArrow,				// ^P
+	/*11*/	CTRLED(EStdKeyLeftArrow),	// ^Q - make window narrower
+	/*12*/	CTRLED(FUNCED('5')),		// ^R - rotate windows in text window server
+	/*13*/	EStdKeyNull,
+	/*14*/	CTRLED(EStdKeyDownArrow),	// ^T - make window taller
+	/*15*/	SHIFTED(EStdKeyUpArrow),	// ^U - move window up
+	/*16*/	EStdKeyNull,
+	/*17*/	CTRLED(EStdKeyRightArrow),	// ^W - make window wider
+	/*18*/	SHIFTED(EStdKeyRightArrow),	// ^X - move window right
+	/*19*/	CTRLED(EStdKeyUpArrow),		// ^Y - make window shorter
+	/*1a*/	SHIFTED(EStdKeyLeftArrow),	// ^Z - move window left
+	/*1b*/	EStdKeyEscape,				// ^[ - Reserved!
+	/*1c*/	EStdKeyNull,
+	/*1d*/	EStdKeyNull,
+	/*1e*/	EStdKeyNull,
+	/*1f*/	EStdKeyNull,
+	/*20*/	EStdKeySpace,
+	/*21*/	SHIFTED('1'),		// !
+	/*22*/	SHIFTED('2'),		// "
+	/*23*/	EStdKeyHash,		// #
+	/*24*/	SHIFTED('4'),		// $
+	/*25*/	SHIFTED('5'),		// %
+	/*26*/	SHIFTED('7'),		// &
+	/*27*/	EStdKeySingleQuote,
+	/*28*/	SHIFTED('9'),		// (
+	/*29*/	SHIFTED('0'),		// )
+	/*2a*/	SHIFTED('8'),		// *
+	/*2b*/	SHIFTED(EStdKeyEquals),	// +
+	/*2c*/	EStdKeyComma,
+	/*2d*/	EStdKeyMinus,
+	/*2e*/	EStdKeyFullStop,
+	/*2f*/	EStdKeyForwardSlash,
+	/*30*/	'0',
+	/*31*/	'1',
+	/*32*/	'2',
+	/*33*/	'3',
+	/*34*/	'4',
+	/*35*/	'5',
+	/*36*/	'6',
+	/*37*/	'7',
+	/*38*/	'8',
+	/*39*/	'9',
+	/*3a*/	SHIFTED(EStdKeySemiColon),	// :
+	/*3b*/	EStdKeySemiColon,
+	/*3c*/	SHIFTED(EStdKeyComma),		// <
+	/*3d*/	EStdKeyEquals,
+	/*3e*/	SHIFTED(EStdKeyFullStop),	// >
+	/*3f*/	SHIFTED(EStdKeyForwardSlash),	// ?
+	/*40*/	SHIFTED(EStdKeySingleQuote),	// @
+	/*41*/	SHIFTED('A'),
+	/*42*/	SHIFTED('B'),
+	/*43*/	SHIFTED('C'),
+	/*44*/	SHIFTED('D'),
+	/*45*/	SHIFTED('E'),
+	/*46*/	SHIFTED('F'),
+	/*47*/	SHIFTED('G'),
+	/*48*/	SHIFTED('H'),
+	/*49*/	SHIFTED('I'),
+	/*4a*/	SHIFTED('J'),
+	/*4b*/	SHIFTED('K'),
+	/*4c*/	SHIFTED('L'),
+	/*4d*/	SHIFTED('M'),
+	/*4e*/	SHIFTED('N'),
+	/*4f*/	SHIFTED('O'),
+	/*50*/	SHIFTED('P'),
+	/*51*/	SHIFTED('Q'),
+	/*52*/	SHIFTED('R'),
+	/*53*/	SHIFTED('S'),
+	/*54*/	SHIFTED('T'),
+	/*55*/	SHIFTED('U'),
+	/*56*/	SHIFTED('V'),
+	/*57*/	SHIFTED('W'),
+	/*58*/	SHIFTED('X'),
+	/*59*/	SHIFTED('Y'),
+	/*5a*/	SHIFTED('Z'),
+	/*5b*/	EStdKeySquareBracketLeft,
+	/*5c*/	EStdKeyBackSlash,
+	/*5d*/	EStdKeySquareBracketRight,
+	/*5e*/	SHIFTED('6'),			// ^
+	/*5f*/	SHIFTED(EStdKeyMinus),	// _
+	/*60*/	EStdKeyBacklightToggle,	// Actually `
+	/*61*/	'A',
+	/*62*/	'B',
+	/*63*/	'C',
+	/*64*/	'D',
+	/*65*/	'E',
+	/*66*/	'F',
+	/*67*/	'G',
+	/*68*/	'H',
+	/*69*/	'I',
+	/*6a*/	'J',
+	/*6b*/	'K',
+	/*6c*/	'L',
+	/*6d*/	'M',
+	/*6e*/	'N',
+	/*6f*/	'O',
+	/*70*/	'P',
+	/*71*/	'Q',
+	/*72*/	'R',
+	/*73*/	'S',
+	/*74*/	'T',
+	/*75*/	'U',
+	/*76*/	'V',
+	/*77*/	'W',
+	/*78*/	'X',
+	/*79*/	'Y',
+	/*7a*/	'Z',
+	/*7b*/	SHIFTED(EStdKeySquareBracketLeft),
+	/*7c*/	SHIFTED(EStdKeyBackSlash),
+	/*7d*/	SHIFTED(EStdKeySquareBracketRight),
+	/*7e*/	SHIFTED(EStdKeyHash),
+	/*7f*/	EKeyDelete
+	};
+
+static const TUint16 KEscapedScanCode[] =
+	{
+	EStdKeyUpArrow,
+	EStdKeyDownArrow,
+	EStdKeyRightArrow,
+	EStdKeyLeftArrow
+	};
+
+const TUint8 KEscapeChar = 0x1b;
+const TUint8 KEscapeBase = 0x41;
+const TUint8 KEscapeCount = sizeof(KEscapedScanCode) / sizeof(KEscapedScanCode[0]);
+const TUint16 KEscapeScanCode = EStdKeyEscape;
+
+NONSHARABLE_CLASS(TSerialKeyboard) : public DBase
+	{
+public:
+	inline TSerialKeyboard();
+	TInt Create();
+
+private:
+	static void UartIsr( TAny* aParam );
+	static void AddKeyDfc( TAny* aParam );
+	void AddKey( TUint aKey );
+	
+
+private:
+	enum TState
+		{
+		ENormal,
+		EEscaping1,
+		EEscaping2
+		};
+
+	TDfc				iAddKeyDfc;
+	Omap3530Uart::TUart	iUart;
+	TUint				iPrmClientId;
+	TState				iState : 8;
+	TUint8				iKey;
+	};
+
+inline TSerialKeyboard::TSerialKeyboard()
+:	iAddKeyDfc( AddKeyDfc, this, Kern::DfcQue0(), 1 ),
+	iUart( Omap3530Assp::DebugPortNumber() ),
+	iState( ENormal )
+	{
+	// Convert the scan rate from milliseconds to nanokernel ticks (normally 1/64 of a second)
+	}
+
+TInt TSerialKeyboard::Create()
+	{
+	TInt r = KErrNone;
+
+	const Omap3530Uart::TUartNumber portNumber( Omap3530Assp::DebugPortNumber() );
+	
+	if( portNumber >= 0 )
+		{
+		// Register with the power resource manager
+		_LIT( KName, "serkey" );
+		/*r = PowerResourceManager::RegisterClient( iPrmClientId, KName );
+		if( r != KErrNone )
+			{
+			return r;
+			}*/
+
+		__KTRACE_OPT(KBOOT,Kern::Printf("+TSerialKeyboardl::Create:PRM client ID=%x", iPrmClientId )) ;
+		Kern::Printf("+TSerialKeyboardl::Create:PRM client ID=%x", iPrmClientId );
+
+ 		r = Interrupt::Bind( iUart.InterruptId(), UartIsr, this );
+		if ( r < 0 )
+ 			{
+			return r;
+ 			}
+
+		// Ask power resource manager to turn on clocks to the UART
+		// (this could take some time but we're not in any hurry)
+		/*r = PowerResourceManager::ChangeResourceState( iPrmClientId, iUart.PrmFunctionClk(), Prcm::EClkOn );
+		if( KErrNone != r )
+			{
+			return r;
+			}*/
+			
+		/*r = PowerResourceManager::ChangeResourceState( iPrmClientId, iUart.PrmInterfaceClk(), Prcm::EClkOn );
+		if( KErrNone != r )
+			{
+			return r;
+			}*/
+
+		// We can assume that the debug output code has already initialized the UART, we just need to prepare it for RX
+		iUart.EnableFifo( Omap3530Uart::TUart::EEnabled, Omap3530Uart::TUart::ETriggerUnchanged, Omap3530Uart::TUart::ETrigger8 );
+		iUart.EnableInterrupt( Omap3530Uart::TUart::EIntRhr );
+
+		Interrupt::Enable( iUart.InterruptId() );
+		}
+
+	return r;
+	}
+
+void TSerialKeyboard::UartIsr( TAny* aParam )
+	{
+	TSerialKeyboard* self = reinterpret_cast<TSerialKeyboard*>( aParam );
+	
+	const TUint iir = Omap3530Uart::IIR::iMem.Read( self->iUart );
+
+	if ( 0 == (iir bitand Omap3530Uart::IIR::IT_PENDING::KMask) )
+		{
+		const TUint pending = iir bitand Omap3530Uart::IIR::IT_TYPE::KFieldMask;
+
+		// Although the TI datasheet descrivwed IT_TYPE as being an enumerated priority-decoded interrupt
+		// it appears to actually be a bitmask of active interrupt sources
+		if ( (pending bitand Omap3530Uart::IIR::IT_TYPE::ERHR) || (pending bitand Omap3530Uart::IIR::IT_TYPE::ERxLineStatus) )
+			{
+			TUint byte = self->iUart.Read();
+			
+			if( KMagicCrashValue == byte )
+				{
+				Kern::Fault( "SERKEY-FORCED", 0 );
+				}
+			else
+				{
+				self->iKey = byte;
+				self->iAddKeyDfc.Add();
+				Interrupt::Disable( self->iUart.InterruptId() );
+				}
+			}
+		}
+	}
+
+void TSerialKeyboard::AddKeyDfc( TAny* aParam )
+	{
+	TSerialKeyboard* self = reinterpret_cast<TSerialKeyboard*>( aParam );
+
+	switch ( self->iState )
+		{
+	case ENormal:
+		if ( self->iKey == KEscapeChar )
+			{
+			self->iState = EEscaping1;
+			}
+		else
+			{
+			self->AddKey( KScanCode[ self->iKey ] );
+			}
+		break;
+
+	case EEscaping1:
+		if ( self->iKey == KEscapeChar )
+			{
+			self->iState = EEscaping2;
+			}
+		else
+			{
+			self->AddKey( KEscapeScanCode );
+			self->AddKey( KScanCode[ self->iKey ] );
+			self->iState = ENormal;
+			}
+		break;
+
+	case EEscaping2:
+		{
+		TInt index = self->iKey - KEscapeBase;
+		
+		if ( (index >= 0) && (index < KEscapeCount) )
+			{
+			self->AddKey( KEscapedScanCode[ index ] );
+			}
+		else
+			{
+			self->AddKey( KEscapeScanCode );
+			self->AddKey( KScanCode[ self->iKey ] );
+			}
+		self->iState = ENormal;
+		}
+		break;
+
+	default:
+		self->iState = ENormal;
+		break;
+		};
+
+	Interrupt::Enable( self->iUart.InterruptId() );
+	}
+
+void TSerialKeyboard::AddKey( TUint aKey )
+	{
+	const TBool shifted = ISSHIFTED(aKey);
+	const TBool ctrl = ISCTRL(aKey);
+	const TBool func = ISFUNC(aKey);
+	const TUint8 stdKey = STDKEY(aKey);
+
+	TRawEvent e;
+
+	if ( func )
+		{
+		e.Set( TRawEvent::EKeyDown, EStdKeyRightFunc, 0 );
+		Kern::AddEvent( e );
+		}
+	
+	if ( ctrl )
+		{
+		e.Set( TRawEvent::EKeyDown, EStdKeyRightCtrl, 0 );
+		Kern::AddEvent( e );
+		}
+
+	if ( shifted )
+		{
+		e.Set( TRawEvent::EKeyDown, EStdKeyRightShift, 0 );
+		Kern::AddEvent( e );
+		}
+
+	e.Set( TRawEvent::EKeyDown, stdKey, 0 );
+	Kern::AddEvent( e );
+	e.Set( TRawEvent::EKeyUp, stdKey, 0 );
+	Kern::AddEvent( e );
+
+	if ( shifted )
+		{
+		e.Set( TRawEvent::EKeyUp, EStdKeyRightShift, 0 );
+		Kern::AddEvent( e );
+		}
+
+	if ( ctrl )
+		{
+		e.Set( TRawEvent::EKeyUp, EStdKeyRightCtrl, 0 );
+		Kern::AddEvent( e );
+		}
+
+	if ( func )
+		{
+		e.Set( TRawEvent::EKeyUp, EStdKeyRightFunc, 0 );
+		Kern::AddEvent( e );
+		}
+	}
+
+
+DECLARE_STANDARD_EXTENSION()
+	{
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("Starting serial keyboard driver"));
+
+	TInt r = KErrNoMemory;
+	TSerialKeyboard* keyboard = new TSerialKeyboard;
+	if ( keyboard )
+		{
+		r = keyboard->Create();
+		}
+
+	__KTRACE_OPT(KEXTENSION,Kern::Printf("Returns %d",r));
+	return r;
+	}