sl@0: // Copyright (c) 2002-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: // sl@0: sl@0: #include "t_prop_ldd.h" sl@0: #include sl@0: #include "nk_priv.h" sl@0: sl@0: class DPropLDevice : public DLogicalDevice sl@0: { sl@0: public: sl@0: DPropLDevice(); sl@0: virtual TInt Install(); sl@0: virtual void GetCaps(TDes8& aDes) const; sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); sl@0: }; sl@0: sl@0: class DPropLChannel : public DLogicalChannelBase sl@0: { sl@0: public: sl@0: DPropLChannel(); sl@0: ~DPropLChannel(); sl@0: sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: sl@0: private: sl@0: TInt Basic(RPropChannel::TBasicInfo* aInfo); sl@0: sl@0: static void CompleteFn(TAny* aPtr, TInt aReason); sl@0: TInt iReason; sl@0: NFastSemaphore iSem; sl@0: sl@0: }; sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: // sl@0: // Create a new device sl@0: // sl@0: { sl@0: return new DPropLDevice; sl@0: } sl@0: sl@0: DPropLDevice::DPropLDevice() sl@0: // sl@0: // Constructor sl@0: // sl@0: { sl@0: //iUnitsMask=0; sl@0: iVersion = TVersion(1,0,1); sl@0: // iParseMask = 0; sl@0: } sl@0: sl@0: TInt DPropLDevice::Install() sl@0: // sl@0: // Install the device driver. sl@0: // sl@0: { sl@0: TInt r = SetName(&KPropLdName); sl@0: return r; sl@0: } sl@0: sl@0: void DPropLDevice::GetCaps(TDes8&) const sl@0: // sl@0: // Return the Comm capabilities. sl@0: // sl@0: { sl@0: } sl@0: sl@0: TInt DPropLDevice::Create(DLogicalChannelBase*& aChannel) sl@0: // sl@0: // Create a channel on the device. sl@0: // sl@0: { sl@0: aChannel = new DPropLChannel; sl@0: return aChannel ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: DPropLChannel::DPropLChannel() sl@0: { sl@0: NKern::FSSetOwner(&iSem, NKern::CurrentThread()); sl@0: } sl@0: sl@0: TInt DPropLChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /* aInfo*/ , const TVersion& aVer) sl@0: // sl@0: // Create the channel from the passed info. sl@0: // sl@0: { sl@0: if (!Kern::QueryVersionSupported(TVersion(1,0,1),aVer)) sl@0: return KErrNotSupported; sl@0: return KErrNone; sl@0: } sl@0: sl@0: DPropLChannel::~DPropLChannel() sl@0: { sl@0: } sl@0: sl@0: sl@0: #define BASIC_ERROR(aRes, aCond) \ sl@0: {\ sl@0: if (!(aCond)) \ sl@0: { \ sl@0: Kern::Printf("Test '" #aCond "' fails; r = %d;\n\tfile '" __FILE__ "'; line %d;\n", aRes, __LINE__); \ sl@0: prop.Close(); \ sl@0: return EFalse; \ sl@0: } \ sl@0: } sl@0: sl@0: void DPropLChannel::CompleteFn(TAny* aPtr, TInt aReason) sl@0: { // static sl@0: DPropLChannel* self = (DPropLChannel*) aPtr; sl@0: self->iReason = aReason; sl@0: NKern::FSSignal(&self->iSem); sl@0: } sl@0: sl@0: TBool DPropLChannel::Basic(RPropChannel::TBasicInfo* aInfo) sl@0: { sl@0: sl@0: TUid category = aInfo->iCategory; sl@0: TUint key = aInfo->iKey; sl@0: TUint count = aInfo->iCount; sl@0: RProperty::TType type = aInfo->iType; sl@0: sl@0: for (TUint i = 0; i < count; ++i) sl@0: { sl@0: RPropertyRef prop; sl@0: TInt r = prop.Open(category, key); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: r = prop.Attach(category, key); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: // Defines the attributes and access control for a property. This can only be done sl@0: // once for each property. Subsequent attempts to define the same property will return sl@0: // KErrAlreadyExists. sl@0: sl@0: TSecurityPolicy policy; sl@0: sl@0: r = prop.Define(type, policy, policy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = prop.Define(type, policy, policy); sl@0: BASIC_ERROR(r, r == KErrAlreadyExists); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: // Define fails with KErrArgument if wrong type or attribute was specified. sl@0: r = prop.Define(RProperty::ETypeLimit, policy, policy); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: sl@0: static _LIT_SECURITY_POLICY_PASS(KPassPolicy); sl@0: TSecurityPolicy badPolicy; sl@0: *(TInt*)&badPolicy = -1; sl@0: sl@0: r = prop.Define(type, badPolicy, policy); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: r = prop.Define(type, KPassPolicy, badPolicy); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: sl@0: if (type == RProperty::EInt) sl@0: { sl@0: // Define fails with KErrArgument if aType is TInt and aPreallocate is not 0 sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy, 16); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: sl@0: // Following defintion the property has a default value, 0 for integer properties sl@0: r = prop.Define(RProperty::EInt, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: TInt value; sl@0: r = prop.Get(value); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(value, value == 0); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: // Defne fails with KErrTooBig if aPeallocate is grater than KMaxPropertySize. sl@0: r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy, RProperty::KMaxPropertySize); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy, RProperty::KMaxPropertySize+1); sl@0: BASIC_ERROR(r, r == KErrTooBig); sl@0: sl@0: // Following defintion the property has a default value, zero-length data for byte-array and text sl@0: // properties. sl@0: r = prop.Define(RProperty::EByteArray, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: TBuf8<16> buf; sl@0: r = prop.Get(buf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(buf.Size(), buf.Size() == 0); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: sl@0: // Pending subscriptions for this property will not be completed until a new value is published. sl@0: TPropertySubsRequest subs(CompleteFn, this); sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrNotFound); sl@0: sl@0: // If the property has not been defined Delete() fails with KErrNotFound. sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: sl@0: // When deleted any pending subscriptions for the property will be completed with KErrNotFound. sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrNotFound); sl@0: sl@0: // Any new request will not complete until the property is defined and published again. sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: if (type == RProperty::EInt) sl@0: { sl@0: r = prop.Set(1); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: TBuf8<16> buf((TUint8*) "Foo"); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrNone); sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: // If the property has not been defined Set()/Get() fail with KErrNotFound. sl@0: { sl@0: TInt value; sl@0: TBuf8<16> buf; sl@0: if (type == RProperty::EInt) sl@0: { sl@0: r = prop.Get(value); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: r = prop.Set(value); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: } sl@0: else sl@0: { sl@0: r = prop.Get(buf); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrNotFound); sl@0: } sl@0: } sl@0: sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: // If the property is larger than KMaxPropertySize Set() fails with KErrTooBig sl@0: { sl@0: if (type == RProperty::EByteArray) sl@0: { sl@0: TBuf8 buf(RProperty::KMaxPropertySize + 1); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrTooBig); sl@0: } sl@0: } sl@0: sl@0: // When type of operation mismatch with the property type Set()/Get() fails with KErrArgument. sl@0: { sl@0: if (type != RProperty::EInt) sl@0: { sl@0: TInt value; sl@0: r = prop.Get(value); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: r = prop.Set(value); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: } sl@0: else sl@0: { sl@0: TBuf8<16> buf; sl@0: r = prop.Get(buf); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrArgument); sl@0: } sl@0: } sl@0: sl@0: // Get/Set sl@0: if (type == RProperty::EInt) sl@0: { sl@0: r = prop.Set(1); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: TInt value = 0; sl@0: r = prop.Get(value); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(value, value == 1); sl@0: } sl@0: else sl@0: { sl@0: TBuf8<16> ibuf((TUint8*)"Foo"); sl@0: TBuf8<16> obuf; sl@0: r = prop.Set(ibuf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = prop.Get(obuf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = obuf.Compare(ibuf); sl@0: BASIC_ERROR(r, r == 0); sl@0: } sl@0: sl@0: // If the supplied buffer is too small Get() fails with KErrOverflow and the truncated value is reported. sl@0: if (type == RProperty::EByteArray) sl@0: { sl@0: TBuf8<16> ibuf((TUint8*) "0123456789012345"); sl@0: TBuf8<16> obuf((TUint8*) "abcdefghigklmnop"); sl@0: TPtr8 optr((TUint8*) obuf.Ptr(), 0, 15); sl@0: r = prop.Set(ibuf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: r = prop.Get(optr); sl@0: BASIC_ERROR(r, r == KErrOverflow); sl@0: BASIC_ERROR(optr.Length(), optr.Length() == 15); sl@0: BASIC_ERROR(obuf[14], obuf[14] == '4'); sl@0: BASIC_ERROR(obuf[15], obuf[15] == 'p'); sl@0: } sl@0: sl@0: // The calling thread will have the specified request status signalled when the property is next updated. sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: if (type == RProperty::EInt) sl@0: { sl@0: r = prop.Set(1); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: TBuf8<16> buf((TUint8*) "Foo"); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrNone); sl@0: sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: // Cancel an outstanding subscription request. sl@0: // If it has not already completed, the request is completed with KErrCancelled. sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: prop.Cancel(subs); sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrCancel); sl@0: sl@0: r = prop.Define(type, KPassPolicy, KPassPolicy); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: if (type == RProperty::EInt) sl@0: { sl@0: r = prop.Set(1); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: else sl@0: { sl@0: TBuf8<16> buf((TUint8*) "Foo"); sl@0: r = prop.Set(buf); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: } sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrNone); sl@0: prop.Cancel(subs); sl@0: BASIC_ERROR(iReason, iReason == KErrNone); sl@0: sl@0: iReason = KRequestPending; sl@0: r = prop.Subscribe(subs); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: BASIC_ERROR(iReason, iReason == KRequestPending); sl@0: prop.Cancel(subs); sl@0: NKern::FSWait(&iSem); sl@0: BASIC_ERROR(iReason, iReason == KErrCancel); sl@0: sl@0: r = prop.Delete(); sl@0: BASIC_ERROR(r, r == KErrNone); sl@0: sl@0: prop.Close(); sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: // sl@0: // Client requests. sl@0: // sl@0: TBool DPropLChannel::Request(TInt aFunction, TAny* a1, TAny*) sl@0: { sl@0: TBool r; sl@0: switch (aFunction) sl@0: { sl@0: case RPropChannel::EBasicTests: sl@0: RPropChannel::TBasicInfo info; sl@0: kumemget32(&info, a1, sizeof(info)); sl@0: NKern::ThreadEnterCS(); sl@0: r = Basic(&info); sl@0: NKern::ThreadLeaveCS(); sl@0: break; sl@0: default: sl@0: r = EFalse; sl@0: break; sl@0: } sl@0: return r; sl@0: }