--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/ethernet/d_ethernet.cpp Thu Dec 17 09:24:54 2009 +0200
@@ -0,0 +1,792 @@
+// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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\drivers\ethernet\d_ethernet.cpp
+// LDD the ethernet which has no power managment and is not PCCard based
+//
+//
+
+/**
+ @file d_ethernet.cpp
+*/
+
+#include <drivers/ethernet.h>
+#include <kernel/kern_priv.h>
+#include <e32hal.h>
+#include <e32uid.h>
+
+
+_LIT(KLddName,"Ethernet");
+
+#ifdef KNETWORK1
+const TUint8 ETHER2_TYPE_IP_MSB = 0x08;
+const TUint8 ETHER2_TYPE_IP_LSB = 0x00;
+const TUint8 IP_TYPE_TCP = 0x06;
+
+static TBool IsTcp(TDesC8 &aFrame)
+ {
+ return (aFrame[12] == ETHER2_TYPE_IP_MSB && aFrame[13] == ETHER2_TYPE_IP_LSB && aFrame[23] == IP_TYPE_TCP);
+ }
+
+static TInt GetTcpSeqNumber(TDesC8 &aFrame)
+ {
+ TInt seqNum = 0;
+ if (IsTcp(aFrame))
+ seqNum = aFrame[38] << 24 | aFrame[39] << 16 | aFrame[40] << 8| aFrame[41];
+ return seqNum;
+ }
+
+static TInt GetTcpAckNumber(TDesC8 &aFrame)
+ {
+ TInt ackNum = 0;
+ if (IsTcp(aFrame))
+ ackNum = aFrame[42] << 24 | aFrame[43] << 16 | aFrame[44] << 8| aFrame[45];
+ return ackNum;
+ }
+#endif
+
+DDeviceEthernet::DDeviceEthernet()
+// Constructor
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DDeviceEthernet::DDeviceEthernet()"));
+ iParseMask=KDeviceAllowAll;
+ iUnitsMask=0xffffffff; // Leave units decision to the PDD
+ iVersion=TVersion(KEthernetMajorVersionNumber,
+ KEthernetMinorVersionNumber,
+ KEthernetBuildVersionNumber);
+ }
+
+
+TInt DDeviceEthernet::Install()
+// Install the device driver.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DDeviceEthernet::Install()"));
+ return(SetName(&KLddName));
+ }
+
+
+void DDeviceEthernet::GetCaps(TDes8& aDes) const
+// Return the Ethernet capabilities.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DDeviceEthernet::GetCaps(TDes8& aDes) const"));
+ TPckgBuf<TCapsDevEthernetV01> b;
+ b().version=TVersion(KEthernetMajorVersionNumber,
+ KEthernetMinorVersionNumber,
+ KEthernetBuildVersionNumber);
+ Kern::InfoCopy(aDes,b);
+ }
+
+
+TInt DDeviceEthernet::Create(DLogicalChannelBase*& aChannel)
+// Create a channel on the device.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DDeviceEthernet::Create(DLogicalChannelBase*& aChannel)"));
+ aChannel=new DChannelEthernet;
+
+ return aChannel?KErrNone:KErrNoMemory;
+ }
+
+
+DChannelEthernet::DChannelEthernet()
+// Constructor
+ : iRxCompleteDfc(CompleteRxDfc, this, 2)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DChannelEthernet()"));
+
+ // Setup the default config
+ iConfig.iEthSpeed = KEthSpeed10BaseT;
+ iConfig.iEthDuplex = KEthDuplexHalf;
+ iConfig.iEthAddress[0] = 0x00;
+ iConfig.iEthAddress[1] = 0x00;
+ iConfig.iEthAddress[2] = 0x00;
+ iConfig.iEthAddress[3] = 0x00;
+ iConfig.iEthAddress[4] = 0x00;
+ iConfig.iEthAddress[5] = 0x00;
+
+ iStatus=EOpen;
+
+ iClient=&Kern::CurrentThread();
+ // Increse the Dthread's ref count so that it does not close without us
+ iClient->Open();
+ }
+
+
+DChannelEthernet::~DChannelEthernet()
+// Destructor
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::~DChannelEthernet()"));
+ Kern::DestroyClientRequest(iWriteRequest);
+ Kern::DestroyClientBufferRequest(iReadRequest);
+ // decrement it's reference count
+ Kern::SafeClose((DObject*&)iClient, NULL);
+ }
+
+
+void DChannelEthernet::Complete(TInt aMask, TInt aReason)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Complete(TInt aMask, TInt aReason)"));
+ if (aMask & ERx)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Complete iReadRequest"));
+ if (iReadRequest->IsReady())
+ {
+ Kern::QueueBufferRequestComplete(iClient, iReadRequest, aReason);
+ }
+ }
+ if (aMask & ETx)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Complete iWriteRequest"));
+ __KTRACE_OPT(KNETWORK2, Kern::Printf(" >ldd tx: PRE complete reason=%d iClient=%08x iTxStatus=%08x\n", aReason, iClient, iWriteRequest->StatusPtr()));
+ Kern::QueueRequestComplete(iClient, iWriteRequest, aReason);
+ }
+ }
+
+
+void DChannelEthernet::Shutdown()
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf("DChannelEthernet::Shutdown()"));
+
+ // Suspend the chip and disable interrupts
+ (static_cast<DEthernet*>(iPdd))->Stop(EStopNormal);
+
+ Complete(EAll, KErrAbort);
+
+ if (iRxCompleteDfc.Queued())
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Shutdown()- Cancelling old dfc"));
+ // Ethernet interrupts are disabled; must make sure DFCs are not queued.
+ iRxCompleteDfc.Cancel();
+ }
+
+ // No harm in doing this
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Shutdown()- Completing message"));
+ iMsgQ.iMessage->Complete(KErrNone,EFalse);
+ }
+
+
+TInt DChannelEthernet::DoCreate(TInt aUnit,
+ const TDesC8* /*anInfo*/,
+ const TVersion &aVer)
+// Create the channel from the passed info.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)"));
+
+ if(!Kern::CurrentThreadHasCapability(ECapabilityCommDD,__PLATSEC_DIAGNOSTIC_STRING("Checked by ENET.LDD (Ethernet Driver)")))
+ return KErrPermissionDenied;
+
+ if (!Kern::QueryVersionSupported(TVersion(KEthernetMajorVersionNumber,
+ KEthernetMinorVersionNumber,
+ KEthernetBuildVersionNumber),
+ aVer))
+ return KErrNotSupported;
+
+ TInt r = Kern::CreateClientBufferRequest(iReadRequest, 1, TClientBufferRequest::EPinVirtual);
+ if (r != KErrNone)
+ return r;
+
+ r = Kern::CreateClientRequest(iWriteRequest);
+ if (r != KErrNone)
+ return r;
+
+ SetDfcQ(((DEthernet*)iPdd)->DfcQ(aUnit));
+ iRxCompleteDfc.SetDfcQ(iDfcQ);
+ iMsgQ.Receive();
+
+ ((DEthernet *)iPdd)->iLdd=this;
+
+ //Get config from the device
+ ((DEthernet *)iPdd)->GetConfig(iConfig);
+
+ PddCheckConfig(iConfig);
+ return KErrNone;
+ }
+
+
+void DChannelEthernet::Start()
+// Start the driver receiving.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::Start()"));
+ if (iStatus!=EClosed)
+ {
+ PddStart();
+ iStatus=EActive;
+ }
+ }
+
+
+void DChannelEthernet::ReceiveIsr()
+ // Copies data into the iFifo's buffers
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::ReceiveIsr()"));
+ TBuf8<KMaxEthernetPacket+32> * buffer;
+// TInt err;
+
+ buffer = iFIFO.GetFree();
+ if(buffer == NULL)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::ReceiveIsr()- Dropping a frame"));
+ /*err =*/ PddReceive(*buffer, EFalse); //Need to call as must drain RX buffer
+ // Should something be done about returned errors?
+ return;
+ }
+ else
+ /*err =*/ PddReceive(*buffer, ETrue);
+ // Should something be done about returned errors?
+
+ // Add another DFc as we have a buffer and is not already queued
+ if (!iRxCompleteDfc.Queued())
+ {
+ if (NKern::CurrentContext()==NKern::EInterrupt)
+ iRxCompleteDfc.Add();
+ else
+ iRxCompleteDfc.Enque();
+ return;
+ }
+
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::ReceiveIsr()- DFC already added"));
+ }
+
+
+void DChannelEthernet::CompleteRxDfc(TAny* aPtr)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::CompleteRxDfc(TAny* aPtr)"));
+ DChannelEthernet *pC=(DChannelEthernet*)aPtr;
+ pC->DoCompleteRx();
+ }
+
+
+void DChannelEthernet::DoCompleteRx()
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoCompleteRx()"));
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd isr triggered..."));
+
+
+ if (iReadRequest->IsReady())
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoCompleteRx()- Read waiting"));
+ TBuf8<KMaxEthernetPacket+32> * buffer;
+
+ buffer = iFIFO.GetNext();
+ if (buffer == NULL)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoCompleteRx()- Unexpected read request earlier"));
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd isr - miss = empty"));
+ Complete(ERx, KErrNone);
+ return;
+ }
+
+ // RX buffer has data, must scan buffer and then complete
+ TInt r = Kern::ThreadBufWrite(iClient, iClientReadBuffer, *(const TDesC8*)buffer, 0, KChunkShiftBy0, iClient);
+ iFIFO.SetNext();
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd isr - hit = rx tcp seq=%u ack=%u\n", GetTcpSeqNumber(*buffer), GetTcpAckNumber(*buffer)) );
+ Complete(ERx, r);
+ }
+ else
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd isr - skipped! no request pending\n"));
+ }
+
+ }
+
+//Override sendMsg to allow data copy in the context of client thread for WDP.
+TInt DChannelEthernet::SendMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = m.iValue;
+ TInt r = KErrNone;
+ if (id != (TInt)ECloseMsg && id != KMaxTInt)
+ {
+ if (id<0)
+ {
+ TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+ r = SendRequest(aMsg);
+ if (r != KErrNone)
+ {
+ Kern::RequestComplete(pS,r);
+ }
+ }
+ else
+ {
+ r = SendControl(aMsg);
+ }
+ }
+ else
+ {
+ r = DLogicalChannel::SendMsg(aMsg);
+ }
+ return r;
+ }
+
+
+TInt DChannelEthernet::SendControl(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = m.iValue;
+ TInt bufLen;
+ TInt bufMaxLen;
+ TEthernetConfigV01 config;
+ TEthernetCaps caps;
+ TAny* a1 = m.Ptr0();
+ TInt r = KErrNone;
+ switch(id)
+ {
+ case RBusDevEthernet::EControlConfig:
+ {
+
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::SendControl EControlConfig"));
+ Kern::KUDesInfo(*(const TDesC8*)a1, bufLen, bufMaxLen);
+ if((TUint)bufMaxLen < sizeof(TEthernetConfigV01))
+ {
+ return KErrUnderflow;
+ }
+ m.iArg[0] = &config;
+ break;
+ }
+ case RBusDevEthernet::EControlCaps:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::SendControl EControlCaps"));
+ Kern::KUDesInfo(*(const TDesC8*)a1, bufLen, bufMaxLen);
+ if((TUint)bufMaxLen < sizeof(caps))
+ {
+ return KErrUnderflow;
+ }
+ m.iArg[0] = ∩︀
+ break;
+ }
+ case RBusDevEthernet::EControlSetConfig:
+ case RBusDevEthernet::EControlSetMac:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::SendControl EControlSetConfig"));
+ Kern::KUDesInfo(*(const TDesC8*)a1, bufLen, bufMaxLen);
+ if((TUint)bufLen > sizeof(config))
+ {
+ return KErrOverflow;
+ }
+ memset(&config,0,sizeof(config));
+ TPtr8 cfg((TUint8*)&config,0,sizeof(config));
+ Kern::KUDesGet(*(TDes8*)&cfg, *(const TDesC8*)a1);
+ m.iArg[0] = (TAny*)&config;
+ break;
+ }
+ default:
+ return KErrNotSupported;
+ }
+ r = DLogicalChannel::SendMsg(aMsg);
+ if(r != KErrNone)
+ return r;
+ switch(id)
+ {
+ case RBusDevEthernet::EControlConfig:
+ {
+ Kern::InfoCopy(*(TDes8*)a1, (const TUint8*)&config, sizeof(TEthernetConfigV01));
+ break;
+ }
+ case RBusDevEthernet::EControlCaps:
+ {
+ Kern::KUDesPut(*(TDes8*)a1, (const TDesC8&)caps);
+ break;
+ }
+ }
+ return r;
+ }
+
+TInt DChannelEthernet::SendRequest(TMessageBase* aMsg)
+ {
+ TThreadMessage& m = *(TThreadMessage*)aMsg;
+ TInt id = ~m.iValue;
+ TRequestStatus* pS = (TRequestStatus*)m.Ptr0();
+ TAny* a1 = m.Ptr1();
+ TAny* a2 = m.Ptr2();
+ TInt r = KErrNone;
+ switch(id)
+ {
+ case RBusDevEthernet::ERequestWrite:
+ {
+ if(iStatus == EClosed)
+ {
+ return KErrNotReady;
+ }
+ TInt len;
+ umemget32(&len, a2, sizeof(len));
+ if(len == 0)
+ {
+ return KErrNone;
+ }
+ if(!a1)
+ {
+ return KErrArgument;
+ }
+ Kern::KUDesGet((TDes8&)iFIFO.iTxBuf, *(const TDesC8*)a1);
+ iFIFO.iTxBuf.SetLength(len);
+ iWriteRequest->SetStatus(pS);
+ break;
+ }
+ case RBusDevEthernet::ERequestRead:
+ {
+ TInt len;
+ TInt bufLen;
+ TInt bufMaxLen;
+ umemget32(&len, a2, sizeof(len));
+ if(len == 0)
+ {
+ return KErrNone;
+ }
+ Kern::KUDesInfo(*(const TDesC8*)a1, bufLen, bufMaxLen);
+ if(bufMaxLen < Abs(len))
+ {
+ return KErrGeneral;
+ }
+ if(bufLen != 0)
+ {
+ Kern::KUDesSetLength(*(TDes8*)a1, 0);
+ }
+ r = iReadRequest->StartSetup(pS);
+ if (r != KErrNone)
+ {
+ return r;
+ }
+ r = iReadRequest->AddBuffer(iClientReadBuffer, a1);
+ if (r != KErrNone)
+ {
+ return KErrNoMemory;
+ }
+ iReadRequest->EndSetup();
+ break;
+ }
+#ifdef ETH_CHIP_IO_ENABLED
+ case RBusDevEthernet::EChipDiagIOCtrl:
+ {
+ Kern::KUDesGet((TDes8&)iChipInfo, *(const TDesC8*)a1);
+ break;
+ }
+#endif
+ default:
+ return KErrNotSupported;
+ }
+ r = DLogicalChannel::SendMsg(aMsg);
+#ifdef ETH_CHIP_IO_ENABLED
+ if(r == KErrNone)
+ {
+ switch(id)
+ {
+ case RBusDevEthernet::EChipDiagIOCtrl:
+ {
+ Kern::KUDesPut(*(TDes8*)a1, (const TDesC8&)iChipInfo);
+ Kern::RequestComplete(pS,r);
+ break;
+ }
+ }
+ }
+#endif
+ return r;
+ }
+
+void DChannelEthernet::HandleMsg(TMessageBase* aMsg)
+ {
+ TThreadMessage& m=*(TThreadMessage*)aMsg;
+ TInt id=m.iValue;
+
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd: DChannelEthernet::HandleMsg(TMessageBase* aMsg) id=%d\n", id));
+
+ if (id==(TInt)ECloseMsg)
+ {
+ Shutdown();
+ return;
+ }
+ else if (id==KMaxTInt)
+ {
+ // DoCancel
+ DoCancel(m.Int0());
+ m.Complete(KErrNone,ETrue);
+ return;
+ }
+
+ if (id<0)
+ {
+ // DoRequest
+ TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+ TInt r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2());
+ //Kern::Printf(" >ldd: about to complete TThreadMessage id=%d...\n", id);
+ m.Complete(r,ETrue);
+ }
+ else
+ {
+ // DoControl
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd: do control id=%d...\n", id));
+ TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+ m.Complete(r,ETrue);
+ }
+ }
+
+
+void DChannelEthernet::DoCancel(TInt aMask)
+// Cancel an outstanding request.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoCancel(TInt aMask = %d)", aMask));
+
+ if (aMask & RBusDevEthernet::ERequestReadCancel)
+ {
+ if (iRxCompleteDfc.Queued())
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf("DChannelEthernet::DoCancel()- Cancelling old dfc"));
+ iRxCompleteDfc.Cancel();
+ }
+ Complete(ERx,KErrCancel);
+ }
+
+ if (aMask & RBusDevEthernet::ERequestWriteCancel)
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf("> ldd: DChannelEthernet::DoCancel - Completing write cancel\n"));
+ Complete(ETx,KErrCancel);
+ }
+ }
+
+
+TInt DChannelEthernet::DoRequest(TInt aReqNo, TRequestStatus* /*aStatus*/, TAny* a1, TAny* /*a2*/)
+// Async requests.
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)"));
+ // First check if we have started
+ if (iStatus==EOpen)
+ {
+ Start();
+ }
+
+ // Now we can dispatch the request
+ TInt r=KErrNone;
+ TInt len=0;
+ switch (aReqNo)
+ {
+ case RBusDevEthernet::ERequestRead:
+ InitiateRead(a1,len);
+ break;
+
+ case RBusDevEthernet::ERequestWrite:
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd tx: RBusDevEthernet::ERequestWrite..."));
+ InitiateWrite(a1,len);
+ break;
+#ifdef ETH_CHIP_IO_ENABLED
+ case RBusDevEthernet::EChipDiagIOCtrl:
+ {
+ r=((DEthernet*)iPdd)->BgeChipIOCtrl(iChipInfo);
+ break;
+ }
+#endif
+ }
+ return r;
+ }
+
+
+void DChannelEthernet::InitiateRead(TAny* /*aRxDes*/, TInt aLength)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::InitiateRead(TAny *aRxDes, TInt aLength)"));
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd client triggered read...\n"));
+ iRxLength=Abs(aLength);
+ TBuf8<KMaxEthernetPacket+32> * next;
+ next = iFIFO.GetNext();
+ if (next == NULL)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::InitiateRead - RX buffer empty"));
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd client - miss = rx buf empty...\n"));
+ return;
+ }
+
+ iFIFO.SetNext();
+ // RX buffer has data, must scan buffer and then complete
+ TInt r = Kern::ThreadBufWrite(iClient, iClientReadBuffer, *(const TDesC8*)next, 0, KChunkShiftBy0, iClient);
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd client - hit = rx tcp seq=%u ack=%d\n", GetTcpSeqNumber(*next), GetTcpAckNumber(*next)) );
+ Complete(ERx,r);
+ }
+
+
+void DChannelEthernet::InitiateWrite(TAny* /*aTxDes*/, TInt /*aLength*/)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::InitiateWrite(TAny *aTxDes, TInt aLength)"));
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >ldd tx: tcp seq=%u ack=%u\n", GetTcpSeqNumber(iFIFO.iTxBuf), GetTcpAckNumber(iFIFO.iTxBuf)) );
+ if(PddSend(iFIFO.iTxBuf) != KErrNone)
+ Complete(ETx, KErrCommsLineFail);
+ else
+ Complete(ETx, KErrNone);
+ }
+
+
+TInt DChannelEthernet::SetConfig(TEthernetConfigV01& c)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::SetConfig(TEthernetConfigV01& c)"));
+ TInt r;
+
+ if ((r=ValidateConfig(c))!=KErrNone)
+ return r;
+
+ iConfig = c;
+
+ PddConfigure(iConfig);
+
+ return r;
+ }
+
+
+TInt DChannelEthernet::SetMAC(TEthernetConfigV01& c)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::SetMAC(TEthernetConfigV01& c)"));
+ TInt r;
+
+ if ((r=ValidateConfig(c))!=KErrNone)
+ return r;
+
+ iConfig = c;
+
+ MacConfigure(iConfig);
+ PddConfigure(iConfig);
+
+ return r;
+ }
+
+
+TInt DChannelEthernet::DoControl(TInt aFunction, TAny* a1, TAny* /*a2*/)
+// Sync requests.
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf("DChannelEthernet::DoControl(TInt aFunction, TAny* a1, TAny* a2)") );
+ TInt r=KErrNone;
+
+ switch (aFunction)
+ {
+ case RBusDevEthernet::EControlConfig:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoControl EControlConfig"));
+ *(TEthernetConfigV01*)a1 = iConfig;
+ break;
+ }
+ case RBusDevEthernet::EControlSetConfig:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoControl EControlSetConfig"));
+ r=SetConfig(*(TEthernetConfigV01*)a1);
+ break;
+ }
+ case RBusDevEthernet::EControlSetMac:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoControl EControlSetMac"));
+ r = SetMAC(*(TEthernetConfigV01*)a1);
+ break;
+ }
+ case RBusDevEthernet::EControlCaps:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoControl EControlCaps"));
+ TEthernetCaps capsBuf;
+ PddCaps(capsBuf);
+ *(TEthernetCaps*)a1 = capsBuf;
+ break;
+ }
+ default:
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernet::DoControl default 0x%x", aFunction));
+ r=KErrNotSupported;
+ }
+ }
+ return(r);
+ }
+
+// Implementation of driver Rx / Tx FIFO class.
+DChannelEthernetFIFO::DChannelEthernetFIFO()
+ {
+ iRxQueIterNext = 0;
+ iRxQueIterFree = 0;
+ iNumFree = KNumRXBuffers;
+ }
+
+DChannelEthernetFIFO::~DChannelEthernetFIFO()
+ {
+ }
+
+TBuf8<KMaxEthernetPacket+32> * DChannelEthernetFIFO::GetFree()
+ // Return location of current Rx FIFO free element
+ {
+ if(iNumFree == 0)
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf("DChannelEthernetFIFO::GetFree()- No free free buffers"));
+ return NULL;
+ }
+
+ iNumFree--;
+
+ TBuf8<KMaxEthernetPacket+32> &rxBuf = iRxBuf[iRxQueIterFree++];
+ if(iRxQueIterFree == KNumRXBuffers)
+ {
+ iRxQueIterFree = 0;
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernetFIFO::GetFree()- free wrap return 0"));
+ }
+
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernetFIFO::GetFree()- free return %d", iRxQueIterFree));
+ return &rxBuf;
+ }
+
+
+TBuf8<KMaxEthernetPacket+32> * DChannelEthernetFIFO::GetNext()
+ // Return location of next data element within Rx FIFO
+ {
+ __KTRACE_OPT2(KNETWORK1, KNETWORK2, Kern::Printf(" >LDDx: GetNext() - iNumFree=%d iRxQueIterNext(read)=%d iRxQueIterFree(write)=%d", iNumFree, iRxQueIterNext, iRxQueIterFree));
+
+ if(iNumFree == KNumRXBuffers)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernetFIFO::GetNext()- No data waiting"));
+ return NULL;
+ }
+
+ TBuf8<KMaxEthernetPacket+32> &rxBuf = iRxBuf[iRxQueIterNext++];
+ if(iRxQueIterNext == KNumRXBuffers)
+ {
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernetFIFO::GetNext()- Wrap next return 0"));
+ iRxQueIterNext = 0;
+ }
+
+ __KTRACE_OPT(KNETWORK1, Kern::Printf("DChannelEthernetFIFO::GetNext()- Data found return %d", iRxQueIterNext));
+ return &rxBuf;
+ }
+
+void DChannelEthernetFIFO::SetNext()
+ // Increment location of next data element within Rx FIFO
+ {
+ // locked since iNumFree is decremented in function which could be called
+ // from interrupt context
+ // DENNIS: SOUNDS DODGY
+ __e32_atomic_add_ord32(&iNumFree, 1);
+ }
+
+/** @addtogroup enet Ethernet Drivers
+ * Kernel Ethernet Support
+ */
+
+/** @addtogroup enet_ldd Driver LDD's
+ * @ingroup enet
+ */
+
+/**
+ * @addtogroup enet_ldd_nopm_nopccard Ethernet LDD Not PCMCIA and No Power Managment
+ * @ingroup enet_ldd
+ * @{
+ */
+
+/**
+ * Real entry point from the Kernel: return a new driver
+ */
+DECLARE_STANDARD_LDD()
+ {
+ return new DDeviceEthernet;
+ }
+
+
+/** @} */ // end of assabet group
+
+
+
+