# HG changeset patch # User hgs # Date 1279871687 -28800 # Node ID 089413cdde3c153ff63181910527a7d5746df98e # Parent 59aa7d6e3e0fc2297cab42bf13b07774e8678ecf 201028_02 diff -r 59aa7d6e3e0f -r 089413cdde3c package_definition.xml --- a/package_definition.xml Wed Jul 07 15:08:54 2010 +0800 +++ b/package_definition.xml Fri Jul 23 15:54:47 2010 +0800 @@ -1,8 +1,10 @@ - - + + + + diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/group/bld.inf --- a/usb_plat/group/bld.inf Wed Jul 07 15:08:54 2010 +0800 +++ b/usb_plat/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -15,6 +15,7 @@ * */ +#include "../usb_shai_api/group/bld.inf" PRJ_PLATFORMS DEFAULT diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,32 @@ +/* +* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: Build information file +* +*/ + +#include + +PRJ_PLATFORMS +ARMV5 + +PRJ_EXPORTS + + +../inc/usb_common_shai.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_host_shai.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_otg_shai.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_peripheral_shai.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_peripheral_shai.inl SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_peripheral_shai_shared.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) +../inc/usb_charger_detection_shai.h SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(usb/) diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_charger_detection_shai.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_charger_detection_shai.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,403 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + @brief USB Charger Detection SHAI header + @version 0.2.0 + + This header specifies the USB Charger Detection SHAI. + + @publishedDeviceAbstraction +*/ + + +#ifndef USB_CHARGER_DETECTION_SHAI_H +#define USB_CHARGER_DETECTION_SHAI_H + +// System includes +#include + +/** + * This macro specifies the version of the USB Charger Detection SHAI + * header in binary coded decimal format. This allows the PSL layer to + * confirm a certain definition is available, if needed. This can for + * example make it possible for a new PSL to support compilation in an + * older environment with old USB SHAI version that is missing some + * new definitions. + */ +#define USB_CHARGER_DETECTION_SHAI_VERSION 0x020 + +// The namespace is documented in file usb_common_shai.h, so it is not +// repeated here +namespace UsbShai + { + // Data types + + /** + * An enumeration listing the different port types that can be + * reported to the PIL layer by a registered Charger Detector + * PSL. The available types mostly correspond to those mentioned + * in the Battery Charging Specification Revision 1.1. + */ + enum TPortType + { + /** + * This type is reported to indicate that the Charger Detector + * PSL has detected that we are no longer connected to a + * powered port. This situation occurs when VBUS driven from + * outside drops, or the Accessory Charger Adapter changes the + * RID state from RID_A to RID_GND (which usually also means + * that VBUS will drop very soon). + */ + EPortTypeNone = 0, + + /** + * This type is reported to indicate that the Charger + * Detector PSL has detected that our device is connected to + * an unsupported port. One common type of an unsupported port + * is a PS/2 to USB adapter connected to a PS/2 port of a + * computer. + */ + EPortTypeUnsupported, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to a charging port, + * but has not yet distinguished whether the port is a + * Charging Downstream Port or a Dedicated Charging Port. + * + * When this port type is detected, the upper layers will + * connect to the USB bus as the peripheral by requesting the + * Peripheral Controller PSL to assert the D+ pull-up. The + * Charger Detector PSL can then detect the exact port type by + * observing what happens to the level of the D- line, as + * specified in the Battery Charging Specification. Upon + * detecting the exact port type, the Charger Detector PSL can + * notify a new event with the correct type. + * + * If the Charger Detector PSL can directly distinguish the + * exact port type, the PSL does not need to report this + * generic charging port type, but can directly report the + * more specific type EPortTypeDedicatedChargingPort or + * EPortTypeChargingDownstreamPort. + */ + EPortTypeChargingPort, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to a Dedicated + * Charging Port. + * + * When this port type is detected, the upper layers will + * connect to the USB bus as the peripheral by requesting the + * Peripheral Controller PSL to assert the D+ pull-up, as + * specified in the Battery Charging Specification. + */ + EPortTypeDedicatedChargingPort, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to a Charging + * Downstream Port. + * + * When this port type is detected, the upper layers will + * connect to the USB bus as the peripheral by requesting the + * Peripheral Controller PSL to assert the D+ pull-up, as + * specified in the Battery Charging Specification. + */ + EPortTypeChargingDownstreamPort, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to a Standard + * Downstream Port. + * + * When this port type is detected, the upper layers will + * connect to the USB bus as the peripheral by requesting the + * Peripheral Controller PSL to assert the D+ pull-up, as + * specified in the Battery Charging Specification. + */ + EPortTypeStandardDownstreamPort, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to the OTG port of an + * Accessory Charger Adapter and the ID pin is in the RID_A + * range. + * + * When this port type is detected in an OTG-capable device, + * the OTG State Machine will default to the host role. + */ + EPortTypeAcaRidA, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to the OTG port of an + * Accessory Charger Adapter and the ID pin is in the RID_B + * range. + * + * When this port type is detected, the USB Peripheral PIL + * layer will ensure that the Peripheral Controller PSL is not + * allowed to connect to the bus, as required by the Battery + * Charging Specification. + */ + EPortTypeAcaRidB, + + /** + * This type is reported when the Charger Detector PSL has + * detected that our device is connected to the OTG port of an + * Accessory Charger Adapter and the ID pin is in the RID_C + * range. + * + * When this port type is detected, the upper layers will + * connect to the USB bus as the peripheral by requesting the + * Peripheral Controller PSL to assert the D+ pull-up, as + * specified in the Battery Charging Specification. + */ + EPortTypeAcaRidC, + }; + + + // Class declaration + + /** + * An interface class implemented by the PIL layer to allow the + * Charger Detector PSL to report charger detection events to the + * PIL layer. + */ + NONSHARABLE_CLASS( MChargerDetectorObserverIf ) + { + public: + /** + * Called by the Charger Detector PSL to report the detection + * of a specified type of a port. + * + * When the PIL layer has registered itself as the observer of + * the Charger Detector PSL, it is the responsibility of the + * Charger Detector PSL to run the charger detection algorithm + * when applicable. These situations include: + * + * 1. When VBUS has risen while our device is the B-device. A + * Charger Detector PSL that supports Data Contact Detect + * (see Battery Charging Specification 1.1, Section 3.3) + * should complete Data Contact Detect and the charger + * detection algorithm before notifying the VBUS rising + * event to the respective PIL layer. + * + * For a peripheral-only port, this requirement is + * documented in more detail in usb_peripheral_shai.h, + * function + * MUsbPeripheralPilCallbackIf::DeviceEventNotification(). For + * an OTG-capable port, the requirement is documented in + * usb_otg_shai.h, function + * MOtgObserverIf::NotifyVbusState(). + * + * 2. When VBUS is high, the Charger Detector PSL needs to + * observe changes in the ID pin state, if the Charger + * Detector PSL support detecting the port types relevant + * to Accessory Charger Adapter. This requirement is + * documented in more detail in usb_otg_shai.h, function + * MOtgObserverIf::NotifyIdPinState(). + * + * @param aPortType The type of the port detected + */ + virtual void NotifyPortType( TPortType aPortType ) = 0; + }; + + + /** + * An interface class that needs to be implemented by the Charger + * Detector PSL that registers to the PIL layer. + * + * A system that does not support USB Battery Charging does not + * need a Charger Detector PSL. In this case the PIL layer will + * always assume the device is connected to a Standard Downstream + * Port and will always connect to the bus when VBUS rises. + * + * Due to the dependencies between normal USB functionality + * (observing the state of the ID pin, the VBUS level, the line + * state, and controlling connecting to the bus) and USB Battery + * Charging (in terms of charger detection and requirements about + * connecting to the bus and driving VBUS), the Charger Detector + * PSL cannot be considered independent of the USB Controller + * PSLs. + * + * In practice, it is expected that the Charger Detector interface + * for a peripheral-only port is implemented by the Peripheral + * Controller PSL, or at least that the Peripheral Controller PSL + * is communicating with the Charger Detector PSL. This is + * necessary to ensure that the necessary parts of charger + * detection are run before reporting VBUS high, and that the + * Peripheral Controller and the charger detection can safely + * share the bus without conflict (as both will need to touch the + * line state). See usb_peripheral_shai.h, + * MUsbPeripheralPilCallbackIf::DeviceEventNotification() for + * description of the requirements. + * + * Similarly, it is expected that the Charger Detector interface + * for an OTG-capable port is implemented by the OTG Controller + * PSL, or at least that the OTG Controller PSL is communicating + * with the Charger Detector PSL. See usb_otg_shai.h, + * MOtgObserverIf::NotifyIdPinState() and + * MOtgObserverIf::NotifyVbusState() for description of the + * requirements. + * + * When the PIL layer is ready to receive charger detection + * notifications from the PSL, it will use this interface to + * register itself as the Charger Detector PSL observer. This is + * guaranteed to occur before any USB usage is attempted. + */ + NONSHARABLE_CLASS( MChargerDetectorIf ) + { + public: + /** + * Called by the PIL layer to set itself as the observer of + * charger detection events. + * + * If the port type has already been detected by the Charger + * Detector PSL when the observer is being set (typically + * because VBUS was already high at boot time), it is the + * responsibility of the Charger Detector PSL to immediately + * report the previously detected port type to the observer to + * get the PIL layer to the correct state. + * + * @param aObserver Reference to the observer interface that + * the charger detector is required to report events to + */ + virtual void SetChargerDetectorObserver( MChargerDetectorObserverIf& aObserver ) = 0; + }; + + + /** + * This class specifies the information provided by a Charger + * Detector PSL when registering to the PIL layer. + * + * The PSL should prepare for the possibility that members may be + * added to the end of this class in later SHAI versions if new + * information is needed to support new features. The PSL should + * not use this class as a direct member in an object that is not + * allowed to grow in size due to binary compatibility reasons. + * + * @see UsbChargerDetectionPil::RegisterChargerDetector() + */ + NONSHARABLE_CLASS( TChargerDetectorProperties ) + { + public: // Types and constants + /** + * A bitmask type used to indicate the static capabilities of + * the Charger Detector. + */ + typedef TUint32 TChargerDetectorCaps; + + /** + * Capability bit to indicate whether the USB system below the + * SHAI (either in HW or in the low-level SW) supports + * automatically reducing charging current for the duration of + * the USB high-speed chirp signalling. See Battery Charging + * Specification Revision 1.1, Chapter 3.6.2 for description + * of the problem. + * + * If the system does not support this feature, the upper + * layer USB components that calculate available charging + * current will always limit the charging current taken from a + * Charging Downstream Port so that the maximum current during + * chirp is not violated. + * + * If the system supports this feature, the full available + * charging current from a Charging Downstream Port is + * utilized. It is then the responsibility of the HW or some + * low-level SW below to SHAI to ensure that the charging + * current is automatically reduced for the duration of chirp + * signalling. + * + * If the system supports this feature, the PSL shall set the + * corresponding bit in iCapabilities (by bitwise OR'ing this + * value). Otherwise the PSL shall clear the corresponding bit + * in iCapabilities. + */ + static const TChargerDetectorCaps KChargerDetectorCapChirpCurrentLimiting = 0x00000001; + + public: + /** + * Inline constructor for the Charger Detector properties + * object. This is inline rather than an exported function to + * prevent a binary break in a case where an older PSL binary + * might provide the constructor a smaller object due to the + * PSL being compiled against an older version of the SHAI + * header. When it's inline, the function is always in sync + * with the object size. + * + * We slightly violate the coding conventions which say that + * inline functions should be in their own file. We don't want + * to double the number of USB SHAI headers just for sake of a + * trivial constructor. + */ + inline TChargerDetectorProperties() : + iCapabilities(0) + { + }; + + public: // Data + /** + * A bitmask specifying the static capabilities of this + * Charger Detector. The PSL fills this field by bitwise + * OR'ing the TChargerDetectorCaps capability bits + * corresponding to supported features. + */ + TChargerDetectorCaps iCapabilities; + }; + + /** + * A static class implemented by the USB PIL layer to allow the + * PSL layer to register its charger detector component to the PIL + * layer. + */ + NONSHARABLE_CLASS( UsbChargerDetectionPil ) + { + public: + /** + * Registration function to be used by the USB PSL layer to + * register a charger detector component to the PIL layer. The + * PIL layer will set itself as the observer of the charger + * detector component to receive notification of detected USB + * chargers. + * + * The intended usage is that the component that implements + * USB charger detection registers itself to the USB PIL layer + * by making this call from their own kernel extension entry + * point function (or an equivalent code that runs during + * bootup). + * + * @param aChargerDetector Reference to the Charger Detector + * interface implemented by the registering PSL. + * + * @param aProperties Reference to an object describing the + * static properties of the Charger Detector. The PIL layer + * requires that the supplied reference remains valid + * indefinitely, as the registering Charger Detector cannot + * unregister. + * + * @lib usbperipheralpil.lib + */ + IMPORT_C static void RegisterChargerDetector( MChargerDetectorIf& aChargerDetector, + TChargerDetectorProperties& aProperties ); + }; + }; + +#endif //USB_CHARGER_DETECTION_SHAI_H +// END of file + diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_common_shai.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_common_shai.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,92 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + @brief USB SHAI header for common types and constants + @version 0.2.0 + + This header specifies common types and constants used by both the + peripheral and host/OTG USB SHAIs. It is automatically included by + the USB Host and Peripheral SHAI headers and is not intended to be + directly included by SHAI implementations. + + The file is versioned for the sake of the human reader, but a + compile-time constant to show the header version is not available, + as this header is not intended to be directly included by PSL + implementations. If a change in this header impacts the overall + USB SHAI interface (i.e. change other than documentation + improvements), the version of the impacted interfaces (USB Host + SHAI, USB OTG SHAI, and/or USB Peripheral SHAI) shall too be + changed to make the change visible to the PSL. + + @publishedDeviceAbstraction +*/ + + +#ifndef USB_COMMON_SHAI_H +#define USB_COMMON_SHAI_H + +// System includes +#include + +/** + * @brief USB SHAI types and interfaces + * + * This namespace holds all USB SHAI related types, constants, + * classes, and functions. + */ +namespace UsbShai + { + // Data types + + /** + * Enumeration specifying the available USB endpoint types. + */ + enum TEndpointType + { + /** Endpoint type is control */ + EEpTypeControl = 0, + + /** Endpoint type is bulk */ + EEpTypeBulk, + + /** Endpoint type is interrupt */ + EEpTypeInterrupt, + + /** Endpoint type is isochronous */ + EEpTypeIsochronous + }; + + /** + * Enumeration specifying the available USB speeds. + */ + enum TSpeed + { + /** The bus operates in low speed mode */ + ELowSpeed = 0, + + /** The bus operates in full speed mode */ + EFullSpeed, + + /** The bus operates in high speed mode */ + EHighSpeed + }; + }; + +#endif // USB_COMMON_SHAI_H + +/* End of File */ diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_host_shai.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_host_shai.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,1290 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + @brief USB Host SHAI header + @version 0.2.0 + + This header specifies the USB host SHAI. + + @publishedDeviceAbstraction +*/ + + +#ifndef USB_HOST_SHAI_H +#define USB_HOST_SHAI_H + +// System includes +#include +#include // Common types shared between the USB SHAIs + +/** + * This macro specifies the version of the USB Host SHAI header in + * binary coded decimal format. This allows the PSL layer to confirm a + * certain definition is available, if needed. This can for example + * make it possible for a new PSL to support compilation in an older + * environment with old USB SHAI version that is missing some new + * definitions. + */ +#define USB_HOST_SHAI_VERSION 0x020 + +// The namespace is documented in file usb_common_shai.h, so it is not +// repeated here +namespace UsbShai + { + // Forward declarations + + class MHostControllerIf; + class MHostTransferCallbackIf; + class MRootHubCallbackIf; + class MRootHubIf; + + // Data types + + /** + * An enumeration listing the host role electrical test modes + * supported. These correspond to the test modes specified in + * Section "6.4.1.1 Test Modes" of the "On-The-Go and Embedded + * Host Supplement to the USB Revision 2.0 Specification" Revision + * 2.0 (a.k.a. USB OTG 2.0). + * + * @see MHostControllerIf::EnterHostTestMode() + */ + enum THostTestMode + { + /** + * Drive SE0 until host controller is reset. The call returns + * immediately after enabling the test mode. + */ + ETestModeTestSE0NAK = 0, + + /** + * Drive high-speed J until host controller is reset. The call + * returns immediately after enabling the test mode. + */ + ETestModeTestJ, + + /** + * Drive high-speed K until host controller is reset. The call + * returns immediately after enabling the test mode. + */ + ETestModeTestK, + + /** + * Send test packets until host controller is reset. The + * format of the required test packet is specified in Section + * "7.1.20 Test Mode Support" of the USB 2.0 specification. + * + * The call returns immediately after enabling the test + * mode. + */ + ETestModeTestPacket, + + /** + * Suspend and resume the port with 15 second delays to allow + * the operator to adjust test tool settings. The Host + * Controller PSL must perform the following test steps: + * + * 1. Allow SOFs to continue for 15 seconds. + * + * 2. Suspend the port under test. + * + * 3. Wait for 15 seconds. + * + * 4. Resume the port under test. + * + * This test mode is synchronous, i.e. the call returns after + * the test has been completed. + */ + ETestModeHsHostPortSuspendResume, + + /** + * Perform a single-step GetDescriptor(Device) transfer. This + * is called after the USB Host Stack has enumerated a device + * with VID=0x1A0A and PID=0x0107. The Host Controller PSL + * must perform the following test steps: + * + * 1. Allow SOFs to continue for 15 seconds. + * + * 2. Send a complete GetDescriptor(Device) transfer + * + * This test mode is synchronous, i.e. the call returns after + * the test has been completed. + */ + ETestModeSingleStepGetDeviceDescriptor, + + /** + * Perform a single-step GetDescriptor(Device) transfer with a + * delayed data phase. This is called after the USB Host Stack + * has enumerated a device with VID=0x1A0A and PID=0x0108. The + * Host Controller PSL must perform the following test steps: + * + * 1. Send the SETUP packet for GetDescriptor(Device). The + * device ACKs the packet as usual. + * + * 2. Allow SOFs to continue for 15 seconds. + * + * 3. Send the IN token for the data phase of + * GetDescriptor(Device). The device responds with + * the data. + * + * 4. Send the acknowledgement (zero-length OUT data) in + * response to the data. + * + * This test mode is synchronous, i.e. the call returns after + * the test has been completed. + */ + ETestModeSingleStepGetDeviceDescriptorData + }; + + + // Class declaration + + /** + * This class specifies a memory block that is used for USB + * transfers. The memory pointers and the buffer length are filled + * by the USB Host stack before issuing the transfer to the Host + * Controller PSL. + */ + NONSHARABLE_CLASS( TUsbMemoryBlock ) + { + public: + /** + * Linear (virtual) start address of the memory buffer. This + * address is always provided. + */ + TLinAddr iLinAddr; + + /** + * Physical start address of the memory buffer. This address + * is always provided, but it is the responsibility of the + * Host Controller PSL to guarantee that the memory is + * physically contiguous, if contiguous memory is needed. The + * PSL can guarantee this by implementing + * MHostControllerIf::ChunkCreate() to allocate physically + * contiguous memory. + * + * @see MHostControllerIf::ChunkCreate() + */ + TPhysAddr iPhysAddr; + + /** + * Pointer to an array of physical addresses each pointing to + * one physical page of the memory block. This address is + * always provided. + * + * The size of each page matches the size reported in + * THostControllerProperties::iControllerPageSize by the Host + * Controller PSL when it registered to the PIL. + */ + TPhysAddr* iPhysPages; + + /** The length of the memory buffer in bytes */ + TUint iLength; + }; + + + /** + * This class specifies the enumerated types for different endpoint + * configuration items and specifies the structure of the endpoint + * configuration. Instances of this class are used to specify the + * endpoint information when opening a pipe. + * + * @see MHostControllerIf::OpenPipe() + */ + NONSHARABLE_CLASS( THostPipe ) + { + public: + // These are flag constants that specify the values that can + // be bitwise OR'ed to the endpoint flags field iEndpointFlags + // to indicate some boolean parameters of the endpoint + + /** + * This flag specifies whether the targeted endpoint is behind + * a hub that is performing transaction translation. This + * occurs when the attached device is a low/full-speed device + * attached to a high-speed hub. + * + * When this flag is set, the iHubAddr and iHubPort members + * specify the hub address and the port to which the targeted + * device is connected, and the iEndpointFlags flag + * KHubHasMultipleTTs specifies whether the hub has been + * configured to use multiple transaction translators. + */ + static const TUint32 KHubTranslates = 0x00000001; + + /** + * When the iEndpointFlags flag KHubTranslates is set, this + * flag is set if the hub has multiple transaction + * translators. + */ + static const TUint32 KHubHasMultipleTTs = 0x00000002; + + public: // Data + /** + * The type of the endpoint (control, bulk, interrupt, + * isochronous) + */ + TEndpointType iType; + + /** Maximum packet size to be used on this endpoint */ + TUint iMaxPacketSize; + + /** Flags specifying some boolean parameters of the endpoint */ + TUint32 iEndpointFlags; + + /** + * The speed (low, full, high) to use for this endpoint. This + * may differ from the current speed of the local port if the + * targeted device is a low-speed or full-speed device + * connected to a high-speed hub. + */ + TSpeed iSpeed; + + /** + * The polling interval specified as number of frames or + * microframes, depending on the speed. This is used for + * interrupt and isochronous endpoints only. + */ + TUint iPollingInterval; + + /** + * The USB address of the remote device that we are + * communicating with + */ + TUint8 iRemoteAddr; + + /** + * The remote endpoint number that we are communicating + * with. This is the physical endpoint number in the USB 2.0 + * descriptor format, i.e. the most significant bit indicates + * the direction (1 for IN, 0 for OUT), and the least + * significant bits indicate the endpoint number. + */ + TUint8 iRemoteEpNum; + + /** + * For cases where the attached device is a low/full-speed + * device attached to a high-speed hub that does the necessary + * transaction translation, this member records the address of + * the hub doing the translation. + */ + TUint8 iHubAddr; + + /** + * For cases where the attached device is a low/full-speed + * device attached to a high-speed hub that does the necessary + * transaction translation, this member records the number of + * the port where the device is connected on the hub that does + * the transaction translation. + */ + TUint8 iHubPort; + }; + + + /** + * This class specifies the structure of the endpoint transfer + * requests. The USB Host Stack passes the Host Controller PSL a + * reference to an object of this class when setting up a new transfer + * with MHostPipeIf::StartTransfer(). + */ + NONSHARABLE_CLASS( THostTransfer ) + { + public: + // These are public constants that specify the values that can + // be bitwise OR'ed to the request flags field iRequestFlags + // to indicate some boolean parameters of the transfer + + /** + * When set, specifies that the transfer direction is IN, + * i.e. the host is reading from the connected device. This is + * needed for endpoint zero, which is bi-directional and + * cannot implicitly know the direction of the transfer. + * + * This bit is set or cleared by the USB Host stack before + * issuing a new transfer. + */ + static const TUint32 KTransferDirIsIN = 0x00000001; + + /** + * For OUT endpoint transfers, indicates whether the Host + * Controller PSL is required to force a short packet at the + * end of the transfer. + * + * When the bit is set, the Host Controller PSL must send a + * ZLP (Zero-Length Packet) after the last packet of the + * transfer, if and only if the last packet was a full packet, + * i.e. had the same size as the maximum packet size for the + * endpoint. + * + * This bit is set or cleared by the USB Host stack before + * issuing a new transfer. + */ + static const TUint32 KOutForceShortPacket = 0x00000002; + + /** + * For IN endpoint transfers, indicates whether the transfer + * was terminated with a ZLP (Zero-Length Packet). + * + * This bit is set by the Host Controller PSL before + * completing the transfer if the transfer ended due to a + * ZLP. Otherwise the bit is cleared by the Host Controller + * PSL. + */ + static const TUint32 KInZlpReceived = 0x00000004; + + /** + * Enumeration specifying the packet status values to be used + * for isochronous transfers. + */ + enum TIsocPacketStatus + { + /** No error has occurred, transfer succesful */ + ESuccess = 0, + + /** + * Data error has occurred in a data transfer, i.e. the + * CRC did not match + */ + EDataError, + + /** Overrun has occurred */ + EOverrun, + + /** Underrun has occurred */ + EUnderrun, + }; + + public: // Data + /** + * Pointer to the information of the pipe that this transfer + * is being made on. This is the same information that was + * used when opening the pipe that the transfer is being made + * on. + */ + THostPipe* iPipeInfo; + + /** + * A pointer to the callback interface to be used for + * indicating the completion of the transfer. This is set by + * the USB Host Stack before making a transfer request. + */ + MHostTransferCallbackIf* iTransferCbIf; + + /** + * Request flags specifying some boolean parameters for the + * transfer. + */ + TUint32 iRequestFlags; + + /** + * Memory block specifying the memory buffer used for the data + * transfer. This is filled by the USB Host Stack before + * making a transfer request. + * + * The memory block used here will be part of a chunk + * previously created by a call to + * MHostControllerIf::ChunkCreate() and the block will + * fullfill the alignment requirements reported by the call to + * MHostControllerIf::GetSizeAndAlignment(). + * + * For control transfers, this specifies the buffer for the + * data stage and has zero length and NULL pointers if the + * transaction does not include a data stage. + */ + TUsbMemoryBlock iDataBuffer; + + /** + * For control transfers, this memory block specifies the + * contents of the setup packet to be sent. For other than + * control transfers, it is not used, and it has zero length + * and NULL pointers. + */ + TUsbMemoryBlock iSetupBuffer; + + /** + * For isochronous transfers, this sets the number of + * isochronous packets to send/receive. This is set by the + * USB Host Stack before making a transfer request. + */ + TInt iNumIsocPackets; + + /** + * The number of bytes successfully transferred during the + * data transfer. This is set by the Host Controller PSL + * before completing the transfer. + */ + TUint iTransferLength; + + /** + * The status code of a completed transfer. This is set by the + * Host Controller PSL before completing the request to the + * transfer callback interface. + */ + TInt iStatus; + + /** + * For isochronous transfers, a pointer to an array of + * iNumIsoPackets entries that specify the length of each + * packet in the transfer. For OUT transfers, the array is + * filled by the USB Host Stack and is read by the Host + * Controller PSL to decide the length for each packet. For IN + * transfers, the array is filled by the Host Controller PSL + * to record to length of each received packet. + */ + TUint16* iIsocPacketLengths; + + /** + * For isochronous transfers, a pointer to an array of + * iNumIsoPackets entries that specify the status of each + * packet in the transfer. The array is filled by the Host + * Controller PSL to record to success or failure of each + * received packet. + */ + TIsocPacketStatus* iIsocPacketStatuses; + }; + + + /** + * This class specifies the structure and contents of root hub + * information that is filled by the adaptation to let the USB Host + * Stack hub driver learn the capabilities of the root hub. + * + * @see MHostControllerIf::OpenRootHub + */ + NONSHARABLE_CLASS( TRootHubInfo ) + { + public: // Types and constants + /** + * A bitmask type used to indicate the static capabilities of + * the root hub. + */ + typedef TUint32 TRootHubCaps; + + /** + * Capability bit to indicate whether the root hub supports + * user-visible port indications such as LEDs. + * + * If the root hub supports this feature, the PSL shall set + * the corresponding bit in iCapabilities (by bitwise OR'ing + * this value). Otherwise the PSL shall clear the + * corresponding bit in iCapabilities. + */ + static const TRootHubCaps KRootHubCapPortIndication = 0x00000001; + + public: // Data + /** + * A bitmask specifying the static capabilities of this root + * hub. The PSL fills this field by bitwise OR'ing the + * TRootHubCaps capability bits corresponding to supported + * features. + */ + TRootHubCaps iCapabilities; + + /** Number of ports in this root hub */ + TUint iNumberOfPorts; + + /** + * Maximum number of milliamps of current that this root hub + * can supply to VBUS. + */ + TUint iMaxSuppliedVbusCurrentMA; + + /** + * Time taken by this root hub between starting to power up a + * port and power being good on that port. This is expressed + * in units of one millisecond. + */ + TUint iTimePowerOnToPowerGoodMs; + + /** + * The maximum speed supported by the root hub. + */ + TSpeed iMaxSpeed; + + /** Pointer to the root hub interface */ + MRootHubIf* iRootHubIf; + }; + + + /** + * An interface class used by the USB Host Stack to perform data + * transfers on a USB pipe. The Host Controller PSL must implement + * this interface and provide a pointer to a pipe-specific + * instance when the USB Host Stack creates the pipe by calling + * MHostControllerIf::OpenPipe(). + * + * The USB Host Stack will call the functions of this interface + * from a DFC queued on the DFC queue supplied by the Host + * Controller in THostControllerProperties::iControllerDfcQueue when the + * Host Controller PSL registered. + * + * @see MHostControllerIf::OpenPipe() + */ + NONSHARABLE_CLASS( MHostPipeIf ) + { + public: + /** + * Close the USB pipe. This is called by the USB Host Stack + * when the pipe is no longer used and the Host Controller PSL + * may release any resources that were allocated for this + * instance, including deleting the object itself. + * + * @param aPipeInfo Information describing the target endpoint + * of the pipe. This is the same information passed to + * MHostControllerIf::OpenPipe() when creating the + * pipe. + * + * @post After calling the function, the USB Host stack will + * consider the invoked instance to have been deleted and will + * no longer call any of the functions. + */ + virtual void ClosePipeD( const THostPipe& aPipeInfo ) = 0; + + /** + * Clear the data toggle bit of this pipe. This is used for + * interrupt and bulk pipes when the host stack needs to + * guarantee that the host controller will start the next + * interrupt or bulk transfer with data toggle value zero. + * + * @param aPipeInfo Information describing the target endpoint + * of the pipe. This is the same information passed to + * MHostControllerIf::OpenPipe() when creating the + * pipe. + */ + virtual void ClearDataToggle( const THostPipe& aPipeInfo ) = 0; + + /** + * Start a transfer on this pipe. + * + * When the transfer is considered completed, the Host + * Controller PSL must update the transfer information object + * with the actual length and status of the transfer and then + * complete it to the callback interface by calling + * MHostTransferCallbackIf::CompleteTransfer(). The pointer to + * the callback interface is provided in the member + * THostTransfer::iTransferCbIf of the supplied aTransferInfo. + * + * The following rules shall be used by the Host Controller + * PSL to assess the completeness of a transfer: + * + * 1. A read or write transfer on a control pipe is completed + * when all the stages (two or three) of the control transfer + * have been completed successfully, or when an error + * occurs. It is the responsibility of the upper layers to + * guarantee that there is sufficient buffer space for a read + * request, so the buffer should not run out. + * + * 2. A read or write transfer on an isochronous pipe is + * completed when the number of isochronous packets specified + * in the member THostTransfer::iNumIsocPackets of the + * supplied aTransferInfo have been sent or received + * successfully, or if a fatal error occurs. It is the + * responsibility of the upper layers to guarantee that there + * is sufficient buffer space for a read request, so the + * buffer should not run out. + * + * 3. A read transfer on a bulk or interrupt pipe is completed + * when the buffer space is exhausted, a short packet (a + * packet smaller than the maximum packet size of the pipe) is + * received, or an error occurs. + * + * 4. A write transfer on a bulk or interrupt pipe is + * completed when the requested buffer has been fully sent, or + * an error occurs. + * + * @param aTransferInfo Information specifying the transfer to perform + * + * @return KErrNone if the transfer was started successfully, + * otherwise a system-wide error code + */ + virtual TInt StartTransfer( THostTransfer& aTransferInfo ) = 0; + + /** + * Cancel a transfer that was previously started with + * StartTransfer(). The Host Controller PSL must flush any + * pending data (either received or about to be sent) and + * discard the transfer. The PSL must not attempt to complete + * the canceled transfer by calling + * MHostTransferCallbackIf::CompleteTransfer(). + * + * @param aTransferInfo Information specifying the transfer to + * cancel. This is the same information passed to + * StartTransfer() when the transfer as started. + */ + virtual void CancelTransfer( THostTransfer& aTransferInfo ) = 0; + }; + + + /** + * An interface class used by the USB Host Stack hub driver to + * operate on the root hub ports. The Host Controller PSL must + * implement this interface and provide a pointer when the USB + * Host Stack opens the root hub by calling + * MHostControllerIf::OpenRootHub(). + * + * The USB Host Stack will call the functions of this interface + * from a DFC queued on the DFC queue supplied by the Host + * Controller in THostControllerProperties::iControllerDfcQueue + * when the Host Controller PSL registered. + * + * @see MHostControllerIf::OpenRootHub() + */ + NONSHARABLE_CLASS( MRootHubIf ) + { + public: + /** + * Close the connection to the root hub. This is called by the + * USB Host Stack when the Host Controller is about to be + * deleted and the root hub is no longer used. The Host + * Controller PSL may release any resources that were + * allocated for this instance, including deleting the object + * itself. + * + * @post After calling the function, the USB Host stack will + * consider the invoked instance to have been deleted and will + * no longer call any of the functions. + */ + virtual void CloseRootHubD() = 0; + + /** + * Enable the power supply, i.e. raise VBUS, on the specified + * root hub port. + * + * If there are problems raising VBUS, the Host Controller PSL + * must report a VBUS error by notifying the root hub callback + * interface MRootHubCallbackIf of an over-current condition + * on the port. + * + * @param aPort The number of the root hub port to operate + * on. For a root hub with N ports, the port numbers are in + * range [1..N]. + * + * @see MRootHubCallbackIf::OverCurrentDetected() + */ + virtual void PowerOnPort( TUint aPort ) = 0; + + /** + * Stop session (A-device only). + * + * @param aPort The number of the root hub port to operate + * on. For a root hub with N ports, the port numbers are in + * range [1..N]. + */ + virtual void PowerOffPort( TUint aPort ) = 0; + + /** + * Reset the specified root hub port. The total reset length + * has to be at least 50 milliseconds and the reset signalling + * must follow the requirements specified in USB 2.0 + * Specification Section 7.1.7.5 Reset Signaling. + * + * This function is synchronous and should return when the + * reset signalling on the port has completed. + * + * @param aPort The number of the root hub port to operate + * on. For a root hub with N ports, the port numbers are in + * range [1..N]. + */ + virtual void ResetPort( TUint aPort ) = 0; + + /** + * Place the specified root hub port to the USB suspend state + * where it does not send SOF packets to the connected device. + * + * When all ports of the root hub have been suspended, the USB + * Host Stack will suspend the entire host controller by + * calling MHostControllerIf::SuspendController(). + * + * When the root hub only has one port and SOFs cannot be + * gated on the port without suspending the whole controller, + * the Host Controller PSL should ignore the port-specific + * suspend and resume calls and instead suspend/resume the + * controller based on the controller-specific suspend and + * resume calls in MHostControllerIf. + * + * @param aPort The number of the root hub port to operate + * on. For a root hub with N ports, the port numbers are in + * range [1..N]. + */ + virtual void SuspendPort( TUint aPort ) = 0; + + /** + * Resume the specified root hub port from the USB suspend + * state by driving the resume signalling on the port. The + * signalling must last at least 20 milliseconds and follow + * the requirements specified in USB 2.0 Specification Section + * 7.1.7.7 Resume Signaling. After the resume signalling has + * completed, the port must allow SOFs to be sent to the + * connected device again. + * + * Before resuming the first port of a completely suspended + * controller, the USB Host Stack will first resume the entire + * host controller by calling + * MHostControllerIf::ResumeController(). + * + * When the root hub only has one port and SOFs cannot be + * gated on the port without suspending the whole controller, + * the Host Controller PSL should ignore the port-specific + * suspend and resume calls and instead suspend/resume the + * controller based on the controller-specific suspend and + * resume calls in MHostControllerIf. + * + * @param aPort The number of the root hub port to operate + * on. For a root hub with N ports, the port numbers are in + * range [1..N]. + */ + virtual void ResumePort( TUint aPort ) = 0; + + /** + * Query whether a device (a hub or a function) is currently + * connected to the specified root hub port, and what speed it + * is. + * + * @param aPort The number of the root hub port to check for a + * connected device on. For a root hub with N ports, the port + * numbers are in range [1..N]. + * + * @param aSpeed Variable to fill with the speed, if connected + * + * @return ETrue if a device is currently connected and aSpeed + * has been set to the speed of the connected device. EFalse + * otherwise. + */ + virtual TBool IsDeviceConnected( TUint aPort, + TSpeed& aSpeed ) = 0; + }; + + + /** + * An interface class that needs to be implemented by each Host + * Controller PSL that registers to the USB stack. + * + * This interface is used by the USB Host Stack to do controller level + * operations like suspending and resuming the host controller. It is + * also used to open the root hub interface upon creating the SHAI + * Host Controller, and to open USB pipes to connected devices. + * + * The USB Host Stack will call the functions of this interface + * from a DFC queued on the DFC queue supplied by the Host + * Controller in THostControllerProperties::iControllerDfcQueue when the + * Host Controller PSL registered. + */ + NONSHARABLE_CLASS( MHostControllerIf ) + { + public: + /** + * Open a pipe to an endpoint on a remote USB peripheral. + * + * This function is called by the USB host stack when it wants + * to communicate with a certain endpoint on a discovered USB + * peripheral. The opened pipe is then used to read or write + * from/to the peripheral until the pipe is later closed by + * MHostPipeIf::ClosePipeD(). + * + * @param aPipeInfo Information describing the target endpoint + * that the USB host stack wants to create a pipe to. The + * ownership of the info object remains with the USB host + * stack and the Host Controller PSL must not refer to data + * inside this after the function has returned. All + * MHostPipeIf functions that operate on the pipe will be + * passed the same pipe information so that the Host + * Controller PSL does not necessarily need to take a copy. + * + * @param aPipe Upon success, set by the Host Controller PSL + * to point to an instance that implements the SHAI pipe + * interface for the opened pipe. This interface will then be + * used by the USB Host Stack to perform transfers until the + * pipe is eventually closed by the USB Host Stack calling + * MHostPipeIf::ClosePipeD(). + * + * @return KErrNone if successful, otherwise a system error code + */ + virtual TInt OpenPipe( const THostPipe& aPipeInfo, + MHostPipeIf*& aPipe ) = 0; + + /** + * Open the root hub for the Host Controller. + * + * This is called by the USB Host Stack after creating the + * Host Controller PSL to learn the capabilities of the + * respective root hub and to establish the communication + * between the hub driver in the USB Host Stack and the root + * hub ports controlled by the Host Controller PSL. + * + * @param aRootHubInfo Reference to a root hub information + * object to be filled by the adaptation. + * + * @param aRootHubCbIf Reference to the callback interface of + * the root hub driver in the USB stack. The root hub + * implementation of the Host Controller PSL shall use this + * interface to report events of this root hub. + * + * @return KErrNone if successful, otherwise a system error code + */ + virtual TInt OpenRootHub( TRootHubInfo& aRootHubInfo, + MRootHubCallbackIf& aRootHubCbIf ) = 0; + + /** + * Start and enable the host controller. This is called prior + * to powering up any port of the root hub to allow to Host + * Controller PSL to perform any preparation that may be + * necessary to activate the controller. This may include + * actions such as enabling clocks or power to the host + * controller HW. + * + * This function is also used in an OTG environment when the + * host stack becomes enabled and the controller needs to be + * started and enabled for host use. If the HW platform shares + * resources such as clocks and power between the host and + * peripheral HW, it is probably easiest for the PSL to handle + * the role switch based on the + * MOtgControllerIf::SetControllerRole() call to the OTG + * Controller interface. + * + * @return KErrNone if the host controller was successfully started, + * otherwise a system-wide error code. + * + * @see usb_otg_shai.h, MOtgControllerIf::SetControllerRole() + */ + virtual TInt StartHostController() = 0; + + /** + * Disable and stop the host controller. This is called after + * powering down all ports of the root hub to allow to Host + * Controller PSL to release any HW resources needed by the + * controller. This may include actions such as disabling + * clocks or power to the host controller HW. + * + * This function is also used in an OTG environment when the + * host stack becomes disabled and the host HW resources can + * be released. If the HW platform shares resources such as + * clocks and power between the host and peripheral HW, it is + * probably easiest for the PSL to handle the role switch + * based on the MOtgControllerIf::SetControllerRole() call to + * the OTG Controller interface. + * + * @return KErrNone if the host controller was successfully started, + * otherwise a system-wide error code. + * + * @see usb_otg_shai.h, MOtgControllerIf::SetControllerRole() + */ + virtual TInt StopHostController() = 0; + + /** + * Place the host controller to the USB suspend state where it + * does not send SOF packets. + */ + virtual void SuspendController() = 0; + + /** + * Resume the host controller from the USB suspend state by + * driving the resume signalling towards the root hub. The + * signalling must last at least 20 milliseconds and follow + * the requirements specified in USB 2.0 Specification Section + * 7.1.7.7 Resume Signaling. After the resume signalling has + * completed, the controller must allow SOFs to be sent to the + * connected device again. + */ + virtual void ResumeController() = 0; + + /** + * Force the controller into a specific high-speed host test + * mode. This function needs to be implemented only by Host + * Controller PSLs for high-speed capable controllers. The + * function will only be called when the controller is + * operating in high-speed mode and a special test device has + * been enumerated. + * + * When called, the Host Controller PSL shall synchronously + * run the selected test as specified for each tests in the + * documentation of THostTestMode. + * + * @param aTestMode Specifies the test mode to enter + * + * @param aDefaultPipe Information of the default pipe (the + * control pipe to endpoint zero) of the connected test + * device. + * + * @return KErrNone if the specified test mode was entered + * successfully, otherwise a system-wide error + */ + virtual TInt EnterHostTestMode( THostTestMode aTestMode, + const THostPipe& aDefaultPipe ) = 0; + + /** + * Get the size and alignment requirements for the Host + * Controller. The reference parameters are both input and + * output. Upon input, they describe the values requested by + * the client, but they may be increased by this function if + * the Host Controller requires additional memory or has some + * alignment requirements. + * + * @param aType The type of the endpoint that the memory will + * be used for. + * + * @param aAlignment Output for required alignment in bytes + * + * @param aSize Input/output for buffer size (may be increased + * in this function) + * + * @param aMaxPackets Input/output for maximum number of + * packets in the transfer (may be increased in this function) + * + * @return KErrNone if successful, otherwise a system-wide + * error code + */ + virtual TInt GetSizeAndAlignment( TEndpointType aType, + TUint& aAlignment, + TInt& aSize, + TInt& aMaxPackets ) = 0; + + /** + * Creates a shared chunk and commits memory to it. The memory + * allocated with this function will later be used when making + * data transfers with this Host Controller (see + * THostTransfer::iDataBuffer). + * + * The adaptation shall create a chunk by calling + * Kern::ChunkCreate(), and then commit memory to it with one + * of the Commit functions Kern::ChunkCommit(), + * Kern::ChunkCommitContiguous(), and Kern::ChunkCommitPhysical(). + * + * This task is delegated to the adaptation so that it can + * allocate the correct type of memory. For example, if the + * Host Controller requires the memory to be physically + * contiguous, the implementation of this function must commit + * contiguous memory to the chunk. + * + * @param aChunk Output handle to the chunk that was created. + * The adaptation must pass this value as the aChunk argument + * to the Kern::ChunkCreate() call. + * + * @param aOffset The offset (in bytes) from start of chunk, + * which indicates the start of the memory region to be + * committed. This will be a multiple of the MMU page + * size. The adaptation must pass this value as the aOffset + * argument to the used Commit call. + * + * @param aSize Number of bytes to commit. This will be a + * multiple of the MMU page size. The adaptation must pass + * this value as the aSize argument to the used Commit call. + * + * @param aInfo At input, specifies the chunk properties + * requested by the upper layers. The adaptation is allowed + * to change the attributes in aInfo.iMapAttr to match the + * requirements of the Host Controller. The adaptation must + * pass this value as the aInfo argument to the + * Kern::ChunkCreate() call. If the adaptation commits + * cached memory, it is the responsibility of the adaptation + * to deal with cache synchronization when making data + * transfers. If the adaptation needs special cleanup when + * the chunk is deleted, the adaptation can set a cleanup + * DFC pointer in aInfo.iDestroyedDfc. + * + * @param aPhysicalAddress On success, will be set to the + * physical address of the chunk as referenced by the HC + * + * @return KErrNone if successful, otherwise a system-wide + * error code + * + * @see System documentation for Kern::ChunkCreate(), + * Kern::ChunkCommit(), Kern::ChunkCommitContiguous(), and + * Kern::ChunkCommitPhysical() + */ + virtual TInt ChunkCreate( DChunk*& aChunk, + TUint aOffset, + TUint aSize, + TChunkCreateInfo& aInfo, + TPhysAddr& aPhysicalAddress ) = 0; + + /** + * Maps virtual to physical addresses. If the memory addresses + * used by the host controller are different to the ones of + * the main memory bus (e.g. due to memory mapping or use of + * different address spaces), this method is used to translate + * from kernel physical addresses to host controller physical + * addresses. + * + * @param aPhysicalAddressList On entering, the list of + * physical addresses as used kernel-side, on successful + * return it contains the list of physical addresses as + * referenced by the HC + * + * @param aPhysicalAddressListSize Number of elements in + * aPhysicalAddressList + * + * @return KErrNone if successful, otherwise a system-wide + * error code + */ + virtual TInt MapPhysicalAddresses( TPhysAddr*& aPhysicalAddressList, + TInt aPhysicalAddressListSize ) = 0; + }; + + + /** + * An interface class implemented by the USB stack to allow the + * host controller to report events to the root hub. This includes + * notifications of a device being connected or disconnected on a + * port, and other port conditions such as seeing a remote wakeup + * signalling, an error on the port (such as babble from a + * peripheral), or VBUS over-current. + * + * It is required that the Host Controller PSL calls these + * functions in the context of the DFC queue supplied by the Host + * Controller PSL in + * THostControllerProperties::iControllerDfcQueue when the Host + * Controller PSL registered. + */ + NONSHARABLE_CLASS( MRootHubCallbackIf ) + { + public: + /** + * A constant to specify an unknown port. In those port + * notifications where this is explicitly specified to be OK, + * this value is allowed to be used as the port number where + * the real port number is unknown. + */ + static const TUint KPortUnknown = 0; + + /** + * Informs the root hub that a device (a hub or function) has + * been connected to the specified root hub port. + * + * The Host Controller PSL uses this function to inform device + * connection also during HNP role switch when the remote + * device connects in peripheral role. + * + * @param aPort The number of the root hub port that the event + * occurred on. For a root hub with N ports, the port numbers + * are in range [1..N]. + */ + virtual void DeviceConnected( TUint aPort ) = 0; + + /** + * Informs the root hub that a device (a hub or function) has + * been disconnected from the specified root hub port. + * + * The Host Controller PSL uses this function to inform device + * disconnection also during HNP role switch when the remote + * peripheral disconnects to start the role switch. + * + * The Host Controller PSL must report device disconnection by + * calling this function even if the port is currently + * suspended. A disconnection that is part of an HNP role + * switch will always occur in suspended state, and even a + * normal peripheral may be physically disconnected at any + * time. + * + * @param aPort The number of the root hub port that the event + * occurred on. For a root hub with N ports, the port numbers + * are in range [1..N]. + */ + virtual void DeviceDisconnected( TUint aPort ) = 0; + + /** + * Informs the root hub that a device connected to the + * specified root hub port has requested remote wakeup. + * + * @param aPort The number of the root hub port that the event + * occurred on. For a root hub with N ports, the port numbers + * are in range [1..N]. + */ + virtual void RemoteWakeupRequested( TUint aPort ) = 0; + + /** + * Informs the root hub that a port error (such as babble) has + * been detected on the specified root hub port. The + * adaptation is expected to disable the port that has caused + * the error condition. + * + * @param aPort The number of the root hub port that the event + * occurred on. For a root hub with N ports, the port numbers + * are in range [1..N]. + */ + virtual void PortErrorDetected( TUint aPort ) = 0; + + /** + * Informs the root hub that an over-current condition has + * been detected on the specified port. + * + * It may not always be possible to see which port out of + * several caused the overcurrent. In this case the Host + * Controller PSL may use the port number + * MRootHubCallbackIf::KPortUnknown. + * + * @param aPort The number of the root hub port that the event + * occurred on, if known. For a root hub with N ports, the + * port numbers are in range [1..N]. If the exact port is + * not known, the Host Controller PSL root hub may report + * the port number MRootHubCallbackIf::KPortUnknown. + */ + virtual void OverCurrentDetected( TUint aPort ) = 0; + }; + + + /** + * An interface class implemented by the USB Host Stack to allow the + * host controller to complete transfers to the USB Host Stack. + * + * It is required that the Host Controller PSL calls these + * functions in the context of the DFC queue supplied by the Host + * Controller PSL in THostControllerProperties::iControllerDfcQueue when + * the Host Controller PSL registered. + */ + NONSHARABLE_CLASS( MHostTransferCallbackIf ) + { + public: + /** + * Complete a transfer request that had been set up with + * MHostPipeIf::StartTransfer(). + * + * @param aTransferInfo The transfer information that + * identifies the transfer that has completed + */ + virtual void CompleteTransfer( const THostTransfer& aTransferInfo ) = 0; + }; + + + /** + * This class specifies the static information provided by a Host + * Controller PSL when registering to the USB Host stack. + * + * The PSL should prepare for the possibility that members may be + * added to the end of this class in later SHAI versions if new + * information is needed to support new features. The PSL should + * not use this class as a direct member in an object that is not + * allowed to grow in size due to binary compatibility reasons. + * + * @see UsbHostPil::RegisterHostController() + */ + NONSHARABLE_CLASS( THostControllerProperties ) + { + public: // Types and constants + /** + * A bitmask type used to indicate the static capabilities of + * the Host Controller. + */ + typedef TUint32 THostCaps; + + public: + /** + * Inline constructor for the Host Controller properties + * object. This is inline rather than an exported function to + * prevent a binary break in a case where an older PSL binary + * might provide the constructor a smaller object due to the + * PSL being compiled against an older version of the SHAI + * header. When it's inline, the function is always in sync + * with the object size. + * + * We slightly violate the coding conventions which say that + * inline functions should be in their own file. We don't want + * to double the number of USB SHAI headers just for sake of a + * trivial constructor. + */ + inline THostControllerProperties() : + iCapabilities(0), + iControllerDfcQueue(NULL), + iControllerPageSize(0) + { + }; + + public: // Data + /** + * A bitmask specifying the static capabilities of this Host + * Controller. No capabilities are specified at the moment and + * the PSL shall fill this field with a zero value. + * + * The field is added for sake of future proofing the binary + * compatibility of the Host SHAI. By having a field reserved + * for capability bits, we can later specify bits to indicate + * added virtual functions or extension to this controller + * properties structure. The PIL layer can then at runtime + * confirm the existence of the new functions or fields and + * safely support an older binary, if we choose to. + */ + THostCaps iCapabilities; + + /** + * Pointer to a DFC queue that will be used for DFCs of this + * controller. + * + * A stand-alone (one not associated with an OTG-port) Host + * Controller PSL must supply a pointer to a dedicated DFC + * queue that has been created for this controller. Both the + * PSL itself and the PIL layer must queue their DFCs for this + * controller in this DFC queue to ensure the code is running + * in the same context. + * + * A Host Controller PSL that is part of an OTG port will be + * registered by the OTG PSL. In this case, the DFC queue + * supplied here must be the same DFC queue as the one + * supplied in the properties of the OTG Controller. + */ + TDfcQue* iControllerDfcQueue; + + /** + * The page size used by this Host Controller. The host stack + * will fill scatter-gather lists with pages of this size. If + * the Host Controller does not have specific page + * requirements itself, the registering Host Controller PSL + * must supply here the CPU MMU page size that can be obtained + * by the call Kern::RoundToPageSize(1). + */ + TInt iControllerPageSize; + }; + + + /** + * A static class implemented by the USB Host PIL layer to allow + * the host controller PSL to register to the PIL layer. + */ + NONSHARABLE_CLASS( UsbHostPil ) + { + public: + /** + * Registration function to be used by a stand-alone (non-OTG + * port) Host Controller PSL to register itself to the PIL + * layer. Host Controllers that are part of an OTG-port are + * registered by the OTG Controller PSL (see usb_otg_shai.h, + * function UsbOtgPil::RegisterOtgController). + * + * The intended usage is that each stand-alone Host Controller + * PSL is a kernel extension that registers itself to the USB + * Host PIL layer by making this call from their own kernel + * extension entry point function (or an equivalent code that + * runs during bootup). + * + * @param aHostControllerIf Reference to the Host Controller + * interface implemented by the registering PSL. + * + * @param aProperties Reference to an object describing the + * static properties of the Host Controller. The PIL layer + * requires that the supplied reference remains valid + * indefinitely, as a Host Controller cannot unregister. + * + * @lib usbotghostpil.lib + */ + IMPORT_C static void RegisterHostController( + MHostControllerIf& aHostControllerIf, + const THostControllerProperties& aProperties ); + }; + }; + +#endif // USB_HOST_SHAI_H + +/* End of File */ diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_otg_shai.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_otg_shai.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,626 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + @brief USB OTG SHAI header + @version 0.2.0 + + This header specifies the USB OTG SHAI. + + @publishedDeviceAbstraction +*/ + + +#ifndef USB_OTG_SHAI_H +#define USB_OTG_SHAI_H + +// System includes +#include +#include // Common types shared between the USB SHAIs + +/** + * This macro specifies the version of the USB OTG SHAI header in + * binary coded decimal format. This allows the PSL layer to confirm a + * certain definition is available, if needed. This can for example + * make it possible for a new PSL to support compilation in an older + * environment with old USB SHAI version that is missing some new + * definitions. + */ +#define USB_OTG_SHAI_VERSION 0x020 + +// The namespace is documented in file usb_common_shai.h, so it is not +// repeated here +namespace UsbShai + { + // Forward declarations + + class MOtgControllerIf; + class MOtgObserverIf; + class MPeripheralControllerIf; + class TPeripheralControllerProperties; + class MHostControllerIf; + class THostControllerProperties; + + // Data types + + /** + * Enumeration listing the possible states of the ID pin. Due to a + * dependency between OTG and USB Battery Charging, this + * enumeration lists also the special states introduced as part of + * the Battery Charging Specification version 1.1. + * + * An OTG Controller PSL for a system that does not support + * Accessory Charger Adapter (ACA) will always report only + * EIdStateRidFloat or EIdStateRidGnd. An OTG Controller PSL that + * supports ACA is required to report the ID pin state accurately + * in order for the OTG State Machine to understand why VBUS + * appears high even though we should default to the host role and + * should normally drive VBUS ourselves (in case of RID_A). + * + * Reporting an ACA state via the ID pin notification mechanism is + * not a substitute for reporting port type detection via the USB + * Charger Detection SHAI that is documented separately in + * usb_charger_detection_shai.h. When ACA is supported, it is + * required that the Charger Detector PSL guarantees that the OTG + * Observer gets notified of the ID pin state before reporting the + * port type to the Charger Detector Observer. + * + * @see usb_charger_detection_shai.h + */ + enum TIdPinState + { + /** ID pin is grounded */ + EIdStateRidGnd = 0, + + /** ID pin is floating */ + EIdStateRidFloat, + + /** + * ID pin is in the RID_A range, as specified in Battery + * Charging 1.1 specification + */ + EIdStateRidA, + + /** + * ID pin is in the RID_B range, as specified in Battery + * Charging 1.1 specification + */ + EIdStateRidB, + + /** + * ID pin is in the RID_C range, as specified in Battery + * Charging 1.1 specification + */ + EIdStateRidC + }; + + /** + * Enumeration listing the reported states of VBUS on the OTG + * port. + * + * The threshold for Session Valid comparison is VOTG_SESS_VLD as + * defined in the "On-The-Go and Embedded Host Supplement to the + * USB Revision 2.0 Specification", Table 4-1 Electrical + * Characteristics. The voltage level for a compliant + * implementation can be anywhere between 0.8 V and 4.0 V. + */ + enum TVbusState + { + /** VBUS is below the OTG Session Valid threshold */ + EVbusStateNoSession = 0, + + /** + * VBUS is above the OTG Session Valid threshold, but below + * the requirements of AVbusValid. + */ + EVbusStateSessionValid, + + /** + * When operating as the A-device and driving VBUS, indicates + * that the VBUS is in regulation, as defined in "On-The-Go + * and Embedded Host Supplement to the USB Revision 2.0 + * Specification" Section 4.2.1, "VBUS Output Voltage and + * Current". + * + * When a VBUS session has been started as the A-device, the + * OTG Controller PSL is required to report a VBUS level of + * EVbusStateAVbusValid when VBUS has successfully risen to + * allow the OTG State Machine to transition out of the + * a_wait_vrise state. + * + * After VBUS has been successfully raised when operating as + * the A-device, the PSL reporting a VBUS level less than + * EVbusStateAVbusValid is considered as a report of a VBUS + * error (over-current) situation and will result in ending + * the session immediately. + */ + EVbusStateAVbusValid + }; + + /** + * Enumeration listing the state of the OTG 2.0 state machine. + * + * The states match those defined in the "On-The-Go and Embedded + * Host Supplement to the USB Revision 2.0 Specification" for the + * OTG A-device and B-device states. + */ + enum TOtgState + { + /** The OTG state is b_idle */ + EOtgStateBIdle = 0, + + /** The OTG state is b_peripheral */ + EOtgStateBPeripheral, + + /** The OTG state is b_wait_acon */ + EOtgStateBWaitAcon, + + /** The OTG state is b_host */ + EOtgStateBHost, + + /** The OTG state is a_idle */ + EOtgStateAIdle, + + /** The OTG state is a_wait_vrise */ + EOtgStateAWaitVrise, + + /** The OTG state is a_wait_bcon */ + EOtgStateAWaitBcon, + + /** The OTG state is a_host */ + EOtgStateAHost, + + /** The OTG state is a_suspend */ + EOtgStateASuspend, + + /** The OTG state is a_peripheral */ + EOtgStateAPeripheral, + + /** The OTG state is a_wait_vfall */ + EOtgStateAWaitVfall, + + /** The OTG state is a_vbus_err */ + EOtgStateAVbusErr + }; + + /** + * Enumeration listing the roles that our device can be in. + */ + enum TOtgRole + { + /** + * Our device is idle, i.e. we are not operating in either the + * peripheral or the host role. This role indicates that + * neither the host controller nor the peripheral controller + * needs to be activated and the PSL is free to power down the + * controllers. + */ + EOtgRoleIdle = 0, + + /** Our device is operating in the peripheral role */ + EOtgRolePeripheral, + + /** Our device is operating in the host role */ + EOtgRoleHost + }; + + // Class declaration + + /** + * An interface class that needs to be implemented by each OTG + * Controller PSL that registers to the USB stack. + * + * The USB OTG Stack will call the functions of this interface + * from a DFC queued on the DFC queue supplied by the OTG + * Controller PSL in TOtgControllerProperties::iControllerDfcQueue + * when the OTG Controller PSL registered. + */ + NONSHARABLE_CLASS( MOtgControllerIf ) + { + public: + /** + * Called by the OTG stack to set the observer callback + * interface to be used by the OTG Controller PSL to report + * events. + * + * When the observer pointer is set to non-NULL value, the OTG + * Controller PSL is required to immediately report the + * current VBUS and ID states to the observer to get the + * status of the OTG stack up to date. + * + * @param aObserver Pointer to the observer interface to use, + * or NULL when the OTG stack is being unloaded. + */ + virtual void SetOtgObserver( MOtgObserverIf* aObserver ) = 0; + + /** + * When operating as the B-peripheral, the OTG stack calls + * this function to indicate that the upper layers are + * requesting our device to become the B-host. This means that + * our OTG device will need start the HNP signalling by + * disconnecting from the bus and allowing the A-device to + * connect as the peripheral. The signalling shall be started + * when the host has suspended the bus, which may already be + * the case or happen later. + * + * This function call is only relevant for OTG controllers + * that implement the HNP signalling in hardware and require + * an explicit request from SW to start the HNP role switch. + * If the OTG controller is under SW control by the Host and + * Peripheral Controller PSLs, the OTG Controller PSL should + * ignore this call. The HNP signalling in the SW-controlled + * case will be handled as normal calls to disconnect as + * peripheral and then start the host controller. + * + * For all controller types, the Host Controller PSL and the + * Peripheral Controller PSL associated with the OTG port are + * required to report events as they normally would when + * operating as the default role. For the Host Controller PSL, + * this includes notifying device connection, disconnection, + * and other relevant events via MRootHubCallbackIf. For the + * Peripheral Controller PSL, this includes notifying bus + * state events such as reset, suspend, and resume via + * MUsbPeripheralPilCallbackIf::DeviceEventNotification. + * + * The OTG Controller PSL is not required to perform any + * monitoring of HNP success or failure, or report that to the + * PIL layer. The PSL is only responsible for making the + * normal host and peripheral notifications mentioned above, + * and the PIL can see the HNP success or failure from those + * notifications. + */ + virtual void SetBHnpRequest() = 0; + + /** + * When operating as the B-device, the OTG stack calls this + * function to request the PSL to drive SRP signalling on the + * bus by pulsing the D+ dataline. The OTG Controller PSL may + * synchronously drive the 5..10 millisecond pulse before + * returning, but it may also do it asynchronously. + * + * The OTG PIL layer guarantees that the initial conditions + * for driving SRP are satisfied before the PIL calls this + * function. That is, the PIL guarantees that sufficient time + * has elapsed since the end of the previous VBUS session (if + * any) and the bus has been idle long enough. + * + * No special report from the OTG Controller PSL is required + * in either success or fail case. In a success case, the + * A-device will raise VBUS and the OTG state machine gets + * this as a normal VBUS notifications from the OTG Controller + * PSL. In a fail case, a timer in the upper layers will + * expire, indicating to upper layers that the SRP was not + * successful. + */ + virtual void SignalBSrp() = 0; + + /** + * Called by the OTG state machine to indicate a change in the + * required controller role. + * + * Whether the PSL needs to do any actions depends on the HW. + * For controllers that require special configuration in + * changing a role (other than just starting the peripheral + * controller or the host controller normally), the OTG + * Controller should do that special configuration when it + * gets this call. + * + * When changing a role, the OTG state machine will first + * disable the stack for the previous role, causing that stack + * to issue a stop request to the respective controller + * PSL. The OTG state machine will then call this function + * SetControllerRole() to set the controller role to the + * target role. Following this, the OTG state machine will + * enable the stack for the target role, causing that stack to + * issue a start request to the respective controller PSL. + * + * @param aControllerRole The OTG role to set our device to + * + * @return KErrNone if the OTG Controller successfully set the + * role or required no actions. Otherwise a system-wide + * error code. + */ + virtual TInt SetControllerRole( TOtgRole aControllerRole ) = 0; + }; + + + /** + * An interface class implemented by the USB stack to allow the + * OTG controller to report events to the USB stack. This includes + * events like VBUS rising and falling, ID pin becoming grounded + * or floating, and SRP being detected. + * + * It is required that the OTG Controller PSL calls these + * functions in the context of the DFC queue supplied by the OTG + * Controller PSL in TOtgControllerProperties::iControllerDfcQueue + * when the OTG Controller PSL registered. + */ + NONSHARABLE_CLASS( MOtgObserverIf ) + { + public: + /** + * Notify the current ID-pin state to the OTG stack. This + * needs to be called by the OTG Controller PSL everytime + * there is a change in the ID pin level. Redundant + * notifications that don't change the previously reported + * state are silently ignored, so the function is safe to call + * without worrying about extra calls. + * + * When USB Battery Charging is supported on the OTG-capable + * port, there is a dependency between normal USB + * functionality and USB Battery Charging (see + * usb_charger_detection_shai.h and specifically the + * description of class MChargerDetectorIf). In this case it + * is the responsibility of the OTG Controller PSL to + * communicate with the Charger Detector PSL (which it may + * implement itself) with respect to VBUS and ID pin events. + * + * For ID pin events that indicate connection to an Accessory + * Charger Adapter, it is required that the port type is first + * notified to the Charger Detector PSL Observer, followed by + * notifying the ID pin state to the OTG Observer (via this + * function). + * + * @param aIdPinState The current ID-pin state + */ + virtual void NotifyIdPinState( TIdPinState aIdPinState ) = 0; + + /** + * Notify the current VBUS state to the OTG stack. This needs + * to be called by the OTG Controller PSL everytime there is a + * change in the VBUS level. Redundant notifications that + * don't change the previously reported state are silently + * ignored, so the function is safe to call without worrying + * about extra calls. + * + * When USB Battery Charging is supported on the OTG-capable + * port, there is a dependency between normal USB + * functionality and USB Battery Charging (see + * usb_charger_detection_shai.h and specifically the + * description of class MChargerDetectorIf). In this case it + * is the responsibility of the OTG Controller PSL to + * communicate with the Charger Detector PSL (which it may + * implement itself) with respect to VBUS and ID pin events. + * + * When VBUS rises on the OTG-capable port that is currently + * the B-device and fully supports Battery Charging + * Specification Revision 1.1, the Charger Detector PSL and + * the OTG Controller PSL need to together guarantee that Data + * Contact Detect is completed and the port type detected + * before reporting VBUS rising. When the port type is known, + * the port type needs to be notified to the Charger Detector + * PSL Observer, followed by notifying the VBUS state to the + * OTG Observer (via this function). + * + * Where Data Contact Detect is not supported, the VBUS rise + * event needs to be notified to the OTG Observer (via this + * function) immediately and charger detection needs to + * proceed in parallel with the upper layers preparing the USB + * personality. This is necessary in order to ensure that we + * can fulfill the requirement to connect to the bus within a + * second, while still making as long as possible charger + * detection cycle to minimize the changes of false detections + * due to datalines not making contact yet. + * + * The OTG Controller PSL, the Peripheral Controller PSL and + * the Charger Detector PSL need to together guarantee that + * the peripheral controller does not attempt to connect to + * the bus while charger detection is still on-going. When + * detection has been completed and upper layers have + * indicated readiness to connect to the bus (see + * MPeripheralControllerIf::PeripheralConnect(), the + * Peripheral Controller PSL must connect to the bus. + * + * @param aVbusState The current VBUS state + */ + virtual void NotifyVbusState( TVbusState aVbusState ) = 0; + + /** + * When operating as the A-device with VBUS low, notify the + * OTG stack that SRP signalling has been detected on the + * bus. The OTG Controller must detect the SRP signalling from + * dataline pulsing, as specified in the "On-The-Go and + * Embedded Host Supplement to the USB Revision 2.0 + * Specification". + */ + virtual void NotifySrpDetected() = 0; + + /** + * This function is called by the OTG Controller PSL to report + * that it has detected the attachment of a device (A or B) + * that is malfunctioning in a low-level way that prevents + * attempting communication with the connected device. Such + * cases may include but are not necessarily limited to: + * + * 1. A B-device that drives its upstream VBUS. To prevent + * damage to the VBUS charge pump in our A-device, it may be + * necessary to prevent VBUS from being raised by our device. + * + * 2. A B-device that presents a single-ended one (both + * datalines high) on the bus. + * + * The detection of such malfunctioning devices is left to the + * OTG Controller PSL, as this type of malfunctions are + * low-level problems not necessarily detectable with the + * standard inputs available to the OTG state machine. + * + * To ensure that the OTG state machine stays in an idle + * state, the OTG Controller PSL should report ID floating and + * VBUS low prior to reporting the bad device attachment by + * calling this function. When the bad device is detached, the + * OTG Controller PSL can resume reporting ID and VBUS state + * truthfully, and must call NotifyBadDeviceDetached() to + * allow the upper layers to see the error condition has been + * cleared. + * + * @see NotifyBadDeviceDetached() + */ + virtual void NotifyBadDeviceAttached() = 0; + + /** + * This function is called by the OTG Controller PSL to report + * that a previously detected bad device has been detached. + * See NotifyBadDeviceAttached() for description of this + * functionality. + * + * @see NotifyBadDeviceAttached() + */ + virtual void NotifyBadDeviceDetached() = 0; + }; + + + /** + * This class specifies the information provided by an OTG + * Controller PSL when registering to the USB OTG stack. + * + * The PSL should prepare for the possibility that members may be + * added to the end of this class in later SHAI versions if new + * information is needed to support new features. The PSL should + * not use this class as a direct member in an object that is not + * allowed to grow in size due to binary compatibility reasons. + * + * @see UsbOtgPil::RegisterOtgController() + */ + NONSHARABLE_CLASS( TOtgControllerProperties ) + { + public: // Types and constants + /** + * A bitmask type used to indicate the static capabilities of + * the OTG Controller. + */ + typedef TUint32 TOtgCaps; + + public: + /** + * Inline constructor for the OTG Controller properties + * object. This is inline rather than an exported function to + * prevent a binary break in a case where an older PSL binary + * might provide the constructor a smaller object due to the + * PSL being compiled against an older version of the SHAI + * header. When it's inline, the function is always in sync + * with the object size. + * + * We slightly violate the coding conventions which say that + * inline functions should be in their own file. We don't want + * to double the number of USB SHAI headers just for sake of a + * trivial constructor. + */ + inline TOtgControllerProperties() : + iCapabilities(0), + iControllerDfcQueue(NULL) + { + }; + + public: // Data + /** + * A bitmask specifying the static capabilities of this OTG + * Controller. No capabilities are specified at the moment and + * the PSL shall fill this field with a zero value. + * + * The field is added for sake of future proofing the binary + * compatibility of the OTG SHAI. By having a field reserved + * for capability bits, we can later specify bits to indicate + * added virtual functions or extension to this controller + * properties structure. The PIL layer can then at runtime + * confirm the existence of the new functions or fields and + * safely support an older binary, if we choose to. + */ + TOtgCaps iCapabilities; + + /** + * Pointer to a DFC queue that will be used for DFCs of this + * controller and the associated peripheral and host + * controllers. + * + * The OTG Controller must supply a pointer to a dedicated DFC + * queue that has been created for this OTG Controller PSL. + * Both the OTG Controller PSL itself and the OTG stack must + * queue their DFCs for this controller in this DFC queue to + * ensure the code is running in the same context. + * + * Furthermore, it is the responsibility of the OTG Controller + * PSL that registers to ensure that the Peripheral and Host + * Controller PSLs that are registered at the same time use + * the same DFC Queue in their respective properties object. + */ + TDfcQue* iControllerDfcQueue; + }; + + + /** + * A static class implemented by the USB OTG PIL layer to allow + * the OTG controller PSL to register to the PIL layer. + */ + NONSHARABLE_CLASS( UsbOtgPil ) + { + public: + /** + * Registration function to be used by the OTG Controller PSL + * to register itself and the associated peripheral and host + * controller PSLs to the PIL layer. + * + * The intended usage is that OTG Controller PSL (of which + * only one can exists in a given system) is a kernel + * extension that registers itself and the associated + * peripheral and host controller PSLs to the USB PIL layer by + * making this call from its kernel extension entry point + * function (or an equivalent code that runs during bootup). + * + * @param aOtgControllerIf Reference to the OTG Controller + * interface implemented by the registering PSL. + * + * @param aOtgProperties Reference to an object describing the + * static properties of the OTG Controller. The PIL layer + * requires that the supplied reference remains valid + * indefinitely, as an OTG Controller cannot unregister. + * + * @param aPeripheralControllerIf Reference to the Peripheral + * Controller interface implemented by the PSL controlling the + * Peripheral Controller associated with the registering OTG + * port. + * + * @param aPeripheralProperties Reference to an object + * describing the static properties of the Peripheral + * Controller. The PIL layer requires that the supplied + * reference remains valid indefinitely, as the registering + * OTG Controller cannot unregister. + * + * @param aHostControllerIf Reference to the Host Controller + * interface implemented by the PSL controlling the Host + * Controller associated with the registering OTG port. + * + * @param aHostProperties Reference to an object describing the + * static properties of the Host Controller. The PIL layer + * requires that the supplied reference remains valid + * indefinitely, as the registering OTG Controller cannot + * unregister. + * + * @lib usbotghostpil.lib + */ + IMPORT_C static void RegisterOtgController( + MOtgControllerIf& aOtgControllerIf, + const TOtgControllerProperties& aOtgProperties, + MPeripheralControllerIf& aPeripheralControllerIf, + const TPeripheralControllerProperties& aPeripheralProperties, + MHostControllerIf& aHostControllerIf, + const THostControllerProperties& aHostProperties ); + }; + }; + +#endif // USB_OTG_SHAI_H + +/* End of File */ diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_peripheral_shai.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_peripheral_shai.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,1181 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + + @brief USB Peripheral SHAI header + + @version 0.3.0 + + Abstract interface for USB Peripheral Controller. + + @publishedDeviceAbstraction + + */ + +#ifndef USB_PERIPHERAL_SHAI_H +#define USB_PERIPHERAL_SHAI_H + +// System includes +#include +#include // Common types shared between the USB SHAIs +#include // Common types shared with upper layers + +/** + * This macro specifies the version of the USB Peripheral SHAI header + * in binary coded decimal format. This allows the PSL layer to + * confirm a certain definition is available, if needed. This can for + * example make it possible for a new PSL to support compilation in an + * older environment with old USB SHAI version that is missing some + * new definitions. + */ +#define USB_PERIPHERAL_SHAI_VERSION 0x030 + +// The namespace is documented in file usb_common_shai.h, so it is not +// repeated here +namespace UsbShai + { + /** + * Masks defined for TUsbPeripheralEndpointCaps.iSizes. + * + * Zero means this endpoint is not available (= no size). + */ + const TUint KUsbEpNotAvailable = 0x00000000; + + /** + * Max packet size is continuously variable up to some size specified. + * (Interrupt and Isochronous endpoints only.) + */ + const TUint KUsbEpSizeCont = 0x00000001; + + /** Max packet size 8 bytes is supported */ + const TUint KUsbEpSize8 = 0x00000008; + + /** Max packet size 16 bytes is supported */ + const TUint KUsbEpSize16 = 0x00000010; + + /** Max packet size 32 bytes is supported */ + const TUint KUsbEpSize32 = 0x00000020; + + /** Max packet size 64 bytes is supported */ + const TUint KUsbEpSize64 = 0x00000040; + + /** Max packet size 128 bytes is supported */ + const TUint KUsbEpSize128 = 0x00000080; + + /** Max packet size 256 bytes is supported */ + const TUint KUsbEpSize256 = 0x00000100; + + /** Max packet size 512 bytes is supported */ + const TUint KUsbEpSize512 = 0x00000200; + + /** Max packet size 1023 bytes is supported */ + const TUint KUsbEpSize1023 = 0x00000400; + + /** Max packet size 1024 bytes is supported */ + const TUint KUsbEpSize1024 = 0x00000800; + + /** + * Test Mode Selectors (Set/ClearFeature) + * Refer to usb specification 2.0, Chapter 9.4.9, table 9-7 + */ + enum TUsbTestModeSelector + { + EUsbTestSelector_Test_J = 0x01, + EUsbTestSelector_Test_K, + EUsbTestSelector_Test_SE0_NAK, + EUsbTestSelector_Test_Packet, + EUsbTestSelector_Test_Force_Enable + }; + + /** + * Transfer direction of a USB transfer request. + * @see TUsbPeripheralRequest + */ + enum TTransferDirection + { + EControllerNone, + EControllerRead, + EControllerWrite + }; + + /** + * Enumeration listing the event codes that are passed from PSL to + * PIL to indicate peripheral events + */ + enum TUsbPeripheralEvent + { + /** The USB Suspend bus state has been detected. + * + * When the Peripheral Controller PSL is part of an + * OTG-capable port, the PSL shall report this event also when + * operating as the A-peripheral, in which case this final + * suspend event starts the HNP role switch back to A-host. + */ + EUsbEventSuspend, + + /** USB Resume signaling has been detected. */ + EUsbEventResume, + + /** A USB Reset condition has been detected. */ + EUsbEventReset, + + /** + * VBUS level has risen above the B-session valid threshold. This + * is only relevant for a stand-alone peripheral controllers + * (those not associated with an OTG port). For an OTG port, the + * VBUS state is reported to PIL layer by the OTG Controller PSL. + */ + EUsbEventVbusRisen, + + /** + * VBUS level has fallen below the B-session valid threshold. This + * is only relevant for a stand-alone peripheral controllers + * (those not associated with an OTG port). For an OTG port, the + * VBUS state is reported to PIL layer by the OTG Controller PSL. + */ + EUsbEventVbusFallen + }; + + typedef TUint32 TUsbPeripheralPacketArray; + + /** + * @brief A USB transfer request. + * + * This class will be constructed in PIL or upper layer, and be + * passed down to PSL. After the request was done, PSL layer will + * modify corresponding members (like data length, packet info + * etc.) and re-pass it back to PIL via interface + * MUsbPeripheralPilCallbackIf::EndpointRequestComplete(). + * + */ + NONSHARABLE_CLASS(TUsbPeripheralRequest) + { + public: + /** + * This class doesn't need a destructor because it has nothing to be + * freed, closed, destroyed. It 'owns' nothing. + */ + IMPORT_C TUsbPeripheralRequest(TInt aRealEpNum); + + public: + /** The 'real' endpoint number this request to be bind to. */ + TInt iRealEpNum; + + /** + * Start address of this buffer. Filled-in by PIL. + * + * PSL needs to put received data in this buffer if it's a read request. + * PSL needs to get data from this buffer if it is a write request. + */ + TUint8* iBufferStart; + + /** Physical address of buffer start (used for DMA). */ + TUintPtr iBufferAddr; + + /** Length in bytes to be read/write. Filled-in by PIL. */ + TInt iLength; + + /** + * Number of bytes transmitted (if it is a write); + * This value need to be updated by PSL. + */ + TUint iTxBytes; + + /** + * Number of packets received (if it is a read); + * This value need to be updated by PSL. + */ + TUint iRxPackets; + + /** + * This is a re-interpretation of what's inside in buffer iBufferStart. + * It is designed to be that the first packet always contains all the + * bytes received. So only the following scenario are possible: + * + * 1. Nothing, iRxPackets is zero, no packet received. + * + * 2. 1 data Packet, iRxPackets is one. + * iPacketIndex[0] is the offset against iBufferStart of where the + * first byte of received data begins. + * iPacketSize[0] is the size (in bytes) of the received data. + * + * 3. 1 data packet, and one ZLP packet, iRxPackets is two. + * iPacketIndex[0] is the offset against iBufferStart of where the + * first byte of received data begins. + * iPacketSize[0] is the size (in bytes) of the data packet. + * + * iPacketIndex[1] is the offset of the ZLP packet. + * iPacketSize[1] is always set to zero since ZLP contains no data. + * + */ + TUsbPeripheralPacketArray* iPacketIndex; + + /** Array of packet sizes. Details see iPacketIndex */ + TUsbPeripheralPacketArray* iPacketSize; + + /** + * Indicates the transfer direction of this request. + * Note, SetupEndpointRead/Write likewise functions already point out + * the transfer direction, PSL may select to use it or not. + */ + TTransferDirection iTransferDir; + + /** + * For EControllerWrite (IN) transfers, it is used to Indicates that if + * a Zero Length Packet is required at the end of this transfer. + * It will be set to ETrue if ZLP is needed, EFalse otherwise. + */ + TBool iZlpReqd; + + /** + * The error code upon completion of the request; + * PSL need to set it to KErrNone if no errors, Set it to other + * system error codes otherwise. + */ + TInt iError; + }; + + /** + * Peripheral controller capabilities. + * + * PSL should use those values to fill in data member iControllerCaps in + * structure TPeripheralControllerProperties. + * + * @see TPeripheralControllerProperties. + */ + typedef TUint32 TDeviceCaps; + + /** + * Indicates whether peripheral controller hardware supports USB High-speed. + * This capability affects driver functionality and behavior throughout the + * implementation. + * + * Set this bit if this peripheral controller supports USB High-speed; + * Clear it otherwise. + */ + const TDeviceCaps KDevCapHighSpeed = 0x00000001; + + /** + * Indicates whether the peripheral controller supports hardware acceleration + * for setting the device address, i.e. automatically setting device address + * on conclusion of status phase of SET_ADDRESS. + * + * If this capability is supported PIL will call SetDeviceAddress() before + * sending a zero byte status packet. + * + * Set this bit if hardware acceleration is supported. + * Clear it otherwise. + */ + const TDeviceCaps KDevCapSetAddressAcceleration = 0x00000002; + + /** + * Indicates whether controller support Session Request Protocol. + * + * Set this bit if SRP is supported. + * Clear it otherwise. + */ + const TDeviceCaps KDevCapSrpSupport = 0x00000004; + + /** + * Indicates whether controller support Host Negotiation Protocol. + * + * Set this bit if HNP is supported. + * Clear it otherwise. + */ + const TDeviceCaps KDevCapHnpSupport = 0x00000008; + + /** + * Indicates whether controller support Remote wakeup + * + * Set this bit if remote wakeup is supported. + * Clear it otherwise. + */ + const TDeviceCaps KDevCapRemoteWakeupSupport = 0x00000010; + + /** + * Configuration data from PSL to PIL when register a controller through + * interface UsbPeripheralPil::RegisterPeripheralController(). + */ + NONSHARABLE_CLASS(TPeripheralControllerProperties) + { + public: + TPeripheralControllerProperties(); + + public: // Data + /** + * A bitmap used to Indicates the capabilities of this controller. + * PSL should set the corresponding bit to '1' if one capability is + * supported by this controller. + */ + TDeviceCaps iControllerCaps; + + /** + * Pointer to a DFC queue that will be used for DFCs of this controller. + * + * A stand-alone (one not associated with an OTG-port) peripheral PSL + * implementation must supply a pointer to a dedicated DFC queue that + * has been created for this controller. Both the PSL itself and the PIL + * layer must queue their DFCs for this controller in this DFC queue to + * ensure the code is running in the same context. + * + * A peripheral PSL that is part of an OTG port will be registered by + * the OTG PSL. In this case, the DFC queue supplied here must be the + * same DFC queue as the one supplied in the properties of the OTG + * Controller. + */ + TDfcQue* iDfcQueue; + + /** + * Describe the capabilities of all endpoint owned by this controller. + * + * Note that there might be gaps in the array, because the endpoints + * must be numbered by using the 'real endpoint' numbering scheme. + * + * An example of end point capability array: + * + * @code + * static const TUsbPeripheralEndpointCaps DevEndpointCaps[KTotalEps] = + * { + * // MaxSize mask , Types&Dir , High ,Reserved + * speed? + * {KEp0MaxPktSzMask,(KUsbEpTypeControl | KUsbEpDirOut), ETrue ,0 , 0}, + * {KEp0MaxPktSzMask,(KUsbEpTypeControl | KUsbEpDirIn ), ETrue ,0 , 0}, + * + * {KUsbEpNotAvailable,KUsbEpNotAvailable , ETrue ,0 , 0}, + * + * {KBlkMaxPktSzMask,(KUsbEpTypeBulk | KUsbEpDirIn ) , ETrue ,0 , 0}, + * {KBlkMaxPktSzMask,(KUsbEpTypeBulk | KUsbEpDirOut) , ETrue ,0 , 0} + * }; + * @endcode + * + * For endpoint maxinum packet size on USB2.0 High-speed, PSL should + * provide the overlaid values for both full speed and high speed, as + * PIL can deduce the appropriate values for either speed. + * + */ + const TUsbPeripheralEndpointCaps* iDeviceEndpointCaps; + + /** + * Set by the PSL to indicate the number of entries in + * iDeviceEndpointCaps array. + * Be noted that this value include the ones that are marked as + * KUsbEpNotAvailable in table iDeviceEndpointCaps. + */ + TInt iDeviceTotalEndpoints; + + /** + * Maximum size of ep0 packet. + * @see USB spec 2.0, chapter 9, table 9-8. + */ + TUint8 iMaxEp0Size; + + /** + * Device Release number in binary-coded decimal. + * @see USB spec 2.0, chapter 9, table 9-8. + */ + TUint16 iDeviceRelease; + }; + + /** + * Enumeration of stages within a control transfer + * + * Possible stages defined in USB spec include: + * 1. setup -> status in + * 2. setup -> data in -> status out + * 3. setup -> data out -> status in + */ + enum TControlStage + { + /** + * Control transfer always start with a setup stage in which a setup + * packet is expected. + */ + EControlTransferStageSetup, + + /** The stage that a data packet is expected from be received */ + EControlTransferStageDataOut, + + /** + * Status in stage can either following a Setup stage (if no data stage) + * or following a data out stage. + */ + EControlTransferStageStatusIn, + + /** + * Depends on the request type of a setup packet, a data in stage maybe + * followed after a setup packet. + * + * Within this stage we expect upper/ourself to send some data to host. + */ + EControlTransferStageDataIn, + + /** + * This is an optional stage, some controller will silently swallow + * Status out packet and not able to report it. + * PIL has consider this situation when control transfer state machine + * is introduced. + */ + EControlTransferStageStatusOut, + + EControlTransferStageMax + }; + + /** + * Packet types in control transfers. + * + * PSL need to tell PIL about the types of each packet it received. + * @see MUsbPeripheralPilCallbackIf::Ep0RequestComplete(). + */ + enum TControlPacketType + { + /** Indicates a setup packet */ + EControlPacketTypeSetup, + + /** Indicates a data out packet */ + EControlPacketTypeDataOut, + + /** + * Indicates a status in packet. + * optional, PSL can select not to complete this packet. + */ + EControlPacketTypeStatusIn, + + /** Indicates a data in packet */ + EControlPacketTypeDataIn, + + /** + * Indicates that a status out packet. + * optional, PSL can select not to complete this packet. + */ + EControlPacketTypeStatusOut, + + }; + + /** + * @brief Interface for PSL to do callback to PIL + * + * This is the interface that a PSL need talk with PIL in order to: + * 1. Pass device event (reset/suspend/resume/vbus high/vbus low etc) to PIL. + * 2. Complete a read/write request to PIL. + * 3. Query control transfer stage from PIL. + * 3. Other functions like SetAdress/Handle HNP/Get remote wake up etc. + * + * This interface already been implemented and exported via library + * usbperipheralpil.lib. PSL need to add this library as a dependency in + * you PSL .mmp file. + * + * @lib usbperipheralpil.lib + */ + NONSHARABLE_CLASS(MUsbPeripheralPilCallbackIf) + { + public: + /** + * Used to synchronize the Ep0 Stage machine between PSL and PIL. + * Accepts a SETUP packet and returns the next Ep0 Stage. + * + * This function will NOT lead anything to be changed at PIL, it is + * functioning by parsing the supplied buffer only. + * + * @param aSetupBuf The SETUP packet received by PSL. + * @return The next Ep0 Stage at PIL if PIL receive this setup packet. + * + */ + virtual TControlStage EnquireEp0NextStage(const TUint8* aSetupBuf) const = 0; + + /** + * This function gets called by PSL upon completion of a pending + * endpoint zero data transfer request. + * + * @param aRealEndpoint Either 0 for Ep0 OUT (= Read) + * or 1 for Ep0 IN (= Write). + * @param aCount The number of bytes received or transmitted. + * @param aError The error code of the completed transfer request. + * KErrNone if no error. + * KErrCancel if transfer was cancelled. + * KErrPrematureEnd if a premature end was encountered. + * @param aPktType The type of the packet that being completed. + * + * @return KErrNone if no error during transfer completion processing; + * KErrGeneral if request was a read & a Setup packet was received & + * the recipient for that packet couldn't be found (invalid packet: Ep0 + * has been stalled); KErrNotFound if the request was a read & the + * recipient for that packet (Setup or data) _was_ * found - however no + * read had been set up by that recipient (this case should be used by + * PSL to disable Ep0 interrupt at that point and give the upper layer + * software time to set up a new Ep0 read; once the 'missing' read was + * set up either Ep0DataReceiveProceed or Ep0ReadSetupPktProceed of + * MPeripheralControllerIf class will be called by PIL). + */ + virtual TInt Ep0RequestComplete(TInt aRealEndpoint, + TInt aCount, + TInt aError, + TControlPacketType aPktType) = 0; + + /** + * PSL call this function upon completion of a pending data transfer + * request. This function isn't to be used for endpoint zero completions + * (use Ep0RequestComplete instead). + * + * @param aCallback A pointer to a data transfer request callback + * structure which was previously passed to PSL in a + * SetupEndpointWrite() or SetupEndpointRead() call. + * + */ + virtual void EndpointRequestComplete(TUsbPeripheralRequest* aCallback) = 0; + + /** + * This function gets called by PSL upon detection of either of the + * following events: + * - USB Reset, + * - USB Suspend event, + * - USB Resume signaling, + * + * When the Peripheral Controller PSL is part of an + * OTG-capable port, the PSL shall report the above events + * also when operating as the A-peripheral, including + * reporting the final suspend event that starts the HNP role + * switch back to A-host. + * + * In addition to the events above, a stand-alone peripheral + * controller PSL (one not associated with an OTG port) is + * required to report the following events: + * - VBUS rising above the session valid threshold + * - VBUS falling below the session valid threshold + * + * When the peripheral controller is part of an OTG port, the + * PIL layer receives VBUS notifications via the OTG stack, + * and the peripheral PSL is not expected to report them via + * this interface. + * + * When USB Battery Charging is supported on the + * peripheral-only port, there is a dependency between normal + * USB functionality and USB Battery Charging (see + * usb_charger_detection_shai.h and specifically the + * description of class MChargerDetectorIf). In this case it + * is the responsibility of the Peripheral Controller PSL to + * communicate with the Charger Detector PSL (which it may + * implement itself) with respect to VBUS events. + * + * When VBUS rises on the peripheral-only port that fully + * supports Battery Charging Specification Revision 1.1, the + * Charger Detector PSL and the Peripheral Controller PSL need + * to together guarantee that Data Contact Detect is completed + * and the port type detected before notifying VBUS rising. + * When the port type is known, the port type needs to be + * notified to the Charger Detector PSL Observer, followed by + * notifying a VBUS rising event to the Peripheral Controller + * PIL callback interface (via this function). + * + * Where Data Contact Detect is not supported, the VBUS rise + * event needs to be notified to the Peripheral Controller PIL + * callback interface (via this function) immediately and + * charger detection needs to proceed in parallel with the + * upper layers preparing the USB personality. This is + * necessary in order to ensure that we can fulfill the + * requirement to connect to the bus within a second, while + * still making as long as possible charger detection cycle to + * minimize the changes of false detections due to datalines + * not making contact yet. + * + * The Peripheral Controller PSL and the Charger Detector PSL + * need to together guarantee that the peripheral controller + * does not attempt to connect to the bus while charger + * detection is still on-going. When detection has been + * completed and upper layers have indicated readiness to + * connect to the bus (see MPeripheralControllerIf::PeripheralConnect(), + * the Peripheral Controller PSL must connect to the bus. + * + * @param aEvent An enum denoting the event that has occurred. + * + * @return KErrArgument if the event is not recognized, KErrNone + * otherwise + */ + virtual TInt DeviceEventNotification(TUsbPeripheralEvent aEvent) = 0; + + /** + * This function should be called by PSL once the peripheral + * controller (and thus the USB device) is in the Address state. + */ + virtual void MoveToAddressState() = 0; + + /** + * This function should be called by PSL after reception of an Ep0 + * SET_FEATURE request with a feature selector of either {b_hnp_enable, + * a_hnp_support, a_alt_hnp_support}, but ONLY when that Setup packet is + * not handed up to PIL (for instance because it is auto-decoded and + * 'swallowed' by the peripheral controller hardware). + * + * @param aHnpState A bitmask indicating the present state of the three + * OTG feature selectors as follows: + * + * bit.0 == a_alt_hnp_support + * bit.1 == a_hnp_support + * bit.2 == b_hnp_enable + * + * @see TUsbHnpCaps + * + */ + virtual void HandleHnpRequest(TInt aHnpState) = 0; + + /** + * Returns the current USB device state. + * + * 'USB device state' here refers to the device states as defined + * in chapter 9 of the USB specification. + * + * @return The current USB device state, or EUsbPeripheralStateUndefined + * if peripheral stack is disabled. + * + */ + virtual TUsbPeripheralState DeviceStatus() const = 0; + + }; + + /** + * MPeripheralControllerIf + * @brief Abstract class for USB peripheral Chipset API. + * @version 0.2. + * + * PSL driver need to implement all those virtual functions in this class. + * + * Four Steps to create a vendor specific usb peripheral PDD. + * + * Step 1: Derive a new class from MUsbPeripheralControllerIf and + * implement all interfaces defined. + * + * Step 2: Create a new instance (we call it inst_of_psl) of the new class. + * Prepare the configuration data defined by structure + * TUsbPeripheralControllerProps (let's call it cfg_data ) + * + * Step 3: Call UsbPeripheralPil::RegisterPeripheralController(inst_of_psl,cfg_data). + * + * Step 4: Member function SetPilCallbackInterface() will be called. + * An instance of MUsbPeripheralPilCallbackIf will be passed to + * PSL via this call. Record it since PSL need to reuse it later + * for any PIL functionality callback. + * + * That's all. + * + * dynamic view of PDD creation. + * PIL will be compiled and linked alone. + * PSL will be compiled alone and linked against a new lib named + * usbperipheralpil.lib. + * + * For PSL vendors, the following stuff are provided: + * usb_peripheral_shai.h & usb_peripheral_shai_shared.h which is + * used for PSL to implement against. + * usbperipheralpil.lib which is used for PSL to link against. + * + */ + NONSHARABLE_CLASS(MPeripheralControllerIf) + { + public: + /** + * This function will be called once and only once by PIL when a PSL + * registered itself to PIL by calling + * UsbPeripheralPil::RegisterPeripheralController(). + * + * PSL is expected to store the callback interface pointer so that make + * it possible to reporting events back to PIL layer. + * + * For stand-alone peripheral controllers (controllers not associated + * with an OTG port),the Peripheral Controller PSL is required to report + * a EUsbEventVbusRisen event by calling MUsbPeripheralPilCallbackIf:: + * DeviceEventNotification() if VBUS is already high at the point this + * function is called. + * + * @param aPilCallbackIf A reference to PIL callback interface which + a PSL must use to report events. + */ + virtual void SetPilCallbackInterface(MUsbPeripheralPilCallbackIf& aPilCallbackIf) = 0; + + /** + * Sets endpoint zero's RX buffer. + * This buffer is maintains at PIL and always exists. + * + * @param aBuffer the buffer address + * @param aBufferLen the length of the buffer. + * + */ + virtual void SetEp0RxBuffer(TUint8* aBuffer, TInt aBufferLen) = 0; + + /** + * Determines the speed mode that this controller is operating at. + * + * @return one of the speed mode defined by TSpeed. + * @see TSpeed. + */ + virtual TSpeed DeviceOperatingSpeed() = 0; + + /** + * Forces the peripheral controller into a non-idle state to perform a + * USB remote wakeup operation. + * + * PIL layer will make sure the following preconditions are meet before + * calling this function: + * 1. we're already in suspended state for at least 5ms (Twtrsm). + * 2. remote wakeup had been enabled by host. + * + * @return KErrNone if successful, otherwise one of the system-wide + * error codes. + */ + virtual TInt SignalRemoteWakeup() = 0; + + /** + * This function will be called by PIL upon decoding a SET_ADDRESS + * request. PIL will make sure that a status packet will be sent before + * calling this function as USB spec required if capability of + * KDevCapSetAddressAcceleration is not support by hardware; Otherwise + * SetAddress call will go ahead of status packet. + * @see KDevCapSetAddressAcceleration + * + * @param aAddress A valid USB device address that was received with the + * SET_ADDRESS request. + * + * @return KErrNone if address was set successfully or if controller's + * address cannot be set manually. otherwise one of the system- + * wide error codes. + */ + virtual TInt SetDeviceAddress(TInt aAddress) = 0; + + /** + * Configures (enables) an endpoint (incl. Ep0) for data transmission or + * reception. + * + * @param aRealEndpoint The number of the endpoint to be configured. + * @param aEndpointInfo A properly filled-in endpoint info structure. + * + * @return KErrNone if endpoint successfully configured; KErrArgument if + * endpoint number or endpoint info invalid; otherwise one of + * the system-wide error codes. + */ + virtual TInt ConfigureEndpoint(TInt aRealEndpoint, + const TUsbPeripheralEndpointInfo& aEndpointInfo) = 0; + + /** + * De-configures (disables) an endpoint (incl. Ep0). + * + * @param aRealEndpoint The number of the endpoint to be disabled. + * + * @return KErrNone if endpoint successfully de-configured; KErrArgument + * if endpoint number invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt DeConfigureEndpoint(TInt aRealEndpoint) = 0; + + /** + * Queries the use of and endpoint resource. + * + * @param aRealEndpoint The number of the endpoint. + * @param aResource The endpoint resource to be queried. + * they are one of the following currently: + * KUsbEndpointInfoFeatureWord1_DMA. + * KUsbEndpointInfoFeatureWord1_DoubleBuffering. + * + * @return ETrue if the specified resource is in use at the endpoint, + * EFalse if not. + */ + virtual TBool QueryEndpointResource(TInt aRealEndpoint, TUint32 aResource) const = 0; + + /** + * Sets up a read request on an endpoint (excl. Ep0) for data reception. + * + * PIL will construct a read request as aCallback, and use this function + * to setup and indicate the readiness for reading data from end point. + * + * PSL need to update related data member of aCallback and complete this + * request by calling EndpointRequestComplete() when request is done. + * + * @see TUsbPeripheralRequest + * + * @param aRealEndpoint The number of the endpoint to be used. + * @param aCallback A properly filled-in (by PIL) request callback. + * + * @return KErrNone if read successfully set up; KErrArgument if endpoint + * number is invalid. otherwise one of the system-wide error + * codes. + */ + virtual TInt SetupEndpointRead(TInt aRealEndpoint, TUsbPeripheralRequest& aCallback) = 0; + + /** + * Sets up a write request on an endpoint (excl. Ep0) for transmission. + * + * PIL will contruct a write request as aCallback, and use this function + * to pass down it to PSL. + * + * PSL need to update related data member of aCallback and complete this + * request by calling EndpointRequestComplete() when data is transmitted + * or any error found. + * @see TUsbPeripheralRequest + * + * @param aRealEndpoint The number of the endpoint to be used. + * @param aCallback A properly filled-in request callback. + * + * @return KErrNone if write successfully set up; KErrArgument if + * endpoint number is invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt SetupEndpointWrite(TInt aRealEndpoint, TUsbPeripheralRequest& aCallback) = 0; + + /** + * Cancels a read request on an endpoint (excl. Ep0). + * + * Note that endpoint 0 read requests are never cancelled by PIL, so + * there is also no CancelEndpointZeroRead() function. + * + * @param aRealEndpoint The number of the endpoint to be used. + * + * @return KErrNone if read successfully cancelled; KErrArgument if + * endpoint number is invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt CancelEndpointRead(TInt aRealEndpoint) = 0; + + /** + * Cancels a write request on an endpoint (incl. Ep0). + * + * PIL calls this function also to cancel endpoint zero write requests. + * + * @param aRealEndpoint The number of the endpoint to be used. + * + * @return KErrNone if write successfully cancelled; KErrArgument if + * endpoint number is invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt CancelEndpointWrite(TInt aRealEndpoint) = 0; + + /** + * Same as SetupEndpointRead(), but for endpoint zero only. + * + * No callback structure is used here as reading to ep0 (host may at any + * time send a SETUP packet) must be ready even before upper application + * is ready. So, a buffer will be passed down to PSL by + * MPeripheralControllerIf::SetEp0RxBuffer() during PIL construction, + * this will benefits the PSL to have a buffer always available for this + * purpose. + * + * PSL must complete this request by EndpointRequestComplete() + * + * @return KErrNone if read successfully set up; otherwise one of the + * system-wide error codes. + */ + virtual TInt SetupEndpointZeroRead() = 0; + + /** + * Same as SetupEndpointWrite(), but for endpoint zero only. + * + * No callback is used here as this function is only used by + * PIL layer only and no user side request exists for it. + * + * @param aBuffer This points to the beginning of the data to be sent. + * @param aLength The number of bytes to be sent. + * @param aZlpReqd ETrue if a ZLP is must be sent after the data. + * + * PSL must complete this request by EndpointRequestComplete() + * + * @return KErrNone if write successfully set up; otherwise one of the + * system-wide error codes. + */ + virtual TInt SetupEndpointZeroWrite(const TUint8* aBuffer, + TInt aLength, + TBool aZlpReqd = EFalse) = 0; + + /** + * Sets up on Ep0 for the transmission of a single zero-length packet. + * + * @return KErrNone if ZLP successfully set up; otherwise one of the + * system-wide error codes. + */ + virtual TInt SendEp0ZeroByteStatusPacket() = 0; + + /** + * Stalls an endpoint (incl. Ep0). + * + * Not applicable to Isochronous endpoints. + * + * @param aRealEndpoint The number of the endpoint to be stalled. + * + * @return KErrNone if endpoint successfully stalled; KErrArgument if + * endpoint number is invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt StallEndpoint(TInt aRealEndpoint) = 0; + + /** + * Clears the stall condition on an endpoint (incl. Ep0). + * + * Not applicable to Isochronous endpoints. + * + * @param aRealEndpoint The number of the endpoint to be stalled. + * + * @return KErrNone if endpoint successfully de-stalled; KErrArgument if + * endpoint number invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt ClearStallEndpoint(TInt aRealEndpoint) = 0; + + /** + * Resets the data toggle bit for an endpoint (incl. Ep0). + * + * Isochronous endpoints don't use data toggles. + * + * @param aRealEndpoint The number of the endpoint to be used. + * + * @return KErrNone if data toggle successfully reset; KErrArgument if + * endpoint number invalid; otherwise one of the system-wide + * error codes. + */ + virtual TInt ResetDataToggle(TInt aRealEndpoint) = 0; + + /** + * Returns the frame number of the last received SOF packet. + * + * @return The (11-bit) frame number of the last received SOF packet. + * + */ + virtual TInt SynchFrameNumber() const = 0; + + /** + * Stores the (11-bit) frame number that should be sent in response to + * the next SYNCH_FRAME request(s). + * + * @param aFrameNumber The (11-bit) frame number to be set + */ + virtual void SetSynchFrameNumber(TInt aFrameNumber) = 0; + + /** + * Starts peripheral controller. + * + * This initializes the device controller hardware before any other + * operation can be performed. + * Tasks to be carried out here might include: + * - resetting the whole peripheral controller design + * - enabling the peripheral controller's clock + * - binding & enabling the peripheral controller (primary) interrupt + * - write meaningful values to some general controller registers + * - enabling the USB Reset interrupt + * - enabling the peripheral controller proper (for instance by + * setting an Enable bit). + * + * This function is also used in an OTG environment when the + * peripheral stack becomes enabled and the controller needs + * to be started and enabled for peripheral use. If the HW + * platform shares resources such as clocks and power between + * the host and peripheral HW, it is probably easiest for the + * PSL to handle the role switch based on the + * MOtgControllerIf::SetControllerRole() call to the OTG + * Controller interface. + * + * @return KErrNone if the controller was successfully started; + * otherwise one of the system-wide error codes. + * + * @see usb_otg_shai.h, MOtgControllerIf::SetControllerRole() + */ + virtual TInt StartPeripheralController() = 0; + + /** + * Stops the peripheral controller. + * + * This basically makes undone what happened in StartPeripheralController(). + * Tasks to be carried out here might include: + * - disabling peripheral controller proper. + * - disabling the USB Reset interrupt. + * - disabling & unbinding the peripheral controller (primary) interrupt. + * - disabling the peripheral controller's clock. + * + * This function is also used in an OTG environment when the peripheral + * stack becomes disabled and the peripheral hardware resources can be + * released. If the hardware platform shares resources such as clocks + * and power between the host and peripheral hardware, it is probably + * easiest for the PSL to handle the role switch based on the + * MOtgControllerIf::SetControllerRole() call to the OTG Controller + * interface. + * + * @return KErrNone if peripheral controller successfully stopped; + * otherwise one of the system-wide error codes. + * + * @see usb_otg_shai.h, MOtgControllerIf::SetControllerRole() + */ + virtual TInt StopPeripheralController() = 0; + + /** + * This function is used to indicate that upper layers are ready to + * start operating as peripheral and want to connect to the USB bus + * if possible. + * + * Since this functionality is not part of the USB specification it + * has to be explicitly supported, either by the peripheral controller + * itself or by the hardware platform. + * + * This call merely reports the upper layer readiness to connect, and + * it is the responsiblity of the PSL to assess when all prerequisites + * for connection are satisfied and physically connect when they are. + * These prerequisites include: + * + * 1. Upper layer readiness has been indicated by calling + * PeripheralConnect(). + * + * 2. The peripheral controller has been started and enabled + * by StartPeripheralController(). + * + * The connection readiness assessment responsibility is delegated to the + * PSL because the physical connection may sometimes be handled by a HW + * state machine, thus making the correct SW-controlled connection time + * HW-specific. + * + * @return KErrNone if peripheral controller successfully connected; + * otherwise one of the system-wide error codes. + */ + virtual TInt PeripheralConnect() = 0; + + /** + * Called to indicate that upper layers no longer want to operate as the + * peripheral and we must disconnect from the USB bus. + * + * Since this functionality is not part of the USB specification it + * has to be explicitly supported, either by the peripheral controller + * itself or by the hardware platform. + * + * @return KErrNone if controller is successfully disconnected; + * otherwise one of the system-wide error codes. + */ + virtual TInt PeripheralDisconnect() = 0; + + /** + * Implements anything peripheral controller might required by following + * bus resume signal. + * + * This function gets called by PIL after it has been notified (by + * PSL) about the Suspend condition. + */ + virtual void Suspend() = 0; + + /** + * Implements anything peripheral controller might required by following + * bus resume signal. + * + * This function gets called by PIL after it has been notified (by + * PSL) about the Resume event. + */ + virtual void Resume() = 0; + + /** + * Implements anything peripheral controller might required by following + * bus resume signal. + * + * This function gets called by PIL after it has been notified (by + * PSL) about the Reset event. + */ + virtual void Reset() = 0; + + /** + * PIL call this function to signal PSL that it has finished processing + * a received Setup packet (on Ep0) and that PSL can now prepare + * itself for the next Ep0 reception. + * + * The reason for having this function is that the situation where no + * Ep0 read has been set up by user and thus a received Setup packet + * cannot immediately be delivered to user. Once user however + * sets up an Ep0 read, PIL then completes the request and eventually + * calls this function. We can implement some sort of flow-control by + * this way. + */ + virtual void Ep0ReadSetupPktProceed() = 0; + + /** + * PIL call this function to signal PSL that it has finished processing + * a received Ep0 data packet and that PSL can now prepare itself for + * the next Ep0 reception. + * + * The reason for having this function is that the situation where no + * Ep0 read has been set up by user and thus a received Setup packet + * cannot immediately be delivered to user. Once user however + * sets up an Ep0 read, PIL then completes the request and eventually + * calls this function. We can implement some sort of flow-control by + * this way. + */ + virtual void Ep0ReadDataPktProceed() = 0; + + /** + * Puts controller into a specific test mode (during HS operation only). + * + * 9.4.9 Set Feature: "The transition to test mode must be complete no + * later than 3 ms after the completion of the status stage of the + * request." (The status stage will have been completed immediately + * before this function gets called.) + * + * @param aTestSelector The specific test mode selector. + * + * @return KErrNone if the specified test mode was entered successfully; + * otherwise one of the system-wide error codes. + */ + virtual TInt EnterTestMode(TUsbTestModeSelector aTestSelector) = 0; + }; + + + /** + * This static class provides the interface which PSL implementation shall + * use to register itself to PIL layer. + */ + NONSHARABLE_CLASS(UsbPeripheralPil) + { + public: + /** + * Registration function to be used by a stand-alone (non-OTG + * port) Peripheral Controller PSL to register itself to the + * PIL layer. Peripheral Controllers that are part of an + * OTG-port are registered by the OTG Controller PSL (see + * usb_otg_shai.h, function UsbOtgPil::RegisterOtgController). + * + * The intended usage is that each stand-alone Peripheral + * Controller PSL is a kernel extension that registers itself + * to the USB Peripheral PIL layer by making this call from + * their own kernel extension entry point function (or an + * equivalent code that runs during bootup). + * + * When the PSL makes this call, PIL layer will call + * SetPilCallbackInterface() function of the supplied Peripheral + * Controller interface to supply the PSL a reference to PIL + * callback interface to be used for reporting peripheral events. + * + * @param aPeripheralControllerIf Reference to the Peripheral + * Controller interface implemented by the registering PSL. + * + * @param aProperties Reference to an object describing the + * static properties of the Peripheral Controller. PIL + * layer requires that the supplied reference remains valid + * indefinitely, as a Peripheral Controller cannot unregister. + * + * @lib usbperipheralpil.lib + */ + IMPORT_C static void RegisterPeripheralController(MPeripheralControllerIf& aPeripheralControllerIf, + const TPeripheralControllerProperties& aProperties ); + + private: + /** + * No instance of this class need to be created + */ + UsbPeripheralPil(); + }; + }; + +#include + +#endif // USB_PERIPHERAL_SHAI_H + +// End of File diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_peripheral_shai.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_peripheral_shai.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,36 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +#ifndef USB_PERIPHERAL_SHAI_INL +#define USB_PERIPHERAL_SHAI_INL + +// +// inline constructor for TPeripheralControllerProperties. +// The responsibility of this constructor is to reset all +// data member of TPeripheralControllerProperties to zero. +// +inline UsbShai::TPeripheralControllerProperties::TPeripheralControllerProperties(): + iControllerCaps(0), + iDfcQueue(NULL), + iDeviceEndpointCaps(NULL), + iDeviceTotalEndpoints(0), + iMaxEp0Size(0), + iDeviceRelease(0) + { + } + +#endif diff -r 59aa7d6e3e0f -r 089413cdde3c usb_plat/usb_shai_api/inc/usb_peripheral_shai_shared.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usb_plat/usb_shai_api/inc/usb_peripheral_shai_shared.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,200 @@ +/* +* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "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: +* +*/ + +/** @file + + @brief USB Peripheral SHAI header shared part. + + Some Non-kernel USB code will also use structure defined in this + header. Since usb_peripheral_shai.h always need to include + which is not visible to non-kernel layers, a + separated header is needed. + + This header is the one that defined all common structures used by + kernel & non-kernel layers software. + + Peripheral SHAI header always include this header automatically. + + @publishedDeviceAbstraction +*/ + +#ifndef USB_PERIPHERAL_SHAI_SHARED_H +#define USB_PERIPHERAL_SHAI_SHARED_H + +// The namespace is documented in file usb_common_shai.h, so it is not +// repeated here +namespace UsbShai + { + /** + * Bitmaps for TUsbPeripheralEndpointCaps.iSupportedTypesAndDir. + * Endpoint supports Control transfer type. + */ + const TUint KUsbEpTypeControl = 0x00000001; + const TUint KUsbEpTypeIsochronous = 0x00000002; + const TUint KUsbEpTypeBulk = 0x00000004; + const TUint KUsbEpTypeInterrupt = 0x00000008; + + /** Endpoint supports IN transfers. */ + const TUint KUsbEpDirIn = 0x80000000; + /** Endpoint supports OUT transfers. */ + const TUint KUsbEpDirOut = 0x40000000; + /** Endpoint supports bidirectional (Control) transfers only.*/ + const TUint KUsbEpDirBidirect = 0x20000000; + + /** + * Indicates that whether DMA is preferred to be applied for this endpoint. + * + * Upper application will declare whether DMA is expected to be used for + * this endpoint if there is one available (PSL knows about it) when setup + * an interface. + * + * PSL can ignore this request if NO DMA is available. + * + * PIL may query whether a DMA is really applied via interface + * MPeripheralControllerIf::QueryEndpointResource() later. + * + * @see TUsbPeripheralEndpointInfo::iFeatureWord1. + */ + const TUint KUsbEndpointInfoFeatureWord1_DMA = 0x00000001; + + /** + * Indicates that whether double buffering is preferred to be applied for + * this endpoint. + * + * Upper application will declare whether double buffering is expected to + * be used for this endpoint if there is one available (PSL knows about it) + * when setup an interface. + * + * PSL can ignore this request if NO double buffering is possible. + * + * PIL may query whether a double buffering is really applied via interface + * MPeripheralControllerIf::QueryEndpointResource() later. + * + * @see TUsbPeripheralEndpointInfo::iFeatureWord1. + */ + const TUint KUsbEndpointInfoFeatureWord1_DoubleBuffering = 0x00000002; + + /** + * These are states that are described in the USB standard. + */ + enum TUsbPeripheralState + { + EUsbPeripheralStateUndefined, // 0 + EUsbPeripheralStateAttached, // 1 + EUsbPeripheralStatePowered, // 2 + EUsbPeripheralStateDefault, // 3 + EUsbPeripheralStateAddress, // 4 + EUsbPeripheralStateConfigured, // 5 + EUsbPeripheralStateSuspended, // 6 + EUsbPeripheralNoState = 0xff // 255 (used as a place holder) + }; + + /** + * Endpoint capabilities as reported by the PSL driver. + */ + class TUsbPeripheralEndpointCaps + { + public: + /** The supported maximum packet sizes. */ + TUint iSizes; + + /** + * The supported endpoint types and directions. + * see the bitmap definition for type and dir inside this header. + */ + TUint iTypesAndDir; + + /** set it to ETrue if it is a 'high-speed, high bandwidth' endpoint. */ + TBool iHighBandwidth; + + /** + * Reserved for future use. + * PSL must set those reserved ram to zero to keep binary compatibility + * with new (in furture) PIL binary which may utilize some of the + * reserved space. + */ + TUint32 iReserved[2]; + }; + + /** + * The desired endpoint capabilities. + * @see MPeripheralControllerIf::ConfigureEndpoint. + */ + class TUsbPeripheralEndpointInfo + { + public: + /** + * Endpoint type. + *(mask: UsbShai::KUsbEpTypeControl, etc., but used as value). + */ + TUint iType; + + /** Direction (mask: UsbShai::KUsbEpDirIn, etc., but used as value). */ + TUint iDir; + + /** Maximum packet size (literal, no mask). */ + TInt iSize; + + /** + * Interval for polling full-speed interrupt and isochronous endpoints. + * Expressed either directly in milliseconds with a valid range 1..255 + * (interrupt), or for use as 'value' in the expression of + * interval=2^(value-1) with a valid range 1..16 (isochronous). + */ + TInt iInterval; + + /** + * Interval for polling high-speed interrupt and isochronous endpoints, + * or to specify the NAK rate for high-speed control and bulk OUT + * endpoints. Expressed either for use as 'value' in the expression + * interval=2^(value-1) with a valid range 1..16 (interrupt and + * isochronous), or directly as the maximum NAK rate with a valid range + * 0..255 (control and bulk). + */ + TInt iInterval_Hs; + + /** + * The number of additional transactions per frame to be scheduled(0..2) + * (A value greater than zero is only valid for high-speed high bandwidth + * interrupt and isochronous endpoints. Also note that there are endpoint + * size restrictions associated with additional transactions - see 9.6.6.). + */ + TInt iTransactions; + + /** + * The number of extra bytes that the standard endpoint descriptor + * should be extended by. In almost all cases, this should be 0 (zero). + */ + TInt iExtra; + + /** + * 32 flag bits indicating miscellaneous endpoint features. + * Currently defined are: + * - KUsbEndpointInfoFeatureWord1_DMA which means apply DMA to this + * endpoint if available. + * - KUsbEndpointInfoFeatureWord1_DoubleBuffering which means apply + * double buffering to this endpoint if available. + */ + TUint32 iFeatureWord1; + + /** Reserved for future use. */ + TUint32 iReserved; + }; + } +#endif //USB_PERIPHERAL_SHAI_SHARED_H + +// End of files diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perildd/group/base_e32_drivers_usbcli.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perildd/group/base_e32_drivers_usbcli.mrp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,17 @@ +# component name "USB Client Driver" + +component base_e32_drivers_usbcli + + +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbc +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbcc +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbcsc + +binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbc all +exports \sf\os\kernelhwsrv\kernel\eka\drivers\usbc + +notes_source \component_defs\release.src + + +ipr E + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perildd/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perildd/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,39 @@ +// 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: +// bld.inf +// USB Client Driver +// +// + +/** + @file +*/ +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_MMPFILES + +#if defined(GENERIC_MARM) || defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +usbc +#endif +#endif + + +#endif +#endif diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perildd/group/usbc.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perildd/group/usbc.mmp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,35 @@ +// Copyright (c) 1998-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/usbc/usbc.mmp +// +// + + +#include + +OS_LAYER_SYSTEMINCLUDE + + + +target usbcshai.ldd +targettype ldd + +sourcepath ../src +source d_usbc.cpp usbdma.cpp + +library usbperipheralpil.lib + +uid 0 0x101F8928 +VENDORID 0x70000001 +capability all diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perildd/src/d_usbc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perildd/src/d_usbc.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,3233 @@ +// Copyright (c) 2000-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/usbc/d_usbc.cpp +// LDD for USB Device driver stack: +// The channel object. +// +// + +/** + @file d_usbc.cpp + @internalTechnology +*/ + +#include + + +_LIT(KUsbLddName, "Usbc"); + +static const TInt KUsbRequestCallbackPriority = 2; + + +// Quick sanity check on endpoint properties +static TBool ValidateEndpoint(const TUsbcEndpointInfo* aEndpointInfo) + { + const TUint dir = aEndpointInfo->iDir; + const TInt size = aEndpointInfo->iSize; + if (size <= 0) + return EFalse; + + switch (aEndpointInfo->iType) + { + case UsbShai::KUsbEpTypeControl: + if (dir != UsbShai::KUsbEpDirBidirect || size > 64) + return EFalse; + break; + case UsbShai::KUsbEpTypeIsochronous: + if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 1024) + return EFalse; + break; + case UsbShai::KUsbEpTypeBulk: + if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 512) + return EFalse; + break; + case UsbShai::KUsbEpTypeInterrupt: + if ((dir != UsbShai::KUsbEpDirIn && dir != UsbShai::KUsbEpDirOut) || size > 1024) + return EFalse; + break; + default: + return EFalse; + } + return ETrue; + } + + +/** Real entry point from the Kernel: return a new driver. + */ +DECLARE_STANDARD_LDD() + { + return new DUsbcLogDevice; + } + + +/** Create a channel on the device. + + @internalComponent +*/ +TInt DUsbcLogDevice::Create(DLogicalChannelBase*& aChannel) + { + aChannel = new DLddUsbcChannel; + return aChannel ? KErrNone : KErrNoMemory; + } + + +DUsbcLogDevice::DUsbcLogDevice() + { + iParseMask = KDeviceAllowUnit; + iUnitsMask = 0xffffffff; // Leave units decision to the Controller + iVersion = TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion); + } + + +TInt DUsbcLogDevice::Install() + { + // Only proceed if we have the Controller underneath us + if (!DUsbClientController::UsbcControllerPointer()) + { + __KTRACE_OPT(KPANIC, Kern::Printf("LDD Install: USB Controller Not Present")); + return KErrGeneral; + } + return SetName(&KUsbLddName); + } + + +// +// Return the USB controller capabilities. +// +void DUsbcLogDevice::GetCaps(TDes8& aDes) const + { + TPckgBuf b; + b().version = iVersion; + Kern::InfoCopy(aDes, b); + } + + +// +// Constructor +// +DLddUsbcChannel::DLddUsbcChannel() + : iValidInterface(EFalse), + iAlternateSettingList(NULL), + iCompleteAllCallbackInfo(this, DLddUsbcChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority), + iStatusChangePtr(NULL), + iStatusCallbackInfo(this, DLddUsbcChannel::StatusChangeCallback, KUsbRequestCallbackPriority), + iEndpointStatusChangePtr(NULL), + iEndpointStatusCallbackInfo(this, DLddUsbcChannel::EndpointStatusChangeCallback, + KUsbRequestCallbackPriority), + iOtgFeatureChangePtr(NULL), + iOtgFeatureCallbackInfo(this, DLddUsbcChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority), + iNumberOfEndpoints(0), + iDeviceState(UsbShai::EUsbPeripheralStateUndefined), + iOwnsDeviceControl(EFalse), + iAlternateSetting(0), + iDeviceStatusNeeded(EFalse), + iChannelClosing(EFalse) + { + __KTRACE_OPT(KUSB, Kern::Printf("*** DLddUsbcChannel::DLddUsbcChannel CTOR")); + iClient = &Kern::CurrentThread(); + iClient->Open(); + for (TInt i = 1; i <= KMaxEndpointsPerClient; i++) + { + iEndpoint[i] = NULL; + } + for (TInt i = 1; i < KUsbcMaxRequests; i++) + { + iRequestStatus[i] = NULL; + } + } + + +DLddUsbcChannel::~DLddUsbcChannel() + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::~DLddUsbcChannel()")); + if (iController) + { + iController->DeRegisterClient(this); + iStatusCallbackInfo.Cancel(); + iEndpointStatusCallbackInfo.Cancel(); + iOtgFeatureCallbackInfo.Cancel(); + iCompleteAllCallbackInfo.Cancel(); + AbortInterface(); + DestroyAllInterfaces(); + if (iOwnsDeviceControl) + { + iController->ReleaseDeviceControl(this); + iOwnsDeviceControl = EFalse; + } + DestroyEp0(); + delete iStatusFifo; + Kern::DestroyClientRequest(iStatusChangeReq); + Kern::DestroyClientRequest(iEndpointStatusChangeReq); + Kern::DestroyClientRequest(iOtgFeatureChangeReq); + + Kern::DestroyVirtualPinObject(iPinObj1); + Kern::DestroyVirtualPinObject(iPinObj2); + Kern::DestroyVirtualPinObject(iPinObj3); + + for (TInt i = 0; i < KUsbcMaxRequests; i++) + { + Kern::DestroyClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest); + delete iClientAsynchNotify[i]; + } + } + Kern::SafeClose((DObject*&)iClient, NULL); + } + + +inline TBool DLddUsbcChannel::ValidEndpoint(TInt aEndpoint) + { + return (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0); + } + + +// +// Create channel +// +TInt DLddUsbcChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) + { + __KTRACE_OPT(KUSB, Kern::Printf("LDD DoCreateL 1 Ver = %02d %02d %02d", + aVer.iMajor, aVer.iMinor, aVer.iBuild)); + if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD, + __PLATSEC_DIAGNOSTIC_STRING("Checked by USBC.LDD (USB Driver)"))) + { + return KErrPermissionDenied; + } + + iController = DUsbClientController::UsbcControllerPointer(); + + if (!iController) + { + return KErrGeneral; + } + + iStatusFifo = new TUsbcDeviceStatusQueue; + if (iStatusFifo == NULL) + { + return KErrNoMemory; + } + + if (!Kern::QueryVersionSupported(TVersion(KUsbcMajorVersion, KUsbcMinorVersion, KUsbcBuildVersion), aVer)) + { + return KErrNotSupported; + } + + // set up the correct DFC queue + SetDfcQ(iController->DfcQ(0)); // sets the channel's dfc queue + #ifdef DFC_REALTIME_STATE + iDfcQ.SetRealtimeState(ERealtimeStateOn); + #endif + iCompleteAllCallbackInfo.SetDfcQ(iDfcQ); + iStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc + iEndpointStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc + iOtgFeatureCallbackInfo.SetDfcQ(iDfcQ); + iMsgQ.Receive(); //start up the message q + TInt r = iController->RegisterClientCallback(iCompleteAllCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForStatusChange(iStatusCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForEndpointStatusChange(iEndpointStatusCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForOtgFeatureChange(iOtgFeatureCallbackInfo); + if (r != KErrNone) + return r; + + r = Kern::CreateClientDataRequest(iStatusChangeReq); + if (r != KErrNone) + return r; + r = Kern::CreateClientDataRequest(iEndpointStatusChangeReq); + if (r != KErrNone) + return r; + r = Kern::CreateClientDataRequest(iOtgFeatureChangeReq); + if (r != KErrNone) + return r; + + Kern::CreateVirtualPinObject(iPinObj1); + Kern::CreateVirtualPinObject(iPinObj2); + Kern::CreateVirtualPinObject(iPinObj3); + + for (TInt i = 0; i < KUsbcMaxRequests; i++) + { + iClientAsynchNotify[i] = new TClientAsynchNotify; + if(iClientAsynchNotify[i] == NULL) + return KErrNoMemory; + r = Kern::CreateClientBufferRequest(iClientAsynchNotify[i]->iBufferRequest,1,TClientBufferRequest::EPinVirtual); + if (r != KErrNone) + { + delete iClientAsynchNotify[i]; + iClientAsynchNotify[i]=NULL; + return r; + } + } + + return r; + } + + + +void DLddUsbcChannel::CompleteBufferRequest(DThread* aThread, TInt aReqNo, TInt aReason) +{ + iRequestStatus[aReqNo]=NULL; + Kern::QueueBufferRequestComplete(aThread, iClientAsynchNotify[aReqNo]->iBufferRequest, aReason); +} + + +TClientBuffer * DLddUsbcChannel::GetClientBuffer(TInt aEndpoint) +{ + return iClientAsynchNotify[aEndpoint]->iClientBuffer; +} + +//Runs in client thread +TInt DLddUsbcChannel::SendMsg(TMessageBase * aMsg) +{ + TThreadMessage& m=* (TThreadMessage*)aMsg; + TInt id = m.iValue; + + TInt r = KErrNone; + //Cancel Request + if (id == KMaxTInt) + { + r = DLogicalChannel::SendMsg(aMsg); + return r; + } + if (id < 0) + { + // DoRequest + TRequestStatus* pS = (TRequestStatus*) m.Ptr0(); + r = PreSendRequest(aMsg,~id, pS, m.Ptr1(), m.Ptr2()); + if (r == KErrNone) + { + r = DLogicalChannel::SendMsg(aMsg); + } + } + else + { + //SendControl + r = SendControl(aMsg); + } + return r; +} + + +TInt DLddUsbcChannel::PreSendRequest(TMessageBase * aMsg,TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) +{ + TInt r = KErrNone; + if (aReqNo >= KUsbcMaxRequests) + { + Kern::RequestComplete(aStatus, KErrNotSupported); + return KErrNotSupported; + } + if (aReqNo > KUsbcMaxEpNumber)//DoOtherAsyncReq + { + switch (aReqNo) + { + case RDevUsbcClient::ERequestEndpointStatusNotify: + iEndpointStatusChangeReq->Reset(); + iEndpointStatusChangeReq->SetStatus(aStatus); + iEndpointStatusChangeReq->SetDestPtr(a1); + break; + case RDevUsbcClient::ERequestOtgFeaturesNotify: + iOtgFeatureChangeReq->Reset(); + iOtgFeatureChangeReq->SetStatus(aStatus); + iOtgFeatureChangeReq->SetDestPtr(a1); + break; + case RDevUsbcClient::ERequestAlternateDeviceStatusNotify: + iStatusChangeReq->Reset(); + iStatusChangeReq->SetStatus(aStatus); + iStatusChangeReq->SetDestPtr(a1); + break; + case RDevUsbcClient::ERequestReEnumerate://WE use bufferrequest to complete even tho we dont add any buffers + iClientAsynchNotify[aReqNo]->Reset(); + r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus); + if (r != KErrNone) + return r; + iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup(); + break; + } + } + else //DoTransferAsyncReq + { + if(a1 == NULL) + return KErrArgument; + iClientAsynchNotify[aReqNo]->Reset(); + r=iClientAsynchNotify[aReqNo]->iBufferRequest->StartSetup(aStatus); + if (r != KErrNone) + return r; + kumemget(&iTfrInfo,a1,sizeof(TEndpointTransferInfo)); + r=iClientAsynchNotify[aReqNo]->iBufferRequest->AddBuffer(iClientAsynchNotify[aReqNo]->iClientBuffer, iTfrInfo.iDes); + if (r != KErrNone) + return r; + iClientAsynchNotify[aReqNo]->iBufferRequest->EndSetup(); + TThreadMessage& m=*(TThreadMessage*)aMsg; + m.iArg[1] = (TAny*)&iTfrInfo; //Use Channel owned TransfereInfo structure + } + return KErrNone; +} + + +void DLddUsbcChannel::HandleMsg(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + if (id == (TInt) ECloseMsg) + { + iChannelClosing = ETrue; + m.Complete(KErrNone, EFalse); + return; + } + else if (id == KMaxTInt) + { + // Cancel request + TInt mask = m.Int0(); + TInt b = 1; + for(TInt reqNo = 0; reqNo < KUsbcMaxRequests; reqNo++) + { + TRequestStatus* pS = iRequestStatus[reqNo]; + if ((mask & b) && (pS != NULL)) + { + DoCancel(reqNo); + } + b <<= 1; + } + m.Complete(KErrNone, ETrue); + return; + } + + if (id < 0) + { + // DoRequest + TRequestStatus* pS = (TRequestStatus*) m.Ptr0(); + DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); + m.Complete(KErrNone, ETrue); + } + else + { + // DoControl + TInt r = DoControl(id, m.Ptr0(), m.Ptr1()); + m.Complete(r, ETrue); + } + } + + +// +// Overriding DObject virtual +// +TInt DLddUsbcChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::RequestUserHandle")); + // The USB client LDD is not designed for a channel to be shared between + // threads. It saves a pointer to the current thread when it is opened, and + // uses this to complete any asynchronous requests. + // It is therefore not acceptable for the handle to be duplicated and used + // by another thread: + if (aThread == iClient) + { + return KErrNone; + } + else + { + return KErrAccessDenied; + } + } + + +// +// Asynchronous requests - overriding pure virtual +// +void DLddUsbcChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) + { + // Check on request status + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo)); + TInt r = KErrNone; + if (iRequestStatus[aReqNo] != NULL) + { + DestroyAllInterfaces(); + PanicClientThread(ERequestAlreadyPending); + } + else + { + TBool needsCompletion; + iRequestStatus[aReqNo] = aStatus; + + if (aReqNo > KUsbcMaxEpNumber) + { + r = DoOtherAsyncReq(aReqNo, a1, a2, needsCompletion); + if (needsCompletion) + { + switch (aReqNo) + { + case RDevUsbcClient::ERequestEndpointStatusNotify: + iRequestStatus[aReqNo]=NULL; + Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,r); + break; + case RDevUsbcClient::ERequestOtgFeaturesNotify: + iRequestStatus[aReqNo]=NULL; + Kern::QueueRequestComplete(iClient,iOtgFeatureChangeReq,r); + break; + case RDevUsbcClient::ERequestAlternateDeviceStatusNotify: + iRequestStatus[aReqNo]=NULL; + Kern::QueueRequestComplete(iClient,iStatusChangeReq,r); + break; + case RDevUsbcClient::ERequestReEnumerate: + iRequestStatus[aReqNo]=NULL; + Kern::QueueBufferRequestComplete(iClient, iClientAsynchNotify[aReqNo]->iBufferRequest, r); + break; + } + } + } + else + { + r = DoTransferAsyncReq(aReqNo, a1, a2, needsCompletion); + if (needsCompletion) + { + //Kern::RequestComplete(iClient, iRequestStatus[aReqNo], r); + CompleteBufferRequest(iClient, aReqNo, r); + } + } + } + } + + + +TInt DLddUsbcChannel::DoOtherAsyncReq(TInt aReqNo, TAny* a1, TAny* a2, TBool& aNeedsCompletion) + { + // The general assumption is that none of these will complete now. + // However, those that make this function return something other than + // KErrNone will get completed by the calling function. + // So, 1) If you are returning KErrNone but really need to complete because + // completion criteria can be met (for example, sufficient data is + // available in the buffer) and then set aNeedsCompletion = ETrue. + // 2) Do NOT complete here AT ALL. + // + aNeedsCompletion = EFalse; + TInt r = KErrNone; + + switch (aReqNo) + { + case RDevUsbcClient::ERequestAlternateDeviceStatusNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("EControlReqDeviceStatusNotify")); + if (a1 != NULL) + { + iDeviceStatusNeeded = ETrue; + iStatusChangePtr = a1; + aNeedsCompletion = AlternateDeviceStateTestComplete(); + } + else + r = KErrArgument; + break; + } + case RDevUsbcClient::ERequestReEnumerate: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate")); + // If successful, this will complete via the status notification. + r = iController->ReEnumerate(); + break; + } + case RDevUsbcClient::ERequestEndpointStatusNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify")); + if (a1 != NULL) + { + iEndpointStatusChangePtr = a1; + } + else + r = KErrArgument; + break; + } + case RDevUsbcClient::ERequestOtgFeaturesNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify")); + if (a1 != NULL) + { + iOtgFeatureChangePtr = a1; + } + else + r = KErrArgument; + break; + } + default: + r = KErrNotSupported; + } + + aNeedsCompletion = aNeedsCompletion || (r != KErrNone); + + return r; + } + + +TInt DLddUsbcChannel::DoTransferAsyncReq(TInt aEndpointNum, TAny* a1, TAny* a2, TBool& aNeedsCompletion) + { + // The general assumption is that none of these will complete now. + // however, those that are returning something other than KErrNone will get completed + // by the calling function. + // So, 1) if you are returning KErrNone but really need to complete because completion criteria can be met + // (for example, sufficient data is available in the buffer) and then set aNeedsCompletion=ETrue.. + // 2) Do NOT complete here AT ALL. + // + aNeedsCompletion = EFalse; + TInt r = KErrNone; + TUsbcEndpoint* pEndpoint = NULL; + TUsbcEndpointInfo* pEndpointInfo = NULL; + TEndpointTransferInfo* pTfr = NULL; + + if (aEndpointNum == 0) + { + // ep0 requests + if (!(iValidInterface || iOwnsDeviceControl)) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected: not configured (Ep0)")); + r = KErrUsbInterfaceNotReady; + goto exit; + } + } + else + { + // other eps + if (!(iValidInterface && (iDeviceState == UsbShai::EUsbPeripheralStateConfigured || + iDeviceState == UsbShai::EUsbPeripheralStateSuspended)) + ) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest rejected not configured (Ep %d)", aEndpointNum)); + r = KErrUsbInterfaceNotReady; + goto exit; + } + } + + if (!ValidEndpoint(aEndpointNum)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete")); + r = KErrUsbEpNotInInterface; + goto exit; + } + + if (a1 == NULL) + { + r = KErrArgument; + goto exit; + } + pTfr = (TEndpointTransferInfo *)a1; + + if (pTfr->iTransferSize < 0) + { + r = KErrArgument; + goto exit; + } + pEndpoint = iEndpoint[aEndpointNum]; + if (!pEndpoint) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete")); + r = KErrUsbEpNotInInterface; + goto exit; + } + + pEndpointInfo = pEndpoint->EndpointInfo(); + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest %d", aEndpointNum)); + + switch (pTfr->iTransferType) + { + + case ETransferTypeReadData: + case ETransferTypeReadPacket: + case ETransferTypeReadUntilShort: + case ETransferTypeReadOneOrMore: + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read")); + if (pEndpoint->iDmaBuffers->RxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxActive", aEndpointNum)); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("**** ReadReq ep%d RxInActive", aEndpointNum)); + } + + if (pEndpointInfo->iDir != UsbShai::KUsbEpDirOut && + pEndpointInfo->iDir != UsbShai::KUsbEpDirBidirect) + { + // Trying to do the wrong thing + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Read: in error complete")); + r = KErrUsbEpBadDirection; + break; + } + // Set the length of data to zero now to catch all cases + TPtrC8 pZeroDesc(NULL, 0); + r=Kern::ThreadBufWrite(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer, pZeroDesc, 0, 0,iClient); + if (r != KErrNone) + PanicClientThread(r); + pEndpoint->SetTransferInfo(pTfr); + if (pEndpoint->iDmaBuffers->IsReaderEmpty()) + { + pEndpoint->SetClientReadPending(ETrue); + } + else + { + if (pTfr->iTransferType == ETransferTypeReadPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read packet: data available complete")); + r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer); + aNeedsCompletion = ETrue; + break; + } + else if (pTfr->iTransferType == ETransferTypeReadData) + { + if (pTfr->iTransferSize <= pEndpoint->RxBytesAvailable()) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete")); + r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer); + aNeedsCompletion = ETrue; + break; + } + else + { + pEndpoint->SetClientReadPending(ETrue); + } + } + else if (pTfr->iTransferType == ETransferTypeReadOneOrMore) + { + if (pEndpoint->RxBytesAvailable() > 0) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete")); + r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer); + aNeedsCompletion = ETrue; + break; + } + else + { + pEndpoint->SetClientReadPending(ETrue); + } + } + else if (pTfr->iTransferType == ETransferTypeReadUntilShort) + { + TInt nRx = pEndpoint->RxBytesAvailable(); + TInt maxPacketSize = pEndpoint->EndpointInfo()->iSize; + if( (pTfr->iTransferSize <= nRx) || + (nRx < maxPacketSize) || + pEndpoint->iDmaBuffers->ShortPacketExists()) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read data: data available complete")); + r = pEndpoint->CopyToClient(iClient,iClientAsynchNotify[aEndpointNum]->iClientBuffer); + aNeedsCompletion = ETrue; + } + else + { + pEndpoint->SetClientReadPending(ETrue); + } + } + } + r = pEndpoint->TryToStartRead(EFalse); + if (r != KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Read: couldn't start read")); + r = KErrNone; // Reader full isn't a userside error; + } + break; + } + + case ETransferTypeWrite: + { + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 1")); + if (pEndpointInfo->iDir != UsbShai::KUsbEpDirIn && + pEndpointInfo->iDir != UsbShai::KUsbEpDirBidirect) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: wrong direction complete")); + r = KErrUsbEpBadDirection; + break; + } + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 2")); + + + TInt desLength=iClientAsynchNotify[aEndpointNum]->iClientBuffer->Length(); + + if (desLength < pTfr->iTransferSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: user buffer too short")); + r = KErrUsbTransferSize; + break; + } + + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest Write 3 length=%d maxlength=%d", + pTfr->iTransferSize, desLength)); + // Zero length writes are acceptable + pEndpoint->SetClientWritePending(ETrue); + r = pEndpoint->TryToStartWrite(pTfr); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoRequest Write: couldn't start write")); + pEndpoint->SetClientWritePending(EFalse); + } + break; + } + + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DoTransferAsyncReq: pTfr->iTransferType = %d not supported", + pTfr->iTransferType)); + r = KErrNotSupported; + break; + } + exit: + aNeedsCompletion = aNeedsCompletion || (r != KErrNone); + return r; + } + + +// +// Cancel an outstanding request - overriding pure virtual +// +TInt DLddUsbcChannel::DoCancel(TInt aReqNo) + { + TInt r = KErrNone; + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x", aReqNo)); + if (aReqNo <= iNumberOfEndpoints) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel endpoint: 0x%x", aReqNo)); + iEndpoint[aReqNo]->CancelTransfer(iClient,iClientAsynchNotify[aReqNo]->iClientBuffer); + } + else if (aReqNo == RDevUsbcClient::ERequestAlternateDeviceStatusNotify) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo)); + iDeviceStatusNeeded = EFalse; + iStatusFifo->FlushQueue(); + if (iStatusChangePtr) + { + iStatusChangeReq->Data()=iController->GetDeviceStatus(); + iStatusChangePtr = NULL; + + if (iStatusChangeReq->IsReady()) + { + iRequestStatus[aReqNo] = NULL; + Kern::QueueRequestComplete(iClient, iStatusChangeReq, KErrCancel); + } + return KErrNone; + } + } + else if (aReqNo == RDevUsbcClient::ERequestReEnumerate) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo)); + } + else if (aReqNo == RDevUsbcClient::ERequestEndpointStatusNotify) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo)); + CancelNotifyEndpointStatus(); + if (iEndpointStatusChangeReq->IsReady()) + { + iRequestStatus[aReqNo] = NULL; + Kern::QueueRequestComplete(iClient, iEndpointStatusChangeReq, KErrCancel); + } + return KErrNone; + } + else if (aReqNo == RDevUsbcClient::ERequestOtgFeaturesNotify) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo)); + CancelNotifyOtgFeatures(); + if (iOtgFeatureChangeReq->IsReady()) + { + iRequestStatus[aReqNo] = NULL; + Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq, KErrCancel); + } + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo)); + } + + if (r == KErrNone) + r = KErrCancel; + + CompleteBufferRequest(iClient, aReqNo, r); + return r; + } + + +void DLddUsbcChannel::CancelNotifyEndpointStatus() + { + if (iEndpointStatusChangePtr) + { + TUint epBitmap = 0; + for (TInt i = 0; i <= iNumberOfEndpoints; i++) + { + TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber()); + TUint b; + (v == EEndpointStateStalled) ? b = 1 : b = 0; + epBitmap |= b << i; + } + iEndpointStatusChangeReq->Data()=epBitmap; + iEndpointStatusChangePtr = NULL; + } + } + + +void DLddUsbcChannel::CancelNotifyOtgFeatures() + { + if (iOtgFeatureChangePtr) + { + TUint8 features; + iController->GetCurrentOtgFeatures(features); + iOtgFeatureChangeReq->Data()=features; + iOtgFeatureChangePtr = NULL; + } + } + +TInt DLddUsbcChannel::PinMemory(TDesC8 *aDes, TVirtualPinObject *aPinObj) + { + TInt r = KErrNone; + TInt len,mlen; + + const TUint8*p = Kern::KUDesInfo(*aDes, len,mlen); + r=Kern::PinVirtualMemory(aPinObj, (TLinAddr) p, len); + return r; + } + +//Called in Client thread context +TInt DLddUsbcChannel::SendControl(TMessageBase* aMsg) + { + TThreadMessage& m=*(TThreadMessage*)aMsg; + const TInt fn=m.iValue; + TAny *const a1=m.Ptr0(); + TAny *const a2=m.Ptr1(); + TInt kern_param; + TEndpointDescriptorInfo epi; + TUsbcIfcInfo ifc; + TCSDescriptorInfo desInfo; + TInt r = KErrNone; + + switch (fn) + { + + case RDevUsbcClient::EControlDeviceStatus: + case RDevUsbcClient::EControlGetAlternateSetting: + m.iArg[0] = &kern_param; // update message to point to kernel-side buffer + break; + + case RDevUsbcClient::EControlQueryReceiveBuffer: + case RDevUsbcClient::EControlEndpointStatus: + m.iArg[1] = &kern_param; // update message to point to kernel-side buffer + break; + + case RDevUsbcClient::EControlEndpointCaps: + case RDevUsbcClient::EControlDeviceCaps: + case RDevUsbcClient::EControlGetDeviceDescriptor: + case RDevUsbcClient::EControlSetDeviceDescriptor: + case RDevUsbcClient::EControlGetDeviceDescriptorSize: + case RDevUsbcClient::EControlGetConfigurationDescriptor: + case RDevUsbcClient::EControlGetConfigurationDescriptorSize: + case RDevUsbcClient::EControlGetDeviceQualifierDescriptor: + case RDevUsbcClient::EControlSetDeviceQualifierDescriptor: + case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor: + case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor: + case RDevUsbcClient::EControlGetStringDescriptorLangId: + case RDevUsbcClient::EControlGetManufacturerStringDescriptor: + case RDevUsbcClient::EControlSetManufacturerStringDescriptor: + case RDevUsbcClient::EControlGetProductStringDescriptor: + case RDevUsbcClient::EControlSetProductStringDescriptor: + case RDevUsbcClient::EControlGetSerialNumberStringDescriptor: + case RDevUsbcClient::EControlSetSerialNumberStringDescriptor: + case RDevUsbcClient::EControlGetConfigurationStringDescriptor: + case RDevUsbcClient::EControlSetConfigurationStringDescriptor: + case RDevUsbcClient::EControlSetOtgDescriptor: + case RDevUsbcClient::EControlGetOtgDescriptor: + case RDevUsbcClient::EControlGetOtgFeatures: + r=PinMemory((TDesC8 *) a1, iPinObj1); + if(r!=KErrNone) + { + PanicClientThread(r); + return r; + } + break; + + case RDevUsbcClient::EControlGetInterfaceDescriptor: + case RDevUsbcClient::EControlGetInterfaceDescriptorSize: + case RDevUsbcClient::EControlSetInterfaceDescriptor: + case RDevUsbcClient::EControlGetCSInterfaceDescriptor: + case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize: + case RDevUsbcClient::EControlGetStringDescriptor: + case RDevUsbcClient::EControlSetStringDescriptor: + r=PinMemory((TDesC8 *) a2, iPinObj1); + if(r!=KErrNone) + { + PanicClientThread(r); + return r; + } + break; + + case RDevUsbcClient::EControlGetEndpointDescriptor: + case RDevUsbcClient::EControlGetEndpointDescriptorSize: + case RDevUsbcClient::EControlSetEndpointDescriptor: + case RDevUsbcClient::EControlGetCSEndpointDescriptor: + case RDevUsbcClient::EControlGetCSEndpointDescriptorSize: + if(a1!=NULL) + { + r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(epi)); + if(r!=KErrNone) + { + PanicClientThread(r); + return r; + } + kumemget(&epi, a1, sizeof(epi)); + r=PinMemory((TDesC8 *) epi.iArg, iPinObj2); + if(r!=KErrNone) + { + Kern::UnpinVirtualMemory(iPinObj1); + PanicClientThread(r); + return r; + } + } + break; + + case RDevUsbcClient::EControlSetInterface: + if(a2!=NULL) + { + r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a2, sizeof(ifc)); + if(r!=KErrNone) + { + PanicClientThread(r); + return r; + } + kumemget(&ifc, a2, sizeof(ifc)); + r=PinMemory((TDesC8 *) ifc.iInterfaceData, iPinObj2); + if(r!=KErrNone) + { + Kern::UnpinVirtualMemory(iPinObj1); + PanicClientThread(r); + return r; + } + } + break; + + case RDevUsbcClient::EControlSetCSInterfaceDescriptor: + case RDevUsbcClient::EControlSetCSEndpointDescriptor: + if(a1!=NULL) + { + r=Kern::PinVirtualMemory(iPinObj1, (TLinAddr)a1, sizeof(desInfo)); + if(r!=KErrNone) + { + PanicClientThread(r); + return r; + } + kumemget(&desInfo, a1, sizeof(desInfo)); + r=PinMemory((TDesC8 *) desInfo.iArg, iPinObj2); + if(r!=KErrNone) + { + Kern::UnpinVirtualMemory(iPinObj1); + PanicClientThread(r); + return r; + } + } + break; + } + + + //Send Message and wait for synchronous complete + r = DLogicalChannel::SendMsg(aMsg); + + + + switch (fn) + { + case RDevUsbcClient::EControlDeviceStatus: + case RDevUsbcClient::EControlGetAlternateSetting: + umemput32(a1, &kern_param, sizeof(kern_param)); + break; + + case RDevUsbcClient::EControlQueryReceiveBuffer: + case RDevUsbcClient::EControlEndpointStatus: + umemput32(a2, &kern_param, sizeof(kern_param)); + break; + + case RDevUsbcClient::EControlDeviceCaps: + case RDevUsbcClient::EControlEndpointCaps: + case RDevUsbcClient::EControlGetDeviceDescriptor: + case RDevUsbcClient::EControlSetDeviceDescriptor: + case RDevUsbcClient::EControlGetDeviceDescriptorSize: + case RDevUsbcClient::EControlGetConfigurationDescriptor: + case RDevUsbcClient::EControlGetConfigurationDescriptorSize: + case RDevUsbcClient::EControlGetDeviceQualifierDescriptor: + case RDevUsbcClient::EControlSetDeviceQualifierDescriptor: + case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor: + case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor: + case RDevUsbcClient::EControlGetStringDescriptorLangId: + case RDevUsbcClient::EControlGetManufacturerStringDescriptor: + case RDevUsbcClient::EControlSetManufacturerStringDescriptor: + case RDevUsbcClient::EControlGetProductStringDescriptor: + case RDevUsbcClient::EControlSetProductStringDescriptor: + case RDevUsbcClient::EControlGetSerialNumberStringDescriptor: + case RDevUsbcClient::EControlSetSerialNumberStringDescriptor: + case RDevUsbcClient::EControlGetConfigurationStringDescriptor: + case RDevUsbcClient::EControlSetConfigurationStringDescriptor: + case RDevUsbcClient::EControlSetOtgDescriptor: + case RDevUsbcClient::EControlGetOtgDescriptor: + case RDevUsbcClient::EControlGetOtgFeatures: + if(a1!=NULL) + { + Kern::UnpinVirtualMemory(iPinObj1); + } + break; + + case RDevUsbcClient::EControlGetInterfaceDescriptor: + case RDevUsbcClient::EControlGetInterfaceDescriptorSize: + case RDevUsbcClient::EControlSetInterfaceDescriptor: + case RDevUsbcClient::EControlGetCSInterfaceDescriptor: + case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize: + case RDevUsbcClient::EControlGetStringDescriptor: + case RDevUsbcClient::EControlSetStringDescriptor: + if(a2!=NULL) + { + Kern::UnpinVirtualMemory(iPinObj1); + } + break; + + case RDevUsbcClient::EControlGetEndpointDescriptor: + case RDevUsbcClient::EControlGetEndpointDescriptorSize: + case RDevUsbcClient::EControlSetEndpointDescriptor: + case RDevUsbcClient::EControlGetCSEndpointDescriptor: + case RDevUsbcClient::EControlGetCSEndpointDescriptorSize: + case RDevUsbcClient::EControlSetCSInterfaceDescriptor: + case RDevUsbcClient::EControlSetCSEndpointDescriptor: + if(a1!=NULL) + { + Kern::UnpinVirtualMemory(iPinObj1); + Kern::UnpinVirtualMemory(iPinObj2); + } + break; + + case RDevUsbcClient::EControlSetInterface: + if(a2!=NULL) + { + Kern::UnpinVirtualMemory(iPinObj1); + Kern::UnpinVirtualMemory(iPinObj2); + } + break; + } + + return r; + } + + +TInt DLddUsbcChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction)); + + TInt r = KErrNone; + TInt ep; + TUsbcEndpoint* pEndpoint; + TPtrC8 pZeroDesc(NULL, 0); + TEndpointDescriptorInfo epInfo; + TUsbcIfcInfo ifcInfo; + TCSDescriptorInfo desInfo; + TUsbcEndpointResource epRes; + TInt bandwidthPriority; + + switch (aFunction) + { + case RDevUsbcClient::EControlEndpointZeroRequestError: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError")); + r = KErrNone; + if (iOwnsDeviceControl || (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured)) + { + iController->Ep0Stall(this); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlGetAlternateSetting: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting")); + if (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + { + r = iController->GetInterfaceNumber(this, *(TInt*)a1); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlDeviceStatus: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus")); + *(TInt*)a1 = iController->GetDeviceStatus(); + break; + + case RDevUsbcClient::EControlEndpointStatus: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + pEndpoint = iEndpoint[(TInt)a1]; + if (pEndpoint == NULL) + r = KErrNotSupported; + else + { + *(TInt*)a2 = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber()); + } + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlQueryReceiveBuffer: + __KTRACE_OPT(KUSB, Kern::Printf("EControlQueryReceiveBuffer")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + pEndpoint=iEndpoint[(TInt) a1]; + if (pEndpoint == NULL) + r = KErrNotSupported; + else if (pEndpoint->EndpointInfo()->iDir != UsbShai::KUsbEpDirIn) + { + __KTRACE_OPT(KUSB, Kern::Printf(" bytes = %d", pEndpoint->RxBytesAvailable())); + *(TInt*)a2 = pEndpoint->RxBytesAvailable(); + } + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlEndpointCaps: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointCaps")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + iController->EndpointCaps(this, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlDeviceCaps: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceCaps")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + iController->DeviceCaps(this, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlSendEp0StatusPacket: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket")); + iController->SendEp0StatusPacket(this); + break; + + case RDevUsbcClient::EControlHaltEndpoint: + __KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlClearHaltEndpoint: + __KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcClient::EControlDumpRegisters: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters")); + iController->DumpRegisters(); + break; + + case RDevUsbcClient::EControlReleaseDeviceControl: + __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl")); + iController->ReleaseDeviceControl(this); + iOwnsDeviceControl = EFalse; + break; + + case RDevUsbcClient::EControlEndpointZeroMaxPacketSizes: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes")); + r = iController->EndpointZeroMaxPacketSizes(); + break; + + case RDevUsbcClient::EControlSetEndpointZeroMaxPacketSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize")); + r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast(a1)); + break; + + case RDevUsbcClient::EControlGetEndpointZeroMaxPacketSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize")); + r = iController->Ep0PacketSize(); + break; + + case RDevUsbcClient::EControlGetDeviceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetDeviceDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlSetDeviceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor")); + if (a1 != NULL) + r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1)); + else + r = KErrArgument; + break; + + case RDevUsbcClient::EControlGetDeviceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize")); + if (a1 != NULL) + r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1)); + else + r = KErrArgument; + break; + + case RDevUsbcClient::EControlGetConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlGetConfigurationDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize")); + if (a1 != NULL) + { + r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1)); + } + else + r = KErrArgument; + break; + + case RDevUsbcClient::EControlSetConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor")); + r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlGetInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor")); + r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcClient::EControlGetInterfaceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize")); + r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2); + break; + + case RDevUsbcClient::EControlSetInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor")); + r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcClient::EControlGetEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcClient::EControlGetEndpointDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptorSize")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetEndpointDescriptorSize(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcClient::EControlSetEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->SetEndpointDescriptor(iClient, this, epInfo.iSetting, + ep, *(TDes8*)epInfo.iArg); + break; + + case RDevUsbcClient::EControlGetDeviceQualifierDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceQualifierDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlSetDeviceQualifierDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor")); + if (a1 != NULL) + r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); + else + r = KErrArgument; + break; + + case RDevUsbcClient::EControlGetOtherSpeedConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtherSpeedConfigurationDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlSetOtherSpeedConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor")); + r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + + case RDevUsbcClient::EControlGetCSInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor")); + r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcClient::EControlGetCSInterfaceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize")); + r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2); + break; + + case RDevUsbcClient::EControlGetCSEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetCSEndpointDescriptorBlock(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcClient::EControlGetCSEndpointDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptorSize")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetCSEndpointDescriptorBlockSize(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcClient::EControlSignalRemoteWakeup: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup")); + r = iController->SignalRemoteWakeup(); + break; + + case RDevUsbcClient::EControlDeviceDisconnectFromHost: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost")); + r = iController->UsbDisconnect(); + break; + + case RDevUsbcClient::EControlDeviceConnectToHost: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost")); + r = iController->UsbConnect(); + break; + + case RDevUsbcClient::EControlDevicePowerUpUdc: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc")); + r = iController->PowerUpUdc(); + break; + + case RDevUsbcClient::EControlSetDeviceControl: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl")); + r = iController->SetDeviceControl(this); + if (r == KErrNone) + { + iOwnsDeviceControl = ETrue; + if (iEndpoint[0] == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl 11")); + r = SetupEp0(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed")); + iController->ReleaseDeviceControl(this); + DestroyEp0(); + iOwnsDeviceControl = EFalse; + } + iEndpoint[0]->TryToStartRead(EFalse); + } + } + else + r = KErrInUse; + break; + + case RDevUsbcClient::EControlCurrentlyUsingHighSpeed: + __KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed")); + r = iController->CurrentlyUsingHighSpeed(); + break; + + case RDevUsbcClient::EControlSetInterface: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface")); + r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo)); + if (r != KErrNone) + PanicClientThread(r); + if (iValidInterface && (iDeviceState == UsbShai::EUsbPeripheralStateConfigured)) + { + r = KErrGeneral; + } + else + { + bandwidthPriority = ifcInfo.iBandwidthPriority; + if ((bandwidthPriority & 0xffffff00) || + ((bandwidthPriority & 0x0f) >= KUsbcDmaBufMaxPriorities) || + (((bandwidthPriority >> 4) & 0x0f) >= KUsbcDmaBufMaxPriorities)) + { + r = KErrArgument; + } + else + { + r = SetInterface((TInt) a1, &ifcInfo); + } + } + + break; + + case RDevUsbcClient::EControlReleaseInterface: + __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface")); + r = iController->ReleaseInterface(this, (TInt) a1); + if (r == KErrNone) + { + DestroyInterface((TUint) a1); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error in PIL: LDD interface won't be released.")); + } + break; + + case RDevUsbcClient::EControlSetCSInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSInterfaceDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); + if (r != KErrNone) + PanicClientThread(r); + r = iController->SetCSInterfaceDescriptorBlock(iClient, this, desInfo.iSetting, + *reinterpret_cast(desInfo.iArg), + desInfo.iSize); + break; + + case RDevUsbcClient::EControlSetCSEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(desInfo.iSetting, desInfo.iEndpoint); + r = iController->SetCSEndpointDescriptorBlock(iClient, this, desInfo.iSetting, ep, + *reinterpret_cast(desInfo.iArg), + desInfo.iSize); + break; + + case RDevUsbcClient::EControlGetStringDescriptorLangId: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId")); + r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcClient::EControlSetStringDescriptorLangId: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId")); + r = iController->SetStringDescriptorLangId(reinterpret_cast(a1)); + break; + + case RDevUsbcClient::EControlGetManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor")); + r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlSetManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor")); + r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlRemoveManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor")); + r = iController->RemoveManufacturerStringDescriptor(); + break; + + case RDevUsbcClient::EControlGetProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor")); + r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlSetProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor")); + r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlRemoveProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor")); + r = iController->RemoveProductStringDescriptor(); + break; + + case RDevUsbcClient::EControlGetSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor")); + r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlSetSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor")); + r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlRemoveSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor")); + r = iController->RemoveSerialNumberStringDescriptor(); + break; + + case RDevUsbcClient::EControlGetConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor")); + r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlSetConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor")); + r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcClient::EControlRemoveConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor")); + r = iController->RemoveConfigurationStringDescriptor(); + break; + + case RDevUsbcClient::EControlGetStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor")); + r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); + break; + + case RDevUsbcClient::EControlSetStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor")); + r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); + break; + + case RDevUsbcClient::EControlRemoveStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor")); + r = iController->RemoveStringDescriptor((TUint8) (TInt) a1); + break; + + case RDevUsbcClient::EControlQueryEndpointResourceUse: + epRes = (TUsbcEndpointResource)((TInt) a2); + if (!ValidEndpoint((TInt)a1)) + { + r = KErrUsbEpNotInInterface; + } + else + { + r = iController->QueryEndpointResource(this, iEndpoint[(TInt)a1]->RealEpNumber(), epRes); + } + break; + + case RDevUsbcClient::EControlSetOtgDescriptor: + { + r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1)); + } + break; + + case RDevUsbcClient::EControlGetOtgDescriptor: + { + r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1)); + } + break; + + case RDevUsbcClient::EControlGetOtgFeatures: + { + r = iController->GetOtgFeatures(iClient, *((TDes8*)a1)); + } + break; + + default: + __KTRACE_OPT(KUSB, Kern::Printf("Function code not supported")); + r = KErrNotSupported; + } + + return r; + } + + +TInt DLddUsbcChannel::SetInterface(TInt aInterfaceNumber, TUsbcIfcInfo* aInfoBuf) + { + TUsbcInterfaceInfoBuf ifc_info_buf; + TUsbcInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData; + const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr); + if (srcLen < ifc_info_buf.Length()) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface can't copy")); + PanicClientThread(EDesOverflow); + } + + TInt r = Kern::ThreadDesRead(iClient, ifc_info_buf_ptr, ifc_info_buf, 0, KChunkShiftBy0); + if (r != KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Copy failed reason=%d", r)); + PanicClientThread(r); + } + + TUsbcEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData; + + // If an alternate interface is being asked for then do nothing, + // just pass it down to the Controller. + const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed; + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints)); + + // [The next 4 variables have to be initialized here because of the goto's that follow.] + // Both IN and OUT buffers will be fully cached: + const TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax; + const TUint32 bandwidthPriority = aInfoBuf->iBandwidthPriority; + + // Supports ep0+5 endpoints + TInt real_ep_numbers[6] = {-1, -1, -1, -1, -1, -1}; + + // See if PIL will accept this interface + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller")); + r = iController->SetInterface(this, + iClient, + aInterfaceNumber, + ifc_info_buf().iClass, + aInfoBuf->iString, + ifc_info_buf().iTotalEndpointsUsed, + ifc_info_buf().iEndpointData, + &real_ep_numbers, + ifc_info_buf().iFeatureWord); + + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface controller returned %d", r)); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface failed reason=%d", r)); + return r; + } + + // [The next variable has to be initialized here because of the goto's that follow.] + TUsbcAlternateSettingList* alternateSettingListRec; + + // ep0 + if (iEndpoint[0] == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface 11")); + r = SetupEp0(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed")); + DestroyEp0(); + goto F1; + } + } + + alternateSettingListRec = new TUsbcAlternateSettingList; + if (!alternateSettingListRec) + { + r = KErrNoMemory; + goto F1; + } + + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::SetInterface num_endpoints=%d", num_endpoints)); + + // other endpoints + // calculate the total buffer size + for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i)); + if (!ValidateEndpoint(pEndpointData)) + { + r = KErrUsbBadEndpoint; + goto F2; + } + + TUsbcEndpoint* ep = new TUsbcEndpoint(this, iController, pEndpointData, i, bandwidthPriority); + alternateSettingListRec->iEndpoint[i] = ep; + if (!ep) + { + r = KErrNoMemory; + goto F2; + } + if (ep->Construct() != KErrNone) + { + r = KErrNoMemory; + goto F2; + } + + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x", + i, alternateSettingListRec, ep)); + } + + // buf size of each endpoint + TInt bufSizes[KMaxEndpointsPerClient + 1]; + TInt epNum[KMaxEndpointsPerClient + 1]; + + // init + for( TInt i=0;iiEndpoint[i]->BufferSize(); + } + + __KTRACE_OPT(KUSB, Kern::Printf("Sort the endpoints:")); + + // sort the endpoint number by the bufsize decreasely + for( TInt i=1;iiEpNumDeOrderedByBufSize[i] = epNum[i]; + + __KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[i], bufSizes[i])); + } + alternateSettingListRec->iEpNumDeOrderedByBufSize[num_endpoints] = epNum[num_endpoints]; + __KTRACE_OPT(KUSB, Kern::Printf(" %d:%d", epNum[num_endpoints], bufSizes[num_endpoints])); + __KTRACE_OPT(KUSB, Kern::Printf("\n")); + + // chain in this alternate setting + alternateSettingListRec->iNext = iAlternateSettingList; + iAlternateSettingList = alternateSettingListRec; + alternateSettingListRec->iSetting = aInterfaceNumber; + alternateSettingListRec->iNumberOfEndpoints = num_endpoints; + + // Record the 'real' endpoint number used by the PDD in both the Ep and + // the Req callback: + for (TInt i = 1; i <= num_endpoints; i++) + { + alternateSettingListRec->iEndpoint[i]->SetRealEpNumber(real_ep_numbers[i]); + } + + r = SetupInterfaceMemory(iHwChunks, cacheAttribs ); + if( r==KErrNone ) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface ready to exit")); + + if (aInterfaceNumber == 0) + { + // make sure we're ready to go with the main interface + iValidInterface = ETrue; + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface SelectAlternateSetting")); + SelectAlternateSetting(0); + } + return KErrNone; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("Destroying all interfaces")); + DestroyAllInterfaces(); + DestroyEp0(); + return r; + } + + F2: + delete alternateSettingListRec; + //Fall through + + F1: +#if _DEBUG + TInt r1 = iController->ReleaseInterface(this, aInterfaceNumber); + __KTRACE_OPT(KUSB, Kern::Printf("Release Interface controller returned %d", r1)); +#else + (void) iController->ReleaseInterface(this, aInterfaceNumber); +#endif + return r; + } + +// realloc the memory, and set the previous interfaces +TInt DLddUsbcChannel::SetupInterfaceMemory(RArray &aHwChunks, + TUint32 aCacheAttribs ) + { + TUsbcAlternateSettingList* asRec = iAlternateSettingList; + + // if buffers has been changed + TBool chunkChanged = EFalse; + TInt numOfEp = asRec->iNumberOfEndpoints; + + // 1, collect all bufs' sizes for the current interface + // to realloc all the chunks + __KTRACE_OPT(KUSB, Kern::Printf("Collect all buffer sizes:")); + RArray bufSizes; + for(TInt i=1;i<=numOfEp;i++) + { + TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i]; + TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber(); + __KTRACE_OPT(KUSB, Kern::Printf(" ep %d, buf count %d", nextEp, epBufCount )); + for(TInt k=0;kiEndpoint[nextEp]->BufferSize(); + TInt r = bufSizes.Append(epBufSize); + if(r!=KErrNone) + { + iController->DeRegisterClient(this); + bufSizes.Close(); + return r; + } + __KTRACE_OPT(KUSB,Kern::Printf(" %d", epBufSize )); + } + __KTRACE_OPT(KUSB, Kern::Printf("\n")); + + } + + // 2, alloc the buffer decreasely, biggest-->smallest + // 2.1 check the existing chunks + TInt bufCount = bufSizes.Count(); + __KTRACE_OPT(KUSB, Kern::Printf(" ep buf number needed %d", bufCount )); + __KTRACE_OPT(KUSB, Kern::Printf(" chunks available %d", aHwChunks.Count() )); + + TInt chunkInd = 0; + while( (chunkInd(aHwChunks[chunkInd]->LinearAddress()); + + DPlatChunkHw* chunk = ReAllocate(bufSizes[chunkInd], aHwChunks[chunkInd], aCacheAttribs); + if (chunk == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunks size %d!", bufSizes[chunkInd])); + // lost all interfaces: + // Tell Controller to release Interface and h/w resources associated with this + iController->DeRegisterClient(this); + bufSizes.Close(); + return KErrNoMemory; + } + else + { + // Parcel out the memory between endpoints + TUint8* newAddr = reinterpret_cast(chunk->LinearAddress()); + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d", newAddr,bufSizes[chunkInd])); + // The check is important to avoid chunkChanged to be corrupted. + // This code change is to fix the problem that one chunk is used by multiple interfaces. + if(!chunkChanged) + { + chunkChanged = (newAddr != oldAddr); + } + aHwChunks[chunkInd] = chunk; + } + chunkInd++; + } + + // 2.2 in case available chunks are not enough + while( chunkIndDeRegisterClient(this); + bufSizes.Close(); + return KErrNoMemory; + } + else + { + // Parcel out the memory between endpoints + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d", + reinterpret_cast(chunk->LinearAddress()), bufSizes[chunkInd])); + TInt r = aHwChunks.Append(chunk); + if(r!=KErrNone) + { + ClosePhysicalChunk(chunk); + iController->DeRegisterClient(this); + bufSizes.Close(); + return r; + } + } + chunkInd++; + } + + // 3, Set the the bufs of the interfaces + + ReSetInterfaceMemory(asRec, aHwChunks); + + if(chunkChanged) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing.")); + asRec = asRec->iNext; + while (asRec) + { + // Interfaces are not concurrent so they can all start at the same logical address + __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory readdressing setting=%d", asRec->iSetting)); + ReSetInterfaceMemory(asRec, aHwChunks); + asRec = asRec->iNext; + } + } + return KErrNone; + } + +TInt DLddUsbcChannel::SetupEp0() + { + __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 entry %x", this)); + TInt ep0Size = iController->Ep0PacketSize(); + TUsbcEndpointInfo ep0Info = TUsbcEndpointInfo(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirBidirect, ep0Size); + TUsbcEndpoint* ep0 = new TUsbcEndpoint(this, iController, &ep0Info, 0, 0); + if (ep0 == NULL) + { + return KErrNoMemory; + } + // In case we have to return early: + iEndpoint[0] = ep0; + TInt r = ep0->Construct(); + if (r != KErrNone) + { + return KErrNoMemory; + } + + TInt bufferNum = ep0->BufferNumber(); + TInt bufferSize = ep0->BufferSize(); + TUint32 cacheAttribs = EMapAttrSupRw | EMapAttrCachedMax; + + for(TInt i=0;iLinearAddress(); + ep0->SetBufferAddr( i, buf); + __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer number %d", i)); + __KTRACE_OPT(KUSB, Kern::Printf("SetupEp0 60 buffer size %d", bufferSize)); + } + + ep0->SetRealEpNumber(0); + return KErrNone; + } + +// Set buffer address of the interface +// Precondition: Enough chunks available. +void DLddUsbcChannel::ReSetInterfaceMemory(TUsbcAlternateSettingList* aAlternateSettingListRec, + RArray &aHwChunks) + { + TUsbcAlternateSettingList* asRec = aAlternateSettingListRec; + + // set all the interfaces + TInt chunkInd = 0; + TInt numOfEp = asRec->iNumberOfEndpoints; + + for (TInt i = 1; i <= numOfEp; i++) + { + TInt nextEp = asRec->iEpNumDeOrderedByBufSize[i]; + TInt epBufCount = asRec->iEndpoint[nextEp]->BufferNumber(); + for(TInt k=0;kiEndpoint[nextEp]; + if (ep != NULL ) + { + TUint8* pBuf = NULL; + pBuf = reinterpret_cast(aHwChunks[chunkInd]->LinearAddress()); + ep->SetBufferAddr( k, pBuf); + __KTRACE_OPT(KUSB, Kern::Printf(" ep %d, buf %d, addr 0x%x", nextEp, k, pBuf )); + chunkInd++; + __ASSERT_DEBUG(chunkInd<=aHwChunks.Count(), + Kern::Printf(" Error: available chunks %d, run out at epInd%d, bufInd%d", + aHwChunks.Count(), i, k)); + __ASSERT_DEBUG(chunkInd<=aHwChunks.Count(), + Kern::Fault("usbc.ldd", __LINE__)); + } + } + } + + } + +void DLddUsbcChannel::DestroyAllInterfaces() + { + // Removes all interfaces + TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList; + while (alternateSettingListRec) + { + iController->ReleaseInterface(this, alternateSettingListRec->iSetting); + TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext; + delete alternateSettingListRec; + alternateSettingListRec = alternateSettingListRecNext; + } + iNumberOfEndpoints = 0; + iAlternateSettingList = NULL; + + for(TInt i=0;iiNext; + if (alternateSettingListRec->iSetting == aInterfaceNumber) + { + // This record is to be deleted + if (alternateSettingListRecOld == NULL) + { + // The record to be deleted is at the list head + iAlternateSettingList = alternateSettingListRecNext; + } + else + { + // The record to be deleted is NOT at the list head + alternateSettingListRecOld->iNext = alternateSettingListRecNext; + } + delete alternateSettingListRec; + break; + } + alternateSettingListRecOld = alternateSettingListRec; + alternateSettingListRec = alternateSettingListRecNext; + } + + if (iAlternateSettingList == NULL) + { + // if no interfaces left destroy non-ep0 buffering + for(TInt i=0;iiChannelClosing) + return; + TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State(); + const TInt reqNo = (TInt) RDevUsbcClient::ERequestEndpointStatusNotify; + if (dUsbc->iRequestStatus[reqNo]) + { + __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status")); + DThread* client = dUsbc->iClient; + + dUsbc->iEndpointStatusChangeReq->Data() = endpointState; + dUsbc->iRequestStatus[reqNo] = NULL; + Kern::QueueRequestComplete(client,dUsbc->iEndpointStatusChangeReq,KErrNone); + dUsbc->iEndpointStatusChangePtr = NULL; + } + } + + +void DLddUsbcChannel::StatusChangeCallback(TAny* aDLddUsbcChannel) + { + DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel; + if (dUsbc->iChannelClosing) + return; + + TUsbcDeviceState deviceState; + TInt i; + for (i = 0; + (i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != UsbShai::EUsbPeripheralNoState); + ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState)); + if (deviceState & KUsbAlternateSetting) + { + dUsbc->ProcessAlternateSetting(deviceState); + } + else + { + dUsbc->ProcessDeviceState(deviceState); + } + // Only queue if userside is interested + if (dUsbc->iDeviceStatusNeeded) + { + dUsbc->iStatusFifo->AddStatusToQueue(deviceState); + const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify; + if (dUsbc->AlternateDeviceStateTestComplete()) + { + dUsbc->iRequestStatus[reqNo]=NULL; + Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iStatusChangeReq,KErrNone); + } + } + } + // We don't want to be interrupted in the middle of this: + const TInt irqs = NKern::DisableInterrupts(2); + dUsbc->iStatusCallbackInfo.ResetState(); + NKern::RestoreInterrupts(irqs); + } + + +void DLddUsbcChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcChannel) + { + __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback")); + DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel; + if (dUsbc->iChannelClosing) + return; + + TUint8 features; + // No return value check. Assume OTG always supported here + dUsbc->iController->GetCurrentOtgFeatures(features); + + const TInt reqNo = (TInt) RDevUsbcClient::ERequestOtgFeaturesNotify; + if (dUsbc->iRequestStatus[reqNo]) + { + __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status")); + dUsbc->iOtgFeatureChangeReq->Data()=features; + dUsbc->iRequestStatus[reqNo] = NULL; + Kern::QueueRequestComplete(dUsbc->iClient,dUsbc->iOtgFeatureChangeReq,KErrNone); + dUsbc->iOtgFeatureChangePtr = NULL; + } + } + + +TInt DLddUsbcChannel::SelectAlternateSetting(TUint aAlternateSetting) + { + TInt r = KErrGeneral; // error code doesn't go userside + TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList; + while (alternateSettingListRec) + { + if (alternateSettingListRec->iSetting == aAlternateSetting) + { + // found the correct interface, now latch in new endpoint set + for (TInt i = 1; i <= KMaxEndpointsPerClient; i++) + { + iEndpoint[i] = NULL; + } + iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints; + r = KErrNone; + for (TInt i = 1; i <= KMaxEndpointsPerClient; i++) + { + iEndpoint[i] = alternateSettingListRec->iEndpoint[i]; + } + // Only after correct alternate setting has been chosen. + UpdateEndpointSizes(); + } + alternateSettingListRec = alternateSettingListRec->iNext; + } + return r; + } + + +TInt DLddUsbcChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint) + { + TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList; + while (alternateSettingListRec) + { + if (alternateSettingListRec->iSetting == aAlternateSetting) + { + if ((aEndpoint <= alternateSettingListRec->iNumberOfEndpoints) && + (aEndpoint >= 0)) + { + return alternateSettingListRec->iEndpoint[aEndpoint]->RealEpNumber(); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aEndpoint %d wrong for aAlternateSetting %d", + aEndpoint, aAlternateSetting)); + return -1; + } + } + alternateSettingListRec = alternateSettingListRec->iNext; + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no aAlternateSetting %d found", aAlternateSetting)); + return -1; + } + + +TInt DLddUsbcChannel::ProcessAlternateSetting(TUint aAlternateSetting) + { + ResetInterface(KErrUsbInterfaceChange); // kill any outstanding transfers + __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x", aAlternateSetting)); + TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting); + __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting selecting alternate setting 0x%08x", newSetting)); + TInt r = SelectAlternateSetting(newSetting); + if (r != KErrNone) + return r; + StartEpReads(); + iAlternateSetting = newSetting; + return KErrNone; + } + + +TInt DLddUsbcChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf("ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState)); + if (iDeviceState == aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No state change => nothing to be done.")); + return KErrNone; + } + if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Coming out of Suspend: old state = %d", iOldDeviceState)); + iDeviceState = iOldDeviceState; + if (iDeviceState == aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf(" New state same as before Suspend => nothing to be done.")); + return KErrNone; + } + } + TBool renumerateState = (aDeviceState == UsbShai::EUsbPeripheralStateConfigured); + TBool deconfigured = EFalse; + TInt cancellationCode = KErrNone; + if (aDeviceState == UsbShai::EUsbPeripheralStateSuspended) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Suspending...")); + iOldDeviceState = iDeviceState; + // Put PSL into low power mode here + } + else + { + deconfigured = (iDeviceState == UsbShai::EUsbPeripheralStateConfigured && + aDeviceState != UsbShai::EUsbPeripheralStateConfigured); + if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + { + if (aDeviceState == UsbShai::EUsbPeripheralStateUndefined) + cancellationCode = KErrUsbCableDetached; + else if (aDeviceState == UsbShai::EUsbPeripheralStateAddress) + cancellationCode = KErrUsbDeviceNotConfigured; + else if (aDeviceState == UsbShai::EUsbPeripheralStateDefault) + cancellationCode = KErrUsbDeviceBusReset; + else + cancellationCode = KErrUsbDeviceNotConfigured; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" %d --> %d", iDeviceState, aDeviceState)); + iDeviceState = aDeviceState; + if (iValidInterface || iOwnsDeviceControl) + { + // This LDD may not own an interface. It could be some manager reenumerating + // after its subordinate LDDs have setup their interfaces. + if (deconfigured) + { + DeConfigure(cancellationCode); + } + else if (renumerateState) + { + // Update size of Ep0. + iEndpoint[0]->SetMaxPacketSize(iController->Ep0PacketSize()); + // First cancel transfers on all endpoints + ResetInterface(KErrUsbInterfaceChange); + // Select main interface & latch in new endpoint set + SelectAlternateSetting(0); + // Here we go + StartEpReads(); + } + } + + const TInt reqNo = (TInt) RDevUsbcClient::ERequestReEnumerate; + if (renumerateState && iRequestStatus[reqNo]) + { + // This lot must be done if we are reenumerated + CompleteBufferRequest(iClient, reqNo, KErrNone); + } + + return KErrNone; + } + + +void DLddUsbcChannel::UpdateEndpointSizes() + { + // The regular ones. + TInt i = 0; + while ((++i <= KMaxEndpointsPerClient) && iEndpoint[i]) + { + const TInt size = iController->EndpointPacketSize(this, iEndpoint[i]->RealEpNumber()); + if (size < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Packet size < 0 for ep %d", i)); + continue; + } + iEndpoint[i]->SetMaxPacketSize(size); + } + __ASSERT_DEBUG(i == iNumberOfEndpoints + 1, + Kern::Printf(" Error: iNumberOfEndpoints wrong (%d)", iNumberOfEndpoints)); + } + + +DPlatChunkHw* DLddUsbcChannel::ReAllocate(TInt aBuffersize, DPlatChunkHw* aHwChunk, TUint32 aCacheAttribs) + { + DPlatChunkHw* chunk = aHwChunk; + if ((!chunk) || (chunk->iSize < aBuffersize)) + { + if (chunk) + { + ClosePhysicalChunk(chunk); + } + __KTRACE_OPT(KUSB, Kern::Printf("ReAllocate need to get new chunk")); + chunk = Allocate(aBuffersize, aCacheAttribs); + } + return chunk; + } + + +DPlatChunkHw* DLddUsbcChannel::Allocate(TInt aBuffersize, TUint32 aCacheAttribs) + { + TUint32 physAddr = 0; + TUint32 size = Kern::RoundToPageSize(aBuffersize); + + if (Epoc::AllocPhysicalRam(size, physAddr) != KErrNone) + return NULL; + + DPlatChunkHw* HwChunk; + if (DPlatChunkHw::New(HwChunk, physAddr, aBuffersize, aCacheAttribs) != KErrNone) + { + Epoc::FreePhysicalRam(physAddr, size); + return NULL; + } + + return HwChunk; + } + + +TInt DLddUsbcChannel::DoRxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TBool aReEntrant) + { + TBool completeNow; + TInt err = aTUsbcEndpoint->CopyToClient(iClient, completeNow,iClientAsynchNotify[aEndpoint]->iClientBuffer); + if (completeNow) + { + aTUsbcEndpoint->SetClientReadPending(EFalse); + CompleteBufferRequest(iClient, aEndpoint, err); + } + aTUsbcEndpoint->TryToStartRead(aReEntrant); + return err; + } + + +void DLddUsbcChannel::DoRxCompleteNow(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint) + { + aTUsbcEndpoint->SetClientReadPending(EFalse); + CompleteBufferRequest(iClient, aEndpoint, KErrCancel); + } + + +void DLddUsbcChannel::DoTxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TInt aError) + { + aTUsbcEndpoint->SetClientWritePending(EFalse); + CompleteBufferRequest(iClient, aEndpoint, aError); + } + + +TBool DLddUsbcChannel::AlternateDeviceStateTestComplete() + { + TBool completeNow = EFalse; + const TInt reqNo = (TInt) RDevUsbcClient::ERequestAlternateDeviceStatusNotify; + if (iRequestStatus[reqNo]) + { + // User req is outstanding + TUint32 deviceState; + if (iStatusFifo->GetDeviceQueuedStatus(deviceState) == KErrNone) + { + // Device state waiting to be sent userside + completeNow = ETrue; + __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallback Notify status")); + iStatusChangeReq->Data()=deviceState; + iStatusChangePtr = NULL; + } + } + return completeNow; + } + + +void DLddUsbcChannel::EmergencyCompleteDfc(TAny* aDLddUsbcChannel) + { + ((DLddUsbcChannel*) aDLddUsbcChannel)->DoEmergencyComplete(); + } + + +void DLddUsbcChannel::DeConfigure(TInt aErrorCode) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcChannel::DeConfigure()")); + // Called after deconfiguration. Cancels transfers on all endpoints. + ResetInterface(aErrorCode); + // Cancel the endpoint status notify request if it is outstanding. + const TInt KEpNotReq = RDevUsbcClient::ERequestEndpointStatusNotify; + if (iRequestStatus[KEpNotReq]) + { + CancelNotifyEndpointStatus(); + iRequestStatus[KEpNotReq]=NULL; + Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,aErrorCode); + } + // We have to reset the alternate setting number when the config goes away. + SelectAlternateSetting(0); + iAlternateSetting = 0; + } + + +void DLddUsbcChannel::StartEpReads() + { + // Queued after enumeration. Starts reads on all endpoints. + // The endpoint itself decides if it can do a read + TInt i; + for (i = 0; i <= iNumberOfEndpoints; i++) + { + // The endpoint itself will decide if it can read + iEndpoint[i]->TryToStartRead(EFalse); + } + } + + +void DLddUsbcChannel::ResetInterface(TInt aErrorCode) + { + // Called after change in alternate setting. Cancels transfers on all endpoints + if (iValidInterface || iOwnsDeviceControl) + { + // Reset each endpoint except ep0 + for (TInt i = 1; i <= iNumberOfEndpoints; i++) + { + __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i)); + iEndpoint[i]->CancelTransfer(iClient,iClientAsynchNotify[i]->iClientBuffer); // Copies data userside + iEndpoint[i]->AbortTransfer(); // kills any ldd->pil outstanding transfers + iEndpoint[i]->iDmaBuffers->Flush(); + if (iRequestStatus[i] != NULL) + CompleteBufferRequest(iClient, i, aErrorCode); + iEndpoint[i]->SetClientWritePending(EFalse); + iEndpoint[i]->SetClientReadPending(EFalse); + } + } + } + + +void DLddUsbcChannel::AbortInterface() + { + // Called after when channel is closing + if (iValidInterface || iOwnsDeviceControl) + { + for (TInt i = 0; i <= iNumberOfEndpoints; i++) + { + if (iEndpoint[i]) + { + // kills any LDD->PDD outstanding transfers + iEndpoint[i]->AbortTransfer(); + } + } + } + } + + +void DLddUsbcChannel::ClosePhysicalChunk(DPlatChunkHw*& aHwChunk) + { + if (aHwChunk) + { + const TPhysAddr addr = aHwChunk->PhysicalAddress(); + const TInt size = aHwChunk->iSize; + aHwChunk->Close(NULL); + Epoc::FreePhysicalRam(addr, size); + } + aHwChunk = NULL; + } + + +TInt DLddUsbcChannel::DoEmergencyComplete() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::DoEmergencyComplete")); + // cancel any pending DFCs + // complete all client requests + for (TInt i = 0; i < KUsbcMaxRequests; i++) + { + if (iRequestStatus[i]) + { + __KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i])); + + if (i == RDevUsbcClient::ERequestAlternateDeviceStatusNotify) + { + + iDeviceStatusNeeded = EFalse; + iStatusFifo->FlushQueue(); + + if (iStatusChangePtr) + { + iStatusChangeReq->Data() = iController->GetDeviceStatus(); + iStatusChangePtr = NULL; + + if (iStatusChangeReq->IsReady()) + { + iRequestStatus[i] = NULL; + Kern::QueueRequestComplete(iClient, iStatusChangeReq, + KErrDisconnected); + } + } + + } + else if (i == RDevUsbcClient::ERequestEndpointStatusNotify) + { + + if (iEndpointStatusChangePtr) + { + TUint epBitmap = 0; + for (TInt i = 0; i <= iNumberOfEndpoints; i++) + { + TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber()); + TUint b; + (v == EEndpointStateStalled) ? b = 1 : b = 0; + epBitmap |= b << i; + } + + iEndpointStatusChangeReq->Data() = epBitmap; + iEndpointStatusChangePtr = NULL; + } + + if (iEndpointStatusChangeReq->IsReady()) + { + iRequestStatus[i] = NULL; + Kern::QueueRequestComplete(iClient,iEndpointStatusChangeReq,KErrDisconnected); + } + + } + else if (i == RDevUsbcClient::ERequestOtgFeaturesNotify) + { + + if (iOtgFeatureChangePtr) + { + TUint8 features; + iController->GetCurrentOtgFeatures(features); + iOtgFeatureChangeReq->Data()=features; + iOtgFeatureChangePtr = NULL; + } + + if (iOtgFeatureChangeReq->IsReady()) + { + iRequestStatus[i] = NULL; + Kern::QueueRequestComplete(iClient, iOtgFeatureChangeReq, + KErrDisconnected); + } + + } + else + { + CompleteBufferRequest(iClient, i, KErrDisconnected); + } + + } + } + + iStatusCallbackInfo.Cancel(); + iEndpointStatusCallbackInfo.Cancel(); + iOtgFeatureCallbackInfo.Cancel(); + return KErrNone; + } + + +void DLddUsbcChannel::PanicClientThread(TInt aReason) + { + Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat); + } + + +// ===============Endpoint==================== + +// Constructor +TUsbcEndpoint::TUsbcEndpoint(DLddUsbcChannel* aLDD, DUsbClientController* aController, + const TUsbcEndpointInfo* aEndpointInfo, TInt aEndpointNum, + TInt aBandwidthPriority) + : iController(aController), + iEndpointInfo(aEndpointInfo->iType, aEndpointInfo->iDir, aEndpointInfo->iSize), + iClientReadPending(EFalse), + iClientWritePending(EFalse), + iEndpointNumber(aEndpointNum), + iRealEpNumber(-1), + iLdd(aLDD), + iError(KErrNone), + iRequestCallbackInfo(NULL), + iBytesTransferred(0), + iBandwidthPriority(aBandwidthPriority) + { + ResetTransferInfo(); + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::TUsbcEndpoint 2")); + } + + +TInt TUsbcEndpoint::Construct() + { + iDmaBuffers = new TDmaBuf(&iEndpointInfo, iBandwidthPriority); + if (iDmaBuffers == NULL) + { + return KErrNoMemory; + } + const TInt r = iDmaBuffers->Construct(&iEndpointInfo); + if (r != KErrNone) + { + return r; + } + iRequestCallbackInfo = new TUsbcRequestCallback(iLdd, + iEndpointNumber, + TUsbcEndpoint::RequestCallback, + this, + iLdd->iDfcQ, + KUsbRequestCallbackPriority); + if (iRequestCallbackInfo == NULL) + { + return KErrNoMemory; + } + return KErrNone; + } + + +TUsbcEndpoint::~TUsbcEndpoint() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::~TUsbcEndpoint(%d)", iEndpointNumber)); + AbortTransfer(); + delete iRequestCallbackInfo; + delete iDmaBuffers; + } + + +void TUsbcEndpoint::RequestCallback(TAny* aTUsbcEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::RequestCallback")); + ((TUsbcEndpoint*) aTUsbcEndpoint)->EndpointComplete(); + } + + +void TUsbcEndpoint::SetMaxPacketSize(TInt aSize) + { + iEndpointInfo.iSize = aSize; + iDmaBuffers->SetMaxPacketSize(aSize); + } + + +TInt TUsbcEndpoint::EndpointComplete() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete ep=%d %d", + iEndpointNumber, iRequestCallbackInfo->iEndpointNum)); + + if (iLdd->ChannelClosing()) + { + __KTRACE_OPT(KUSB, Kern::Printf("We're going home -> completions no longer accepted")); + return KErrNone; + } + + UsbShai::TTransferDirection transferDir = iRequestCallbackInfo->iTransferDir; + TInt error = iRequestCallbackInfo->iError; + + switch (transferDir) + { + + case UsbShai::EControllerWrite: + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Write 2")); + if (!iDmaBuffers->TxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf(" TX completion but !iDmaBuffers->TxIsActive()")); + break; + } + + iDmaBuffers->TxSetInActive(); + TBool completeNow = EFalse; + iBytesTransferred += iRequestCallbackInfo->iTxBytes; + if (iClientWritePending) + { + //Complete Outstanding Write if necessary + iError = error; + if (iError != KErrNone) + { + completeNow = ETrue; + if (iError == KErrPrematureEnd) // Previous write could not be completed + iError = KErrNone; + } + else + { + if (iBytesTransferred == (TUint32) iTransferInfo.iTransferSize) + { + completeNow = ETrue; + } + else + { + iError = ContinueWrite(); + if (iError != KErrNone) + completeNow = ETrue; + } + } + if (completeNow) + { + TxComplete(); + ResetTransferInfo(); + if (iEndpointNumber == 0) + { + iDmaBuffers->Flush(); + TryToStartRead(EFalse); + } + } + } + break; + } + + case UsbShai::EControllerRead: + { + // The first packet always contains the total #of bytes + const TInt byteCount = iRequestCallbackInfo->iPacketSize[0]; + const TInt packetCount = iRequestCallbackInfo->iRxPackets; + iDmaBuffers->ReadXferComplete(byteCount, packetCount, error); + + // We queue the dfc if we can complete the read, i.e. if we are reading a packet, + // or if we have enough data to satisfy a read data request. + if (iClientReadPending) + { + //Complete outstanding read + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpoint::EndpointComplete Read 3 (bytes " + "available=%d)", iDmaBuffers->RxBytesAvailable())); + TInt bytesReqd = iTransferInfo.iTransferSize - iBytesTransferred; + TBool completeNow = EFalse; + + if (iTransferInfo.iTransferType == ETransferTypeReadPacket || + iTransferInfo.iTransferType == ETransferTypeReadOneOrMore) + { + // Always complete on a packet read + completeNow = ETrue; + } + else if (iTransferInfo.iTransferType == ETransferTypeReadData) + { + // Complete only if enough data is present + if (iDmaBuffers->RxBytesAvailable() >= bytesReqd) + completeNow = ETrue; + } + else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort) + { + // Complete if enough data is present or if a short packet has been delivered + const TInt maxPacketSize = iEndpointInfo.iSize; + const TInt lastPacketSize = iRequestCallbackInfo->iPacketSize[packetCount - 1]; + if (lastPacketSize < maxPacketSize) + completeNow = ETrue; + else if (iDmaBuffers->RxBytesAvailable() >= bytesReqd) + completeNow = ETrue; + else + { + const TUint type = iEndpointInfo.iType; + if ((type == UsbShai::KUsbEpTypeBulk) && (lastPacketSize & (maxPacketSize - 1))) + { + completeNow = ETrue; + } + else if ((type != UsbShai::KUsbEpTypeBulk) && + (lastPacketSize > maxPacketSize) && + (lastPacketSize % maxPacketSize)) + { + completeNow = ETrue; + } + } + } + if (completeNow) + { + iError = error; + RxComplete(EFalse); + iClientReadPending = EFalse; + } + } + iDmaBuffers->RxSetInActive(); + if (error != KErrNone) + { + return error; + } + if (TryToStartRead(EFalse) != KErrNone) + { +// if (iEndpointNumber != 0) +// Kern::Printf("EndpointComplete couldn't start read on ep=%d", iEndpointNumber); + } + break; + } + + default: + // shouldn't get here + break; + } + + return KErrNone; + } + + +void TUsbcEndpoint::TxComplete() + { + iLdd->DoTxComplete(this, iEndpointNumber, iError); + } + + +TInt TUsbcEndpoint::RxComplete(TBool aReEntrant) + { + return iLdd->DoRxComplete(this, iEndpointNumber, aReEntrant); + } + + +void TUsbcEndpoint::RxCompleteNow() + { + iLdd->DoRxCompleteNow(this, iEndpointNumber); + } + + +TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TClientBuffer *aTcb) + { + TBool completeNow; + return CopyToClient(aClient, completeNow,aTcb); + } + + +TInt TUsbcEndpoint::CopyToClient(DThread* aClient, TBool& aCompleteNow, TClientBuffer *aTcb) + { + TInt err; + const TInt length = iTransferInfo.iTransferSize; + const TBool KReadData = EFalse; + const TBool KReadUntilShort = ETrue; + + __KTRACE_OPT(KUSB, Kern::Printf("CopyToClient: length = %d", length)); + + if (iTransferInfo.iTransferType == ETransferTypeReadPacket) + { + err = iDmaBuffers->RxCopyPacketToClient(aClient, aTcb, length); + aCompleteNow = ETrue; + } + else if (iTransferInfo.iTransferType == ETransferTypeReadOneOrMore) + { + err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred, + KReadData, aCompleteNow); + aCompleteNow = ETrue; + } + else if (iTransferInfo.iTransferType == ETransferTypeReadUntilShort) + { + err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred, + KReadUntilShort, aCompleteNow); + } + else + { + err = iDmaBuffers->RxCopyDataToClient(aClient, aTcb, length, iBytesTransferred, + KReadData, aCompleteNow); + } + + if (aCompleteNow) + { + ResetTransferInfo(); + SetClientReadPending(EFalse); + } + + return err; + } + + +TInt TUsbcEndpoint::TryToStartRead(TBool aReEntrant) + { + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 1 ep=%d", iEndpointNumber)); + TInt r = KErrNone; + if (iEndpointInfo.iDir != UsbShai::KUsbEpDirOut && + iEndpointInfo.iDir != UsbShai::KUsbEpDirBidirect) + { + // Verify ep direction + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead wrong direction ep=%d", iEndpointNumber)); + return KErrUsbEpBadDirection; + } + + if (iEndpointNumber == 0) + { + // Can't issue an Ep0 read if reader or writer is active + if (iDmaBuffers->TxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Tx already active FATAL")); + return KErrUsbEpNotReady; + } + if (iDmaBuffers->RxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead ep0 Rx already active non-FATAL")); + } + } + + if (!(iDmaBuffers->RxIsActive())) + { + TUint8* bufferAddr; + TPhysAddr physAddr; + TUsbcPacketArray* indexArray; + TUsbcPacketArray* sizeArray; + TInt length; + r = iDmaBuffers->RxGetNextXfer(bufferAddr, indexArray, sizeArray, length, physAddr); + if (r == KErrNone) + { + iDmaBuffers->RxSetActive(); + iRequestCallbackInfo->SetRxBufferInfo(bufferAddr, physAddr, indexArray, sizeArray, length); + + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartRead 2 bufferAddr=0x%08x", bufferAddr)); + + r = iController->SetupReadBuffer(*iRequestCallbackInfo); + if (r != KErrNone) + { + iDmaBuffers->RxSetInActive(); + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: TryToStartRead controller rejects read")); + } + } + else + { + if (iClientReadPending) + { + // Deadlock, try to resolve it by draining buffer into descriptor + if (!aReEntrant) + { + RxComplete(ETrue); + } + else + { + // we are stuck, better complete userside otherwise the userside request will hang + RxCompleteNow(); + } + } + } + } + return r; + } + + +TInt TUsbcEndpoint::TryToStartWrite(TEndpointTransferInfo* pTfr) + { + __KTRACE_OPT(KUSB, Kern::Printf("TryToStartWrite 1 ep=%d", iEndpointNumber)); + if (iEndpointInfo.iDir != UsbShai::KUsbEpDirIn && + iEndpointInfo.iDir != UsbShai::KUsbEpDirBidirect) + { + // Verify ep direction + return KErrUsbEpBadDirection; + } + if (iEndpointNumber == 0) + { + // Can't issue an Ep0 write if unread data is available or writer is active + if (iDmaBuffers->TxIsActive() || !iDmaBuffers->IsReaderEmpty()) + { + return KErrUsbEpNotReady; + } + if (iDmaBuffers->RxIsActive()) + { + // if a reader is active then cancel the read + iDmaBuffers->RxSetInActive(); + iController->CancelReadBuffer(iLdd, iRealEpNumber); + } + } + SetTransferInfo(pTfr); + ContinueWrite(); + return KErrNone; + } + + +TInt TUsbcEndpoint::ContinueWrite() + { + __KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 2")); + TUint8* bufferAddr; + TPhysAddr physAddr; + TInt bufferLength; + TInt r = iDmaBuffers->TxGetNextXfer(bufferAddr, bufferLength, physAddr); + if (r != KErrNone) // probably already active + return r; + __KTRACE_OPT(KUSB, Kern::Printf("ContinueWrite 3")); + iDmaBuffers->TxSetActive(); + TBool zlpReqd = EFalse; + TUint32 transferSize = iTransferInfo.iTransferSize; + TInt length = Min(transferSize - iBytesTransferred, (TUint32) bufferLength); + if (iBytesTransferred+length>=transferSize) + { + // only send a zlp if this is the last buffer of the transfer + zlpReqd = iTransferInfo.iZlpReqd; + } + r = iDmaBuffers->TxStoreData(iLdd->Client(), iLdd->GetClientBuffer(iEndpointNumber), length, iBytesTransferred); + if (r != KErrNone) + return r; + iDmaBuffers->TxSetActive(); + iRequestCallbackInfo->SetTxBufferInfo(bufferAddr, physAddr, length); + iRequestCallbackInfo->iZlpReqd = zlpReqd; +#if 0 + for (TInt i = 0; i < iRequestCallbackInfo->iLength; i++) + { + __KTRACE_OPT(KUSB, Kern::Printf("Buffer[%d] = 0x%02x", i, iRequestCallbackInfo->iBufferStart[i])); + } +#endif + r = iController->SetupWriteBuffer(*iRequestCallbackInfo); + return r; + } + + +void TUsbcEndpoint::CancelTransfer(DThread* aThread, TClientBuffer *aTcb) + { + __KTRACE_OPT(KUSB, Kern::Printf("CancelTransfer")); + if (iDmaBuffers != NULL) + { + if (iClientWritePending) + { + __KTRACE_OPT(KUSB, Kern::Printf(" (iClientWritePending)")); + iClientWritePending = EFalse; + iController->CancelWriteBuffer(iLdd, iRealEpNumber); + iDmaBuffers->TxSetInActive(); + } + if (iClientReadPending) + { + __KTRACE_OPT(KUSB, Kern::Printf(" (iClientReadPending)")); + iClientReadPending = EFalse; + CopyToClient(aThread,aTcb); + } + } + } + + +void TUsbcEndpoint::AbortTransfer() + { + __KTRACE_OPT(KUSB, Kern::Printf("Abort Transfer")); + if (iDmaBuffers != NULL) + { + if (iDmaBuffers->TxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf(" (iClientWritePending)")); + iController->CancelWriteBuffer(iLdd, iRealEpNumber); + iDmaBuffers->TxSetInActive(); + } + if (iDmaBuffers->RxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf(" (iClientReadPending)")); + iController->CancelReadBuffer(iLdd, iRealEpNumber); + iDmaBuffers->RxSetInActive(); + } + iRequestCallbackInfo->iDfc.Cancel(); + } + } + + +TUsbcAlternateSettingList::TUsbcAlternateSettingList() + : iNext(NULL), + iNumberOfEndpoints(0), + iSetting(0) + { + for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) + { + iEpNumDeOrderedByBufSize[i] = -1; + iEndpoint[i] = NULL; + } + } + + +TUsbcAlternateSettingList::~TUsbcAlternateSettingList() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcAlternateSettingList::~TUsbcAlternateSettingList()")); + for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) + { + delete iEndpoint[i]; + } + } + + +TUsbcDeviceStatusQueue::TUsbcDeviceStatusQueue() + { + FlushQueue(); + } + + +void TUsbcDeviceStatusQueue::FlushQueue() + { + for (TInt i = 0; i < KUsbDeviceStatusQueueDepth; i++) + { + iDeviceStatusQueue[i] = KUsbDeviceStatusNull; + } + iStatusQueueHead = 0; + } + + +void TUsbcDeviceStatusQueue::AddStatusToQueue(TUint32 aDeviceStatus) + { + // Only add a new status if it is not a duplicate of the one at the head of the queue + if (!(iStatusQueueHead != 0 && + iDeviceStatusQueue[iStatusQueueHead - 1] == aDeviceStatus)) + { + if (iStatusQueueHead == KUsbDeviceStatusQueueDepth) + { + // Discard item at tail of queue + TUint32 status; + GetDeviceQueuedStatus(status); + } + iDeviceStatusQueue[iStatusQueueHead] = aDeviceStatus; + iStatusQueueHead++; + } + } + + +TInt TUsbcDeviceStatusQueue::GetDeviceQueuedStatus(TUint32& aDeviceStatus) + { + TInt r = KErrNone; + if (iStatusQueueHead <= 0) + { + r = KErrGeneral; + aDeviceStatus = KUsbDeviceStatusNull; + } + else + { + aDeviceStatus = iDeviceStatusQueue[0]; + for(TInt i = 1; i < KUsbDeviceStatusQueueDepth; i++) + { + TUint32 s = iDeviceStatusQueue[i]; + iDeviceStatusQueue[i - 1] = s; + } + iStatusQueueHead--; + iDeviceStatusQueue[KUsbDeviceStatusQueueDepth - 1] = KUsbDeviceStatusNull; + } + return r; + } + +void TClientAsynchNotify::Reset() +{ + iBufferRequest->Reset(); + iClientBuffer=NULL; +} + +//--- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perildd/src/usbdma.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perildd/src/usbdma.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,983 @@ +// Copyright (c) 2000-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\usbc\usbdma.cpp +// LDD for USB Device driver stack: +// Management of DMA-capable data buffers. +// +// + +/** + @file usbdma.cpp + @internalTechnology +*/ + +#include + + +#if defined(_DEBUG) +static const char KUsbPanicLdd[] = "USB LDD"; +#endif + + +TDmaBuf::TDmaBuf(TUsbcEndpointInfo* aEndpointInfo, TInt aBandwidthPriority) + : iBufBasePtr(NULL), + iCurrentDrainingBuffer(NULL), + iCurrentPacket(0), + iCurrentPacketIndexArray(NULL), + iCurrentPacketSizeArray(NULL) + { + iMaxPacketSize = aEndpointInfo->iSize; + iEndpointType = aEndpointInfo->iType; + + switch (aEndpointInfo->iType) + { + case UsbShai::KUsbEpTypeControl: + iBufSz = KUsbcDmaBufSzControl; + iNumberofBuffers = KUsbcDmaBufNumControl; + break; + case UsbShai::KUsbEpTypeIsochronous: + iBufSz = KUsbcDmaBufSzIsochronous; + iNumberofBuffers = KUsbcDmaBufNumIsochronous; + break; + case UsbShai::KUsbEpTypeBulk: + { + if (aEndpointInfo->iDir == UsbShai::KUsbEpDirOut) + { + const TInt priorityOUT = aBandwidthPriority & 0x0f; + iBufSz = KUsbcDmaBufSizesBulkOUT[priorityOUT]; + } + else + { + const TInt priorityIN = (aBandwidthPriority >> 4) & 0x0f; + iBufSz = KUsbcDmaBufSizesBulkIN[priorityIN]; + } + iNumberofBuffers = KUsbcDmaBufNumBulk; + } + break; + case UsbShai::KUsbEpTypeInterrupt: + iBufSz = KUsbcDmaBufSzInterrupt; + iNumberofBuffers = KUsbcDmaBufNumInterrupt; + break; + default: + iBufSz = 0; + iNumberofBuffers = 0; + } + + if (aEndpointInfo->iDir == UsbShai::KUsbEpDirIn) + { + iNumberofBuffers = 1; // IN endpoints only have 1 buffer + } + + for (TInt i = 0; i < KUsbcDmaBufNumMax; i++) + { + // Buffer logical addresses (pointers) + iBuffers[i] = NULL; + // Buffer physical addresses + iBufferPhys[i] = 0; + // Packet indexes base array + iPacketIndex[i] = NULL; + // Packet sizes base array + iPacketSize[i] = NULL; + } + } + + +TInt TDmaBuf::Construct(TUsbcEndpointInfo* aEndpointInfo) + { + if (aEndpointInfo->iDir != UsbShai::KUsbEpDirIn) + { + // IN endpoints don't need a packet array + + // At most 2 packets (clump of max packet size packets) + possible zlp + TUsbcPacketArray* bufPtr = iPacketInfoStorage; + // this divides up the packet indexing & packet size array over the number of buffers + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() array base=0x%08x", bufPtr)); + for (TInt i = 0; i < iNumberofBuffers; i++) + { + iPacketIndex[i] = bufPtr; + bufPtr += KUsbcDmaBufMaxPkts; + iPacketSize[i] = bufPtr; + bufPtr += KUsbcDmaBufMaxPkts; + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() packetIndex[%d]=0x%08x packetSize[%d]=0x%08x", + i, iPacketIndex[i], i, iPacketSize[i])); + } + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Construct() IN endpoint")); + } + Flush(); + return KErrNone; + } + + +TDmaBuf::~TDmaBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::~TDmaBuf()")); + } + +TInt TDmaBuf::BufferTotalSize() const + { + return iBufSz * iNumberofBuffers; + } + +TInt TDmaBuf::BufferSize() const + { + return iBufSz; + } + +TInt TDmaBuf::SetBufferAddr(TInt aBufInd, TUint8* aBufAddr) + { + __ASSERT_DEBUG((aBufInd < iNumberofBuffers), + Kern::Fault(KUsbPanicLdd, __LINE__)); + iDrainable[aBufInd] = iCanBeFreed[aBufInd] = EFalse; + iBuffers[aBufInd] = aBufAddr; + iBufferPhys[aBufInd] = Epoc::LinearToPhysical((TLinAddr)aBufAddr); + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::SetBufferAddr() iBuffers[%d]=0x%08x", aBufInd, iBuffers[aBufInd])); + return KErrNone; + } + +TInt TDmaBuf::BufferNumber() const + { + return iNumberofBuffers; + } + +void TDmaBuf::SetMaxPacketSize(TInt aSize) + { + iMaxPacketSize = aSize; + } + + +void TDmaBuf::Flush() + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::Flush %x", this)); + iRxActive = EFalse; + iTxActive = EFalse; + iExtractOffset = 0; + iTotalRxBytesAvail = 0; + iTotalRxPacketsAvail = 0; + iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex; + iCurrentFillingBufferIndex = 0; + iDrainQueueIndex = KUsbcInvalidDrainQueueIndex; + for (TInt i = 0; i < KUsbcDmaBufNumMax; i++) + { + iDrainable[i] = EFalse; + iCanBeFreed[i] = EFalse; + iNumberofBytesRx[i] = 0; + iNumberofPacketsRx[i] = 0; + iError[i] = KErrGeneral; + iDrainQueue[i] = KUsbcInvalidBufferIndex; +#if defined(USBC_LDD_BUFFER_TRACE) + iFillingOrderArray[i] = 0; + iNumberofBytesRxRemain[i] = 0; + iNumberofPacketsRxRemain[i] = 0; +#endif + } + // Drain queue is 1 oversized + iDrainQueue[KUsbcDmaBufNumMax] = KUsbcInvalidBufferIndex; + +#if defined(USBC_LDD_BUFFER_TRACE) + iFillingOrder = 0; + iDrainingOrder = 0; +#endif + } + + +void TDmaBuf::RxSetActive() + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetActive %x", this)); + iRxActive = ETrue; + } + + +void TDmaBuf::RxSetInActive() + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxSetInActive %x", this)); + iRxActive = EFalse; + } + + +TBool TDmaBuf::RxIsActive() + { + return iRxActive; + } + + +void TDmaBuf::TxSetActive() + { + iTxActive = ETrue; + } + + +void TDmaBuf::TxSetInActive() + { + iTxActive = EFalse; + } + + +TBool TDmaBuf::TxIsActive() + { + return iTxActive; + } + + +/**************************** Rx DMA Buffer Access *************************/ + +void TDmaBuf::ModifyTotalRxBytesAvail(TInt aVal) + { + iTotalRxBytesAvail += aVal; + } + + +void TDmaBuf::ModifyTotalRxPacketsAvail(TInt aVal) + { + iTotalRxPacketsAvail += aVal; + } + + +TBool TDmaBuf::AdvancePacket() + { + ModifyTotalRxPacketsAvail(-1); + TBool r = ETrue; + __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0), + Kern::Fault(KUsbPanicLdd, __LINE__)); + if (++iCurrentPacket >= iNumberofPacketsRx[iCurrentDrainingBufferIndex]) + { + r = NextDrainableBuffer(); + } + iExtractOffset = 0; + __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) || + (iCurrentPacket < KUsbcDmaBufMaxPkts), + Kern::Fault(KUsbPanicLdd, __LINE__)); + return r; + } + + +TInt TDmaBuf::PeekNextPacketSize() + { + TUint pkt = iCurrentPacket; + TInt index = iCurrentDrainingBufferIndex; + TInt size = -1; + if (pkt >= iNumberofPacketsRx[index]) + { + index = PeekNextDrainableBuffer(); + pkt = 0; + } + + if ((index != KUsbcInvalidBufferIndex) && iNumberofPacketsRx[index]) + { + const TUsbcPacketArray* sizeArray = iPacketSize[index]; + size = (TInt)sizeArray[pkt]; + } + + __ASSERT_DEBUG((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) || + (iCurrentPacket < KUsbcDmaBufMaxPkts), + Kern::Fault(KUsbPanicLdd, __LINE__)); + return size; + } + + +inline TInt TDmaBuf::GetCurrentError() + { + // USB bus errors are v.rare. To avoid having an error code attached to every packet since + // almost every errorcode will be KErrNone, we have a single error code per buffer + // If the error code is != KErrNone then it refers to the LAST packet in the buffer + TInt errorCode = KErrNone; + //Check the index, it's not equal to negative (-1) value defined in + //KUsbcInvalidBufferIndex. + __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0), + Kern::Fault(KUsbPanicLdd, __LINE__)); + + if (iError[iCurrentDrainingBufferIndex] != KErrNone) + { + // See if we are at the last packet + if ((iCurrentPacket + 1) == iNumberofPacketsRx[iCurrentDrainingBufferIndex]) + { + errorCode = iError[iCurrentDrainingBufferIndex]; + } + } + return errorCode; + } + + +// used to decide whether a client read can complete straight away +TBool TDmaBuf::IsReaderEmpty() + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::IsReaderEmpty iTotalRxPacketsAvail=%d", + iTotalRxPacketsAvail)); + return (iTotalRxPacketsAvail == 0); + } + + +void TDmaBuf::ReadXferComplete(TInt aNoBytesRecv, TInt aNoPacketsRecv, TInt aErrorCode) + { + // Adjust pending packet + if ((aNoBytesRecv == 0) && (aErrorCode != KErrNone)) + { + // Make the buffer available for reuse + iDrainable[iCurrentFillingBufferIndex] = EFalse; + return; + } + + ModifyTotalRxBytesAvail(aNoBytesRecv); + ModifyTotalRxPacketsAvail(aNoPacketsRecv); + iNumberofBytesRx[iCurrentFillingBufferIndex] = aNoBytesRecv; + iNumberofPacketsRx[iCurrentFillingBufferIndex] = aNoPacketsRecv; + +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofBytesRxRemain[iCurrentFillingBufferIndex] = aNoBytesRecv; + iNumberofPacketsRxRemain[iCurrentFillingBufferIndex] = aNoPacketsRecv; +#endif + + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ReadXferComplete 2 # of bytes=%d # of packets=%d", + iTotalRxBytesAvail, iTotalRxPacketsAvail)); + iDrainable[iCurrentFillingBufferIndex] = ETrue; + iError[iCurrentFillingBufferIndex] = aErrorCode; + AddToDrainQueue(iCurrentFillingBufferIndex); + if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) + { + NextDrainableBuffer(); + } + } + + +TInt TDmaBuf::RxGetNextXfer(TUint8*& aBufferAddr, TUsbcPacketArray*& aIndexArray, + TUsbcPacketArray*& aSizeArray, TInt& aLength, TPhysAddr& aBufferPhys) + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer 1")); + if (RxIsActive()) + { + __KTRACE_OPT(KUSB, Kern::Printf(" ---> RxIsActive, returning")); + return KErrInUse; + } + + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer Current buffer=%d", + iCurrentFillingBufferIndex)); + if (iDrainable[iCurrentFillingBufferIndex]) + { + // If the controller refused the last read request, then the current buffer will still be marked + // as !Drainable, because the controller never completed the read to the ldd. and therefore the buffer + // can be reused. + if (!NextFillableBuffer()) + { + return KErrNoMemory; + } + } + + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxGetNextXfer New buffer=%d", + iCurrentFillingBufferIndex)); + aBufferAddr = iBuffers[iCurrentFillingBufferIndex]; + aBufferPhys = iBufferPhys[iCurrentFillingBufferIndex]; + aIndexArray = iPacketIndex[iCurrentFillingBufferIndex]; + aSizeArray = iPacketSize[iCurrentFillingBufferIndex]; + aLength = iBufSz; + +#if defined(USBC_LDD_BUFFER_TRACE) + iFillingOrderArray[iCurrentFillingBufferIndex] = ++iFillingOrder; +#endif + + return KErrNone; + } + + +TInt TDmaBuf::RxCopyPacketToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength) + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 1")); + +#if defined(USBC_LDD_BUFFER_TRACE) + const TInt numPkts = NoRxPackets(); + const TInt numPktsAlt = NoRxPacketsAlt(); + const TInt numBytes = RxBytesAvailable(); + const TInt numBytesAlt = NoRxBytesAlt(); + + if (numPkts != numPktsAlt) + { + Kern::Printf( + "TDmaBuf::RxCopyPacketToClient: Error: #pkts mismatch global=%d actual=%d", + numPkts, numPktsAlt); + } + if (numBytes != numBytesAlt) + { + Kern::Printf( + "TDmaBuf::RxCopyPacketToClient: Error: #bytes mismatch global=%d actual=%d", + numBytes, numBytesAlt); + } + if ((numPkts == 0) && (numBytes !=0)) + { + Kern::Printf( + "TDmaBuf::RxCopyPacketToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d", + numPkts, numBytes); + } + if ((numPktsAlt == 0) && (numBytesAlt !=0)) + { + Kern::Printf( + "TDmaBuf::RxCopyPacketToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d", + numPktsAlt, numBytesAlt); + } +#endif + + if (!NoRxPackets()) + return KErrNotFound; + + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 2")); + // the next condition should be true because we have some packets available + // coverity[var_tested_neg] + if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) + { + // Marked as Coverity "Intentional" as the member variable + // iCurrentDrainingBufferIndex is attentionaly negative, from previous + // initialization to KUsbcInvalidBufferIndex (which equals -1). + if (!NextDrainableBuffer()) + return KErrNotFound; + } + + __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ), + Kern::Fault(KUsbPanicLdd, __LINE__)); + + if (!iDrainable[iCurrentDrainingBufferIndex]) + return KErrNotFound; + + // Calculate copy-from address & adjust for the fact that + // some data may have already been read from the packet + TUint8* logicalSrc = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset; + TInt packetSz = iCurrentPacketSizeArray[iCurrentPacket]; + TInt thisPacketSz = packetSz - iExtractOffset; + TInt errorCode; + // try and sort out what a "packet" might mean. + // in a multi-packet dma environment, we might see super-packets + // i.e. we might just see one packet, maybe 4K or so long, made of lots of small packets + // Since we don't know where the packet boundaries will be, we have to assume that + // any 'packet' larger than the max packet size of the ep is, in fact, a conglomeration + // of smaller packets. However, for the purposes of the packet count, this is still regarded + // as a single packet and the packet count only decremented when it is consumed. + // As before, if the user fails to read an entire packet out then the next packet is moved onto anyway + // To be safe the user must always supply a buffer of at least max packet size bytes. + if (thisPacketSz > iMaxPacketSize) + { + // Multiple packets left in buffer + // calculate number of bytes to end of packet + if (iEndpointType == UsbShai::KUsbEpTypeBulk) + { + thisPacketSz = iMaxPacketSize - (iExtractOffset & (iMaxPacketSize - 1)); + } + else + { + thisPacketSz = iMaxPacketSize - (iExtractOffset % iMaxPacketSize); + } + errorCode = KErrNone; + } + else + { + errorCode = GetCurrentError(); // single packet left + } + + iExtractOffset += thisPacketSz; // iExtractOffset is now at the end of the real or notional packet + + ModifyTotalRxBytesAvail(-thisPacketSz); +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= thisPacketSz; +#endif + // this can only be untrue if the "packet" is a conglomeration of smaller packets: + if (iExtractOffset == packetSz) + { + // packet consumed, advance to next packet in buffer +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1; +#endif + AdvancePacket(); + } + + TPtrC8 des(logicalSrc, thisPacketSz); + TInt r=Kern::ThreadBufWrite(aThread, aTcb, des, 0, 0, aThread); + if (r == KErrNone) + { + r = errorCode; + } + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyPacketToClient 3")); + + FreeDrainedBuffers(); + + // Use this error code to complete client read request: + return r; + } + + +TInt TDmaBuf::RxCopyDataToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength, TUint32& aDestOffset, + TBool aRUS, TBool& aCompleteNow) + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 1")); + aCompleteNow = ETrue; + +#if defined(USBC_LDD_BUFFER_TRACE) + const TInt numPkts = NoRxPackets(); + const TInt numPktsAlt = NoRxPacketsAlt(); + const TInt numBytes = RxBytesAvailable(); + const TInt numBytesAlt = NoRxBytesAlt(); + + if (numPkts != numPktsAlt) + { + Kern::Printf( + "TDmaBuf::RxCopyDataToClient: Error: #pkts mismatch global=%d actual=%d", + numPkts, numPktsAlt); + } + if (numBytes != numBytesAlt) + { + Kern::Printf( + "TDmaBuf::RxCopyDataToClient: Error: #bytes mismatch global=%d actual=%d", + numBytes, numBytesAlt); + } + if ((numPkts == 0) && (numBytes != 0)) + { + Kern::Printf( + "TDmaBuf::RxCopyDataToClient: Error: global bytes & pkts mismatch pkts=%d bytes=%d", + numPkts, numBytes); + } + if ((numPktsAlt == 0) && (numBytesAlt != 0)) + { + Kern::Printf( + "TDmaBuf::RxCopyDataToClient: Error: actual bytes & pkts mismatch pkts=%d bytes=%d", + numPktsAlt, numBytesAlt); + } +#endif + + if (!NoRxPackets()) + { + return KErrNotFound; + } + + // coverity[var_tested_neg] + if (iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) + { + // Marked as Coverity "Inentional" as the member variable + // iCurrentDrainingBufferIndex is attentionaly negative, from previous + // initialization to KUsbcInvalidBufferIndex (which equals -1). + + if (!NextDrainableBuffer()) + { +#if defined(USBC_LDD_BUFFER_TRACE) + Kern::Printf("TDmaBuf::RxCopyDataToClient: Error: No buffer draining=%d, packets=%d", + iCurrentDrainingBufferIndex, iTotalRxPacketsAvail); +#endif + return KErrNotFound; + } + } +#if defined(USBC_LDD_BUFFER_TRACE) + + __ASSERT_DEBUG((iCurrentDrainingBufferIndex >= 0 ), + Kern::Fault(KUsbPanicLdd, __LINE__)); + + if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex]) + { + Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 10 draining=%d", + iCurrentDrainingBufferIndex); + } +#endif + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::RxCopyDataToClient 2")); + + TUint8* blockStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset; + TUint8* lastEndAddr = blockStartAddr; // going to track the contiguity of the memory + TUint8* thisStartAddr = blockStartAddr; + TInt toDo = Min(aLength - (TInt)aDestOffset, iTotalRxBytesAvail); +#if defined(USBC_LDD_BUFFER_TRACE) + TInt bufnum = iCurrentDrainingBufferIndex; +#endif + TInt errorCode = KErrNone; + TBool isShortPacket = EFalse; + const TInt maxPacketSizeMask = iMaxPacketSize - 1; + do + { +#if defined(USBC_LDD_BUFFER_TRACE) + if (bufnum != iCurrentDrainingBufferIndex) + { + bufnum = iCurrentDrainingBufferIndex; + if (iDrainingOrder != iFillingOrderArray[iCurrentDrainingBufferIndex]) + { + Kern::Printf("!!! Out of Order Draining TDmaBuf::RxCopyDataToClient 20 draining=%d", + iCurrentDrainingBufferIndex); + } + } +#endif + if (errorCode == KErrNone) + { + errorCode = GetCurrentError(); + } + thisStartAddr = iCurrentDrainingBuffer + iCurrentPacketIndexArray[iCurrentPacket] + iExtractOffset; + const TInt thisPacketSize = iCurrentPacketSizeArray[iCurrentPacket]; + const TInt size = thisPacketSize - iExtractOffset; + if (aRUS) + { + if (iEndpointType == UsbShai::KUsbEpTypeBulk) + { + isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask); + } + else + { + // this 'if' block is arranged to avoid a division on packet sizes <= iMaxPacketSize + isShortPacket = (size < iMaxPacketSize) || + ((size > iMaxPacketSize) && (size % iMaxPacketSize)); + } + } + TInt copySize = Min(size, toDo); + iExtractOffset += copySize; + toDo -= copySize; + if (thisStartAddr != lastEndAddr) + { + TInt bytesToCopy = lastEndAddr - blockStartAddr; + TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset); + if(r != KErrNone) + Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat); + blockStartAddr = thisStartAddr; + } + + ModifyTotalRxBytesAvail(-copySize); +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofBytesRxRemain[iCurrentDrainingBufferIndex] -= copySize; +#endif + lastEndAddr = thisStartAddr + copySize; + if (iExtractOffset == thisPacketSize) + { + // More data to copy, so need to access new packet +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1; +#endif + if (!AdvancePacket()) + { + break; // no more packets left + } + } + } while (toDo > 0 && !isShortPacket); + + if (thisStartAddr != lastEndAddr) + { + TInt bytesToCopy = lastEndAddr - blockStartAddr; + TInt r=CopyToUser(aThread, blockStartAddr, bytesToCopy, aTcb, aDestOffset); + if(r != KErrNone) + Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat); + } + + // If we have transferred the requested amount of data it is still possible that + // the next packet is a zlp which needs to be bumped over + + if (aRUS && (toDo == 0) && (iExtractOffset == 0) && (!isShortPacket) && (!IsReaderEmpty()) && + (PeekNextPacketSize() == 0)) + { + // swallow a zlp + isShortPacket = ETrue; +#if defined(USBC_LDD_BUFFER_TRACE) + iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex] -= 1; +#endif + AdvancePacket(); + } + aCompleteNow = isShortPacket || (((TInt)aDestOffset) == aLength) || (errorCode != KErrNone); + + FreeDrainedBuffers(); + + // Use this error code to complete client read request + return errorCode; + } + + +inline TInt TDmaBuf::CopyToUser(DThread* aThread, const TUint8* aSourceAddr, + TInt aLength, TClientBuffer *aTcb, TUint32& aDestOffset) + { + TPtrC8 des(aSourceAddr, aLength); + TInt errorCode = Kern::ThreadBufWrite(aThread, aTcb, des, aDestOffset, KChunkShiftBy0, aThread); + if (errorCode == KErrNone) + { + aDestOffset += aLength; + } + return errorCode; + } + + +inline TInt TDmaBuf::NoRxPackets() const + { + return iTotalRxPacketsAvail; + } + + +inline void TDmaBuf::IncrementBufferIndex(TInt& aIndex) + { + if (++aIndex == iNumberofBuffers) + aIndex = 0; + } + + +TBool TDmaBuf::NextDrainableBuffer() + { + TBool r = EFalse; + if (iCurrentDrainingBufferIndex != KUsbcInvalidBufferIndex) + { + iCanBeFreed[iCurrentDrainingBufferIndex] = ETrue; + iNumberofPacketsRx[iCurrentDrainingBufferIndex] = 0; // Current buffer is empty + iNumberofBytesRx[iCurrentDrainingBufferIndex] = 0; // Current buffer is empty + +#if defined(USBC_LDD_BUFFER_TRACE) + TUint& bytesRemain = iNumberofBytesRxRemain[iCurrentDrainingBufferIndex]; + TUint& pktsRemain = iNumberofPacketsRxRemain[iCurrentDrainingBufferIndex]; + if ((bytesRemain != 0) || (pktsRemain != 0)) + { + Kern::Printf( + "TDmaBuf::NextDrainableBuffer: Error: data discarded buffer=%d pkts=%d bytes=%d", + iCurrentDrainingBufferIndex, pktsRemain, bytesRemain); + bytesRemain = 0; + pktsRemain = 0; + } +#endif + + iCurrentDrainingBufferIndex = KUsbcInvalidBufferIndex; + iCurrentPacket = KUsbcInvalidPacketIndex; + } + + if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex) + { + r = ETrue; + const TInt index = iDrainQueue[0]; + iDrainQueueIndex--; + for (TInt i = 0; i < iNumberofBuffers; i++) + { + iDrainQueue[i] = iDrainQueue[i+1]; + } + +#if defined(USBC_LDD_BUFFER_TRACE) + if (index != KUsbcInvalidBufferIndex) + iDrainingOrder++; +#endif + + iCurrentDrainingBufferIndex = index; + iCurrentDrainingBuffer = iBuffers[index]; + iCurrentPacketIndexArray = iPacketIndex[index]; + iCurrentPacketSizeArray = iPacketSize[index]; + iCurrentPacket = 0; + } + return r; + } + + +TInt TDmaBuf::PeekNextDrainableBuffer() + { + TInt r = KUsbcInvalidBufferIndex; + if (iDrainQueueIndex != KUsbcInvalidDrainQueueIndex) + { + r = iDrainQueue[0]; + } + return r; + } + + +TBool TDmaBuf::NextFillableBuffer() + { + TBool r = EFalse; + TInt index = iCurrentFillingBufferIndex; + IncrementBufferIndex(index); + // the sequence will restart at 0 if a buffer can't be found this time + iCurrentFillingBufferIndex = 0; + for (TInt i = 0; i < iNumberofBuffers; i++) + { + if (!iDrainable[index]) + { + iCurrentFillingBufferIndex = index; + r = ETrue; + break; + } + IncrementBufferIndex(index); + } + return r; + } + + +void TDmaBuf::FreeDrainedBuffers() + { + for (TInt i = 0; i < iNumberofBuffers; i++) + { + if (iDrainable[i] && iCanBeFreed[i]) + { + iDrainable[i] = iCanBeFreed[i] = EFalse; + } + } + } + + +TBool TDmaBuf::ShortPacketExists() + { + // Actually, a short packet or residue data + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::ShortPacketExists 1")); + TInt index = iCurrentDrainingBufferIndex; + TUsbcPacketArray* pktSizeArray = iCurrentPacketSizeArray; + + if (iMaxPacketSize > 0) + { + // No buffers available for draining + if ((iCurrentDrainingBufferIndex == KUsbcInvalidBufferIndex) || + (iCurrentPacket == KUsbcInvalidPacketIndex)) + return EFalse; + + // Zlp waiting at tail + if ((iTotalRxBytesAvail == 0) && (NoRxPackets() == 1)) + return ETrue; + + if (iEndpointType == UsbShai::KUsbEpTypeBulk) + { + const TInt mask = iMaxPacketSize - 1; + if (iTotalRxBytesAvail & mask) + return ETrue; + + // residue==0; this can be because + // zlps exist, or short packets combine to n * max_packet_size + // This means spadework + const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset; + if ((s == 0) || (s & mask)) + { + return ETrue; + } + + for (TInt i = 0; i < iNumberofBuffers; i++) + { + if (index == KUsbcInvalidBufferIndex) + break; + if (iDrainable[index]) + { + const TInt packetCount = iNumberofPacketsRx[index]; + const TInt lastPacketSize=pktSizeArray[packetCount - 1]; + if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize & mask)) + { + return ETrue; + } + } + index = iDrainQueue[i]; + pktSizeArray = iPacketSize[index]; + } + } + else + { + if (iTotalRxBytesAvail % iMaxPacketSize) + return ETrue; + + // residue==0; this can be because + // zlps exist, or short packets combine to n * max_packet_size + // This means spadework + const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset; + if ((s == 0) || (s % iMaxPacketSize)) + { + return ETrue; + } + + for (TInt i = 0; i < iNumberofBuffers; i++) + { + if (index == KUsbcInvalidBufferIndex) + break; + if (iDrainable[index]) + { + const TInt packetCount = iNumberofPacketsRx[index]; + const TInt lastPacketSize = pktSizeArray[packetCount - 1]; + if ((lastPacketSize < iMaxPacketSize) || (lastPacketSize % iMaxPacketSize)) + { + return ETrue; + } + } + index = iDrainQueue[i]; + pktSizeArray = iPacketSize[index]; + } + } + } + + return EFalse; + } + + +void TDmaBuf::AddToDrainQueue(TInt aBufferIndex) + { + if (iDrainQueue[iDrainQueueIndex + 1] != KUsbcInvalidBufferIndex) + { +#if defined(USBC_LDD_BUFFER_TRACE) + Kern::Printf("TDmaBuf::AddToDrainQueue: Error: invalid iDrainQueue[x]"); +#endif + } + iDrainQueue[++iDrainQueueIndex] = aBufferIndex; + } + + +#if defined(USBC_LDD_BUFFER_TRACE) +TInt TDmaBuf::NoRxPacketsAlt() const + { + TInt pktCount = 0; + for(TInt i = 0; i < iNumberofBuffers; i++) + { + if (iDrainable[i]) + { + pktCount += iNumberofPacketsRxRemain[i]; + } + } + return pktCount; + } + + +TInt TDmaBuf::NoRxBytesAlt() const + { + TInt byteCount = 0; + for(TInt i = 0; i < iNumberofBuffers; i++) + { + if (iDrainable[i]) + { + byteCount += iNumberofBytesRxRemain[i]; + } + } + return byteCount; + } +#endif + + +// We only store 1 transaction, no other buffering is done +TInt TDmaBuf::TxStoreData(DThread* aThread, TClientBuffer *aTcb, TInt aTxLength, TUint32 aBufferOffset) + { + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 1")); + if (!IsReaderEmpty()) + return KErrInUse; + + __KTRACE_OPT(KUSB, Kern::Printf("TDmaBuf::TxStoreData 2")); + + TInt remainTxLength = aTxLength; + TUint32 bufferOffset = aBufferOffset; + // Store each buffer separately + for( TInt i=0;(i0);i++) + { + TUint8* logicalDest = iBuffers[i]; + TInt xferSz = Min(remainTxLength, iBufSz); + TPtr8 des(logicalDest, xferSz, xferSz); + TInt r = Kern::ThreadBufRead(aThread, aTcb, des, bufferOffset, KChunkShiftBy0); + if(r != KErrNone) + { + Kern::ThreadKill(aThread, EExitPanic, r, KUsbLDDKillCat); + return r; + } + remainTxLength -= iBufSz; + bufferOffset += iBufSz; + } + + return KErrNone; + } + + +TInt TDmaBuf::TxGetNextXfer(TUint8*& aBufferAddr, TInt& aTxLength, TPhysAddr& aBufferPhys) + { + if (iTxActive) + return KErrInUse; + + aBufferAddr = iBuffers[0]; // only 1 tx buffer + aBufferPhys = iBufferPhys[0]; + aTxLength = BufferTotalSize(); + + return KErrNone; + } + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/appifwrapper/eabi/usbcscu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/appifwrapper/eabi/usbcscu.def Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,23 @@ +EXPORTS + _ZN15TEndpointBuffer11WriteBufferEPvjiR14TRequestStatus @ 1 NONAME + _ZN15TEndpointBuffer11WriteBufferEjjiR14TRequestStatus @ 2 NONAME + _ZN15TEndpointBuffer16GetInBufferRangeERPvRj @ 3 NONAME + _ZN15TEndpointBuffer16GetInBufferRangeERjS0_ @ 4 NONAME + _ZN15TEndpointBuffer5CloseEv @ 5 NONAME + _ZN15TEndpointBuffer9GetBufferERPvRjRiR14TRequestStatusj @ 6 NONAME + _ZN15TEndpointBufferC1Ev @ 7 NONAME + _ZN15TEndpointBufferC2Ev @ 8 NONAME + _ZN16RDevUsbcScClient12OpenEndpointER15TEndpointBufferi @ 9 NONAME + _ZN16RDevUsbcScClient17FinalizeInterfaceERP6RChunk @ 10 NONAME + _ZN16RDevUsbcScClient17FinalizeInterfaceEv @ 11 NONAME + _ZN16RDevUsbcScClient20GetDataTransferChunkERP6RChunk @ 12 NONAME + _ZN16RDevUsbcScClient28StartNextOutAlternateSettingEi @ 13 NONAME + _ZN18TUsbcScChunkHeader20GetNumberOfEndpointsEi @ 14 NONAME + _ZN18TUsbcScChunkHeader9GetBufferEiiRP24TUsbcScHdrEndpointRecord @ 15 NONAME + _ZN18TUsbcScChunkHeaderC1E6RChunk @ 16 NONAME + _ZN18TUsbcScChunkHeaderC2E6RChunk @ 17 NONAME + _ZN15TEndpointBuffer4DumpEv @ 18 NONAME + _ZN15TEndpointBuffer10TakeBufferERPvRjRiR14TRequestStatusj @ 19 NONAME + _ZN15TEndpointBuffer6ExpireEv @ 20 NONAME + _ZN15TEndpointBuffer6ExpireEPv @ 21 NONAME + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/appifwrapper/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/appifwrapper/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,39 @@ +// 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: +// bld.inf +// USB Client Driver +// +// + +/** + @file +*/ +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_MMPFILES + +#if defined(GENERIC_MARM) || defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +usbcsc_bil +#endif +#endif + + +#endif +#endif diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/appifwrapper/group/usbcsc_bil.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/appifwrapper/group/usbcsc_bil.mmp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,31 @@ +// Copyright (c) 2008-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/usbcsc/usbcsc_bil.mmp +// +// +USERINCLUDE ../../include + +OS_LAYER_SYSTEMINCLUDE + +target usbcsc_bilshai.dll +targettype dll +sourcepath ../src +source usbcsc_bil.cpp + +library euser.lib + +deffile ../~/usbcsc.def + +VENDORID 0x70000001 +capability all diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/appifwrapper/src/usbcsc_bil.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/appifwrapper/src/usbcsc_bil.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,633 @@ +// Copyright (c) 2008-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\usbcsc\usbcsc_bil.cpp +// +// + +#include +#include +#include +#include + +/** @file usbcsc_bil.cpp + + Buffer Interface Layer for USB Client Device driver stack, using shared chunks. + + @internalTechnology +*/ + +EXPORT_C TInt RDevUsbcScClient::FinalizeInterface() + { + TInt errorOrhandle = DoControl(EControlRealizeInterface); //returns a error value or chunk handle + TInt r = iSharedChunk.SetReturnedHandle(errorOrhandle); + iEndpointStatus = 0x00; //all endpoints are closed at the moment + iAlternateSetting = 0; + iNewAltSetting = 0; + iAltSettingSeq = 0; + return r; + } + + +EXPORT_C TInt RDevUsbcScClient::FinalizeInterface(RChunk*& aChunk) + { + TInt errorOrhandle = DoControl(EControlRealizeInterface); + iSharedChunk.SetReturnedHandle(errorOrhandle); + iEndpointStatus = 0x00; //all endpoints are closed at the moment + iAlternateSetting = 0; + return aChunk->SetReturnedHandle(errorOrhandle); + } + + +EXPORT_C TInt RDevUsbcScClient::OpenEndpoint(TEndpointBuffer& aEpB, TInt aEpI) + { + TUsbcScHdrEndpointRecord* endpointInf = NULL; + TBuf8 descriptor; + TUsbcScChunkHeader chunkHeader(iSharedChunk); + //Do some validity checks + if((aEpB.iInState != TEndpointBuffer::ENotValid) && (aEpB.iOutState != TEndpointBuffer::ENotValid)) + return KErrArgument; + + TInt nEndpoints = chunkHeader.GetNumberOfEndpoints(iAlternateSetting); + if ((aEpI < KEp0Number) && (aEpI > nEndpoints)) // Check endpoint number range + return KErrNotFound; + + if(iEndpointStatus & (1 << aEpI)) // Check that endpoint isn't already opene + return KErrInUse; + + if(aEpI == KEp0Number) //endpoint 0 + { + TUsbcScHdrEndpointRecord ep0= TUsbcScHdrEndpointRecord(KUsbcScEndpointZero, KUsbScHdrEpDirectionBiDir | KUsbScHdrEpTypeControl); + aEpB.Construct(this,iSharedChunk.Base(), &ep0 ,aEpI, + (SUsbcScBufferHeader*) ((TUint)iSharedChunk.Base() + (chunkHeader.iBuffers)->Ep0Out()->Offset())); + + aEpB.iBufferStartAddr = (TUint8*) ((TUint)iSharedChunk.Base() + (chunkHeader.iBuffers)->Ep0In()->Offset()); + aEpB.iSize = chunkHeader.iBuffers->Ep0In()->Size(); + } + else // If normal endpoint (!ep0) + { + TUsbcScBufferRecord* buf = chunkHeader.GetBuffer(iAlternateSetting,aEpI,endpointInf); + if (!buf) + return KErrGeneral; + // Set up endpoint members + aEpB.iBufferStartAddr = (TUint8*) (buf->Offset() + (TUint)iSharedChunk.Base()); + aEpB.iSize = buf->Size(); + TInt r = GetEndpointDescriptor(iAlternateSetting, aEpI, descriptor); + if(r != KErrNone) // We need this to be able to calculate alignment + { + return r; + } + + if (endpointInf->Direction()&KUsbScHdrEpDirectionIn) + { //in case of IN endpoints, first endpoint buffer location points to end offset + aEpB.Construct(this,iSharedChunk.Base(),endpointInf,aEpI); + if (iInAltSetting==KErrEof) + aEpB.iInState=TEndpointBuffer::EEOF; + + } + else + { + SUsbcScBufferHeader *endpointHdr = (SUsbcScBufferHeader *) aEpB.iBufferStartAddr; + //In this case,SUsbcScBufferHeader points to full OUT endpoint header + aEpB.Construct(this,iSharedChunk.Base(),endpointInf,aEpI, endpointHdr); + } + } + iEndpointStatus |= (1 << aEpI); + +#ifdef _DEBUG + aEpB.Dump(); + RDebug::Printf("iEndpointStatus: %x \n",iEndpointStatus); +#endif + return KErrNone; + } + + +//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...) +//This drains any old data from an OUT buffer, and gets it ready for reading an ep. +//aBufferOffset - The offset, into the chunk, that the buffer in question, may be found. + +TInt RDevUsbcScClient::Drain(TUint aBufferOffset) +{ + TUint8* base = iSharedChunk.Base(); + SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (aBufferOffset+base); + TUint localTail = endpointHdr->iBilTail; + TUsbcScTransferHeader* currentTransfer; + TUint16 next = (iAltSettingSeq+1)&0xFFFF; + TInt err=KErrNone; + + while (ETrue) + { + if (localTail == (TUint) endpointHdr->iHead) + { + err = KErrNotReady; + break; + } + currentTransfer = (TUsbcScTransferHeader*) (base + localTail); + + if (currentTransfer->iAltSettingSeq == next) + { + iNewAltSetting=currentTransfer->iAltSetting; // record new alt setting + break; + } + else + { + localTail = currentTransfer->iNext; + } + } // end while + endpointHdr->iBilTail = localTail; + endpointHdr->iTail = localTail; + return err; +} + +//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...) +//This method checks that the OUT buffer is ready for reading an ep. +//aBufferOffset - The offset, into the chunk, that the buffer in question, may be found. + +TInt RDevUsbcScClient::Peek(TUint aBufferOffset) +{ + TUint8* base = iSharedChunk.Base(); + SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (aBufferOffset+base); + TUint localTail = endpointHdr->iBilTail; + TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (base + localTail); + + if ((localTail == (TUint)endpointHdr->iHead) || (currentTransfer->iAltSettingSeq != (iAltSettingSeq+1)&0xFFFF)) + // if alternate setting has not changed + return KErrNotReady; + else + { + iNewAltSetting=currentTransfer->iAltSetting; + return KErrNone; + } +} + +//Internal, used by RDevUsbcScClient::StartNextOutAlternateSetting(...) +//This method is called if an alternate setting change happens from a set of ONLY IN endpoints. +//Used to find the least possible alternate setting it can return to the user, stored in iNewAltSetting +//Returns the sequence number of the 'latest' alternate setting it can switch to + +TInt RDevUsbcScClient::FindNextAlternateSetting() + { + TUsbcScChunkHeader chunkHeader(iSharedChunk); + TUsbcScHdrEndpointRecord* endpointInf = NULL; + TUint bufOff; + TInt altSet; + TInt ep; + TInt bufNum; + + RArray bufferOffset; // Array to contain all OUT enpoint buffer offsets + // Populate array + for (altSet = 0; altSet < chunkHeader.iAltSettings->iNumOfAltSettings ; altSet++) + { + TInt numEndpoints = chunkHeader.GetNumberOfEndpoints(altSet); + for (ep = 1; ep <= numEndpoints ; ep ++) + { + bufOff = chunkHeader.GetBuffer(altSet, ep, endpointInf)->Offset(); + if ((endpointInf->Direction() & KUsbScHdrEpDirectionOut) && (bufferOffset.Find(bufOff) == KErrNotFound)) + { + bufferOffset.Append(bufOff); + } + } + } + + TInt err = KErrNotFound; + TUint16 altSetSeqDelta = 0; + TUint16 currentaltSetSeqDelta = 0; + TBool noNewSettingFound = ETrue; + TInt altSetSeq = iAltSettingSeq; + TUint8* base = iSharedChunk.Base(); + + for (bufNum = 0; bufNum < bufferOffset.Count(); bufNum++) // Scan all OUT buffers + { + SUsbcScBufferHeader* endpointHdr = (SUsbcScBufferHeader*) (bufferOffset[bufNum] + base); + TUint localTail = endpointHdr->iBilTail; + TUsbcScTransferHeader* currentTransfer; + TUint16 next = (iAltSettingSeq+1)&0xFFFF; + + while (ETrue) + { + if (localTail == (TUint) endpointHdr->iHead) + { + break; // This OUT endpoint buffer has no data, proceed checking with other OUT endpoint buffers + } + currentTransfer = (TUsbcScTransferHeader*) (base + localTail); + + if (currentTransfer->iAltSettingSeq != iAltSettingSeq) + { + if (currentTransfer->iAltSettingSeq == next) + { + altSetSeq = currentTransfer->iAltSettingSeq; + iNewAltSetting = currentTransfer->iAltSetting; // record new alt setting + err = KErrNone; + break; + } + + if (noNewSettingFound) + { + altSetSeqDelta = Abs(iAltSettingSeq - currentTransfer->iAltSettingSeq); + altSetSeq = currentTransfer->iAltSettingSeq; + iNewAltSetting = currentTransfer->iAltSetting; // record new alt setting + noNewSettingFound = EFalse; + } + else + { + currentaltSetSeqDelta = Abs(iAltSettingSeq - currentTransfer->iAltSettingSeq); + if (currentaltSetSeqDelta < altSetSeqDelta) + { + altSetSeqDelta = currentaltSetSeqDelta; + altSetSeq = currentTransfer->iAltSettingSeq; + iNewAltSetting = currentTransfer->iAltSetting; + } + } + break; + } + + localTail = currentTransfer->iNext; + } // end while + + if (!err) // Found an alt set sequence one after iAltSettingSeq + { + break; // found 'the next' alternate setting, exit for loop + } + + }// for loop + + return altSetSeq; + } + +EXPORT_C TInt RDevUsbcScClient::StartNextOutAlternateSetting(TBool aFlush) + { + TUsbcScChunkHeader chunkHeader(iSharedChunk); + + //if endpoints are still open, return KErrInUse + if((iEndpointStatus&~1) != 0) + { + return KErrInUse; + } + + TInt r; + TInt ep; + TInt noEp; + TUint bufOff; + TBool inEndpointSet = ETrue; + TUsbcScHdrEndpointRecord* endpointInf = NULL; + + // check if alternate setting contains all IN endpoints + noEp = chunkHeader.GetNumberOfEndpoints(iAlternateSetting); + + // for each used buffer. + for (ep=1;ep<=noEp;ep++) + { + bufOff = chunkHeader.GetBuffer(iAlternateSetting,ep,endpointInf)->Offset(); + + if (endpointInf->Direction() & KUsbScHdrEpDirectionOut) + { + inEndpointSet = EFalse; + if (aFlush) + r = Drain(bufOff); // we need to remove anythng in the way, and get it ready for reading. + else + r = Peek(bufOff); // we need to check it is ready for reading! + if (r) + return r; + } + } + + + TInt altSeq = 0; + if (inEndpointSet) // If all endpoints in the current alternate setting are IN endpoints + { // go through all OUT buffers for alternate setting change + altSeq = FindNextAlternateSetting(); + } + + if((iNewAltSetting == iAlternateSetting) && (!inEndpointSet)) + { + return KErrNotReady; + } + + // Find/Set IN alternate setting + TInt ret = StartNextInAlternateSetting(); + SUsbcScAlternateSetting* altrec = ((SUsbcScAlternateSetting*) (&ret)); + + if (altrec->iSequence==iAltSettingSeq+1) + { + if (altrec->iSetting!=iNewAltSetting) + return KErrGeneral; + iInAltSetting=iNewAltSetting; + } + else + { + if (inEndpointSet) + { + if ((altSeq == iAltSettingSeq) || (iAltSettingSeq == altrec->iSequence)) + { + return KErrNotReady; + } + else if (altSeq != altrec->iSequence) + { + iInAltSetting=KErrEof; + } + } + iInAltSetting=KErrEof; + } + + iAlternateSetting = iNewAltSetting; + iAltSettingSeq += 1; + + return iAlternateSetting; + } + + +EXPORT_C TInt RDevUsbcScClient::GetDataTransferChunk(RChunk* & aChunk) + { + aChunk = &iSharedChunk; + return KErrNone; + } + +// Constructor + +EXPORT_C TEndpointBuffer::TEndpointBuffer() + :iInState(ENotValid), + iOutState(ENotValid), + iEndpointNumber(-1), + iBufferNum(-1), + iBufferStartAddr(0), + iSize(0) + { + } + +// Internal, called by RDevUsbcScClient::OpenEndpoint. +void TEndpointBuffer::Construct(RDevUsbcScClient* aClient, TUint8* aBaseAddr, const TUsbcScHdrEndpointRecord* aEpType , TInt aEndpointNumber,SUsbcScBufferHeader* aEndpointHdr) + { + iClient = aClient; + iBaseAddr = (TUint) aBaseAddr; + iInState = (((aEpType->Direction())&KUsbScHdrEpDirectionIn) ? EValid : ENotValid); + iOutState = (((aEpType->Direction())&KUsbScHdrEpDirectionOut) ? EValid : ENotValid); + iBufferNum = (aEpType->iBufferNo==(KUsbcScEndpointZero&0xFF))?KUsbcScEndpointZero:aEpType->iBufferNo; + iEndpointNumber = aEndpointNumber; + + iEndpointHdr = aEndpointHdr; + }; + +EXPORT_C TInt TEndpointBuffer::GetInBufferRange(TAny*& aStart, TUint& aSize) + { + if ((iInState)) + { + return iInState; + } + aStart= iBufferStartAddr; + aSize= iSize; + return KErrNone; + }; + +EXPORT_C TInt TEndpointBuffer::GetInBufferRange(TUint& aStart, TUint& aSize) + { + if ((iInState)) + return iInState; + aStart= (TUint) iBufferStartAddr - iBaseAddr; + aSize= iSize; + return KErrNone; + } + + +EXPORT_C TInt TEndpointBuffer::GetBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength) + { + if (iOutState) + return iOutState; + + TUsbcScTransferHeader* currentTransfer; + TInt r; + do // until we have a transfer with data. + { + iEndpointHdr->iTail = iEndpointHdr->iBilTail; + if(iEndpointHdr->iBilTail == iEndpointHdr->iHead) //If no new data, create request + { + r = iClient->ReadDataNotify(iBufferNum,aStatus); + if (r!=KErrCompletion) // Data could arrive since we checked. + return r; + } + currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iBilTail); + + iEndpointHdr->iBilTail = currentTransfer->iNext; + aZLP = (currentTransfer->iFlags & KUsbcScShortPacket)!=EFalse; + + if(currentTransfer->iAltSettingSeq != (iClient->iAltSettingSeq)) // if alternate setting has changed + { + if (currentTransfer->iAltSettingSeq == (iClient->iAltSettingSeq+1)) //Note- KIS ATM, if multiple alternate setting changes happen + iClient->iNewAltSetting = currentTransfer->iAltSetting; //before StartNextOutAlternateSetting is called, + //this variable will reflect the latest requested AlternateSetting + + + if (iEndpointNumber != KEp0Number) + { +// iOutState = EEOF; + return KErrEof; + } + else if ((currentTransfer->iBytes==0) && (!aZLP)) + { + return KErrAlternateSettingChanged; + } + } + + } + while ((currentTransfer->iBytes==0) && (!aZLP)); // ignore empty transfers + + aBuffer = currentTransfer->iData.i; + aSize = currentTransfer->iBytes; + return (currentTransfer->iFlags & KUsbcScStateChange)?KStateChange:KErrCompletion; + } + +EXPORT_C TInt TEndpointBuffer::TakeBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength) + { + if (iOutState) + return iOutState; + + TUsbcScTransferHeader* currentTransfer; + TInt r; + do // until we have a transfer with data. + { + if(iEndpointHdr->iBilTail == iEndpointHdr->iHead) //If no new data, create request + { + r = iClient->ReadDataNotify(iBufferNum,aStatus); + if (r!=KErrCompletion) // Data could arrive since we checked. + { + return r; + } + } + + currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iBilTail); + iEndpointHdr->iBilTail = currentTransfer->iNext; + aZLP = (currentTransfer->iFlags & KUsbcScShortPacket)!=EFalse; // True if short packet else false + + if(currentTransfer->iAltSettingSeq != (iClient->iAltSettingSeq)) // if alternate setting has changed + { + if (currentTransfer->iAltSettingSeq == (iClient->iAltSettingSeq+1)) //Note- KIS ATM, if multiple alternate setting changes happen + iClient->iNewAltSetting = currentTransfer->iAltSetting; //before StartNextOutAlternateSetting is called, + //this variable will reflect the latest requested AlternateSetting + Expire(currentTransfer->iData.i); + if (iEndpointNumber != KEp0Number) + { +// iOutState = EEOF; + return KErrEof; + } + else if ((currentTransfer->iBytes==0) && (!aZLP)) + { + return KErrAlternateSettingChanged; + } + + } + + if ((currentTransfer->iBytes==0) && (!aZLP)) // here , if empty transfer with alt setting information, Call expire + { + Expire(currentTransfer->iData.i); + } + } + while ((currentTransfer->iBytes==0) && (!aZLP)); // ignore empty transfers + + aBuffer = currentTransfer->iData.i; + aSize = currentTransfer->iBytes; + return (currentTransfer->iFlags & KUsbcScStateChange)?KStateChange:KErrCompletion; + } + +EXPORT_C TInt TEndpointBuffer::Expire() + { + if (!(iOutState != ENotValid)) + return iOutState; + + if (iEndpointHdr->iTail != iEndpointHdr->iBilTail) + { + TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iTail); + iEndpointHdr->iTail = currentTransfer->iNext; + } + return KErrNone; + } + +EXPORT_C TInt TEndpointBuffer::Expire(TAny* aAddress) + { + if (!(iOutState != ENotValid)) + return iOutState; + + TUint headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. + TInt transferToExpire = ((TUint) aAddress - headerSize); + TInt offsetToExpire = transferToExpire - iBaseAddr; + + TInt currentTail = iEndpointHdr->iTail; + + TInt prevTail = NULL; + TBool found = EFalse; + while (currentTail != iEndpointHdr->iBilTail) + { + TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + currentTail); + if (currentTail == offsetToExpire) // found which to expire + { + found = ETrue; + // This offset is to be expired + if (prevTail == NULL) + { + // The offset is at the list head + iEndpointHdr->iTail = currentTransfer->iNext; + } + else + { + // The offset is NOT at the list head + // This leaves a GAP in the buffer which will not be filled unless the 'transfers' before 'currentTail' are expired + currentTail = currentTransfer->iNext; + TUsbcScTransferHeader* prevTransfer = (TUsbcScTransferHeader*) (iBaseAddr + prevTail); + prevTransfer->iNext = currentTail; + } + break; + } + prevTail = currentTail; + currentTail = currentTransfer->iNext; + } + return found ? KErrNone : KErrNotFound; + } + + +EXPORT_C TInt TEndpointBuffer::WriteBuffer(TAny* aBuffer,TUint aSize,TBool aZLP,TRequestStatus& aStatus) + { + if (iInState) + return iInState; + + iClient->WriteData(iBufferNum, ((TUint)aBuffer - (TUint)iBaseAddr),aSize,aZLP,aStatus); + return KErrNone; + } + + +EXPORT_C TInt TEndpointBuffer::WriteBuffer(TUint aOffset,TUint aSize,TBool aZLP,TRequestStatus& aStatus) + { + if (iInState) + return iInState; + + iClient->WriteData(iBufferNum,aOffset,aSize,aZLP,aStatus); + return KErrNone; + } + + +/** +Closes the endpoint buffer +@return KErrNone if close is successfull +*/ +EXPORT_C TInt TEndpointBuffer::Close() + { + if ((iInState == ENotValid) && (iOutState == ENotValid)) + return KErrNotFound; + if (iOutState != ENotValid) + { + TUsbcScTransferHeader* currentTransfer = (TUsbcScTransferHeader*) (iBaseAddr + iEndpointHdr->iTail); + //Incase of AlternateSetting changes and using TEndpointBuffer::GetBuffer, iTail is always one 'transfer' behind iBilTail + //Incase of AlternateSetting changes and using TEndpointBuffer::TakeBuffer, this shuold force the user to update iTail & only then closes the endpoint buffer + if (((TInt) currentTransfer->iNext != iEndpointHdr->iBilTail) && (iEndpointHdr->iTail != iEndpointHdr->iBilTail)) + return KErrNotReady; + } + iClient->iEndpointStatus &= ~(1 << iEndpointNumber); //reset the bit corresponding to endpoint + iInState = ENotValid; + iOutState = ENotValid; + return KErrNone; + } + + + +EXPORT_C TUsbcScChunkHeader::TUsbcScChunkHeader(RChunk aChunk) + { + iChunk = aChunk; + iBuffers = (TUsbcScChunkBuffersHeader*) (aChunk.Base()+((TUsbcScChunkHdrOffs*)iChunk.Base())->iBuffers); + iAltSettings = (TUsbcScChunkAltSettingHeader*) (aChunk.Base()+((TUsbcScChunkHdrOffs*)iChunk.Base())->iAltSettings); + } + +EXPORT_C TInt TUsbcScChunkHeader::GetNumberOfEndpoints(TInt aAltSetting) + { + if ((aAltSetting<0) || (aAltSetting>=iAltSettings->iNumOfAltSettings)) + return KErrArgument; + return *((TInt*) (iAltSettings->iAltTableOffset[aAltSetting] + (TInt) iChunk.Base())); + } + + +EXPORT_C TUsbcScBufferRecord* TUsbcScChunkHeader::GetBuffer(TInt aAltSetting, TInt aEndpoint, TUsbcScHdrEndpointRecord*& aEndpointInf) + { + if ((aAltSetting<0) || (aAltSetting>=iAltSettings->iNumOfAltSettings)) + return NULL; + TInt8* iEndpoint = (TInt8*) (iAltSettings->iAltTableOffset[aAltSetting] + (TInt) iChunk.Base()); + if ((aEndpoint<=0) || (aEndpoint>*iEndpoint)) + return NULL; + aEndpointInf = (TUsbcScHdrEndpointRecord*) &(iEndpoint[aEndpoint*iAltSettings->iEpRecordSize]); + return iBuffers->Buffers(aEndpointInf->iBufferNo); + } + + +/* Debug functions */ + +EXPORT_C void TEndpointBuffer::Dump() + { + RDebug::Printf("TEndpointBuffer::Dump iBufferStart: 0x%x, iSize: 0x%x, iEndpointNumber: 0x%x, iBufferNum: %d, iInState: 0x%x iOutState: 0x%x\n", + iBufferStartAddr,iSize,iEndpointNumber,iBufferNum,iInState,iOutState); + } + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,43 @@ +// 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: +// bld.inf +// USB Client Driver +// +// + +/** + @file +*/ +#include "../appifwrapper/group/bld.inf" + +PRJ_PLATFORMS + +BASEDEFAULT + +PRJ_EXPORTS + +PRJ_MMPFILES + +#if defined(GENERIC_MARM) || defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +usbcsc +#endif +#endif + + +#endif +#endif diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/group/usbcsc.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/group/usbcsc.mmp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,32 @@ +// Copyright (c) 1998-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/usbcsc/usbcsc.mmp +// +// +#include + + +OS_LAYER_SYSTEMINCLUDE + +target usbcscshai.ldd +targettype ldd + +sourcepath ../src +source d_usbcsc.cpp + +library usbperipheralpil.lib + +uid 0 0x101F8928 +VENDORID 0x70000001 +capability all diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/ldd/perilddsc/src/d_usbcsc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/ldd/perilddsc/src/d_usbcsc.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,3663 @@ +// Copyright (c) 2000-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\usbcsc\d_usbcsc.cpp +// LDD for USB Device driver stack, using shared chunks: +// The channel object. +// +// + +/** + @file d_usbcsc.cpp + @internalTechnology +*/ + +// #include +#include +#include "platform.h" + +/*****************************************************************************\ +* DUsbcScLogDevice * +* * +* Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class * +* * +\*****************************************************************************/ + +_LIT(KUsbScLddName, "Usbcsc"); + +static const TInt KUsbRequestCallbackPriority = 2; + +/** Real entry point from the Kernel: return a new driver. + */ +DECLARE_STANDARD_LDD() + { + return new DUsbcScLogDevice; + } + +/** Create a channel on the device. + + @internalComponent +*/ +TInt DUsbcScLogDevice::Create(DLogicalChannelBase*& aChannel) + { + aChannel = new DLddUsbcScChannel; + return aChannel ? KErrNone : KErrNoMemory; + } + + +DUsbcScLogDevice::DUsbcScLogDevice() + { + iParseMask = KDeviceAllowUnit; + iUnitsMask = 0xffffffff; // Leave units decision to the Controller + iVersion = TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion); + } + + +TInt DUsbcScLogDevice::Install() + { + // Only proceed if we have the Controller underneath us + if (!DUsbClientController::UsbcControllerPointer()) + { + __KTRACE_OPT(KPANIC, Kern::Printf("LDD Install: USB Controller Not Present")); + return KErrGeneral; + } + return SetName(&KUsbScLddName); + } + + +// +// Return the USB controller capabilities. +// +void DUsbcScLogDevice::GetCaps(TDes8& aDes) const + { + TPckgBuf b; + b().version = iVersion; + Kern::InfoCopy(aDes, b); + } + +// End DUsbcScLogDevice + +/*****************************************************************************\ +* TUsbcScChunkInfo * +* * +* Where Chunk information is stored for the channel, and preseved for the * +* life of the chunk. * +* * +\*****************************************************************************/ + +void DfcChunkCleanup(TAny*); + +TUsbcScChunkInfo::TUsbcScChunkInfo(DLogicalDevice* aLdd) + : iChunk(NULL), + iCleanup((TDfcFn)&DfcChunkCleanup,this,Kern::SvMsgQue(),0), + iChunkMem(NULL), + iLdd(aLdd) + { + iPageNtz = (TInt8)__e32_find_ls1_32(Kern::RoundToPageSize(1)); + } + +TInt TUsbcScChunkInfo::CreateChunk(TInt aTotalSize) + { + // First, reserve an TUint of memory for each of pages needed to hold aTotalSize of memory. + // This will form the chunk map, so that we can look up the memory geometry. + iAllocatedSize = (aTotalSize>>iPageNtz)*sizeof(TUint); + iPhysicalMap = (TUint*) Kern::AllocZ(iAllocatedSize); + TInt r; + if (iPhysicalMap==NULL) + r = KErrNoMemory; + else + { + TChunkCreateInfo chunkInfo; + chunkInfo.iType = TChunkCreateInfo::ESharedKernelMultiple; + chunkInfo.iMaxSize = aTotalSize; + chunkInfo.iMapAttr = EMapAttrCachedMax; + chunkInfo.iOwnsMemory = EFalse; + chunkInfo.iDestroyedDfc = &iCleanup; + + TLinAddr chunkMem; + r = Kern::ChunkCreate(chunkInfo, iChunk, chunkMem, iChunkMapAttr); + iChunkMem = (TInt8*) chunkMem; + if (r==KErrNone) + iLdd->Open(); + } + + return r; +} + + +// This method requests closing the chunk. +// Note that nothing may happen immediately, as something else may have the chunk open. +void TUsbcScChunkInfo::Close() +{ + Kern::ChunkClose(iChunk); +} + + +TInt TUsbcScChunkInfo::ChunkAlloc(TInt aOffset, TInt aSize) + { + TUint pageMask = (~0)<>iPageNtz); rle>0; rle--, i++,physAddr+=pageSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("::phys offset 0x%x = 0x%x", + (aOffset>>iPageNtz)+i, (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle))); + iPhysicalMap[(aOffset>>iPageNtz)+i] = (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle); + } + } + } + else if (r==KErrNoMemory) + r = -KErrNoMemory; // Semi-expected error. + return r; + } + +/** +This method retrieves the physical address of a given offset into the Chunk, and returns +the length of contiguous physical memory from this point. + +@param aOffset the offset from the start of the chunk, to be queried. +@param aPhysical a pointer to a TPhysAddr, to be filled with the physical + address of the memory at the given offset. + +@returns the length of contiguous physical memory from the given offset. +*/ + +TInt TUsbcScChunkInfo::GetPhysical(TInt aOffset, TPhysAddr* aPhysical) + { + // Use masks, to retrieve the two components from the physical map, we created of the memory. + TUint pageMask = (~0)<>iPageNtz]; + *aPhysical=(val & pageMask)+(aOffset & ~pageMask); + return ((val & ~pageMask)<ChunkCleanup(); + } + + +void TUsbcScChunkInfo::ChunkCleanup() +{ + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::ChunkCleanup()")); + TUint physAddr; + TInt length; + TInt offset = 0; + + // The part of the field used for the physical page address. + TUint pageMask = (~0)<>2); + + while (offset < records) + { + physAddr = iPhysicalMap[offset] & pageMask; + length = iPhysicalMap[offset] & rleMask; + + if (physAddr>0) + Epoc::FreePhysicalRam(physAddr, length); + + offset += (length>0)?length:1; + } + Kern::Free(iPhysicalMap); + + DLogicalDevice* ldd = iLdd; + delete this; + ldd->Close(NULL); +} + +TInt TUsbcScChunkInfo::New(TUsbcScChunkInfo*& aChunk, TInt aSize, DLogicalDevice* aLdd) +{ + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New totalSize %d", aSize)); + + aChunk = new TUsbcScChunkInfo(aLdd); + if (aChunk==NULL) + { + return KErrNoMemory; + } + + TInt r = aChunk->CreateChunk(aSize); + if (r!=KErrNone) + { + delete aChunk; + aChunk=NULL; + return r; + } + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New Created at 0x%x", aChunk->iChunkMem )); + return KErrNone; +} + +// End TUsbcScChunkInfo + +/*****************************************************************************\ +* TUsbcScBuffer * +* * +* Represents a buffer, within a chunk. Each buffers can be used by * +* differt endpoint on differnt alt settings * +* * +\*****************************************************************************/ + + +TInt TUsbcScBuffer::Construct(TInt aDirection, DLddUsbcScChannel* aLdd, TInt aBufferOffset, TInt aBufferEndOffset, TInt aMinReadSize, TInt aMaxPacketSize, TInt aMaxReadSize) + { + TInt r; +#ifdef _DEBUG + iSequence = aBufferOffset; // Initialized at this, so that each buffer starts with a diffrent sequence number +#endif + iMinReadSize = aMinReadSize; + TInt size = (aBufferEndOffset - aBufferOffset); + TInt pageSize = Kern::RoundToPageSize(1); + if (aMaxReadSize > 0) + iMaxReadSize = aMaxReadSize; + else + iMaxReadSize = pageSize + ((size/3) & ~(pageSize -1)); + iLdd = aLdd; + iDirection = aDirection; + iMode=0; + iChunkInfo = aLdd->iChunkInfo; + iChunkAddr = (TLinAddr) (aLdd->iChunkInfo->iChunkMem); //aChunkAddr; + + TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. + + + TUint maxAlignment; // Note: This is a mask for max Alignment, + + if (aMaxPacketSize) + { // EP0 packets are not DMAed, and so dont need ialignment. + iAlignMask = ~3; + maxAlignment = 3; + } + else + maxAlignment = 1023; // We don't know what the alignment requirement will be until enumeration, so assume worse case. + + iFirstPacket = aBufferOffset + sizeof(SUsbcScBufferHeader) + headerSize; + iFirstPacket = (iFirstPacket + maxAlignment) & ~maxAlignment; + + iBufferStart = (SUsbcScBufferHeader *) (iChunkAddr+aBufferOffset); + iBufferEnd = aBufferEndOffset; + + if ((iDirection&1)==KUsbcScOut) + iHead = iFirstPacket-headerSize;//aBufferOffset + sizeof(SUsbcScBufferHeader); + else + iSent = 0; + + iStalled=0; + iMaxPacketSize=0; + + r = iStatusList.Construct((aDirection==KUsbcScIn)?KUsbcScInRequests:KUsbcScOutRequests, iLdd->iClient); + if (!r) + { + iMaxPacketSize = aMaxPacketSize; // Indicates configured if ep0, otherwise not. + } + return r; + } + + +void TUsbcScBuffer::CreateChunkBufferHeader() +{ + if ((iDirection&1)==KUsbcScOut) + { + iBufferStart->iHead= iHead; + iBufferStart->iTail= iHead; // Initially no data! + iBufferStart->iBilTail=iHead; + __KTRACE_OPT(KUSB, Kern::Printf("Realize: iHead 0x%x bufferHeader 0x%x", iHead,iBufferStart )); + + // Dont need to round here, as we will round it up on endpoint change. (configuration) + } +} + +/* +TUsbcScBuffer::StartEndpoint + +This method sets the nessesary paramenters to the buffer, for use for a particular endpoint. + +*/ +void TUsbcScBuffer::StartEndpoint(TUsbcRequestCallback* aRequestInfo, TUint aFlags) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint (0x%x) : ep %d(%d)",this,aRequestInfo->iEndpointNum, aRequestInfo->iRealEpNum)); + + iCallback=aRequestInfo; + iMaxPacketSize = iLdd->iController->EndpointPacketSize(iLdd, aRequestInfo->iRealEpNum); + iAlignMask = ~(((iMaxPacketSize+1) & 0xFFFFFFF8)-1); + iMode = aFlags; + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint : max Packets %d, mask 0x%x flags 0x%x", iMaxPacketSize, iAlignMask, iMode)); + if ((iDirection&1)==KUsbcScOut) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UsbcScOut\n")); + // Add dummy packet (doesnt have to be aligned, which avoids what if it changes issue) + // And Start next read. + iNeedsPacket=KEpIsStarting; + } + } + + + +void TUsbcScBuffer::Destroy() +{ + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::Destroy()")); + Cancel(KErrCancel); + if (iLdd->iController && ((iDirection&1)==KUsbcScOut)) + { // Me must cancel reads to LDD to, an there will be no list for the callbacks to look into. + iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); + } + iStatusList.Destroy(); +} + + + +TInt TUsbcScBuffer::StartDataRead() +{ + if (!iMaxPacketSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Not Configured")); + return KErrNone; + } + if (iStatusList.iState!=ENotRunning) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Already Stated! (%d)",iStatusList.iState)); + return KErrNone; + } + + TInt maxLength; + TInt freeSpace; + TPhysAddr physAddr; + + // get next request + TUsbcScStatusElement* nextJob = iStatusList.Next(); + if (nextJob == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("No more jobs")); + if (iMode && KUsbScCoupledRead) + return KErrEof; + iStatusList.iState=EReadingAhead; + } + else + iStatusList.iState=EInProgress; + + TInt tail = iBufferStart->iTail; + TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. + maxLength = iChunkInfo->GetPhysical(iHead + headerSize, &physAddr); //returns all the bytes available after iHead + headerSize) + + __ASSERT_DEBUG(maxLength>0,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__)); + + + if (tail>iHead) // # # # H _ _ _ T # # # # + { + __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScBuffer::StartDataRead() - tail 0x%x>head 0x%x, maxlength 0x%x", tail, iHead, maxLength)); + + freeSpace = (tail & iAlignMask) - (iHead +headerSize + (~iAlignMask+1) ); // Cant read right up to last buffer, or head/tail will cross. + + if (freeSpace iMaxReadSize) + maxLength = iMaxReadSize; + // else tail=iMinReadSize,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__)); + + TUint8* data = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.b; + // set up callback stucture + + iCallback->SetRxBufferInfo(data, physAddr, iIndexArray, iSizeArray,maxLength); + TInt r; + // Go!! + r = iLdd->iController->SetupReadBuffer(*iCallback); + if (r!=KErrNone) + { + __KTRACE_OPT(KUSB,Kern::Printf("SetupReadBuffer Error: %d, RT %d",r, iStatusList.iState)); + iStatusList.Complete(r); + } + // After this, TUsbcScEndpoint::RequestCallback is called in a DFC. + // This in turn calls either TUsbcScBuffer::CompleteRead. + return KErrNone; +} + + +void TUsbcScBuffer::CompleteRead(TBool aStartNextRead) +{ + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteRead buff=%x",this)); + + // The first packet always contains the total #of bytes + const TInt byteCount = iCallback->iPacketSize[0]; + const TInt packetCount = iCallback->iRxPackets; + iCallback->iRxPackets=0; + TUint flags = 0; + + if (iCallback->iPacketSize[packetCount - 1] < (TUint) iMaxPacketSize) + flags = KUsbcScShortPacket; + + UpdateBufferList(byteCount, flags, aStartNextRead); +} + + +// This method "submits" the current transfer, and starts off the next read. + +void TUsbcScBuffer::UpdateBufferList(TInt aByteCount,TUint aFlags, TBool aStartNextRead) + { + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst aByteCount %d, flags 0x%x iHead 0x%x", aByteCount, aFlags, iHead)); + + TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. + TLinAddr dummy; + __KTRACE_OPT(KUSB, Kern::Printf("iHead 0x%x headerSize 0x%x",iHead, headerSize)); + + // Find iNext + + TInt next = iHead + headerSize + aByteCount; // next unused byte in buffer. + TInt maxLength; + + // This may take a few loops before we settle on a value. + do + { + // round up. + next = (next + headerSize + ~iAlignMask) & iAlignMask; + maxLength = iChunkInfo->GetPhysical(next, &dummy); + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst next %x buffer end %x min-read: %x maxRun %x", next, iBufferEnd, iMinReadSize, maxLength)); + // At the end of the buffer - wrap it if needbe. + if ((TUint)(next + iMinReadSize) > iBufferEnd) + { + next = iFirstPacket; + continue; + } + // Not enough space, move onto next block. + if (maxLengthiHashId=59*(iLdd->iAlternateSetting+1)+iCallback->iRealEpNum; // Alt setting realated.... + header->iSequence=iSequence; + iSequence++; +#endif + header->iBytes=aByteCount; + header->iNext=next; + header->iAltSettingSeq=iLdd->iAsSeq; + header->iAltSetting=iLdd->iAlternateSetting; + header->iFlags=aFlags; + __KTRACE_OPT(KUSB, Kern::Printf("We set next to 0x%x", next)); + + iStatusList.iState=ENotRunning; + if (next==iBufferStart->iTail) //or (othwise is as good as full) + { + iStalled=next; + } + else + { + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst StartRead?? ")); + TInt oldHead=iHead; + iHead = next; + + if ((aStartNextRead) && (StartDataRead() == KErrOverflow)) + { // Oh crumbs, set state as slalled. + if (oldHead != iBufferStart->iBilTail) + // If user has not read everything in the buffer + // then set up a stall, so that ldd get to be woken early + { + iStalled=next; + iHead=oldHead; + } + else // otherwise if everything is read + // no choice but to return what we have + { + iBufferStart->iHead = iHead; + } + } + else + { + iBufferStart->iHead = next; + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst Compleating\n")); + } + // Complete userside + iStatusList.Complete(); + } + } + +void TUsbcScBuffer::PopStall() + { + if (iStalled==iBufferStart->iTail) + return; // Still stalled. + + if (iStalled!=-1) // If not Alt packet only stall + { + // pop off packet + iHead = iStalled; + } + iStalled=0; + // If Alt setting of the popped packet is different to now + // Add alt setting change packet. + + + if (StartDataRead() == KErrOverflow) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::PopStall Warning: Transfer was freed, but still no space!\n")); + } + + iBufferStart->iHead = iHead; + } + + + +void TUsbcScBuffer::StartDataWrite() + { + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite()")); + TUsbcScStatusElement* nextJob = iStatusList.Next(); + TBool zlpReqd; + TInt length; + TUint start; + TUint8* startAddr; + TInt maxLength; + TPhysAddr physAddr; + TInt r; + if (!iMaxPacketSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - Not Configured")); + return; + } + + if (nextJob == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - No more jobs d=%d", iDirection)); + if (iDirection==KUsbcScBiIn) // assume this is EP0, if this is true. + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() Queue Read on EP0.")); + // Start other read again. + iLdd->iBuffers[iLdd->iEP0OutBuff].StartDataRead(); + } + } + else + { + if (iStatusList.iState==ENotRunning) + iSent=0; + iStatusList.iState=EInProgress; + + start = nextJob->iStart; + startAddr = (TUint8*) (start + ((TUint) (iChunkInfo->iChunkMem))); + + length = nextJob->iLength; + zlpReqd = (nextJob->iFlags & KUsbcScWriteFlagsZlp) !=0; + // get max read length + maxLength = iChunkInfo->GetPhysical( start, &physAddr); + + if (maxLength < length) + { + // modify request. + nextJob->iStart += maxLength; + nextJob->iLength -= maxLength; + // start this request. + iStatusList.iState=EFramgementInProgress; + zlpReqd=EFalse; + length = maxLength; + } + + if (iDirection==KUsbcScBiIn) // this is for EP0 + { + iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); + iLdd->iBuffers[iLdd->iEP0OutBuff].iStatusList.iState=ENotRunning; + } + + iCallback->SetTxBufferInfo(startAddr, physAddr, length); + iCallback->iZlpReqd = zlpReqd; + r = iLdd->iController->SetupWriteBuffer(*iCallback); + if (r!=KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetupWriteBUffer Error: %d",r)); + iStatusList.Complete(r); + } + } + + } + +void TUsbcScBuffer::CompleteWrite() + { + TInt error = iCallback->iError; + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteWrite buff=%x, err=%d",this, error)); + iSent+= iCallback->iTxBytes; + + // More to send? + if (error || iStatusList.iState!=EFramgementInProgress) + { + // complete request with error (if one). + // Some data could have been transmitted, even with an error. + iStatusList.Complete(error); + } + + // Start next request, or next part of this one. + StartDataWrite(); + + } + +// Cancels the current request's callback. +// This is not to say it will cancel the actual operation, +// However it will cancel any further sections of the user perceived operation +// that are not yet started. +void TUsbcScBuffer::Cancel(TInt aErrorCode) + { + iStatusList.CancelQueued(); + if (iLdd->iController && ((iDirection&1)==KUsbcScIn)) + { + iLdd->iController->CancelWriteBuffer(iLdd, iCallback->iRealEpNum); + } + + iStatusList.Complete(aErrorCode); + } + +void TUsbcScBuffer::Ep0CancelLddRead() + { + // Stopping a read isn't as easy as one might think. + // We cancel the callback, but then check if any data was received (but not returned to us). + // If so, we must de-queue the request, and call the completion code. + + iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); + if (iCallback->iRxPackets) // received data? + { + // remove DFC (if infact sent) + iCallback->iDfc.Cancel(); + + // process the callback now, but dont start another + CompleteRead(EFalse); + } + } + +void TUsbcScBuffer::SendEp0StatusPacket(TInt aState) +{ + __KTRACE_OPT(KUSB, Kern::Printf(" TUsbcScBuffer::SendEp0StatusPacket(%d)", aState)); + + // We need to add a packet to the buffer, so we must stop the pending read, and start + // another after we have added out packet. + Ep0CancelLddRead(); + + TUint* state = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.i; + *state = aState; + UpdateBufferList(4,KUsbcScStateChange); +} + +// End TUsbcScBuffer + +/*****************************************************************************\ +* TUsbcScStatusList * +* * +* This is a list of read or write requests, containing user status * +* requests, that should later be completed. * +* * +\*****************************************************************************/ + +/** +Constructor for TUsbcScStatusList. + +@param aSize is the number of requests to allow at any one time. This value + must be a power of two, for correct operation. + +@returns KErrNoMemory if memory allocation failure, otherwise KErrNone. +*/ + +TInt TUsbcScStatusList::Construct(TInt aSize, DThread* aClient) + { + iSize=aSize; + iHead = 0; + iLength = 0; + iClient = aClient; + iElements=(TUsbcScStatusElement *) Kern::AllocZ(sizeof(TUsbcScStatusElement)*aSize); + return (iElements==NULL)?KErrNoMemory:KErrNone; + }; + + +// StatusList must be inactive before destroying. +void TUsbcScStatusList::Destroy() + { + if (iState!=ENotRunning) + Kern::Fault("TUsbcScStatusList::Destroy", __LINE__); + if (iElements) + { + Kern::Free(iElements); + iElements=NULL; + } + iClient=NULL; +} + +void TUsbcScStatusList::Pop() + { + if (iLength>0) + { + iLength--; + iHead = ((iHead+1) & (iSize-1)); + } + } + +TUsbcScStatusElement* TUsbcScStatusList::Next() + { + return (iLength==0)?NULL:&(iElements[iHead]); + } + +TInt TUsbcScStatusList ::Add(TRequestStatus* aStatus, TInt aLength, TUint aStart, TUint aFlags) + { + __KTRACE_OPT(KUSB,Kern::Printf("Adding request. iLength %d iSize %d", iLength, iSize)); + if (iLength0; elements2Complete--) + { + Kern::RequestComplete(iClient, iElements[head].iStatus, aError); + head = ((head+1) & (iSize-1)); + } + +} + + +/* This method Completes the head status request, and pops it from its list. +This version of Complete is to be used in cases where the next request is not +chained - usually because of an error. + +@Param aError - the code to complete with. + +returns KErrNotFound if there was no request to complete +*/ + + +TInt TUsbcScStatusList::Complete(TInt aError) + { + if (iState==ENotRunning) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScStatusList::Complete() - iState == ENotRunning!")); + } + else + { + iState=ENotRunning; + if (iLength==0) + return KErrNotFound; + + Kern::RequestComplete(iClient, iElements[iHead].iStatus, aError); + + iLength--; + iHead = ((iHead+1) & (iSize-1)); + } + return KErrNone; + } + + +/* This method Completes the head status request, and pops it from its list. (If found.) +This version of Complete is to be used in cases where the request is successful, and + next request after this has (if present) been chained. +*/ + +void TUsbcScStatusList::Complete() + { + if (iLength==0) + return; + __KTRACE_OPT(KUSB, Kern::Printf("Completing request. iLength %d", iLength)); + + Kern::RequestComplete(iClient, iElements[iHead].iStatus, KErrNone); + + iLength--; + iHead = ((iHead+1) & (iSize-1)); + } + +// End TUsbcScStatusList + +/*****************************************************************************\ +* TRealizeInfo * +* * +* Used by DLddUsbcScChannel::RealizeInterface to set up the chunk * +* * +\*****************************************************************************/ + +// Init +// +// This method works out the number potential maximum number of endpoints +// and the number of alt settings. With this information it allocs +// the necessary space for the given stucture to store information about +// the endpoints. +// This is intended to be called by RealizeInterface. This stucture is +// intended to be only temporary, and the space will be freed with Free() +// before RealizeInteface has finished. + +void TRealizeInfo::Init(TUsbcScAlternateSettingList* aAlternateSettingList) +{ + iAlternateSettingList = aAlternateSettingList; + iMaxEndpoints=0; + iTotalSize =0; + iTotalBuffers=0; + iAltSettings =0; + __KTRACE_OPT(KUSB, Kern::Printf("Realize: work out max endpoint")); + // Work out max endpoints and number of alternate settings. + + if (iAlternateSettingList) + { + TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead; + while (alt != NULL) + { + iAltSettings++; + if (alt->iNumberOfEndpoints>iMaxEndpoints) + iMaxEndpoints = alt->iNumberOfEndpoints; + // could work out in/out specifics, but unnecessary. + alt = alt->iNext; + }; + } + + // Alloc some temporary working space for temp endpoint metadata + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Alloc temp. Maxendpoints %d", iMaxEndpoints)); + TInt inout; + for (inout=KUsbcScIn; inoutiHead;alt!=NULL;alt = alt->iNext ) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: AlternateSetting %x", alt)); + + iBufs[KUsbcScIn].iEps =0; + iBufs[KUsbcScOut].iEps =0; + + // For alt setting, iterate eps + for (altEp=1; altEp <= alt->iNumberOfEndpoints; altEp++) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Endpoint to add: %d",altEp)); + + TUsbcScEndpoint* nextEp = alt->iEndpoint[altEp]; + + __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep Buffer Size: %d",nextEp->EndpointInfo()->iBufferSize)); + + inout = (nextEp->EndpointInfo()->iDir==UsbShai::KUsbEpDirIn)?KUsbcScIn: + (nextEp->EndpointInfo()->iDir==UsbShai::KUsbEpDirOut)?KUsbcScOut:KUsbcScUnknown; + if (inout==KUsbcScUnknown) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: KUsbcScUnknown %x",nextEp->EndpointInfo()->iDir)); + return KErrArgument; + } + + bufsd = &(iBufs[inout]); + __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep direction: %x # endpoints %d", inout, bufsd->iEps)); + + + // find and position ep, and insert. + + if (bufsd->iEps==0) // First entry. + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Add first endpoint")); + endpointOffs = altSetting*iMaxEndpoints; + bufsd->iEp[endpointOffs] = nextEp; + } + else + { + placed = EFalse; + // Move down the list, until we find the right place. + for (endpoint=bufsd->iEps-1; endpoint>-1; endpoint--) + { + endpointOffs = altSetting*iMaxEndpoints + endpoint; + if (bufsd->iEp[endpointOffs]->EndpointInfo()->iBufferSize < nextEp->EndpointInfo()->iBufferSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Shift Endpoint %d", endpoint)); + + bufsd->iEp[endpointOffs+1] = bufsd->iEp[endpointOffs]; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Insert After Endpoint %d", endpoint)); + + bufsd->iEp[endpointOffs+1] = nextEp; + placed = ETrue; + break; + } + } // end for endpoint + if (!placed) // if we didn't place it, it must be the biggest so far, so goes at the top. + bufsd->iEp[0] = nextEp; + } // endif + bufsd->iEps++; + } // for altEp + altSetting++; + } // for alt + }// if iAltsettingList + return KErrNone; + } + +// CalcBuffSizes +// +// This works out the sizes of all the buffers, and stores the result in aBufInfo +// based on the buffer information provided in the same structure. +// Realize_CopyAndSortEndpoints is used to fill the structure with the informaition +// required. + +void TRealizeInfo::CalcBuffSizes() + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Calculate Buffers")); + + TInt endpoint; + TInt inout; + TInt altSetting; + TUsbcScEndpoint* nextEp; + TInt bufferSize; + TEndpointSortBufs* bufsd; + + for (inout=KUsbcScIn; inoutiEp[altSetting* iMaxEndpoints + endpoint]; + if (nextEp!=NULL) + { + bufferSize = nextEp->EndpointInfo()->iBufferSize; + __KTRACE_OPT(KUSB, Kern::Printf("Realize: comparing size %d", bufferSize)); + if (bufferSize> bufMaxSize) + bufMaxSize = bufferSize; + } + } // for altsetting + __KTRACE_OPT(KUSB, Kern::Printf("Realize: bufMaxSize %d", bufMaxSize)); + bufsd->iSizes[endpoint] = bufMaxSize; + if (bufMaxSize>0) + { + iTotalSize += bufsd->iSizes[endpoint]; + iTotalBuffers++; + } + } // for endpoint + } // for in/out +} + +// Free +// +// Cleans up after Init() + +void TRealizeInfo::Free() + { + TInt inout; + for (inout=KUsbcScIn; inoutiChunkMem; + + chkHdr->iBuffers = sizeof(TUsbcScChunkHdrOffs); // First struct just after this one. + iChunkStuct = (TUsbcScChunkBuffersHeader*) ( (TInt) aChunkInfo->iChunkMem + chkHdr->iBuffers); + + // Store number of buffers in chunk + iChunkStuct->iRecordSize = sizeof(TUsbcScBufferRecord); + iChunkStuct->iNumOfBufs=iTotalBuffers; + + iAltSettingsTbl = (TUsbcScChunkAltSettingHeader*) &(iChunkStuct->iBufferOffset[(iTotalBuffers+2)*sizeof(TUsbcScBufferRecord)]); // 2 extra for EP0 in and out. + + chkHdr->iAltSettings = (TUint) iAltSettingsTbl - (TUint) aChunkInfo->iChunkMem; + + iAltSettingsTbl->iEpRecordSize = sizeof(TUint); + iAltSettingsTbl->iNumOfAltSettings = iAltSettings; + + + TInt tableOffset = (TUint) iAltSettingsTbl->iAltTableOffset - (TUint) aChunkInfo->iChunkMem + iAltSettings*sizeof(TInt); + __KTRACE_OPT(KUSB, Kern::Printf("Realize: table offset: 0x%x, altTble %x iChnkMem %x altSettings %x",tableOffset, iAltSettingsTbl, aChunkInfo->iChunkMem, iAltSettings )); + + __KTRACE_OPT(KUSB, Kern::Printf("Realize: populate chunk - create alt settings table")); + + // Create alt settings table. Set each element of altsettings table, to each induivatual alt setting table. + // then fill in the number of endpoints for that alt setting, in the table. + + TInt* noEpForAlt; + TInt altSetting; + TUsbcScAlternateSetting* alt; + if (iAlternateSettingList) + { + alt = iAlternateSettingList->iHead; + for (altSetting=0; altSettingiAltTableOffset[altSetting] = tableOffset; + noEpForAlt = (TInt*) &aChunkInfo->iChunkMem[tableOffset]; + + *noEpForAlt = alt->iNumberOfEndpoints; // Set NumberofEndpoints field in Altsetting table + tableOffset+= sizeof(TInt)+ alt->iNumberOfEndpoints*sizeof(TUsbcScHdrEndpointRecord); + alt = alt->iNext; + } + } + +} // end LayoutChunkHeader + + + +/*****************************************************************************\ +* DLddUsbcScChannel * +* * +* Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class * +* * +\*****************************************************************************/ + +// +// Constructor +// +DLddUsbcScChannel::DLddUsbcScChannel() + : iValidInterface(EFalse), + iAlternateSettingList(NULL), + iEndpoint(NULL), + iCompleteAllCallbackInfo(this, DLddUsbcScChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority), + iStatusChangePtr(NULL), + iStatusCallbackInfo(this, DLddUsbcScChannel::StatusChangeCallback, KUsbRequestCallbackPriority), + iEndpointStatusChangePtr(NULL), + iEndpointStatusCallbackInfo(this, DLddUsbcScChannel::EndpointStatusChangeCallback, + KUsbRequestCallbackPriority), + iOtgFeatureChangePtr(NULL), + iOtgFeatureCallbackInfo(this, DLddUsbcScChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority), + iNumberOfEndpoints(0), + iDeviceState(UsbShai::EUsbPeripheralStateUndefined), + iOwnsDeviceControl(EFalse), + iAlternateSetting(0), + iAsSeq(0), + iStatusFifo(NULL), + iUserKnowsAltSetting(ETrue), + iDeviceStatusNeeded(EFalse), + iChannelClosing(EFalse), + iRealizeCalled(EFalse), + iChunkInfo(NULL), + iNumBuffers(-1), + iBuffers(NULL), + iEp0Endpoint(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DLddUsbcScChannel()")); + iClient = &Kern::CurrentThread(); + iClient->Open(); + for (TInt i = 1; i < KUsbcMaxRequests; i++) + { + iRequestStatus[i] = NULL; + } + } + + +// +// Destructor +// + +DLddUsbcScChannel::~DLddUsbcScChannel() + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::~DLddUsbcScChannel()")); + if (iController) + { + iController->DeRegisterClient(this); + iStatusCallbackInfo.Cancel(); + iEndpointStatusCallbackInfo.Cancel(); + iOtgFeatureCallbackInfo.Cancel(); + iCompleteAllCallbackInfo.Cancel(); + DestroyAllInterfaces(); + if (iOwnsDeviceControl) + { + iController->ReleaseDeviceControl(this); + iOwnsDeviceControl = EFalse; + } + iController=NULL; + DestroyEp0(); + if (iStatusFifo!=NULL) + { + delete iStatusFifo; + } + } + __KTRACE_OPT(KUSB, Kern::Printf("Closing buffers")); + if (iBuffers) + { + TInt i; + for (i=0; i<(iNumBuffers+2); i++) + { + iBuffers[i].Destroy(); + } + Kern::Free(iBuffers); + } + + if (iRealizeCalled) + { + // Close Chunk + iChunkInfo->Close(); + // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed. + iChunkInfo=NULL; + } + __KTRACE_OPT(KUSB, Kern::Printf("about to SafeClose")); + Kern::SafeClose((DObject*&)iClient, NULL); + } + + +// +// DoCreate - Create channel +// + +TInt DLddUsbcScChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) + { + __KTRACE_OPT(KUSB, Kern::Printf("LDD DoCreateL 1 Ver = %02d %02d %02d", + aVer.iMajor, aVer.iMinor, aVer.iBuild)); + if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD, + __PLATSEC_DIAGNOSTIC_STRING("Checked by USBCSC.LDD (USB Driver)"))) + { + return KErrPermissionDenied; + } + + iController = DUsbClientController::UsbcControllerPointer(); + + if (!iController) + { + return KErrGeneral; + } + + iStatusFifo = new TUsbcDeviceStatusQueue; + if (iStatusFifo == NULL) + { + return KErrNoMemory; + } + + if (!Kern::QueryVersionSupported(TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion), aVer)) + { + return KErrNotSupported; + } + + // set up the correct DFC queue + SetDfcQ(iController->DfcQ(0)); // sets the channel's dfc queue + iCompleteAllCallbackInfo.SetDfcQ(iDfcQ); + iStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc + iEndpointStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc + iOtgFeatureCallbackInfo.SetDfcQ(iDfcQ); + iMsgQ.Receive(); //start up the message q + TInt r = iController->RegisterClientCallback(iCompleteAllCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForStatusChange(iStatusCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForEndpointStatusChange(iEndpointStatusCallbackInfo); + if (r != KErrNone) + return r; + r = iController->RegisterForOtgFeatureChange(iOtgFeatureCallbackInfo); + if (r != KErrNone) + return r; + + return r; + } +// end DoCreate. + + +// +// HandleMsg +// +// Events from userside arrive here, and delegated to either DoRequest, DoControl or DoCancel. +// + +void DLddUsbcScChannel::HandleMsg(TMessageBase* aMsg) + { + TThreadMessage& m = *(TThreadMessage*)aMsg; + TInt id = m.iValue; + __KTRACE_OPT(KUSB, Kern::Printf("HandleMsg 0x%x", id)); + + if (id == (TInt) ECloseMsg) + { + iChannelClosing = ETrue; + m.Complete(KErrNone, EFalse); + return; + } + + TInt r; + if (id < 0) + { + // DoRequest + TRequestStatus* pS = (TRequestStatus*) m.Ptr0(); + r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); + m.Complete(r, ETrue); + } + else if (id & RDevUsbcScClient::ERequestCancel) + { + // DoCancel + r = DoCancel(id, (TUint) m.Ptr0(), (TUint) m.Ptr1()); + m.Complete(r, ETrue); + } + else + { + // DoControl + r = DoControl(id, m.Ptr0(), m.Ptr1()); + m.Complete(r, ETrue); + } + } +// end HandleMsg. + + +#define BREAK_IF_NULL_ARG(a,r) if (a==NULL) { r = KErrArgument; __KTRACE_OPT(KUSB,Kern::Printf("NULL Argument")); break; } + +// +// DoRequest - Asynchronous requests +// +// Overrides pure virtual, called by HandleMsg. (Above) +// +TInt DLddUsbcScChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) + { + TInt reqNo = aReqNo & RDevUsbcScClient::KFieldIdMask; + TInt r = KErrNone; // return via request notify + TBool needsCompletion =EFalse; + + __KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo)); + + if ((reqNo>RDevUsbcScClient::ERequestReadDataNotify) && + (reqNo>RDevUsbcScClient::KFieldBuffPos)&RDevUsbcScClient::KFieldBuffMask; + __KTRACE_OPT(KUSB, Kern::Printf("ERequestWriteData")); + BREAK_IF_NULL_ARG(a2,r); + + r = DoWriteData( aStatus, buffer, (TInt) a1 /*Start*/, (TInt) a2 /* Length */, + aReqNo>>RDevUsbcScClient::KFieldFlagsPos ); // Flags + break; + } + case RDevUsbcScClient::ERequestReadDataNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestReadDataNotify")); + return DoReadDataNotify(aStatus, (TInt) a1, (TInt) a2); // a1 = aBufferNumber, a2 - aLength; + } + + case RDevUsbcScClient::ERequestAlternateDeviceStatusNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestAlternateDeviceStatusNotify")); + BREAK_IF_NULL_ARG(a1,r); + iDeviceStatusNeeded = ETrue; + iStatusChangePtr = a1; + needsCompletion = AlternateDeviceStateTestComplete(); + break; + } + case RDevUsbcScClient::ERequestReEnumerate: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate")); + // If successful, this will complete via the status notification. + r = iController->ReEnumerate(); + break; + } + case RDevUsbcScClient::ERequestEndpointStatusNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify")); + BREAK_IF_NULL_ARG(a1,r); + + iEndpointStatusChangePtr = a1; + break; + } + case RDevUsbcScClient::ERequestOtgFeaturesNotify: + { + __KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify")); + BREAK_IF_NULL_ARG(a1,r); + + iOtgFeatureChangePtr = a1; + break; + } + default: + r = KErrNotSupported; + } + + if ((needsCompletion) || (r != KErrNone)) + { + iRequestStatus[reqNo] = aStatus; + Kern::RequestComplete(iClient, iRequestStatus[reqNo], r); + } + return KErrNone; + } +// end DoRequest. + + +// +// DoReadDataNotify +// +// This method sets up the request to facilitate the userside being notifed when new data has been read. +// +TInt DLddUsbcScChannel::DoReadDataNotify(TRequestStatus* aStatus, TInt aBufferNum, TInt aLength) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify(x, %d, 0x%x)", aBufferNum, aLength)); + TInt r = KErrNone; + // check range + if ((aBufferNum<0) || (aBufferNum>=iNumBuffers)) // Indirectly checks that we are set up. + { + if (aBufferNum!=KUsbcScEndpointZero) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Number!")); + return KErrArgument; + } + else + { + aBufferNum = iEP0OutBuff; + } + } + else + { + // check direction + if (iBuffers[aBufferNum].iDirection!=KUsbcScOut) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Direction!")); + return KErrNotSupported; + } + if (!Configured()) + return KErrUsbInterfaceNotReady; + } + SUsbcScBufferHeader* scBuffer = (SUsbcScBufferHeader*) iBuffers[aBufferNum].iBufferStart; + + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify head %x tail %x", iBuffers[aBufferNum].iHead , scBuffer->iTail )); + + if (iBuffers[aBufferNum].iHead != scBuffer->iBilTail) + r = KErrCompletion; + else + if (iBuffers[aBufferNum].iStalled) + { + iBuffers[aBufferNum].PopStall(); + return KErrCompletion; + } + else + r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, 0,0); + + if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning) + { + iBuffers[aBufferNum].StartDataRead(); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!")); + } + return r; + } +// end DoReadDataNotify. + + + +// +// DoWriteData +// +// This method sets up the request to write data to USB from userside. +// +TInt DLddUsbcScChannel::DoWriteData(TRequestStatus* aStatus,TInt aBufferNum, TUint aStart, TUint aLength, TUint aFlags) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData(%d, 0x%x, 0x%x, 0x%x)", aBufferNum, aStart, aLength, aFlags)); + if (!iUserKnowsAltSetting) + return KErrEof; + // Check Buffer Number + if ((aBufferNum<0) || (aBufferNum>=iNumBuffers)) + { + if ((TUint)aBufferNum!=RDevUsbcScClient::KFieldBuffMask) // KUsbcScEndpointZero & KFieldBuffMas = KFieldBuffMas; + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData : Bad Buffer Number!")); + return KErrArgument; + } + else + { + aBufferNum = iEP0InBuff; + } + } + else + { + // check direction + if (iBuffers[aBufferNum].iDirection!=KUsbcScIn) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad endpoint Direction")); + return KErrArgument; + } + } + + TUsbcScBuffer& buf=iBuffers[aBufferNum]; + + if ((aStart< (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr)) || ((aStart+aLength)>iBuffers[aBufferNum].iBufferEnd)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad Range aStart or aLength 0x%x > 0x%x + 0x%x < 0x%x", (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr),aStart, aLength, iBuffers[aBufferNum].iBufferEnd )); + return KErrArgument; + } + + if ( (aBufferNum != iEP0InBuff) && !Configured()) + return KErrUsbInterfaceNotReady; + + if (aStart & ~buf.iAlignMask) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::DoDataWrite: address 0x%x unaligned.",aStart)); + return KErrArgument; + } + + TInt r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, aStart, aFlags); //update + + if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning) + { + iBuffers[aBufferNum].StartDataWrite(); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!")); + } + + + return r; + } +// end DoWriteData. + + +// +// Cancel an outstanding request // Cancel need reworking. +// +TInt DLddUsbcScChannel::DoCancel(TInt aReqNo, TUint aBuff, TUint aSpair) + { + TInt r = KErrNone; + TInt direction=KUsbcScOut; + + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x aBuff 0x%x", aReqNo, aBuff)); + switch (aReqNo) + { + case RDevUsbcScClient::ERequestCancel: + TInt buffer; + TInt mask; + + for (buffer=1, mask=1; bufferAbortTransfer(); + if (direction==KUsbcScIn) + aBuff=iEP0InBuff; + else + aBuff=iEP0OutBuff; + } + else if ((TInt)aBuff >= iNumBuffers) // check buff no range. + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer number")); + return KErrArgument; + } + + if ((iBuffers[aBuff].iDirection&1)!=direction) // Does direction match call type? + { + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer direction")); + return KErrArgument; + } + iBuffers[aBuff].iStatusList.CancelQueued(); + iBuffers[aBuff].Cancel(KErrCancel); + + return KErrNone; + + case RDevUsbcScClient::ERequestAlternateDeviceStatusNotifyCancel: + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo)); + iDeviceStatusNeeded = EFalse; + iStatusFifo->FlushQueue(); + if (iStatusChangePtr) + { + TInt deviceState = iController->GetDeviceStatus(); + r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState, sizeof(deviceState), iClient); + if (r != KErrNone) + PanicClientThread(r); + iStatusChangePtr = NULL; + } + break; + + case RDevUsbcScClient::ERequestReEnumerateCancel: + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo)); + break; + + case RDevUsbcScClient::ERequestEndpointStatusNotifyCancel: + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo)); + CancelNotifyEndpointStatus(); + break; + + case RDevUsbcScClient::ERequestOtgFeaturesNotifyCancel: + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo)); + CancelNotifyOtgFeatures(); + break; + + default: + __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo)); + return KErrArgument; + } + + Kern::RequestComplete(iClient,iRequestStatus[aReqNo & ~RDevUsbcScClient::ERequestCancel], KErrCancel); + return r; + } + + +void DLddUsbcScChannel::CancelNotifyEndpointStatus() + { + if (iEndpointStatusChangePtr) + { + TUint epBitmap = 0; + for (TInt i = 1; i <= iNumberOfEndpoints; i++) + { + TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber()); + TUint b; + (v == EEndpointStateStalled) ? b = 1 : b = 0; + epBitmap |= b << i; + } + TInt r=Kern::ThreadRawWrite(iClient, iEndpointStatusChangePtr, (TUint8*) &epBitmap, sizeof(epBitmap), iClient); + if (r != KErrNone) + PanicClientThread(r); + iEndpointStatusChangePtr = NULL; + } + } + +void DLddUsbcScChannel::CancelNotifyOtgFeatures() + { + if (iOtgFeatureChangePtr) + { + TUint8 features; + iController->GetCurrentOtgFeatures(features); + TInt r=Kern::ThreadRawWrite(iClient, iOtgFeatureChangePtr, (TUint8*)&features, sizeof(features), iClient); + if (r != KErrNone) + PanicClientThread(r); + iOtgFeatureChangePtr = NULL; + } + } + + + +// +// DoControl - Synchronous requests +// +// Called from HandleMsg. + +TInt DLddUsbcScChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + __KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction)); + + TInt r = KErrNone; + TInt ep, param; + TUsbcScEndpoint* pEndpoint; + TPtrC8 pZeroDesc(NULL, 0); + TEndpointDescriptorInfo epInfo; + TUsbcScIfcInfo ifcInfo; + TCSDescriptorInfo desInfo; + TUsbcEndpointResource epRes; + + switch (aFunction) + { + case RDevUsbcScClient::EControlEndpointZeroRequestError: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError")); + r = KErrNone; + if (iOwnsDeviceControl || (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured)) + { + iController->Ep0Stall(this); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcScClient::EControlGetAlternateSetting: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting")); + if (iValidInterface && iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + { + r = iController->GetInterfaceNumber(this, param); + if (r == KErrNone) + { + r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient); + if (r != KErrNone) + PanicClientThread(r); + } + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcScClient::EControlDeviceStatus: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus")); + param = iController->GetDeviceStatus(); + r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient); + if (r != KErrNone) + PanicClientThread(r); + break; + + case RDevUsbcScClient::EControlEndpointStatus: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + pEndpoint = iEndpoint[(TInt)a1]; + if (pEndpoint == NULL) + r = KErrNotSupported; + else + { + param = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber()); + r = Kern::ThreadRawWrite(iClient, a2, ¶m, sizeof(param), iClient); + if (r != KErrNone) + PanicClientThread(r); + } + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcScClient::EControlEndpointCaps: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointCaps")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + iController->EndpointCaps(this, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlDeviceCaps: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceCaps")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + iController->DeviceCaps(this, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlSendEp0StatusPacket: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket")); + iController->SendEp0StatusPacket(this); + break; + + case RDevUsbcScClient::EControlHaltEndpoint: + __KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcScClient::EControlClearHaltEndpoint: + __KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint")); + if (iValidInterface && ValidEndpoint((TInt) a1)) + { + r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); + } + else + { + if (iDeviceState != UsbShai::EUsbPeripheralStateConfigured) + r = KErrUsbDeviceNotConfigured; + else + r = KErrUsbInterfaceNotReady; + } + break; + + case RDevUsbcScClient::EControlDumpRegisters: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters")); + iController->DumpRegisters(); + break; + + case RDevUsbcScClient::EControlReleaseDeviceControl: + __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl")); + iController->ReleaseDeviceControl(this); + iOwnsDeviceControl = EFalse; + break; + + case RDevUsbcScClient::EControlEndpointZeroMaxPacketSizes: + __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes")); + r = iController->EndpointZeroMaxPacketSizes(); + break; + + case RDevUsbcScClient::EControlSetEndpointZeroMaxPacketSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize")); + r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast(a1)); + break; + + case RDevUsbcScClient::EControlGetEndpointZeroMaxPacketSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize")); + r = iController->Ep0PacketSize(); + break; + + case RDevUsbcScClient::EControlGetDeviceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetDeviceDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlSetDeviceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor")); + BREAK_IF_NULL_ARG(a1,r); + r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlGetDeviceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize")); + BREAK_IF_NULL_ARG(a1,r); + r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlGetConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlGetConfigurationDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize")); + if (a1 != NULL) + { + r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1)); + } + else + r = KErrArgument; + break; + + case RDevUsbcScClient::EControlSetConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor")); + r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlGetInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor")); + r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcScClient::EControlGetInterfaceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize")); + r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2); + break; + + case RDevUsbcScClient::EControlSetInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor")); + r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcScClient::EControlGetEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = (ep<0)?ep:iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcScClient::EControlGetEndpointDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptorSize")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetEndpointDescriptorSize(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcScClient::EControlSetEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->SetEndpointDescriptor(iClient, this, epInfo.iSetting, + ep, *(TDes8*)epInfo.iArg); + break; + + case RDevUsbcScClient::EControlGetDeviceQualifierDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceQualifierDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlSetDeviceQualifierDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor")); + BREAK_IF_NULL_ARG(a1,r); + r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlGetOtherSpeedConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtherSpeedConfigurationDescriptor")); + r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); + if (r != KErrNone) + PanicClientThread(r); + r = iController->GetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlSetOtherSpeedConfigurationDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor")); + r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); + break; + + + case RDevUsbcScClient::EControlGetCSInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor")); + r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2)); + break; + + case RDevUsbcScClient::EControlGetCSInterfaceDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize")); + r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2); + break; + + case RDevUsbcScClient::EControlGetCSEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetCSEndpointDescriptorBlock(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcScClient::EControlGetCSEndpointDescriptorSize: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptorSize")); + r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); + r = iController->GetCSEndpointDescriptorBlockSize(iClient, this, epInfo.iSetting, + ep, *(TDes8*) epInfo.iArg); + break; + + case RDevUsbcScClient::EControlSignalRemoteWakeup: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup")); + r = iController->SignalRemoteWakeup(); + break; + + case RDevUsbcScClient::EControlDeviceDisconnectFromHost: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost")); + r = iController->UsbDisconnect(); + break; + + case RDevUsbcScClient::EControlDeviceConnectToHost: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost")); + r = iController->UsbConnect(); + break; + + case RDevUsbcScClient::EControlDevicePowerUpUdc: + __KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc")); + r = iController->PowerUpUdc(); + break; + + case RDevUsbcScClient::EControlSetDeviceControl: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl")); + r = iController->SetDeviceControl(this); + if (r == KErrNone) + { + iOwnsDeviceControl = ETrue; + if (iEp0Endpoint == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl")); + r = SetupEp0(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed")); + iController->ReleaseDeviceControl(this); + iOwnsDeviceControl=EFalse; + DestroyEp0(); + } + } + } + else + r = KErrInUse; + break; + + case RDevUsbcScClient::EControlCurrentlyUsingHighSpeed: + __KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed")); + r = iController->CurrentlyUsingHighSpeed(); + break; + + case RDevUsbcScClient::EControlSetInterface: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface")); + r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo)); + if (r != KErrNone) + PanicClientThread(r); + r = SetInterface((TInt) a1, &ifcInfo); + break; + + case RDevUsbcScClient::EControlReleaseInterface: + __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface")); + if (!iRealizeCalled) + { + r = iController->ReleaseInterface(this, (TInt) a1); + if (r == KErrNone) + { + DestroyInterface((TUint) a1); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error in PIL: LDD interface won't be released.")); + } + } + else + r = KErrUsbAlreadyRealized; + break; + + case RDevUsbcScClient::EControlSetCSInterfaceDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSInterfaceDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); + if (r != KErrNone) + PanicClientThread(r); + r = iController->SetCSInterfaceDescriptorBlock(iClient, this, desInfo.iSetting, + *reinterpret_cast(desInfo.iArg), + desInfo.iSize); + break; + + case RDevUsbcScClient::EControlSetCSEndpointDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSEndpointDescriptor")); + r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); + if (r != KErrNone) + PanicClientThread(r); + ep = EpFromAlternateSetting(desInfo.iSetting, desInfo.iEndpoint); + r = iController->SetCSEndpointDescriptorBlock(iClient, this, desInfo.iSetting, ep, + *reinterpret_cast(desInfo.iArg), + desInfo.iSize); + break; + + case RDevUsbcScClient::EControlGetStringDescriptorLangId: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId")); + r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1)); + break; + + case RDevUsbcScClient::EControlSetStringDescriptorLangId: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId")); + r = iController->SetStringDescriptorLangId(reinterpret_cast(a1)); + break; + + case RDevUsbcScClient::EControlGetManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor")); + r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlSetManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor")); + r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlRemoveManufacturerStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor")); + r = iController->RemoveManufacturerStringDescriptor(); + break; + + case RDevUsbcScClient::EControlGetProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor")); + r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlSetProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor")); + r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlRemoveProductStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor")); + r = iController->RemoveProductStringDescriptor(); + break; + + case RDevUsbcScClient::EControlGetSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor")); + r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlSetSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor")); + r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlRemoveSerialNumberStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor")); + r = iController->RemoveSerialNumberStringDescriptor(); + break; + + case RDevUsbcScClient::EControlGetConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor")); + r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlSetConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor")); + r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); + break; + + case RDevUsbcScClient::EControlRemoveConfigurationStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor")); + r = iController->RemoveConfigurationStringDescriptor(); + break; + + case RDevUsbcScClient::EControlGetStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor")); + r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); + break; + + case RDevUsbcScClient::EControlSetStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor")); + r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); + break; + + case RDevUsbcScClient::EControlRemoveStringDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor")); + r = iController->RemoveStringDescriptor((TUint8) (TInt) a1); + break; + + case RDevUsbcScClient::EControlQueryEndpointResourceUse: + { + __KTRACE_OPT(KUSB, Kern::Printf("EControlQueryEndpointResourceUse")); + epRes = (TUsbcEndpointResource)((TInt) a2); + TInt realEp=-1; + r = GetRealEpForEpResource((TInt)a1, realEp); + if (r==KErrNone) + r = iController->QueryEndpointResource(this, realEp, epRes); + break; + } + case RDevUsbcScClient::EControlSetOtgDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtgDescriptor")); + r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1)); + break; + + case RDevUsbcScClient::EControlGetOtgDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgDescriptor")); + r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1)); + break; + + case RDevUsbcScClient::EControlGetOtgFeatures: + __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgFeatures")); + r = iController->GetOtgFeatures(iClient, *((TDes8*)a1)); + break; + + case RDevUsbcScClient::EControlRealizeInterface: + __KTRACE_OPT(KUSB, Kern::Printf("EControlRealizeInterface")); + r = RealizeInterface(); + break; + case RDevUsbcScClient::EControlStartNextInAlternateSetting: + __KTRACE_OPT(KUSB, Kern::Printf("EControlStartNextInAlternateSetting")); + r = StartNextInAlternateSetting(); + break; + + default: + __KTRACE_OPT(KUSB, Kern::Printf("Function code not supported")); + r = KErrNotSupported; + } + + return r; + } +// end DoControl. + + + +// +// Overriding DObject virtual +// +TInt DLddUsbcScChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::RequestUserHandle")); + // The USB client LDD is not designed for a channel to be shared between + // threads. It saves a pointer to the current thread when it is opened, and + // uses this to complete any asynchronous requests. + // It is therefore not acceptable for the handle to be duplicated and used + // by another thread: + if (aThread == iClient) + { + return KErrNone; + } + else + { + return KErrAccessDenied; + } + } + +inline TInt DLddUsbcScChannel::GetRealEpForEpResource(TInt aEndpoint, TInt& aRealEp) + { + if (iEndpoint) // if we've enumerated at least once, proceed as normal. + { + if (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0) + { + aRealEp=iEndpoint[aEndpoint]->RealEpNumber(); + return KErrNone; + } + } + else // Assume alternate setting 0. + { + if (iAlternateSettingList) // Check it has been set up. + { + TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead; + if (alt && (aEndpoint <= alt->iNumberOfEndpoints && aEndpoint >= 0)) + { + aRealEp= alt->iEndpoint[aEndpoint]->RealEpNumber(); + return KErrNone; + } + } + } + return KErrUsbDeviceNotConfigured; + } + + +TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcScEndpointInfo* aData, TInt aDataSize) + { + iType = EUsbcScEndpointInfo; + iData = (TUint8*) aData; + if (aDataSize>0) + iDataSize = aDataSize; + else + iDataSize = sizeof(TUsbcScEndpointInfo); + } + + +// +// SetInterface +// +// Called from DoControl. Sets the configuration of a given Interface. // Needs changing +// All interfaces must be configured before one can be used. +// + +TInt DLddUsbcScChannel::SetInterface(TInt aInterfaceNumber, TUsbcScIfcInfo* aInfoBuf) + { + // Copy interface description. + + if (iRealizeCalled) + return KErrUsbAlreadyRealized; + + if (!iAlternateSettingList) + { + iAlternateSettingList = new TUsbcScAlternateSettingList; + if (iAlternateSettingList==NULL) + { + return KErrNoMemory; + } + } + + // Read descriptor in + TUsbcScInterfaceInfoBuf ifc_info_buf; + TUsbcScInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData; + const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr); + + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface srcLen = %d len = %d", srcLen, ifc_info_buf.Length() )); + + if (srcLen < ifc_info_buf.Length()) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface can't copy")); + PanicClientThread(EDesOverflow); + } + + TInt r = Kern::ThreadDesRead(iClient, ifc_info_buf_ptr, ifc_info_buf, 0, KChunkShiftBy0); + if (r != KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Copy failed reason=%d", r)); + PanicClientThread(r); + } + + // The list of endpoints is within the interface info. + TUsbcScEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData; + + const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed; + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints)); + if (num_endpoints>KMaxEndpointsPerClient) + return KErrOverflow; + + + // Initialize real ep numbers list. + TInt i; + TInt real_ep_numbers[KMaxEndpointsPerClient+1]; // range 1->KMaxEndpointsPerClient (0 not used) + for (i=0; i<=KMaxEndpointsPerClient; i++) + real_ep_numbers[i] = -1; + + + // See if PIL will accept this interface + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller")); + TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(ifc_info_buf().iEndpointData); + + r = iController->SetInterface(this, + iClient, + aInterfaceNumber, + ifc_info_buf().iClass, + aInfoBuf->iString, + (TInt) ifc_info_buf().iTotalEndpointsUsed, + endpointData, + &real_ep_numbers[0], + ifc_info_buf().iFeatureWord); + + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface controller returned %d", r)); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface failed reason=%d", r)); + return r; + } + + // create alternate setting record + TUsbcScAlternateSetting* alternateSettingListRec = new TUsbcScAlternateSetting; + if (!alternateSettingListRec) + { + r = KErrNoMemory; + goto ReleaseInterface; + } + + // other endpoints + for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++) + { + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i)); + + if ((pEndpointData->iType==UsbShai::KUsbEpTypeControl) + || (pEndpointData->iDir != UsbShai::KUsbEpDirIn && pEndpointData->iDir != UsbShai::KUsbEpDirOut) + || (pEndpointData->iSize > 1024) || (pEndpointData->iSize<=0)) + { + r = KErrUsbBadEndpoint; + goto CleanUp; + } + // Check data + + TUint* bufferSize = &(pEndpointData->iBufferSize); + if (*bufferSize==0) + *bufferSize= KUsbcScDefaultBufferSize; + + TInt pageSize = Kern::RoundToPageSize(1); + // Round buffersize up to nearest pagesize. + *bufferSize = (*bufferSize+pageSize-1) & ~(pageSize-1); + + TUsbcScEndpoint* ep = new TUsbcScEndpoint(this, iController, pEndpointData, i); + alternateSettingListRec->iEndpoint[i] = ep; + if (!ep) + { + r = KErrNoMemory; + goto CleanUp; + } + if (ep->Construct() != KErrNone) + { + r = KErrNoMemory; + goto CleanUp; + } + + + __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x", + i, alternateSettingListRec, ep)); + } + + if (iAlternateSettingList->iHead) + { + iAlternateSettingList->iTail->iNext = alternateSettingListRec; + alternateSettingListRec->iPrevious = iAlternateSettingList->iTail; + iAlternateSettingList->iTail = alternateSettingListRec; + } + else + { + iAlternateSettingList->iHead = alternateSettingListRec; + iAlternateSettingList->iTail = alternateSettingListRec; + } + + alternateSettingListRec->iNext = NULL; + alternateSettingListRec->iSetting = aInterfaceNumber; + alternateSettingListRec->iNumberOfEndpoints = num_endpoints; + + // Record the 'real' endpoint number used by the PDD in both the Ep and + // the Req callback: + for (TInt i = 1; i <= num_endpoints; i++) + { + alternateSettingListRec->iEndpoint[i]->SetRealEpNumber(real_ep_numbers[i]); + } + + return KErrNone; + + CleanUp: + delete alternateSettingListRec; + //Fall Through + + ReleaseInterface: +#if _DEBUG + TInt r1 = iController->ReleaseInterface(this, aInterfaceNumber); + __KTRACE_OPT(KUSB, Kern::Printf("Release Interface controller returned %d", r1)); +#else + (void) iController->ReleaseInterface(this, aInterfaceNumber); +#endif + return r; + } +// end SetInterface + + + +#ifdef _DEBUG +void RealizeInterface_Dump(TUint* aMem) + { + TUint *mem= NULL; + __KTRACE_OPT(KUSB, mem = aMem); + if (mem!=NULL) + { + TInt j; + Kern::Printf("Final chunk header State:"); + for (j=0; j<30; j+=8) + Kern::Printf("%2x: %8x %8x %8x %8x %8x %8x %8x %8x", j, mem[j], mem[j+1], mem[j+2], mem[j+3], mem[j+4], mem[j+5], mem[j+6], mem[j+7] ); + }; + }; +#endif + + +/* +Chunk Created, filled with structure, and passed back to userside. +*/ +TInt DLddUsbcScChannel::RealizeInterface(void) +{ + if (iRealizeCalled) + return KErrUsbAlreadyRealized; + + TRealizeInfo bufInfo; + + TInt errorOrChunk = KErrNone; + TBool openedCS = EFalse; + TInt offset =0; + + // Start by creating a temporary scratchpad for endpoint calculations. + bufInfo.Init(iAlternateSettingList); + + // Fill in our scratchpad with all the required endpoints, sorting them + // in order of size required. + errorOrChunk = bufInfo.CopyAndSortEndpoints(); + if (errorOrChunk!=KErrNone) + { + goto realize_end; + } + + // We now have endpoints sorted in order of size for each altsetting. + // The very largest for each endpoint will share the first buffer, and all of + // the second largest ends points will share the second buffer, and so on. + // Find the highest buffer size for each row, to determine the buffer size, + // and keep a total of total space needed. + bufInfo.CalcBuffSizes(); + + // We now have the max sizes wanted for each endpoint buffer. + // we also have to total size for all endpoints. + // and finally we have the total number of buffers. + + // Add on size for header, then add on size for guard pages. + bufInfo.iTotalSize+= KHeaderSize + bufInfo.iTotalBuffers * KGuardSize; + + // Create shared Chunk . . . . . . . . . . + if (iChunkInfo==NULL) + { + NKern::ThreadEnterCS(); + openedCS = ETrue; + errorOrChunk = TUsbcScChunkInfo::New(iChunkInfo, bufInfo.iTotalSize, (DLogicalDevice*) iDevice); + if (errorOrChunk!=KErrNone) + { + goto realize_end; + } + } + else + { + // As of writing, the was no way for iChunk to be anything other then NULL. + // You cannot 'unrealise' and iChunk cannot be set any other way. + Kern::Fault("DLddUsbcScChannel::RealizeInterface", __LINE__); + } + + // Populate the shared chunk . . . . . . . + + + // First create chunk header. + errorOrChunk = iChunkInfo->ChunkAlloc(offset, KHeaderSize); + if (errorOrChunk!=KErrNone) + { + if (errorOrChunk==-KErrNoMemory) + errorOrChunk=KErrNoMemory; + goto realize_end; + } + + + offset+=KHeaderSize + KGuardSize; // Also any more for EP0? + + // Next, lay out the geometry of the chunk header. + + bufInfo.LayoutChunkHeader(iChunkInfo); + + + { // Scope ep0Size + TInt ep0Size=0; + + // Create K-side buffer table + if (!iBuffers) + iBuffers = (TUsbcScBuffer *) Kern::AllocZ(sizeof(TUsbcScBuffer) * (bufInfo.iTotalBuffers+2)); // +2 is for ep0. + if (!iBuffers) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Error: Alloc iBufers failed!")); + errorOrChunk = KErrNoMemory; + goto realize_end; + } + + + errorOrChunk = SetupEp0(); + if (errorOrChunk) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: SetupEp0 . ERROR %d",errorOrChunk)); + goto realize_end; + } + + ep0Size = iEp0Endpoint->EndpointInfo()->iSize; + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0. max packet size %d", ep0Size)); + + // Create EP0 buffers + iEP0OutBuff=bufInfo.iTotalBuffers; + errorOrChunk = iBuffers[iEP0OutBuff].Construct(KUsbcScBiOut, this, KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd, ep0Size, ep0Size, ep0Size); + if (errorOrChunk) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 Out. ERROR %d",errorOrChunk)); + goto realize_end; + } + + iBuffers[iEP0OutBuff].CreateChunkBufferHeader(); + iBuffers[iEP0OutBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo; + ((TUsbcScBufferRecord*) &( + bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0OutBuff*sizeof(TUsbcScBufferRecord)] + )) ->Set(KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd); + + + iEP0InBuff=bufInfo.iTotalBuffers+1; + errorOrChunk = iBuffers[iEP0InBuff].Construct( KUsbcScBiIn , this, KUsbScEP0InBufPos , KUsbScEP0InBufEnd , ep0Size, ep0Size, ep0Size); + if (errorOrChunk) + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 In. ERROR %d",errorOrChunk)); + goto realize_end; + } + + iBuffers[iEP0InBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo; + + ((TUsbcScBufferRecord*) &( + bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0InBuff*sizeof(TUsbcScBufferRecord)] + ))->Set(KUsbScEP0InBufPos, KUsbScEP0InBufEnd); + + + } // end ep0Size scope + + // Create resources and tables. . . . . . + __KTRACE_OPT(KUSB, Kern::Printf("Realize: Create resources tables")); + + { // scope of bufNum + // For each EP buffer + TInt buffNum=0; + TInt buffMinSize; + TInt endpointNumber; + TUsbcScEndpoint* endpointRecord; + TInt endpoint; + TInt inout; + TEndpointSortBufs* bufsd; + TUsbcScHdrEndpointRecord* epRecord; + for (endpoint=0; endpointiEp[altSetting*bufInfo.iMaxEndpoints + endpoint]; + if (endpointRecord) + { + endpointNumber = endpointRecord->EpNumber(); + endpointRecord->SetBuffer(&iBuffers[buffNum]); + + epRecord = (TUsbcScHdrEndpointRecord*) &iChunkInfo->iChunkMem[ + (bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting]) // i.e. Just after altSettingsTbl + +sizeof(TInt) // after number of endpoints field + +(endpointNumber-1)*sizeof(TUsbcScHdrEndpointRecord) + ]; + epRecord->iBufferNo = (TUint8) buffNum; + + TInt epType=(endpointRecord->EndpointInfo()->iType); + epType= (epType& UsbShai::KUsbEpTypeControl)?KUsbScHdrEpTypeControl: + (epType& UsbShai::KUsbEpTypeIsochronous)?KUsbScHdrEpTypeIsochronous: + (epType& UsbShai::KUsbEpTypeBulk)?KUsbScHdrEpTypeBulk: + (epType& UsbShai::KUsbEpTypeInterrupt)?KUsbScHdrEpTypeInterrupt:KUsbScHdrEpTypeUnknown; + + epRecord->iType = (inout+1) | (epType<<2); + + if (endpointRecord->EndpointInfo()->iReadSize) + maxReadSize = (maxReadSize <= endpointRecord->EndpointInfo()->iReadSize) ? maxReadSize : endpointRecord->EndpointInfo()->iReadSize; + + __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum %d in altSetting %d, alt table @ %d", + endpointNumber, altSetting,bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting])); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum NA in altSetting %d", altSetting)); + } + + } // end for + + + // Alloc memory for buffer. + TInt grabSize = needed; + // Generally, a buffer fragmented into smaller memory regions will reduce the efficiency + // of reading or writing data, and so avoiding the allocation of very small sections + // is advantageous. + // However, if only a small amount is being allocated to start with, it is likely + // smaller amounts of data are to be sent (reducing this advantage), and 1 memory page + // is a much bigger proportion of the buffer, and so more worth allocating individually. + + TInt minimumGrab; + if (needed= minimumGrab) + { + TInt r; + r = iChunkInfo->ChunkAlloc(offset, grabSize); + if (r==KErrNone) + { + offset+=grabSize; + needed-=grabSize; + } + else + { + if (r==-KErrNoMemory) + { + grabSize>>=1; + } + if ((grabSizeiBufferOffset[(buffNum+2)*sizeof(TUsbcScBufferRecord)] + ))->Set(bufStart, offset); + + + // inc pointers for next buffer + buffNum++; + offset+=KGuardSize; + } // end if needed + + } // end for inout + } // end for each buffer + } // scope of bufNum + +#ifdef _DEBUG + RealizeInterface_Dump((TUint*) iChunkInfo->iChunkMem); // Debug only tracing +#endif + +realize_end: + __KTRACE_OPT(KUSB, Kern::Printf("Realize: cleanup. Err=%d", errorOrChunk)); + // Here we clean up after either success, or after bailing out early. + + bufInfo.Free(); + + if (iChunkInfo) + { + if (errorOrChunk==KErrNone) + { + // Everything is looking good - create RChunk for Userside. + errorOrChunk = Kern::MakeHandleAndOpen(iClient, iChunkInfo->iChunk); + iRealizeCalled = (errorOrChunk>=0); + } // endif errorOrChunk + + if (errorOrChunk<0) // If error, destroy the chunk. + { + iChunkInfo->Close(); + // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed. + iChunkInfo=NULL; + + // Destroy iBuffers + if (iBuffers) + { + TInt i; + for (i=0; i<(iNumBuffers+2); i++) + { + iBuffers[i].iStatusList.Destroy(); + } + Kern::Free(iBuffers); + iBuffers=NULL; + } + + } + else + { + iNumBuffers = bufInfo.iTotalBuffers; + iValidInterface = ETrue; // Let the games commence! + } + + } // endif iChunkInfo + if (openedCS) + NKern::ThreadLeaveCS(); + + __KTRACE_OPT(KUSB, Kern::Printf("Realize: returning %x (%d)", errorOrChunk, errorOrChunk)); + return errorOrChunk; +} // End RealizeInterface + + +// +// DestroyAllInterfaces +// + +void DLddUsbcScChannel::DestroyAllInterfaces() + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces")); + // Removes all interfaces + if (iAlternateSettingList) + { + if (iAlternateSettingList->iHead != NULL) + { + TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail; + while (alternateSettingListRec) + { + iAlternateSettingList->iTail = alternateSettingListRec->iPrevious; + // If this contains NULL now that is only possible if the record to be deleted was at the head + __KTRACE_OPT(KUSB, Kern::Printf("Release interface %d \n", alternateSettingListRec->iSetting)); + iController->ReleaseInterface(this, alternateSettingListRec->iSetting); + delete alternateSettingListRec; + if (iAlternateSettingList->iTail == NULL) //No more interfaces left + break; + else + { + iAlternateSettingList->iTail->iNext = NULL; + alternateSettingListRec = iAlternateSettingList->iTail; + } + } + } + delete iAlternateSettingList; + } + + iNumberOfEndpoints = 0; + iAlternateSettingList = NULL; + iValidInterface = EFalse; + + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces done")); + } + + + + + +// +// DestroyInterface +// + +void DLddUsbcScChannel::DestroyInterface(TUint aInterfaceNumber) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface \n")); + + if (iAlternateSetting == aInterfaceNumber) + { + ResetInterface(KErrUsbInterfaceNotReady); + iValidInterface = EFalse; + iNumberOfEndpoints = 0; + } + if (iAlternateSettingList) + { + TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail; + TUsbcScAlternateSetting* alternateSettingListRecFound = NULL; + while (alternateSettingListRec) + { + if (alternateSettingListRec->iSetting == aInterfaceNumber) + { + alternateSettingListRecFound = alternateSettingListRec; + if (alternateSettingListRec->iPrevious == NULL) //Interface is at HEAD OF List, Should only be if Interface is also at Tail of list + { + iAlternateSettingList->iHead = alternateSettingListRec->iNext; // Should be NULL + if (alternateSettingListRec->iNext) + iAlternateSettingList->iHead->iPrevious = NULL; + } + else if (alternateSettingListRec->iNext == NULL) //Interface is at TAIL OF List + { + iAlternateSettingList->iTail = alternateSettingListRecFound->iPrevious; + iAlternateSettingList->iTail->iNext = NULL; + } + else //Somewhere in the middle (would not expect this in normal operation, but here for completeness) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface Middle interface!\n")); + alternateSettingListRec->iPrevious->iNext = alternateSettingListRec->iNext; + alternateSettingListRec->iNext->iPrevious = alternateSettingListRec->iPrevious; + } + + delete alternateSettingListRecFound; + break; + } + alternateSettingListRec = alternateSettingListRec->iPrevious; + } + } + } + +// +// SetupEp0 +// + +TInt DLddUsbcScChannel::SetupEp0() + { + __ASSERT_ALWAYS(iEp0Endpoint==NULL, Kern::Fault("DLddUsbcScChannel::SetupEp0", __LINE__)); + + TUsbcScEndpointInfo ep0Info = TUsbcScEndpointInfo(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirBidirect); + ep0Info.iSize = iController->Ep0PacketSize(); + + TUsbcScEndpoint* ep0 = new TUsbcScEndpoint(this, iController, &ep0Info, 0); + if (ep0 == NULL) + { + return KErrNoMemory; + } + + TInt r = ep0->Construct(); + if (r != KErrNone) + { + delete ep0; + return KErrNoMemory; + } + + ep0->SetRealEpNumber(0); + ep0->SetBuffer(NULL); // Cannot find it this way. + + iEp0Endpoint = ep0; + return KErrNone; + } + +// +// DestroyEp0 +// + +void DLddUsbcScChannel::DestroyEp0() + { + __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DestroyEp0")); + delete iEp0Endpoint; + iEp0Endpoint = NULL; + } + + +void DLddUsbcScChannel::RequestCallbackEp0(TAny* aDLddUsbcScChannel) + { + DLddUsbcScChannel* channel = (DLddUsbcScChannel*) aDLddUsbcScChannel; + + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0")); + + if (channel->ChannelClosing()) + { + __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!")); + return; + } + + switch (channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir) + { + case UsbShai::EControllerWrite: + channel->iBuffers[channel->iEP0InBuff].CompleteWrite(); + return; + case UsbShai::EControllerRead: + channel->iBuffers[channel->iEP0OutBuff].CompleteRead(); + return; + default: + Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0 - Unexpected completion direction %d",channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir); + Kern::Fault("DLddUsbcScChannel::RequestCallbackEp0", __LINE__); + } + } + + + + + + +// +// EndpointStatusChangeCallback +// + +void DLddUsbcScChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcScChannel) + { + __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback")); + DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; + if (dUsbc->iChannelClosing) + return; + TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State(); + const TInt reqNo = (TInt) RDevUsbcScClient::ERequestEndpointStatusNotify; + if (dUsbc->iRequestStatus[reqNo]) + { + __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status")); + DThread* client = dUsbc->iClient; + // set client descriptor length to zero + TInt r = Kern::ThreadRawWrite(client, dUsbc->iEndpointStatusChangePtr, &endpointState, + sizeof(TUint), client); + if (r != KErrNone) + dUsbc->PanicClientThread(r); + Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r); + dUsbc->iEndpointStatusChangePtr = NULL; + } + } + + +// +// StatusChangeCallback +// + +void DLddUsbcScChannel::StatusChangeCallback(TAny* aDLddUsbcScChannel) + { + DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; + if (dUsbc->iChannelClosing) + return; + + TUsbcDeviceState deviceState; + TInt i; + for (i = 0; + (i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != UsbShai::EUsbPeripheralNoState); + ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState)); + if (deviceState & KUsbAlternateSetting) + { + dUsbc->ProcessAlternateSetting(deviceState); + } + else + { + dUsbc->ProcessDeviceState(deviceState); + // Send Status to EP0 buffer. + // Before the client calls RDevUsbcScClient::FinalizeInterface(), + // this function might be called. + // So we add a guard for dUsbc->iBuffers + if( dUsbc->iBuffers ) + { + dUsbc->iBuffers[dUsbc->iEP0OutBuff].SendEp0StatusPacket(deviceState); + } + } + + // Only queue if userside is interested + if (dUsbc->iDeviceStatusNeeded) + { + dUsbc->iStatusFifo->AddStatusToQueue(deviceState); + const TInt reqNo = (TInt) RDevUsbcScClient::ERequestAlternateDeviceStatusNotify; + if (dUsbc->AlternateDeviceStateTestComplete()) + Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], KErrNone); + } + } + // We don't want to be interrupted in the middle of this: + const TInt irqs = NKern::DisableInterrupts(2); + dUsbc->iStatusCallbackInfo.ResetState(); + NKern::RestoreInterrupts(irqs); + } + + +void DLddUsbcScChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcScChannel) + { + __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback")); + DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; + if (dUsbc->iChannelClosing) + return; + + TUint8 features; + // No return value check. Assume OTG always supported here + dUsbc->iController->GetCurrentOtgFeatures(features); + + const TInt reqNo = (TInt) RDevUsbcScClient::ERequestOtgFeaturesNotify; + if (dUsbc->iRequestStatus[reqNo]) + { + __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status")); + TInt r = Kern::ThreadRawWrite(dUsbc->iClient, dUsbc->iOtgFeatureChangePtr, + &features, sizeof(TUint8), dUsbc->iClient); + if (r != KErrNone) + dUsbc->PanicClientThread(r); + Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r); + dUsbc->iOtgFeatureChangePtr = NULL; + } + } + + +// +// SelectAlternateSetting +// + +TInt DLddUsbcScChannel::SelectAlternateSetting(TUint aAlternateSetting) + { + TUsbcScEndpoint* ep; + + // First, find the alt setting record, which corresponds to the alt setting number. + TUsbcScAlternateSetting* alternateSettingListRec; + if(iAlternateSettingList) + { + for (alternateSettingListRec = iAlternateSettingList->iHead; alternateSettingListRec; alternateSettingListRec = alternateSettingListRec->iNext) + if (alternateSettingListRec->iSetting == aAlternateSetting) + { + // Record has been located. + + // Update current ep setting vars + iEndpoint = alternateSettingListRec->iEndpoint; + iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints; + + + + // Reset buffers for new ep set + for (TInt i = 1; i <= KMaxEndpointsPerClient; i++) + { + ep = alternateSettingListRec->iEndpoint[i]; + if (ep!=NULL) + ep->StartBuffer(); // Buffer::StartEndpoint(...) sets the necessary parameters to the buffer, for use for a perticular endpoint. + } + + return KErrNone; + } + } + return KErrGeneral; + } + +/* The user calls this to move into the next alternate setting. After this call, it is assumed the user wants to +Transmit using endpoints belonging to this alternate Setting. Writes to the IN endpoints will be allowed until +the host changed the alternate setting again +Returns a 32 int with the top 16 bits represents the sequance, and the botten, the alternatre setting no. +*/ +TInt32 DLddUsbcScChannel::StartNextInAlternateSetting() + { + iUserKnowsAltSetting = ETrue; + return iAsSeq<<16 | iAlternateSetting; + } + + +// +// EpFromAlternateSetting +// + +TInt DLddUsbcScChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint) + { + TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iHead; + while (alternateSettingListRec) + { + if (alternateSettingListRec->iSetting == aAlternateSetting) + { + if ((aEndpoint <= alternateSettingListRec->iNumberOfEndpoints) && + (aEndpoint > 0)) + { + return alternateSettingListRec->iEndpoint[aEndpoint]->RealEpNumber(); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aEndpoint %d wrong for aAlternateSetting %d", + aEndpoint, aAlternateSetting)); + return KErrNotFound; + } + } + alternateSettingListRec = alternateSettingListRec->iNext; + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no aAlternateSetting %d found", aAlternateSetting)); + return KErrNotFound; + } + +// +// ProcessAlternateSetting +// + +TInt DLddUsbcScChannel::ProcessAlternateSetting(TUint aAlternateSetting) + { + + TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting); + __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x selecting alternate setting 0x%08x", aAlternateSetting, newSetting)); + iUserKnowsAltSetting=EFalse; + iAlternateSetting = newSetting; + iAsSeq++; + + ResetInterface(KErrUsbInterfaceChange); // kill any outstanding IN transfers + + TInt r = SelectAlternateSetting(newSetting); + if (r != KErrNone) + return r; + + + StartEpReads(); + return KErrNone; + } + + +// +// ProcessDeviceState +// +// Called from StatusChangeCallback. + +TInt DLddUsbcScChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState)); + if (iDeviceState == aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No state change => nothing to be done.")); + return KErrNone; + } + if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Coming out of Suspend: old state = %d", iOldDeviceState)); + iDeviceState = iOldDeviceState; + if (iDeviceState == aDeviceState) + { + __KTRACE_OPT(KUSB, Kern::Printf(" New state same as before Suspend => nothing to be done.")); + return KErrNone; + } + } + TBool renumerateState = (aDeviceState == UsbShai::EUsbPeripheralStateConfigured); + TBool deconfigured = EFalse; + TInt cancellationCode = KErrNone; + if (aDeviceState == UsbShai::EUsbPeripheralStateSuspended) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Suspending...")); + iOldDeviceState = iDeviceState; + // Put PSL into low power mode here + } + else + { + deconfigured = (iDeviceState == UsbShai::EUsbPeripheralStateConfigured && + aDeviceState != UsbShai::EUsbPeripheralStateConfigured); + if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + { + if (aDeviceState == UsbShai::EUsbPeripheralStateUndefined) + cancellationCode = KErrUsbCableDetached; + else if (aDeviceState == UsbShai::EUsbPeripheralStateAddress) + cancellationCode = KErrUsbDeviceNotConfigured; + else if (aDeviceState == UsbShai::EUsbPeripheralStateDefault) + cancellationCode = KErrUsbDeviceBusReset; + else + cancellationCode = KErrUsbDeviceNotConfigured; + } + } + iDeviceState = aDeviceState; + if (iValidInterface || iOwnsDeviceControl) + { + + // This LDD may not own an interface. It could be some manager reenumerating + // after its subordinate LDDs have setup their interfaces. + if (deconfigured) + { + DeConfigure(cancellationCode); + } + else if (renumerateState) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: Reumerated!")); + // Select main interface & latch in new endpoint set + SelectAlternateSetting(0); + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: StartReads!")); + StartEpReads(); + } + } + + const TInt reqNo = (TInt) RDevUsbcScClient::ERequestReEnumerate; + if (renumerateState && iRequestStatus[reqNo]) + { + // This lot must be done if we are reenumerated + Kern::RequestComplete(iClient, iRequestStatus[reqNo], KErrNone); + } + + return KErrNone; + } + + +TBool DLddUsbcScChannel::AlternateDeviceStateTestComplete() + { + TBool completeNow = EFalse; + const TInt reqNo = (TInt) RDevUsbcScClient::ERequestAlternateDeviceStatusNotify; + if (iRequestStatus[reqNo]) + { + // User req is outstanding + TUint32 deviceState; + if (iStatusFifo->GetDeviceQueuedStatus(deviceState) == KErrNone) + { + // Device state waiting to be sent userside + completeNow = ETrue; + __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallback Notify status")); + // set client descriptor length to zero + TInt r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState, + sizeof(TUint32), iClient); + if (r != KErrNone) + PanicClientThread(r); + iStatusChangePtr = NULL; + } + } + return completeNow; + } + + +void DLddUsbcScChannel::DeConfigure(TInt aErrorCode) + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DeConfigure()")); + // Called after deconfiguration. Cancels transfers on all endpoints. + ResetInterface(aErrorCode); + // Cancel the endpoint status notify request if it is outstanding. + const TInt KEpNotReq = RDevUsbcScClient::ERequestEndpointStatusNotify; + if (iRequestStatus[KEpNotReq]) + { + CancelNotifyEndpointStatus(); + Kern::RequestComplete(iClient, iRequestStatus[KEpNotReq], aErrorCode); + } + // We have to reset the alternate setting number when the config goes away. + SelectAlternateSetting(0); + iAlternateSetting = 0; + } + + +void DLddUsbcScChannel::StartEpReads() + { + // Queued after enumeration. Starts reads on all endpoints. + // The endpoint itself decides if it can do a read + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 1")); + + TInt i; + TInt8 needsPacket; + + for (i=0; iAbortTransfer(); + + // All OUT endpoints need a packet sent, to indicate the termination of the current ep 'pipe'. + // This will complete any current read, or will be read later. + // All IN endpoints must be simply cancelled, including anything queued. + // Ep0 operates outside alt settings, and so we don't cancel anything. + + buffer=iEndpoint[i]->GetBuffer(); + if (buffer->iDirection==KUsbcScIn) + { + buffer->iStatusList.Complete(KErrCancel); //aErrorCode + buffer->iStatusList.CancelQueued(); //aErrorCode + } + else + buffer->iNeedsPacket=TUsbcScBuffer::KEpIsEnding; // We will send a packet on re-start, which doubles as a 'cancel' + // for the old alt setting. + } + } + + + +void DLddUsbcScChannel::EmergencyCompleteDfc(TAny* aDLddUsbcScChannel) + { + ((DLddUsbcScChannel*) aDLddUsbcScChannel)->DoEmergencyComplete(); + } + +TInt DLddUsbcScChannel::DoEmergencyComplete() + { + __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DoEmergencyComplete")); + // cancel any pending DFCs + // complete all client requests + + TUsbcScBuffer* buffer; + TInt i; + // Complete EP0 request + + TInt direction=iEp0Endpoint->iRequestCallbackInfo->iTransferDir; + if (direction==UsbShai::EControllerWrite) + { + iBuffers[iEP0InBuff].iStatusList.CancelQueued(); + iBuffers[iEP0InBuff].iStatusList.Complete(KErrDisconnected); + } + else if (direction==UsbShai::EControllerRead) + { + iBuffers[iEP0OutBuff].iStatusList.CancelQueued(); + iBuffers[iEP0OutBuff].iStatusList.Complete(KErrDisconnected); + } + + // Complete other Eps request + for (i = 1; i <= iNumberOfEndpoints; i++) + { + __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i)); + buffer=iEndpoint[i]->GetBuffer(); + buffer->iStatusList.CancelQueued(); + buffer->iStatusList.Complete(KErrDisconnected); + } + + // Complete remaining requests + + for (TInt i = 0; i < KUsbcMaxRequests; i++) + { + if (iRequestStatus[i]) + { + __KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i])); + Kern::RequestComplete(iClient, iRequestStatus[i], KErrDisconnected); + } + } + iStatusCallbackInfo.Cancel(); + iEndpointStatusCallbackInfo.Cancel(); + iOtgFeatureCallbackInfo.Cancel(); + + return KErrNone; + } + + +void DLddUsbcScChannel::PanicClientThread(TInt aReason) + { + Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat); + } + +// End DLddUsbcScChannel + +/*****************************************************************************\ +* TUsbcScEndpoint * +* * +* * +* * +\*****************************************************************************/ + + +// Constructor +TUsbcScEndpoint::TUsbcScEndpoint(DLddUsbcScChannel* aLDD, DUsbClientController* aController, + const TUsbcScEndpointInfo* aEndpointInfo, TInt aEndpointNum + ) + : iRequestCallbackInfo(NULL), + iController(aController), + iEndpointInfo(*aEndpointInfo), + iClientReadPending(EFalse), + iClientWritePending(EFalse), + iEndpointNumber(aEndpointNum), + iRealEpNumber(-1), + iLdd(aLDD), + iError(KErrNone), + iBytesTransferred(0), + iBuffer(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint")); + } + + +TInt TUsbcScEndpoint::Construct() + { + __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint iEndpointNumber %d\n",iEndpointNumber)); + + iRequestCallbackInfo = new TUsbcRequestCallback(iLdd, + iEndpointNumber, + (iEndpointNumber==0)?DLddUsbcScChannel::RequestCallbackEp0:TUsbcScEndpoint::RequestCallback, + (iEndpointNumber==0)? (TAny*) iLdd: (TAny*) this, + iLdd->iDfcQ, + KUsbRequestCallbackPriority); + + return (iRequestCallbackInfo == NULL)?KErrNoMemory:KErrNone; + } + + +TUsbcScEndpoint::~TUsbcScEndpoint() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::~TUsbcScEndpoint(%d)", iEndpointNumber)); + AbortTransfer(); + delete iRequestCallbackInfo; + } + +// This is called by the PIL, on return from a read or write. +// Inturn it calls either the read or write function for that buffer. + +void TUsbcScEndpoint::RequestCallback(TAny* aTUsbcScEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::RequestCallback")); + + if (((TUsbcScEndpoint*)aTUsbcScEndpoint)->iLdd->ChannelClosing()) + { + __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!")); + return; + } + + switch (((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir) + { + case UsbShai::EControllerWrite: + ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteWrite(); + return; + case UsbShai::EControllerRead: + ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteRead(); + return; + default: + Kern::Printf("TUsbcScEndpoint::RequestCallback - Unexpected compleation direction %d",((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir); + Kern::Fault("TUsbcScEndpoint::RequestCallback", __LINE__); + } + } + + +/* + +This is used to tidy up cancel calls into the PIL, regardless of them being reads or writes + +*/ + +void TUsbcScEndpoint::AbortTransfer() + { + if (!iLdd->iRealizeCalled) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d - N.R.",iEndpointNumber, iRealEpNumber)); + return; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d",iEndpointNumber, iRealEpNumber)); + } + + + if (iBuffer && (iBuffer->iStatusList.iState) || (!iRealEpNumber)) + { + if (iRequestCallbackInfo->iTransferDir==UsbShai::EControllerWrite) + iController->CancelWriteBuffer(iLdd, iRealEpNumber); + else if (iRequestCallbackInfo->iTransferDir==UsbShai::EControllerRead) + iController->CancelReadBuffer(iLdd, iRealEpNumber); + else + { + if (iEndpointNumber!=0) // endpoint zero starts off not sent in any direction, then keeps changing. + { + __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: Invalid Direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber)); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf("\nTUsbcScEndpoint::AbortTransfer Can't stop direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber)); + } + } + } + else if (!iBuffer) + { + __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iBuffer is NULL on (%d,%d)\n",iEndpointNumber, iRealEpNumber)); + return; + } + + if (iRequestCallbackInfo) + iRequestCallbackInfo->iDfc.Cancel(); + else + { + __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iRequestCallbackInfo is NULL\n")); + } + + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint Done.")); + } + +// End TUsbcScEndpoint + + +/*****************************************************************************\ +* TUsbcScAlternateSettingList * +* * +* * +* * +\*****************************************************************************/ + + +TUsbcScAlternateSetting::TUsbcScAlternateSetting() + : iNext(NULL), + iPrevious(NULL), + iNumberOfEndpoints(0), + iSetting(0) + { + for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) + { + iEndpoint[i] = NULL; + } + } + + +TUsbcScAlternateSetting::~TUsbcScAlternateSetting() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScAlternateSetting::~TUsbcScAlternateSetting()")); + for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) + { + delete iEndpoint[i]; + } + } + +// End TUsbcScAlternateSettingList + + + +TUsbcScAlternateSettingList::TUsbcScAlternateSettingList() + : iHead(NULL), + iTail(NULL) + { + } + +TUsbcScAlternateSettingList::~TUsbcScAlternateSettingList() + { + } + + + +/*****************************************************************************\ +* TUsbcDeviceStatusQueue * +* * +* * +* * +\*****************************************************************************/ + + +TUsbcDeviceStatusQueue::TUsbcDeviceStatusQueue() + { + FlushQueue(); + } + + +void TUsbcDeviceStatusQueue::FlushQueue() + { + for (TInt i = 0; i < KUsbDeviceStatusQueueDepth; i++) + { + iDeviceStatusQueue[i] = KUsbDeviceStatusNull; + } + iStatusQueueHead = 0; + } + + +void TUsbcDeviceStatusQueue::AddStatusToQueue(TUint32 aDeviceStatus) + { + // Only add a new status if it is not a duplicate of the one at the head of the queue + if (!(iStatusQueueHead != 0 && + iDeviceStatusQueue[iStatusQueueHead - 1] == aDeviceStatus)) + { + if (iStatusQueueHead == KUsbDeviceStatusQueueDepth) + { + // Discard item at tail of queue + TUint32 status; + GetDeviceQueuedStatus(status); + } + iDeviceStatusQueue[iStatusQueueHead] = aDeviceStatus; + iStatusQueueHead++; + } + } + + +TInt TUsbcDeviceStatusQueue::GetDeviceQueuedStatus(TUint32& aDeviceStatus) + { + TInt r = KErrNone; + if (iStatusQueueHead <= 0) + { + r = KErrGeneral; + aDeviceStatus = KUsbDeviceStatusNull; + } + else + { + aDeviceStatus = iDeviceStatusQueue[0]; + for(TInt i = 1; i < KUsbDeviceStatusQueueDepth; i++) + { + TUint32 s = iDeviceStatusQueue[i]; + iDeviceStatusQueue[i - 1] = s; + } + iStatusQueueHead--; + iDeviceStatusQueue[KUsbDeviceStatusQueueDepth - 1] = KUsbDeviceStatusNull; + } + return r; + } + +// End TUsbcDeviceStatusQueue + +//--- + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/eabi/usbperipheralpilu.def --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/eabi/usbperipheralpilu.def Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,95 @@ +EXPORTS + _ZN20DUsbClientController10PowerUpUdcEv @ 1 NONAME + _ZN20DUsbClientController10UsbConnectEv @ 2 NONAME + _ZN20DUsbClientController11ReEnumerateEv @ 3 NONAME + _ZN20DUsbClientController12HaltEndpointEPK5DBasei @ 4 NONAME + _ZN20DUsbClientController12SetInterfaceEPK5DBaseP7DThreadiR14TUsbcClassInfoP6TDesC8i22TUsbcEndpointInfoArrayPim @ 5 NONAME + _ZN20DUsbClientController12SetInterfaceEPK5DBaseP7DThreadiR14TUsbcClassInfoP6TDesC8iPK17TUsbcEndpointInfoPA6_im @ 6 NONAME + _ZN20DUsbClientController13DumpRegistersEv @ 7 NONAME + _ZN20DUsbClientController13UsbDisconnectEv @ 8 NONAME + _ZN20DUsbClientController15SetupReadBufferER20TUsbcRequestCallback @ 9 NONAME + _ZN20DUsbClientController16CancelReadBufferEPK5DBasei @ 10 NONAME + _ZN20DUsbClientController16DeRegisterClientEPK5DBase @ 11 NONAME + _ZN20DUsbClientController16ReleaseInterfaceEPK5DBasei @ 12 NONAME + _ZN20DUsbClientController16SetDeviceControlEPK5DBase @ 13 NONAME + _ZN20DUsbClientController16SetOtgDescriptorEP7DThreadRK6TDesC8 @ 14 NONAME + _ZN20DUsbClientController16SetupWriteBufferER20TUsbcRequestCallback @ 15 NONAME + _ZN20DUsbClientController17CancelWriteBufferEPK5DBasei @ 16 NONAME + _ZN20DUsbClientController17ClearHaltEndpointEPK5DBasei @ 17 NONAME + _ZN20DUsbClientController17EnableClientStackEv @ 18 NONAME + _ZN20DUsbClientController18DisableClientStackEv @ 19 NONAME + _ZN20DUsbClientController18EndpointPacketSizeEPK5DBasei @ 20 NONAME + _ZN20DUsbClientController18SignalRemoteWakeupEv @ 21 NONAME + _ZN20DUsbClientController19GetDeviceDescriptorEP7DThreadR5TDes8 @ 22 NONAME + _ZN20DUsbClientController19GetStringDescriptorEP7DThreadhR5TDes8 @ 23 NONAME + _ZN20DUsbClientController19SendEp0StatusPacketEPK5DBase @ 24 NONAME + _ZN20DUsbClientController19SetDeviceDescriptorEP7DThreadRK5TDes8 @ 25 NONAME + _ZN20DUsbClientController19SetStringDescriptorEP7DThreadhRK5TDes8 @ 26 NONAME + _ZN20DUsbClientController20ReleaseDeviceControlEPK5DBase @ 27 NONAME + _ZN20DUsbClientController21GetEndpointDescriptorEP7DThreadPK5DBaseiiR5TDes8 @ 28 NONAME + _ZN20DUsbClientController21QueryEndpointResourceEPK5DBasei21TUsbcEndpointResource @ 29 NONAME + _ZN20DUsbClientController21SetEndpointDescriptorEP7DThreadPK5DBaseiiRK5TDes8 @ 30 NONAME + _ZN20DUsbClientController21UsbcControllerPointerEi @ 31 NONAME + _ZN20DUsbClientController22GetInterfaceDescriptorEP7DThreadPK5DBaseiR5TDes8 @ 32 NONAME + _ZN20DUsbClientController22RegisterClientCallbackER19TUsbcClientCallback @ 33 NONAME + _ZN20DUsbClientController22RemoveStringDescriptorEh @ 34 NONAME + _ZN20DUsbClientController22SetInterfaceDescriptorEP7DThreadPK5DBaseiRK5TDes8 @ 35 NONAME + _ZN20DUsbClientController23CurrentlyUsingHighSpeedEv @ 36 NONAME + _ZN20DUsbClientController23GetDeviceDescriptorSizeEP7DThreadR5TDes8 @ 37 NONAME + _ZN20DUsbClientController23RegisterForStatusChangeER19TUsbcStatusCallback @ 38 NONAME + _ZN20DUsbClientController25DeRegisterForStatusChangeEPK5DBase @ 39 NONAME + _ZN20DUsbClientController25GetEndpointDescriptorSizeEP7DThreadPK5DBaseiiR5TDes8 @ 40 NONAME + _ZN20DUsbClientController25GetStringDescriptorLangIdEP7DThreadR5TDes8 @ 41 NONAME + _ZN20DUsbClientController25SetStringDescriptorLangIdEt @ 42 NONAME + _ZN20DUsbClientController26GetConfigurationDescriptorEP7DThreadR5TDes8 @ 43 NONAME + _ZN20DUsbClientController26GetInterfaceDescriptorSizeEP7DThreadPK5DBaseiR5TDes8 @ 44 NONAME + _ZN20DUsbClientController26GetProductStringDescriptorEP7DThreadR5TDes8 @ 45 NONAME + _ZN20DUsbClientController26SetConfigurationDescriptorEP7DThreadRK5TDes8 @ 46 NONAME + _ZN20DUsbClientController26SetProductStringDescriptorEP7DThreadRK5TDes8 @ 47 NONAME + _ZN20DUsbClientController27RegisterForOtgFeatureChangeER23TUsbcOtgFeatureCallback @ 48 NONAME + _ZN20DUsbClientController28GetCSEndpointDescriptorBlockEP7DThreadPK5DBaseiiR5TDes8 @ 49 NONAME + _ZN20DUsbClientController28GetDeviceQualifierDescriptorEP7DThreadR5TDes8 @ 50 NONAME + _ZN20DUsbClientController28SetCSEndpointDescriptorBlockEP7DThreadPK5DBaseiiRK5TDes8i @ 51 NONAME + _ZN20DUsbClientController28SetDeviceQualifierDescriptorEP7DThreadRK5TDes8 @ 52 NONAME + _ZN20DUsbClientController28SetEndpointZeroMaxPacketSizeEi @ 53 NONAME + _ZN20DUsbClientController29DeRegisterForOtgFeatureChangeEPK5DBase @ 54 NONAME + _ZN20DUsbClientController29GetCSInterfaceDescriptorBlockEP7DThreadPK5DBaseiR5TDes8 @ 55 NONAME + _ZN20DUsbClientController29RemoveProductStringDescriptorEv @ 56 NONAME + _ZN20DUsbClientController29SetCSInterfaceDescriptorBlockEP7DThreadPK5DBaseiRK5TDes8i @ 57 NONAME + _ZN20DUsbClientController30GetConfigurationDescriptorSizeEP7DThreadR5TDes8 @ 58 NONAME + _ZN20DUsbClientController31GetManufacturerStringDescriptorEP7DThreadR5TDes8 @ 59 NONAME + _ZN20DUsbClientController31GetSerialNumberStringDescriptorEP7DThreadR5TDes8 @ 60 NONAME + _ZN20DUsbClientController31RegisterForEndpointStatusChangeER27TUsbcEndpointStatusCallback @ 61 NONAME + _ZN20DUsbClientController31SetManufacturerStringDescriptorEP7DThreadRK5TDes8 @ 62 NONAME + _ZN20DUsbClientController31SetSerialNumberStringDescriptorEP7DThreadRK5TDes8 @ 63 NONAME + _ZN20DUsbClientController32GetCSEndpointDescriptorBlockSizeEP7DThreadPK5DBaseiiR5TDes8 @ 64 NONAME + _ZN20DUsbClientController32GetConfigurationStringDescriptorEP7DThreadR5TDes8 @ 65 NONAME + _ZN20DUsbClientController32SetConfigurationStringDescriptorEP7DThreadRK5TDes8 @ 66 NONAME + _ZN20DUsbClientController33DeRegisterForEndpointStatusChangeEPK5DBase @ 67 NONAME + _ZN20DUsbClientController33GetCSInterfaceDescriptorBlockSizeEP7DThreadPK5DBaseiR5TDes8 @ 68 NONAME + _ZN20DUsbClientController34RemoveManufacturerStringDescriptorEv @ 69 NONAME + _ZN20DUsbClientController34RemoveSerialNumberStringDescriptorEv @ 70 NONAME + _ZN20DUsbClientController35RemoveConfigurationStringDescriptorEv @ 71 NONAME + _ZN20DUsbClientController36GetOtherSpeedConfigurationDescriptorEP7DThreadR5TDes8 @ 72 NONAME + _ZN20DUsbClientController36SetOtherSpeedConfigurationDescriptorEP7DThreadRK5TDes8 @ 73 NONAME + _ZN20DUsbClientController4DfcQEi @ 74 NONAME + _ZN20DUsbClientController6CreateERN7UsbShai23MPeripheralControllerIfERKNS0_31TPeripheralControllerPropertiesEi @ 75 NONAME + _ZN20DUsbClientController8Ep0StallEPK5DBase @ 76 NONAME + _ZN20DUsbClientController8IsActiveEv @ 77 NONAME + _ZN20TUsbcRequestCallback15SetRxBufferInfoEPhmPmS1_i @ 78 NONAME + _ZN20TUsbcRequestCallback15SetTxBufferInfoEPhmi @ 79 NONAME + _ZN7UsbShai16UsbPeripheralPil28RegisterPeripheralControllerERNS_23MPeripheralControllerIfERKNS_31TPeripheralControllerPropertiesE @ 80 NONAME + _ZN7UsbShai21TUsbPeripheralRequestC1Ei @ 81 NONAME + _ZN7UsbShai21TUsbPeripheralRequestC2Ei @ 82 NONAME + _ZN7UsbShai22UsbChargerDetectionPil23RegisterChargerDetectorERNS_18MChargerDetectorIfERNS_26TChargerDetectorPropertiesE @ 83 NONAME + _ZNK20DUsbClientController10DeviceCapsEPK5DBaseR5TDes8 @ 84 NONAME + _ZNK20DUsbClientController12EndpointCapsEPK5DBaseR5TDes8 @ 85 NONAME + _ZNK20DUsbClientController13Ep0PacketSizeEv @ 86 NONAME + _ZNK20DUsbClientController14GetOtgFeaturesEP7DThreadR5TDes8 @ 87 NONAME + _ZNK20DUsbClientController15GetDeviceStatusEv @ 88 NONAME + _ZNK20DUsbClientController16GetOtgDescriptorEP7DThreadR5TDes8 @ 89 NONAME + _ZNK20DUsbClientController17GetEndpointStatusEPK5DBasei @ 90 NONAME + _ZNK20DUsbClientController18GetInterfaceNumberEPK5DBaseRi @ 91 NONAME + _ZNK20DUsbClientController21GetCurrentOtgFeaturesERh @ 92 NONAME + _ZNK20DUsbClientController26EndpointZeroMaxPacketSizesEv @ 93 NONAME + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/group/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/group/bld.inf Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,21 @@ +/* + Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which accompanies + this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Initial Contributors: + Nokia Corporation - initial contribution. + + Contributors: +*/ +#include + +PRJ_PLATFORMS +ARMV5 + +PRJ_MMPFILES +usbperipheralpil diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/group/usbperipheralpil.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/group/usbperipheralpil.mmp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,45 @@ +/* + Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which accompanies + this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Initial Contributors: + Nokia Corporation - initial contribution. + + Contributors: +*/ + +#include + +#include "kernel/kern_ext.mmh" + +target usbperipheralpil.dll +targettype kext +linkas usbperipheralpil.dll +deffile ../~/usbperipheralpil.def +VENDORID 0x70000001 +uid 0x00000000 0x2002E6DB +capability all +epocallowdlldata + +// The sytem include paths are declared by using the following macros + +OS_LAYER_SYSTEMINCLUDE + + + +// Include dirs of the HS-USB component +userinclude ../inc + +// PIL layer source files +sourcepath ../src +source chapter9.cpp +source descriptors.cpp +source misc.cpp +source ps_usbc.cpp +source queue.cpp +source controltransfersm.cpp diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/chapter9.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/chapter9.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,1599 @@ +// Copyright (c) 2000-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/usbcc/chapter9.cpp +// Platform independent layer (PIL) of the USB Device controller driver: +// Processing of USB spec chapter 9 standard requests. +// +// + +/** + @file chapter9.cpp + @internalTechnology +*/ + +#include + +#include "controltransfersm.h" + +//#define ENABLE_EXCESSIVE_DEBUG_OUTPUT +// +// === USB Controller member function implementation - PSL API (protected) ======================== +// + +/** Used to synchronize the Ep0 state machine between the PSL and PIL. + Accepts a SETUP packet and returns the next Ep0 state. + + @param aSetupBuf The SETUP packet just received by the PSL. + @return The next Ep0 state. + + @publishedPartner @released +*/ +UsbShai::TControlStage DUsbClientController::EnquireEp0NextStage(const TUint8* aSetupBuf) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnquireEp0NextState()")); + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + if (SWAP_BYTES_16((reinterpret_cast(aSetupBuf)[3])) == 0) // iLength + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EControlTransferStageStatusIn")); + return UsbShai::EControlTransferStageStatusIn; // No-data Control => Status_IN + } + else if ((aSetupBuf[0] & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev) + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EControlTransferStageDataOut")); + return UsbShai::EControlTransferStageDataOut; // Control Write => Data_OUT + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EControlTransferStageDataIn")); + return UsbShai::EControlTransferStageDataIn; // Control Read => Data_IN + } + } + +// +// About iLastError. +// This member is used to remember the last error happend during a +// processXXX likewise function. +// +// Before entry of each ProcessXXX, iLastError will be cleared to KErrNone. +// + +// --- The USB Spec Chapter 9 Standard Endpoint Zero Device Requests --- +// Record error happend with iLastError, the value already been set to zero +// before entering ProcessSetupPacket call. +void DUsbClientController::ProcessGetDeviceStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetDeviceStatus()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + // We always assume Device is bus-powered, even though mobile phone almost always + // has a battry there, because self-powered device can not required more then 100ma current + // which is not acceptable for Usb charging. + TBool selfPowered = EFalse; + + /* FIXME: modify selfPowered to make it compilance with following rule. + + 1. If current draw exceeds 100mA, the device must report itself + as bus-powered during enumeration. + + 2. In all cases, the GetStatus(DEVICE) call must accurately report + whether the device is currently operating on self- or bus-power. + + 3. A device that is actively drawing more than 100mA from USB must + report itself as bus-powered in the GetStatus(DEVICE) call. + + 4. Peripherals that return "Self-powered" in the GetStatus(DEVICE) + call are prohibited from drawing more than 100mA at any time. + */ + /* + TBuf8 config; + + if(iDescriptors.GetConfigurationDescriptorTC(&Kern::CurrentThread(),config) == KErrNone) + { + TUint8 maxPower = config[8]; + if(maxPower <= 50) + { + selfPowered = EFalse; + } + } + */ + + const TUint16 status = ((selfPowered ? KUsbDevStat_SelfPowered : 0) | + (iRmWakeupStatus_Enabled ? KUsbDevStat_RemoteWakeup : 0)); + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting device status: 0x%02x", status)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (iConTransferMgr->SetupEndpointZeroWrite(iEp0_TxBuf, sizeof(status)) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + +void DUsbClientController::ProcessGetInterfaceStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetInterfaceStatus()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + if (InterfaceExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface does not exist")); + iLastError = KErrGeneral; + } + else + { + const TUint16 status = 0x0000; // as of USB Spec 2.0 + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting interface status: 0x%02x", status)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (iConTransferMgr->SetupEndpointZeroWrite(iEp0_TxBuf, sizeof(status)) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + } + + +void DUsbClientController::ProcessGetEndpointStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetEndpointStatus()")); + if ( + ((iDeviceState < UsbShai::EUsbPeripheralStateAddress) || + (iDeviceState == UsbShai::EUsbPeripheralStateAddress && (aPacket.iIndex & KUsbEpAddress_Portmask) != 0))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + if (EndpointExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + iLastError = KErrGeneral; + } + else + { + const TInt ep = EpAddr2Idx(aPacket.iIndex); + const TUint16 status = (iRealEndpoints[ep].iHalt) ? KUsbEpStat_Halt : 0; + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting endpoint status 0x%02x for real endpoint %d", + status, ep)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (iConTransferMgr->SetupEndpointZeroWrite(iEp0_TxBuf, 2) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + } + + +void DUsbClientController::ProcessSetClearDevFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearDevFeature()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateDefault) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + return; + } + + TInt test_sel = 0; + + if (aPacket.iRequest == KUsbRequest_SetFeature) + { + switch (aPacket.iValue) + { + case KUsbFeature_RemoteWakeup: + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + iRmWakeupStatus_Enabled = ETrue; + } + break; + + case KUsbFeature_TestMode: + if (!iHighSpeed) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported in High-Speed mode")); + iLastError = KErrGeneral; + } + else if (LowByte(aPacket.iIndex) != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Lower byte of wIndex must be zero")); + iLastError = KErrGeneral; + } + else + { + test_sel = HighByte(aPacket.iIndex); + if ((test_sel < UsbShai::EUsbTestSelector_Test_J) || (test_sel > UsbShai::EUsbTestSelector_Test_Force_Enable)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid test selector: %d", test_sel)); + iLastError = KErrGeneral; + } + } + break; + + case KUsbFeature_B_HnpEnable: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + iLastError = KErrGeneral; + } + else if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + iLastError = KErrGeneral; + } + else + { + iOtgFuncMap |= KUsbOtgAttr_B_HnpEnable; + OtgFeaturesNotify(); + } + break; + + case KUsbFeature_A_HnpSupport: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + iLastError = KErrGeneral; + } + else if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + iLastError = KErrGeneral; + } + else + { + iOtgFuncMap |= KUsbOtgAttr_A_HnpSupport; + OtgFeaturesNotify(); + } + break; + + case KUsbFeature_A_AltHnpSupport: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + iLastError = KErrGeneral; + } + else if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + iLastError = KErrGeneral; + } + else + { + iOtgFuncMap |= KUsbOtgAttr_A_AltHnpSupport; + OtgFeaturesNotify(); + } + break; + + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + iLastError = KErrGeneral; + } + } + else // KUsbRequest_ClearFeature + { + switch (aPacket.iValue) + { + case KUsbFeature_RemoteWakeup: + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + iRmWakeupStatus_Enabled = EFalse; + } + break; + + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + iLastError = KErrGeneral; + } + } + + if(iLastError == KErrNone) + { + // Sent out status packet if no error found. + iConTransferMgr->SendEp0ZeroByteStatusPacket(); // success: zero bytes data during status stage + + // 9.4.9: "The transition to test mode of an upstream facing port must not happen until + // after the status stage of the request." + if (test_sel) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Entering HS Test Mode %d", test_sel)); + iController.EnterTestMode((UsbShai::TUsbTestModeSelector)test_sel); + } + } + } + + +void DUsbClientController::ProcessSetClearIfcFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearIfcFeature()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + // No interface features defined in USB spec, thus + iLastError = KErrGeneral; + } + } + + +void DUsbClientController::ProcessSetClearEpFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearEpFeature()")); + if ( + ((iDeviceState < UsbShai::EUsbPeripheralStateAddress) || + (iDeviceState == UsbShai::EUsbPeripheralStateAddress && (aPacket.iIndex & KUsbEpAddress_Portmask) != 0))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if (aPacket.iValue != KUsbFeature_EndpointHalt) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + iLastError = KErrGeneral; + } + else if (EndpointExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + iLastError = KErrGeneral; + } + else + { + const TInt ep = EpAddr2Idx(aPacket.iIndex); + if (iRealEndpoints[ep].iLEndpoint->iInfo.iType == UsbShai::KUsbEpTypeControl || + iRealEndpoints[ep].iLEndpoint->iInfo.iType == UsbShai::KUsbEpTypeIsochronous) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint is Control or Isochronous")); + iLastError = KErrGeneral; + } + else + { + SetClearHaltFeature(ep, aPacket.iRequest); + + // success: zero bytes data during status stage + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + } + } + } + + +void DUsbClientController::ProcessSetAddress(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetAddress()")); + if ( iDeviceState > UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else + { + const TUint16 addr = aPacket.iValue; + + if (addr > 127) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad address value: %d (>127)", addr)); + iLastError = KErrGeneral; + } + else if (addr == 0) + { + // Enter Default state (from Default or Address) + NextDeviceState(UsbShai::EUsbPeripheralStateDefault); + } + + __KTRACE_OPT(KUSB, Kern::Printf(" USB address: %d", addr)); + + // If controller support hw acceleration,call set address first and then status + if(iControllerProperties.iControllerCaps & UsbShai::KDevCapSetAddressAcceleration) + { + iController.SetDeviceAddress(addr); + } + + // The spec says, under section 9.4.6: + // "Stages after the initial Setup packet assume the same device address as the Setup packet. The USB + // device does not change its device address until after the Status stage of this request is completed + // successfully. Note that this is a difference between this request and all other requests. For all other + // requests, the operation indicated must be completed before the Status stage." + // Therefore, here we first send the status packet and only then actually execute the request. + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + + // If controller doesn't support hw acceleration, call set address after status + if((iControllerProperties.iControllerCaps & UsbShai::KDevCapSetAddressAcceleration) == 0) + { + iController.SetDeviceAddress(addr); + } + } + } + + +void DUsbClientController::ProcessGetDescriptor(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetDescriptor()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateDefault) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + return ; + } + + // Make sure we assume the correct speed + __ASSERT_DEBUG((iHighSpeed == CurrentlyUsingHighSpeed()), Kern::Fault(KUsbPILPanicCat, __LINE__)); + + TInt size = 0; + const TInt result = iDescriptors.FindDescriptor(HighByte(aPacket.iValue), // Type + LowByte(aPacket.iValue), // Index + aPacket.iIndex, // Language ID + size); + + if ((result != KErrNone) || (size == 0)) + { + // This doesn't have to be an error - protocol-wise it's OK. + __KTRACE_OPT(KUSB, Kern::Printf(" Couldn't retrieve descriptor")); + iLastError = KErrGeneral; + return; + } + + __KTRACE_OPT(KUSB, Kern::Printf(" Descriptor found, size: %d (requested: %d)", + size, aPacket.iLength)); + if (size > KUsbcBufSz_Ep0Tx) + { + // This should actually not be possible (i.e. we should never get here). + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ep0_Tx buffer too small")); + } + if (size > aPacket.iLength) + { + // Send only as much data as requested by the host + size = aPacket.iLength; + } + +#ifdef ENABLE_EXCESSIVE_DEBUG_OUTPUT + __KTRACE_OPT(KUSB, + Kern::Printf(" Data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ...", + iEp0_TxBuf[0], iEp0_TxBuf[1], iEp0_TxBuf[2], iEp0_TxBuf[3], + iEp0_TxBuf[4], iEp0_TxBuf[5], iEp0_TxBuf[6], iEp0_TxBuf[7])); +#endif + // If we're about to send less bytes than expected by the host AND our number is a + // multiple of the packet size, in order to indicate the end of the control transfer, + // we must finally send a zero length data packet (ZLP): + const TBool zlp = ((size < aPacket.iLength) && (size % iEp0MaxPacketSize == 0)); + if (iConTransferMgr->SetupEndpointZeroWrite(iEp0_TxBuf, size, zlp) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + + +void DUsbClientController::ProcessSetDescriptor(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetDescriptor()")); +#ifndef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + iLastError = KErrGeneral; + return; +#else + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + // Error: Invalid device state! + iLastError = KErrGeneral; + } + else if (aPacket.iLength > KUsbcBufSz_Ep0Rx) + { + // Error: Our Rx buffer is too small! (Raise a defect to make it larger) + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ep0_Rx buffer too small")); + iLastError = KErrGeneral; + } + else + { + SetEp0DataOutVars(); + iConTransferMgr->SetupEndpointZeroRead(); + } +#endif + } + +void DUsbClientController::ProcessGetConfiguration(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetConfiguration()")); + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if ( iDeviceState == UsbShai::EUsbPeripheralStateAddress && iCurrentConfig != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DeviceState Address && Config != 0")); + iLastError = KErrGeneral; + } + else if ( iDeviceState == UsbShai::EUsbPeripheralStateConfigured && iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DeviceState Configured && Config == 0")); + iLastError = KErrGeneral; + } + else + { + if (aPacket.iLength != 1) // "unspecified behavior" + { + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: wLength != 1 (= %d)", aPacket.iLength)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting configuration value %d", iCurrentConfig)); + if (iConTransferMgr->SetupEndpointZeroWrite(&iCurrentConfig, sizeof(iCurrentConfig)) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + + +/** Changes the device's configuration value, including interface setup and/or + teardown and state change notification of higher-layer clients. + May also be called by the PSL in special cases - therefore publishedPartner. + + @param aPacket The received Ep0 SET_CONFIGURATION setup request packet. + @return KErrGeneral in case of a protocol error, KErrNone otherwise. + + @publishedPartner @released +*/ +TInt DUsbClientController::ProcessSetConfiguration(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetConfiguration()")); + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + const TInt value = aPacket.iValue; + + if ( iDeviceState < UsbShai::EUsbPeripheralStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if (value > 1) // we support only one configuration + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Configuration value too large: %d", value)); + iLastError = KErrGeneral; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration value: %d", value)); + ChangeConfiguration(value); + + // In 9.4.5 under GET_STATUS we read, that after SET_CONFIGURATION the HALT feature + // for all endpoints is reset to zero. + TInt num = 0; + (TAny) DoForEveryEndpointInUse(&DUsbClientController::ClearHaltFeature, num); + __KTRACE_OPT(KUSB, Kern::Printf(" Called ClearHaltFeature() for %d endpoints", num)); + // success: zero bytes data during status stage + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + } + + return iLastError; + } + +void DUsbClientController::ProcessGetInterface(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetInterface()")); + + const TInt number = aPacket.iIndex; + + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if (iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device not configured")); + iLastError = KErrGeneral; + } + else if (!InterfaceExists(number)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad interface index: %d", number)); + iLastError = KErrGeneral; + } + else + { + // Send alternate setting code of iCurrentInterface of Interface(set) of the current + // config (iCurrentConfig). + const TUint8 setting = InterfaceNumber2InterfacePointer(number)->iCurrentInterface; + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting interface setting %d", setting)); + if (iConTransferMgr->SetupEndpointZeroWrite(&setting, 1) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + + +void DUsbClientController::ProcessSetInterface(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetInterface()")); + + const TInt number = aPacket.iIndex; + + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if (iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device not configured")); + iLastError = KErrGeneral; + } + else if (!InterfaceExists(number)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad interface index: %d", number)); + iLastError = KErrGeneral; + } + else + { + const TInt setting = aPacket.iValue; + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(number); + RPointerArray& ifcs = ifcset_ptr->iInterfaces; + if (setting >= ifcs.Count()) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Alt Setting >= bNumAltSettings: %d", setting)); + iLastError = KErrGeneral; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Interface setting:: %d", setting)); + // Set iCurrentInterface of Interface(set) of the current config + // (iCurrentConfig) to alternate setting . + ChangeInterface(ifcs[setting]); + // In 9.4.5 under GET_STATUS we read, that after SET_INTERFACE the HALT feature + // for all endpoints (of the now current interface setting) is reset to zero. + RPointerArray& eps = ifcset_ptr->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt i = 0; i < num_eps; i++) + { + const TInt ep_num = EpAddr2Idx(eps[i]->iPEndpoint->iEndpointAddr); + (TAny) ClearHaltFeature(ep_num); + } + // success: zero bytes data during status stage + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + } + } + } + + +void DUsbClientController::ProcessSynchFrame(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSynchFrame()")); + + const TInt ep = aPacket.iIndex; + + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + iLastError = KErrGeneral; + } + else if (EndpointExists(ep) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + iLastError = KErrGeneral; + } + else if (iRealEndpoints[EpAddr2Idx(ep)].iLEndpoint->iInfo.iType != UsbShai::KUsbEpTypeIsochronous) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint is not isochronous")); + iLastError = KErrGeneral; + } + else + { + // We always send 0: + *reinterpret_cast(iEp0_TxBuf) = 0x00; + if (iConTransferMgr->SetupEndpointZeroWrite(iEp0_TxBuf, 2) == KErrNone) + { + iEp0WritePending = ETrue; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Wrong: Write to Ep0 Failed")); + } + } + } + + +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST +void DUsbClientController::ProceedSetDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProceedSetDescriptor()")); + // iEp0DataReceived already reflects the current buffer state + if (iEp0DataReceived < iConTransferMgr->PktParser().DataLength()) + { + // Not yet all data received => proceed + return; + } + if (iEp0DataReceived > iConTransferMgr->PktParser().DataLength()) + { + // Error: more data received than expected + // but we don't care... + } + const TUint8 type = HighByte(iConTransferMgr->PktParser().Value()); + if (type == KUsbDescType_String) + { + // set/add new string descriptor + } + else + { + // set/add new ordinary descriptor + } + TUint8 index = LowByte(iConTransferMgr->PktParser().Value()); + TUint16 langid = iConTransferMgr->PktParser().Index(); + TUint16 length_total = iConTransferMgr->PktParser().DataLength(); + + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + } +#endif + + +// --- Secondary (Helper) Functions + +void DUsbClientController::SetClearHaltFeature(TInt aRealEndpoint, TUint8 aRequest) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetClearHaltFeature()")); + if (aRequest == KUsbRequest_SetFeature) + { + if (iRealEndpoints[aRealEndpoint].iHalt) + { + // (This condition is not really an error) + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: HALT feature already set")); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" setting HALT feature for real endpoint %d", + aRealEndpoint)); + iController.StallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = ETrue; + } + else // KUsbRequest_ClearFeature + { + if (iRealEndpoints[aRealEndpoint].iHalt == EFalse) + { + // In this case, before we return, the data toggles are reset to DATA0. + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: HALT feature already cleared")); + iController.ResetDataToggle(aRealEndpoint); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" clearing HALT feature for real endpoint %d", + aRealEndpoint)); + iController.ResetDataToggle(aRealEndpoint); + iController.ClearStallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = EFalse; + } + EpStatusNotify(aRealEndpoint); // only called if actually something changed + } + + +TInt DUsbClientController::ClearHaltFeature(TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ClearHaltFeature()")); + if (iRealEndpoints[aRealEndpoint].iHalt != EFalse) + { + iController.ClearStallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = EFalse; + } + return KErrNone; + } + + +void DUsbClientController::ChangeConfiguration(TUint16 aValue) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ChangeConfiguration()")); + // New configuration is the same as the old one: 0 + if (iCurrentConfig == 0 && aValue == 0) + { + // no-op + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration: New == Old == 0 --> exiting")); + return; + } + // New configuration is the same as the old one (but not 0) + if (iCurrentConfig == aValue) + { + // no-op + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration: New == Old == %d --> exiting", aValue)); + return; + } + // Device is already configured + if (iCurrentConfig != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device was configured: %d", iCurrentConfig)); + // Tear down all interface(set)s of the old configuration + RPointerArray& ifcsets = CurrentConfig()->iInterfaceSets; + for (TInt i = 0; i < ifcsets.Count(); ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Tearing down InterfaceSet %d", i)); + InterfaceSetTeardown(ifcsets[i]); + } + iCurrentConfig = 0; + // Enter Address state (from Configured) + if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + NextDeviceState(UsbShai::EUsbPeripheralStateAddress); + } + // Device gets a new configuration + if (aValue != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device gets new configuration...")); + // Setup all alternate settings 0 of all interfaces + // (Don't separate the next two lines of code.) + iCurrentConfig = aValue; + RPointerArray& ifcsets = CurrentConfig()->iInterfaceSets; + const TInt n = ifcsets.Count(); + for (TInt i = 0; i < n; ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting up InterfaceSet %d", i)); + InterfaceSetup(ifcsets[i]->iInterfaces[0]); + } + // Enter Configured state (from Address or Configured) + NextDeviceState(UsbShai::EUsbPeripheralStateConfigured); + } + __KTRACE_OPT(KUSB, Kern::Printf(" New configuration: %d", iCurrentConfig)); + return; + } + + +void DUsbClientController::InterfaceSetup(TUsbcInterface* aIfc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InterfaceSetup()")); + const TInt num_eps = aIfc->iEndpoints.Count(); + for (TInt i = 0; i < num_eps; i++) + { + // Prepare this endpoint for I/O + TUsbcLogicalEndpoint* const ep = aIfc->iEndpoints[i]; + // (TUsbcLogicalEndpoint's FS/HS endpoint sizes and interval values got + // adjusted in its constructor.) + if (iHighSpeed) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting Ep info size to %d (HS)", ep->iEpSize_Hs)); + ep->iInfo.iSize = ep->iEpSize_Hs; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting Ep info size to %d (FS)", ep->iEpSize_Fs)); + ep->iInfo.iSize = ep->iEpSize_Fs; + } + const TInt idx = EpAddr2Idx(ep->iPEndpoint->iEndpointAddr); + if (iController.ConfigureEndpoint(idx, ep->iInfo) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d configuration failed", idx)); + continue; + } + // Should there be a problem with it then we could try resetting the ep + // data toggle at this point (or before the Configure) as well. + __KTRACE_OPT(KUSB, Kern::Printf(" Connecting real ep addr 0x%02x & logical ep #%d", + ep->iPEndpoint->iEndpointAddr, ep->iLEndpointNum)); + ep->iPEndpoint->iLEndpoint = ep; + } + aIfc->iInterfaceSet->iCurrentInterface = aIfc->iSettingCode; + return; + } + + +void DUsbClientController::InterfaceSetTeardown(TUsbcInterfaceSet* aIfcSet) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InterfaceSetTeardown()")); + if (aIfcSet->iInterfaces.Count() == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No interfaces exist - returning")); + return; + } + RPointerArray& eps = aIfcSet->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt i = 0; i < num_eps; i++) + { + TUsbcLogicalEndpoint* const ep = eps[i]; + const TInt idx = EpAddr2Idx(ep->iPEndpoint->iEndpointAddr); + + CancelTransferRequests(idx); + + if (!ep->iPEndpoint->iLEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf(" real ep %d not configured: skipping", idx)); + continue; + } + if (iController.ResetDataToggle(idx) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d data toggle reset failed", idx)); + } + if (iController.DeConfigureEndpoint(idx) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d de-configuration failed", idx)); + } + + __KTRACE_OPT(KUSB, Kern::Printf(" disconnecting real ep & logical ep")); + ep->iPEndpoint->iLEndpoint = NULL; + } + if (aIfcSet->CurrentInterface() != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Resetting alternate interface setting to 0")); + //Add this mutex to protect the interface set data structure + if (NKern::CurrentContext() == EThread) + { + NKern::FMWait(&iMutex); + } + + aIfcSet->iCurrentInterface = 0; + if (NKern::CurrentContext() == EThread) + { + NKern::FMSignal(&iMutex); + } + } + return; + } + + +void DUsbClientController::ChangeInterface(TUsbcInterface* aIfc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ChangeInterface()")); + TUsbcInterfaceSet* ifcset = aIfc->iInterfaceSet; + const TUint8 setting = aIfc->iSettingCode; + if (ifcset->iCurrentInterface == setting) + { + __KTRACE_OPT(KUSB, Kern::Printf(" New Ifc == old Ifc: nothing to do")); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Setting new interface setting #%d", setting)); + InterfaceSetTeardown(ifcset); + InterfaceSetup(aIfc); + StatusNotify(static_cast(KUsbAlternateSetting | setting), ifcset->iClientId); + } + + +// aFunction gets called, successively, with the endpoint index of every ep in-use as its argument. +// (BTW: The declaration "type (class::*name)(params)" makes a "pointer to element function".) +// +TInt DUsbClientController::DoForEveryEndpointInUse(TInt (DUsbClientController::*aFunction)(TInt), TInt& aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DoForEveryEndpointInUse()")); + aCount = 0; + TUsbcConfiguration* const config = CurrentConfig(); + if (!config) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device is not configured - returning")); + return KErrNone; + } + RPointerArray& ifcsets = config->iInterfaceSets; + const TInt num_ifcsets = ifcsets.Count(); + for (TInt i = 0; i < num_ifcsets; i++) + { + RPointerArray& eps = ifcsets[i]->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt j = 0; j < num_eps; j++) + { + const TInt ep_num = EpAddr2Idx(eps[j]->iPEndpoint->iEndpointAddr); + const TInt result = (this->*aFunction)(ep_num); + ++aCount; + if (result != KErrNone) + { + return result; + } + } + } + return KErrNone; + } + +// Data Tx is done. +void DUsbClientController::ProcessDataInPacket(TInt aCount,TInt aErrCode) + { + // Clear Error Code + iLastError = KErrNone; + + // For tx, no premature end is allowed. + if(aErrCode != KErrNone) + { + // something wrong in hardware, we can do nothing as remedy + // just stall the endpoint. + iConTransferMgr->StallEndpoint(KEp0_In); + iConTransferMgr->SetupEndpointZeroRead(); + + // set err code to Error general if end point is stalled + iLastError = KErrGeneral; + } + else + { + // no longer a write pending + iEp0WritePending = EFalse; + + // If it was a client who set up this transmission, we report to that client + if (iEp0ClientDataTransmitting) + { + iEp0ClientDataTransmitting = EFalse; + TUsbcRequestCallback* const p = iRequestCallbacks[KEp0_Tx]; + + if (p) + { + __ASSERT_DEBUG((p->iTransferDir == UsbShai::EControllerWrite), Kern::Fault(KUsbPILPanicCat, __LINE__)); + p->iError = aErrCode; + p->iTxBytes = aCount; + + // tell the client that the sending is done + // later, it is possible that a status out packet comes in, + // just ignore it. + ProcessDataTransferDone(*p); + } + else + { + // we should never goes here + iConTransferMgr->StallEndpoint(KEp0_In); + + // request not found + iLastError = KErrNotFound; + } + } + // else + // it is our own who sending the data, no more action needed + } + } + +// Status Rx is done +void DUsbClientController::ProcessStatusOutPacket(TInt aErrCode) + { + // Clear Error Code + iLastError = KErrNone; + + // Dangdang, psl saying a status out packet recieved from + // host, but, we already completed user's writting request, just ignore it. + + // any way, receiving this means no write is pending. + iEp0WritePending = EFalse; + } + +// Data Rx is (partial) done +void DUsbClientController::ProcessDataOutPacket(TInt aCount,TInt aErrCode) + { + // Clear Error Code + iLastError = KErrNone; + + if (aErrCode != KErrNone && aErrCode != KErrPrematureEnd) + { + // something wrong in hardware, we can do nothing as remedy + // just stall the endpoint. + iConTransferMgr->StallEndpoint(KEp0_Out); + iConTransferMgr->SetupEndpointZeroRead(); + + // set err code to Error general if end point is stalled + iLastError = KErrGeneral; + } + else + { + // Trim aCount with iEp0MaxPacketSize per packet + if (aCount > iEp0MaxPacketSize) + { + aCount = iEp0MaxPacketSize; + } + + iEp0DataReceived += aCount; + + if (iEp0ClientId == NULL) + { + // it is us( not an app), who owns this transaction + switch( iConTransferMgr->PktParser().Request()) + { +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + case KUsbRequest_SetDescriptor: + { + memcpy(iEp0_RxCollectionBuf + iEp0DataReceived, iEp0_RxBuf, aCount); + + // Status will be sent in side this function + // if we had recieved enough bytes + ProceedSetDescriptor(); + } + break; +#endif + default: + { + iConTransferMgr->StallEndpoint(KEp0_In); + ResetEp0DataOutVars(); + + // set err code to Error general if end point is stalled + iLastError = KErrGeneral; + } + break; + } + + if (iEp0DataReceived >= iConTransferMgr->PktParser().DataLength()) + { + // all data seems now to be here + ResetEp0DataOutVars(); + } + } + else + { + // it is an application who is requesting this data + // pass the data on to a client + + // it is the client's responsibility of sending a status + // packet back to host to indicate the whole transfer is + // done + + // Find the client Request callback + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == iEp0ClientId) + { + memcpy(p->iBufferStart, iEp0_RxBuf, aCount); + p->iError = KErrNone; + *(p->iPacketSize) = aCount; + p->iRxPackets = 1; + *(p->iPacketIndex) = 0; + break; + } + } + + // pass data to client if found one. + if ( p != NULL) + { + ProcessDataTransferDone(*p); + + if (iEp0DataReceived >= iConTransferMgr->PktParser().DataLength()) + { + // all data seems now to be here + ResetEp0DataOutVars(); + } + + iLastError = KErrNone; + + } + else + { + // that's bad, we found a client is request this data + // but no matching request callback found. + + iEp0_RxExtraCount = aCount; + //iEp0_RxExtraData = ETrue; + //iEp0_RxExtraError = aErrCode; + iEp0DataReceived -= aCount; + + // No status packet will be send to host since no client is reading this data, + // waiting client to send a status packet. + + iLastError = KErrNotFound; + } + } + } + } + +// Status Tx is done +void DUsbClientController::ProcessStatusInPacket(TInt aErrCode) + { + // Clear Error Code + iLastError = KErrNone; + + // it is time to start a new read + iEp0WritePending = EFalse; + } + +// +// Setup Rx is done +// +void DUsbClientController::ProcessSetupPacket(TInt aCount,TInt aErrCode) + { + + if (aErrCode != KErrNone) + { + // something wrong in hardware, we can do nothing as remedy + // just stall the endpoint. + iConTransferMgr->StallEndpoint(KEp0_Out); + iConTransferMgr->SetupEndpointZeroRead(); + + // set err code to Error general if end point is stalled + iLastError = KErrGeneral; + } + + TUsbcSetup packet; + Buffer2Setup(iEp0_RxBuf, packet); + + // Clear Error Code + iLastError = KErrNone; + + // If this is a standard request, we can handle it here + // not need to bother app layer + if ((packet.iRequestType & KUsbRequestType_TypeMask) == KUsbRequestType_TypeStd) + { + // Fixme: this may not needed any more + iEp0ReceivedNonStdRequest = EFalse; + ProcessStandardRequest(aCount,packet); + } + else + { + // Fixme: This may not needed anymore + iEp0ReceivedNonStdRequest = ETrue; + ProcessNonStandardRequest(aCount,packet); + } + } + +#define USB_PROCESS_REQUEST(request,param) \ + do \ + { \ + Process ## request(param); \ + if (iLastError != KErrNone) \ + { \ + __KTRACE_OPT(KUSB, \ + Kern::Printf(" ProcessEp0SetupReceived: Stalling Ep0")); \ + iConTransferMgr->StallEndpoint(KEp0_In); \ + } \ + }while(0) + + +// +// Standard request +// Please note that:Macro USB_PROCESS_REQUEST(xxx) will stall endpoint +// if anything wrong during the process, in which case status packet is +// not needed. +// +void DUsbClientController::ProcessStandardRequest(TInt /*aCount*/,const TUsbcSetup& aPacket) + { + switch (aPacket.iRequest) + { + case KUsbRequest_GetStatus: + switch (aPacket.iRequestType & KUsbRequestType_DestMask) + { // Recipient + case KUsbRequestType_DestDevice: + USB_PROCESS_REQUEST(GetDeviceStatus,aPacket); + break; + + case KUsbRequestType_DestIfc: + USB_PROCESS_REQUEST(GetInterfaceStatus,aPacket); + break; + + case KUsbRequestType_DestEp: + USB_PROCESS_REQUEST(GetEndpointStatus,aPacket); + break; + + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: GET STATUS - Other or Unknown recipient")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> DUsbClientController::ProcessEp0SetupReceived: " + "Stalling Ep0")); + iConTransferMgr->StallEndpoint(KEp0_In); + iLastError = KErrGeneral; + break; + } + break; + + case KUsbRequest_ClearFeature: + case KUsbRequest_SetFeature: + switch (aPacket.iRequestType & KUsbRequestType_DestMask) + { // Recipient + case KUsbRequestType_DestDevice: + USB_PROCESS_REQUEST(SetClearDevFeature,aPacket); + break; + case KUsbRequestType_DestIfc: + // will 100% stall endpoint + USB_PROCESS_REQUEST(SetClearIfcFeature,aPacket); + break; + case KUsbRequestType_DestEp: + USB_PROCESS_REQUEST(SetClearEpFeature,aPacket); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SET/CLEAR FEATURE - " + "Other or Unknown recipient")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> Stalling Ep0")); + iConTransferMgr->StallEndpoint(KEp0_In); + iLastError = KErrGeneral; + break; + } + break; + + case KUsbRequest_SetAddress: + USB_PROCESS_REQUEST(SetAddress,aPacket); + break; + + case KUsbRequest_GetDescriptor: + USB_PROCESS_REQUEST(GetDescriptor,aPacket); + break; + + case KUsbRequest_SetDescriptor: + USB_PROCESS_REQUEST(SetDescriptor,aPacket); + break; + + case KUsbRequest_GetConfig: + USB_PROCESS_REQUEST(GetConfiguration,aPacket); + break; + + case KUsbRequest_SetConfig: + USB_PROCESS_REQUEST(SetConfiguration,aPacket); + break; + + case KUsbRequest_GetInterface: + USB_PROCESS_REQUEST(GetInterface,aPacket); + break; + + case KUsbRequest_SetInterface: + USB_PROCESS_REQUEST(SetInterface,aPacket); + break; + + case KUsbRequest_SynchFrame: + USB_PROCESS_REQUEST(SynchFrame,aPacket); + break; + + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown/unsupported Std Setup Request")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> Stalling Ep0")); + iConTransferMgr->StallEndpoint(KEp0_In); + iLastError = KErrGeneral; + break; + } + } + +#undef USB_PROCESS_REQUEST + +// +// class- or vendor-specific request +// we dont send back any status to host in PIL for class- or vendor-specific request +// if no client is waiting, stall the endpoint +// if client is not ready, just record them and waiting for client to read them +// (and, send a status packet) +// +void DUsbClientController::ProcessNonStandardRequest(TInt aCount,const TUsbcSetup& aPacket) + { + // Find out which client can handle this request + const DBase* client = FindNonStandardRequestClient(aPacket.iRequestType & KUsbRequestType_DestMask,aPacket); + + // If client is valide + if (client != NULL) + { + // Try to relay aPacket to the real recipient + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + + // Find out the request callback with match the client + // returned from last FindNonStandardRequestClient(). + while ((p = iter++) != NULL) + { + if (p->Owner() == client) + { + __ASSERT_DEBUG((p->iEndpointNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __ASSERT_DEBUG((p->iTransferDir == UsbShai::EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" Found Ep0 read request")); + if (aPacket.iLength != 0) + { + if ((aPacket.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev) + { + // Data transfer & direction OUT => there'll be a DATA_OUT stage + __KTRACE_OPT(KUSB, Kern::Printf(" Next is DATA_OUT: setting up DataOutVars")); + SetEp0DataOutVars(client); + } + else if ((aPacket.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToHost) + { + // For possible later use (ZLP). + iEp0_TxNonStdCount = aPacket.iLength; + } + } + + // Found the request callback, jump out now + break; + } + } + + // if a request callback matching the client is found, + // complete the request + if( p != NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 read request completed to client")); + memcpy(p->iBufferStart, iEp0_RxBuf, aCount); + p->iError = KErrNone; + *(p->iPacketSize) = aCount; + p->iRxPackets = 1; + *(p->iPacketIndex) = 0; + ProcessDataTransferDone(*p); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 read request not found: setting RxExtra vars (Setup)")); + iEp0_RxExtraCount = aCount; + //iEp0_RxExtraData = ETrue; + //iEp0_RxExtraError = aErrCode; + iSetupPacketPending = ETrue; + + // For setup packet,a zero bytes status is always needed + iLastError = KErrNotFound; + } + } + else // if (client == NULL) + { + // Pil don't know how to deal with non-standard request, stall endpoint + __KTRACE_OPT(KPANIC, Kern::Printf(" Ep0 request error: Stalling Ep0")); + iConTransferMgr->StallEndpoint(KEp0_In); + iLastError = KErrGeneral; + } + } + +const DBase* DUsbClientController::FindNonStandardRequestClient(TUint8 aPacketTypeDestination,const TUsbcSetup& aPacket) + { + const DBase* client = NULL; + + switch (aPacketTypeDestination) + { // Recipient + case KUsbRequestType_DestDevice: + { + client = iEp0DeviceControl; + } + break; + + case KUsbRequestType_DestIfc: + { + //Add this mutex to protect the interface set data structure + if (NKern::CurrentContext() == EThread) + { + NKern::FMWait(&iMutex); + } + + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + } + else + { + const TUsbcInterfaceSet* const ifcset_ptr = + InterfaceNumber2InterfacePointer(aPacket.iIndex); + + //In some rare case, ifcset_ptr is not NULL but the ifcset_ptr->iInterfaces.Count() is 0, + //so panic will happen when excute the following line. so I add the conditon + //0 != ifcset_ptr->iInterfaces.Count() here. + if (ifcset_ptr && 0 != ifcset_ptr->iInterfaces.Count()) + { + if (ifcset_ptr->CurrentInterface()->iNoEp0Requests) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Recipient says: NoEp0RequestsPlease")); + } + else + { + client = ifcset_ptr->iClientId; + } + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface 0x%02x does not exist", + aPacket.iIndex)); + } + } + + if (NKern::CurrentContext() == EThread) + { + NKern::FMSignal(&iMutex); + } + } + break; + + case KUsbRequestType_DestEp: + { + //Add this mutex to protect the interface set data structure + if (NKern::CurrentContext() == EThread) + { + NKern::FMWait(&iMutex); + } + if ( iDeviceState < UsbShai::EUsbPeripheralStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + } + else if (EndpointExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint 0x%02x does not exist", + aPacket.iIndex)); + } + else + { + const TInt idx = EpAddr2Idx(aPacket.iIndex); + const TUsbcInterfaceSet* const ifcset_ptr = + iRealEndpoints[idx].iLEndpoint->iInterface->iInterfaceSet; + if (ifcset_ptr->CurrentInterface()->iNoEp0Requests) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Recipient says: NoEp0RequestsPlease")); + } + else + { + client = ifcset_ptr->iClientId; + } + } + if (NKern::CurrentContext() == EThread) + { + NKern::FMSignal(&iMutex); + } + } + break; + + default: + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Other or Unknown recipient")); + break; + } + } + + return client; + } + +TInt DUsbClientController::ProcessSetupEndpointZeroRead() + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: Read EP0 Issued")); + return iController.SetupEndpointZeroRead(); + } + +TInt DUsbClientController::ProcessSetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd) + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: Write EP0 Issued")); + return iController.SetupEndpointZeroWrite(aBuffer,aLength,aZlpReqd); + } + +TInt DUsbClientController::ProcessSendEp0ZeroByteStatusPacket() + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: Zero Status to EP0 Issued")); + return iController.SendEp0ZeroByteStatusPacket(); + } + +TInt DUsbClientController::ProcessStallEndpoint(TInt aRealEndpoint) + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: EP0(%d) Stall Issued",aRealEndpoint)); + return iController.StallEndpoint(aRealEndpoint); + } + +void DUsbClientController::ProcessEp0SetupPacketProceed() + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: Missed setup packet procced")); + iController.Ep0ReadSetupPktProceed(); + } + +void DUsbClientController::ProcessEp0DataPacketProceed() + { + __KTRACE_OPT(KPANIC, Kern::Printf("DUsbClientController:: Missed data packet procced")); + iController.Ep0ReadDataPktProceed(); + } + +// -eof- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/controltransfersm.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/controltransfersm.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,604 @@ +/* + Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which accompanies + this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Initial Contributors: + Nokia Corporation - initial contribution. + + Contributors: +*/ + +#include "controltransfersm.h" + +// Bitmap of setup packet +/* +Offset 0, bmRequestType, 1 bytes + 1 Bit-Map + D7 Data Phase Transfer Direction + 0 = Host to Device + 1 = Device to Host + + D6..5 Type + 0 = Standard + 1 = Class + 2 = Vendor + 3 = Reserved + + D4..0 Recipient + 0 = Device + 1 = Interface + 2 = Endpoint + 3 = Other + 4..31 = Reserved + +Offset 1, bRequest + +Offset 6, Count, 2 bytes + Number of bytes to transfer if there is a data phase +*/ + +#if defined(_DEBUG) + +#define CTSM_ID "ControlTransferSM " + +char* DebugName[] = + { + "Setup", + "Data Out", + "Status In", + "Data In", + "Status Out" + }; + +#endif + +// Static data instance +TUsbcSetup TSetupPkgParser::iSetupPkt; + +TSetupPkgParser::TSetupPkgParser() + { + iSetupPkt.iRequestType = 0; + iSetupPkt.iRequest = 0; + + iSetupPkt.iValue = 0; + iSetupPkt.iIndex = 0; + iSetupPkt.iLength = 0; + } + +// Code for TSetupPkgParser +// we do a bitwise copy here. +void TSetupPkgParser::Set(const TUint8* aSetupBuf) + { + // TUint8 index + iSetupPkt.iRequestType = static_cast(aSetupBuf)[0]; + iSetupPkt.iRequest = static_cast(aSetupBuf)[1]; + // TUint16 index from here! + iSetupPkt.iValue = SWAP_BYTES_16((reinterpret_cast(aSetupBuf))[1]); + iSetupPkt.iIndex = SWAP_BYTES_16((reinterpret_cast(aSetupBuf))[2]); + iSetupPkt.iLength = SWAP_BYTES_16((reinterpret_cast(aSetupBuf))[3]); + + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "TSetupPkgParser::Set")); + } + +// return the next stage by decoding the setup packet +// the possible stage followed by a setup packet are: +// StatusIn (no data stage) +// DataOut (host sent to peripheral) +// DataIn (peripheral to host) +UsbShai::TControlStage TSetupPkgParser::NextStage() + { + UsbShai::TControlStage ret = UsbShai::EControlTransferStageMax; + + // Take the data length out, 0 length means no data stage + if (iSetupPkt.iLength == 0) + { + ret = UsbShai::EControlTransferStageStatusIn; + } + else if ((iSetupPkt.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev) + { + // Dir to device means host will send data out + ret = UsbShai::EControlTransferStageDataOut; + } + else + { + // Otherwise, there must be a datain stage follows + ret = UsbShai::EControlTransferStageDataIn; + } + + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "TSetupPkgParser::NextStage %d", ret)); + + return ret; + } + +// Base class of stage sm +TControlStageSm::TControlStageSm(DControlTransferManager& aTransferMgr): + iTransferMgr(aTransferMgr) + { + } + +void TControlStageSm::ChangeToStage(UsbShai::TControlStage aToStage) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "<> TControlStageSm::ChangeToStage: %s",DebugName[aToStage])); + iTransferMgr.iCurrentStage = aToStage; + } + +void TControlStageSm::ClearPendingRead() + { + iTransferMgr.iReadPending = EFalse; + } + +// Code for DControlTransferManager +// + +DControlTransferManager::DControlTransferManager(MControlTransferIf& aCtrTransIf): + iCtrTransferIf(aCtrTransIf) + { + for(int i=0; iIsRequstAllowed(TControlTransferRequestRead)) + { + if(!iReadPending) + { + iReadPending = ETrue; + return CtrTransferIf().ProcessSetupEndpointZeroRead(); + } + else + { + // A read operation already on going, ignore this request + return KErrNone; + } + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SetupEndpointZeroRead discard")); + return KErrNotReady; + } + } + +TInt DControlTransferManager::SetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd) + { + if(iState[iCurrentStage]->IsRequstAllowed(TControlTransferRequestWrite)) + { + return CtrTransferIf().ProcessSetupEndpointZeroWrite(aBuffer,aLength,aZlpReqd); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SetupEndpointZeroWrite discard")); + return KErrNotReady; + } + } + +TInt DControlTransferManager::SendEp0ZeroByteStatusPacket() + { + if(iState[iCurrentStage]->IsRequstAllowed(TControlTransferRequestSendStatus)) + { + iCurrentStage = UsbShai::EControlTransferStageSetup; + return CtrTransferIf().ProcessSendEp0ZeroByteStatusPacket(); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SendEp0ZeroByteStatusPacket discard")); + return KErrNotReady; + } + } + +TInt DControlTransferManager::StallEndpoint(TInt aRealEndpoint) + { + // Endpoint is stalled, we need to reset our state machine. + Reset(); + return CtrTransferIf().ProcessStallEndpoint(aRealEndpoint); + } + +void DControlTransferManager::Ep0SetupPacketProceed() + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! Missed setup packet processed")); + CtrTransferIf().ProcessEp0SetupPacketProceed(); + } + +void DControlTransferManager::Ep0DataPacketProceed() + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! Missed data packet processed")); + CtrTransferIf().ProcessEp0DataPacketProceed(); + } + +void DControlTransferManager::Reset() + { + iCurrentStage = UsbShai::EControlTransferStageSetup; + iReadPending = EFalse; + } + +void DControlTransferManager::Ep0RequestComplete(TUint8* aBuf, + TInt aCount, + TInt aError, + UsbShai::TControlPacketType aPktType) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "> DControlTransferManager::Ep0RequestComplete, packet type: %s", DebugName[aPktType])); + // If a setup packet comes, update our local setup packet buffer first + if(aPktType == UsbShai::EControlPacketTypeSetup) + { + iPacketParser.Set(aBuf); + // This is the only place this variable to be reset. + iDataTransfered = 0; + } + + // RequestComplete will return ETrue if it can not handle a packet + // And it knows that some other sm can handle it. + // It will update the state to the one which can hanlde that packet first. + TBool furtherProcessNeeded = ETrue; + while(furtherProcessNeeded) + { + __KTRACE_OPT(KUSB, Kern::Printf(" We're at Stage: %s", DebugName[iCurrentStage])); + furtherProcessNeeded = iState[iCurrentStage]->RequestComplete(aCount,aError,aPktType); + __KTRACE_OPT(KUSB, Kern::Printf(" We're moved to stage: %s", DebugName[iCurrentStage])); + } + + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "< DControlTransferManager::Ep0RequestComplete")); + } + +// setup the state machine for a state +void DControlTransferManager::AddState(UsbShai::TControlStage aStage,TControlStageSm& aStageSm) + { + if( (aStage >= UsbShai::EControlTransferStageSetup) && (aStage < UsbShai::EControlTransferStageMax)) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " AddState(), Stage: %s", DebugName[aStage])); + iState[aStage] = &aStageSm; + } + } + +// *************** Code for SETUP state machines ************************************** +// +DSetupStageSm::DSetupStageSm(DControlTransferManager& aTransferMgr): + TControlStageSm(aTransferMgr) + { + } + +// WE are waiting a SETUP packet +TBool DSetupStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType) + { + TBool ret = EFalse; + + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "DSetupStageSm::RequestComplete")); + + if(aPktType != UsbShai::EControlPacketTypeSetup) + { + // we just discard any non-setup packet + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DSetupStageSm - Non-Setup recieved")); + return ret; + } + + // change state to whatever returned from this call. + ChangeToStage(iTransferMgr.PktParser().NextStage()); + + // We're going to complete User's read request, consume the previous + // read operation + ClearPendingRead(); + + // Setup packet are always need to be processed + iTransferMgr.CtrTransferIf().ProcessSetupPacket(aPktSize,aError); + + return EFalse; + } + +TBool DSetupStageSm::IsRequstAllowed(TControlTransferRequest aRequest) + { + // Allow user to read, No other operation is allowed + TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse; + + if( ! ret) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DSetupStageSm",aRequest)); + } + + return ret; + } + + +// *************** Code for DATA IN state machines ************************************** + +DDataInStageSm::DDataInStageSm(DControlTransferManager& aTransferMgr): + TControlStageSm(aTransferMgr) + { + } + +// We are waiting for a competion of DATA IN packet +TBool DDataInStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType) + { + TInt completionCode = aError; + TBool furtherRequest = EFalse; + + switch(aPktType) + { + case UsbShai::EControlPacketTypeSetup: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataInStageSm - Setup recieved")); + // Something goes wrong, host is abandoning the unfinished control transfer + completionCode = KErrGeneral; + + // Force SM restart at setup stage + ChangeToStage(UsbShai::EControlTransferStageSetup); + + // this packet is partially processed here + // need another SM to continue + furtherRequest = ETrue; + } + break; + + case UsbShai::EControlPacketTypeDataIn: + { + // PSL notifing us that the data had been sent to host + // next step is to wait for the status from Host + ChangeToStage(UsbShai::EControlTransferStageStatusOut); + + // In USB spec, a compete control transfer must inclue a status stage + // which is not case in reality,some PSL/Hardware will swallow the + // Status out report, so, we just complete client normally. + } + break; + + default: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataInStageSm - %s recieved",DebugName[aPktType])); + + // Unexpected packet will be discard, and lead us reset state machine + // so that we can wait for next SETUP packet. + // Of course error will be report to any client if any there. + ChangeToStage(UsbShai::EControlTransferStageSetup); + completionCode = KErrGeneral; + } + break; + } + + iTransferMgr.CtrTransferIf().ProcessDataInPacket(aPktSize,completionCode); + + return furtherRequest; + } + +TBool DDataInStageSm::IsRequstAllowed(TControlTransferRequest aRequest) + { + // Only write is possible because host is waiting for data from us + TBool ret = (aRequest == TControlTransferRequestWrite)?ETrue:EFalse; + + if( ! ret) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DDataInStageSm",aRequest)); + } + + return ret; + }; + +// *************** Code for STATUS OUT state machines ************************************** +DStatusOutStageSm::DStatusOutStageSm(DControlTransferManager& aTransferMgr): + TControlStageSm(aTransferMgr) + { + } + +// We are waiting for a competion of STATUS OUT or a SETUP packet if PSL or hardware don't +// complete a status in packet +TBool DStatusOutStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType) + { + TBool furtherRequest = EFalse; + TInt completionCode = aError; + + switch(aPktType) + { + case UsbShai::EControlPacketTypeSetup: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusOutStageSm - Setup recieved")); + // hw or PSL may not send back the status packet for a DATA OUT + // and we're ok for this, just back to EControlTransferStageSetup stage + + // Force SM restart at setup stage + ChangeToStage(UsbShai::EControlTransferStageSetup); + + // this packet is partially processed here + // need another SM to continue + furtherRequest = ETrue; + } + break; + + case UsbShai::EControlPacketTypeStatusOut: + { + // Force SM restart at setup stage + ChangeToStage(UsbShai::EControlTransferStageSetup); + } + break; + + default: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusOutStageSm - %s recieved",DebugName[aPktType])); + + // Unexpected packet will be discard, and lead us reset state machine + // so that we can wait for next SETUP packet. + // Of course error will be report to any client if any there. + ChangeToStage(UsbShai::EControlTransferStageSetup); + completionCode = KErrGeneral; + } + break; + } + + iTransferMgr.CtrTransferIf().ProcessStatusOutPacket(completionCode); + + return furtherRequest; + + } + +TBool DStatusOutStageSm::IsRequstAllowed(TControlTransferRequest aRequest) + { + // Read is ok since client don't care the status out stage. + // and this lead no hurt to anybody. + TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse; + + if( ! ret) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DStatusOutStageSm",aRequest)); + } + + return ret; + }; + +// *************** Code for DATA OUT state machines ************************************** +// +DDataOutStageSm::DDataOutStageSm(DControlTransferManager& aTransferMgr): + TControlStageSm(aTransferMgr) + { + } + +TBool DDataOutStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType) + { + TBool furtherRequest = EFalse; + TInt completionCode = aError; + + switch(aPktType) + { + case UsbShai::EControlPacketTypeSetup: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataOutStageSm - Setup recieved")); + // Host is abandon the previous Transfer + completionCode = KErrGeneral; + + // Force SM restart at setup stage + ChangeToStage(UsbShai::EControlTransferStageSetup); + + // this packet is partially processed here + // need another SM to continue + furtherRequest = ETrue; + } + break; + + case UsbShai::EControlPacketTypeDataOut: + { + iTransferMgr.DataReceived(aPktSize); + + if(!iTransferMgr.IsMoreBytesNeeded()) + { + // We had recieved enough bytes as indicated by the setup + // packet, Data stage is finished. enter STATUS IN state + ChangeToStage(UsbShai::EControlTransferStageStatusIn); + } + } + break; + + case UsbShai::EControlPacketTypeStatusIn: + { + // Status in had been sent to host + // return and waiting for new SETUP + ChangeToStage(UsbShai::EControlTransferStageSetup); + } + break; + + default: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataOutStageSm - %s recieved",DebugName[aPktType])); + + // Unexpected packet will be discard, and lead us reset state machine + // so that we can wait for next SETUP packet. + // Of course error will be report to any client if any there. + ChangeToStage(UsbShai::EControlTransferStageSetup); + completionCode = KErrGeneral; + } + break; + } + + ClearPendingRead(); + iTransferMgr.CtrTransferIf().ProcessDataOutPacket(aPktSize,completionCode); + + return furtherRequest; + } + +TBool DDataOutStageSm::IsRequstAllowed(TControlTransferRequest aRequest) + { + // only read operation is allowed in data out stage. + TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse; + + if( ! ret) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DDataOutStageSm",aRequest)); + } + + return ret; + }; + +// *************** Code for DATA OUT state machines ************************************** +// +DStatusInStageSm::DStatusInStageSm(DControlTransferManager& aTransferMgr): + TControlStageSm(aTransferMgr) + { + } + +TBool DStatusInStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType) + { + TBool furtherRequest = EFalse; + TInt completionCode = KErrNone; + + switch(aPktType) + { + case UsbShai::EControlPacketTypeSetup: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusInStageSm - Setup recieved")); + // Status in is an optional for PSL + // If we received a setup packet here, we assume the previous + // status in packet had been successfully sent to host. + + // Force SM restart at setup stage + ChangeToStage(UsbShai::EControlTransferStageSetup); + + // this packet is partially processed here + // need another SM to continue + furtherRequest = ETrue; + } + break; + + case UsbShai::EControlPacketTypeStatusIn: + { + // Status in had been recieved, monitor setup packet then. + ChangeToStage(UsbShai::EControlTransferStageSetup); + } + break; + + default: + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusInStageSm - %s recieved",DebugName[aPktType])); + + // Unexpected packet will be discard, and lead us reset state machine + // so that we can wait for next SETUP packet. + // Of course error will be report to any client if any there. + ChangeToStage(UsbShai::EControlTransferStageSetup); + completionCode = KErrGeneral; + } + break; + } + + iTransferMgr.CtrTransferIf().ProcessStatusInPacket(completionCode); + + return furtherRequest; + } + +TBool DStatusInStageSm::IsRequstAllowed(TControlTransferRequest aRequest) + { + // Read is ok even we are wait for the client to send a zero status packet + TBool ret = ((aRequest == TControlTransferRequestSendStatus) || + (aRequest == TControlTransferRequestRead))?ETrue:EFalse; + + if( ! ret) + { + __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DStatusInStageSm",aRequest)); + } + + return ret; + } + +// End of file + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/descriptors.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/descriptors.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,2362 @@ +// Copyright (c) 2000-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/usbcc/descriptors.cpp +// Platform independent layer (PIL) of the USB Device controller driver: +// USB descriptor handling and management. +// +// + +/** + @file descriptors.cpp + @internalTechnology +*/ + +#include +// #include +#include + + +// Debug Support +static const char KUsbPanicCat[] = "USB PIL"; + + +// --- TUsbcDescriptorBase + +TUsbcDescriptorBase::TUsbcDescriptorBase() + : +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + iIndex(0), +#endif + iBufPtr(NULL, 0) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorBase::TUsbcDescriptorBase()")); + } + + +TUsbcDescriptorBase::~TUsbcDescriptorBase() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorBase::~TUsbcDescriptorBase()")); + } + + +void TUsbcDescriptorBase::SetByte(TInt aPosition, TUint8 aValue) + { + iBufPtr[aPosition] = aValue; + } + + +void TUsbcDescriptorBase::SetWord(TInt aPosition, TUint16 aValue) + { + *reinterpret_cast(&iBufPtr[aPosition]) = SWAP_BYTES_16(aValue); + } + + +TUint8 TUsbcDescriptorBase::Byte(TInt aPosition) const + { + return iBufPtr[aPosition]; + } + + +TUint16 TUsbcDescriptorBase::Word(TInt aPosition) const + { + return SWAP_BYTES_16(*reinterpret_cast(&iBufPtr[aPosition])); + } + + +void TUsbcDescriptorBase::GetDescriptorData(TDes8& aBuffer) const + { + aBuffer = iBufPtr; + } + + +TInt TUsbcDescriptorBase::GetDescriptorData(TUint8* aBuffer) const + { + memcpy(aBuffer, iBufPtr.Ptr(), Size()); + return Size(); + } + + +TInt TUsbcDescriptorBase::GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const + { + if (aMaxSize < Size()) + { + // No use to copy only half a descriptor + return 0; + } + return GetDescriptorData(aBuffer); + } + + +const TDes8& TUsbcDescriptorBase::DescriptorData() const + { + return iBufPtr; + } + + +TDes8& TUsbcDescriptorBase::DescriptorData() + { + return iBufPtr; + } + + +TUint TUsbcDescriptorBase::Size() const + { + return iBufPtr.Size(); + } + + +TUint8 TUsbcDescriptorBase::Type() const + { + return iBufPtr[1]; + } + + +void TUsbcDescriptorBase::UpdateFs() + { + // virtual function can be overridden in derived classes. + return; + } + + +void TUsbcDescriptorBase::UpdateHs() + { + // virtual function can be overridden in derived classes. + return; + } + + +void TUsbcDescriptorBase::SetBufferPointer(const TDesC8& aDes) + { + iBufPtr.Set(const_cast(aDes.Ptr()), aDes.Size(), aDes.Size()); + } + + +// --- TUsbcDeviceDescriptor + +TUsbcDeviceDescriptor::TUsbcDeviceDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::TUsbcDeviceDescriptor()")); + } + + +TUsbcDeviceDescriptor* TUsbcDeviceDescriptor::New(TUint8 aDeviceClass, TUint8 aDeviceSubClass, + TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0, + TUint16 aVendorId, TUint16 aProductId, + TUint16 aDeviceRelease, TUint8 aNumConfigurations) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::New()")); + TUsbcDeviceDescriptor* self = new TUsbcDeviceDescriptor(); + if (self) + { + if (self->Construct(aDeviceClass, aDeviceSubClass, aDeviceProtocol, aMaxPacketSize0, aVendorId, + aProductId, aDeviceRelease, aNumConfigurations) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcDeviceDescriptor::Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass, TUint8 aDeviceProtocol, + TUint8 aMaxPacketSize0, TUint16 aVendorId, TUint16 aProductId, + TUint16 aDeviceRelease, TUint8 aNumConfigurations) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::Construct()")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Device; // bDescriptorType + SetWord(2, KUsbcUsbVersion); // bcdUSB + iBuf[4] = aDeviceClass; // bDeviceClass + iBuf[5] = aDeviceSubClass; // bDeviceSubClass + iBuf[6] = aDeviceProtocol; // bDeviceProtocol + iBuf[7] = aMaxPacketSize0; // bMaxPacketSize0 + SetWord(8, aVendorId); // idVendor + SetWord(10, aProductId); // idProduct + SetWord(12, aDeviceRelease); // bcdDevice + iBuf[14] = 0; // iManufacturer + iBuf[15] = 0; // iProduct + iBuf[16] = 0; // iSerialNumber + iBuf[17] = aNumConfigurations; // bNumConfigurations + iEp0Size_Fs = aMaxPacketSize0; + return KErrNone; + } + + +void TUsbcDeviceDescriptor::UpdateFs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::UpdateFs()")); + SetByte(7, iEp0Size_Fs); // bMaxPacketSize0 + } + + +void TUsbcDeviceDescriptor::UpdateHs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::UpdateHs()")); + SetByte(7, 64); // bMaxPacketSize0 + } + + +// --- TUsbcDeviceQualifierDescriptor + +TUsbcDeviceQualifierDescriptor::TUsbcDeviceQualifierDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceDescriptor::TUsbcDeviceQualifierDescriptor()")); + } + + +TUsbcDeviceQualifierDescriptor* TUsbcDeviceQualifierDescriptor::New(TUint8 aDeviceClass, + TUint8 aDeviceSubClass, + TUint8 aDeviceProtocol, + TUint8 aMaxPacketSize0, + TUint8 aNumConfigurations, + TUint8 aReserved) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::New()")); + TUsbcDeviceQualifierDescriptor* self = new TUsbcDeviceQualifierDescriptor(); + if (self) + { + if (self->Construct(aDeviceClass, aDeviceSubClass, aDeviceProtocol, aMaxPacketSize0, + aNumConfigurations, aReserved) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcDeviceQualifierDescriptor::Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass, + TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0, + TUint8 aNumConfigurations, TUint8 aReserved) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::Construct()")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_DeviceQualifier; // bDescriptorType + SetWord(2, KUsbcUsbVersion); // bcdUSB + iBuf[4] = aDeviceClass; // bDeviceClass + iBuf[5] = aDeviceSubClass; // bDeviceSubClass + iBuf[6] = aDeviceProtocol; // bDeviceProtocol + iBuf[7] = aMaxPacketSize0; // bMaxPacketSize0 + iBuf[8] = aNumConfigurations; // bNumConfigurations + if (aReserved) aReserved = 0; + iBuf[9] = aReserved; // Reserved for future use, must be zero + iEp0Size_Fs = aMaxPacketSize0; + return KErrNone; + } + + +void TUsbcDeviceQualifierDescriptor::UpdateFs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::UpdateFs()")); + // Here we do exactly the opposite of what's done in the Device descriptor (as this one's + // documenting the 'other than the current speed'). + SetByte(7, 64); // bMaxPacketSize0 + } + + +void TUsbcDeviceQualifierDescriptor::UpdateHs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDeviceQualifierDescriptor::UpdateHs()")); + // Here we do exactly the opposite of what's done in the Device descriptor (as this one's + // documenting the 'other than the current speed'). + SetByte(7, iEp0Size_Fs); // bMaxPacketSize0 + } + + +// --- TUsbcConfigDescriptor + +TUsbcConfigDescriptor::TUsbcConfigDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::TUsbcConfigDescriptor()")); + } + + +TUsbcConfigDescriptor* TUsbcConfigDescriptor::New(TUint8 aConfigurationValue, TBool aSelfPowered, + TBool aRemoteWakeup, TUint16 aMaxPower) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::New()")); + TUsbcConfigDescriptor* self = new TUsbcConfigDescriptor(); + if (self) + { + if (self->Construct(aConfigurationValue, aSelfPowered, aRemoteWakeup, aMaxPower) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcConfigDescriptor::Construct(TUint8 aConfigurationValue, TBool aSelfPowered, + TBool aRemoteWakeup, TUint16 aMaxPower) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfigDescriptor::Construct()")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Config; // bDescriptorType + SetWord(2, KUsbDescSize_Config); // wTotalLength + iBuf[4] = 0; // bNumInterfaces + iBuf[5] = aConfigurationValue; // bConfigurationValue + iBuf[6] = 0; // iConfiguration + iBuf[7] = 0x80 | + (aSelfPowered ? KUsbDevAttr_SelfPowered : 0) | + (aRemoteWakeup ? KUsbDevAttr_RemoteWakeup : 0); // bmAttributes (bit 7 always 1) + if (aMaxPower > 510) + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid value for bMaxPower: %d", aMaxPower)); + iBuf[8] = aMaxPower / 2; // bMaxPower (2mA units!) + return KErrNone; + } + + +// --- TUsbcInterfaceDescriptor + +TUsbcInterfaceDescriptor::TUsbcInterfaceDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::TUsbcInterfaceDescriptor()")); + } + + +TUsbcInterfaceDescriptor* TUsbcInterfaceDescriptor::New(TUint8 aInterfaceNumber, TUint8 aAlternateSetting, + TInt aNumEndpoints, const TUsbcClassInfo& aClassInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::New()")); + TUsbcInterfaceDescriptor* self = new TUsbcInterfaceDescriptor(); + if (self) + { + if (self->Construct(aInterfaceNumber, aAlternateSetting, aNumEndpoints, aClassInfo) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcInterfaceDescriptor::Construct(TUint8 aInterfaceNumber, TUint8 aAlternateSetting, + TInt aNumEndpoints, const TUsbcClassInfo& aClassInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceDescriptor::Construct()")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Interface; // bDescriptorType + iBuf[2] = aInterfaceNumber; // bInterfaceNumber + iBuf[3] = aAlternateSetting; // bAlternateSetting + iBuf[4] = aNumEndpoints; // bNumEndpoints + iBuf[5] = aClassInfo.iClassNum; // bInterfaceClass + iBuf[6] = aClassInfo.iSubClassNum; // bInterfaceSubClass + iBuf[7] = aClassInfo.iProtocolNum; // bInterfaceProtocol + iBuf[8] = 0; // iInterface + return KErrNone; + } + + +// --- TUsbcEndpointDescriptorBase + +TUsbcEndpointDescriptorBase::TUsbcEndpointDescriptorBase() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::TUsbcEndpointDescriptorBase()")); + } + + +TInt TUsbcEndpointDescriptorBase::Construct(const TUsbcEndpointInfo& aEpInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::Construct()")); + // Adjust FS/HS endpoint sizes + if (aEpInfo.AdjustEpSizes(iEpSize_Fs, iEpSize_Hs) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown endpoint type: %d", aEpInfo.iType)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iEpSize_Fs=%d iEpSize_Hs=%d (aEpInfo.iSize=%d)", + iEpSize_Fs, iEpSize_Hs, aEpInfo.iSize)); + + // Adjust HS endpoint size for additional transactions + if ((aEpInfo.iType == UsbShai::KUsbEpTypeIsochronous) || (aEpInfo.iType == UsbShai::KUsbEpTypeInterrupt)) + { + if ((aEpInfo.iTransactions > 0) && (aEpInfo.iTransactions < 3)) + { + // Bits 12..11 specify the number of additional transactions per microframe + iEpSize_Hs |= (aEpInfo.iTransactions << 12); + __KTRACE_OPT(KUSB, Kern::Printf(" Adjusted for add. transact.: iEpSize_Hs=0x%02x " + "(aEpInfo.iTransactions=%d)", + iEpSize_Hs, aEpInfo.iTransactions)); + } + else if (aEpInfo.iTransactions != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Invalid iTransactions value: %d (ignored)", + aEpInfo.iTransactions)); + } + } + + // Adjust HS polling interval + TUsbcEndpointInfo info(aEpInfo); // create local writeable copy + if (info.AdjustPollInterval() != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown ep type (%d) or invalid interval value (%d)", + info.iType, info.iInterval)); + } + iInterval_Fs = info.iInterval; + iInterval_Hs = info.iInterval_Hs; + __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iInterval_Fs=%d iInterval_Hs=%d", + iInterval_Fs, iInterval_Hs)); + return KErrNone; + } + + +void TUsbcEndpointDescriptorBase::UpdateFs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::UpdateFs()")); + // (TUsbcEndpointDescriptorBase's FS/HS endpoint sizes and interval values got + // adjusted in its Construct() method.) + SetWord(4, iEpSize_Fs); // wMaxPacketSize + SetByte(6, iInterval_Fs); // bInterval + } + + +void TUsbcEndpointDescriptorBase::UpdateHs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptorBase::UpdateHs()")); + // (TUsbcEndpointDescriptorBase's FS/HS endpoint sizes and interval values get + // adjusted in its Construct() method.) + SetWord(4, iEpSize_Hs); // wMaxPacketSize + SetByte(6, iInterval_Hs); // bInterval + } + + +// --- TUsbcEndpointDescriptor + +TUsbcEndpointDescriptor::TUsbcEndpointDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::TUsbcEndpointDescriptor()")); + } + + +TUsbcEndpointDescriptor* TUsbcEndpointDescriptor::New(TUint8 aEndpointAddress, + const TUsbcEndpointInfo& aEpInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::New()")); + TUsbcEndpointDescriptor* self = new TUsbcEndpointDescriptor(); + if (self) + { + if (self->Construct(aEndpointAddress, aEpInfo) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcEndpointDescriptor::Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcEndpointDescriptor::Construct()")); + (void) TUsbcEndpointDescriptorBase::Construct(aEpInfo); // Init Base class + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Endpoint; // bDescriptorType + iBuf[2] = aEndpointAddress; // bEndpointAddress + iBuf[3] = EpTypeMask2Value(aEpInfo.iType); // bmAttributes + SetWord(4, iEpSize_Fs); // wMaxPacketSize (default is FS) + iBuf[6] = iInterval_Fs; // bInterval (default is FS) + return KErrNone; + } + + +// --- TUsbcAudioEndpointDescriptor + +TUsbcAudioEndpointDescriptor::TUsbcAudioEndpointDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::TUsbcAudioEndpointDescriptor()")); + } + + +TUsbcAudioEndpointDescriptor* TUsbcAudioEndpointDescriptor::New(TUint8 aEndpointAddress, + const TUsbcEndpointInfo& aEpInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::New()")); + TUsbcAudioEndpointDescriptor* self = new TUsbcAudioEndpointDescriptor(); + if (self) + { + if (self->Construct(aEndpointAddress, aEpInfo) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcAudioEndpointDescriptor::Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcAudioEndpointDescriptor::Construct()")); + (void) TUsbcEndpointDescriptorBase::Construct(aEpInfo); // Init Base class + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Endpoint; // bDescriptorType + iBuf[2] = aEndpointAddress; // bEndpointAddress + iBuf[3] = EpTypeMask2Value(aEpInfo.iType); // bmAttributes + SetWord(4, iEpSize_Fs); // wMaxPacketSize (default is FS) + iBuf[6] = iInterval_Fs; // bInterval (default is FS) + iBuf[7] = 0; + iBuf[8] = 0; + return KErrNone; + } + + +// --- TUsbcOtgDescriptor + +TUsbcOtgDescriptor* TUsbcOtgDescriptor::New(TBool aHnpSupport, TBool aSrpSupport) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::New()")); + TUsbcOtgDescriptor* self = new TUsbcOtgDescriptor(); + if (self && (self->Construct(aHnpSupport, aSrpSupport) != KErrNone)) + { + delete self; + return NULL; + } + return self; + } + + +TUsbcOtgDescriptor::TUsbcOtgDescriptor() + : iBuf() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::TUsbcOtgDescriptor()")); + } + + +TInt TUsbcOtgDescriptor::Construct(TBool aHnpSupport, TBool aSrpSupport) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcOtgDescriptor::Construct()")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBuf[0] = iBuf.Size(); // bLength + iBuf[1] = KUsbDescType_Otg; // bDescriptorType + iBuf[2] = (aHnpSupport ? KUsbOtgAttr_HnpSupp : 0) | + (aSrpSupport ? KUsbOtgAttr_SrpSupp : 0); // bmAttributes + return KErrNone; + } + + +// --- TUsbcClassSpecificDescriptor + +TUsbcClassSpecificDescriptor::TUsbcClassSpecificDescriptor() + : iBuf(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::TUsbcClassSpecificDescriptor()")); + } + + +TUsbcClassSpecificDescriptor::~TUsbcClassSpecificDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::~TUsbcClassSpecificDescriptor()")); + delete iBuf; + } + + +TUsbcClassSpecificDescriptor* TUsbcClassSpecificDescriptor::New(TUint8 aType, TInt aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::New()")); + TUsbcClassSpecificDescriptor* self = new TUsbcClassSpecificDescriptor(); + if (self) + { + if (self->Construct(aType, aSize) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcClassSpecificDescriptor::Construct(TUint8 aType, TInt aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcClassSpecificDescriptor::Construct()")); + iBuf = HBuf8::New(aSize); + if (!iBuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Allocation of CS desc buffer failed")); + return KErrNoMemory; + } + iBuf->SetMax(); + SetBufferPointer(*iBuf); + SetByte(1, aType); // bDescriptorType + return KErrNone; + } + + +// --- TUsbcStringDescriptorBase + +TUsbcStringDescriptorBase::TUsbcStringDescriptorBase() + : /*iIndex(0),*/ iSBuf(0), iBufPtr(NULL, 0) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptorBase::TUsbcStringDescriptorBase()")); + } + + +TUsbcStringDescriptorBase::~TUsbcStringDescriptorBase() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptorBase::~TUsbcStringDescriptorBase()")); + } + + +TUint16 TUsbcStringDescriptorBase::Word(TInt aPosition) const + { + if (aPosition <= 1) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Word(%d) in string descriptor " + "(TUsbcStringDescriptorBase::Word)", aPosition)); + return 0; + } + else + { + // since iBufPtr[0] is actually string descriptor byte index 2, + // we have to subtract 2 from the absolute position. + return SWAP_BYTES_16(*reinterpret_cast(&iBufPtr[aPosition - 2])); + } + } + + +void TUsbcStringDescriptorBase::SetWord(TInt aPosition, TUint16 aValue) + { + if (aPosition <= 1) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetWord(%d) in string descriptor " + "(TUsbcStringDescriptorBase::SetWord)", aPosition)); + return; + } + else + { + // since iBufPtr[0] is actually string descriptor byte index 2, + // we have to subtract 2 from the absolute position. + *reinterpret_cast(&iBufPtr[aPosition - 2]) = SWAP_BYTES_16(aValue); + } + } + + +TInt TUsbcStringDescriptorBase::GetDescriptorData(TUint8* aBuffer) const + { + aBuffer[0] = iSBuf[0]; + aBuffer[1] = iSBuf[1]; + memcpy(&aBuffer[2], iBufPtr.Ptr(), iBufPtr.Size()); + return Size(); + } + + +TInt TUsbcStringDescriptorBase::GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const + { + if (aMaxSize < Size()) + { + // No use to copy only half a string + return 0; + } + return GetDescriptorData(aBuffer); + } + + +const TDes8& TUsbcStringDescriptorBase::StringData() const + { + return iBufPtr; + } + + +TDes8& TUsbcStringDescriptorBase::StringData() + { + return iBufPtr; + } + + +TUint TUsbcStringDescriptorBase::Size() const + { + return iSBuf[0]; + } + + +void TUsbcStringDescriptorBase::SetBufferPointer(const TDesC8& aDes) + { + iBufPtr.Set(const_cast(aDes.Ptr()), aDes.Size(), aDes.Size()); + } + + +// --- TUsbcStringDescriptor + +TUsbcStringDescriptor::TUsbcStringDescriptor() + : iBuf(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::TUsbcStringDescriptor()")); + } + + +TUsbcStringDescriptor::~TUsbcStringDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::~TUsbcStringDescriptor()")); + delete iBuf; + } + + +TUsbcStringDescriptor* TUsbcStringDescriptor::New(const TDesC8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::New")); + TUsbcStringDescriptor* self = new TUsbcStringDescriptor(); + if (self) + { + if (self->Construct(aString) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcStringDescriptor::Construct(const TDesC8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcStringDescriptor::Construct")); + iBuf = HBuf8::New(aString.Size()); // bytes, not UNICODE chars + if (!iBuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Allocation of string buffer failed")); + return KErrNoMemory; + } + iBuf->SetMax(); + SetBufferPointer(*iBuf); + iBufPtr.Copy(aString); + iSBuf.SetMax(); + iSBuf[0] = iBuf->Size() + 2; // Bytes + iSBuf[1] = KUsbDescType_String; + return KErrNone; + } + + +// --- TUsbcLangIdDescriptor + +TUsbcLangIdDescriptor::TUsbcLangIdDescriptor() + : iBuf(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::TUsbcLangIdDescriptor()")); + } + + +TUsbcLangIdDescriptor::~TUsbcLangIdDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::~TUsbcLangIdDescriptor()")); + } + + +TUsbcLangIdDescriptor* TUsbcLangIdDescriptor::New(TUint16 aLangId) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::New")); + TUsbcLangIdDescriptor* self = new TUsbcLangIdDescriptor(); + if (self) + { + if (self->Construct(aLangId) != KErrNone) + { + delete self; + return NULL; + } + } + return self; + } + + +TInt TUsbcLangIdDescriptor::Construct(TUint16 aLangId) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLangIdDescriptor::Construct")); + iBuf.SetMax(); + SetBufferPointer(iBuf); + iBufPtr[0] = LowByte(SWAP_BYTES_16(aLangId)); // Language ID value + iBufPtr[1] = HighByte(SWAP_BYTES_16(aLangId)); + iSBuf.SetMax(); + iSBuf[0] = iBuf.Size() + 2; // Bytes + iSBuf[1] = KUsbDescType_String; + return KErrNone; + } + + +// --- TUsbcDescriptorPool + +TUsbcDescriptorPool::TUsbcDescriptorPool(TUint8* aEp0_TxBuf) +// +// The constructor for this class. +// + : iDescriptors(), iStrings(), iIfcIdx(0), iEp0_TxBuf(aEp0_TxBuf), iHighSpeed(EFalse) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::TUsbcDescriptorPool()")); + } + + +TUsbcDescriptorPool::~TUsbcDescriptorPool() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::~TUsbcDescriptorPool()")); + // The destructor of each object is called before the objects themselves are destroyed. + __KTRACE_OPT(KUSB, Kern::Printf(" iDescriptors.Count(): %d", iDescriptors.Count())); + iDescriptors.ResetAndDestroy(); + __KTRACE_OPT(KUSB, Kern::Printf(" iStrings.Count(): %d", iStrings.Count())); + iStrings.ResetAndDestroy(); + } + + +TInt TUsbcDescriptorPool::Init(TUsbcDeviceDescriptor* aDeviceDesc, TUsbcConfigDescriptor* aConfigDesc, + TUsbcLangIdDescriptor* aLangId, TUsbcStringDescriptor* aManufacturer, + TUsbcStringDescriptor* aProduct, TUsbcStringDescriptor* aSerialNum, + TUsbcStringDescriptor* aConfig, TUsbcOtgDescriptor* aOtgDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::Init()")); + if (!aDeviceDesc || !aConfigDesc) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: No Device or Config descriptor specified")); + return KErrArgument; + } + for (TInt n = 0; n < KDescPosition_FirstAvailable; n++) + { + iDescriptors.Append(NULL); + } + __ASSERT_DEBUG((iDescriptors.Count() == KDescPosition_FirstAvailable), + Kern::Printf(" Error: iDescriptors.Count() (%d) != KDescPosition_FirstAvailable (%d)", + iDescriptors.Count(), KDescPosition_FirstAvailable)); + iDescriptors[KDescPosition_Device] = aDeviceDesc; + iDescriptors[KDescPosition_Config] = aConfigDesc; + if (aOtgDesc) + { + iDescriptors[KDescPosition_Otg] = aOtgDesc; + // Update the config descriptor's wTotalLength field + UpdateConfigDescriptorLength(KUsbDescSize_Otg); + } + if (!aLangId) + { + // USB spec 9.6.7 says: "String index zero for all languages returns a string descriptor + // that contains an array of two-byte LANGID codes supported by the device. ... + // USB devices that omit all string descriptors must not return an array of LANGID codes." + // So if we have at least one string descriptor, we must also have a LANGID descriptor. + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: No LANGID string descriptor specified")); + return KErrArgument; + } + iStrings.Insert(aLangId, KStringPosition_Langid); + iStrings.Insert(aManufacturer, KStringPosition_Manufact); + iStrings.Insert(aProduct, KStringPosition_Product); + iStrings.Insert(aSerialNum, KStringPosition_Serial); + iStrings.Insert(aConfig, KStringPosition_Config); + __ASSERT_DEBUG((iStrings.Count() == 5), + Kern::Printf(" Error: iStrings.Count() != 5 (%d)", iStrings.Count())); +#ifdef _DEBUG + for (TInt i = KStringPosition_Langid; i <= KStringPosition_Config; i++) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool.iStrings[%d] = 0x%x", i, iStrings[i])); + } +#endif + // Set string indices + if (aManufacturer) + iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Manufact, + KStringPosition_Manufact); + if (aProduct) + iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Product, + KStringPosition_Product); + if (aSerialNum) + iDescriptors[KDescPosition_Device]->SetByte(KUsbDescStringIndex_Serial, + KStringPosition_Serial); + if (aConfig) + iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config, + KStringPosition_Config); + return KErrNone; + } + + +TInt TUsbcDescriptorPool::InitHs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InitHs()")); + __ASSERT_DEBUG((iDescriptors.Count() >= KDescPosition_FirstAvailable), + Kern::Printf(" Error: Call Init() first)")); + + TUsbcDeviceQualifierDescriptor* const dq_desc = TUsbcDeviceQualifierDescriptor::New( + iDescriptors[KDescPosition_Device]->Byte(4), // aDeviceClass + iDescriptors[KDescPosition_Device]->Byte(5), // aDeviceSubClass + iDescriptors[KDescPosition_Device]->Byte(6), // aDeviceProtocol + iDescriptors[KDescPosition_Device]->Byte(7), // aMaxPacketSize0 + iDescriptors[KDescPosition_Device]->Byte(17)); // aNumConfigurations + if (!dq_desc) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for dev qualif desc failed.")); + return KErrGeneral; + } + iDescriptors[KDescPosition_DeviceQualifier] = dq_desc; + + TUsbcOtherSpeedConfigDescriptor* const osc_desc = TUsbcOtherSpeedConfigDescriptor::New( + iDescriptors[KDescPosition_Config]->Byte(5), // aConfigurationValue + iDescriptors[KDescPosition_Config]->Byte(7) & KUsbDevAttr_SelfPowered, // aSelfPowered + iDescriptors[KDescPosition_Config]->Byte(7) & KUsbDevAttr_RemoteWakeup, // aRemoteWakeup + iDescriptors[KDescPosition_Config]->Byte(8) * 2); // aMaxPower (mA) + if (!osc_desc) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for other speed conf desc failed.")); + return KErrGeneral; + } + + // We need to set the bDescriptorType field manually, as that's the only one + // that differs from a Configuration descriptor. + osc_desc->SetByte(1, KUsbDescType_OtherSpeedConfig); + + // Also, initially we set the iConfiguration string index to the same value as + // in the Configuration descriptor. + osc_desc->SetByte(KUsbDescStringIndex_Config, + iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config)); + + iDescriptors[KDescPosition_OtherSpeedConfig] = osc_desc; + + return KErrNone; + } + + +TInt TUsbcDescriptorPool::UpdateDescriptorsFs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateDescriptorsFs()")); + const TInt count = iDescriptors.Count(); + for (TInt i = KDescPosition_FirstAvailable; i < count; i++) + { + TUsbcDescriptorBase* const ptr = iDescriptors[i]; + ptr->UpdateFs(); + } + iHighSpeed = EFalse; + return KErrNone; + } + + +TInt TUsbcDescriptorPool::UpdateDescriptorsHs() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateDescriptorsHs()")); + const TInt count = iDescriptors.Count(); + for (TInt i = KDescPosition_FirstAvailable; i < count; i++) + { + TUsbcDescriptorBase* const ptr = iDescriptors[i]; + ptr->UpdateHs(); + } + iHighSpeed = ETrue; + return KErrNone; + } + + +// +// An error can be indicated by either a return value != KErrNone or by a descriptor size == 0. +// +TInt TUsbcDescriptorPool::FindDescriptor(TUint8 aType, TUint8 aIndex, TUint16 aLangid, TInt& aSize) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindDescriptor()")); + TInt result = KErrGeneral; + switch (aType) + { + case KUsbDescType_Device: + if (aLangid != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad langid: 0x%04x", aLangid)); + } + else if (aIndex > 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad device index: %d", aIndex)); + } + else + { + aSize = GetDeviceDescriptor(KDescPosition_Device); + result = KErrNone; + } + break; + case KUsbDescType_Config: + if (aLangid != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad langid: 0x%04x", aLangid)); + } + else if (aIndex > 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad config index: %d", aIndex)); + } + else + { + aSize = GetConfigurationDescriptor(KDescPosition_Config); + result = KErrNone; + } + break; + case KUsbDescType_DeviceQualifier: + if (aLangid != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad langid: 0x%04x", aLangid)); + } + else if (aIndex > 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad device index: %d", aIndex)); + } + else + { + aSize = GetDeviceDescriptor(KDescPosition_DeviceQualifier); + result = KErrNone; + } + break; + case KUsbDescType_OtherSpeedConfig: + if (aLangid != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad langid: 0x%04x", aLangid)); + } + else if (aIndex > 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bad config index: %d", aIndex)); + } + else + { + aSize = GetConfigurationDescriptor(KDescPosition_OtherSpeedConfig); + result = KErrNone; + } + break; + case KUsbDescType_Otg: + aSize = GetOtgDescriptor(); + result = KErrNone; + break; + case KUsbDescType_String: + if (aIndex == 0) // 0 addresses the LangId array + { + if (AnyStringDescriptors()) + { + aSize = GetStringDescriptor(aIndex); + result = KErrNone; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" No string descriptors: not returning LANGID array")); + } + } + else + { + if (!aLangid) + { + __KTRACE_OPT(KUSB, + Kern::Printf(" Strange: LANGID=0 for a $ descriptor (ignoring LANGID)")); + // The USB spec doesn't really say what to do in this case, but as there are host apps + // that fail if we return an error here, we choose to ignore the issue. + } + else if (aLangid != iStrings[KStringPosition_Langid]->Word(2)) + { + // We have only one (this) language + __KTRACE_OPT(KUSB, + Kern::Printf(" Bad LANGID: 0x%04X requested, 0x%04X supported (ignoring LANGID)", + aLangid, iStrings[KStringPosition_Langid]->Word(2))); + // We could return an error here, but rather choose to ignore the discrepancy + // (the USB spec is not very clear what to do in such a case anyway). + } + aSize = GetStringDescriptor(aIndex); + result = KErrNone; + } + break; + case KUsbDescType_CS_Interface: + /* fall through */ + case KUsbDescType_CS_Endpoint: + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: finding of class specific descriptors not supported")); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: unknown descriptor type requested: %d", aType)); + break; + } + return result; + } + + +void TUsbcDescriptorPool::InsertDescriptor(TUsbcDescriptorBase* aDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertDescriptor()")); + switch (aDesc->Type()) + { + case KUsbDescType_Interface: + InsertIfcDesc(aDesc); + break; + case KUsbDescType_Endpoint: + InsertEpDesc(aDesc); + break; + default: + __KTRACE_OPT(KUSB, Kern::Printf(" Error: unsupported descriptor type")); + } + } + + +void TUsbcDescriptorPool::SetIfcStringDescriptor(TUsbcStringDescriptor* aDesc, TInt aNumber, TInt aSetting) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetIfcDescriptor(%d, %d)", aNumber, aSetting)); + const TInt i = FindIfcDescriptor(aNumber, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifc descriptor not found (%d, %d)", + aNumber, aSetting)); + return; + } + // Try to find available NULL postition + TInt str_idx = FindAvailableStringPos(); + if (str_idx >= 0) + { + // Insert string descriptor for specified interface + ExchangeStringDescriptor(str_idx, aDesc); + } + else + { + // No NULL found - expand array + str_idx = iStrings.Count(); + if (str_idx > 0xff) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: $ descriptor array full (idx=%d)", str_idx)); + return; + } + while (str_idx < KStringPosition_FirstAvailable) + { + iStrings.Append(NULL); + str_idx = iStrings.Count(); + } + // Append string descriptor for specified interface + iStrings.Append(aDesc); + } + // Update this ifc descriptor's string index field + iDescriptors[i]->SetByte(8, str_idx); + __KTRACE_OPT(KUSB, Kern::Printf(" String for ifc %d/%d (@ pos %d): \"%S\"", aNumber, aSetting, str_idx, + &iStrings[str_idx]->StringData())); + } + + +void TUsbcDescriptorPool::DeleteIfcDescriptor(TInt aNumber, TInt aSetting) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::DeleteIfcDescriptor(%d, %d)", aNumber, aSetting)); + const TInt i = FindIfcDescriptor(aNumber, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DeleteIfcDescriptor - descriptor not found (%d, %d)", + aNumber, aSetting)); + return; + } + // Delete (if necessary) specified interface's string descriptor + const TInt si = iDescriptors[i]->Byte(8); + if (si != 0) + { + ExchangeStringDescriptor(si, NULL); + } + // Delete specified ifc setting + all its cs descriptors + all its endpoints + all their cs descriptors: + // find position of the next interface descriptor: we need to delete everything in between + const TInt count = iDescriptors.Count(); + TInt j = i, n = 1; + while (++j < count && iDescriptors[j]->Type() != KUsbDescType_Interface) + ++n; + DeleteDescriptors(i, n); + // Update all the following interfaces' bInterfaceNumber field if required + // (because those descriptors might have moved down by one position) + UpdateIfcNumbers(aNumber); + iIfcIdx = 0; // ifc index no longer valid + } + + +// The TC in many of the following functions stands for 'ThreadCopy', +// because that's what's happening there. + +TInt TUsbcDescriptorPool::GetDeviceDescriptorTC(DThread* aThread, TDes8& aBuffer) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceDescriptorTC()")); + return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Device]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetDeviceDescriptorTC(DThread* aThread, const TDes8& aBuffer) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceDescriptorTC()")); + TBuf8 device; + const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, device, 0); + if (r != KErrNone) + { + return r; + } + iDescriptors[KDescPosition_Device]->SetByte(2, device[2]); // bcdUSB + iDescriptors[KDescPosition_Device]->SetByte(3, device[3]); // bcdUSB (part II) + iDescriptors[KDescPosition_Device]->SetByte(4, device[4]); // bDeviceClass + iDescriptors[KDescPosition_Device]->SetByte(5, device[5]); // bDeviceSubClass + iDescriptors[KDescPosition_Device]->SetByte(6, device[6]); // bDeviceProtocol + iDescriptors[KDescPosition_Device]->SetByte(8, device[8]); // idVendor + iDescriptors[KDescPosition_Device]->SetByte(9, device[9]); // idVendor (part II) + iDescriptors[KDescPosition_Device]->SetByte(10, device[10]); // idProduct + iDescriptors[KDescPosition_Device]->SetByte(11, device[11]); // idProduct (part II) + iDescriptors[KDescPosition_Device]->SetByte(12, device[12]); // bcdDevice + iDescriptors[KDescPosition_Device]->SetByte(13, device[13]); // bcdDevice (part II) + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetConfigurationDescriptorTC()")); + return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Config]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetConfigurationDescriptorTC()")); + TBuf8 config; + const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, config, 0); + if (r != KErrNone) + { + return r; + } + iDescriptors[KDescPosition_Config]->SetByte(7, config[7]); // bmAttributes + iDescriptors[KDescPosition_Config]->SetByte(8, config[8]); // bMaxPower + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetOtgDescriptorTC(DThread* aThread, TDes8& aBuffer) const + { + return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[KDescPosition_Otg]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetOtgDescriptor(const TDesC8& aBuffer) + { + iDescriptors[KDescPosition_Otg]->SetByte(2, aBuffer[2]); // bmAttributes + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer, + TInt aInterface, TInt aSetting) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetInterfaceDescriptorTC()")); + const TInt i = FindIfcDescriptor(aInterface, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return KErrNotFound; + } + return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetInterfaceDescriptor(const TDes8& aBuffer, TInt aInterface, TInt aSetting) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetInterfaceDescriptor()")); + const TInt i = FindIfcDescriptor(aInterface, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return KErrNotFound; + } + iDescriptors[i]->SetByte(2, aBuffer[2]); // bInterfaceNumber + iDescriptors[i]->SetByte(5, aBuffer[5]); // bInterfaceClass + iDescriptors[i]->SetByte(6, aBuffer[6]); // bInterfaceSubClass + iDescriptors[i]->SetByte(7, aBuffer[7]); // bInterfaceProtocol + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer, + TInt aInterface, TInt aSetting, TUint8 aEndpointAddress) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetEndpointDescriptorTC()")); + const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + return Kern::ThreadDesWrite(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer, + TInt aInterface, TInt aSetting, TUint8 aEndpointAddress) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetEndpointDescriptorTC()")); + const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + TBuf8 ep; // it could be an audio endpoint + const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, ep, 0); + if (r != KErrNone) + { + return r; + } + iDescriptors[i]->SetByte(3, ep[3]); // bmAttributes + iDescriptors[i]->SetByte(6, ep[6]); // bInterval + if (iDescriptors[i]->Size() == KUsbDescSize_AudioEndpoint) + { + iDescriptors[i]->SetByte(7, ep[7]); // bRefresh + iDescriptors[i]->SetByte(8, ep[8]); // bSynchAddress + } + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetEndpointDescriptorSize(TInt aInterface, TInt aSetting, TUint8 aEndpointAddress, + TInt& aSize) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetEndpointDescriptorSize()")); + const TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + aSize = iDescriptors[i]->Size(); + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetDeviceQualifierDescriptorTC(DThread* aThread, TDes8& aBuffer) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceQualifierDescriptorTC()")); + if (iDescriptors[KDescPosition_DeviceQualifier] == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Device_Qualifier descriptor not supported")); + return KErrNotSupported; + } + return Kern::ThreadDesWrite(aThread, &aBuffer, + iDescriptors[KDescPosition_DeviceQualifier]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetDeviceQualifierDescriptorTC(DThread* aThread, const TDes8& aBuffer) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceQualifierDescriptorTC()")); + if (iDescriptors[KDescPosition_DeviceQualifier] == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Device_Qualifier descriptor not supported")); + return KErrNotSupported; + } + TBuf8 device; + const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, device, 0); + if (r != KErrNone) + { + return r; + } + iDescriptors[KDescPosition_DeviceQualifier]->SetByte(2, device[2]); // bcdUSB + iDescriptors[KDescPosition_DeviceQualifier]->SetByte(3, device[3]); // bcdUSB (part II) + iDescriptors[KDescPosition_DeviceQualifier]->SetByte(4, device[4]); // bDeviceClass + iDescriptors[KDescPosition_DeviceQualifier]->SetByte(5, device[5]); // bDeviceSubClass + iDescriptors[KDescPosition_DeviceQualifier]->SetByte(6, device[6]); // bDeviceProtocol + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetOtherSpeedConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetOtherSpeedConfigurationDescriptorTC()")); + if (iDescriptors[KDescPosition_OtherSpeedConfig] == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Other_Speed_Configuration descriptor not supported")); + return KErrNotSupported; + } + return Kern::ThreadDesWrite(aThread, &aBuffer, + iDescriptors[KDescPosition_OtherSpeedConfig]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::SetOtherSpeedConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetOtherSpeedConfigurationDescriptorTC()")); + if (iDescriptors[KDescPosition_OtherSpeedConfig] == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Other_Speed_Configuration descriptor not supported")); + return KErrNotSupported; + } + TBuf8 config; + const TInt r = Kern::ThreadDesRead(aThread, &aBuffer, config, 0); + if (r != KErrNone) + { + return r; + } + iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(7, config[7]); // bmAttributes + iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(8, config[8]); // bMaxPower + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetCSInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer, + TInt aInterface, TInt aSetting) const + { + // first find the interface + TInt i = FindIfcDescriptor(aInterface, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return KErrNotFound; + } + TInt r = KErrNotFound; + TInt offset = 0; + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface) + { + r = Kern::ThreadDesWrite(aThread, &aBuffer, + iDescriptors[i]->DescriptorData(), offset); + if (r != KErrNone) + break; + offset += iDescriptors[i]->Size(); + } + return r; + } + + +TInt TUsbcDescriptorPool::SetCSInterfaceDescriptorTC(DThread* aThread, const TDes8& aBuffer, + TInt aInterface, TInt aSetting, TInt aSize) + { + // First find the interface + TInt i = FindIfcDescriptor(aInterface, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return KErrNotFound; + } + // Find a position where to insert the new class specific interface descriptor(s) + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface) + ; + // Create a new cs descriptor + TUsbcClassSpecificDescriptor* desc = TUsbcClassSpecificDescriptor::New(KUsbDescType_CS_Interface, aSize); + if (!desc) + { + return KErrNoMemory; + } + __KTRACE_OPT(KUSB, Kern::Printf(" inserting descriptor at position %d", i)); + iDescriptors.Insert(desc, i); + + // Update the config descriptor's wTotalLength field + UpdateConfigDescriptorLength(aSize); + + // Copy contents from the user side + return Kern::ThreadDesRead(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::GetCSInterfaceDescriptorSize(TInt aInterface, TInt aSetting, TInt& aSize) const + { + // first find the interface + TInt i = FindIfcDescriptor(aInterface, aSetting); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return KErrNotFound; + } + TInt r = KErrNotFound; + TInt size = 0; + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Interface) + { + size += iDescriptors[i]->Size(); + r = KErrNone; + } + if (r == KErrNone) + aSize = size; + return r; + } + + +TInt TUsbcDescriptorPool::GetCSEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface, + TInt aSetting, TUint8 aEndpointAddress) const + { + // first find the endpoint + TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + TInt r = KErrNotFound; + TInt offset = 0; + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint) + { + r = Kern::ThreadDesWrite(aThread, &aBuffer, + iDescriptors[i]->DescriptorData(), offset); + if (r != KErrNone) + break; + offset += iDescriptors[i]->Size(); + } + return r; + } + + +TInt TUsbcDescriptorPool::SetCSEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer, TInt aInterface, + TInt aSetting, TUint8 aEndpointAddress, TInt aSize) + { + // first find the endpoint + TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + // find a position where to insert the new class specific endpoint descriptor(s) + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint) + ; + // create a new cs descriptor + TUsbcClassSpecificDescriptor* desc = TUsbcClassSpecificDescriptor::New(KUsbDescType_CS_Endpoint, aSize); + if (!desc) + { + return KErrNoMemory; + } + iDescriptors.Insert(desc, i); + // update the config descriptor's wTotalLength field + UpdateConfigDescriptorLength(aSize); + // copy contents from user side + return Kern::ThreadDesRead(aThread, &aBuffer, iDescriptors[i]->DescriptorData(), 0); + } + + +TInt TUsbcDescriptorPool::GetCSEndpointDescriptorSize(TInt aInterface, TInt aSetting, + TUint8 aEndpointAddress, TInt& aSize) const + { + // first find the endpoint + TInt i = FindEpDescriptor(aInterface, aSetting, aEndpointAddress); + if (i < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return KErrNotFound; + } + TInt r = KErrNotFound; + TInt size = 0; + const TInt count = iDescriptors.Count(); + while (++i < count && iDescriptors[i]->Type() == KUsbDescType_CS_Endpoint) + { + size += iDescriptors[i]->Size(); + r = KErrNone; + } + if (r == KErrNone) + aSize = size; + return r; + } + + +TInt TUsbcDescriptorPool::GetStringDescriptorLangIdTC(DThread* aThread, TDes8& aLangId) const + { + const TUint16 id = iStrings[KStringPosition_Langid]->Word(2); + const TPtrC8 id_des(reinterpret_cast(&id), sizeof(id)); + return Kern::ThreadDesWrite(aThread, &aLangId, id_des, 0); + } + + +TInt TUsbcDescriptorPool::SetStringDescriptorLangId(TUint16 aLangId) + { + iStrings[KStringPosition_Langid]->SetWord(2, aLangId); + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetManufacturerStringDescriptorTC(DThread* aThread, TDes8& aString) const + { + return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Manufact, + KStringPosition_Manufact); + } + + +TInt TUsbcDescriptorPool::SetManufacturerStringDescriptorTC(DThread* aThread, const TDes8& aString) + { + return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Manufact, + KStringPosition_Manufact); + } + + +TInt TUsbcDescriptorPool::RemoveManufacturerStringDescriptor() + { + return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Manufact, KStringPosition_Manufact); + } + + +TInt TUsbcDescriptorPool::GetProductStringDescriptorTC(DThread* aThread, TDes8& aString) const + { + return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Product, + KStringPosition_Product); + } + + +TInt TUsbcDescriptorPool::SetProductStringDescriptorTC(DThread* aThread, const TDes8& aString) + { + return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Product, + KStringPosition_Product); + } + + +TInt TUsbcDescriptorPool::RemoveProductStringDescriptor() + { + return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Product, KStringPosition_Product); + } + + +TInt TUsbcDescriptorPool::GetSerialNumberStringDescriptorTC(DThread* aThread, TDes8& aString) const + { + return GetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Serial, + KStringPosition_Serial); + } + + +TInt TUsbcDescriptorPool::SetSerialNumberStringDescriptorTC(DThread* aThread, const TDes8& aString) + { + return SetDeviceStringDescriptorTC(aThread, aString, KUsbDescStringIndex_Serial, + KStringPosition_Serial); + } + + +TInt TUsbcDescriptorPool::RemoveSerialNumberStringDescriptor() + { + return RemoveDeviceStringDescriptor(KUsbDescStringIndex_Serial, KStringPosition_Serial); + } + + +TInt TUsbcDescriptorPool::GetConfigurationStringDescriptorTC(DThread* aThread, TDes8& aString) const + { + const TInt str_idx = iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config); + if (str_idx) + { + __ASSERT_ALWAYS((str_idx == KStringPosition_Config), Kern::Fault(KUsbPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" String @ pos %d (conf $): \"%S\"", + str_idx, &iStrings[str_idx]->StringData())); + return Kern::ThreadDesWrite(aThread, &aString, + iStrings[str_idx]->StringData(), 0); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" No config string descriptor @ pos %d", str_idx)); + return KErrNotFound; + } + } + + +TInt TUsbcDescriptorPool::SetConfigurationStringDescriptorTC(DThread* aThread, const TDes8& aString) + { + // we don't know the length of the string, so we have to allocate memory dynamically + TUint strlen = Kern::ThreadGetDesLength(aThread, &aString); + if (strlen > KUsbStringDescStringMaxSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: config $ descriptor too long - will be truncated")); + strlen = KUsbStringDescStringMaxSize; + } + HBuf8* const strbuf = HBuf8::New(strlen); + if (!strbuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for config $ desc string failed (1)")); + return KErrNoMemory; + } + strbuf->SetMax(); + // the aString points to data that lives in user memory, so we have to copy it: + const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); + delete strbuf; + return r; + } + TUsbcStringDescriptor* sd = TUsbcStringDescriptor::New(*strbuf); + if (!sd) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for config $ desc failed (2)")); + delete strbuf; + return KErrNoMemory; + } + // Delete old string, put in new one + ExchangeStringDescriptor(KStringPosition_Config, sd); + // Update Config descriptor string index field + iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config, KStringPosition_Config); + // Update Other_Speed_Config descriptor string index field as well, if applicable + if (iDescriptors[KDescPosition_OtherSpeedConfig]) + iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(KUsbDescStringIndex_Config, + KStringPosition_Config); + delete strbuf; + return KErrNone; + } + + +TInt TUsbcDescriptorPool::RemoveConfigurationStringDescriptor() + { + if (iDescriptors[KDescPosition_Config]->Byte(KUsbDescStringIndex_Config) == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" RemoveConfigurationStringDescriptor: no $ desc @ index %d", + KUsbDescStringIndex_Config)); + return KErrNotFound; + } + // Delete old string, put in NULL pointer + ExchangeStringDescriptor(KStringPosition_Config, NULL); + // Update Config descriptor string index field + iDescriptors[KDescPosition_Config]->SetByte(KUsbDescStringIndex_Config, 0); + // Update Other_Speed_Config descriptor string index field as well, if applicable + if (iDescriptors[KDescPosition_OtherSpeedConfig]) + iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(KUsbDescStringIndex_Config, 0); + return KErrNone; + } + + +TInt TUsbcDescriptorPool::GetStringDescriptorTC(DThread* aThread, TInt aIndex, TDes8& aString) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetStringDescriptorTC()")); + if (!StringDescriptorExists(aIndex)) + { + return KErrNotFound; + } + __KTRACE_OPT(KUSB, Kern::Printf(" String @ pos %d: \"%S\"", + aIndex, &iStrings[aIndex]->StringData())); + return Kern::ThreadDesWrite(aThread, &aString, iStrings[aIndex]->StringData(), 0); + } + + +TInt TUsbcDescriptorPool::SetStringDescriptorTC(DThread* aThread, TInt aIndex, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetStringDescriptorTC()")); + // we don't know the length of the string, so we have to allocate memory dynamically + TUint strlen = Kern::ThreadGetDesLength(aThread, &aString); + if (strlen > KUsbStringDescStringMaxSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: $ descriptor too long - will be truncated")); + strlen = KUsbStringDescStringMaxSize; + } + HBuf8* strbuf = HBuf8::New(strlen); + if (!strbuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Mem alloc for $ desc string failed (1)")); + return KErrNoMemory; + } + strbuf->SetMax(); + // the aString points to data that lives in user memory, so we have to copy it over: + const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); + delete strbuf; + return r; + } + TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*strbuf); + if (!sd) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Mem alloc for $ desc failed (2)")); + delete strbuf; + return KErrNoMemory; + } + if (aIndex < iStrings.Count()) + { + ExchangeStringDescriptor(aIndex, sd); + } + else // if (aIndex >= iStrings.Count()) + { + while (aIndex > iStrings.Count()) + { + iStrings.Append(NULL); + } + iStrings.Append(sd); + } + delete strbuf; + return KErrNone; + } + + +TInt TUsbcDescriptorPool::RemoveStringDescriptor(TInt aIndex) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::RemoveStringDescriptor()")); + if (!StringDescriptorExists(aIndex)) + { + return KErrNotFound; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Removing string @ pos %d: \"%S\"", + aIndex, &iStrings[aIndex]->StringData())); + ExchangeStringDescriptor(aIndex, NULL); + + // Make sure there's no $ after aIndex. + const TInt n = iStrings.Count(); + for (TInt i = aIndex; i < n; i++) + { + if (iStrings[i] != NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Found $ @ idx %d - not compressing", i)); + return KErrNone; + } + } + + __KTRACE_OPT(KUSB, Kern::Printf(" No $ found after idx %d - compressing array", aIndex)); + // Move aIndex back just before the first !NULL element. + while (iStrings[--aIndex] == NULL) + ; + // Let aIndex point to first NULL. + aIndex++; + __KTRACE_OPT(KUSB, Kern::Printf(" Starting at index %d", aIndex)); + // Now remove NULL pointers until (Count() == aIndex). + __KTRACE_OPT(KUSB, Kern::Printf(" iStrings.Count() before: %d", iStrings.Count())); + do + { + iStrings.Remove(aIndex); + __KTRACE_OPT(KUSB, Kern::Printf(" Removing $")); + } + while (iStrings.Count() > aIndex); + __KTRACE_OPT(KUSB, Kern::Printf(" iStrings.Count() after: %d", iStrings.Count())); + + // Regain some memory. + iStrings.Compress(); + + return KErrNone; + } + + +// =================================================================== +// --- private --- +// =================================================================== + +// +// Insert an Interface descriptor into the descriptor array at the appropriate index. +// +void TUsbcDescriptorPool::InsertIfcDesc(TUsbcDescriptorBase* aDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertIfcDesc()")); + + const TInt count = iDescriptors.Count(); + TBool ifc_exists = EFalse; // set to 'true' if we're adding an alternate + // setting to an already existing interface + TInt i = KDescPosition_FirstAvailable; + while (i < count) + { + __KTRACE_OPT(KUSB, Kern::Printf(" already descriptors there (%d)...", count)); + if (iDescriptors[i]->Type() == KUsbDescType_Interface) + { + if (iDescriptors[i]->Byte(2) > aDesc->Byte(2)) + { + // our interface number is less than the one's just found => insert before it (= here) + break; + } + else if (iDescriptors[i]->Byte(2) == aDesc->Byte(2)) + { + ifc_exists = ETrue; + // same interface number => look at settings number + if (iDescriptors[i]->Byte(3) > aDesc->Byte(3)) + { + // our setting number is less than the one's found => insert before (= here) + break; + } + else if (iDescriptors[i]->Byte(3) == aDesc->Byte(3)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: first delete old desc " + "(TUsbcDescriptorPool::InsertIfcDesc)")); + return; + } + } + } + ++i; + } + // In any case: put the new descriptor at position i. + __KTRACE_OPT(KUSB, Kern::Printf(" inserting descriptor at position %d", i)); + iDescriptors.Insert(aDesc, i); + + // Update the config descriptor's wTotalLength field. + UpdateConfigDescriptorLength(KUsbDescSize_Interface); + + if (!ifc_exists) + { + // If this is the first setting for the interface, increment bNumInterfaces. + UpdateConfigDescriptorNumIfcs(1); + } + + iIfcIdx = i; + } + + +// +// Insert an Endpoint descriptor into the descriptor array at the appropriate index. +// +void TUsbcDescriptorPool::InsertEpDesc(TUsbcDescriptorBase* aDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::InsertEpDesc()")); + if (iIfcIdx == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: only after interface " + "(TUsbcDescriptorPool::InsertEpDesc)")); + return; + } + const TInt count = iDescriptors.Count(); + TInt i = iIfcIdx + 1; + while (i < count) + { + if (iDescriptors[i]->Type() != KUsbDescType_Endpoint) + break; + ++i; + } + // put the new descriptor at position i + iDescriptors.Insert(aDesc, i); + // update the config descriptor's wTotalLength field + UpdateConfigDescriptorLength(aDesc->Size()); + } + + +// +// Find the index of the Interface descriptor for a given interface setting. +// +TInt TUsbcDescriptorPool::FindIfcDescriptor(TInt aIfcNumber, TInt aIfcSetting) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindIfcDescriptor(%d, %d)", + aIfcNumber, aIfcSetting)); + const TInt count = iDescriptors.Count(); + for (TInt i = KDescPosition_FirstAvailable; i < count; i++) + { + if ((iDescriptors[i]->Type() == KUsbDescType_Interface) && + (iDescriptors[i]->Byte(2) == aIfcNumber) && + (iDescriptors[i]->Byte(3) == aIfcSetting)) + { + return i; + } + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return -1; + } + + +// +// Find the index of the Endpoint descriptor for a given endpoint on a given interface setting. +// +TInt TUsbcDescriptorPool::FindEpDescriptor(TInt aIfcNumber, TInt aIfcSetting, TUint8 aEpAddress) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindEpDescriptor(%d, %d, 0x%02x)", + aIfcNumber, aIfcSetting, aEpAddress)); + // first find the interface + const TInt ifc = FindIfcDescriptor(aIfcNumber, aIfcSetting); + if (ifc < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such interface")); + return ifc; + } + const TInt count = iDescriptors.Count(); + // then, before the next interface, try to locate the endpoint + for (TInt i = ifc + 1; i < count; i++) + { + if (iDescriptors[i]->Type() == KUsbDescType_Interface) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint before next interface")); + return -1; + } + else if ((iDescriptors[i]->Type() == KUsbDescType_Endpoint) && + (iDescriptors[i]->Byte(2) == aEpAddress)) + { + // found + return i; + } + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no such endpoint")); + return -1; + } + + +// +// Delete n descriptors starting from aIndex and remove their pointers from the array. +// +void TUsbcDescriptorPool::DeleteDescriptors(TInt aIndex, TInt aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::DeleteDescriptors()")); + if (aIndex < KDescPosition_FirstAvailable) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aIndex < KDescPosition_FirstAvailable")); + return; + } + if (aCount <= 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aCount <= 0")); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Removing descriptors at index %d:", aIndex)); + // Try to update wTotalLength field in Config descriptor + while (aCount--) + { + // In this loop we don't decrement aIndex, because after deleting an element + // aIndex is already indexing the next one. + TUsbcDescriptorBase* const ptr = iDescriptors[aIndex]; + switch (ptr->Type()) + { + case KUsbDescType_Interface: + __KTRACE_OPT(KUSB, Kern::Printf(" - an interface descriptor")); + UpdateConfigDescriptorLength(-KUsbDescSize_Interface); + break; + case KUsbDescType_Endpoint: + __KTRACE_OPT(KUSB, Kern::Printf(" - an endpoint descriptor")); + UpdateConfigDescriptorLength(-ptr->Size()); + break; + case KUsbDescType_CS_Interface: + /* fall through */ + case KUsbDescType_CS_Endpoint: + __KTRACE_OPT(KUSB, Kern::Printf(" - a class specific descriptor")); + UpdateConfigDescriptorLength(-ptr->Size()); + break; + default: + __KTRACE_OPT(KUSB, Kern::Printf(" - an unknown descriptor")); + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: unknown descriptor type")); + } + iDescriptors.Remove(aIndex); + delete ptr; + } + } + + +// +// Update the wTotalLength field in the Configuration descriptor (aLength can be negative). +// +void TUsbcDescriptorPool::UpdateConfigDescriptorLength(TInt aLength) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateConfigDescriptorLength(%d)", aLength)); + TUsbcDescriptorBase* const cnf = iDescriptors[KDescPosition_Config]; + __KTRACE_OPT(KUSB, Kern::Printf(" wTotalLength old: %d", cnf->Word(2))); + // Update Config descriptor + cnf->SetWord(2, cnf->Word(2) + aLength); + __KTRACE_OPT(KUSB, Kern::Printf(" wTotalLength new: %d", cnf->Word(2))); + // Update Other_Speed_Config descriptor as well, if applicable + if (iDescriptors[KDescPosition_OtherSpeedConfig]) + iDescriptors[KDescPosition_OtherSpeedConfig]->SetWord(2, cnf->Word(2)); + } + + +// +// Update the bNumInterfaces field in the Configuration descriptor (aNumber can be negative). +// +void TUsbcDescriptorPool::UpdateConfigDescriptorNumIfcs(TInt aNumber) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateConfigDescriptorNumIfcs(%d)", aNumber)); + TUsbcDescriptorBase* const cnf = iDescriptors[KDescPosition_Config]; + __KTRACE_OPT(KUSB, Kern::Printf(" bNumInterfaces old: %d", cnf->Byte(4))); + const TInt n = cnf->Byte(4) + aNumber; + if (n < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bNumInterfaces + aNumber < 0")); + return; + } + // Update Config descriptor + cnf->SetByte(4, n); + __KTRACE_OPT(KUSB, Kern::Printf(" bNumInterfaces new: %d", cnf->Byte(4))); + // Update Other_Speed_Config descriptor as well, if applicable + if (iDescriptors[KDescPosition_OtherSpeedConfig]) + iDescriptors[KDescPosition_OtherSpeedConfig]->SetByte(4, n); + } + + +// +// Update the bNumInterfaces field in the Configuration descriptor if necessary. +// +void TUsbcDescriptorPool::UpdateIfcNumbers(TInt aNumber) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::UpdateIfcNumbers(%d)", aNumber)); + const TInt count = iDescriptors.Count(); + for (TInt i = KDescPosition_FirstAvailable; i < count; i++) + { + if ((iDescriptors[i]->Type() == KUsbDescType_Interface) && + (iDescriptors[i]->Byte(2) == aNumber)) + { + // there's still an interface with 'number' so we don't need to update anything + return; + } + } + // if we haven't returned yet, we decrement bNumInterfaces + UpdateConfigDescriptorNumIfcs(-1); + } + + +// +// Put the current Device or Device_Qualifier descriptor in the Ep0 Tx buffer. +// Only used for Ep0 standard requests, so target buffer can be hard-wired. +// +TInt TUsbcDescriptorPool::GetDeviceDescriptor(TInt aIndex) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceDescriptor()")); + __ASSERT_DEBUG((aIndex == KDescPosition_Device) || (aIndex == KDescPosition_DeviceQualifier), + Kern::Printf(" Error: invalid descriptor index: %d", aIndex)); + if (iDescriptors[aIndex] == NULL) + { + // This doesn't have to be an error - we might get asked here for the Device_Qualifier descriptor + // on a FS-only device. + __KTRACE_OPT(KUSB, Kern::Printf(" Descriptor #%d requested but not available", aIndex)); + return 0; + } + return iDescriptors[aIndex]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx); + } + + +// +// Put the current Configuration or Other_Speed_Configuration descriptor + all the following +// descriptors in the Ep0 Tx buffer. +// Only used for Ep0 standard requests, so target buffer can be hard-wired. +// +TInt TUsbcDescriptorPool::GetConfigurationDescriptor(TInt aIndex) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetConfigDescriptor(%d)", aIndex)); + __ASSERT_DEBUG((aIndex == KDescPosition_Config) || (aIndex == KDescPosition_OtherSpeedConfig), + Kern::Printf(" Error: invalid descriptor index: %d", aIndex)); + if (iDescriptors[aIndex] == NULL) + { + // This is always an error: We should always have a Configuration descriptor and we should never + // get asked for the Other_Speed_Configuration descriptor if we don't have one (9.6.2). + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Descriptor %d requested but not available", aIndex)); + return 0; + } + const TInt count = iDescriptors.Count(); + TInt copied = 0; + TUint8* buf = iEp0_TxBuf; + for (TInt i = aIndex; i < count; i++) + { + TUsbcDescriptorBase* const ptr = iDescriptors[i]; + if ((aIndex == KDescPosition_OtherSpeedConfig) && (i == KDescPosition_Config)) + { + // Skip Config descriptor when returning Other_Speed_Config + continue; + } + if ((i == KDescPosition_Otg) && (iDescriptors[i] == NULL)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" no OTG descriptor -> next")); + continue; + } + // We need to edit endpoint descriptors on the fly because we have only one copy + // of each and that copy has to contain different information, depending on the + // current speed and the type of descriptor requested. + if (ptr->Type() == KUsbDescType_Endpoint) + { + if ((iHighSpeed && (aIndex == KDescPosition_Config)) || + (!iHighSpeed && (aIndex == KDescPosition_OtherSpeedConfig))) + { + ptr->UpdateHs(); + } + else + { + ptr->UpdateFs(); + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" desc[%02d]: type = 0x%02x size = %d ", + i, ptr->Type(), ptr->Size())); + const TInt size = ptr->GetDescriptorData(buf, KUsbcBufSz_Ep0Tx - copied); + if (size == 0) + { + __KTRACE_OPT(KPANIC, + Kern::Printf(" Error: No Tx buffer space to copy this descriptor -> exiting")); + break; + } + copied += size; + if (copied >= KUsbcBufSz_Ep0Tx) + { + __KTRACE_OPT(KPANIC, + Kern::Printf(" Error: No Tx buffer space left -> stopping here")); + break; + } + buf += size; + } + __KTRACE_OPT(KUSB, Kern::Printf(" copied %d bytes", copied)); + return copied; + } + + +// +// Put the current OTG descriptor in the Ep0 Tx buffer. +// Only used for Ep0 standard requests, so target buffer can be hard-wired. +// +TInt TUsbcDescriptorPool::GetOtgDescriptor() const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetOtgDescriptor()")); + if (iDescriptors[KDescPosition_Otg] == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf(" OTG Descriptor not set")); + return 0; + } + return iDescriptors[KDescPosition_Otg]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx); + } + + +// +// Put a specific String descriptor in the Ep0 Tx buffer. +// Only used for Ep0 standard requests, so target buffer can be hard-wired. +// +TInt TUsbcDescriptorPool::GetStringDescriptor(TInt aIndex) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetStringDescriptor(%d)", aIndex)); + // I really would have liked to display the descriptor contents here, but without trailing zero + // we got a problem: how can we tell printf where the string ends? We would have to + // dynamically allocate memory (since we don't know the size in advance), copy the descriptor + // contents there, append a zero, and give this to printf. That's a bit too much effort... + if (!StringDescriptorExists(aIndex)) + { + return 0; + } + return iStrings[aIndex]->GetDescriptorData(iEp0_TxBuf, KUsbcBufSz_Ep0Tx); + } + + +// +// Write a String descriptor pointed to by the Device descriptor to the user side +// (one of Manufacturer, Product, SerialNumber). +// +TInt TUsbcDescriptorPool::GetDeviceStringDescriptorTC(DThread* aThread, TDes8& aString, + TInt aIndex, TInt aPosition) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::GetDeviceStringDescriptorTC()")); + const TInt str_idx = iDescriptors[KDescPosition_Device]->Byte(aIndex); + if (str_idx) + { + __ASSERT_ALWAYS((str_idx == aPosition), Kern::Fault(KUsbPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" String @ pos %d (device $): \"%S\"", + str_idx, &iStrings[str_idx]->StringData())); + return Kern::ThreadDesWrite(aThread, &aString, + iStrings[str_idx]->StringData(), 0); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" No string descriptor @ pos %d", aIndex)); + return KErrNotFound; + } + } + + +// +// Read a Device String descriptor from the user side and put in the descriptor arrays +// (one of Manufacturer, Product, SerialNumber). +// +TInt TUsbcDescriptorPool::SetDeviceStringDescriptorTC(DThread* aThread, const TDes8& aString, + TInt aIndex, TInt aPosition) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::SetDeviceStringDescriptorTC()")); + // we don't know the length of the string, so we have to allocate memory dynamically + TUint strlen = Kern::ThreadGetDesLength(aThread, &aString); + if (strlen > KUsbStringDescStringMaxSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: $ descriptor too long - will be truncated")); + strlen = KUsbStringDescStringMaxSize; + } + HBuf8* const strbuf = HBuf8::New(strlen); + if (!strbuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for dev $ desc string failed (1)")); + return KErrNoMemory; + } + strbuf->SetMax(); + // the aString points to data that lives in user memory, so we have to copy it: + const TInt r = Kern::ThreadDesRead(aThread, &aString, *strbuf, 0); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); + delete strbuf; + return r; + } + TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*strbuf); + if (!sd) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for dev $ desc failed (2)")); + delete strbuf; + return KErrNoMemory; + } + ExchangeStringDescriptor(aPosition, sd); + iDescriptors[KDescPosition_Device]->SetByte(aIndex, aPosition); + delete strbuf; + return r; + } + + +// +// Remove a Device String descriptor from the descriptor arrays +// (one of Manufacturer, Product, SerialNumber). +// +TInt TUsbcDescriptorPool::RemoveDeviceStringDescriptor(TInt aIndex, TInt aPosition) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::RemoveDeviceStringDescriptor()")); + if (iDescriptors[KDescPosition_Device]->Byte(aIndex) == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" RemoveDeviceStringDescriptor: no $ desc @ index %d", aIndex)); + return KErrNotFound; + } + ExchangeStringDescriptor(aPosition, NULL); + iDescriptors[KDescPosition_Device]->SetByte(aIndex, 0); + return KErrNone; + } + + +// +// Puts aDesc at postion aIndex in the string descriptor array, after deleting what was (possibly) there. +// +void TUsbcDescriptorPool::ExchangeStringDescriptor(TInt aIndex, const TUsbcStringDescriptor* aDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::ExchangeStringDescriptor()")); + TUsbcStringDescriptorBase* const ptr = iStrings[aIndex]; + __KTRACE_OPT(KUSB, Kern::Printf(" Deleting string descriptor at index %d: 0x%x", aIndex, ptr)); + iStrings.Remove(aIndex); + delete ptr; + __KTRACE_OPT(KUSB, Kern::Printf(" Inserting string descriptor at index %d: 0x%x", aIndex, aDesc)); + iStrings.Insert(aDesc, aIndex); + } + + +// +// Checks whether there are any string descriptors in the array (apart from LangID). +// +TBool TUsbcDescriptorPool::AnyStringDescriptors() const + { + const TInt n = iStrings.Count(); + for (TInt i = 1; i < n; i++) + { + if (iStrings[i] != NULL) + return ETrue; + } + return EFalse; + } + + +// +// Returns true if aIndex exists and what is at that positition is not a NULL pointer. +// +TBool TUsbcDescriptorPool::StringDescriptorExists(TInt aIndex) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::StringDescriptorExists()")); + if (aIndex >= iStrings.Count()) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad string index: %d", aIndex)); + return EFalse; + } + else if (iStrings[aIndex] == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: No $ descriptor @ pos %d", aIndex)); + return EFalse; + } + return ETrue; + } + + +// +// +// +TInt TUsbcDescriptorPool::FindAvailableStringPos() const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcDescriptorPool::FindAvailableStringPos()")); + const TInt n = iStrings.Count(); + // We don't start from 0 because the first few locations are 'reserved'. + for (TInt i = KStringPosition_FirstAvailable; i < n; i++) + { + if (iStrings[i] == NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Found available NULL position: %d", i)); + return i; + } + } + return -1; + } + + +// -eof- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/misc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/misc.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,413 @@ +// Copyright (c) 2000-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/usbcc/misc.cpp +// Platform independent layer (PIL) of the USB Device controller driver: +// Implementations of misc. classes defined in usbc.h. +// +// + +/** + @file misc.cpp + @internalTechnology +*/ +// #include +#include + + +/** Helper function for logical endpoints and endpoint descriptors: + Split single Ep size into separate FS/HS sizes. + This function modifies its arguments. + */ +TInt TUsbcEndpointInfo::AdjustEpSizes(TInt& aEpSize_Fs, TInt& aEpSize_Hs) const + { + if (iType == UsbShai::KUsbEpTypeBulk) + { + // FS: [8|16|32|64] HS: 512 + if (iSize < 64) + { + aEpSize_Fs = iSize; + } + else + { + aEpSize_Fs = 64; + } + aEpSize_Hs = 512; + } + else if (iType == UsbShai::KUsbEpTypeInterrupt) + { + // FS: [0..64] HS: [0..1024] + if (iSize < 64) + { + aEpSize_Fs = iSize; + } + else + { + aEpSize_Fs = 64; + } + aEpSize_Hs = iSize; + } + else if (iType == UsbShai::KUsbEpTypeIsochronous) + { + // FS: [0..1023] HS: [0..1024] + if (iSize < 1023) + { + aEpSize_Fs = iSize; + } + else + { + aEpSize_Fs = 1023; + } + aEpSize_Hs = iSize; + } + else if (iType == UsbShai::KUsbEpTypeControl) + { + // FS: [8|16|32|64] HS: 64 + if (iSize < 64) + { + aEpSize_Fs = iSize; + } + else + { + aEpSize_Fs = 64; + } + aEpSize_Hs = 64; + } + else + { + aEpSize_Fs = aEpSize_Hs = 0; + return KErrGeneral; + } + + // For the reason of the following checks see Table 9-14. "Allowed wMaxPacketSize + // Values for Different Numbers of Transactions per Microframe". + if ((iType == UsbShai::KUsbEpTypeInterrupt) || (iType == UsbShai::KUsbEpTypeIsochronous)) + { + if (iTransactions == 1) + { + if (aEpSize_Hs < 513) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 513. Correcting...", + aEpSize_Hs)); + aEpSize_Hs = 513; + } + } + else if (iTransactions == 2) + { + if (aEpSize_Hs < 683) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 683. Correcting...", + aEpSize_Hs)); + aEpSize_Hs = 683; + } + } + } + return KErrNone; + } + + +/** Helper function for logical endpoints and endpoint descriptors: + If not set, assign a valid and meaningful value to iInterval_Hs, deriving from iInterval. + This function modifies the objects's data member(s). + */ +TInt TUsbcEndpointInfo::AdjustPollInterval() + { + if (iInterval_Hs != -1) + { + // Already done. + return KErrNone; + } + if ((iType == UsbShai::KUsbEpTypeBulk) || (iType == UsbShai::KUsbEpTypeControl)) + { + // Valid range: 0..255 (maximum NAK rate). + // (The host controller will probably ignore this value though - + // see the last sentence of section 9.6.6 for details.) + iInterval_Hs = 255; + } + else if (iType == UsbShai::KUsbEpTypeInterrupt) + { + // HS interval = 2^(iInterval_Hs-1) with a valid iInterval_Hs range of 1..16. + // The following table shows the mapping of HS values to actual intervals (and + // thus FS values) for the range of possible FS values (1..255). + // There is not always a 1:1 mapping possible, but we want at least to make sure + // that the HS polling interval is never longer than the FS one (except for 255). + // + // 1 = 1 + // 2 = 2 + // 3 = 4 + // 4 = 8 + // 5 = 16 + // 6 = 32 + // 7 = 64 + // 8 = 128 + // 9 = 256 + if (iInterval == 255) + iInterval_Hs = 9; + else if (iInterval >= 128) + iInterval_Hs = 8; + else if (iInterval >= 64) + iInterval_Hs = 7; + else if (iInterval >= 32) + iInterval_Hs = 6; + else if (iInterval >= 16) + iInterval_Hs = 5; + else if (iInterval >= 8) + iInterval_Hs = 4; + else if (iInterval >= 4) + iInterval_Hs = 3; + else if (iInterval >= 2) + iInterval_Hs = 2; + else if (iInterval == 1) + iInterval_Hs = 1; + else + { + // iInterval wasn't set properly by the user + iInterval_Hs = 1; + return KErrGeneral; + } + } + else if (iType == UsbShai::KUsbEpTypeIsochronous) + { + // Interpretation is the same for FS and HS. + iInterval_Hs = iInterval; + } + else + { + // '1' is a valid value for all endpoint types... + iInterval_Hs = 1; + return KErrGeneral; + } + return KErrNone; + } + + +TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint() + : iEndpointAddr(0), iIfcNumber(NULL), iLEndpoint(NULL), iSettingReserve(EFalse), iHalt(EFalse) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint")); + } + + +TInt TUsbcPhysicalEndpoint::TypeAvailable(TUint aType) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TypeAvailable")); + switch (aType) + { + case UsbShai::KUsbEpTypeControl: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpTypeControl); + case UsbShai::KUsbEpTypeIsochronous: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpTypeIsochronous); + case UsbShai::KUsbEpTypeBulk: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpTypeBulk); + case UsbShai::KUsbEpTypeInterrupt: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpTypeInterrupt); + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP type: %d", aType)); + return 0; + } + } + + +TInt TUsbcPhysicalEndpoint::DirAvailable(TUint aDir) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::DirAvailable")); + switch (aDir) + { + case UsbShai::KUsbEpDirIn: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpDirIn); + case UsbShai::KUsbEpDirOut: + return (iCaps.iTypesAndDir & UsbShai::KUsbEpDirOut); + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP direction: %d", aDir)); + return 0; + } + } + + +TInt TUsbcPhysicalEndpoint::EndpointSuitable(const TUsbcEndpointInfo* aEpInfo, TInt aIfcNumber) const + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::EndpointSuitable")); + __KTRACE_OPT(KUSB, Kern::Printf(" looking for EP: type=0x%x dir=0x%x size=%d (ifc_num=%d)", + aEpInfo->iType, aEpInfo->iDir, aEpInfo->iSize, aIfcNumber)); + if (iSettingReserve) + { + __KTRACE_OPT(KUSB, Kern::Printf(" -> setting conflict")); + return 0; + } + // (aIfcNumber == -1) means the ep is for a new default interface setting + else if (iIfcNumber && (*iIfcNumber != aIfcNumber)) + { + // If this endpoint has already been claimed (iIfcNumber != NULL), + // but by a different interface(-set) than the currently looking one + // (*iIfcNumber != aIfcNumber), then it's not available. + // This works because we can assign the same physical endpoint + // to different alternate settings of the *same* interface, and + // because we check for available endpoints for every alternate setting + // as a whole. + __KTRACE_OPT(KUSB, Kern::Printf(" -> ifc conflict")); + return 0; + } + else if (!TypeAvailable(aEpInfo->iType)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" -> type conflict")); + return 0; + } + else if (!DirAvailable(aEpInfo->iDir)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" -> direction conflict")); + return 0; + } + else if (!(iCaps.iSizes & PacketSize2Mask(aEpInfo->iSize)) && !(iCaps.iSizes & UsbShai::KUsbEpSizeCont)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" -> size conflict")); + return 0; + } + else + return 1; + } + + +TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint()")); + iLEndpoint = NULL; + } + + +TUsbcLogicalEndpoint::TUsbcLogicalEndpoint(DUsbClientController* aController, TUint aEndpointNum, + const TUsbcEndpointInfo& aEpInfo, TUsbcInterface* aInterface, + TUsbcPhysicalEndpoint* aPEndpoint) + : iController(aController), iLEndpointNum(aEndpointNum), iInfo(aEpInfo), iInterface(aInterface), + iPEndpoint(aPEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::TUsbcLogicalEndpoint()")); + // Adjust FS/HS endpoint sizes + if (iInfo.AdjustEpSizes(iEpSize_Fs, iEpSize_Hs) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown endpoint type: %d", iInfo.iType)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iEpSize_Fs=%d iEpSize_Hs=%d (iInfo.iSize=%d)", + iEpSize_Fs, iEpSize_Hs, iInfo.iSize)); + // Adjust HS polling interval + if (iInfo.AdjustPollInterval() != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown ep type (%d) or invalid interval value (%d)", + iInfo.iType, iInfo.iInterval)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iInfo.iInterval=%d iInfo.iInterval_Hs=%d", + iInfo.iInterval, iInfo.iInterval_Hs)); + // Additional transactions requested on a non High Bandwidth ep? + if ((iInfo.iTransactions > 0) && !aPEndpoint->iCaps.iHighBandwidth) + { + __KTRACE_OPT(KPANIC, + Kern::Printf(" Warning: Additional transactions requested but not a High Bandwidth ep")); + } + } + + +TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint: #%d", iLEndpointNum)); + // If the real endpoint this endpoint points to is also used by + // any other logical endpoint in any other setting of this interface + // then we leave the real endpoint marked as used. Otherwise we mark + // it as available (set its ifc number pointer to NULL). + const TInt n = iInterface->iInterfaceSet->iInterfaces.Count(); + for (TInt i = 0; i < n; ++i) + { + const TUsbcInterface* const ifc = iInterface->iInterfaceSet->iInterfaces[i]; + const TInt m = ifc->iEndpoints.Count(); + for (TInt j = 0; j < m; ++j) + { + const TUsbcLogicalEndpoint* const ep = ifc->iEndpoints[j]; + if ((ep->iPEndpoint == iPEndpoint) && (ep != this)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Physical endpoint still in use -> we leave it as is")); + return; + } + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" Closing DMA channel")); + const TInt idx = iController->EpAddr2Idx(iPEndpoint->iEndpointAddr); + // If the endpoint doesn't support DMA (now or ever) the next operation will be a no-op. + // iController->CloseDmaChannel(idx); + __KTRACE_OPT(KUSB, Kern::Printf(" Setting physical ep 0x%02x ifc number to NULL (was %d)", + iPEndpoint->iEndpointAddr, *iPEndpoint->iIfcNumber)); + iPEndpoint->iIfcNumber = NULL; + } + + +TUsbcInterface::TUsbcInterface(TUsbcInterfaceSet* aIfcSet, TUint8 aSetting, TBool aNoEp0Requests) + : iEndpoints(2), iInterfaceSet(aIfcSet), iSettingCode(aSetting), iNoEp0Requests(aNoEp0Requests) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::TUsbcInterface()")); + } + + +TUsbcInterface::~TUsbcInterface() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::~TUsbcInterface()")); + iEndpoints.ResetAndDestroy(); + } + + +TUsbcInterfaceSet::TUsbcInterfaceSet(const DBase* aClientId, TUint8 aIfcNum) + : iInterfaces(2), iClientId(aClientId), iInterfaceNumber(aIfcNum), iCurrentInterface(0) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::TUsbcInterfaceSet()")); + } + + +TUsbcInterfaceSet::~TUsbcInterfaceSet() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::~TUsbcInterfaceSet()")); + iInterfaces.ResetAndDestroy(); + } + + +TUsbcConfiguration::TUsbcConfiguration(TUint8 aConfigVal) + : iInterfaceSets(1), iConfigValue(aConfigVal) // iInterfaceSets(1): granularity + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::TUsbcConfiguration()")); + } + + +TUsbcConfiguration::~TUsbcConfiguration() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::~TUsbcConfiguration()")); + iInterfaceSets.ResetAndDestroy(); + } + + +_LIT(KDriverName, "Usbcc"); + +DUsbcPowerHandler::DUsbcPowerHandler(DUsbClientController* aController) + : DPowerHandler(KDriverName), iController(aController) + {} + + +void DUsbcPowerHandler::PowerUp() + { + if (iController) + iController->iPowerUpDfc.Enque(); + } + + +void DUsbcPowerHandler::PowerDown(TPowerState) + { + if (iController) + iController->iPowerDownDfc.Enque(); + } + + +// -eof- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/ps_usbc.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/ps_usbc.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,4832 @@ +// Copyright (c) 2000-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/usbcc/ps_usbc.cpp +// Platform independent layer (PIL) of the USB Device controller driver (PDD). +// Interface to the USB LDD. +// +// + +/** + @file ps_usbc.cpp + @internalTechnology +*/ +//#include +#include + +#include "controltransfersm.h" +/** + TUsbcInterfaceSet and TUsbcInterface + ==================================== + + TUsbcInterfaceSet represents a 'USB Interface' and TUsbcInterface + represents an 'Alternate Setting of a USB Interface'. + + Since every LDD governs exactly one interface, the above distinction is + made only within the USB implementation. At the LDD API, there is/are + simply one or more settings for this single interface, numbered from '0' + (the default) to 'n', and specified by the parameter 'TInt aInterfaceNum'. + + Within the PDD implementation, for a TUsbcInterfaceSet number the parameter + 'TInt aIfcSet' is used (local variable ifcset); for a TUsbcInterface number + the parameter 'TInt aIfc' is used (local variable ifc). + + + iConfigs[0] and CurrentConfig() + =============================== + + One problem with this file is that it always uses iConfigs[0] and not + CurrentConfig(). This is mainly because the API to the LDD doesn't know + about the concept of multiple configurations, and thus always assumes one + single configuration (which is also always active: a further problem). + + In the file chapter9.cpp this issue doesn't exist, since there we always + have to obey the USB protocol, and in this way will use the configuration + which is selected by the host (which will then again currently always be + iConfigs[0].) + + iEp0ClientId + ================================== + + The purpose of these two members of class DUsbClientController is the + following. + + They are used only during Ep0 control transactions which have an OUT (Rx) + data stage. We cannot deduce from the received data itself to whom + it is addressed (that's because of the shared nature of Ep0). + + In order to be able to tell whether received Ep0 data is to be processed by + the PIL or a LDD, we use iEp0ClientId. iEp0ClientId is usually NULL, which + means it is our data. However it is set to the client ID of an LDD in case + 2) above. That way we can subsequently hand over received data to the + correct client LDD. + + iEp0DataReceived tracks the amount of data already received - it is used to + determine the end of the DATA_OUT phase, irrespective of the owner of the + data. The total amount that is to be received can be obtained via + iConTransferMgr->PktParser().Length(). (iConTransferMgr->PktParser() holds in + that case the Setup packet of the current Control transfer.) + + iEp0ClientDataTransmitting is only set to TRUE if a client sets up an Ep0 + write. After that transmission has completed we use this value to decide + whether we have to report the completion to a client or not. (If this + variable is FALSE, we did set up the write and thus no client notification + is necessary.) + +*/ + +// +// === Global and Local Variables ================================================================== +// + +// Currently we support at most 2 peripheral stack +GLDEF_D DUsbClientController* DUsbClientController::UsbClientController[] = {NULL, NULL}; + +static const TInt KUsbReconnectDelay = 500; // milliseconds + +// Charger detector is the guy(PSL) who can detect the charger type and report +// it via a charger type observer +static UsbShai::MChargerDetectorIf* gChargerDetector = NULL; + +// Charger observer is the guy who want to monitor the chager type event. +static UsbShai::MChargerDetectorObserverIf* gChargerObsever = NULL; + + +// Those const variables are used to construct the default +// Usb descriptors, Upper layer can change them later. +/** Default vendor ID to set in device descriptor */ +static const TUint16 KUsbVendorId = KUsbVendorId_Symbian; +/** Default product ID to set in device descriptor */ +static const TUint16 KUsbProductId = 0x1111; +/** Default language ID (US English) to set in device descriptor */ +static const TUint16 KUsbLangId = 0x0409; +static const TUint8 KUsbNumberOfConfiguration = 0x01; +/** Default manufacturer string */ +static const wchar_t KStringManufacturer[] = L"Nokia Corporation"; +/** Default product name string */ +static const wchar_t KStringProduct[] = L"Nokia USB Driver"; +/** Default configuration name string */ +static const wchar_t KStringConfig[] = L"Bulk transfer method configuration"; +/** Default configuration name string */ +static const wchar_t KStringSerial[] = L"Serial Not defined"; + + +// +// === USB Controller member function implementations - LDD API (public) =========================== +// + +DECLARE_STANDARD_EXTENSION()//lint !e1717 !e960 defined by symbian + { + __KTRACE_OPT(KUSB, Kern::Printf("> Peripheral PIL Extension entry")); + // Don't need to do anything here, using extension just to make sure + // we're loaded when peripheral PSL trying to register itself to us. + __KTRACE_OPT(KUSB, Kern::Printf("< Peripheral PIL Extension exit")); + return KErrNone; + } + +/** The class destructor. + + This rarely gets called, except, for example when something goes + wrong during construction. + + It's not exported because it is virtual. +*/ +DUsbClientController::~DUsbClientController() + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::~DUsbClientController()")); + if (iPowerHandler) + { + iPowerHandler->Remove(); + delete iPowerHandler; + } + + // ResetAndDestroy() will call for every array element the destructor of the pointed-to object, + // before deleting the element itself, and closing the array. + iConfigs.ResetAndDestroy(); + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::~DUsbClientController(): Done.")); + } + +EXPORT_C DUsbClientController* DUsbClientController::Create(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, + const UsbShai::TPeripheralControllerProperties& aProperties, + TBool aIsOtgPort) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::Create")); + // Attempt to create the object + DUsbClientController* usbcc = new DUsbClientController(aPeripheralControllerIf, + aProperties, + aIsOtgPort); + + __ASSERT_DEBUG( (usbcc != NULL), Kern::Fault( " USB PSL Out of memory, DUsbClientController", __LINE__ ) ); + + if (usbcc != NULL) + { + // Second phase constructor + TInt err = usbcc->Construct(); + __ASSERT_DEBUG( (err == KErrNone), Kern::Fault( "DUsbClientController::Construct failed", err) ); + + if (err != KErrNone) + { + delete usbcc; + usbcc = NULL; + } + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::Create instance = %d",usbcc)); + + return usbcc; + } + +/** + * FIXME: This function used to be called by the dummy DCD to disable + * the peripheral stack. It has been deprecated and we currently use + * DisablePeripheralStack() to achieve the same effect. + */ +EXPORT_C void DUsbClientController::DisableClientStack() + { + __KTRACE_OPT(KUSB, Kern::Printf("CALL TO OBSOLETE FUNCTION: DUsbClientController::DisableClientStack()")); + } + + +/** + * FIXME: This function used to be called by the dummy DCD to enable + * the peripheral stack. It has been deprecated and we currently use + * EnablePeripheralStack() to achieve the same effect. + */ +EXPORT_C void DUsbClientController::EnableClientStack() + { + __KTRACE_OPT(KUSB, Kern::Printf("CALL TO OBSOLETE FUNCTION: DUsbClientController::EnableClientStack()")); + } + + +/** Called by LDD to see if controller is usable. + + @return ETrue if controller is in normal state, EFalse if it is disabled. +*/ +EXPORT_C TBool DUsbClientController::IsActive() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::IsActive = %d",iStackIsActive)); + return iStackIsActive; + } + + +/** Called by LDD to register client callbacks. + + @return KErrNone if successful, KErrAlreadyExists callback exists. +*/ +EXPORT_C TInt DUsbClientController::RegisterClientCallback(TUsbcClientCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::RegisterClientCallback()")); + if (iClientCallbacks.Elements() == KUsbcMaxListLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", + KUsbcMaxListLength)); + return KErrGeneral; + } + TSglQueIter iter(iClientCallbacks); + TUsbcClientCallback* p; + while ((p = iter++) != NULL) + if (p == &aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: ClientCallback @ 0x%x already registered", &aCallback)); + return KErrAlreadyExists; + } + iClientCallbacks.AddLast(aCallback); + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::RegisterClientCallback()")); + return KErrNone; + } + + +/** Returns a pointer to the USB client controller object. + + This function is static. + + @param aUdc The number of the UDC (0..n) for which the pointer is to be returned. + + @return A pointer to the USB client controller object. +*/ +EXPORT_C DUsbClientController* DUsbClientController::UsbcControllerPointer(TInt aUdc) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::UsbcControllerPointer()")); + + if (aUdc < 0 || aUdc > 1) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); + return NULL; + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::UsbcControllerPointer()")); + + return UsbClientController[aUdc]; + } + + +/** Fills the buffer passed in as an argument with endpoint capability information. + + @see DUsbClientController::DeviceCaps() + @see TUsbcEndpointData + @see TUsbDeviceCaps + + @param aClientId A pointer to the LDD making the enquiry. + @param aCapsBuf A reference to a descriptor buffer, which, on return, contains an array of + TUsbcEndpointData elements; there are TUsbDeviceCaps::iTotalEndpoints elements in the array; + call DeviceCaps() to get the number of elements required. +*/ +EXPORT_C void DUsbClientController::EndpointCaps(const DBase* aClientId, TDes8& aCapsBuf) const + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::EndpointCaps()")); + // Here we do not simply call DUsbClientController::DeviceEndpointCaps(), + // because that function fills an array which comprises of _all_ endpoints, + // whereas this function omits ep0 and all unusable endpoints. + // Apart from that, we have to fill an array of TUsbcEndpointData, not TUsbcEndpointCaps. + TUsbcEndpointData data[KUsbcMaxEndpoints]; + const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); + for (TInt i = 2, j = 0; i < iDeviceTotalEndpoints; ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DUsbClientController::Caps: RealEndpoint #%d", i)); + if (iRealEndpoints[i].iCaps.iTypesAndDir != UsbShai::KUsbEpNotAvailable) + { + __KTRACE_OPT(KUSB, Kern::Printf(" DUsbClientController::Caps: --> UsableEndpoint #%d", j)); + + data[j].iCaps.iSizes = iRealEndpoints[i].iCaps.iSizes; + data[j].iCaps.iTypesAndDir = iRealEndpoints[i].iCaps.iTypesAndDir; + data[j].iCaps.iHighBandwidth = iRealEndpoints[i].iCaps.iHighBandwidth; + data[j].iCaps.iReserved[0] = iRealEndpoints[i].iCaps.iReserved[0]; + data[j].iCaps.iReserved[1] = iRealEndpoints[i].iCaps.iReserved[1]; + + if (ifcset_num < 0) + { + // If this LDD doesn't own an interface, but the Ep points to one, + // then that must be the interface of a different LDD. Hence the Ep + // is not available for this LDD. + data[j].iInUse = (iRealEndpoints[i].iIfcNumber != NULL); + } + else + { + // If this LDD does already own an interface, and the Ep also points to one, + // then the Ep is not available for this LDD only if that interface is owned + // by a different LDD (i.e. if the interface number is different). + // Reason: Even though the endpoint might already be part of an interface setting, + // it is still available for a different alternate setting of the same interface. + data[j].iInUse = ((iRealEndpoints[i].iIfcNumber != NULL) && + (*(iRealEndpoints[i].iIfcNumber) != ifcset_num)); + } + + j++; + } + } + // aCapsBuf resides in userland + TPtrC8 des((TUint8*)data, sizeof(data)); + const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), + &aCapsBuf, des, 0, KChunkShiftBy0, NULL); + if (r != KErrNone) + { + Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), + EExitPanic, r, KUsbPILKillCat); + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::EndpointCaps()")); + } + + +/** Fills the buffer passed in as an argument with device capability information. + + @see TUsbDeviceCaps + @see TUsbDeviceCapsV01 + + @param aClientId A pointer to the LDD making the enquiry. + @param aCapsBuf A reference to a descriptor buffer which, on return, contains + a TUsbDeviceCaps structure. +*/ +EXPORT_C void DUsbClientController::DeviceCaps(const DBase* aClientId, TDes8& aCapsBuf) const + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::DeviceCaps()")); + TUsbDeviceCaps caps; + caps().iTotalEndpoints = iDeviceUsableEndpoints; // not DeviceTotalEndpoints()! + + caps().iSelfPowered = iSelfPowered; + caps().iRemoteWakeup = iRemoteWakeup; + caps().iHighSpeed = (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed)?ETrue:EFalse; + + // PIL always assume controller support this caps, see explaination in peripheral shai header + caps().iFeatureWord1 = caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_CableDetectWithoutPower; + + caps().iFeatureWord1 = caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_EndpointResourceAllocV2; + caps().iReserved = 0; + + // aCapsBuf resides in userland + const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), + &aCapsBuf, caps, 0, KChunkShiftBy0, NULL); + if (r != KErrNone) + { + Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), + EExitPanic, r, KUsbPILKillCat); + } + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::DeviceCaps()")); + } + + +TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcEndpointInfo* aData, TInt aDataSize) + { + iType = EUsbcEndpointInfo; + iData = (TUint8*) aData; + if (aDataSize > 0) + iDataSize = aDataSize; + else + iDataSize = sizeof(TUsbcEndpointInfo); + } + + +inline TUsbcEndpointInfo& TUsbcEndpointInfoArray::operator[](TInt aIndex) const + { + return *(TUsbcEndpointInfo*) &iData[aIndex * iDataSize]; + } + + +EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, + TInt aInterfaceNum, TUsbcClassInfo& aClass, + TDesC8* aString, TInt aTotalEndpointsUsed, + const TUsbcEndpointInfo aEndpointData[], + TInt (*aRealEpNumbers)[6], TUint32 aFeatureWord) + { + TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(aEndpointData); + return SetInterface(aClientId, aThread, aInterfaceNum, aClass, aString, aTotalEndpointsUsed, + endpointData, (TInt*) aRealEpNumbers, aFeatureWord); + } + + +/** Creates a new USB interface (one setting), complete with endpoints, descriptors, etc., + and chains it into the internal device configuration tree. + + @param aClientId A pointer to the LDD owning the new interface. + @param aThread A pointer to the thread the owning LDD is running in. + @param aInterfaceNum The interface setting number of the new interface setting. This must be 0 + if it is the first setting of the interface that gets created, or 1 more than the last setting + that was created for this interface. + @param aClass Contains information about the device class this interface might belong to. + @param aString A pointer to a string that is used for the string descriptor of this interface. + @param aTotalEndpointsUsed The number of endpoints used by this interface (and also the number of + elements of the following array). + @param aEndpointData An array with aTotalEndpointsUsed elements, containing information about the + endpoints of this interface. + + @return KErrNotSupported if Control endpoints are requested by the LDD but aren't supported by the PIL, + KErrInUse if at least one requested endpoint is - temporarily or permanently - not available for use, + KErrNoMemory if (endpoint, interface, string) descriptor allocation fails, KErrGeneral if something else + goes wrong during endpoint or interface or descriptor creation, KErrNone if interface successfully set up. +*/ +EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, + TInt aInterfaceNum, TUsbcClassInfo& aClass, + TDesC8* aString, TInt aTotalEndpointsUsed, + const TUsbcEndpointInfoArray aEndpointData, + TInt aRealEpNumbers[], TUint32 aFeatureWord) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::SetInterface()")); + if (aInterfaceNum != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" alternate interface setting request: #%d", aInterfaceNum)); + } + +#ifndef USB_SUPPORTS_CONTROLENDPOINTS + for (TInt i = 0; i < aTotalEndpointsUsed; ++i) + { + if (aEndpointData[i].iType == UsbShai::KUsbEpTypeControl) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: control endpoints not supported")); + return KErrNotSupported; + } + } +#endif + + // Check for endpoint availability & check those endpoint's capabilities + const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); + + // The passed-in ifcset_num may be -1 now, but that's intended. + if (!CheckEpAvailability(aTotalEndpointsUsed, aEndpointData, ifcset_num)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoints not (all) available")); + return KErrInUse; + } + + // Create & setup new interface + TUsbcInterface* ifc = CreateInterface(aClientId, aInterfaceNum, aFeatureWord); + if (ifc == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ifc == NULL")); + return KErrGeneral; + } + + // Create logical endpoints + TInt r = CreateEndpoints(ifc, aTotalEndpointsUsed, aEndpointData, aRealEpNumbers); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: CreateEndpoints() err = %d ",r)); + DeleteInterface(ifc->iInterfaceSet->iInterfaceNumber, aInterfaceNum); + return r; + } + + // Create & setup interface, string, and endpoint descriptors + r = SetupIfcDescriptor(ifc, aClass, aThread, aString, aEndpointData); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupIfcDescriptor() err = %d",r)); + return r; + } + + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::SetInterface()")); + return KErrNone; + } + + +/** Releases an existing USB interface (one setting), complete with endpoints, descriptors, etc., + and removes it from the internal device configuration tree. + + @param aClientId A pointer to the LDD owning the interface. + @param aInterfaceNum The setting number of the interface setting to be deleted. This must be + the highest numbered (or 'last') setting for this interface. + + @return KErrNotFound if interface (not setting) for some reason cannot be found, KErrArgument if an + invalid interface setting number is specified (not existing or existing but too small), KErrNone if + interface successfully released or if this client doesn't own any interface. +*/ +EXPORT_C TInt DUsbClientController::ReleaseInterface(const DBase* aClientId, TInt aInterfaceNum) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ReleaseInterface(..., %d)", aInterfaceNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" interface not found")); // no error + return KErrNone; + } + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); + if (!ifcset_ptr) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); + return KErrNotFound; + } + const TInt setting_count = ifcset_ptr->iInterfaces.Count(); + if ((setting_count - 1) != aInterfaceNum) + { + __KTRACE_OPT(KUSB, + Kern::Printf(" Error: interface settings must be released in descending order:\n\r" + " %d setting(s) exist, #%d was requested to be released.\n\r" + " (#%d has to be released first)", + setting_count, aInterfaceNum, setting_count - 1)); + return KErrArgument; + } + // Tear down current setting (invalidate configured state) + __KTRACE_OPT(KUSB, Kern::Printf(" tearing down InterfaceSet %d", ifcset)); + // Cancel all transfers on the current setting of this interface and deconfigure all its endpoints. + InterfaceSetTeardown(ifcset_ptr); + // 'Setting 0' means: delete all existing settings. + if (aInterfaceNum == 0) + { + TInt m = ifcset_ptr->iInterfaces.Count(); + while (m > 0) + { + m--; + // Ground the physical endpoints' logical_endpoint_pointers + const TInt n = ifcset_ptr->iInterfaces[m]->iEndpoints.Count(); + for (TInt i = 0; i < n; ++i) + { + TUsbcPhysicalEndpoint* ptr = const_cast + (ifcset_ptr->iInterfaces[m]->iEndpoints[i]->iPEndpoint); + ptr->iLEndpoint = NULL; + } + // Delete the setting itself + its ifc & ep descriptors + DeleteInterface(ifcset, m); + iDescriptors.DeleteIfcDescriptor(ifcset, m); + } + } + else + { + // Ground the physical endpoints' logical_endpoint_pointers + const TInt n = ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints.Count(); + for (TInt i = 0; i < n; ++i) + { + TUsbcPhysicalEndpoint* ptr = const_cast + (ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints[i]->iPEndpoint); + ptr->iLEndpoint = NULL; + } + // Delete the setting itself + its ifc & ep descriptors + DeleteInterface(ifcset, aInterfaceNum); + iDescriptors.DeleteIfcDescriptor(ifcset, aInterfaceNum); + } + // Delete the whole interface if all settings are gone + if (ifcset_ptr->iInterfaces.Count() == 0) + { + DeleteInterfaceSet(ifcset); + } + // We now no longer have a valid current configuration + iCurrentConfig = 0; + if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured) + { + NextDeviceState(UsbShai::EUsbPeripheralStateAddress); + } + // If it was the last interface(set)... + if (iConfigs[0]->iInterfaceSets.Count() == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No ifc left -> turning off UDC")); + // First disconnect the device from the bus + UsbDisconnect(); + DeActivateHardwareController(); + // (this also disables endpoint zero; we cannot have a USB device w/o interface, see 9.6.3) + } + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ReleaseInterface")); + return KErrNone; + } + + +/** Enforces a USB re-enumeration by disconnecting the UDC from the bus (if it is currently connected) and + re-connecting it. + + This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. +*/ +EXPORT_C TInt DUsbClientController::ReEnumerate() + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ReEnumerate()")); + + // ReEnumerate is possible only when stack is enabled + if (!iStackIsActive) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); + return KErrNotReady; + } + + // If no interfaces setup, there is no point to reenumerate + if (iConfigs[0]->iInterfaceSets.Count() == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" > No interface registered -> no need to re-enumerate")); + return KErrNone;; + } + + if (!iHardwareActivated) + { + // If the UDC is still off, we switch it on here. + const TInt r = ActivateHardwareController(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); + return r; + } + + // Finally connect the device to the bus + UsbConnect(); + } + else + { + UsbDisconnect(); + + // Now we have to wait a certain amount of time, in order to give the host the opportunity + // to come to terms with the new situation. + // (The ETrue parameter makes the callback get called in DFC instead of in ISR context.) + iReconnectTimer.OneShot(KUsbReconnectDelay, ETrue); + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ReEnumerate()")); + return KErrNone;; + } + + +/** Powers up the UDC if one or more interfaces exist. + + @return KErrNone if UDC successfully powered up, KErrNotReady if no + interfaces have been registered yet, KErrHardwareNotAvailable if UDC + couldn't be activated. +*/ +EXPORT_C TInt DUsbClientController::PowerUpUdc() + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerUpUdc()")); + + // we need to check whether Stack is activate or not(can be done by otg sw in otg setup + // or by vBus risen/fallen event in a non-otg env) + if (!iStackIsActive) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); + return KErrNotReady; + } + + if (iConfigs[0]->iInterfaceSets.Count() == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No interface registered -> won't power up UDC")); + return KErrNotReady; + } + + // If the UDC is still off, we switch it on here. + const TInt r = ActivateHardwareController(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerUpUdc() returns %d",r)); + return r; + } + + +/** Connects the UDC to the bus. + + @return KErrNone if UDC successfully connected, + KErrNotSupported if KDevCapSoftConnect not supported + KErrGeneral if there was an error. + +*/ +EXPORT_C TInt DUsbClientController::UsbConnect() + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::UsbConnect()")); + iClientSupportReady = ETrue; + + // If a deferred reset is pending, service it now + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + if (iUsbResetDeferred) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Resetting USB Reset 'defer' flag")); + iUsbResetDeferred = EFalse; + (void) ProcessResetEvent(EFalse); + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + + // Indicate readiness to connect to the PSL + const TInt r = iController.PeripheralConnect(); + + // Check whether Stack is activated by OTG controller + // or Vbus Risen had been detected. + // If either of them is true and HW is not activated yet, do it here. + if (iStackIsActive && !iHardwareActivated ) + { + // PowerUpUdc only do Activating Hardware when there are at least 1 + // Iterface registered + PowerUpUdc(); + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::UsbConnect()")); + return r; + } + + +/** Disconnects the UDC from the bus. + + This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. + + @return KErrNone if UDC successfully disconnected, KErrGeneral if there was an error. +*/ +EXPORT_C TInt DUsbClientController::UsbDisconnect() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::UsbDisconnect()")); + iClientSupportReady = EFalse; + + // Indicate to PSL that we are no longer ready to connect + const TInt r = iController.PeripheralDisconnect(); + + // There won't be any notification by the PSL about this, + // so we have to notify the LDD/user ourselves: + if ((r == KErrNone) && (iDeviceState != UsbShai::EUsbPeripheralStateUndefined)) + { + // Not being in state UNDEFINED implies that the cable is inserted. + if (iHardwareActivated) + { + NextDeviceState(UsbShai::EUsbPeripheralStatePowered); + } + // (If the hardware is NOT activated at this point, we can only be in + // state UsbShai::EUsbPeripheralStateAttached, so we don't have to move to it.) + } + return r; + } + + +/** Registers a notification callback for changes of the USB device state. + + In the event of a device state change, the callback's state member gets updated (using SetState) with a + new UsbShai::TUsbPeripheralState value, and then the callback is executed (DoCallback). 'USB device state' here refers + to the Visible Device States as defined in chapter 9 of the USB specification. + + @param aCallback A reference to a properly filled in status callback structure. + + @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered + (it won't be registered twice). +*/ +EXPORT_C TInt DUsbClientController::RegisterForStatusChange(TUsbcStatusCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForStatusChange()")); + if (iStatusCallbacks.Elements() == KUsbcMaxListLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", + KUsbcMaxListLength)); + return KErrGeneral; + } + if (IsInTheStatusList(aCallback)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: StatusCallback @ 0x%x already registered", &aCallback)); + return KErrGeneral; + } + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + iStatusCallbacks.AddLast(aCallback); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + + +/** De-registers (removes from the list of pending requests) a notification callback for the USB device + status. + + @param aClientId A pointer to the LDD owning the status change callback. + + @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. +*/ +EXPORT_C TInt DUsbClientController::DeRegisterForStatusChange(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForStatusChange()")); + __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iStatusCallbacks); + TUsbcStatusCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing StatusCallback @ 0x%x", p)); + iStatusCallbacks.Remove(*p); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNotFound; + } + + +/** Registers a notification callback for changes of the state of endpoints. + + In the event of a state change of an endpoint that is spart of an interface which is owned by the LDD + specified in the callback structure, the callback's state member gets updated (using SetState) with a new + value, and the callback is executed (DoCallback). 'Endpoint state' here refers to the state of the + ENDPOINT_HALT feature of an endpoint as described in chapter 9 of the USB specification. The contents of + the state variable reflects the state of the halt features for all endpoints of the current interface + setting: bit 0 represents endpoint 1, bit 1 endpoint 2, etc. A set bit means 'endpoint halted', a cleared + bit 'endpoint not halted'. + + @param aCallback A reference to a properly filled in endpoint status callback structure. + + @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered + (it won't be registered twice). +*/ +EXPORT_C TInt DUsbClientController::RegisterForEndpointStatusChange(TUsbcEndpointStatusCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForEndpointStatusChange()")); + if (iEpStatusCallbacks.Elements() == KUsbcMaxListLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", + KUsbcMaxListLength)); + return KErrGeneral; + } + if (IsInTheEpStatusList(aCallback)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: EpStatusCallback @ 0x%x already registered", &aCallback)); + return KErrGeneral; + } + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + iEpStatusCallbacks.AddLast(aCallback); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + + +/** De-registers (removes from the list of pending requests) a notification callback for changes of the state + of endpoints. + + @param aClientId A pointer to the LDD owning the endpoint status change callback. + + @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. +*/ +EXPORT_C TInt DUsbClientController::DeRegisterForEndpointStatusChange(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForEndpointStatusChange()")); + __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iEpStatusCallbacks); + TUsbcEndpointStatusCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing EpStatusCallback @ 0x%x", p)); + iEpStatusCallbacks.Remove(*p); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNotFound; + } + + +/** Returns the number of the currently active alternate interface setting for this interface. + + @param aClientId A pointer to the LDD owning the interface. + @param aInterfaceNum Here the interface gets written to. + + @return KErrNotFound if an interface for this client couldn't be found, KErrNone if setting value was + successfully written. +*/ +EXPORT_C TInt DUsbClientController::GetInterfaceNumber(const DBase* aClientId, TInt& aInterfaceNum) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceNumber()")); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error (ifc < 0)")); + return KErrNotFound; + } + const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); + return KErrNotFound; + } + aInterfaceNum = ifcset_ptr->iCurrentInterface; + return KErrNone; + } + + +/** This is normally called once by an LDD's destructor, either after a Close() on the user side, + or during general cleanup. + + It might also be called by the LDD when some internal unrecoverable error occurs. + + This function + - de-registers a possibly pending device state change notification request, + - de-registers a possibly pending endpoint state change notification request, + - releases all interfaces + settings owned by this LDD, + - cancels all remaining (if any) read/write requests. + + @param aClientId A pointer to the LDD to be unregistered. + + @return KErrNone. +*/ +EXPORT_C TInt DUsbClientController::DeRegisterClient(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient(0x%x)", aClientId)); + // Cancel all device state notification requests + DeRegisterForStatusChange(aClientId); + // Cancel all endpoint state notification requests + DeRegisterForEndpointStatusChange(aClientId); + DeRegisterForOtgFeatureChange(aClientId); + DeRegisterClientCallback(aClientId); + // Delete the interface including all its alternate settings which might exist. + // (If we release the default setting (0), all alternate settings are deleted as well.) + const TInt r = ReleaseInterface(aClientId, 0); + // Cancel all remaining (if any) read/write requests + DeleteRequestCallbacks(aClientId); + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient: Done.")); + return r; + } + + +/** Returns the currently used Ep0 max packet size. + + @return The currently used Ep0 max packet size. +*/ +EXPORT_C TInt DUsbClientController::Ep0PacketSize() const + { + const TUsbcLogicalEndpoint* const ep = iRealEndpoints[0].iLEndpoint; + if (iHighSpeed) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (HS)", ep->iEpSize_Hs)); + return ep->iEpSize_Hs; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (FS)", ep->iEpSize_Fs)); + return ep->iEpSize_Fs; + } + } + + +/** Stalls Ep0. + + @param aClientId A pointer to the LDD wishing to stall Ep0 (this is for PIL internal purposes only). + + @return KErrNone if endpoint zero successfully stalled, KErrGeneral otherwise. +*/ +EXPORT_C TInt DUsbClientController::Ep0Stall(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Ep0Stall()")); + if (aClientId == iEp0ClientId) + { + ResetEp0DataOutVars(); + } + const TInt err = iConTransferMgr->StallEndpoint(KEp0_Out); + if (err < 0) + { + return err; + } + else + return iConTransferMgr->StallEndpoint(KEp0_In); + } + + +/** Sends a zero-byte status packet on Ep0. + + @param aClientId A pointer to the LDD wishing to send the status packet (not used at present). +*/ +EXPORT_C void DUsbClientController::SendEp0StatusPacket(const DBase* /* aClientId */) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SendEp0StatusPacket()")); + iConTransferMgr->SendEp0ZeroByteStatusPacket(); + } + + +/** Returns the current USB device state. + + 'USB device state' here refers to the Visible Device States as defined in chapter 9 of the USB + specification. + + @return The current USB device state, or UsbShai::EUsbPeripheralStateUndefined +*/ +EXPORT_C UsbShai::TUsbPeripheralState DUsbClientController::GetDeviceStatus() const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceStatus()")); + return iDeviceState; + } + + +/** Returns the state of an endpoint. + + 'Endpoint state' here refers to the state of the ENDPOINT_HALT feature of + an endpoint as described in chapter 9 of the USB specification. + + @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be queried. + @param aEndpointNum The number of the endpoint to be queried. + + @return The current endpoint state, or EEndpointStateUnknown if the endpoint couldn't be found. +*/ +EXPORT_C TEndpointState DUsbClientController::GetEndpointStatus(const DBase* aClientId, TInt aEndpointNum) const + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::GetEndpointStatus()")); + + TEndpointState ret = (iRealEndpoints[aEndpointNum].iHalt)?EEndpointStateStalled : EEndpointStateNotStalled; + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::GetEndpointStatus() %d",ret)); + + return ret; + } + + +/** Sets up a data read request for an endpoint. + + @param aCallback A reference to a properly filled in data transfer request callback structure. + + @return KErrNone if callback successfully registered or if this callback is already registered + (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if + endpoint number invalid (PSL), KErrGeneral if something else goes wrong. +*/ +EXPORT_C TInt DUsbClientController::SetupReadBuffer(TUsbcRequestCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupReadBuffer()")); + const TInt ep = aCallback.iRealEpNum; + __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); + __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); + TInt err = KErrGeneral; + if (ep != 0) + { + if (iRequestCallbacks[ep]) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); + if (iRequestCallbacks[ep] == &aCallback) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x)", &aCallback)); + } + return KErrNone; + } + // This may seem awkward: + // First we add a callback, and then, in case of an error, we remove it again. + // However this is necessary because the transfer request might complete (through + // an ISR) _before_ the SetupEndpointRead function returns. Since we don't know the + // outcome, we have to provide the callback before making the setup call. + // + __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); + iRequestCallbacks[ep] = &aCallback; + if ((err = iController.SetupEndpointRead(ep, aCallback)) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", + &aCallback)); + iRequestCallbacks[ep] = NULL; + } + } + else // (ep == 0) + { + if (iEp0ReadRequestCallbacks.Elements() == KUsbcMaxListLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", + KUsbcMaxListLength)); + return KErrGeneral; + } + if (IsInTheRequestList(aCallback)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" RequestCallback @ 0x%x already registered", &aCallback)); + return KErrNone; + } + // Ep0 reads don't need to be prepared - there's always one pending + __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback @ 0x%x (ep0)", &aCallback)); + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + iEp0ReadRequestCallbacks.AddLast(aCallback); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + err = KErrNone; + if (iEp0_RxExtraCount != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" iEp0_RxExtraData: trying again...")); + + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + + // Extra data is either a setup packet or a data packet + // They are not possible to be both + // And, the error code must be KErrNone, otherwise, we can not arrive here + if( iSetupPacketPending ) + { + ProcessSetupPacket(iEp0_RxExtraCount,KErrNone); + } + else + { + ProcessDataOutPacket(iEp0_RxExtraCount,KErrNone); + } + + // clear it since already completed to client + iEp0_RxExtraCount = 0; + + err = iLastError; + + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + if (err == KErrNone) + { + //iEp0_RxExtraData = EFalse; + // Queue a new Ep0 read (because xxxProceed only re-enables the interrupt) + iConTransferMgr->SetupEndpointZeroRead(); + if (iSetupPacketPending) + { + iConTransferMgr->Ep0SetupPacketProceed(); + iSetupPacketPending = EFalse; + } + else + { + iConTransferMgr->Ep0DataPacketProceed(); + } + + __KTRACE_OPT(KUSB, Kern::Printf(" :-)")); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: :-(")); + err = KErrGeneral; + } + return err; + } + } + return err; + } + + +/** Sets up a data write request for an endpoint. + + @param aCallback A reference to a properly filled in data transfer request callback structure. + + @return KErrNone if callback successfully registered or if this callback is already registered + (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if + endpoint number invalid (PSL), KErrGeneral if something else goes wrong. +*/ +EXPORT_C TInt DUsbClientController::SetupWriteBuffer(TUsbcRequestCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupWriteBuffer()")); + TInt ep = aCallback.iRealEpNum; + __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); + __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); + if (iRequestCallbacks[ep]) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); + if (iRequestCallbacks[ep] == &aCallback) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); + return KErrNone; + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x - poss. error)", + &aCallback)); + return KErrGeneral; + } + } + if (ep == 0) + { + if (iEp0_TxNonStdCount) + { + if (iEp0_TxNonStdCount > aCallback.iLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending less data than requested")); + if ((aCallback.iLength % iEp0MaxPacketSize == 0) && !aCallback.iZlpReqd) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Zlp should probably be requested")); + } + } + else if (iEp0_TxNonStdCount < aCallback.iLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending more data than requested")); + } + iEp0_TxNonStdCount = 0; + } + // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. + ep = KEp0_Tx; + } + // This may seem awkward: + // First we add a callback, and then, in case of an error, we remove it again. + // However this is necessary because the transfer request might complete (through + // an ISR) _before_ the SetupEndpointWrite function returns. Since we don't know the + // outcome, we have to provide the callback before making the setup call. + // + __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); + iRequestCallbacks[ep] = &aCallback; + if (ep == KEp0_Tx) + { + iEp0ClientDataTransmitting = ETrue; // this must be set before calling SetupEndpointZeroWrite + TInt ret = iConTransferMgr->SetupEndpointZeroWrite(aCallback.iBufferStart, aCallback.iLength, aCallback.iZlpReqd); + if (ret != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); + iRequestCallbacks[ep] = NULL; + iEp0ClientDataTransmitting = EFalse; + return ret; + } + } + else if (iController.SetupEndpointWrite(ep, aCallback) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); + iRequestCallbacks[ep] = NULL; + } + return KErrNone; + } + + +/** Cancels a data read request for an endpoint. + + The request callback will be removed from the queue and the + callback function won't be executed. + + @param aClientId A pointer to the LDD owning the interface which contains the endpoint. + @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. +*/ +EXPORT_C void DUsbClientController::CancelReadBuffer(const DBase* aClientId, TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelReadBuffer(%d)", aRealEndpoint)); + if (aRealEndpoint < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); + return; + } + // Note that we here don't cancel Ep0 read requests at the PSL level! + if (aRealEndpoint > 0) + { + iController.CancelEndpointRead(aRealEndpoint); + } + DeleteRequestCallback(aClientId, aRealEndpoint, UsbShai::EControllerRead); + } + + +/** Cancels a data write request for an endpoint. + + It cannot be guaranteed that the data is not sent nonetheless, as some UDCs don't permit a flushing of a + TX FIFO once it has been filled. The request callback will be removed from the queue in any case and the + callback function won't be executed. + + @param aClientId A pointer to the LDD owning the interface which contains the endpoint. + @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. +*/ +EXPORT_C void DUsbClientController::CancelWriteBuffer(const DBase* aClientId, TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelWriteBuffer(%d)", aRealEndpoint)); + if (aRealEndpoint < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); + return; + } + if (aRealEndpoint == 0) + { + // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. + aRealEndpoint = KEp0_Tx; + } + iController.CancelEndpointWrite(aRealEndpoint); + if (aRealEndpoint == KEp0_Tx) + { + // Since Ep0 is shared among clients, we don't have to care about the client id. + iEp0WritePending = EFalse; + } + DeleteRequestCallback(aClientId, aRealEndpoint, UsbShai::EControllerWrite); + } + + +/** Halts (stalls) an endpoint (but not Ep0). + + @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be stalled. + @param aEndpointNum The number of the endpoint. + + @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully + stalled, KErrGeneral otherwise. +*/ +EXPORT_C TInt DUsbClientController::HaltEndpoint(const DBase* aClientId, TInt aEndpointNum) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HaltEndpoint(%d)", aEndpointNum)); + const TInt r = iController.StallEndpoint(aEndpointNum); + if (r == KErrNone) + { + iRealEndpoints[aEndpointNum].iHalt = ETrue; + } + else if (r == KErrArgument) + { + return KErrNotFound; + } + return r; + } + + +/** Clears the halt condition of an endpoint (but not Ep0). + + @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be un-stalled. + @param aEndpointNum The number of the endpoint. + + @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully + stalled, KErrGeneral otherwise. +*/ +EXPORT_C TInt DUsbClientController::ClearHaltEndpoint(const DBase* aClientId, TInt aEndpointNum) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ClearHaltEndpoint(%d)", aEndpointNum)); + const TInt r = iController.ClearStallEndpoint(aEndpointNum); + if (r == KErrNone) + { + iRealEndpoints[aEndpointNum].iHalt = EFalse; + } + else if (r == KErrArgument) + { + return KErrNotFound; + } + return r; + } + + +/** This function requests 'device control' for an LDD. + + Class or vendor specific Ep0 requests addressed to the USB device as a whole (Recipient field in + bmRequestType byte of a Setup packet set to zero) are delivered to the LDD that owns device control. For + obvious reasons only one USB LDD can have device control at any given time. + + @param aClientId A pointer to the LDD requesting device control. + + @return KErrNone if device control successfully claimed or if this LDD already owns it, KErrGeneral if + device control already owned by a different client. +*/ +EXPORT_C TInt DUsbClientController::SetDeviceControl(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceControl()")); + if (iEp0DeviceControl) + { + if (iEp0DeviceControl == aClientId) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Device Control already owned by this client")); + return KErrNone; + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control already claimed by a different client")); + return KErrGeneral; + } + iEp0DeviceControl = aClientId; + return KErrNone; + } + + +/** This function releases device control for an LDD. + + @see DUsbClientController::SetDeviceControl() + + @param aClientId A pointer to the LDD releasing device control. + + @return KErrNone if device control successfully released, KErrGeneral if device control owned by a + different client or by no client at all. +*/ +EXPORT_C TInt DUsbClientController::ReleaseDeviceControl(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReleaseDeviceControl()")); + if (iEp0DeviceControl) + { + if (iEp0DeviceControl == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Releasing Device Control")); + iEp0DeviceControl = NULL; + return KErrNone; + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control owned by a different client")); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control not owned by any client")); + } + return KErrGeneral; + } + + +/** Returns all available (configurable) max packet sizes for Ep0. + + The information is coded as bitwise OR'ed values of KUsbEpSizeXXX constants (the bitmap format used for + TUsbcEndpointCaps.iSupportedSizes). + + @return All available (configurable) max packet sizes for Ep0. +*/ +EXPORT_C TUint DUsbClientController::EndpointZeroMaxPacketSizes() const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointZeroMaxPacketSizes()")); + return iRealEndpoints[0].iCaps.iSizes; + } + + +/** Sets (configures) the max packet size for Ep0. + + For available sizes as returned by DUsbClientController::EndpointZeroMaxPacketSizes() + + Note that for HS operation the Ep0 size cannot be chosen, but is fixed at 64 bytes. + + @return KErrNotSupported if invalid size specified, KErrNone if new max packet size successfully set or + requested size was already set. +*/ +EXPORT_C TInt DUsbClientController::SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointZeroMaxPacketSize(%d)", + aMaxPacketSize)); + + if (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed) + { + // We're not going to mess with this on a HS device. + return KErrNone; + } + + if (!(iRealEndpoints[0].iCaps.iSizes & PacketSize2Mask(aMaxPacketSize))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid size")); + return KErrNotSupported; + } + if (iRealEndpoints[0].iLEndpoint->iEpSize_Fs == aMaxPacketSize) + { + __KTRACE_OPT(KUSB, Kern::Printf(" this packet size already set -> returning")); + return KErrNone; + } + const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; + const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; + const_cast(ep0_0)->iEpSize_Fs = aMaxPacketSize; + const_cast(ep0_1)->iEpSize_Fs = aMaxPacketSize; + + // @@@ We should probably modify the device descriptor here as well... + + if (iHardwareActivated) + { + // De-configure endpoint zero + iController.DeConfigureEndpoint(KEp0_Out); + iController.DeConfigureEndpoint(KEp0_In); + // Re-configure endpoint zero + const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; + const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; + iController.ConfigureEndpoint(0, ep0_0->iInfo); + iController.ConfigureEndpoint(1, ep0_1->iInfo); + iEp0MaxPacketSize = ep0_0->iInfo.iSize; + } + return KErrNone; + } + + +/** Returns the current USB Device descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aDeviceDescriptor A reference to a buffer into which the requested descriptor should be written + (most likely located user-side). + + @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target + buffer. +*/ +EXPORT_C TInt DUsbClientController::GetDeviceDescriptor(DThread* aThread, TDes8& aDeviceDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptor()")); + return iDescriptors.GetDeviceDescriptorTC(aThread, aDeviceDescriptor); + } + + +/** Sets a new USB Device descriptor. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aDeviceDescriptor A reference to a buffer which contains the descriptor to be set (most likely + located user-side). + + @return The return value of the thread read operation, Kern::ThreadRead(), when reading from the source + buffer in case of a failure, KErrNone if the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetDeviceDescriptor(DThread* aThread, const TDes8& aDeviceDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceDescriptor()")); + return iDescriptors.SetDeviceDescriptorTC(aThread, aDeviceDescriptor); + } + + +/** Returns the current USB Device descriptor size. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aSize A reference to a buffer into which the requested descriptor size should be written + (most likely located user-side). + + @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target + buffer. +*/ +EXPORT_C TInt DUsbClientController::GetDeviceDescriptorSize(DThread* aThread, TDes8& aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptorSize()")); + // We do not really enquire here.... + const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Device), sizeof(KUsbDescSize_Device)); + return Kern::ThreadDesWrite(aThread, &aSize, size, 0); + } + + +/** Returns the current USB configuration descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor should be + written (most likely located user-side). + + @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target + buffer. +*/ +EXPORT_C TInt DUsbClientController::GetConfigurationDescriptor(DThread* aThread, TDes8& aConfigurationDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptor()")); + return iDescriptors.GetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); + } + + +/** Sets a new USB configuration descriptor. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most + likely located user-side). + + @return The return value of the thread read operation, Kern::ThreadRead() when reading from the source + buffer in case of a failure, KErrNone if the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetConfigurationDescriptor(DThread* aThread, + const TDes8& aConfigurationDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationDescriptor()")); + return iDescriptors.SetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); + } + + +/** Returns the current USB configuration descriptor size. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aSize A reference to a buffer into which the requested descriptor size should be written + (most likely located user-side). + + @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target + buffer. +*/ +EXPORT_C TInt DUsbClientController::GetConfigurationDescriptorSize(DThread* aThread, TDes8& aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptorSize()")); + // We do not really enquire here.... + const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Config), sizeof(KUsbDescSize_Config)); + return Kern::ThreadDesWrite(aThread, &aSize, size, 0); + } + + +/** Returns the current USB OTG descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aOtgDesc A reference to a buffer into which the requested descriptor should be + written (most likely located user-side). + + @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(), + when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetOtgDescriptor(DThread* aThread, TDes8& aOtgDesc) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgDescriptor()")); + if (!iOtgSupport) + { + return KErrNotSupported; + } + return iDescriptors.GetOtgDescriptorTC(aThread, aOtgDesc); + } + + +/** Sets a new OTG descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aOtgDesc A reference to a buffer which contains new OTG descriptor. + + @return KErrNotSupported or the return value of the thread read operation, Kern::ThreadDesRead(). +*/ +EXPORT_C TInt DUsbClientController::SetOtgDescriptor(DThread* aThread, const TDesC8& aOtgDesc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtgDescriptor()")); + if (!iOtgSupport) + { + return KErrNotSupported; + } + TBuf8 otg; + const TInt r = Kern::ThreadDesRead(aThread, &aOtgDesc, otg, 0); + if (r != KErrNone) + { + return r; + } + // Check descriptor validity + if (otg[0] != KUsbDescSize_Otg || otg[1] != KUsbDescType_Otg || otg[2] > 3) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid OTG descriptor")); + return KErrGeneral; + } + __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap before: 0x%x", iOtgFuncMap)); + // Update value in controller as well + const TUint8 hnp = otg[2] & KUsbOtgAttr_HnpSupp; + const TUint8 srp = otg[2] & KUsbOtgAttr_SrpSupp; + if (hnp && !srp) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Invalid OTG attribute combination (HNP && !SRP")); + } + if (hnp && !(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_HnpSupp")); + iOtgFuncMap |= KUsbOtgAttr_HnpSupp; + } + else if (!hnp && (iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_HnpSupp")); + iOtgFuncMap &= ~KUsbOtgAttr_HnpSupp; + } + if (srp && !(iOtgFuncMap & KUsbOtgAttr_SrpSupp)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_SrpSupp")); + iOtgFuncMap |= KUsbOtgAttr_SrpSupp; + } + else if (!srp && (iOtgFuncMap & KUsbOtgAttr_SrpSupp)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_SrpSupp")); + iOtgFuncMap &= ~KUsbOtgAttr_SrpSupp; + } + __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap after: 0x%x", iOtgFuncMap)); + return iDescriptors.SetOtgDescriptor(otg); + } + + +/** Returns current OTG features of USB device. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aFeatures A reference to a buffer into which the requested OTG features should be written. + + @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(). +*/ +EXPORT_C TInt DUsbClientController::GetOtgFeatures(DThread* aThread, TDes8& aFeatures) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgFeatures()")); + if (!iOtgSupport) + { + return KErrNotSupported; + } + TBuf8<1> features(1); + features[0] = iOtgFuncMap & 0x1C; + return Kern::ThreadDesWrite(aThread, &aFeatures, features, 0); + } + + +/** Returns current OTG features of USB device. This function is intended to be + called only from kernel side. + + @param aFeatures The reference to which the current features should be set at. + @return KErrNone if successful, KErrNotSupported if OTG is unavailable. +*/ +EXPORT_C TInt DUsbClientController::GetCurrentOtgFeatures(TUint8& aFeatures) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCurrentOtgFeatures()")); + if (!iOtgSupport) + { + return KErrNotSupported; + } + aFeatures = iOtgFuncMap & 0x1C; + return KErrNone; + } + + +/** Registers client request for OTG feature change. Client is notified when any OTG + feature is changed. + + @see KUsbOtgAttr_B_HnpEnable, KUsbOtgAttr_A_HnpSupport, KUsbOtgAttr_A_AltHnpSupport + + @param aCallback Callback function. Gets called when OTG features change + + @return KErrNone if successful, KErrAlreadyExists if aCallback is already in the queue. +*/ +EXPORT_C TInt DUsbClientController::RegisterForOtgFeatureChange(TUsbcOtgFeatureCallback& aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForOtgFeatureChange()")); + if (iOtgCallbacks.Elements() == KUsbcMaxListLength) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", + KUsbcMaxListLength)); + return KErrGeneral; + } + if (IsInTheOtgFeatureList(aCallback)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: OtgFeatureCallback @ 0x%x already registered", &aCallback)); + return KErrAlreadyExists; + } + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + iOtgCallbacks.AddLast(aCallback); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + + +/** De-registers (removes from the list of pending requests) a notification callback for + OTG feature change. + + @param aClientId A pointer to the LDD owning the endpoint status change callback. + + @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. +*/ +EXPORT_C TInt DUsbClientController::DeRegisterForOtgFeatureChange(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForOtgFeatureChange()")); + __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iOtgCallbacks); + TUsbcOtgFeatureCallback* p; + while ((p = iter++) != NULL) + { + if (!aClientId || p->Owner() == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing OtgFeatureCallback @ 0x%x", p)); + iOtgCallbacks.Remove(*p); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNone; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return KErrNotFound; + } + + +/** Returns a specific standard USB interface descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aClientId A pointer to the LDD requesting the descriptor. + @param aSettingNum The setting number of the interface for which the descriptor is requested. + @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor should be written + (most likely located user-side). + + @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TDes8& aInterfaceDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptor(x, 0x%08x, %d, y)", + aClientId, aSettingNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + return iDescriptors.GetInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); + } + + +/** Sets a new standard USB interface descriptor. + + This function can also be used, by the user, and under certain conditions, to change an interface's number + (reported as bInterfaceNumber in the descriptor). The conditions are: 1) We cannot accept a number that is + already used by another interface, 2) We allow the interface number to be changed only when it's still the + only setting, and 3) We allow the interface number to be changed only for the default setting (0). (All + alternate settings created for that interface thereafter will inherit the new, changed number.) + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aClientId A pointer to the LDD requesting the setting of the descriptor. + @param aSettingNum The setting number of the interface for which the descriptor is to be set. + @param aInterfaceDescriptor A reference to a buffer which contains the descriptor to be set (most + likely located user-side). + + @return KErrNotFound if the specified interface couldn't be found, the return value of the thread read + operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrArgument if the + interface number is to be changed (via bInterfaceNumber in the descriptor) and either the requested + interface number is already used by another interface or the interface has more than one setting. KErrNone + if the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, const TDes8& aInterfaceDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetInterfaceDescriptor(x, 0x%08x, %d, y)", + aClientId, aSettingNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + TBuf8 new_ifc; + TInt r = Kern::ThreadDesRead(aThread, &aInterfaceDescriptor, new_ifc, 0); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Copying interface descriptor buffer failed (%d)", r)); + return r; + } + const TInt ifcset_new = new_ifc[2]; + const TBool ifc_num_changes = (ifcset != ifcset_new); + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); + return KErrNotFound; + } + if (ifc_num_changes) + { + // If the user wants to change the interface number, we need to do some sanity checks: + if (InterfaceExists(ifcset_new)) + { + // Obviously we cannot accept a number that is already used by another interface. + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d already in use", ifcset_new)); + return KErrArgument; + } + if (ifcset_ptr->iInterfaces.Count() > 1) + { + // We allow the interface number to be changed only when it's the only setting. + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface has more than one alternate setting")); + return KErrArgument; + } + if (aSettingNum != 0) + { + // We allow the interface number to be changed only when it's the default setting. + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number can only be changed for setting 0")); + return KErrArgument; + } + } + if ((r = iDescriptors.SetInterfaceDescriptor(new_ifc, ifcset, aSettingNum)) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iDescriptors.SetInterfaceDescriptorfailed")); + return r; + } + if (ifc_num_changes) + { + // Alright then, let's do it... + __KTRACE_OPT(KUSB, Kern::Printf(" about to change interface number from %d to %d", + ifcset, ifcset_new)); + ifcset_ptr->iInterfaceNumber = ifcset_new; + } + return KErrNone; + } + + +/** Returns the size of a specific standard USB interface descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aClientId A pointer to the LDD requesting the descriptor size. + @param aSettingNum The setting number of the interface for which the descriptor size is requested. + @param aSize A reference to a buffer into which the requested descriptor size should be written (most + likely located user-side). + + @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetInterfaceDescriptorSize(DThread* aThread, const DBase* aClientId, + TInt /*aSettingNum*/, TDes8& aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptorSize()")); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + // Actually, we do not really enquire here.... + const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Interface), sizeof(KUsbDescSize_Interface)); + Kern::ThreadDesWrite(aThread, &aSize, size, 0); + return KErrNone; + } + + +/** Returns a specific standard USB endpoint descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aClientId A pointer to the LDD requesting the descriptor. + @param aSettingNum The setting number of the interface that contains the endpoint for which the + descriptor is requested. + @param aEndpointNum The endpoint for which the descriptor is requested. + @param aEndpointDescriptor A reference to a buffer into which the requested descriptor should be written + (most likely located user-side). + + @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value + of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetEndpointDescriptor(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + TDes8& aEndpointDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptor(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + return iDescriptors.GetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, + aSettingNum, EpIdx2Addr(aEndpointNum)); + } + + +/** Sets a new standard USB endpoint descriptor. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aClientId A pointer to the LDD requesting the setting of the descriptor. + @param aSettingNum The setting number of the interface that contains the endpoint for which the + descriptor is to be set. + @param aEndpointNum The endpoint for which the descriptor is to be set. + @param aEndpointDescriptor A reference to a buffer which contains the descriptor to be set (most + likely located user-side). + + @return KErrNotFound if the specified interface or endpoint couldn't be found, the return value of the + thread read operation, Kern::ThreadRead(), when reading from the source buffer in case of a read failure, + KErrNone if the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetEndpointDescriptor(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + const TDes8& aEndpointDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointDescriptor(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + return iDescriptors.SetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, + aSettingNum, EpIdx2Addr(aEndpointNum)); + } + + +/** Returns the size of a specific standard USB endpoint descriptor. + + @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. + @param aClientId A pointer to the LDD requesting the descriptor size. + @param aSettingNum The setting number of the interface that contains the endpoint for which the + descriptor size is requested. + @param aEndpointNum The endpoint for which the descriptor size is requested. + @param aEndpointDescriptor A reference to a buffer into which the requested descriptor size should be + written (most likely located user-side). + + @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value + of the thread write operation, kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetEndpointDescriptorSize(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + TDes8& aSize) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptorSize(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + TInt s; + TInt r = iDescriptors.GetEndpointDescriptorSize(ifcset, aSettingNum, + EpIdx2Addr(aEndpointNum), s); + if (r == KErrNone) + { + TPtrC8 size(reinterpret_cast(&s), sizeof(s)); + r = Kern::ThreadDesWrite(aThread, &aSize, size, 0); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint descriptor not found")); + } + return r; + } + + +/** Returns the current Device_Qualifier descriptor. On a USB device which doesn't support high-speed + operation this function will return an error. Note that the contents of the descriptor depend on + the current device speed (full-speed or high-speed). + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aDeviceQualifierDescriptor A reference to a buffer into which the requested descriptor + should be written (most likely located user-side). + + @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetDeviceQualifierDescriptor(DThread* aThread, + TDes8& aDeviceQualifierDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceQualifierDescriptor()")); + return iDescriptors.GetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); + } + + +/** Sets a new Device_Qualifier descriptor. On a USB device which doesn't support high-speed + operation this function will return an error. Note that the contents of the descriptor should take + into account the current device speed (full-speed or high-speed) as it is dependent on it. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aDeviceQualifierDescriptor A reference to a buffer which contains the descriptor to be set (most + likely located user-side). + + @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread + read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if + the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetDeviceQualifierDescriptor(DThread* aThread, + const TDes8& aDeviceQualifierDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceQualifierDescriptor()")); + return iDescriptors.SetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); + } + + +/** Returns the current Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed + operation this function will return an error. Note that the contents of the descriptor depend on the + current device speed (full-speed or high-speed). + + @param aThread A pointer to the thread the LDD requesting the descriptor is running in. + @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor + should be written (most likely located user-side). + + @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetOtherSpeedConfigurationDescriptor(DThread* aThread, + TDes8& aConfigurationDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtherSpeedConfigurationDescriptor()")); + return iDescriptors.GetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); + } + + +/** Sets a new Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed + operation this function will return an error. Note that the contents of the descriptor should take + into account the current device speed (full-speed or high-speed) as it is dependent on it. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. + @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most + likely located user-side). + + @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread + read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if + the new descriptor was successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetOtherSpeedConfigurationDescriptor(DThread* aThread, + const TDes8& aConfigurationDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtherSpeedConfigurationDescriptor()")); + return iDescriptors.SetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); + } + + +/** Returns a block of all available non-standard (class-specific) interface descriptors for a specific + interface. + + @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. + @param aClientId A pointer to the LDD requesting the descriptor block. + @param aSettingNum The setting number of the interface for which the descriptor block is requested. + @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor(s) should be + written (most likely located user-side). + + @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, + TDes8& aInterfaceDescriptor) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y)", + aClientId, aSettingNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + return iDescriptors.GetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); + } + + +/** Sets a block of (i.e. one or more) non-standard (class-specific) interface descriptors for a specific + interface. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running + in. + @param aClientId A pointer to the LDD requesting the setting of the descriptor block. + @param aSettingNum The setting number of the interface for which the setting of the descriptor block is + requested. + @param aInterfaceDescriptor A reference to a buffer which contains the descriptor block to be set (most + likely located user-side). + @param aSize The size of the descriptor block to be set. + + @return KErrNotFound if the specified interface couldn't be found, KErrArgument if aSize is less than 2, + KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the return value + of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. +*/ +EXPORT_C TInt DUsbClientController::SetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, + const TDes8& aInterfaceDescriptor, TInt aSize) + { + __KTRACE_OPT(KUSB, + Kern::Printf("DUsbClientController::SetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y, %d)", + aClientId, aSettingNum, aSize)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + if (aSize < 2) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); + return KErrArgument; + } + return iDescriptors.SetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum, aSize); + } + + +/** Returns the total size all non-standard (class-specific) interface descriptors for a specific interface. + + @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. + @param aClientId A pointer to the LDD requesting the descriptor block size. + @param aSettingNum The setting number of the interface for which the descriptor block size is + requested. + @param aSize A reference to a buffer into which the requested descriptor block size should be written (most + likely located user-side). + + @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread + write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlockSize(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TDes8& aSize) + { + __KTRACE_OPT(KUSB, + Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlockSize(x, 0x%08x, %d, y)", + aClientId, aSettingNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + TInt s; + const TInt r = iDescriptors.GetCSInterfaceDescriptorSize(ifcset, aSettingNum, s); + if (r == KErrNone) + { + const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); + Kern::ThreadDesWrite(aThread, &aSize, size, 0); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs interface descriptor not found")); + } + return r; + } + + +/** Returns a block of all available non-standard (class-specific) endpoint descriptors for a specific endpoint. + + @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. + @param aClientId A pointer to the LDD requesting the descriptor block. + @param aSettingNum The setting number of the interface that contains the endpoint for which the + descriptor block is requested. + @param aEndpointNum The endpoint for which the descriptor block is requested. + @param aEndpointDescriptor A reference to a buffer into which the requested descriptor(s) should be written + (most likely located user-side). + + @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value + of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + TDes8& aEndpointDescriptor) + { + __KTRACE_OPT(KUSB, + Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + return iDescriptors.GetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, + aSettingNum, EpIdx2Addr(aEndpointNum)); + } + + +/** Sets a block of (i.e. one or more) non-standard (class-specific) endpoint descriptors for a specific + endpoint. + + @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running + in. + @param aClientId A pointer to the LDD requesting the setting of the descriptor block. + @param aSettingNum The setting number of the interface that contains the endpoint for which the + descriptor block is to be set. + @param aEndpointNum The endpoint for which the descriptor block is to be set. + @param aEndpointDescriptor A reference to a buffer which contains the descriptor block to be set (most + likely located user-side). + @param aSize The size of the descriptor block to be set. + + @return KErrNotFound if the specified interface or endpoint couldn't be found, KErrArgument if aSize is + less than 2, KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the + return value of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. +*/ +EXPORT_C TInt DUsbClientController::SetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + const TDes8& aEndpointDescriptor, TInt aSize) + { + __KTRACE_OPT(KUSB, + Kern::Printf("DUsbClientController::SetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + if (aSize < 2) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); + return KErrArgument; + } + return iDescriptors.SetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, + aSettingNum, EpIdx2Addr(aEndpointNum), aSize); + } + + +/** Returns the total size all non-standard (class-specific) endpoint descriptors for a specific endpoint. + + @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. + @param aClientId A pointer to the LDD requesting the descriptor block size. + @param aSettingNum The setting number of the interface for which the descriptor block size is + requested. + @param aEndpointNum The endpoint for which the descriptor block size is requested. + @param aSize A reference to a buffer into which the requested descriptor block size should be written (most + likely located user-side). + + @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value + of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlockSize(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TInt aEndpointNum, + TDes8& aSize) + { + __KTRACE_OPT(KUSB, + Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlockSize(x, 0x%08x, %d, %d, y)", + aClientId, aSettingNum, aEndpointNum)); + const TInt ifcset = ClientId2InterfaceNumber(aClientId); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); + return KErrNotFound; + } + TInt s; + const TInt r = iDescriptors.GetCSEndpointDescriptorSize(ifcset, aSettingNum, + EpIdx2Addr(aEndpointNum), s); + if (r == KErrNone) + { + const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); + Kern::ThreadDesWrite(aThread, &aSize, size, 0); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs endpoint descriptor not found")); + } + return r; + } + + +/** Returns the currently set string descriptor language ID (LANGID) code. + + @param aThread A pointer to the thread the LDD requesting the LANGID is running in. + @param aLangId A reference to a buffer into which the requested code should be written (most likely + located user-side). + + @return The return value of the thread write operation, Kern::ThreadDesWrite(), + when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetStringDescriptorLangId(DThread* aThread, TDes8& aLangId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); + return iDescriptors.GetStringDescriptorLangIdTC(aThread, aLangId); + } + + +/** Sets the string descriptor language ID (LANGID) code. + + @param aLangId The langauge ID code to be written. + + @return KErrNone. +*/ +EXPORT_C TInt DUsbClientController::SetStringDescriptorLangId(TUint16 aLangId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); + return iDescriptors.SetStringDescriptorLangId(aLangId); + } + + +/** Returns the currently set Manufacturer string (which is referenced by the iManufacturer field in the device + descriptor). + + (Thus, the function should actually be called either 'GetManufacturerString' + or 'GetManufacturerStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the string is running in. + @param aString A reference to a buffer into which the requested string should be written (most likely + located user-side). + + @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return + value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetManufacturerStringDescriptor(DThread* aThread, TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetManufacturerStringDescriptor()")); + return iDescriptors.GetManufacturerStringDescriptorTC(aThread, aString); + } + + +/** Sets a new Manufacturer string in the Manufacturer string descriptor (which is referenced by the + iManufacturer field in the device descriptor). + + (Thus, the function should actually be called either + 'SetManufacturerString' or 'SetManufacturerStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. + @param aString A reference to a buffer which contains the string to be set (most likely located + user-side). + + @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the + return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, + KErrNone if new string descriptor successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetManufacturerStringDescriptor(DThread* aThread, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetManufacturerStringDescriptor()")); + return iDescriptors.SetManufacturerStringDescriptorTC(aThread, aString); + } + + +/** Removes (deletes) the Manufacturer string descriptor (which is referenced by the + iManufacturer field in the device descriptor). + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found +*/ +EXPORT_C TInt DUsbClientController::RemoveManufacturerStringDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveManufacturerStringDescriptor()")); + return iDescriptors.RemoveManufacturerStringDescriptor(); + } + + +/** Returns the currently set Product string (which is referenced by the iProduct field in the device + descriptor). + + (Thus, the function should actually be called either 'GetProductString' or + 'GetProductStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the string is running in. + @param aString A reference to a buffer into which the requested string should be written (most likely + located user-side). + + @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return + value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetProductStringDescriptor(DThread* aThread, TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetProductStringDescriptor()")); + return iDescriptors.GetProductStringDescriptorTC(aThread, aString); + } + + +/** Sets a new Product string in the Product string descriptor (which is referenced by the iProduct field in + the device descriptor). + + (Thus, the function should actually be called either 'SetProductString' or + 'SetProductStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. + @param aString A reference to a buffer which contains the string to be set (most likely located + user-side). + + @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the + return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, + KErrNone if new string descriptor successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetProductStringDescriptor(DThread* aThread, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetProductStringDescriptor()")); + return iDescriptors.SetProductStringDescriptorTC(aThread, aString); + } + + +/** Removes (deletes) the Product string descriptor (which is referenced by the + iProduct field in the device descriptor). + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found +*/ +EXPORT_C TInt DUsbClientController::RemoveProductStringDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveProductStringDescriptor()")); + return iDescriptors.RemoveProductStringDescriptor(); + } + + +/** Returns the currently set SerialNumber string (which is referenced by the iSerialNumber field in the device + descriptor). + + (Thus, the function should actually be called either 'GetSerialNumberString' or + 'GetSerialNumberStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the string is running in. + @param aString A reference to a buffer into which the requested string should be written (most likely + located user-side). + + @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return + value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetSerialNumberStringDescriptor(DThread* aThread, TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetSerialNumberStringDescriptor()")); + return iDescriptors.GetSerialNumberStringDescriptorTC(aThread, aString); + } + + +/** Sets a new SerialNumber string in the SerialNumber string descriptor (which is referenced by the + iSerialNumber field in the device descriptor). + + (Thus, the function should actually be called either + 'SetSerialNumberString' or 'SetSerialNumberStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. + @param aString A reference to a buffer which contains the string to be set (most likely located + user-side). + + @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the + return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, + KErrNone if new string descriptor successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetSerialNumberStringDescriptor(DThread* aThread, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetSerialNumberStringDescriptor()")); + return iDescriptors.SetSerialNumberStringDescriptorTC(aThread, aString); + } + + +/** Removes (deletes) the Serial Number string descriptor (which is referenced by the + iSerialNumber field in the device descriptor). + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found +*/ +EXPORT_C TInt DUsbClientController::RemoveSerialNumberStringDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveSerialNumberStringDescriptor()")); + return iDescriptors.RemoveSerialNumberStringDescriptor(); + } + + +/** Returns the currently set Configuration string (which is referenced by the iConfiguration field in the + configuration descriptor). + + (Thus, the function should actually be called either 'GetConfigurationString' or + 'GetConfigurationStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the string is running in. + @param aString A reference to a buffer into which the requested string should be written (most likely + located user-side). + + @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return + value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetConfigurationStringDescriptor(DThread* aThread, TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationStringDescriptor()")); + return iDescriptors.GetConfigurationStringDescriptorTC(aThread, aString); + } + + +/** Sets a new Configuration string in the Configuration string descriptor (which is referenced by the + iConfiguration field in the configuration descriptor). + + (Thus, the function should actually be called either + 'SetConfigurationString' or 'SetConfigurationStringDescriptorString'.) + + @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. + @param aString A reference to a buffer which contains the string to be set (most likely located + user-side). + + @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the + return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, + KErrNone if new string descriptor successfully set. +*/ +EXPORT_C TInt DUsbClientController::SetConfigurationStringDescriptor(DThread* aThread, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationStringDescriptor()")); + return iDescriptors.SetConfigurationStringDescriptorTC(aThread, aString); + } + + +/** Removes (deletes) the Configuration string descriptor (which is referenced by the + iConfiguration field in the configuration descriptor). + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. +*/ +EXPORT_C TInt DUsbClientController::RemoveConfigurationStringDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveConfigurationStringDescriptor()")); + return iDescriptors.RemoveConfigurationStringDescriptor(); + } + + +/** Copies the string descriptor at the specified index in the string descriptor array into + the aString argument. + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aThread A pointer to the thread the LDD requesting the string is running in. + @param aString A reference to a buffer into which the requested string should be written (most likely + located user-side). + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index, or the + return value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. +*/ +EXPORT_C TInt DUsbClientController::GetStringDescriptor(DThread* aThread, TUint8 aIndex, TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptor(%d)", aIndex)); + return iDescriptors.GetStringDescriptorTC(aThread, aIndex, aString); + } + + +/** Sets the aString argument to be a string descriptor at the specified index in the string + descriptor array. If a string descriptor already exists at that position then it will be replaced. + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. + @param aString A reference to a buffer which contains the string to be set (most likely located + user-side). + + @return KErrNone if successful, KErrArgument if aIndex is invalid, KErrNoMemory if no memory is available + to store the new string (an existing descriptor at that index will be preserved), or the return value of + the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong. +*/ +EXPORT_C TInt DUsbClientController::SetStringDescriptor(DThread* aThread, TUint8 aIndex, const TDes8& aString) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetStringDescriptor(%d)", aIndex)); + return iDescriptors.SetStringDescriptorTC(aThread, aIndex, aString); + } + + +/** Removes (deletes) the string descriptor at the specified index in the string descriptor array. + + @param aIndex The position of the string descriptor in the string descriptor array. + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index. +*/ +EXPORT_C TInt DUsbClientController::RemoveStringDescriptor(TUint8 aIndex) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveStringDescriptor(%d)", aIndex)); + return iDescriptors.RemoveStringDescriptor(aIndex); + } + + +/** Queries the use of and endpoint resource. + + If the resource gets successfully allocated, it will be used from when the current bus transfer + has been completed. + + @param aClientId A pointer to the LDD querying the endpoint resource. + @param aEndpointNum The number of the endpoint. + @param aResource The endpoint resource to be queried. + + @return ETrue if the specified resource is in use at the endpoint, EFalse if not or if there was any error + during the execution of the function. +*/ +EXPORT_C TBool DUsbClientController::QueryEndpointResource(const DBase* /*aClientId*/, TInt aEndpointNum, + TUsbcEndpointResource aResource) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::QueryEndpointResource()")); + return iController.QueryEndpointResource(aEndpointNum, aResource); + } + + +EXPORT_C TInt DUsbClientController::EndpointPacketSize(const DBase* aClientId, TInt aEndpointNum) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointPacketSize(0x%08x, %d)", + aClientId, aEndpointNum)); + + const TUsbcInterfaceSet* const ifcset_ptr = ClientId2InterfacePointer(aClientId); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface or clientid not found")); + return -1; + } + const TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[ifcset_ptr->iCurrentInterface]; + const RPointerArray& ep_array = ifc_ptr->iEndpoints; + const TInt n = ep_array.Count(); + for (TInt i = 0; i < n; i++) + { + const TUsbcLogicalEndpoint* const ep = ep_array[i]; + if (EpAddr2Idx(ep->iPEndpoint->iEndpointAddr) == static_cast(aEndpointNum)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Endpoint packet sizes: FS = %d HS = %d", + ep->iEpSize_Fs, ep->iEpSize_Hs)); + const TInt size = iHighSpeed ? ep->iEpSize_Hs : ep->iEpSize_Fs; + __KTRACE_OPT(KUSB, Kern::Printf(" Returning %d", size)); + return size; + } + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint not found")); + return -1; + } + +EXPORT_C TDfcQue* DUsbClientController::DfcQ(TInt /*aIndex*/) + { + return iControllerProperties.iDfcQueue; + } + +EXPORT_C void DUsbClientController::DumpRegisters() + { + return; + } + +EXPORT_C TInt DUsbClientController::SignalRemoteWakeup() + { + return iController.SignalRemoteWakeup(); + } + +EXPORT_C TBool DUsbClientController::CurrentlyUsingHighSpeed() + { + UsbShai::TSpeed speed = iController.DeviceOperatingSpeed(); + + return (speed == UsbShai::EHighSpeed)?ETrue:EFalse; + } + +// +// === USB Controller member function implementations - PSL API (public) =========================== +// + +/** Gets called by the PSL to register a newly created derived class controller object. + + @param aUdc The number of the new UDC. It should be 0 for the first (or only) UDC in the system, 1 for the + second one, and so forth. KUsbcMaxUdcs determines how many UDCs are supported. + + @return A pointer to the controller if successfully registered, NULL if aUdc out of (static) range. + + @publishedPartner @released +*/ +TInt DUsbClientController::RegisterUdc(TInt aUdc) + { + TInt err = KErrNone; + + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterUdc()")); + + if (aUdc < 0 || aUdc > (KUsbcMaxUdcs - 1)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); + return KErrInUse; + } + else + { + UsbClientController[aUdc] = this; + } + + return err; + } + + +// +// === USB Controller member function implementations - PSL API (protected) ======================== +// + +/** Initialises an instance of this class, which is the base class of the derived class (= PSL, which is + supposed to call this function). + + It does the following things: + + - disconnects the UDC from the bus, + - initialises the USB descriptor pool, uses data from the PSL (see function argument list) + - creates and initialises the basic USB device configuration + - initialises the array of physical endpoints + - initialises Ep0 structures (but doesn't configure & enable Ep0 yet) + - creates and installs the USB power handler + + @param aDeviceDesc A pointer to a valid standard USB device descriptor or NULL. The values initially + required in the descriptor follow from its constructor. The descriptor is not copied over, but rather this + pointer is queued directly into the descriptor pool. Must be writable memory. + + @param aConfigDesc A pointer to a valid standard USB configuration descriptor or NULL. The values + initially required in the descriptor follow from its constructor. The descriptor is not copied over, but + rather this pointer is queued directly into the descriptor pool. Must be writable memory. + + @param aLangId A pointer to a valid USB language ID (string) descriptor. The values initially required in + the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is + queued directly into the descriptor pool. Must be writable memory. Other than the remaining four string + descriptors, this one is not optional. The reason is that the USB spec mandates a LangId descriptor as + soon as a single string descriptor gets returned by the device. So, even though the device might omit the + Manufacturer, Product, SerialNumber, and Configuration string descriptors, it is at this point not known + whether there will be any Interface string descriptors. Since any USB API user can create an interface + with an Interface string descriptor, we have to insist here on the provision of a LangId string + descriptor. (The PIL decides at run-time whether or not to return the LangId string descriptor to the + host, depending on whether there exist any string descriptors at that time.) + + @param aManufacturer A pointer to a valid USB string descriptor or NULL. The values initially required in + the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is + queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by + the iManufacturer field in the device descriptor. + + @param aProduct A pointer to a valid USB string descriptor or NULL. The values initially required in the + descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is + queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by + the iProduct field in the device descriptor. + + @param aSerialNum A pointer to a valid USB string descriptor or NULL. The values initially required in the + descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is + queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by + the iSerialNumber field in the device descriptor. + + @param aConfig A pointer to a valid USB string descriptor or NULL. The values initially required in the + descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is + queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by + the iConfiguration field in the configuration descriptor. + + @param aOtgDesc A pointer to a valid USB OTG descriptor (if OTG is supported by this device and is to be + supported by the driver) or NULL. The values initially required in the descriptor follow from its + constructor. The descriptor is not copied over, but rather this pointer is queued directly into the + descriptor pool. Must be writable memory. + + @return EFalse, if USB descriptor pool initialisation fails, or if configuration creation fails, or if the + PSL reports more endpoints than the constant KUsbcMaxEndpoints permits, or if the Ep0 logical endpoint + creation fails, or if the creation of the power handler fails; ETrue, if base class object successfully + initialised. + + @publishedPartner @released +*/ +TBool DUsbClientController::Initialise(TUsbPeripheralDescriptorPool& aDescPool, + const UsbShai::TUsbPeripheralEndpointCaps* aEndpointCaps, + TInt aTotalEndpoints) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InitialiseBaseClass()")); + + // We don't want the host to see us (at least not yet): + UsbDisconnect(); + + iDeviceTotalEndpoints = aTotalEndpoints; + + // Initialise USB descriptor pool + if (iDescriptors.Init(aDescPool.iDeviceDesc, + aDescPool.iConfigDesc, + aDescPool.iLangId, + aDescPool.iManufacturer, + aDescPool.iProduct, + aDescPool.iSerialNum, + aDescPool.iConfig, + aDescPool.iOtgDesc) != KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Error: Descriptor initialization failed")); + return EFalse; + } + + if (aDescPool.iOtgDesc) + { + iOtgSupport = ETrue; + iOtgFuncMap = aDescPool.iOtgDesc->DescriptorData()[2]; + } + + // Some member variables + iSelfPowered = aDescPool.iConfigDesc->Byte(7) & (1 << 6); // Byte 7: bmAttributes + iRemoteWakeup = aDescPool.iConfigDesc->Byte(7) & (1 << 5); + + if (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed) + { + if (iDescriptors.InitHs() != KErrNone) + { + return EFalse; + } + } + + // Create and initialise our first (and only) configuration + TUsbcConfiguration* config = new TUsbcConfiguration(1); + if (!config) + { + return EFalse; + } + iConfigs.Append(config); + + // Initialise the array of physical endpoints + __KTRACE_OPT(KUSB, Kern::Printf(" DeviceTotalEndpoints: %d", aTotalEndpoints)); + + // KUsbcMaxEndpoints doesn't include ep 0 + if ((aTotalEndpoints > (KUsbcMaxEndpoints + 2)) || + ((aTotalEndpoints * sizeof(TUsbcPhysicalEndpoint)) > sizeof(iRealEndpoints))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints! (change KUsbcMaxEndpoints: %d)", + KUsbcMaxEndpoints)); + return EFalse; + } + + for (TInt i = 0; i < aTotalEndpoints; ++i) + { + iRealEndpoints[i].iEndpointAddr = EpIdx2Addr(i); + + __KTRACE_OPT(KUSB, Kern::Printf(" aEndpointCaps[%02d] - iTypes: 0x%08x iSizes: 0x%08x", + i, aEndpointCaps[i].iTypesAndDir, aEndpointCaps[i].iSizes)); + + iRealEndpoints[i].iCaps = aEndpointCaps[i]; + + // Reset revered bytes to zero + iRealEndpoints[i].iCaps.iReserved[0] = 0; + iRealEndpoints[i].iCaps.iReserved[1] = 0; + + if ((i > 1) && (aEndpointCaps[i].iTypesAndDir != UsbShai::KUsbEpNotAvailable)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> UsableEndpoint: #%d", i)); + iDeviceUsableEndpoints++; + } + } + + // Initialise Ep0 structures (logical endpoints are numbered 1..KMaxEndpointsPerClient, + // and virtual 0 is real 0): + // -- Ep0 OUT + iEp0MaxPacketSize = MaxEndpointPacketSize(aEndpointCaps[0].iSizes); + __KTRACE_OPT(KUSB, Kern::Printf(" using Ep0 maxpacketsize of %d bytes", iEp0MaxPacketSize)); + + TUsbcEndpointInfo info(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirOut, 0); + TUsbcLogicalEndpoint* ep = NULL; + + info.iSize = iEp0MaxPacketSize; + ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_Out]); + if (!ep) + { + return EFalse; + } + + __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_Out)); + iRealEndpoints[KEp0_Out].iLEndpoint = ep; + + // -- Ep0 IN + info.iDir = UsbShai::KUsbEpDirIn; + ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_In]); + if (!ep) + { + delete iRealEndpoints[KEp0_Out].iLEndpoint; + iRealEndpoints[KEp0_Out].iLEndpoint = NULL; + return EFalse; + } + __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_In)); + iRealEndpoints[KEp0_In].iLEndpoint = ep; + + iPowerHandler = new DUsbcPowerHandler(this); + if (!iPowerHandler) + { + delete iRealEndpoints[KEp0_Out].iLEndpoint; + iRealEndpoints[KEp0_Out].iLEndpoint = NULL; + delete iRealEndpoints[KEp0_In].iLEndpoint; + iRealEndpoints[KEp0_In].iLEndpoint = NULL; + return EFalse; + } + iPowerHandler->Add(); + + return ETrue; + } + +/** The standard constructor for this class. + + @publishedPartner @released + */ +DUsbClientController::DUsbClientController(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, + const UsbShai::TPeripheralControllerProperties& aProperties, + TBool aIsOtgPort) + : iEp0ReceivedNonStdRequest(EFalse), + iRmWakeupStatus_Enabled(EFalse), + iEp0_RxBuf(), + iDeviceTotalEndpoints(0), + iDeviceUsableEndpoints(0), + iDeviceState(UsbShai::EUsbPeripheralStateUndefined), + iDeviceStateB4Suspend(UsbShai::EUsbPeripheralStateUndefined), + iSelfPowered(EFalse), + iRemoteWakeup(EFalse), + iHardwareActivated(EFalse), + iOtgSupport(EFalse), + iOtgFuncMap(0), + iHighSpeed(EFalse), + iEp0MaxPacketSize(0), + iEp0ClientId(NULL), + iEp0DataReceived(0), + iEp0WritePending(EFalse), + iEp0ClientDataTransmitting(EFalse), + iEp0DeviceControl(NULL), + iDescriptors(iEp0_TxBuf), + iCurrentConfig(0), + iConfigs(1), + iRealEndpoints(), + iEp0_TxBuf(), + iEp0_RxExtraCount(0), + iEp0_TxNonStdCount(0), + iEp0ReadRequestCallbacks(_FOFF(TUsbcRequestCallback, iLink)), + iClientCallbacks(_FOFF(TUsbcClientCallback, iLink)), + iStatusCallbacks(_FOFF(TUsbcStatusCallback, iLink)), + iEpStatusCallbacks(_FOFF(TUsbcEndpointStatusCallback, iLink)), + iOtgCallbacks(_FOFF(TUsbcOtgFeatureCallback, iLink)), + iReconnectTimer(ReconnectTimerCallback, this), + iUsbLock(TSpinLock::EOrderGenericIrqLow3), + iController(aPeripheralControllerIf), + iControllerProperties(aProperties), + iIsOtgPort(aIsOtgPort), + iOtgObserver(NULL), + iConTransferMgr(NULL), + iLastError(EFalse), + iSetupPacketPending(EFalse), + iCommonDfcQThread(NULL), + iPowerUpDfc(PowerUpDfc, this, 3), + iPowerDownDfc(PowerDownDfc, this, 3), + iDeviceEventNotifyDfc(DeviceEventNotifyDfc,this,3), + iThreadContextFinder(ThreadContextFinderDfc,this,3), + iStandby(EFalse), + iStackIsActive(EFalse), + iClientSupportReady(EFalse), + iUsbResetDeferred(EFalse), + iEnablePullUpOnDPlus(NULL), + iDisablePullUpOnDPlus(NULL), + iOtgContext(NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DUsbClientController()")); + + iLastError = KErrNone; + +#ifndef SEPARATE_USB_DFC_QUEUE + iPowerUpDfc.SetDfcQ(Kern::DfcQue0()); + iPowerDownDfc.SetDfcQ(Kern::DfcQue0()); +#endif // SEPARATE_USB_DFC_QUEUE + + for (TInt i = 0; i < KUsbcEpArraySize; i++) + iRequestCallbacks[i] = NULL; + } + +TInt DUsbClientController::Construct() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Construct")); + + // Setup the state machines of ep0 + TInt err = SetupEp0StateMachine(); + if( err != KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Can not setup state machines, exit")); + return err; + } + +#ifdef SEPARATE_USB_DFC_QUEUE + iPowerUpDfc.SetDfcQ(iControllerProperties.iDfcQueue); + iPowerDownDfc.SetDfcQ(iControllerProperties.iDfcQueue); +#endif // SEPARATE_USB_DFC_QUEUE + + iDeviceEventNotifyDfc.SetDfcQ(iControllerProperties.iDfcQueue); + iThreadContextFinder.SetDfcQ(iControllerProperties.iDfcQueue); + + // Register + if( RegisterUdc(0) != KErrNone) + { + // This is the only reason. + return KErrInUse; + } + + __KTRACE_OPT(KUSB, Kern::Printf(" peripheral controller registered")); + TUsbPeripheralDescriptorPool descPool; + + if( CreateDescriptors(descPool) == KErrNone) + { + __KTRACE_OPT(KUSB, Kern::Printf(" descriptors created")); + + // Initialise the array of physical endpoints + __KTRACE_OPT(KUSB, Kern::Printf(" initialising PIL ")); + TBool initOk = Initialise(descPool, + iControllerProperties.iDeviceEndpointCaps, + iControllerProperties.iDeviceTotalEndpoints); + + // Let UDC has a changes to know the callback interface is ready. + // Any further initialization/startup/preparation etc can be performed now. + if ( initOk ) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Initializing PSL ")); + + // Set Rx buffer for endpoint zero + iController.SetEp0RxBuffer(iEp0_RxBuf,KUsbcBufSzControl); + + // Set pil callback interface for PSL. + iController.SetPilCallbackInterface(*this); + + } + else + { + return KErrNoMemory; + } + } + + // Register ourself as the ONLY one client of charger detection observer + gChargerObsever = this; + + // In case the charger detector already registered, start monitor + // Charger type notifications + if( gChargerDetector != NULL ) + { + gChargerDetector->SetChargerDetectorObserver(*gChargerObsever); + } + + iThreadContextFinder.Enque(); + + return KErrNone; + } + +// This function doesn't consider the situation of OOM. +// Because, this function will be call during extension's entry point, +// There is no way to start up phone successfully if anything failed anyway... +TInt DUsbClientController::SetupEp0StateMachine() + { + // Create the state machine first + __ASSERT_DEBUG((iConTransferMgr == NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + iConTransferMgr = new DControlTransferManager(*this); + if(iConTransferMgr == 0) + { + return KErrNoMemory; + } + + // Add UsbShai::EControlTransferStageSetup stage machine + TControlStageSm* stageSm = new DSetupStageSm(*iConTransferMgr); + __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(stageSm != NULL) + { + iConTransferMgr->AddState(UsbShai::EControlTransferStageSetup,*stageSm); + } + else + { + return KErrNoMemory; + } + + // Add EControlTransferStageDataOut stage state machine + stageSm = new DDataOutStageSm(*iConTransferMgr); + __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(stageSm != NULL) + { + iConTransferMgr->AddState(UsbShai::EControlTransferStageDataOut,*stageSm); + } + else + { + // we don't need bother to delete the previous allocated memory + // system can not bootup if we return error + return KErrNoMemory; + } + + // Add EControlTransferStageStatusIn stage state machine + stageSm = new DStatusInStageSm(*iConTransferMgr); + __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(stageSm != NULL) + { + iConTransferMgr->AddState(UsbShai::EControlTransferStageStatusIn,*stageSm); + } + else + { + return KErrNoMemory; + } + + // Add EControlTransferStageDataIn stage state machine + stageSm = new DDataInStageSm(*iConTransferMgr); + __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(stageSm != NULL) + { + iConTransferMgr->AddState(UsbShai::EControlTransferStageDataIn,*stageSm); + } + else + { + return KErrNoMemory; + } + + // Add EControlTransferStageStatusOut stage state machine + stageSm = new DStatusOutStageSm(*iConTransferMgr); + __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(stageSm != NULL) + { + iConTransferMgr->AddState(UsbShai::EControlTransferStageStatusOut,*stageSm); + } + else + { + return KErrNoMemory; + } + + return KErrNone; + } + +// --------------------------------------------------------------------------- +// From MUsbPeripheralPilCallbackIf. +// Enable the peripheral stack +// --------------------------------------------------------------------------- +// +void DUsbClientController::EnablePeripheralStack() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnablePeripheralStack")); + + if (iStackIsActive) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Already enabled - returning")); + return; + } + + // Mark stack is enabled, Waiting upper application to power controller + // Anyway, this will lead us to attached state + iStackIsActive = ETrue; + NextDeviceState(UsbShai::EUsbPeripheralStateAttached); + + // If hardware is not activated yet, do it here. + if(iClientSupportReady && !iHardwareActivated) + { + // PowerUpUdc only do Activating Hardware when there are at least 1 + // Iterface registered. + PowerUpUdc(); + } + + } + + +// --------------------------------------------------------------------------- +// From MUsbPeripheralPilCallbackIf. +// Disable the peripheral stack +// --------------------------------------------------------------------------- +// +void DUsbClientController::DisablePeripheralStack() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DisablePeripheralStack")); + + if (!iStackIsActive) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Already disabled - returning")); + return; + } + + // Reset OTG features, leave attributes as is (just as in USB Reset case) + // (OTG spec 1.3 sections 6.5.x all say "... on a bus reset or at the end + // of a session." VBus drop is the end of a session.) + iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; + OtgFeaturesNotify(); + // Tear down the current configuration (if any) + ChangeConfiguration(0); + + if (iDeviceState != UsbShai::EUsbPeripheralStateUndefined) + { + // Not being in state UNDEFINED implies that the cable is inserted. + if (iHardwareActivated) + { + NextDeviceState(UsbShai::EUsbPeripheralStatePowered); + } + // (If the hardware is NOT activated at this point, we can only be in + // state UsbShai::EUsbPeripheralStateAttached, so we don't have to move to it.) + } + DeActivateHardwareController(); // turn off UDC altogether + iStackIsActive = EFalse; + // Notify registered clients on the user side about a USB device state + // change event and a transition to the "Undefined" state. + // Note: the state should be changed to "Undefined" before calling RunClientCallbacks(), + // otherwise the "Undefined" state will probably be lost. + NextDeviceState(UsbShai::EUsbPeripheralStateUndefined); + // Complete all pending requests, returning KErrDisconnected + RunClientCallbacks(); + } + + +// --------------------------------------------------------------------------- +// From MUsbPeripheralPilCallbackIf. +// Set the OTG Observer +// --------------------------------------------------------------------------- +// +void DUsbClientController::SetOtgObserver(MUsbOtgPeripheralObserverIf* aObserver) + { + iOtgObserver = aObserver; + } + + +/** This function gets called by the PSL upon detection of either of the following events: + - USB Reset, + - USB Suspend event, + - USB Resume signalling, + - The USB cable has been attached (inserted) or detached (removed). + + @param anEvent An enum denoting the event that has occured. + + @return KErrArgument if the event is not recognized, otherwise KErrNone. + + @publishedPartner @released +*/ +TInt DUsbClientController::DeviceEventNotification(UsbShai::TUsbPeripheralEvent anEvent) + { + TInt err = KErrNone; + + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceEventNotification(anEvent=%d)", anEvent)); + + switch (anEvent) + { + case UsbShai::EUsbEventSuspend: + case UsbShai::EUsbEventResume: + case UsbShai::EUsbEventReset: + case UsbShai::EUsbEventVbusRisen: + case UsbShai::EUsbEventVbusFallen: + { + TInt nkern_curr_ctx= NKern::CurrentContext(); + + if( (nkern_curr_ctx != NKern::EInterrupt) && (nkern_curr_ctx != NKern::EIDFC)) + { + // Normal context + __ASSERT_DEBUG((iCommonDfcQThread != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + if(iCommonDfcQThread == &(Kern::CurrentThread().iNThread)) + { + // we already in the correct context, just run processes here directly. + __KTRACE_OPT(KUSB, Kern::Printf(" Correct thread context")); + ProcessDeviceEventNotification(anEvent); + } + else + { + // we're in a normal thread, but it is not the same as the DfcQ context + // passed by PSL, queue it + __KTRACE_OPT(KUSB, Kern::Printf(" Incorrect thread context")); + iDevEventQueue.FifoAdd(anEvent); + iDeviceEventNotifyDfc.Enque(); + } + } + else + { + // We're in a ISR or IDFC context + __KTRACE_OPT(KUSB, Kern::Printf(" ISR|IDFC context")); + iDevEventQueue.FifoAdd(anEvent); + iDeviceEventNotifyDfc.Add(); + } + } + break; + + default: + err = KErrArgument; + } + + return err; + } + + +/** This function gets called by the PSL upon completion of a pending data transfer request. + + This function is not to be used for endpoint zero completions (use Ep0RequestComplete instead). + + @param aCallback A pointer to a data transfer request callback structure which was previously passed to + the PSL in a SetupReadBuffer() or SetupWriteBuffer() call. + + @publishedPartner @released +*/ +void DUsbClientController::EndpointRequestComplete(UsbShai::TUsbPeripheralRequest* aCallback) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointRequestComplete(%p)", aCallback)); + + TUsbcRequestCallback* cb = static_cast(aCallback); + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + // We don't test aCallback for NULL here (and therefore risk a crash) + // because the PSL should never give us a NULL argument. If it does it + // means the PSL is buggy and ought to be fixed. + ProcessDataTransferDone(*cb); + } + + +/** This function should be called by the PSL after reception of an Ep0 + SET_FEATURE request with a feature selector of either {b_hnp_enable, + a_hnp_support, a_alt_hnp_support}, but only when that Setup packet is not + handed up to the PIL (for instance because it is auto-decoded and + 'swallowed' by the UDC hardware). + + @param aHnpState A bitmask indicating the present state of the three OTG + feature selectors as follows: + + bit.0 == a_alt_hnp_support + bit.1 == a_hnp_support + bit.2 == b_hnp_enable + + @see DUsbClientController::ProcessSetClearDevFeature() + + @publishedPartner @released +*/ +void DUsbClientController::HandleHnpRequest(TInt aHnpState) +// This function is called by the PSL from within an ISR -- so we have to take care what we do here +// (and also in all functions that get called from here). + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HandleHnpRequest(%d)", aHnpState)); + + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + return; + } + if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + return; + } + // (case KUsbFeature_B_HnpEnable:) + if (aHnpState & 0x04) + { + iOtgFuncMap |= KUsbOtgAttr_B_HnpEnable; + } + // (case KUsbFeature_A_HnpSupport:) + if (aHnpState & 0x02) + { + iOtgFuncMap |= KUsbOtgAttr_A_HnpSupport; + } + // (case KUsbFeature_A_AltHnpSupport:) + if (aHnpState & 0x01) + { + iOtgFuncMap |= KUsbOtgAttr_A_AltHnpSupport; + } + OtgFeaturesNotify(); + } + +void DUsbClientController::GetEp0RxBufferInfo(TUint8*& aBuffer, TInt& aBufferLen) + { + aBuffer = iEp0_RxBuf; + aBufferLen = KUsbcBufSzControl; + } + +UsbShai::TUsbPeripheralState DUsbClientController::DeviceStatus() const + { + return iDeviceState; + } + +TBool DUsbClientController::Ep0ReceivedNonStdRequest() + { + return iEp0ReceivedNonStdRequest; + } + +/** This function gets called by the PSL upon completion of a pending endpoint zero data transfer request. + + @param aRealEndpoint Either 0 for Ep0 OUT (= Read), or 1 for Ep0 IN (= Write). + @param aCount The number of bytes received or transmitted, respectively. + @param aError The error status of the completed transfer request. Can be KErrNone if no error, KErrCancel + if transfer was cancelled, or KErrPrematureEnd if a premature status end was encountered. + + @return KErrNone if no error during transfer completion processing, KErrGeneral if the request was a read & + a Setup packet was received & the recipient for that packet couldn't be found (invalid packet: Ep0 has been + stalled), KErrNotFound if the request was a read & the recipient for that packet (Setup or data) _was_ + found - however no read had been set up by that recipient (this case should be used by the PSL to disable + the Ep0 interrupt at that point and give the LDD time to set up a new Ep0 read; once the 'missing' read + was set up either Ep0ReceiveProceed or Ep0ReadSetupPktProceed will be called by the PIL). + + @publishedPartner @released +*/ +TInt DUsbClientController::Ep0RequestComplete(TInt aRealEndpoint, + TInt aCount, + TInt aError, + UsbShai::TControlPacketType aPktType) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::Ep0RequestComplete(%d)", aRealEndpoint)); + + iLastError = KErrNone; + + iConTransferMgr->Ep0RequestComplete(iEp0_RxBuf,aCount,aError,aPktType); + + __KTRACE_OPT(KUSB, Kern::Printf(" iLastError(%d)", iLastError)); + + if(iEp0WritePending == EFalse) + { + iConTransferMgr->SetupEndpointZeroRead(); + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::Ep0RequestComplete")); + return iLastError; + } + +/** This function should be called by the PSL once the UDC (and thus the USB device) is in the Address state. + + @publishedPartner @released +*/ +void DUsbClientController::MoveToAddressState() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::MoveToAddressState()")); + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + NextDeviceState(UsbShai::EUsbPeripheralStateAddress); + } + + +TBool DUsbClientController::CreateDescriptors(TUsbPeripheralDescriptorPool& aOutput) + { + TInt errCode = KErrNone; + + // Create all the string descriptors + TUsbcDeviceDescriptor* deviceDesc = TUsbcDeviceDescriptor::New( + 0, // aDeviceClass, will be changed later by upper app + 0, // aDeviceSubClass, will be changed later by upper app + 0, // aDeviceProtocol, will be changed later by upper app + iControllerProperties.iMaxEp0Size , // aMaxPacketSize0 + KUsbVendorId, // aVendorId + KUsbProductId , // aProductId + iControllerProperties.iDeviceRelease, // aDeviceRelease + KUsbNumberOfConfiguration);// aNumConfigurations + __ASSERT_DEBUG( (deviceDesc != NULL), Kern::Fault( "USB PSL Out of memory, deviceDesc", __LINE__ )); + + TUsbcConfigDescriptor* configDesc = TUsbcConfigDescriptor::New( + 1, // Only one configruation is supported current. + EFalse, // at here, we always mark it as bus powered. + (iControllerProperties.iControllerCaps & UsbShai::KDevCapRemoteWakeupSupport)?ETrue:EFalse, // remote wakeup + 100); // 100 is a default value, thise value will be changed by + + __ASSERT_DEBUG( (configDesc != NULL), Kern::Fault( "USB PSL Out of memory, configDesc", __LINE__ )); + + TUsbcLangIdDescriptor* stringDescLang = TUsbcLangIdDescriptor::New(KUsbLangId); + __ASSERT_DEBUG( (stringDescLang != NULL), Kern::Fault( "USB PSL Out of memory, stringDescLang", __LINE__ )); + + // Default manufacturer string + TPtrC8 aString; + aString.Set(reinterpret_cast(KStringManufacturer), sizeof(KStringManufacturer) - 2); + TUsbcStringDescriptor* stringDescManu = TUsbcStringDescriptor::New(aString); + __ASSERT_DEBUG( (stringDescManu != NULL), Kern::Fault( "USB PSL Out of memory, stringDescManu", __LINE__ )); + + // Default product name string + aString.Set(reinterpret_cast(KStringProduct), sizeof(KStringProduct) - 2); + TUsbcStringDescriptor* stringDescProd = TUsbcStringDescriptor::New(aString); + __ASSERT_DEBUG( (stringDescProd != NULL), Kern::Fault( "USB PSL Out of memory, stringDescProd", __LINE__ )); + + // Default configuration name string + aString.Set(reinterpret_cast(KStringConfig), sizeof(KStringConfig) - 2); + TUsbcStringDescriptor* stringDescConf = TUsbcStringDescriptor::New(aString); + __ASSERT_DEBUG( (stringDescConf != NULL), Kern::Fault( "USB PSL Out of memory, stringDescConf", __LINE__ )); + + // Default serial bumber string + aString.Set(reinterpret_cast(KStringSerial), sizeof(KStringSerial) - 2); + TUsbcStringDescriptor* stringSerial = TUsbcStringDescriptor::New(aString); + __ASSERT_DEBUG( (stringSerial != NULL), Kern::Fault( "USB PSL Out of memory, stringDescConf", __LINE__ )); + + TUsbcOtgDescriptor* otgDesc = NULL; + + // In an OTG-environment, we also need to create the OTG + // descriptor. The PSL supports both HNP and SRP and hence we + // report support for them. Upper layers will override the + // descriptors anyway. + if (iIsOtgPort) + { + TBool srpSupported = (iControllerProperties.iControllerCaps & UsbShai::KDevCapSrpSupport)?ETrue:EFalse; + TBool hnpSupported = (iControllerProperties.iControllerCaps & UsbShai::KDevCapHnpSupport)?ETrue:EFalse; + + otgDesc = TUsbcOtgDescriptor::New(srpSupported, + hnpSupported); + + __ASSERT_DEBUG( (otgDesc != NULL), Kern::Fault( "USB PSL Out of memory, otgDesc", __LINE__ )); + } + + if( (deviceDesc != NULL) && + (configDesc != NULL) && + (stringDescLang != NULL) && + (stringDescManu != NULL) && + (stringDescProd != NULL) && + (stringDescConf != NULL) && + ((!iIsOtgPort) || (iIsOtgPort && (otgDesc != NULL)))) + { + aOutput.iDeviceDesc = deviceDesc; + aOutput.iConfigDesc = configDesc; + aOutput.iLangId = stringDescLang; + aOutput.iManufacturer = stringDescManu; + aOutput.iProduct = stringDescProd; + aOutput.iConfig = stringDescConf; + aOutput.iSerialNum = stringSerial; + aOutput.iOtgDesc = otgDesc; + } + else + { + if( deviceDesc != NULL ) + { + delete deviceDesc; + } + + if( configDesc != NULL ) + { + delete configDesc; + } + + if( stringDescLang != NULL ) + { + delete stringDescLang; + } + + if( stringDescManu != NULL ) + { + delete stringDescManu; + } + + if( stringDescProd != NULL ) + { + delete stringDescProd; + } + + if( stringDescConf != NULL ) + { + delete stringDescConf; + } + + if( stringSerial != NULL ) + { + delete stringSerial; + } + + if( otgDesc != NULL ) + { + delete otgDesc; + } + + errCode = KErrNoMemory; + } + + // We don't support serial number + aOutput.iSerialNum = NULL; + + return errCode; + } + +// +// === USB Controller member function implementations - Internal utility functions (private) ======= +// + +TInt DUsbClientController::DeRegisterClientCallback(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClientCallback()")); + __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); + TSglQueIter iter(iClientCallbacks); + TUsbcClientCallback* p; + while ((p = iter++) != NULL) + if (p->Owner() == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing ClientCallback @ 0x%x", p)); + iClientCallbacks.Remove(*p); + return KErrNone; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Client not found")); + return KErrNotFound; + } + + +TBool DUsbClientController::CheckEpAvailability(TInt aEndpointsUsed, + const TUsbcEndpointInfoArray& aEndpointData, + TInt aIfcNumber) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CheckEpAvailability()")); + if (aEndpointsUsed > KMaxEndpointsPerClient) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints claimed (%d)", aEndpointsUsed)); + return EFalse; + } + TBool reserve[KUsbcEpArraySize]; // iDeviceTotalEndpoints can be equal to 32 + memset(reserve, EFalse, sizeof(reserve)); // reset the array + for (TInt i = 0; i < aEndpointsUsed; ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" checking for (user) endpoint #%d availability...", i + 1)); + TInt j = 2; + while (j < iDeviceTotalEndpoints) + { + if ((iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], aIfcNumber)) && + (reserve[j] == EFalse)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" ---> found suitable endpoint: RealEndpoint #%d", j)); + reserve[j] = ETrue; // found one: mark this ep as reserved + break; + } + __KTRACE_OPT(KUSB, Kern::Printf(" -> endpoint not suitable: RealEndpoint #%d", j)); + j++; + } + if (j == iDeviceTotalEndpoints) + { + return EFalse; + } + } + return ETrue; + } + + +TUsbcInterface* DUsbClientController::CreateInterface(const DBase* aClientId, TInt aIfc, TUint32 aFeatureWord) +// We know that 9.2.3 says: "Interfaces are numbered from zero to one less than the number of +// concurrent interfaces supported by the configuration." But since we permit the user to +// change interface numbers, we can neither assume nor enforce anything about them here. + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateInterface(x, aIfc=%d)", aIfc)); + TUsbcInterfaceSet* ifcset_ptr = NULL; + TInt ifcset = ClientId2InterfaceNumber(aClientId); + TBool new_ifc; + if (ifcset < 0) + { + // New interface(set), so we need to find a number for it. + new_ifc = ETrue; + const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); + if (num_ifcsets == 255) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Too many interfaces already exist: 255")); + return NULL; + } + // Find the smallest interface number that has not yet been used. + for (ifcset = 0; ifcset < 256; ++ifcset) + { + TBool n_used = EFalse; + for (TInt i = 0; i < num_ifcsets; ++i) + { + if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == ifcset) + { + __KTRACE_OPT(KUSB, Kern::Printf(" interface number %d already used", ifcset)); + n_used = ETrue; + break; + } + } + if (!n_used) + { + break; + } + } + if (ifcset == 256) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no available interface number found")); + return NULL; + } + // append the ifcset + __KTRACE_OPT(KUSB, Kern::Printf(" creating new InterfaceSet %d first", ifcset)); + if (aIfc != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (1): %d", aIfc)); + return NULL; + } + if ((ifcset_ptr = new TUsbcInterfaceSet(aClientId, ifcset)) == NULL) + { + __KTRACE_OPT(KPANIC, + Kern::Printf(" Error: new TUsbcInterfaceSet(aClientId, ifcset_num) failed")); + return NULL; + } + iConfigs[0]->iInterfaceSets.Append(ifcset_ptr); + } + else /* if (ifcset_num >= 0) */ + { + // use an existent ifcset + new_ifc = EFalse; + __KTRACE_OPT(KUSB, Kern::Printf(" using existing InterfaceSet %d", ifcset)); + ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); + if (aIfc != ifcset_ptr->iInterfaces.Count()) + { + // 9.2.3: "Alternate settings range from zero to one less than the number of alternate + // settings for a specific interface." (Thus we can here only append a setting.) + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (2): %d", aIfc)); + return NULL; + } + // Check whether the existing interface belongs indeed to this client + if (ifcset_ptr->iClientId != aClientId) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iClientId (%p) != aClientId (%p)", + ifcset_ptr->iClientId, aClientId)); + return NULL; + } + } + const TBool no_ep0_requests = aFeatureWord & KUsbcInterfaceInfo_NoEp0RequestsPlease; + TUsbcInterface* const ifc_ptr = new TUsbcInterface(ifcset_ptr, aIfc, no_ep0_requests); + if (!ifc_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcInterface(ifcset, aIfc) failed")); + if (new_ifc) + { + DeleteInterfaceSet(ifcset); + } + return NULL; + } + ifcset_ptr->iInterfaces.Append(ifc_ptr); + return ifc_ptr; + } + + +#define RESET_SETTINGRESERVE \ + for (TInt i = start_ep; i < iDeviceTotalEndpoints; i++) \ + { \ + if (iRealEndpoints[i].iSettingReserve) \ + iRealEndpoints[i].iSettingReserve = EFalse; \ + } \ + +TInt DUsbClientController::CreateEndpoints(TUsbcInterface* aIfc, TInt aEndpointsUsed, + const TUsbcEndpointInfoArray& aEndpointData, + TInt aRealEpNumbers[]) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateEndpoints()")); + const TInt ifc_num = aIfc->iInterfaceSet->iInterfaceNumber; + const TInt start_ep = 2; + for (TInt i = 0; i < aEndpointsUsed; ++i) + { + for (TInt j = start_ep; j < iDeviceTotalEndpoints; ++j) + { + if (iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], ifc_num)) + { + // Logical endpoints are numbered 1..KMaxEndpointsPerClient (virtual 0 is real 0 and 1) + TUsbcLogicalEndpoint* const ep = new TUsbcLogicalEndpoint(this, i + 1, aEndpointData[i], + aIfc, &iRealEndpoints[j]); + if (!ep) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcLogicalEndpoint() failed")); + aIfc->iEndpoints.ResetAndDestroy(); + RESET_SETTINGRESERVE; + return KErrNoMemory; + } + aIfc->iEndpoints.Append(ep); + // Check on logical endpoint's sizes for compliance with special restrictions. + if (aIfc->iSettingCode == 0) + { + // For details see last paragraph of 5.7.3 "Interrupt Transfer Packet Size Constraints". + if ((ep->iInfo.iType == UsbShai::KUsbEpTypeInterrupt) && (ep->iEpSize_Hs > 64)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: INT ep HS size = %d on default ifc setting", + ep->iEpSize_Hs)); + __KTRACE_OPT(KPANIC, Kern::Printf(" (should be <= 64)")); + } + // For details see last paragraph of 5.6.3 "Isochronous Transfer Packet Size Constraints". + else if ((ep->iInfo.iType == UsbShai::KUsbEpTypeIsochronous) && (ep->iInfo.iSize > 0)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: ISO ep size = %d on default ifc setting", + ep->iInfo.iSize)); + __KTRACE_OPT(KPANIC, Kern::Printf(" (should be zero or ep non-existent)")); + } + } + // If the endpoint doesn't support DMA (now or never) the next operation + // will be a successful no-op. + /* + const TInt r = OpenDmaChannel(j); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Opening of DMA channel failed")); + aIfc->iEndpoints.ResetAndDestroy(); + RESET_SETTINGRESERVE; + return r; + } + */ + __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d -> logical ep %d", + j, i + 1)); + iRealEndpoints[j].iIfcNumber = &aIfc->iInterfaceSet->iInterfaceNumber; + iRealEndpoints[j].iSettingReserve = ETrue; + __KTRACE_OPT(KUSB, + Kern::Printf(" ep->iInfo: iType=0x%x iDir=0x%x iSize=%d iInterval=%d", + ep->iInfo.iType, ep->iInfo.iDir, ep->iInfo.iSize, + ep->iInfo.iInterval)); + __KTRACE_OPT(KUSB, + Kern::Printf(" ep->iInfo: iInterval_Hs=%d iTransactions=%d iExtra=%d", + ep->iInfo.iInterval_Hs, ep->iInfo.iTransactions, + ep->iInfo.iExtra)); + // Store real endpoint numbers: + // array[x] holds the number for logical ep x. + aRealEpNumbers[i + 1] = j; + break; + } + } + } + aRealEpNumbers[0] = 0; // ep0: 0. + __KTRACE_OPT(KUSB,{ + Kern::Printf(" Endpoint Mapping for Interface %d / Setting %d:", ifc_num, aIfc->iSettingCode); + Kern::Printf("Logical | Real"); + Kern::Printf("Endpoint | Endpoint"); + for (TInt ep = 0; ep <= aEndpointsUsed; ++ep) Kern::Printf(" %2d %3d",ep, aRealEpNumbers[ep]); + }); + RESET_SETTINGRESERVE; + return KErrNone; + } + + +TInt DUsbClientController::SetupIfcDescriptor(TUsbcInterface* aIfc, TUsbcClassInfo& aClass, DThread* aThread, + TDesC8* aString, const TUsbcEndpointInfoArray& aEndpointData) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupIfcDescriptor()")); + + // Interface descriptor + TUsbcDescriptorBase* d = TUsbcInterfaceDescriptor::New(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode, + aIfc->iEndpoints.Count(), + aClass); + if (!d) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc desc failed.")); + return KErrNoMemory; + } + iDescriptors.InsertDescriptor(d); + + // Interface string descriptor + if (aString) + { + // we don't know the length of the string, so we have to allocate memory dynamically + TUint strlen = Kern::ThreadGetDesLength(aThread, aString); + if (strlen > KUsbStringDescStringMaxSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: $ descriptor too long - string will be truncated")); + strlen = KUsbStringDescStringMaxSize; + } + HBuf8* const stringbuf = HBuf8::New(strlen); + if (!stringbuf) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc string failed.")); + iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode); + return KErrNoMemory; + } + stringbuf->SetMax(); + // the aString points to data that lives in user memory, so we have to copy it: + TInt r = Kern::ThreadDesRead(aThread, aString, *stringbuf, 0); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); + iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode); + delete stringbuf; + return r; + } + TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*stringbuf); + if (!sd) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc failed.")); + iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode); + delete stringbuf; + return KErrNoMemory; + } + iDescriptors.SetIfcStringDescriptor(sd, aIfc->iInterfaceSet->iInterfaceNumber, aIfc->iSettingCode); + delete stringbuf; // the (EPOC) descriptor was copied by New() + } + + // Endpoint descriptors + for (TInt i = 0; i < aIfc->iEndpoints.Count(); ++i) + { + // The reason for using another function argument for Endpoint Info + // (and not possibly - similar to the Endpoint Address - + // "aIfc->iEndpoints[i]->iPEndpoint->iLEndpoint->iInfo") is that this time + // there are no logical endpoints associated with our real endpoints, + // i.e. iLEndpoint is NULL!. + if (aEndpointData[i].iExtra) + { + // if a non-standard endpoint descriptor is requested... + if (aEndpointData[i].iExtra != 2) + { + // ...then it must be a Audio Class endpoint descriptor. Else... + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EP desc extension > 2 bytes (%d)", + aEndpointData[i].iExtra)); + iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode); + return KErrArgument; + } + d = TUsbcAudioEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, + aEndpointData[i]); + } + else + { + d = TUsbcEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, + aEndpointData[i]); + } + if (!d) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ep desc #%d failed.", i)); + iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, + aIfc->iSettingCode); + return KErrNoMemory; + } + iDescriptors.InsertDescriptor(d); + } + + return KErrNone; + } + + +TInt DUsbClientController::ClientId2InterfaceNumber(const DBase* aClientId) const + { + const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); + for (TInt i = 0; i < num_ifcsets; ++i) + { + if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) + { + return iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber; + } + } + return -1; + } + + +TUsbcInterfaceSet* DUsbClientController::ClientId2InterfacePointer(const DBase* aClientId) const + { + const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); + for (TInt i = 0; i < num_ifcsets; ++i) + { + if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) + { + return iConfigs[0]->iInterfaceSets[i]; + } + } + return NULL; + } + + +const DBase* DUsbClientController::InterfaceNumber2ClientId(TInt aIfcSet) const + { + if (!InterfaceExists(aIfcSet)) + { + return NULL; + } + return InterfaceNumber2InterfacePointer(aIfcSet)->iClientId; + } + + +TUsbcInterfaceSet* DUsbClientController::InterfaceNumber2InterfacePointer(TInt aIfcSet) const + { + const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); + for (TInt i = 0; i < num_ifcsets; ++i) + { + if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == aIfcSet) + { + return iConfigs[0]->iInterfaceSets[i]; + } + } + return NULL; + } + + +TInt DUsbClientController::ActivateHardwareController() + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ActivateHardwareController()")); + + // iStackIsActive must be ETrue at this time + // the caller of this function shall checked that iStackIsActive is ETrue + __ASSERT_DEBUG(iStackIsActive, Kern::Fault(KUsbPILPanicCat, __LINE__)); + + if (iHardwareActivated) + { + __KTRACE_OPT(KUSB, Kern::Printf(" already active -> returning")); + return KErrNone; + } + // Initialise HW + TInt r = iController.StartPeripheralController(); + if (r != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: StartPeripheralController() failed")); + return KErrHardwareNotAvailable; + } + + iHardwareActivated = ETrue; + + // Configure & enable endpoint zero + const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; + const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; + if (iHighSpeed) + { + const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Hs; + const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Hs; + } + else + { + const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; + const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; + } + iController.ConfigureEndpoint(0, ep0_0->iInfo); + iController.ConfigureEndpoint(1, ep0_1->iInfo); + iEp0MaxPacketSize = ep0_0->iInfo.iSize; + + __KTRACE_OPT(KUSB, Kern::Printf(" Controller activated.")); + + // Controller is powered up, changes device state to powered + NextDeviceState(UsbShai::EUsbPeripheralStatePowered); + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ActivateHardwareController()")); + return KErrNone;; + } + + +void DUsbClientController::DeActivateHardwareController() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeActivateHardwareController()")); + if (!iHardwareActivated) + { + __KTRACE_OPT(KUSB, Kern::Printf(" not active -> returning")); + return; + } + // Deconfigure & disable endpoint zero + iController.DeConfigureEndpoint(KEp0_Out); + iController.DeConfigureEndpoint(KEp0_In); + // Stop HW + iController.StopPeripheralController(); + iHardwareActivated = EFalse; + __KTRACE_OPT(KUSB, Kern::Printf(" Controller deactivated.")); + + // Always go to attached state, until statck is disabled + NextDeviceState(UsbShai::EUsbPeripheralStateAttached); + + return; + } + + +void DUsbClientController::DeleteInterfaceSet(TInt aIfcSet) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterfaceSet(%d)", aIfcSet)); + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); + return; + } + const TInt idx = iConfigs[0]->iInterfaceSets.Find(ifcset_ptr); + if (idx == KErrNotFound) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface not found in array")); + return; + } + //Add this mutex to protect the interface set data structure + if (NKern::CurrentContext() == EThread) + { + NKern::FMWait(&iMutex); + } + + iConfigs[0]->iInterfaceSets.Remove(idx); + if (NKern::CurrentContext() == EThread) + { + NKern::FMSignal(&iMutex); + } + delete ifcset_ptr; + } + + +void DUsbClientController::DeleteInterface(TInt aIfcSet, TInt aIfc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterface(%d, %d)", aIfcSet, aIfc)); + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); + return; + } + if (ifcset_ptr->iInterfaces.Count() <= aIfc) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting: %d", aIfc)); + return; + } + //Add this mutex to protect the interface set data structure + if (NKern::CurrentContext() == EThread) + { + NKern::FMWait(&iMutex); + } + TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[aIfc]; + // Always first remove, then delete (see ~TUsbcLogicalEndpoint() for the reason why) + ifcset_ptr->iInterfaces.Remove(aIfc); + + if (aIfc == ifcset_ptr->iCurrentInterface) + { + __KTRACE_OPT(KUSB, Kern::Printf(" > Warning: deleting current interface setting")); + ifcset_ptr->iCurrentInterface = 0; + } + if (NKern::CurrentContext() == EThread) + { + NKern::FMSignal(&iMutex); + } + delete ifc_ptr; + } + + +void DUsbClientController::CancelTransferRequests(TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelTransferRequests(aRealEndpoint=%d)", + aRealEndpoint)); + const DBase* const clientId = PEndpoint2ClientId(aRealEndpoint); + if (EpIdx2Addr(aRealEndpoint) & KUsbEpAddress_In) + { + CancelWriteBuffer(clientId, aRealEndpoint); + } + else + { + CancelReadBuffer(clientId, aRealEndpoint); + } + } + + +void DUsbClientController::DeleteRequestCallback(const DBase* aClientId, TInt aEndpointNum, + UsbShai::TTransferDirection aTransferDir) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallback()")); + // Ep0 OUT + if (aEndpointNum == 0) + { + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == aClientId) + { + __ASSERT_DEBUG((p->iRealEpNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __ASSERT_DEBUG((p->iTransferDir == UsbShai::EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); + iEp0ReadRequestCallbacks.Remove(*p); + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return; + } + // Other endpoints + TUsbcRequestCallback* const p = iRequestCallbacks[aEndpointNum]; + if (p) + { + __ASSERT_DEBUG((p->Owner() == aClientId), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __ASSERT_DEBUG((p->iTransferDir == aTransferDir), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); + iRequestCallbacks[aEndpointNum] = NULL; + } + } + + +void DUsbClientController::DeleteRequestCallbacks(const DBase* aClientId) + { + // aClientId being NULL means: delete all requests for *all* clients. + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallbacks()")); + // Ep0 OUT + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (!aClientId || p->Owner() == aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); + iEp0ReadRequestCallbacks.Remove(*p); + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + // Other endpoints + for (TInt i = 1; i < KUsbcEpArraySize; i++) + { + TUsbcRequestCallback* const p = iRequestCallbacks[i]; + if (p && (!aClientId || p->Owner() == aClientId)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); + iRequestCallbacks[i] = NULL; + } + } + } + + +void DUsbClientController::StatusNotify(UsbShai::TUsbPeripheralState aState, const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::StatusNotify()")); + + // This function may be called by the PSL (via chapter9.cpp) from within an + // ISR -- so we have to take care what we do here (and also in all + // functions that get called from here). + + TSglQueIter iter(iStatusCallbacks); + TUsbcStatusCallback* p; + while ((p = iter++) != NULL) + { + if (!aClientId || aClientId == p->Owner()) + { + __KTRACE_OPT(KUSB, Kern::Printf(" notifying LDD @ 0x%x about %d", p->Owner(), aState)); + p->SetState(aState); + p->DoCallback(); + } + } + } + + +void DUsbClientController::EpStatusNotify(TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EpStatusNotify()")); + + // This function may be called by the PSL (via chapter9.cpp) from within an + // ISR -- so we have to take care what we do here (and also in all + // functions that get called from here). + + const DBase* const client_id = PEndpoint2ClientId(aRealEndpoint); + if (!client_id) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Client not found for real ep %d", aRealEndpoint)); + return; + } + // Check if there is a notification request queued for that client (if not, we can return here). + TSglQueIter iter(iEpStatusCallbacks); + TUsbcEndpointStatusCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == client_id) + { + break; + } + } + if (!p) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No notification request for that client, returning")); + return; + } + const TInt ifcset = ClientId2InterfaceNumber(client_id); + if (ifcset < 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset not found for clientid %d", client_id)); + return; + } + const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); + if (!ifcset_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset pointer not found for ifcset %d", ifcset)); + return; + } + const TUsbcInterface* const ifc_ptr = ifcset_ptr->CurrentInterface(); + if (!ifc_ptr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Current ifc pointer not found for ifcset %d", ifcset)); + return; + } + TUint state = 0; + const TInt eps = ifc_ptr->iEndpoints.Count(); + for (TInt i = 0; i < eps; i++) + { + const TUsbcLogicalEndpoint* const ep_ptr = ifc_ptr->iEndpoints[i]; + __KTRACE_OPT(KUSB, Kern::Printf(" checking logical ep #%d for stall state...", + ep_ptr->iLEndpointNum)); + if (ep_ptr->iPEndpoint->iHalt) + { + __KTRACE_OPT(KUSB, Kern::Printf(" -- stalled")); + // set the bit n to 1, where n is the logical endpoint number minus one + state |= (1 << (ep_ptr->iLEndpointNum - 1)); + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" -- not stalled")); + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" passing ep state 0x%x on to LDD @ 0x%x", state, client_id)); + p->SetState(state); + p->DoCallback(); + } + + +void DUsbClientController::OtgFeaturesNotify() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OtgFeaturesNotify()")); + + // This function may be called from the PSL (via PIL's chapter9.cpp) from + // within an ISR -- so we have to take care what we do here (and also in + // all functions that get called from here). + + TSglQueIter iter(iOtgCallbacks); + TUsbcOtgFeatureCallback* p; + while ((p = iter++) != NULL) + { + p->SetFeatures(iOtgFuncMap & 0x1C); + p->DoCallback(); + } + } + + +void DUsbClientController::RunClientCallbacks() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RunClientCallbacks()")); + TSglQueIter iter(iClientCallbacks); + TUsbcClientCallback* p; + while ((p = iter++) != NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf("Callback 0x%x", p)); + p->DoCallback(); + } + } + + +void DUsbClientController::ProcessDataTransferDone(TUsbcRequestCallback& aRcb) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessDataTransferDone()")); + // This piece can only be called in thread context from ProcessEp0DataReceived() / + // ProcessEp0SetupReceived() via the call to ProcessEp0ReceiveDone() in + // SetupReadBuffer(), which is guarded by an interrupt lock. + TInt ep = aRcb.iRealEpNum; + if (ep == 0) + { + if (aRcb.iTransferDir == UsbShai::EControllerRead) + { + // Ep0 OUT is special + iEp0ReadRequestCallbacks.Remove(aRcb); + } + else // UsbShai::EControllerWrite + { + // Ep0 IN needs to be adjusted: it's '1' within the PIL. + ep = KEp0_Tx; + } + } + if (ep > 0) // not 'else'! + { + __ASSERT_DEBUG((iRequestCallbacks[ep] == &aRcb), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" > removing RequestCallback[%d] @ 0x%x", ep, &aRcb)); + iRequestCallbacks[ep] = NULL; + } + aRcb.DoCallback(); + } + + +void DUsbClientController::NextDeviceState(UsbShai::TUsbPeripheralState aNextState) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::NextDeviceState()")); +#ifdef _DEBUG + const char* const states[] = {"Undefined", "Attached", "Powered", "Default", + "Address", "Configured", "Suspended"}; + if ((aNextState >= UsbShai::EUsbPeripheralStateUndefined) && + (aNextState <= UsbShai::EUsbPeripheralStateSuspended)) + { + __KTRACE_OPT(KUSB, Kern::Printf(" next device state: %s", states[aNextState])); + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown next device state: %d", aNextState)); + } + // Print a warning when an invalid state transition is detected + // 'Undefined' is not a state that is mentioned in the USB spec, but + // that's what we're in once the cable gets pulled (for instance). + switch (iDeviceState) + { + case UsbShai::EUsbPeripheralStateUndefined: + // valid: Undefined -> Attached + if (aNextState != UsbShai::EUsbPeripheralStateAttached) + break; + goto OK; + case UsbShai::EUsbPeripheralStateAttached: + // valid: Attached -> {Undefined, Powered} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStatePowered)) + break; + goto OK; + case UsbShai::EUsbPeripheralStatePowered: + // valid: Powered -> {Undefined, Attached, Default, Suspended} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStateAttached) && + (aNextState != UsbShai::EUsbPeripheralStateDefault) && + (aNextState != UsbShai::EUsbPeripheralStateSuspended)) + break; + goto OK; + case UsbShai::EUsbPeripheralStateDefault: + // valid: Default -> {Undefined, Powered, Default, Address, Suspended} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStatePowered) && + (aNextState != UsbShai::EUsbPeripheralStateDefault) && + (aNextState != UsbShai::EUsbPeripheralStateAddress) && + (aNextState != UsbShai::EUsbPeripheralStateSuspended)) + break; + goto OK; + case UsbShai::EUsbPeripheralStateAddress: + // valid: Address -> {Undefined, Powered, Default, Configured, Suspended} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStatePowered) && + (aNextState != UsbShai::EUsbPeripheralStateDefault) && + (aNextState != UsbShai::EUsbPeripheralStateConfigured) && + (aNextState != UsbShai::EUsbPeripheralStateSuspended)) + break; + goto OK; + case UsbShai::EUsbPeripheralStateConfigured: + // valid: Configured -> {Undefined, Powered, Default, Address, Suspended} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStatePowered) && + (aNextState != UsbShai::EUsbPeripheralStateDefault) && + (aNextState != UsbShai::EUsbPeripheralStateAddress) && + (aNextState != UsbShai::EUsbPeripheralStateSuspended)) + break; + goto OK; + case UsbShai::EUsbPeripheralStateSuspended: + // valid: Suspended -> {Undefined, Powered, Default, Address, Configured} + if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && + (aNextState != UsbShai::EUsbPeripheralStatePowered) && + (aNextState != UsbShai::EUsbPeripheralStateDefault) && + (aNextState != UsbShai::EUsbPeripheralStateAddress) && + (aNextState != UsbShai::EUsbPeripheralStateConfigured)) + break; + goto OK; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown current device state: %d", iDeviceState)); + goto OK; + } + // KUSB only (instead of KPANIC) so as not to worry people too much where + // a particular h/w regularly enforces invalid (but harmless) transitions + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: Invalid next state from %s", states[iDeviceState])); +OK: +#endif // _DEBUG + + iDeviceState = aNextState; + StatusNotify(iDeviceState); + } + + +TInt DUsbClientController::ProcessSuspendEvent() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSuspendEvent()")); + // A suspend interrupt has been received and needs attention. + iDeviceStateB4Suspend = iDeviceState; + + // We have to move to the Suspend state immediately (in case it's a genuine Suspend) + // because 7.1.7.6 says: "The device must actually be suspended, [...] after no more + // than 10ms of bus inactivity [...]." Assuming we got the interrupt 3ms after the + // Suspend condition arose, we have now 7ms left. + NextDeviceState(UsbShai::EUsbPeripheralStateSuspended); + iController.Suspend(); + + return KErrNone; + } + +TInt DUsbClientController::ProcessResumeEvent() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResumeEvent()")); + if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended) + { + NextDeviceState(iDeviceStateB4Suspend); + } + iController.Resume(); + return KErrNone; + } + + +TInt DUsbClientController::ProcessResetEvent(TBool aPslUpcall) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResetEvent()")); + + if (aPslUpcall) + { + // Call back into PSL if we're coming from there. + // Also, do it always, even when PIL processing will be deferred. + iController.Reset(); + } + + // In an OTG-environment, some OTG controllers have implemented + // the OTG state machine in HW and connect to the bus + // automatically already before the SW has indicated + // readiness. Peripheral PSL operating on top of such controller + // may report a reset event already before the upper layers are + // ready. In this case we defer the reset processing to after the + // upper layers have indicated their readiness. + if (iUsbResetDeferred) + { + __KTRACE_OPT(KUSB, Kern::Printf(" User-side (still) not ready -> returning")); + return KErrNone; + } + else if (!iClientSupportReady) + { + // Wait with the PIL Reset processing until user-side is ready + __KTRACE_OPT(KUSB, Kern::Printf(" User-side not ready -> deferring")); + iUsbResetDeferred = ETrue; + return KErrNone; + } + + if (iDeviceState == UsbShai::EUsbPeripheralStateAttached) + { + NextDeviceState(UsbShai::EUsbPeripheralStatePowered); + } + // Notify the world. (This will just queue a DFC, so users won't actually be + // notified before we return. But we change the device state already here so + // ChangeConfiguration will see the correct one.) + NextDeviceState(UsbShai::EUsbPeripheralStateDefault); + // Tear down the current configuration (never called from thread) + ChangeConfiguration(0); + // Reset essential vars + ResetEp0DataOutVars(); + //iEp0_RxExtraData = EFalse; + iEp0WritePending = EFalse; + iEp0ClientDataTransmitting = EFalse; + + iLastError = KErrNone; + iSetupPacketPending = EFalse; + //iEp0_RxExtraError = 0; + iConTransferMgr->Reset(); + + // Reset OTG features, leave attributes as is + iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; + if (iOtgSupport) + { + OtgFeaturesNotify(); + } + + // Check whether there's a speed change + const TBool was_hs = iHighSpeed; + iHighSpeed = CurrentlyUsingHighSpeed(); + if (!was_hs && iHighSpeed) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Moving to High-speed")); + EnterHighSpeed(); + } + else if (was_hs && !iHighSpeed) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Moving to Full-speed")); + EnterFullSpeed(); + } + + // Setup initial Ep0 read (SetupEndpointZeroRead never called from thread) + if (iConTransferMgr->SetupEndpointZeroRead() != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: while setting up Ep0 read")); + return KErrGeneral; + } + + return KErrNone; + } + + +TInt DUsbClientController::ProcessVbusRisenEvent() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessVbusRisenEvent()")); + if (iIsOtgPort) + { + // In an OTG environment, this notification is not expected + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventVbusRisen shouldn't be sent by an OTG Client PSL")); + return KErrArgument; + } + else + { + // In a non-OTG environment, seeing VBUS rising causes the + // peripheral stack to be enabled + EnablePeripheralStack(); + return KErrNone; + } + } + + +TInt DUsbClientController::ProcessVbusFallenEvent() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessVbusFallenEvent()")); + if (iIsOtgPort) + { + // In an OTG environment, this notification is not expected + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventVbusFallen shouldn't be sent by an OTG Client PSL")); + return KErrArgument; + } + else + { + // In a non-OTG environment, seeing VBUS falling causes the + // peripheral stack to be disabled + DisablePeripheralStack(); + return KErrNone; + } + } + + +void DUsbClientController::EnterFullSpeed() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterFullSpeed()")); + iDescriptors.UpdateDescriptorsFs(); + } + + +void DUsbClientController::EnterHighSpeed() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterHighSpeed()")); + iDescriptors.UpdateDescriptorsHs(); + } + + +// +// DFC (static), we are runing in a DFC context. +// +void DUsbClientController::ReconnectTimerCallback(TAny *aPtr) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReconnectTimerCallback()")); + if (!aPtr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); + return; + } + + DUsbClientController* const ptr = static_cast(aPtr); + + ptr->UsbConnect(); + + } + +// +// static Dfc function +// +void DUsbClientController::PowerUpDfc(TAny* aPtr) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerUpDfc")); + if (!aPtr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); + return; + } + + DUsbClientController* const ptr = static_cast(aPtr); + + __PM_ASSERT(ptr->iStandby); + + ptr->iStandby = EFalse; + + // We have nothing to do when powerup + ptr->iPowerHandler->PowerUpDone(); + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerUpDfc")); + return ; + } + +// +// static Dfc function +// +void DUsbClientController::PowerDownDfc(TAny* aPtr) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerDownDfc")); + if (!aPtr) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); + return; + } + + DUsbClientController* const ptr = static_cast(aPtr); + __PM_ASSERT(!ptr->iStandby); + + ptr->iStandby = ETrue; + + // Disable stack(stop controller inside) + ptr->DisablePeripheralStack(); + + ptr->iPowerHandler->PowerDownDone(); + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerDownDfc")); + return ; + } + +// +// Static Dfc function +// +void DUsbClientController::DeviceEventNotifyDfc(TAny* aPtr) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::DeviceEventNotifyDfc")); + DUsbClientController* const ptr = static_cast(aPtr); + + UsbShai::TUsbPeripheralEvent event = ptr->iDevEventQueue.FifoGet(); + + if( event == -1) + { + // No event queued + __KTRACE_OPT(KUSB, Kern::Printf(" Warning, No event found, exit !!!")); + return; + } + + ptr->ProcessDeviceEventNotification(event); + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::DeviceEventNotifyDfc")); + } + +// +// Static Dfc function +// +void DUsbClientController::ThreadContextFinderDfc(TAny* aPtr) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ThreadContextFinderDfc")); + + DUsbClientController* const ptr = static_cast(aPtr); + + ptr->iCommonDfcQThread = NKern::CurrentThread(); + __KTRACE_OPT(KUSB, Kern::Printf(" iCommonDfcQThread = %d",ptr->iCommonDfcQThread)); + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ThreadContextFinderDfc")); + } +// +// +// +void DUsbClientController::ProcessDeviceEventNotification(UsbShai::TUsbPeripheralEvent aEvent) + { + __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ProcessDeviceEventNotification %d",aEvent)); + // If an OTG Observer has registered, forward the event + // notification to it as well + if (iOtgObserver != NULL) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Forwarding to OTG Observer")); + iOtgObserver->NotifyPeripheralEvent(aEvent); + } + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + switch (aEvent) + { + case UsbShai::EUsbEventSuspend: + ProcessSuspendEvent(); + break; + case UsbShai::EUsbEventResume: + ProcessResumeEvent(); + break; + case UsbShai::EUsbEventReset: + ProcessResetEvent(); + break; + case UsbShai::EUsbEventVbusRisen: + ProcessVbusRisenEvent(); + break; + case UsbShai::EUsbEventVbusFallen: + ProcessVbusFallenEvent(); + break; + + default: + break; + } + + __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ProcessDeviceEventNotification")); + } + +// Functions from UsbShai::MChargerDetectorObserverIf +void DUsbClientController::NotifyPortType(UsbShai::TPortType aPortType) + { + // FIXME: Not yet implemented! + } + +void DUsbClientController::Buffer2Setup(const TAny* aBuf, TUsbcSetup& aSetup) const + { + // TUint8 index + aSetup.iRequestType = static_cast(aBuf)[0]; + aSetup.iRequest = static_cast(aBuf)[1]; + // TUint16 index from here! + aSetup.iValue = SWAP_BYTES_16((static_cast(aBuf))[1]); + aSetup.iIndex = SWAP_BYTES_16((static_cast(aBuf))[2]); + aSetup.iLength = SWAP_BYTES_16((static_cast(aBuf))[3]); + } + +TUsbPeriDeviceEventQueue::TUsbPeriDeviceEventQueue() + { + iDeviceQueueHead = 0; + iDeviceQueueTail = 0; + } + +// FifoAdd will be called from Isr or IDfc context +// be careful when processing +void TUsbPeriDeviceEventQueue::FifoAdd(UsbShai::TUsbPeripheralEvent aDeviceEvent) + { + __KTRACE_OPT(KUSB, Kern::Printf("> TUsbPeriDeviceEventQueue::FifoAdd %d , %d",iDeviceQueueHead,iDeviceQueueTail)); + iDeviceEventQueue[iDeviceQueueTail] = aDeviceEvent; + + iDeviceQueueTail ++; + iDeviceQueueTail %= KUsbDeviceEventQueueDepth; + if(iDeviceQueueTail == iDeviceQueueHead) + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbPeriDeviceEventQueue::FifoAdd overflow, oldest event missed")); + iDeviceQueueHead ++; + iDeviceQueueHead %= KUsbDeviceEventQueueDepth; + } + __KTRACE_OPT(KUSB, Kern::Printf("< TUsbPeriDeviceEventQueue::FifoAdd %d , %d",iDeviceQueueHead,iDeviceQueueTail)); + } + +// FifoAdd will be called from thread context +UsbShai::TUsbPeripheralEvent TUsbPeriDeviceEventQueue::FifoGet() + { + __KTRACE_OPT(KUSB, Kern::Printf("> TUsbPeriDeviceEventQueue::FifoGet %d , %d",iDeviceQueueHead,iDeviceQueueTail)); + UsbShai::TUsbPeripheralEvent ret = (UsbShai::TUsbPeripheralEvent)-1; + + if(iDeviceQueueHead != iDeviceQueueTail) + { + ret = iDeviceEventQueue[iDeviceQueueHead]; + iDeviceQueueHead++; + iDeviceQueueHead %= KUsbDeviceEventQueueDepth; + } + __KTRACE_OPT(KUSB, Kern::Printf("< TUsbPeriDeviceEventQueue::FifoGet %d , %d",iDeviceQueueHead,iDeviceQueueTail)); + return ret; + } + +/** Sets some data members of this request for a read request. + + @param aBufferStart The start of the data buffer to be filled. + @param aBufferAddr The physical address of the buffer (used for DMA). + @param aPacketIndex A pointer to the packet index values array. + @param aPacketSize A pointer to the packet size values array. + @param aLength The number of bytes to be received. +*/ +EXPORT_C void TUsbcRequestCallback::SetRxBufferInfo(TUint8* aBufferStart, TUintPtr aBufferAddr, + TUint32* aPacketIndex, + TUint32* aPacketSize, + TInt aLength) + { + iTransferDir = UsbShai::EControllerRead; + iBufferStart = aBufferStart; + iBufferAddr = aBufferAddr; + iPacketIndex = aPacketIndex; + iPacketSize = aPacketSize; + iLength = aLength; + } + + +/** Sets some data members of this request for a write request. + + @param aBufferStart The start of the buffer that contains the data to be sent. + @param aBufferAddr The physical address of the buffer (used for DMA). + @param aLength The number of bytes to be transmitted. +*/ +EXPORT_C void TUsbcRequestCallback::SetTxBufferInfo(TUint8* aBufferStart, TUintPtr aBufferAddr, TInt aLength) + { + iTransferDir = UsbShai::EControllerWrite; + iBufferStart = aBufferStart; + iBufferAddr = aBufferAddr; + iLength = aLength; + } + +EXPORT_C UsbShai::TUsbPeripheralRequest::TUsbPeripheralRequest(TInt aRealEpNum): + iRealEpNum(aRealEpNum), + iBufferStart(NULL), + iBufferAddr(0), + iLength(0), + iTxBytes(0), + iRxPackets(0), + iPacketIndex(NULL), // actually TUint16 (*)[] + iPacketSize(NULL), // actually TUint16 (*)[] + iTransferDir(EControllerNone), + iZlpReqd(EFalse), + iError(KErrNone) + { + } + +// Peripheral PSL use this interface to register itself to PIL layer, in our case, +// DUsbClientController instance +// +// param aPeripheralControllerIf point to an implementation of +// UsbShai::MPeripheralControllerIf which represent a peripheral controller hardware. +EXPORT_C void UsbShai::UsbPeripheralPil::RegisterPeripheralController( UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, + const UsbShai::TPeripheralControllerProperties& aProperties) + { + __KTRACE_OPT(KUSB, Kern::Printf("> UsbPeripheralPil::RegisterPeripheralController enter.")); + + DUsbClientController* usbcc = DUsbClientController::Create(aPeripheralControllerIf, + aProperties, + /*aIsOtgPort=*/EFalse); + __ASSERT_DEBUG( (usbcc != NULL), + Kern::Fault( "DUsbClientController extension entry point: USB PSL Out of memory", __LINE__ ) ); + } + +// The way for charger detector(PSL) to make it known to us. +EXPORT_C void UsbShai::UsbChargerDetectionPil::RegisterChargerDetector(UsbShai::MChargerDetectorIf& aChargerDetector, + UsbShai::TChargerDetectorProperties& aProperties) + { + // Only on charger detector is allowed per system. + if( gChargerDetector != NULL) + { + return ; + } + + gChargerDetector = &aChargerDetector; + + if(gChargerObsever != NULL) + { + // Register to charger detector to listen to any charger type change + // events. + gChargerDetector->SetChargerDetectorObserver(*gChargerObsever); + } + } + +// -EOF- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/pdd/pil/src/queue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/pdd/pil/src/queue.cpp Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,124 @@ +// Copyright (c) 2002-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\usbcc\queue.cpp +// Platform independent layer (PIL) of the USB Device controller driver: +// Simple singly linked list + its iterator. +// +// + +/** + @file queue.cpp + @internalTechnology +*/ +//#include +#include + + +void TSglQueLink::Enque(TSglQueLink* aLink) +// +// Enque this after aLink. +// + { + iNext = aLink->iNext; + aLink->iNext = this; + } + + +TSglQueBase::TSglQueBase(TInt aOffset) +// +// Constructor +// + : iHead(NULL), iLast((TSglQueLink*) &iHead), iOffset(aOffset), iElements(0) + { + // ESQueOffsetNotAligned + __ASSERT_ALWAYS((iOffset % 4 == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + } + + +void TSglQueBase::DoAddLast(TAny* aPtr) +// +// Add the object at the end of the queue. +// + { + TSglQueLink* pL = PtrAdd((TSglQueLink*) aPtr, iOffset); + pL->Enque(iLast); + iLast = pL; + iElements++; + __ASSERT_DEBUG((iElements > 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + } + + +void TSglQueBase::DoRemove(TAny* aPtr) +// +// Remove the object from the queue. +// + { + TSglQueLink* pP = (TSglQueLink*) (&iHead); + TSglQueLink* pL = PtrAdd((TSglQueLink*) aPtr, iOffset); + TSglQueLink* pN = pP->iNext; + while (pN) + { + if (pN == pL) + { + pP->iNext = pN->iNext; + if (iLast == pL) + { + iLast = pP; + if (iLast == NULL) + iLast = (TSglQueLink*) (&iHead); + } + iElements--; + __ASSERT_DEBUG((iElements >= 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + return; + } + pP = pN; + pN = pP->iNext; + } + // This doesn't have to indicate an error (but might): + __KTRACE_OPT(KPANIC, Kern::Printf("TSglQueBase::DoRemove: ESQueLinkNotQueued")); + } + + +TSglQueIterBase::TSglQueIterBase(TSglQueBase& aQue) +// +// Constructor. +// + : iOffset(aQue.iOffset), iHead(aQue.iHead), iNext(aQue.iHead) + { + } + + +void TSglQueIterBase::SetToFirst() +// +// Start from the beginning of the que. +// + { + iNext = iHead->iNext; + } + + +TAny* TSglQueIterBase::DoPostInc() +// +// Return the current pointer and increment. +// + { + TAny* pN = iNext; + if (pN == NULL) + return NULL; + iNext = iNext->iNext; + return PtrSub(pN, iOffset); + } + + +//--- diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbc.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,1163 @@ +// 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/include/d32usbc.h +// User side class definitions for USB Device support. +// +// + +/** + @file d32usbc.h + @publishedPartner + @released +*/ + +#ifndef __D32USBC_H__ +#define __D32USBC_H__ + +#include +#include +#include + + + +/** @internalComponent +*/ +enum TTransferType + { + ETransferTypeReadData, + ETransferTypeReadPacket, + ETransferTypeWrite, + ETransferTypeNone, + ETransferTypeReadOneOrMore, + ETransferTypeReadUntilShort + }; + + +/** Available endpoints. At most only these are available per interface. +*/ +enum TEndpointNumber + { + EEndpoint0 = 0, + EEndpoint1 = 1, + EEndpoint2 = 2, + EEndpoint3 = 3, + EEndpoint4 = 4, + EEndpoint5 = 5 + }; + + + + +/** Bandwidth indicators for an Interface + + @see RDevUsbcClient::SetInterface() +*/ +enum TUsbcBandwidthPriority + { + /** Economical OUT buffering. */ + EUsbcBandwidthOUTDefault = 0x00, + /** More memory than Default for OUT buffering. */ + EUsbcBandwidthOUTPlus1 = 0x01, + /** More memory than Plus1 for OUT buffering. */ + EUsbcBandwidthOUTPlus2 = 0x02, + /** Maximum memory for OUT buffering. + Use this value for high volume USB High-speed + data transfers only, otherwise memory will be wasted. + */ + EUsbcBandwidthOUTMaximum = 0x03, + // + /** Economical IN buffering */ + EUsbcBandwidthINDefault = 0x00, + /** More memory than Default for IN buffering */ + EUsbcBandwidthINPlus1 = 0x10, + /** More memory than Plus1 for IN buffering */ + EUsbcBandwidthINPlus2 = 0x20, + /** Maximum memory for IN buffering. + Use this value for high volume USB High-speed + data transfers only, otherwise memory will be wasted. + */ + EUsbcBandwidthINMaximum = 0x30 + }; + + + + + + + +/** Bit positions of endpoints. + + @see RDevUsbcClient::EndpointStatusNotify() + @see RDevUsbcClient::EndpointTransferCancel() + + Bit position of endpoint0. +*/ +const TUint KUsbcEndpoint0Bit = 1< TUsbcInterfaceInfoBuf; + + +/** The user side handle to the USB client driver. +*/ +class RDevUsbcClient : public RBusLogicalChannel + { +public: + /** @internalComponent */ + enum TVer + { + EMajorVersionNumber = 0, + EMinorVersionNumber = 1, + EBuildVersionNumber = KE32BuildVersionNumber + }; + + enum TRequest + { + // Positive requests. + ERequestEp0 = 0x0, + ERequestEp1 = EEndpoint1, + ERequestEp2 = EEndpoint2, + ERequestEp3 = EEndpoint3, + ERequestEp4 = EEndpoint4, + ERequestEp5 = EEndpoint5, + ERequestUnused = 6, + ERequestAlternateDeviceStatusNotify = 7, + ERequestReEnumerate = 8, + ERequestEndpointStatusNotify = 9, + // The cancel TRequest's are interpreted as bitmaps. As they're not mixed + // with the previous ones, it doesn't matter if they have the same absolute + // value as those. + ERequestEp0Cancel = 1<(data), sizeof(data), sizeof(data)); + ret = usbPort.EndpointCaps(dataPtr); + @endcode + + @param aEpCapsBuf a descriptor encapsulating an array of TUsbcEndpointData. + + @return KErrNone if successful. + */ + inline TInt EndpointCaps(TDes8& aEpCapsBuf); + + /** Retrieves the capabilities of the USB device. + + @see TUsbDeviceCaps + + @param aDevCapsBuf a TUsbDeviceCaps object. + + @return KErrNone if successful. + */ + inline TInt DeviceCaps(TUsbDeviceCaps& aDevCapsBuf); + + /** Copies the current alternate setting for this interface into aInterfaceNumber + For USB Interfaces whose main interface is active, this will be 0 (zero). + + @param aInterfaceNumber current alternate setting for this interface is copied into this. + + @return KErrNone if successful. + */ + inline TInt GetAlternateSetting(TInt& aInterfaceNumber); + + /** Copies the current device status into aDeviceStatus. + + @param aDeviceStatus current device status is copied into this. + + @return KErrNone if successful + */ + inline TInt DeviceStatus(TUsbcDeviceState& aDeviceStatus); + + /** Copies the current endpoint status into aEndpointStatus. + + @param aEndpoint endpoint number valid for the current alternate setting. + @param aEndpointStatus the current endpoint status, might be stalled, not stalled or unknown. + + @return KErrNone if successful. + */ + inline TInt EndpointStatus(TEndpointNumber aEndpoint, TEndpointState& aEndpointStatus); + + /** Copies the number of bytes available in the aEndpoint read buffer into aNumberOfBytes. + + @param aEndpoint endpoint number valid for the current alternate setting. + @param aNumberOfBytes number of bytes available in the aEndpoint read buffer. + + @return KErrNone if successful. + */ + inline TInt QueryReceiveBuffer(TEndpointNumber aEndpoint, TInt& aNumberOfBytes); + + /** Requests that a zero length status packet be sent to the host in response + to a class or vendor specific ep0 SETUP packet. + + @return KErrNone if successful. + */ + inline TInt SendEp0StatusPacket(); + + /** Stalls endpoint aEndpoint, usually to indicate an error condition with a previous command. + The host will normally send a SET_FEATURE command on ep0 to acknowledge and clear the stall. + + @return KErrNone if successful. + */ + inline TInt HaltEndpoint(TEndpointNumber aEndpoint); + + /** Clears the stall condition on endpoint aEndpoint. This is inluded for symmetry and test purposes. + + @return KErrNone if successful. + */ + inline TInt ClearHaltEndpoint(TEndpointNumber aEndpoint); + + /** Requests that device control be allocated to this channel. + + @return KErrNone if successful. + */ + inline TInt SetDeviceControl(); + + /** Relinquishes device control previously allocated to this channel. + + @return KErrNone if successful. + */ + inline TInt ReleaseDeviceControl(); + + /** Returns a bitmap of available ep0 maximum packet sizes. + + @return bitmap of available ep0 maximum packet sizes. + */ + inline TUint EndpointZeroMaxPacketSizes(); + + /** Requests that a maximum packet size of aMaxPacketSize be set on ep0. + + @param aMaxPacketSize The maximum packet size. + + @return KErrNone if successful. + */ + inline TInt SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize); + + /** Queries the current maximum packet size on ep0. + + @return The currently set maximum packet size on ep0. + */ + inline TInt GetEndpointZeroMaxPacketSize(); + + /** Copies the current device descriptor into aDeviceDescriptor. + + @param aDeviceDescriptor Receives the current device descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceDescriptor(TDes8& aDeviceDescriptor); + + /** Sets the contents of aDeviceDescriptor to be the current device descriptor. + + @param aDeviceDescriptor contains the device descriptor. + + @return KErrNone if successful. + */ + inline TInt SetDeviceDescriptor(const TDesC8& aDeviceDescriptor); + + /** Gets the size of the current device descriptor. This is unlikely to be anything other than 9. + + @param aSize receives the size of the current device descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceDescriptorSize(TInt& aSize); + + /** Copies the current configuration descriptor into aConfigurationDescriptor. + + @param aConfigurationDescriptor Receives the current configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetConfigurationDescriptor(TDes8& aConfigurationDescriptor); + + /** Sets the contents of aConfigurationDescriptor to be the current configuration descriptor. + + @param aConfigurationDescriptor contains the configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt SetConfigurationDescriptor(const TDesC8& aConfigurationDescriptor); + + /** Gets the size of the current configuration descriptor. + + @param aSize receives the size of the current configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetConfigurationDescriptorSize(TInt& aSize); + + /** Copies the interface descriptor into aInterfaceDescriptor for the interface with alternate + setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Receives the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetInterfaceDescriptor(TInt aSettingNumber, TDes8& aInterfaceDescriptor); + + /** Sets the interface descriptor contained in aInterfaceDescriptor for the interface with + alternate setting aSettingNumber, 0 for the main interface, for transmission to the host + during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetInterfaceDescriptor(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor); + + /** Copies the size of the interface descriptor for the interface with alternate + setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber The alternate setting. + @param aSize receives the size of the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize); + + /** Copies the endpoint descriptor for logical endpoint number aEndpointNumber into aEndpointDescriptor + for the interface with alternate setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber. + @param aEndpointDescriptor Receives the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, TDes8& aEndpointDescriptor); + + /** Sets the endpoint descriptor for logical endpoint number aEndpointNumber contained in + aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main interface, + for transmission to the host during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Contains the endpoint descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor); + + /** Copies the size of the endpoint descriptor for logical endpoint number aEndpointNumber for the + interface with alternate setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aSize receives the size of the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize); + + /** Get OTG descriptor size + + @param aSize TInt reference which contains OTG descriptor size on return + */ + inline void GetOtgDescriptorSize(TInt& aSize); + + /** Get OTG descriptor of USB on-the-go feature + + @param aOtgDesc User-side buffer to store copy of descriptor + + @return KErrNone if successful + */ + inline TInt GetOtgDescriptor(TDes8& aOtgDesc); + + /** Set OTG descriptor by user to enable/disable USB on-the-go feature + + @param aOtgDesc Descriptor buffer containing OTG features + + @return KErrNone if successful + */ + inline TInt SetOtgDescriptor(const TDesC8& aOtgDesc); + + /** Copies the current device_qualifier descriptor into aDescriptor. + + @param aDescriptor Receives the current device_qualifier descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceQualifierDescriptor(TDes8& aDescriptor); + + /** Sets the device_qualifier descriptor to the contents of aDescriptor. + + @param aDescriptor contains the new device_qualifier descriptor. + + @return KErrNone if successful. + */ + inline TInt SetDeviceQualifierDescriptor(const TDesC8& aDescriptor); + + /** Copies the current other_speed_configuration descriptor into aDescriptor. + + @param aDescriptor Receives the current other_speed_configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor); + + /** Sets the other_speed_configuration descriptor to the contents of aDescriptor. + + @param aDescriptor contains the new other_speed_configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor); + + /** Copies the class specific interface descriptor block into aInterfaceDescriptor for the interface + with alternate setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor); + + /** aSettingNumber is the alternate interface setting, 0 for the main interface, that the descriptor block + aDes should be attached to. aDes is a block of data containing at least one class specific descriptor + for transmission during enumeration after the class interface descriptor (or alternate interface + descriptor) has been sent, but before the endpoint descriptors belonging to this interface are sent. + aDes may contain as many descriptors as are necessary or only 1. SetCSInterfaceDescriptorBlock() + should be called at any time after SetInterface() has been called to establish a main interface or an + alternate interface. More than one call may be made - the data blocks will be concatenated prior to + sending. No checking or validation of the contents of aDes will be made and it is the caller's + responsibility to ensure that the data supplied is correct and appropriate to the interface identified + by aSettingNumber. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetCSInterfaceDescriptorBlock(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor); + + /** Copies the size of the class specific interface descriptor block for the interface with alternate + setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber The alternate setting number. + @param aSize receives the size of the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize); + + /** Copies the class specific endpoint descriptor for logical endpoint number aEndpointNumber + into aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main + interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Receives the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor); + + /** Sets the class specific endpoint descriptor for logical endpoint number aEndpointNumber contained in + aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main interface, + for transmission to the host during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Contains the endpoint descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor); + + /** Copies the size of the class specific endpoint descriptor block for logical endpoint number + aEndpointNumber for the interface with alternate setting aSettingNumber, 0 for the main interface, + into aSize. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aSize On return, contains the size of the class specific endpoint descriptor block. + + @return KErrNone if successful. + */ + inline TInt GetCSEndpointDescriptorBlockSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize); + + /** Generates a Remote Wakeup bus condition + The capability of the device to generate Remote Wakeup signalling is enquired in + RDevUsbcClient::DeviceCaps. + + @return KErrNone if this signalling is possible and the signal has been generated. + */ + inline TInt SignalRemoteWakeup(); + + /** Simulates a physical removal of the USB cable by disabling the D+/- pull-ups.The iConnect member of + TUsbDeviceCapsV01, returned by RDevUsbcClient::DeviceCaps(), indicates whether this functionality is + supported. + + @return KErrNone if successful. + */ + inline TInt DeviceDisconnectFromHost(); + + /** Simulates a physical insertion of the USB cable by enabling the D+/- pull-ups.The iConnect member + of TUsbDeviceCapsV01, returned by RDevUsbcClient::DeviceCaps(), indicates whether this functionality + is supported. + + @return KErrNone if successful. + */ + inline TInt DeviceConnectToHost(); + + /** Powers up the UDC and connects it to the bus if one or more interfaces exist. + + @return KErrNone if UDC successfully powered up, KErrNotReady if no + interfaces have been registered yet, KErrHardwareNotAvailable if UDC + couldn't be activated. + */ + inline TInt PowerUpUdc(); + + /** Enquires about the current operating speed of the UDC. + + @return ETrue if the UDC is currently operating at High speed, EFalse otherwise. + */ + inline TBool CurrentlyUsingHighSpeed(); + + /** Allocates the use of aResource to aEndpoint. it will be used from when the current bus transfer has been + completed. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number to which the resource is to be allocated. + + @return KErrNone if successful, KErrInUse if the resource is already consumed and cannot be allocated, + KErrNotSupported if the endpoint does not support the resource requested. + + @publishedPartner @deprecated + + @see TUsbcEndpointInfo + */ + inline TInt AllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Deallocates the use of aResource aEndpoint or ends a specified endpoint behaviour. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number from which the resource is to be removed. + + @return KErrNone if the resource has been successfully deallocated, KErrNotSupported if the endpoint + does not support the resource requested. + + @publishedPartner @deprecated + + @see TUsbcEndpointInfo + */ + inline TInt DeAllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Queries endpoint resource use. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number at which the resource is to be queried. + + @return ETrue is the specified resource is in use at the endpoint and EFalse if not. + */ + inline TBool QueryEndpointResourceUse(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Request (i.e. claim for this channel) up to five endpoints and set the class type for this USB + interface. 'aInterfaceData' is a package buffer which describes the interface and all the endpoints + being requested by the driver for this interface. + + @param aInterfaceNumber Distinguishes between alternate interfaces. If these are not be used then this + should always be zero. If this parameter is used, then its value must be one more than that of the + proceeding alternate interface. + @param aInterfaceData a package buffer which describes the interface and all the endpoints being + requested by the driver for this interface. + @param aBandwidthPriority is a bitmap combining the required IN and OUT priorities. Values are in the + range [0,3] from the lowest priority bandwidth, 0, to the highest 3 and are separately specified for + IN and OUT endpoints. Interfaces requiring higher bandwidth are allocated significantly more buffering + than low bandwidth interfaces. Interfaces should not be given a higher bandwidth priority than they + require. + + @return KErrInUse if any of the endpoints being requested have already been claimed by another channel + KErrNotSupported if an endpoint with all of the specified properties is not supported on this + platform. KErrNoMemory if insufficient memory is available to complete the operation. + */ + inline TInt SetInterface(TInt aInterfaceNumber, TUsbcInterfaceInfoBuf& aInterfaceData, + TUint32 aBandwidthPriority = + (EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault)); + + /** Release an interface previously claimed by this channel. Alternate interfaces need to be released + in strict descending order, starting with the last (i.e. highest numbered) one. + It is not necessary to release an interface that wasn't successfully requested. + + @param aInterfaceNumber Specifies the alternate setting number 'aInterfaceNum' of the interface to be + released. + + @return KErrNone if successful. KErrArgument if the alternate setting doesn't exist or is released out + of order. + */ + inline TInt ReleaseInterface(TInt aInterfaceNumber); + + /** Copies the current string descriptor language ID (LANGID) code into the aLangId argument. Even though + the USB spec allows for the existence of a whole array of LANGID codes, we only support one. + + @param aLangId receives the LANGID code. + + @return KErrNone if successful, KErrArgument if problem with argument (memory cannot be written to, etc.). + */ + inline TInt GetStringDescriptorLangId(TUint16& aLangId); + + /** Sets the string descriptor language ID (LANGID). Even though the USB spec allows for the existence of + a whole array of LANGID codes, we only support one. + + @param aLangId the LANGID code to be set. + + @return KErrNone if successful. + */ + inline TInt SetStringDescriptorLangId(TUint16 aLangId); + + /** Copies the string descriptor identified by the iManufacturer index field of the Standard Device + Descriptor into the aString argument. + + @param aString receives manufacturer string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetManufacturerStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iManufacturer index field of the Standard Device + Descriptor to the aString argument. + + @param aString Contains the new manufacturer string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetManufacturerStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iManufacturer index field of the Standard + Device Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveManufacturerStringDescriptor(); + + /** Retrieves the string descriptor identified by the iProduct index field of the Standard Device + Descriptor into the aString argument. + + @param aString receives product string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetProductStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iProduct index field of the Standard Device Descriptor to + the aString argument. + + @param aString Contains the new product string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetProductStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iProduct index field of the Standard Device + Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveProductStringDescriptor(); + + /** Retrieves the string descriptor identified by the iSerialNumber index field of the Standard Device + Descriptor into the aString argument. + + @param aString receives product string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetSerialNumberStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iSerialNumber index field of the Standard Device + Descriptor to the aString argument. + + @param aString Contains the new serial number string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetSerialNumberStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iSerialNumber index field of the Standard + Device Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveSerialNumberStringDescriptor(); + + /** Retrieves the string descriptor identified by the iConfiguration index field of the (first) Standard + Configuration Descriptor into the aString argument. + + @param aString receives configuration string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetConfigurationStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iConfiguration index field of the Standard Configuration + Descriptor to the aString argument. + + @param aString Contains the new serial number string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetConfigurationStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iConfiguration index field of the Standard + Configuration Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveConfigurationStringDescriptor(); + + /** Copies the string of the USB string descriptor at the specified index in the string descriptor array + into the aString argument. + + Although this function can also be used for it, for querying most standard string descriptors + there exists a set of dedicated access functions. + + @see RDevUsbcClient::GetStringDescriptorLangId + @see RDevUsbcClient::GetManufacturerStringDescriptor + @see RDevUsbcClient::GetProductStringDescriptor + @see RDevUsbcClient::GetSerialNumberStringDescriptor + @see RDevUsbcClient::GetConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aString The target location for the string descriptor copy. + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index, + KErrArgument if MaxLength() of aString is too small to hold the entire descriptor. + */ + inline TInt GetStringDescriptor(TUint8 aIndex, TDes16& aString); + + /** Sets the aString argument to be the string of a USB string descriptor at the specified index in the + string descriptor array. If a string descriptor already exists at that position then its string will + be replaced. + + Care should be taken, when choosing aIndex, not to inadvertently overwrite one of the standard + string descriptors. For their manipulation there exists a set of dedicated access functions. + + @see RDevUsbcClient::SetStringDescriptorLangId + @see RDevUsbcClient::SetManufacturerStringDescriptor + @see RDevUsbcClient::SetProductStringDescriptor + @see RDevUsbcClient::SetSerialNumberStringDescriptor + @see RDevUsbcClient::SetConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aString Contains the string descriptor to be set. + + @return KErrNone if successful, KErrArgument if aIndex is invalid, KErrNoMemory if no memory + is available to store the new string (an existing descriptor at that index will be preserved). + */ + inline TInt SetStringDescriptor(TUint8 aIndex, const TDesC16& aString); + + /** Removes (deletes) the USB string descriptor at the specified index in the string descriptor array. + The position in the array of other string descriptors is not affected. + + Care should be taken, when choosing aIndex, not to inadvertently delete a standard string descriptor + (also because index references from non-string descriptors would be invalidated). For the deletion + of most standard string descriptors there exists a set of dedicated functions. + + @see RDevUsbcClient::RemoveManufacturerStringDescriptor + @see RDevUsbcClient::RemoveProductStringDescriptor + @see RDevUsbcClient::RemoveSerialNumberStringDescriptor + @see RDevUsbcClient::RemoveConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index. + */ + inline TInt RemoveStringDescriptor(TUint8 aIndex); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. + Request completes when the specified number of bytes is received, length taken from max. length of + descriptor. + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + */ + inline void Read(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. + Request completes when the specified number of bytes is received. + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + @param aLen The number of bytes to read. + */ + inline void Read(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes, TInt aLen); + + /** Asynchronously read an entire packet of data from endpoint 'aEndpoint' into the descriptor 'aDes'. + If a packet has previously been partly read. then only the remainder of the packet will be returned. + The request should be for the maximum packet size of the endpoint. If less data is requested, then + after this read completes the remainder of the data in the packet will be discarded and the next read + will start from the next available packet. + Request completes when either a complete packet is received or the length of the packet currently + being received exceeds 'aMaxLen'. + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + @param aMaxLen . + */ + inline void ReadPacket(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes, TInt aMaxLen); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. + Request completes when the specified number of bytes is received (in first version, + length taken from max. length of descriptor). + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + */ + inline void ReadUntilShort(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. + Request completes when the specified number of bytes is received (in first version, + length taken from max. length of descriptor). + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + @param aLen The number of bytes to receive. + */ + inline void ReadUntilShort(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes, TInt aLen); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. The request completes + when the specified number of bytes is received, length taken from max. length of descriptor or a + packet whose size is smaller than the endpoint's maximum packet size is received. + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + */ + inline void ReadOneOrMore(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes); + + /** Asynchronously read data from endpoint 'aEndpoint' into the descriptor 'aDes'. The request completes + when the specified number of bytes is received, or a packet whose size is smaller than the endpoint's + maximum packet size is received. + + @param aStatus The request status. + @param aEndpoint The endpoint number to read from. + @param aDes Descriptor to receive the data. + @param aLen The number of bytes to receive. + */ + inline void ReadOneOrMore(TRequestStatus& aStatus, TEndpointNumber aEndpoint, TDes8& aDes, TInt aLen); + + /** Cancels an outstanding read request. The request will complete with whatever data is available. + */ + inline void ReadCancel(TEndpointNumber aEndpoint); + + /** Asynchronously write 'aLen' bytes of data to endpoint 'aEndpoint' from descriptor 'aDes'. 'aZlpRequired' + (optional) signals that ZLP termination may be required. + + @param aStatus The request status. + @param aEndpoint The endpoint number to write to. + @param aDes Descriptor to provide the data. + @param aLen The number of bytes of data to be written. + @param aZlpRequired True, if ZLP termination is required; false, otherwise. + */ + inline void Write(TRequestStatus& aStatus, TEndpointNumber aEndpoint, const TDesC8& aDes, TInt aLen, + TBool aZlpRequired=EFalse); + + /** Cancels an outstanding write request on endpoint aEndpoint. + + @param aEndpoint The endpoint number whose write is to be cancelled. + */ + inline void WriteCancel(TEndpointNumber aEndpoint); + + /** Cancels any transfer on any endpoint specified in aEndpointMask. + + @code + // Cancel transfer requests on endpoints 1, 2 & 3 + usbPort.EndpointTransferCancel(KUsbcEndpoint1Bit | KUsbcEndpoint2Bit | KUsbcEndpoint3Bit); + @endcode + + @param aEndpointMask bitmap of the endpoints. + */ + inline void EndpointTransferCancel(TUint aEndpointMask); + + /** Register for notification when a change of the Interface alternate setting or the USB Controller's + current state occurs. When the alternate setting or the Controller state changes, then the + asynchronous function completes and the current alternate setting number or Controller state is + written back to aValue. If the KUsbAlternateSetting bit is set then the remaining bits are the + alternate setting number. Otherwise aValue is interpreted as a TUsbcDeviceState. + + @see TUsbcDeviceState + + @param aStatus The request status. + @param aValue Receives the alternate setting number or Controller state. + */ + inline void AlternateDeviceStatusNotify(TRequestStatus& aStatus, TUint& aValue); + + /** Completes an AlternateDeviceStatusNotify request. If a request has previously been made then the + status variable is updated with the current device state. + */ + inline void AlternateDeviceStatusNotifyCancel(); + + /** If the channel has changed the grouping of endpoints between interfaces or changed the interface class + type from the defaults then it is necessary to force a re-enumeration. This will typically involve the + Symbian OS device initiating a disconnection and re-connection. This is an asynchronous operation + which will complete when the Controller is successfully configured by the host, i.e. has achieved + UsbShai::EUsbPeripheralStateConfigured. Since it is not known if the operation has failed, at the same time that + a ReEnumerate request is made, a timer should be set up to complete after approximately 5 seconds. It + can be assumed that if the operation has not completed after this time interval then it will not + complete. + + @param aStatus The request status. + */ + inline void ReEnumerate(TRequestStatus& aStatus); + + /** Cancels an outstanding ReEnumerate() request. + */ + inline void ReEnumerateCancel(); + + /** Register for notification when a change in stall status of any of the interface's endpoints occurs, + but not ep0. When a change in stall status occurs, then the asynchronous function completes and the + current stall state is written back to 'aEndpointStatus' as a bit map: Only stall state changes caused + by SET_FEATURE and CLEAR_FEATURE standard commands on ep0 will be notified when this function + completes. After this request completes the request should be re-issued to obtain future + notifications. + + @param aStatus The request status. + @param aEndpointMask a bitmap of the endpoints stall status. This is filled in when the call completes + bit 1 represents the interface's virtual endpoint 1, (KUsbcEndpoint1Bit) + bit 2 represents the interface's virtual endpoint 2, (KUsbcEndpoint2Bit) etc. + bit value 0 - not stalled, + bit value 1 - stalled. + */ + inline void EndpointStatusNotify(TRequestStatus& aStatus, TUint& aEndpointMask); + + /** Completes an endpoint status notify request. + */ + inline void EndpointStatusNotifyCancel(); + + /** Get current on-the-go features relating to the ability of device/host pair to + perform OTG role swap. + + @param aFeatures On return it contanis features the device currently has + bit 2 represents b_hnp_enable, (KUsbOtgAttr_B_HnpEnable) + bit 3 represents a_hnp_support, (KUsbOtgAttr_A_HnpSupport) + bit 4 represents a_alt_hnp_support, (KUsbOtgAttr_A_AltHnpSupport) + @return KErrNone if successful, KErrNotSupported if OTG is not supported by + this device, otherwise system-wide error returns + */ + inline TInt GetOtgFeatures(TUint8& aFeatures); + + /** Register for notification on USB on-the-go features' change. If any OTG feature + is changed, request completes and current feature value is filled in aValue. + + @param aStatus Request status object + @param aValue On request completion, it contains current OTG feature value + */ + inline void OtgFeaturesNotify(TRequestStatus& aStatus, TUint8& aValue); + + /** Cancel pending OTG feature request. + */ + inline void OtgFeaturesNotifyCancel(); + +#endif // #ifndef __KERNEL_MODE__ + }; + + +#include + + +#endif // __D32USBC_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbc.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbc.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,702 @@ +// 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/include/d32usbc.inl +// User side class definitions for USB Device support (inline header). +// +// + +/** + @file d32usbc.inl + @publishedPartner + @released +*/ + +#ifndef __D32USBC_INL__ +#define __D32USBC_INL__ + + +/** @internalTechnology +*/ +struct TUsbcIfcInfo + { + TUsbcInterfaceInfoBuf* iInterfaceData; + TPtr8* iString; + TUint32 iBandwidthPriority; + }; + + +/** @internalTechnology +*/ +struct TEndpointTransferInfo + { + TDesC8* iDes; + TTransferType iTransferType; + TInt iTransferSize; + TBool iZlpReqd; + }; + +inline TUsbcInterfaceInfo::TUsbcInterfaceInfo(TInt aClass, TInt aSubClass, + TInt aProtocol, TDesC16* aString, + TUint aTotalEndpoints) + : iClass(aClass, aSubClass, aProtocol), iString(aString), + iTotalEndpointsUsed(aTotalEndpoints), iEndpointData(), iFeatureWord(0) + {} + + +#ifndef __KERNEL_MODE__ + +/** @capability CommDD +*/ +inline TInt RDevUsbcClient::Open(TInt aUnit) + { + _LIT(KUsbDevName, "Usbc"); + return (DoCreate(KUsbDevName, VersionRequired(), aUnit, NULL, NULL, EOwnerThread)); + } + + +inline TVersion RDevUsbcClient::VersionRequired() const + { + return (TVersion(EMajorVersionNumber, EMinorVersionNumber, EBuildVersionNumber)); + } + + +inline TInt RDevUsbcClient::EndpointZeroRequestError() + { + return DoControl(EControlEndpointZeroRequestError); + } + + +inline TInt RDevUsbcClient::EndpointCaps(TDes8& aCapsBuf) + { + return DoControl(EControlEndpointCaps, &aCapsBuf); + } + + +inline TInt RDevUsbcClient::DeviceCaps(TUsbDeviceCaps& aCapsBuf) + { + return DoControl(EControlDeviceCaps, &aCapsBuf); + } + + +inline TInt RDevUsbcClient::GetAlternateSetting(TInt &aInterfaceNumber) + { + return DoControl(EControlGetAlternateSetting, &aInterfaceNumber); + } + + +inline TInt RDevUsbcClient::DeviceStatus(TUsbcDeviceState &aDeviceStatus) + { + return DoControl(EControlDeviceStatus, &aDeviceStatus); + } + + +inline TInt RDevUsbcClient::EndpointStatus(TEndpointNumber aEndpoint,TEndpointState &aEndpointStatus) + { + return DoControl(EControlEndpointStatus,(TAny*) aEndpoint, &aEndpointStatus); + } + + +inline TInt RDevUsbcClient::QueryReceiveBuffer(TEndpointNumber aEndpoint,TInt& aNumberOfBytes) + { + return DoControl(EControlQueryReceiveBuffer, (TAny*) aEndpoint, &aNumberOfBytes); + } + + +inline TInt RDevUsbcClient::SendEp0StatusPacket() + { + return DoControl(EControlSendEp0StatusPacket); + } + + +inline TInt RDevUsbcClient::HaltEndpoint(TEndpointNumber aEndpoint) + { + return DoControl(EControlHaltEndpoint, (TAny*) aEndpoint); + } + + +inline TInt RDevUsbcClient::ClearHaltEndpoint(TEndpointNumber aEndpoint) + { + return DoControl(EControlClearHaltEndpoint, (TAny*) aEndpoint); + } + + +inline TUint RDevUsbcClient::EndpointZeroMaxPacketSizes() + { + return DoControl(EControlEndpointZeroMaxPacketSizes); + } + + +inline TInt RDevUsbcClient::SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize) + { + return DoControl(EControlSetEndpointZeroMaxPacketSize, (TAny*) aMaxPacketSize); + } + + +inline TInt RDevUsbcClient::GetEndpointZeroMaxPacketSize() + { + return DoControl(EControlGetEndpointZeroMaxPacketSize); + } + + +inline TInt RDevUsbcClient::GetDeviceDescriptor(TDes8& aDeviceDescriptor) + { + return DoControl(EControlGetDeviceDescriptor, &aDeviceDescriptor); + } + + +inline TInt RDevUsbcClient::SetDeviceDescriptor(const TDesC8& aDeviceDescriptor) + { + return DoControl(EControlSetDeviceDescriptor, const_cast(&aDeviceDescriptor)); + } + + +inline TInt RDevUsbcClient::GetDeviceDescriptorSize(TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetDeviceDescriptorSize, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcClient::GetConfigurationDescriptor(TDes8& aConfigurationDescriptor) + { + return DoControl(EControlGetConfigurationDescriptor, &aConfigurationDescriptor); + } + + +inline TInt RDevUsbcClient::SetConfigurationDescriptor(const TDesC8& aConfigurationDescriptor) + { + return DoControl(EControlSetConfigurationDescriptor, const_cast (&aConfigurationDescriptor)); + } + + +inline TInt RDevUsbcClient::GetConfigurationDescriptorSize(TInt& aSize) + { + TPckgBuf p; + TInt r=DoControl(EControlGetConfigurationDescriptorSize, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcClient::GetInterfaceDescriptor(TInt aSettingNumber, TDes8& aInterfaceDescriptor) + { + return DoControl(EControlGetInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor); + } + + +inline TInt RDevUsbcClient::SetInterfaceDescriptor(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor) + { + return DoControl(EControlSetInterfaceDescriptor,(TAny*) aSettingNumber, + const_cast(&aInterfaceDescriptor)); + } + + +inline TInt RDevUsbcClient::GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetInterfaceDescriptorSize,(TAny*) aSettingNumber, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcClient::GetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &aEndpointDescriptor}; + return DoControl(EControlGetEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcClient::SetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, const_cast(&aEndpointDescriptor)}; + return DoControl(EControlSetEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcClient::GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize) + { + TPckgBuf p; + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &p}; + TInt r = DoControl(EControlGetEndpointDescriptorSize, &info, NULL); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline void RDevUsbcClient::GetOtgDescriptorSize(TInt& aSize) + { + aSize = KUsbDescSize_Otg; + } + + +inline TInt RDevUsbcClient::GetOtgDescriptor(TDes8& aOtgDesc) + { + return DoControl(EControlGetOtgDescriptor, (TAny*)&aOtgDesc); + } + + +inline TInt RDevUsbcClient::SetOtgDescriptor(const TDesC8& aOtgDesc) + { + return DoControl(EControlSetOtgDescriptor, (TAny*)&aOtgDesc); + } + + +inline TInt RDevUsbcClient::GetDeviceQualifierDescriptor(TDes8& aDescriptor) + { + return DoControl(EControlGetDeviceQualifierDescriptor, &aDescriptor); + } + + +inline TInt RDevUsbcClient::SetDeviceQualifierDescriptor(const TDesC8& aDescriptor) + { + return DoControl(EControlSetDeviceQualifierDescriptor, const_cast(&aDescriptor)); + } + + +inline TInt RDevUsbcClient::GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor) + { + return DoControl(EControlGetOtherSpeedConfigurationDescriptor, &aDescriptor); + } + + +inline TInt RDevUsbcClient::SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor) + { + return DoControl(EControlSetOtherSpeedConfigurationDescriptor, const_cast (&aDescriptor)); + } + + +inline TInt RDevUsbcClient::GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor) + { + return DoControl(EControlGetCSInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor); + } + + +inline TInt RDevUsbcClient::GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetCSInterfaceDescriptorSize,(TAny*) aSettingNumber, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcClient::GetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info={aSettingNumber, aEndpointNumber, &aEndpointDescriptor}; + return DoControl(EControlGetCSEndpointDescriptor,&info,NULL); + } + + +inline TInt RDevUsbcClient::GetCSEndpointDescriptorBlockSize(TInt aSettingNumber, TInt aEndpointNumber, + TInt& aSize) + { + TPckgBuf p; + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &p}; + TInt r = DoControl(EControlGetCSEndpointDescriptorSize, &info, NULL); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcClient::SignalRemoteWakeup() + { + return DoControl(EControlSignalRemoteWakeup); + } + + +inline TInt RDevUsbcClient::DeviceDisconnectFromHost() + { + return DoControl(EControlDeviceDisconnectFromHost); + } + + +inline TInt RDevUsbcClient::DeviceConnectToHost() + { + return DoControl(EControlDeviceConnectToHost); + } + + +inline TInt RDevUsbcClient::PowerUpUdc() + { + return DoControl(EControlDevicePowerUpUdc); + } + + +inline TBool RDevUsbcClient::CurrentlyUsingHighSpeed() + { + return DoControl(EControlCurrentlyUsingHighSpeed); + } + + +inline TInt RDevUsbcClient::SetInterface(TInt aInterfaceNumber, TUsbcInterfaceInfoBuf& aInterfaceData, + TUint32 aBandwidthPriority) + { + TPtr8 name_8(NULL,0); + TUsbcIfcInfo ifcinfo; + ifcinfo.iInterfaceData = const_cast(&aInterfaceData); + if (!aInterfaceData().iString) + { + ifcinfo.iString = NULL; + } + else + { + name_8.Set(const_cast(reinterpret_cast(aInterfaceData().iString->Ptr())), + aInterfaceData().iString->Size(), aInterfaceData().iString->Size()); + ifcinfo.iString = &name_8; + } + ifcinfo.iBandwidthPriority = aBandwidthPriority; + return DoControl(EControlSetInterface, (TAny*)aInterfaceNumber, &ifcinfo); + } + + +inline TInt RDevUsbcClient::ReleaseInterface(TInt aInterfaceNumber) + { + return DoControl(EControlReleaseInterface, (TAny*)aInterfaceNumber); + } + + +inline TInt RDevUsbcClient::SetCSInterfaceDescriptorBlock(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor) + { + TCSDescriptorInfo info = {aSettingNumber, 0, const_cast(&aInterfaceDescriptor), + aInterfaceDescriptor.Size()}; + return DoControl(EControlSetCSInterfaceDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcClient::SetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor) + { + TCSDescriptorInfo info = {aSettingNumber, aEndpointNumber, const_cast(&aEndpointDescriptor), + aEndpointDescriptor.Size()}; + return DoControl(EControlSetCSEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcClient::SetDeviceControl() + { + return DoControl(EControlSetDeviceControl); + } + + +inline TInt RDevUsbcClient::ReleaseDeviceControl() + { + return DoControl(EControlReleaseDeviceControl); + } + + +inline TInt RDevUsbcClient::GetStringDescriptorLangId(TUint16& aLangId) + { + TPckgBuf p; + const TInt r = DoControl(EControlGetStringDescriptorLangId, &p); + if (r == KErrNone) + aLangId = p(); + return r; + } + + +inline TInt RDevUsbcClient::SetStringDescriptorLangId(TUint16 aLangId) + { + return DoControl(EControlSetStringDescriptorLangId, (TAny*)(TUint)aLangId); + } + + +inline TInt RDevUsbcClient::GetManufacturerStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetManufacturerStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcClient::SetManufacturerStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetManufacturerStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcClient::RemoveManufacturerStringDescriptor() + { + return DoControl(EControlRemoveManufacturerStringDescriptor); + } + + +inline TInt RDevUsbcClient::GetProductStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetProductStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcClient::SetProductStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetProductStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcClient::RemoveProductStringDescriptor() + { + return DoControl(EControlRemoveProductStringDescriptor); + } + + +inline TInt RDevUsbcClient::GetSerialNumberStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetSerialNumberStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcClient::SetSerialNumberStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetSerialNumberStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcClient::RemoveSerialNumberStringDescriptor() + { + return DoControl(EControlRemoveSerialNumberStringDescriptor); + } + + +inline TInt RDevUsbcClient::GetConfigurationStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetConfigurationStringDescriptor, &name_8); + aString.SetLength(name_8.Size() / 2); + return r; + } + + +inline TInt RDevUsbcClient::SetConfigurationStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetConfigurationStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcClient::RemoveConfigurationStringDescriptor() + { + return DoControl(EControlRemoveConfigurationStringDescriptor); + } + + +inline TInt RDevUsbcClient::GetStringDescriptor(TUint8 aIndex, TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetStringDescriptor, (TAny*)(TUint)aIndex, &name_8); + aString.SetLength(name_8.Size() / 2); + return r; + } + + +inline TInt RDevUsbcClient::SetStringDescriptor(TUint8 aIndex, const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetStringDescriptor, (TAny*)(TUint)aIndex, &name_8); + } + + +inline TInt RDevUsbcClient::RemoveStringDescriptor(TUint8 aIndex) + { + return DoControl(EControlRemoveStringDescriptor, (TAny*)(TUint)aIndex); + } + + +inline TInt RDevUsbcClient::AllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlAllocateEndpointResource, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline TInt RDevUsbcClient::DeAllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlDeAllocateEndpointResource, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline TBool RDevUsbcClient::QueryEndpointResourceUse(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlQueryEndpointResourceUse, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline void RDevUsbcClient::ReadUntilShort(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadUntilShort, aDes.MaxLength()}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::ReadUntilShort(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes, + TInt aLen) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadUntilShort, aLen}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::ReadOneOrMore(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadOneOrMore, aDes.MaxLength()}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::ReadOneOrMore(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes, + TInt aLen) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadOneOrMore, aLen}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::Read(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadData, aDes.MaxLength()}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::Read(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes, TInt aLen) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadData, aLen}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::ReadPacket(TRequestStatus &aStatus, TEndpointNumber aEndpoint, TDes8 &aDes, + TInt aMaxLen) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {&aDes, ETransferTypeReadPacket, aMaxLen}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::Write(TRequestStatus &aStatus, TEndpointNumber aEndpoint, const TDesC8& aDes, + TInt aLen, TBool aZlpRequired) + { + TInt ep = (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) ? KInvalidEndpointNumber : aEndpoint; + TEndpointTransferInfo info = {const_cast(&aDes), ETransferTypeWrite, aLen, aZlpRequired}; + DoRequest(ep, aStatus, &info, NULL); + } + + +inline void RDevUsbcClient::AlternateDeviceStatusNotify(TRequestStatus& aStatus, TUint& aValue) + { + DoRequest(ERequestAlternateDeviceStatusNotify, aStatus, &aValue); + } + + +inline void RDevUsbcClient::ReEnumerate(TRequestStatus& aStatus) + { + DoRequest(ERequestReEnumerate, aStatus); + } + + +inline void RDevUsbcClient::EndpointStatusNotify(TRequestStatus& aStatus, TUint& aEndpointMask) + { + DoRequest(ERequestEndpointStatusNotify, aStatus, &aEndpointMask); + } + + +inline void RDevUsbcClient::ReadCancel(TEndpointNumber aEndpoint) + { + if (aEndpoint < 0 || aEndpoint > KMaxEndpointsPerClient) + return; + DoCancel(1 << aEndpoint); + } + + +inline void RDevUsbcClient::WriteCancel(TEndpointNumber aEndpoint) + { + ReadCancel(aEndpoint); + } + + +inline void RDevUsbcClient::EndpointTransferCancel(TUint aEndpointMask) + { + /* Mask off non-endpoint cancels */ + DoCancel(aEndpointMask & ERequestAllCancel); + } + + +inline void RDevUsbcClient::AlternateDeviceStatusNotifyCancel() + { + DoCancel(ERequestAlternateDeviceStatusNotifyCancel); + } + + +inline void RDevUsbcClient::ReEnumerateCancel() + { + DoCancel(ERequestReEnumerateCancel); + } + + +inline void RDevUsbcClient::EndpointStatusNotifyCancel() + { + DoCancel(ERequestEndpointStatusNotifyCancel); + } + +inline TInt RDevUsbcClient::GetOtgFeatures(TUint8& aFeatures) + { + TPckgBuf p; + TInt r = DoControl(EControlGetOtgFeatures, &p); + if (r == KErrNone) + aFeatures = p(); + return r; + } + + +inline void RDevUsbcClient::OtgFeaturesNotify(TRequestStatus& aStatus, TUint8& aValue) + { + DoRequest(ERequestOtgFeaturesNotify, aStatus, &aValue); + } + + +inline void RDevUsbcClient::OtgFeaturesNotifyCancel() + { + DoCancel(ERequestOtgFeaturesNotifyCancel); + } + + +#endif // #ifndef __KERNEL_MODE__ + +#endif // #ifndef __D32USBC_INL__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbcsc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbcsc.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,1558 @@ +// Copyright (c) 2008-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\include\d32usbcsc.h +// User side class definitions for USB Device support. +// +// + +/** + @file d32usbcsc.h + @publishedPartner + @released +*/ + +#ifndef __D32USBCSC_H__ +#define __D32USBCSC_H__ + +#include +#include +#include + + +/** This means that SetInterface was called after RealizeInterface had been called. + RealizeInterface is meant to signal that all interfaces have been set. +*/ +const TInt KErrUsbAlreadyRealized = -6813; //Changed from -6713 for future compatibility with the d32usbcshared.h file + +const TInt KErrAlternateSettingChanged = -6814; + + +const TUint KChunkCellSize = 1; //1 32 bit integer +const TInt KEpDescPacketSizeOffset = 4; + +/** The user side enpoint number of Endpoint Zero. */ +const TInt KEp0Number = 0; + +/* Used in TUsbcScHdrEndpointRecord to describe the endpoint type +*/ + +const TUint8 KUsbScHdrEpDirectionIn=1; +const TUint8 KUsbScHdrEpDirectionOut=2; +const TUint8 KUsbScHdrEpDirectionBiDir=3; + + +const TUint8 KUsbScHdrEpTypeControl = 0; +const TUint8 KUsbScHdrEpTypeIsochronous =1; +const TUint8 KUsbScHdrEpTypeBulk = 2; +const TUint8 KUsbScHdrEpTypeInterrupt = 3; +const TUint8 KUsbScHdrEpTypeUnknown = ~0; +/** Used in the the Shared Chunk Header, to represent an endpoint. +*/ +class TUsbcScHdrEndpointRecord + { +public: + inline TUsbcScHdrEndpointRecord(TInt aBufferNo, TUint8 aType); + inline TUint Direction() const; + inline TUint Type() const; +public: + TUint8 iBufferNo; + TUint8 iType; + TUint16 iReserved; + }; + + +// This is used to hold the geometry of the shared buffers +class TUsbcScBufferRecord + { + friend class DLddUsbcScChannel; + +public: + inline TUint Offset() const; + inline TUint Size() const; +private: + inline void Set(TUint aOffset, TUint aEndOffset); + TUint iOffset; + TUint iSize; + }; + +struct SUsbcScBufferHeader + { + TInt iHead; // Where the LDD will next write a transfer + TInt iTail; // Indicates the fist packet that user side is processing (anything prior is disposable) + TInt iBilTail; // This is not used by LDD at all, but just for the BIL's benifit. + }; + + +struct SUsbcScAlternateSetting + { + TUint16 iSetting; + TUint16 iSequence; + }; + +/** Endpoint pair information. This can be used to control pairing of endpoint +for classes that require explicit pairing of endpoint, such as ADC. + +This is currently not used. +*/ + +class TEndpointPairInfo +{ +public: + TEndpointPairInfo(TUint8 aType=0, TUint16 aPair=0, TUint8 aSpare=0); +public: + TUint8 iType; + TUint8 iSpare; + TUint16 iPair; +}; + +/** +This is the buffer number reserved for use with endpoint zero with the ReadDataNotify and WriteData methods. +*/ +const TInt KUsbcScEndpointZero = -1; + +/** +This flag is reserved in TUsbcscEndpointInfo::iFlags, to indicate that the client driver's client wishes reads to operate in a coupled fashion. +This behaviour is not currently supported. +*/ +const TUint KUsbScCoupledRead = 0x1; + +/** +This flag, used in parameter aFlag of WriteData, is used to indicate that a ZLP should be sent. +*/ +const TUint KUsbcScWriteFlagsZlp = 0x0001; + + +// Bit fields used in iFlags of TUsbcScTransferHeader + +const TUint KUsbcScShortPacket = 0x0001; +const TUint KUsbcScStateChange = 0x0004; + +class TUsbcScTransferHeader +{ +public: +#ifdef _DEBUG + TUint iHashId; + TUint iSequence; +#endif + TUint iBytes; + TUint iFlags; + TUint iNext; + TUint16 iAltSettingSeq; + TInt16 iAltSetting; + union + { + TUint i[1]; // Extends + TUint8 b[4]; // Extends + } iData; +}; + +/** The desired endpoint capabilities used in RDevUsbcScClient::SetInterface(). + +This derived class has additional fields used in the shared chunk USB driver. +*/ +class TUsbcScEndpointInfo: public TUsbcEndpointInfo + { +public: + TUsbcScEndpointInfo(TUint aType=UsbShai::KUsbEpTypeBulk, TUint aDir=UsbShai::KUsbEpDirOut, TInt aInterval=0, TInt aExtra=0, + TUint aBufferSize=0, TUint aReadSize=0); + + +public: + /** This indicates the requested size of the endpoint buffer and must be at + least as large as iReadSize. + */ + TUint iBufferSize; + + /** This is the amount of data that the LDD reads from the bus before it sets + up another read and is normally intended to read many packets. + */ + TUint iReadSize; + + /** TEndpointPairInfo represents pairing information for isochronous endpoints. + Should be zero in other cases. If this specifies paired endpoints then + iExtra (in the base class TUsbcEndpointInfo) also needs to be set to the + class specific size for this endpoint descriptor (This is here only for future use). + */ + TEndpointPairInfo iPairing; + + /** The necessary alignment, in bytes, that needs to be applied to the transfer start points + of the data. This is only observed on OUT endpoints. Zero can be specified to indicate + there are no class side requirements for alignment. The alignment for OUT endpoints is + which ever is greater of this field or the USB hardware requirements. + */ + TUint iAlignment; + + /** Flags to indicate how the endpoint should function. None currently defined, + but could be used to allow support for direct read. + */ + TUint iFlags; + + /** Reserved for future use. */ + TUint32 iReserved2[2]; + }; + +/** This must be filled in prior to a call to RDevUsbcClient::SetInterface(). +*/ +class TUsbcScInterfaceInfo + { +public: + TUsbcScInterfaceInfo(TInt aClass=0, TInt aSubClass=0, TInt aProtocol=0, + TDesC16* aString=NULL, TUint aTotalEndpoints=0); +public: + /** The class, subclass and protocol that this interface supports. */ + TUsbcClassInfo iClass; + /** The description string for the interface. Used to construct the interface string descriptor. */ + const TDesC16* iString; + /** Total number of endpoints being requested (0-5). Endpoint 0 should not be included in this number. */ + TUint iTotalEndpointsUsed; + /** Desired properties of the endpoints requested. + Do NOT include endpoint 0. + APIs use endpoint numbers that are offsets into this array. + */ + TUsbcScEndpointInfo iEndpointData[KMaxEndpointsPerClient]; + /** 32 flag bits used for specifying miscellaneous Interface features. + Currently defined are: + - KUsbcInterfaceInfo_NoEp0RequestsPlease = 0x00000001 + */ + TUint32 iFeatureWord; + }; + +/** Package buffer for a TUsbcInterfaceInfo object. + + @see TUsbcInterfaceInfo +*/ +typedef TPckgBuf TUsbcScInterfaceInfoBuf; + +struct TUsbcScChunkHdrOffs + { + TUint iBuffers; + TUint iAltSettings; + }; + + +class TUsbcScChunkBuffersHeader // Not instantiable + { + friend class DLddUsbcScChannel; + friend class TRealizeInfo; + +public: + inline TUsbcScBufferRecord* Ep0Out() const; + inline TUsbcScBufferRecord* Ep0In() const; + inline TUsbcScBufferRecord* Buffers(TInt aBuffer) const; + inline TInt NumberOfBuffers() const; + +private: + TUsbcScChunkBuffersHeader(); +private: + TInt iRecordSize; + TInt iNumOfBufs; + TUint8 iBufferOffset[8]; // Extends + }; + +struct TUsbcScChunkAltSettingHeader // Not instantiable + { + TInt iEpRecordSize; + TInt iNumOfAltSettings; + TUint iAltTableOffset[1]; // Extends + }; + +class TEndpointBuffer; + + +/** The user side handle to the USB client driver. +*/ +class RDevUsbcScClient : public RBusLogicalChannel + { +public: + /** @internalComponent */ + enum TVer + { + EMajorVersionNumber = 0, + EMinorVersionNumber = 1, + EBuildVersionNumber = KE32BuildVersionNumber + }; + +// Bit pattern. s = Request/Control. c = Cancel, m = mode bits, B = Buffer number, R = request number. +// scmm mmmm | mmmm mmmm | mmBB BBBB |RRRR RRRR + + enum TRequest + { + ERequestWriteData = 1, + ERequestReadDataNotify = 2, + ERequestAlternateDeviceStatusNotify = 3, + ERequestReEnumerate = 4, + ERequestEndpointStatusNotify = 5, + ERequestOtgFeaturesNotify = 6, + ERequestMaxRequests, // 7 + + ERequestCancel = 0x40000000, + + ERequestWriteDataCancel = ERequestWriteData | ERequestCancel, + ERequestReadDataNotifyCancel = ERequestReadDataNotify | ERequestCancel, + ERequestAlternateDeviceStatusNotifyCancel = ERequestAlternateDeviceStatusNotify | ERequestCancel, + ERequestReEnumerateCancel = ERequestReEnumerate | ERequestCancel, + ERequestEndpointStatusNotifyCancel = ERequestEndpointStatusNotify | ERequestCancel, + ERequestOtgFeaturesNotifyCancel = ERequestOtgFeaturesNotify | ERequestCancel + }; + + enum TControl + { + // Changing the order of these enums will break BC. + EControlEndpointZeroRequestError, // 00 + EControlEndpointCaps, + EControlDeviceCaps, + EControlGetAlternateSetting, + EControlDeviceStatus, + EControlEndpointStatus, + EControlSetInterface, + EControlReleaseInterface, + EControlSendEp0StatusPacket, + EControlHaltEndpoint, // 09 + // + EControlClearHaltEndpoint, // 10 + EControlSetDeviceControl, + EControlReleaseDeviceControl, + EControlEndpointZeroMaxPacketSizes, + EControlSetEndpointZeroMaxPacketSize, + EControlGetDeviceDescriptor, + EControlSetDeviceDescriptor, + EControlGetDeviceDescriptorSize, + EControlGetConfigurationDescriptor, + EControlSetConfigurationDescriptor, // 19 + // + EControlGetConfigurationDescriptorSize, // 20 + EControlGetInterfaceDescriptor, + EControlSetInterfaceDescriptor, + EControlGetInterfaceDescriptorSize, + EControlGetEndpointDescriptor, + EControlSetEndpointDescriptor, + EControlGetEndpointDescriptorSize, + EControlGetCSInterfaceDescriptor, + EControlSetCSInterfaceDescriptor, + EControlGetCSInterfaceDescriptorSize, // 29 + // + EControlGetCSEndpointDescriptor, // 30 + EControlSetCSEndpointDescriptor, + EControlGetCSEndpointDescriptorSize, + EControlSignalRemoteWakeup, + EControlGetStringDescriptorLangId, + EControlSetStringDescriptorLangId, + EControlGetManufacturerStringDescriptor, + EControlSetManufacturerStringDescriptor, + EControlRemoveManufacturerStringDescriptor, + EControlGetProductStringDescriptor, // 39 + // + EControlSetProductStringDescriptor, // 40 + EControlRemoveProductStringDescriptor, + EControlGetSerialNumberStringDescriptor, + EControlSetSerialNumberStringDescriptor, + EControlRemoveSerialNumberStringDescriptor, + EControlGetConfigurationStringDescriptor, + EControlSetConfigurationStringDescriptor, + EControlRemoveConfigurationStringDescriptor, + EControlDeviceDisconnectFromHost, + EControlDeviceConnectToHost, // 49 + // + EControlDevicePowerUpUdc, // 50 + EControlDumpRegisters, + EControlAllocateEndpointResource, + EControlDeAllocateEndpointResource, + EControlQueryEndpointResourceUse, + EControlGetEndpointZeroMaxPacketSize, + EControlGetDeviceQualifierDescriptor, + EControlSetDeviceQualifierDescriptor, + EControlGetOtherSpeedConfigurationDescriptor, + EControlSetOtherSpeedConfigurationDescriptor, // 59 + // + EControlCurrentlyUsingHighSpeed, // 60 + EControlSetStringDescriptor, + EControlGetStringDescriptor, + EControlRemoveStringDescriptor, + EControlSetOtgDescriptor, + EControlGetOtgDescriptor, + EControlGetOtgFeatures, + EControlRealizeInterface, + EControlStartNextInAlternateSetting + }; + + + // const static TUint KFieldIdPos = 0; + const static TUint KFieldIdMask = 0xFF; + const static TUint KFieldBuffPos = 8; + const static TUint KFieldBuffMask = 0x3F; + const static TUint KFieldFlagsPos = 14; + const static TUint KFieldFlagsMask = 0xFFFF; + + +public: + +#ifndef __KERNEL_MODE__ + + /** Opens a channel. + + @param aUnit This should be 0 (zero). + + @return KErrNone if successful. + */ + inline TInt Open(TInt aUnit); + + inline TVersion VersionRequired() const; + + /** Stalls ep0 to signal command fault to the host. + + @return KErrNone if successful. + */ + inline TInt EndpointZeroRequestError(); + + /** Retrieves the capabilities of all the endpoints on the device. + + Suggested use is as follows: + + @code + TUsbcEndpointData data[KUsbcMaxEndpoints]; + TPtr8 dataPtr(reinterpret_cast(data), sizeof(data), sizeof(data)); + ret = usbPort.EndpointCaps(dataPtr); + @endcode + + @param aEpCapsBuf A descriptor encapsulating an array of TUsbcEndpointData. + + @return KErrNone if successful. + */ + inline TInt EndpointCaps(TDes8& aEpCapsBuf); + + /** Retrieves the capabilities of the USB device. + + @see TUsbDeviceCaps + + @param aDevCapsBuf A TUsbDeviceCaps object. + + @return KErrNone if successful. + */ + inline TInt DeviceCaps(TUsbDeviceCaps& aDevCapsBuf); + + /** Copies the current alternate setting for this interface into aInterfaceNumber + For USB Interfaces whose main interface is active, this will be 0 (zero). + + @param aInterfaceNumber Current alternate setting for this interface is copied into this. + + @return KErrNone if successful. + */ + inline TInt GetAlternateSetting(TInt& aInterfaceNumber); + + /** Copies the current device status into aDeviceStatus. + + @param aDeviceStatus Current device status is copied into this. + + @return KErrNone if successful + */ + inline TInt DeviceStatus(TUsbcDeviceState& aDeviceStatus); + + /** Copies the current endpoint status into aEndpointStatus. + + @param aEndpoint Endpoint number valid for the current alternate setting. + @param aEndpointStatus The current endpoint status, might be stalled, not stalled or unknown. + + @return KErrNone if successful. + */ + inline TInt EndpointStatus(TInt aEndpoint, TEndpointState& aEndpointStatus); + + + /** Requests that a zero length status packet be sent to the host in response + to a class or vendor specific ep0 SETUP packet. + + @return KErrNone if successful. + */ + inline TInt SendEp0StatusPacket(); + + /** Stalls endpoint aEndpoint, usually to indicate an error condition with a previous command. + The host will normally send a SET_FEATURE command on ep0 to acknowledge and clear the stall. + + @return KErrNone if successful. + */ + inline TInt HaltEndpoint(TInt aEndpoint); + + /** Clears the stall condition on endpoint aEndpoint. This is inluded for symmetry and test purposes. + + @return KErrNone if successful. + */ + inline TInt ClearHaltEndpoint(TInt aEndpoint); + + /** Requests that device control be allocated to this channel. + + @return KErrNone if successful. + */ + inline TInt SetDeviceControl(); + + /** Relinquishes device control previously allocated to this channel. + + @return KErrNone if successful. + */ + inline TInt ReleaseDeviceControl(); + + /** Returns a bitmap of available ep0 maximum packet sizes. + + @return bitmap of available ep0 maximum packet sizes. + */ + inline TUint EndpointZeroMaxPacketSizes(); + + /** Requests that a maximum packet size of aMaxPacketSize be set on ep0. + + @param aMaxPacketSize The maximum packet size. + + @return KErrNone if successful. + */ + inline TInt SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize); + + /** Queries the current maximum packet size on ep0. + + @return The currently set maximum packet size on ep0. + */ + inline TInt GetEndpointZeroMaxPacketSize(); + + /** Copies the current device descriptor into aDeviceDescriptor. + + @param aDeviceDescriptor Receives the current device descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceDescriptor(TDes8& aDeviceDescriptor); + + /** Sets the contents of aDeviceDescriptor to be the current device descriptor. + + @param aDeviceDescriptor Contains the device descriptor. + + @return KErrNone if successful. + */ + inline TInt SetDeviceDescriptor(const TDesC8& aDeviceDescriptor); + + /** Gets the size of the current device descriptor. This is unlikely to be anything other than 9. + + @param aSize Receives the size of the current device descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceDescriptorSize(TInt& aSize); + + /** Copies the current configuration descriptor into aConfigurationDescriptor. + + @param aConfigurationDescriptor Receives the current configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetConfigurationDescriptor(TDes8& aConfigurationDescriptor); + + /** Sets the contents of aConfigurationDescriptor to be the current configuration descriptor. + + @param aConfigurationDescriptor Contains the configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt SetConfigurationDescriptor(const TDesC8& aConfigurationDescriptor); + + /** Gets the size of the current configuration descriptor. + + @param aSize Receives the size of the current configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetConfigurationDescriptorSize(TInt& aSize); + + /** Copies the interface descriptor into aInterfaceDescriptor for the interface with alternate + setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Receives the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetInterfaceDescriptor(TInt aSettingNumber, TDes8& aInterfaceDescriptor); + + /** Sets the interface descriptor contained in aInterfaceDescriptor for the interface with + alternate setting aSettingNumber, 0 for the main interface, for transmission to the host + during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetInterfaceDescriptor(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor); + + /** Copies the size of the interface descriptor for the interface with alternate + setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber The alternate setting. + @param aSize receives the size of the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize); + + /** Copies the endpoint descriptor for logical endpoint number aEndpointNumber into aEndpointDescriptor + for the interface with alternate setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber The endpoint number of the endpoint. + @param aEndpointDescriptor Receives the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, TDes8& aEndpointDescriptor); + + /** Sets the endpoint descriptor for logical endpoint number aEndpointNumber contained in + aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main interface, + for transmission to the host during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Contains the endpoint descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor); + + /** Copies the size of the endpoint descriptor for logical endpoint number aEndpointNumber for the + interface with alternate setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aSize Receives the size of the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize); + + /** Get OTG descriptor size + + @param aSize TInt Reference which contains OTG descriptor size on return. + */ + inline void GetOtgDescriptorSize(TInt& aSize); + + /** Get OTG descriptor of USB on-the-go feature. + + @param aOtgDesc User-side buffer to store copy of descriptor. + + @return KErrNone if successful. + */ + inline TInt GetOtgDescriptor(TDes8& aOtgDesc); + + /** Set OTG descriptor by user to enable/disable USB on-the-go feature. + + @param aOtgDesc Descriptor buffer containing OTG features. + + @return KErrNone if successful. + */ + inline TInt SetOtgDescriptor(const TDesC8& aOtgDesc); + + /** Copies the current device_qualifier descriptor into aDescriptor. + + @param aDescriptor Receives the current device_qualifier descriptor. + + @return KErrNone if successful. + */ + inline TInt GetDeviceQualifierDescriptor(TDes8& aDescriptor); + + /** Sets the device_qualifier descriptor to the contents of aDescriptor. + + @param aDescriptor Contains the new device_qualifier descriptor. + + @return KErrNone if successful. + */ + inline TInt SetDeviceQualifierDescriptor(const TDesC8& aDescriptor); + + /** Copies the current other_speed_configuration descriptor into aDescriptor. + + @param aDescriptor Receives the current other_speed_configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor); + + /** Sets the other_speed_configuration descriptor to the contents of aDescriptor. + + @param aDescriptor Contains the new other_speed_configuration descriptor. + + @return KErrNone if successful. + */ + inline TInt SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor); + + /** Copies the class specific interface descriptor block into aInterfaceDescriptor for the interface + with alternate setting aSettingNumber, 0 for the main interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor); + + /** aSettingNumber is the alternate interface setting, 0 for the main interface, that the descriptor block + aDes should be attached to. aDes is a block of data containing at least one class specific descriptor + for transmission during enumeration after the class interface descriptor (or alternate interface + descriptor) has been sent, but before the endpoint descriptors belonging to this interface are sent. + aDes may contain as many descriptors as are necessary or only one. SetCSInterfaceDescriptorBlock() + should be called at any time after SetInterface() has been called to establish a main interface or an + alternate interface. More than one call may be made - the data blocks will be concatenated prior to + sending. No checking or validation of the contents of aDes will be made and it is the caller's + responsibility to ensure that the data supplied is correct and appropriate to the interface identified + by aSettingNumber. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aInterfaceDescriptor Contains the interface descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetCSInterfaceDescriptorBlock(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor); + + /** Copies the size of the class specific interface descriptor block for the interface with alternate + setting aSettingNumber, 0 for the main interface, into aSize. + + @param aSettingNumber The alternate setting number. + @param aSize receives the size of the interface descriptor. + + @return KErrNone if successful. + */ + inline TInt GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize); + + /** Copies the class specific endpoint descriptor for logical endpoint number aEndpointNumber + into aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main + interface. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Receives the endpoint descriptor. + + @return KErrNone if successful. + */ + inline TInt GetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor); + + /** Sets the class specific endpoint descriptor for logical endpoint number aEndpointNumber contained in + aEndpointDescriptor for the interface with alternate setting aSettingNumber, 0 for the main interface, + for transmission to the host during enumeration. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aEndpointDescriptor Contains the endpoint descriptor to be set. + + @return KErrNone if successful. + */ + inline TInt SetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor); + + /** Copies the size of the class specific endpoint descriptor block for logical endpoint number + aEndpointNumber for the interface with alternate setting aSettingNumber, 0 for the main interface, + into aSize. + + @param aSettingNumber Alternate setting number on the interface, 0 for the main interface. + @param aEndpointNumber Valid endpoint number on this interface. + @param aSize On return, contains the size of the class specific endpoint descriptor block. + + @return KErrNone if successful. + */ + inline TInt GetCSEndpointDescriptorBlockSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize); + + /** Generates a Remote Wakeup bus condition. + The capability of the device to generate Remote Wakeup signalling is enquired in + RDevUsbcClient::DeviceCaps. + + @return KErrNone if this signalling is possible and the signal has been generated. + */ + inline TInt SignalRemoteWakeup(); + + /** Simulates a physical removal of the USB cable by disabling the D+/- pull-ups.The iConnect member of + TUsbDeviceCapsV01, returned by RDevUsbcClient::DeviceCaps(), indicates whether this functionality is + supported. + + @return KErrNone if successful. + */ + inline TInt DeviceDisconnectFromHost(); + + /** Simulates a physical insertion of the USB cable by enabling the D+/- pull-ups.The iConnect member + of TUsbDeviceCapsV01, returned by RDevUsbcClient::DeviceCaps(), indicates whether this functionality + is supported. + + @return KErrNone if successful. + */ + inline TInt DeviceConnectToHost(); + + /** Powers up the UDC and connects it to the bus if one or more interfaces exist. + + @return KErrNone if UDC successfully powered up, KErrNotReady if no + interfaces have been registered yet, KErrHardwareNotAvailable if UDC + couldn't be activated. + */ + inline TInt PowerUpUdc(); + + /** Enquires about the current operating speed of the UDC. + + @return ETrue if the UDC is currently operating at High speed, EFalse otherwise. + */ + inline TBool CurrentlyUsingHighSpeed(); + + /** Allocates the use of aResource to aEndpoint. It will be used from when the current bus transfer has been + completed. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number to which the resource is to be allocated. + + @return KErrNone if successful, KErrInUse if the resource is already consumed and cannot be allocated, + KErrNotSupported if the endpoint does not support the resource requested. + + @publishedPartner @deprecated + */ + inline TInt AllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Deallocates the use of aResource aEndpoint or ends a specified endpoint behaviour. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number from which the resource is to be removed. + + @return KErrNone if the resource has been successfully deallocated, KErrNotSupported if the endpoint + does not support the resource requested. + + @publishedPartner @deprecated + */ + inline TInt DeAllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Queries endpoint resource use. + + @param aResource is typically some rationed hardware resource or possibly specifies a type of endpoint + behaviour. aResource is not a bitmap and TEndpointResource values should not be combined. + @param aEndpoint The endpoint number at which the resource is to be queried. + + @return ETrue is the specified resource is in use at the endpoint and EFalse if not. + */ + inline TBool QueryEndpointResourceUse(TInt aEndpoint, TUsbcEndpointResource aResource); + + /** Request (i.e. claim for this channel) up to five endpoints and set the class type for this USB + interface. 'aInterfaceData' is a package buffer which describes the interface and all the endpoints + being requested by the driver for this interface. + + @param aInterfaceNumber Distinguishes between alternate interfaces. If these are not be used then this + should always be zero. If this parameter is used, then its value must be one more than that of the + proceeding alternate interface. + @param aInterfaceData A package buffer which describes the interface and all the endpoints being + requested by the driver for this interface. + + + @return KErrInUse if any of the endpoints being requested have already been claimed by another channel. + KErrNotSupported if an endpoint with all of the specified properties is not supported on this + platform. KErrNoMemory if insufficient memory is available to complete the operation. + */ + inline TInt SetInterface(TInt aInterfaceNumber, TUsbcScInterfaceInfoBuf& aInterfaceData); + + + /** + This method should be called after SetInterface has been called for all possible alternative settings. + Calling this invalidates further calls to SetInterface. On success, a chunk handle is created and + passed back though aChunk. This is needed for the user side to access the shared chunk where the + data is stored. Note that if you are using the BIL (described later), then FinalizeInterface (...) + should be used instead, which will call this method. + + @return KErrNone on successful completion, or one of the system wide error codes. + */ + inline TInt RealizeInterface(RChunk& aChunk); + + + /** Release an interface previously claimed by this channel. Alternate interfaces need to be released + in strict descending order, starting with the last (i.e. highest numbered) one. + It is not necessary to release an interface that wasn't successfully requested. + + @param aInterfaceNumber Specifies the alternate setting number 'aInterfaceNum' of the interface to be + released. + + @return KErrNone if successful. KErrArgument if the alternate setting doesn't exist or is released out + of order. + */ + inline TInt ReleaseInterface(TInt aInterfaceNumber); + + /** Copies the current string descriptor language ID (LANGID) code into the aLangId argument. Even though + the USB spec allows for the existence of a whole array of LANGID codes, we only support one. + + @param aLangId Receives the LANGID code. + + @return KErrNone if successful, KErrArgument if problem with argument (memory cannot be written to, etc.). + */ + inline TInt GetStringDescriptorLangId(TUint16& aLangId); + + /** Sets the string descriptor language ID (LANGID). Even though the USB spec allows for the existence of + a whole array of LANGID codes, we only support one. + + @param aLangId The LANGID code to be set. + + @return KErrNone if successful. + */ + inline TInt SetStringDescriptorLangId(TUint16 aLangId); + + /** Copies the string descriptor identified by the iManufacturer index field of the Standard Device + Descriptor into the aString argument. + + @param aString Receives manufacturer string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetManufacturerStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iManufacturer index field of the Standard Device + Descriptor to the aString argument. + + @param aString Contains the new manufacturer string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetManufacturerStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iManufacturer index field of the Standard + Device Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveManufacturerStringDescriptor(); + + /** Retrieves the string descriptor identified by the iProduct index field of the Standard Device + Descriptor into the aString argument. + + @param aString Receives product string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetProductStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iProduct index field of the Standard Device Descriptor to + the aString argument. + + @param aString Contains the new product string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetProductStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iProduct index field of the Standard Device + Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveProductStringDescriptor(); + + /** Retrieves the string descriptor identified by the iSerialNumber index field of the Standard Device + Descriptor into the aString argument. + + @param aString Receives product string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetSerialNumberStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iSerialNumber index field of the Standard Device + Descriptor to the aString argument. + + @param aString Contains the new serial number string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetSerialNumberStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iSerialNumber index field of the Standard + Device Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveSerialNumberStringDescriptor(); + + /** Retrieves the string descriptor identified by the iConfiguration index field of the (first) Standard + Configuration Descriptor into the aString argument. + + @param aString Receives configuration string. + + @return KErrNone if successful, KErrArgument if MaxLength of aString is too small to hold the entire + descriptor, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt GetConfigurationStringDescriptor(TDes16& aString); + + /** Sets the string descriptor identified by the iConfiguration index field of the Standard Configuration + Descriptor to the aString argument. + + @param aString Contains the new serial number string descriptor. + + @return KErrNone if successful, KErrNoMemory if no memory is available to store the new string from + aString (in which case the old string descriptor will be preserved). + */ + inline TInt SetConfigurationStringDescriptor(const TDesC16& aString); + + /** Removes (deletes) the string descriptor identified by the iConfiguration index field of the Standard + Configuration Descriptor and sets that field to zero. + + @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. + */ + inline TInt RemoveConfigurationStringDescriptor(); + + /** Copies the string of the USB string descriptor at the specified index in the string descriptor array + into the aString argument. + + Although this function can also be used for it, for querying most standard string descriptors + there exists a set of dedicated access functions. + + @see RDevUsbcClient::GetStringDescriptorLangId + @see RDevUsbcClient::GetManufacturerStringDescriptor + @see RDevUsbcClient::GetProductStringDescriptor + @see RDevUsbcClient::GetSerialNumberStringDescriptor + @see RDevUsbcClient::GetConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aString The target location for the string descriptor copy. + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index, + KErrArgument if MaxLength() of aString is too small to hold the entire descriptor. + */ + inline TInt GetStringDescriptor(TUint8 aIndex, TDes16& aString); + + /** Sets the aString argument to be the string of a USB string descriptor at the specified index in the + string descriptor array. If a string descriptor already exists at that position then its string will + be replaced. + + Care should be taken, when choosing aIndex, not to inadvertently overwrite one of the standard + string descriptors. For their manipulation there exists a set of dedicated access functions. + + @see RDevUsbcClient::SetStringDescriptorLangId + @see RDevUsbcClient::SetManufacturerStringDescriptor + @see RDevUsbcClient::SetProductStringDescriptor + @see RDevUsbcClient::SetSerialNumberStringDescriptor + @see RDevUsbcClient::SetConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + @param aString Contains the string descriptor to be set. + + @return KErrNone if successful, KErrArgument if aIndex is invalid, KErrNoMemory if no memory + is available to store the new string (an existing descriptor at that index will be preserved). + */ + inline TInt SetStringDescriptor(TUint8 aIndex, const TDesC16& aString); + + /** Removes (deletes) the USB string descriptor at the specified index in the string descriptor array. + The position in the array of other string descriptors is not affected. + + Care should be taken, when choosing aIndex, not to inadvertently delete a standard string descriptor + (also because index references from non-string descriptors would be invalidated). For the deletion + of most standard string descriptors there exists a set of dedicated functions. + + @see RDevUsbcClient::RemoveManufacturerStringDescriptor + @see RDevUsbcClient::RemoveProductStringDescriptor + @see RDevUsbcClient::RemoveSerialNumberStringDescriptor + @see RDevUsbcClient::RemoveConfigurationStringDescriptor + + @param aIndex The position of the string descriptor in the string descriptor array. + + @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index. + */ + inline TInt RemoveStringDescriptor(TUint8 aIndex); + + + + /** Requests notification for when there is data available on the buffer indicated. If the buffer + already has data in it, it will return immediately, otherwise it will block until there is. + + If the BIL methods are being used (recommended), then this method should not be called directly, + using TEndpointBuffer::GetBuffer instead. + + @param aBufferNumber Indicates the buffer for which the caller wishes to know about data + additions. The buffer needed of any given endpoint can be found by inspecting the alternative + setting table, in the chunk header. The location of the buffer can be found by looking at the + buffer offset table, also in the chunk header. + + @param aStatus The request status where notification of completion is directed. KErrCancel is + returned if the asynchronous operation was cancelled. + + @param aLength A preference for the quantity of data to be read. This value is only a + suggestion and my be ignored. The default value of 0 indicates no preference. + + @return KErrNone on success, or KErrArgument if the buffer number is invalid. + */ + inline TInt ReadDataNotify(TInt aBufferNumber, TRequestStatus& aStatus, TInt aLength=0); + + + /** Requests the LDD to write the contents of the given buffer to the USB hardware. Notification is + given when this is complete. More then one write request can be queued on any one endpoint, to allow + for less Hardware idling between buffers. + + If the BIL methods are being used (recommended), then this method should not be called directly, + using TEndpointBuffer::WriteBuffer instead. + + @param aBufferNumber represents the buffer number of the buffer of which the caller has placed the + data. As described with ReadDataNotify(...), details of the buffers can be found in the chunk header. + + @param aStart Represents the start offset of the data within the chunk. This start location must be + aligned to a multiple of the maximum packet size for the endpoint, so that the data can be DMAed + straight out of the buffer. + + @param aLength Represents the amount of data to be sent to the host in bytes. + + @param aFlags Is a bitfield, where bit 0 should be set if a ZLP is to be sent to the host after the + current transaction. All other bits are reserved for future use. +*/ + inline void WriteData(TInt aBufferNumber, TUint aStart, TUint aLength, TUint aFlags, TRequestStatus& aStatus); + + + + /** Cancels an outstanding read request on endpoint buffer aBufferNumber. + + @param aBufferNumber The endpoint buffer number whose read is to be cancelled. + */ + inline void ReadCancel(TInt aBufferNumber); + + + /** Cancels an outstanding write request on endpoint buffer aBufferNumber. + + @param aBufferNumber The endpoint buffer number whose write is to be cancelled. + */ + inline void WriteCancel(TInt aBufferNumber); + + /** Cancels any transfer on any endpoint buffer specified in aBufferMask. + + @code + // Cancel transfer requests on buffers 1, 2, 3 & 4 + usbPort.EndpointTransferCancel(1 | 2 | 4 | 8); + @endcode + + @param aBufferMask bitmap of the endpoint buffer numbers. + */ + inline void EndpointTransferCancel(TUint aBufferMask); + + /** Register for notification when a change of the Interface alternate setting or the USB Controller's + current state occurs. When the alternate setting or the Controller state changes, then the + asynchronous function completes and the current alternate setting number or Controller state is + written back to aValue. If the KUsbAlternateSetting bit is set then the remaining bits are the + alternate setting number. Otherwise aValue is interpreted as a TUsbcDeviceState. + + @see TUsbcDeviceState + + @param aStatus The request status. + @param aValue Receives the alternate setting number or Controller state. + */ + inline void AlternateDeviceStatusNotify(TRequestStatus& aStatus, TUint& aValue); + + /** Completes an AlternateDeviceStatusNotify request. If a request has previously been made then the + status variable is updated with the current device state. + */ + inline void AlternateDeviceStatusNotifyCancel(); + + /** If the channel has changed the grouping of endpoints between interfaces or changed the interface class + type from the defaults then it is necessary to force a re-enumeration. This will typically involve the + Symbian OS device initiating a disconnection and re-connection. This is an asynchronous operation + which will complete when the Controller is successfully configured by the host, i.e. has achieved + UsbShai::EUsbPeripheralStateConfigured. Since it is not known if the operation has failed, at the same time that + a ReEnumerate request is made, a timer should be set up to complete after approximately 5 seconds. It + can be assumed that if the operation has not completed after this time interval then it will not + complete. + + @param aStatus The request status. + */ + inline void ReEnumerate(TRequestStatus& aStatus); + + /** Cancels an outstanding ReEnumerate() request. + */ + inline void ReEnumerateCancel(); + + /** Register for notification when a change in stall status of any of the interface's endpoints occurs, + but not ep0. When a change in stall status occurs, then the asynchronous function completes and the + current stall state is written back to 'aEndpointStatus' as a bit map: Only stall state changes caused + by SET_FEATURE and CLEAR_FEATURE standard commands on ep0 will be notified when this function + completes. After this request completes the request should be re-issued to obtain future + notifications. + + @param aStatus The request status. + @param aEndpointMask A bitmap of the endpoints' stall status. This is filled in when the call completes. + bit 1 represents the interface's virtual endpoint 1, (KUsbcEndpoint1Bit) + bit 2 represents the interface's virtual endpoint 2, (KUsbcEndpoint2Bit) etc. + bit value 0 - not stalled, + bit value 1 - stalled. + */ + inline void EndpointStatusNotify(TRequestStatus& aStatus, TUint& aEndpointMask); + + /** Completes an endpoint status notify request. + */ + inline void EndpointStatusNotifyCancel(); + + /** Get current on-the-go features relating to the ability of device/host pair to + perform OTG role swap. + + @param aFeatures On return it contains features the device currently has. + bit 2 represents b_hnp_enable, (KUsbOtgAttr_B_HnpEnable) + bit 3 represents a_hnp_support, (KUsbOtgAttr_A_HnpSupport) + bit 4 represents a_alt_hnp_support, (KUsbOtgAttr_A_AltHnpSupport) + @return KErrNone if successful, KErrNotSupported if OTG is not supported by + this device, otherwise system-wide error returns. + */ + inline TInt GetOtgFeatures(TUint8& aFeatures); + + /** Register for notification on USB on-the-go features' change. If any OTG feature + is changed, request completes and current feature value is filled in aValue. + + @param aStatus Request status object. + @param aValue On request completion, contains current OTG feature value. + */ + inline void OtgFeaturesNotify(TRequestStatus& aStatus, TUint8& aValue); + + /** Cancel pending OTG feature request. + */ + inline void OtgFeaturesNotifyCancel(); + + /** This function retrieves the alternate setting that the WriteData function can + write to. After a host sets the alternate setting, writes to the IN endpoint + are not permitted by the LDD until this method has been called. + This function is not asynchronous nor blocking, and should not be used to + detect that an alternate setting has happened. + + If the BIL methods are being used (recommended), then this method should not be called directly. + + @return The alternative setting number or KErrInUse if the current alternative + setting is already in use, that is to say that the alternative setting has not changed. + */ + inline TInt StartNextInAlternateSetting(); + + + /*******************************\ + * Buffer Interface Layer (BIL) * + \*******************************/ + + // This following functions, as well as the ones in TEndpointBuffer (below), + // can be considered the BIL. + + + /** + Finalize the interface, creating a chunk for use with reading/writing to endpoints. + FinalizeInterface should be called after all alternate interfaces have been set up with SetInteface. + Any attempt to call SetInterface after this stage will fail. + + @return KErrNone if operation is successfull + System wide error codes if chunk creation failed + */ + IMPORT_C TInt FinalizeInterface(); + + /** + Finalize the interface, creating a chunk for use with reading/writing to endpoints. This + version of the method provides a handle to the chunk, which is needed if the + buffer is to be passed and used by other processes. + FinalizeInterface should be called after all alternate interfaces have been set up with SetInteface. + Any attempt to call SetInterface after this stage will fail. + + @param aChunk On success aChunk points to the created chunk. + @return KErrNone if operation is successfull + System wide error codes if chunk creation failed + */ + IMPORT_C TInt FinalizeInterface(RChunk*& aChunk); + + /** + Opens an endpoint, an endpoint should be opened before any operations are attempted on it. + + @param aEpB On success aEpB will be filled with the relevant details for that endpoint + @param aEpI endpoint number to be opened + @return KErrNone if operation is successfull + KErrNotFound if endpoint number is not valid for current alternate setting + KErrInUse if endpoint is already opened + KErrArgument if endpoint buffer argument passed is already in existence and being used + */ + IMPORT_C TInt OpenEndpoint(TEndpointBuffer & aEpB, TInt aEpI); + + /** + Switches to processing from one Alternate setting to the next. All open endpoints (except EP0) must + be close before this can be called. + + @param aFlush If ETrue, the method will purge the buffers of any data unread for the old setting. + If each endpoint was not read up until KErrEof was reached, then this should be set. + + @return the alternate Setting if operation is successful + KErrInUse if any endpoints in present alternate setting is still open (except Ep0) + KErrNotReady if there is no change in alternate setting + KErrInUse if StartNextInAlternateSetting detects no change in alternate setting. + KErrCorrupt if the buffer structure becomes corrupt. + */ + IMPORT_C TInt StartNextOutAlternateSetting(TBool aFlush); + + /** + Sets aChunk to RChunk currently in use by BIL. + + @param aChunk aChunk will point to RChunk currently in use by BIL + @return KErrNone on success otherwise a system wide error code, if an error has occurred. + */ + IMPORT_C TInt GetDataTransferChunk(RChunk*& aChunk); + +private: + /** @internalTechnology */ + TInt Drain(TUint aBuffer); + /** @internalTechnology */ + TInt Peek(TUint aBuffer); + /** @internalTechnology */ + TInt FindNextAlternateSetting(); + +private: + TUint8 iEndpointStatus; /** @internalTechnology Each bit corresponds to each endpoint's open/close status. */ + RChunk iSharedChunk; /** @internalTechnology The shared chunk in use. */ + TInt iAltSettingSeq; /** @internalTechnology Used to track alternate setting changes. */ + TInt iAlternateSetting; /** @internalTechnology The alternate setting used by OUT endpoints, which may lag that of IN endpoints. */ + TInt iNewAltSetting; /** @internalTechnology Used to track the next alternate setting change on OUT endpoints, + during transition from one to the next. */ + TInt iInAltSetting; /** @internalTechnology The alternate setting used by IN endpoints, which may be ahead of OUT endpoints. */ + + + friend class TEndpointBuffer; +#endif // #ifndef __KERNEL_MODE__ + }; + +#ifndef __KERNEL_MODE__ + + +/** + This class forms part of the Buffer Interface Layer (BIL), which forms the + user side component of the USB Shared Chunk Client. Objects of this type + represent the shared chunk buffer, for a given endpoint. + The method RDevUsbcScClient::OpenEndpoint() should be used to initialise + objects of this type. +*/ +class TEndpointBuffer + { +public: + + /** + This return value used by GetBuffer indicates that the item pointed to by + aBuffer/aOffset represents a state change, instead of endpoint data. + */ + const static TInt KStateChange = 0x01; + +public: + IMPORT_C TEndpointBuffer(); + + /** + Read the next block of data from the Shared chunk buffer. This method should be used if the user wishes to process one block of data at a time. + This method also expires the previously read block, meaning that the memory used by the block of data may be re-used by the system, overwriting it + with new data. + @param aBuffer aBuffer will point to data location in shared chunk + @param aSize aSize will hold the number of valid bytes that can be read + @param aZLP aZLP will indicate whether its a short packet or not + @param aStatus In case of no data available to be read, aStatus will be passed on to LDD, and user side should wait for + asynchronous call ReadDataNotify to return + @param aLength Not used at the moment + @return KErrCompletion if operation is successfull and data is available in the buffer + KErrNone if no data is available to be read + KErrEof if alternate setting has changed + KErrAccessDenied if endpoint is not opened + KErrNotSupported if its an IN endpoint + TEndpointBuffer::KStateChange if the returned data represents a state change (Ep0 only) + */ + IMPORT_C TInt GetBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength=0); + + /** + Read the next block of data from the Shared chunk buffer. This method should be used if the user wishes to process one block of data at a time. + This method also expires the previously read block, meaning that the memory used by the block of data may be re-used by the system, overwriting it + with new data. + @param aOffset aOffset will point to data offset in shared chunk + @param aSize aSize will hold the number of valid bytes that can be read + @param aZLP aZLP will indicate whether its a short packet or not + @param aStatus In case of no data available to be read, aStatus will be passed on to LDD, and user side should wait for + asynchronous call ReadDataNotify to return + @param aLength Not used at the moment + @return KErrCompletion if operation is successfull and data is available in the buffer + KErrNone if no data is available to be read + KErrEof if alternate setting has changed + KErrAccessDenied if endpoint is not opened + KErrNotSupported if its an IN endpoint + TEndpointBuffer::KStateChange if the returned data represents a state change (Ep0 only) + */ + inline TInt GetBuffer(TUint& aOffset,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength=0); + + /** + Read the next block of data from the Shared chunk buffer. This method should be used if the user wishes to process more than one block of data + simultaneously. The user must call one of the Expire() methods to free the memory used by the block of data, and make it available for new data. + @param aBuffer aBuffer will point to data location in shared chunk + @param aSize aSize will hold the number of valid bytes that can be read + @param aZLP aZLP will indicate whether its a short packet or not + @param aStatus In case of no data available to be read, aStatus will be passed on to LDD, and user side should wait for + asynchronous call ReadDataNotify to return + @param aLength Not used at the moment + @return KErrCompletion if operation is successfull and data is available in the buffer + KErrNone if no data is available to be read + KErrEof if alternate setting has changed + KErrAccessDenied if endpoint is not opened + KErrNotSupported if its an IN endpoint + TEndpointBuffer::KStateChange if the returned data represents a state change (Ep0 only) + */ + IMPORT_C TInt TakeBuffer(TAny*& aBuffer,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength=0); + + /** + Used in conjunction with TakeBuffer method. This will make the 'oldest' block of data previously read out using the TakeBuffer method, but not + already expired, to be released back to the system. This block can then be overwritten with new data, when it becomes available. + @return KErrNotSupported if its an IN endpoint + KErrNone if iTail is successfully bumped to the next transfer to be read + */ + + IMPORT_C TInt Expire(); + + /** + Used in conjunction with TakeBuffer method. This function allows blocks to be expired in a different order from which the user read the data out + of the buffer. Note that the system will only reuse blocks up to the point of the oldest non-expired block read. This means that the user must + ensure to expire all blocks in a timely manner to prevent the system from running out of usable memory. + @param aAddress aAddress is the start address of the block of data previously read by the user which can be overwritten. + @return KErrNotSupported if its an IN endpoint + KErrNone if iTail is successfully bumped to the next transfer to be read + KErrNotFound if a 'transfer' with start address of the data block is aAddress is not found + */ + + IMPORT_C TInt Expire(TAny* aAddress); + + /** + Initiates write operation. + @param aBuffer aBuffer will point to data in shared chunk to be written out. aBuffer should be aligned + @param aSize aSize will hold the number of valid bytes to be written out + @param aZLP aZLP will indicate whether a ZLP should be transmitted after writing the data out + @param aStatus This is an asynchronous function and user side should wait on status to know the end of write operation + @return KErrNone if a write is successfully queued + KErrEof if an alternate setting change has occurred, ending this endpoint. + KErrNotSupported if its an OUT endpoint + KErrAccessDenied if endpoint is not opened, or if buffer is out of range + */ + IMPORT_C TInt WriteBuffer(TAny* aBuffer,TUint aSize,TBool aZLP,TRequestStatus& aStatus); + + /** + Initiates write operation. + @param aOffset aOffset will point to offset of data in shared chunk to be written out. + @param aSize aSize will hold the number of valid bytes to be written out + @param aZLP aZLP will indicate whether a ZLP should be transmitted after writing the data out + @param aStatus This is an asynchronous function and user side should wait on status to know the end of write operation + @return KErrNone if a write is successfully queued + KErrEof if an alternate setting change has occurred, ending this endpoint. + KErrNotSupported if its an OUT endpoint + KErrAccessDenied if endpoint is not opened, or if buffer is out of range + */ + IMPORT_C TInt WriteBuffer(TUint aOffset,TUint aSize,TBool aZLP,TRequestStatus& aStatus); + /** + For IN endpoints, this method retrieves the geometry for the buffer, for which the + caller should stay within, when using the WriteBuffer method. + + @param aStart A pointer, which is set to point to the start of the buffer. + @param aSize An TUint for which the size (in bytes) of buffer, is written into. + + @returns KErrNotSupported if the object is on an open IN endpoint, + otherwise it KErrNone is returned on success. + */ + IMPORT_C TInt GetInBufferRange(TAny*& aStart, TUint& aSize); + + /** + For IN endpoints, this method retrieves the geometry for the buffer, for which the + caller should stay within, when using the WriteBuffer method. + + @param aStart A TUint for which the buffer's start offset from the start of the chunk, + in written into. + @param aSize An TUint for which the size (in bytes) of buffer, is written into. + + @returns KErrNotSupported if the object is on an open IN endpoint, + otherwise it KErrNone is returned on success. + */ + IMPORT_C TInt GetInBufferRange(TUint& aStart, TUint& aSize); + + /** + This method closes the endpoint, after it was opened with + RDevUsbcScClient::OpenEndpoint(...). + No method of this object can be used after this call, until + RDevUsbcScClient::OpenEndpoint(...) is called on it again. + + @return KErrNone on success, otherwise KErrNotFound, if the current object is not open. + */ + IMPORT_C TInt Close(); + + IMPORT_C void Dump(); + + /** + Used to retrieve the endpoint number for which this object was open on. + + @returns the endpoint number opened by this object. + */ + inline TInt GetEndpointNumber(); + +private: + /** @internalTechnology */ + void Construct(RDevUsbcScClient* aClient, TUint8* aBaseAddr, const TUsbcScHdrEndpointRecord* aEpType, + TInt aEndpointNumber, SUsbcScBufferHeader* aEndpointHdr=NULL); + +private: + enum TDir {EValid = KErrNone, ENotValid = KErrNotSupported, EEOF = KErrEof}; + TDir iInState; /** @internalTechnology describes state of endpoint, KErrNone if IN endpoint and ready to use, KErrNotSupportd if not an IN endpoint, KErrEof on alternate setting change */ + TDir iOutState; /** @internalTechnology describes state of endpoint, KErrNone if OUT endpoint and ready to use, KErrNotSupportd if not an OUT endpoint, KErrEoF on alternate setting change */ + TInt iEndpointNumber; /** @internalTechnology associated endpoint number */ + TInt iBufferNum; /** @internalTechnology buffer number within shared chunk */ + RDevUsbcScClient *iClient; /** @internalTechnology Parent RDevUsbcScClient object */ + TUint iBaseAddr; /** @internalTechnology The address of the beginning of the Ldd's chunk */ + + SUsbcScBufferHeader* iEndpointHdr; /** @internalTechnology Pointer to the buffer Header for OUT/BI endpoints */ + TUint8* iBufferStartAddr; /** @internalTechnology IN/BI endpoint buffer start address within shared chunk */ + TUint iSize; /** @internalTechnology IN/BI endpoint buffer size within shared chunk */ + friend class RDevUsbcScClient; + }; + +/** +This class can be used to retrieve the geometry of the structures +within a shared chunk, as used by RDevUsbcScClient. + +@see RDevUsbcScClient +*/ + +class TUsbcScChunkHeader + { +public: +/** +The constructor for the TUsbcScChunkHeader class takes a RChunk object, +containing USBcSc data structures, and initialises itself, so that +GetNumberOfEndpoints & GetBuffer can be used to interpret the chunk structures. + +@param An RChunk object, which represents an shared chunk, containing the + USBcSc data structures to be retrieved. +*/ + IMPORT_C TUsbcScChunkHeader(RChunk aChunk); +/** +Retrieves the available information in the chunk, about the given endpoint, +on the given alternate setting. The returned TUsbcScBufferRecord, +represents the buffer geometry, used for for the endpoint, while +the filled in TUsbcScHdrEndpointRecord represents additional endpoint +information. + +@param aAltSetting The alternate setting, for which the provided endpoint number, is a member of. +@param aEndpoint The endpoint, who's buffer geometry is required. +@param aEndpointInf The provided record is filled in with details of the endpoint, who's number was given. +*/ + IMPORT_C TUsbcScBufferRecord* GetBuffer(TInt aAltSetting, TInt aEndpoint, TUsbcScHdrEndpointRecord*& aEndpointInf); +/** +Retrieves the number of endpoints found in a given alternate setting. +@param aAltSetting The alternate setting number, for which the number of endpoints contained within, is needed. +*/ + IMPORT_C TInt GetNumberOfEndpoints(TInt aAltSetting); + +public: + TUsbcScChunkBuffersHeader* iBuffers; /** A pointer to the TUsbcScChunkBuffersHeader object, within the chunk header */ + TUsbcScChunkAltSettingHeader* iAltSettings; /** A pointer to the TUsbcScChunkAltSettingHeader object, within the chunk header */ +private: + RChunk iChunk; + }; + +#endif + +#include + +#endif // __D32USBCSC_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbcsc.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbcsc.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,735 @@ +// 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\include\d32usbcsc.inl +// User side class definitions for USB Device support (inline header). +// +// + +/** @file d32usbcsc.inl + @publishedPartner + @released +*/ + +#ifndef __D32USBCSC_INL__ +#define __D32USBCSC_INL__ + + +/** @internalTechnology +*/ +struct TUsbcScIfcInfo + { + TUsbcScInterfaceInfoBuf* iInterfaceData; + TPtr8* iString; + TUint32 iBandwidthPriority; + }; + + +inline TUsbcScHdrEndpointRecord::TUsbcScHdrEndpointRecord(TInt aBufferNo, TUint8 aType) +: iBufferNo((TUint8)aBufferNo), + iType(aType) + { + }; + + +inline TUint TUsbcScHdrEndpointRecord::Type() const + { + return (TUint) (iType>>2); + }; + +inline TUint TUsbcScHdrEndpointRecord::Direction() const + { + return (TUint) (iType&3); + }; + + +inline void TUsbcScBufferRecord::Set(TUint aOffset, TUint aEndOffset) + { + iOffset = aOffset; + iSize = aEndOffset-aOffset; + }; + +inline TUint TUsbcScBufferRecord::Offset() const + { + return iOffset; + }; + +inline TUint TUsbcScBufferRecord::Size() const + { + return iSize; + }; + + +inline TEndpointPairInfo::TEndpointPairInfo(TUint8 aType, TUint16 aPair, TUint8 aSpare) + : iType(aType), iSpare(aSpare), iPair(aPair) + {} + + +inline TUsbcScEndpointInfo::TUsbcScEndpointInfo(TUint aType, TUint aDir, TInt aInterval, TInt aExtra, + TUint aBufferSize, TUint aReadSize +) + : TUsbcEndpointInfo(aType, aDir, 0, aInterval, aExtra), + iBufferSize(aBufferSize), iReadSize(aReadSize), iPairing(), iAlignment(0), iFlags(0) + {} + + + + +inline TUsbcScInterfaceInfo::TUsbcScInterfaceInfo(TInt aClass, TInt aSubClass, + TInt aProtocol, TDesC16* aString, + TUint aTotalEndpoints) + : iClass(aClass, aSubClass, aProtocol), iString(aString), + iTotalEndpointsUsed(aTotalEndpoints), iFeatureWord(0) + {} + + +inline TUsbcScBufferRecord* TUsbcScChunkBuffersHeader::Ep0Out() const + { + return (TUsbcScBufferRecord*) &iBufferOffset[0]; + }; +inline TUsbcScBufferRecord* TUsbcScChunkBuffersHeader::Ep0In() const + { + return (TUsbcScBufferRecord*) &iBufferOffset[iRecordSize]; + }; +inline TUsbcScBufferRecord* TUsbcScChunkBuffersHeader::Buffers(TInt aBuffer) const + { + return (TUsbcScBufferRecord*) &iBufferOffset[(aBuffer+2)*iRecordSize]; + }; + +inline TInt TUsbcScChunkBuffersHeader::NumberOfBuffers() const + { + return iNumOfBufs; + }; + + +#ifndef __KERNEL_MODE__ + + + +/** @capability CommDD +*/ +inline TInt RDevUsbcScClient::Open(TInt aUnit) + { + _LIT(KUsbDevName, "usbcsc"); + return (DoCreate(KUsbDevName, VersionRequired(), aUnit, NULL, NULL, EOwnerThread)); + } + + +inline TVersion RDevUsbcScClient::VersionRequired() const + { + return (TVersion(EMajorVersionNumber, EMinorVersionNumber, EBuildVersionNumber)); + } + + +inline TInt RDevUsbcScClient::EndpointZeroRequestError() + { + return DoControl(EControlEndpointZeroRequestError); + } + + +inline TInt RDevUsbcScClient::EndpointCaps(TDes8& aCapsBuf) + { + return DoControl(EControlEndpointCaps, &aCapsBuf); + } + + +inline TInt RDevUsbcScClient::DeviceCaps(TUsbDeviceCaps& aCapsBuf) + { + return DoControl(EControlDeviceCaps, &aCapsBuf); + } + + +inline TInt RDevUsbcScClient::GetAlternateSetting(TInt &aInterfaceNumber) + { + return DoControl(EControlGetAlternateSetting, &aInterfaceNumber); + } + + +inline TInt RDevUsbcScClient::DeviceStatus(TUsbcDeviceState &aDeviceStatus) + { + return DoControl(EControlDeviceStatus, &aDeviceStatus); + } + + +inline TInt RDevUsbcScClient::EndpointStatus(TInt aEndpoint,TEndpointState &aEndpointStatus) + { + return DoControl(EControlEndpointStatus,(TAny*) aEndpoint, &aEndpointStatus); + } + +/* +inline TInt RDevUsbcScClient::QueryReceiveBuffer(TInt aEndpoint,TInt& aNumberOfBytes) + { + return DoControl(EControlQueryReceiveBuffer, (TAny*) aEndpoint, &aNumberOfBytes); + } + +*/ +inline TInt RDevUsbcScClient::SendEp0StatusPacket() + { + return DoControl(EControlSendEp0StatusPacket); + } + + +inline TInt RDevUsbcScClient::HaltEndpoint(TInt aEndpoint) + { + return DoControl(EControlHaltEndpoint, (TAny*) aEndpoint); + } + + +inline TInt RDevUsbcScClient::ClearHaltEndpoint(TInt aEndpoint) + { + return DoControl(EControlClearHaltEndpoint, (TAny*) aEndpoint); + } + + +inline TUint RDevUsbcScClient::EndpointZeroMaxPacketSizes() + { + return DoControl(EControlEndpointZeroMaxPacketSizes); + } + + +inline TInt RDevUsbcScClient::SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize) + { + return DoControl(EControlSetEndpointZeroMaxPacketSize, (TAny*) aMaxPacketSize); + } + + +inline TInt RDevUsbcScClient::GetEndpointZeroMaxPacketSize() + { + return DoControl(EControlGetEndpointZeroMaxPacketSize); + } + + +inline TInt RDevUsbcScClient::GetDeviceDescriptor(TDes8& aDeviceDescriptor) + { + return DoControl(EControlGetDeviceDescriptor, &aDeviceDescriptor); + } + + +inline TInt RDevUsbcScClient::SetDeviceDescriptor(const TDesC8& aDeviceDescriptor) + { + return DoControl(EControlSetDeviceDescriptor, const_cast(&aDeviceDescriptor)); + } + + +inline TInt RDevUsbcScClient::GetDeviceDescriptorSize(TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetDeviceDescriptorSize, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcScClient::GetConfigurationDescriptor(TDes8& aConfigurationDescriptor) + { + return DoControl(EControlGetConfigurationDescriptor, &aConfigurationDescriptor); + } + + +inline TInt RDevUsbcScClient::SetConfigurationDescriptor(const TDesC8& aConfigurationDescriptor) + { + return DoControl(EControlSetConfigurationDescriptor, const_cast (&aConfigurationDescriptor)); + } + + +inline TInt RDevUsbcScClient::GetConfigurationDescriptorSize(TInt& aSize) + { + TPckgBuf p; + TInt r=DoControl(EControlGetConfigurationDescriptorSize, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcScClient::GetInterfaceDescriptor(TInt aSettingNumber, TDes8& aInterfaceDescriptor) + { + return DoControl(EControlGetInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor); + } + + +inline TInt RDevUsbcScClient::SetInterfaceDescriptor(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor) + { + return DoControl(EControlSetInterfaceDescriptor,(TAny*) aSettingNumber, + const_cast(&aInterfaceDescriptor)); + } + + +inline TInt RDevUsbcScClient::GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetInterfaceDescriptorSize,(TAny*) aSettingNumber, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcScClient::GetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &aEndpointDescriptor}; + return DoControl(EControlGetEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcScClient::SetEndpointDescriptor(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, const_cast(&aEndpointDescriptor)}; + return DoControl(EControlSetEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcScClient::GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize) + { + TPckgBuf p; + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &p}; + TInt r = DoControl(EControlGetEndpointDescriptorSize, &info, NULL); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline void RDevUsbcScClient::GetOtgDescriptorSize(TInt& aSize) + { + aSize = KUsbDescSize_Otg; + } + + +inline TInt RDevUsbcScClient::GetOtgDescriptor(TDes8& aOtgDesc) + { + return DoControl(EControlGetOtgDescriptor, (TAny*)&aOtgDesc); + } + + +inline TInt RDevUsbcScClient::SetOtgDescriptor(const TDesC8& aOtgDesc) + { + return DoControl(EControlSetOtgDescriptor, (TAny*)&aOtgDesc); + } + + +inline TInt RDevUsbcScClient::GetDeviceQualifierDescriptor(TDes8& aDescriptor) + { + return DoControl(EControlGetDeviceQualifierDescriptor, &aDescriptor); + } + + +inline TInt RDevUsbcScClient::SetDeviceQualifierDescriptor(const TDesC8& aDescriptor) + { + return DoControl(EControlSetDeviceQualifierDescriptor, const_cast(&aDescriptor)); + } + + +inline TInt RDevUsbcScClient::GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor) + { + return DoControl(EControlGetOtherSpeedConfigurationDescriptor, &aDescriptor); + } + + +inline TInt RDevUsbcScClient::SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor) + { + return DoControl(EControlSetOtherSpeedConfigurationDescriptor, const_cast (&aDescriptor)); + } + + +inline TInt RDevUsbcScClient::GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor) + { + return DoControl(EControlGetCSInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor); + } + + +inline TInt RDevUsbcScClient::GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize) + { + TPckgBuf p; + TInt r = DoControl(EControlGetCSInterfaceDescriptorSize,(TAny*) aSettingNumber, &p); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcScClient::GetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + TDes8& aEndpointDescriptor) + { + TEndpointDescriptorInfo info={aSettingNumber, aEndpointNumber, &aEndpointDescriptor}; + return DoControl(EControlGetCSEndpointDescriptor,&info,NULL); + } + + +inline TInt RDevUsbcScClient::GetCSEndpointDescriptorBlockSize(TInt aSettingNumber, TInt aEndpointNumber, + TInt& aSize) + { + TPckgBuf p; + TEndpointDescriptorInfo info = {aSettingNumber, aEndpointNumber, &p}; + TInt r = DoControl(EControlGetCSEndpointDescriptorSize, &info, NULL); + if (r == KErrNone) + aSize = p(); + return r; + } + + +inline TInt RDevUsbcScClient::SignalRemoteWakeup() + { + return DoControl(EControlSignalRemoteWakeup); + } + + +inline TInt RDevUsbcScClient::DeviceDisconnectFromHost() + { + return DoControl(EControlDeviceDisconnectFromHost); + } + + +inline TInt RDevUsbcScClient::DeviceConnectToHost() + { + return DoControl(EControlDeviceConnectToHost); + } + + +inline TInt RDevUsbcScClient::PowerUpUdc() + { + return DoControl(EControlDevicePowerUpUdc); + } + + +inline TBool RDevUsbcScClient::CurrentlyUsingHighSpeed() + { + return DoControl(EControlCurrentlyUsingHighSpeed); + } + + +inline TInt RDevUsbcScClient::SetInterface(TInt aInterfaceNumber, TUsbcScInterfaceInfoBuf& aInterfaceData) + { + TPtr8 name_8(NULL,0); + TUsbcScIfcInfo ifcinfo; + ifcinfo.iInterfaceData = const_cast(&aInterfaceData); + if (!aInterfaceData().iString) + { + ifcinfo.iString = NULL; + } + else + { + name_8.Set(const_cast(reinterpret_cast(aInterfaceData().iString->Ptr())), + aInterfaceData().iString->Size(), aInterfaceData().iString->Size()); + ifcinfo.iString = &name_8; + } + return DoControl(EControlSetInterface, (TAny*)aInterfaceNumber, &ifcinfo); + } + +inline TInt RDevUsbcScClient::RealizeInterface(RChunk& aChunk) + { + return aChunk.SetReturnedHandle(DoControl(EControlRealizeInterface)); + } + + +inline TInt RDevUsbcScClient::ReleaseInterface(TInt aInterfaceNumber) + { + return DoControl(EControlReleaseInterface, (TAny*)aInterfaceNumber); + } + + +inline TInt RDevUsbcScClient::SetCSInterfaceDescriptorBlock(TInt aSettingNumber, const TDesC8& aInterfaceDescriptor) + { + TCSDescriptorInfo info = {aSettingNumber, 0, const_cast(&aInterfaceDescriptor), + aInterfaceDescriptor.Size()}; + return DoControl(EControlSetCSInterfaceDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcScClient::SetCSEndpointDescriptorBlock(TInt aSettingNumber, TInt aEndpointNumber, + const TDesC8& aEndpointDescriptor) + { + TCSDescriptorInfo info = {aSettingNumber, aEndpointNumber, const_cast(&aEndpointDescriptor), + aEndpointDescriptor.Size()}; + return DoControl(EControlSetCSEndpointDescriptor, &info, NULL); + } + + +inline TInt RDevUsbcScClient::SetDeviceControl() + { + return DoControl(EControlSetDeviceControl); + } + + +inline TInt RDevUsbcScClient::ReleaseDeviceControl() + { + return DoControl(EControlReleaseDeviceControl); + } + + +inline TInt RDevUsbcScClient::GetStringDescriptorLangId(TUint16& aLangId) + { + TPckgBuf p; + const TInt r = DoControl(EControlGetStringDescriptorLangId, &p); + if (r == KErrNone) + aLangId = p(); + return r; + } + + +inline TInt RDevUsbcScClient::SetStringDescriptorLangId(TUint16 aLangId) + { + return DoControl(EControlSetStringDescriptorLangId, (TAny*)(TUint)aLangId); + } + + +inline TInt RDevUsbcScClient::GetManufacturerStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetManufacturerStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcScClient::SetManufacturerStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetManufacturerStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcScClient::RemoveManufacturerStringDescriptor() + { + return DoControl(EControlRemoveManufacturerStringDescriptor); + } + + +inline TInt RDevUsbcScClient::GetProductStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetProductStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcScClient::SetProductStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetProductStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcScClient::RemoveProductStringDescriptor() + { + return DoControl(EControlRemoveProductStringDescriptor); + } + + +inline TInt RDevUsbcScClient::GetSerialNumberStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetSerialNumberStringDescriptor, &name_8); + aString.SetLength(name_8.Size()/2); + return r; + } + + +inline TInt RDevUsbcScClient::SetSerialNumberStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetSerialNumberStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcScClient::RemoveSerialNumberStringDescriptor() + { + return DoControl(EControlRemoveSerialNumberStringDescriptor); + } + + +inline TInt RDevUsbcScClient::GetConfigurationStringDescriptor(TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetConfigurationStringDescriptor, &name_8); + aString.SetLength(name_8.Size() / 2); + return r; + } + + +inline TInt RDevUsbcScClient::SetConfigurationStringDescriptor(const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetConfigurationStringDescriptor, &name_8); + } + + +inline TInt RDevUsbcScClient::RemoveConfigurationStringDescriptor() + { + return DoControl(EControlRemoveConfigurationStringDescriptor); + } + + +inline TInt RDevUsbcScClient::GetStringDescriptor(TUint8 aIndex, TDes16& aString) + { + TPtr8 name_8(const_cast(reinterpret_cast(aString.Ptr())), aString.MaxSize()); + const TInt r = DoControl(EControlGetStringDescriptor, (TAny*)(TUint)aIndex, &name_8); + aString.SetLength(name_8.Size() / 2); + return r; + } + + +inline TInt RDevUsbcScClient::SetStringDescriptor(TUint8 aIndex, const TDesC16& aString) + { + TPtrC8 name_8(reinterpret_cast(aString.Ptr()), aString.Size()); + return DoControl(EControlSetStringDescriptor, (TAny*)(TUint)aIndex, &name_8); + } + + +inline TInt RDevUsbcScClient::RemoveStringDescriptor(TUint8 aIndex) + { + return DoControl(EControlRemoveStringDescriptor, (TAny*)(TUint)aIndex); + } + + +inline TInt RDevUsbcScClient::AllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlAllocateEndpointResource, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline TInt RDevUsbcScClient::DeAllocateEndpointResource(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlDeAllocateEndpointResource, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline TBool RDevUsbcScClient::QueryEndpointResourceUse(TInt aEndpoint, TUsbcEndpointResource aResource) + { + return DoControl(EControlQueryEndpointResourceUse, (TAny*)aEndpoint, (TAny*)aResource); + } + + +inline TInt RDevUsbcScClient::ReadDataNotify(TInt aBufferNumber, TRequestStatus& aStatus, TInt aLength) + { + TAny *a[2]; + a[0]=(TAny*) aBufferNumber; + a[1]=(TAny*) aLength; + aStatus=KRequestPending; + TInt r = DoControl(~ERequestReadDataNotify, &aStatus, &a[0]); + if (r) + aStatus=r; + return r; + } + + + +inline void RDevUsbcScClient::WriteData(TInt aBufferNumber, TUint aStart, TUint aLength, TUint aFlags, TRequestStatus& aStatus) + { + DoRequest( ERequestWriteData | ((aBufferNumber&KFieldBuffMask) << KFieldBuffPos) | ((aFlags&KFieldFlagsMask) << KFieldFlagsPos), + aStatus, (TAny*) aStart, (TAny*) aLength); + } + + + +inline void RDevUsbcScClient::AlternateDeviceStatusNotify(TRequestStatus& aStatus, TUint& aValue) + { + DoRequest(ERequestAlternateDeviceStatusNotify, aStatus, &aValue); + } + + +inline void RDevUsbcScClient::ReEnumerate(TRequestStatus& aStatus) + { + DoRequest(ERequestReEnumerate, aStatus); + } + + +inline void RDevUsbcScClient::EndpointStatusNotify(TRequestStatus& aStatus, TUint& aEndpointMask) + { + DoRequest(ERequestEndpointStatusNotify, aStatus, &aEndpointMask); + } + + +inline void RDevUsbcScClient::ReadCancel(TInt aBuffer) + { + DoControl(ERequestReadDataNotifyCancel, (TAny*) aBuffer); + } + + +inline void RDevUsbcScClient::WriteCancel(TInt aBuffer) + { + DoControl(ERequestWriteDataCancel, (TAny*) aBuffer); + } + + +inline void RDevUsbcScClient::EndpointTransferCancel(TUint aBufferMask) + { + DoControl(ERequestCancel, (TAny*) aBufferMask); + } + + +inline void RDevUsbcScClient::AlternateDeviceStatusNotifyCancel() + { + DoControl(ERequestAlternateDeviceStatusNotifyCancel); + } + + +inline void RDevUsbcScClient::ReEnumerateCancel() + { + DoControl(ERequestReEnumerateCancel); + } + + +inline void RDevUsbcScClient::EndpointStatusNotifyCancel() + { + DoControl(ERequestEndpointStatusNotifyCancel); + } + +inline TInt RDevUsbcScClient::GetOtgFeatures(TUint8& aFeatures) + { + TPckgBuf p; + TInt r = DoControl(EControlGetOtgFeatures, &p); + if (r == KErrNone) + aFeatures = p(); + return r; + } + + +inline void RDevUsbcScClient::OtgFeaturesNotify(TRequestStatus& aStatus, TUint8& aValue) + { + DoRequest(ERequestOtgFeaturesNotify, aStatus, &aValue); + } + +inline void RDevUsbcScClient::OtgFeaturesNotifyCancel() + { + DoControl(ERequestOtgFeaturesNotifyCancel); + } + +inline TInt RDevUsbcScClient::StartNextInAlternateSetting() + { + return DoControl(EControlStartNextInAlternateSetting); + } + +//Buffer Interface Layer (BIL) inline functions + + +inline TInt TEndpointBuffer::GetBuffer(TUint& aOffset,TUint& aSize,TBool& aZLP,TRequestStatus& aStatus,TUint aLength) + { + TInt r = GetBuffer(aOffset,aSize,aZLP,aStatus,aLength); + aOffset -= iBaseAddr; + return r; + }; + + +inline TInt TEndpointBuffer::GetEndpointNumber() + { + return iEndpointNumber; + } + +#endif // #ifndef __KERNEL_MODE__ + +#endif // #ifndef __D32USBCSC_INL__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbcshared.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbcshared.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,338 @@ +// Copyright (c) 2008-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/include/d32usbcshared.h +// User side class definitions for USB Device support. +// +// + +/** + @file d32usbcshared.h + @publishedPartner + @released +*/ + +#ifndef __D32USBCSHARED_H__ +#define __D32USBCSHARED_H__ + +#include + +// FIXME: for dummy dcd compitible, move this line to usbcshared.h +// used by shared chunk version LDD's user app interface +typedef TInt TUsbcDeviceState; + +// USB driver error codes + +/** USB driver specific error codes start from here +*/ +const TInt KErrUsbDriverBase = -6701; + +/** Attempt at data transfer, or something interface related, + when neither an Interface has been set up nor Device Control is owned by + the channel +*/ +const TInt KErrUsbInterfaceNotReady = -6702; + +/** Attempt at data transfer on an endpoint that does not belong to the active interface +*/ +const TInt KErrUsbEpNotInInterface = -6703; + +/** Attempt at data transfer in a direction not supported by the endpoint +*/ +const TInt KErrUsbEpBadDirection = -6704; + +/** The data transfer size specified exceeds that of the source or + destination buffer descriptor +*/ +const TInt KErrUsbTransferSize = -6705; + +/** This has multiple uses: + 1) User request completed because device is no longer in configured state + 2) Something endpoint related, stall, unstall, status enquiry etc, + that requires the device to be configured +*/ +const TInt KErrUsbDeviceNotConfigured = -6706; + +/** Requested endpoint properties inconsistent during Interface setup +*/ +const TInt KErrUsbBadEndpoint = -6707; + +/** User data request completed because channel is closing (channel destructor called) +*/ +const TInt KErrUsbDeviceClosing = -6708; + +/** User data request completed because current endpoint set is being + replaced since alternate setting is changing +*/ +const TInt KErrUsbInterfaceChange = -6709; + +/** User data request completed because cable has been detached (or equivalent) +*/ +const TInt KErrUsbCableDetached = -6710; + +/** User data request completed because cable has been detached (or equivalent) +*/ +const TInt KErrUsbDeviceBusReset = -6711; + +/** This means that read data is still available when a write request is made. + Relates to bidirectional eps only (ep0). + A bidirectional ep must consume all of its read data before attempting to write. +*/ +const TInt KErrUsbEpNotReady = -6712; + +// FIXME: REMOVE THIS GUY, ONCE DUMMY DCD is modified according to new SHAI. +const TInt EUsbcDeviceStateUndefined = UsbShai::EUsbPeripheralStateUndefined; // 0 +const TInt EUsbcDeviceStateAttached = UsbShai::EUsbPeripheralStateAttached; // 1 +const TInt EUsbcDeviceStatePowered = UsbShai::EUsbPeripheralStatePowered;// 2 +const TInt EUsbcDeviceStateDefault = UsbShai::EUsbPeripheralStateDefault;// 3 +const TInt EUsbcDeviceStateAddress = UsbShai::EUsbPeripheralStateAddress; // 4 +const TInt EUsbcDeviceStateConfigured = UsbShai::EUsbPeripheralStateConfigured;// 5 +const TInt EUsbcDeviceStateSuspended = UsbShai::EUsbPeripheralStateSuspended;// 6 +const TInt EUsbcNoState = UsbShai::EUsbPeripheralNoState; // 255 (used as a place holder) + +/** The endpoint states. + + @see RDevUsbcClient::EndpointStatus() + @see RDevUsbcClient::EndpointStatusNotify() +*/ +enum TEndpointState + { + EEndpointStateNotStalled, + EEndpointStateStalled, + EEndpointStateUnknown + }; + +class TUsbcEndpointCaps : public UsbShai::TUsbPeripheralEndpointCaps + { + public: + /** Returns the greatest available packet size for this endpoint. */ + TInt MaxPacketSize() const; + /** Returns the smallest available packet size for this endpoint. */ + TInt MinPacketSize() const; + }; + +/** Endpoint resources/behaviours. + + @see AllocateEndpointResource() + @see DeAllocateEndpointResource() + @see QueryEndpointResourceUse() +*/ +enum TUsbcEndpointResource + { + /** Requests the use of DMA. */ + EUsbcEndpointResourceDMA = 0, + /** Requests the use of double FIFO buffering. */ + EUsbcEndpointResourceDoubleBuffering = 1 + }; + +const TUint KUsbcEndpointInfoFeatureWord1_DMA = UsbShai::KUsbEndpointInfoFeatureWord1_DMA; +const TUint KUsbcEndpointInfoFeatureWord1_DoubleBuffering = UsbShai::KUsbEndpointInfoFeatureWord1_DoubleBuffering; + +/** The USB client device capability class. +*/ +class TCapsDevUsbc + { + public: + /** The device version. */ + TVersion version; + }; + +/** The maximum number of endpoints supported by the device, excluding ep0. +*/ +const TInt KUsbcMaxEndpoints = 30; + +/** The maximum number of endpoints per interface, excluding ep0. +*/ +const TInt KMaxEndpointsPerClient = 5; + +/** @internalComponent +*/ +const TInt KInvalidEndpointNumber = 31; + +/** The alternate setting flag; when this bit is set the state change notified by + RDevUsbcClient::AlternateDeviceStatusNotify() is an alternate setting number. +*/ +const TUint KUsbAlternateSetting = 0x80000000; + +/** The USB cable detection feature flag; used by TUsbDeviceCapsV01::iFeatureWord1. + When this bit is set then the USB controller hardware (UDC) supports detection + of a plugged-in USB cable even when not powered. + + @see TUsbDeviceCapsV01 +*/ +const TUint KUsbDevCapsFeatureWord1_CableDetectWithoutPower = 0x00000001; + +/** If this flag is set then the driver supports the new endpoint resource + allocation scheme for DMA and Double-buffering via + TUsbcEndpointInfo::iFeatureWord1. + + @see TUsbDeviceCapsV01 +*/ +const TUint KUsbDevCapsFeatureWord1_EndpointResourceAllocV2 = 0x00000002; + + +/** Device USB capabilities. +*/ +class TUsbDeviceCapsV01 + { +public: + /** The total number of endpoints on the device. */ + TInt iTotalEndpoints; + /** Indicates whether the device supports software connect/disconnect. */ + TBool iConnect; + /** Indicates whether the device is self powered. */ + TBool iSelfPowered; + /** Indicates whether the device can send Remote Wakeup. */ + TBool iRemoteWakeup; + /** Indicates whether the device supports High-speed mode. */ + TBool iHighSpeed; + /** 32 flag bits indicating miscellaneous UDC/device features. + Currently defined are: + - KUsbDevCapsFeatureWord1_CableDetectWithoutPower = 0x00000001 + - KUsbDevCapsFeatureWord1_EndpointResourceAllocV2 = 0x00000002 + */ + TUint32 iFeatureWord1; + /** Reserved for future use. */ + TUint32 iReserved; + }; + +/** Package buffer for a TUsbDeviceCapsV01 object. + + @see TUsbDeviceCapsV01 +*/ +typedef TPckgBuf TUsbDeviceCaps; + +/** Bitmaps for TUsbcEndpointCaps.iSizes. + + This endpoint is not available (= no size). +*/ +const TUint KUsbEpNotAvailable = 0x00000000; +/** Max packet size is continuously variable up to some size specified. + (Interrupt and Isochronous endpoints only.) +*/ +const TUint KUsbEpSizeCont = 0x00000001; +/** Max packet size 8 bytes is supported +*/ +const TUint KUsbEpSize8 = 0x00000008; +/** Max packet size 16 bytes is supported +*/ +const TUint KUsbEpSize16 = 0x00000010; +/** Max packet size 32 bytes is supported +*/ +const TUint KUsbEpSize32 = 0x00000020; +/** Max packet size 64 bytes is supported +*/ +const TUint KUsbEpSize64 = 0x00000040; +/** Max packet size 128 bytes is supported +*/ +const TUint KUsbEpSize128 = 0x00000080; +/** Max packet size 256 bytes is supported +*/ +const TUint KUsbEpSize256 = 0x00000100; +/** Max packet size 512 bytes is supported +*/ +const TUint KUsbEpSize512 = 0x00000200; +/** Max packet size 1023 bytes is supported +*/ +const TUint KUsbEpSize1023 = 0x00000400; +/** Max packet size 1024 bytes is supported +*/ +const TUint KUsbEpSize1024 = 0x00000800; + +/** Bitmaps for TUsbcEndpointCaps.iSupportedTypesAndDir. + + Endpoint supports Control transfer type. +*/ +const TUint KUsbEpTypeControl = UsbShai::KUsbEpTypeControl; +/** Endpoint supports Isochronous transfer type. +*/ +const TUint KUsbEpTypeIsochronous = UsbShai::KUsbEpTypeIsochronous; +/** Endpoint supports Bulk transfer type. +*/ +const TUint KUsbEpTypeBulk = UsbShai::KUsbEpTypeBulk; +/** Endpoint supports Interrupt transfer type. +*/ +const TUint KUsbEpTypeInterrupt = UsbShai::KUsbEpTypeInterrupt; +/** Endpoint supports IN transfers. +*/ +const TUint KUsbEpDirIn = UsbShai::KUsbEpDirIn; +/** Endpoint supports OUT transfers. +*/ +const TUint KUsbEpDirOut = UsbShai::KUsbEpDirOut; +/** Endpoint supports bidirectional (Control) transfers only. +*/ +const TUint KUsbEpDirBidirect = UsbShai::KUsbEpDirBidirect; + + +/** Converts an absolute size value into a KUsbEpSize... mask. +*/ +static inline TUint PacketSize2Mask(TInt aSize); + +/** Converts an endpoint type mask KUsbEpType... into an endpoint attribute + value KUsbEpAttr_.... +*/ +static inline TUint EpTypeMask2Value(TInt aType); + + +/** Endpoint capabilities as returned by RDevUsbcClient::EndpointCaps(). +*/ +class TUsbcEndpointData + { +public: + /** Detail of endpoint capabilities. */ + TUsbcEndpointCaps iCaps; + /** Indicates whether this endpoint is already claimed. */ + TBool iInUse; + }; + +class TUsbcEndpointInfo : public UsbShai::TUsbPeripheralEndpointInfo + { + public: + TUsbcEndpointInfo(TUint aType=UsbShai::KUsbEpTypeBulk, TUint aDir=UsbShai::KUsbEpDirOut, + TInt aSize=0, TInt aInterval=0, TInt aExtra=0); + + TInt AdjustEpSizes(TInt& aEpSize_Fs, TInt& aEpSize_Hs) const; + + TInt AdjustPollInterval(); + }; + +/** USB Class information used in RDevUsbcClient::SetInterface(). +*/ +class TUsbcClassInfo + { +public: + TUsbcClassInfo(TInt aClass=0, TInt aSubClass=0, TInt aProtocol=0); +public: + /** The class type number. */ + TInt iClassNum; + /** The sub-class type number. */ + TInt iSubClassNum; + /** The protocol number. */ + TInt iProtocolNum; + /** Reserved for future use. */ + TUint32 iReserved; + }; + + +/** The Ep0 Setup request 'unsubscribe' flag; used by + TUsbcInterfaceInfo::iFeatureWord. When this bit is set then valid vendor- + or class-specific Ep0 requests addressed to this interface or any of its + endpoints will be stalled by the USB PDD PIL. + + @see TUsbcInterfaceInfo +*/ +const TUint KUsbcInterfaceInfo_NoEp0RequestsPlease = 0x00000001; + +#include + +#endif diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbcshared.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbcshared.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,145 @@ +// Copyright (c) 2008-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/include/d32usbcshared.inl +// User side class definitions for USB Device support. +// +// + +/** + @file d32usbcshared.inl + @publishedPartner + @released +*/ + +#ifndef __D32USBCSHARED_INL__ +#define __D32USBCSHARED_INL__ + +inline TInt MaxEndpointPacketSize(TInt aSizes) + { + return (aSizes & KUsbEpSize1024) ? 1024 : + ((aSizes & KUsbEpSize1023) ? 1023 : + ((aSizes & KUsbEpSize512) ? 512 : + ((aSizes & KUsbEpSize256) ? 256 : + ((aSizes & KUsbEpSize128) ? 128 : + ((aSizes & KUsbEpSize64) ? 64 : + ((aSizes & KUsbEpSize32) ? 32 : + ((aSizes & KUsbEpSize16) ? 16 : + ((aSizes & KUsbEpSize8) ? 8 : 0)))))))); + } + + +inline TInt MinEndpointPacketSize(TInt aSizes) + { + return (aSizes & KUsbEpSize8) ? 8 : + ((aSizes & KUsbEpSize16) ? 16 : + ((aSizes & KUsbEpSize32) ? 32 : + ((aSizes & KUsbEpSize64) ? 64 : + ((aSizes & KUsbEpSize128) ? 128 : + ((aSizes & KUsbEpSize256) ? 256 : + ((aSizes & KUsbEpSize512) ? 512 : + ((aSizes & KUsbEpSize1023) ? 1023 : + ((aSizes & KUsbEpSize1024) ? 1024 : 0)))))))); + } + +inline TInt TUsbcEndpointCaps::MaxPacketSize() const + { + return (iSizes & KUsbEpSize1024) ? 1024 : + ((iSizes & KUsbEpSize1023) ? 1023 : + ((iSizes & KUsbEpSize512) ? 512 : + ((iSizes & KUsbEpSize256) ? 256 : + ((iSizes & KUsbEpSize128) ? 128 : + ((iSizes & KUsbEpSize64) ? 64 : + ((iSizes & KUsbEpSize32) ? 32 : + ((iSizes & KUsbEpSize16) ? 16 : + ((iSizes & KUsbEpSize8) ? 8 : 0)))))))); + } + + +inline TInt TUsbcEndpointCaps::MinPacketSize() const + { + return (iSizes & KUsbEpSize8) ? 8 : + ((iSizes & KUsbEpSize16) ? 16 : + ((iSizes & KUsbEpSize32) ? 32 : + ((iSizes & KUsbEpSize64) ? 64 : + ((iSizes & KUsbEpSize128) ? 128 : + ((iSizes & KUsbEpSize256) ? 256 : + ((iSizes & KUsbEpSize512) ? 512 : + ((iSizes & KUsbEpSize1023) ? 1023 : + ((iSizes & KUsbEpSize1024) ? 1024 : 0)))))))); + } + +static inline TUint PacketSize2Mask(TInt aSize) + { + return (aSize == 8) ? KUsbEpSize8 : + ((aSize == 16) ? KUsbEpSize16 : + ((aSize == 32) ? KUsbEpSize32 : + ((aSize == 64) ? KUsbEpSize64 : + ((aSize == 128) ? KUsbEpSize128 : + ((aSize == 256) ? KUsbEpSize256 : + ((aSize == 512) ? KUsbEpSize512 : + ((aSize == 1023) ? KUsbEpSize1023 : + ((aSize == 1024) ? KUsbEpSize1024 : 0)))))))); + } + + +static inline TUint EpTypeMask2Value(TInt aType) + { + return (aType & UsbShai::KUsbEpTypeControl) ? KUsbEpAttr_TransferTypeControl : + ((aType & UsbShai::KUsbEpTypeIsochronous) ? KUsbEpAttr_TransferTypeIsochronous : + ((aType & UsbShai::KUsbEpTypeBulk) ? KUsbEpAttr_TransferTypeBulk : + ((aType & UsbShai::KUsbEpTypeInterrupt) ? KUsbEpAttr_TransferTypeInterrupt : -1))); + } + + +/** @internalTechnology +*/ +struct TEndpointDescriptorInfo + { + TInt iSetting; // alternate setting + TInt iEndpoint; // excludes ep0 + TAny* iArg; // address of data + }; + + +/** @internalTechnology +*/ +struct TCSDescriptorInfo + { + TInt iSetting; // alternate setting + TInt iEndpoint; // excludes ep0, not used for CS ifc desc + TAny* iArg; // address of data + TInt iSize; // size of data (descriptor block) + }; + +inline TUsbcEndpointInfo::TUsbcEndpointInfo(TUint aType, TUint aDir, TInt aSize, + TInt aInterval, TInt aExtra) + { + iType = aType; + iDir = aDir; + iSize = aSize; + iInterval = aInterval; + iInterval_Hs = -1; + iTransactions = 0; + iExtra = aExtra; + iFeatureWord1 = 0; + iReserved = 0; + } + +inline TUsbcClassInfo::TUsbcClassInfo(TInt aClass, TInt aSubClass, TInt aProtocol) + : iClassNum(aClass), iSubClassNum(aSubClass), iProtocolNum(aProtocol), iReserved(0) + {} + +#endif + + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbdescriptors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbdescriptors.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,548 @@ +// 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: +// + +#ifndef D32USBDESCRIPTORS_H +#define D32USBDESCRIPTORS_H + +#include + + +/*****************************************************************************/ +/* */ +/* USB descriptors parser framework */ +/* */ +/*****************************************************************************/ + +class TUsbGenericDescriptor; + +/** +The Symbian USB Descriptor Parsing Framework class. + +This class is to aid users of USBDI by providing the facilities to parse the +raw descriptor data into wrapper classes that allow access to the fields in +the descriptor bodies, and pointers to map the serial data blob into the tree +structure that descriptors logically have. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(UsbDescriptorParser) + { +public: + typedef TUsbGenericDescriptor* (*TUsbDescriptorParserL)(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + +public: + // Main parse function. + IMPORT_C static TInt Parse(const TDesC8& aUsbDes, TUsbGenericDescriptor*& aDesc); + + // Custom parsing framework. + IMPORT_C static void RegisterCustomParserL(TUsbDescriptorParserL aParserFunc); + IMPORT_C static void UnregisterCustomParser(TUsbDescriptorParserL aParserFunc); + +private: + static TUsbGenericDescriptor* FindParserAndParseAndCheckL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + static TUsbGenericDescriptor* FindParserAndParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + static void ParseDescriptorTreeL(TPtrC8& aUsbDes, TUsbGenericDescriptor& aPreviousDesc); + static void BuildTreeL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aPreviousDesc); + static TUsbGenericDescriptor& FindSuitableParentL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aTopParent); + static TUsbGenericDescriptor* UnknownUsbDescriptorParserL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + }; + + +/*****************************************************************************/ +/* */ +/* USB standard descriptors */ +/* */ +/*****************************************************************************/ + + +/** +Base class for USB descriptors. +All USB descriptors contain type and length, and may have peers and children. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +class TUsbGenericDescriptor + { +public: + IMPORT_C TUsbGenericDescriptor(); + + IMPORT_C void DestroyTree(); + + IMPORT_C TUint8 TUint8At(TInt aOffset) const; + IMPORT_C TUint16 TUint16At(TInt aOffset) const; + IMPORT_C TUint32 TUint32At(TInt aOffset) const; + + IMPORT_C TUsbGenericDescriptor& operator=(const TUsbGenericDescriptor& aDescriptor); + + /** + Helper function to allow TUsbGenericDescriptor types to be placed on the cleanup stack. + */ + inline operator TCleanupItem() { return TCleanupItem(Cleanup,this); } + +public: + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + virtual TBool IsChild(TUsbGenericDescriptor& aPotentialChild); + +private: + IMPORT_C static void Cleanup(TAny* aPtr); + static void WalkAndDelete(TUsbGenericDescriptor* aDesc); + +public: // USB standard fields + /** + The offset in a standard USB descriptor to the bLength field. + */ + static const TInt KbLengthOffset = 0; + + /** + The offset in a standard USB descriptor to the bDescriptorType field. + */ + static const TInt KbDescriptorTypeOffset = 1; + + /** + Standard Length field. + */ + TUint8 ibLength; + + /** + Standard Type field. + */ + TUint8 ibDescriptorType; + +public: + /** + The flag to indicate whether the USB descriptor has been recognised + and parsed. + */ + enum TUsbGenericDescriptorFlags + { + EUnrecognised = 0x00, + ERecognised = 0x01, + }; + +public: // Symbian generated fields + /** + Flag to show if the descriptor has been recognised and parsed, or if its data can only be represented as a + binary blob. This field should particularly be checked if writing code which may run on older versions of + the operating system, where a (now) known descriptor may not have been parsed, or before parsing a new + descriptor from a blob, where later versions of the operating system may have already extracted the fields. + */ + TUint8 iRecognisedAndParsed; + + /** + A pointer to the next peer of this descriptor, or NULL. + As an example, an endpoint descriptor will contain pointers to any other endpoint descriptors on the same + interface. + */ + TUsbGenericDescriptor* iNextPeer; + + /** + A pointer to the first child of this descriptor, or NULL. + As an example, an interface descriptor will contain a pointer to the first endpoint descriptor on the + interface. The iNextPeer member can then be used to examine other endpoints on the interface. + */ + TUsbGenericDescriptor* iFirstChild; + + /** + A pointer to the parent to this descriptor, or NULL. + As an example an endpoint descriptor from a configuration bundle will have the interface that it + is a member of as it's parent. + */ + TUsbGenericDescriptor* iParent; + + /** + The binary blob that contains this descriptor + */ + TPtrC8 iBlob; + }; + +enum TUsbDescriptorType + { + EDevice = 1, + EConfiguration = 2, + EString = 3, + EInterface = 4, + EEndpoint = 5, + EDeviceQualifier = 6, + EOtherSpeedConfiguration = 7, + EInterfacePower = 8, + EOTG = 9, + EDebug = 10, + EInterfaceAssociation = 11, + }; + +/** +Device descriptor. + +See section 9.6.1 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbDeviceDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbDeviceDescriptor(); + IMPORT_C static TUsbDeviceDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 18; + enum TFieldOffsets + { + EbcdUSB = 2, + EbDeviceClass = 4, + EbDeviceSubClass = 5, + EbDeviceProtocol = 6, + EbMaxPacketSize0 = 7, + EidVendor = 8, + EidProduct = 10, + EbcdDevice = 12, + EiManufacturer = 14, + EiProduct = 15, + EiSerialNumber = 16, + EbNumConfigurations = 17 + }; + +public: + IMPORT_C TUint16 USBBcd() const; + IMPORT_C TUint8 DeviceClass() const; + IMPORT_C TUint8 DeviceSubClass() const; + IMPORT_C TUint8 DeviceProtocol() const; + IMPORT_C TUint8 MaxPacketSize0() const; + IMPORT_C TUint16 VendorId() const; + IMPORT_C TUint16 ProductId() const; + IMPORT_C TUint16 DeviceBcd() const; + IMPORT_C TUint8 ManufacturerIndex() const; + IMPORT_C TUint8 ProductIndex() const; + IMPORT_C TUint8 SerialNumberIndex() const; + IMPORT_C TUint8 NumConfigurations() const; + +public: + static TUsbDeviceDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + + +/** +Device Qualifier descriptor. + +See section 9.6.2 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbDeviceQualifierDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbDeviceQualifierDescriptor(); + IMPORT_C static TUsbDeviceQualifierDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 10; + enum TFieldOffsets + { + EbcdUSB = 2, + EbDeviceClass = 4, + EbDeviceSubClass = 5, + EbDeviceProtocol = 6, + EbMaxPacketSize0 = 7, + EbNumConfigurations = 8, + EbReserved = 9 + }; + +public: + IMPORT_C TUint16 USBBcd() const; + IMPORT_C TUint8 DeviceClass() const; + IMPORT_C TUint8 DeviceSubClass() const; + IMPORT_C TUint8 DeviceProtocol() const; + IMPORT_C TUint8 MaxPacketSize0() const; + IMPORT_C TUint8 NumConfigurations() const; + IMPORT_C TUint8 Reserved() const; + +public: + static TUsbDeviceQualifierDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + + +/** +Configuration descriptor. + +See section 9.6.3 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbConfigurationDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbConfigurationDescriptor(); + IMPORT_C static TUsbConfigurationDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 9; + enum TFieldOffsets + { + EwTotalLength = 2, + EbNumInterfaces = 4, + EbConfigurationValue = 5, + EiConfiguration = 6, + EbmAttributes = 7, + EbMaxPower = 8 + }; + +public: + IMPORT_C TUint16 TotalLength() const; + IMPORT_C TUint8 NumInterfaces() const; + IMPORT_C TUint8 ConfigurationValue() const; + IMPORT_C TUint8 ConfigurationIndex() const; + IMPORT_C TUint8 Attributes() const; + IMPORT_C TUint8 MaxPower() const; + +public: + static TUsbConfigurationDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + + +/** +Other Speed descriptor. + +See section 9.6.4 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbOtherSpeedDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbOtherSpeedDescriptor(); + IMPORT_C static TUsbOtherSpeedDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 9; + enum TFieldOffsets + { + EwTotalLength = 2, + EbNumInterfaces = 4, + EbConfigurationValue = 5, + EiConfiguration = 6, + EbmAttributes = 7, + EbMaxPower = 8 + }; + +public: + IMPORT_C TUint16 TotalLength() const; + IMPORT_C TUint8 NumInterfaces() const; + IMPORT_C TUint8 ConfigurationValue() const; + IMPORT_C TUint8 ConfigurationIndex() const; + IMPORT_C TUint8 Attributes() const; + IMPORT_C TUint8 MaxPower() const; + +public: + static TUsbOtherSpeedDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + + +/** +Interface Association Descriptor + +See the USB IAD ECN. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbInterfaceAssociationDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbInterfaceAssociationDescriptor(); + IMPORT_C static TUsbInterfaceAssociationDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 8; + enum TFieldOffsets + { + EbFirstInterface = 2, + EbInterfaceCount = 3, + EbFunctionClass = 4, + EbFunctionSubClass = 5, + EbFunctionProtocol = 6, + EiFunction = 7 + }; + +public: + IMPORT_C TUint8 FirstInterface() const; + IMPORT_C TUint8 InterfaceCount() const; + IMPORT_C TUint8 FunctionClass() const; + IMPORT_C TUint8 FunctionSubClass() const; + IMPORT_C TUint8 FunctionProtocol() const; + IMPORT_C TUint8 FunctionIndex() const; + +public: + static TUsbInterfaceAssociationDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + virtual TBool IsChild(TUsbGenericDescriptor& aPotentialChild); + }; + +/** +Interface descriptor. + +See section 9.6.5 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbInterfaceDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbInterfaceDescriptor(); + IMPORT_C static TUsbInterfaceDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 9; + enum TFieldOffsets + { + EbInterfaceNumber = 2, + EbAlternateSetting = 3, + EbNumEndpoints = 4, + EbInterfaceClass = 5, + EbInterfaceSubClass = 6, + EbInterfaceProtocol = 7, + EiInterface = 8 + }; + +public: + IMPORT_C TUint8 InterfaceNumber() const; + IMPORT_C TUint8 AlternateSetting() const; + IMPORT_C TUint8 NumEndpoints() const; + IMPORT_C TUint8 InterfaceClass() const; + IMPORT_C TUint8 InterfaceSubClass() const; + IMPORT_C TUint8 InterfaceProtocol() const; + IMPORT_C TUint8 Interface() const; + +public: + static TUsbInterfaceDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + +/** +Endpoint descriptor. + +See section 9.6.6 of the USB 2.0 specification. +Note these exclude support support for: +'Standard AC Interrupt Endpoint Descriptor' +'Standard AS Isochronous Synch Endpoint Descriptor' +'Standard AS Isochronous Audio Data Endpoint Descriptor' +as defined in USB Audio Device Class Spec v1.0 which are all 9 bytes in size. +To support these custom descriptors may be registered with the +parser. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbEndpointDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbEndpointDescriptor(); + IMPORT_C static TUsbEndpointDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 7; + enum TFieldOffsets + { + EbEndpointAddress = 2, + EbmAttributes = 3, + EwMaxPacketSize = 4, + EbInterval = 6 + }; + +public: + IMPORT_C TUint8 EndpointAddress() const; + IMPORT_C TUint8 Attributes() const; + IMPORT_C TUint16 MaxPacketSize() const; + IMPORT_C TUint8 Interval() const; + +public: + static TUsbEndpointDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + +/** +String descriptor + +See section 9.6.7 of the USB 2.0 specification. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbStringDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbStringDescriptor(); + IMPORT_C static TUsbStringDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + IMPORT_C TInt GetLangId(TInt aIndex) const; + IMPORT_C void StringData(TDes16& aString) const; + +public: + static TUsbStringDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + +/** +OTG descriptor. + +See section 6.4 of the USB 2.0 On-The-Go Supplement Revision 1.3 + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(TUsbOTGDescriptor) : public TUsbGenericDescriptor + { +public: + IMPORT_C TUsbOTGDescriptor(); + IMPORT_C static TUsbOTGDescriptor* Cast(TUsbGenericDescriptor* aOriginal); + +public: + static const TInt KSizeInOctets = 3; + enum TFieldOffsets + { + EbmAttributes = 2 + }; + +public: + IMPORT_C TUint8 Attributes() const; + IMPORT_C TBool HNPSupported() const; + IMPORT_C TBool SRPSupported() const; +public: + static TUsbOTGDescriptor* ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc); + virtual TBool IsParent(TUsbGenericDescriptor& aPotentialParent); + virtual TBool IsPeer(TUsbGenericDescriptor& aPotentialPeer); + }; + + +#endif // D32USBDESCRIPTORS_H diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/d32usbtransfers.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/d32usbtransfers.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,239 @@ +// 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: +// + +#ifndef __D32USBTRANSFERS_H +#define __D32USBTRANSFERS_H + +#ifdef __KERNEL_MODE__ +#include +#else +#include +#endif +#include + + +class RUsbTransferStrategy; + +/** +Base class for all transfer descriptors. + +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(RUsbTransferDescriptor) + { +public: + enum TTransferType + { + EBulk, + EIsochronous, + EInterrupt + }; + + enum TZlpStatus + { + ESuppressZlp, + ESendZlpIfRequired, // Default + EAlwaysSendZlp + }; + +#ifndef __KERNEL_MODE__ +friend class RUsbPipe; +friend class RUsbTransferStrategy; + +public: + virtual void Close(); + +protected: + RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets); + +protected: + static const TInt KInvalidHandle = -1; + +protected: + /** + A pointer to the transfer strategy the descriptor is registered in. + */ + RUsbTransferStrategy* iTransferStrategy; + + /** + Handle into the transfer strategy for the descriptor. + */ + TInt iHandle; + +public: + /** + The type of transfer descriptor this instance represents. + */ + const TTransferType iType; + + /** + For isochronous transfers this refers to the maximum packet size packets + in this descriptor may be. + For other transfers this refers to the maximum size of the transfer. + */ + const TInt iMaxSize; + + /** + Used to specify the maximum number of packets the descriptor will hold. + */ + const TInt iMaxNumPackets; +#endif // __KERNEL_MODE__ + }; + + +#ifndef __KERNEL_MODE__ + +/** +A class that refers to the list of packet lengths for a isochronous transfer +descriptor. + +@publishedPartner +@prototype +*/ +NONSHARABLE_CLASS(TPacketLengths) + { +public: + NONSHARABLE_CLASS(TLength) + { + public: + IMPORT_C TUint16 operator=(TUint16 aValue); + IMPORT_C operator TUint16() const; + public: + TLength(TUint16& aRecv, TUint16& aReq); + private: + TUint16& iRecv; + TUint16& iReq; + }; +public: + IMPORT_C TLength At(TInt aIndex); + IMPORT_C const TLength At(TInt aIndex) const; + IMPORT_C TLength operator[](TInt aIndex); + IMPORT_C const TLength operator[](TInt aIndex) const; + IMPORT_C TInt MaxNumPackets(); + +public: + TPacketLengths(TUint16* aRecvPtr, TUint16* aReqPtr, TInt& aMaxNumPackets); + +private: + TUint16* iRecvPtr; + TUint16* iReqPtr; + TInt& iMaxNumPackets; + }; + +/** +A class that refers to the list of packet results for a isochronous transfer +descriptor. + +@publishedPartner +@prototype +*/ +NONSHARABLE_CLASS(TPacketResults) + { +public: + IMPORT_C TInt At(TInt aIndex) const; + IMPORT_C TInt operator[](TInt aIndex) const; + IMPORT_C TInt MaxNumPackets(); + +public: + TPacketResults(TInt* aResPtr, TInt& aMaxNumPackets); + +private: + TInt* iResPtr; + TInt& iMaxNumPackets; + }; + + +/** +Provides *SEQUENTIAL* access to the packet slots in an isochronous transfer descriptor. +As some HCs may pack the buffer space tightly, with one packet starting immediately after the preceeding one, +random access is not possible -- in this implementation, even replacing the content of a slot with another packet +of the same size is not 'intentionally' possible. +Note that reading data is possible in a random access manner -- the sequential constraint only applies to writing. +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(RUsbIsocTransferDescriptor) : public RUsbTransferDescriptor + { +friend class RUsbTransferStrategy; + +public: + IMPORT_C RUsbIsocTransferDescriptor(TInt aMaxPacketSize, TInt aMaxNumPackets); + +public: + IMPORT_C void Reset(); + IMPORT_C TPacketLengths Lengths(); + IMPORT_C TPacketResults Results(); + IMPORT_C TInt MaxPacketSize(); + +public: // Sending + IMPORT_C TPtr8 WritablePackets(TInt aNumPacketsRequested, TInt& aMaxNumOfPacketsAbleToWrite); + IMPORT_C void SaveMultiple(TInt aNumOfPackets); + +public: // Receiving + IMPORT_C TPtrC8 Packets(TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumOfPacketsReturned) const; + IMPORT_C void ReceivePackets(TInt aNumOfPackets); + +private: + /** + The handle to represent the current point in writing an isoc. transfer. + */ + TInt iWriteHandle; + }; + + +/** +Provides buffer management for Bulk transfers +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(RUsbBulkTransferDescriptor) : public RUsbTransferDescriptor + { +public: + IMPORT_C RUsbBulkTransferDescriptor(TInt aMaxSize); + +public: // Setters + IMPORT_C TPtr8 WritableBuffer(); + IMPORT_C void SaveData(TInt aLength); + IMPORT_C void SetZlpStatus(TZlpStatus aZlpStatus); + +public: // Getters + IMPORT_C TPtrC8 Buffer() const; + }; + + + +/** +Provides buffer management for Interrupt transfers +@publishedPartner Intended to be available to 3rd parties later +@prototype +*/ +NONSHARABLE_CLASS(RUsbIntrTransferDescriptor) : public RUsbTransferDescriptor + { +public: + IMPORT_C RUsbIntrTransferDescriptor(TInt aMaxSize); + +public: // Setters + IMPORT_C TPtr8 WritableBuffer(); + IMPORT_C void SaveData(TInt aLength); + IMPORT_C void SetZlpStatus(TZlpStatus aZlpStatus); + +public: // Getters + IMPORT_C TPtrC8 Buffer() const; + }; + +#endif // __KERNEL_MODE__ + +#endif // __D32USBTRANSFERS_H diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usb.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usb.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,246 @@ +// Copyright (c) 2002-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\include\usb.h +// Definitions of USB-specific constants and macros. +// +// + +/** + @file usb.h + @publishedPartner + @released +*/ + +#ifndef __USB_H__ +#define __USB_H__ + +// +// 'Chapter 9' Request Types (bmRequestType) +// +const TUint8 KUsbRequestType_DirShift = 7; +const TUint8 KUsbRequestType_DirMask = (1 << KUsbRequestType_DirShift); + +const TUint8 KUsbRequestType_DirToDev = (0 << KUsbRequestType_DirShift); +const TUint8 KUsbRequestType_DirToHost = (1 << KUsbRequestType_DirShift); + +const TUint8 KUsbRequestType_TypeShift = 5; +const TUint8 KUsbRequestType_TypeMask = (3 << KUsbRequestType_TypeShift); +const TUint8 KUsbRequestType_TypeStd = (0 << KUsbRequestType_TypeShift); +const TUint8 KUsbRequestType_TypeClass = (1 << KUsbRequestType_TypeShift); +const TUint8 KUsbRequestType_TypeVendor = (2 << KUsbRequestType_TypeShift); + +const TUint8 KUsbRequestType_DestShift = 0; +const TUint8 KUsbRequestType_DestMask = (0x1f << KUsbRequestType_DestShift); +const TUint8 KUsbRequestType_DestDevice = (0x00 << KUsbRequestType_DestShift); +const TUint8 KUsbRequestType_DestIfc = (0x01 << KUsbRequestType_DestShift); +const TUint8 KUsbRequestType_DestEp = (0x02 << KUsbRequestType_DestShift); +const TUint8 KUsbRequestType_DestOther = (0x03 << KUsbRequestType_DestShift); + +// +// 'Chapter 9' Endpoint Zero Requests (bRequest) +// +const TUint8 KUsbRequest_GetStatus = 0; +const TUint8 KUsbRequest_ClearFeature = 1; +const TUint8 KUsbRequest_SetFeature = 3; +const TUint8 KUsbRequest_SetAddress = 5; +const TUint8 KUsbRequest_GetDescriptor = 6; +const TUint8 KUsbRequest_SetDescriptor = 7; +const TUint8 KUsbRequest_GetConfig = 8; +const TUint8 KUsbRequest_SetConfig = 9; +const TUint8 KUsbRequest_GetInterface = 10; +const TUint8 KUsbRequest_SetInterface = 11; +const TUint8 KUsbRequest_SynchFrame = 12; + +// +// Descriptor Types +// +const TUint8 KUsbDescType_Device = 1; +const TUint8 KUsbDescType_Config = 2; +const TUint8 KUsbDescType_String = 3; +const TUint8 KUsbDescType_Interface = 4; +const TUint8 KUsbDescType_Endpoint = 5; +const TUint8 KUsbDescType_DeviceQualifier = 6; +const TUint8 KUsbDescType_OtherSpeedConfig = 7; +const TUint8 KUsbDescType_InterfacePower = 8; +const TUint8 KUsbDescType_Otg = 9; +const TUint8 KUsbDescType_Debug = 10; +const TUint8 KUsbDescType_InterfaceAssociation = 11; + +// +// Descriptor Sizes +// +const TUint KUsbDescSize_Device = 18; +const TUint KUsbDescSize_Config = 9; +const TUint KUsbDescSize_Interface = 9; +const TUint KUsbDescSize_Endpoint = 7; +const TUint KUsbDescSize_Otg = 3; +const TUint KUsbDescSize_DeviceQualifier = 10; +const TUint KUsbDescSize_OtherSpeedConfig = 9; +const TUint KUsbDescSize_InterfaceAssociation = 8; +const TUint KUsbDescMaxSize_String = 255; +const TUint KUsbStringDescStringMaxSize = 252; // it's actually 253, but that's awkward + +// +// Configuration Characteristics (Configuration Descriptor) +// +const TUint8 KUsbDevAttr_SelfPowered = (0x01 << 6); +const TUint8 KUsbDevAttr_RemoteWakeup = (0x01 << 5); + +// +// Descriptor Indices for String Descriptors +// +const TUint KUsbDescStringIndex_Manufact = 14; +const TUint KUsbDescStringIndex_Product = 15; +const TUint KUsbDescStringIndex_Serial = 16; +const TUint KUsbDescStringIndex_Config = 6; + +// +// Endpoint Attributes +// +const TUint8 KUsbEpAttr_TransferTypeShift = 0; +const TUint8 KUsbEpAttr_TransferTypeMask = (0x03 << KUsbEpAttr_TransferTypeShift); +const TUint8 KUsbEpAttr_TransferTypeControl = (0x00 << KUsbEpAttr_TransferTypeShift); +const TUint8 KUsbEpAttr_TransferTypeIsochronous = (0x01 << KUsbEpAttr_TransferTypeShift); +const TUint8 KUsbEpAttr_TransferTypeBulk = (0x02 << KUsbEpAttr_TransferTypeShift); +const TUint8 KUsbEpAttr_TransferTypeInterrupt = (0x03 << KUsbEpAttr_TransferTypeShift); + +const TUint8 KUsbEpAttr_SyncTypeShift = 2; +const TUint8 KUsbEpAttr_SyncTypeMask = (0x03 << KUsbEpAttr_SyncTypeShift); +const TUint8 KUsbEpAttr_SyncTypeNoSync = (0x00 << KUsbEpAttr_SyncTypeShift); +const TUint8 KUsbEpAttr_SyncTypeAsync = (0x01 << KUsbEpAttr_SyncTypeShift); +const TUint8 KUsbEpAttr_SyncTypeAdaptive = (0x02 << KUsbEpAttr_SyncTypeShift); +const TUint8 KUsbEpAttr_SyncTypeSync = (0x03 << KUsbEpAttr_SyncTypeShift); + +const TUint8 KUsbEpAttr_UsageTypeShift = 4; +const TUint8 KUsbEpAttr_UsageTypeMask = (0x03 << KUsbEpAttr_UsageTypeShift); +const TUint8 KUsbEpAttr_UsageTypeDataEp = (0x00 << KUsbEpAttr_UsageTypeShift); +const TUint8 KUsbEpAttr_UsageTypeFeedbackEp = (0x01 << KUsbEpAttr_UsageTypeShift); +const TUint8 KUsbEpAttr_UsageTypeImplFbDataEp = (0x02 << KUsbEpAttr_UsageTypeShift); +const TUint8 KUsbEpAttr_UsageTypeReserved = (0x03 << KUsbEpAttr_UsageTypeShift); + +// +// OTG Feature Indicators +// +const TUint8 KUsbOtgAttr_SrpSupp = 0x01; +const TUint8 KUsbOtgAttr_HnpSupp = 0x02; +const TUint8 KUsbOtgAttr_B_HnpEnable = 0x04; +const TUint8 KUsbOtgAttr_A_HnpSupport = 0x08; +const TUint8 KUsbOtgAttr_A_AltHnpSupport = 0x10; + +// +// Feature Settings +// +const TUint KUsbFeature_EndpointHalt = 0; +const TUint KUsbFeature_RemoteWakeup = 1; +const TUint KUsbFeature_TestMode = 2; +const TUint KUsbFeature_B_HnpEnable = 3; +const TUint KUsbFeature_A_HnpSupport = 4; +const TUint KUsbFeature_A_AltHnpSupport = 5; + +// +// Test Mode Selectors (Set/ClearFeature) +// +const TUint KUsbTestSelector_Test_J = 0x01; +const TUint KUsbTestSelector_Test_K = 0x02; +const TUint KUsbTestSelector_Test_SE0_NAK = 0x03; +const TUint KUsbTestSelector_Test_Packet = 0x04; +const TUint KUsbTestSelector_Test_Force_Enable = 0x05; + +// +// Address Masks +// +const TUint8 KUsbEpAddress_In = 0x80; +const TUint8 KUsbEpAddress_Portmask = 0x0f; + +// +// Device Status Values (GET_STATUS) +// +const TUint16 KUsbDevStat_SelfPowered = (1 << 0); +const TUint16 KUsbDevStat_RemoteWakeup = (1 << 1); + +// +// Endpoint Status Values (GET_STATUS) +// +const TUint16 KUsbEpStat_Halt = (1 << 0); + + +// +// USB Descriptor Handling +// +/*------------------------------------------------ + USB transfers data in little-endian fashion. + The following macros swap the byte order in + words (16 bit) and longwords (32 bit), such that + they are in little-endian order afterwards. + ------------------------------------------------*/ +#if defined(__BIG_ENDIAN__) // Hitachi SuperH, Motorola 68k +#define SWAP_BYTES_16(x) \ + ((((x) >> 8) & 0x00ff) | \ + (((x) << 8) & 0xff00)) +#define SWAP_BYTES_32(x) \ + ((((x) >> 24) & 0x000000ff) | \ + (((x) >> 8) & 0x0000ff00) | \ + (((x) << 24) & 0xff000000) | \ + (((x) << 8) & 0x00ff0000)) +#else // ARM, Intel +#define SWAP_BYTES_16(x) (x) +#define SWAP_BYTES_32(x) (x) +#endif // defined(__BIG_ENDIAN__) + + +static inline TUint8 LowByte(TUint16 aWord) + { + return static_cast(aWord & 0x00ff); + } + +static inline TUint8 HighByte(TUint16 aWord) + { + return static_cast((aWord >> 8) & 0x00ff); + } + + +// +// Class-specific Values +// + +// These are from the CDC (valid also for Audio Class) +const TUint8 KUsbDescType_CS_Interface = 0x24; +const TUint8 KUsbDescType_CS_Endpoint = 0x25; + +// Audio Device Class +const TUint KUsbDescSize_AudioEndpoint = KUsbDescSize_Endpoint + 2; +const TUint KUsbAudioInterfaceClassCode = 0x01; +const TUint KUsbAudioInterfaceSubclassCode_Subclass_Undefined = 0x00; +const TUint KUsbAudioInterfaceSubclassCode_Audiocontrol = 0x01; +const TUint KUsbAudioInterfaceSubclassCode_Audiostreaming = 0x02; +const TUint KUsbAudioInterfaceSubclassCode_Midistreaming = 0x03; +const TUint KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined = 0x00; + + +// +// These are defined just for convenience: +// +const TUint8 KEp0_Out = 0; +const TUint8 KEp0_In = 1; +const TUint8 KEp0_Rx = KEp0_Out; +const TUint8 KEp0_Tx = KEp0_In; + + +// +// USB Implementers Forum, Inc (USB-IF) assigned Vendor IDs: +// +const TUint16 KUsbVendorId_Symbian = 0x0E22; // Symbian Ltd. (dec. 3618) + + +#endif // __USB_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbc.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,359 @@ +// Copyright (c) 2000-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/include/drivers/usbc.h +// Kernel side definitions for the USB Device driver stack (PIL + LDD). +// +// + +/** + @file usbc.h + @internalTechnology +*/ + +#ifndef __USBC_H__ +#define __USBC_H__ + +#include +#include +#include +#include + +#include + +//#include +#include + + + +/** LDD Major version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcMajorVersion = 0; + +/** LDD Minor version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcMinorVersion = 1; + +/** LDD Build version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcBuildVersion = KE32BuildVersionNumber; + +/** Must correspond to the max enum of TRequest + 1; + currently this is ERequestOtgFeaturesNotify = 10. +*/ +const TInt KUsbcMaxRequests = 11; + +// +//########################### Logical Device Driver (LDD) ############################# +// + +/** USB LDD factory class. +*/ +class DUsbcLogDevice : public DLogicalDevice + { +public: + DUsbcLogDevice(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); + }; + + +/** OUT buffering is a collection of flat buffers. Each is either fillable or drainable. + When one buffer becomes full (notified by the PIL) it is marked as not-fillable and the next + fillable buffer is used. When the buffer has finished draining it is marked as fillable. +*/ +class TDmaBuf + { +public: + TDmaBuf(); + TDmaBuf(TUsbcEndpointInfo* aEndpointInfo, TInt aBandwidthPriority); + ~TDmaBuf(); + TInt Construct(TUsbcEndpointInfo* aEndpointInfo); + TInt BufferTotalSize() const; + TInt BufferSize() const; + TInt SetBufferAddr(TInt aBufInd, TUint8* aBufAddr); + TInt BufferNumber() const; + void SetMaxPacketSize(TInt aSize); + void Flush(); + // Rx (OUT) variants + void RxSetActive(); + void RxSetInActive(); + TBool RxIsActive(); + TBool IsReaderEmpty(); + void ReadXferComplete(TInt aNoBytesRx, TInt aNoPacketsRx, TInt aErrorCode); + TInt RxCopyDataToClient(DThread* aThread, TClientBuffer *aTcb, TInt aLength, TUint32& aDestOffset, + TBool aRUS, TBool& aCompleteNow); + TInt RxCopyPacketToClient(DThread* aThread,TClientBuffer *aTcb, TInt aLength); + TInt RxGetNextXfer(TUint8*& aBufferAddr, TUsbcPacketArray*& aIndexArray, TUsbcPacketArray*& aSizeArray, + TInt& aLength, TPhysAddr& aBufferPhys); + TBool RxIsEnoughSpace(TInt aSize); + inline TInt RxBytesAvailable() const; + inline void IncrementBufferIndex(TInt& aIndex); + inline TInt NoRxPackets() const; + TInt SetDrainable(TInt aBufferNum); + // Tx (IN) variants + void TxSetActive(); + void TxSetInActive(); + TBool TxIsActive(); + TInt TxStoreData(DThread* aThread,TClientBuffer *aTcb, TInt aTxLength, TUint32 aBufferOffset); + TInt TxGetNextXfer(TUint8*& aBufferAddr, TInt& aTxLength, TPhysAddr& aBufferPhys); + TBool ShortPacketExists(); + +#if defined(USBC_LDD_BUFFER_TRACE) + TInt NoRxPacketsAlt() const; + TInt NoRxBytesAlt() const; +#endif + +private: + TBool AdvancePacket(); + inline TInt GetCurrentError(); + TBool NextDrainableBuffer(); + TBool NextFillableBuffer(); + void FreeDrainedBuffers(); + TInt PeekNextPacketSize(); + TInt PeekNextDrainableBuffer(); + void ModifyTotalRxBytesAvail(TInt aVal); + void ModifyTotalRxPacketsAvail(TInt aVal); + void AddToDrainQueue(TInt aBufferIndex); + inline TInt CopyToUser(DThread* aThread, const TUint8* aSourceAddr, TInt aLength, + TClientBuffer *aTcb, TUint32& aDestOffset); +private: + TInt iExtractOffset; // offset into current packet for data read + TInt iMaxPacketSize; + TInt iNumberofBuffers; + TInt iBufSz; + TBool iRxActive; + TBool iTxActive; + TInt iTotalRxBytesAvail; + TInt iTotalRxPacketsAvail; + // + TUint8* iBufBasePtr; + TUint8* iCurrentDrainingBuffer; + TInt iCurrentDrainingBufferIndex; + TInt iCurrentFillingBufferIndex; + TUint iCurrentPacket; + TUsbcPacketArray* iCurrentPacketIndexArray; + TUsbcPacketArray* iCurrentPacketSizeArray; + TUint8* iBuffers[KUsbcDmaBufNumMax]; + TBool iDrainable[KUsbcDmaBufNumMax]; + TUsbcPacketArray iPacketInfoStorage[KUsbcDmaBufNumMax * KUsbcDmaBufNumArrays * KUsbcDmaBufMaxPkts]; + TUsbcPacketArray* iPacketIndex[KUsbcDmaBufNumMax]; + TUsbcPacketArray* iPacketSize[KUsbcDmaBufNumMax]; + TUint iNumberofBytesRx[KUsbcDmaBufNumMax]; + TUint iNumberofPacketsRx[KUsbcDmaBufNumMax]; + TInt iError[KUsbcDmaBufNumMax]; + TPhysAddr iBufferPhys[KUsbcDmaBufNumMax]; + TBool iCanBeFreed[KUsbcDmaBufNumMax]; + TInt iDrainQueue[KUsbcDmaBufNumMax + 1]; + TInt iDrainQueueIndex; + TUint iEndpointType; + +#if defined(USBC_LDD_BUFFER_TRACE) + TInt iFillingOrder; + TInt iFillingOrderArray[KUsbcDmaBufNumMax]; + TInt iDrainingOrder; + TUint iNumberofBytesRxRemain[KUsbcDmaBufNumMax]; + TUint iNumberofPacketsRxRemain[KUsbcDmaBufNumMax]; +#endif + }; + + +class DLddUsbcChannel; + +/** Endpoint tracking for the LDD buffering etc. +*/ +class TUsbcEndpoint + { +public: + TUsbcEndpoint(); + TUsbcEndpoint(DLddUsbcChannel* aLDD, DUsbClientController* aController, + const TUsbcEndpointInfo* aEndpointInfo, TInt aEndpointNum, + TInt aBandwidthPriority); + ~TUsbcEndpoint(); + TInt Construct(); + TInt TryToStartRead(TBool aReEntrant); + TInt TryToStartWrite(TEndpointTransferInfo* pTfr); + TInt CopyToClient(DThread* aThread, TClientBuffer *aTcb); + TInt CopyToClient(DThread* aClient, TBool& aCompleteNow, TClientBuffer *aTcb); + TInt ContinueWrite(); + void SetMaxPacketSize(TInt aSize); + void CancelTransfer(DThread* aThread, TClientBuffer *aTcb); + void AbortTransfer(); + inline TUsbcEndpointInfo* EndpointInfo(); + inline TInt RxBytesAvailable() const; + + inline TInt BufferSize() const; + inline TInt SetBufferAddr( TInt aBufInd, TUint8* aAddr); + inline TInt BufferNumber() const; + + inline void SetTransferInfo(TEndpointTransferInfo* aTransferInfo); + inline void ResetTransferInfo(); + inline void SetClientReadPending(TBool aVal); + inline void SetClientWritePending(TBool aVal); + inline TBool ClientWritePending(); + inline TBool ClientReadPending(); + inline void SetRealEpNumber(TInt aRealEpNumber); + inline TInt RealEpNumber() const; + +public: + TDmaBuf* iDmaBuffers; + +private: + static void RequestCallback(TAny* aTUsbcEndpoint); + void TxComplete(); + TInt RxComplete(TBool aReEntrant); + void RxCompleteNow(); + TInt EndpointComplete(); + +private: + DUsbClientController* iController; + TUsbcEndpointInfo iEndpointInfo; + TEndpointTransferInfo iTransferInfo; + TBool iClientReadPending; + TBool iClientWritePending; + TInt iEndpointNumber; + TInt iRealEpNumber; + DLddUsbcChannel* iLdd; + TInt iError; + TUsbcRequestCallback* iRequestCallbackInfo; + TUint32 iBytesTransferred; + TInt iBandwidthPriority; + }; + + +/** Linked list of 'alternate setting' info for use by the LDD. +*/ +class TUsbcAlternateSettingList + { +public: + TUsbcAlternateSettingList(); + ~TUsbcAlternateSettingList(); + +public: + TUsbcAlternateSettingList* iNext; + TInt iNumberOfEndpoints; + TUint iSetting; + TInt iEpNumDeOrderedByBufSize[KMaxEndpointsPerClient + 1]; + TUsbcEndpoint* iEndpoint[KMaxEndpointsPerClient + 1]; + }; + + +struct TClientAsynchNotify + { + TClientBufferRequest *iBufferRequest; + TClientBuffer *iClientBuffer; + void Reset(); + }; +/** The channel class - the actual USB LDD. +*/ +class DLddUsbcChannel : public DLogicalChannel + { +public: + DLddUsbcChannel(); + ~DLddUsbcChannel(); + virtual TInt SendMsg(TMessageBase * aMsg); + TInt PreSendRequest(TMessageBase * aMsg,TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2); + TInt SendControl(TMessageBase* aMsg); + virtual void HandleMsg(TMessageBase* aMsg); + virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); + virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType); + TInt DoRxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TBool aReentrant); + void DoRxCompleteNow(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint); + void DoTxComplete(TUsbcEndpoint* aTUsbcEndpoint, TInt aEndpoint, TInt aError); + inline DThread* Client() const {return iClient;} + inline TBool ChannelClosing() const {return iChannelClosing;} + inline TUint AlternateSetting() const {return iAlternateSetting;} + TClientBuffer *GetClientBuffer(TInt aEndpoint); + +private: + TInt DoCancel(TInt aReqNo); + void DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2); + TInt DoControl(TInt aFunction, TAny* a1, TAny* a2); + TInt DoTransferAsyncReq(TInt aEndpointNum, TAny* a1, TAny* a2, TBool& aNeedsCompletion); + TInt DoOtherAsyncReq(TInt aReqNo, TAny* a1, TAny* a2, TBool& aNeedsCompletion); + TBool AlternateDeviceStateTestComplete(); + TInt SetInterface(TInt aInterfaceNum, TUsbcIfcInfo* aUserInterfaceInfoBuf); + void StartEpReads(); + void DestroyAllInterfaces(); + void DestroyInterface(TUint aInterface); + void DestroyEp0(); + inline TBool ValidEndpoint(TInt aEndpoint); + TInt DoEmergencyComplete(); + void ReadDes8(const TAny* aPtr, TDes8& aDes); + TInt SetupEp0(); + DPlatChunkHw* ReAllocate(TInt aBuffersize, DPlatChunkHw* aHwChunk, TUint32 aCacheAttribs); + DPlatChunkHw* Allocate(TInt aBuffersize, TUint32 aCacheAttribs); + void ClosePhysicalChunk(DPlatChunkHw* &aHwChunk); + void CancelNotifyEndpointStatus(); + void CancelNotifyOtgFeatures(); + static void StatusChangeCallback(TAny* aDLddUsbcChannel); + static void EndpointStatusChangeCallback(TAny* aDLddUsbcChannel); + static void OtgFeatureChangeCallback(TAny* aDLddUsbcChannel); + static void EmergencyCompleteDfc(TAny* aDLddUsbcChannel); + void DeConfigure(TInt aErrorCode); + TInt SelectAlternateSetting(TUint aAlternateSetting); + TInt EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint); + TInt ProcessAlternateSetting(TUint aAlternateSetting); + TInt ProcessDeviceState(TUsbcDeviceState aDeviceState); + void ResetInterface(TInt aErrorCode); + void AbortInterface(); + // Set buffer address of the interface + void ReSetInterfaceMemory(TUsbcAlternateSettingList* aAlternateSettingListRec, + RArray &aHwChunks ); + void UpdateEndpointSizes(); + // Check and alloc memory for the interface + TInt SetupInterfaceMemory(RArray &aHwChunks, + TUint32 aCacheAttribs ); + void PanicClientThread(TInt aReason); + TInt PinMemory(TDesC8 *aDes, TVirtualPinObject *iPinObj); //Descriptor pinning helper. + void CompleteBufferRequest(DThread* aThread, TInt aReqNo, TInt aReason); +private: + DUsbClientController* iController; + DThread* iClient; + TBool iValidInterface; + TUsbcAlternateSettingList* iAlternateSettingList; + TUsbcEndpoint* iEndpoint[KMaxEndpointsPerClient + 1]; // include ep0 + TRequestStatus* iRequestStatus[KUsbcMaxRequests]; + TClientAsynchNotify* iClientAsynchNotify[KUsbcMaxRequests]; + TUsbcClientCallback iCompleteAllCallbackInfo; + TAny* iStatusChangePtr; + TUsbcStatusCallback iStatusCallbackInfo; + TAny* iEndpointStatusChangePtr; + TUsbcEndpointStatusCallback iEndpointStatusCallbackInfo; + TAny* iOtgFeatureChangePtr; + TUsbcOtgFeatureCallback iOtgFeatureCallbackInfo; + TInt iNumberOfEndpoints; + RArray iHwChunksEp0; + RArray iHwChunks; + + TUsbcDeviceState iDeviceState; + TUsbcDeviceState iOldDeviceState; + TBool iOwnsDeviceControl; + TUint iAlternateSetting; + TBool iDeviceStatusNeeded; + TUsbcDeviceStatusQueue* iStatusFifo; + TBool iChannelClosing; + TVirtualPinObject *iPinObj1; + TVirtualPinObject *iPinObj2; + TVirtualPinObject *iPinObj3; + TClientDataRequest *iStatusChangeReq; + TClientDataRequest *iEndpointStatusChangeReq; + TClientDataRequest *iOtgFeatureChangeReq; + TEndpointTransferInfo iTfrInfo; + }; + + +#include + +#endif // __USBC_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbc.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbc.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,115 @@ +// Copyright (c) 1996-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\include\drivers\usbc.inl +// Kernel side inline header file for USB device driver. +// +// + +/** + @file usbc.inl + @internalTechnology +*/ + +#ifndef __USBC_INL__ +#define __USBC_INL__ + + +// --- USB Logical Device Driver (LDD) --- +// + +TInt TDmaBuf::RxBytesAvailable() const + { + return iTotalRxBytesAvail; + } + + +TUsbcEndpointInfo* TUsbcEndpoint::EndpointInfo() + { + return &iEndpointInfo; + } + + +TInt TUsbcEndpoint::RxBytesAvailable() const + { + return iDmaBuffers->RxBytesAvailable(); + } + +TInt TUsbcEndpoint::BufferSize() const + { + return iDmaBuffers->BufferSize(); + } +TInt TUsbcEndpoint::SetBufferAddr( TInt aBufInd, TUint8* aBufAddr) + { + return iDmaBuffers->SetBufferAddr(aBufInd, aBufAddr); + } +TInt TUsbcEndpoint::BufferNumber() const + { + return iDmaBuffers->BufferNumber(); + } + +void TUsbcEndpoint::SetTransferInfo(TEndpointTransferInfo* aTransferInfo) + { + iTransferInfo = *aTransferInfo; + iBytesTransferred = 0; + } + + +void TUsbcEndpoint::ResetTransferInfo() + { + iTransferInfo.iDes = NULL; + iTransferInfo.iTransferType = ETransferTypeNone; + iTransferInfo.iTransferSize = 0; + iTransferInfo.iZlpReqd = EFalse; + iBytesTransferred = 0; + } + + +void TUsbcEndpoint::SetClientReadPending(TBool aVal) + { + iClientReadPending = aVal; + } + + +TBool TUsbcEndpoint::ClientReadPending() + { + return iClientReadPending; + } + + +void TUsbcEndpoint::SetClientWritePending(TBool aVal) + { + iClientWritePending = aVal; + } + + +TBool TUsbcEndpoint::ClientWritePending() + { + return iClientWritePending; + } + + +void TUsbcEndpoint::SetRealEpNumber(TInt aRealEpNumber) + { + iRealEpNumber = aRealEpNumber; + iRequestCallbackInfo->iRealEpNum = aRealEpNumber; + } + + +TInt TUsbcEndpoint::RealEpNumber() const + { + return iRealEpNumber; + } + + +#endif // __USBC_INL__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcdesc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcdesc.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,360 @@ +// Copyright (c) 2002-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/include/drivers/usbcdesc.h +// USB descriptors and their management. +// +// + +/** + @file usbcdesc.h + @internalTechnology +*/ + +#ifndef __USBCDESC_H__ +#define __USBCDESC_H__ + +#include + + +// Hard-wired positions of some descriptors in iDescriptors array (whether present or not): +static const TInt KDescPosition_Device = 0; +static const TInt KDescPosition_DeviceQualifier = 1; +static const TInt KDescPosition_OtherSpeedConfig = 2; +static const TInt KDescPosition_Config = 3; +static const TInt KDescPosition_Otg = 4; +static const TInt KDescPosition_FirstAvailable = 5; + +// Hard-wired positions of string descriptors in iStrings array (whether present or not): +static const TInt KStringPosition_Langid = 0; +static const TInt KStringPosition_Manufact = 1; +static const TInt KStringPosition_Product = 2; +static const TInt KStringPosition_Serial = 3; +static const TInt KStringPosition_Config = 4; +static const TInt KStringPosition_OtherSpeedConfig = 5; +static const TInt KStringPosition_FirstAvailable = 6; + + +NONSHARABLE_CLASS(TUsbcDescriptorBase) + { +public: + virtual ~TUsbcDescriptorBase(); + void SetByte(TInt aPosition, TUint8 aValue); + void SetWord(TInt aPosition, TUint16 aValue); + TUint8 Byte(TInt aPosition) const; + TUint16 Word(TInt aPosition) const; + void GetDescriptorData(TDes8& aBuffer) const; + TInt GetDescriptorData(TUint8* aBuffer) const; + TInt GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const; + const TDes8& DescriptorData() const; + TDes8& DescriptorData(); + TUint Size() const; + TUint8 Type() const; + virtual void UpdateFs(); + virtual void UpdateHs(); +protected: + TUsbcDescriptorBase(); + void SetBufferPointer(const TDesC8& aDes); +private: +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + TUint8 iIndex; // only needed for SET_DESCRIPTOR +#endif + TPtr8 iBufPtr; + }; + + +NONSHARABLE_CLASS(TUsbcDeviceDescriptor) : public TUsbcDescriptorBase + { +public: + /** aMaxPacketSize0 should be the Ep0 max packet size for FS operation (as the HS size + is fixed and known). + */ + static TUsbcDeviceDescriptor* New(TUint8 aDeviceClass, TUint8 aDeviceSubClass, + TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0, + TUint16 aVendorId, TUint16 aProductId, + TUint16 aDeviceRelease, TUint8 aNumConfigurations); + virtual void UpdateFs(); + virtual void UpdateHs(); +private: + TUsbcDeviceDescriptor(); + TInt Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass, TUint8 aDeviceProtocol, + TUint8 aMaxPacketSize0, TUint16 aVendorId, TUint16 aProductId, + TUint16 aDeviceRelease, TUint8 aNumConfigurations); + TBuf8 iBuf; + TUint8 iEp0Size_Fs; // holds Ep0 size for FS (could be < 64) + }; + + +NONSHARABLE_CLASS(TUsbcDeviceQualifierDescriptor) : public TUsbcDescriptorBase + { +public: + /** aMaxPacketSize0 should be the Ep0 max packet size for FS operation (as the HS size + is fixed and known). + */ + static TUsbcDeviceQualifierDescriptor* New(TUint8 aDeviceClass, TUint8 aDeviceSubClass, + TUint8 aDeviceProtocol, TUint8 aMaxPacketSize0, + TUint8 aNumConfigurations, TUint8 aReserved=0); + virtual void UpdateFs(); + virtual void UpdateHs(); +private: + TUsbcDeviceQualifierDescriptor(); + TInt Construct(TUint8 aDeviceClass, TUint8 aDeviceSubClass, TUint8 aDeviceProtocol, + TUint8 aMaxPacketSize0, TUint8 aNumConfigurations, TUint8 aReserved); + TBuf8 iBuf; + TUint8 iEp0Size_Fs; // holds Ep0 size for FS (could be < 64) + }; + + +NONSHARABLE_CLASS(TUsbcConfigDescriptor) : public TUsbcDescriptorBase + { +public: + /** aMaxPower should be given here in milliamps (not mA/2). */ + static TUsbcConfigDescriptor* New(TUint8 aConfigurationValue, TBool aSelfPowered, TBool aRemoteWakeup, + TUint16 aMaxPower); +private: + TUsbcConfigDescriptor(); + TInt Construct(TUint8 aConfigurationValue, TBool aSelfPowered, TBool aRemoteWakeup, TUint16 aMaxPower); + TBuf8 iBuf; + }; + + +// The Other_Speed_Configuration descriptor has same size and layout as the +// standard Configuration descriptor, therefore we don't need a new definition. +typedef TUsbcConfigDescriptor TUsbcOtherSpeedConfigDescriptor; + + +NONSHARABLE_CLASS(TUsbcInterfaceDescriptor) : public TUsbcDescriptorBase + { +public: + static TUsbcInterfaceDescriptor* New(TUint8 aInterfaceNumber, TUint8 aAlternateSetting, TInt NumEndpoints, + const TUsbcClassInfo& aClassInfo); +private: + TUsbcInterfaceDescriptor(); + TInt Construct(TUint8 aInterfaceNumber, TUint8 aAlternateSetting, TInt aNumEndpoints, + const TUsbcClassInfo& aClassInfo); + TBuf8 iBuf; + }; + + +NONSHARABLE_CLASS(TUsbcEndpointDescriptorBase) : public TUsbcDescriptorBase + { +public: + virtual void UpdateFs(); + virtual void UpdateHs(); +protected: + TInt Construct(const TUsbcEndpointInfo& aEpInfo); + TUsbcEndpointDescriptorBase(); +protected: + /** Stores the endpoint size to be used for FS. */ + TInt iEpSize_Fs; + /** Stores the endpoint size to be used for HS. */ + TInt iEpSize_Hs; + /** Stores the endpoint polling interval to be used for FS. */ + TInt iInterval_Fs; + /** Stores the endpoint polling interval to be used for HS. */ + TInt iInterval_Hs; + }; + + +NONSHARABLE_CLASS(TUsbcEndpointDescriptor) : public TUsbcEndpointDescriptorBase + { +public: + static TUsbcEndpointDescriptor* New(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo); +private: + TUsbcEndpointDescriptor(); + TInt Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo); + TBuf8 iBuf; + }; + + +class TUsbcAudioEndpointDescriptor : public TUsbcEndpointDescriptorBase + { +public: + static TUsbcAudioEndpointDescriptor* New(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo); +private: + TUsbcAudioEndpointDescriptor(); + TInt Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo); + TBuf8 iBuf; + }; + + +NONSHARABLE_CLASS(TUsbcOtgDescriptor) : public TUsbcDescriptorBase + { +public: + static TUsbcOtgDescriptor* New(TBool aHnpSupport, TBool aSrpSupport); +private: + TUsbcOtgDescriptor(); + TInt Construct(TBool aHnpSupport, TBool aSrpSupport); + TBuf8 iBuf; + }; + + +NONSHARABLE_CLASS(TUsbcClassSpecificDescriptor) : public TUsbcDescriptorBase + { +public: + virtual ~TUsbcClassSpecificDescriptor(); + static TUsbcClassSpecificDescriptor* New(TUint8 aType, TInt aSize); +private: + TUsbcClassSpecificDescriptor(); + TInt Construct(TUint8 aType, TInt aSize); + HBuf8* iBuf; + }; + + +NONSHARABLE_CLASS(TUsbcStringDescriptorBase) + { +public: + virtual ~TUsbcStringDescriptorBase(); + TUint16 Word(TInt aPosition) const; + void SetWord(TInt aPosition, TUint16 aValue); + TInt GetDescriptorData(TUint8* aBuffer) const; + TInt GetDescriptorData(TUint8* aBuffer, TUint aMaxSize) const; + const TDes8& StringData() const; + TDes8& StringData(); + TUint Size() const; + void SetBufferPointer(const TDesC8& aDes); +protected: + TUsbcStringDescriptorBase(); + TBuf8<2> iSBuf; + TPtr8 iBufPtr; +private: +// TUint8 iIndex; // not needed in DescriptorPool: position == index + }; + + +NONSHARABLE_CLASS(TUsbcStringDescriptor) : public TUsbcStringDescriptorBase + { +public: + virtual ~TUsbcStringDescriptor(); + static TUsbcStringDescriptor* New(const TDesC8& aString); +private: + TUsbcStringDescriptor(); + TInt Construct(const TDesC8& aString); + HBuf8* iBuf; + }; + + +// Currently we support only one language, and thus there's no need to provide +// a LangId string descriptor with more than one array element. +NONSHARABLE_CLASS(TUsbcLangIdDescriptor) : public TUsbcStringDescriptorBase + { +public: + virtual ~TUsbcLangIdDescriptor(); + static TUsbcLangIdDescriptor* New(TUint16 aLangId); +private: + TUsbcLangIdDescriptor(); + TInt Construct(TUint16 aLangId); + TBuf8<2> iBuf; + }; + + +class TUsbcDescriptorPool + { +public: + TUsbcDescriptorPool(TUint8* aEp0_TxBuf); + ~TUsbcDescriptorPool(); + TInt Init(TUsbcDeviceDescriptor* aDeviceDesc, TUsbcConfigDescriptor* aConfigDesc, + TUsbcLangIdDescriptor* aLangId, TUsbcStringDescriptor* aManufacturer, + TUsbcStringDescriptor* aProduct, TUsbcStringDescriptor* aSerialNum, + TUsbcStringDescriptor* aConfig, TUsbcOtgDescriptor* aOtgDesc); + TInt InitHs(); + TInt UpdateDescriptorsFs(); + TInt UpdateDescriptorsHs(); + + // Descriptors + TInt FindDescriptor(TUint8 aType, TUint8 aIndex, TUint16 aLangid, TInt& aSize) const; + void InsertDescriptor(TUsbcDescriptorBase* aDesc); + void DeleteIfcDescriptor(TInt aNumber, TInt aSetting=0); + // The TC in many of the following functions stands for 'ThreadCopy' because that's what happens there. + TInt GetDeviceDescriptorTC(DThread* aThread, TDes8& aBuffer) const; + TInt SetDeviceDescriptorTC(DThread* aThread, const TDes8& aBuffer); + TInt GetConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const; + TInt SetConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer); + TInt GetOtgDescriptorTC(DThread* aThread, TDes8& aBuffer) const; + TInt SetOtgDescriptor(const TDesC8& aBuffer); + TInt GetInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface, TInt aSetting) const; + TInt SetInterfaceDescriptor(const TDes8& aBuffer, TInt aInterface, TInt aSetting); + TInt GetEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface, TInt aSetting, + TUint8 aEndpointAddress) const; + TInt SetEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer, TInt aInterface, TInt aSetting, + TUint8 aEndpointAddress); + TInt GetEndpointDescriptorSize(TInt aInterface, TInt aSetting, TUint8 aEndpointAddress, TInt& aSize) const; + TInt GetDeviceQualifierDescriptorTC(DThread* aThread, TDes8& aBuffer) const; + TInt SetDeviceQualifierDescriptorTC(DThread* aThread, const TDes8& aBuffer); + TInt GetOtherSpeedConfigurationDescriptorTC(DThread* aThread, TDes8& aBuffer) const; + TInt SetOtherSpeedConfigurationDescriptorTC(DThread* aThread, const TDes8& aBuffer); + TInt GetCSInterfaceDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface, TInt aSetting) const; + TInt SetCSInterfaceDescriptorTC(DThread* aThread, const TDes8& aBuffer, TInt aInterface, TInt aSetting, + TInt aSize); + TInt GetCSInterfaceDescriptorSize(TInt aInterface, TInt aSetting, TInt& aSize) const; + TInt GetCSEndpointDescriptorTC(DThread* aThread, TDes8& aBuffer, TInt aInterface, TInt aSetting, + TUint8 aEndpointAddress) const; + TInt SetCSEndpointDescriptorTC(DThread* aThread, const TDes8& aBuffer, TInt aInterface, TInt aSetting, + TUint8 aEndpointAddress, TInt aSize); + TInt GetCSEndpointDescriptorSize(TInt aInterface, TInt aSetting, TUint8 aEndpointAddress, TInt& aSize) const; + + // String descriptors + void SetIfcStringDescriptor(TUsbcStringDescriptor* aDesc, TInt aNumber, TInt aSetting=0); + TInt GetStringDescriptorLangIdTC(DThread* aThread, TDes8& aLangId) const; + TInt SetStringDescriptorLangId(TUint16 aLangId); + TInt GetManufacturerStringDescriptorTC(DThread* aThread, TDes8& aString) const; + TInt SetManufacturerStringDescriptorTC(DThread* aThread, const TDes8& aString); + TInt RemoveManufacturerStringDescriptor(); + TInt GetProductStringDescriptorTC(DThread* aThread, TDes8& aString) const; + TInt SetProductStringDescriptorTC(DThread* aThread, const TDes8& aString); + TInt RemoveProductStringDescriptor(); + TInt GetSerialNumberStringDescriptorTC(DThread* aThread, TDes8& aString) const; + TInt SetSerialNumberStringDescriptorTC(DThread* aThread, const TDes8& aString); + TInt RemoveSerialNumberStringDescriptor(); + TInt GetConfigurationStringDescriptorTC(DThread* aThread, TDes8& aString) const; + TInt SetConfigurationStringDescriptorTC(DThread* aThread, const TDes8& aString); + TInt RemoveConfigurationStringDescriptor(); + TInt GetStringDescriptorTC(DThread* aThread, TInt aIndex, TDes8& aString) const; + TInt SetStringDescriptorTC(DThread* aThread, TInt aIndex, const TDes8& aString); + TInt RemoveStringDescriptor(TInt aIndex); + +private: + // Descriptors + void InsertIfcDesc(TUsbcDescriptorBase* aDesc); + void InsertEpDesc(TUsbcDescriptorBase* aDesc); + TInt FindIfcDescriptor(TInt aIfcNumber, TInt aIfcSetting) const; + TInt FindEpDescriptor(TInt aIfcNumber, TInt aIfcSetting, TUint8 aEpAddress) const; + void DeleteDescriptors(TInt aIndex, TInt aCount = 1); + void UpdateConfigDescriptorLength(TInt aLength); + void UpdateConfigDescriptorNumIfcs(TInt aNumber); + void UpdateIfcNumbers(TInt aNumber); + TInt GetDeviceDescriptor(TInt aIndex) const; + TInt GetConfigurationDescriptor(TInt aIndex) const; + TInt GetOtgDescriptor() const; + + // String descriptors + TInt GetStringDescriptor(TInt aIndex) const; + TInt GetDeviceStringDescriptorTC(DThread* aThread, TDes8& aString, TInt aIndex, TInt aPosition) const; + TInt SetDeviceStringDescriptorTC(DThread* aThread, const TDes8& aString, TInt aIndex, TInt aPosition); + TInt RemoveDeviceStringDescriptor(TInt aIndex, TInt aPosition); + void ExchangeStringDescriptor(TInt aIndex, const TUsbcStringDescriptor* aDesc); + TBool AnyStringDescriptors() const; + TBool StringDescriptorExists(TInt aIndex) const; + TInt FindAvailableStringPos() const; + +private: + // Data members + RPointerArray iDescriptors; + RPointerArray iStrings; + TInt iIfcIdx; + TUint8* const iEp0_TxBuf; // points to the controller's ep0 TX buffer + TBool iHighSpeed; // true if currently operating at high-speed + }; + + +#endif // __USBCDESC_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcontrolxferif.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcontrolxferif.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,60 @@ +/* + Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). + All rights reserved. + + This program and the accompanying materials are made available + under the terms of the Eclipse Public License v1.0 which accompanies + this distribution, and is available at + http://www.eclipse.org/legal/epl-v10.html + + Initial Contributors: + Nokia Corporation - initial contribution. + + Contributors: +*/ + +#ifndef USBCONTROLXFERIF_H +#define USBCONTROLXFERIF_H + +#include // General types definition + +/** + * Callback interfaces that used to process packet received from Host + * and interfaces through which that PIL or app can send request to PSL + */ +NONSHARABLE_CLASS(MControlTransferIf) + { + public: + // Interface for RX + // Transfer direction from Device to Host + // This two interface is saying PSL had finished + // sending those data to host. + virtual void ProcessDataInPacket(TInt aCount,TInt aErrCode) = 0; + virtual void ProcessStatusInPacket(TInt aErrCode) = 0; + + // Transfer direction from Host to Device + // they are saying that some data had been recieved from host + virtual void ProcessDataOutPacket(TInt aCount,TInt aErrCode) = 0; + virtual void ProcessStatusOutPacket(TInt aErrCode) = 0; + virtual void ProcessSetupPacket(TInt aCount,TInt aErrCode) = 0; + + // Interface for TX and Control + // Data/Status transfer function + virtual TInt ProcessSetupEndpointZeroRead() = 0; + virtual TInt ProcessSetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd=EFalse) = 0; + virtual TInt ProcessSendEp0ZeroByteStatusPacket() = 0; + virtual TInt ProcessStallEndpoint(TInt aRealEndpoint) = 0; + + // Flow control interface + // In case of we can not deliver received packet(setup or data) to a registered client + // (because the request callback is not ready), we need PSL stop reporting more packet + // to PIL until the pending packet had been process. + // this 2 functions is used to notify PSL: you can continue, the pending packet is proceed. + virtual void ProcessEp0SetupPacketProceed() = 0; + virtual void ProcessEp0DataPacketProceed() = 0; + }; + +#endif //USBCONTROLXFERIF_H + +// End of file + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcque.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcque.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,147 @@ +// Copyright (c) 2002-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\include\drivers\usbcque.h +// Simple singly linked list + its iterator for the USB Device driver. +// +// + +/** + @file usbcque.h + @internalTechnology +*/ + +#ifndef __USBCQUE_H__ +#define __USBCQUE_H__ + +#include + + +// +// --- Class definitions --- +// + +class TSglQueLink + { +private: + void Enque(TSglQueLink* aLink); +public: + TSglQueLink* iNext; + friend class TSglQueBase; + }; + + +class TSglQueBase + { +protected: + TSglQueBase(TInt aOffset); + void DoAddLast(TAny* aPtr); + void DoRemove(TAny* aPtr); +protected: + TSglQueLink* iHead; + TSglQueLink* iLast; + TInt iOffset; + TInt iElements; +private: + friend class TSglQueIterBase; + }; + + +template +class TSglQue : public TSglQueBase + { +public: + inline TSglQue(TInt aOffset); + inline void AddLast(T& aRef); + inline void Remove(T& aRef); + inline TInt Elements() const; + }; + + +class TSglQueIterBase + { +public: + void SetToFirst(); +protected: + TSglQueIterBase(TSglQueBase& aQue); + TAny* DoPostInc(); + TAny* DoCurrent(); +protected: + TInt iOffset; + TSglQueLink*& iHead; + TSglQueLink* iNext; + }; + + +template +class TSglQueIter : public TSglQueIterBase + { +public: + inline TSglQueIter(TSglQueBase& aQue); + inline operator T*(); + inline T* operator++(TInt); + }; + +// +// --- Inline implementations --- +// + +// Class TSglQue +template +inline TSglQue::TSglQue(TInt aOffset) + : TSglQueBase(aOffset) + {} + + +template +inline void TSglQue::AddLast(T& aRef) + { + DoAddLast(&aRef); + } + + +template +inline void TSglQue::Remove(T& aRef) + { + DoRemove(&aRef); + } + + +template +inline TInt TSglQue::Elements() const + { + return iElements; + } + + +// Class TSglQueIter +template +inline TSglQueIter::TSglQueIter(TSglQueBase& aQue) + : TSglQueIterBase(aQue) + {} + + +template +inline TSglQueIter::operator T*() + { + return ((T*)DoCurrent()); + } + +template +inline T* TSglQueIter::operator++(TInt) + { + return ((T*)DoPostInc()); + } + + +#endif // __USBCQUE_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcsc.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcsc.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,500 @@ +// Copyright (c) 2000-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\include\drivers\usbcsc.h +// Kernel side definitions for the USB Device driver stack (PIL + LDD). +// +// + +/** + @file usbcsc.h + @internalTechnology +*/ + +#ifndef __USBCSC_H__ +#define __USBCSC_H__ + +#include +#include +#include +#include + +#include + +// #include +#include + +/** LDD Major version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcScMajorVersion = 0; + +/** LDD Minor version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcScMinorVersion = 1; + +/** LDD Build version, This should agree with the information in RDevUsbcClient::TVer. +*/ +const TInt KUsbcScBuildVersion = KE32BuildVersionNumber; + +/** Must correspond to the max enum of TRequest + 1; + currently this is ERequestOtgFeaturesNotify = 10. +*/ +const TInt KUsbcScMaxRequests = 11; + +// Request queue sizes need to be power of 2. + +/** The number of requests that can be queued on any IN endpoint */ +const TInt KUsbcScInRequests = 4; +/** The number of requests that can be queued on any OUT endpoint */ +const TInt KUsbcScOutRequests = 2; + +/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an IN endpoint */ +const TInt KUsbcScIn = 0; +/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an OUT endpoint */ +const TInt KUsbcScOut = 1; + + +/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an Bidirectional endpoint +currently operating as an IN endpoint */ +const TInt KUsbcScBiIn = 2; +/** In TUsbcScBuffer.iDirection, this indicates that the endpoint is an Bidirectional endpoint +currently operating as an OUT endpoint */ +const TInt KUsbcScBiOut = 3; + +/** The number of directions supported for endpoints, other then EP0. Currently 2, IN and OUT. */ +const TInt KUsbcScDirections = 2; + +/** In TUsbcScBuffer::iDirection, this indicates that the endpoint direction is Unknown. */ +const TInt KUsbcScUnknown = 4; + +const TInt KPageSize = 0x1000; + +/** The default buffer size requested for a endpoint, if the user app does not specify a size.*/ +const TInt KUsbcScDefaultBufferSize = 0x10000; // 64k + +/** The size of the unmapped region of memory between endpoint buffers. +This serves as a guard region, making memory over/under runs more obviose.*/ +const TInt KGuardSize = KPageSize; + +/** The size put aside for the chunk header structre.*/ +const TInt KHeaderSize = KPageSize; + +/** For buffers of size >= KUsbScBigBuffIs, The smallest unit of continiouse memory that will be used. +No read will be set up smaller then this, to avoid overly fragmenting the data. +*/ +const TInt KUsbSc_BigBuff_MinimumRamRun = KPageSize; + +/** For buffers of size < KUsbScBigBuffIs, The smallest unit of continiouse memory that will be used. +No read will be set up smaller then this, to avoid overly fragmenting the data.*/ +const TInt KUsbSc_SmallBuff_MinimumRamRun = 1024; + +/** The size a buffer request has to be to switch to using KUsbSc_BigBuff_MinimumRamRun. +If the requested buffer is smaller, then the smallest memory allocated to a buffer is KPageSize*/ +const TInt KUsbScBigBuffIs = KPageSize*6; + + + +// EP0 is mapped manually, unlike the other endpoints. + +/** The position, within the chunk, that the EP0 IN buffer appears*/ +const TInt KUsbScEP0InBufPos = 0x800; +/** The position, within the chunk, that the EP0 IN buffer ends*/ +const TInt KUsbScEP0InBufEnd = KUsbScEP0InBufPos + 0x400; + +// Its better for Out to go 2nd, so gaurd page after it. +/** The position, within the chunk, that the EP0 OUT buffer appears*/ +const TInt KUsbScEP0OutBufPos = 0xc00; +/** The position, within the chunk, that the EP0 OUT buffer ends*/ +const TInt KUsbScEP0OutBufEnd = KUsbScEP0OutBufPos + 0x400; + +/** The number of the entry within the chunk BufferRecord table, for the OUT ep0 buffer.*/ +const TInt KUsbcScEp0OutBuff = 0; +/** The number of the entry within the chunk BufferRecord table, for the IN ep0 buffer.*/ +const TInt KUsbcScEp0InBuff = 1; + + +// +//########################### Logical Device Driver (LDD) ############################# +// + +/** USB LDD factory class. +*/ +class DUsbcScLogDevice : public DLogicalDevice + { +public: + DUsbcScLogDevice(); + virtual TInt Install(); + virtual void GetCaps(TDes8& aDes) const; + virtual TInt Create(DLogicalChannelBase*& aChannel); + }; + + +class DLddUsbcScChannel; +class TUsbcScBuffer; +/** Endpoint tracking for the LDD buffering etc. +*/ +class TUsbcScEndpoint + { +public: + TUsbcScEndpoint(DLddUsbcScChannel* aLDD, DUsbClientController* aController, + const TUsbcScEndpointInfo* aEndpointInfo, TInt aEndpointNum + ); + ~TUsbcScEndpoint(); + TInt Construct(); + void CancelTransfer(DThread* aThread); + void AbortTransfer(); + inline TUsbcScEndpointInfo* EndpointInfo(); + inline TInt RxBytesAvailable() const; + inline void ResetTransferInfo(); + inline void SetClientReadPending(TBool aVal); + inline void SetClientWritePending(TBool aVal); + inline TBool ClientWritePending(); + inline TBool ClientReadPending(); + inline void SetRealEpNumber(TInt aRealEpNumber); + inline TInt RealEpNumber() const; + inline TInt EpNumber() const; + inline void StartBuffer(); + inline void SetBuffer(TUsbcScBuffer* aBuffer); + inline TUsbcScBuffer* GetBuffer(); + + +private: + static void RequestCallback(TAny* aTUsbcScEndpoint); + void TxComplete(); + TInt RxComplete(TBool aReEntrant); + void RxCompleteNow(); + + + +public: + TUsbcRequestCallback* iRequestCallbackInfo; + +private: + DUsbClientController* iController; + TUsbcScEndpointInfo iEndpointInfo; + TBool iClientReadPending; + TBool iClientWritePending; + TInt iEndpointNumber; + TInt iRealEpNumber; + DLddUsbcScChannel* iLdd; + TInt iError; + TUint32 iBytesTransferred; + TInt iBandwidthPriority; + TUsbcScBuffer* iBuffer; + + }; + + +/** Linked list of 'alternate setting' info for use by the LDD. +*/ +class TUsbcScAlternateSetting + { +public: + TUsbcScAlternateSetting(); + ~TUsbcScAlternateSetting(); + +public: + TUsbcScAlternateSetting* iNext; + TUsbcScAlternateSetting* iPrevious; + TInt iNumberOfEndpoints; + TUint iSetting; + TUsbcScEndpoint* iEndpoint[KMaxEndpointsPerClient + 1]; + }; + +class TUsbcScAlternateSettingList + { +public: + TUsbcScAlternateSettingList(); + ~TUsbcScAlternateSettingList(); + +public: + TUsbcScAlternateSetting* iHead; + TUsbcScAlternateSetting* iTail; + }; + +class TUsbcScChunkInfo + { +public: + TUsbcScChunkInfo(DLogicalDevice* aLdd); + TInt CreateChunk(TInt aTotalSize); + void Close(); + TInt ChunkAlloc(TInt aOffset, TInt aSize); + void ChunkCleanup(); + TInt GetPhysical(TInt aOffset, TPhysAddr* aPhysical); + static TInt New(TUsbcScChunkInfo*& aChunk, TInt aSize, DLogicalDevice* aLdd); +private: + TUint* iPhysicalMap; +public: + DChunk* iChunk; + TDfc iCleanup; + + TInt8 iPageNtz; // Number of trailing zeros for a page. (Eg 4k page has 12 t.z.) + TInt iAllocatedSize; + TInt8* iChunkMem; + TUint32 iChunkMapAttr; + DLogicalDevice* iLdd; + }; + + +// Used to represent a matrix of endpoints with a column of sizes. +// Used by TRealizeInfo + +class TEndpointSortBufs + { + public: + TUsbcScEndpoint** iEp; + TInt* iSizes; + TInt iEps; + }; + +// This is used to calculate the layout of the shared chunk +// based on a list of alternative settings / endpoints provided. + +class TRealizeInfo + { + public: + void Init(TUsbcScAlternateSettingList* aAlternateSettingList); + TInt CopyAndSortEndpoints(); + void CalcBuffSizes(); + void Free(); + + void LayoutChunkHeader(TUsbcScChunkInfo* aChunkInfo); + public: + TInt iMaxEndpoints; + TInt iTotalSize; + TInt iTotalBuffers; + TInt iAltSettings; + TEndpointSortBufs iBufs[KUsbcScDirections]; + TUsbcScAlternateSettingList* iAlternateSettingList; + + // Chunk layout info. + TUsbcScChunkBuffersHeader* iChunkStuct; + TUsbcScChunkAltSettingHeader* iAltSettingsTbl; + }; + + + +/** The channel class - the actual USB LDD. +*/ +class DLddUsbcScChannel : public DLogicalChannel + { +public: + DLddUsbcScChannel(); + ~DLddUsbcScChannel(); + virtual void HandleMsg(TMessageBase* aMsg); + virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); + virtual TInt RequestUserHandle(DThread* aThread, TOwnerType aType); + inline DThread* Client() const {return iClient;} + inline TBool ChannelClosing() const {return iChannelClosing;} + inline TUint AlternateSetting() const {return iAlternateSetting;} + + static void RequestCallbackEp0(TAny* aTUsbcScChannel); + +private: + + TInt DoCancel(TInt aReqNo, TUint aMask, TUint a1); + TInt DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2); + TInt DoControl(TInt aFunction, TAny* a1, TAny* a2); + TInt DoReadDataNotify(TRequestStatus* aStatus, TInt aBufferNum, TInt aLength); + void StartDataRead(TInt aBufferNum); + TInt DoWriteData(TRequestStatus* aStatus,TInt aBufferNum, TUint aStart, TUint aLength, TUint aFlags); + TBool AlternateDeviceStateTestComplete(); + TInt SetInterface(TInt aInterfaceNum, TUsbcScIfcInfo* aUserInterfaceInfoBuf); + void StartEpReads(); + void DestroyAllInterfaces(); + void DestroyInterface(TUint aInterface); + void DestroyEp0(); + inline TBool ValidEndpoint(TInt aEndpoint); + TInt GetRealEpForEpResource(TInt aEndpoint, TInt& aRealEp); + inline TBool Configured(); + TInt DoEmergencyComplete(); + void ReadDes8(const TAny* aPtr, TDes8& aDes); + TInt SetupEp0(); + void CancelNotifyEndpointStatus(); + void CancelNotifyOtgFeatures(); + static void StatusChangeCallback(TAny* aDLddUsbcChannel); + static void EndpointStatusChangeCallback(TAny* aDLddUsbcChannel); + static void OtgFeatureChangeCallback(TAny* aDLddUsbcChannel); + static void EmergencyCompleteDfc(TAny* aDLddUsbcChannel); + void DeConfigure(TInt aErrorCode); + TInt SelectAlternateSetting(TUint aAlternateSetting); + TInt EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint); + TInt ProcessAlternateSetting(TUint aAlternateSetting); + TInt32 StartNextInAlternateSetting(); + TInt ProcessDeviceState(TUsbcDeviceState aDeviceState); + void ResetInterface(TInt aErrorCode); + void PanicClientThread(TInt aReason); + + TInt RealizeInterface(void); + +private: + DUsbClientController* iController; + DThread* iClient; + TBool iValidInterface; + + TUsbcScAlternateSettingList* iAlternateSettingList; + TUsbcScEndpoint** iEndpoint; // Pointer to the current endpoint set. + + static const TInt KUsbcMaxRequests = RDevUsbcScClient::ERequestMaxRequests; + TRequestStatus* iRequestStatus[KUsbcMaxRequests]; + TUsbcClientCallback iCompleteAllCallbackInfo; + TAny* iStatusChangePtr; + TUsbcStatusCallback iStatusCallbackInfo; + TAny* iEndpointStatusChangePtr; + TUsbcEndpointStatusCallback iEndpointStatusCallbackInfo; + TAny* iOtgFeatureChangePtr; + TUsbcOtgFeatureCallback iOtgFeatureCallbackInfo; + TUint8* iBufferBaseEp0; + TInt iBufferSizeEp0; + TInt iNumberOfEndpoints; + TUsbcDeviceState iDeviceState; + TUsbcDeviceState iOldDeviceState; + TBool iOwnsDeviceControl; + TUint16 iAlternateSetting; + TUint16 iAsSeq; + + TUsbcDeviceStatusQueue* iStatusFifo; + TBool iUserKnowsAltSetting; + TBool iDeviceStatusNeeded; + TBool iChannelClosing; + TBool iRealizeCalled; + + TUsbcScChunkInfo* iChunkInfo; + TInt iNumBuffers; + TUsbcScBuffer *iBuffers; + + TUsbcScEndpoint* iEp0Endpoint; + TInt iEP0InBuff; + TInt iEP0OutBuff; + + friend class TUsbcScBuffer; + friend void TUsbcScEndpoint::AbortTransfer(); + }; + +/** +This class is used by TUsbcScStatusList to form a queue of status requests. +These requests are on a buffer basis, so that all buffers can have at least two requests +pending, at the same time. (i.e. buffer 1 could have two requests outstanding, as well as 2 on buffer 2.) +*/ + +class TUsbcScStatusElement +{ +public: + TRequestStatus* iStatus; + TInt iLength; + TUint iStart; + TUint iFlags; +}; + +enum TUsbcScStatusState +{ + ENotRunning, + EInProgress, + EReadingAhead, + EFramgementInProgress +}; + +class TUsbcScStatusList +{ +public: + TInt Construct(TInt aSize, DThread* aThread); + void Destroy(); + + TUsbcScStatusElement* Next(); + void Pop(); + TInt Add(TRequestStatus* aStatus, TInt aLength, TUint aStart, TUint aFlags); + void CancelQueued(TInt aErrorCode=KErrCancel); + TInt Complete(TInt aError); + void Complete(); +public: + TUsbcScStatusState iState; + +private: + DThread* iClient; + TInt iHead; // The element at the head of the queue, ie, the earliest added, and next to be removed. + TInt iLength; // Length of queue, ie number of elements within + TInt iSize; // size of array, ie, max # of requests at a time. + TUsbcScStatusElement* iElements; + +}; + + + +/** +This class holds the kernel's copy of all the details related to a shared endpoint buffer, +and provides methods for the LDD to manipulate it. +*/ +class TUsbcScBuffer +{ +public: + static const TInt8 KNoEpAssigned=0; + static const TInt8 KEpIsEnding=1; + static const TInt8 KEpIsStarting=2; + +public: + TInt Construct(TInt aDirection, DLddUsbcScChannel* aLdd, TInt aBufferOffset, TInt aBufferEndOffset, TInt aMinReadSize, TInt aMaxPacketSize, TInt aMaxReadSize); + void CreateChunkBufferHeader(); + void StartEndpoint(TUsbcRequestCallback* iRequestInfo, TUint iFlags); + + void Destroy(); + + TInt StartDataRead(); + void CompleteRead(TBool aStartNextRead=ETrue); + void PopStall(); + void StartDataWrite(); + void CompleteWrite(); + void Cancel(TInt aErrorCode); + + void UpdateBufferList(TInt aByteCount,TUint aFlags, TBool aStartNextRead=ETrue); + void Ep0CancelLddRead(); + void SendEp0StatusPacket(TInt aState); + +public: + + TInt8 iDirection; + TInt8 iMode; + TInt8 iNeedsPacket; + TInt8 iReserved; + DLddUsbcScChannel* iLdd; + TLinAddr iChunkAddr; + SUsbcScBufferHeader* iBufferStart; + TUint iBufferEnd; // One word on from the last word in the buffer. + TUint iAlignMask; + TUsbcScStatusList iStatusList; + TUsbcRequestCallback* iCallback; + union + { + TInt iHead; // Out endpoints only; + TUint iSent; // In endpoints only + }; + TUsbcScChunkInfo* iChunkInfo; + TInt iMinReadSize; + TInt iMaxReadSize; + TInt iMaxPacketSize; // 0 indicates unconfiured. + TInt iFirstPacket; + TInt iStalled; + + // needed for backwards compatibility + TUsbcPacketArray iIndexArray[KUsbcDmaBufNumMax]; // Has 2 elements + TUsbcPacketArray iSizeArray[KUsbcDmaBufNumMax]; // Has 2 elements +#ifdef _DEBUG + TUint iSequence; +#endif + +}; + + + +#include + +#endif // __USBCSC_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcsc.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcsc.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,107 @@ +// Copyright (c) 2008-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\include\drivers\usbcsc.inl +// Kernel side inline header file for USB device driver. +// +// + +/** + @file usbcsc.inl + @internalTechnology +*/ + +#ifndef __USBCSC_INL__ +#define __USBCSC_INL__ + + +// +// --- USB Logical Device Driver (LDD) --- +// + +TUsbcScEndpointInfo* TUsbcScEndpoint::EndpointInfo() + { + return &iEndpointInfo; + } + + +void TUsbcScEndpoint::SetClientReadPending(TBool aVal) + { + iClientReadPending = aVal; + } + + +TBool TUsbcScEndpoint::ClientReadPending() + { + return iClientReadPending; + } + + +void TUsbcScEndpoint::SetClientWritePending(TBool aVal) + { + iClientWritePending = aVal; + } + + +TBool TUsbcScEndpoint::ClientWritePending() + { + return iClientWritePending; + } + + +void TUsbcScEndpoint::SetRealEpNumber(TInt aRealEpNumber) + { + iRealEpNumber = aRealEpNumber; + iRequestCallbackInfo->iRealEpNum = aRealEpNumber; + } + + +TInt TUsbcScEndpoint::RealEpNumber() const + { + return iRealEpNumber; + } +TInt TUsbcScEndpoint::EpNumber() const + { + return iEndpointNumber; + } +void TUsbcScEndpoint::StartBuffer() + { + iBuffer->StartEndpoint(iRequestCallbackInfo, iEndpointInfo.iFlags); + } + +void TUsbcScEndpoint::SetBuffer(TUsbcScBuffer* aBuffer) + { + __ASSERT_ALWAYS(iBuffer==NULL, Kern::Fault("TUsbcScEndpoint::SetBuffer", __LINE__)); + iBuffer = aBuffer; + } + +TUsbcScBuffer* TUsbcScEndpoint::GetBuffer() + { + __ASSERT_DEBUG(iBuffer!=NULL, Kern::Fault("TUsbcScEndpoint::GetBuffer", __LINE__)); + return iBuffer; + } + +inline TBool DLddUsbcScChannel::ValidEndpoint(TInt aEndpoint) + { + return (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0); + } + +inline TBool DLddUsbcScChannel::Configured() + { + if (iValidInterface && + (iDeviceState == UsbShai::EUsbPeripheralStateConfigured || iDeviceState == UsbShai::EUsbPeripheralStateSuspended)) + return ETrue; + return EFalse; + } + +#endif // __USBCSC_INL__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcshared.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcshared.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,997 @@ +// Copyright (c) 2000-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\include\drivers\usbcshared.h +// Kernel side definitions for the USB Device driver stack (PIL + LDD). +// +// + +/** + @file usbcshared.h + @internalTechnology +*/ + +#ifndef __USBCSHARED_H__ +#define __USBCSHARED_H__ + +//#include +#include + +// Define here what options are required: +// (USB_SUPPORTS_CONTROLENDPOINTS and USB_SUPPORTS_SET_DESCRIPTOR_REQUEST +// have never been tested though...) +//#define USB_SUPPORTS_CONTROLENDPOINTS +//#define USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + +//#include +#include +//#include +#include + +#include +#include + +#include + +// FIXME: Remove this typedef once PIL and LDD are ready for SHAI +typedef UsbShai::TUsbPeripheralEvent TUsbcDeviceEvent; +typedef UsbShai::TUsbPeripheralPacketArray TUsbcPacketArray; + +// Forward declaration +class DControlTransferManager; +class TUsbcSetup; + +// Debug Support + +// Use for debugging purposes only (commented out for normal operation): +//#define USBC_LDD_BUFFER_TRACE + +static const char KUsbPILPanicCat[] = "USB PIL FAULT"; // kernel fault category +_LIT(KUsbPILKillCat, "USB PIL KILL"); // thread kill category +_LIT(KUsbLDDKillCat, "USB LDD KILL"); // thread kill category + +/** Error code for stalled endpoint. +*/ +const TInt KErrEndpointStall = KErrLocked; + +/** Error code for Ep0 write prematurely ended by a host OUT token. +*/ +const TInt KErrPrematureEnd = KErrDiskFull; + +/** The following constants control the buffer arrangement for OUT transfers (IN transfers have only 1 + buffer). The total size of buffering for an OUT endpoint will be number of buffers * buffersize, + so that, for example, a Bulk OUT endpoint will have KUsbcDmaBufNumBulk * KUsbcDmaBufSzBulk bytes of + buffering. + These buffers will be physically contiguous, so that DMA may be used. + The number of buffers MUST be >=2 - otherwise the buffering scheme won't work. + The buffer sizes should be an exact fraction of 4kB and the number of buffers such that the + buffersize * number of buffers is an exact multiple of 4kB, otherwise memory will be wasted. +*/ +/** Size of a Control ep buffer. +*/ +const TInt KUsbcDmaBufSzControl = 1024; + +/** Size of a Bulk ep buffer. +*/ +const TInt KUsbcDmaBufSzBulk = 4096; + +/** Size of an Interrupt ep buffer. +*/ +const TInt KUsbcDmaBufSzInterrupt = 4096; + +/** Size of an Isochronous ep buffer. +*/ +const TInt KUsbcDmaBufSzIsochronous = 4096; + +/** Number of buffers for Control OUT endpoints. +*/ +const TInt KUsbcDmaBufNumControl = 2; + +/** Number of buffers for Isochronous OUT endpoints. +*/ +const TInt KUsbcDmaBufNumIsochronous = 2; + +/** Number of buffers for Bulk OUT endpoints. +*/ +const TInt KUsbcDmaBufNumBulk = 2; + +/** Number of buffers for Interrupt OUT endpoints. +*/ +const TInt KUsbcDmaBufNumInterrupt = 2; + +/** Maximum buffer number. +*/ +const TInt KUsbcDmaBufNumMax = MAX4(KUsbcDmaBufNumControl, KUsbcDmaBufNumIsochronous, + KUsbcDmaBufNumBulk, KUsbcDmaBufNumInterrupt); + +/** Maximum number of recorded packets possible. +*/ +const TUint KUsbcDmaBufMaxPkts = 2; + +/** Number of arrays. +*/ +const TInt KUsbcDmaBufNumArrays = 2; + +/** Max size that Ep0 packets might have. +*/ +const TInt KUsbcBufSzControl = 64; + +/** The Ep0 RX data collection buffer area. + (Arbitrary size, judged to be sufficient for SET_DESCRIPTOR requests) +*/ +const TInt KUsbcBufSz_Ep0Rx = 1024; + +/** The Ep0 TX buffer area. + (Size sufficient to hold as much data as can be requested via GET_DESCRIPTOR) +*/ +const TInt KUsbcBufSz_Ep0Tx = 1024 * 64; + + +/** The USB version the stack is compliant with: 2.0 (BCD). +*/ +const TUint16 KUsbcUsbVersion = 0x0200; + +/** Maximum number of endpoints an interface (i.e. LDD) may have. +*/ +const TInt KUsbcMaxEpNumber = 5; + +/** Status FIFO depth; enough for 2 complete configs. +*/ +const TInt KUsbDeviceStatusQueueDepth = 15; + +/** = 'no status info'. +*/ +const TUint32 KUsbDeviceStatusNull = 0xffffffffu; + +/** = 'no buffer available'. +*/ +const TInt KUsbcInvalidBufferIndex = -1; + +/** = 'no packet available'. +*/ +const TUint KUsbcInvalidPacketIndex = (TUint)(-1); + +/** = 'no drainable buffers'. +*/ +const TInt KUsbcInvalidDrainQueueIndex = -1; + +/** Number of possible bandwidth priorities. +*/ +const TInt KUsbcDmaBufMaxPriorities = 4; + +// The following buffer sizes are used within the LDD for the different +// user-selectable endpoint bandwidth priorities +// (EUsbcBandwidthOUTDefault/Plus1/Plus2/Maximum + the same for 'IN'). +// These values, in particular those for the Maximum setting, were obtained +// empirically. + +/** Bulk IN buffer sizes for different priorities (4K, 16K, 64K, 512K). +*/ +const TInt KUsbcDmaBufSizesBulkIN[KUsbcDmaBufMaxPriorities] = + {KUsbcDmaBufSzBulk, 0x4000, 0x10000, 0x80000}; + +/** Bulk OUT buffer sizes for different priorities (4K, 16K, 64K, 512K). +*/ +const TInt KUsbcDmaBufSizesBulkOUT[KUsbcDmaBufMaxPriorities] = + {KUsbcDmaBufSzBulk, 0x4000, 0x10000, 0x80000}; + +/** Number of UDCs supported in the system. + (Support for more than one UDC is preliminary.) +*/ +const TInt KUsbcMaxUdcs = 2; + +/** Number of endpoints a USB device can have. + (30 regular endpoints + 2 x Ep0) +*/ +const TInt KUsbcEpArraySize = KUsbcMaxEndpoints + 2; + +/** Number of notification requests of the same kind that can be registered at + a time. As normally not more than one request per kind per LDD is + permitted, this number is roughly equivalent to the maximum number of LDDs + that can be operating at the same time. + This constant is used by the PIL while maintaining its request lists + (iClientCallbacks, iStatusCallbacks, iEpStatusCallbacks, iOtgCallbacks) to + ensure that the lists are of a finite length and thus the list traverse + time is bounded. + This value is chosen with the maximum number of USB interfaces (not + settings) allowed by the spec for a single device in mind. +*/ +const TInt KUsbcMaxListLength = 256; + +/** + * device event FIFO depth, there are 5 different event define currently, + * 10 should be enough + */ +const TInt KUsbDeviceEventQueueDepth = 10; + +/** USB LDD client callback. +*/ +class TUsbcClientCallback + { +public: + inline TUsbcClientCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority); + inline DBase* Owner() const; + inline TInt DoCallback(); + inline void Cancel(); + inline void SetDfcQ(TDfcQue* aDfcQ); +public: + /** Used by the PIL to queue callback objects into a TSglQue. */ + TSglQueLink iLink; +private: + DBase* iOwner; + TDfc iDfc; + }; + + +/** The endpoint halt/clear_halt status. +*/ +class TUsbcEndpointStatusCallback + { +public: + inline TUsbcEndpointStatusCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority); + inline void SetState(TUint aState); + inline TUint State() const; + inline DBase* Owner() const; + inline TInt DoCallback(); + inline void Cancel(); + inline void SetDfcQ(TDfcQue* aDfcQ); +public: + /** Used by the PIL to queue callback objects into a TSglQue. */ + TSglQueLink iLink; +private: + DBase* iOwner; + TDfc iDfc; + TUint iState; + }; + + +/** Maximum number of device status requests that can be queued at a time. + The value chosen is thought to be sufficient in all situations. +*/ +const TInt KUsbcDeviceStateRequests = 8; + + +/** The USB device status. +*/ +class TUsbcStatusCallback + { +public: + inline TUsbcStatusCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority); + inline void SetState(UsbShai::TUsbPeripheralState aState); + inline UsbShai::TUsbPeripheralState State(TInt aIndex) const; + inline void ResetState(); + inline DBase* Owner() const; + inline TInt DoCallback(); + inline void Cancel(); + inline void SetDfcQ(TDfcQue* aDfcQ); +public: + /** Used by the PIL to queue callback objects into a TSglQue. */ + TSglQueLink iLink; +private: + DBase* iOwner; + TDfc iDfc; + UsbShai::TUsbPeripheralState iState[KUsbcDeviceStateRequests]; + }; + + +/** A USB transfer request. + + @publishedPartner + @released +*/ +class TUsbcRequestCallback : public UsbShai::TUsbPeripheralRequest + { +public: + /** @internalTechnology */ + inline TUsbcRequestCallback(const DBase* aOwner, TInt aEndpointNum, TDfcFn aDfcFunc, + TAny* aEndpoint, TDfcQue* aDfcQ, TInt aPriority); + /** @internalTechnology */ + inline ~TUsbcRequestCallback(); + + IMPORT_C void SetRxBufferInfo(TUint8* aBufferStart, + TUintPtr aBufferAddr, + TUint32* aPacketIndex, + TUint32* aPacketSize, + TInt aLength); + + IMPORT_C void SetTxBufferInfo(TUint8* aBufferStart, + TUintPtr aBufferAddr, + TInt aLength); + + /** @internalTechnology */ + inline void SetTransferDirection(UsbShai::TTransferDirection aTransferDir); + /** @internalTechnology */ + inline const DBase* Owner() const; + /** @internalTechnology */ + inline TInt DoCallback(); + /** @internalTechnology */ + inline void Cancel(); +public: + /** Used by the PIL to queue callback objects into a TSglQue. + @internalTechnology + */ + TSglQueLink iLink; +public: + /** The endpoint number. */ + const TInt iEndpointNum; + + /** Indicates the LDD client for this transfer. */ + const DBase* const iOwner; + /** DFC, used by PIL to call back the LDD when transfer completes to the LDD. */ + TDfc iDfc; + }; + +/** USB On-The-Go feature change callback. +*/ +class TUsbcOtgFeatureCallback + { +public: + inline TUsbcOtgFeatureCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority); + inline void SetFeatures(TUint8 aFeatures); + inline TUint8 Features() const; + inline DBase* Owner() const; + inline TInt DoCallback(); + inline void Cancel(); + inline void SetDfcQ(TDfcQue* aDfcQ); +public: + /** Used by the PIL to queue callback objects into a TSglQue. */ + TSglQueLink iLink; +private: + DBase* iOwner; + TDfc iDfc; + TUint8 iValue; + }; + +// +//########################### Physical Device Driver (PIL + PSL) ###################### +// + +class TUsbcLogicalEndpoint; + +/** This models a physical (real) endpoint of the UDC. +*/ +class TUsbcPhysicalEndpoint + { +public: + TUsbcPhysicalEndpoint(); + ~TUsbcPhysicalEndpoint(); + TBool EndpointSuitable(const TUsbcEndpointInfo* aEpInfo, TInt aIfcNumber) const; // Check Todo, SC will pass pointer to derived class + TInt TypeAvailable(TUint aType) const; + TInt DirAvailable(TUint aDir) const; +public: + /** This endpoint's capabilities. */ + UsbShai::TUsbPeripheralEndpointCaps iCaps; + /** USB address: 0x00, 0x80, 0x01, 0x81, etc. */ + TUint8 iEndpointAddr; + /** Pointer to interface # this endpoint has been assigned to. */ + const TUint8* iIfcNumber; + /** Pointer to corresponding logical endpoint or NULL. */ + const TUsbcLogicalEndpoint* iLEndpoint; + /** Only used when searching for available endpoints. */ + TBool iSettingReserve; + /** True if endpoint is halted (i.e. issues STALL handshakes), false otherwise. */ + TBool iHalt; + }; + + +class DUsbClientController; +class TUsbcInterface; + +/** This is a 'logical' endpoint, as used by our device configuration model. +*/ +class TUsbcLogicalEndpoint + { +public: + TUsbcLogicalEndpoint(DUsbClientController* aController, TUint aEndpointNum, + const TUsbcEndpointInfo& aEpInfo, TUsbcInterface* aInterface, + TUsbcPhysicalEndpoint* aPEndpoint); // Check Todo, SC will pass pointer to derived class + ~TUsbcLogicalEndpoint(); +public: + /** Pointer to controller object. */ + DUsbClientController* iController; + /** The virtual (logical) endpoint number. */ + const TInt iLEndpointNum; + /** This endpoint's info structure. */ + TUsbcEndpointInfo iInfo; // Check Todo, SC will pass pointer to derived class + /** Stores the endpoint size to be used for FS. */ + TInt iEpSize_Fs; + /** Stores the endpoint size to be used for HS. */ + TInt iEpSize_Hs; + /** 'Back' pointer. */ + const TUsbcInterface* iInterface; + /** Pointer to corresponding physical endpoint, never NULL. */ + TUsbcPhysicalEndpoint* const iPEndpoint; + }; + + +class TUsbcInterfaceSet; + +/** This is an 'alternate setting' of an interface. +*/ +class TUsbcInterface + { +public: + TUsbcInterface(TUsbcInterfaceSet* aIfcSet, TUint8 aSetting, TBool aNoEp0Requests); + ~TUsbcInterface(); +public: + /** Array of endpoints making up (belonging to) this setting. */ + RPointerArray iEndpoints; + /** 'Back' pointer. */ + TUsbcInterfaceSet* const iInterfaceSet; + /** bAlternateSetting (zero-based). */ + const TUint8 iSettingCode; + /** KUsbcInterfaceInfo_NoEp0RequestsPlease: stall non-std Setup requests. */ + const TBool iNoEp0Requests; + }; + + +/** This is an 'interface' (owning 1 or more alternate settings). + + @see TUsbcInterface +*/ +class TUsbcInterfaceSet + { +public: + TUsbcInterfaceSet(const DBase* aClientId, TUint8 aIfcNum); + ~TUsbcInterfaceSet(); + inline const TUsbcInterface* CurrentInterface() const; + inline TUsbcInterface* CurrentInterface(); +public: + /** Array of alternate settings provided by (belonging to) this interface. */ + RPointerArray iInterfaces; + /** Pointer to the LDD which created and owns this interface. */ + const DBase* const iClientId; + /** bInterfaceNumber (zero-based). */ + TUint8 iInterfaceNumber; + /** bAlternateSetting (zero-based). */ + TUint8 iCurrentInterface; + }; + + +/** This is a 'configuration' of the USB device. + Currently we support only one configuration. +*/ +class TUsbcConfiguration + { +public: + TUsbcConfiguration(TUint8 aConfigVal); + ~TUsbcConfiguration(); +public: + /** Array of interfaces making up (belonging to) this configuration. */ + RPointerArray iInterfaceSets; + /** bConfigurationValue (one-based). */ + const TUint8 iConfigValue; + }; + + +/** The USB controller's power handler class. +*/ +NONSHARABLE_CLASS(DUsbcPowerHandler) : public DPowerHandler + { +public: + void PowerUp(); + void PowerDown(TPowerState); +public: + DUsbcPowerHandler(DUsbClientController* aController); +private: + DUsbClientController* iController; + }; + + +/* +This is the EndpointInfo class used by the usb shared chunk client driver. +*/ + +class TUsbcScEndpointInfo; + + +/** +Used to represent an array of (or inheriting from) TUsbcEndpointInfo objects. + +@see DUsbClientController::SetInterface +*/ + +class TUsbcEndpointInfoArray + { +public: + typedef enum {EUsbcEndpointInfo, EUsbcScEndpointInfo} TArrayType; + + TUsbcEndpointInfoArray(const TUsbcEndpointInfo* aData, TInt aDataSize=0); + TUsbcEndpointInfoArray(const TUsbcScEndpointInfo* aData, TInt aDataSize=0); + inline TUsbcEndpointInfo& operator[](TInt aIndex) const; + + TArrayType iType; +private: + TUint8* iData; + TInt iDataSize; + }; + +class TUsbPeriDeviceEventQueue + { +public: + TUsbPeriDeviceEventQueue(); + + void FifoAdd(TUsbcDeviceEvent aDeviceStatus); + TUsbcDeviceEvent FifoGet(); + +private: + TUsbcDeviceEvent iDeviceEventQueue[KUsbDeviceEventQueueDepth]; + TInt iDeviceQueueHead; + TInt iDeviceQueueTail; + }; + +class TUsbcRequestCallback; // todo?? required only for class below + +/** The USB Device software controller class. + + Implements the platform-independent layer (PIL), and defines the interface to the + platform-specific layer PSL). + + The implementation of the platform-specific layer interfaces with the hardware. +*/ +NONSHARABLE_CLASS(DUsbClientController) : public DBase, + public MUsbOtgPeripheralControlIf, + public UsbShai::MUsbPeripheralPilCallbackIf, + public MControlTransferIf, + public UsbShai::MChargerDetectorObserverIf + { + friend class UsbShai::UsbPeripheralPil; + friend class TUsbHostWrapperEntry; + friend class DUsbcPowerHandler; + friend TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint(); + // + // --- Platform Independent Layer (PIL) --- + // + + +private: + /** + * Two-phase constructor used by the friend classes that receive + * the registration calls for peripheral controllers. + * + * @param aPeripheralControllerIf Reference to the Peripheral + * Controller interface implemented by the registering PSL. + * + * @param aProperties Reference to an object describing the + * static properties of the Peripheral Controller. The PIL + * layer requires that the supplied reference remains valid + * indefinitely, as a Peripheral Controller cannot unregister. + * + * @param aIsOtgPort ETrue if this Peripheral Controller is part + * of an OTG port. EFalse otherwise. + * + * @return Pointer to a new instance or NULL if failed + */ + IMPORT_C static DUsbClientController* Create(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, + const UsbShai::TPeripheralControllerProperties& aProperties, + TBool aIsOtgPort); + + +public: + + // + // --- The following functions constitute the PIL interface to the LDD --- + // + virtual ~DUsbClientController(); + IMPORT_C void DisableClientStack(); + IMPORT_C void EnableClientStack(); + IMPORT_C TBool IsActive(); + IMPORT_C TInt RegisterClientCallback(TUsbcClientCallback& aCallback); + IMPORT_C static DUsbClientController* UsbcControllerPointer(TInt aUdc=0); + IMPORT_C void EndpointCaps(const DBase* aClientId, TDes8 &aCapsBuf) const; + IMPORT_C void DeviceCaps(const DBase* aClientId, TDes8 &aCapsBuf) const; + IMPORT_C TInt SetInterface(const DBase* aClientId, DThread* aThread, TInt aInterfaceNum, + TUsbcClassInfo& aClass, TDesC8* aString, TInt aTotalEndpointsUsed, + const TUsbcEndpointInfo aEndpointData[], TInt (*aRealEpNumbers)[6], + TUint32 aFeatureWord); + IMPORT_C TInt SetInterface(const DBase* aClientId, DThread* aThread, + TInt aInterfaceNum, TUsbcClassInfo& aClass, + TDesC8* aString, TInt aTotalEndpointsUsed, + const TUsbcEndpointInfoArray aEndpointData, + TInt aRealEpNumbers[], TUint32 aFeatureWord); + IMPORT_C TInt ReleaseInterface(const DBase* aClientId, TInt aInterfaceNum); + IMPORT_C TInt ReEnumerate(); + IMPORT_C TInt PowerUpUdc(); + IMPORT_C TInt UsbConnect(); + IMPORT_C TInt UsbDisconnect(); + IMPORT_C TInt RegisterForStatusChange(TUsbcStatusCallback& aCallback); + IMPORT_C TInt DeRegisterForStatusChange(const DBase* aClientId); + IMPORT_C TInt RegisterForEndpointStatusChange(TUsbcEndpointStatusCallback& aCallback); + IMPORT_C TInt DeRegisterForEndpointStatusChange(const DBase* aClientId); + IMPORT_C TInt GetInterfaceNumber(const DBase* aClientId, TInt& aInterfaceNum) const; + IMPORT_C TInt DeRegisterClient(const DBase* aClientId); + IMPORT_C TInt Ep0PacketSize() const; + IMPORT_C TInt Ep0Stall(const DBase* aClientId); + IMPORT_C void SendEp0StatusPacket(const DBase* aClientId); + IMPORT_C UsbShai::TUsbPeripheralState GetDeviceStatus() const; + IMPORT_C TEndpointState GetEndpointStatus(const DBase* aClientId, TInt aEndpointNum) const; + IMPORT_C TInt SetupReadBuffer(TUsbcRequestCallback& aCallback); + IMPORT_C TInt SetupWriteBuffer(TUsbcRequestCallback& aCallback); + IMPORT_C void CancelReadBuffer(const DBase* aClientId, TInt aRealEndpoint); + IMPORT_C void CancelWriteBuffer(const DBase* aClientId, TInt aRealEndpoint); + IMPORT_C TInt HaltEndpoint(const DBase* aClientId, TInt aEndpointNum); + IMPORT_C TInt ClearHaltEndpoint(const DBase* aClientId, TInt aEndpointNum); + IMPORT_C TInt SetDeviceControl(const DBase* aClientId); + IMPORT_C TInt ReleaseDeviceControl(const DBase* aClientId); + IMPORT_C TUint EndpointZeroMaxPacketSizes() const; + IMPORT_C TInt SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize); + IMPORT_C TInt GetDeviceDescriptor(DThread* aThread, TDes8& aDeviceDescriptor); + IMPORT_C TInt SetDeviceDescriptor(DThread* aThread, const TDes8& aDeviceDescriptor); + IMPORT_C TInt GetDeviceDescriptorSize(DThread* aThread, TDes8& aSize); + IMPORT_C TInt GetConfigurationDescriptor(DThread* aThread, TDes8& aConfigurationDescriptor); + IMPORT_C TInt SetConfigurationDescriptor(DThread* aThread, const TDes8& aConfigurationDescriptor); + IMPORT_C TInt GetConfigurationDescriptorSize(DThread* aThread, TDes8& aSize); + IMPORT_C TInt SetOtgDescriptor(DThread* aThread, const TDesC8& aOtgDesc); + IMPORT_C TInt GetOtgDescriptor(DThread* aThread, TDes8& aOtgDesc) const; + IMPORT_C TInt GetOtgFeatures(DThread* aThread, TDes8& aFeatures) const; + IMPORT_C TInt GetCurrentOtgFeatures(TUint8& aFeatures) const; + IMPORT_C TInt RegisterForOtgFeatureChange(TUsbcOtgFeatureCallback& aCallback); + IMPORT_C TInt DeRegisterForOtgFeatureChange(const DBase* aClientId); + IMPORT_C TInt GetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TDes8& aInterfaceDescriptor); + IMPORT_C TInt SetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + const TDes8& aInterfaceDescriptor); + IMPORT_C TInt GetInterfaceDescriptorSize(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TDes8& aSize); + IMPORT_C TInt GetEndpointDescriptor(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, TDes8& aEndpointDescriptor); + IMPORT_C TInt SetEndpointDescriptor(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, const TDes8& aEndpointDescriptor); + IMPORT_C TInt GetEndpointDescriptorSize(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, TDes8& aSize); + IMPORT_C TInt GetDeviceQualifierDescriptor(DThread* aThread, TDes8& aDeviceQualifierDescriptor); + IMPORT_C TInt SetDeviceQualifierDescriptor(DThread* aThread, const TDes8& aDeviceQualifierDescriptor); + IMPORT_C TInt GetOtherSpeedConfigurationDescriptor(DThread* aThread, TDes8& aConfigurationDescriptor); + IMPORT_C TInt SetOtherSpeedConfigurationDescriptor(DThread* aThread, const TDes8& aConfigurationDescriptor); + IMPORT_C TInt GetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TDes8& aInterfaceDescriptor); + IMPORT_C TInt SetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + const TDes8& aInterfaceDescriptor, TInt aSize); + IMPORT_C TInt GetCSInterfaceDescriptorBlockSize(DThread* aThread, const DBase* aClientId, + TInt aSettingNum, TDes8& aSize); + IMPORT_C TInt GetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, TDes8& aEndpointDescriptor); + IMPORT_C TInt SetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, const TDes8& aEndpointDescriptor, + TInt aSize); + IMPORT_C TInt GetCSEndpointDescriptorBlockSize(DThread* aThread, const DBase* aClientId, TInt aSettingNum, + TInt aEndpointNum, TDes8& aSize); + IMPORT_C TInt GetStringDescriptorLangId(DThread* aThread, TDes8& aLangId); + IMPORT_C TInt SetStringDescriptorLangId(TUint16 aLangId); + IMPORT_C TInt GetManufacturerStringDescriptor(DThread* aThread, TDes8& aString); + IMPORT_C TInt SetManufacturerStringDescriptor(DThread* aThread, const TDes8& aString); + IMPORT_C TInt RemoveManufacturerStringDescriptor(); + IMPORT_C TInt GetProductStringDescriptor(DThread* aThread, TDes8& aString); + IMPORT_C TInt SetProductStringDescriptor(DThread* aThread, const TDes8& aString); + IMPORT_C TInt RemoveProductStringDescriptor(); + IMPORT_C TInt GetSerialNumberStringDescriptor(DThread* aThread, TDes8& aString); + IMPORT_C TInt SetSerialNumberStringDescriptor(DThread* aThread, const TDes8& aString); + IMPORT_C TInt RemoveSerialNumberStringDescriptor(); + IMPORT_C TInt GetConfigurationStringDescriptor(DThread* aThread, TDes8& aString); + IMPORT_C TInt SetConfigurationStringDescriptor(DThread* aThread, const TDes8& aString); + IMPORT_C TInt RemoveConfigurationStringDescriptor(); + IMPORT_C TInt GetStringDescriptor(DThread* aThread, TUint8 aIndex, TDes8& aString); + IMPORT_C TInt SetStringDescriptor(DThread* aThread, TUint8 aIndex, const TDes8& aString); + IMPORT_C TInt RemoveStringDescriptor(TUint8 aIndex); + IMPORT_C TBool QueryEndpointResource(const DBase* aClientId, TInt aEndpointNum, + TUsbcEndpointResource aResource); + IMPORT_C TInt EndpointPacketSize(const DBase* aClientId, TInt aEndpointNum); + + // Called by LDD + IMPORT_C TDfcQue* DfcQ(TInt aIndex); + IMPORT_C void DumpRegisters(); + IMPORT_C TInt SignalRemoteWakeup(); + IMPORT_C TBool CurrentlyUsingHighSpeed(); + + TInt RegisterUdc(TInt aUdc); + +protected: + + // From base class MUsbPeripheralPilCallbackIf + void EnablePeripheralStack(); + void DisablePeripheralStack(); + void SetOtgObserver(MUsbOtgPeripheralObserverIf* aObserver); + + // Function derived from MUsbPeripheralPilCallbackIf + UsbShai::TControlStage EnquireEp0NextStage(const TUint8* aSetupBuf) const; + TInt Ep0RequestComplete(TInt aRealEndpoint, TInt aCount, TInt aError,UsbShai::TControlPacketType aPktType); + void EndpointRequestComplete(UsbShai::TUsbPeripheralRequest* aCallback); + TInt DeviceEventNotification(TUsbcDeviceEvent aEvent); + void MoveToAddressState(); + TInt ProcessSetConfiguration(const TUsbcSetup& aPacket); + void HandleHnpRequest(TInt aHnpState); + void GetEp0RxBufferInfo(TUint8*& aBuffer, TInt& aBufferLen); + void SetRmWakeupStatusEnabled(TBool aRmEnabled); + UsbShai::TUsbPeripheralState DeviceStatus() const; + TBool Ep0ReceivedNonStdRequest(); + + // Functions derived from MControlTransferIf + // PSL -> PIL + void ProcessDataInPacket(TInt aCount,TInt aErrCode); + void ProcessStatusInPacket(TInt aErrCode); + void ProcessDataOutPacket(TInt aCount,TInt aErrCode); + void ProcessStatusOutPacket(TInt aErrCode); + void ProcessSetupPacket(TInt aCount,TInt aErrCode); + + // Request from PIL -> PSL + TInt ProcessSetupEndpointZeroRead(); + TInt ProcessSetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd=EFalse); + TInt ProcessSendEp0ZeroByteStatusPacket(); + TInt ProcessStallEndpoint(TInt aRealEndpoint); + + // Flow control PIL <--> PSL + void ProcessEp0SetupPacketProceed(); + void ProcessEp0DataPacketProceed(); + + // Functions from MChargerDetectorObserverIf + void NotifyPortType(UsbShai::TPortType aPortType); + // + // + // --- Functions and data members provided by PIL, called by PSL --- + // +private: + struct TUsbPeripheralDescriptorPool + { + TUsbcDeviceDescriptor* iDeviceDesc; + TUsbcConfigDescriptor* iConfigDesc; + TUsbcLangIdDescriptor* iLangId; + TUsbcStringDescriptor* iManufacturer; + TUsbcStringDescriptor* iProduct; + TUsbcStringDescriptor* iSerialNum; + TUsbcStringDescriptor* iConfig; + TUsbcOtgDescriptor* iOtgDesc; + }; + +private: + // Internal functions that used in Construct only + // This function will new a set of descriptors + TBool CreateDescriptors(TUsbPeripheralDescriptorPool& aOutput); + + TBool Initialise(TUsbPeripheralDescriptorPool& aDescPool, + const UsbShai::TUsbPeripheralEndpointCaps* aEndpointCaps, + TInt aTotalEndpoint); + + DUsbClientController(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, + const UsbShai::TPeripheralControllerProperties& aProperties, + TBool aIsOtgPort); + + TInt Construct(); + + void ProcessStandardRequest(TInt aCount,const TUsbcSetup& aPacket); + void ProcessNonStandardRequest(TInt aCount,const TUsbcSetup& aPacket); + + const DBase* FindNonStandardRequestClient(TUint8 aPacketTypeDestination,const TUsbcSetup& aPacket); + + TInt SetupEp0StateMachine(); + +private: + + /** This info can be used by the PSL before sending ZLPs. + + @publishedPartner @released + */ + TBool iEp0ReceivedNonStdRequest; + + /** True if RMW is currently enabled (set by either PIL or PSL). + + @publishedPartner @released + */ + TBool iRmWakeupStatus_Enabled; + + /** Ep0 incoming (rx) data is placed here (one packet). + + @publishedPartner @released + */ + TUint8 iEp0_RxBuf[KUsbcBufSzControl]; + +private: + + // + // --- Private member functions (used by PIL) --- + // + TInt DeRegisterClientCallback(const DBase* aClientId); + TBool CheckEpAvailability(TInt aEndpointsUsed, const TUsbcEndpointInfoArray& aEndpointData, TInt aIfcNumber) + const; + TUsbcInterface* CreateInterface(const DBase* aClientId, TInt aIfc, TUint32 aFeatureWord); + TInt CreateEndpoints(TUsbcInterface* aIfc, TInt aEndpointsUsed, const TUsbcEndpointInfoArray& aEndpointData, + TInt *aRealEpNumbers); + TInt SetupIfcDescriptor(TUsbcInterface* aIfc, TUsbcClassInfo& aClass, DThread* aThread, TDesC8* aString, + const TUsbcEndpointInfoArray& aEndpointData); + TInt ClientId2InterfaceNumber(const DBase* aClientId) const; + TUsbcInterfaceSet* ClientId2InterfacePointer(const DBase* aClientId) const; + const DBase* InterfaceNumber2ClientId(TInt aIfcSet) const; + TUsbcInterfaceSet* InterfaceNumber2InterfacePointer(TInt aIfcSet) const; + inline const DBase* PEndpoint2ClientId(TInt aRealEndpoint) const; + inline TInt PEndpoint2LEndpoint(TInt aRealEndpoint) const; + TInt ActivateHardwareController(); + void DeActivateHardwareController(); + void DeleteInterfaceSet(TInt aIfcSet); + void DeleteInterface(TInt aIfcSet, TInt aIfc); + void CancelTransferRequests(TInt aRealEndpoint); + void DeleteRequestCallback(const DBase* aClientId, TInt aEndpointNum, UsbShai::TTransferDirection aTransferDir); + void DeleteRequestCallbacks(const DBase* aClientId); + void StatusNotify(UsbShai::TUsbPeripheralState aState, const DBase* aClientId=NULL); + void EpStatusNotify(TInt aRealEndpoint); + void OtgFeaturesNotify(); + void RunClientCallbacks(); + void ProcessDataTransferDone(TUsbcRequestCallback& aRcb); + void NextDeviceState(UsbShai::TUsbPeripheralState aNextState); + TInt ProcessSuspendEvent(); + TInt ProcessSuspendEventProceed(); + TInt ProcessResumeEvent(); + TInt ProcessResetEvent(TBool aPslUpcall=ETrue); + TInt ProcessVbusRisenEvent(); + TInt ProcessVbusFallenEvent(); + + void ProcessGetDeviceStatus(const TUsbcSetup& aPacket); + void ProcessGetInterfaceStatus(const TUsbcSetup& aPacket); + void ProcessGetEndpointStatus(const TUsbcSetup& aPacket); + void ProcessSetClearDevFeature(const TUsbcSetup& aPacket); + void ProcessSetClearIfcFeature(const TUsbcSetup& aPacket); + void ProcessSetClearEpFeature(const TUsbcSetup& aPacket); + void ProcessSetAddress(const TUsbcSetup& aPacket); + void ProcessGetDescriptor(const TUsbcSetup& aPacket); + void ProcessSetDescriptor(const TUsbcSetup& aPacket); + void ProcessGetConfiguration(const TUsbcSetup& aPacket); + void ProcessGetInterface(const TUsbcSetup& aPacket); + void ProcessSetInterface(const TUsbcSetup& aPacket); + void ProcessSynchFrame(const TUsbcSetup& aPacket); + + void ProceedSetDescriptor(); + void ProcessDeviceEventNotification(TUsbcDeviceEvent aEvent); + + void SetClearHaltFeature(TInt aRealEndpoint, TUint8 aRequest); + TInt ClearHaltFeature(TInt aRealEndpoint); + void ChangeConfiguration(TUint16 aValue); + void InterfaceSetup(TUsbcInterface* aIfc); + void InterfaceSetTeardown(TUsbcInterfaceSet* aIfc); + void ChangeInterface(TUsbcInterface* aIfc); + TInt DoForEveryEndpointInUse(TInt (DUsbClientController::*aFunction)(TInt), TInt& aCount); + void EnterFullSpeed(); + void EnterHighSpeed(); + TInt EvaluateOtgConnectFlags(); + inline const TUsbcConfiguration* CurrentConfig() const; + inline TUsbcConfiguration* CurrentConfig(); + inline TBool InterfaceExists(TInt aNumber) const; + inline TBool EndpointExists(TUint aAddress) const; + void Buffer2Setup(const TAny* aBuf, TUsbcSetup& aSetup) const; + inline TUint EpIdx2Addr(TUint aRealEndpoint) const; + inline TUint EpAddr2Idx(TUint aAddress) const; + inline void SetEp0DataOutVars(const DBase* aClientId = NULL); + inline void ResetEp0DataOutVars(); + inline TBool IsInTheStatusList(const TUsbcStatusCallback& aCallback); + inline TBool IsInTheEpStatusList(const TUsbcEndpointStatusCallback& aCallback); + inline TBool IsInTheOtgFeatureList(const TUsbcOtgFeatureCallback& aCallback); + inline TBool IsInTheRequestList(const TUsbcRequestCallback& aCallback); + static void ReconnectTimerCallback(TAny* aPtr); + static void CableStatusTimerCallback(TAny* aPtr); + static void PowerUpDfc(TAny* aPtr); + static void PowerDownDfc(TAny* aPtr); + static void DeviceEventNotifyDfc(TAny* aPtr); + static void ThreadContextFinderDfc(TAny* aPtr); + +private: + + // + // --- Private data members --- + // + + static DUsbClientController* UsbClientController[KUsbcMaxUdcs]; + + TInt iDeviceTotalEndpoints; // number of endpoints reported by PSL + TInt iDeviceUsableEndpoints; // number of endpoints reported to LDD + + UsbShai::TUsbPeripheralState iDeviceState; // states as of USB spec chapter 9.1 + UsbShai::TUsbPeripheralState iDeviceStateB4Suspend; // state before entering suspend state + + TBool iSelfPowered; // true if device is capable of beeing self-powered + TBool iRemoteWakeup; // true if device is capable of signalling rmwakeup + TBool iHardwareActivated; // true if controller silicon is in operating state + TBool iOtgSupport; // true if OTG is supported by this device + TUint8 iOtgFuncMap; // bitmap indicating OTG extension features + TBool iHighSpeed; // true if currently operating at high-speed + + TInt iEp0MaxPacketSize; // currently configured max packet size for Ep0 + const DBase* iEp0ClientId; // see comment at the begin of ps_usbc.cpp + TUint16 iEp0DataReceived; // indicates how many bytes have already been received + TBool iEp0WritePending; // true if a write on ep0 has been set up + TBool iEp0ClientDataTransmitting; // true if ep0's in DATA_IN on behalf of a client + const DBase* iEp0DeviceControl; // Device Ep0 requests are delivered to this LDD + + TUsbcDescriptorPool iDescriptors; // the descriptors as of USB spec chapter 9.5 + TUint8 iCurrentConfig; // bConfigurationValue of current Config (1-based!) + RPointerArray iConfigs; // the root of the modelled USB device + TUsbcPhysicalEndpoint iRealEndpoints[KUsbcEpArraySize]; // array will be filled once at startup + TUint8 iEp0_TxBuf[KUsbcBufSz_Ep0Tx]; // ep0 outgoing (tx) data is placed here +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + TUint8 iEp0_RxCollectionBuf[KUsbcBufSz_Ep0Rx]; // used for (optional) SET_DESCRIPTOR request +#endif + TInt iEp0_RxExtraCount; // number of bytes received but not yet delivered + TBool iEp0_RxExtraData; // true if iEp0_RxExtraCount is valid + TInt iEp0_TxNonStdCount; // number of bytes requested by non-std Ep0 request + + TUsbcRequestCallback* iRequestCallbacks[KUsbcEpArraySize]; // xfer requests; indexed by real ep number + TSglQue iEp0ReadRequestCallbacks; // list of ep0 read requests + TSglQue iClientCallbacks; // registered LDD clients and their callback functions + TSglQue iStatusCallbacks; // list of device state notification requests + TSglQue iEpStatusCallbacks; // list of endpoint state notification requests + TSglQue iOtgCallbacks; // list of OTG feature change requests + + NTimer iReconnectTimer; // implements USB re-enumeration delay + NTimer iCableStatusTimer; // implements USB cable status detection delay + DUsbcPowerHandler* iPowerHandler; // pointer to USB power handler object + TSpinLock iUsbLock; // implement SMP for USB PDD and LDD + NFastMutex iMutex; // To pretect interface set with NFastMutex + UsbShai::MPeripheralControllerIf& iController; // PSL code + + const UsbShai::TPeripheralControllerProperties& iControllerProperties; // Static configuration from PSL + TBool iIsOtgPort; // Is this instance a driver for otg port, + // Set at construction time. + + /** + * Pointer to the currently set OTG Observer, if any. Not owned. + */ + MUsbOtgPeripheralObserverIf* iOtgObserver; // Otg interface which is used to listen event from DeviceEventNotification + + DControlTransferManager* iConTransferMgr; // Usb Control transfer manager, responsible for chaptor9 + + TInt iLastError; // Used by chaptor9 sm. No else. + TBool iSetupPacketPending; // Indicate whether the no-req-callback data is a setup packet + + TUsbPeriDeviceEventQueue iDevEventQueue; // PSL can call DeviceEventNotification(...) at any context, + // but for PIL, we want to serialize the execution of each event + + // The thread context for the DfcQ pass by PSL to us. + NThread* iCommonDfcQThread; + +protected: + TDfc iPowerUpDfc; // queued by power handler upon power-up + TDfc iPowerDownDfc; // queued by power handler upon power-down + TDfc iDeviceEventNotifyDfc; // queued by device event notification + TDfc iThreadContextFinder; // this is used to find which thread does the DfcQ passed by PSL + // is runing. + +private: + TBool iStandby; // toggled by power handler as appropriate + TBool iStackIsActive; // client stack's function is usable + TBool iClientSupportReady; // user-side USB Client support is loaded & active + TBool iUsbResetDeferred; // set when user-side wasn't ready yet + +public: + // FIXME: These used to be filled by the OTG component Dummy DCD + // so that the PIL layer can call it to enable and disable the D+ + // pull-up. This mechanism is no longer used + TInt (*iEnablePullUpOnDPlus)(TAny* aOtgContext); + TInt (*iDisablePullUpOnDPlus)(TAny* aOtgContext); + TAny* iOtgContext; + }; + +/** Simple queue of status changes to be recorded. + Items are fetched by userside when able. +*/ +class TUsbcDeviceStatusQueue + { +public: + TUsbcDeviceStatusQueue(); + void AddStatusToQueue(TUint32 aDeviceStatus); + TInt GetDeviceQueuedStatus(TUint32& aDeviceStatus); + void FlushQueue(); + +private: + TUint32 iDeviceStatusQueue[KUsbDeviceStatusQueueDepth]; + TInt iStatusQueueHead; + }; + +#include + +#endif // __USBCSHARED_H__ diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbcshared.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbcshared.inl Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,571 @@ +// Copyright (c) 2000-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\include\drivers\usbcshared.inl +// Kernel side definitions for the USB Device driver stack (PIL + LDD). +// +// + +/** + @file usbcshared.inl + @internalTechnology +*/ + +#ifndef __USBCSHARED_INL__ +#define __USBCSHARED_INL__ + +// +// --- DUsbClientController (USB PDD) --- +// + +// --- Private member functions, used by controller itself --- + +const DBase* DUsbClientController::PEndpoint2ClientId(TInt aRealEndpoint) const + { + if (iRealEndpoints[aRealEndpoint].iLEndpoint) + return iRealEndpoints[aRealEndpoint].iLEndpoint->iInterface->iInterfaceSet->iClientId; + else + return NULL; + } + + +TInt DUsbClientController::PEndpoint2LEndpoint(TInt aRealEndpoint) const + { + if (iRealEndpoints[aRealEndpoint].iLEndpoint) + return iRealEndpoints[aRealEndpoint].iLEndpoint->iLEndpointNum; + else + return -1; + } + + +const TUsbcConfiguration* DUsbClientController::CurrentConfig() const + { + return (iCurrentConfig ? iConfigs[iCurrentConfig - 1] : NULL); + } + + +TUsbcConfiguration* DUsbClientController::CurrentConfig() + { + return (iCurrentConfig ? iConfigs[iCurrentConfig - 1] : NULL); + } + + +TBool DUsbClientController::InterfaceExists(TInt aNumber) const + { + const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); + RPointerArray& ifcsets = iConfigs[0]->iInterfaceSets; + for (TInt i = 0; i < num_ifcsets; i++) + { + if (ifcsets[i]->iInterfaceNumber == aNumber) + { + return ETrue; + } + } + return EFalse; + } + + +TBool DUsbClientController::EndpointExists(TUint aAddress) const + { + // Ep0 doesn't have a "logical ep" pointer (there's no virtual endpoint zero); + // that's why this pointer being non-NULL is not a sufficient criterion for + // endpoint-existence. (Apart from that, ep0 always exists.) + const TInt idx = EpAddr2Idx(aAddress); + return ((idx < iDeviceTotalEndpoints) && + ((iRealEndpoints[idx].iLEndpoint != NULL) || + ((aAddress & KUsbEpAddress_Portmask) == 0))); + } + +TUint DUsbClientController::EpIdx2Addr(TUint aRealEndpoint) const + { + return ((aRealEndpoint << 7) & 0x80) | ((aRealEndpoint >> 1) & 0x0f); + } + + +TUint DUsbClientController::EpAddr2Idx(TUint aAddress) const + { + return ((aAddress & 0x80) >> 7) | ((aAddress & 0x0f) << 1); + } + + +void DUsbClientController::SetEp0DataOutVars(const DBase* aClientId) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEp0DataOutVars()")); + //iSetup = aPacket; + iEp0DataReceived = 0; + iEp0ClientId = aClientId; + } + + +void DUsbClientController::ResetEp0DataOutVars() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ResetEp0DataOutVars()")); + iEp0DataReceived = 0; + iEp0ClientId = NULL; + } + + +TBool DUsbClientController::IsInTheRequestList(const TUsbcRequestCallback& aCallback) + { + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (p == &aCallback) + { + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return ETrue; + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return EFalse; + } + + +TBool DUsbClientController::IsInTheStatusList(const TUsbcStatusCallback& aCallback) + { + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iStatusCallbacks); + TUsbcStatusCallback* p; + while ((p = iter++) != NULL) + { + if (p == &aCallback) + { + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return ETrue; + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return EFalse; + } + + +TBool DUsbClientController::IsInTheEpStatusList(const TUsbcEndpointStatusCallback& aCallback) + { + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iEpStatusCallbacks); + TUsbcEndpointStatusCallback* p; + while ((p = iter++) != NULL) + { + if (p == &aCallback) + { + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return ETrue; + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return EFalse; + } + + +TBool DUsbClientController::IsInTheOtgFeatureList(const TUsbcOtgFeatureCallback& aCallback) + { + const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); + TSglQueIter iter(iOtgCallbacks); + TUsbcOtgFeatureCallback* p; + while ((p = iter++) != NULL) + { + if (p == &aCallback) + { + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return ETrue; + } + } + __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); + return EFalse; + } + +// +// --- Misc classes --- +// + +// --- TUsbcClientCallback + +/** Constructor. + */ +TUsbcClientCallback::TUsbcClientCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority) + : iOwner(aOwner), + iDfc(aCallback, aOwner, aPriority) + {} + + +/** Returns a pointer to the owner of this request. + + @return A pointer to the owner of this request. +*/ +DBase* TUsbcClientCallback::Owner() const + { + return iOwner; + } + + +/** Executes the callback function set by the owner of this request. + + @return KErrNone. +*/ +TInt TUsbcClientCallback::DoCallback() + { + __ASSERT_DEBUG((NKern::CurrentContext() == EThread), Kern::Fault(KUsbPILPanicCat, __LINE__)); + iDfc.Enque(); + return KErrNone; + } + + +/** Cancels the callback function set by the owner of this request. + */ +void TUsbcClientCallback::Cancel() + { + iDfc.Cancel(); + } + + +/** Sets the DFC queue used by the callback function. + @param aDfcQ DFC queue to be set + */ +void TUsbcClientCallback::SetDfcQ(TDfcQue* aDfcQ) + { + iDfc.SetDfcQ(aDfcQ); + } + + +// --- TUsbcEndpointStatusCallback + +/** Constructor. + */ +TUsbcEndpointStatusCallback::TUsbcEndpointStatusCallback(DBase* aOwner, TDfcFn aCallback, + TInt aPriority) + : iOwner(aOwner), + iDfc(aCallback, aOwner, aPriority), + iState(0) + {} + + +/** Sets the state of this request to aState. + + @param aState The new state to be set. +*/ +void TUsbcEndpointStatusCallback::SetState(TUint aState) + { + iState = aState; + } + + +/** Returns the state value of this request. + + @return The state value of this request. +*/ +TUint TUsbcEndpointStatusCallback::State() const + { + return iState; + } + + +/** Returns a pointer to the owner of this request. + + @return A pointer to the owner of this request. +*/ +DBase* TUsbcEndpointStatusCallback::Owner() const + { + return iOwner; + } + + +/** Executes the callback function set by the owner of this request. + + @return KErrNone. +*/ +TInt TUsbcEndpointStatusCallback::DoCallback() + { + if (NKern::CurrentContext() == EThread) + iDfc.Enque(); + else + iDfc.Add(); + return KErrNone; + } + + +/** Cancels the callback function set by the owner of this request. +*/ +void TUsbcEndpointStatusCallback::Cancel() + { + iDfc.Cancel(); + } + + +/** Sets the DFC queue used by the callback function. +*/ +void TUsbcEndpointStatusCallback::SetDfcQ(TDfcQue* aDfcQ) + { + iDfc.SetDfcQ(aDfcQ); + } + + +// --- TUsbcStatusCallback + +/** Constructor. + */ +TUsbcStatusCallback::TUsbcStatusCallback(DBase* aOwner, TDfcFn aCallback, TInt aPriority) + : iOwner(aOwner), + iDfc(aCallback, aOwner, aPriority) + { + ResetState(); + } + + +/** Sets the state of this request to aState (at the first available position + in the state value array). + + @param aState The new state to be set. +*/ +void TUsbcStatusCallback::SetState(UsbShai::TUsbPeripheralState aState) + { + for (TInt i = 0; i < KUsbcDeviceStateRequests; i++) + { + if (iState[i] == UsbShai::EUsbPeripheralNoState) + { + iState[i] = aState; + return; + } + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: KUsbcDeviceStateRequests too small (%d)!", + KUsbcDeviceStateRequests)); + } + + +/** Returns the state value of this request at a certain index. + + @param aIndex The index to be used for referencing the state array. + + @return The state value of this request at aIndex. +*/ +UsbShai::TUsbPeripheralState TUsbcStatusCallback::State(TInt aIndex) const + { + if (aIndex >= 0 && aIndex < KUsbcDeviceStateRequests) + { + return iState[aIndex]; + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aIndex too large (%d)!", aIndex)); + return UsbShai::EUsbPeripheralNoState; + } + } + + +/** Resets the entire state value array of this request. +*/ +void TUsbcStatusCallback::ResetState() + { + for (TInt i = 0; i < KUsbcDeviceStateRequests; ++i) + { + iState[i] = UsbShai::EUsbPeripheralNoState; + } + } + + +/** Returns a pointer to the owner of this request. + + @return A pointer to the owner of this request. +*/ +DBase* TUsbcStatusCallback::Owner() const + { + return iOwner; + } + + +/** Executes the callback function set by the owner of this request. + + @return KErrNone. +*/ +TInt TUsbcStatusCallback::DoCallback() + { + if (NKern::CurrentContext() == EThread) + iDfc.Enque(); + else + iDfc.Add(); + return KErrNone; + } + + +/** Cancels the callback function set by the owner of this request. +*/ +void TUsbcStatusCallback::Cancel() + { + iDfc.Cancel(); + } + + +/** Sets the DFC queue used by the callback function. +*/ +void TUsbcStatusCallback::SetDfcQ(TDfcQue* aDfcQ) + { + iDfc.SetDfcQ(aDfcQ); + } + +// --- TUsbcRequestCallback + +/** Constructor. + */ +TUsbcRequestCallback::TUsbcRequestCallback(const DBase* aOwner, TInt aEndpointNum, TDfcFn aDfcFunc, + TAny* aEndpoint, TDfcQue* aDfcQ, TInt aPriority) + : TUsbPeripheralRequest(-1), + iEndpointNum(aEndpointNum), + iOwner(aOwner), + iDfc(aDfcFunc, aEndpoint, aDfcQ, aPriority) + { + } + + +/** Destructor. + */ +TUsbcRequestCallback::~TUsbcRequestCallback() + { + __KTRACE_OPT(KUSB, Kern::Printf("TUsbcRequestCallback::~TUsbcRequestCallback()")); + iDfc.Cancel(); + } + +/** Sets the transfer direction for this request. + + @param aTransferDir The new transfer direction. +*/ +void TUsbcRequestCallback::SetTransferDirection(UsbShai::TTransferDirection aTransferDir) + { + iTransferDir = aTransferDir; + } + + +/** Returns a pointer to the owner of this request. + + @return A pointer to the owner of this request. +*/ +const DBase* TUsbcRequestCallback::Owner() const + { + return iOwner; + } + + +/** Executes the callback function set by the owner of this request. + + @return KErrNone. +*/ +TInt TUsbcRequestCallback::DoCallback() + { + if (NKern::CurrentContext() == NKern::EThread) + iDfc.Enque(); + else + iDfc.Add(); + return KErrNone; + } + + +/** Cancels the callback function set by the owner of this request. +*/ +void TUsbcRequestCallback::Cancel() + { + iDfc.Cancel(); + } + +// --- TUsbcOtgFeatureCallback + +/** Constructor. + */ +TUsbcOtgFeatureCallback::TUsbcOtgFeatureCallback(DBase* aOwner, TDfcFn aCallback, + TInt aPriority) + : iOwner(aOwner), + iDfc(aCallback, aOwner, aPriority), + iValue(0) + {} + + +/** Returns a pointer to the owner of this request. + @return A pointer to the owner of this request. +*/ +DBase* TUsbcOtgFeatureCallback::Owner() const + { + return iOwner; + } + + +/** Set feature value which is to be notified to client. + @param OTG feature value to be set +*/ +void TUsbcOtgFeatureCallback::SetFeatures(TUint8 aFeatures) + { + iValue = aFeatures; + } + + +/** Set feature value which is to be notified to client. + @return Value of OTG features +*/ +TUint8 TUsbcOtgFeatureCallback::Features() const + { + return iValue; + } + + +/** Set DFC queue. + @param aDfcQ DFC queue to be set +*/ +void TUsbcOtgFeatureCallback::SetDfcQ(TDfcQue* aDfcQ) + { + iDfc.SetDfcQ(aDfcQ); + } + + +/** Executes the callback function set by the owner of this request. + @return KErrNone. +*/ +TInt TUsbcOtgFeatureCallback::DoCallback() + { + if (NKern::CurrentContext() == EThread) + iDfc.Enque(); + else + iDfc.Add(); + return KErrNone; + } + + +/** Cancels the callback function set by the owner of this request. + */ +void TUsbcOtgFeatureCallback::Cancel() + { + iDfc.Cancel(); + } + + +/** Returns a pointer to the currently selected (active) setting of this interface. + + @return A pointer to the currently selected (active) setting of this interface. +*/ +const TUsbcInterface* TUsbcInterfaceSet::CurrentInterface() const + { + return iInterfaces[iCurrentInterface]; + } + + +/** Returns a pointer to the currently selected (active) setting of this interface. + + @return A pointer to the currently selected (active) setting of this interface. +*/ + +TUsbcInterface* TUsbcInterfaceSet::CurrentInterface() + { + return iInterfaces[iCurrentInterface]; + } + +#endif // __USBCSHARED_INL__ + + + diff -r 59aa7d6e3e0f -r 089413cdde3c usbdrv/peripheral/public/usbotgperipheralcontrolif.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/usbdrv/peripheral/public/usbotgperipheralcontrolif.h Fri Jul 23 15:54:47 2010 +0800 @@ -0,0 +1,80 @@ +// Copyright (c) 2000-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\include\drivers\usbcshared.h +// Kernel side definitions for the USB Device driver stack (PIL + LDD). +// +// + +/** + @file usbotgperipheralcontrolif.h + @internalTechnology +*/ + +#ifndef USBOTGPERIPHERALCONTROLIF_H +#define USBOTGPERIPHERALCONTROLIF_H + +#include // For UsbShai::TUsbPeripheralEvent + +/** + * This M-class specifies the observer interface that the OTG state + * machine implements to listen to events of the peripheral stack. + */ +NONSHARABLE_CLASS(MUsbOtgPeripheralObserverIf) + { + public: + /** + * Called by the peripheral stack to report a peripheral event to + * the OTG stack. + * + * @param aEvent An enumeration value specifying the type of event + * that has occurred + */ + virtual void NotifyPeripheralEvent(UsbShai::TUsbPeripheralEvent aEvent) = 0; + }; + + +/** + * This M-class specifies the control interface that the OTG state + * machine uses to control the peripheral stack and register for + * peripheral events. + */ +NONSHARABLE_CLASS(MUsbOtgPeripheralControlIf) + { + public: + /** + * Called by the OTG state machine to enable the peripheral stack. + * When called, the peripheral stack must activate the controller + * and connect to the bus as soon as possible. + */ + virtual void EnablePeripheralStack() = 0; + + /** + * Called by the OTG state machine to disable the peripheral + * stack. When called, the peripheral stack must immediately + * disconnect from the bus and deactivate the controller. + */ + virtual void DisablePeripheralStack() = 0; + + /** + * Called by the OTG state machine to set the peripheral event + * observer. + * + * @param aObserver Pointer to the OTG Observer, or NULL when the + * OTG stack is being shutdown. + */ + virtual void SetOtgObserver(MUsbOtgPeripheralObserverIf* aObserver) = 0; + }; + + +#endif // USBOTGPERIPHERALCONTROLIF_H