Merge "overlay: Fix rotator output buffer size."
diff --git a/libexternal/external.cpp b/libexternal/external.cpp
index 1c8f170..883a39f 100644
--- a/libexternal/external.cpp
+++ b/libexternal/external.cpp
@@ -450,7 +450,7 @@
 bool ExternalDisplay::closeFrameBuffer()
 {
     int ret = 0;
-    if(mFd > 0) {
+    if(mFd >= 0) {
         ret = close(mFd);
         mFd = -1;
     }
diff --git a/libgralloc/Android.mk b/libgralloc/Android.mk
index f4e3834..749a672 100644
--- a/libgralloc/Android.mk
+++ b/libgralloc/Android.mk
@@ -35,7 +35,7 @@
 LOCAL_MODULE                  := libmemalloc
 LOCAL_MODULE_TAGS             := optional
 LOCAL_C_INCLUDES              := $(common_includes) $(kernel_includes)
-LOCAL_SHARED_LIBRARIES        := $(common_libs) libgenlock libqdutils
+LOCAL_SHARED_LIBRARIES        := $(common_libs) libgenlock libqdutils libdl
 LOCAL_CFLAGS                  := $(common_flags) -DLOG_TAG=\"qdmemalloc\"
 LOCAL_ADDITIONAL_DEPENDENCIES := $(common_deps) $(kernel_deps)
 LOCAL_SRC_FILES               :=  ionalloc.cpp alloc_controller.cpp
diff --git a/libgralloc/alloc_controller.cpp b/libgralloc/alloc_controller.cpp
index 5aca758..ebd7e98 100644
--- a/libgralloc/alloc_controller.cpp
+++ b/libgralloc/alloc_controller.cpp
@@ -29,6 +29,7 @@
 
 #include <cutils/log.h>
 #include <fcntl.h>
+#include <dlfcn.h>
 #include "gralloc_priv.h"
 #include "alloc_controller.h"
 #include "memalloc.h"
@@ -84,29 +85,72 @@
 }
 
 //-------------- AdrenoMemInfo-----------------------//
+AdrenoMemInfo::AdrenoMemInfo()
+{
+    libadreno_utils = ::dlopen("libadreno_utils.so", RTLD_NOW);
+    if (libadreno_utils) {
+        *(void **)&LINK_adreno_compute_padding = ::dlsym(libadreno_utils,
+                                           "compute_surface_padding");
+    }
+}
+
+AdrenoMemInfo::~AdrenoMemInfo()
+{
+    if (libadreno_utils) {
+        ::dlclose(libadreno_utils);
+    }
+}
+
 int AdrenoMemInfo::getStride(int width, int format)
 {
     int stride = ALIGN(width, 32);
-    switch (format)
-    {
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
-            stride = ALIGN(width, 32);
-            break;
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
-            stride = ALIGN(width, 128);
-            break;
-        case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP:
-        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-        case HAL_PIXEL_FORMAT_YV12:
-        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-        case HAL_PIXEL_FORMAT_YCrCb_422_SP:
-            stride = ALIGN(width, 16);
-            break;
-        case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
-            stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
-            break;
-        default: break;
+    // Currently surface padding is only computed for RGB* surfaces.
+    if (format < 0x7) {
+        int bpp = 4;
+        switch(format)
+        {
+            case HAL_PIXEL_FORMAT_RGB_888:
+                bpp = 3;
+                break;
+            case HAL_PIXEL_FORMAT_RGB_565:
+            case HAL_PIXEL_FORMAT_RGBA_5551:
+            case HAL_PIXEL_FORMAT_RGBA_4444:
+                bpp = 2;
+                break;
+            default: break;
+        }
+        if ((libadreno_utils) && (LINK_adreno_compute_padding)) {
+            int surface_tile_height = 1;   // Linear surface
+            int raster_mode         = 1;   // Adreno TW raster mode.
+            int padding_threshold   = 512; // Threshold for padding surfaces.
+            // the function below expects the width to be a multiple of
+            // 32 pixels, hence we pass stride instead of width.
+            stride = LINK_adreno_compute_padding(stride, bpp,
+                                      surface_tile_height, raster_mode,
+                                      padding_threshold);
+        }
+    } else {
+        switch (format)
+        {
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP_ADRENO:
+                stride = ALIGN(width, 32);
+                break;
+            case HAL_PIXEL_FORMAT_YCbCr_420_SP_TILED:
+                stride = ALIGN(width, 128);
+                break;
+            case HAL_PIXEL_FORMAT_NV12_ENCODEABLE:
+            case HAL_PIXEL_FORMAT_YCbCr_420_SP:
+            case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            case HAL_PIXEL_FORMAT_YV12:
+            case HAL_PIXEL_FORMAT_YCbCr_422_SP:
+            case HAL_PIXEL_FORMAT_YCrCb_422_SP:
+                stride = ALIGN(width, 16);
+                break;
+            case HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS:
+                stride = VENUS_Y_STRIDE(COLOR_FMT_NV12, width);
+                break;
+            default: break;
+        }
     }
     return stride;
 }
diff --git a/libgralloc/gr.h b/libgralloc/gr.h
index c6bd137..5343c35 100644
--- a/libgralloc/gr.h
+++ b/libgralloc/gr.h
@@ -84,12 +84,25 @@
 class AdrenoMemInfo : public android::Singleton <AdrenoMemInfo>
 {
     public:
-    AdrenoMemInfo() {}
+    AdrenoMemInfo();
 
-    ~AdrenoMemInfo() {}
+    ~AdrenoMemInfo();
 
+    /*
+     * Function to compute the adreno stride based on the width and format.
+     *
+     * @return stride.
+     */
     int getStride(int width, int format);
 
     private:
+        // Pointer to the padding library.
+        void *libadreno_utils;
+
+        // link to the surface padding library.
+        int (*LINK_adreno_compute_padding) (int width, int bpp,
+                                                int surface_tile_height,
+                                                int screen_tile_height,
+                                                int padding_threshold);
 };
 #endif /* GR_H_ */
diff --git a/libhwcomposer/hwc.cpp b/libhwcomposer/hwc.cpp
index 6a0e0ee..187ec4a 100644
--- a/libhwcomposer/hwc.cpp
+++ b/libhwcomposer/hwc.cpp
@@ -487,13 +487,15 @@
 void hwc_dump(struct hwc_composer_device_1* dev, char *buff, int buff_len)
 {
     hwc_context_t* ctx = (hwc_context_t*)(dev);
-    android::String8 buf("");
-    dumpsys_log(buf, "Qualcomm HWC state:\n");
-    dumpsys_log(buf, "  MDPVersion=%d\n", ctx->mMDP.version);
-    dumpsys_log(buf, "  DisplayPanel=%c\n", ctx->mMDP.panel);
-    ctx->mMDPComp->dump(buf);
-    //XXX: Call Other dump functions
-    strlcpy(buff, buf.string(), buff_len);
+    android::String8 aBuf("");
+    dumpsys_log(aBuf, "Qualcomm HWC state:\n");
+    dumpsys_log(aBuf, "  MDPVersion=%d\n", ctx->mMDP.version);
+    dumpsys_log(aBuf, "  DisplayPanel=%c\n", ctx->mMDP.panel);
+    ctx->mMDPComp->dump(aBuf);
+    char ovDump[2048] = {'\0'};
+    ctx->mOverlay->getDump(ovDump, 2048);
+    dumpsys_log(aBuf, ovDump);
+    strlcpy(buff, aBuf.string(), buff_len);
 }
 
 static int hwc_device_close(struct hw_device_t *dev)
diff --git a/libhwcomposer/hwc_utils.cpp b/libhwcomposer/hwc_utils.cpp
index 0c26bda..e7c60d6 100644
--- a/libhwcomposer/hwc_utils.cpp
+++ b/libhwcomposer/hwc_utils.cpp
@@ -405,11 +405,11 @@
         if(list->hwLayers[i].compositionType == HWC_OVERLAY ||
            list->hwLayers[i].compositionType == HWC_FRAMEBUFFER_TARGET) {
             //Close the acquireFenceFds
-            if(list->hwLayers[i].acquireFenceFd > 0) {
+            if(list->hwLayers[i].acquireFenceFd >= 0) {
                 close(list->hwLayers[i].acquireFenceFd);
                 list->hwLayers[i].acquireFenceFd = -1;
             }
-            if(fd > 0) {
+            if(fd >= 0) {
                 close(fd);
                 fd = -1;
             }
diff --git a/liboverlay/overlay.cpp b/liboverlay/overlay.cpp
index 04deee5..441b822 100644
--- a/liboverlay/overlay.cpp
+++ b/liboverlay/overlay.cpp
@@ -202,10 +202,28 @@
 
 void Overlay::dump() const {
     if(strlen(mDumpStr)) { //dump only on state change
-        ALOGD("%s\n", mDumpStr);
+        ALOGD_IF(PIPE_DEBUG, "%s\n", mDumpStr);
     }
 }
 
+void Overlay::getDump(char *buf, size_t len) {
+    int totalPipes = 0;
+    const char *str = "\nOverlay State\n==========================\n";
+    strncat(buf, str, strlen(str));
+    for(int i = 0; i < PipeBook::NUM_PIPES; i++) {
+        if(mPipeBook[i].valid()) {
+            mPipeBook[i].mPipe->getDump(buf, len);
+            char str[64] = {'\0'};
+            snprintf(str, 64, "Attached to dpy=%d\n\n", mPipeBook[i].mDisplay);
+            strncat(buf, str, strlen(str));
+            totalPipes++;
+        }
+    }
+    char str_pipes[64] = {'\0'};
+    snprintf(str_pipes, 64, "Pipes used=%d\n\n", totalPipes);
+    strncat(buf, str_pipes, strlen(str_pipes));
+}
+
 void Overlay::PipeBook::init() {
     mPipe = NULL;
     mDisplay = DPY_UNUSED;
diff --git a/liboverlay/overlay.h b/liboverlay/overlay.h
index a470f45..0f15baa 100644
--- a/liboverlay/overlay.h
+++ b/liboverlay/overlay.h
@@ -77,6 +77,10 @@
     void setExtFbNum(int fbNum);
     /* Returns framebuffer index of the current external display */
     int getExtFbNum();
+    /* Returns pipe dump. Expects a NULL terminated buffer of big enough size
+     * to populate.
+     */
+    void getDump(char *buf, size_t len);
 
 private:
     /* Ctor setup */
diff --git a/liboverlay/overlayCtrlData.h b/liboverlay/overlayCtrlData.h
index 0c49bdd..c9a4949 100644
--- a/liboverlay/overlayCtrlData.h
+++ b/liboverlay/overlayCtrlData.h
@@ -81,9 +81,6 @@
     /* retrieve cached crop data */
     utils::Dim getCrop() const;
 
-    /* dump the state of the object */
-    void dump() const;
-
     /* Perform transformation calculations */
     void doTransform();
 
@@ -96,6 +93,12 @@
     /* Update the src format */
     void updateSrcformat(const uint32_t& inputsrcFormat);
 
+    /* dump the state of the object */
+    void dump() const;
+
+    /* Return the dump in the specified buffer */
+    void getDump(char *buf, size_t len);
+
 private:
     /* Retrieve screen info from underlying mdp */
     bool getScreenInfo(utils::ScreenInfo& info);
@@ -134,6 +137,9 @@
     /* sump the state of the obj */
     void dump() const;
 
+    /* Return the dump in the specified buffer */
+    void getDump(char *buf, size_t len);
+
 private:
     // mdp data struct
     MdpData mMdp;
@@ -213,6 +219,10 @@
     return mMdp.getDownscalefactor();
 }
 
+inline void Ctrl::getDump(char *buf, size_t len) {
+    mMdp.getDump(buf, len);
+}
+
 inline Data::Data() {
     mMdp.reset();
 }
@@ -249,6 +259,9 @@
     ALOGE("== Dump Data MDP end ==");
 }
 
+inline void Data::getDump(char *buf, size_t len) {
+    mMdp.getDump(buf, len);
+}
 
 } // overlay
 
diff --git a/liboverlay/overlayMdp.cpp b/liboverlay/overlayMdp.cpp
index 8a617db..8f2e2b6 100644
--- a/liboverlay/overlayMdp.cpp
+++ b/liboverlay/overlayMdp.cpp
@@ -269,6 +269,10 @@
     ALOGE("== Dump MdpCtrl end ==");
 }
 
+void MdpCtrl::getDump(char *buf, size_t len) {
+    ovutils::getDump(buf, len, "Ctrl(mdp_overlay)", mOVInfo);
+}
+
 void MdpData::dump() const {
     ALOGE("== Dump MdpData start ==");
     mFd.dump();
@@ -276,6 +280,10 @@
     ALOGE("== Dump MdpData end ==");
 }
 
+void MdpData::getDump(char *buf, size_t len) {
+    ovutils::getDump(buf, len, "Data(msmfb_overlay_data)", mOvData);
+}
+
 void MdpCtrl3D::dump() const {
     ALOGE("== Dump MdpCtrl start ==");
     mFd.dump();
diff --git a/liboverlay/overlayMdp.h b/liboverlay/overlayMdp.h
index c1684fc..55e2787 100644
--- a/liboverlay/overlayMdp.h
+++ b/liboverlay/overlayMdp.h
@@ -141,9 +141,6 @@
     /* using user_data, sets/unsets roationvalue in mdp flags */
     void setRotationFlags();
 
-    /* dump state of the object */
-    void dump() const;
-
     /* Perform transformation calculations */
     void doTransform();
 
@@ -156,6 +153,12 @@
     /* Update the src format */
     void updateSrcformat(const uint32_t& inputsrcFormat);
 
+    /* dump state of the object */
+    void dump() const;
+
+    /* Return the dump in the specified buffer */
+    void getDump(char *buf, size_t len);
+
 private:
 
     /* helper functions for overlayTransform */
@@ -237,6 +240,10 @@
 
     /* dump state of the object */
     void dump() const;
+
+    /* Return the dump in the specified buffer */
+    void getDump(char *buf, size_t len);
+
 private:
 
     /* actual overlay mdp data */
diff --git a/liboverlay/overlayMdpRot.cpp b/liboverlay/overlayMdpRot.cpp
old mode 100644
new mode 100755
index d0a9ee5..c9843f2
--- a/liboverlay/overlayMdpRot.cpp
+++ b/liboverlay/overlayMdpRot.cpp
@@ -58,15 +58,12 @@
 }
 
 void MdpRot::setDownscale(int ds) {
-    if (mRotImgInfo.src.format == MDP_Y_CR_CB_GH2V2 &&
-                            (mRotImgInfo.src_rect.h & 0xF)) {
-        mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
-    } else if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
+    if ((utils::ROT_DS_EIGHTH == ds) && (mRotImgInfo.src_rect.h & 0xF)) {
         // Ensure src_rect.h is a multiple of 16 for 1/8 downscaling.
         // This is an undocumented MDP Rotator constraint.
         // Note that src_rect.h is already ensured to be 32 pixel height aligned
         // for MDP_Y_CRCB_H2V2_TILE and MDP_Y_CBCR_H2V2_TILE formats.
-        mRotImgInfo.src_rect.h = utils::alignup(mRotImgInfo.src_rect.h, 16);
+        mRotImgInfo.src_rect.h = utils::aligndown(mRotImgInfo.src_rect.h, 16);
     }
     mRotImgInfo.downscale_ratio = ds;
 }
@@ -279,4 +276,9 @@
     ALOGE("== Dump MdpRot end ==");
 }
 
+void MdpRot::getDump(char *buf, size_t len) const {
+    ovutils::getDump(buf, len, "MdpRotCtrl(msm_rotator_img_info)", mRotImgInfo);
+    ovutils::getDump(buf, len, "MdpRotData(msm_rotator_data_info)", mRotDataInfo);
+}
+
 } // namespace overlay
diff --git a/liboverlay/overlayMdssRot.cpp b/liboverlay/overlayMdssRot.cpp
index 32e0e77..fd747dd 100644
--- a/liboverlay/overlayMdssRot.cpp
+++ b/liboverlay/overlayMdssRot.cpp
@@ -274,4 +274,10 @@
 
     return opBufSize;
 }
+
+void MdssRot::getDump(char *buf, size_t len) const {
+    ovutils::getDump(buf, len, "MdssRotCtrl(mdp_overlay)", mRotInfo);
+    ovutils::getDump(buf, len, "MdssRotData(msmfb_overlay_data)", mRotData);
+}
+
 } // namespace overlay
diff --git a/liboverlay/overlayRotator.h b/liboverlay/overlayRotator.h
index 9058d30..bd2fd7e 100644
--- a/liboverlay/overlayRotator.h
+++ b/liboverlay/overlayRotator.h
@@ -62,6 +62,7 @@
     virtual uint32_t getSessId() const = 0;
     virtual bool queueBuffer(int fd, uint32_t offset) = 0;
     virtual void dump() const = 0;
+    virtual void getDump(char *buf, size_t len) const = 0;
     static Rotator *getRotator();
 
 protected:
@@ -134,6 +135,7 @@
     virtual uint32_t getSessId() const;
     virtual bool queueBuffer(int fd, uint32_t offset);
     virtual void dump() const;
+    virtual void getDump(char *buf, size_t len) const;
 
 private:
     explicit MdpRot();
@@ -195,6 +197,7 @@
     virtual uint32_t getSessId() const;
     virtual bool queueBuffer(int fd, uint32_t offset);
     virtual void dump() const;
+    virtual void getDump(char *buf, size_t len) const;
 
 private:
     explicit MdssRot();
diff --git a/liboverlay/overlayUtils.cpp b/liboverlay/overlayUtils.cpp
index f339466..de10c9f 100644
--- a/liboverlay/overlayUtils.cpp
+++ b/liboverlay/overlayUtils.cpp
@@ -378,6 +378,83 @@
     return (mdpVersion >= qdutils::MDSS_V5);
 }
 
+void getDump(char *buf, size_t len, const char *prefix,
+        const mdp_overlay& ov) {
+    char str[256] = {'\0'};
+    snprintf(str, 256,
+            "%s id=%d z=%d fg=%d alpha=%d mask=%d flags=0x%x\n",
+            prefix, ov.id, ov.z_order, ov.is_fg, ov.alpha,
+            ov.transp_mask, ov.flags);
+    strncat(buf, str, strlen(str));
+    getDump(buf, len, "\tsrc(msmfb_img)", ov.src);
+    getDump(buf, len, "\tsrc_rect(mdp_rect)", ov.src_rect);
+    getDump(buf, len, "\tdst_rect(mdp_rect)", ov.dst_rect);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const msmfb_img& ov) {
+    char str_src[256] = {'\0'};
+    snprintf(str_src, 256,
+            "%s w=%d h=%d format=%d %s\n",
+            prefix, ov.width, ov.height, ov.format,
+            overlay::utils::getFormatString(ov.format));
+    strncat(buf, str_src, strlen(str_src));
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const mdp_rect& ov) {
+    char str_rect[256] = {'\0'};
+    snprintf(str_rect, 256,
+            "%s x=%d y=%d w=%d h=%d\n",
+            prefix, ov.x, ov.y, ov.w, ov.h);
+    strncat(buf, str_rect, strlen(str_rect));
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const msmfb_overlay_data& ov) {
+    char str[256] = {'\0'};
+    snprintf(str, 256,
+            "%s id=%d\n",
+            prefix, ov.id);
+    strncat(buf, str, strlen(str));
+    getDump(buf, len, "\tdata(msmfb_data)", ov.data);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const msmfb_data& ov) {
+    char str_data[256] = {'\0'};
+    snprintf(str_data, 256,
+            "%s offset=%d memid=%d id=%d flags=0x%x priv=%d\n",
+            prefix, ov.offset, ov.memory_id, ov.id, ov.flags,
+            ov.priv);
+    strncat(buf, str_data, strlen(str_data));
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const msm_rotator_img_info& rot) {
+    char str[256] = {'\0'};
+    snprintf(str, 256, "%s sessid=%u rot=%d, enable=%d downscale=%d\n",
+            prefix, rot.session_id, rot.rotations, rot.enable,
+            rot.downscale_ratio);
+    strncat(buf, str, strlen(str));
+    getDump(buf, len, "\tsrc", rot.src);
+    getDump(buf, len, "\tdst", rot.dst);
+    getDump(buf, len, "\tsrc_rect", rot.src_rect);
+}
+
+void getDump(char *buf, size_t len, const char *prefix,
+        const msm_rotator_data_info& rot) {
+    char str[256] = {'\0'};
+    snprintf(str, 256,
+            "%s sessid=%u verkey=%d\n",
+            prefix, rot.session_id, rot.version_key);
+    strncat(buf, str, strlen(str));
+    getDump(buf, len, "\tsrc", rot.src);
+    getDump(buf, len, "\tdst", rot.dst);
+    getDump(buf, len, "\tsrc_chroma", rot.src_chroma);
+    getDump(buf, len, "\tdst_chroma", rot.dst_chroma);
+}
+
 } // utils
 
 } // overlay
diff --git a/liboverlay/overlayUtils.h b/liboverlay/overlayUtils.h
index 5ce936a..45d1924 100644
--- a/liboverlay/overlayUtils.h
+++ b/liboverlay/overlayUtils.h
@@ -36,6 +36,7 @@
 #include <hardware/hardware.h>
 #include <hardware/gralloc.h> // buffer_handle_t
 #include <linux/msm_mdp.h> // flags
+#include <linux/msm_rotator.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -752,6 +753,17 @@
     return OV_MDP_PIPE_ANY;
 }
 
+void getDump(char *buf, size_t len, const char *prefix, const mdp_overlay& ov);
+void getDump(char *buf, size_t len, const char *prefix, const msmfb_img& ov);
+void getDump(char *buf, size_t len, const char *prefix, const mdp_rect& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+        const msmfb_overlay_data& ov);
+void getDump(char *buf, size_t len, const char *prefix, const msmfb_data& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+        const msm_rotator_img_info& ov);
+void getDump(char *buf, size_t len, const char *prefix,
+        const msm_rotator_data_info& ov);
+
 } // namespace utils ends
 
 //--------------------Class Res stuff (namespace overlay only) -----------
diff --git a/liboverlay/pipes/overlayGenPipe.cpp b/liboverlay/pipes/overlayGenPipe.cpp
index 0b864df..486cfda 100644
--- a/liboverlay/pipes/overlayGenPipe.cpp
+++ b/liboverlay/pipes/overlayGenPipe.cpp
@@ -241,6 +241,13 @@
     ALOGE("== Dump Generic pipe end ==");
 }
 
+void GenericPipe::getDump(char *buf, size_t len) {
+    mCtrlData.ctrl.getDump(buf, len);
+    mCtrlData.data.getDump(buf, len);
+    if(mRotUsed && mRot)
+        mRot->getDump(buf, len);
+}
+
 bool GenericPipe::isClosed() const  {
     return (pipeState == CLOSED);
 }
diff --git a/liboverlay/pipes/overlayGenPipe.h b/liboverlay/pipes/overlayGenPipe.h
index 604529a..1d1be25 100644
--- a/liboverlay/pipes/overlayGenPipe.h
+++ b/liboverlay/pipes/overlayGenPipe.h
@@ -84,6 +84,10 @@
 
     /* dump the state of the object */
     void dump() const;
+
+    /* Return the dump in the specified buffer */
+    void getDump(char *buf, size_t len);
+
 private:
     /* set Closed pipe */
     bool setClosed();