--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/acm/classimplementation/ecacm/src/AcmReader.cpp Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,870 @@
+/*
+* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+#include <cs_port.h>
+#include "AcmReader.h"
+#include "AcmUtils.h"
+#include "ActiveReader.h"
+#include "ActiveReadOneOrMoreReader.h"
+#include "CdcAcmClass.h"
+#include "AcmPanic.h"
+#include "AcmPort.h"
+#include <usb/usblogger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "ECACM");
+#endif
+
+CAcmReader* CAcmReader::NewL(CAcmPort& aPort,
+ TUint aBufSize)
+/**
+ * Factory function.
+ *
+ * @param aPort The CAcmPort parent.
+ * @param aBufSize The size of the buffer.
+ * @return Ownership of a new CAcmReader.
+ */
+ {
+ LOG_STATIC_FUNC_ENTRY
+
+ CAcmReader* self = new(ELeave) CAcmReader(aPort, aBufSize);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CLEANUPSTACK_POP(self);
+ return self;
+ }
+
+CAcmReader::~CAcmReader()
+/**
+ * Destructor.
+ */
+ {
+ LOG_FUNC
+
+ ReadCancel();
+
+ delete iBuffer;
+ }
+
+CAcmReader::CAcmReader(CAcmPort& aPort,
+ TUint aBufSize)
+/**
+ * Constructor.
+ *
+ * @param aPort The CPort parent.
+ * @param aBufSize The size of the buffer.
+ */
+ : iBufSize(aBufSize),
+ iInBuf(NULL,0,0),
+ iPort(aPort)
+ {
+ }
+
+void CAcmReader::ConstructL()
+/**
+ * 2nd-phase construction.
+ */
+ {
+ // Create iBuffer.
+ LOGTEXT(_L8("\tabout to create iBuffer"));
+ LEAVEIFERRORL(SetBufSize(iBufSize));
+ }
+
+void CAcmReader::Read(const TAny* aClientBuffer, TUint aMaxLen)
+/**
+ * Read API.
+ *
+ * @param aClientBuffer Pointer to the client's memory space.
+ * @param aMaxLen Maximum length to read.
+ */
+ {
+ LOG_FUNC
+ LOGTEXT3(_L8("\taClientBuffer=0x%08x, aMaxLen=%d"),
+ aClientBuffer, aMaxLen);
+
+ // Check we're open to requests and make a note of interesting data.
+ // including iLengthToGo
+ CheckNewRequest(aClientBuffer, aMaxLen);
+ iCurrentRequest.iRequestType = ERead;
+
+ // A read larger than our internal buffer limit will result in us doing
+ // multiple reads to the ports below.
+ // We used to just refuse the request with a KErrNoMemory.
+ if ( iTerminatorCount == 0 )
+ {
+ ReadWithoutTerminators();
+ }
+ else
+ {
+ ReadWithTerminators();
+ }
+ }
+
+void CAcmReader::ReadWithoutTerminators()
+/**
+ * Process a read request given that no terminator characters are set.
+ */
+ {
+ LOG_FUNC
+
+ // Can we complete immediately from the buffer?
+ const TUint bufLen = BufLen();
+ LOGTEXT2(_L8("\thave %d bytes in buffer"), bufLen);
+ LOGTEXT2(_L8("\tLength to go is %d bytes"), iLengthToGo);
+ if ( iLengthToGo <= bufLen )
+ {
+ LOGTEXT2(_L8("\tcompleting request immediately from buffer with %d "
+ "bytes"), iLengthToGo);
+ WriteBackData(iLengthToGo);
+ CompleteRequest(KErrNone);
+ return;
+ }
+
+ // There isn't enough in the buffer to complete the request, so we write
+ // back as much as we have, and issue a Read for more.
+ if ( bufLen )
+ {
+ LOGTEXT2(_L8("\twriting back %d bytes"), bufLen);
+ // Write back as much data as we've got already.
+ WriteBackData(bufLen);
+ }
+
+ // Issue a read for the data we still need.
+ LOGTEXT2(_L8("\tRequesting read - require %d bytes"),iLengthToGo);
+ IssueRead();
+ }
+
+void CAcmReader::ReadWithTerminators()
+/**
+ * Process a read request given that terminator characters are set.
+ */
+ {
+ LOG_FUNC
+
+ // Can we complete immediately from the buffer? Search the buffer we have
+ // for any terminators. If found, complete back to the client. If not
+ // found, start issuing ReadOneOrMores until we either find one or run out
+ // of client buffer.
+
+ const TUint bufLen = BufLen();
+ LOGTEXT2(_L8("\tbufLen = %d"), bufLen);
+ if ( bufLen )
+ {
+ CheckForBufferedTerminatorsAndProceed();
+ return;
+ }
+
+ // There's no buffered data. Get some.
+ IssueReadOneOrMore();
+ }
+
+void CAcmReader::ReadOneOrMore(const TAny* aClientBuffer, TUint aMaxLen)
+/**
+ * ReadOneOrMore API. Note that this is implemented to completely ignore
+ * terminator characters.
+ *
+ * @param aClientBuffer Pointer to the client's memory space.
+ * @param aMaxLen Maximum length to read.
+ */
+ {
+ LOG_FUNC
+ LOGTEXT3(_L8("\taClientBuffer=0x%08x, aMaxLen=%d"),
+ aClientBuffer, aMaxLen);
+
+ // Check we're open to requests and make a note of interesting data.
+ CheckNewRequest(aClientBuffer, aMaxLen);
+
+ iCurrentRequest.iRequestType = EReadOneOrMore;
+
+ // Check to see if there's anything in our buffer- if there is, we can
+ // complete immediately.
+ const TUint bufLen = BufLen();
+ LOGTEXT2(_L8("\tbufLen = %d"), bufLen);
+ if ( bufLen )
+ {
+ // Complete request with what's in the buffer
+ LOGTEXT2(_L8("\tcompleting request immediately from buffer with %d "
+ "bytes"), bufLen);
+ WriteBackData(bufLen);
+ CompleteRequest(KErrNone);
+ return;
+ }
+
+ // Get some more data.
+ IssueReadOneOrMore();
+ }
+
+void CAcmReader::NotifyDataAvailable()
+/**
+ * NotifyDataAvailable API. If a request is pending completes the client with KErrInUse.
+ */
+ {
+ LOG_FUNC
+ if(iCurrentRequest.iClientPtr) // a request is pending
+ {
+ iPort.NotifyDataAvailableCompleted(KErrInUse);
+ return;
+ }
+ iCurrentRequest.iClientPtr = iBuffer;
+ iCurrentRequest.iRequestType = ENotifyDataAvailable;
+ iPort.Acm()->NotifyDataAvailable(*this);
+ }
+
+void CAcmReader::NotifyDataAvailableCancel()
+/**
+ * NotifyDataAvailableCancel API. Issues a ReadCancel() to abort pending requests on the LDD
+ *
+ */
+ {
+ LOG_FUNC
+ if (ENotifyDataAvailable == iCurrentRequest.iRequestType)
+ {
+ // Cancel any outstanding request on the LDD.
+ if (iPort.Acm())
+ {
+ LOGTEXT(_L8("\tiPort.Acm() exists- calling NotifyDataAvailableCancel() on it"));
+ iPort.Acm()->NotifyDataAvailableCancel();
+ }
+ // Reset our flag to say there's no current outstanding request. What's
+ // already in our buffer can stay there.
+ iCurrentRequest.iClientPtr = NULL;
+ }
+ }
+
+void CAcmReader::ReadCancel()
+/**
+ * Cancel API. Cancels any outstanding (Read or ReadOneOrMore) request.
+ */
+ {
+ LOG_FUNC
+
+ if (ENotifyDataAvailable != iCurrentRequest.iRequestType)
+ {
+ // Cancel any outstanding request on the LDD.
+ if (iPort.Acm())
+ {
+ LOGTEXT(_L8("\tiPort.Acm() exists- calling ReadCancel on it"));
+ iPort.Acm()->ReadCancel();
+ }
+
+ // Reset our flag to say there's no current outstanding request. What's
+ // already in our buffer can stay there.
+ iCurrentRequest.iClientPtr = NULL;
+ }
+ }
+
+TUint CAcmReader::BufLen() const
+/**
+ * This function returns the amount of data (in bytes) still remaining in the
+ * circular buffer.
+ *
+ * @return Length of data in buffer.
+ */
+ {
+ LOGTEXT(_L8(">>CAcmReader::BufLen"));
+
+ TUint len = 0;
+ if ( BufWrap() )
+ {
+ LOGTEXT(_L8("\tbuf wrapped"));
+ len = iBufSize - ( iOutPtr - iInPtr );
+ }
+ else
+ {
+ LOGTEXT(_L8("\tbuf not wrapped"));
+ len = iInPtr - iOutPtr;
+ }
+
+ LOGTEXT2(_L8("<<CAcmReader::BufLen len=%d"), len);
+ return len;
+ }
+
+void CAcmReader::ResetBuffer()
+/**
+ * Called by the port to clear the buffer.
+ */
+ {
+ LOG_FUNC
+
+ // A request is outstanding- C32 should protect against this.
+ __ASSERT_DEBUG(!iCurrentRequest.iClientPtr,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // Reset the pointers. All data is 'lost'.
+ iOutPtr = iInPtr = iBufStart;
+ }
+
+TInt CAcmReader::SetBufSize(TUint aSize)
+/**
+ * Called by the port to set the buffer size. Also used as a utility by us to
+ * create the buffer at instantiation. Note that this causes what was in the
+ * buffer at the time to be lost.
+ *
+ * @param aSize The required size of the buffer.
+ */
+ {
+ LOG_FUNC
+ LOGTEXT2(_L8("\taSize=%d"), aSize);
+
+ if ( iCurrentRequest.iClientPtr )
+ {
+ // A request is outstanding. C32 does not protect us against this.
+ LOGTEXT(_L8("\t***a request is outstanding- returning KErrInUse"));
+ return KErrInUse;
+ }
+
+ // Create the new buffer.
+ HBufC8* newBuf = HBufC8::New(aSize);
+ if ( !newBuf )
+ {
+ LOGTEXT(_L8("\tfailed to create new buffer- returning KErrNoMemory"));
+ return KErrNoMemory;
+ }
+ delete iBuffer;
+ iBuffer = newBuf;
+
+ // Update pointers etc.
+ TPtr8 ptr = iBuffer->Des();
+ iBufStart = const_cast<TUint8*>(reinterpret_cast<const TUint8*>(ptr.Ptr()));
+ iBufSize = aSize;
+ CheckBufferEmptyAndResetPtrs();
+
+ return KErrNone;
+ }
+
+void CAcmReader::SetTerminators(const TCommConfigV01& aConfig)
+/**
+ * API to change the terminator characters.
+ *
+ * @param aConfig The new configuration.
+ */
+ {
+ LOG_FUNC
+
+ // C32 protects the port against having config set while there's a request
+ // outstanding.
+ __ASSERT_DEBUG(!iCurrentRequest.iClientPtr,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ iTerminatorCount = aConfig.iTerminatorCount;
+ LOGTEXT2(_L8("\tnow %d terminators:"), iTerminatorCount);
+ for ( TUint ii = 0; ii < static_cast<TUint>(KConfigMaxTerminators) ; ii++ )
+ {
+ iTerminator[ii] = aConfig.iTerminator[ii];
+ LOGTEXT2(_L8("\t\t%d"), iTerminator[ii]);
+ }
+ }
+
+void CAcmReader::ReadCompleted(TInt aError)
+/**
+ * Called by lower classes when an LDD Read completes.
+ *
+ * @param aError Error.
+ */
+ {
+ LOGTEXT2(_L8(">>CAcmReader::ReadCompleted aError=%d"), aError);
+
+ const TUint justRead = static_cast<TUint>(iInBuf.Length());
+ LOGTEXT3(_L8("\tiInBuf length=%d, iLengthToGo=%d"),
+ justRead,
+ iLengthToGo);
+
+ // This protects against a regression in the LDD- read requests shouldn't
+ // ever complete with zero bytes and KErrNone.
+ if ( justRead == 0 && aError == KErrNone )
+ {
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError);
+ }
+
+ // The new data will have been added to our buffer. Move iInPtr up by the
+ // length just read.
+ iInPtr += justRead;
+
+ if ( aError )
+ {
+ // If the read failed, we complete back to the client and don't do
+ // anything more. (We don't want to get into retry strategies.) In a
+ // multi-stage Read the client will get any data already written back
+ // to them with IPCWrite.
+ CompleteRequest(aError);
+ return;
+ }
+
+ // calling this will write the data to the clients address space
+ // it will also complete the request if we've given the client enough data
+ // or will reissue another read if not
+ ReadWithoutTerminators();
+
+ LOGTEXT(_L8("<<CAcmReader::ReadCompleted"));
+ }
+
+void CAcmReader::ReadOneOrMoreCompleted(TInt aError)
+/**
+ * Called by lower classes when an LDD ReadOneOrMore completes.
+ *
+ * @param aError Error.
+ */
+ {
+ LOGTEXT2(_L8(">>CAcmReader::ReadOneOrMoreCompleted aError=%d"), aError);
+
+ const TUint justRead = static_cast<TUint>(iInBuf.Length());
+ LOGTEXT2(_L8("\tjustRead = %d"), justRead);
+
+ // The new data will have been added to our buffer. Move iInPtr
+ // up by the length just read.
+ iInPtr += justRead;
+
+ if ( aError )
+ {
+ // If the ReadOneOrMore failed, we complete back to the client and
+ // don't do anything more. The client will get any data already
+ // written back to them with IPCWrite.
+ CompleteRequest(aError);
+ return;
+ }
+
+ // TODO: may the LDD complete ROOM with zero bytes, eg if a ZLP comes in?
+ // NB The LDD is at liberty to complete a ReadPacket request with zero
+ // bytes and KErrNone, if the given packet was zero-length (a ZLP). In
+ // this case, we have to reissue the packet read until we do get some
+ // data.
+ if ( justRead == 0 )
+ {
+ LOGTEXT(_L8("\twe appear to have a ZLP- reissuing ReadOneOrMore"));
+ IssueReadOneOrMore();
+ return;
+ }
+
+ if ( EReadOneOrMore == iCurrentRequest.iRequestType )
+ {
+ // Complete the client's request with as much data as we can. NB
+ // Opinion may be divided over whether to do this, or complete with
+ // just 1 byte. We implement the more generous approach.
+ LOGTEXT2(_L8("\tcurrent request is ReadOneOrMore- completing with "
+ "%d bytes"), justRead);
+ WriteBackData(justRead);
+ CompleteRequest(KErrNone);
+ }
+ else
+ {
+ // Outstanding request is a Read with terminators. (Except for
+ // ReadOneOrMore, we only request LDD::ReadOneOrMore in this case.)
+
+ // Process the buffer for terminators.
+ LOGTEXT(_L8("\tcurrent request is Read with terminators"));
+ CheckForBufferedTerminatorsAndProceed();
+ }
+
+ LOGTEXT(_L8("<<CAcmReader::ReadOneOrMoreCompleted"));
+ }
+
+void CAcmReader::NotifyDataAvailableCompleted(TInt aError)
+ {
+/**
+ * Called by lower classes when data has arrived at the LDD after a
+ * NotifyDataAvailable request has been posted on the port.
+ *
+ * @param aError Error.
+ */
+ LOGTEXT2(_L8(">>CAcmReader::NotifyDataAvailableCompleted aError=%d"), aError);
+
+ // If the NotifyDataAvailable request failed, we complete back
+ // to the client and don't do anything more.
+ CompleteRequest(aError);
+
+ LOGTEXT(_L8("<<CAcmReader::NotifyDataAvailableCompleted"));
+ }
+
+void CAcmReader::CheckBufferEmptyAndResetPtrs()
+/**
+ * Utility to assert that the buffer is empty and to reset the read and write
+ * pointers to the beginning of the buffer. We reset them there to cut down on
+ * fiddling around wrapping at the end of the buffer.
+ */
+ {
+ LOGTEXT(_L8("CAcmReader::CheckBufferEmptyAndResetPtrs"));
+
+ if ( BufLen() != 0 )
+ {
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError);
+ }
+
+ iOutPtr = iInPtr = iBufStart;
+ }
+
+void CAcmReader::CheckNewRequest(const TAny* aClientBuffer, TUint aMaxLen)
+/**
+ * Utility function to check a Read or ReadOneOrMore request from the port.
+ * Also checks that there isn't a request already outstanding. Makes a note of
+ * the relevant parameters and sets up internal counters.
+ *
+ * @param aClientBuffer Pointer to the client's memory space.
+ * @param aMaxLen Maximum length to read.
+ */
+ {
+ // The port should handle zero-length reads, not us.
+ __ASSERT_DEBUG(aMaxLen > 0, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(aMaxLen <= static_cast<TUint>(KMaxTInt),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // Check we have no outstanding request already.
+ if ( iCurrentRequest.iClientPtr )// just panic in case of concurrent Read or ReadOneOrMore queries.
+ { // in case of NotifyDataAvailable queries, we already have completed the client with KErrInUse.
+ // This code is kept for legacy purpose. That justifies the existence of IsNotifyDataAvailableQueryPending
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError);
+ }
+ // Sanity check on what C32 gave us.
+ __ASSERT_DEBUG(aClientBuffer,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // Make a note of interesting data.
+ iCurrentRequest.iClientPtr = aClientBuffer;
+ iLengthToGo = aMaxLen;
+ iOffsetIntoClientsMemory = 0;
+ }
+
+void CAcmReader::CheckForBufferedTerminatorsAndProceed()
+/**
+ * Checks for terminator characters in the buffer. Completes the client's
+ * request if possible, and issues further ReadOneOrMores for the appropriate
+ * amount if not.
+ */
+ {
+ LOG_FUNC
+
+ TInt ret = FindTerminator();
+ LOGTEXT2(_L8("\tFindTerminator = %d"), ret);
+ if ( ret < KErrNone )
+ {
+ LOGTEXT(_L8("\tno terminator found"));
+ const TUint bufLen = BufLen();
+ LOGTEXT2(_L8("\tbufLen = %d"), bufLen);
+ // No terminator was found. Does the buffer already exceed the
+ // client's descriptor?
+ if ( bufLen >= iLengthToGo )
+ {
+ // Yes- complete as much data to the client as their
+ // descriptor can handle.
+ LOGTEXT2(_L8("\tbuffer >= client descriptor- "
+ "writing back %d bytes"), iLengthToGo);
+ WriteBackData(iLengthToGo);
+ CompleteRequest(KErrNone);
+ }
+ else
+ {
+ // No- write back the data we've got and issue a request to get
+ // some more data.
+ WriteBackData(bufLen);
+ IssueReadOneOrMore();
+ }
+ }
+ else
+ {
+ LOGTEXT(_L8("\tterminator found!"));
+ // Will the terminator position fit within the client's descriptor?
+ if ( static_cast<TUint>(ret) <= iLengthToGo )
+ {
+ // Yes- complete (up to the terminator) back to the client.
+ LOGTEXT2(_L8("\tterminator will fit in client's descriptor- "
+ "writing back %d bytes"), ret);
+ WriteBackData(static_cast<TUint>(ret));
+ CompleteRequest(KErrNone);
+ }
+ else
+ {
+ // No- complete as much data to the client as their descriptor can
+ // handle.
+ LOGTEXT2(_L8("\tterminator won't fit in client's descriptor- "
+ "writing back %d bytes"), iLengthToGo);
+ WriteBackData(iLengthToGo);
+ CompleteRequest(KErrNone);
+ }
+ }
+ }
+
+void CAcmReader::WriteBackData(TUint aLength)
+/**
+ * This function writes back data to the client address space. The write will
+ * be performed in one go if the data to be written back is not wrapped across
+ * the end of the circular buffer. If the data is wrapped, the write is done
+ * in two stages. The read pointer is updated to reflect the data consumed, as
+ * is the counter for remaining data required by the client (iLengthToGo), and
+ * the pointer into the client's memory (iOffsetIntoClientsMemory).
+ *
+ * @param aLength Amount of data to write back.
+ */
+ {
+ LOGTEXT2(_L8("CAcmReader::WriteBackData aLength = %d"), aLength);
+ LOGTEXT2(_L8("\tBufLen() = %d"), BufLen());
+
+ LOGTEXT2(_L8("\tBufLen() = %d"), BufLen());
+
+ __ASSERT_DEBUG(aLength <= BufLen(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ const TUint lenBeforeWrap = iBufStart + iBufSize - iOutPtr;
+
+ LOGTEXT2(_L8("\tiOutPtr=%d"), iOutPtr - iBufStart);
+ LOGTEXT2(_L8("\tiInPtr=%d"), iInPtr - iBufStart);
+ LOGTEXT2(_L8("\tiOffsetIntoClientsMemory=%d"), iOffsetIntoClientsMemory);
+ LOGTEXT2(_L8("\tlenBeforeWrap=%d"), lenBeforeWrap);
+
+ if ( aLength > lenBeforeWrap )
+ {
+ // We'll have to do this in two stages...
+ LOGTEXT(_L8("\twriting back in two stages"));
+
+ __ASSERT_DEBUG(BufWrap(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // Stage 1...
+ TPtrC8 ptrBeforeWrap(iOutPtr, lenBeforeWrap);
+ TInt err = iPort.IPCWrite(iCurrentRequest.iClientPtr,
+ ptrBeforeWrap,
+ iOffsetIntoClientsMemory);
+ LOGTEXT2(_L8("\tIPCWrite = %d"), err);
+ __ASSERT_DEBUG(!err, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ static_cast<void>(err);
+ iOffsetIntoClientsMemory += lenBeforeWrap;
+
+ // Stage 2...
+ TInt seg2Len = aLength - lenBeforeWrap;
+ TPtrC8 ptrAfterWrap(iBufStart, seg2Len);
+ err = iPort.IPCWrite(iCurrentRequest.iClientPtr,
+ ptrAfterWrap,
+ iOffsetIntoClientsMemory);
+ LOGTEXT2(_L8("\tIPCWrite = %d"), err);
+ __ASSERT_DEBUG(!err, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iOffsetIntoClientsMemory += seg2Len;
+
+ // and set the pointers to show that we've consumed the data...
+ iOutPtr = iBufStart + seg2Len;
+ LOGTEXT(_L8("\twrite in two segments completed"));
+ }
+ else // We can do it in one go...
+ {
+ LOGTEXT(_L8("\twriting in one segment"));
+
+ TPtrC8 ptr(iOutPtr, aLength);
+ TInt err = iPort.IPCWrite(iCurrentRequest.iClientPtr,
+ ptr,
+ iOffsetIntoClientsMemory);
+ LOGTEXT2(_L8("\tIPCWrite = %d"), err);
+ __ASSERT_DEBUG(!err, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ static_cast<void>(err);
+ iOffsetIntoClientsMemory += aLength;
+
+ // Set the pointers to show that we've consumed the data...
+ iOutPtr += aLength;
+ LOGTEXT(_L8("\twrite in one segment completed"));
+ }
+
+ LOGTEXT2(_L8("\tiOutPtr=%d"), iOutPtr - iBufStart);
+ LOGTEXT2(_L8("\tiOffsetIntoClientsMemory=%d"), iOffsetIntoClientsMemory);
+
+ // Adjust iLengthToGo
+ __ASSERT_DEBUG(iLengthToGo >= aLength,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iLengthToGo -= aLength;
+ }
+
+void CAcmReader::CompleteRequest(TInt aError)
+/**
+ * Utility to reset our 'outstanding request' flag and complete the client's
+ * request back to them. Does not actually write back data to the client's
+ * address space.
+ *
+ * @param aError The error code to complete with.
+ */
+ {
+ LOGTEXT2(_L8("CAcmReader::CompleteRequest aError=%d"), aError);
+
+ // Set our flag to say that we no longer have an outstanding request.
+ iCurrentRequest.iClientPtr = NULL;
+
+ if(ENotifyDataAvailable==iCurrentRequest.iRequestType)
+ {
+ LOGTEXT2(_L8("\tcalling NotifyDataAvailableCompleted with error %d"), aError);
+ iPort.NotifyDataAvailableCompleted(aError);
+ }
+ else // read and readoneormore
+ {
+ LOGTEXT2(_L8("\tcalling ReadCompleted with error %d"), aError);
+ iPort.ReadCompleted(aError);
+ }
+ }
+
+void CAcmReader::IssueRead()
+/**
+ * Issues a read request for N bytes, where N is the minimum of iLengthToGo,
+ * the LDD's limit on Read requests, and how far we are from the end of our
+ * buffer. Used when trying to satisfy an RComm Read without terminators.
+ * We enforce that the buffer is empty, so we don't have to worry about the
+ * buffer being wrapped and the consequent risk of overwriting.
+ */
+ {
+ LOG_FUNC
+
+ CheckBufferEmptyAndResetPtrs();
+
+ LOGTEXT2(_L8("\tiBufSize = %d"), iBufSize);
+ LOGTEXT2(_L8("\tiInPtr = %d"), iInPtr - iBufStart);
+
+ const TUint lenBeforeWrap = iBufStart + iBufSize - iInPtr;
+
+ LOGTEXT2(_L8("\tiLengthToGo = %d"), iLengthToGo);
+ LOGTEXT2(_L8("\tlenBeforeWrap = %d"), lenBeforeWrap);
+
+ const TUint limit = Min(static_cast<TInt>(iLengthToGo),
+ static_cast<TInt>(lenBeforeWrap));
+ LOGTEXT2(_L8("\tissuing read for %d bytes"), limit);
+ iInBuf.Set(iInPtr, 0, limit);
+ __ASSERT_DEBUG(iPort.Acm(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iPort.Acm()->Read(*this, iInBuf, limit);
+ }
+
+void CAcmReader::IssueReadOneOrMore()
+/**
+ * Issues a read request for N bytes, where N is the minimum of iLengthToGo,
+ * and how far we are from the end of our buffer. Used when trying to satisfy
+ * an RComm ReadOneOrMore.
+ * We enforce that the buffer is empty, so we don't have to worry about the
+ * buffer being wrapped and the consequent risk of overwriting.
+ */
+ {
+ LOG_FUNC
+
+ CheckBufferEmptyAndResetPtrs();
+
+ LOGTEXT2(_L8("\tiBufSize = %d"), iBufSize);
+ LOGTEXT2(_L8("\tiInPtr = %d"), iInPtr - iBufStart);
+
+ const TUint lenBeforeWrap = iBufStart + iBufSize - iInPtr;
+
+ LOGTEXT2(_L8("\tiLengthToGo = %d"), iLengthToGo);
+ LOGTEXT2(_L8("\tlenBeforeWrap = %d"), lenBeforeWrap);
+
+ const TUint limit1 = Min(static_cast<TInt>(lenBeforeWrap), iLengthToGo);
+
+ LOGTEXT2(_L8("\tissuing read one or more for %d bytes"), limit1);
+ iInBuf.Set(iInPtr, 0, limit1);
+ __ASSERT_DEBUG(iPort.Acm(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iPort.Acm()->ReadOneOrMore(*this, iInBuf, limit1);
+ }
+
+TInt CAcmReader::FindTerminator() const
+/**
+ * This function searches the circular buffer for one of a number of
+ * termination characters.
+ * The search is conducted between the read and write pointers. The function
+ * copes with the wrapping of the buffer.
+ *
+ * @return If positive: the number of bytes between where iOutPtr is pointing
+ * at and where the terminator was found inclusive. Takes wrapping into
+ * account. If negative: error.
+ */
+ {
+ LOGTEXT(_L8(">>CAcmReader::FindTerminator"));
+
+ TInt pos = 0;
+ TInt ret = KErrNone;
+ if ( !BufWrap() )
+ {
+ ret = PartialFindTerminator(iOutPtr, iInPtr, pos);
+ if ( !ret )
+ {
+ // Buffer wasn't wrapped, terminator found.
+ ret = pos;
+ }
+ }
+ else
+ {
+ ret = PartialFindTerminator(iOutPtr, iBufStart+iBufSize, pos);
+ if ( !ret )
+ {
+ // Buffer was wrapped, but terminator was found in the section
+ // before the wrap.
+ ret = pos;
+ }
+ else
+ {
+ ret = PartialFindTerminator(iBufStart, iInPtr, pos);
+ if ( !ret )
+ {
+ // Buffer was wrapped, terminator was found in the wrapped
+ // section.
+ const TUint lenBeforeWrap = iBufStart + iBufSize - iOutPtr;
+ ret = pos + lenBeforeWrap;
+ }
+ }
+ }
+
+ // Check we're returning what we said we would.
+ __ASSERT_DEBUG(ret != KErrNone,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ LOGTEXT2(_L8("<<CAcmReader::FindTerminator ret=%d"), ret);
+ return ret;
+ }
+
+TInt CAcmReader::PartialFindTerminator(TUint8* aFrom,
+ TUint8* aTo,
+ TInt& aPos) const
+/**
+ * This function searches the buffer for one of a number of termination
+ * characters. The search is conducted between the pointers given. The
+ * function only searches a continuous buffer space, and does not respect the
+ * circular buffer wrap.
+ *
+ * @param aFrom The pointer at which to start searching.
+ * @param aTo The pointer one beyond where to stop searching.
+ * @param aPos The number of bytes beyond (and including) aFrom the terminator
+ * was found. That is, if the terminator was found adjacent to aFrom, aPos
+ * will be 2- the client can take this as meaning that 2 bytes are to be
+ * written back to the RComm client (aFrom and the one containing the
+ * terminator).
+ * @return KErrNone- a terminator was found. KErrNotFound- no terminator was
+ * found.
+ */
+ {
+ LOG_FUNC
+
+ aPos = 1;
+ LOGTEXT3(_L8("\taFrom=%d, aTo=%d"), aFrom-iBufStart, aTo-iBufStart);
+
+ for ( TUint8* p = aFrom ; p < aTo ; p++, aPos++ )
+ {
+ for ( TUint i = 0 ; i < iTerminatorCount ; i++ )
+ {
+ __ASSERT_DEBUG(p, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ if ( *p == iTerminator[i] )
+ {
+ LOGTEXT3(_L8("\tterminator %d found at aPos %d"),
+ iTerminator[i], aPos);
+ return KErrNone;
+ }
+ }
+ }
+
+ LOGTEXT(_L8("\tno terminator found"));
+ return KErrNotFound;
+ }
+
+//
+// End of file