--- 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 @@
<?xml version="1.0" encoding="UTF-8"?>
<SystemDefinition schema="3.0.0">
<package id="usb" name="USB" levels="adaptation hw-if plugin framework server app-if">
- <collection id="usbldd" name="USB Logical Device Drivers" level="hw-if">
- <!-- usbclientdrivers to be moved here from kernelhwsrv-->
+ <collection id="usbdrv" name="USB Device Drivers" level="hw-if">
+ <component id="peripheraldrv" name="Usb peripheral driver" purpose="optional">
+ <unit version="1" bldFile="usbdrv/peripheral/group" mrp="usbdrv/peripheral/group/peripheral.mrp"/>
+ </component>
</collection>
<collection id="usbmgmt" name="USB Management" level="server">
<component id="usbmgr" name="USB Manager" purpose="optional">
--- 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
--- /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 <platform_paths.hrh>
+
+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/)
--- /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 <kern_priv.h>
+
+/**
+ * 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
+
--- /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 <kern_priv.h>
+
+/**
+ * @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 */
--- /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 <kern_priv.h>
+#include <usb/usb_common_shai.h> // 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 */
--- /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 <kern_priv.h>
+#include <usb/usb_common_shai.h> // 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 */
--- /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 <kern_priv.h>
+#include <usb/usb_common_shai.h> // Common types shared between the USB SHAIs
+#include <usb/usb_peripheral_shai_shared.h> // 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 <usb/usb_peripheral_shai.inl>
+
+#endif // USB_PERIPHERAL_SHAI_H
+
+// End of File
--- /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
--- /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
+ <kern_priv.h> 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
--- /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
+
--- /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
--- /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 <kernel/kern_ext.mmh>
+
+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
--- /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 <usb/usbc.h>
+
+
+_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<TCapsDevUsbc> 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<TInt>(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<const TDes8*>(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<const TDes8*>(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<TUint>(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;i<KMaxEndpointsPerClient+1;i++ )
+ {
+ bufSizes[i] = -1;
+ epNum[i] = i;
+ }
+
+ // Record the actual buf size of each endpoint
+ for( TInt i=1;i<=num_endpoints;i++ )
+ {
+ bufSizes[i] = alternateSettingListRec->iEndpoint[i]->BufferSize();
+ }
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Sort the endpoints:"));
+
+ // sort the endpoint number by the bufsize decreasely
+ for( TInt i=1;i<num_endpoints;i++ )
+ {
+ TInt epMaxBuf = i;
+ for(TInt k=i+1;k<=num_endpoints;k++ )
+ {
+ if( bufSizes[epMaxBuf]<bufSizes[k])
+ {
+ epMaxBuf = k;
+ }
+ }
+ TInt temp = bufSizes[i];
+ bufSizes[i] = bufSizes[epMaxBuf];
+ bufSizes[epMaxBuf] = temp;
+
+ temp = epNum[i];
+ epNum[i] = epNum[epMaxBuf];
+ epNum[epMaxBuf] = temp;
+
+ alternateSettingListRec->iEpNumDeOrderedByBufSize[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<DPlatChunkHw*> &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<TInt> 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;k<epBufCount;k++)
+ {
+ TInt epBufSize = asRec->iEndpoint[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.Count())&& (chunkInd<bufCount))
+ {
+ TUint8* oldAddr = NULL;
+ oldAddr = reinterpret_cast<TUint8*>(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<TUint8*>(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( chunkInd<bufCount)
+ {
+ DPlatChunkHw* chunk = NULL;
+ chunk = Allocate( bufSizes[chunkInd], aCacheAttribs);
+ if (chunk == NULL)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Failed to alloc chunk, 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
+ __KTRACE_OPT(KUSB, Kern::Printf("SetupInterfaceMemory alloc new chunk=0x%x, size=%d",
+ reinterpret_cast<TUint8*>(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;i<bufferNum;i++)
+ {
+ DPlatChunkHw* chunk = Allocate(bufferSize, cacheAttribs );
+ if(chunk==NULL)
+ {
+ return KErrNoMemory;
+ }
+ TInt r = iHwChunksEp0.Append(chunk);
+ if(r!=KErrNone)
+ {
+ ClosePhysicalChunk(chunk);
+ return r;
+ }
+ TUint8 * buf;
+ buf = (TUint8*) chunk->LinearAddress();
+ 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<DPlatChunkHw*> &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;k<epBufCount;k++)
+ {
+ TUsbcEndpoint* ep = asRec->iEndpoint[nextEp];
+ if (ep != NULL )
+ {
+ TUint8* pBuf = NULL;
+ pBuf = reinterpret_cast<TUint8*>(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;i<iHwChunks.Count();i++)
+ {
+ ClosePhysicalChunk( iHwChunks[i]);
+ }
+ iHwChunks.Close();
+
+ iValidInterface = EFalse;
+ }
+
+
+void DLddUsbcChannel::DestroyInterface(TUint aInterfaceNumber)
+ {
+ if (iAlternateSetting == aInterfaceNumber)
+ {
+ ResetInterface(KErrUsbInterfaceNotReady);
+ iValidInterface = EFalse;
+ iNumberOfEndpoints = 0;
+ for (TInt i = 1; i <= KMaxEndpointsPerClient; i++)
+ {
+ iEndpoint[i] = NULL;
+ }
+ }
+ TUsbcAlternateSettingList* alternateSettingListRec = iAlternateSettingList;
+ TUsbcAlternateSettingList* alternateSettingListRecOld = NULL;
+ while (alternateSettingListRec)
+ {
+ TUsbcAlternateSettingList* alternateSettingListRecNext = alternateSettingListRec->iNext;
+ 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;i<iHwChunks.Count();i++)
+ {
+ ClosePhysicalChunk( iHwChunks[i]);
+ }
+ iHwChunks.Close();
+ }
+ }
+
+
+void DLddUsbcChannel::DestroyEp0()
+ {
+ delete iEndpoint[0];
+ iEndpoint[0] = NULL;
+ for(TInt i=0;i<iHwChunksEp0.Count();i++)
+ {
+ ClosePhysicalChunk( iHwChunksEp0[i] );
+ }
+ iHwChunksEp0.Close();
+ }
+
+
+void DLddUsbcChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcChannel)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback"));
+ DLddUsbcChannel* dUsbc = (DLddUsbcChannel*) aDLddUsbcChannel;
+ if (dUsbc->iChannelClosing)
+ 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;
+}
+
+//---
--- /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 <usb/usbc.h>
+
+
+#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;(i<iNumberofBuffers)&&(remainTxLength>0);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;
+ }
+
--- /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
+
--- /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
--- /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
--- /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 <e32std.h>
+#include <e32std_private.h>
+#include <usb/d32usbcsc.h>
+#include <e32debug.h>
+
+/** @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<KUsbDescSize_Endpoint> 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 <TInt> 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);
+ }
+
--- /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
--- /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 <kernel/kern_ext.mmh>
+
+
+OS_LAYER_SYSTEMINCLUDE
+
+target usbcscshai.ldd
+targettype ldd
+
+sourcepath ../src
+source d_usbcsc.cpp
+
+library usbperipheralpil.lib
+
+uid 0 0x101F8928
+VENDORID 0x70000001
+capability all
--- /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 <drivers/usbcsc.h>
+#include <usb/usbcsc.h>
+#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<TCapsDevUsbc> 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;
+ TUint rleMask = ~pageMask;
+ TUint pageSize = rleMask+1;
+ TInt r;
+ TLinAddr physAddr;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("::chunkalloc AllocPhysicalRam aSize %d", aSize));
+
+ r = Epoc::AllocPhysicalRam(aSize, physAddr);
+ __KTRACE_OPT(KUSB, if (r!=KErrNone) Kern::Printf("::chunkalloc AllocPhysicalRam r=%d (Error!)", r));
+ if (r==KErrNone)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("::chunkalloc ChunkCommitPhysical iChunk 0x%x size(%d), aOffset 0x%x, aSize 0x%x phsAddr 0x%x",
+ iChunk, sizeof(DChunk), aOffset, aSize,physAddr ));
+
+ r = Kern::ChunkCommitPhysical(iChunk, aOffset, aSize, physAddr);
+ __KTRACE_OPT(KUSB, if (r!=KErrNone) Kern::Printf("::chunkalloc ChunkCommitPhysical r=%d (Error!)", r));
+
+ if (r!=KErrNone)
+ Epoc::FreePhysicalRam(physAddr, aSize);
+ else
+ { // record physical address and length in physical map
+ TInt rle;
+ TInt i=0;
+ for (rle=(aSize>>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;
+ TUint val = iPhysicalMap[aOffset>>iPageNtz];
+ *aPhysical=(val & pageMask)+(aOffset & ~pageMask);
+ return ((val & ~pageMask)<<iPageNtz) - (aOffset & ~pageMask);
+ }
+
+
+// DFC calls this fuction, which invokes the cleanup method.
+
+void DfcChunkCleanup(TAny* aChunkInfo)
+ {
+ ((TUsbcScChunkInfo*) aChunkInfo)->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)<<iPageNtz;
+
+ // The part of the field used for the run length encoding, of the contiguous pages.
+ TUint rleMask = ~pageMask;
+ TInt records=(iAllocatedSize>>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<iMinReadSize)
+ {
+ iStatusList.iState=ENotRunning;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Stall!!"));
+ return KErrOverflow; // Read STALL !! !! !!
+ }
+
+ if (freeSpace<maxLength)
+ maxLength = freeSpace;
+ }
+ if (maxLength> iMaxReadSize)
+ maxLength = iMaxReadSize;
+ // else tail<iHead (or empty) _ _ _ T # # # H _ _ _ _
+ // We would not have set iHead here if too small. So must be ok.
+
+ __ASSERT_DEBUG(maxLength>=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 (maxLength<iMinReadSize)
+ {
+ next+=maxLength;
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst Skip exhausted block. next %x max %d", next, maxLength));
+ continue;
+ }
+ }
+ while (EFalse);
+
+ __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst next (pre deduct): %x, Fill in header at head: 0x%x, BuffStart: 0x%x.", next, iHead, iBufferStart));
+
+ next -= headerSize; // Move next back from the data start position, to the header start.
+
+ TUsbcScTransferHeader* header = (TUsbcScTransferHeader*) (iHead + iChunkAddr);
+
+// Create Header
+#ifdef _DEBUG
+ header->iHashId=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 (iLength<iSize)
+ {
+ TUsbcScStatusElement& e = iElements[((iHead+iLength) & (iSize-1))];
+ e.iStatus = aStatus;
+ e.iLength = aLength;
+ e.iStart = aStart;
+ e.iFlags = aFlags;
+ iLength++;
+ __KTRACE_OPT(KUSB,Kern::Printf("Adding request. new iLength %d", iLength));
+
+ return KErrNone;
+ }
+ else
+ return KErrInUse;
+ }
+
+
+
+// This method cancels any requests that have yet to be started.
+
+void TUsbcScStatusList::CancelQueued(TInt aError)
+{
+ if ((iLength==0) || ((iState!=ENotRunning) && (iLength==1))) // Nothing to do.
+ return;
+ TInt elements2Complete = iLength - (iState?1:0);
+ TInt head = iHead;
+ iLength = 0;
+ if (iState) // If (iState != ENotRunning), complete all elements excepting the one at head
+ {
+ head = ((head+1) & (iSize-1)); // To iterate through the queue
+ iLength = 1;
+ }
+ // complete them all.
+ for (; elements2Complete>0; 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; inout<KUsbcScDirections; inout++)
+ {
+ iBufs[inout].iEp = (TUsbcScEndpoint **) Kern::AllocZ(iAltSettings*iMaxEndpoints*sizeof(TUsbcScEndpoint *));
+ iBufs[inout].iSizes = (TInt *) Kern::AllocZ(iMaxEndpoints*sizeof(TInt));
+ }
+}
+
+// CopyAndSortEndpoints
+//
+// This method copies pointers to the endpoint records into TRealizeInfo
+// such that they are sorted in order of size per alt setting.
+// In and Out endpoints are separated, and kept separate.
+// The provided data structure is assumed to have been initialised with
+// Realize_InitRealizeInfo.
+//
+// Return KErrArgument if the direction field is neither In or Out.
+//
+
+TInt TRealizeInfo::CopyAndSortEndpoints()
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: copy And sort"));
+
+ TInt altSetting = 0;
+ TInt endpointOffs;
+ TInt endpoint;
+ TInt altEp;
+ TInt inout;
+ TBool placed;
+ TUsbcScAlternateSetting* alt;
+ TEndpointSortBufs* bufsd;
+
+ if (iAlternateSettingList)
+ {
+ for (alt = iAlternateSettingList->iHead;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; inout<KUsbcScDirections; inout++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: Direction: %d", inout));
+
+
+ bufsd = &(iBufs[inout]);
+ // for each row, ie, buffer, find largest buffer need.
+ for (endpoint=0; endpoint<iMaxEndpoints; endpoint++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpoint %d", endpoint));
+ TInt bufMaxSize=0;
+ for (altSetting=0; altSetting< iAltSettings; altSetting++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: altSetting %d", altSetting));
+ nextEp= bufsd->iEp[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; inout<KUsbcScDirections; inout++)
+ {
+ Kern::Free(iBufs[inout].iEp);
+ Kern::Free(iBufs[inout].iSizes);
+ }
+ }
+
+// End TRealizeInfo
+
+
+// LayoutChunkHeader
+//
+// Sets up some geometry for the chunk;
+
+void TRealizeInfo::LayoutChunkHeader(TUsbcScChunkInfo* aChunkInfo)
+{
+ // First set up the indexes to the header structures.
+ TUsbcScChunkHdrOffs* chkHdr = (TUsbcScChunkHdrOffs*) aChunkInfo->iChunkMem;
+
+ 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; altSetting<iAltSettings; altSetting++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: altSetting %d, tableOffset %d", altSetting, tableOffset));
+
+ iAltSettingsTbl->iAltTableOffset[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::ERequestMaxRequests))
+ {
+ if (iRequestStatus[reqNo])
+ {
+ PanicClientThread(ERequestAlreadyPending);
+ return 0;
+ }
+ iRequestStatus[reqNo] = aStatus;
+ }
+
+ switch (reqNo)
+ {
+ case RDevUsbcScClient::ERequestWriteData:
+ {
+ TInt buffer = (aReqNo>>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; buffer<iNumBuffers; buffer++,mask<<=1)
+ if (aBuff&mask)
+ iBuffers[buffer].Cancel(KErrCancel);
+
+ return KErrNone;
+
+ // coverity[missing_break]
+ case RDevUsbcScClient::ERequestWriteDataCancel:
+ direction = KUsbcScIn;
+ case RDevUsbcScClient::ERequestReadDataNotifyCancel:
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Direction %d endpoints: 0x%x",direction, aReqNo));
+
+ if (((TInt)aBuff)==KUsbcScEndpointZero) // EP0 is bi-directional, so pick correct buffer for call type
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Cancel Endpoint 0/%d",direction));
+ iEp0Endpoint->AbortTransfer();
+ 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<TInt>(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<const TDes8*>(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<const TDes8*>(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<TUint>(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; endpoint<bufInfo.iMaxEndpoints; endpoint++) // endpoint = buf row.
+ {
+ for (inout=KUsbcScIn; inout<KUsbcScDirections; inout++)
+ {
+ buffMinSize = KUsbSc_BigBuff_MinimumRamRun;
+
+ TInt needed = bufInfo.iBufs[inout].iSizes[endpoint];
+ if (needed)
+ {
+ TInt bufStart = offset;
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Realize: buf row:%d inout %d, iBufferOffset[%d+2]=%x",endpoint, inout, buffNum, bufStart));
+
+ bufsd = &(bufInfo.iBufs[inout]);
+ // and then point all endpoints that use it, towards it.
+ TInt altSetting;
+ TUint maxReadSize = ~0;
+ for (altSetting=0; altSetting < bufInfo.iAltSettings; altSetting++)
+ {
+ endpointRecord =bufsd->iEp[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<KUsbScBigBuffIs)
+ {
+ minimumGrab=Kern::RoundToPageSize(1);
+ buffMinSize = KUsbSc_SmallBuff_MinimumRamRun; // 1k
+ }
+ else
+ {
+ minimumGrab = buffMinSize+Kern::RoundToPageSize(1);
+ }
+
+ // Grab required memory, in bits as big as possible, down to the minimum size.
+ while (needed >= minimumGrab)
+ {
+ TInt r;
+ r = iChunkInfo->ChunkAlloc(offset, grabSize);
+ if (r==KErrNone)
+ {
+ offset+=grabSize;
+ needed-=grabSize;
+ }
+ else
+ {
+ if (r==-KErrNoMemory)
+ {
+ grabSize>>=1;
+ }
+ if ((grabSize<minimumGrab) || (r!=-KErrNoMemory))
+ {
+ errorOrChunk = r;
+ goto realize_end;
+ }
+ }
+ } // end while needed
+
+ // Initialize buffer
+ iBuffers[buffNum].Construct(inout, this, bufStart, offset, buffMinSize, 0, maxReadSize);
+ iBuffers[buffNum].CreateChunkBufferHeader();
+ ((TUsbcScBufferRecord*) &(
+ bufInfo.iChunkStuct->iBufferOffset[(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; i<iNumBuffers; i++)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 2 %d",i));
+
+ needsPacket = iBuffers[i].iNeedsPacket;
+ if (needsPacket)
+ {
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 3"));
+ iBuffers[i].UpdateBufferList(0,0,(needsPacket==TUsbcScBuffer::KEpIsStarting));
+ }
+ }
+
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 4"));
+
+ // now update ep0
+ iBuffers[iEP0OutBuff].Ep0CancelLddRead();
+ iBuffers[iEP0OutBuff].UpdateBufferList(0,0);
+ __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 5"));
+
+ }
+
+
+void DLddUsbcScChannel::ResetInterface(TInt aErrorCode)
+ {
+ if (!iValidInterface && !iOwnsDeviceControl)
+ return;
+
+ TInt i;
+ for (i=0; i<iNumBuffers; i++)
+ {
+ iBuffers[i].iNeedsPacket=TUsbcScBuffer::KNoEpAssigned;
+ }
+
+ TUsbcScBuffer* buffer;
+
+ for (i = 1; i <= iNumberOfEndpoints; i++)
+ {
+ // Firstly, cancel ('garbge collect') any stale reads/writes into PIL.
+
+ __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i));
+ iEndpoint[i]->AbortTransfer();
+
+ // 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
+
+//---
+
--- /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
+
--- /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 <platform_paths.hrh>
+
+PRJ_PLATFORMS
+ARMV5
+
+PRJ_MMPFILES
+usbperipheralpil
--- /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 <platform_paths.hrh>
+
+#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
--- /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 <usb/usbc.h>
+
+#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<const TUint16*>(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<KUsbDescSize_Config> 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<TUint16*>(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<TUint16*>(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<TUint16*>(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) <number> 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<TUsbcInterface>& 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) <number> of the current config
+ // (iCurrentConfig) to alternate setting <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<TUsbcLogicalEndpoint>& 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<TUint16*>(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<TUsbcInterfaceSet>& 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<TUsbcInterfaceSet>& 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<TUsbcLogicalEndpoint>& 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<UsbShai::TUsbPeripheralState>(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 <name> 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<TUsbcInterfaceSet>& ifcsets = config->iInterfaceSets;
+ const TInt num_ifcsets = ifcsets.Count();
+ for (TInt i = 0; i < num_ifcsets; i++)
+ {
+ RPointerArray<TUsbcLogicalEndpoint>& 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<TUsbcRequestCallback> 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<TUsbcRequestCallback> 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-
--- /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<const TUint8*>(aSetupBuf)[0];
+ iSetupPkt.iRequest = static_cast<const TUint8*>(aSetupBuf)[1];
+ // TUint16 index from here!
+ iSetupPkt.iValue = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(aSetupBuf))[1]);
+ iSetupPkt.iIndex = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(aSetupBuf))[2]);
+ iSetupPkt.iLength = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(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; i<UsbShai::EControlTransferStageMax; i++)
+ {
+ iState[i] = NULL;
+ }
+
+ Reset();
+ }
+
+TInt DControlTransferManager::SetupEndpointZeroRead()
+ {
+ if(iState[iCurrentStage]->IsRequstAllowed(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
+
--- /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 <kernel/kern_priv.h>
+// #include <drivers/usbc.h>
+#include <usb/usbc.h>
+
+
+// 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<TUint16*>(&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<const TUint16*>(&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<TUint8*>(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<const TUint16*>(&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<TUint16*>(&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<TUint8*>(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 <class T> 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<KUsbDescSize_Device> 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<KUsbDescSize_Config> 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<KUsbDescSize_AudioEndpoint> 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<KUsbDescSize_DeviceQualifier> 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<KUsbDescSize_OtherSpeedConfig> 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<const TUint8*>(&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-
--- /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 <drivers/usbc.h>
+#include <usb/usbc.h>
+
+
+/** 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-
--- /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 <drivers/usbc.h>
+#include <usb/usbc.h>
+
+#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<TUsbcClientCallback> 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<const DLddUsbcChannel*>(aClientId))->Client(),
+ &aCapsBuf, des, 0, KChunkShiftBy0, NULL);
+ if (r != KErrNone)
+ {
+ Kern::ThreadKill((reinterpret_cast<const DLddUsbcChannel*>(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<const DLddUsbcChannel*>(aClientId))->Client(),
+ &aCapsBuf, caps, 0, KChunkShiftBy0, NULL);
+ if (r != KErrNone)
+ {
+ Kern::ThreadKill((reinterpret_cast<const DLddUsbcChannel*>(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<TUsbcPhysicalEndpoint*>
+ (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<TUsbcPhysicalEndpoint*>
+ (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<TUsbcStatusCallback> 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<TUsbcEndpointStatusCallback> 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<TUsbcLogicalEndpoint*>(ep0_0)->iEpSize_Fs = aMaxPacketSize;
+ const_cast<TUsbcLogicalEndpoint*>(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<TUsbcLogicalEndpoint*>(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs;
+ const_cast<TUsbcLogicalEndpoint*>(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<const TUint8*>(&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<const TUint8*>(&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<KUsbDescSize_Otg> 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<TUsbcOtgFeatureCallback> 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<KUsbDescSize_Interface> 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<const TUint8*>(&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<const TUint8*>(&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<const TUint8*>(&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<const TUint8*>(&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<TUsbcLogicalEndpoint>& 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<TUint>(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<TUsbcRequestCallback*>(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<const TUint8*>(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<const TUint8*>(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<const TUint8*>(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<const TUint8*>(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<TUsbcClientCallback> 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<TUsbcLogicalEndpoint*>(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Hs;
+ const_cast<TUsbcLogicalEndpoint*>(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Hs;
+ }
+ else
+ {
+ const_cast<TUsbcLogicalEndpoint*>(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs;
+ const_cast<TUsbcLogicalEndpoint*>(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<TUsbcRequestCallback> 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<TUsbcRequestCallback> 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<TUsbcStatusCallback> 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<TUsbcEndpointStatusCallback> 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<TUsbcOtgFeatureCallback> 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<TUsbcClientCallback> 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<DUsbClientController*>(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<DUsbClientController*>(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<DUsbClientController*>(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<DUsbClientController*>(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<DUsbClientController*>(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<const TUint8*>(aBuf)[0];
+ aSetup.iRequest = static_cast<const TUint8*>(aBuf)[1];
+ // TUint16 index from here!
+ aSetup.iValue = SWAP_BYTES_16((static_cast<const TUint16*>(aBuf))[1]);
+ aSetup.iIndex = SWAP_BYTES_16((static_cast<const TUint16*>(aBuf))[2]);
+ aSetup.iLength = SWAP_BYTES_16((static_cast<const TUint16*>(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-
--- /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 <drivers/usbc.h>
+#include <usb/usbc.h>
+
+
+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);
+ }
+
+
+//---
--- /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 <e32ver.h>
+#include <usb/usb.h>
+#include <usb/d32usbcshared.h>
+
+
+
+/** @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<<EEndpoint0;
+/** Bit position of endpoint1.
+*/
+const TUint KUsbcEndpoint1Bit = 1<<EEndpoint1;
+/** Bit position of endpoint2.
+*/
+const TUint KUsbcEndpoint2Bit = 1<<EEndpoint2;
+/** Bit position of endpoint3.
+*/
+const TUint KUsbcEndpoint3Bit = 1<<EEndpoint3;
+/** Bit position of endpoint4.
+*/
+const TUint KUsbcEndpoint4Bit = 1<<EEndpoint4;
+/** Bit position of endpoint5.
+*/
+const TUint KUsbcEndpoint5Bit = 1<<EEndpoint5;
+
+
+
+
+
+
+
+
+/** This must be filled in prior to a call to RDevUsbcClient::SetInterface().
+*/
+class TUsbcInterfaceInfo
+ {
+public:
+ TUsbcInterfaceInfo(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.
+ */
+ TUsbcEndpointInfo 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<TUsbcInterfaceInfo> 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<<ERequestEp0,
+ ERequestEp1Cancel = 1<<ERequestEp1,
+ ERequestEp2Cancel = 1<<ERequestEp2,
+ ERequestEp3Cancel = 1<<ERequestEp3,
+ ERequestEp4Cancel = 1<<ERequestEp4,
+ ERequestEp5Cancel = 1<<ERequestEp5,
+ ERequestUnusedCancel = 1<<ERequestUnused,
+ ERequestAllCancel = (ERequestEp0Cancel | ERequestEp1Cancel |
+ ERequestEp2Cancel | ERequestEp3Cancel |
+ ERequestEp4Cancel | ERequestEp5Cancel |
+ ERequestUnusedCancel),
+ ERequestAlternateDeviceStatusNotifyCancel = 1<<ERequestAlternateDeviceStatusNotify,
+ ERequestReEnumerateCancel = 1<<ERequestReEnumerate,
+ ERequestEndpointStatusNotifyCancel = 1<<ERequestEndpointStatusNotify,
+ ERequestOtgFeaturesNotify = 10,
+ ERequestOtgFeaturesNotifyCancel = 1<<ERequestOtgFeaturesNotify,
+ };
+
+ enum TControl
+ {
+ // Changing the order of these enums will break BC.
+ EControlEndpointZeroRequestError, // 0
+ EControlEndpointCaps,
+ EControlDeviceCaps,
+ EControlGetAlternateSetting,
+ EControlDeviceStatus,
+ EControlEndpointStatus,
+ EControlSetInterface,
+ EControlReleaseInterface,
+ EControlQueryReceiveBuffer,
+ EControlSendEp0StatusPacket, // 9
+ //
+ EControlHaltEndpoint, // 10
+ EControlClearHaltEndpoint,
+ EControlSetDeviceControl,
+ EControlReleaseDeviceControl,
+ EControlEndpointZeroMaxPacketSizes,
+ EControlSetEndpointZeroMaxPacketSize,
+ EControlGetDeviceDescriptor,
+ EControlSetDeviceDescriptor,
+ EControlGetDeviceDescriptorSize,
+ EControlGetConfigurationDescriptor, // 19
+ //
+ EControlSetConfigurationDescriptor, // 20
+ EControlGetConfigurationDescriptorSize,
+ EControlGetInterfaceDescriptor,
+ EControlSetInterfaceDescriptor,
+ EControlGetInterfaceDescriptorSize,
+ EControlGetEndpointDescriptor,
+ EControlSetEndpointDescriptor,
+ EControlGetEndpointDescriptorSize,
+ EControlGetCSInterfaceDescriptor,
+ EControlSetCSInterfaceDescriptor, // 29
+ //
+ EControlGetCSInterfaceDescriptorSize, // 30
+ EControlGetCSEndpointDescriptor,
+ EControlSetCSEndpointDescriptor,
+ EControlGetCSEndpointDescriptorSize,
+ EControlSignalRemoteWakeup,
+ EControlGetStringDescriptorLangId,
+ EControlSetStringDescriptorLangId,
+ EControlGetManufacturerStringDescriptor,
+ EControlSetManufacturerStringDescriptor,
+ EControlRemoveManufacturerStringDescriptor, // 39
+ //
+ EControlGetProductStringDescriptor, // 40
+ EControlSetProductStringDescriptor,
+ EControlRemoveProductStringDescriptor,
+ EControlGetSerialNumberStringDescriptor,
+ EControlSetSerialNumberStringDescriptor,
+ EControlRemoveSerialNumberStringDescriptor,
+ EControlGetConfigurationStringDescriptor,
+ EControlSetConfigurationStringDescriptor,
+ EControlRemoveConfigurationStringDescriptor,
+ EControlDeviceDisconnectFromHost, // 49
+ //
+ EControlDeviceConnectToHost, // 50
+ EControlDevicePowerUpUdc,
+ EControlDumpRegisters,
+ EControlSetInterface1, // (not used)
+ EControlAllocateEndpointResource,
+ EControlDeAllocateEndpointResource,
+ EControlQueryEndpointResourceUse,
+ EControlGetEndpointZeroMaxPacketSize,
+ EControlGetDeviceQualifierDescriptor,
+ EControlSetDeviceQualifierDescriptor, // 59
+ //
+ EControlGetOtherSpeedConfigurationDescriptor, // 60
+ EControlSetOtherSpeedConfigurationDescriptor,
+ EControlCurrentlyUsingHighSpeed,
+ EControlSetStringDescriptor,
+ EControlGetStringDescriptor,
+ EControlRemoveStringDescriptor,
+ EControlSetOtgDescriptor,
+ EControlGetOtgDescriptor,
+ EControlGetOtgFeatures
+ };
+
+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<TUint8*>(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 <usb/d32usbc.inl>
+
+
+#endif // __D32USBC_H__
--- /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<TDesC8*>(&aDeviceDescriptor));
+ }
+
+
+inline TInt RDevUsbcClient::GetDeviceDescriptorSize(TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*> (&aConfigurationDescriptor));
+ }
+
+
+inline TInt RDevUsbcClient::GetConfigurationDescriptorSize(TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aInterfaceDescriptor));
+ }
+
+
+inline TInt RDevUsbcClient::GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aEndpointDescriptor)};
+ return DoControl(EControlSetEndpointDescriptor, &info, NULL);
+ }
+
+
+inline TInt RDevUsbcClient::GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aDescriptor));
+ }
+
+
+inline TInt RDevUsbcClient::GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor)
+ {
+ return DoControl(EControlGetOtherSpeedConfigurationDescriptor, &aDescriptor);
+ }
+
+
+inline TInt RDevUsbcClient::SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor)
+ {
+ return DoControl(EControlSetOtherSpeedConfigurationDescriptor, const_cast<TDesC8*> (&aDescriptor));
+ }
+
+
+inline TInt RDevUsbcClient::GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor)
+ {
+ return DoControl(EControlGetCSInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor);
+ }
+
+
+inline TInt RDevUsbcClient::GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TInt> 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<TUsbcInterfaceInfoBuf*>(&aInterfaceData);
+ if (!aInterfaceData().iString)
+ {
+ ifcinfo.iString = NULL;
+ }
+ else
+ {
+ name_8.Set(const_cast<TUint8*>(reinterpret_cast<const TUint8*>(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<TDesC8*>(&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<TDesC8*>(&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<TUint16> 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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TDesC8*>(&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<TUint8> 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__
--- /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 <e32ver.h>
+#include <usb/usb.h>
+#include <usb/d32usbcshared.h>
+
+
+/** 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<TUsbcScInterfaceInfo> 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<TUint8*>(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 <usb/d32usbcsc.inl>
+
+#endif // __D32USBCSC_H__
--- /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<TDesC8*>(&aDeviceDescriptor));
+ }
+
+
+inline TInt RDevUsbcScClient::GetDeviceDescriptorSize(TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*> (&aConfigurationDescriptor));
+ }
+
+
+inline TInt RDevUsbcScClient::GetConfigurationDescriptorSize(TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aInterfaceDescriptor));
+ }
+
+
+inline TInt RDevUsbcScClient::GetInterfaceDescriptorSize(TInt aSettingNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aEndpointDescriptor)};
+ return DoControl(EControlSetEndpointDescriptor, &info, NULL);
+ }
+
+
+inline TInt RDevUsbcScClient::GetEndpointDescriptorSize(TInt aSettingNumber, TInt aEndpointNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TDesC8*>(&aDescriptor));
+ }
+
+
+inline TInt RDevUsbcScClient::GetOtherSpeedConfigurationDescriptor(TDes8& aDescriptor)
+ {
+ return DoControl(EControlGetOtherSpeedConfigurationDescriptor, &aDescriptor);
+ }
+
+
+inline TInt RDevUsbcScClient::SetOtherSpeedConfigurationDescriptor(const TDesC8& aDescriptor)
+ {
+ return DoControl(EControlSetOtherSpeedConfigurationDescriptor, const_cast<TDesC8*> (&aDescriptor));
+ }
+
+
+inline TInt RDevUsbcScClient::GetCSInterfaceDescriptorBlock(TInt aSettingNumber, TDes8& aInterfaceDescriptor)
+ {
+ return DoControl(EControlGetCSInterfaceDescriptor,(TAny*) aSettingNumber, &aInterfaceDescriptor);
+ }
+
+
+inline TInt RDevUsbcScClient::GetCSInterfaceDescriptorBlockSize(TInt aSettingNumber, TInt& aSize)
+ {
+ TPckgBuf<TInt> 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<TInt> 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<TUsbcScInterfaceInfoBuf*>(&aInterfaceData);
+ if (!aInterfaceData().iString)
+ {
+ ifcinfo.iString = NULL;
+ }
+ else
+ {
+ name_8.Set(const_cast<TUint8*>(reinterpret_cast<const TUint8*>(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<TDesC8*>(&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<TDesC8*>(&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<TUint16> 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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8*>(reinterpret_cast<const TUint8*>(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<const TUint8*>(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<TUint8> 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__
--- /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 <usb/usb_peripheral_shai_shared.h>
+
+// 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<TUsbDeviceCapsV01> 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 <usb/d32usbcshared.inl>
+
+#endif
--- /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
+
+
--- /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 <e32base.h>
+
+
+/*****************************************************************************/
+/* */
+/* 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
--- /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 <kernel/klib.h>
+#else
+#include <e32base.h>
+#endif
+#include <d32usbdi.h>
+
+
+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
--- /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<TUint8>(aWord & 0x00ff);
+ }
+
+static inline TUint8 HighByte(TUint16 aWord)
+ {
+ return static_cast<TUint8>((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__
--- /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 <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <kernel/kpower.h>
+#include <platform.h>
+
+#include <usb/d32usbc.h>
+
+//#include <drivers/usbcshared.h>
+#include <usb/usbcshared.h>
+
+
+
+/** 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<DPlatChunkHw*> &aHwChunks );
+ void UpdateEndpointSizes();
+ // Check and alloc memory for the interface
+ TInt SetupInterfaceMemory(RArray<DPlatChunkHw*> &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<DPlatChunkHw*> iHwChunksEp0;
+ RArray<DPlatChunkHw*> iHwChunks;
+
+ TUsbcDeviceState iDeviceState;
+ TUsbcDeviceState iOldDeviceState;
+ TBool iOwnsDeviceControl;
+ TUint iAlternateSetting;
+ TBool iDeviceStatusNeeded;
+ TUsbcDeviceStatusQueue* iStatusFifo;
+ TBool iChannelClosing;
+ TVirtualPinObject *iPinObj1;
+ TVirtualPinObject *iPinObj2;
+ TVirtualPinObject *iPinObj3;
+ TClientDataRequest<TUint> *iStatusChangeReq;
+ TClientDataRequest<TUint> *iEndpointStatusChangeReq;
+ TClientDataRequest<TUint> *iOtgFeatureChangeReq;
+ TEndpointTransferInfo iTfrInfo;
+ };
+
+
+#include <usb/usbc.inl>
+
+#endif // __USBC_H__
--- /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__
--- /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 <kernel/kernel.h>
+
+
+// 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<KUsbDescSize_Device> 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<KUsbDescSize_DeviceQualifier> 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<KUsbDescSize_Config> 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<KUsbDescSize_Interface> 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<KUsbDescSize_Endpoint> iBuf;
+ };
+
+
+class TUsbcAudioEndpointDescriptor : public TUsbcEndpointDescriptorBase
+ {
+public:
+ static TUsbcAudioEndpointDescriptor* New(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo);
+private:
+ TUsbcAudioEndpointDescriptor();
+ TInt Construct(TUint8 aEndpointAddress, const TUsbcEndpointInfo& aEpInfo);
+ TBuf8<KUsbDescSize_AudioEndpoint> iBuf;
+ };
+
+
+NONSHARABLE_CLASS(TUsbcOtgDescriptor) : public TUsbcDescriptorBase
+ {
+public:
+ static TUsbcOtgDescriptor* New(TBool aHnpSupport, TBool aSrpSupport);
+private:
+ TUsbcOtgDescriptor();
+ TInt Construct(TBool aHnpSupport, TBool aSrpSupport);
+ TBuf8<KUsbDescSize_Otg> 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<TUsbcDescriptorBase> iDescriptors;
+ RPointerArray<TUsbcStringDescriptorBase> 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__
--- /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 <e32def.h> // 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
+
--- /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 <kernel/kernel.h>
+
+
+//
+// --- 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 T>
+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 T>
+class TSglQueIter : public TSglQueIterBase
+ {
+public:
+ inline TSglQueIter(TSglQueBase& aQue);
+ inline operator T*();
+ inline T* operator++(TInt);
+ };
+
+//
+// --- Inline implementations ---
+//
+
+// Class TSglQue
+template<class T>
+inline TSglQue<T>::TSglQue(TInt aOffset)
+ : TSglQueBase(aOffset)
+ {}
+
+
+template<class T>
+inline void TSglQue<T>::AddLast(T& aRef)
+ {
+ DoAddLast(&aRef);
+ }
+
+
+template<class T>
+inline void TSglQue<T>::Remove(T& aRef)
+ {
+ DoRemove(&aRef);
+ }
+
+
+template<class T>
+inline TInt TSglQue<T>::Elements() const
+ {
+ return iElements;
+ }
+
+
+// Class TSglQueIter
+template<class T>
+inline TSglQueIter<T>::TSglQueIter(TSglQueBase& aQue)
+ : TSglQueIterBase(aQue)
+ {}
+
+
+template<class T>
+inline TSglQueIter<T>::operator T*()
+ {
+ return ((T*)DoCurrent());
+ }
+
+template<class T>
+inline T* TSglQueIter<T>::operator++(TInt)
+ {
+ return ((T*)DoPostInc());
+ }
+
+
+#endif // __USBCQUE_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 <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <kernel/kpower.h>
+#include <platform.h>
+
+#include <usb/d32usbcsc.h>
+
+// #include <drivers/usbcshared.h>
+#include <usb/usbcshared.h>
+
+/** 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 <usb/usbcsc.inl>
+
+#endif // __USBCSC_H__
--- /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__
--- /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 <drivers/usbcque.h>
+#include <usb/usbcque.h>
+
+// 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 <drivers/usbcdesc.h>
+#include <usb/usbcdesc.h>
+//#include <drivers/usbotgperipheralcontrolif.h>
+#include <usb/usbotgperipheralcontrolif.h>
+
+#include <usb/usb_peripheral_shai.h>
+#include <usb/usb_charger_detection_shai.h>
+
+#include <usb/usbcontrolxferif.h>
+
+// 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<TUsbcLogicalEndpoint> 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<TUsbcInterface> 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<TUsbcInterfaceSet> 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<TUsbcConfiguration> 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<TUsbcRequestCallback> iEp0ReadRequestCallbacks; // list of ep0 read requests
+ TSglQue<TUsbcClientCallback> iClientCallbacks; // registered LDD clients and their callback functions
+ TSglQue<TUsbcStatusCallback> iStatusCallbacks; // list of device state notification requests
+ TSglQue<TUsbcEndpointStatusCallback> iEpStatusCallbacks; // list of endpoint state notification requests
+ TSglQue<TUsbcOtgFeatureCallback> 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 <usb/usbcshared.inl>
+
+#endif // __USBCSHARED_H__
--- /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<TUsbcInterfaceSet>& 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<TUsbcRequestCallback> 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<TUsbcStatusCallback> 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<TUsbcEndpointStatusCallback> 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<TUsbcOtgFeatureCallback> 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__
+
+
+
--- /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 <usb/usb_peripheral_shai.h> // 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