kerneltest/e32test/mmu/d_sharedio.cpp
changeset 0 a41df078684a
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // e32test\mmu\d_sharedio.cpp
       
    15 // LDD for testing SharedIoBuffers
       
    16 // 
       
    17 //
       
    18 
       
    19 #include <kernel/kern_priv.h>
       
    20 #include "d_sharedio.h"
       
    21 
       
    22 //
       
    23 // LDD factory
       
    24 //
       
    25 
       
    26 class DSharedIoTestFactory : public DLogicalDevice
       
    27 	{
       
    28 public:
       
    29 	DSharedIoTestFactory();
       
    30 	~DSharedIoTestFactory();
       
    31 	virtual TInt Install();
       
    32 	virtual void GetCaps(TDes8& aDes) const;
       
    33 	virtual TInt Create(DLogicalChannelBase*& aChannel);
       
    34 public:
       
    35 	DSharedIoBuffer* iGlobalBuffer;
       
    36 	};
       
    37 
       
    38 //
       
    39 // Logical Channel
       
    40 //
       
    41 
       
    42 class DSharedIoTest : public DLogicalChannelBase
       
    43 	{
       
    44 public:
       
    45 	virtual ~DSharedIoTest();
       
    46 protected:
       
    47 	virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
       
    48 	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
       
    49 public:
       
    50 	DSharedIoBuffer* iIoBuffer;
       
    51 	DSharedIoBuffer* iGlobalBuffer;
       
    52 	DSharedIoTestFactory* iFactory;
       
    53 #ifndef __WINS__
       
    54 	TPhysAddr iPhysAddress;
       
    55 #endif
       
    56 	};
       
    57 
       
    58 //
       
    59 // LDD factory
       
    60 //
       
    61 
       
    62 DSharedIoTestFactory::DSharedIoTestFactory()
       
    63 	{
       
    64 	iGlobalBuffer=NULL;
       
    65 	}
       
    66 
       
    67 DSharedIoTestFactory::~DSharedIoTestFactory()
       
    68 	{
       
    69 	delete iGlobalBuffer;
       
    70 	}
       
    71 TInt DSharedIoTestFactory::Create(DLogicalChannelBase*& aChannel)
       
    72 	{
       
    73 	__KTRACE_OPT(KMMU,Kern::Printf(">DSharedIoTestFactory::Create iGlobalBuffer=%x",iGlobalBuffer));
       
    74 	if(!iGlobalBuffer)
       
    75 		{
       
    76 #ifdef __WINS__
       
    77 		TUint aAttribs=0;
       
    78 #else
       
    79 		TUint aAttribs=EMapAttrSupRw | EMapAttrFullyBlocking;
       
    80 #endif
       
    81 		TInt r=DSharedIoBuffer::New(iGlobalBuffer,KSizeGlobalBuffer,aAttribs);
       
    82 		if(r!=KErrNone)
       
    83 			return r;
       
    84 		}
       
    85 	aChannel=new DSharedIoTest;
       
    86 	if(!aChannel)
       
    87 		return KErrNoMemory;
       
    88 	((DSharedIoTest*)aChannel)->iGlobalBuffer=iGlobalBuffer;
       
    89 	((DSharedIoTest*)aChannel)->iFactory=this;
       
    90 	__KTRACE_OPT(KMMU,Kern::Printf("<DSharedIoTestFactory::Create iGlobalBuffer=%x",iGlobalBuffer));
       
    91 	return KErrNone;
       
    92 	}
       
    93 
       
    94 TInt DSharedIoTestFactory::Install()
       
    95 	{
       
    96 	return SetName(&KSharedIoTestLddName);
       
    97 	}
       
    98 
       
    99 void DSharedIoTestFactory::GetCaps(TDes8& /* aDes */) const
       
   100 	{
       
   101 	//aDes.FillZ(aDes.MaxLength());
       
   102 	}
       
   103 
       
   104 DECLARE_STANDARD_LDD()
       
   105 	{
       
   106 	return new DSharedIoTestFactory;
       
   107 	}
       
   108 
       
   109 //
       
   110 // Logical Channel
       
   111 //
       
   112 
       
   113 TInt DSharedIoTest::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
       
   114 	{
       
   115 	return KErrNone;
       
   116 	}
       
   117 
       
   118 DSharedIoTest::~DSharedIoTest()
       
   119 	{
       
   120 	delete iIoBuffer;
       
   121 	}
       
   122 
       
   123 TInt checkBuffer(TAny* buffer, TUint32 aSize, TUint32 key)
       
   124 	{
       
   125 	TInt r=KErrNone;
       
   126 	TUint8* m=(TUint8*)buffer;
       
   127 	for(TUint32 size=0;size<aSize;size++,key+=5,m++)
       
   128 		{
       
   129 		if(*m!=(TUint8)(key%256))
       
   130 			{
       
   131 			r=KErrCorrupt;
       
   132 			break;
       
   133 			}
       
   134 		}
       
   135 	return r;
       
   136 	}
       
   137 
       
   138 TInt fillBuffer(TAny* buffer, TUint32 aSize, TUint32 key)
       
   139 	{
       
   140 	TUint8* m=(TUint8*)buffer;
       
   141 	for(TUint32 size=0;size<aSize;size++,key+=5,m++)
       
   142 		{
       
   143 		*m=(TUint8)(key%256);
       
   144 		}
       
   145 	return KErrNone;
       
   146 	}
       
   147 
       
   148 static void AppendNumToBuf(TDes8& aDes, const TDesC& aNum, TInt width, char fill)
       
   149 {
       
   150 	TInt l = aNum.Length();
       
   151 	for (; l < width; ++l)
       
   152 		aDes.Append(TChar(fill));
       
   153 	aDes.Append(aNum);
       
   154 }
       
   155 
       
   156 static void DumpMemory(TUint8* aStart, TInt aSize)
       
   157 {
       
   158 	TBuf8<80> line;
       
   159 	TBuf8<24> val;
       
   160 	TChar space(' ');
       
   161 
       
   162 	TInt i = (TInt)aStart & 0xF;	// first byte in this line to dump
       
   163 	TInt n = 16;					// end byte in this line
       
   164 
       
   165 	while (aSize > 0)
       
   166 		{
       
   167 		if (i + aSize < 16)
       
   168 			n = i + aSize;
       
   169 
       
   170 		val.Num((TUint32)aStart & ~0xF, EHex);
       
   171 		AppendNumToBuf(line, val, 8, '0');
       
   172 		line.Append(space);
       
   173 		line.Append(space);
       
   174 
       
   175 		TInt j;
       
   176 
       
   177 		for (j = 0; j < i; ++j)
       
   178 			{
       
   179 			line.Append(space);
       
   180 			line.Append(space);
       
   181 			line.Append(space);
       
   182 
       
   183 			if (j == 7) line.Append(space);
       
   184 			}
       
   185 
       
   186 		for (; j < n; ++j)
       
   187 			{
       
   188 			val.Num(aStart[j-i], EHex);
       
   189 			line.Append(space);
       
   190 			AppendNumToBuf(line, val, 2, '0');
       
   191 
       
   192 			if (j == 7) line.Append(space);
       
   193 			}
       
   194 
       
   195 		for (; j < 16; ++j)
       
   196 			{
       
   197 			line.Append(space);
       
   198 			line.Append(space);
       
   199 			line.Append(space);
       
   200 
       
   201 			if (j == 7) line.Append(space);
       
   202 			}
       
   203 
       
   204 		line.Append(space);
       
   205 		line.Append(space);
       
   206 
       
   207 		for (j = 0; j < i; ++j)
       
   208 			line.Append(space);
       
   209 
       
   210 		for (; j < n; ++j)
       
   211 			{
       
   212 			char c = aStart[j-i];
       
   213 			if (c < ' ' || c > 126) c = '.';
       
   214 			line.Append(TChar(c));
       
   215 			}
       
   216 
       
   217 		Kern::Printf("%S", &line);
       
   218 
       
   219 		line.SetLength(0);
       
   220 
       
   221 		aStart += (n - i);
       
   222 		aSize -= (n - i);
       
   223 
       
   224 		i = 0;
       
   225 		}
       
   226 }
       
   227 
       
   228 TBool CheckMemCleared(TLinAddr aAddress, TInt aSize)
       
   229 {
       
   230 	TUint8* aPtr = (TUint8*)aAddress;
       
   231 	for(TInt i = 0; i<aSize; i++)
       
   232 		{
       
   233 		if(aPtr[i] != 0x03)
       
   234 			{
       
   235 			Kern::Printf("CheckMemCleared(0x%x, %d) failed at i = 0x%x", aAddress, aSize, i);
       
   236 			// Start on current line & ~0xF, run for 16 lines x 16 bytes
       
   237 			TUint8 *p = (TUint8*)((aAddress + i) & ~0x0F);
       
   238 			TInt n = 256;
       
   239 
       
   240 			if (p < aPtr) p = aPtr;
       
   241 			if (p - aPtr > aSize - n)	// if (p + n > aPtr + aSize) rearranged (to avoid overflow)
       
   242 				n = aPtr + aSize - p;
       
   243 
       
   244 			DumpMemory(p, n);
       
   245 			return EFalse;
       
   246 			}
       
   247 		}
       
   248 	return ETrue;
       
   249 }
       
   250 
       
   251 TInt DSharedIoTest::Request(TInt aFunction, TAny* a1, TAny* a2)
       
   252 	{
       
   253 	TInt r=KErrNone;
       
   254 	switch (aFunction)
       
   255 		{
       
   256 		case RTestLdd::ECreateBuffer:
       
   257 			{
       
   258 			TUint32 size = (TUint32)a1;
       
   259 			r = KErrNoMemory;
       
   260 #ifdef __WINS__
       
   261 			TUint aAttribs1=0;
       
   262 			TUint aAttribs2=0;
       
   263 			TUint aAttribs3=0;
       
   264 #else
       
   265 			TUint aAttribs1=EMapAttrSupRw | EMapAttrBufferedNC;
       
   266 			TUint aAttribs2=EMapAttrSupRw | EMapAttrFullyBlocking;
       
   267 			TUint aAttribs3=EMapAttrSupRw | EMapAttrCachedMax;
       
   268 #endif
       
   269 			NKern::ThreadEnterCS();
       
   270 			r=DSharedIoBuffer::New(iIoBuffer,size,aAttribs1);
       
   271 			if(r!=KErrNone)
       
   272 				{
       
   273 				Kern::Printf("Error creating buffer r=%d\n",r);
       
   274 				NKern::ThreadLeaveCS();
       
   275 				return r;
       
   276 				}
       
   277 
       
   278 			//Check the buffer is properly initialized (the previous content 
       
   279 			//deleted by inserting all 0x03s)
       
   280 			if (!CheckMemCleared(iIoBuffer->iAddress, iIoBuffer->iSize))
       
   281 				{
       
   282 				Kern::Printf("Error memory zeroing test for shared io buffers");
       
   283 				NKern::ThreadLeaveCS();
       
   284 				return KErrCorrupt;
       
   285 				}
       
   286 
       
   287 			//just test that we can construct a second shared buffer
       
   288 			DSharedIoBuffer* ptr;
       
   289 			r=DSharedIoBuffer::New(ptr,size,aAttribs2);
       
   290 			if(r!=KErrNone)
       
   291 				{
       
   292 				Kern::Printf("Error creating the 2nd buffer r=%d\n",r);
       
   293 				delete iIoBuffer;
       
   294 				iIoBuffer=NULL;
       
   295 				NKern::ThreadLeaveCS();
       
   296 				return r;
       
   297 				}
       
   298 			delete ptr; //creation successfull, simply delete the object
       
   299 
       
   300 			// and the third one, this time fully cached.
       
   301 			r=DSharedIoBuffer::New(ptr,size,aAttribs3);
       
   302 			if(r!=KErrNone)
       
   303 				{
       
   304 				Kern::Printf("Error creating the 3rd buffer r=%d\n",r);
       
   305 				delete iIoBuffer;
       
   306 				iIoBuffer=NULL;
       
   307 				NKern::ThreadLeaveCS();
       
   308 				return r;
       
   309 				}
       
   310 			delete ptr; //creation successfull, simply delete the object
       
   311 
       
   312 			NKern::ThreadLeaveCS();
       
   313 			if(iIoBuffer->iSize!=size)   // test
       
   314 				{
       
   315 				Kern::Printf("Error checking size iIoBuffer->iSize=%d size=%d\n",iIoBuffer->iSize,size);
       
   316 				return KErrGeneral;
       
   317 				}
       
   318 			memset((void*)iIoBuffer->iAddress,0,size);
       
   319 			}
       
   320 			return r;
       
   321 
       
   322 		case RTestLdd::EMapInGlobalBuffer:
       
   323 			{
       
   324 			if(!iGlobalBuffer)
       
   325 				return KErrGeneral;
       
   326 
       
   327 			TUint id;
       
   328 			kumemget32(&id,a1,sizeof(TUint));
       
   329 
       
   330 			NKern::ThreadEnterCS();
       
   331 			Kern::Containers()[EProcess]->Wait();
       
   332 			DProcess* process=Kern::ProcessFromId(id);
       
   333 			if(process)
       
   334 				process->Open();
       
   335 			Kern::Containers()[EProcess]->Signal();
       
   336 			if(process)
       
   337 				{
       
   338 				r=iGlobalBuffer->UserMap(process);
       
   339 				process->Close(0);
       
   340 				}
       
   341 			else
       
   342 				r = KErrGeneral;
       
   343 			NKern::ThreadLeaveCS();
       
   344 
       
   345 			if(r!=KErrNone)
       
   346 				return r;
       
   347 
       
   348 			if(iGlobalBuffer->UserToKernel(iGlobalBuffer->iUserAddress,iGlobalBuffer->iSize)!=iGlobalBuffer->iAddress)
       
   349 				return KErrGeneral;
       
   350 			
       
   351 			if(iGlobalBuffer->UserToKernel(iGlobalBuffer->iUserAddress,iGlobalBuffer->iSize+1)!=NULL)
       
   352 				return KErrGeneral;
       
   353 
       
   354 			if(iGlobalBuffer->KernelToUser(iGlobalBuffer->iAddress)!=iGlobalBuffer->iUserAddress)
       
   355 				return KErrGeneral;
       
   356 
       
   357 			kumemput32(a1,&iGlobalBuffer->iUserAddress,sizeof(TAny*));
       
   358 			kumemput32(a2,&iGlobalBuffer->iSize,sizeof(TInt));
       
   359 
       
   360 			return KErrNone;
       
   361 			}
       
   362 
       
   363 		case RTestLdd::EMapOutGlobalBuffer:
       
   364 			{
       
   365 			if(!iGlobalBuffer)
       
   366 				return KErrGeneral;
       
   367 			r=iGlobalBuffer->UserUnmap();
       
   368 			if(r==KErrNone)
       
   369 				if(iGlobalBuffer->iUserProcess)
       
   370 					r = KErrGeneral;
       
   371 			return r;
       
   372 			}
       
   373 
       
   374 		case RTestLdd::EDestroyGlobalBuffer:
       
   375 			{
       
   376 			NKern::ThreadEnterCS();
       
   377 			delete iGlobalBuffer;
       
   378 			iGlobalBuffer = NULL;
       
   379 			iFactory->iGlobalBuffer=NULL;
       
   380 			NKern::ThreadLeaveCS();
       
   381 			return KErrNone;
       
   382 			}
       
   383 
       
   384 		case RTestLdd::ECreateBufferPhysAddr:
       
   385 			{
       
   386 #ifdef __WINS__
       
   387 			return KErrNotSupported;
       
   388 #else
       
   389 			TUint32 size=Kern::RoundToPageSize(1);
       
   390 			NKern::ThreadEnterCS();
       
   391 			r=Epoc::AllocPhysicalRam(size,iPhysAddress);
       
   392 			Kern::Printf("phys addr = %X!\n",iPhysAddress);
       
   393 			if(r!=KErrNone)
       
   394 				{
       
   395 				NKern::ThreadLeaveCS();
       
   396 				return r;
       
   397 				}
       
   398 			r = KErrNoMemory;
       
   399 
       
   400 			//test that we can construct a fully cached sharedio
       
   401 			DSharedIoBuffer* ptr;
       
   402 			r=DSharedIoBuffer::New(ptr,iPhysAddress,size,EMapAttrSupRw|EMapAttrCachedMax);
       
   403 			if(r!=KErrNone)
       
   404 				{
       
   405 				Kern::Printf("Error creating the physical cached buffer r=%d\n",r);
       
   406 				Epoc::FreePhysicalRam(iPhysAddress,size);
       
   407 				iPhysAddress=0;
       
   408 				NKern::ThreadLeaveCS();
       
   409 				return r;
       
   410 				}
       
   411 			delete ptr; //creation successfull, simply delete the object
       
   412 
       
   413 
       
   414 			r=DSharedIoBuffer::New(iIoBuffer,iPhysAddress,size,EMapAttrSupRw|EMapAttrFullyBlocking);
       
   415 			if(r!=KErrNone)
       
   416 				{
       
   417 				Epoc::FreePhysicalRam(iPhysAddress,size);
       
   418 				iPhysAddress=0;
       
   419 				NKern::ThreadLeaveCS();
       
   420 				return r;
       
   421 				}
       
   422 
       
   423 			if(iIoBuffer->iSize!=size)   // test
       
   424 				{
       
   425 				delete iIoBuffer;
       
   426 				iIoBuffer=NULL;
       
   427 				Epoc::FreePhysicalRam(iPhysAddress,size);
       
   428 				iPhysAddress=0;
       
   429 				NKern::ThreadLeaveCS();
       
   430 				return KErrGeneral;
       
   431 				}
       
   432 
       
   433 			fillBuffer((TAny*)iIoBuffer->iAddress,size,180);
       
   434 
       
   435 			DPlatChunkHw* hwChunk;
       
   436 			r=DPlatChunkHw::New(hwChunk, iPhysAddress, size, EMapAttrSupRw|EMapAttrFullyBlocking);
       
   437 			if(r!=KErrNone)
       
   438 				{
       
   439 				delete iIoBuffer;
       
   440 				iIoBuffer=NULL;
       
   441 				Epoc::FreePhysicalRam(iPhysAddress,size);
       
   442 				iPhysAddress=0;
       
   443 				NKern::ThreadLeaveCS();
       
   444 				return r;
       
   445 				}
       
   446 			
       
   447 			r=checkBuffer((TAny*)hwChunk->LinearAddress(),size,180);
       
   448 			if(r!=KErrNone)
       
   449 				{
       
   450 				delete iIoBuffer;
       
   451 				iIoBuffer=NULL;
       
   452 				hwChunk->Close(NULL);
       
   453 				Epoc::FreePhysicalRam(iPhysAddress,size);
       
   454 				iPhysAddress=0;
       
   455 				NKern::ThreadLeaveCS();
       
   456 				return r;
       
   457 				}
       
   458 
       
   459 			hwChunk->Close(NULL);
       
   460 			NKern::ThreadLeaveCS();
       
   461 			return r;
       
   462 #endif
       
   463 			}
       
   464 
       
   465 		case RTestLdd::EDestroyBufferPhysAddr:
       
   466 			{
       
   467 #ifdef __WINS__
       
   468 			return KErrNotSupported;
       
   469 #else
       
   470 			TUint32 size=Kern::RoundToPageSize(1);
       
   471 			NKern::ThreadEnterCS();
       
   472 			delete iIoBuffer;
       
   473 			iIoBuffer = NULL;
       
   474 			r=Epoc::FreePhysicalRam(iPhysAddress,size);
       
   475 			iPhysAddress=0;
       
   476 			NKern::ThreadLeaveCS();
       
   477 			return r;
       
   478 #endif
       
   479 			}
       
   480 
       
   481 
       
   482 		case RTestLdd::EMapInBuffer:
       
   483 			{
       
   484 			r=iIoBuffer->UserMap(&Kern::CurrentProcess());
       
   485 			if(r!=KErrNone)
       
   486 				return r;
       
   487 
       
   488 			TAny** p = (TAny**)iIoBuffer->iAddress;
       
   489 			TAny* ua = (TAny*)iIoBuffer->iUserAddress;
       
   490 			TAny** end = (TAny**)((TInt)p+iIoBuffer->iSize);
       
   491 			while(p<end)
       
   492 				{
       
   493 				*p++ = ua;
       
   494 				ua = (TAny*)((TInt)ua+sizeof(TAny*));
       
   495 				}
       
   496 			if(iIoBuffer->UserToKernel(iIoBuffer->iUserAddress,iIoBuffer->iSize)!=iIoBuffer->iAddress)
       
   497 				return KErrGeneral;
       
   498 			
       
   499 			if(iIoBuffer->UserToKernel(iIoBuffer->iUserAddress,iIoBuffer->iSize+1)!=NULL)
       
   500 				return KErrGeneral;
       
   501 
       
   502 			if(iIoBuffer->KernelToUser(iIoBuffer->iAddress)!=iIoBuffer->iUserAddress)
       
   503 				return KErrGeneral;
       
   504 			kumemput32(a1,&iIoBuffer->iUserAddress,sizeof(TAny*));
       
   505 			kumemput32(a2,&iIoBuffer->iSize,sizeof(TInt));
       
   506 			return r;
       
   507 			}
       
   508 
       
   509 		case RTestLdd::EMapOutBuffer:
       
   510 			{
       
   511 			r=iIoBuffer->UserUnmap();
       
   512 			if(r==KErrNone)
       
   513 				if(iIoBuffer->iUserProcess)
       
   514 					r = KErrGeneral;
       
   515 			return r;
       
   516 			}
       
   517 
       
   518 		case RTestLdd::EDestroyBuffer:
       
   519 			NKern::ThreadEnterCS();
       
   520 			delete iIoBuffer;
       
   521 			iIoBuffer = NULL;
       
   522 			NKern::ThreadLeaveCS();
       
   523 			return KErrNone;
       
   524 
       
   525 		case RTestLdd::ECheckBuffer:
       
   526 			if(!iIoBuffer->iAddress || !iIoBuffer->iUserAddress || !iIoBuffer->iUserProcess)
       
   527 				return KErrGeneral;
       
   528 			return checkBuffer((TAny*)iIoBuffer->iAddress,iIoBuffer->iSize,(TUint32)a1);
       
   529 			
       
   530 		case RTestLdd::EFillBuffer:
       
   531 			if(!iIoBuffer->iAddress || !iIoBuffer->iUserAddress || !iIoBuffer->iUserProcess)
       
   532 				return KErrGeneral;
       
   533 			return fillBuffer((TAny*)iIoBuffer->iAddress,iIoBuffer->iSize,(TUint32)a1);
       
   534 
       
   535 		case RTestLdd::EThreadRW:
       
   536 			{
       
   537 			TInt dummy;
       
   538 			TPckg<TInt> a(dummy);
       
   539 			DThread* pT;
       
   540 			if((TInt)a2==-1)
       
   541 				{
       
   542 				pT=&Kern::CurrentThread();
       
   543 				}
       
   544 			else
       
   545 				{
       
   546 				NKern::ThreadEnterCS();
       
   547 				DObjectCon* pC=Kern::Containers()[EThread];
       
   548 				pC->Wait();
       
   549 				pT=Kern::ThreadFromId((TInt)a2);
       
   550 				pC->Signal();
       
   551 				if(!pT)
       
   552 					return KErrNotFound;
       
   553 				NKern::ThreadLeaveCS();
       
   554 				}
       
   555 			r=Kern::ThreadDesRead(pT,a1,a,0,KChunkShiftBy0);
       
   556 			if(r!=KErrNone)
       
   557 				return r;
       
   558 			if(dummy!=KMagic1)
       
   559 				return KErrCorrupt;
       
   560 			dummy=KMagic2;
       
   561 			r=Kern::ThreadDesWrite(pT,a1,a,0,KChunkShiftBy0,&Kern::CurrentThread());
       
   562 			if(r!=KErrNone)
       
   563 				return r;
       
   564 			return KErrNone;
       
   565 			}
       
   566 
       
   567 		default:
       
   568 			r=KErrNotSupported;
       
   569 			break;
       
   570 		}
       
   571 	return r;
       
   572 	}
       
   573