usbdrv/peripheral/public/usbcsc.h
author hgs
Wed, 20 Oct 2010 12:04:53 +0800
changeset 59 bbdce6bffaad
parent 48 21625e5de155
permissions -rw-r--r--
201041_02

/*
* Copyright (c) 2010 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:
* e32\include\drivers\usbcsc.h
* Kernel side definitions for the USB Device driver stack (PIL + LDD).
*
*/

/**
 @file usbcsc.h
 @internalTechnology
*/

#ifndef __USBCSC_H__
#define __USBCSC_H__

#include <kernel/kernel.h>
#include <kernel/kern_priv.h>
#include <kernel/kpower.h>
#include <platform.h>

#include <usb/d32usbcsc.h>

// #include <drivers/usbcshared.h>
#include <usb/usbcshared.h>

/** LDD Major version, This should agree with the information in RDevUsbcClient::TVer.
*/
const TInt KUsbcScMajorVersion = 0;

/** LDD Minor version, This should agree with the information in RDevUsbcClient::TVer.
*/
const TInt KUsbcScMinorVersion = 1;

/** LDD Build version, This should agree with the information in RDevUsbcClient::TVer.
*/
const TInt KUsbcScBuildVersion = KE32BuildVersionNumber;

/** Must correspond to the max enum of TRequest + 1;
    currently this is ERequestOtgFeaturesNotify = 10.
*/
const TInt KUsbcScMaxRequests = 11;

// Request queue sizes need to be power of 2.

/** The number of requests that can be queued on any IN endpoint */
const TInt KUsbcScInRequests = 4;
/** The number of requests that can be queued on any OUT endpoint */
const TInt KUsbcScOutRequests = 2;

/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an IN endpoint */
const TInt KUsbcScIn =  0;
/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an OUT endpoint */
const TInt KUsbcScOut = 1;


/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an Bidirectional endpoint
currently operating as an IN endpoint */
const TInt KUsbcScBiIn = 2;
/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an Bidirectional endpoint
currently operating as an OUT endpoint */
const TInt KUsbcScBiOut = 3;

/** The number of directions supported for endpoints, other then EP0.  Currently 2, IN and OUT. */
const TInt KUsbcScDirections = 2;

/** In TUsbcScBuffer::iDirection, this indicates that the endpoint direction is Unknown. */
const TInt KUsbcScUnknown = 4;

const TInt KPageSize = 0x1000;

/** The default buffer size requested for a endpoint, if the user app does not specify a size.*/
const TInt KUsbcScDefaultBufferSize = 0x10000; // 64k

/** The size of the unmapped region of memory between endpoint buffers.
This serves as a guard region, making memory over/under runs more obviose.*/
const TInt KGuardSize = KPageSize;

/** The size put aside for the chunk header structre.*/
const TInt KHeaderSize = KPageSize;

/** For buffers of size >= KUsbScBigBuffIs, The smallest unit of continiouse memory that will be used.
No read will be set up smaller then this, to avoid overly fragmenting the data.
*/
const TInt KUsbSc_BigBuff_MinimumRamRun = KPageSize;

/** For buffers of size < KUsbScBigBuffIs, The smallest unit of continiouse memory that will be used.
No read will be set up smaller then this, to avoid overly fragmenting the data.*/
const TInt KUsbSc_SmallBuff_MinimumRamRun = 1024;

/** The size a buffer request has to be to switch to using KUsbSc_BigBuff_MinimumRamRun.
If the requested buffer is smaller, then the smallest memory allocated to a buffer is KPageSize*/
const TInt KUsbScBigBuffIs = KPageSize*6;



// EP0 is mapped manually, unlike the other endpoints.

/** The position, within the chunk, that the EP0 IN buffer appears*/
const TInt KUsbScEP0InBufPos = 0x800;
/** The position, within the chunk, that the EP0 IN buffer ends*/
const TInt KUsbScEP0InBufEnd = KUsbScEP0InBufPos + 0x400;

// Its better for Out to go 2nd, so gaurd page after it.
/** The position, within the chunk, that the EP0 OUT buffer appears*/
const TInt KUsbScEP0OutBufPos = 0xc00;
/** The position, within the chunk, that the EP0 OUT buffer ends*/
const TInt KUsbScEP0OutBufEnd = KUsbScEP0OutBufPos + 0x400;

/** The number of the entry within the chunk BufferRecord table, for the OUT ep0 buffer.*/
const TInt KUsbcScEp0OutBuff = 0;
/** The number of the entry within the chunk BufferRecord table, for the IN ep0 buffer.*/
const TInt KUsbcScEp0InBuff = 1;


//
//########################### Logical Device Driver (LDD) #############################
//

/** USB LDD factory class.
*/
class DUsbcScLogDevice : public DLogicalDevice
    {
public:
    DUsbcScLogDevice();
    virtual TInt Install();
    virtual void GetCaps(TDes8& aDes) const;
    virtual TInt Create(DLogicalChannelBase*& aChannel);
    };


class DLddUsbcScChannel;
class TUsbcScBuffer;
/** Endpoint tracking for the LDD buffering etc.
*/
class TUsbcScEndpoint
    {
public:
    TUsbcScEndpoint(DLddUsbcScChannel* aLDD, DUsbClientController* aController,
                  const TUsbcScEndpointInfo* aEndpointInfo, TInt aEndpointNum
                  );
    ~TUsbcScEndpoint();
    TInt Construct();
    void CancelTransfer(DThread* aThread);
    void AbortTransfer();
    inline TUsbcScEndpointInfo* EndpointInfo();
    inline TInt RxBytesAvailable() const;
    inline void ResetTransferInfo();
    inline void SetClientReadPending(TBool aVal);
    inline void SetClientWritePending(TBool aVal);
    inline TBool ClientWritePending();
    inline TBool ClientReadPending();
    inline void SetRealEpNumber(TInt aRealEpNumber);
    inline TInt RealEpNumber() const;
    inline TInt EpNumber() const;
    inline void StartBuffer();
    inline void SetBuffer(TUsbcScBuffer* aBuffer);
    inline TUsbcScBuffer* GetBuffer();


private:
    static void RequestCallback(TAny* aTUsbcScEndpoint);
    void TxComplete();
    TInt RxComplete(TBool aReEntrant);
    void RxCompleteNow();



public:
    TUsbcRequestCallback* iRequestCallbackInfo;

private:
    DUsbClientController* iController;
    TUsbcScEndpointInfo iEndpointInfo;
    TBool iClientReadPending;
    TBool iClientWritePending;
    TInt iEndpointNumber;
    TInt iRealEpNumber;
    DLddUsbcScChannel* iLdd;
    TInt iError;
    TUint32 iBytesTransferred;
    TInt iBandwidthPriority;
    TUsbcScBuffer* iBuffer;

    };


/** Linked list of 'alternate setting' info for use by the LDD.
*/
class TUsbcScAlternateSetting
    {
public:
    TUsbcScAlternateSetting();
    ~TUsbcScAlternateSetting();

public:
    TUsbcScAlternateSetting* iNext;
    TUsbcScAlternateSetting* iPrevious;
    TInt iNumberOfEndpoints;
    TUint iSetting;
    TUsbcScEndpoint* iEndpoint[KMaxEndpointsPerClient + 1];
    };

class TUsbcScAlternateSettingList
    {
public:
    TUsbcScAlternateSettingList();
    ~TUsbcScAlternateSettingList();

public:
    TUsbcScAlternateSetting* iHead;
    TUsbcScAlternateSetting* iTail;
    };

class TUsbcScChunkInfo
    {
public:
    TUsbcScChunkInfo(DLogicalDevice* aLdd);
    TInt CreateChunk(TInt aTotalSize);
    void Close();
    TInt ChunkAlloc(TInt aOffset, TInt aSize);
    void ChunkCleanup();
    TInt GetPhysical(TInt aOffset, TPhysAddr* aPhysical);
    static TInt New(TUsbcScChunkInfo*& aChunk, TInt aSize, DLogicalDevice* aLdd);
private:
    TUint* iPhysicalMap;
public:
    DChunk* iChunk;
    TDfc iCleanup;

    TInt8 iPageNtz; // Number of trailing zeros for a page. (Eg 4k page has 12 t.z.)
    TInt iAllocatedSize;
    TInt8* iChunkMem;
    TUint32 iChunkMapAttr;
    DLogicalDevice* iLdd;
    };


// Used to represent a matrix of endpoints with a column of sizes.
// Used by TRealizeInfo

class TEndpointSortBufs
    {
    public:
        TUsbcScEndpoint** iEp;
        TInt* iSizes;
        TInt iEps;
    };

// This is used to calculate the layout of the shared chunk
// based on a list of alternative settings / endpoints provided.
 
class TRealizeInfo
    {
    public:
        void Init(TUsbcScAlternateSettingList* aAlternateSettingList);
        TInt CopyAndSortEndpoints();
        void CalcBuffSizes();
        void Free();

        void LayoutChunkHeader(TUsbcScChunkInfo* aChunkInfo);
    public:
        TInt iMaxEndpoints;
        TInt iTotalSize;
        TInt iTotalBuffers;
        TInt iAltSettings;
        TEndpointSortBufs iBufs[KUsbcScDirections];
        TUsbcScAlternateSettingList* iAlternateSettingList;

        // Chunk layout info.
        TUsbcScChunkBuffersHeader* iChunkStuct;
        TUsbcScChunkAltSettingHeader* iAltSettingsTbl;
    };



/** The channel class - the actual USB LDD.
*/
class DLddUsbcScChannel : public DLogicalChannel
    {
public:
    DLddUsbcScChannel();
    ~DLddUsbcScChannel();
    virtual void HandleMsg(TMessageBase* aMsg);
    virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
    virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType);
    inline DThread* Client() const {return iClient;}
    inline TBool ChannelClosing() const {return iChannelClosing;}
    inline TUint AlternateSetting() const {return iAlternateSetting;}
    
    static void RequestCallbackEp0(TAny* aTUsbcScChannel);

private:

    TInt DoCancel(TInt aReqNo, TUint aMask, TUint a1);
    TInt DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2);
    TInt DoControl(TInt aFunction, TAny* a1, TAny* a2);
    TInt DoReadDataNotify(TRequestStatus* aStatus, TInt aBufferNum, TInt aLength);
    void StartDataRead(TInt aBufferNum);
    TInt DoWriteData(TRequestStatus* aStatus,TInt aBufferNum, TUint aStart, TUint aLength, TUint aFlags);
    TBool AlternateDeviceStateTestComplete();
    TInt SetInterface(TInt aInterfaceNum, TUsbcScIfcInfo* aUserInterfaceInfoBuf);
    void StartEpReads();
    void DestroyAllInterfaces();
    void DestroyInterface(TUint aInterface);
    void DestroyEp0();
    inline TBool ValidEndpoint(TInt aEndpoint);
    TInt GetRealEpForEpResource(TInt aEndpoint, TInt& aRealEp);
    inline TBool Configured();
    TInt DoEmergencyComplete();
    void ReadDes8(const TAny* aPtr, TDes8& aDes);
    TInt SetupEp0();
    void CancelNotifyEndpointStatus();
    void CancelNotifyOtgFeatures();
    void CancelNotifyChargerType();
    static void StatusChangeCallback(TAny* aDLddUsbcChannel);
    static void EndpointStatusChangeCallback(TAny* aDLddUsbcChannel);
    static void OtgFeatureChangeCallback(TAny* aDLddUsbcChannel);
    static void ChargerTypeChangeCallback(TAny* aDLddUsbcChannel);	
    static void EmergencyCompleteDfc(TAny* aDLddUsbcChannel);
    void DeConfigure(TInt aErrorCode);
    TInt SelectAlternateSetting(TUint aAlternateSetting);
    TInt EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint);
    TInt ProcessAlternateSetting(TUint aAlternateSetting);
    TInt32 StartNextInAlternateSetting();
    TInt ProcessDeviceState(TUsbcDeviceState aDeviceState);
    void ResetInterface(TInt aErrorCode);
    void PanicClientThread(TInt aReason);

    TInt RealizeInterface(void);

private:
    DUsbClientController* iController;
    DThread* iClient;
    TBool iValidInterface;
    
    TUsbcScAlternateSettingList* iAlternateSettingList;
    TUsbcScEndpoint** iEndpoint;  // Pointer to the current endpoint set.

    static const TInt KUsbcMaxRequests = RDevUsbcScClient::ERequestMaxRequests;
    TRequestStatus* iRequestStatus[KUsbcMaxRequests];
    TUsbcClientCallback iCompleteAllCallbackInfo;
    TAny* iStatusChangePtr;
    TUsbcStatusCallback iStatusCallbackInfo;
    TAny* iEndpointStatusChangePtr;
    TUsbcEndpointStatusCallback iEndpointStatusCallbackInfo;
    TAny* iOtgFeatureChangePtr;
    TUsbcOtgFeatureCallback iOtgFeatureCallbackInfo;
    TAny* iChargerTypeChangePtr;
    TUsbcChargerTypeCallback iChargerTypeCallbackInfo;
    TUint8* iBufferBaseEp0;
    TInt iBufferSizeEp0;
    TInt iNumberOfEndpoints;
    TUsbcDeviceState iDeviceState;
    TUsbcDeviceState iOldDeviceState;
    TBool iOwnsDeviceControl;
    TUint16 iAlternateSetting;
    TUint16 iAsSeq;

    TUsbcDeviceStatusQueue* iStatusFifo;
    TBool iUserKnowsAltSetting;
    TBool iDeviceStatusNeeded;
    TBool iChannelClosing;
    TBool iRealizeCalled;

    TUsbcScChunkInfo* iChunkInfo;
    TInt iNumBuffers;
    TUsbcScBuffer *iBuffers;

    TUsbcScEndpoint* iEp0Endpoint;
    TInt iEP0InBuff;
    TInt iEP0OutBuff;

    friend class TUsbcScBuffer;
    friend void TUsbcScEndpoint::AbortTransfer();
    };

/**
This class is used by TUsbcScStatusList to form a queue of status requests.
These requests are on a buffer basis, so that all buffers can have at least two requests
pending, at the same time. (i.e. buffer 1 could have two requests outstanding, as well as 2 on buffer 2.)
*/

class TUsbcScStatusElement
{
public:
    TRequestStatus* iStatus;
    TInt iLength;
    TUint iStart;
    TUint iFlags;    
};

enum TUsbcScStatusState
{
    ENotRunning,
    EInProgress,
    EReadingAhead,
    EFramgementInProgress
};

class TUsbcScStatusList
{
public:
    TInt Construct(TInt aSize, DThread* aThread);
    void Destroy();

    TUsbcScStatusElement* Next();
    void Pop();
    TInt Add(TRequestStatus* aStatus, TInt aLength, TUint aStart, TUint aFlags);
    void CancelQueued(TInt aErrorCode=KErrCancel);
    TInt Complete(TInt aError);
    void Complete();
public:
    TUsbcScStatusState iState;

private:
    DThread* iClient;
    TInt iHead;   // The element at the head of the queue, ie, the earliest added, and next to be removed.
    TInt iLength; // Length of queue, ie number of elements within
    TInt iSize;   // size of array, ie, max # of requests at a time.
    TUsbcScStatusElement* iElements;

};



/**
This class holds the kernel's copy of all the details related to a shared endpoint buffer,
and provides methods for the LDD to manipulate it.
*/
class TUsbcScBuffer
{
public:
    static const TInt8 KNoEpAssigned=0;
    static const TInt8 KEpIsEnding=1;
    static const TInt8 KEpIsStarting=2;

public:
    TInt Construct(TInt aDirection, DLddUsbcScChannel* aLdd, TInt aBufferOffset, TInt aBufferEndOffset, TInt aMinReadSize, TInt aMaxPacketSize, TInt aMaxReadSize);
    void CreateChunkBufferHeader();
    void StartEndpoint(TUsbcRequestCallback* iRequestInfo, TUint iFlags);

    void Destroy();

    TInt StartDataRead();
    void CompleteRead(TBool aStartNextRead=ETrue);
    void PopStall();
    void StartDataWrite();
    void CompleteWrite();
    void Cancel(TInt aErrorCode);

    void UpdateBufferList(TInt aByteCount,TUint aFlags, TBool aStartNextRead=ETrue);
    void Ep0CancelLddRead();
    void SendEp0StatusPacket(TInt aState);

public:
    
    TInt8 iDirection;
    TInt8 iMode;
    TInt8 iNeedsPacket;
    TInt8 iReserved;
    DLddUsbcScChannel* iLdd;
    TLinAddr iChunkAddr;
    SUsbcScBufferHeader* iBufferStart;
    TUint iBufferEnd; // One word on from the last word in the buffer.
    TUint iAlignMask;
    TUsbcScStatusList iStatusList;
    TUsbcRequestCallback* iCallback;
    union 
    {
        TInt iHead; // Out endpoints only;
        TUint iSent; // In endpoints only
    };
    TUsbcScChunkInfo* iChunkInfo;
    TInt iMinReadSize;
    TInt iMaxReadSize;
    TInt iMaxPacketSize;  // 0 indicates unconfiured.
    TInt iFirstPacket;
    TInt iStalled;

    // needed for backwards compatibility
    TUsbcPacketArray iIndexArray[KUsbcDmaBufNumMax]; // Has 2 elements
    TUsbcPacketArray iSizeArray[KUsbcDmaBufNumMax];  // Has 2 elements
#ifdef _DEBUG
    TUint iSequence;
#endif

};



#include <usb/usbcsc.inl>

#endif    // __USBCSC_H__