Fix for Bug 2186 - QEMU baseport serial driver doesn't work with multiple UARTs and is unreliable
--- 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;
+ }
--- 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