# HG changeset patch # User andrew.jordan <> # Date 1272837798 -3600 # Node ID 84dca1410127c3269d410df12dd1f64e625164ab # Parent 99ca724f982901408c11ad50134eae87557ac779 Fix for Bug 2186 - QEMU baseport serial driver doesn't work with multiple UARTs and is unreliable diff -r 99ca724f9829 -r 84dca1410127 baseport/syborg/serial/syborg_serial.cpp --- a/baseport/syborg/serial/syborg_serial.cpp Thu Apr 22 14:59:02 2010 +0100 +++ b/baseport/syborg/serial/syborg_serial.cpp Sun May 02 23:03:18 2010 +0100 @@ -10,10 +10,10 @@ * Nokia Corporation - initial contribution. * * Contributors: +* NTT DOCOMO, INC. -- Fix bug 2186 - QEMU baseport serial driver doesn't work with multiple UARTs and is unreliable * * Description: Minimalistic serial driver * -* TODO: Handle multiple Units, hardcoded FIFO Size */ #include "syborg_serial.h" @@ -24,233 +24,287 @@ #define DPRINT(x) #define DPRINT2(x,y) +_LIT(KSerialDfcQName,"SerialDFC"); +const TInt KDfcQuePriority = 27; // --------------------------------------------------------------- // --------------------------------------------------------------- DDriverSyborgComm::DDriverSyborgComm() -{ - iVersion=TVersion(KCommsMajorVersionNumber,KCommsMinorVersionNumber,KCommsBuildVersionNumber); -} + { + DPRINT("DDriverSyborgComm::DDriverSyborgComm()"); + iVersion=TVersion(KCommsMajorVersionNumber, KCommsMinorVersionNumber, KCommsBuildVersionNumber); + } + + DDriverSyborgComm::~DDriverSyborgComm() + { + DPRINT("~DDriverSyborgComm::DDriverSyborgComm()"); + } TInt DDriverSyborgComm::Install() -{ - DPRINT("DDriverSyborgComm::Install"); - return SetName(&KPddName); -} + { + DPRINT("DDriverSyborgComm::Install"); + return SetName(&KPddName); + } void DDriverSyborgComm::GetCaps(TDes8 &aDes) const -{ - DPRINT("DDriverSyborgComm::GetCaps"); + { + DPRINT("DDriverSyborgComm::GetCaps"); - TCommCaps3 capsBuf; - TCommCapsV03 &c=capsBuf(); - c.iRate=KCapsBps110|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200|KCapsBps230400; - c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8; - c.iStopBits=KCapsStop1|KCapsStop2; - c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd; - c.iHandshake=KCapsObeyXoffSupported|KCapsSendXoffSupported|KCapsObeyCTSSupported|KCapsFailCTSSupported|KCapsObeyDSRSupported|KCapsFailDSRSupported|KCapsObeyDCDSupported|KCapsFailDCDSupported|KCapsFreeRTSSupported|KCapsFreeDTRSupported; - c.iSignals=KCapsSignalCTSSupported|KCapsSignalDSRSupported|KCapsSignalDCDSupported|KCapsSignalRTSSupported|KCapsSignalDTRSupported; - c.iSIR=0; - c.iNotificationCaps=KNotifyDataAvailableSupported|KNotifySignalsChangeSupported; - c.iFifo=KCapsHasFifo; - c.iRoleCaps=0; - c.iFlowControlCaps=0; - c.iBreakSupported=ETrue; - aDes.FillZ(aDes.MaxLength()); - aDes=capsBuf.Left(Min(capsBuf.Length(),aDes.MaxLength())); -} + TCommCaps3 capsBuf; + TCommCapsV03 &c=capsBuf(); + c.iRate=KCapsBps110|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200|KCapsBps230400; + c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8; + c.iStopBits=KCapsStop1|KCapsStop2; + c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd; + c.iHandshake=KCapsObeyXoffSupported|KCapsSendXoffSupported|KCapsObeyCTSSupported|KCapsFailCTSSupported|KCapsObeyDSRSupported|KCapsFailDSRSupported|KCapsObeyDCDSupported|KCapsFailDCDSupported|KCapsFreeRTSSupported|KCapsFreeDTRSupported; + c.iSignals=KCapsSignalCTSSupported|KCapsSignalDSRSupported|KCapsSignalDCDSupported|KCapsSignalRTSSupported|KCapsSignalDTRSupported; + c.iSIR=0; + c.iNotificationCaps=KNotifyDataAvailableSupported|KNotifySignalsChangeSupported; + c.iFifo=KCapsHasFifo; + c.iRoleCaps=0; + c.iFlowControlCaps=0; + c.iBreakSupported=ETrue; + aDes.FillZ(aDes.MaxLength()); + aDes=capsBuf.Left(Min(capsBuf.Length(),aDes.MaxLength())); + } TInt DDriverSyborgComm::Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer) -{ - DPRINT("DDriverSyborgComm::Create"); + { + DPRINT("DDriverSyborgComm::Create"); - DCommSyborgSoc* pD=new DCommSyborgSoc; - aChannel=pD; - TInt r=KErrNoMemory; - if (pD) - r=pD->DoCreate(aUnit,anInfo); - return r; -} + DCommSyborgSoc* pD=new DCommSyborgSoc(this); + aChannel=pD; + TInt r=KErrNoMemory; + if (pD) + { + r=pD->DoCreate(aUnit,anInfo); + } + return r; + } TInt DDriverSyborgComm::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer) -{ - DPRINT("DDriverSyborgComm::Validate"); - if ((!Kern::QueryVersionSupported(iVersion,aVer)) || + { + DPRINT("DDriverSyborgComm::Validate"); + if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild)))) - return KErrNotSupported; - return KErrNone; -} + return KErrNotSupported; + return KErrNone; + } + +/* Reference counted open on Serial Block Drivers DfcQueue */ +TInt DDriverSyborgComm::OpenDfcQueue() + { + DPRINT("DDriverSyborgComm::OpenDfcQueue()"); + if (iDfcQRefCount > 0) + { + iDfcQRefCount++; + return KErrNone; + } + + TInt err = Kern::DynamicDfcQCreate(iDfcQueue, KDfcQuePriority, KSerialDfcQName); + + if (!err) + { + iDfcQRefCount++; + } + return err; + } + +/* Reference counted open on Serial Block Drivers DfcQueue */ +void DDriverSyborgComm::CloseDfcQueue() + { + DPRINT("DDriverSyborgComm::CloseDfcQueue()"); + iDfcQRefCount--; + if (iDfcQRefCount == 0) + { + iDfcQueue->Destroy(); + } + } + +TDfcQue* DDriverSyborgComm::DfcQueue() + { + return iDfcQueue; + } // --------------------------------------------------------------- // --------------------------------------------------------------- -DCommSyborgSoc::DCommSyborgSoc() -{ -} +DCommSyborgSoc::DCommSyborgSoc(DDriverSyborgComm* aDriverSyborgComm) + :iDriverSyborgComm(aDriverSyborgComm) + { + } DCommSyborgSoc::~DCommSyborgSoc() -{ - Interrupt::Unbind(iIrq); -} - -TInt DCommSyborgSoc::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/) -{ - DPRINT2("DCommSyborgSoc::DoCreate %d",aUnit); - switch(aUnit) { - case 0: - iPortAddr = KHwBaseUart0; - iIrq = EIntSerial0; - break; - case 1: - iPortAddr = KHwBaseUart1; - iIrq = EIntSerial1; - break; - case 2: - iPortAddr = KHwBaseUart2; - iIrq = EIntSerial2; - break; - case 3: - iPortAddr = KHwBaseUart3; - iIrq = EIntSerial3; - break; - default: - iPortAddr = KHwBaseUart0; - iIrq = EIntSerial0; - break; + (TInt)Interrupt::Unbind(iIrq); + if (iDfcQueueOpened) + { + iDriverSyborgComm->CloseDfcQueue(); + } } - Interrupt::Bind(EIntSerial0,Isr,this); +TInt DCommSyborgSoc::DoCreate(TInt aUnit, const TDesC8* /*anInfo*/) + { + DPRINT2("DCommSyborgSoc::DoCreate %d",aUnit); + TInt err = KErrNone; + switch(aUnit) + { + case 0: + iPortAddr = KHwBaseUart0; + iIrq = EIntSerial0; + break; + case 1: + iPortAddr = KHwBaseUart1; + iIrq = EIntSerial1; + break; + case 2: + iPortAddr = KHwBaseUart2; + iIrq = EIntSerial2; + break; + case 3: + iPortAddr = KHwBaseUart3; + iIrq = EIntSerial3; + break; + default: + err = KErrNotSupported; + break; + } - return KErrNone; - -} + if (!err) + { + err = iDriverSyborgComm->OpenDfcQueue(); + iDfcQueueOpened = ETrue; + } + if (!err) + { + err = Interrupt::Bind(iIrq,Isr,this); + } + return err; + } TInt DCommSyborgSoc::Start() -{ - DPRINT("DCommSyborgSoc::Start"); - WriteReg(iPortAddr, SERIAL_INT_ENABLE, 0x1); - Interrupt::Enable(iIrq); - return KErrNone; -} + { + DPRINT("DCommSyborgSoc::Start"); + WriteReg(iPortAddr, SERIAL_INT_ENABLE, 0x1); + TInt err = Interrupt::Enable(iIrq); + return err; + } void DCommSyborgSoc::Stop(TStopMode aMode) -{ - DPRINT("DCommSyborgSoc::Stop"); - WriteReg(iPortAddr, SERIAL_INT_ENABLE, 0x0); - Interrupt::Disable(iIrq); -} + { + DPRINT("DCommSyborgSoc::Stop"); + WriteReg(iPortAddr, SERIAL_INT_ENABLE, 0x0); + (TInt)Interrupt::Disable(iIrq); + } void DCommSyborgSoc::Break(TBool aState) -{ - DPRINT("DCommSyborgSoc::Break"); -} + { + DPRINT("DCommSyborgSoc::Break"); + } void DCommSyborgSoc::EnableTransmit() -{ - DPRINT("DCommSyborgSoc::EnableTransmit"); - while (Kern::PowerGood()) { - TInt r=TransmitIsr(); - if (r<0) - break; - WriteReg(iPortAddr, SERIAL_DATA, r); + DPRINT("DCommSyborgSoc::EnableTransmit"); + while (Kern::PowerGood()) + { + TInt r=TransmitIsr(); + if (r<0) + { + break; + } + WriteReg(iPortAddr, SERIAL_DATA, r); + } + + // Request LDD to check if more data is available in the client buffer. + // TransmitISR only copies data from the LDD buffer which is 1k. + iLdd->CheckTxBuffer(); } - iLdd->iTxError = KErrNone; - iLdd->iTxCompleteDfc.Add(); - -} - TUint DCommSyborgSoc::Signals() const -{ - DPRINT("DCommSyborgSoc::Signals"); - return(0); -} - + { + DPRINT("DCommSyborgSoc::Signals"); + return(0); + } + void DCommSyborgSoc::SetSignals(TUint aSetMask, TUint aClearMask) -{ - DPRINT("DCommSyborgSoc::SetSignals"); -} + { + DPRINT("DCommSyborgSoc::SetSignals"); + } TInt DCommSyborgSoc::ValidateConfig(const TCommConfigV01 &aConfig) const -{ - DPRINT("DCommSyborgSoc::ValidateConfig"); - return KErrNone; -} + { + DPRINT("DCommSyborgSoc::ValidateConfig"); + return KErrNone; + } void DCommSyborgSoc::Configure(TCommConfigV01 &aConfig) -{ - DPRINT("DCommSyborgSoc::Configure"); -} + { + DPRINT("DCommSyborgSoc::Configure"); + } void DCommSyborgSoc::Caps(TDes8 &aCaps) const -{ - DPRINT("DCommSyborgSoc::Caps"); - TCommCaps3 capsBuf; - TCommCapsV03 &c=capsBuf(); - c.iRate=KCapsBps110|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200|KCapsBps230400; - c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8; - c.iStopBits=KCapsStop1|KCapsStop2; - c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd; - c.iHandshake=KCapsObeyXoffSupported|KCapsSendXoffSupported|KCapsObeyCTSSupported|KCapsFailCTSSupported|KCapsObeyDSRSupported|KCapsFailDSRSupported|KCapsObeyDCDSupported|KCapsFailDCDSupported|KCapsFreeRTSSupported|KCapsFreeDTRSupported; - c.iSignals=KCapsSignalCTSSupported|KCapsSignalDSRSupported|KCapsSignalDCDSupported|KCapsSignalRTSSupported|KCapsSignalDTRSupported; - c.iSIR=0; - c.iNotificationCaps=KNotifyDataAvailableSupported|KNotifySignalsChangeSupported; - c.iFifo=KCapsHasFifo; - c.iRoleCaps=0; - c.iFlowControlCaps=0; - c.iBreakSupported=ETrue; - aCaps.FillZ(aCaps.MaxLength()); - aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength())); -} + { + DPRINT("DCommSyborgSoc::Caps"); + TCommCaps3 capsBuf; + TCommCapsV03 &c=capsBuf(); + c.iRate=KCapsBps110|KCapsBps150|KCapsBps300|KCapsBps600|KCapsBps1200|KCapsBps2400|KCapsBps4800|KCapsBps9600|KCapsBps19200|KCapsBps38400|KCapsBps57600|KCapsBps115200|KCapsBps230400; + c.iDataBits=KCapsData5|KCapsData6|KCapsData7|KCapsData8; + c.iStopBits=KCapsStop1|KCapsStop2; + c.iParity=KCapsParityNone|KCapsParityEven|KCapsParityOdd; + c.iHandshake=KCapsObeyXoffSupported|KCapsSendXoffSupported|KCapsObeyCTSSupported|KCapsFailCTSSupported|KCapsObeyDSRSupported|KCapsFailDSRSupported|KCapsObeyDCDSupported|KCapsFailDCDSupported|KCapsFreeRTSSupported|KCapsFreeDTRSupported; + c.iSignals=KCapsSignalCTSSupported|KCapsSignalDSRSupported|KCapsSignalDCDSupported|KCapsSignalRTSSupported|KCapsSignalDTRSupported; + c.iSIR=0; + c.iNotificationCaps=KNotifyDataAvailableSupported|KNotifySignalsChangeSupported; + c.iFifo=KCapsHasFifo; + c.iRoleCaps=0; + c.iFlowControlCaps=0; + c.iBreakSupported=ETrue; + aCaps.FillZ(aCaps.MaxLength()); + aCaps=capsBuf.Left(Min(capsBuf.Length(),aCaps.MaxLength())); + } TInt DCommSyborgSoc::DisableIrqs() -{ - DPRINT("DCommSyborgSoc::DisableIrqs"); - return NKern::DisableAllInterrupts(); -} + { + DPRINT("DCommSyborgSoc::DisableIrqs"); + return NKern::DisableAllInterrupts(); + } void DCommSyborgSoc::RestoreIrqs(TInt aIrq) -{ - DPRINT("DCommSyborgSoc::RestoreIrqs"); - NKern::RestoreInterrupts(aIrq); -} + { + DPRINT("DCommSyborgSoc::RestoreIrqs"); + NKern::RestoreInterrupts(aIrq); + } -TDfcQue* DCommSyborgSoc::DfcQ(TInt /*aUnit*/) -{ - return Kern::DfcQue0(); -} +TDfcQue* DCommSyborgSoc::DfcQ(TInt aUnit) + { + return iDriverSyborgComm->DfcQueue(); + } void DCommSyborgSoc::CheckConfig(TCommConfigV01& aConfig) -{ - DPRINT("DCommSyborgSoc::CheckConfig"); -} + { + DPRINT("DCommSyborgSoc::CheckConfig"); + } void DCommSyborgSoc::Isr(TAny* aPtr) -{ - DCommSyborgSoc& d=*(DCommSyborgSoc*)aPtr; - TUint rx[32]; - TInt rxi=0; - - DPRINT2("DCommSyborgSoc::Isr %x",d.iIrq); - - // Is now auto clear - // WriteReg(d.iPortAddr, SERIAL_CLEAR_INT, 0x0); // clear interrupts + { + DCommSyborgSoc& d=*(DCommSyborgSoc*)aPtr; + TUint rx[32]; + TInt rxi=0; - while(ReadReg(d.iPortAddr, SERIAL_FIFO_COUNT)!=0) { - TUint ch = ReadReg(d.iPortAddr, SERIAL_DATA); - rx[rxi++]=ch; - } - d.ReceiveIsr(rx,rxi,0); -} + TInt fifo = ReadReg(d.iPortAddr, SERIAL_FIFO_COUNT ); + while(fifo > 0 && rxi<32) + { + TUint ch = ReadReg(d.iPortAddr, SERIAL_DATA); + rx[rxi++]=ch; -// --------------------------------------------------------------- -// --------------------------------------------------------------- + fifo = ReadReg(d.iPortAddr, SERIAL_FIFO_COUNT ); + } + d.ReceiveIsr(rx,rxi,0); + } DECLARE_STANDARD_PDD() -{ - DPRINT("DECLARE_STANDARD_PDD()"); - return new DDriverSyborgComm; -} + { + DPRINT("DECLARE_STANDARD_PDD()"); + return new DDriverSyborgComm; + } diff -r 99ca724f9829 -r 84dca1410127 baseport/syborg/serial/syborg_serial.h --- a/baseport/syborg/serial/syborg_serial.h Thu Apr 22 14:59:02 2010 +0100 +++ b/baseport/syborg/serial/syborg_serial.h Sun May 02 23:03:18 2010 +0100 @@ -10,6 +10,7 @@ * Nokia Corporation - initial contribution. * * Contributors: +* NTT DOCOMO, INC. -- Fix bug 2186 - QEMU baseport serial driver doesn't work with multiple UARTs and is unreliable * * Description: Minimalistic serial driver * @@ -26,52 +27,75 @@ const TInt KMinimumLddMinorVersion=1; const TInt KMinimumLddBuild=1; +/** + * Serial Ports Device Driver + * + * + **/ class DDriverSyborgComm : public DPhysicalDevice -{ + { public: DDriverSyborgComm(); + ~DDriverSyborgComm(); virtual TInt Install(); virtual void GetCaps(TDes8 &aDes) const; virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion &aVer); virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer); -}; -class DCommSyborgSoc : public DComm -{ -public: - DCommSyborgSoc(); - ~DCommSyborgSoc(); - TInt DoCreate(TInt aUnit, const TDesC8* anInfo); +// interface for single comm port. public: - virtual TInt Start(); - virtual void Stop(TStopMode aMode); - virtual void Break(TBool aState); - virtual void EnableTransmit(); - virtual TUint Signals() const; - virtual void SetSignals(TUint aSetMask, TUint aClearMask); - virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const; - virtual void Configure(TCommConfigV01 &aConfig); - virtual void Caps(TDes8 &aCaps) const; - virtual TInt DisableIrqs(); - virtual void RestoreIrqs(TInt aIrq); - virtual TDfcQue* DfcQ(TInt aUnit); - virtual void CheckConfig(TCommConfigV01& aConfig); - static void Isr(TAny* aPtr); + TInt OpenDfcQueue(); + void CloseDfcQueue(); + TDfcQue* DfcQueue(); + +private: + TDynamicDfcQue* iDfcQueue; // single Dfc queue for all comm ports + TUint8 iDfcQRefCount; // reference count for dfc queue + }; + + + +/** + * Driver for a single Comm port + **/ +class DCommSyborgSoc : public DComm + { +public: + DCommSyborgSoc(DDriverSyborgComm* aDriverSyborgComm); + ~DCommSyborgSoc(); + TInt DoCreate(TInt aUnit, const TDesC8* anInfo); +public: + virtual TInt Start(); + virtual void Stop(TStopMode aMode); + virtual void Break(TBool aState); + virtual void EnableTransmit(); + virtual TUint Signals() const; + virtual void SetSignals(TUint aSetMask, TUint aClearMask); + virtual TInt ValidateConfig(const TCommConfigV01 &aConfig) const; + virtual void Configure(TCommConfigV01 &aConfig); + virtual void Caps(TDes8 &aCaps) const; + virtual TInt DisableIrqs(); + virtual void RestoreIrqs(TInt aIrq); + virtual TDfcQue* DfcQ(TInt aUnit); + virtual void CheckConfig(TCommConfigV01& aConfig); + static void Isr(TAny* aPtr); public: - TLinAddr iPortAddr; - TInt iIrq; + DDriverSyborgComm* iDriverSyborgComm; + TLinAddr iPortAddr; + TInt iIrq; + TBool iDfcQueueOpened; - enum { - SERIAL_ID = 0, - SERIAL_DATA = 1, - SERIAL_FIFO_COUNT = 2, - SERIAL_INT_ENABLE = 3, - SERIAL_DMA_TX_ADDR = 4, - SERIAL_DMA_TX_COUNT = 5, /* triggers dma */ - SERIAL_DMA_RX_ADDR = 6, - SERIAL_DMA_RX_COUNT = 7 /* triggers dma */ - }; -}; + enum { + SERIAL_ID = 0, + SERIAL_DATA = 1, + SERIAL_FIFO_COUNT = 2, + SERIAL_INT_ENABLE = 3, + SERIAL_DMA_TX_ADDR = 4, + SERIAL_DMA_TX_COUNT = 5, /* triggers dma */ + SERIAL_DMA_RX_ADDR = 6, + SERIAL_DMA_RX_COUNT = 7 /* triggers dma */ + }; + }; #endif