Example #1
0
/**
  Called from a DFC after the PDD has signalled that ReceiveData completed.
*/
void DZeroCopyLoopbackChannel::DoReceiveDataComplete()
	{
	if(iReceiveDataStatus)
		{
		PROBE_LDD(8);

		// Fetch the receive buffer. We shouldn't be told to complete rx unless there is data waiting
		DCommsBuf* rxBuf = Pdd()->ReceiveBuffer();
		__ASSERT_ALWAYS(rxBuf, Kern::Fault("comms loopback", KErrUnderflow));

		// Prepare commsbuf for handing to the client and close our reference to it
		TInt result;
		result = rxBuf->TransferToClient(iClient);
		
		// If we managed to create a handle for the client
		if(result > 0)
			{
			// Complete client's request (it will carry the handle to the received buffer)
			Kern::RequestComplete(iClient, iReceiveDataStatus, result);
			}

		// Step the receive queue
		Pdd()->AdvanceReceiveQueue();
		}
	}
Example #2
0
/**
  Fill a TConfig with the drivers current configuration.
*/
void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig)
	{
	aConfig.iSpeed = Pdd()->Speed();
	aConfig.iPddBufferSize = Pdd()->BufferSize();
	aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize();
	aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize();
	}
Example #3
0
/**
  Fill a TConfig with the drivers current configuration.
*/
void DZeroCopyLoopbackChannel::CurrentConfig(RZeroCopyLoopbackDriver::TConfig& aConfig)
	{
	aConfig.iSpeed = Pdd()->Speed();
	aConfig.iPddBufferSize = Pdd()->BufferSize();
	aConfig.iMaxSendDataSize = KLoopbackMTU;
	aConfig.iMaxReceiveDataSize = KLoopbackMTU;
	}
Example #4
0
/**
  Start processing a ReceiveData request.
*/
TInt DZeroCopyLoopbackChannel::ReceiveData(TRequestStatus* aStatus, TInt* aRxBufferPtr)
	{
	PROBE_LDD(4);
	// Check that a 'ReceiveData' isn't already in progress
	if(iReceiveDataStatus)
		{
		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KZeroCopyLoopbackPanicCategory);
		return KErrInUse;
		}

	// Save the client request status and descriptor for later completion
	iReceiveDataStatus = aStatus;
	iReceiveDataDescriptor = aRxBufferPtr;
	
	if(Pdd()->ReceivedQueueLen() > 0)
		{
		// complete with waiting data
		DoReceiveDataComplete();
		}

	// Ask PDD for data
	NKern::Lock(); 
	TInt r = Pdd()->RequestDataReceipt();
	NKern::Unlock(); 

	if(r != KErrNone)
		{
		iReceiveDataDescriptor = NULL;
		return r;
		}

	PROBE_LDD(5);
	return KErrNone;
	}
/**
 Transmits the data, passed as parameter over UART device. It invokes the 
 PDD transmit function to perform the actual device specific operation.
 
 
 @param		aOffset
 			Offset in the shared chunk, where the data resides
 @param		aSize
 			Size of the data to be transmitted
 			
 @return	KErrNone on success or standard error code on failure			
 */
 TInt DExDriverLogicalChannel::TransmitData(TUint aOffset, TInt aSize) 	
 	{  	
 	TInt r;
 	TInt size;
 	
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::TransmitData"));
 	
	if (Pdd()->iTxChunkLocal == Pdd()->ENone)	
		{
		Kern::RequestComplete(iClient,iTxDataStatus,KErrGeneral);
		return KErrGeneral;
		}
	// In case of zero length buffer or invalid length, abort the request.  	
  	//  
  	iBytesTxed = aSize;
  	if (iBytesTxed<=0)
 		return KErrAbort; 		
  	
  	
	
	// If Offset + demanded data size is > chunk size
	// then
	//		Get the available space from offset till chunk end.
	//  	If the demanded data size is greater than available space.
	//		then 
	//			Read only available space amount of data.
	if ((aOffset + aSize) >= Pdd()->iTxChunk->iSize)
		{
		TInt temp;
		temp = Pdd()->iTxChunk->iSize - aOffset;
		if (aSize >temp )
			aSize = temp;
		}
 	 		 	
 	// Transmit the data to device/PDD in blocks of LDD buffer length (256). 
 	// First transmit 1 frame here. In case of extra data it will be handled
 	// after completion of transmission of this frame.
 	// 	
 	size=(aSize<KTxDmaBufferSize)?aSize:KTxDmaBufferSize;
 	
	// Invoke PDD function to actually do the hardware specific
	// operation on the device. Here the buffer pointer can be				
	// accessed directly as both LDD and PDD are in kernel space.				
	//
	r = Pdd()->TransmitData(aOffset, size);
	
	
	return r;
 	}
/**
 Get the handle to the shared receive chunk. This function creates the chunk
 for receive buffer and returns the handle to the user to use it. User then
 accesses the shared chunk using this handle.
 
 @param	aHandle
 		Handle of the chunk, to be returned to user
 		
 @return KErrNone on success, standard error code on failure
 */
TInt DExDriverLogicalChannel::GetRxChunkHandle(TInt* aHandle)
	{
	TInt r;
	TInt hnd;
			
	// Invoke PDD function to create the chunk and return handle to the
	// user thread that made the request
	//				
	hnd=Pdd()->MakeRxChunkHandle(iClient);				
	if (hnd<0)
		return hnd;
	
	KEXDEBUG(Kern::Printf("Rx Chunk handle = %d",hnd));	
	
	// Write the hande value to user thread, iClient using 
	// kernel API, Kern::ThreadRawWrite to copy <hnd> to <aHandle>.
	// This request is run in user thread context. Kern::ThreadRawWrite()
	// writes the data directly and does not deal with descritors. Hence,
	// size also need to be provided to API as length info is not present as
	// in case of descriptor.
	// 
	// In user context kumemget() and kumemput() API have to be used to copy
	// the data. However, these API cannot be called in critical section with
	// DMutex held. Hence, Kern::ThreadXXX API are being used
	// 
	r=Kern::ThreadRawWrite(iClient,(TAny*)aHandle,(const TAny*)&hnd,sizeof(hnd));	
	
	
	return r;
	}
/** 
 Cancel Asynchronous Requests. This is called from HandleMsg() to cancel pending
 asynchronous requests. This function determines which operation is to be cancelled
 and tidy up the resources specific to the request being cancelled, any outstanding
 DFCs, timers and signals the client that the operation is completed.
 
 @param 	aMask
 		  	Mask containing the request number that has to be cancelled 
 */	
void DExDriverLogicalChannel::DoCancel(TUint aMask)
	{
	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::DoCancel"));
	// Any of the asynchronous operation if pending can be cancelled.Hence check if
	// it is a valid asynchronous request to cancel. e.g Transmit request
	//
	if(aMask&(1<<RExDriverChannel::ERequestTransmitData))
		{				
		if (iTxDataStatus)
			{			
    		// Stop the DMA for receive
			//
			Pdd()->StopDma(RExDriverChannel::ERequestTransmitData);
			
    		// Notify the Tx request client(iClient) that the request is completed and TRequestStatus
    		// object updated with the status and the completion code is provided to the
    		// client. KErrCancel indicates that the request has been cancelled. Typically,
    		// client thread waiting on User::WaitForRequest(TRequestStatus &aStatus) or using
    		// active object framework is unblocked and notified. Then the client may read the 
    		// request status from TRequestStatus object. 
    		//  
			Kern::RequestComplete(iClient,iTxDataStatus,KErrCancel);
			}
		}
		
	// Check if it is a receive data request	      
	//
    if(aMask&(1<<RExDriverChannel::ERequestReceiveData))
    	{
    	if (iRxDataStatus)
    		{
    		// Stop the DMA for receive
			//
			Pdd()->StopDma(RExDriverChannel::ERequestReceiveData);
			
    		// Notify the Rx request client (iClient) that the request is completed and TRequestStatus
    		// object updated with the status and the completion code is provided to the
    		// client. KErrCancel indicates that the request has been cancelled. Typically,
    		// client thread waiting on User::WaitForRequest(TRequestStatus &aStatus) or
    		// using active object framework is unblocked and notified. Then the client may
    		// read the request status from TRequestStatus object.
    		//    	
			Kern::RequestComplete(iClient,iRxDataStatus,KErrCancel);			
    		}
    	}
    	
	}
/**
 Set the internal loopback mode of the device (Uart). This is device specific API,
 that provides functionality to configure the uart's internal loopback mode, as
 set by the user.User calls this by using RBusLogicalChannel::DoControl() with
 appropriate request number

 @param		aMode
			Holds the loopback enable and disable option
			KLoopbackEnable for enable and KLoopbackDisable for disable

 @return	KErrNone or system wide standard error code
 */
 TInt DExDriverLogicalChannel::SetIntLoopback(const TInt* aMode)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::SetIntLoopback"));

 	TInt r=KErrNone;
	TInt mode;
	
	// Read the user option.	
	kumemget (&mode, aMode , sizeof(TInt));
		
	// See the Rx and Tx Status.
	// Anything in progress then do not allow changing the loopback mode.
	WaitOnConfigDMutex();
	
	WaitOnRxFMutex();
	if (iRxProgress)
		{
		SignalRxFMutex();
		SignalConfigDMutex();
		return KErrInUse;
		}
	iRxProgress = ETrue;
	SignalRxFMutex();
	
	WaitOnTxFMutex();
	if (iTxProgress)
		{
		SignalTxFMutex();
		SignalConfigDMutex();
		return KErrInUse;
		}
	iTxProgress = ETrue;
	SignalTxFMutex();
		
	if ((mode==KLoopbackEnable)||(mode==KLoopbackDisable))
			{
 			// Invoke PDD function to actually do the hardware
			// specific configuration on the device. Here the
			// buffer pointer can be passed and accessd directly
			// as both LDD and PDD are in kernel space.
			//
			Pdd()->SetIntLoopback(mode);
			}
		else
			r= KErrArgument;
	
	WaitOnRxFMutex();
	iRxProgress = EFalse;
	SignalRxFMutex();
	
	WaitOnTxFMutex();
	iTxProgress = EFalse;
	SignalTxFMutex();
	
	SignalConfigDMutex();
	// return the result
	return r;
 	}
/**
 Logical Channel - DoCreate(), called by framework after creating logical
 channel object as a part of the driver loading process. Driver should do
 the required validation like capabilities check, version check etc. It
 can do any required driver level initializations here.

 @param	aUnit
 		device unit number
 @param anInfo
 		device related information
 @param aVer
 		version number
 @return	KErrNone or standard error code
 */
TInt DExDriverLogicalChannel::DoCreate(TInt aUnit,
										const TDesC8* /*anInfo*/,
										const TVersion& aVer)
	{
	// Not using anInfo, so anInfo is commented in function arguments.
	// It can also be made void it to avoid compilation warnings by doing
	// (void)anInfo;

	// As a part of platform security guidelines, every driver needs to
	// enusure capability check. This check is to ensure that the client
	// accessing the driver has the required level of trust to perform any
	// operations on the device. Any client that does not have required
	// capability as expected by the driver is returned with no permission
	// error.Kernel API Kern::CurrentThreadHasCapability(),checks if the
	// current thread has the required capability (arg1) and displays the
	// diagnostic string in case of failure.
	//
	// Check if the client has level of trust to do serial comm related
	// operations.
	if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD,
				__PLATSEC_DIAGNOSTIC_STRING("Checked by Tutorial Driver")))
		return KErrPermissionDenied;

	// Check if driver version matches with the version client is trying
	// to use. Kernel API, Kern::QueryVersionSupported() verifies if the
	// versions match, returns true if test version is less than current
	// version (arg2<arg1).
	//
	if (!Kern::QueryVersionSupported(iDevice->iVersion,aVer))
		return KErrNotSupported;

	// Store the LDD object pointer in PDD. This will enable PDD to access
	// and call the LDD member functions easily. In case of callbacks to
	// LDD, PDD can use this pointer.
	//
	Pdd()->iLdd=this;

	TInt r = Kern::MutexCreate(iSyncConfigDMutex, KExMutexName, KMutexOrdGeneral0);
 	if(r!= KErrNone)
 		return r;

	// Allocate buffers for Tx and Rx. Kern::Alloc allocates a block of
	// specified size and zero fills the memory block. On success, this returns
	// pointer to the allocated buffer, else returns NULL pointer
	//
	iTxBuffer = (TUint8*) Kern::Alloc(KTxBufferSize);
	if (!iTxBuffer)
		return KErrNoMemory;
	
	iRxBuffer = (TUint8*) Kern::Alloc(KRxBufferSize);
	if (!iRxBuffer)
		return KErrNoMemory;

	// return no error
    return KErrNone;
	}
Example #10
0
/**
  DMA complete notification handler function. This function will be called
  by the PDD from the DMA Rx service function on successful DMA Rx operation.
  It notifies the user about receive request completion.
  
  @param	aSize
  			Accumulated size of data received over all individual reads.
  			aResult
  			DMA operation return value.
*/
 void DExDriverLogicalChannel::RxDmaComplete(TInt aSize, TInt aResult)
 	{
 	
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::RxDmaComplete")); 	
 	
 	
	// Action required only if a Rx request is issued and is pending
	//
	if (iRxDataStatus)	
		{
		// If this function is called on error condition, fail the user request
		if (aResult==KErrGeneral)
			{
			// Complete the current request with the abort result.
			Kern::RequestComplete(iClient,iRxDataStatus,aResult);
			return;
			}
						
		// aSize will have the number of bytes recieved in the transfer.
	 	iBytesRxed = iBytesRxed-aSize;
	 	
	 	// Calculate the offset till where the data is written.
		iRxOffset+=aSize;
		
		if (iBytesRxed<=0)
				{
				Kern::RequestComplete(iClient,iRxDataStatus,KErrNone);	
				return;
				}
				
		// If the DFC is scheduled on a Rx timeout condition, then
		// complete the request with timeout result
		//
		if (aResult==KErrTimedOut)
			{	
			
				// Complete the current request with the timeout result.
				Kern::RequestComplete(iClient,iRxDataStatus,aResult);
			return;
			}
	 	
	 	
	 	// If we have reached the end of the chunk.
	 	// then wrap around to the initial offset position. (User specified Offset)
	 	if (iRxOffset == Pdd()->iRxChunk->iSize)		
	 		{
	 		iRxOffset =  iRxInitialOffset;
	 		}
		
		// Re-start receiving the data
		ReceiveData(iRxOffset,iBytesRxed);
		
		
		return;		
		}
 	}
Example #11
0
/**
@purpose Processes a request to send a commsbuf
@param aStatus
@param aUserHandle Opaque handle to commsbuf to be sent.
*/
TInt DZeroCopyLoopbackChannel::SendData(TRequestStatus* aStatus, TInt aUserHandle)
	{
	// Check that a 'SendData' isn't already in progress
	PROBE_LDD(0);
	if(iSendDataStatus)
		{
		Kern::ThreadKill(iClient, EExitPanic, ERequestAlreadyPending, KZeroCopyLoopbackPanicCategory);
		return KErrInUse;
		}

	// Open the commsbuf received from the user for ourselves - the user side hold on it will be dropped
	// We need to provide a kernel private location for the incoming buffer so the current send buffer will do nicely
	DCommsBuf* sendBuf = Pdd()->SendBuffer();
	if(sendBuf)
		{
		TInt r = DCommsBuf::AcceptFromClient(iClient, aUserHandle, sendBuf);

		// Outbound packet loaded in to the output buffer so can now ask the pdd to send it
		if(r == KErrNone)
			{
			r = Pdd()->RequestDataSend();
			if(r != KErrNone)
				return r;

			// Save the client request status and return
			iSendDataStatus = aStatus;
			return KErrNone;
			}
		else
			{
			return r;
			}
		}
	else
		{
		// No where to put outbound buffer so can only drop it
		DCommsBuf sendBuf;
		TInt r = DCommsBuf::AcceptFromClient(iClient, aUserHandle, &sendBuf);
		sendBuf.Free();
		return KErrNone;
		}
	}
Example #12
0
/**
 Receive data from the serial port. Data received from device is filled
 into the buffer descriptor and returned. User calls this by using
 RBusLogicalChannel::DoControl() to LDD and ldd inturn calls the PDD
 function to do the actual reception od data from the device.

 @param 	aData
 			Receive buffer descriptor, returned to caller
 			aLen
 			Length of data requested by user

  @return	KErrNone or system wide standard error code
 */
 TInt DExDriverLogicalChannel::ReceiveData(TDes8* aData)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::ReceiveData"));

 	TInt size;
 	TInt length;

 	// Reset the target for a new receive
 	iRxOffset=0;

  	// Read the descriptor info from the user thread.	
	Kern::KUDesInfo(*aData ,length ,iRxCount );
	if (iRxCount<=0)
		{
		WaitOnRxFMutex();
  		iRxProgress = EFalse;
  		SignalRxFMutex();
		return KErrAbort;
		}
	
 	// Save the user buffer pointer to copy the data received later
	iRxData = aData;

	TInt r;
	
	do 
		{
		// Handle KRxBufferSize size of data in each iteration
		size=(iRxCount<KRxBufferSize)?iRxCount:KRxBufferSize;

		// Create a descriptor of the receive buffer of requested size
		TPtr8 rxbuf((TUint8*)iRxBuffer,size);

		// Initiate receiving data and Rx interrupt notification. PSL does
		// the hardware initialization
		// Loop around receive data from the device till complete data is
		// received or any error encountered.	
		//
		TInt lengthreceived;
		r = Pdd()->InitiateReceive(rxbuf, size, lengthreceived);	
		RxDataAvailable(lengthreceived,r);
		
		} 
	while (r==KErrNone && iRxCount >0);
		
	// Flag Rx is not in progress any more.
	// 
	WaitOnRxFMutex();
  	iRxProgress = EFalse;
  	SignalRxFMutex();
	
	// Return the result of ReceieveData.
	return r;
	}
Example #13
0
/**
 Takes the handle to the shared Receive chunk. This function takes shared chunk handle
 created by other driver (Channel) from user. PDD then opens it and populate all the physical and kernel address.
  
 @param	aHandle
 		Handle of the chunk, to be returned to user
 		
 @return KErrNone on success, standard error code on failure
 
 */
TInt DExDriverLogicalChannel::PassRxChunkHandle(TInt* aHandle)
	{
	TInt r;
	TInt hnd;
			
	r=Kern::ThreadRawRead(iClient,aHandle,(TAny*)&hnd,sizeof(hnd));	
	
	// Invoke PDD function to Pass the shared chunk handle to PDD
	r = Pdd()->TakeRxChunkHandle(iClient,hnd);
		
	return r;
	}
Example #14
0
/**
  Cancel a SendData request.
*/
void DDriver1Channel::SendDataCancel()
	{
	if(iSendDataStatus)
		{
		// Tell PDD to stop processing the request
		Pdd()->SendDataCancel();
		// Cancel DFC
		iSendDataDfc.Cancel();
		// Complete clients request
		Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
		}
	}
Example #15
0
/**
  All driver's client requests (synchronous and asynchronous) are sent as
  kernel messages by generic kernel to logical channel. This function
  catches messages sent by the generic kernel.
 
  @param aMsg Kernel side thread message to process.

	The iValue member of this distinguishes the message type:
	iValue==ECloseMsg, channel close message
	iValue==KMaxTInt, a 'DoCancel' message
	iValue>=0, a 'DoControl' message with function number equal to iValue
	iValue<0, a 'DoRequest' message with function number equal to ~iValue
 */ 
void DDisplayLdd::HandleMsg(TMessageBase* aMsg)
	{
    TThreadMessage& m	= *(TThreadMessage*)aMsg ;
	TInt id 			= m.iValue ;
    DThread* client 	= m.Client();

    // close message
    if (id == (TInt)ECloseMsg)
    	{
    	//Device specific cleanup operations
    	Pdd()->CloseMsg();
    	
        // cancel outstanding requests
        for(TInt k = 0; k < KPendingReqArraySize; k++)
        	{ 
			for(TInt i = 0; i < KMaxQueuedRequests; i++)
				{
	        	if( iPendingReq[k][i].iTClientReq) 
	            	{
	            	if(iPendingReq[k][i].iTClientReq->IsReady() )
	            		{
	            		CompleteRequest(iPendingReq[k][i].iOwningThread,iPendingReq[k][i].iTClientReq,KErrCancel);
	            		}            	            		
	            	}
				}
        	}
        Pdd()->SetLegacyMode();
		m.Complete(KErrNone, EFalse);
		return;
		}
    // cancel
    if (id == KMaxTInt)
		{
		// DoCancel
		TInt req = m.Int0() >> 1;
		DoCancel(req);
		m.Complete(KErrNone,ETrue);
    	return;
		}
Example #16
0
/**
 Initiates receiving data from the UART device. It enable the receive 
 interrupt,a way to get the data available notification from device
  
 */
 void DExDriverLogicalChannel::ReceiveData(TUint aOffset,TInt aSize)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::ReceiveData"));
 	
	
	// Initiate receiving data and Rx interrupt notification. PSL does
	// the hardware initialization
	//
	
	TInt temp;
	
	// If Offset + demanded data size is > chunk size
	// then
	//		Get the available space from offset till chunk end.
	//  	If the demanded data size is greater than available space.
	//		then 
	//			Read only available space amount of data.
	if ((aOffset + aSize) >= Pdd()->iRxChunk->iSize)
		{
		temp = Pdd()->iRxChunk->iSize - aOffset;
		if (aSize >temp )
			aSize = temp;
		}
			
	if (Pdd()->iRxChunkLocal == Pdd()->ENone)	
		{
		Kern::RequestComplete(iClient,iRxDataStatus,KErrGeneral);
		return;
		}
	// Receive the data from device/PDD in blocks of LDD buffer length (256). 
 	// First Receive 1 frame here. In case of extra data it will be handled
 	// after completion of Receipt of this frame.
	if (aSize > KRxDmaBufferSize)
		aSize = KRxDmaBufferSize;
		
	Pdd()->InitiateReceive(aOffset,aSize);
	return;
	}
Example #17
0
/**
  Cancel a ReceiveData request.
*/
void DDriver1Channel::ReceiveDataCancel()
	{
	if(iReceiveDataStatus)
		{
		// Tell PDD to stop processing the request
		Pdd()->ReceiveDataCancel();
		// Cancel DFC
		iReceiveDataDfc.Cancel();
		// Finished with client descriptor, so NULL it to help detect coding errors
		iReceiveDataDescriptor = NULL;
		// Complete clients request
		Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel);
		}
	}
Example #18
0
/**
  Process a SetConfig control message. This sets the driver configuration using a
  RZeroCopyLoopbackDriver::TConfigBuf supplied by the client.
*/
TInt DZeroCopyLoopbackChannel::SetConfig(const TDesC8* aConfigBuf)
	{
	// Don't allow configuration changes whilst we're busy
	if(iSendDataStatus || iReceiveDataStatus)
		return KErrInUse;

	// Create a config structure.
	RZeroCopyLoopbackDriver::TConfig config;
	CurrentConfig(config);

	// Note: We have filled config with the current settings, this is to allow
	// backwards compatibility when a client gives us an old (and shorter) version
	// of the config structure.

	// Read the config structure from client
	TPtr8 ptr((TUint8*)&config,sizeof(config));
	TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
	if(r!=KErrNone)
		return r;

	// Use config data to setup the driver. Checking that parameters which aren't settable
	// either contain the correct values or are zero (meaning 'default')
	if(config.iPddBufferSize && config.iPddBufferSize!=Pdd()->BufferSize())
		return KErrArgument;

	if(config.iMaxSendDataSize && config.iMaxSendDataSize!=KLoopbackMTU)
		return KErrArgument;

	if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=KLoopbackMTU)
		return KErrArgument;

	r=Pdd()->SetSpeed(config.iSpeed);
	if(r!=KErrNone)
		return r;

	return r;
	}
Example #19
0
/**
 Get the channel capabilities of UART. This function reads the channels
 capabilities from the Platform Specific Layer (PSL). User uses this info
 to configure the channel as per supported capabilties.

 @param		aCaps
 			Buffer to read the channel capabilities
 @return	KErrNone on success or system wide error code on failure of
 			data copy to user
 */
 TInt DExDriverLogicalChannel::Caps(TDes8* aCaps)
 	{
 	
	
	//  Package buffer for TCommCapsV03
 	TCommCaps3 caps;

 	// Call the PSL capabilities function
	Pdd()->Caps(caps);
	
	// Copy the caps to aCaps.
    Kern::InfoCopy(*aCaps,caps);
    
    return KErrNone;
 	}
Example #20
0
/**
 Configure the hardware device (Uart). This is device specific API, that
 provides functionality to configure the uart. Uart configuration settings are
 passed to this function by user. User calls this by using
 RBusLogicalChannel::DoControl() with appropriate request number

 @param		aConfig
 			configuration settings for the device
 @return	KErrNone or system wide standard error code
 
 */
 TInt DExDriverLogicalChannel::SetConfig(const TDesC8* aConfig)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::SetConfig"));

 	TInt r;
 	
	
 	// TCommConfigV01 structure defined in d32comm.h is used
 	// to hold the configuration details like baudrate, parity,
 	// databits etc for serial
 	//
	TCommConfigV01 config;

	// Set the bytes to zero using the nanokernel
	// utility function, memclr()
	//
	memclr(&config, sizeof(config));

	// Constructs 8-bit modifiable pointer descriptor, with
	// length 0 and max length, sizeof(config)
	//
	TPtr8 cfg((TUint8*)&config, 0, sizeof(config));

	// Read the descriptor from user thread, iClient using
	// kernel API, Kern::ThreadDesRead to copy aConfig to cfg.
	// Incase of reading raw data,Kern::ThreadRawData() can
	// be used. Then, TPtr8 descriptor need not be created.
	// Here, aConfig is source and cfg is destination.
	//
	r = Kern::ThreadDesRead(iClient,aConfig,cfg,0,0);							
	if (r==KErrNone)
		{
 		// Invoke PDD function to actually do the hardware
		// specific configuration on the device. Here the
		// buffer pointer can be passed and accessed directly
		// as both LDD and PDD are in kernel space.
		//
		r = Pdd()->Configure(config);
		}
		
	
	// return the result
	return r;
 	}
Example #21
0
/**
  Start processing a ReceiveData request.
*/
TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr)
	{
	// Check that a 'ReceiveData' isn't already in progress
	if(iReceiveDataStatus)
		{
		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
		return KErrInUse;
		}

	// Ask PDD for data
	TInt r=Pdd()->ReceiveData(iReceiveDataBuffer);
	if(r!=KErrNone)
		return r;

	// Save the client request status and descriptor before returning
	iReceiveDataStatus = aStatus;
	iReceiveDataDescriptor = aPtr;
	return KErrNone;
	}
Example #22
0
/**
  Second stage constructor called by the kernel's device driver framework.
  This is called in the context of the user thread (client) which requested the creation of a Logical Channel
  (E.g. through a call to RBusLogicalChannel::DoCreate)
  The thread is in a critical section.

  @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
  @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
  @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate

  @return KErrNone if successful, otherwise one of the other system wide error codes.
*/
TInt DZeroCopyLoopbackChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
	{
	// Check Platform Security capabilities of client thread (if required).
	//
	// Here we handle the simple case where:
	// 1. The device driver can only have one client thread
	// 2. The security policy is the binary all-or-nothing policy.
	//    E.g. "If you have the right capability you can do anything with the driver
	//    and if you don't have the capability you can't do anything"
	// 
	// If only some functionality of the driver is restricted, then the security check should
	// go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
	// shouldn't be used because the 'current thread' isn't the client.
	//
	// In this example we do a check here for ECapability_None (which always passes)...
	if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by zerocopy loopback")))
		return KErrPermissionDenied;

	// Check version
	if (!Kern::QueryVersionSupported(RZeroCopyLoopbackDriver::VersionRequired(),aVer))
		return KErrNotSupported;

	// Setup LDD for receiving client messages
	SetDfcQ(((DZeroCopyLoopbackPddFactory*)iPhysicalDevice)->iDfcQ);
	iMsgQ.Receive();

	// Associate DFCs with the same queue we set above to receive client messages on
	iSendDataDfc.SetDfcQ(iDfcQ);
	iReceiveDataDfc.SetDfcQ(iDfcQ);

	iPond = DCommsPond::New();
	if(!iPond)
		{
		return KErrNoMemory;
		}
	
	// Give PDD a pointer to this channel
	Pdd()->iLdd = this;

	// Done
	return KErrNone;
	}
Example #23
0
/**
 Set the internal loopback mode of the device (Uart). This is device specific API,
 that provides functionality to configure the uart's internal loopback mode, as
 set by the user.User calls this by using RBusLogicalChannel::DoControl() with
 appropriate request number

 @param		aMode
			Holds the loopback enable and disable option
			KLoopbackEnable for enable and KLoopbackDisable for disable

 @return	KErrNone or system wide standard error code
 
 */
 TInt DExDriverLogicalChannel::SetIntLoopback(const TInt* aMode)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::SetIntLoopback"));

 	TInt r;
	TInt mode;
	
	
	// Read the user option from user thread, iClient using
	// kernel API, Kern::ThreadRawRead to copy aMode to mode.
	// Kern::ThreadRawData() reads the data from user thread
	// to the kernel thread.
	// 
	// In user context kumemget() and kumemput() API have to be used to copy
	// the data. However, these API cannot be called in critical section with
	// DMutex held. Hence, Kern::ThreadXXX API are being used
	// 
	r = Kern::ThreadRawRead(iClient,aMode,&mode,sizeof(TInt));
	if (r==KErrNone)
		{
		// Check if the mode requested to set is valid. It can
		// only be either enable or disable.
		//
		if ((mode==KLoopbackEnable)||(mode==KLoopbackDisable))
			{
 			// Invoke PDD function to actually do the hardware
			// specific configuration on the device. Here the
			// buffer pointer can be passed and accessd directly
			// as both LDD and PDD are in kernel space.
			//
			Pdd()->SetIntLoopback(mode);
			}
		else
			return KErrArgument;
		}
	
	// return the result
	return r;
 	}
Example #24
0
/**
 Get the channel capabilities of UART. This function reads the channels
 capabilities from the Platform Specific Layer (PSL). User uses this info
 to configure the channel as per supported capabilties.

 @param		aCaps
 			Buffer to read the channel capabilities
 @return	KErrNone on success or system wide error code on failure of
 			data copy to user
 */
 TInt DExDriverLogicalChannel::Caps(TDes8* aCaps)
 	{
 	TInt r;
	
	
 	//  Package buffer for TCommCapsV03
 	TCommCaps3 caps;

 	// Call the PSL capabilities function
	Pdd()->Caps(caps);

	// Write the descriptor to user thread, iClient using
	// kernel API, Kern::ThreadDesWrite to copy caps to aCaps.
	// 
	// In user context kumemget() and kumemput() API have to be used to copy
	// the data. However, these API cannot be called in critical section with
	// DMutex held. Hence, Kern::ThreadXXX API are being used
	// 
    r=Kern::ThreadDesWrite(iClient,aCaps,caps,0);    	
    
    
	return r;
 	}
Example #25
0
/**
  Start processing a SendData request.
*/
TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData)
	{
	// Check that a 'SendData' isn't already in progress
	if(iSendDataStatus)
		{
		Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
		return KErrInUse;
		}

	// Read data from client into our buffer
	TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0);
	if(r!=KErrNone)
		return r;

	// Give data to PDD so that it can do the work
	r=Pdd()->SendData(iSendDataBuffer);
	if(r!=KErrNone)
		return r;

	// Save the client request status and return
	iSendDataStatus = aStatus;
	return KErrNone;
	}
Example #26
0
/**
	LDD second stage constructor
*/
TInt DDisplayLdd::DoCreate(TInt aUnit, const TDesC8* /* anInfo*/, const TVersion& aVer)
	{ 
	
	__DEBUG_PRINT("DDisplayLdd::DoCreate()\n"); 

	if(    !Kern::CurrentThreadHasCapability(ECapabilityPowerMgmt,      __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
		|| !Kern::CurrentThreadHasCapability(ECapabilityReadDeviceData, __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
		|| !Kern::CurrentThreadHasCapability(ECapabilityWriteDeviceData,__PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") )
		|| !Kern::CurrentThreadHasCapability(ECapabilityProtServ,       __PLATSEC_DIAGNOSTIC_STRING("Checked by DISPLAY.LDD (GCE Driver)") ) )
		{
		return KErrPermissionDenied;
		}
		  
	// Check that the display driver version specified by the client is compatible.
	if (!Kern::QueryVersionSupported(RDisplayChannel::VersionRequired(),aVer))
		{
		return(KErrNotSupported);		
		}
				
	// Check that a channel hasn't already been opened on this unit.
	TInt r=((DDisplayLddFactory*)iDevice)->SetUnitOpen(aUnit,ETrue); // Try to update 'units open mask' in the LDD factory.
	if (r!=KErrNone)
		return r;
	iUnit=aUnit;

 	Pdd()->iLdd	= this;
 	
 	r		= Pdd()->CreateChannelSetup(aUnit); 	
 	if ( r!= KErrNone)
 		{
 		return r; 		
 		}
 
     // set up user buffer nodes
    for (TInt node = 0; node < KDisplayUBMax; node++)
    	{
        iUserBuffer[node].iType 	= EBufferTypeUser;
        iUserBuffer[node].iBufferId = (node + 1);
        iUserBuffer[node].iFree 	= ETrue;
        iUserBuffer[node].iState 	= EBufferFree;
        iUserBuffer[node].iAddress  = 0;
        iUserBuffer[node].iSize  	= 0;
        iUserBuffer[node].iHandle  	= 0;
        iUserBuffer[node].iChunk  	= 0;
        iUserBuffer[node].iOffset 	= 0;
        iUserBuffer[node].iPendingRequest = 0;
    	}

    //Initialise pending queue for asynchronous requests and queue of TClientRequests
    for(TInt k = 0; k < KPendingReqArraySize; k++) 
    	{
    	
    	iPendingIndex[k]=0;
    	
		for(TInt i = 0; i < KMaxQueuedRequests; i++)
			{
			iPendingReq[k][i].iTClientReq   = 0;
			iPendingReq[k][i].iOwningThread = 0;
			
			
			r = Kern::CreateClientRequest(iClientRequest[k][i]);
			if (r != KErrNone)
				{
				return r;      	
				}
			}	
    	} 
    
    r = Kern::MutexCreate(iClientRequestMutex, KClientRequestMutex, KMutexOrder);	
	if (r != KErrNone)
		{
		return r;
		}	
    
          
    Pdd()->SetGceMode();	
	SetDfcQ(Pdd()->DfcQ(aUnit));	   
    iMsgQ.Receive();
    
    return KErrNone;		
}
Example #27
0
/** 
 Handle Asynchronous Requests. This is called from Request() to process
 asynchrounous requests. It is responsible for setting up the hardware to create
 an event that will complete the request at some point in future. Multiple 
 outstanding asynchronous requests can be handled and is implementation specific.
 
 @param 	aReqNo
 		  	Asynchronous Request number
 @param 	aStatus
 			TRequestStatus (32-bit length) object allocated on user stack. This
 			provides the request status to the client
 @param 	a1
 			parameter1 passed by user for the request
 @param 	a2
 			parameter2 passed by user for the request	
 @return	KErrNone or standard error code
 */	
TInt DExDriverLogicalChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
	{
	TInt r=KErrNone;
	
	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::DoRequest"));
	
	switch(aReqNo)
		{
		// User request to transmit data to the device (uart)		
		//	
		case RExDriverChannel::ERequestTransmitData:				
			// Check if there is another Tx request pending and we received
			// another Tx request, then reject the request and return busy.
			//
			if (iTxDataStatus)
				{
				// return busy
				return KErrInUse;	
				}	

				// The status of transmit request status is stored to use while
				// notifying the completion of the request at a later point.
				//
				iTxDataStatus = aStatus;
				iTxInitialOffset = (TInt ) a1;
				
				if (iTxInitialOffset>=Pdd()->iTxChunk->iSize)
					{
					return KErrOverflow;
					}
				
				// Call TransmitData function, with offset 0
				r = TransmitData((TUint)a1,(TInt)a2);				
			break;
		// User request to receive data from the device (uart)		
		//
		case RExDriverChannel::ERequestReceiveData:						
			// Check if there is another Rx request pending and we received
			// another Rx request, then reject the request and return busy.
			//
			if (iRxDataStatus)
				{
				// return busy
				return KErrInUse;
				}

			// The status of receive request status is stored to use while
			// notifying the completion of the request at a later point.
			//
			iRxDataStatus = aStatus;
			iBytesRxed = (TUint)a2;
			iRxOffset = (TUint)a1;
			iRxInitialOffset = iRxOffset;
			
			if (iRxOffset >= Pdd()->iRxChunk->iSize)
				{
				return KErrOverflow;
				}
			// Call receive data function											
			ReceiveData((TUint)a1,iBytesRxed);
			break;
		default:
			// Unknown request and therefore not supported
			//
			r=KErrNotSupported;
		}
			
	// returns KErrNone or standard error code as returned by API used above
	//
	return r;
	}
Example #28
0
/**
 Transmit the data over the serial port.Transmit data is passed
 as buffer descriptor to this function by user. User calls this
 by using RBusLogicalChannel::DoControl() to LDD and ldd inturn
 calls the PDD function to do the actual transmission to the
 device.

 @param		aData
 			Transmit buffer descriptor
 @return	KErrNone on success
 			KErrAbort on invalid length
 			or any other system wide error code
 */
 TInt DExDriverLogicalChannel::TransmitData(const TDesC8* aData)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::TransmitData"));

 	TInt r;
 	TInt maxlength,size;

  	// Reset offset for every Tx
  	iTxOffset=0;
  	
  
  	// In case of zero length buffer or invalid length, abort the request.
  	//
  	Kern::KUDesInfo(*aData,iBytesTxed,maxlength);
  	if (iBytesTxed<=0)
  		{
  		WaitOnTxFMutex();
  		iTxProgress = EFalse;
  		SignalTxFMutex();
   		return KErrAbort;	
  		}

	// Transmit data 1 frame (256 bytes) at a time.
	// Loop around till the complete User data is transferred.
	//
	do 
	{
			
 	// Copy the data ptr to intermediate ptr. 
 	//
 	iTxData=(TAny*)aData;

 	// Transmit the data to device/PDD in blocks of LDD buffer length (256).
 	// Loop around untill the complete data is transferred.
 	//
  	size=(iBytesTxed<KTxBufferSize)?iBytesTxed:KTxBufferSize;
 	
 	// Clear the buffer to zero using the nanokernel
	// utility function, memclr()
	//
	memclr(iTxBuffer, KTxBufferSize);

	// Constructs 8-bit modifiable pointer descriptor, with
	// length 0 and max length, size
	//
 	TPtr8 txbuf(iTxBuffer,0,size);

 	// Copy the descriptor from user into LDD buffer.
 	// aData->Ptr()+iTxOffset will give the pointer to the next frame to be
 	// transferred. And size is the number bytes to be copied.
 	//
 	txbuf.SetLength(size);

	kumemget(iTxBuffer,(TAny *)((aData->Ptr()) + iTxOffset),size);
				
	// Invoke PDD function to actually do the hardware specific
	// operation on the device. Here the buffer pointer can be
	// accessed directly as both LDD and PDD are in kernel space.
	//
	r = Pdd()->TransmitData(txbuf);
	
	// iBytesTxed keeps track of how many bytes transferred till now.
	iBytesTxed = iBytesTxed - size;
	// iTxOffset will give the next data frame offset.
	iTxOffset = iTxOffset + size;
		
 	} while (iBytesTxed>0);
 	
	WaitOnTxFMutex();
  	iTxProgress = EFalse;
  	SignalTxFMutex();
  	  	
	return r;
 	}
Example #29
0
/**
 Configure the hardware device (Uart). This is device specific API, that
 provides functionality to configure the uart. Uart configuration settings are
 passed to this function by user. User calls this by using
 RBusLogicalChannel::DoControl() with appropriate request number

 @param		aConfig
 			configuration settings for the device
 @return	KErrNone or system wide standard error code
 */
 TInt DExDriverLogicalChannel::SetConfig(const TDesC8* aConfig)
 	{
 	KEXDEBUG(Kern::Printf("++DExDriverLogicalChannel::SetConfig"));

 	TInt r;

 	// TCommConfigV01 structure defined in d32comm.h is used
 	// to hold the configuration details like baudrate, parity,
 	// databits etc for serial
 	//
	TCommConfigV01 config;
	// Set the bytes to zero using the nanokernel
	// utility function, memclr()
	//
	memclr(&config, sizeof(config));

	// Constructs 8-bit modifiable pointer descriptor, with
	// length 0 and max length, sizeof(config)
	//
	TPtr8 cfg((TUint8*)&config, 0, sizeof(config));

	// Read the descriptor.
	//
	Kern::KUDesGet(cfg , *aConfig);
	
 	// See the Rx and Tx Status.
	// Anything in progress then do not allow setting configurations.
	WaitOnConfigDMutex();
	
	WaitOnRxFMutex();
	if (iRxProgress)
		{
		SignalRxFMutex();
		SignalConfigDMutex();
		return KErrInUse;
		}
	iRxProgress = ETrue;
	SignalRxFMutex();
	
	WaitOnTxFMutex();
	if (iTxProgress)
		{
		SignalTxFMutex();
		SignalConfigDMutex();
		return KErrInUse;
		}
	iTxProgress = ETrue;
	SignalTxFMutex();
		
 		
	// Invoke PDD function to actually do the hardware
	// specific configuration on the device. Here the
	// buffer pointer can be passed and accessed directly
	// as both LDD and PDD are in kernel space.
	//
	r = Pdd()->Configure(config);
		
	WaitOnRxFMutex();
	iRxProgress = EFalse;
	SignalRxFMutex();
	
	WaitOnTxFMutex();
	iTxProgress = EFalse;
	SignalTxFMutex();
	
	SignalConfigDMutex();	
	// return the result
	//
	return r;
 	}
Example #30
0
/**
 Logical Channel - DoCreate(), called by framework after creating logical
 channel object as a part of the driver loading process. Driver should do
 the required validation like capabilities check, version check etc. It
 associates the DFC queue which it shall use to queue the requests. It
 can do any required driver level initializations here.
   
 @param	aUnit
 		device unit number
 @param anInfo
 		device related information
 @param aVer
 		version number
 @return	KErrNone or standard error code
 */
TInt DExDriverLogicalChannel::DoCreate(TInt aUnit,
										const TDesC8* /*anInfo*/,
										const TVersion& aVer)
	{


	// Not using anInfo, so anInfo is commented in function arguments.
	// It can also be made void it to avoid compilation warnings by doing
	// (void)anInfo;
	//
	// As a part of platform security guidelines, every driver needs to
	// enusure capability check. This check is to ensure that the client
	// accessing the driver has the required level of trust to perform any
	// operations on the device. Any client that does not have required
	// capability as expected by the driver is returned with no permission
	// error.Kernel API Kern::CurrentThreadHasCapability(),checks if the
	// current thread has the required capability (arg1) and displays the
	// diagnostic string in case of failure.
	//
	// Check if the client has level of trust to do serial comm related
	// operations.
	if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD,
				__PLATSEC_DIAGNOSTIC_STRING("Checked by Tutorial Driver")))
		return KErrPermissionDenied;

	// Check if driver version matches with the version client is trying
	// to use. Kernel API, Kern::QueryVersionSupported() verifies if the
	// versions match, returns true if test version is less than current
	// version (arg2<arg1).
	//
	if (!Kern::QueryVersionSupported(iDevice->iVersion,aVer))
		return KErrNotSupported;
	

	// Store the LDD object pointer in PDD. This will enable PDD to access
	// and call the LDD member functions easily. In case of callbacks to
	// LDD, PDD can use this pointer.
	//
	Pdd()->iLdd=this;
	// Logical channel based driver has a DFC created for itself. A dedicated
	// DFC can be created for the driver, instead of using default kernel DFC
	// thread 0. PDD implements DFCQ function and returns the DFCQ created
	// by PDD. All synchronous and asynchronous messages and events for this 
	// driver will be queued to this queue.
	// 
	// Here, LDD leaves it to PDD to associate a context,(dfcq+kernel thread)
	// with a hardware unit, so that requests on different channels (units)
	// execute in different contexts.
	//
	// SetDfcQ() initializes the message queue used by LDD with the 
	// DFC(TDynamicDfcQue object) returned by Pdd()->DfcQ().
	//
	SetDfcQ(Pdd()->DfcQ(aUnit));
        
	// Set the message queue to start receiving the messages.
	// TMessageQue::Receive() will request driver to receive next message
	// (sent by client) in the queue. It makes the queue as ready and also 
	// activates the DFC when the message is present in queue.
	//
    iMsgQ.Receive();
    
    Pdd()->SetChannelOpened(aUnit);
	// return no error
	//
    return KErrNone;
	}