/**************************************************************************
 *  Handle Image 
 **************************************************************************/
u32 handle_imgp (u32 * pktsz)
{
    DM_EXT_IMAGE_INFO_PACKET ext_imgp;
    DM_IMAGE_INFO_PACKET imgp;

    memset(&ext_imgp, 0, sizeof(DM_EXT_IMAGE_INFO_PACKET));
    memset(&imgp, 0, sizeof(DM_IMAGE_INFO_PACKET));

    DM_ENTRY_LOG ();
    mt_usbtty_getcn (DM_SZ_EXT_IMG_INFO_PKT, (u8 *) & ext_imgp);
    fill_internal_imgp(&imgp , &ext_imgp);

    check_imgp (&imgp, pktsz);
    mt_usbtty_puts (DM_STR_START_REQ);
    return *pktsz;
}
static bool usb_listen(struct bldr_comport *comport, uint8 *data, uint32 size, uint32 tmo_ms)
{
    ulong  start_time = get_timer(0);
    uint32 dsz;
    uint32 tmo_en = (tmo_ms) ? 1 : 0;
    uint8 *ptr = data;

    if (!size)
        return FALSE;

    while (1) {
        if (tool_is_present())
            mt_usbtty_puts(HSHK_COM_READY); /* "READY" */

        if (tmo_en && (get_timer(start_time) > tmo_ms))
            return FALSE;

        if (!tmo_en) {
            /* kick watchdog to avoid cpu reset */
            platform_wdt_all_kick();
        }

        dsz = mt_usbtty_query_data_size();
        if (dsz) {
            dsz = dsz < size ? dsz : size;
            mt_usbtty_getcn(dsz, (char*)ptr);
            #if CFG_USB_DOWNLOAD && !CFG_LEGACY_USB_DOWNLOAD
            if (*ptr == 0xa0) {
                print("%s sync time %dms\n", MOD, get_timer(start_time));
                usbdl_handler(comport, 300);
                print("%s : ignore %d bytes garbage data\n", MOD, dsz);
                continue; /* ingore received data */
            }
            #endif
            ptr  += dsz;
            size -= dsz;
        }
        if (size == 0)
            break;

        udelay(20000); /* 20ms */
    }

    print("%s sync time %dms\n", MOD, get_timer(start_time));

    return TRUE;
}
/**************************************************************************
 *  Middle State
 **************************************************************************/
void handle_midle_state (u8 * buf)
{
    DM_PKT_TYPE pkt_type;
    DM_EXT_IMAGE_INFO_PACKET *ext_imgp;
    DM_PATCH_CMD_PACKET *patch_cmd;
    DM_IMAGE_INFO_PACKET imgp;

    u32 pktsz = 0;
    part_t *part;
    u8 *name = NULL;
    
    DM_ENTRY_LOG ();

    memset(&imgp, 0, sizeof(DM_IMAGE_INFO_PACKET));
    reset_dm_descriptor ();

    /* receive a little bit data, check if it is REBOOT */
    mt_usbtty_getcn (DM_SZ_REBOOT_STR, buf);
    pkt_type = judge_pkt_type ((const void *) buf);

    if (pkt_type == DM_PKT_REBT)
    {
        dm_ctx.dm_status = DM_STATUS_REBOOT;
        return;
    }

    if (pkt_type == DM_PKT_AUTO)
    {
        print ("autoboot mode !!!\n");
        dm_ctx.dm_status = DM_STATUS_ATBOOT;
        return;
    }

    if (pkt_type == DM_PKT_UPDT)
    {
        print ("update partition table\n");
        dm_ctx.dm_status = DM_STATUS_UPDATE;
        return;
    }
    
    /* pcaket type is IMGP */
    if (pkt_type == DM_PKT_IMGP)
    {
        //print ("\nCASE 2 : pcaket type is DM_PKT_IMGP\n");
        mt_usbtty_getcn (DM_SZ_EXT_IMG_INFO_PKT - DM_SZ_REBOOT_STR, (u8 *) (buf + DM_SZ_REBOOT_STR));
        ext_imgp = (DM_EXT_IMAGE_INFO_PACKET *) buf;
        fill_internal_imgp (&imgp , &(*ext_imgp));
        check_imgp (&imgp, &pktsz);
        mt_usbtty_puts (DM_STR_START_REQ);
    }
    else
    {
        print ("\nCASE 3 : others\n");
        if (pkt_type != DM_PKT_IMGP)
        {
            print ("pkt_type = 0x%x\n", pkt_type);
        }
        ASSERT (0);
    }
 
    return;
}
/**************************************************************************
 *  Check Image Information
 **************************************************************************/
u32 check_imgp (DM_IMAGE_INFO_PACKET * imgp, u32 * pktsz)
{
    print ("\n%s : ------------------ IMG ---------------\n", MOD);
    print ("%s : IMG fmt    = %s   \t type = %s\n", MOD, get_img_fmt (imgp->img_info.img_format),  get_img_type (imgp->img_info.img_type));
    print ("%s : IMG sz     = 0x%x \t addr = 0x%x\n", MOD,(imgp->img_info.img_size), (imgp->img_info.addr_off));
    print ("%s : addr       = 0x%x \t boundary = 0x%x\n", MOD, (imgp->img_info.addr_off), (imgp->img_info.addr_boundary));
    print ("%s : pkt sz     = 0x%x \n", MOD, (imgp->img_info.pkt_size));
    //print ("%s : --------------------------------------\n", MOD);
    print ("%s : IMG range  = 0x%x ~ 0x%x\n", MOD, (imgp->img_info.addr_off), (imgp->img_info.addr_off) + (imgp->img_info.img_size));
    //print ("%s : --------------------------------------\n", MOD);

    // image type is partition table inform
    if (DM_IMG_TYPE_PT_TABLE_INFORM == imgp->img_info.img_type)
    {
        print ("partition table inform\n");
        mt_usbtty_puts (DM_STR_START_REQ);
        handle_pt_cmd ();
        return;
    }
    
    // check image boundary  
    if (g_dl_safe_start_addr > imgp->img_info.addr_off)
    {
        print ("can't flash this image !\n");
        print ("current safe starting address for flashing (0x%x) > current image address (0x%x)\n", g_dl_safe_start_addr, imgp->img_info.addr_off);
        ASSERT (0);
    }

    DM_LOG ("%s : cur safe start addr for flashing (0x%x)\n", MOD, g_dl_safe_start_addr);
    g_dl_safe_start_addr = imgp->img_info.addr_off;

    if (imgp->pattern != DM_IMAGE_INFO_PKT_PATN)
    {
        DM_ASSERT (imgp->pattern == DM_IMAGE_INFO_PKT_PATN);
        dm_ctx.dm_status = DM_STATUS_ERR_ONGOING;
        dm_ctx.dm_err = DM_ERR_WRONG_SEQ;
    }
    // start address offset must be block alignment
    else if (imgp->img_info.addr_off % dm_ctx.block_size)
    {
        DM_ASSERT (imgp->img_info.addr_off % dm_ctx.block_size == 0);
        dm_ctx.dm_status = DM_STATUS_ERR_ONGOING;
        dm_ctx.dm_err = DM_ERR_WRONG_ADDR;
        *pktsz = save_imgp (imgp);
    }
    // packet size must be page size + spare size
    else if (imgp->img_info.pkt_size != dm_ctx.page_size + dm_ctx.spare_size)
    {
        DM_ASSERT (imgp->img_info.pkt_size == dm_ctx.page_size + dm_ctx.spare_size);
        dm_ctx.dm_status = DM_STATUS_ERR_ONGOING;
        dm_ctx.dm_err = DM_ERR_WRONG_PKT_SZ;
        *pktsz = save_imgp (imgp);
    }
    else
    {
        *pktsz = save_imgp (imgp);
         dm_ctx.dm_status = DM_STATUS_SECT_ONGING;
         DM_TIME_BEGIN;
         // erase whole partition to keep data consistent
         force_erase (&imgp->img_info, *pktsz);
         DM_TIME_END_NAND_ERASE;
    }

    return *pktsz;
}