diff -r 000000000000 -r a41df078684a kernel/eka/include/d32usbdi.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/include/d32usbdi.inl Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,538 @@ +// Copyright (c) 2007-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: +// + +/** + + The driver's name + + @return The name of the driver + + @internalComponent +*/ +const TDesC& RUsbInterface::Name() + { + _LIT(KDriverName,"USBDI"); + return KDriverName; + } + +/** +The driver's version + +@return The version number of the driver + +@internalComponent +*/ +TVersion RUsbInterface::VersionRequired() + { + const TInt KMajorVersionNumber=1; + const TInt KMinorVersionNumber=0; + const TInt KBuildVersionNumber=KE32BuildVersionNumber; + return TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); + } + + + +#ifndef __KERNEL_MODE__ +RUsbInterface::RUsbInterface() + : iHeadInterfaceDescriptor(NULL) + , iInterfaceDescriptorData(NULL) + , iTransferStrategy(NULL) + , iAlternateSetting(0) + { + } + +/** +Signals to the hub driver that this interface is idle and may be suspended. +As suspend operates at the device level, this will only trigger a removal of bus activity if all interfaces +associated with the device are marked as suspended. + +@param [in] aResumeSignal The TRequestStatus that will be completed when the interface is resumed. +*/ +void RUsbInterface::PermitSuspendAndWaitForResume(TRequestStatus& aResumeSignal) + { + DoRequest(ESuspend, aResumeSignal); + } + +/** +Cancel the outstanding permission to suspend. +*/ +void RUsbInterface::CancelPermitSuspend() + { + DoCancel(ECancelSuspend); + } + +/** +Cancel the outstanding PermitSuspendAndWaitForResume request with KErrCancel +*/ +void RUsbInterface::CancelWaitForResume() + { + DoCancel(ECancelWaitForResume); + } + +/** +Request or clear the interface's remote wakeup flag. If any interface on the device +has this flag set, suspending the device will cause it to have remote wakeup capability +enabled. This function may only be called when the interface is active -- the device will +not be woken to change the status if it is currently suspended. +Note that clearing this flag will not prevent a device from using remote wakeup -- this +will happen only if all interfaces on the device do not require it. +By default the device will not have remote wakeup enabled. + +@param aAllowed ETrue if remote wakeup should be permitted, EFalse if this interface does +not require it. + +@return KErrNotReady if two calls have been made in succession with the same parameter. +KErrUsbDeviceSuspended if the interface is currently marked as suspended. +*/ +TInt RUsbInterface::PermitRemoteWakeup(TBool aAllowed) + { + return DoControl(EPermitRemoteWakeup, (TAny*)aAllowed); + } + + +/** +Select the specified alternate interface. + +Asserts that all open pipes have been closed. + +@param [in] aAlternateInterface The alternate interface to select. + +@return KErrArgument if the specified alternate interface does not exist. +@return KErrOverflow if selecting this alternate interface would overcommit the bus' bandwidth. +*/ +TInt RUsbInterface::SelectAlternateInterface(TInt aAlternateInterface) + { + TInt err = DoControl(ESelectAlternateInterface, (TAny*)aAlternateInterface); + if(err == KErrNone) + { + iAlternateSetting = aAlternateInterface; + } + return err; + } + +TInt RUsbInterface::GetStringDescriptor(TDes8& aStringDescriptor, TUint8 aIndex, TUint16 aLangId) + { + TUint32 params; + params = aIndex | (aLangId << 16); + return DoControl(EGetStringDescriptor, &aStringDescriptor, ¶ms); + } + + +/** +Performs an Endpoint 0 transfer. +*/ +void RUsbInterface::Ep0Transfer(TUsbTransferRequestDetails& aDetails, const TDesC8& aSend, TDes8& aRecv, TRequestStatus& aRequest) + { + aDetails.iSend = &aSend; + aDetails.iRecv = &aRecv; + DoRequest(EEp0Transfer, aRequest, (TAny*)&aDetails); + } + +/** +Cancel an Endpoint 0 transfer. +*/ +void RUsbInterface::CancelEP0Transfer() + { + DoCancel(ECancelEp0Transfer); + } + +/** +Establish a pipe between host and device. The RUsbPipe object returned is ready for use. + +@param aPipe The pipe to connect to the remote endpoint. [out] +@param aEndpoint The endpoint on the remote device to connect to. [in] +@param aUseDMA In future implementations where DMA is supported this flag indicates DMA must be used. The Open attempt will fail if DMA cannot be offered on the pipe. [in] + +@return KErrArgument if the specified endpoint does not exist. +@see SelectAlternateInterface +*/ +TInt RUsbInterface::OpenPipeForEndpoint(RUsbPipe& aPipe, TInt aEndpoint, TBool /*aUseDMA*/) + { + if(aPipe.iHandle) + { + return KErrInUse; + } + + TInt err = GetEndpointDescriptor(iAlternateSetting, aEndpoint, aPipe.iHeadEndpointDescriptor); + // Allow KErrNotFound as audio endpoint descriptors are not valid endpoint descriptors + if ((err == KErrNone) || (err == KErrNotFound)) + { + TUint32 pipeHandle; + err = DoControl(EOpenPipe, &pipeHandle, reinterpret_cast(aEndpoint)); + if (err == KErrNone) + { + aPipe.iHandle = pipeHandle; + aPipe.iInterface = this; + } + } + + return err; + } + +/** +@internalComponent +*/ +TInt RUsbInterface::AllocateSharedChunk(RChunk& aChunk, TInt aSize, TInt& aOffset) + { + TInt chunkHandle = 0; + RUsbInterface::TChunkRequestDetails details; + details.iRequestSize = aSize; + details.iChunkHandle = &chunkHandle; + details.iOffset = &aOffset; + TInt err = DoControl(EAllocChunk, &details); + if(err == KErrNone) + { + aChunk.SetHandle(chunkHandle); + } + return err; + } + +/** +Return the section of the USB Configuration Descriptor under this interface, including any alternate +interfaces. + +Note: the supplied TUsbInterfaceDescriptor is owned by the caller, but any descriptor objects linked to it +remain the property of the RUsbInterface object. Memory leaks will result if the head pointer is not +cleaned up, but the pointed to objects should not be destroyed. + +@param [out] aDescriptor The supplied TUsbInterfaceDescriptor object will be populated from the data retrieved from +the device. Note that the caller owns the head of the list, but not any children or peers. + +@return System wide error code. +*/ +TInt RUsbInterface::GetInterfaceDescriptor(TUsbInterfaceDescriptor& aDescriptor) + { + if (!iHeadInterfaceDescriptor) + { + return KErrNotReady; + } + + aDescriptor = *iHeadInterfaceDescriptor; + return KErrNone; + } + +/** +Find and return the section of the USB Configuration Descriptor under the supplied alternate interface. + +Note: the supplied TUsbInterfaceDescriptor is owned by the caller, but any descriptor objects linked to it +remain the property of the RUsbInterface object. Memory leaks will result if the head pointer is not +cleaned up, but the pointed to objects should not be destroyed. + +@param aAlternateInterface The alternate interface number to return the descriptor for. [in] +@param aDescriptor The supplied TUsbInterfaceDescriptor object will be populated from the data retrieved from +the device. Note that the caller owns the head of the list, but not any children or peers. [out] + +@return KErrArgument if the specified alternate interface does not exist. +*/ +TInt RUsbInterface::GetAlternateInterfaceDescriptor(TInt aAlternateInterface, TUsbInterfaceDescriptor& aDescriptor) + { + if (!iHeadInterfaceDescriptor) + { + return KErrNotReady; + } + + TUsbGenericDescriptor* descriptor = iHeadInterfaceDescriptor; + while (descriptor) + { + TUsbInterfaceDescriptor* interface = TUsbInterfaceDescriptor::Cast(descriptor); + if (interface) + { + if (interface->AlternateSetting() == aAlternateInterface) + { + aDescriptor = *interface; + return KErrNone; + } + } + // we must check any Interface Association Descriptors for + // Alternate Interface settings. The spec is abiguous on how these may be organised so we + // presume the worst and do a full search + TUsbInterfaceAssociationDescriptor* iad = TUsbInterfaceAssociationDescriptor::Cast(descriptor); + if (iad) + { + TUsbGenericDescriptor* assocDes = iad->iFirstChild; + while (assocDes) + { + interface = TUsbInterfaceDescriptor::Cast(assocDes); + if (interface) + { + if (interface->AlternateSetting() == aAlternateInterface) + { + aDescriptor = *interface; + return KErrNone; + } + } + assocDes = assocDes->iNextPeer; + } + } + descriptor = descriptor->iNextPeer; + } + + return KErrArgument; + } + +/** +Find and return the section of the USB Configuration Descriptor under the supplied endpoint. + +Note: the supplied TUsbEndpointDescriptor is owned by the caller, but any descriptor objects linked to it +remain the property of the RUsbInterface object. Memory leaks will result if the head pointer is not +cleaned up, but the pointed to objects should not be destroyed. + +@param aAlternateInterface The alternate interface number to return the descriptor for. [in] +@param aEndpoint The endpoint number to return the descriptor for. [in] +@param aDescriptor The supplied TUsbEndpointDescriptor object will be populated from the data retrieved from +the device. Note that the caller owns the head of the list, but not any children or peers. [out] + +@return KErrArgument if the specified alternate interface does not exist, or KErrNotFound if the specified +endpoint cannot be found on the alternate interface. +*/ +TInt RUsbInterface::GetEndpointDescriptor(TInt aAlternateInterface, TInt aEndpoint, TUsbEndpointDescriptor& aDescriptor) + { + TUsbEndpointDescriptor* descriptor = &aDescriptor; + TInt err = GetEndpointDescriptor(aAlternateInterface, aEndpoint, descriptor); + if ((err == KErrNone) && descriptor) + { + aDescriptor = *descriptor; + } + return err; + } + +TInt RUsbInterface::GetEndpointDescriptor(TInt aAlternateInterface, TInt aEndpoint, TUsbEndpointDescriptor*& aDescriptor) + { + aDescriptor = NULL; + + TUsbInterfaceDescriptor alternate; + TInt err = GetAlternateInterfaceDescriptor(aAlternateInterface, alternate); + if (err != KErrNone) + { + return err; + } + + TUsbGenericDescriptor* descriptor = alternate.iFirstChild; + while (descriptor) + { + TUsbEndpointDescriptor* endpoint = TUsbEndpointDescriptor::Cast(descriptor); + if (endpoint && (endpoint->EndpointAddress() == aEndpoint)) + { + aDescriptor = endpoint; + return KErrNone; + } + + descriptor = descriptor->iNextPeer; + } + + return KErrNotFound; + } + +/** +@return Number of alternate interface options on this interface. +*/ +TInt RUsbInterface::GetAlternateInterfaceCount() + { + if (!iHeadInterfaceDescriptor) + { + return KErrNotReady; + } + + TInt count = 0; + + // Don't need to look for children of the interface -- all the alternates + // must be peers. + TUsbGenericDescriptor* descriptor = iHeadInterfaceDescriptor; + while (descriptor) + { + TUsbInterfaceDescriptor* interface = TUsbInterfaceDescriptor::Cast(descriptor); + if (interface) + { + ++count; + } + else + { + // we must check any Interface Association Descriptors for + // Alternate Interface settings. The spec is abiguous on how these may be organised so we + // presume the worst and do a full search + TUsbInterfaceAssociationDescriptor* iad = TUsbInterfaceAssociationDescriptor::Cast(descriptor); + if (iad) + { + TUsbGenericDescriptor* assocDes = iad->iFirstChild; + while (assocDes) + { + interface = TUsbInterfaceDescriptor::Cast(assocDes); + if (interface) + { + ++count; + } + assocDes = assocDes->iNextPeer; + } + } + } + descriptor = descriptor->iNextPeer; + } + + return count; + } + +/** +Count the endpoints on an alternate interface. + +@param [in] aAlternateInterface The alternate interface to count endpoints on. +@return Number of endpoionts on the requested alternate interface or an error code. +*/ +TInt RUsbInterface::EnumerateEndpointsOnInterface(TInt aAlternateInterface) + { + TUsbInterfaceDescriptor alternate; + TInt err = GetAlternateInterfaceDescriptor(aAlternateInterface, alternate); + if (err != KErrNone) + { + return err; + } + + return alternate.NumEndpoints(); + } + +/** +Returns an identifier that is unique for the bus that the device that provides this interface is on. +@param aBusId On success provides an identifier that is unique for the bus this interface is on. +@return KErrNone on success, otherwise a system-wide error code. +*/ +TInt RUsbInterface::GetBusId(TUsbBusId& aBusId) + { + return DoControl(EGetBusId, &aBusId); + } + +/** +Returns the size of pages used by the HCD. +@internalComponent +@return The HCD's page size. +*/ +TInt RUsbInterface::HcdPageSize() + { + return DoControl(EHcdPageSize); + } + +/** +Returns the speed the remote device is connected at. +@param aDeviceSpeed On sucess an enumeration value describing the current speed of the remote device. +@return KErrNone on success, otherwise a system-wide error code. +*/ +TInt RUsbInterface::GetDeviceSpeed(RUsbInterface::TDeviceSpeed& aDeviceSpeed) + { + return DoControl(EGetDeviceSpeed, &aDeviceSpeed); + } + + + + + +RUsbPipe::RUsbPipe() + : iHandle(0) + , iInterface(NULL) + { + } + +TUint32 RUsbPipe::Handle() const + { + return iHandle; + } + +/** +Close a pipe to a remote device. +*/ +void RUsbPipe::Close() + { + if (iInterface) + { + static_cast(iInterface->DoControl(EClose, (TAny*)iHandle)); + } + iHeadEndpointDescriptor = NULL; + iInterface = NULL; + iHandle = 0; + } + +/** +Clear a stall on the remote endpoint. + +@return System-wide error code. +*/ +TInt RUsbPipe::ClearRemoteStall() + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + return iInterface->DoControl(EClearRemoteStall, (TAny*)iHandle); + } + +/** +Cancel all queued transfers +*/ +void RUsbPipe::CancelAllTransfers() + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + static_cast(iInterface->DoControl(EAbort, (TAny*)iHandle)); + } + +/** +Issues a transfer. +@internalComponent +*/ +void RUsbPipe::IssueTransfer(TInt aTransferHandle, TRequestStatus& aRequest) + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + iInterface->DoRequest(EIssueTransfer, aRequest, (TAny*)iHandle, (TAny*)aTransferHandle); + } + +/** +Get endpoint ID +*/ +TInt RUsbPipe::GetEndpointId(TUsbEndpointId& aEndpointId) + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + return iInterface->DoControl(EGetEndpointId, reinterpret_cast(iHandle), &aEndpointId); + } + +/** +Get Bus ID +*/ +TInt RUsbPipe::GetBusId(TUsbBusId& aBusId) + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + return iInterface->GetBusId(aBusId); + } + +/** +Return the section of the USB Configuration Descriptor under the supplied endpoint. + +@param [out] aDescriptor The descriptor tree for this endpoint. +@return System-wide error code. +*/ +TInt RUsbPipe::GetEndpointDescriptor(TUsbEndpointDescriptor& aDescriptor) + { + __ASSERT_ALWAYS(iHandle, User::Panic(UsbdiPanics::KUsbdiPanicCat, UsbdiPanics::EPipeRequestMadeWhileClosed)); + __ASSERT_DEBUG(iInterface, User::Panic(UsbdiFaults::KUsbdiFaultCat, UsbdiFaults::EUsbPipeHasHandleButNoInterface)); + + if (iHeadEndpointDescriptor) + { + aDescriptor = *iHeadEndpointDescriptor; + return KErrNone; + } + else + { + return KErrNotFound; + } + } + +#endif