/** 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(); } }
/** 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(); }
/** 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; }
/** 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; }
/** 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; } }
/** @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; } }
/** 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; }
/** 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; }
/** 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); } }
/** 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; }
/** 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; }
/** 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); } }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }
/** 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; }