kernel/eka/kernel/device.cpp
changeset 0 a41df078684a
child 43 c1f20ce4abcf
equal deleted inserted replaced
-1:000000000000 0:a41df078684a
       
     1 // Copyright (c) 1995-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 // e32\kernel\device.cpp
       
    15 // 
       
    16 //
       
    17 
       
    18 #include <kernel/kern_priv.h>
       
    19 #include <e32uid.h>
       
    20 #include "execs.h"
       
    21 
       
    22 _LIT(KDotStar,".*");
       
    23 
       
    24 /********************************************
       
    25  * Logical device base class
       
    26  ********************************************/
       
    27 
       
    28 
       
    29 /**	Base class destructor for DLogicalDevice
       
    30 
       
    31 	This arranges for the code segment to be unloaded when the system next goes
       
    32 	idle.
       
    33 
       
    34 	@pre Calling thread must be in a critical section.
       
    35 	@pre Interrupts must be enabled.
       
    36 	@pre Kernel must be unlocked.
       
    37 	@pre No fast mutex can be held.
       
    38 	@pre Call in a thread context.
       
    39  */
       
    40 EXPORT_C DLogicalDevice::~DLogicalDevice()
       
    41 	{
       
    42 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalDevice::~DLogicalDevice");	
       
    43 	if (iCodeSeg)
       
    44 		{
       
    45 		__DEBUG_EVENT(EEventUnloadLdd, iCodeSeg);
       
    46 		iCodeSeg->ScheduleKernelCleanup(EFalse);
       
    47 		}
       
    48 	}
       
    49 
       
    50 
       
    51 /**	Checks if a specific interface version is supported.
       
    52 
       
    53 	Default implementation.
       
    54 
       
    55 	All old versions are supported.
       
    56 
       
    57 	@param	aVer	The requested interface version
       
    58 	
       
    59 	@return	TRUE if supported, FALSE if not.
       
    60  */
       
    61 EXPORT_C TBool DLogicalDevice::QueryVersionSupported(const TVersion& aVer) const
       
    62 	{
       
    63 	return Kern::QueryVersionSupported(iVersion,aVer);
       
    64 	}
       
    65 
       
    66 
       
    67 /**	Checks if a specified unit number and additional info and a specific PDD is supported.
       
    68 
       
    69 	Default implementation.
       
    70 
       
    71 	@param	aUnit	The requested unit number
       
    72 	@param	aPdd	The requested PDD name
       
    73 	@param	aInfo	The additional information
       
    74 	
       
    75 	@return	TRUE if supported, FALSE if not.
       
    76  */
       
    77 EXPORT_C TBool DLogicalDevice::IsAvailable(TInt /*aUnit*/, const TDesC* /*aPdd*/, const TDesC8* /*aInfo*/) const
       
    78 	{
       
    79 	return ETrue;
       
    80 	}
       
    81 
       
    82 EXPORT_C TInt Kern::InstallLogicalDevice(DLogicalDevice* aDevice)
       
    83 //
       
    84 // Must be called in a critical section
       
    85 //
       
    86 	{
       
    87 	aDevice->SetProtection(DObject::EGlobal);
       
    88 	aDevice->iObjectFlags |= DObject::EObjectExtraReference;
       
    89 	TInt r=aDevice->Install();
       
    90 	if (r==KErrNone)
       
    91 		r=K::AddObject(aDevice,ELogicalDevice); // Mustn't access aDevice after a successful AddObject!
       
    92 	return r;
       
    93 	}
       
    94 
       
    95 TInt DoLogicalDeviceLoad(DCodeSeg* aSeg)
       
    96 	{
       
    97 	TLogicalDeviceNew f=(TLogicalDeviceNew)aSeg->Lookup(1);
       
    98 	if (!f)
       
    99 		return KErrGeneral;
       
   100 	// Dispatch event before calling CreateLogicalDevice() so the latter can be debugged.
       
   101 	__DEBUG_EVENT(EEventLoadLdd, aSeg);
       
   102 	DLogicalDevice *pD=(*f)();
       
   103 	TInt r=KErrNoMemory;
       
   104 	if (pD)
       
   105 		{
       
   106 		pD->iCodeSeg = aSeg;
       
   107 		r=Kern::InstallLogicalDevice(pD);
       
   108 		if (r==KErrNone)
       
   109 			{
       
   110 			// workaround to try and prevent codeseg destruction from happening whilst
       
   111 			// object destuctor code if it is still executing...
       
   112 			pD->iObjectFlags |= DObject::EObjectDeferKernelCodesegCleanup;
       
   113 			}
       
   114 		else
       
   115 			{
       
   116 			// Claim back ownership code seg and close device
       
   117 			pD->iCodeSeg=0;
       
   118 			pD->Close(NULL);
       
   119 			}
       
   120 		}
       
   121 	__COND_DEBUG_EVENT(r!=KErrNone, EEventUnloadLdd, aSeg);
       
   122 	return r;
       
   123 	}
       
   124 
       
   125 EXPORT_C TInt Kern::InstallPhysicalDevice(DPhysicalDevice* aDevice)
       
   126 //
       
   127 // Must be called in a critical section
       
   128 //
       
   129 	{
       
   130 	aDevice->iObjectFlags |= DObject::EObjectExtraReference;
       
   131 	TInt r=aDevice->Install();
       
   132 	if (r==KErrNone)
       
   133 		r=K::AddObject(aDevice,EPhysicalDevice); // Mustn't access aDevice after a successful AddObject!
       
   134 	return r;
       
   135 	}
       
   136 
       
   137 TInt DoPhysicalDeviceLoad(DCodeSeg* aSeg)
       
   138 	{
       
   139 	TPhysicalDeviceNew f=(TPhysicalDeviceNew)aSeg->Lookup(1);
       
   140 	if (!f)
       
   141 		return KErrGeneral;
       
   142 	// Dispatch event before calling CreatePhysicalDevice() so the latter can be debugged.
       
   143 	__DEBUG_EVENT(EEventLoadPdd, aSeg);
       
   144 	DPhysicalDevice *pD=(*f)();
       
   145 	TInt r=KErrNoMemory;
       
   146 	if (pD)
       
   147 		{
       
   148 		pD->iCodeSeg=aSeg;
       
   149 		r=Kern::InstallPhysicalDevice(pD);
       
   150 		if (r==KErrNone)
       
   151 			{
       
   152 			// workaround to try and prevent codeseg destruction from happening whilst
       
   153 			// object destuctor code if it is still executing...
       
   154 			pD->iObjectFlags |= DObject::EObjectDeferKernelCodesegCleanup;
       
   155 			}
       
   156 		else
       
   157 			{
       
   158 			// Claim back ownership code seg and close device
       
   159 			pD->iCodeSeg=0;
       
   160 			pD->Close(NULL);
       
   161 			}
       
   162 		}
       
   163 	__COND_DEBUG_EVENT(r!=KErrNone, EEventUnloadPdd, aSeg);
       
   164 	return r;
       
   165 	}
       
   166 
       
   167 TInt ReopenDriver(TInt aDeviceType,DCodeSeg* aCodeSeg)
       
   168 	{
       
   169 	DObject* pClose = NULL;
       
   170 	TInt objtype = aDeviceType ? EPhysicalDevice : ELogicalDevice;
       
   171 	DObjectCon& oc = *K::Containers[objtype];
       
   172 	oc.Wait();
       
   173 	TInt c = oc.Count();
       
   174 	TInt r = KErrNotFound;
       
   175 	for (TInt i=0; i<c; i++)
       
   176 		{
       
   177 		DObject* pD = oc[i];
       
   178 		DCodeSeg* pS = aDeviceType ? ((DPhysicalDevice*)pD)->iCodeSeg
       
   179 								   : ((DLogicalDevice*)pD)->iCodeSeg;
       
   180 		if(pS==aCodeSeg)
       
   181 			{
       
   182 			// Found the driver so...
       
   183 			if(pD->Open()!=KErrNone)
       
   184 				r = KErrDied;  // Failed to Open
       
   185 			else
       
   186 				{
       
   187 				TUint oldFlags = __e32_atomic_ior_ord8(&pD->iObjectFlags, DObject::EObjectExtraReference);
       
   188 				if(!(oldFlags&DObject::EObjectExtraReference))
       
   189 					r = KErrNone;  // We succesfully added the 'extra reference'
       
   190 				else
       
   191 					{
       
   192 					// The extra reference was already set.
       
   193 					r = KErrAlreadyExists;
       
   194 					pClose = pD;  // need to close again
       
   195 					}
       
   196 				}
       
   197 			break;
       
   198 			}
       
   199 		}
       
   200 	oc.Signal();
       
   201 	if(pClose)
       
   202 		pClose->Close(NULL);
       
   203 	return r;
       
   204 	}
       
   205 
       
   206 TInt ExecHandler::DeviceLoad(TAny* aHandle, TInt aDeviceType)
       
   207 //
       
   208 // Install a logical or physical device driver
       
   209 //
       
   210 	{
       
   211 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::DeviceLoad type %d",aDeviceType));
       
   212 	DCodeSeg* pS=DCodeSeg::VerifyCallerAndHandle(aHandle);
       
   213 	DProcess& kern=*K::TheKernelProcess;
       
   214 	TUint32 uid2=aDeviceType ? KPhysicalDeviceDriverUidValue : KLogicalDeviceDriverUidValue;
       
   215 	if (TUint32(pS->iUids.iUid[1].iUid)!=uid2)
       
   216 		return KErrNotSupported;
       
   217 
       
   218 	NKern::ThreadEnterCS();
       
   219 	TInt r;
       
   220 
       
   221 	// Attempt to reopen the 'extra reference' on the driver...
       
   222 	r = ReopenDriver(aDeviceType,pS);
       
   223 	if(r==KErrNotFound)
       
   224 		{
       
   225 		// Driver didn't exist, so try and load it...
       
   226 
       
   227 		// See if Codeseg already exists in the kernel
       
   228 		SCodeSegEntry find;
       
   229 		find.iSeg=pS;
       
   230 		find.iLib=NULL;
       
   231 		TInt i;
       
   232 		DCodeSeg::Wait();
       
   233 		r=kern.iDynamicCode.FindInUnsignedKeyOrder(find,i);
       
   234 		if(r==KErrNone)
       
   235 			{
       
   236 			// The Codeseg already exists but we didn't previousely find the driver.
       
   237 			// This means that the driver must be in the process of destruction.
       
   238 			// We can't do anything about this so return an error.
       
   239 			DCodeSeg::Signal();
       
   240 			r = KErrDied;
       
   241 			}
       
   242 		else
       
   243 			{
       
   244 			// Add Codeseg to kernel
       
   245 			SDblQue cs_list;
       
   246 			r=kern.AddCodeSeg(pS,NULL,cs_list);
       
   247 			DCodeSeg::EmptyQueue(cs_list,0);
       
   248 
       
   249 			DCodeSeg::Signal();
       
   250 
       
   251 			if (r==KErrNone)
       
   252 				{
       
   253 				// Create the driver object
       
   254 				if (aDeviceType)
       
   255 					r=DoPhysicalDeviceLoad(pS);
       
   256 				else
       
   257 					r=DoLogicalDeviceLoad(pS);
       
   258 
       
   259 				// If driver create failed, remove the Codeseg we added
       
   260 				if (r!=KErrNone)
       
   261 					pS->ScheduleKernelCleanup(ETrue);
       
   262 				}
       
   263 			}
       
   264 		}
       
   265 
       
   266 	NKern::ThreadLeaveCS();
       
   267 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::DeviceLoad returns %d",r));
       
   268 	return r;
       
   269 	}
       
   270 
       
   271 TInt ExecHandler::DeviceFree(const TDesC8& aName, TInt aDeviceType)
       
   272 	{
       
   273 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::DeviceFree type %d",aDeviceType));
       
   274 	TKName devname;
       
   275 	Kern::KUDesGet(devname, aName);
       
   276 	__KTRACE_OPT(KDEVICE,Kern::Printf("Name %S",&devname));
       
   277 	TInt r = Kern::ValidateName(devname);
       
   278 	if (r<0)
       
   279 		return r;
       
   280 	
       
   281 	TFindHandle h;
       
   282 	TKName name;
       
   283 	TInt objtype = aDeviceType ? EPhysicalDevice : ELogicalDevice;
       
   284 	DObjectCon& oc = *K::Containers[objtype];
       
   285 	NKern::ThreadEnterCS();
       
   286 	oc.Wait();
       
   287 	r = oc.FindByName(h, devname, name);
       
   288 	if (r==KErrNone)
       
   289 		{
       
   290 		DObject* pO = oc.At(h);
       
   291 		TUint oldFlags = __e32_atomic_and_ord8(&pO->iObjectFlags, (TUint8)~DObject::EObjectExtraReference);
       
   292 		oc.Signal();
       
   293 		r = KErrInUse;  // start of by assuming device will not deleted
       
   294 		if (oldFlags&DObject::EObjectExtraReference)
       
   295 			{
       
   296 			DCodeSeg::DeferKernelCleanup(); // ensure device codeseg doen't get unloaded until after Close() returns
       
   297 			if (pO->Close(NULL)&DObject::EObjectDeleted)
       
   298 				r = KErrNone;  // We closed the 'extra reference' and the object was deleted
       
   299 			DCodeSeg::EndDeferKernelCleanup();
       
   300 			}
       
   301 		}
       
   302 	else
       
   303 		{
       
   304 		oc.Signal();
       
   305 		r = KErrNone;  // Treat 'not found' as a successfull DeviceFree
       
   306 		}
       
   307 	NKern::ThreadLeaveCS();
       
   308 
       
   309 	return r;
       
   310 	}
       
   311 
       
   312 void ExecHandler::LogicalDeviceGetCaps(DLogicalDevice* aDevice, TDes8& aDes)
       
   313 	{
       
   314 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::LogicalDeviceGetCaps %O",aDevice));
       
   315 	aDevice->CheckedOpen();
       
   316 	DThread& t=*TheCurrentThread;
       
   317 	t.iTempObj=aDevice;
       
   318 	NKern::UnlockSystem();
       
   319 	Kern::InfoCopy(aDes,0,0); // intialise to empty - and will also safely panic if aDes is bad
       
   320 	aDevice->GetCaps(aDes);
       
   321 	NKern::ThreadEnterCS();
       
   322 	t.iTempObj=NULL;
       
   323 	aDevice->Close(NULL);
       
   324 	NKern::ThreadLeaveCS();
       
   325 	}
       
   326 
       
   327 TBool ExecHandler::LogicalDeviceQueryVersionSupported(DLogicalDevice* aDevice, const TVersion& aVer)
       
   328 	{
       
   329 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::LogicalDeviceQueryVersionSupported %O",aDevice));
       
   330 	aDevice->CheckedOpen();
       
   331 	DThread& t=*TheCurrentThread;
       
   332 	t.iTempObj=aDevice;
       
   333 	NKern::UnlockSystem();
       
   334 	TVersion v;
       
   335 	kumemget32(&v,&aVer,sizeof(v));
       
   336 	TBool r=aDevice->QueryVersionSupported(v);
       
   337 	NKern::ThreadEnterCS();
       
   338 	t.iTempObj=NULL;
       
   339 	aDevice->Close(NULL);
       
   340 	NKern::ThreadLeaveCS();
       
   341 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::LogicalDeviceQueryVersionSupported ret %d",r));
       
   342 	return r;
       
   343 	}
       
   344 
       
   345 TBool ExecHandler::LogicalDeviceIsAvailable(DLogicalDevice* aDevice, TInt aUnit, const TDesC* aPhysicalDevice, const TDesC8* aInfo)
       
   346 	{
       
   347 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::LogicalDeviceIsAvailable %O",aDevice));
       
   348 	aDevice->CheckedOpen();
       
   349 	DThread& t=*TheCurrentThread;
       
   350 	t.iTempObj=aDevice;
       
   351 	NKern::UnlockSystem();
       
   352 	TBool r=aDevice->IsAvailable(aUnit,aPhysicalDevice,aInfo);
       
   353 	NKern::ThreadEnterCS();
       
   354 	t.iTempObj=NULL;
       
   355 	aDevice->Close(NULL);
       
   356 	NKern::ThreadLeaveCS();
       
   357 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::LogicalDeviceIsAvailable ret %d",r));
       
   358 	return r;
       
   359 	}
       
   360 
       
   361 
       
   362 /********************************************
       
   363  * Physical device base class
       
   364  ********************************************/
       
   365 
       
   366 /**	Base class destructor for DLogicalDevice.
       
   367 
       
   368 	This arranges for the code segment to be unloaded when the system next goes
       
   369 	idle.
       
   370 
       
   371 	@pre Calling thread must be in a critical section.
       
   372 	@pre No fast mutex can be held.
       
   373 	@pre Kernel must be unlocked
       
   374 	@pre Call in a thread context
       
   375 	@pre interrupts enabled
       
   376  */
       
   377 EXPORT_C DPhysicalDevice::~DPhysicalDevice()
       
   378 	{
       
   379 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DPhysicalDevice::~DPhysicalDevice");	
       
   380 	if (iCodeSeg)
       
   381 		{
       
   382 		__DEBUG_EVENT(EEventUnloadPdd, iCodeSeg);
       
   383 		iCodeSeg->ScheduleKernelCleanup(EFalse);
       
   384 		}
       
   385 	}
       
   386 
       
   387 
       
   388 /**	Checks if a specific interface version is supported.
       
   389 	Default implementation.
       
   390 
       
   391 	All old versions are supported.
       
   392 
       
   393 	@param	aVer	The requested interface version
       
   394 	
       
   395 	@return	TRUE if supported, FALSE if not.
       
   396  */
       
   397 EXPORT_C TBool DPhysicalDevice::QueryVersionSupported(const TVersion& aVer) const
       
   398 	{
       
   399 	return Kern::QueryVersionSupported(iVersion,aVer);
       
   400 	}
       
   401 
       
   402 
       
   403 /**	Checks if a specified unit number and additional info is supported.
       
   404 
       
   405     Default implementation.
       
   406 
       
   407 	@param	aUnit	The requested unit number
       
   408 	@param	aInfo	The additional information
       
   409 	
       
   410 	@return	TRUE if supported, FALSE if not.
       
   411  */
       
   412 EXPORT_C TBool DPhysicalDevice::IsAvailable(TInt /*aUnit*/, const TDesC8* /*aInfo*/) const
       
   413 	{
       
   414 	return ETrue;
       
   415 	}
       
   416 
       
   417 
       
   418 /** Gets additional device specific or device class specific information about
       
   419 	this driver.
       
   420 
       
   421 	Currently used only for driver priorities in conjunction with the
       
   422 	RPhysicalDeviceArray class which is used to find media drivers.
       
   423 
       
   424 	@param	aFunction	The piece of information being requested
       
   425 	@param	a1			Arbitrary additional parameter(s)
       
   426 	
       
   427 	@return	The requested information.
       
   428 
       
   429 	@see RPhysicalDeviceArray
       
   430  */
       
   431 EXPORT_C TInt DPhysicalDevice::Info(TInt aFunction, TAny* /*a1*/)
       
   432 	{
       
   433 	if (aFunction==EPriority)
       
   434 		return 0;
       
   435 	return KErrNotSupported;
       
   436 	}
       
   437 
       
   438 
       
   439 // Utility for finding PDDs in priority order
       
   440 
       
   441 /**	Constructor for physical device array.
       
   442  */
       
   443 EXPORT_C RPhysicalDeviceArray::RPhysicalDeviceArray()
       
   444 	: RArray<SPhysicalDeviceEntry>(8,_FOFF(SPhysicalDeviceEntry,iPriority))
       
   445 	{}
       
   446 
       
   447 
       
   448 /** Frees all resources held by this array.
       
   449 
       
   450 	This closes any devices held in the array before freeing memory used by
       
   451 	the array itself.
       
   452 
       
   453 	@pre Call in a thread context.
       
   454 	@pre Calling thread must be in a critical section.
       
   455 	@pre No fast mutex can be held.
       
   456 	@pre Kernel must be unlocked.
       
   457 	@pre interrupts enabled
       
   458  */
       
   459 EXPORT_C void RPhysicalDeviceArray::Close()
       
   460 	{
       
   461 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"RPhysicalDeviceArray::Close");	
       
   462 	TInt i;
       
   463 	TInt c=Count();
       
   464 	for (i=0; i<c; i++)
       
   465 		{
       
   466 		SPhysicalDeviceEntry& e=operator[](i);
       
   467 		Kern::SafeClose((DObject*&)e.iPhysicalDevice,NULL);
       
   468 		}
       
   469 	RArray<SPhysicalDeviceEntry>::Reset();
       
   470 	}
       
   471 
       
   472 
       
   473 /**	Populates the array with a list of PDDs meeting certain criteria.
       
   474 
       
   475 	@param	aMatch	Descriptor which the PDD's name must match
       
   476 	@param	aUnit	Unit number which the PDD must support
       
   477 	@param	aInfo	Additional information about what the PDD must support
       
   478 	@param	aVer	Interface version which the PDD must support
       
   479 	
       
   480 	@return	KErrNone, if at least one PDD matched the criteria.
       
   481 	        KErrNotFound, if no PDD matched the criteria;
       
   482 	        KErrNoMemory, if the array could not be expanded at some point.
       
   483 
       
   484 	@pre Call in a thread context.
       
   485 	@pre Calling thread must be in a critical section.
       
   486 	@pre No fast mutex can be held.
       
   487 	@pre Kernel must be unlocked.
       
   488 	@pre interrupts enabled
       
   489 
       
   490 	@post	The array is populated with pointers to DPhysicalDevice objects
       
   491 			matching the requested criteria, along with the priorities of those
       
   492 			PDDs. The pointers are reference counted. The array is sorted in
       
   493 			ascending order of driver priority.
       
   494 			If an OOM occurred the list will be empty.
       
   495 			
       
   496  */
       
   497 EXPORT_C TInt RPhysicalDeviceArray::GetDriverList(const TDesC& aMatch, TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
       
   498 	{
       
   499 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"RPhysicalDeviceArray::GetDriverList");	
       
   500 	Reset();
       
   501 	TInt r=KErrNone;
       
   502 	DObjectCon& pdev=*K::Containers[EPhysicalDevice];
       
   503 	pdev.Wait();
       
   504 	TFindHandle h;
       
   505 	TKName name;
       
   506 	FOREVER
       
   507 		{
       
   508 		TInt s=pdev.FindByName(h,aMatch,name);
       
   509 		if (s!=KErrNone)
       
   510 			break;
       
   511 		DPhysicalDevice* pD=(DPhysicalDevice*)pdev.At(h);
       
   512 		s=pD->Open();
       
   513 		if (s==KErrNone)
       
   514 			{
       
   515 			s=pD->Validate(aUnit,aInfo,aVer);
       
   516 			if (s!=KErrNone)
       
   517 				pD->Close(NULL);
       
   518 			else
       
   519 				{
       
   520 				SPhysicalDeviceEntry e;
       
   521 				e.iPriority=pD->Info(DPhysicalDevice::EPriority,NULL);
       
   522 				e.iPhysicalDevice=pD;
       
   523 				r=InsertInSignedKeyOrderAllowRepeats(e);
       
   524 				if (r!=KErrNone)
       
   525 					{
       
   526 					// we are out of memory
       
   527 					pD->Close(NULL);
       
   528 					break;
       
   529 					}
       
   530 				}
       
   531 			}
       
   532 		}
       
   533 	pdev.Signal();
       
   534 	if (r!=KErrNone)
       
   535 		Close();
       
   536 	else if (Count()==0)
       
   537 		r=KErrNotFound;
       
   538 	return r;
       
   539 	}
       
   540 
       
   541 
       
   542 /********************************************
       
   543 * Logical Channel base class
       
   544  ********************************************/
       
   545 
       
   546 /**
       
   547 The base class destructor for all logical channel objects.
       
   548 
       
   549 @pre Calling thread must be in a critical section.
       
   550 @pre No fast mutex can be held.
       
   551 @pre Kernel must be unlocked
       
   552 @pre interrupts enabled
       
   553 @pre Call in a thread context
       
   554 */
       
   555 EXPORT_C DLogicalChannelBase::~DLogicalChannelBase()
       
   556 	{
       
   557 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalChannelBase::~DLogicalChannelBase");	
       
   558 	__KTRACE_OPT(KDEVICE,Kern::Printf("~DLogicalChannelBase %O LDD %O PDD %O",this,iDevice,iPhysicalDevice));
       
   559 	__e32_atomic_tas_ord32(&iDevice->iOpenChannels, 1, -1, 0);
       
   560 	DBase* pV=iPdd;
       
   561 	iPdd=NULL;
       
   562 	DBase::Delete(pV);
       
   563 	Kern::SafeClose((DObject*&)iPhysicalDevice,NULL);
       
   564 	Kern::SafeClose((DObject*&)iDevice,NULL);
       
   565 	}
       
   566 
       
   567 
       
   568 
       
   569 
       
   570 /**	
       
   571 Second phase constructor for DLogicalChannelBase objects.
       
   572 
       
   573 It is called in creating thread context in a critical section with
       
   574 no fast mutexes	held.
       
   575 
       
   576 The default implementation does nothing.
       
   577 
       
   578 @param	aUnit	Requested unit number
       
   579 @param	aInfo	Additional info supplied by client
       
   580 @param	aVer	Requested interface version
       
   581 
       
   582 @return	KErrNone if construction was successful,
       
   583         otherwise one of the other system-wide error codes.
       
   584 
       
   585 @pre Calling thread must be in a critical section.
       
   586 @pre No fast mutex can be held.
       
   587 @pre Kernel must be unlocked
       
   588 @pre interrupts enabled
       
   589 @pre Call in a thread context
       
   590 */
       
   591 EXPORT_C TInt DLogicalChannelBase::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/)
       
   592 	{
       
   593 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalChannelBase::DoCreate");
       
   594 	return KErrNone;
       
   595 	}
       
   596 
       
   597 
       
   598 TInt DLogicalDevice::FindPhysicalDevice(DLogicalChannelBase* aChannel, TChannelCreateInfo& aInfo)
       
   599 	{
       
   600 	DPhysicalDevice* pP=NULL;
       
   601 	TInt r=KErrNone;
       
   602 	TFullName n;
       
   603 	TFullName fn;
       
   604 	FullName(n);	// n=logical device full name
       
   605 	n+=KDotStar;
       
   606 	TFindHandle h;
       
   607 	DObjectCon& pdev=*K::Containers[EPhysicalDevice];
       
   608 	pdev.Wait();
       
   609 	if (aInfo.iPhysicalDevice) // Given a driver by name
       
   610 		{
       
   611 		if (aInfo.iPhysicalDevice->Match(n)<KErrNone) // Physical Device is not for this logical device
       
   612 			r=KErrBadDriver;
       
   613 		else
       
   614 			{
       
   615 			r=pdev.FindByFullName(h,*aInfo.iPhysicalDevice,fn);
       
   616 			if (r==KErrNone)
       
   617 				{
       
   618 				pP=(DPhysicalDevice *)pdev.At(h);
       
   619 				r=pP->Validate(aInfo.iUnit,aInfo.iInfo,iVersion);
       
   620 				if (r==KErrNone)
       
   621 					r=pP->Open();
       
   622 				}
       
   623 			}
       
   624 		}
       
   625 	else
       
   626 		{
       
   627 		FOREVER
       
   628 			{
       
   629 			r=pdev.FindByFullName(h,n,fn);
       
   630 			if (r!=KErrNone)
       
   631 				break;
       
   632 			__KTRACE_OPT(KDEVICE,Kern::Printf("Found PDD %lS",&fn));
       
   633 			pP=(DPhysicalDevice *)pdev.At(h);
       
   634 			__KTRACE_OPT(KDEVICE,{TBuf<16> verBuf(iVersion.Name()); Kern::Printf("unit=%d, info=%08x, ver=%lS",aInfo.iUnit,aInfo.iInfo,&verBuf);});
       
   635 			r=pP->Validate(aInfo.iUnit,aInfo.iInfo,iVersion);
       
   636 			__KTRACE_OPT(KDEVICE,Kern::Printf("DPhysicalDevice::Validate returns %d",r));
       
   637 			if (r!=KErrNotSupported)
       
   638 				break;
       
   639 			}
       
   640 		if (r==KErrNone)
       
   641 			r=pP->Open();
       
   642 		else if (r==KErrNotFound)
       
   643 			r=KErrNotSupported;
       
   644 		}
       
   645 	pdev.Signal();
       
   646 	if (r==KErrNone)
       
   647 		aChannel->iPhysicalDevice=pP;
       
   648 	return r;
       
   649 	}
       
   650 
       
   651 
       
   652 TInt DLogicalDevice::ChannelCreate(DLogicalChannelBase*& pC, TChannelCreateInfo& aInfo)
       
   653 	{
       
   654 	// aInfo has been moved over to kernel side
       
   655 	TInt r=Create(pC);	// create channel on this device
       
   656 	__KTRACE_OPT(KDEVICE,Kern::Printf("DLogicalChannelBase at %08x, r=%d",pC,r));
       
   657 	if (r!=KErrNone)
       
   658 		return r;
       
   659 	if (!pC)
       
   660 		return KErrNoMemory;
       
   661 	pC->iObjectFlags |= DObject::EObjectDeferKernelCodesegCleanup; // workaround to try and prevent device codeseg destruction from happening whilst channel object destuctor code is still executing
       
   662 	pC->iDevice=this;
       
   663 	__e32_atomic_add_ord32(&iOpenChannels, 1);
       
   664 	if (iParseMask & KDeviceAllowPhysicalDevice) // We need a physical device for the logical device
       
   665 		{
       
   666 		r=FindPhysicalDevice(pC,aInfo);
       
   667 		if (r!=KErrNone)
       
   668 			return r;
       
   669 		r=pC->iPhysicalDevice->Create(pC->iPdd,aInfo.iUnit,aInfo.iInfo,iVersion);
       
   670 		if (r!=KErrNone)
       
   671 			return r;
       
   672 		}
       
   673 	r=pC->DoCreate(aInfo.iUnit,aInfo.iInfo,aInfo.iVersion);
       
   674 	if (r==KErrNone)
       
   675 		r=K::AddObject(pC,ELogicalChannel);
       
   676 	return r;
       
   677 	}
       
   678 
       
   679 TInt ExecHandler::ChannelCreate(const TDesC8& aLogicalDevice, TChannelCreateInfo& aInfo, TInt aType)
       
   680 //
       
   681 // Create a channel from a device.
       
   682 //
       
   683 	{
       
   684 	TKName lddName;
       
   685 	TKName pddName;
       
   686 	Kern::KUDesGet(lddName,aLogicalDevice);
       
   687 	TChannelCreateInfo info;
       
   688 	kumemget32(&info,&aInfo,sizeof(TChannelCreateInfo));
       
   689 	if (info.iPhysicalDevice)
       
   690 		{
       
   691 		Kern::KUDesGet(pddName,*info.iPhysicalDevice);
       
   692 		info.iPhysicalDevice=&pddName;
       
   693 		}
       
   694 
       
   695 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::ChannelCreate LDD %lS PDD %lS Unit %d",&lddName,info.iPhysicalDevice,info.iUnit));
       
   696 
       
   697 	TInt r=Kern::ValidateName(lddName);
       
   698 	if (r<0)
       
   699 		return(r);
       
   700 	
       
   701 	NKern::ThreadEnterCS();
       
   702 	DLogicalDevice* pD=NULL;
       
   703 	DLogicalChannelBase* pC=NULL;
       
   704 	r=K::Containers[ELogicalDevice]->OpenByFullName((DObject*&)pD,lddName);
       
   705 	if (r!=KErrNone)
       
   706 		{
       
   707 		NKern::ThreadLeaveCS();
       
   708 		__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::ChannelCreate ret %d",r));
       
   709 		return r;
       
   710 		}
       
   711 	if ((pD->iParseMask&KDeviceAllowUnit) ? (info.iUnit>=KMaxUnits):(info.iUnit!=KNullUnit))
       
   712 		{
       
   713 		pD->Close(NULL);
       
   714 		NKern::ThreadLeaveCS();
       
   715 		K::PanicKernExec(EBadUnitNumber);
       
   716 		}
       
   717 	r=pD->ChannelCreate(pC,info);
       
   718 	if (r==KErrNone)
       
   719 		{
       
   720 		if(aType&KCreateProtectedObject)
       
   721 			{
       
   722 			pC->SetProtection(DObject::EProtected);
       
   723 			pC->SetOwner(NULL);
       
   724 			}
       
   725 		r=K::MakeHandle((TOwnerType)(aType&~KCreateProtectedObject),pC);
       
   726 		}
       
   727 	if (r<KErrNone)
       
   728         {
       
   729 		if (pC)
       
   730 			pC->Close(NULL);	// this also deletes iPdd and closes devices if necessary
       
   731 		else
       
   732 			pD->Close(NULL);	// close device if failed to create DLogicalChannelBase
       
   733         }
       
   734 	NKern::ThreadLeaveCS();
       
   735 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::ChannelCreate ret %d",r));
       
   736 	return r;
       
   737 	}
       
   738 
       
   739 TInt ExecHandler::ChannelRequest(DLogicalChannelBase* aChannel, TInt aFunction, TAny* a1, TAny* a2)
       
   740 	{
       
   741 	__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::ChannelControl ch %08x func %d",aChannel,aFunction));
       
   742 	DThread& t=*TheCurrentThread;
       
   743 	if (aChannel->Open()==KErrNone)
       
   744 		{
       
   745 		t.iTempObj=aChannel;
       
   746 		NKern::UnlockSystem();
       
   747 		TInt r=aChannel->Request(aFunction,a1,a2);
       
   748 		NKern::ThreadEnterCS();
       
   749 		t.iTempObj=NULL;
       
   750 		aChannel->Close(NULL);
       
   751 		NKern::ThreadLeaveCS();
       
   752 		__KTRACE_OPT(KDEVICE,Kern::Printf("Exec::ChannelControl ret %d",r));
       
   753 		return r;
       
   754 		}
       
   755 	K::PanicCurrentThread(EBadHandle);
       
   756 	return 0;
       
   757 	}
       
   758 
       
   759 
       
   760 /********************************************
       
   761  * Message-based logical channel
       
   762  ********************************************/
       
   763 
       
   764 /**
       
   765 Base class constructor for DLogicalChannel objects.
       
   766 
       
   767 Initialises the message queue.
       
   768 
       
   769 @pre Calling thread must be in a critical section.
       
   770 @pre No fast mutex can be held.
       
   771 @pre Kernel must be unlocked
       
   772 @pre interrupts enabled
       
   773 @pre Call in a thread context
       
   774 */
       
   775 EXPORT_C DLogicalChannel::DLogicalChannel()
       
   776 	:	iMsgQ(MsgQFunc,this,NULL,1)
       
   777 	{
       
   778 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalChannel::DLogicalChannel");
       
   779 	}
       
   780 
       
   781 
       
   782 
       
   783 
       
   784 /**
       
   785 Base class destructor for DLogicalChannel objects.
       
   786 
       
   787 It checks that there are no outstanding messages.
       
   788 
       
   789 @pre Calling thread must be in a critical section.
       
   790 @pre No fast mutex can be held.
       
   791 @pre ernel must be unlocked
       
   792 @pre interrupts enabled
       
   793 @pre Call in a thread context
       
   794 */
       
   795 EXPORT_C DLogicalChannel::~DLogicalChannel()
       
   796 	{
       
   797 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalChannel::~DLogicalChannel");	
       
   798 	__ASSERT_ALWAYS(!iMsgQ.Poll(),K::Fault(K::ELogicalChannelMsgUncompleted));
       
   799 	}
       
   800 
       
   801 
       
   802 
       
   803 
       
   804 /**
       
   805 Closes a message-based logical channel.
       
   806 
       
   807 It overrides DObject::Close() to send a close message to the device
       
   808 driver thread before deleting the object.
       
   809 
       
   810 @see DObject::Close()
       
   811 
       
   812 @pre Calling thread must be in a critical section.
       
   813 @pre No fast mutex can be held.
       
   814 @pre ernel must be unlocked
       
   815 @pre interrupts enabled
       
   816 @pre Call in a thread context
       
   817 */
       
   818 EXPORT_C TInt DLogicalChannel::Close(TAny*)
       
   819 	{
       
   820 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"DLogicalChannel::Close");
       
   821 	__KTRACE_OPT(KOBJECT,Kern::Printf("DLogicalChannel::Close %d %O",AccessCount(),this));
       
   822 	if (Dec()==1)
       
   823 		{
       
   824 		NKern::LockSystem();		// just in case someone is still using this object
       
   825 		NKern::UnlockSystem();
       
   826 		if (iDfcQ)
       
   827 			{
       
   828 			TThreadMessage& m=Kern::Message();
       
   829 			m.iValue=ECloseMsg;
       
   830 			m.SendReceive(&iMsgQ);
       
   831 			}
       
   832 		K::ObjDelete(this);
       
   833 		return EObjectDeleted;
       
   834 		}
       
   835 	return 0;
       
   836 	}
       
   837 
       
   838 
       
   839 
       
   840 
       
   841 /**
       
   842 Sets the DFC queue to be used by this logical channel.
       
   843 
       
   844 @param	aDfcQ	A pointer to the DFC queue to be used.
       
   845                 This must not be NULL.
       
   846 */
       
   847 EXPORT_C void DLogicalChannel::SetDfcQ(TDfcQue* aDfcQ)
       
   848 	{
       
   849 	iDfcQ=aDfcQ;
       
   850 	iMsgQ.SetDfcQ(aDfcQ);
       
   851 	}
       
   852 
       
   853 
       
   854 
       
   855 
       
   856 /**
       
   857 Handles a client request in the client context.
       
   858 
       
   859 It overrides DLogicalChannelBase::Request() to pass all requests to
       
   860 the driver thread as kernel side messages.
       
   861 
       
   862 @param	aReqNo	The number of the client request
       
   863 @param	a1		Arbitrary argument
       
   864 @param	a2		Arbitrary argument
       
   865 
       
   866 @return	Return value from the device driver call
       
   867 
       
   868 @pre	Called in context of client thread.
       
   869 @pre    Calling thread must not be in a critical section.
       
   870 @pre 	No fast mutex can be held.
       
   871 */
       
   872 EXPORT_C TInt DLogicalChannel::Request(TInt aReqNo, TAny* a1, TAny* a2)
       
   873 	{
       
   874 	CHECK_PRECONDITIONS(MASK_NO_CRITICAL|MASK_NO_FAST_MUTEX,"DLogicalChannel::Request");	
       
   875 	if (aReqNo<(TInt)EMinRequestId)
       
   876 		K::PanicKernExec(ERequestNoInvalid);
       
   877 	TThreadMessage& m=Kern::Message();
       
   878 	m.iValue=aReqNo;
       
   879 	m.iArg[0]=a1;
       
   880 	if (aReqNo<0)
       
   881 		{
       
   882 		kumemget32(&m.iArg[1],a2,2*sizeof(TAny*));
       
   883 		}
       
   884 	else
       
   885 		m.iArg[1]=a2;
       
   886 	return SendMsg(&m);
       
   887 	}
       
   888 
       
   889 
       
   890 
       
   891 
       
   892 /**
       
   893 Send a message to the DFC thread for processing by HandleMsg().
       
   894 
       
   895 This function is called in the context of the client thread.
       
   896 
       
   897 This can be used to pin client data in the context of the client thread, so that it can be safely
       
   898 accessed from kernel threads without the possibility of taking page faults.
       
   899 
       
   900 The default implementation sends the message to the queue and waits for a reply.  Code that
       
   901 overrides this method would probably call the this implementation in the default case.  It is also
       
   902 possible that some messages may be handled completely in the context of the client thread, in which
       
   903 case this would not be called.
       
   904 
       
   905 @param aMsg  The message to process.
       
   906              The iValue member of this distinguishes the message type:
       
   907 			 iValue==ECloseMsg, channel close message
       
   908 			 iValue==KMaxTInt, a 'DoCancel' message
       
   909 			 iValue>=0, a 'DoControl' message with function number equal to iValue
       
   910 			 iValue<0, a 'DoRequest' message with function number equal to ~iValue
       
   911 
       
   912 @return KErrNone if the message was send successfully, otherwise one of the other system-wide error
       
   913         codes.
       
   914 */
       
   915 EXPORT_C TInt DLogicalChannel::SendMsg(TMessageBase* aMsg)
       
   916 	{
       
   917 	return aMsg->SendReceive(&iMsgQ);
       
   918 	}
       
   919 
       
   920 
       
   921 
       
   922 
       
   923 /** Called when a client message becomes available
       
   924 	Called in the context of the driver thread.
       
   925 	Just passes the message on to the driver implementation as a call to pure
       
   926 	virtual DLogicalChannel::HandleMsg()
       
   927 
       
   928 	@param	aPtr	Pointer to the DLogicalChannel object which received the message
       
   929 
       
   930 	@internalComponent
       
   931  */
       
   932 void DLogicalChannel::MsgQFunc(TAny* aPtr)
       
   933 	{
       
   934 	DLogicalChannel* pC=(DLogicalChannel*)aPtr;
       
   935 	pC->HandleMsg(pC->iMsgQ.iMessage);
       
   936 	}
       
   937