kerneltest/e32test/examples/convert1/convert1_ldd.cpp
changeset 9 96e5fb8b040d
equal deleted inserted replaced
-1:000000000000 9:96e5fb8b040d
       
     1 // Copyright (c) 2005-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 // its implementation.
       
    15 // 
       
    16 //
       
    17 
       
    18 /**
       
    19  @file An example data converter device driver which uses Shared Chunks in
       
    20  @publishedPartner
       
    21  @prototype 9.1
       
    22 */
       
    23 
       
    24 #include <kernel/kern_priv.h>
       
    25 #include <kernel/cache.h>
       
    26 #include "convert1.h"
       
    27 #include "convert1_dev.h"
       
    28 
       
    29 
       
    30 #if 0  // Set true for tracing
       
    31 #define TRACE(x) x
       
    32 #else
       
    33 #define TRACE(x)
       
    34 #endif
       
    35 
       
    36 
       
    37 _LIT(KConvert1PanicCategory,"CONVERT1");
       
    38 
       
    39 
       
    40 //
       
    41 // DConvert1Factory
       
    42 //
       
    43 
       
    44 /**
       
    45   Number of hardware 'resources' available to driver.
       
    46   E.g. the number of simultaneous channels it can support.
       
    47 */
       
    48 const TInt KTotalConvert1Resources = 4;
       
    49 
       
    50 /**
       
    51   A resource ID representing no resources
       
    52 */
       
    53 const TInt KNullConvert1ResourceId = -1;
       
    54 
       
    55 /**
       
    56   Standard export function for LDDs. This creates a DLogicalDevice derived object,
       
    57   in this case, our DConvert1Factory
       
    58 */
       
    59 DECLARE_STANDARD_LDD()
       
    60 	{
       
    61 	return new DConvert1Factory;
       
    62 	}
       
    63 
       
    64 /**
       
    65   Constructor
       
    66 */
       
    67 DConvert1Factory::DConvert1Factory()
       
    68 	{
       
    69 	// Set version number for this device
       
    70 	iVersion=RConvert1::VersionRequired();
       
    71 	// Indicate that do support units or a PDD
       
    72 	iParseMask=0;
       
    73 	// Mark all resources available
       
    74 	iResourceFlags = (1<<KTotalConvert1Resources)-1;
       
    75 	}
       
    76 
       
    77 /**
       
    78   Second stage constructor for DConvert1Factory.
       
    79   This must at least set a name for the driver object.
       
    80 
       
    81   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    82 */
       
    83 TInt DConvert1Factory::Install()
       
    84 	{
       
    85 	return SetName(&RConvert1::Name());
       
    86 	}
       
    87 
       
    88 /**
       
    89   Destructor
       
    90 */
       
    91 DConvert1Factory::~DConvert1Factory()
       
    92 	{
       
    93 	}
       
    94 
       
    95 /**
       
    96   Return the drivers capabilities.
       
    97   Called in the response to an RDevice::GetCaps() request.
       
    98 
       
    99   @param aDes User-side descriptor to write capabilities information into
       
   100 */
       
   101 void DConvert1Factory::GetCaps(TDes8& aDes) const
       
   102 	{
       
   103 	// Create a capabilities object
       
   104 	RConvert1::TCaps caps;
       
   105 	caps.iVersion = iVersion;
       
   106 	caps.iMaxChannels = KTotalConvert1Resources;
       
   107 
       
   108 	// Write it back to user memory
       
   109 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
       
   110 	}
       
   111 
       
   112 /**
       
   113   Called by the kernel's device driver framework to create a Logical Channel.
       
   114   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
   115   (E.g. through a call to RBusLogicalChannel::DoCreate)
       
   116   The thread is in a critical section.
       
   117 
       
   118   @param aChannel Set to point to the created Logical Channel
       
   119 
       
   120   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   121 */
       
   122 TInt DConvert1Factory::Create(DLogicalChannelBase*& aChannel)
       
   123 	{
       
   124 	aChannel=new DConvert1Channel(this);
       
   125 	if(!aChannel)
       
   126 		return KErrNoMemory;
       
   127 
       
   128 	return KErrNone;
       
   129 	}
       
   130 
       
   131 /**
       
   132   Claim a hardware resource. This example driver has KTotalConvert1Resources
       
   133   'hardware resources' and returns the ID of the next unallocated one.
       
   134 */
       
   135 TInt DConvert1Factory::ClaimResource(TInt& aResourceId)
       
   136 	{
       
   137 	// Wait on mutex protecting resource allocation
       
   138 	NKern::FMWait(&iResourceMutex);
       
   139 
       
   140 	// Search for a free resource
       
   141 	TUint resourceFlags = iResourceFlags;
       
   142 	TUint mask = 1;
       
   143 	TInt id = 0;
       
   144 	do
       
   145 		{
       
   146 		if(resourceFlags&mask)
       
   147 			break;
       
   148 		mask <<= 1;
       
   149 		}
       
   150 	while(++id<KTotalConvert1Resources);
       
   151 
       
   152 	if(resourceFlags&mask)
       
   153 		iResourceFlags = resourceFlags&~mask; // Found resource, so mark it in use
       
   154 	else
       
   155 		id = KNullConvert1ResourceId; // No resource available
       
   156 
       
   157 	// Set returned resource id
       
   158 	aResourceId = id;
       
   159 
       
   160 	// Release mutex protecting resource allocation
       
   161 	NKern::FMSignal(&iResourceMutex);
       
   162 
       
   163 	return id<0 ? KErrInUse : KErrNone;
       
   164 	}
       
   165 
       
   166 /**
       
   167   Released the hardware resource indicated by the given id
       
   168 */
       
   169 void DConvert1Factory::ReleaseResource(TInt aResourceId)
       
   170 	{
       
   171 	// Do nothing if the null id was given
       
   172 	if(aResourceId==KNullConvert1ResourceId)
       
   173 		return;
       
   174 
       
   175 	// Wait on mutex protecting resource allocation
       
   176 	NKern::FMWait(&iResourceMutex);
       
   177 
       
   178 	// Check for valid resource and that it is not already free
       
   179 	__NK_ASSERT_DEBUG(TUint(aResourceId)<TUint(KTotalConvert1Resources));
       
   180 	__NK_ASSERT_DEBUG((iResourceFlags&(1<<aResourceId))==0);
       
   181 
       
   182 	// Flag resource free again
       
   183 	iResourceFlags |= 1<<aResourceId;
       
   184 
       
   185 	// Release mutex protecting resource allocation
       
   186 	NKern::FMSignal(&iResourceMutex);
       
   187 	}
       
   188 
       
   189 //
       
   190 // Logical Channel
       
   191 //
       
   192 
       
   193 /**
       
   194   Default configuration (4k buffer, No Input Chunk, 1MB/sec speed)
       
   195 */
       
   196 static const RConvert1::TConfig DefaultConfig = {4<<10,EFalse,1<<20};
       
   197 
       
   198 /**
       
   199   Constructor
       
   200 */
       
   201 DConvert1Channel::DConvert1Channel(DConvert1Factory* aFactory)
       
   202 	:	iFactory(aFactory), 
       
   203 		iResourceId(KNullConvert1ResourceId),
       
   204 		iConfig(DefaultConfig),
       
   205 		iConvertTimer(ConvertDfcTrampoline,this)
       
   206 	{
       
   207 	}
       
   208 
       
   209 /**
       
   210   Second stage constructor called by the kernel's device driver framework.
       
   211   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
   212   (E.g. through a call to RBusLogicalChannel::DoCreate)
       
   213   The thread is in a critical section.
       
   214 
       
   215   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
       
   216   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
       
   217   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
       
   218 
       
   219   @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   220 */
       
   221 TInt DConvert1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
       
   222 	{
       
   223 	// Check client has EMultimediaDD capability
       
   224 	if(!Kern::CurrentThreadHasCapability(ECapabilityMultimediaDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by CAPTURE1")))
       
   225 		return KErrPermissionDenied;
       
   226 
       
   227 	// Check version
       
   228 	if (!Kern::QueryVersionSupported(RConvert1::VersionRequired(),aVer))
       
   229 		return KErrNotSupported;
       
   230 
       
   231 	// Claim ownership of a hardware resource
       
   232 	TInt r=iFactory->ClaimResource(iResourceId);
       
   233 	if(r!=KErrNone)
       
   234 		return r;
       
   235 
       
   236 	// Set client thread with which channel will be used by
       
   237 	iClient = &Kern::CurrentThread();
       
   238 
       
   239 	// Done
       
   240 	return KErrNone;
       
   241 	}
       
   242 
       
   243 /**
       
   244   Destructor
       
   245 */
       
   246 DConvert1Channel::~DConvert1Channel()
       
   247 	{
       
   248 	// Cancel outsatnding requests
       
   249 	DoCancel(RConvert1::EAllRequests);
       
   250 
       
   251 	// Release hardware resource which we own
       
   252 	iFactory->ReleaseResource(iResourceId);
       
   253 	}
       
   254 
       
   255 /**
       
   256   Called when a user thread requests a handle to this channel.
       
   257 */
       
   258 TInt DConvert1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType)
       
   259 	{
       
   260 	// Make sure that only our client can get a handle
       
   261 	if (aType!=EOwnerThread || aThread!=iClient)
       
   262 		return KErrAccessDenied;
       
   263 	return KErrNone;
       
   264 	}
       
   265 
       
   266 /**
       
   267   Process a request on this logical channel.
       
   268 
       
   269   @param aReqNo Request number:
       
   270   	            ==KMaxTInt, a 'DoCancel' message
       
   271 	            >=0, a 'DoControl' message with function number equal to iValue
       
   272 	            <0, a 'DoRequest' message with function number equal to ~iValue
       
   273   @param a1     First argument. For DoRequest requests this is a pointer to the TRequestStatus.
       
   274   @param a2     Second argument. For DoRequest this is a pointer to the 2 actual TAny* arguments.
       
   275 
       
   276   @return       Result. Ignored by device driver framework for DoRequest requests.
       
   277 */
       
   278 TInt DConvert1Channel::Request(TInt aReqNo, TAny* a1, TAny* a2)
       
   279 	{
       
   280 	// Decode the message type and dispatch it to the relevent handler function...
       
   281 	if ((TUint)aReqNo<(TUint)KMaxTInt)
       
   282 		return DoControl(aReqNo,a1,a2);
       
   283 	if(aReqNo==KMaxTInt)
       
   284 		return DoCancel((TInt)a1);
       
   285 	return DoRequest(aReqNo,a1,a2);
       
   286 	}
       
   287 
       
   288 /**
       
   289   Process synchronous 'control' requests
       
   290 */
       
   291 TInt DConvert1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
       
   292 	{
       
   293 	TRACE(Kern::Printf(">DConvert1Channel::DoControl fn=%d\n",aFunction);)
       
   294 
       
   295 	TInt r = KErrNotSupported;
       
   296 	switch (aFunction)
       
   297 		{
       
   298 		case RConvert1::EGetConfig:
       
   299 			r = GetConfig((TDes8*)a1);
       
   300 			break;
       
   301 
       
   302 		case RConvert1::ESetConfig:
       
   303 			r = SetConfig((const TDesC8*)a1,(RConvert1::TBufferInfo*)a2);
       
   304 			break;
       
   305 
       
   306 		case RConvert1::EConvertDes:
       
   307 			ConvertDes((const TDesC8*)a1,(TRequestStatus*)a2);
       
   308 			break;
       
   309 
       
   310 		case RConvert1::EConvertChunk:
       
   311 			ConvertChunk((const RConvert1::TConvertArgs*)a1,(TRequestStatus*)a2);
       
   312 			break;
       
   313 
       
   314 		case RConvert1::EConvertInChunk:
       
   315 			ConvertInChunk((TInt)a1,(TRequestStatus*)a2);
       
   316 			break;
       
   317 		}
       
   318 
       
   319 	TRACE(Kern::Printf("<DConvert1Channel::DoControl result=%d\n",r);)
       
   320 
       
   321 	return r;
       
   322 	}
       
   323 
       
   324 /**
       
   325   Process asynchronous requests.
       
   326   This driver doesn't have any 'DoRequest' requests because we handle asyncronous
       
   327   requests using 'DoControl' for performance reasons. I.e. to avoid having to read
       
   328   the arguments with kumemget()
       
   329 */
       
   330 TInt DConvert1Channel::DoRequest(TInt aNotReqNo, TAny* a1, TAny* a2)
       
   331 	{
       
   332 	TRACE(Kern::Printf(">DConvert1Channel::DoRequest req=%d\n",aNotReqNo);)
       
   333 
       
   334 	// Get arguments
       
   335 	TAny* a[2];
       
   336 	kumemget32(a,a2,sizeof(a)); 
       
   337 	TRequestStatus* status=(TRequestStatus*)a1;
       
   338 	TInt reqNo = ~aNotReqNo;
       
   339 
       
   340 	// Do the request
       
   341 	TInt r;
       
   342 	switch(reqNo)
       
   343 		{
       
   344 		case RConvert1::EConvertDes:
       
   345 		case RConvert1::EConvertChunk:
       
   346 		case RConvert1::EConvertInChunk:
       
   347 			// Not used because we do these asyncronous request as a
       
   348 			// DoControl rather than a DoRequest for performance reasons.
       
   349 
       
   350 		default:
       
   351 			r = KErrNotSupported;
       
   352 			break;
       
   353 		}
       
   354 
       
   355 	// Complete request if there was an error
       
   356 	if (r!=KErrNone)
       
   357 		Kern::RequestComplete(&Kern::CurrentThread(),status,r);
       
   358 
       
   359 	TRACE(Kern::Printf("<DConvert1Channel::DoRequest result=%d\n",r);)
       
   360 
       
   361 	return KErrNone;  // Result is ignored by device driver framework for DoRequest requests
       
   362 	}
       
   363 
       
   364 /**
       
   365   Process cancelling of asynchronous requests.
       
   366 */
       
   367 TInt DConvert1Channel::DoCancel(TUint aMask)
       
   368 	{
       
   369 	TRACE(Kern::Printf(">DConvert1Channel::DoCancel mask=%08x\n",aMask);)
       
   370 
       
   371 	if(aMask&( (1<<RConvert1::EConvertDes) | (1<<RConvert1::EConvertChunk) | (1<<RConvert1::EConvertInChunk) ) )
       
   372 		ConvertCancel();
       
   373 
       
   374 	TRACE(Kern::Printf("<DConvert1Channel::DoCancel\n");)
       
   375 
       
   376 	return KErrNone;
       
   377 	}
       
   378 
       
   379 //
       
   380 // Methods for processing configuration control messages
       
   381 //
       
   382 
       
   383 /**
       
   384   Process a GetConfig control message. This writes the current driver configuration to a
       
   385   RConvert1::TConfigBuf supplied by the client.
       
   386 */
       
   387 TInt DConvert1Channel::GetConfig(TDes8* aConfigBuf)
       
   388 	{
       
   389 	// Write the config to the client
       
   390 	Kern::InfoCopy(*aConfigBuf,(const TUint8*)&iConfig,sizeof(iConfig));
       
   391 	return KErrNone;
       
   392 	}
       
   393 
       
   394 /**
       
   395   Process a SetConfig control message. This sets the driver configuration using a
       
   396   RConvert1::TConfigBuf supplied by the client.
       
   397 */
       
   398 TInt DConvert1Channel::SetConfig(const TDesC8* aConfigBuf,RConvert1::TBufferInfo* aBufferInfo)
       
   399 	{
       
   400 	// Create a config structure.
       
   401 	RConvert1::TConfig config(DefaultConfig);
       
   402 
       
   403 	// Note: We have constructed a config using DefaultConfig, this is to allow
       
   404 	// backwards compatibility when a client gives us an old (and shorter) version
       
   405 	// of the config structure.
       
   406 
       
   407 	// Read the config structure from client
       
   408 	TPtr8 ptr((TUint8*)&config,sizeof(config));
       
   409 	Kern::KUDesGet(ptr,*aConfigBuf);
       
   410 
       
   411 	// 'info' is the data we will return to client at the end
       
   412 	RConvert1::TBufferInfo info;
       
   413 	memclr(&info,sizeof(info));
       
   414 
       
   415 	TInt r;
       
   416 
       
   417 	// Need to be in critical section whilst allocating objects
       
   418 	NKern::ThreadEnterCS();
       
   419 
       
   420 	// Check we aren't in the middle of converting data
       
   421 	if(iConvertRequestStatus)
       
   422 		{
       
   423 		r = KErrInUse;
       
   424 		goto done;
       
   425 		}
       
   426 
       
   427 	// Note: The above check is enough to ensure we have exclusive access
       
   428 	// to this channels buffer and hardware resources because:
       
   429 	// 1. The covert DFC can't run because we haven't started converting yet.
       
   430 	// 2. No other request can come in because the channel only allows one
       
   431 	//    client thread to use it. See DConvert1Channel::Request()
       
   432 	// 3. The channel destructor can't be called whilst we are processing a request.
       
   433 
       
   434 
       
   435 	// For some settings we allow zero to mean default...
       
   436 	if(!config.iBufferSize)
       
   437 		config.iBufferSize = DefaultConfig.iBufferSize;
       
   438 	if(!config.iSpeed)
       
   439 		config.iSpeed = DefaultConfig.iSpeed;
       
   440 
       
   441 	// Validate configuration
       
   442 	if(config.iBufferSize<=0)
       
   443 		{
       
   444 		r = KErrArgument;
       
   445 		goto done;
       
   446 		}
       
   447 	if(config.iSpeed<=0)
       
   448 		{
       
   449 		r = KErrArgument;
       
   450 		goto done;
       
   451 		}
       
   452 
       
   453 	// Change the config
       
   454 	iConfig = config; 
       
   455 
       
   456 	{
       
   457 
       
   458 	// Calculate buffer size
       
   459 	TInt bufferSize = Kern::RoundToPageSize(config.iBufferSize);
       
   460 
       
   461 	// Destroy old buffers
       
   462 	iClientBuffer.Destroy();
       
   463 	iInBuffer.Destroy();
       
   464 	iOutBuffer.Destroy();
       
   465 
       
   466 	// Setup iClientBuffer
       
   467 	r = iClientBuffer.SetMaxSize(bufferSize);
       
   468 	if(r!=KErrNone)
       
   469 		goto done;
       
   470 
       
   471 	// Create output buffer
       
   472 	r = iOutBuffer.Create(bufferSize);
       
   473 	if(r!=KErrNone)
       
   474 		goto done;
       
   475 	// Make handle for output buffer
       
   476 	r = Kern::MakeHandleAndOpen(NULL, iOutBuffer.iChunk);
       
   477 	if(r<0) // -ve value is error, +ve value is a handle
       
   478 		goto done;
       
   479 	info.iOutChunkHandle = r;
       
   480 	r = KErrNone;
       
   481 
       
   482 	// Create input buffer if requested
       
   483 	if(iConfig.iCreateInputChunk)
       
   484 		{
       
   485 		r = iInBuffer.Create(bufferSize);
       
   486 		if(r!=KErrNone)
       
   487 			goto done;
       
   488 		// Make handle for input buffer
       
   489 		r = Kern::MakeHandleAndOpen(NULL, iInBuffer.iChunk);
       
   490 		if(r<0) // -ve value is error, +ve value is a handle
       
   491 			goto done;
       
   492 		info.iInChunkHandle = r;
       
   493 		r = KErrNone;
       
   494 		// Set info about input buffer
       
   495 		//
       
   496 		// Note we don't set iInBufferPtr because this is the address in
       
   497 		// client process which it must set for itself
       
   498 		info.iInBufferOffset = iInBuffer.iChunkOffset;
       
   499 		info.iInBufferSize = iInBuffer.iMaxSize;
       
   500 		}
       
   501 	}
       
   502 done:
       
   503 	// Cleanup if there was an error
       
   504 	if(r!=KErrNone)
       
   505 		{
       
   506 		iClientBuffer.Destroy();
       
   507 		iInBuffer.Destroy();
       
   508 		iOutBuffer.Destroy();
       
   509 		if(info.iOutChunkHandle)
       
   510 			Kern::CloseHandle(NULL,info.iOutChunkHandle);
       
   511 		if(info.iInChunkHandle)
       
   512 			Kern::CloseHandle(NULL,info.iInChunkHandle);
       
   513 		memclr(&info,sizeof(info));
       
   514 		}
       
   515 
       
   516 	NKern::ThreadLeaveCS();
       
   517 
       
   518 	// Write chunk handles and other info back to client memory
       
   519 	kumemput32(aBufferInfo,&info,sizeof(info));
       
   520 
       
   521 	return r;
       
   522 	}
       
   523 
       
   524 //
       
   525 // Methods for processing Convert requests
       
   526 //
       
   527 
       
   528 /**
       
   529   Process Convert request where the source data is specified by a descriptor
       
   530 */
       
   531 void DConvert1Channel::ConvertDes(const TDesC8* aSrc,TRequestStatus* aRequestStatus)
       
   532 	{
       
   533 	TInt r;
       
   534 
       
   535 	// Get descriptor info
       
   536 	TInt len;
       
   537 	TInt maxLen;
       
   538 	TAny* uptr = (TAny*)Kern::KUDesInfo(*aSrc,len,maxLen);
       
   539 
       
   540 	// Check there isn't an outstanding request
       
   541 	if(iConvertRequestStatus)
       
   542 		Kern::ThreadKill(NULL,EExitPanic,ERequestAlreadyPending,KConvert1PanicCategory);
       
   543 
       
   544 	// Check output buffer has been created
       
   545 	if(!iOutBuffer.iChunk)
       
   546 		{
       
   547 		r = KErrNotReady;
       
   548 		goto done;
       
   549 		}
       
   550 
       
   551 	// Check chunk has been created (TConfig::iCreateInputChunk True when SetConfig was called)
       
   552 	if(!iInBuffer.iChunk)
       
   553 		{
       
   554 		r = KErrNotSupported;
       
   555 		goto done;
       
   556 		}
       
   557 
       
   558 	// See if client data is in a shared chunk
       
   559 	r = iClientBuffer.Open(uptr,len);
       
   560 	if(r==KErrNone)
       
   561 		iSource = &iClientBuffer; // use iClientBuffer as input buffer
       
   562 	else
       
   563 		{
       
   564 		// Copy data from client descriptor into our iInBuffer
       
   565 		r = iInBuffer.Copy(uptr,len);
       
   566 		if(r==KErrNone)
       
   567 			iSource = &iInBuffer; // use iInBuffer as input buffer
       
   568 		}
       
   569 
       
   570 	// Start convert if no error
       
   571 	if(r==KErrNone)
       
   572 		{
       
   573 		iConvertRequestStatus = aRequestStatus;
       
   574 		DoConvertStart(0,len);
       
   575 		}
       
   576 done:
       
   577 	// Complete request if there was an error
       
   578 	if (r!=KErrNone)
       
   579 		Kern::RequestComplete(&Kern::CurrentThread(),aRequestStatus,r);
       
   580 	}
       
   581 
       
   582 /**
       
   583   Process Convert request where the source data is specified by a chunk
       
   584 */
       
   585 void DConvert1Channel::ConvertChunk(const RConvert1::TConvertArgs* aSrcArgs,TRequestStatus* aRequestStatus)
       
   586 	{
       
   587 	TInt r;
       
   588 
       
   589 	// Check there isn't an outstanding request
       
   590 	if(iConvertRequestStatus)
       
   591 		Kern::ThreadKill(NULL,EExitPanic,ERequestAlreadyPending,KConvert1PanicCategory);
       
   592 
       
   593 	// Check output buffer has been created
       
   594 	if(!iOutBuffer.iChunk)
       
   595 		{
       
   596 		r = KErrNotReady;
       
   597 		goto done;
       
   598 		}
       
   599 
       
   600 	// Unpackage arguments
       
   601 	RConvert1::TConvertArgs args;
       
   602 	kumemget32(&args,aSrcArgs,sizeof(args));
       
   603 
       
   604 	// Make buffer by opening chunk
       
   605 	r=iClientBuffer.Open(args.iChunkHandle,args.iOffset,args.iSize);
       
   606 
       
   607 	// Start convert if no error
       
   608 	if(r==KErrNone)
       
   609 		{
       
   610 		iSource = &iClientBuffer;
       
   611 		iConvertRequestStatus = aRequestStatus;
       
   612 		DoConvertStart(0,args.iSize);
       
   613 		}
       
   614 done:
       
   615 	// Complete request if there was an error
       
   616 	if (r!=KErrNone)
       
   617 		Kern::RequestComplete(&Kern::CurrentThread(),aRequestStatus,r);
       
   618 	}
       
   619 
       
   620 /**
       
   621   Process Convert request where the source data is contained in the input chunk
       
   622 */
       
   623 void DConvert1Channel::ConvertInChunk(TInt aSize,TRequestStatus* aRequestStatus)
       
   624 	{
       
   625 	TInt r;
       
   626 
       
   627 	// Check there isn't an outstanding request
       
   628 	if(iConvertRequestStatus)
       
   629 		Kern::ThreadKill(NULL,EExitPanic,ERequestAlreadyPending,KConvert1PanicCategory);
       
   630 
       
   631 	// Check output buffer has been created
       
   632 	if(!iOutBuffer.iChunk)
       
   633 		{
       
   634 		r = KErrNotReady;
       
   635 		goto done;
       
   636 		}
       
   637 
       
   638 	// Check chunk has been created (TConfig::iCreateInputChunk True when SetConfig was called)
       
   639 	if(!iInBuffer.iChunk)
       
   640 		{
       
   641 		r = KErrNotSupported;
       
   642 		goto done;
       
   643 		}
       
   644 
       
   645 	// Check size of data really fits within chunk
       
   646 	if(TUint(aSize)>=TUint(iInBuffer.iMaxSize))
       
   647 		{
       
   648 		r = KErrArgument;
       
   649 		goto done;
       
   650 		}
       
   651 
       
   652 	// Start the convert 
       
   653 	iSource = &iInBuffer;
       
   654 	iConvertRequestStatus = aRequestStatus;
       
   655 	DoConvertStart(iInBuffer.iChunkOffset,aSize);
       
   656 	r = KErrNone;
       
   657 
       
   658 done:
       
   659 	// Complete request if there was an error
       
   660 	if (r!=KErrNone)
       
   661 		Kern::RequestComplete(&Kern::CurrentThread(),aRequestStatus,r);
       
   662 	}
       
   663 
       
   664 /**
       
   665   Signal ConvertData request completed
       
   666 */
       
   667 void DConvert1Channel::ConvertCancel()
       
   668 	{
       
   669 	// Tell hardware to stop
       
   670 	DoConvertCancel();
       
   671 
       
   672 	// Complete client request
       
   673 	NKern::ThreadEnterCS();
       
   674 	ConvertComplete(KErrCancel);
       
   675 	NKern::ThreadLeaveCS();
       
   676 	}
       
   677 
       
   678 /**
       
   679   DFC callback called after data has been converted.
       
   680 */
       
   681 void DConvert1Channel::ConvertDfcTrampoline(TAny* aSelf)
       
   682 	{
       
   683 	// Just call non-static method
       
   684 	((DConvert1Channel*)aSelf)->ConvertDfc();
       
   685 	}
       
   686 
       
   687 /**
       
   688   DFC callback called after data has been converted
       
   689 */
       
   690 void DConvert1Channel::ConvertDfc()
       
   691 	{
       
   692 	TRACE(Kern::Printf(">DConvert1Channel::ConvertDfc\n");)
       
   693 
       
   694 	// The result value will be the chunk offset of the data we've converted
       
   695 	TInt result = iOutBuffer.iChunkOffset;
       
   696 	ConvertComplete(result);
       
   697 
       
   698 	TRACE(Kern::Printf("<DConvert1Channel::ConvertDfc\n");)
       
   699 	}
       
   700 
       
   701 /**
       
   702   Complete a Convert request
       
   703   @pre In thread critical section or DFC thread
       
   704 */
       
   705 void DConvert1Channel::ConvertComplete(TInt aResult)
       
   706 	{
       
   707 	// Hold mutex to avoid concurrency
       
   708 	NKern::FMWait(&iConvertMutex);
       
   709 
       
   710 	// Claim the client request
       
   711 	TRequestStatus* status = iConvertRequestStatus;
       
   712 	iConvertRequestStatus = NULL;
       
   713 
       
   714 	// Claim chunk handle if we need to close it
       
   715 	DChunk* chunk = NULL;
       
   716 	if(status && iSource==&iClientBuffer)
       
   717 		{
       
   718 		chunk = iClientBuffer.iChunk;
       
   719 		iClientBuffer.iChunk = NULL;
       
   720 		}
       
   721 
       
   722 	// Clear iSource to help show up bugs
       
   723 	iSource = NULL;
       
   724 
       
   725 	// Can release mutex now we own the pointers
       
   726 	NKern::FMSignal(&iConvertMutex);
       
   727 
       
   728 	// Must be in a critical section so we can't die whilst owning 'chunk' and 'status'
       
   729 	__ASSERT_CRITICAL;
       
   730 
       
   731 	// Close chunk if required
       
   732 	if(chunk)
       
   733 		Kern::ChunkClose(chunk);
       
   734 
       
   735 	// Complete the request
       
   736 	if(status)
       
   737 		Kern::RequestComplete(iClient,status,aResult);
       
   738 	}
       
   739 
       
   740 
       
   741 //
       
   742 // DChunkBuffer
       
   743 //
       
   744 
       
   745 /**
       
   746   Constructor
       
   747 */
       
   748 DChunkBuffer::DChunkBuffer()
       
   749 	: iChunk(NULL), iPhysicalPages(NULL)
       
   750 	{
       
   751 	}
       
   752 
       
   753 /**
       
   754   Create chunk and commit memory for buffer
       
   755 */
       
   756 TInt DChunkBuffer::Create(TInt aBufferSize)
       
   757 	{
       
   758 	// Initialise member data for the size of buffer we want
       
   759 	TInt r=SetMaxSize(aBufferSize);
       
   760 	if(r!=KErrNone)
       
   761 		return r;
       
   762 
       
   763 	// Create chunk
       
   764 	__NK_ASSERT_DEBUG(!iChunk);
       
   765 	TChunkCreateInfo info;
       
   766 	info.iType = TChunkCreateInfo::ESharedKernelMultiple;
       
   767 	info.iMaxSize = (TInt)aBufferSize;
       
   768 #ifndef __WINS__
       
   769 	info.iMapAttr = EMapAttrCachedMax;
       
   770 #else
       
   771 	info.iMapAttr = 0;
       
   772 #endif
       
   773 	info.iOwnsMemory = ETrue;
       
   774 	r = Kern::ChunkCreate(info,iChunk,iChunkBase,iChunkMapAttr);
       
   775 
       
   776 	if(r==KErrNone)
       
   777 		{
       
   778 		// Commit memory to chunk
       
   779 		iChunkOffset = 0;
       
   780 		r = Kern::ChunkCommit(iChunk,iChunkOffset,Kern::RoundToPageSize(iMaxSize));
       
   781 		if(r==KErrNone)
       
   782 			{
       
   783 			// Setup physical address info for memory in the buffer
       
   784 			r = SetPhysicalAddresses(iMaxSize);
       
   785 			}
       
   786 		}
       
   787 
       
   788 	if(r!=KErrNone)
       
   789 		Destroy(); // Cleanup
       
   790 
       
   791 	return r;
       
   792 	}
       
   793 
       
   794 /**
       
   795   Free all resources
       
   796 */
       
   797 void DChunkBuffer::Destroy()
       
   798 	{
       
   799 	delete [] iPhysicalPages;
       
   800 	iPhysicalPages = 0;
       
   801 	Close();
       
   802 	}
       
   803 
       
   804 /**
       
   805   Destructor
       
   806 */
       
   807 DChunkBuffer::~DChunkBuffer()
       
   808 	{
       
   809 	Destroy();
       
   810 	}
       
   811 
       
   812 /**
       
   813   Set maximum size for buffer.
       
   814   (Allocates heap resources for this max size.)
       
   815 */
       
   816 TInt DChunkBuffer::SetMaxSize(TInt aMaxSize)
       
   817 	{
       
   818 	// Create array to hold address of physical pages
       
   819 	__NK_ASSERT_DEBUG(!iPhysicalPages);
       
   820 	iPhysicalPages = new TPhysAddr[Kern::RoundToPageSize(aMaxSize)/Kern::RoundToPageSize(1)+1];
       
   821 	if(!iPhysicalPages)
       
   822 		return KErrNoMemory;
       
   823 
       
   824 	iMaxSize = aMaxSize;
       
   825 	return KErrNone;
       
   826 	}
       
   827 
       
   828 /**
       
   829   Open a shared chunk given an user address and siae
       
   830 */
       
   831 TInt DChunkBuffer::Open(TAny* aAddress, TInt aSize, TBool aWrite)
       
   832 	{
       
   833 	TInt r;
       
   834 
       
   835 	// Check size
       
   836 	if(aSize>iMaxSize)
       
   837 		return KErrTooBig;
       
   838 
       
   839 	NKern::ThreadEnterCS();
       
   840 
       
   841 	// Attempt to open chunk
       
   842 	iChunk = Kern::OpenSharedChunk(NULL,aAddress,aWrite,iChunkOffset);
       
   843 	if(!iChunk)
       
   844 		r = KErrArgument;
       
   845 	else
       
   846 		{
       
   847 		// Get physical addresses
       
   848 		r = SetPhysicalAddresses(aSize);
       
   849 		if(r!=KErrNone)
       
   850 			Close();
       
   851 		}
       
   852 
       
   853 	NKern::ThreadLeaveCS();
       
   854 
       
   855 	return r;
       
   856 	}
       
   857 
       
   858 /**
       
   859   Open a specified shared chunk
       
   860 */
       
   861 TInt DChunkBuffer::Open(TInt aChunkHandle, TInt aOffset, TInt aSize, TBool aWrite)
       
   862 	{
       
   863 	TInt r;
       
   864 
       
   865 	// Check size
       
   866 	if(aSize>iMaxSize)
       
   867 		return KErrTooBig;
       
   868 	iChunkOffset = aOffset;
       
   869 
       
   870 	NKern::ThreadEnterCS();
       
   871 
       
   872 	// Attempt to open chunk
       
   873 	iChunk = Kern::OpenSharedChunk(NULL,aChunkHandle,aWrite);
       
   874 	if(!iChunk)
       
   875 		r = KErrArgument;
       
   876 	else
       
   877 		{
       
   878 		// Get physical addresses
       
   879 		r = SetPhysicalAddresses(aSize);
       
   880 		if(r!=KErrNone)
       
   881 			Close();
       
   882 		}
       
   883 
       
   884 	NKern::ThreadLeaveCS();
       
   885 
       
   886 	return r;
       
   887 	}
       
   888 
       
   889 /**
       
   890   Close chunk
       
   891 */
       
   892 void DChunkBuffer::Close()
       
   893 	{
       
   894 	__ASSERT_CRITICAL;
       
   895 	if(iChunk)
       
   896 		{
       
   897 		Kern::ChunkClose(iChunk);
       
   898 		iChunk = NULL;
       
   899 		}
       
   900 	}
       
   901 
       
   902 /**
       
   903   Fill buffer by copying data from the given user address
       
   904 */
       
   905 TInt DChunkBuffer::Copy(TAny* aAddress, TInt aSize)
       
   906 	{
       
   907 	// Check size
       
   908 	if(aSize>iMaxSize)
       
   909 		return KErrTooBig;
       
   910 
       
   911 	// Copy data
       
   912 	kumemget((TAny*)(iChunkBase+iChunkOffset),aAddress,aSize);
       
   913 
       
   914 	return KErrNone;
       
   915 	}
       
   916 
       
   917 /**
       
   918   Setup physical address info for memory in the buffer
       
   919 */
       
   920 TInt DChunkBuffer::SetPhysicalAddresses(TInt aSize)
       
   921 	{
       
   922 	// Assert that the iPhysicalPages array already allocated will be big enough
       
   923 	__NK_ASSERT_DEBUG(aSize<=iMaxSize);
       
   924 
       
   925 	// Get physical addresses
       
   926 	TLinAddr kaddr;
       
   927 	TInt r=Kern::ChunkPhysicalAddress(iChunk,iChunkOffset,aSize,kaddr,iChunkMapAttr,iPhysicalAddress,iPhysicalPages);
       
   928 	// r = 0 or 1 on success. (1 meaning the physical pages are not contiguous)
       
   929 	if(r>=0) 
       
   930 		{
       
   931 		iChunkBase = kaddr-iChunkOffset; // Calculate start of chunk in kernel process address space
       
   932 		r = KErrNone;
       
   933 		}
       
   934 	return r;
       
   935 	}
       
   936 
       
   937 //
       
   938 // Program converter hardware
       
   939 //
       
   940 
       
   941 /**
       
   942   Initialise hardware to start converting data.
       
   943   Input data is in iSource.
       
   944   Output data to be placed in iOutBuffer.
       
   945 */
       
   946 void DConvert1Channel::DoConvertStart(TInt aOffset,TInt aSize)
       
   947 	{
       
   948 	// For this example test...
       
   949 	
       
   950 	TRACE(Kern::Printf("DConvert1Channel::DoConvertStart\n");)
       
   951 
       
   952 	// 'Convert' data by xoring with 1
       
   953 	TUint8* src = (TUint8*)iSource->iChunkBase+iSource->iChunkOffset+aOffset;
       
   954 	TUint8* end = src+aSize;
       
   955 	TUint8* dst = (TUint8*)iOutBuffer.iChunkBase+iOutBuffer.iChunkOffset;
       
   956 	while(src<end)
       
   957 		*dst++ = TUint8(*src++^1);
       
   958 
       
   959 	// Start the timer
       
   960 	TInt ticks = TInt((TInt64)1000000*(TInt64)aSize/(TInt64)iConfig.iSpeed)
       
   961 					/NKern::TickPeriod();
       
   962 	if(ticks<1)
       
   963 		ticks = 1;
       
   964 #ifdef _DEBUG
       
   965 	TInt r=
       
   966 #endif
       
   967 		iConvertTimer.OneShot(ticks,ETrue);
       
   968 	__NK_ASSERT_DEBUG(r==KErrNone);
       
   969 	}
       
   970 
       
   971 /**
       
   972   Tell hardware to stop converting.
       
   973 */
       
   974 void DConvert1Channel::DoConvertCancel()
       
   975 	{
       
   976 	// For this example test...
       
   977 	
       
   978 	TRACE(Kern::Printf("DConvert1Channel::DoConvertCancel\n");)
       
   979 
       
   980 	// Cancel the timer
       
   981 	iConvertTimer.Cancel();
       
   982 	}