os/kernelhwsrv/userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcldd.cpp
Update contrib.
2 * Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
24 #include "cbulkonlytransport.h"
25 #include "cbulkonlytransportusbcldd.h"
26 #include "usbmsshared.h"
27 #include "massstoragedebug.h"
28 #include "cusbmassstorageserver.h"
30 #define InEndpoint EEndpoint1
31 #define OutEndpoint EEndpoint2
33 //This value defined in USB Mass Storage Bulk Only Transrt spec and not supposed to be changed
34 LOCAL_D const TInt KRequiredNumberOfEndpoints = 2; // in addition to endpoint 0.
36 LOCAL_D const TInt KUsbNumInterfacesOffset = 4;
38 ////////////////////////////////////
40 Called by CBulkOnlyTransportUsbcLdd to create an instance of CControlInterfaceUsbcLdd
42 @param aParent reference to the CBulkOnlyTransportUsbcLdd
46 CControlInterfaceUsbcLdd* CControlInterfaceUsbcLdd::NewL(CBulkOnlyTransportUsbcLdd& aParent)
48 CControlInterfaceUsbcLdd* self = new(ELeave) CControlInterfaceUsbcLdd(aParent);
49 CleanupStack::PushL(self);
51 CActiveScheduler::Add(self);
57 void CControlInterfaceUsbcLdd::ConstructL()
65 @param aParent reference to the CBulkOnlyTransportUsbcLdd
67 CControlInterfaceUsbcLdd::CControlInterfaceUsbcLdd(CBulkOnlyTransportUsbcLdd& aParent)
68 :CActive(EPriorityStandard),
78 CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd()
80 __FNLOG("CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd ");
86 Called by CBulkOnlyTransport HwStart to start control interface
88 TInt CControlInterfaceUsbcLdd::Start()
90 __FNLOG("CControlInterfaceUsbcLdd::Start ");
91 TInt res = ReadEp0Data();
97 Called by desctructor of CBulkOnlyTransportUsbcLdd to stop control interface
99 void CControlInterfaceUsbcLdd::Stop()
101 __FNLOG("CControlInterfaceUsbcLdd::Stop ");
104 __PRINT(_L("Not active\n"));
108 __PRINT(_L("\nStopping...\n"));
111 iCurrentState = ENone;
118 Cancel outstanding request (if any)
120 void CControlInterfaceUsbcLdd::DoCancel()
122 __FNLOG("CControlInterfaceUsbcLdd::DoCancel ");
123 switch(iCurrentState)
126 iParent.Ldd().ReadCancel(EEndpoint0);
129 iParent.Ldd().WriteCancel(EEndpoint0);
132 __PRINT(_L("\nWrong state !\n"));
133 __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
139 Implement CControlInterfaceUsbcLdd state machine
141 void CControlInterfaceUsbcLdd::RunL()
143 __FNLOG("CControlInterfaceUsbcLdd::RunL ");
144 if (iStatus != KErrNone)
146 __PRINT1(_L("Error %d in RunL\n"), iStatus.Int());
153 switch (iCurrentState)
164 __PRINT(_L(" error: (Shouldn't end up here...)\n"));
165 __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
173 Post a read request to EEndpoint0 to read request header
175 TInt CControlInterfaceUsbcLdd::ReadEp0Data()
177 __FNLOG("CControlInterfaceUsbcLdd::ReadEp0Data ");
180 __PRINT(_L("Still active\n"));
181 return KErrServerBusy;
183 iParent.Ldd().Read(iStatus, EEndpoint0, iData, KRequestHdrSize);
185 iCurrentState = EReadEp0Data;
193 Decode request header and do appropriate action - get max LUN info or post a reset request
195 void CControlInterfaceUsbcLdd::DecodeEp0Data()
197 __FNLOG("CControlInterfaceUsbcLdd::DecodeEp0Data ");
200 __PRINT(_L("Still active\n"));
201 __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive));
205 TInt err = iRequestHeader.Decode(iData);
210 switch(iRequestHeader.iRequest)
213 // GET MAX LUN (0xFE)
215 case TUsbRequestHdr::EReqGetMaxLun:
217 __PRINT1(_L("DecodeEp0Data : 'Get Max LUN' Request MaxLun = %d"),iParent.MaxLun() );
219 if ( iRequestHeader.iRequestType != 0xA1 //value from USB MS BOT spec
220 || iRequestHeader.iIndex > 15
221 || iRequestHeader.iValue != 0
222 || iRequestHeader.iLength != 1)
224 __PRINT(_L("GetMaxLun command packet check error"));
225 iParent.Ldd().EndpointZeroRequestError();
228 iData.FillZ(1); //Return only 1 byte to host
229 iData[0] = static_cast<TUint8>(iParent.MaxLun()); // Supported Units
230 iParent.Ldd().Write(iStatus, EEndpoint0, iData, 1);
232 iCurrentState = ESendMaxLun;
240 case TUsbRequestHdr::EReqReset:
242 __PRINT(_L("DecodeEp0Data : 'Mass Storage Reset' Request"));
244 if ( iRequestHeader.iRequestType != 0x21 //value from USB MS BOT spec
245 || iRequestHeader.iIndex > 15
246 || iRequestHeader.iValue != 0
247 || iRequestHeader.iLength != 0)
249 __PRINT(_L("MSC Reset command packet check error"));
250 iParent.Ldd().EndpointZeroRequestError();
254 iParent.Controller().Reset();
255 iParent.HwStart(ETrue);
257 err = iParent.Ldd().SendEp0StatusPacket();
266 __PRINT(_L("DecodeEp0Data : Unknown Request"));
270 ReadEp0Data(); //try to get another request
275 // --- class CBulkOnlyTransportUsbcLdd ---------------------------------------------------------
278 CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd(TInt aNumDrives,CUsbMassStorageController& aController)
279 :CBulkOnlyTransport(aNumDrives, aController),
282 __FNLOG("CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd");
286 Constructs the CBulkOnlyTransportUsbcLdd object
288 void CBulkOnlyTransportUsbcLdd::ConstructL()
290 __FNLOG("CBulkOnlyTransportUsbcLdd::ConstructL()");
291 iControlInterface = CControlInterfaceUsbcLdd::NewL(*this);
292 iDeviceStateNotifier = CActiveDeviceStateNotifierBase::NewL(*this, *this);
293 CActiveScheduler::Add(this);
296 CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd()
298 __FNLOG("CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd");
299 if (iInterfaceConfigured)
301 delete iControlInterface ;
302 delete iDeviceStateNotifier;
306 RDevUsbcClient& CBulkOnlyTransportUsbcLdd::Ldd()
313 Set or unset configuration descriptor for USB MassStorage Bulk Only transport
315 @param aUnset indicate whether set or unset descriptor
316 @return KErrNone if operation was completed successfully, errorcode otherwise
318 TInt CBulkOnlyTransportUsbcLdd::SetupConfigurationDescriptor(TBool aUnset)
320 __FNLOG("CBulkOnlyTransportUsbcLdd::SetupConfigurationDescriptor");
323 if ((ret = iLdd.Open(0)) != KErrNone)
326 TInt configDescriptorSize(0);
327 iLdd.GetConfigurationDescriptorSize(configDescriptorSize);
328 if (static_cast<TUint>(configDescriptorSize) != KUsbDescSize_Config)
333 TBuf8<KUsbDescSize_Config> configDescriptor;
334 ret = iLdd.GetConfigurationDescriptor(configDescriptor);
340 // I beleive that other fields setted up during LDD initialisation
343 --configDescriptor[KUsbNumInterfacesOffset];
347 ++configDescriptor[KUsbNumInterfacesOffset];
349 ret = iLdd.SetConfigurationDescriptor(configDescriptor);
359 Set up interface descriptor
361 @return KErrNone if operation was completed successfully, errorcode otherwise
363 TInt CBulkOnlyTransportUsbcLdd::SetupInterfaceDescriptors()
365 __FNLOG("CBulkOnlyTransportUsbcLdd::SetupInterfaceDescriptors");
367 TUsbDeviceCaps d_caps;
368 TInt ret = iLdd.DeviceCaps(d_caps);
373 TInt totalEndpoints = d_caps().iTotalEndpoints;
374 if (totalEndpoints < KRequiredNumberOfEndpoints)
376 return KErrHardwareNotAvailable;
380 TUsbcEndpointData data[KUsbcMaxEndpoints];
381 TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
382 ret = iLdd.EndpointCaps(dataptr);
388 // Set the active interface
389 TUsbcInterfaceInfoBuf ifc;
391 TBool foundBulkIN = EFalse;
392 TBool foundBulkOUT = EFalse;
394 for (TInt i = 0; i < totalEndpoints ; i++)
396 const TUsbcEndpointCaps* caps = &data[i].iCaps;
397 const TInt maxPacketSize = caps->MaxPacketSize();
399 (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) == (KUsbEpTypeBulk | KUsbEpDirIn))
401 // InEndpoint is going to be our TX (IN, write) endpoint
402 ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
403 if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) == KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
404 ifc().iEndpointData[0].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA|KUsbcEndpointInfoFeatureWord1_DoubleBuffering;
405 ifc().iEndpointData[0].iDir = KUsbEpDirIn;
406 ifc().iEndpointData[0].iSize = maxPacketSize;
407 ifc().iEndpointData[0].iInterval_Hs = 0;
409 if (++ep_found == KRequiredNumberOfEndpoints)
416 (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) == (KUsbEpTypeBulk | KUsbEpDirOut))
418 // OutEndpoint is going to be our RX (OUT, read) endpoint
419 ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
420 if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) == KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
421 ifc().iEndpointData[1].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA|KUsbcEndpointInfoFeatureWord1_DoubleBuffering;
422 ifc().iEndpointData[1].iDir = KUsbEpDirOut;
423 ifc().iEndpointData[1].iSize = maxPacketSize;
424 ifc().iEndpointData[1].iInterval_Hs = 0;
425 foundBulkOUT = ETrue;
426 if (++ep_found == KRequiredNumberOfEndpoints)
433 if (ep_found != KRequiredNumberOfEndpoints)
435 return KErrHardwareNotAvailable;
438 _LIT16(string, "USB Mass Storage Interface");
439 ifc().iString = const_cast<TDesC16*>(&string);
440 ifc().iTotalEndpointsUsed = KRequiredNumberOfEndpoints;
441 ifc().iClass.iClassNum = 0x08; // Mass Storage
442 ifc().iClass.iSubClassNum = 0x06; // SCSI Transparent Command Set
443 ifc().iClass.iProtocolNum = 0x50; // Bulk Only Transport
445 TUint bandwidth_priority = (EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault);
446 if (d_caps().iHighSpeed)
448 // If this device supports USB High-speed, then we request 64KB buffers
449 // (otherwise the default 4KB ones will do).
450 bandwidth_priority = (EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2);
451 // Also, tell the Protocol about it, because it might want to do some
453 iProtocol->ReportHighSpeedDevice();
455 ret = iLdd.SetInterface(0, ifc, bandwidth_priority);
459 void CBulkOnlyTransportUsbcLdd::ReleaseInterface()
461 iLdd.ReleaseInterface(0);
464 TInt CBulkOnlyTransportUsbcLdd::StartControlInterface()
466 return iControlInterface->Start();
469 void CBulkOnlyTransportUsbcLdd::CancelControlInterface()
471 iControlInterface->Cancel();
474 void CBulkOnlyTransportUsbcLdd::ActivateDeviceStateNotifier()
476 iDeviceStateNotifier->Activate();
479 void CBulkOnlyTransportUsbcLdd::CancelDeviceStateNotifier()
481 iDeviceStateNotifier->Cancel();
484 void CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests()
486 __FNLOG("CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests");
487 iLdd.WriteCancel(InEndpoint);
488 iLdd.ReadCancel(OutEndpoint);
491 void CBulkOnlyTransportUsbcLdd::AllocateEndpointResources()
493 TUsbDeviceCaps d_caps;
494 TInt ret = iLdd.DeviceCaps(d_caps);
497 if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) != KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
499 // Set up DMA if possible (errors are non-critical)
500 TInt err = iLdd.AllocateEndpointResource(OutEndpoint, EUsbcEndpointResourceDMA);
503 __PRINT1(_L("Set DMA on OUT endpoint failed with error code: %d"), err);
505 err = iLdd.AllocateEndpointResource(InEndpoint, EUsbcEndpointResourceDMA);
508 __PRINT1(_L("Set DMA on IN endpoint failed with error code: %d"), err);
511 // Set up Double Buffering if possible (errors are non-critical)
512 err = iLdd.AllocateEndpointResource(OutEndpoint, EUsbcEndpointResourceDoubleBuffering);
515 __PRINT1(_L("Set Double Buffering on OUT endpoint failed with error code: %d"), err);
517 err = iLdd.AllocateEndpointResource(InEndpoint, EUsbcEndpointResourceDoubleBuffering);
520 __PRINT1(_L("Set Double Buffering on IN endpoint failed with error code: %d"), err);
526 TInt CBulkOnlyTransportUsbcLdd::GetDeviceStatus(TUsbcDeviceState& deviceStatus)
528 return iLdd.DeviceStatus(deviceStatus);
531 void CBulkOnlyTransportUsbcLdd::FlushData()
534 const TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
535 if (err != KErrNone || bytes <= 0)
537 __PRINT1(_L("Error: err=%d bytes=%d"), bytes);
541 __PRINT1(_L("RxBuffer has %d bytes"), bytes);
542 ReadAndDiscardData(bytes);
546 * Read out rest data from OutEndpoint and discard them
548 void CBulkOnlyTransportUsbcLdd::ReadAndDiscardData(TInt aBytes)
550 __FNLOG("CBulkOnlyTransportUsbcLdd::ReadAndDiscardData");
551 iDiscardBuf.SetMax();
552 const TUint bufsize = static_cast<TUint>(iDiscardBuf.Length());
553 TRequestStatus status;
556 __PRINT1(_L("Bytes still to be read: %d\n"), aBytes);
557 iLdd.ReadOneOrMore(status, OutEndpoint, iDiscardBuf, bufsize);
558 User::WaitForRequest(status);
559 TInt err = status.Int();
565 aBytes -= iDiscardBuf.Length();
570 Called by the protocol to determine how many bytes of data are available in the read buffer.
572 @return The number of bytes available in the read buffer
574 TInt CBulkOnlyTransportUsbcLdd::BytesAvailable()
577 TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes);
584 void CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear()
586 __FNLOG("CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear");
588 // Now stall this endpoint
589 __PRINT1(_L("Stalling endpoint %d"), InEndpoint);
590 TInt r = iLdd.HaltEndpoint(InEndpoint);
593 __PRINT2(_L("Error: stalling ep %d failed: %d"), InEndpoint, r);
595 TEndpointState ep_state;
599 // Wait for 10ms before checking the ep status
601 iLdd.EndpointStatus(InEndpoint, ep_state);
604 // 5.5 secs should be enough (see 9.2.6.1 Request Processing Timing)
605 __PRINT1(_L("Error: Checked for ep %d de-stall for 5.5s - giving up now"), InEndpoint);
606 // We can now only hope for a Reset Recovery
609 } while ((ep_state == EEndpointStateStalled) && iStarted);
610 __PRINT2(_L("Checked for ep %d de-stall: %d time(s)"), InEndpoint, i);
615 Read CBW data (KCbwLength) from the host into the read buffer.
617 void CBulkOnlyTransportUsbcLdd::ReadCBW()
619 __FNLOG("CBulkOnlyTransportUsbcLdd::ReadCBW");
622 __PRINT(_L("Still active\n"));
623 __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
628 iLdd.ReadUntilShort(iStatus, OutEndpoint, iCbwBuf, KCbwLength);
630 iCurrentState = EWaitForCBW;
634 void CBulkOnlyTransportUsbcLdd::ExpireData(TAny* /*aAddress*/)
636 // Intentionally left blank
639 void CBulkOnlyTransportUsbcLdd::ProcessCbwEvent()
646 Request data form the host for the protocol
648 @param aLength amount of data (in bytes) to be received from the host
650 void CBulkOnlyTransportUsbcLdd::ReadData(TUint aLength)
652 __FNLOG("CBulkOnlyTransportUsbcLdd::ReadData");
655 __PRINT(_L("Still active\n"));
656 __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
660 SetReadDataBufPtr(aLength);
661 iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, aLength);
663 iCurrentState = EReadingData;
667 void CBulkOnlyTransportUsbcLdd::WriteUsb(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
669 iLdd.Write(aStatus, InEndpoint, aDes, aLength, aZlpRequired);
672 void CBulkOnlyTransportUsbcLdd::SetCbwPtr()
674 iCbwBufPtr.Set(iCbwBuf.Ptr(), iCbwBuf.Length());
677 TPtr8& CBulkOnlyTransportUsbcLdd::SetCommandBufPtr(TUint aLength)
679 iCommandBufPtr.Set((TUint8*) iCommandBuf.Ptr(), aLength, aLength );
680 return iCommandBufPtr;
683 void CBulkOnlyTransportUsbcLdd::SetReadDataBufPtr(TUint aLength) //Write10(Host->Device
687 iDataBuf1.SetLength(aLength);
688 iReadBufPtr.Set(iDataBuf1.LeftTPtr(iDataBuf1.Length()));
693 iDataBuf2.SetLength(aLength);
694 iReadBufPtr.Set(iDataBuf2.LeftTPtr(iDataBuf2.Length()));
699 TPtr8& CBulkOnlyTransportUsbcLdd::SetDataBufPtr() //Read10(Device->Host)
703 iDataBufPtr.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize);
708 iDataBufPtr.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize);
714 void CBulkOnlyTransportUsbcLdd::SetPaddingBufPtr(TUint aLength)
716 iPaddingBufPtr.Set((TUint8*) iBuf.Ptr(), aLength, aLength );
720 void CBulkOnlyTransportUsbcLdd::SetCswBufPtr(TUint aLength)
722 iCswBufPtr.Set((TUint8*) iCswBuf.Ptr(), aLength, aLength );
725 void CBulkOnlyTransportUsbcLdd::ProcessReadingDataEvent()
732 ret = iProtocol->ReadComplete(KErrNone);
735 TUint deviceDataLength = iBufSize; // This is the amount (maximum in case of SC Ldd) to be read next.
737 if(ret == KErrCompletion)
739 // The protocol has indicated with KErrCompletion that sufficient
740 // data is available in the buffer to process the transfer immediately.
742 iDataResidue -= iReadBufPtr.Length();
743 SetReadDataBufPtr(deviceDataLength);
745 iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, deviceDataLength);
746 User::WaitForRequest(iStatus);
747 if (iStatus != KErrNone)
749 // An error occurred - halt endpoints for reset recovery
750 __PRINT1(_L("Error %d in EReadingData, halt endpoints \n"), iStatus.Int());
755 else if(ret == KErrNotReady)
757 // The protocol has indicated with KErrNotReady that insufficient
758 // data is available in the buffer, so should wait for it to arrive
760 iDataResidue -= iReadBufPtr.Length();
761 ReadData(deviceDataLength);
766 // The protocol has indicated that transfer is
767 // complete, so send the CSW response to the host.
768 iDataResidue -= iReadBufPtr.Length();
773 iCmdStatus = ECommandFailed;
778 __PRINT(_L("Discarding residue"));
779 // we have to read as much data as available that host PC sends;
780 // otherwise, bulk-out endpoint will need to keep sending NAK back.
781 ReadAndDiscardData(iDataResidue);
783 SendCSW(iCbwTag, iDataResidue, iCmdStatus);
790 void CBulkOnlyTransportUsbcLdd::DiscardData(TUint aLength)
792 iBuf.SetLength(KBOTMaxBufSize);
794 TRequestStatus status;
798 if (aLength - c > KBOTMaxBufSize)
800 len = KBOTMaxBufSize;
807 iLdd.Read(status, OutEndpoint, iBuf, len);
808 User::WaitForRequest(status);
813 void CBulkOnlyTransportUsbcLdd::WriteToClient(TUint aLength)
816 iLdd.Read(iStatus, OutEndpoint, iDataBufPtr, aLength);
817 User::WaitForRequest(iStatus);
818 iProtocol->ReadComplete(KErrGeneral);
821 #ifdef MSDC_MULTITHREADED
822 void CBulkOnlyTransportUsbcLdd::GetBufferPointers(TPtr8& aDes1, TPtr8& aDes2)
824 aDes1.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize);
825 aDes2.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize);
829 void CBulkOnlyTransportUsbcLdd::Activate(TRequestStatus& aStatus, TUint& aDeviceState)
831 iLdd.AlternateDeviceStatusNotify(aStatus, aDeviceState);
835 void CBulkOnlyTransportUsbcLdd::Cancel()
837 iLdd.AlternateDeviceStatusNotifyCancel();