| author | William Roberts <williamr@symbian.org> |
| Fri, 01 Oct 2010 12:45:26 +0100 | |
| changeset 3 | b41049883d87 |
| parent 0 | 5de814552237 |
| permissions | -rw-r--r-- |
/* * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). * All rights reserved. * This component and the accompanying materials are made available * under the terms of "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: * naviengine_assp\uart\vserialkeyb.cpp * Serial keyboard driver * */ /** @file @internalTechnology */ #include <e32keys.h> #include <comm.h> #include <assp.h> #include "../naviengine_priv.h" #include "../naviengine.h" #include "uart16550_ne.h" #include "vserialkeyb.h" #define SHIFTED(x) (0x8000|(x)) #define ISSHIFTED(x) (0x8000&(x)) #define FUNCED(x) (0x4000|(x)) #define ISFUNCED(x) (0x4000&(x)) #define CTRLED(x) (0x2000|(x)) #define ISCTRLED(x) (0x2000&(x)) #define STDKEY(x) (0x1FFF&(x)) /* * Definition of the converting table for the receive char * through the serial port. * */ const TUint16 convertCodeSerial[] = { /*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 }; /* end of array - convertCodeSerial - */ typedef struct { TUint8 seq[maxSeq+1]; TUint32 convertedCode; } keyType; const keyType escapeCodes[] = { // Three escape codes in a row that completes a sequence { {0x1b, 0x4f, 0x50, 0, 0, 0,}, EStdKeyMenu, }, // F1 gives menu key { {0x1b, 0x4f, 0x51, 0, 0, 0,}, EStdKeyF2, }, // F2 { {0x1b, 0x4f, 0x52, 0, 0, 0,}, EStdKeyF3, }, // F3 { {0x1b, 0x4f, 0x53, 0, 0, 0,}, EStdKeyF4, }, // F4 { {0x1b, 0x4f, 0x74, 0, 0, 0,}, EStdKeyDevice3, }, // F5 gives S60 centre press { {0x1b, 0x4f, 0x75, 0, 0, 0,}, EStdKeyDevice0, }, // F6 gives S60 left softkey { {0x1b, 0x4f, 0x76, 0, 0, 0,}, EStdKeyDevice1, }, // F7 gives S60 right softkey { {0x1b, 0x4f, 0x6c, 0, 0, 0,}, EStdKeyApplication0, }, // F8 gives S60 application softkey { {0x1b, 0x4f, 0x77, 0, 0, 0,}, EStdKeyF9, }, // F9 { {0x1b, 0x4f, 0x78, 0, 0, 0,}, EStdKeyF10, }, // F10 { {0x1b, 0x5b, 0x41, 0, 0, 0,}, EStdKeyUpArrow, }, // Arrow keys { {0x1b, 0x5b, 0x42, 0, 0, 0,}, EStdKeyDownArrow, }, // Arrow keys { {0x1b, 0x5b, 0x43, 0, 0, 0,}, EStdKeyRightArrow, }, // Arrow keys { {0x1b, 0x5b, 0x44, 0, 0, 0,}, EStdKeyLeftArrow, }, // Arrow keys // Four escape codes in a row that completes a sequence { {0x1b, 0x5b, 0x31, 0x7e, 0, 0,}, EStdKeyHome, }, // Home key { {0x1b, 0x5b, 0x34, 0x7e, 0, 0,}, EStdKeyEnd, }, // End key { {0x1b, 0x5b, 0x35, 0x7e, 0, 0,}, EStdKeyPageUp, }, // Page Up key { {0x1b, 0x5b, 0x36, 0x7e, 0, 0,}, EStdKeyPageDown, }, // Page down key { {0x1b, 0x5b, 0x32, 0x7e, 0, 0,}, EStdKeyInsert, }, // Page down key // Five escape codes in a row that completes a sequence { {0x1b, 0x5b, 0x32, 0x33, 0x7e, 0,}, EStdKeyF11, }, // F11 { {0x1b, 0x5b, 0x32, 0x34, 0x7e, 0,}, EStdKeyF12, }, // F12 // end of table - should be all zeros { {0, 0, 0, 0, 0, 0,}, 0, } }; TSerialKeyboard::TSerialKeyboard() : iKeyDfc( KeyDfcFn, this, Kern::DfcQue0(), 1 ), iSeqNum(0) { for (TUint i=0; i<maxSeq; i++) { iCode[i]=0; } } TInt TSerialKeyboard::Create() { // __KTRACE_OPT(KBOOT,Kern::Printf(_L("+TKeyboardSerial::Init"))) ; TUint base; TUint baud; iKeyboardPort = GetSerialPort(baud); switch(iKeyboardPort) { case 1: base=KHwBaseUart1; break; case 2: base=KHwBaseUart2; break; default: base=KHwBaseUart0; iKeyboardPort = 0; //JTAG debug port, use port #0 } __KTRACE_OPT(KBOOT,Kern::Printf("SERIAL KEYBOARD DRIVER: keyboard port=%d", iKeyboardPort )); iUart = new T16550Uart; if (iUart) { iUart->iBase = (TUint8*)base; iUart->SetIER(0); iUart->SetLCR(0); iUart->SetFCR(0); iUart->SetMCR(0); } else return KErrNoMemory; iInterrupt=Interrupt::Bind(KIntIdUart0+iKeyboardPort,Isr,this); if (iInterrupt<0) { delete iUart; return iInterrupt; } iUart->SetLCR(K16550LCR_Data8|K16550LCR_DLAB); iUart->SetBaudRateDivisor((baud==230400) ? KBaudRateDiv_230400 : KBaudRateDiv_default); iUart->SetLCR(K16550LCR_Data8); iUart->SetFCR(K16550FCR_Enable|K16550FCR_RxReset|K16550FCR_TxReset|K16550FCR_RxTrig8); iUart->SetIER(K16550IER_RDAI);// enable receiving data Interrupt::Enable(iInterrupt); return KErrNone; } void TSerialKeyboard::Isr( TAny* aPtr ) // // Interrupt service routine. Called when we receive an interrupt // on the IRQ line it is bound to. If it's a receive, queues DFC // to post the event into the event queue. // { TSerialKeyboard* self = (TSerialKeyboard*)aPtr; T16550Uart& u=*(self->iUart); TUint isr=u.ISR(); if (isr & K16550ISR_NotPending) return; isr&=K16550ISR_IntIdMask; if (isr==K16550ISR_RDAI || isr==K16550ISR_RLSI) { __KTRACE_OPT(KEXTENSION,Kern::Printf("TSerialKeyboard::Isr:RHR")); TUint ch=u.RxData(); if (ch==31) __crash(); // CTRL-? = instant death if (self->iSeqNum < maxSeq) { self->iCode[self->iSeqNum] = ch; self->iSeqNum++; self->iKeyDfc.Add(); Interrupt::Disable(self->iInterrupt); // Can only handle one char at a time } } } void TSerialKeyboard::KeyDfcFn( TAny* aPtr ) // // DFC function. Just calls inline function KeyDfc() // { __KTRACE_OPT(KEXTENSION,Kern::Printf("TSerialKeyboard::KeyDfcFn")); ((TSerialKeyboard*)aPtr)->KeyDfc(); } void TSerialKeyboard::AddConvertedEvent(TUint aKey) { // split aKey into keycode and shift, func, ctrl status TBool isShifted = ISSHIFTED(aKey); TBool isFunced = ISFUNCED(aKey); TBool isCtrled = ISCTRLED(aKey); TUint8 stdKey = STDKEY(aKey); // post it as a sequence of events TRawEvent e; if (isShifted) { e.Set(TRawEvent::EKeyDown,EStdKeyRightShift,0); Kern::AddEvent(e); } if (isCtrled) { e.Set(TRawEvent::EKeyDown,EStdKeyLeftCtrl,0); Kern::AddEvent(e); } if (isFunced) { e.Set(TRawEvent::EKeyDown,EStdKeyLeftFunc,0); Kern::AddEvent(e); } e.Set(TRawEvent::EKeyDown,stdKey,0); Kern::AddEvent(e); e.Set(TRawEvent::EKeyUp,stdKey,0); Kern::AddEvent(e); if (isFunced) { e.Set(TRawEvent::EKeyUp,EStdKeyLeftFunc,0); Kern::AddEvent(e); } if (isCtrled) { e.Set(TRawEvent::EKeyUp,EStdKeyLeftCtrl,0); Kern::AddEvent(e); } if (isShifted) { e.Set(TRawEvent::EKeyUp,EStdKeyRightShift,0); Kern::AddEvent(e); } } void TSerialKeyboard::AddUnconvertedEvent(TUint aKey) { TUint16 convertedKey = convertCodeSerial[aKey]; AddConvertedEvent(convertedKey); } inline void TSerialKeyboard::KeyDfc() // // Processes received characters // { __KTRACE_OPT(KEXTENSION, Kern::Printf("KEY: iSeqNum=%x, key=%x", iSeqNum, iCode[iSeqNum-1])); switch (iSeqNum) { case 1: if (iCode[0] != EEscapingStart) { // Unknown escape sequence - just pass chars as normal events AddUnconvertedEvent(iCode[0]); iSeqNum = 0; } break; case 2: if ((iCode[1] != EEscapingType1) && iCode[1] != EEscapingType2) { // Unknown escape sequence - just pass chars as normal events AddUnconvertedEvent(iCode[0]); AddUnconvertedEvent(iCode[1]); iSeqNum = 0; } break; case 3: case 4: case 5: { TUint escCodeindex = 0; // index into the escape code list TUint seqIndex = 0; // index into the current code sequence TUint bestMatch = 0; // keep a track of the best number of matches so far while (escapeCodes[escCodeindex].seq[0] != 0) { for (seqIndex = 0; seqIndex<iSeqNum; seqIndex++) { if (iCode[seqIndex] != escapeCodes[escCodeindex].seq[seqIndex]) { break; // out of for loop } } if (seqIndex > bestMatch) { bestMatch = seqIndex; } if (escapeCodes[escCodeindex].seq[seqIndex] == 0) { AddConvertedEvent(escapeCodes[escCodeindex].convertedCode); iSeqNum = 0; break; // out of while loop } escCodeindex++; } if ( (bestMatch < iSeqNum) // if we couldn't match all numbers in the sequence so far, this must not be a valid sequence || (iSeqNum == maxSeq) // if we reached the max number of codes in a sequence, this must also not be a valid sequence ) { if (escapeCodes[escCodeindex].seq[0] == 0) { // Unknown escape sequence - just pass chars as normal events for (TUint i=0; i < iSeqNum; i++) { AddUnconvertedEvent(iCode[i]); } } iSeqNum = 0; } } break; default: // Should never reach here! iSeqNum = 0; break; }; Interrupt::Enable(iInterrupt); // Can handle new chars now } /* end of function - KeyDfc - */ // // Kernel Extension entry point // DECLARE_STANDARD_EXTENSION() { __KTRACE_OPT(KEXTENSION,Kern::Printf("Starting keyboard driver")); // create keyboard driver TInt r=KErrNoMemory; TSerialKeyboard* keyboard = new TSerialKeyboard; if ( keyboard ) { r=keyboard->Create(); } __KTRACE_OPT(KEXTENSION,Kern::Printf("Returns %d",r)); return r; }