usbmgmt/usbmgr/device/classdrivers/acm/classimplementation/ecacm/src/AcmPortFactory.cpp
changeset 0 c9bc50fca66e
child 29 59aa7d6e3e0f
equal deleted inserted replaced
-1:000000000000 0:c9bc50fca66e
       
     1 /*
       
     2 * Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 #include "AcmPortFactory.h"
       
    19 #include "AcmUtils.h"
       
    20 #include <acminterface.h>
       
    21 #include "AcmPort.h"
       
    22 #include "AcmPanic.h"
       
    23 #include "acmserver.h"
       
    24 #include "CdcAcmClass.h"
       
    25 #include <usb/usblogger.h>
       
    26 #include "c32comm_internal.h"
       
    27 
       
    28 #ifdef __FLOG_ACTIVE
       
    29 _LIT8(KLogComponent, "ECACM");
       
    30 #endif
       
    31 
       
    32 // Do not move this into a header file. It must be kept private to the CSY. It 
       
    33 // is the secret information that enables the old (registration port) 
       
    34 // mechanism allowing the USB Manager to set up ACM interfaces.
       
    35 const TUint KRegistrationPortUnit = 666;
       
    36 
       
    37 CAcmPortFactory* CAcmPortFactory::NewL()
       
    38 /**
       
    39  * Make a new CAcmPortFactory
       
    40  *
       
    41  * @return Ownership of a newly created CAcmPortFactory object
       
    42  */
       
    43 	{
       
    44 	LOG_STATIC_FUNC_ENTRY
       
    45 
       
    46 	CAcmPortFactory* self = new(ELeave) CAcmPortFactory;
       
    47 	CleanupClosePushL(*self);
       
    48 	self->ConstructL();
       
    49 	CleanupStack::Pop();
       
    50 	return self;
       
    51 	}
       
    52 	
       
    53 CAcmPortFactory::CAcmPortFactory()
       
    54 /**
       
    55  * Constructor.
       
    56  */
       
    57 	{
       
    58 	iVersion = TVersion(
       
    59 		KEC32MajorVersionNumber, 
       
    60 		KEC32MinorVersionNumber, 
       
    61 		KEC32BuildVersionNumber);
       
    62 	iConfigBuf().iAcmConfigVersion = 1;
       
    63 	iOwned = EFalse;
       
    64 	}
       
    65 
       
    66 void CAcmPortFactory::ConstructL()
       
    67 /**
       
    68  * Second phase constructor.
       
    69  */
       
    70 	{
       
    71 	LEAVEIFERRORL(SetName(&KAcmSerialName)); 
       
    72 	iAcmServer = CAcmServer::NewL(*this);
       
    73 	
       
    74 	TInt err = RProperty::Define(KUidSystemCategory, KAcmKey, RProperty::EByteArray, TPublishedAcmConfigs::KAcmMaxFunctions);
       
    75 	if(err == KErrAlreadyExists)
       
    76 		{	
       
    77 		LEAVEIFERRORL(iAcmProperty.Attach(KUidSystemCategory, KAcmKey, EOwnerThread));
       
    78 		//Since the P&S data already exists we need to retrieve it
       
    79 		LEAVEIFERRORL(iAcmProperty.Get(iConfigBuf));
       
    80 		}
       
    81 	else if(err == KErrNone)
       
    82 		{
       
    83 		//A blank iConfigBuf already exists at this point to we don't need to do anything to it
       
    84 		//before publishing the P&S data
       
    85 		LEAVEIFERRORL(iAcmProperty.Attach(KUidSystemCategory, KAcmKey, EOwnerThread));
       
    86 		PublishAcmConfig();
       
    87 		iOwned = ETrue;
       
    88 		}
       
    89 	else
       
    90 		{
       
    91 		LEAVEIFERRORL(err); //This will always leave, but a log will be created at least.	
       
    92 		}
       
    93 		
       
    94 	}
       
    95 
       
    96 /**
       
    97  * Utility function for publishing the TPublishedAcmConfigs data
       
    98  * @pre Requires iAcmProperty to be attached before it is called
       
    99  */
       
   100 void CAcmPortFactory::PublishAcmConfig()
       
   101 	{
       
   102 	// Update the publish and subscribe info
       
   103 	TInt err = iAcmProperty.Set(iConfigBuf);
       
   104 	__ASSERT_DEBUG(err == KErrNone, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
       
   105 	(void)err;
       
   106 	}
       
   107 
       
   108 TSecurityPolicy CAcmPortFactory::PortPlatSecCapability (TUint aPort) const
       
   109 /**
       
   110  * Called by C32 when it needs to check the capabilities of a client against the 
       
   111  * capabilites required to perform C32 defered operations on this port, aPort. 
       
   112  *
       
   113  * @param aPort The number of the port.
       
   114  * @return a security policy
       
   115  */
       
   116 	//return the security policy for the given port number, aPort.  
       
   117 	{
       
   118 	LOG_FUNC
       
   119 	
       
   120 	TSecurityPolicy securityPolicy; 
       
   121 	if ( aPort == KRegistrationPortUnit ) 
       
   122 		{
       
   123 		securityPolicy = TSecurityPolicy(ECapabilityNetworkControl);
       
   124 		}
       
   125 	else
       
   126 		{
       
   127 		securityPolicy = TSecurityPolicy(ECapabilityLocalServices);	
       
   128 		}
       
   129 	return securityPolicy;	 	
       
   130 	}
       
   131 
       
   132 void CAcmPortFactory::AcmPortClosed(const TUint aUnit)
       
   133 /**
       
   134  * Called by an ACM port when it is closed. 
       
   135  *
       
   136  * @param aUnit The port number of the closing port.
       
   137  */
       
   138 	{
       
   139 	LOG_FUNC
       
   140 	LOGTEXT2(_L8("\taUnit = %d"), aUnit);
       
   141 
       
   142 	// I would assert that the calling port is stored in our array, but if we 
       
   143 	// ran out of memory during CAcmPort::NewL, this function would be called 
       
   144 	// from the port's destructor, but the slot in the port array would still 
       
   145 	// be NULL. 
       
   146 
       
   147 	// Reset the slot in our array of ports. 
       
   148 	const TUint index = aUnit - KAcmLowUnit;
       
   149 	iAcmPortArray[index] = NULL;
       
   150 
       
   151 #ifdef _DEBUG
       
   152 	LogPortsAndFunctions();
       
   153 #endif
       
   154 	}
       
   155 
       
   156 CAcmPortFactory::~CAcmPortFactory()
       
   157 /**
       
   158  * Destructor.
       
   159  */
       
   160 	{
       
   161 	LOG_FUNC
       
   162 
       
   163 	// Delete ACM instances. We could assert that the ACM Class Controller has 
       
   164 	// caused them all to be destroyed, but if we do that, and USBSVR panics 
       
   165 	// while it's Started, it will result in C32 panicking too, which is 
       
   166 	// undesirable. TODO: I'm not sure about this philosophy. 
       
   167 	iAcmClassArray.ResetAndDestroy();
       
   168 
       
   169 	// We don't need to clean this array up because C32 will not shut us down 
       
   170 	// while ports are still open on us.
       
   171 	iAcmPortArray.Close();
       
   172 	
       
   173 	// Detach the local handles
       
   174 	iAcmProperty.Close();
       
   175 
       
   176 	// Remove the RProperty entries if they are owned by this instance of the PortFactory
       
   177 	if(iOwned)
       
   178 		{
       
   179 		RProperty::Delete(KUidSystemCategory, KAcmKey);		
       
   180 		}
       
   181 	
       
   182 	delete iAcmServer;
       
   183 	}
       
   184 
       
   185 CPort* CAcmPortFactory::NewPortL(const TUint aUnit)
       
   186 /**
       
   187  * Downcall from C32. Create a new port for the supplied unit number.
       
   188  *
       
   189  * @param aUnit Port unit number
       
   190  */
       
   191 	{
       
   192 	LOG_LINE
       
   193 	LOGTEXT2(_L8(">>CAcmPortFactory::NewPortL aUnit=%d"), aUnit);
       
   194 
       
   195 	CPort* port = NULL;
       
   196 
       
   197 	TUint lowerLimit = KAcmLowUnit; // This non-const TUint avoids compiler remarks (low-level warnings) for the following comparisons..
       
   198 	// ACM ports
       
   199 	if ( (aUnit >= lowerLimit) && aUnit < static_cast<TUint>( iAcmClassArray.Count()) + KAcmLowUnit)
       
   200 		{
       
   201 		// Can only create an ACM port if the corresponding ACM interface 
       
   202 		// itself has been created. We keep the slots in the  iAcmClassArray array 
       
   203 		// up-to-date with how many ACM interface instances have been created.
       
   204 		const TUint index = aUnit - KAcmLowUnit;
       
   205 		if ( iAcmPortArray[index] )
       
   206 			{
       
   207 			LEAVEIFERRORL(KErrInUse); // TODO: is this ever executed?
       
   208 			}						   
       
   209 		iAcmPortArray[index] = CAcmPort::NewL(aUnit, *this);
       
   210 		iAcmPortArray[index]->SetAcm( iAcmClassArray[index]);
       
   211 		port = iAcmPortArray[index];		
       
   212 		}
       
   213 	// Registration port
       
   214 	else if ( aUnit == KRegistrationPortUnit )
       
   215 		{
       
   216 		port = CRegistrationPort::NewL(*this, KRegistrationPortUnit);
       
   217 		}
       
   218 	else 
       
   219 		{
       
   220 		LEAVEIFERRORL(KErrAccessDenied);
       
   221 		}
       
   222 
       
   223 #ifdef _DEBUG
       
   224 	LogPortsAndFunctions();
       
   225 #endif
       
   226 
       
   227 	LOGTEXT2(_L8("<<CAcmPortFactory::NewPortL port=0x%08x"), port);
       
   228 	return port;
       
   229 	}
       
   230 
       
   231 void CAcmPortFactory::DestroyFunctions(const TUint aNoAcms)
       
   232 /**
       
   233  * Utility to delete ACM functions in the array. Deletes ACM functions and 
       
   234  * resizes the ACM array down. Also tells each of the affected ACM ports that 
       
   235  * its function has gone down.
       
   236  *
       
   237  * @param aNoAcms Number of ACM interfaces to destroy.
       
   238  */
       
   239 	{
       
   240 	LOGTEXT2(_L8(">>CAcmPortFactory::DestroyFunctions aNoAcms = %d"), aNoAcms);
       
   241 
       
   242 #ifdef _DEBUG
       
   243 	CheckAcmArray();
       
   244 #endif
       
   245 
       
   246 	for ( TUint ii = 0 ; ii < aNoAcms ; ii++ )
       
   247 		{
       
   248 		const TUint index =  iAcmClassArray.Count() - 1;
       
   249 		
       
   250 		// Inform the relevant ACM ports, if any, so they can complete 
       
   251 		// outstanding requests. NB The ACM port array should have been padded 
       
   252 		// up adequately, but not necessarily filled with ports.
       
   253 		if ( iAcmPortArray[index] )
       
   254 			{
       
   255 			iAcmPortArray[index]->SetAcm(NULL);
       
   256 			// Don't remove slots from the ACM port array, because higher-
       
   257 			// indexed ports might still be open.
       
   258 			}
       
   259 
       
   260 		// Destroy ACM interface.
       
   261 		delete iAcmClassArray[index];
       
   262 		iAcmClassArray.Remove(index);	
       
   263 		}
       
   264 		
       
   265 	//decrement the published configurations counter
       
   266 	iConfigBuf().iAcmCount -= aNoAcms;
       
   267 	PublishAcmConfig();
       
   268 	
       
   269 #ifdef _DEBUG
       
   270 	CheckAcmArray();
       
   271 	LogPortsAndFunctions();
       
   272 #endif
       
   273 
       
   274 	LOGTEXT(_L8("<<CAcmPortFactory::DestroyFunctions"));
       
   275 	}
       
   276 
       
   277 void CAcmPortFactory::CheckAcmArray()
       
   278 /**
       
   279  * Utility to check that each slot in the ACM interface array points to 
       
   280  * something valid. NB It is the ACM port array which may contain empty slots.
       
   281  */
       
   282 	{
       
   283 	LOG_FUNC
       
   284 
       
   285 	for ( TUint ii  = 0; ii < static_cast<TUint>( iAcmClassArray.Count()) ; ii++ )
       
   286 		{
       
   287 		__ASSERT_DEBUG( iAcmClassArray[ii], _USB_PANIC(KAcmPanicCat, EPanicInternalError));
       
   288 		}
       
   289 	}
       
   290 
       
   291 TInt CAcmPortFactory::CreateFunctions(const TUint aNoAcms, const TUint8 aProtocolNum, const TDesC16& aAcmControlIfcName, const TDesC16& aAcmDataIfcName)
       
   292 /**
       
   293  * Tries to create the ACM functions.
       
   294  * 
       
   295  * @param aNoAcms Number of ACM functions to create.
       
   296  * @param aProtocolNum Protocol setting to use for these ACM functions.
       
   297  * @param aAcmControlIfcName Control Interface Name or a null descriptor
       
   298  * @param aAcmDataIfcName Data Interface Name or a null descriptor
       
   299  */
       
   300 	{
       
   301 	LOGTEXT5(_L("\taNoAcms = %d, aProtocolNum = %d, Control Ifc Name = %S, Data Ifc Name = %S"),
       
   302 			aNoAcms, aProtocolNum, &aAcmControlIfcName, &aAcmDataIfcName);
       
   303 
       
   304 #ifdef _DEBUG
       
   305 	CheckAcmArray();
       
   306 #endif
       
   307 
       
   308 	TInt ret = KErrNone;
       
   309 
       
   310 	// Create the ACM class instances.
       
   311 	for ( TUint ii = 0 ; ii < aNoAcms ; ii++ )
       
   312 		{
       
   313 		LOGTEXT2(_L8("\tabout to create ACM instance %d"), ii);
       
   314 		TRAP(ret, CreateFunctionL(aProtocolNum, aAcmControlIfcName, aAcmDataIfcName));
       
   315 		if ( ret != KErrNone )
       
   316 			{
       
   317 			// Destroy the most recent ACMs that _did_ get created.
       
   318 			DestroyFunctions(ii);
       
   319 			break;
       
   320 			}
       
   321 		}
       
   322 
       
   323 	// all the ACM Functions should now have been created. publish the data
       
   324 	PublishAcmConfig();
       
   325 
       
   326 #ifdef _DEBUG
       
   327 	CheckAcmArray();
       
   328 	LogPortsAndFunctions();
       
   329 #endif
       
   330 
       
   331 	LOGTEXT2(_L8("<<CAcmPortFactory::CreateFunctions ret = %d"), ret);
       
   332 	return ret;
       
   333 	}
       
   334 
       
   335 void CAcmPortFactory::CreateFunctionL(const TUint8 aProtocolNum, const TDesC16& aAcmControlIfcName, const TDesC16& aAcmDataIfcName)
       
   336 /**
       
   337  * Creates a single ACM function, appending it to the  iAcmClassArray array.
       
   338  */
       
   339 	{
       
   340 	LOG_FUNC
       
   341 
       
   342 	LOGTEXT3(_L8("\tiAcmPortArray.Count() = %d,  iAcmClassArray.Count() = %d"), 
       
   343 		iAcmPortArray.Count(),  iAcmClassArray.Count());
       
   344 
       
   345 	LOGTEXT4(_L("\taProtocolNum = %d, Control Ifc Name = %S, Data Ifc Name = %S"),
       
   346 			aProtocolNum, &aAcmControlIfcName, &aAcmDataIfcName);
       
   347 
       
   348 	CCdcAcmClass* acm = CCdcAcmClass::NewL(aProtocolNum, aAcmControlIfcName, aAcmDataIfcName);
       
   349 	CleanupStack::PushL(acm);
       
   350 
       
   351 	// If there isn't already a slot in the ACM port array corresponding to 
       
   352 	// this ACM interface instance, create one. 
       
   353 	if ( iAcmPortArray.Count() <  iAcmClassArray.Count() + 1 )
       
   354 		{
       
   355 		LOGTEXT(_L8("\tappending a slot to the ACM port array"));
       
   356 		LEAVEIFERRORL(iAcmPortArray.Append(NULL));
       
   357 		}
       
   358 
       
   359 	LEAVEIFERRORL(iAcmClassArray.Append(acm));
       
   360 	CleanupStack::Pop(acm);
       
   361 	
       
   362 	// If there's an ACM port at the relevant index (held open from when USB 
       
   363 	// was previously Started, perhaps) then tell it about its new ACM 
       
   364 	// interface.
       
   365 	if ( iAcmPortArray[iAcmClassArray.Count() - 1] )
       
   366 		{
       
   367 		LOGTEXT3(_L8("\tinforming CAcmPort instance %d of acm 0x%08x"),  iAcmClassArray.Count() - 1, acm);
       
   368 		iAcmPortArray[iAcmClassArray.Count() - 1]->SetAcm(acm);
       
   369 		}
       
   370  
       
   371 	// update the TPublishedAcmConfig with the current details
       
   372 	iConfigBuf().iAcmConfig[iConfigBuf().iAcmCount].iProtocol = aProtocolNum;
       
   373 	iConfigBuf().iAcmCount++;
       
   374 	//don't update the p&s data here, do it in CreateFunctions after the construction of 
       
   375 	//all the requested functions
       
   376 	}
       
   377 
       
   378 void CAcmPortFactory::Info(TSerialInfo& aSerialInfo)
       
   379 /**
       
   380  * Get info about this CSY, fill in the supplied structure.
       
   381  *
       
   382  * @param aSerialInfo where info will be written to
       
   383  */
       
   384 	{
       
   385 	// NB Our TSerialInfo does not advertise the existence of the registration 
       
   386 	// port.
       
   387 	LOG_FUNC
       
   388 
       
   389 	_LIT(KSerialDescription, "USB Serial Port Emulation via ACM");	
       
   390 	aSerialInfo.iDescription = KSerialDescription;
       
   391 	aSerialInfo.iName = KAcmSerialName;
       
   392 	aSerialInfo.iLowUnit = KAcmLowUnit;
       
   393 	aSerialInfo.iHighUnit = (iAcmPortArray.Count()==0) ? 0 : (iAcmPortArray.Count()-1);
       
   394 	// See comments in AcmInterface.h 
       
   395 	}
       
   396 
       
   397 void CAcmPortFactory::LogPortsAndFunctions()
       
   398 /**
       
   399  * Utility to log in a tabular form all the ACM function instances and any 
       
   400  * associated ports. 
       
   401  * The number of ACM functions listed is the number we have been asked to 
       
   402  * make which we have made successfully. All the ACM 
       
   403  * functions listed should be pointing somewhere (enforced by CheckAcmArray). 
       
   404  * Any or all of the ACM ports may be NULL, indicating simply that the client 
       
   405  * side hasn't opened an RComm on that ACM port yet. 
       
   406  * It may also be the case that there are more ACM port slots than there are 
       
   407  * ACM functions slots. This just means that USB is in a more 'Stopped' state 
       
   408  * than it has been in the past- the ports in these slots may still be open, 
       
   409  * so the ACM port array must retain slots for them.
       
   410  * All this is just so the logging gives a clear picture of the functions and 
       
   411  * port open/closed history of the CSY.
       
   412  */
       
   413 	{
       
   414 	TUint ii;
       
   415 
       
   416 	// Log ACM functions and corresponding ports.
       
   417 	for ( ii = 0 ; ii < static_cast<TUint>( iAcmClassArray.Count()) ; ii++ )
       
   418 		{
       
   419 		LOGTEXT5(_L8("\t iAcmClassArray[%d] = 0x%08x, iAcmPortArray[%d] = 0x%08x"), ii,  iAcmClassArray[ii], ii, iAcmPortArray[ii]);
       
   420 		}
       
   421 	// Log any ports extending beyond where we currently have ACM interfaces.
       
   422 	for ( ; ii < static_cast<TUint>(iAcmPortArray.Count()) ; ii++ )
       
   423 		{
       
   424 		LOGTEXT4(_L8("\t iAcmClassArray[%d] = <no slot>, iAcmPortArray[%d] = 0x%08x"), ii, ii, iAcmPortArray[ii]);
       
   425 		}
       
   426 	}
       
   427 
       
   428 //
       
   429 // End of file