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\xyin\d_xyin.cpp sl@0: // Generic digitiser driver sl@0: // sl@0: // sl@0: sl@0: sl@0: #include sl@0: #include sl@0: sl@0: _LIT(KLitDigitiser,"Digitiser"); sl@0: sl@0: LOCAL_C void sampleDfc(TAny* aPtr) sl@0: { sl@0: ((DDigitiser*)aPtr)->ProcessRawSample(); sl@0: } sl@0: sl@0: LOCAL_C void penUpDfc(TAny* aPtr) sl@0: { sl@0: ((DDigitiser*)aPtr)->ProcessPenUp(); sl@0: } sl@0: sl@0: LOCAL_C TInt halFunction(TAny* aPtr, TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: DDigitiser* pH=(DDigitiser*)aPtr; sl@0: return pH->HalFunction(aFunction,a1,a2); sl@0: } sl@0: sl@0: LOCAL_C void rxMsg(TAny* aPtr) sl@0: { sl@0: DDigitiser& h=*(DDigitiser*)aPtr; sl@0: TMessageBase* pM=h.iMsgQ.iMessage; sl@0: if (pM) sl@0: h.HandleMsg(pM); sl@0: } sl@0: sl@0: DDigitiser::DDigitiser() sl@0: : DPowerHandler(KLitDigitiser), sl@0: iMsgQ(rxMsg,this,NULL,1), sl@0: iSampleDfc(sampleDfc,this,5), sl@0: iPenUpDfc(penUpDfc,this,5) sl@0: { sl@0: // iBufferIndex=0; sl@0: // iLastPos=TPoint(0,0); sl@0: // iState=EIdle; sl@0: // iCount=0; sl@0: // iPointerOn=EFalse sl@0: } sl@0: sl@0: TInt DDigitiser::Create() sl@0: { sl@0: TInt r=DoCreate(); // do hardware-dependent initialisation sl@0: sl@0: if (r!=KErrNone) sl@0: return r; sl@0: sl@0: __ASSERT_DEBUG(iDfcQ, Kern::Fault("DDigitiser::Create iDfcQ not set", __LINE__)); sl@0: iMsgQ.SetDfcQ(iDfcQ); sl@0: iSampleDfc.SetDfcQ(iDfcQ); sl@0: iPenUpDfc.SetDfcQ(iDfcQ); sl@0: sl@0: TInt n=iCfg.iPenUpDiscard; // number of samples to delay sl@0: iBuffer=(TPoint*)Kern::Alloc(n*sizeof(TPoint)); sl@0: if (!iBuffer) sl@0: return KErrNoMemory; sl@0: sl@0: // install the HAL function sl@0: r=Kern::AddHalEntry(EHalGroupDigitiser,halFunction,this); sl@0: if (r!=KErrNone) sl@0: return r; sl@0: sl@0: iMsgQ.Receive(); sl@0: sl@0: // wait for pen down sl@0: WaitForPenDown(); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: void DDigitiser::RawSampleValid() sl@0: // sl@0: // Called by hardware-dependent code when a raw sample is available sl@0: // sl@0: { sl@0: iSampleDfc.Add(); sl@0: } sl@0: sl@0: void DDigitiser::PenUp() sl@0: // sl@0: // Called by hardware-dependent code when the pen goes up sl@0: // sl@0: { sl@0: iPenUpDfc.Add(); sl@0: } sl@0: sl@0: void DDigitiser::ProcessRawSample() sl@0: // sl@0: // DFC to process a raw sample sl@0: // sl@0: { sl@0: TPoint p; sl@0: TInt r; sl@0: TBool ok=SamplesToPoint(p); sl@0: if (!ok) sl@0: { sl@0: // wait for pen to stabilise sl@0: __KTRACE_XY2(Kern::Printf("BS")); sl@0: WaitForPenUpDebounce(); sl@0: return; sl@0: } sl@0: __KTRACE_XY2(Kern::Printf("GS (%d,%d) %d",p.iX,p.iY,iState)); sl@0: switch (iState) sl@0: { sl@0: case EIdle: sl@0: // pen has just gone down sl@0: iCount=iCfg.iPenDownDiscard; sl@0: iState=EDiscardOnPenDown; sl@0: // fall through sl@0: case EDiscardOnPenDown: sl@0: if (iCount) sl@0: { sl@0: // still discarding sl@0: iCount--; sl@0: break; sl@0: } sl@0: iState=EBufferFilling; sl@0: iBufferIndex=0; sl@0: iCount=iCfg.iPenUpDiscard; sl@0: // fall through sl@0: case EBufferFilling: sl@0: if (iCount) sl@0: { sl@0: // buffer still filling sl@0: iCount--; sl@0: iBuffer[iBufferIndex++]=p; sl@0: if (iBufferIndex==iCfg.iPenUpDiscard) sl@0: iBufferIndex=0; sl@0: break; sl@0: } sl@0: iState=EBufferFull; sl@0: // fall through sl@0: case EBufferFull: sl@0: r=DelayAndConvertSample(p,iLastPos); sl@0: if (r!=KErrNone) sl@0: break; // off the screen, so don't issue Pen Down Event sl@0: iState=EPenDown; sl@0: ResetPenMoveFilter(); sl@0: IssuePenDownEvent(); sl@0: break; sl@0: case EPenDown: sl@0: r=DelayAndConvertSample(p,p); sl@0: if (r!=KErrNone) sl@0: { sl@0: iState=EIdle; // off the screen, so treat as pen-up sl@0: IssuePenUpEvent(); sl@0: break; sl@0: } sl@0: FilterPenMove(p); sl@0: break; sl@0: }; sl@0: WaitForPenUp(); // request another sample from the hardware sl@0: } sl@0: sl@0: void DDigitiser::ProcessPenUp() sl@0: // sl@0: // DFC to process pen-up events sl@0: // sl@0: { sl@0: __KTRACE_XY2(Kern::Printf("up %d",iState)); sl@0: switch (iState) sl@0: { sl@0: case EIdle: sl@0: case EDiscardOnPenDown: sl@0: case EBufferFilling: sl@0: case EBufferFull: sl@0: iState=EIdle; sl@0: break; sl@0: case EPenDown: sl@0: iState=EIdle; sl@0: IssuePenUpEvent(); sl@0: break; sl@0: } sl@0: WaitForPenDown(); // tell the hardware to watch for another pen-down sl@0: } sl@0: sl@0: TBool DDigitiser::SamplesToPoint(TPoint& aPoint) sl@0: // sl@0: // Average and validate the raw samples from the hardware sl@0: // sl@0: { sl@0: #if defined(__DIGITISER_DEBUG2__) sl@0: TBuf<80> buf; sl@0: #endif sl@0: TInt i; sl@0: TInt minx=KMaxTInt; sl@0: TInt miny=KMaxTInt; sl@0: TInt maxx=KMinTInt; sl@0: TInt maxy=KMinTInt; sl@0: TInt sumx=0; sl@0: TInt sumy=0; sl@0: TInt n=iCfg.iNumXYSamples; sl@0: for (i=0; imaxx) sl@0: maxx=x; sl@0: sumx+=x; sl@0: TInt y=iY[i]; sl@0: if (ymaxy) sl@0: maxy=y; sl@0: sumy+=y; sl@0: // __KTRACE_XY2(buf.AppendFormat(_L("(%d,%d) "),x,y)); sl@0: __KTRACE_XY2(Kern::Printf("(%d,%d) ",x,y)); sl@0: } sl@0: // __KTRACE_XY2(Kern::Printf("%S", buf)); sl@0: sl@0: TInt spreadx=maxx-minx; sl@0: TInt spready=maxy-miny; sl@0: if (iCfg.iDisregardMinMax) sl@0: { sl@0: sumx-=minx; // disregard extremal values in average sl@0: sumx-=maxx; sl@0: sumy-=miny; sl@0: sumy-=maxy; sl@0: n-=2; sl@0: } sl@0: sumx/=n; // average the values sl@0: sumy/=n; sl@0: if (spreadx=iCfg.iMinX && sumx<=iCfg.iMaxX && sumy>=iCfg.iMinY && sumy<=iCfg.iMaxY) sl@0: { sl@0: // samples are OK sl@0: aPoint.iX=sumx; sl@0: aPoint.iY=sumy; sl@0: return ETrue; sl@0: } sl@0: // samples are dodgy sl@0: return EFalse; sl@0: } sl@0: sl@0: TInt DDigitiser::DelayAndConvertSample(const TPoint& aSample, TPoint& aScreenPoint) sl@0: // sl@0: // Pass a sample through the delay line and convert to screen coordinates sl@0: // sl@0: { sl@0: if (iCfg.iPenUpDiscard != 0) sl@0: { sl@0: TPoint p=iBuffer[iBufferIndex]; // sample leaving delay line sl@0: iBuffer[iBufferIndex++]=aSample; // sample entering delay line sl@0: if (iBufferIndex==iCfg.iPenUpDiscard) sl@0: iBufferIndex=0; sl@0: return DigitiserToScreen(p,aScreenPoint); sl@0: } sl@0: return DigitiserToScreen(aSample,aScreenPoint); sl@0: } sl@0: sl@0: void DDigitiser::IssuePenDownEvent() sl@0: { sl@0: TRawEvent e; sl@0: e.Set(TRawEvent::EButton1Down,iLastPos.iX,iLastPos.iY); sl@0: Kern::AddEvent(e); sl@0: __KTRACE_XY2(Kern::Printf("D %d,%d",e.Pos().iX,e.Pos().iY)); sl@0: } sl@0: sl@0: void DDigitiser::IssuePenUpEvent() sl@0: { sl@0: TRawEvent e; sl@0: e.Set(TRawEvent::EButton1Up,iLastPos.iX,iLastPos.iY); sl@0: Kern::AddEvent(e); sl@0: __KTRACE_XY2(Kern::Printf("U %d,%d",e.Pos().iX,e.Pos().iY)); sl@0: } sl@0: sl@0: void DDigitiser::IssuePenMoveEvent(const TPoint& aPoint) sl@0: { sl@0: TRawEvent e; sl@0: e.Set(TRawEvent::EPointerMove,aPoint.iX,aPoint.iY); sl@0: Kern::AddEvent(e); sl@0: __KTRACE_XY2(Kern::Printf("M %d,%d",e.Pos().iX,e.Pos().iY)); sl@0: } sl@0: sl@0: void DDigitiser::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: if (aMsg->iValue) sl@0: DigitiserOn(); sl@0: else sl@0: DigitiserOff(); sl@0: aMsg->Complete(KErrNone,ETrue); sl@0: } sl@0: sl@0: TInt DDigitiser::HalFunction(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: TInt r=KErrNone; sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("HalFunction %d", aFunction)); sl@0: switch(aFunction) sl@0: { sl@0: case EDigitiserHalXYInfo: sl@0: { sl@0: TPckgBuf vPckg; sl@0: DigitiserInfo(vPckg()); sl@0: Kern::InfoCopy(*(TDes8*)a1,vPckg); sl@0: break; sl@0: } sl@0: case EDigitiserHalSetXYInputCalibration: sl@0: { sl@0: if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDigitiserHalSetXYInputCalibration"))) sl@0: return KErrPermissionDenied; sl@0: TDigitizerCalibration cal; sl@0: kumemget32(&cal,a1,sizeof(TDigitizerCalibration)); sl@0: r=SetXYInputCalibration(cal); sl@0: break; sl@0: } sl@0: case EDigitiserHalCalibrationPoints: sl@0: TDigitizerCalibration cal; sl@0: r=CalibrationPoints(cal); sl@0: kumemput32(a1,&cal,sizeof(TDigitizerCalibration)); sl@0: break; sl@0: case EDigitiserHalSaveXYInputCalibration: sl@0: r=SaveXYInputCalibration(); sl@0: break; sl@0: case EDigitiserHalRestoreXYInputCalibration: sl@0: if(!Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDigitiserHalRestoreXYInputCalibration"))) sl@0: return KErrPermissionDenied; sl@0: r=RestoreXYInputCalibration((TDigitizerCalibrationType)(TInt)a1); sl@0: break; sl@0: case EDigitiserHalSetXYState: sl@0: { sl@0: if(!Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,__PLATSEC_DIAGNOSTIC_STRING("Checked by Hal function EDigitiserHalSetXYState"))) 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); sl@0: } sl@0: else sl@0: { sl@0: TThreadMessage& m=Kern::Message(); sl@0: m.iValue = EFalse; sl@0: m.SendReceive(&iMsgQ); sl@0: } sl@0: } sl@0: break; sl@0: case EDigitiserHalXYState: sl@0: kumemput32(a1, (TBool*)&iPointerOn, sizeof(TBool)); sl@0: break; sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: DECLARE_STANDARD_EXTENSION() sl@0: { sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("Starting digitiser driver")); sl@0: if (Kern::SuperPage().iCpuId & KCpuIdISS) sl@0: return KErrNone; // no digitiser on ARMULATOR sl@0: DDigitiser* pD=DDigitiser::New(); sl@0: TInt r=KErrNoMemory; sl@0: if (pD) sl@0: r=pD->Create(); sl@0: __KTRACE_OPT(KEXTENSION,Kern::Printf("Returning %d",r)); sl@0: return r; sl@0: } sl@0: sl@0: #ifdef __BUILD_DEVICE_DRIVER__ sl@0: class DDigitiserPdd : public DPhysicalDevice sl@0: { sl@0: public: sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: }; sl@0: sl@0: _LIT(KPddName,"XYInput"); sl@0: sl@0: TInt DDigitiserPdd::Install() sl@0: { sl@0: return SetName(&KPddName); sl@0: } sl@0: sl@0: void DDigitiserPdd::GetCaps(TDes8&) const sl@0: { sl@0: } sl@0: sl@0: TInt DDigitiserPdd::Create(DBase*& aChannel, TInt, const TDesC8*, const TVersion&) sl@0: { sl@0: aChannel=NULL; sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt DDigitiserPdd::Validate(TInt, const TDesC8*, const TVersion&) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: DECLARE_EXTENSION_PDD() sl@0: { sl@0: return new DDigitiserPdd; sl@0: } sl@0: #endif