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