static int rtmp_packet_read_one_chunk(URLContext *h, RTMPPacket *p,
                                      int chunk_size, RTMPPacket **prev_pkt_ptr,
                                      int *nb_prev_pkt, uint8_t hdr)
{
    uint8_t buf[16];
    int channel_id, timestamp, size;
    uint32_t ts_field; // non-extended timestamp or delta field
    uint32_t extra = 0;
    enum RTMPPacketType type;
    int written = 0;
    int ret, toread;
    RTMPPacket *prev_pkt;
    written++;
    channel_id = hdr & 0x3F;
    if (channel_id < 2) { //special case for channel number >= 64
        buf[1] = 0;
        if (ffurl_read_complete(h, buf, channel_id + 1) != channel_id + 1)
            return AVERROR(EIO);
        written += channel_id + 1;
        channel_id = AV_RL16(buf) + 64;
    if ((ret = ff_rtmp_check_alloc_array(prev_pkt_ptr, nb_prev_pkt,
                                         channel_id)) < 0)
        return ret;
    prev_pkt = *prev_pkt_ptr;
    size  = prev_pkt[channel_id].size;
    type  = prev_pkt[channel_id].type;
    extra = prev_pkt[channel_id].extra;
    hdr >>= 6; // header size indicator
    if (hdr == RTMP_PS_ONEBYTE) {
        ts_field = prev_pkt[channel_id].ts_field;
    } else {
        if (ffurl_read_complete(h, buf, 3) != 3)
            return AVERROR(EIO);
        written += 3;
        ts_field = AV_RB24(buf);
        if (hdr != RTMP_PS_FOURBYTES) {
            if (ffurl_read_complete(h, buf, 3) != 3)
                return AVERROR(EIO);
            written += 3;
            size = AV_RB24(buf);
            if (ffurl_read_complete(h, buf, 1) != 1)
                return AVERROR(EIO);
            written++;
            type = buf[0];
            if (hdr == RTMP_PS_TWELVEBYTES) {
                if (ffurl_read_complete(h, buf, 4) != 4)
                    return AVERROR(EIO);
                written += 4;
                extra = AV_RL32(buf);
    if (ts_field == 0xFFFFFF) {
        if (ffurl_read_complete(h, buf, 4) != 4)
            return AVERROR(EIO);
        timestamp = AV_RB32(buf);
    } else {
        timestamp = ts_field;
    if (hdr != RTMP_PS_TWELVEBYTES)
        timestamp += prev_pkt[channel_id].timestamp;
    if (!prev_pkt[channel_id].read) {
        if ((ret = ff_rtmp_packet_create(p, channel_id, type, timestamp,
                                         size)) < 0)
            return ret;
        p->read = written;
        p->offset = 0;
        prev_pkt[channel_id].ts_field   = ts_field;
        prev_pkt[channel_id].timestamp  = timestamp;
    } else {
        // previous packet in this channel hasn't completed reading
        RTMPPacket *prev = &prev_pkt[channel_id];
        p->data          = prev->data;
        p->size          = prev->size;
        p->channel_id    = prev->channel_id;
        p->type          = prev->type;
        p->ts_field      = prev->ts_field;
        p->extra         = prev->extra;
        p->offset        = prev->offset;
        p->read          = prev->read + written;
        p->timestamp     = prev->timestamp;
        prev->data       = NULL;
    p->extra = extra;
    // save history
    prev_pkt[channel_id].channel_id = channel_id;
    prev_pkt[channel_id].type       = type;
    prev_pkt[channel_id].size       = size;
    prev_pkt[channel_id].extra      = extra;
    size = size - p->offset;
    toread = FFMIN(size, chunk_size);
    if (ffurl_read_complete(h, p->data + p->offset, toread) != toread) {
        ff_rtmp_packet_destroy(p);
        return AVERROR(EIO);
    size      -= toread;
    p->read   += toread;
    p->offset += toread;
    if (size > 0) {
       RTMPPacket *prev = &prev_pkt[channel_id];
       prev->data = p->data;
       prev->read = p->read;
       prev->offset = p->offset;
       return AVERROR(EAGAIN);
    prev_pkt[channel_id].read = 0; // read complete; reset if needed
    return p->read;


void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)

{

    uint8_t tick = eeprom->tick;

    uint8_t eedo = eeprom->eedo;

    uint16_t address = eeprom->address;

    uint8_t command = eeprom->command;

    logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",

           eecs, eesk, eedi, eedo, tick);

    if (! eeprom->eecs && eecs) {

        /* Start chip select cycle. */

        logout("Cycle start, waiting for 1st start bit (0)\n");

        tick = 0;

        command = 0x0;

        address = 0x0;

    } else if (eeprom->eecs && ! eecs) {

        /* End chip select cycle. This triggers write / erase. */

        if (eeprom->writable) {

            uint8_t subcommand = address >> (eeprom->addrbits - 2);

            if (command == 0 && subcommand == 2) {

                /* Erase all. */

                for (address = 0; address < eeprom->size; address++) {

                    eeprom->contents[address] = 0xffff;

                }

            } else if (command == 3) {

                /* Erase word. */

                eeprom->contents[address] = 0xffff;

            } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {

                if (command == 1) {

                    /* Write word. */

                    eeprom->contents[address] &= eeprom->data;

                } else if (command == 0 && subcommand == 1) {

                    /* Write all. */

                    for (address = 0; address < eeprom->size; address++) {

                        eeprom->contents[address] &= eeprom->data;

                    }

                }

            }

        }

        /* Output DO is tristate, read results in 1. */

        eedo = 1;

    } else if (eecs && ! eeprom->eesk && eesk) {

        /* Raising edge of clock shifts data in. */

        if (tick == 0) {

            /* Wait for 1st start bit. */

            if (eedi == 0) {

                logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");

                tick++;

            } else {

                logout("wrong 1st start bit (is 1, should be 0)\n");

                tick = 2;

                //~ assert(!"wrong start bit");

            }

        } else if (tick == 1) {

            /* Wait for 2nd start bit. */

            if (eedi != 0) {

                logout("Got correct 2nd start bit, getting command + address\n");

                tick++;

            } else {

                logout("1st start bit is longer than needed\n");

            }

        } else if (tick < 2 + 2) {

            /* Got 2 start bits, transfer 2 opcode bits. */

            tick++;

            command <<= 1;

            if (eedi) {

                command += 1;

            }

        } else if (tick < 2 + 2 + eeprom->addrbits) {

            /* Got 2 start bits and 2 opcode bits, transfer all address bits. */

            tick++;

            address = ((address << 1) | eedi);

            if (tick == 2 + 2 + eeprom->addrbits) {

                logout("%s command, address = 0x%02x (value 0x%04x)\n",

                       opstring[command], address, eeprom->contents[address]);

                if (command == 2) {

                    eedo = 0;

                }

                address = address % eeprom->size;

                if (command == 0) {

                    /* Command code in upper 2 bits of address. */

                    switch (address >> (eeprom->addrbits - 2)) {

                        case 0:

                            logout("write disable command\n");

                            eeprom->writable = 0;

                            break;

                        case 1:

                            logout("write all command\n");

                            break;

                        case 2:

                            logout("erase all command\n");

                            break;

                        case 3:

                            logout("write enable command\n");

                            eeprom->writable = 1;

                            break;

                    }

                } else {

                    /* Read, write or erase word. */

                    eeprom->data = eeprom->contents[address];

                }

            }

        } else if (tick < 2 + 2 + eeprom->addrbits + 16) {

            /* Transfer 16 data bits. */

            tick++;

            if (command == 2) {

                /* Read word. */

                eedo = ((eeprom->data & 0x8000) != 0);

            }

            eeprom->data <<= 1;

            eeprom->data += eedi;

        } else {

            logout("additional unneeded tick, not processed\n");

        }

    }

    /* Save status of EEPROM. */

    eeprom->tick = tick;

    eeprom->eecs = eecs;

    eeprom->eesk = eesk;

    eeprom->eedo = eedo;

    eeprom->address = address;

    eeprom->command = command;

}


static void *iothread_run(void *opaque)

{

    IOThread *iothread = opaque;

    qemu_mutex_lock(&iothread->init_done_lock);

    iothread->thread_id = qemu_get_thread_id();

    qemu_cond_signal(&iothread->init_done_cond);

    qemu_mutex_unlock(&iothread->init_done_lock);

    while (!iothread->stopping) {

        aio_context_acquire(iothread->ctx);

        while (!iothread->stopping && aio_poll(iothread->ctx, true)) {

            /* Progress was made, keep going */

        }

        aio_context_release(iothread->ctx);

    }

    return NULL;

}


static av_cold int encode_close(AVCodecContext *avctx)

{

    av_frame_free(&avctx->coded_frame);

    return 0;

}


static void pc_dimm_get_size(Object *obj, Visitor *v, const char *name,

                             void *opaque, Error **errp)

{

    int64_t value;

    MemoryRegion *mr;

    PCDIMMDevice *dimm = PC_DIMM(obj);

    mr = host_memory_backend_get_memory(dimm->hostmem, errp);

    value = memory_region_size(mr);

    visit_type_int(v, name, &value, errp);

}


pflash_t *pflash_cfi02_register(target_phys_addr_t base, ram_addr_t off,

                                BlockDriverState *bs, uint32_t sector_len,

                                int nb_blocs, int nb_mappings, int width,

                                uint16_t id0, uint16_t id1,

                                uint16_t id2, uint16_t id3,

                                uint16_t unlock_addr0, uint16_t unlock_addr1)

{

    pflash_t *pfl;

    int32_t chip_len;

    chip_len = sector_len * nb_blocs;

    /* XXX: to be fixed */

#if 0

    if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&

        total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))

        return NULL;

#endif

    pfl = qemu_mallocz(sizeof(pflash_t));

    /* FIXME: Allocate ram ourselves.  */

    pfl->storage = qemu_get_ram_ptr(off);

    pfl->fl_mem = cpu_register_io_memory(pflash_read_ops, pflash_write_ops,

                                         pfl);

    pfl->off = off;

    pfl->base = base;

    pfl->chip_len = chip_len;

    pfl->mappings = nb_mappings;

    pflash_register_memory(pfl, 1);

    pfl->bs = bs;

    if (pfl->bs) {

        /* read the initial flash content */

        bdrv_read(pfl->bs, 0, pfl->storage, chip_len >> 9);

    }

#if 0 /* XXX: there should be a bit to set up read-only,

       *      the same way the hardware does (with WP pin).

       */

    pfl->ro = 1;

#else

    pfl->ro = 0;

#endif

    pfl->timer = qemu_new_timer(vm_clock, pflash_timer, pfl);

    pfl->sector_len = sector_len;

    pfl->width = width;

    pfl->wcycle = 0;

    pfl->cmd = 0;

    pfl->status = 0;

    pfl->ident[0] = id0;

    pfl->ident[1] = id1;

    pfl->ident[2] = id2;

    pfl->ident[3] = id3;

    pfl->unlock_addr[0] = unlock_addr0;

    pfl->unlock_addr[1] = unlock_addr1;

    /* Hardcoded CFI table (mostly from SG29 Spansion flash) */

    pfl->cfi_len = 0x52;

    /* Standard "QRY" string */

    pfl->cfi_table[0x10] = 'Q';

    pfl->cfi_table[0x11] = 'R';

    pfl->cfi_table[0x12] = 'Y';

    /* Command set (AMD/Fujitsu) */

    pfl->cfi_table[0x13] = 0x02;

    pfl->cfi_table[0x14] = 0x00;

    /* Primary extended table address */

    pfl->cfi_table[0x15] = 0x31;

    pfl->cfi_table[0x16] = 0x00;

    /* Alternate command set (none) */

    pfl->cfi_table[0x17] = 0x00;

    pfl->cfi_table[0x18] = 0x00;

    /* Alternate extended table (none) */

    pfl->cfi_table[0x19] = 0x00;

    pfl->cfi_table[0x1A] = 0x00;

    /* Vcc min */

    pfl->cfi_table[0x1B] = 0x27;

    /* Vcc max */

    pfl->cfi_table[0x1C] = 0x36;

    /* Vpp min (no Vpp pin) */

    pfl->cfi_table[0x1D] = 0x00;

    /* Vpp max (no Vpp pin) */

    pfl->cfi_table[0x1E] = 0x00;

    /* Reserved */

    pfl->cfi_table[0x1F] = 0x07;

    /* Timeout for min size buffer write (NA) */

    pfl->cfi_table[0x20] = 0x00;

    /* Typical timeout for block erase (512 ms) */

    pfl->cfi_table[0x21] = 0x09;

    /* Typical timeout for full chip erase (4096 ms) */

    pfl->cfi_table[0x22] = 0x0C;

    /* Reserved */

    pfl->cfi_table[0x23] = 0x01;

    /* Max timeout for buffer write (NA) */

    pfl->cfi_table[0x24] = 0x00;

    /* Max timeout for block erase */

    pfl->cfi_table[0x25] = 0x0A;

    /* Max timeout for chip erase */

    pfl->cfi_table[0x26] = 0x0D;

    /* Device size */

    pfl->cfi_table[0x27] = ctz32(chip_len);

    /* Flash device interface (8 & 16 bits) */

    pfl->cfi_table[0x28] = 0x02;

    pfl->cfi_table[0x29] = 0x00;

    /* Max number of bytes in multi-bytes write */

    /* XXX: disable buffered write as it's not supported */

    //    pfl->cfi_table[0x2A] = 0x05;

    pfl->cfi_table[0x2A] = 0x00;

    pfl->cfi_table[0x2B] = 0x00;

    /* Number of erase block regions (uniform) */

    pfl->cfi_table[0x2C] = 0x01;

    /* Erase block region 1 */

    pfl->cfi_table[0x2D] = nb_blocs - 1;

    pfl->cfi_table[0x2E] = (nb_blocs - 1) >> 8;

    pfl->cfi_table[0x2F] = sector_len >> 8;

    pfl->cfi_table[0x30] = sector_len >> 16;

    /* Extended */

    pfl->cfi_table[0x31] = 'P';

    pfl->cfi_table[0x32] = 'R';

    pfl->cfi_table[0x33] = 'I';

    pfl->cfi_table[0x34] = '1';

    pfl->cfi_table[0x35] = '0';

    pfl->cfi_table[0x36] = 0x00;

    pfl->cfi_table[0x37] = 0x00;

    pfl->cfi_table[0x38] = 0x00;

    pfl->cfi_table[0x39] = 0x00;

    pfl->cfi_table[0x3a] = 0x00;

    pfl->cfi_table[0x3b] = 0x00;

    pfl->cfi_table[0x3c] = 0x00;

    return pfl;

}


static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)

{

    return s->ops->chmod(&s->ctx, path->data, mode);

}


static int check_physical (CPUState *env, mmu_ctx_t *ctx,

                           target_ulong eaddr, int rw)

{

    int in_plb, ret;

    ctx->raddr = eaddr;

    ctx->prot = PAGE_READ;

    ret = 0;

    switch (env->mmu_model) {

    case POWERPC_MMU_32B:

    case POWERPC_MMU_SOFT_6xx:

    case POWERPC_MMU_SOFT_74xx:

    case POWERPC_MMU_601:

    case POWERPC_MMU_SOFT_4xx:

    case POWERPC_MMU_REAL_4xx:

    case POWERPC_MMU_BOOKE:

        ctx->prot |= PAGE_WRITE;

        break;

#if defined(TARGET_PPC64)

    case POWERPC_MMU_64B:

    case POWERPC_MMU_64BRIDGE:

        /* Real address are 60 bits long */

        ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;

        ctx->prot |= PAGE_WRITE;

        break;

#endif

    case POWERPC_MMU_SOFT_4xx_Z:

        if (unlikely(msr_pe != 0)) {

            /* 403 family add some particular protections,

             * using PBL/PBU registers for accesses with no translation.

             */

            in_plb =

                /* Check PLB validity */

                (env->pb[0] < env->pb[1] &&

                 /* and address in plb area */

                 eaddr >= env->pb[0] && eaddr < env->pb[1]) ||

                (env->pb[2] < env->pb[3] &&

                 eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;

            if (in_plb ^ msr_px) {

                /* Access in protected area */

                if (rw == 1) {

                    /* Access is not allowed */

                    ret = -2;

                }

            } else {

                /* Read-write access is allowed */

                ctx->prot |= PAGE_WRITE;

            }

        }

        break;

    case POWERPC_MMU_BOOKE_FSL:

        /* XXX: TODO */

        cpu_abort(env, "BookE FSL MMU model not implemented\n");

        break;

    default:

        cpu_abort(env, "Unknown or invalid MMU model\n");

        return -1;

    }

    return ret;

}


void ff_xvmc_field_end(MpegEncContext *s)

{

    struct xvmc_pix_fmt *render = (struct xvmc_pix_fmt*)s->current_picture.f.data[2];

    assert(render);

    if (render->filled_mv_blocks_num > 0)

        ff_mpeg_draw_horiz_band(s, 0, 0);

}


void set_system_memory_map(MemoryRegion *mr)

{

    memory_region_transaction_begin();

    address_space_memory.root = mr;

    memory_region_transaction_commit();

}


pp_mode *pp_get_mode_by_name_and_quality(const char *name, int quality)

{

    char temp[GET_MODE_BUFFER_SIZE];

    char *p= temp;

    static const char filterDelimiters[] = ",/";

    static const char optionDelimiters[] = ":";

    struct PPMode *ppMode;

    char *filterToken;

    ppMode= av_malloc(sizeof(PPMode));

    ppMode->lumMode= 0;

    ppMode->chromMode= 0;

    ppMode->maxTmpNoise[0]= 700;

    ppMode->maxTmpNoise[1]= 1500;

    ppMode->maxTmpNoise[2]= 3000;

    ppMode->maxAllowedY= 234;

    ppMode->minAllowedY= 16;

    ppMode->baseDcDiff= 256/8;

    ppMode->flatnessThreshold= 56-16-1;

    ppMode->maxClippedThreshold= 0.01;

    ppMode->error=0;

    memset(temp, 0, GET_MODE_BUFFER_SIZE);

    av_strlcpy(temp, name, GET_MODE_BUFFER_SIZE - 1);

    av_log(NULL, AV_LOG_DEBUG, "pp: %s\n", name);

    for(;;){

        char *filterName;

        int q= 1000000; //PP_QUALITY_MAX;

        int chrom=-1;

        int luma=-1;

        char *option;

        char *options[OPTIONS_ARRAY_SIZE];

        int i;

        int filterNameOk=0;

        int numOfUnknownOptions=0;

        int enable=1; //does the user want us to enabled or disabled the filter

        filterToken= strtok(p, filterDelimiters);

        if(filterToken == NULL) break;

        p+= strlen(filterToken) + 1; // p points to next filterToken

        filterName= strtok(filterToken, optionDelimiters);

        av_log(NULL, AV_LOG_DEBUG, "pp: %s::%s\n", filterToken, filterName);

        if(*filterName == '-'){

            enable=0;

            filterName++;

        }

        for(;;){ //for all options

            option= strtok(NULL, optionDelimiters);

            if(option == NULL) break;

            av_log(NULL, AV_LOG_DEBUG, "pp: option: %s\n", option);

            if(!strcmp("autoq", option) || !strcmp("a", option)) q= quality;

            else if(!strcmp("nochrom", option) || !strcmp("y", option)) chrom=0;

            else if(!strcmp("chrom", option) || !strcmp("c", option)) chrom=1;

            else if(!strcmp("noluma", option) || !strcmp("n", option)) luma=0;

            else{

                options[numOfUnknownOptions] = option;

                numOfUnknownOptions++;

            }

            if(numOfUnknownOptions >= OPTIONS_ARRAY_SIZE-1) break;

        }

        options[numOfUnknownOptions] = NULL;

        /* replace stuff from the replace Table */

        for(i=0; replaceTable[2*i]!=NULL; i++){

            if(!strcmp(replaceTable[2*i], filterName)){

                int newlen= strlen(replaceTable[2*i + 1]);

                int plen;

                int spaceLeft;

                if(p==NULL) p= temp, *p=0;      //last filter

                else p--, *p=',';               //not last filter

                plen= strlen(p);

                spaceLeft= p - temp + plen;

                if(spaceLeft + newlen  >= GET_MODE_BUFFER_SIZE - 1){

                    ppMode->error++;

                    break;

                }

                memmove(p + newlen, p, plen+1);

                memcpy(p, replaceTable[2*i + 1], newlen);

                filterNameOk=1;

            }

        }

        for(i=0; filters[i].shortName!=NULL; i++){

            if(   !strcmp(filters[i].longName, filterName)

               || !strcmp(filters[i].shortName, filterName)){

                ppMode->lumMode &= ~filters[i].mask;

                ppMode->chromMode &= ~filters[i].mask;

                filterNameOk=1;

                if(!enable) break; // user wants to disable it

                if(q >= filters[i].minLumQuality && luma)

                    ppMode->lumMode|= filters[i].mask;

                if(chrom==1 || (chrom==-1 && filters[i].chromDefault))

                    if(q >= filters[i].minChromQuality)

                            ppMode->chromMode|= filters[i].mask;

                if(filters[i].mask == LEVEL_FIX){

                    int o;

                    ppMode->minAllowedY= 16;

                    ppMode->maxAllowedY= 234;

                    for(o=0; options[o]!=NULL; o++){

                        if(  !strcmp(options[o],"fullyrange")

                           ||!strcmp(options[o],"f")){

                            ppMode->minAllowedY= 0;

                            ppMode->maxAllowedY= 255;

                            numOfUnknownOptions--;

                        }

                    }

                }

                else if(filters[i].mask == TEMP_NOISE_FILTER)

                {

                    int o;

                    int numOfNoises=0;

                    for(o=0; options[o]!=NULL; o++){

                        char *tail;

                        ppMode->maxTmpNoise[numOfNoises]=

                            strtol(options[o], &tail, 0);

                        if(tail!=options[o]){

                            numOfNoises++;

                            numOfUnknownOptions--;

                            if(numOfNoises >= 3) break;

                        }

                    }

                }

                else if(filters[i].mask == V_DEBLOCK   || filters[i].mask == H_DEBLOCK

                     || filters[i].mask == V_A_DEBLOCK || filters[i].mask == H_A_DEBLOCK){

                    int o;

                    for(o=0; options[o]!=NULL && o<2; o++){

                        char *tail;

                        int val= strtol(options[o], &tail, 0);

                        if(tail==options[o]) break;

                        numOfUnknownOptions--;

                        if(o==0) ppMode->baseDcDiff= val;

                        else ppMode->flatnessThreshold= val;

                    }

                }

                else if(filters[i].mask == FORCE_QUANT){

                    int o;

                    ppMode->forcedQuant= 15;

                    for(o=0; options[o]!=NULL && o<1; o++){

                        char *tail;

                        int val= strtol(options[o], &tail, 0);

                        if(tail==options[o]) break;

                        numOfUnknownOptions--;

                        ppMode->forcedQuant= val;

                    }

                }

            }

        }

        if(!filterNameOk) ppMode->error++;

        ppMode->error += numOfUnknownOptions;

    }

    av_log(NULL, AV_LOG_DEBUG, "pp: lumMode=%X, chromMode=%X\n", ppMode->lumMode, ppMode->chromMode);

    if(ppMode->error){

        av_log(NULL, AV_LOG_ERROR, "%d errors in postprocess string \"%s\"\n", ppMode->error, name);

        av_free(ppMode);

        return NULL;

    }

    return ppMode;

}


int qcow2_write_l1_entry(BlockDriverState *bs, int l1_index)

{

    BDRVQcowState *s = bs->opaque;

    uint64_t buf[L1_ENTRIES_PER_SECTOR];

    int l1_start_index;

    int i, ret;

    l1_start_index = l1_index & ~(L1_ENTRIES_PER_SECTOR - 1);

    for (i = 0; i < L1_ENTRIES_PER_SECTOR; i++) {

        buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]);

    }

    ret = qcow2_pre_write_overlap_check(bs,

            QCOW2_OL_DEFAULT & ~QCOW2_OL_ACTIVE_L1,

            s->l1_table_offset + 8 * l1_start_index, sizeof(buf));

    if (ret < 0) {

        return ret;

    }

    BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE);

    ret = bdrv_pwrite_sync(bs->file, s->l1_table_offset + 8 * l1_start_index,

        buf, sizeof(buf));

    if (ret < 0) {

        return ret;

    }

    return 0;

}


static void zero_bss(abi_ulong elf_bss, abi_ulong last_bss, int prot)

{

    uintptr_t host_start, host_map_start, host_end;

    last_bss = TARGET_PAGE_ALIGN(last_bss);

    /* ??? There is confusion between qemu_real_host_page_size and

       qemu_host_page_size here and elsewhere in target_mmap, which

       may lead to the end of the data section mapping from the file

       not being mapped.  At least there was an explicit test and

       comment for that here, suggesting that "the file size must

       be known".  The comment probably pre-dates the introduction

       of the fstat system call in target_mmap which does in fact

       find out the size.  What isn't clear is if the workaround

       here is still actually needed.  For now, continue with it,

       but merge it with the "normal" mmap that would allocate the bss.  */

    host_start = (uintptr_t) g2h(elf_bss);

    host_end = (uintptr_t) g2h(last_bss);

    host_map_start = (host_start + qemu_real_host_page_size - 1);

    host_map_start &= -qemu_real_host_page_size;

    if (host_map_start < host_end) {

        void *p = mmap((void *)host_map_start, host_end - host_map_start,

                       prot, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        if (p == MAP_FAILED) {

            perror("cannot mmap brk");

            exit(-1);

        }

        /* Since we didn't use target_mmap, make sure to record

           the validity of the pages with qemu.  */

        page_set_flags(elf_bss & TARGET_PAGE_MASK, last_bss, prot|PAGE_VALID);

    }

    if (host_start < host_map_start) {

        memset((void *)host_start, 0, host_map_start - host_start);

    }

}


static void avc_biwgt_4x4multiple_msa(uint8_t *src,

                                      int32_t src_stride,

                                      uint8_t *dst,

                                      int32_t dst_stride,

                                      int32_t height,

                                      int32_t log2_denom,

                                      int32_t src_weight,

                                      int32_t dst_weight,

                                      int32_t offset_in)

{

    uint8_t cnt;

    uint32_t load0, load1, load2, load3;

    v16i8 src_wgt, dst_wgt, wgt;

    v16i8 src0, src1, src2, src3;

    v16i8 dst0, dst1, dst2, dst3;

    v8i16 temp0, temp1, temp2, temp3;

    v8i16 denom, offset, add_val;

    int32_t val = 128 * (src_weight + dst_weight);

    offset_in = ((offset_in + 1) | 1) << log2_denom;

    src_wgt = __msa_fill_b(src_weight);

    dst_wgt = __msa_fill_b(dst_weight);

    offset = __msa_fill_h(offset_in);

    denom = __msa_fill_h(log2_denom + 1);

    add_val = __msa_fill_h(val);

    offset += add_val;

    wgt = __msa_ilvev_b(dst_wgt, src_wgt);

    for (cnt = height / 4; cnt--;) {

        LOAD_4WORDS_WITH_STRIDE(src, src_stride, load0, load1, load2, load3);

        src += (4 * src_stride);

        src0 = (v16i8) __msa_fill_w(load0);

        src1 = (v16i8) __msa_fill_w(load1);

        src2 = (v16i8) __msa_fill_w(load2);

        src3 = (v16i8) __msa_fill_w(load3);

        LOAD_4WORDS_WITH_STRIDE(dst, dst_stride, load0, load1, load2, load3);

        dst0 = (v16i8) __msa_fill_w(load0);

        dst1 = (v16i8) __msa_fill_w(load1);

        dst2 = (v16i8) __msa_fill_w(load2);

        dst3 = (v16i8) __msa_fill_w(load3);

        XORI_B_4VECS_SB(src0, src1, src2, src3, src0, src1, src2, src3, 128);

        XORI_B_4VECS_SB(dst0, dst1, dst2, dst3, dst0, dst1, dst2, dst3, 128);

        ILVR_B_4VECS_SH(src0, src1, src2, src3, dst0, dst1, dst2, dst3,

                        temp0, temp1, temp2, temp3);

        temp0 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp0);

        temp1 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp1);

        temp2 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp2);

        temp3 = __msa_dpadd_s_h(offset, wgt, (v16i8) temp3);

        SRA_4VECS(temp0, temp1, temp2, temp3,

                  temp0, temp1, temp2, temp3, denom);

        temp0 = CLIP_UNSIGNED_CHAR_H(temp0);

        temp1 = CLIP_UNSIGNED_CHAR_H(temp1);

        temp2 = CLIP_UNSIGNED_CHAR_H(temp2);

        temp3 = CLIP_UNSIGNED_CHAR_H(temp3);

        PCKEV_B_STORE_4_BYTES_4(temp0, temp1, temp2, temp3, dst, dst_stride);

        dst += (4 * dst_stride);

    }

}


static inline void tcg_out_ld(TCGContext *s, TCGType type, TCGReg ret,

                              TCGReg arg1, intptr_t arg2)

{

    int opi, opx;

    assert(TCG_TARGET_REG_BITS == 64 || type == TCG_TYPE_I32);

    if (type == TCG_TYPE_I32) {

        opi = LWZ, opx = LWZX;

    } else {

        opi = LD, opx = LDX;

    }

    tcg_out_mem_long(s, opi, opx, ret, arg1, arg2);

}


void do_delvm(Monitor *mon, const QDict *qdict)

{

    BlockDriverState *bs, *bs1;

    Error *err = NULL;

    const char *name = qdict_get_str(qdict, "name");

    bs = find_vmstate_bs();

    if (!bs) {

        monitor_printf(mon, "No block device supports snapshots\n");

        return;

    }

    bs1 = NULL;

    while ((bs1 = bdrv_next(bs1))) {

        if (bdrv_can_snapshot(bs1)) {

            bdrv_snapshot_delete_by_id_or_name(bs, name, &err);

            if (err) {

                monitor_printf(mon,

                               "Error while deleting snapshot on device '%s':"

                               " %s\n",

                               bdrv_get_device_name(bs),

                               error_get_pretty(err));

                error_free(err);

            }

        }

    }

}


void object_property_add(Object *obj, const char *name, const char *type,

                         ObjectPropertyAccessor *get,

                         ObjectPropertyAccessor *set,

                         ObjectPropertyRelease *release,

                         void *opaque, Error **errp)

{

    ObjectProperty *prop;

    QTAILQ_FOREACH(prop, &obj->properties, node) {

        if (strcmp(prop->name, name) == 0) {

            error_setg(errp, "attempt to add duplicate property '%s'"

                       " to object (type '%s')", name,

                       object_get_typename(obj));

            return;

        }

    }

    prop = g_malloc0(sizeof(*prop));

    prop->name = g_strdup(name);

    prop->type = g_strdup(type);

    prop->get = get;

    prop->set = set;

    prop->release = release;

    prop->opaque = opaque;

    QTAILQ_INSERT_TAIL(&obj->properties, prop, node);

}


static void collie_init(MachineState *machine)

{

    const char *cpu_model = machine->cpu_model;

    const char *kernel_filename = machine->kernel_filename;

    const char *kernel_cmdline = machine->kernel_cmdline;

    const char *initrd_filename = machine->initrd_filename;

    StrongARMState *s;

    DriveInfo *dinfo;

    MemoryRegion *sysmem = get_system_memory();

    if (!cpu_model) {

        cpu_model = "sa1110";

    }

    s = sa1110_init(sysmem, collie_binfo.ram_size, cpu_model);

    dinfo = drive_get(IF_PFLASH, 0, 0);

    pflash_cfi01_register(SA_CS0, NULL, "collie.fl1", 0x02000000,

                    dinfo ? blk_bs(blk_by_legacy_dinfo(dinfo)) : NULL,

                    (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);

    dinfo = drive_get(IF_PFLASH, 0, 1);

    pflash_cfi01_register(SA_CS1, NULL, "collie.fl2", 0x02000000,

                    dinfo ? blk_bs(blk_by_legacy_dinfo(dinfo)) : NULL,

                    (64 * 1024), 512, 4, 0x00, 0x00, 0x00, 0x00, 0);

    sysbus_create_simple("scoop", 0x40800000, NULL);

    collie_binfo.kernel_filename = kernel_filename;

    collie_binfo.kernel_cmdline = kernel_cmdline;

    collie_binfo.initrd_filename = initrd_filename;

    collie_binfo.board_id = 0x208;

    arm_load_kernel(s->cpu, &collie_binfo);

}


void avg_pixels16_altivec(uint8_t *block, const uint8_t *pixels, int line_size, int h)

{

POWERPC_TBL_DECLARE(altivec_avg_pixels16_num, 1);

#ifdef ALTIVEC_USE_REFERENCE_C_CODE

    int i;

POWERPC_TBL_START_COUNT(altivec_avg_pixels16_num, 1);

    for(i=0; i<h; i++) {

      op_avg(*((uint32_t*)(block)),(((const struct unaligned_32 *)(pixels))->l));

      op_avg(*((uint32_t*)(block+4)),(((const struct unaligned_32 *)(pixels+4))->l));

      op_avg(*((uint32_t*)(block+8)),(((const struct unaligned_32 *)(pixels+8))->l));

      op_avg(*((uint32_t*)(block+12)),(((const struct unaligned_32 *)(pixels+12))->l));

      pixels+=line_size;

      block +=line_size;

    }

POWERPC_TBL_STOP_COUNT(altivec_avg_pixels16_num, 1);

#else /* ALTIVEC_USE_REFERENCE_C_CODE */

    register vector unsigned char pixelsv1, pixelsv2, pixelsv, blockv;

    register vector unsigned char perm = vec_lvsl(0, pixels);

    int i;

POWERPC_TBL_START_COUNT(altivec_avg_pixels16_num, 1);

    for(i=0; i<h; i++) {

      pixelsv1 = vec_ld(0, (unsigned char*)pixels);

      pixelsv2 = vec_ld(16, (unsigned char*)pixels);

      blockv = vec_ld(0, block);

      pixelsv = vec_perm(pixelsv1, pixelsv2, perm);

      blockv = vec_avg(blockv,pixelsv);

      vec_st(blockv, 0, (unsigned char*)block);

      pixels+=line_size;

      block +=line_size;

    }

POWERPC_TBL_STOP_COUNT(altivec_avg_pixels16_num, 1);

#endif /* ALTIVEC_USE_REFERENCE_C_CODE */

}


static void blk_send_response_all(struct XenBlkDev *blkdev)

{

    struct ioreq *ioreq;

    int send_notify = 0;

    while (!LIST_EMPTY(&blkdev->finished)) {

        ioreq = LIST_FIRST(&blkdev->finished);

	send_notify += blk_send_response_one(ioreq);

	ioreq_release(ioreq);

    }

    if (send_notify)

	xen_be_send_notify(&blkdev->xendev);

}


static int interface_client_monitors_config(QXLInstance *sin,

                                        VDAgentMonitorsConfig *monitors_config)

{

    PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl);

    QXLRom *rom = memory_region_get_ram_ptr(&qxl->rom_bar);

    int i;

    unsigned max_outputs = ARRAY_SIZE(rom->client_monitors_config.heads);

    if (qxl->revision < 4) {

        trace_qxl_client_monitors_config_unsupported_by_device(qxl->id,

                                                               qxl->revision);

        return 0;

    }

    /*

     * Older windows drivers set int_mask to 0 when their ISR is called,

     * then later set it to ~0. So it doesn't relate to the actual interrupts

     * handled. However, they are old, so clearly they don't support this

     * interrupt

     */

    if (qxl->ram->int_mask == 0 || qxl->ram->int_mask == ~0 ||

        !(qxl->ram->int_mask & QXL_INTERRUPT_CLIENT_MONITORS_CONFIG)) {

        trace_qxl_client_monitors_config_unsupported_by_guest(qxl->id,

                                                            qxl->ram->int_mask,

                                                            monitors_config);

        return 0;

    }

    if (!monitors_config) {

        return 1;

    }

#if SPICE_SERVER_VERSION >= 0x000c06 /* release 0.12.6 */

    /* limit number of outputs based on setting limit */

    if (qxl->max_outputs && qxl->max_outputs <= max_outputs) {

        max_outputs = qxl->max_outputs;

    }

#endif

    memset(&rom->client_monitors_config, 0,

           sizeof(rom->client_monitors_config));

    rom->client_monitors_config.count = monitors_config->num_of_monitors;

    /* monitors_config->flags ignored */

    if (rom->client_monitors_config.count >= max_outputs) {

        trace_qxl_client_monitors_config_capped(qxl->id,

                                monitors_config->num_of_monitors,

                                max_outputs);

        rom->client_monitors_config.count = max_outputs;

    }

    for (i = 0 ; i < rom->client_monitors_config.count ; ++i) {

        VDAgentMonConfig *monitor = &monitors_config->monitors[i];

        QXLURect *rect = &rom->client_monitors_config.heads[i];

        /* monitor->depth ignored */

        rect->left = monitor->x;

        rect->top = monitor->y;

        rect->right = monitor->x + monitor->width;

        rect->bottom = monitor->y + monitor->height;

    }

    rom->client_monitors_config_crc = qxl_crc32(

            (const uint8_t *)&rom->client_monitors_config,

            sizeof(rom->client_monitors_config));

    trace_qxl_client_monitors_config_crc(qxl->id,

            sizeof(rom->client_monitors_config),

            rom->client_monitors_config_crc);

    trace_qxl_interrupt_client_monitors_config(qxl->id,

                        rom->client_monitors_config.count,

                        rom->client_monitors_config.heads);

    qxl_send_events(qxl, QXL_INTERRUPT_CLIENT_MONITORS_CONFIG);

    return 1;

}


static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)

{

    VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);

    VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);

    /*

     * virtio pci bar layout used by default.

     * subclasses can re-arrange things if needed.

     *

     *   region 0   --  virtio legacy io bar

     *   region 1   --  msi-x bar

     *   region 4+5 --  virtio modern memory (64bit) bar

     *

     */

    proxy->legacy_io_bar  = 0;

    proxy->msix_bar       = 1;

    proxy->modern_io_bar  = 2;

    proxy->modern_mem_bar = 4;

    proxy->common.offset = 0x0;

    proxy->common.size = 0x1000;

    proxy->common.type = VIRTIO_PCI_CAP_COMMON_CFG;

    proxy->isr.offset = 0x1000;

    proxy->isr.size = 0x1000;

    proxy->isr.type = VIRTIO_PCI_CAP_ISR_CFG;

    proxy->device.offset = 0x2000;

    proxy->device.size = 0x1000;

    proxy->device.type = VIRTIO_PCI_CAP_DEVICE_CFG;

    proxy->notify.offset = 0x3000;

    proxy->notify.size =

        QEMU_VIRTIO_PCI_QUEUE_MEM_MULT * VIRTIO_QUEUE_MAX;

    proxy->notify.type = VIRTIO_PCI_CAP_NOTIFY_CFG;

    proxy->notify_pio.offset = 0x0;

    proxy->notify_pio.size = 0x4;

    proxy->notify_pio.type = VIRTIO_PCI_CAP_NOTIFY_CFG;

    /* subclasses can enforce modern, so do this unconditionally */

    memory_region_init(&proxy->modern_bar, OBJECT(proxy), "virtio-pci",

                       2 * QEMU_VIRTIO_PCI_QUEUE_MEM_MULT *

                       VIRTIO_QUEUE_MAX);

    memory_region_init_alias(&proxy->modern_cfg,

                             OBJECT(proxy),

                             "virtio-pci-cfg",

                             &proxy->modern_bar,

                             0,

                             memory_region_size(&proxy->modern_bar));

    address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");

    if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus) &&

        !pci_bus_is_root(pci_dev->bus)) {

        int pos;

        pos = pcie_endpoint_cap_init(pci_dev, 0);

        assert(pos > 0);

        pos = pci_add_capability(pci_dev, PCI_CAP_ID_PM, 0, PCI_PM_SIZEOF);

        assert(pos > 0);

        /*

         * Indicates that this function complies with revision 1.2 of the

         * PCI Power Management Interface Specification.

         */

        pci_set_word(pci_dev->config + pos + PCI_PM_PMC, 0x3);

    } else {

        /*

         * make future invocations of pci_is_express() return false

         * and pci_config_size() return PCI_CONFIG_SPACE_SIZE.

         */

        pci_dev->cap_present &= ~QEMU_PCI_CAP_EXPRESS;

    }

    virtio_pci_bus_new(&proxy->bus, sizeof(proxy->bus), proxy);

    if (k->realize) {

        k->realize(proxy, errp);

    }

}


static int cdxl_decode_frame(AVCodecContext *avctx, void *data,

                             int *data_size, AVPacket *pkt)

{

    CDXLVideoContext *c = avctx->priv_data;

    AVFrame * const p = &c->frame;

    int ret, w, h, encoding, format, buf_size = pkt->size;

    const uint8_t *buf = pkt->data;

    if (buf_size < 32)

        return AVERROR_INVALIDDATA;

    encoding        = buf[1] & 7;

    format          = buf[1] & 0xE0;

    w               = AV_RB16(&buf[14]);

    h               = AV_RB16(&buf[16]);

    c->bpp          = buf[19];

    c->palette_size = AV_RB16(&buf[20]);

    c->palette      = buf + 32;

    c->video        = c->palette + c->palette_size;

    c->video_size   = buf_size - c->palette_size - 32;

    if (c->palette_size > 512)

        return AVERROR_INVALIDDATA;

    if (buf_size < c->palette_size + 32)

        return AVERROR_INVALIDDATA;

    if (c->bpp < 1)

        return AVERROR_INVALIDDATA;

    if (c->bpp > 8) {

        av_log_ask_for_sample(avctx, "unsupported pixel size: %d\n", c->bpp);

        return AVERROR_PATCHWELCOME;

    }

    if (format) {

        av_log_ask_for_sample(avctx, "unsupported pixel format: %d\n", format);

        return AVERROR_PATCHWELCOME;

    }

    if ((ret = av_image_check_size(w, h, 0, avctx)) < 0)

        return ret;

    if (w != avctx->width || h != avctx->height)

        avcodec_set_dimensions(avctx, w, h);

    if (c->video_size < FFALIGN(avctx->width, 16) * avctx->height * c->bpp / 8)

        return AVERROR_INVALIDDATA;

    if (!encoding && c->palette_size && c->bpp <= 8) {

        avctx->pix_fmt = PIX_FMT_PAL8;

    } else if (encoding == 1 && (c->bpp == 6 || c->bpp == 8)) {

        if (c->palette_size != (1 << (c->bpp - 1)))

            return AVERROR_INVALIDDATA;

        avctx->pix_fmt = PIX_FMT_BGR24;

    } else {

        av_log_ask_for_sample(avctx, "unsupported encoding %d and bpp %d\n",

                              encoding, c->bpp);

        return AVERROR_PATCHWELCOME;

    }

    if (p->data[0])

        avctx->release_buffer(avctx, p);

    p->reference = 0;

    if ((ret = avctx->get_buffer(avctx, p)) < 0) {

        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");

        return ret;

    }

    p->pict_type = AV_PICTURE_TYPE_I;

    if (encoding) {

        av_fast_padded_malloc(&c->new_video, &c->new_video_size,

                              h * w + FF_INPUT_BUFFER_PADDING_SIZE);

        if (!c->new_video)

            return AVERROR(ENOMEM);

        if (c->bpp == 8)

            cdxl_decode_ham8(c);

        else

            cdxl_decode_ham6(c);

    } else {

        cdxl_decode_rgb(c);

    }

    *data_size      = sizeof(AVFrame);

    *(AVFrame*)data = c->frame;

    return buf_size;

}


static int decode_0(PAFVideoDecContext *c, uint8_t *pkt, uint8_t code)

{

    uint32_t opcode_size, offset;

    uint8_t *dst, *dend, mask = 0, color = 0;

    const uint8_t *src, *send, *opcodes;

    int i, j, op = 0;

    i = bytestream2_get_byte(&c->gb);

    if (i) {

        if (code & 0x10) {

            int align;

            align = bytestream2_tell(&c->gb) & 3;

            if (align)

                bytestream2_skip(&c->gb, 4 - align);

        }

        do {

            int page, val, x, y;

            val    = bytestream2_get_be16(&c->gb);

            page   = val >> 14;

            x      = (val & 0x7F) * 2;

            y      = ((val >> 7) & 0x7F) * 2;

            dst    = c->frame[page] + x + y * c->width;

            dend   = c->frame[page] + c->frame_size;

            offset = (x & 0x7F) * 2;

            j      = bytestream2_get_le16(&c->gb) + offset;

            do {

                offset++;

                if (dst + 3 * c->width + 4 > dend)

                    return AVERROR_INVALIDDATA;

                read4x4block(c, dst, c->width);

                if ((offset & 0x3F) == 0)

                    dst += c->width * 3;

                dst += 4;

            } while (offset < j);

        } while (--i);

    }

    dst  = c->frame[c->current_frame];

    dend = c->frame[c->current_frame] + c->frame_size;

    do {

        set_src_position(c, &src, &send);

        if ((src + 3 * c->width + 4 > send) ||

            (dst + 3 * c->width + 4 > dend))

            return AVERROR_INVALIDDATA;

        copy_block4(dst, src, c->width, c->width, 4);

        i++;

        if ((i & 0x3F) == 0)

            dst += c->width * 3;

        dst += 4;

    } while (i < c->video_size / 16);

    opcode_size = bytestream2_get_le16(&c->gb);

    bytestream2_skip(&c->gb, 2);

    if (bytestream2_get_bytes_left(&c->gb) < opcode_size)

        return AVERROR_INVALIDDATA;

    opcodes = pkt + bytestream2_tell(&c->gb);

    bytestream2_skipu(&c->gb, opcode_size);

    dst = c->frame[c->current_frame];

    for (i = 0; i < c->height; i += 4, dst += c->width * 3)

        for (j = 0; j < c->width; j += 4, dst += 4) {

            int opcode, k = 0;

            if (op > opcode_size)

                return AVERROR_INVALIDDATA;

            if (j & 4) {

                opcode = opcodes[op] & 15;

                op++;

            } else {

                opcode = opcodes[op] >> 4;

            }

            while (block_sequences[opcode][k]) {

                offset = c->width * 2;

                code   = block_sequences[opcode][k++];

                switch (code) {

                case 2:

                    offset = 0;

                case 3:

                    color = bytestream2_get_byte(&c->gb);

                case 4:

                    mask = bytestream2_get_byte(&c->gb);

                    copy_color_mask(dst + offset, c->width, mask, color);

                    break;

                case 5:

                    offset = 0;

                case 6:

                    set_src_position(c, &src, &send);

                case 7:

                    if (src + offset + c->width + 4 > send)

                        return AVERROR_INVALIDDATA;

                    mask = bytestream2_get_byte(&c->gb);

                    copy_src_mask(dst + offset, c->width, mask, src + offset);

                    break;

                }

            }

        }

    return 0;

}


static void save_native_fp_fsave(CPUState *env)

{

    int fptag, i, j;

    uint16_t fpuc;

    struct fpstate fp1, *fp = &fp1;

    asm volatile ("fsave %0" : : "m" (*fp));

    env->fpuc = fp->fpuc;

    env->fpstt = (fp->fpus >> 11) & 7;

    env->fpus = fp->fpus & ~0x3800;

    fptag = fp->fptag;

    for(i = 0;i < 8; i++) {

        env->fptags[i] = ((fptag & 3) == 3);

        fptag >>= 2;

    }

    j = env->fpstt;

    for(i = 0;i < 8; i++) {

        memcpy(&env->fpregs[j].d, &fp->fpregs1[i * 10], 10);

        j = (j + 1) & 7;

    }

    /* we must restore the default rounding state */

    fpuc = 0x037f | (env->fpuc & (3 << 10));

    asm volatile("fldcw %0" : : "m" (fpuc));

}


static int decode_thread(void *arg)

{

    VideoState *is = arg;

    AVFormatContext *ic;

    int err, i, ret, video_index, audio_index, subtitle_index;

    AVPacket pkt1, *pkt = &pkt1;

    AVFormatParameters params, *ap = &params;

    video_index = -1;

    audio_index = -1;

    subtitle_index = -1;

    is->video_stream = -1;

    is->audio_stream = -1;

    is->subtitle_stream = -1;

    global_video_state = is;

    url_set_interrupt_cb(decode_interrupt_cb);

    memset(ap, 0, sizeof(*ap));

    ap->width = frame_width;

    ap->height= frame_height;

    ap->time_base= (AVRational){1, 25};

    ap->pix_fmt = frame_pix_fmt;

    err = av_open_input_file(&ic, is->filename, is->iformat, 0, ap);

    if (err < 0) {

        print_error(is->filename, err);

        ret = -1;

        goto fail;

    }

    is->ic = ic;

    if(genpts)

        ic->flags |= AVFMT_FLAG_GENPTS;

    err = av_find_stream_info(ic);

    if (err < 0) {

        fprintf(stderr, "%s: could not find codec parameters\n", is->filename);

        ret = -1;

        goto fail;

    }

    if(ic->pb)

        ic->pb->eof_reached= 0; //FIXME hack, ffplay maybe should not use url_feof() to test for the end

    /* if seeking requested, we execute it */

    if (start_time != AV_NOPTS_VALUE) {

        int64_t timestamp;

        timestamp = start_time;

        /* add the stream start time */

        if (ic->start_time != AV_NOPTS_VALUE)

            timestamp += ic->start_time;

        ret = av_seek_frame(ic, -1, timestamp, AVSEEK_FLAG_BACKWARD);

        if (ret < 0) {

            fprintf(stderr, "%s: could not seek to position %0.3f\n",

                    is->filename, (double)timestamp / AV_TIME_BASE);

        }

    }

    for(i = 0; i < ic->nb_streams; i++) {

        AVCodecContext *enc = ic->streams[i]->codec;

        ic->streams[i]->discard = AVDISCARD_ALL;

        switch(enc->codec_type) {

        case CODEC_TYPE_AUDIO:

            if ((audio_index < 0 || wanted_audio_stream-- > 0) && !audio_disable)

                audio_index = i;

            break;

        case CODEC_TYPE_VIDEO:

            if ((video_index < 0 || wanted_video_stream-- > 0) && !video_disable)

                video_index = i;

            break;

        case CODEC_TYPE_SUBTITLE:

            if (wanted_subtitle_stream-- >= 0 && !video_disable)

                subtitle_index = i;

            break;

        default:

            break;

        }

    }

    if (show_status) {

        dump_format(ic, 0, is->filename, 0);

        dump_stream_info(ic);

    }

    /* open the streams */

    if (audio_index >= 0) {

        stream_component_open(is, audio_index);

    }

    if (video_index >= 0) {

        stream_component_open(is, video_index);

    } else {

        if (!display_disable)

            is->show_audio = 1;

    }

    if (subtitle_index >= 0) {

        stream_component_open(is, subtitle_index);

    }

    if (is->video_stream < 0 && is->audio_stream < 0) {

        fprintf(stderr, "%s: could not open codecs\n", is->filename);

        ret = -1;

        goto fail;

    }

    for(;;) {

        if (is->abort_request)

            break;

        if (is->paused != is->last_paused) {

            is->last_paused = is->paused;

            if (is->paused)

                av_read_pause(ic);

            else

                av_read_play(ic);

        }

#if CONFIG_RTSP_DEMUXER

        if (is->paused && !strcmp(ic->iformat->name, "rtsp")) {

            /* wait 10 ms to avoid trying to get another packet */

            /* XXX: horrible */

            SDL_Delay(10);

            continue;

        }

#endif

        if (is->seek_req) {

            int stream_index= -1;

            int64_t seek_target= is->seek_pos;

            if     (is->   video_stream >= 0) stream_index= is->   video_stream;

            else if(is->   audio_stream >= 0) stream_index= is->   audio_stream;

            else if(is->subtitle_stream >= 0) stream_index= is->subtitle_stream;

            if(stream_index>=0){

                seek_target= av_rescale_q(seek_target, AV_TIME_BASE_Q, ic->streams[stream_index]->time_base);

            }

            ret = av_seek_frame(is->ic, stream_index, seek_target, is->seek_flags);

            if (ret < 0) {

                fprintf(stderr, "%s: error while seeking\n", is->ic->filename);

            }else{

                if (is->audio_stream >= 0) {

                    packet_queue_flush(&is->audioq);

                    packet_queue_put(&is->audioq, &flush_pkt);

                }

                if (is->subtitle_stream >= 0) {

                    packet_queue_flush(&is->subtitleq);

                    packet_queue_put(&is->subtitleq, &flush_pkt);

                }

                if (is->video_stream >= 0) {

                    packet_queue_flush(&is->videoq);

                    packet_queue_put(&is->videoq, &flush_pkt);

                }

            }

            is->seek_req = 0;

        }

        /* if the queue are full, no need to read more */

        if (is->audioq.size > MAX_AUDIOQ_SIZE ||

            is->videoq.size > MAX_VIDEOQ_SIZE ||

            is->subtitleq.size > MAX_SUBTITLEQ_SIZE) {

            /* wait 10 ms */

            SDL_Delay(10);

            continue;

        }

        if(url_feof(ic->pb)) {

            av_init_packet(pkt);

            pkt->data=NULL;

            pkt->size=0;

            pkt->stream_index= is->video_stream;

            packet_queue_put(&is->videoq, pkt);

            continue;

        }

        ret = av_read_frame(ic, pkt);

        if (ret < 0) {

            if (ret != AVERROR_EOF && url_ferror(ic->pb) == 0) {

                SDL_Delay(100); /* wait for user event */

                continue;

            } else

                break;

        }

        if (pkt->stream_index == is->audio_stream) {

            packet_queue_put(&is->audioq, pkt);

        } else if (pkt->stream_index == is->video_stream) {

            packet_queue_put(&is->videoq, pkt);

        } else if (pkt->stream_index == is->subtitle_stream) {

            packet_queue_put(&is->subtitleq, pkt);

        } else {

            av_free_packet(pkt);

        }

    }

    /* wait until the end */

    while (!is->abort_request) {

        SDL_Delay(100);

    }

    ret = 0;

 fail:

    /* disable interrupting */

    global_video_state = NULL;

    /* close each stream */

    if (is->audio_stream >= 0)

        stream_component_close(is, is->audio_stream);

    if (is->video_stream >= 0)

        stream_component_close(is, is->video_stream);

    if (is->subtitle_stream >= 0)

        stream_component_close(is, is->subtitle_stream);

    if (is->ic) {

        av_close_input_file(is->ic);

        is->ic = NULL; /* safety */

    }

    url_set_interrupt_cb(NULL);

    if (ret != 0) {

        SDL_Event event;

        event.type = FF_QUIT_EVENT;

        event.user.data1 = is;

        SDL_PushEvent(&event);

    }

    return 0;

}


static int adpcm_decode_frame(AVCodecContext *avctx, void *data,
                              int *got_frame_ptr, AVPacket *avpkt)
{
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
    ADPCMDecodeContext *c = avctx->priv_data;
    ADPCMChannelStatus *cs;
    int n, m, channel, i;
    short *samples;
    const uint8_t *src;
    int st; /* stereo */
    int count1, count2;
    int nb_samples, coded_samples, ret;
    nb_samples = get_nb_samples(avctx, buf, buf_size, &coded_samples);
    if (nb_samples <= 0) {
        av_log(avctx, AV_LOG_ERROR, "invalid number of samples in packet\n");
    }
    /* get output buffer */
    c->frame.nb_samples = nb_samples;
    if ((ret = avctx->get_buffer(avctx, &c->frame)) < 0) {
        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
        return ret;
    }
    samples = (short *)c->frame.data[0];
    /* use coded_samples when applicable */
    /* it is always <= nb_samples, so the output buffer will be large enough */
    if (coded_samples) {
        if (coded_samples != nb_samples)
            av_log(avctx, AV_LOG_WARNING, "mismatch in coded sample count\n");
        c->frame.nb_samples = nb_samples = coded_samples;
    }
    src = buf;
    st = avctx->channels == 2 ? 1 : 0;
    switch(avctx->codec->id) {
    case CODEC_ID_ADPCM_IMA_QT:
        /* In QuickTime, IMA is encoded by chunks of 34 bytes (=64 samples).
           Channel data is interleaved per-chunk. */
        for (channel = 0; channel < avctx->channels; channel++) {
            int16_t predictor;
            int step_index;
            cs = &(c->status[channel]);
            /* (pppppp) (piiiiiii) */
            /* Bits 15-7 are the _top_ 9 bits of the 16-bit initial predictor value */
            predictor = AV_RB16(src);
            step_index = predictor & 0x7F;
            predictor &= 0xFF80;
            src += 2;
            if (cs->step_index == step_index) {
                int diff = (int)predictor - cs->predictor;
                if (diff < 0)
                    diff = - diff;
                if (diff > 0x7f)
                    goto update;
            } else {
            update:
                cs->step_index = step_index;
                cs->predictor = predictor;
            }
            if (cs->step_index > 88){
                av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n", cs->step_index);
                cs->step_index = 88;
            }
            samples = (short *)c->frame.data[0] + channel;
            for (m = 0; m < 32; m++) {
                *samples = adpcm_ima_qt_expand_nibble(cs, src[0] & 0x0F, 3);
                samples += avctx->channels;
                *samples = adpcm_ima_qt_expand_nibble(cs, src[0] >> 4  , 3);
                samples += avctx->channels;
                src ++;
            }
        }
        break;
    case CODEC_ID_ADPCM_IMA_WAV:
        if (avctx->block_align != 0 && buf_size > avctx->block_align)
            buf_size = avctx->block_align;
        for(i=0; i<avctx->channels; i++){
            cs = &(c->status[i]);
            cs->predictor = *samples++ = (int16_t)bytestream_get_le16(&src);
            cs->step_index = *src++;
            if (cs->step_index > 88){
                av_log(avctx, AV_LOG_ERROR, "ERROR: step_index = %i\n", cs->step_index);
                cs->step_index = 88;
            }
            if (*src++) av_log(avctx, AV_LOG_ERROR, "unused byte should be null but is %d!!\n", src[-1]); /* unused */
        }
        for (n = (nb_samples - 1) / 8; n > 0; n--) {
            for (i = 0; i < avctx->channels; i++) {
                cs = &c->status[i];
                for (m = 0; m < 4; m++) {
                    uint8_t v = *src++;
                    *samples = adpcm_ima_expand_nibble(cs, v & 0x0F, 3);
                    samples += avctx->channels;
                    *samples = adpcm_ima_expand_nibble(cs, v >> 4  , 3);
                    samples += avctx->channels;
                }
                samples -= 8 * avctx->channels - 1;
            }
            samples += 7 * avctx->channels;
        }
        break;
    case CODEC_ID_ADPCM_4XM:
        for (i = 0; i < avctx->channels; i++)
            c->status[i].predictor= (int16_t)bytestream_get_le16(&src);
        for (i = 0; i < avctx->channels; i++) {
            c->status[i].step_index= (int16_t)bytestream_get_le16(&src);
            c->status[i].step_index = av_clip(c->status[i].step_index, 0, 88);
        }
        for (i = 0; i < avctx->channels; i++) {
            samples = (short *)c->frame.data[0] + i;
            cs = &c->status[i];
            for (n = nb_samples >> 1; n > 0; n--, src++) {
                uint8_t v = *src;
                *samples = adpcm_ima_expand_nibble(cs, v & 0x0F, 4);
                samples += avctx->channels;
                *samples = adpcm_ima_expand_nibble(cs, v >> 4  , 4);
                samples += avctx->channels;
            }
        }
        break;
    case CODEC_ID_ADPCM_MS:
    {
        int block_predictor;
        if (avctx->block_align != 0 && buf_size > avctx->block_align)
            buf_size = avctx->block_align;
        block_predictor = av_clip(*src++, 0, 6);
        c->status[0].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor];
        c->status[0].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor];
        if (st) {
            block_predictor = av_clip(*src++, 0, 6);
            c->status[1].coeff1 = ff_adpcm_AdaptCoeff1[block_predictor];
            c->status[1].coeff2 = ff_adpcm_AdaptCoeff2[block_predictor];
        }
        c->status[0].idelta = (int16_t)bytestream_get_le16(&src);
        if (st){
            c->status[1].idelta = (int16_t)bytestream_get_le16(&src);
        }
        c->status[0].sample1 = bytestream_get_le16(&src);
        if (st) c->status[1].sample1 = bytestream_get_le16(&src);
        c->status[0].sample2 = bytestream_get_le16(&src);
        if (st) c->status[1].sample2 = bytestream_get_le16(&src);
        *samples++ = c->status[0].sample2;
        if (st) *samples++ = c->status[1].sample2;
        *samples++ = c->status[0].sample1;
        if (st) *samples++ = c->status[1].sample1;
        for(n = (nb_samples - 2) >> (1 - st); n > 0; n--, src++) {
            *samples++ = adpcm_ms_expand_nibble(&c->status[0 ], src[0] >> 4  );
            *samples++ = adpcm_ms_expand_nibble(&c->status[st], src[0] & 0x0F);
        }
        break;
    }
    case CODEC_ID_ADPCM_IMA_DK4:
        if (avctx->block_align != 0 && buf_size > avctx->block_align)
            buf_size = avctx->block_align;
        for (channel = 0; channel < avctx->channels; channel++) {
            cs = &c->status[channel];
            cs->predictor  = (int16_t)bytestream_get_le16(&src);
            cs->step_index = *src++;
            src++;
            *samples++ = cs->predictor;
        }
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            uint8_t v = *src;
            *samples++ = adpcm_ima_expand_nibble(&c->status[0 ], v >> 4  , 3);
            *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
        }
        break;
    case CODEC_ID_ADPCM_IMA_DK3:
    {
        unsigned char last_byte = 0;
        unsigned char nibble;
        int decode_top_nibble_next = 0;
        int end_of_packet = 0;
        int diff_channel;
        if (avctx->block_align != 0 && buf_size > avctx->block_align)
            buf_size = avctx->block_align;
        c->status[0].predictor  = (int16_t)AV_RL16(src + 10);
        c->status[1].predictor  = (int16_t)AV_RL16(src + 12);
        c->status[0].step_index = src[14];
        c->status[1].step_index = src[15];
        /* sign extend the predictors */
        src += 16;
        diff_channel = c->status[1].predictor;
        /* the DK3_GET_NEXT_NIBBLE macro issues the break statement when
         * the buffer is consumed */
        while (1) {
            /* for this algorithm, c->status[0] is the sum channel and
             * c->status[1] is the diff channel */
            /* process the first predictor of the sum channel */
            DK3_GET_NEXT_NIBBLE();
            adpcm_ima_expand_nibble(&c->status[0], nibble, 3);
            /* process the diff channel predictor */
            DK3_GET_NEXT_NIBBLE();
            adpcm_ima_expand_nibble(&c->status[1], nibble, 3);
            /* process the first pair of stereo PCM samples */
            diff_channel = (diff_channel + c->status[1].predictor) / 2;
            *samples++ = c->status[0].predictor + c->status[1].predictor;
            *samples++ = c->status[0].predictor - c->status[1].predictor;
            /* process the second predictor of the sum channel */
            DK3_GET_NEXT_NIBBLE();
            adpcm_ima_expand_nibble(&c->status[0], nibble, 3);
            /* process the second pair of stereo PCM samples */
            diff_channel = (diff_channel + c->status[1].predictor) / 2;
            *samples++ = c->status[0].predictor + c->status[1].predictor;
            *samples++ = c->status[0].predictor - c->status[1].predictor;
        }
        break;
    }
    case CODEC_ID_ADPCM_IMA_ISS:
        for (channel = 0; channel < avctx->channels; channel++) {
            cs = &c->status[channel];
            cs->predictor  = (int16_t)bytestream_get_le16(&src);
            cs->step_index = *src++;
            src++;
        }
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            uint8_t v1, v2;
            uint8_t v = *src;
            /* nibbles are swapped for mono */
            if (st) {
                v1 = v >> 4;
                v2 = v & 0x0F;
            } else {
                v2 = v >> 4;
                v1 = v & 0x0F;
            }
            *samples++ = adpcm_ima_expand_nibble(&c->status[0 ], v1, 3);
            *samples++ = adpcm_ima_expand_nibble(&c->status[st], v2, 3);
        }
        break;
    case CODEC_ID_ADPCM_IMA_WS:
        while (src < buf + buf_size) {
            uint8_t v = *src++;
            *samples++ = adpcm_ima_expand_nibble(&c->status[0],  v >> 4  , 3);
            *samples++ = adpcm_ima_expand_nibble(&c->status[st], v & 0x0F, 3);
        }
        break;
    case CODEC_ID_ADPCM_XA:
        while (buf_size >= 128) {
            xa_decode(samples, src, &c->status[0], &c->status[1],
                avctx->channels);
            src += 128;
            samples += 28 * 8;
            buf_size -= 128;
        }
        break;
    case CODEC_ID_ADPCM_IMA_EA_EACS:
        src += 4; // skip sample count (already read)
        for (i=0; i<=st; i++)
            c->status[i].step_index = bytestream_get_le32(&src);
        for (i=0; i<=st; i++)
            c->status[i].predictor  = bytestream_get_le32(&src);
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            *samples++ = adpcm_ima_expand_nibble(&c->status[0],  *src>>4,   3);
            *samples++ = adpcm_ima_expand_nibble(&c->status[st], *src&0x0F, 3);
        }
        break;
    case CODEC_ID_ADPCM_IMA_EA_SEAD:
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            *samples++ = adpcm_ima_expand_nibble(&c->status[0], src[0] >> 4, 6);
            *samples++ = adpcm_ima_expand_nibble(&c->status[st],src[0]&0x0F, 6);
        }
        break;
    case CODEC_ID_ADPCM_EA:
    {
        int32_t previous_left_sample, previous_right_sample;
        int32_t current_left_sample, current_right_sample;
        int32_t next_left_sample, next_right_sample;
        int32_t coeff1l, coeff2l, coeff1r, coeff2r;
        uint8_t shift_left, shift_right;
        /* Each EA ADPCM frame has a 12-byte header followed by 30-byte pieces,
           each coding 28 stereo samples. */
        src += 4; // skip sample count (already read)
        current_left_sample   = (int16_t)bytestream_get_le16(&src);
        previous_left_sample  = (int16_t)bytestream_get_le16(&src);
        current_right_sample  = (int16_t)bytestream_get_le16(&src);
        previous_right_sample = (int16_t)bytestream_get_le16(&src);
        for (count1 = 0; count1 < nb_samples / 28; count1++) {
            coeff1l = ea_adpcm_table[ *src >> 4       ];
            coeff2l = ea_adpcm_table[(*src >> 4  ) + 4];
            coeff1r = ea_adpcm_table[*src & 0x0F];
            coeff2r = ea_adpcm_table[(*src & 0x0F) + 4];
            src++;
            shift_left  = 20 - (*src >> 4);
            shift_right = 20 - (*src & 0x0F);
            src++;
            for (count2 = 0; count2 < 28; count2++) {
                next_left_sample  = sign_extend(*src >> 4, 4) << shift_left;
                next_right_sample = sign_extend(*src,      4) << shift_right;
                src++;
                next_left_sample = (next_left_sample +
                    (current_left_sample * coeff1l) +
                    (previous_left_sample * coeff2l) + 0x80) >> 8;
                next_right_sample = (next_right_sample +
                    (current_right_sample * coeff1r) +
                    (previous_right_sample * coeff2r) + 0x80) >> 8;
                previous_left_sample = current_left_sample;
                current_left_sample = av_clip_int16(next_left_sample);
                previous_right_sample = current_right_sample;
                current_right_sample = av_clip_int16(next_right_sample);
                *samples++ = (unsigned short)current_left_sample;
                *samples++ = (unsigned short)current_right_sample;
            }
        }
        if (src - buf == buf_size - 2)
            src += 2; // Skip terminating 0x0000
        break;
    }
    case CODEC_ID_ADPCM_EA_MAXIS_XA:
    {
        int coeff[2][2], shift[2];
        for(channel = 0; channel < avctx->channels; channel++) {
            for (i=0; i<2; i++)
                coeff[channel][i] = ea_adpcm_table[(*src >> 4) + 4*i];
            shift[channel] = 20 - (*src & 0x0F);
            src++;
        }
        for (count1 = 0; count1 < nb_samples / 2; count1++) {
            for(i = 4; i >= 0; i-=4) { /* Pairwise samples LL RR (st) or LL LL (mono) */
                for(channel = 0; channel < avctx->channels; channel++) {
                    int32_t sample = sign_extend(src[channel] >> i, 4) << shift[channel];
                    sample = (sample +
                             c->status[channel].sample1 * coeff[channel][0] +
                             c->status[channel].sample2 * coeff[channel][1] + 0x80) >> 8;
                    c->status[channel].sample2 = c->status[channel].sample1;
                    c->status[channel].sample1 = av_clip_int16(sample);
                    *samples++ = c->status[channel].sample1;
                }
            }
            src+=avctx->channels;
        }
        /* consume whole packet */
        src = buf + buf_size;
        break;
    }
    case CODEC_ID_ADPCM_EA_R1:
    case CODEC_ID_ADPCM_EA_R2:
    case CODEC_ID_ADPCM_EA_R3: {
        /* channel numbering
           2chan: 0=fl, 1=fr
           4chan: 0=fl, 1=rl, 2=fr, 3=rr
           6chan: 0=fl, 1=c,  2=fr, 3=rl,  4=rr, 5=sub */
        const int big_endian = avctx->codec->id == CODEC_ID_ADPCM_EA_R3;
        int32_t previous_sample, current_sample, next_sample;
        int32_t coeff1, coeff2;
        uint8_t shift;
        unsigned int channel;
        uint16_t *samplesC;
        const uint8_t *srcC;
        const uint8_t *src_end = buf + buf_size;
        int count = 0;
        src += 4; // skip sample count (already read)
        for (channel=0; channel<avctx->channels; channel++) {
            int32_t offset = (big_endian ? bytestream_get_be32(&src)
                                         : bytestream_get_le32(&src))
                           + (avctx->channels-channel-1) * 4;
            if ((offset < 0) || (offset >= src_end - src - 4)) break;
            srcC  = src + offset;
            samplesC = samples + channel;
            if (avctx->codec->id == CODEC_ID_ADPCM_EA_R1) {
                current_sample  = (int16_t)bytestream_get_le16(&srcC);
                previous_sample = (int16_t)bytestream_get_le16(&srcC);
            } else {
                current_sample  = c->status[channel].predictor;
                previous_sample = c->status[channel].prev_sample;
            }
            for (count1 = 0; count1 < nb_samples / 28; count1++) {
                if (*srcC == 0xEE) {  /* only seen in R2 and R3 */
                    srcC++;
                    if (srcC > src_end - 30*2) break;
                    current_sample  = (int16_t)bytestream_get_be16(&srcC);
                    previous_sample = (int16_t)bytestream_get_be16(&srcC);
                    for (count2=0; count2<28; count2++) {
                        *samplesC = (int16_t)bytestream_get_be16(&srcC);
                        samplesC += avctx->channels;
                    }
                } else {
                    coeff1 = ea_adpcm_table[ *srcC>>4     ];
                    coeff2 = ea_adpcm_table[(*srcC>>4) + 4];
                    shift = 20 - (*srcC++ & 0x0F);
                    if (srcC > src_end - 14) break;
                    for (count2=0; count2<28; count2++) {
                        if (count2 & 1)
                            next_sample = sign_extend(*srcC++,    4) << shift;
                        else
                            next_sample = sign_extend(*srcC >> 4, 4) << shift;
                        next_sample += (current_sample  * coeff1) +
                                       (previous_sample * coeff2);
                        next_sample = av_clip_int16(next_sample >> 8);
                        previous_sample = current_sample;
                        current_sample  = next_sample;
                        *samplesC = current_sample;
                        samplesC += avctx->channels;
                    }
                }
            }
            if (!count) {
                count = count1;
            } else if (count != count1) {
                av_log(avctx, AV_LOG_WARNING, "per-channel sample count mismatch\n");
                count = FFMAX(count, count1);
            }
            if (avctx->codec->id != CODEC_ID_ADPCM_EA_R1) {
                c->status[channel].predictor   = current_sample;
                c->status[channel].prev_sample = previous_sample;
            }
        }
        c->frame.nb_samples = count * 28;
        src = src_end;
        break;
    }
    case CODEC_ID_ADPCM_EA_XAS:
        for (channel=0; channel<avctx->channels; channel++) {
            int coeff[2][4], shift[4];
            short *s2, *s = &samples[channel];
            for (n=0; n<4; n++, s+=32*avctx->channels) {
                for (i=0; i<2; i++)
                    coeff[i][n] = ea_adpcm_table[(src[0]&0x0F)+4*i];
                shift[n] = 20 - (src[2] & 0x0F);
                for (s2=s, i=0; i<2; i++, src+=2, s2+=avctx->channels)
                    s2[0] = (src[0]&0xF0) + (src[1]<<8);
            }
            for (m=2; m<32; m+=2) {
                s = &samples[m*avctx->channels + channel];
                for (n=0; n<4; n++, src++, s+=32*avctx->channels) {
                    for (s2=s, i=0; i<8; i+=4, s2+=avctx->channels) {
                        int level = sign_extend(*src >> (4 - i), 4) << shift[n];
                        int pred  = s2[-1*avctx->channels] * coeff[0][n]
                                  + s2[-2*avctx->channels] * coeff[1][n];
                        s2[0] = av_clip_int16((level + pred + 0x80) >> 8);
                    }
                }
            }
        }
        break;
    case CODEC_ID_ADPCM_IMA_AMV:
    case CODEC_ID_ADPCM_IMA_SMJPEG:
        c->status[0].predictor = (int16_t)bytestream_get_le16(&src);
        c->status[0].step_index = bytestream_get_le16(&src);
        if (avctx->codec->id == CODEC_ID_ADPCM_IMA_AMV)
            src+=4;
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            char hi, lo;
            lo = *src & 0x0F;
            hi = *src >> 4;
            if (avctx->codec->id == CODEC_ID_ADPCM_IMA_AMV)
                FFSWAP(char, hi, lo);
            *samples++ = adpcm_ima_expand_nibble(&c->status[0],
                lo, 3);
            *samples++ = adpcm_ima_expand_nibble(&c->status[0],
                hi, 3);
        }
        break;
    case CODEC_ID_ADPCM_CT:
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            uint8_t v = *src;
            *samples++ = adpcm_ct_expand_nibble(&c->status[0 ], v >> 4  );
            *samples++ = adpcm_ct_expand_nibble(&c->status[st], v & 0x0F);
        }
        break;
    case CODEC_ID_ADPCM_SBPRO_4:
    case CODEC_ID_ADPCM_SBPRO_3:
    case CODEC_ID_ADPCM_SBPRO_2:
        if (!c->status[0].step_index) {
            /* the first byte is a raw sample */
            *samples++ = 128 * (*src++ - 0x80);
            if (st)
              *samples++ = 128 * (*src++ - 0x80);
            c->status[0].step_index = 1;
            nb_samples--;
        }
        if (avctx->codec->id == CODEC_ID_ADPCM_SBPRO_4) {
            for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                    src[0] >> 4, 4, 0);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[st],
                    src[0] & 0x0F, 4, 0);
            }
        } else if (avctx->codec->id == CODEC_ID_ADPCM_SBPRO_3) {
            for (n = nb_samples / 3; n > 0; n--, src++) {
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                     src[0] >> 5        , 3, 0);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                    (src[0] >> 2) & 0x07, 3, 0);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                    src[0] & 0x03, 2, 0);
            }
        } else {
            for (n = nb_samples >> (2 - st); n > 0; n--, src++) {
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                     src[0] >> 6        , 2, 2);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[st],
                    (src[0] >> 4) & 0x03, 2, 2);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[0],
                    (src[0] >> 2) & 0x03, 2, 2);
                *samples++ = adpcm_sbpro_expand_nibble(&c->status[st],
                    src[0] & 0x03, 2, 2);
            }
        }
        break;
    case CODEC_ID_ADPCM_SWF:
    {
        GetBitContext gb;
        const int *table;
        int k0, signmask, nb_bits, count;
        int size = buf_size*8;
        init_get_bits(&gb, buf, size);
        //read bits & initial values
        nb_bits = get_bits(&gb, 2)+2;
        //av_log(NULL,AV_LOG_INFO,"nb_bits: %d\n", nb_bits);
        table = swf_index_tables[nb_bits-2];
        k0 = 1 << (nb_bits-2);
        signmask = 1 << (nb_bits-1);
        while (get_bits_count(&gb) <= size - 22*avctx->channels) {
            for (i = 0; i < avctx->channels; i++) {
                *samples++ = c->status[i].predictor = get_sbits(&gb, 16);
                c->status[i].step_index = get_bits(&gb, 6);
            }
            for (count = 0; get_bits_count(&gb) <= size - nb_bits*avctx->channels && count < 4095; count++) {
                int i;
                for (i = 0; i < avctx->channels; i++) {
                    // similar to IMA adpcm
                    int delta = get_bits(&gb, nb_bits);
                    int step = ff_adpcm_step_table[c->status[i].step_index];
                    long vpdiff = 0; // vpdiff = (delta+0.5)*step/4
                    int k = k0;
                    do {
                        if (delta & k)
                            vpdiff += step;
                        step >>= 1;
                        k >>= 1;
                    } while(k);
                    vpdiff += step;
                    if (delta & signmask)
                        c->status[i].predictor -= vpdiff;
                    else
                        c->status[i].predictor += vpdiff;
                    c->status[i].step_index += table[delta & (~signmask)];
                    c->status[i].step_index = av_clip(c->status[i].step_index, 0, 88);
                    c->status[i].predictor = av_clip_int16(c->status[i].predictor);
                    *samples++ = c->status[i].predictor;
                }
            }
        }
        src += buf_size;
        break;
    }
    case CODEC_ID_ADPCM_YAMAHA:
        for (n = nb_samples >> (1 - st); n > 0; n--, src++) {
            uint8_t v = *src;
            *samples++ = adpcm_yamaha_expand_nibble(&c->status[0 ], v & 0x0F);
            *samples++ = adpcm_yamaha_expand_nibble(&c->status[st], v >> 4  );
        }
        break;
    case CODEC_ID_ADPCM_THP:
    {
        int table[2][16];
        int prev[2][2];
        int ch;
        src += 4; // skip channel size
        src += 4; // skip number of samples (already read)
        for (i = 0; i < 32; i++)
            table[0][i] = (int16_t)bytestream_get_be16(&src);
        /* Initialize the previous sample.  */
        for (i = 0; i < 4; i++)
            prev[0][i] = (int16_t)bytestream_get_be16(&src);
        for (ch = 0; ch <= st; ch++) {
            samples = (short *)c->frame.data[0] + ch;
            /* Read in every sample for this channel.  */
            for (i = 0; i < nb_samples / 14; i++) {
                int index = (*src >> 4) & 7;
                unsigned int exp = *src++ & 15;
                int factor1 = table[ch][index * 2];
                int factor2 = table[ch][index * 2 + 1];
                /* Decode 14 samples.  */
                for (n = 0; n < 14; n++) {
                    int32_t sampledat;
                    if(n&1) sampledat = sign_extend(*src++, 4);
                    else    sampledat = sign_extend(*src >> 4, 4);
                    sampledat = ((prev[ch][0]*factor1
                                + prev[ch][1]*factor2) >> 11) + (sampledat << exp);
                    *samples = av_clip_int16(sampledat);
                    prev[ch][1] = prev[ch][0];
                    prev[ch][0] = *samples++;
                    /* In case of stereo, skip one sample, this sample
                       is for the other channel.  */
                    samples += st;
                }
            }
        }
        break;
    }
    default:
        return -1;
    }
    *got_frame_ptr   = 1;
    *(AVFrame *)data = c->frame;
    return src - buf;
}


static void cpu_ioreq_pio(ioreq_t *req)

{

    int i, sign;

    sign = req->df ? -1 : 1;

    if (req->dir == IOREQ_READ) {

        if (!req->data_is_ptr) {

            req->data = do_inp(req->addr, req->size);

        } else {

            uint32_t tmp;

            for (i = 0; i < req->count; i++) {

                tmp = do_inp(req->addr, req->size);

                cpu_physical_memory_write(

                        req->data + (sign * i * (int64_t)req->size),

                        (uint8_t *) &tmp, req->size);

            }

        }

    } else if (req->dir == IOREQ_WRITE) {

        if (!req->data_is_ptr) {

            do_outp(req->addr, req->size, req->data);

        } else {

            for (i = 0; i < req->count; i++) {

                uint32_t tmp = 0;

                cpu_physical_memory_read(

                        req->data + (sign * i * (int64_t)req->size),

                        (uint8_t*) &tmp, req->size);

                do_outp(req->addr, req->size, tmp);

            }

        }

    }

}


static char *choose_pixel_fmts(OutputStream *ost)

{

    if (ost->keep_pix_fmt) {

        if (ost->filter)

            avfilter_graph_set_auto_convert(ost->filter->graph->graph,

                                            AVFILTER_AUTO_CONVERT_NONE);

        if (ost->st->codec->pix_fmt == PIX_FMT_NONE)

            return NULL;

        ost->pix_fmts[0] = ost->st->codec->pix_fmt;

        return ost->pix_fmts;

    }

    if (ost->st->codec->pix_fmt != PIX_FMT_NONE) {

        return av_strdup(av_get_pix_fmt_name(choose_pixel_fmt(ost->st, ost->enc, ost->st->codec->pix_fmt)));

    } else if (ost->enc->pix_fmts) {

        const enum PixelFormat *p;

        AVIOContext *s = NULL;

        uint8_t *ret;

        int len;

        if (avio_open_dyn_buf(&s) < 0)

            exit_program(1);

        p = ost->enc->pix_fmts;

        if (ost->st->codec->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {

            if (ost->st->codec->codec_id == CODEC_ID_MJPEG) {

                p = (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_NONE };

            } else if (ost->st->codec->codec_id == CODEC_ID_LJPEG) {

                p = (const enum PixelFormat[]) { PIX_FMT_YUVJ420P, PIX_FMT_YUVJ422P, PIX_FMT_YUVJ444P, PIX_FMT_YUV420P,

                                                    PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_BGRA, PIX_FMT_NONE };

            }

        }

        for (; *p != PIX_FMT_NONE; p++)

            avio_printf(s, "%s:", av_get_pix_fmt_name(*p));

        len = avio_close_dyn_buf(s, &ret);

        ret[len - 1] = 0;

        return ret;

    } else

        return NULL;

}


static void mov_metadata_creation_time(AVMetadata **metadata, time_t time)

{

    char buffer[32];

    if (time) {

        time -= 2082844800;  /* seconds between 1904-01-01 and Epoch */

        strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", gmtime(&time));

        av_metadata_set2(metadata, "creation_time", buffer, 0);

    }

}


static uint32_t hpet_ram_readl(void *opaque, target_phys_addr_t addr)

{

    HPETState *s = (HPETState *)opaque;

    uint64_t cur_tick, index;

    DPRINTF("qemu: Enter hpet_ram_readl at %" PRIx64 "\n", addr);

    index = addr;

    /*address range of all TN regs*/

    if (index >= 0x100 && index <= 0x3ff) {

        uint8_t timer_id = (addr - 0x100) / 0x20;

        if (timer_id > HPET_NUM_TIMERS - 1) {

            printf("qemu: timer id out of range\n");

            return 0;

        }

        HPETTimer *timer = &s->timer[timer_id];

        switch ((addr - 0x100) % 0x20) {

            case HPET_TN_CFG:

                return timer->config;

            case HPET_TN_CFG + 4: // Interrupt capabilities

                return timer->config >> 32;

            case HPET_TN_CMP: // comparator register

                return timer->cmp;

            case HPET_TN_CMP + 4:

                return timer->cmp >> 32;

            case HPET_TN_ROUTE:

                return timer->fsb >> 32;

            default:

                DPRINTF("qemu: invalid hpet_ram_readl\n");

                break;

        }

    } else {

        switch (index) {

            case HPET_ID:

                return s->capability;

            case HPET_PERIOD:

                return s->capability >> 32;

            case HPET_CFG:

                return s->config;

            case HPET_CFG + 4:

                DPRINTF("qemu: invalid HPET_CFG + 4 hpet_ram_readl \n");

                return 0;

            case HPET_COUNTER:

                if (hpet_enabled())

                    cur_tick = hpet_get_ticks();

                else

                    cur_tick = s->hpet_counter;

                DPRINTF("qemu: reading counter  = %" PRIx64 "\n", cur_tick);

                return cur_tick;

            case HPET_COUNTER + 4:

                if (hpet_enabled())

                    cur_tick = hpet_get_ticks();

                else

                    cur_tick = s->hpet_counter;

                DPRINTF("qemu: reading counter + 4  = %" PRIx64 "\n", cur_tick);

                return cur_tick >> 32;

            case HPET_STATUS:

                return s->isr;

            default:

                DPRINTF("qemu: invalid hpet_ram_readl\n");

                break;

        }

    }

    return 0;

}


void usb_claim_port(USBDevice *dev, Error **errp)

{

    USBBus *bus = usb_bus_from_device(dev);

    USBPort *port;

    assert(dev->port == NULL);

    if (dev->port_path) {

        QTAILQ_FOREACH(port, &bus->free, next) {

            if (strcmp(port->path, dev->port_path) == 0) {

                break;

            }

        }

        if (port == NULL) {

            error_setg(errp, "usb port %s (bus %s) not found (in use?)",

                       dev->port_path, bus->qbus.name);

            return;

        }

    } else {

        if (bus->nfree == 1 && strcmp(object_get_typename(OBJECT(dev)), "usb-hub") != 0) {

            /* Create a new hub and chain it on */

            usb_create_simple(bus, "usb-hub");

        }

        if (bus->nfree == 0) {

            error_setg(errp, "tried to attach usb device %s to a bus "

                       "with no free ports", dev->product_desc);

            return;

        }

        port = QTAILQ_FIRST(&bus->free);

    }

    trace_usb_port_claim(bus->busnr, port->path);

    QTAILQ_REMOVE(&bus->free, port, next);

    bus->nfree--;

    dev->port = port;

    port->dev = dev;

    QTAILQ_INSERT_TAIL(&bus->used, port, next);

    bus->nused++;

}


static void vmxnet3_update_features(VMXNET3State *s)

{

    uint32_t guest_features;

    int rxcso_supported;

    guest_features = VMXNET3_READ_DRV_SHARED32(s->drv_shmem,

                                               devRead.misc.uptFeatures);

    rxcso_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXCSUM);

    s->rx_vlan_stripping = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_RXVLAN);

    s->lro_supported = VMXNET_FLAG_IS_SET(guest_features, UPT1_F_LRO);

    VMW_CFPRN("Features configuration: LRO: %d, RXCSUM: %d, VLANSTRIP: %d",

              s->lro_supported, rxcso_supported,

              s->rx_vlan_stripping);

    if (s->peer_has_vhdr) {

        qemu_peer_set_offload(qemu_get_queue(s->nic),

                        rxcso_supported,

                        s->lro_supported,

                        s->lro_supported,

                        0,

                        0);

    }

}


static int virtio_blk_exit_pci(PCIDevice *pci_dev)

{

    VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);

    blockdev_mark_auto_del(proxy->block.dinfo->bdrv);

    return virtio_exit_pci(pci_dev);

}


yuv2rgba64_full_1_c_template(SwsContext *c, const int32_t *buf0,

                       const int32_t *ubuf[2], const int32_t *vbuf[2],

                       const int32_t *abuf0, uint16_t *dest, int dstW,

                       int uvalpha, int y, enum AVPixelFormat target, int hasAlpha, int eightbytes)

{

    const int32_t *ubuf0 = ubuf[0], *vbuf0 = vbuf[0];

    int i;

    int A = 0xffff<<14;

    if (uvalpha < 2048) {

        for (i = 0; i < dstW; i++) {

            int Y  = (buf0[i]) >> 2;

            int U  = (ubuf0[i] + (-128 << 11)) >> 2;

            int V  = (vbuf0[i] + (-128 << 11)) >> 2;

            int R, G, B;

            Y -= c->yuv2rgb_y_offset;

            Y *= c->yuv2rgb_y_coeff;

            Y += 1 << 13;

            if (hasAlpha) {

                A = abuf0[i] << 11;

                A += 1 << 13;

            }

            R = V * c->yuv2rgb_v2r_coeff;

            G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;

            B =                            U * c->yuv2rgb_u2b_coeff;

            output_pixel(&dest[0], av_clip_uintp2(R_B + Y, 30) >> 14);

            output_pixel(&dest[1], av_clip_uintp2(  G + Y, 30) >> 14);

            output_pixel(&dest[2], av_clip_uintp2(B_R + Y, 30) >> 14);

            if (eightbytes) {

                output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14);

                dest += 4;

            } else {

                dest += 3;

            }

        }

    } else {

        const int32_t *ubuf1 = ubuf[1], *vbuf1 = vbuf[1];

        int A = 0xffff<<14;

        for (i = 0; i < dstW; i++) {

            int Y  = (buf0[i]    ) >> 2;

            int U  = (ubuf0[i] + ubuf1[i] + (-128 << 12)) >> 3;

            int V  = (vbuf0[i] + vbuf1[i] + (-128 << 12)) >> 3;

            int R, G, B;

            Y -= c->yuv2rgb_y_offset;

            Y *= c->yuv2rgb_y_coeff;

            Y += 1 << 13;

            if (hasAlpha) {

                A = abuf0[i] << 11;

                A += 1 << 13;

            }

            R = V * c->yuv2rgb_v2r_coeff;

            G = V * c->yuv2rgb_v2g_coeff + U * c->yuv2rgb_u2g_coeff;

            B =                            U * c->yuv2rgb_u2b_coeff;

            output_pixel(&dest[0], av_clip_uintp2(R_B + Y, 30) >> 14);

            output_pixel(&dest[1], av_clip_uintp2(  G + Y, 30) >> 14);

            output_pixel(&dest[2], av_clip_uintp2(B_R + Y, 30) >> 14);

            if (eightbytes) {

                output_pixel(&dest[3], av_clip_uintp2(A, 30) >> 14);

                dest += 4;

            } else {

                dest += 3;

            }

        }

    }

}


static void uhci_async_complete(USBPacket *packet, void *opaque)

{

    UHCIState *s = opaque;

    UHCIAsync *async = (UHCIAsync *) packet;

    DPRINTF("uhci: async complete. td 0x%x token 0x%x\n", async->td, async->token);

    async->done = 1;

    uhci_process_frame(s);

}


static void gen_neon_unzip(int reg, int q, int tmp, int size)

{

    int n;

    TCGv t0, t1;

    for (n = 0; n < q + 1; n += 2) {

        t0 = neon_load_reg(reg, n);

        t1 = neon_load_reg(reg, n + 1);

        switch (size) {

        case 0: gen_neon_unzip_u8(t0, t1); break;

        case 1: gen_neon_zip_u16(t0, t1); break; /* zip and unzip are the same.  */

        case 2: /* no-op */; break;

        default: abort();

        }

        neon_store_scratch(tmp + n, t0);

        neon_store_scratch(tmp + n + 1, t1);

    }

}


static void parse_numa_distance(NumaDistOptions *dist, Error **errp)

{

    uint16_t src = dist->src;

    uint16_t dst = dist->dst;

    uint8_t val = dist->val;

    if (src >= MAX_NODES || dst >= MAX_NODES) {

        error_setg(errp,

                   "Invalid node %" PRIu16

                   ", max possible could be %" PRIu16,

                   MAX(src, dst), MAX_NODES);

        return;

    }

    if (!numa_info[src].present || !numa_info[dst].present) {

        error_setg(errp, "Source/Destination NUMA node is missing. "

                   "Please use '-numa node' option to declare it first.");

        return;

    }

    if (val < NUMA_DISTANCE_MIN) {

        error_setg(errp, "NUMA distance (%" PRIu8 ") is invalid, "

                   "it shouldn't be less than %d.",

                   val, NUMA_DISTANCE_MIN);

        return;

    }

    if (src == dst && val != NUMA_DISTANCE_MIN) {

        error_setg(errp, "Local distance of node %d should be %d.",

                   src, NUMA_DISTANCE_MIN);

        return;

    }

    numa_info[src].distance[dst] = val;

    have_numa_distance = true;

}


static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc,

                         uint32_t *pal, int colors)

{

    int i;

    for (i = 0; i <= colors; i++) {

        uint8_t r, g, b;

        unsigned int idx = bytestream2_get_be16(gbc); /* color index */

        if (idx > 255) {

            av_log(avctx, AV_LOG_WARNING,

                   "Palette index out of range: %u\n", idx);

            bytestream2_skip(gbc, 6);

            continue;

        }

        r = bytestream2_get_byte(gbc);

        bytestream2_skip(gbc, 1);

        g = bytestream2_get_byte(gbc);

        bytestream2_skip(gbc, 1);

        b = bytestream2_get_byte(gbc);

        bytestream2_skip(gbc, 1);

        pal[idx] = (r << 16) | (g << 8) | b;

    }

    return 0;

}


static int compare_int64(const void *a, const void *b)

{

    int64_t va = *(int64_t *)a, vb = *(int64_t *)b;

    return va < vb ? -1 : va > vb ? +1 : 0;

}


uint32_t kvm_arch_get_supported_cpuid(CPUState *env, uint32_t function,

                                      uint32_t index, int reg)

{

    struct kvm_cpuid2 *cpuid;

    int i, max;

    uint32_t ret = 0;

    uint32_t cpuid_1_edx;

    if (!kvm_check_extension(env->kvm_state, KVM_CAP_EXT_CPUID)) {

        return -1U;

    }

    max = 1;

    while ((cpuid = try_get_cpuid(env->kvm_state, max)) == NULL) {

        max *= 2;

    }

    for (i = 0; i < cpuid->nent; ++i) {

        if (cpuid->entries[i].function == function &&

            cpuid->entries[i].index == index) {

            switch (reg) {

            case R_EAX:

                ret = cpuid->entries[i].eax;

                break;

            case R_EBX:

                ret = cpuid->entries[i].ebx;

                break;

            case R_ECX:

                ret = cpuid->entries[i].ecx;

                break;

            case R_EDX:

                ret = cpuid->entries[i].edx;

                switch (function) {

                case 1:

                    /* KVM before 2.6.30 misreports the following features */

                    ret |= CPUID_MTRR | CPUID_PAT | CPUID_MCE | CPUID_MCA;

                    break;

                case 0x80000001:

                    /* On Intel, kvm returns cpuid according to the Intel spec,

                     * so add missing bits according to the AMD spec:

                     */

                    cpuid_1_edx = kvm_arch_get_supported_cpuid(env, 1, 0, R_EDX);

                    ret |= cpuid_1_edx & 0x183f7ff;

                    break;

                }

                break;

            }

        }

    }

    qemu_free(cpuid);

    return ret;

}


static bool get_next_page(GuestPhysBlock **blockptr, uint64_t *pfnptr,

                          uint8_t **bufptr, DumpState *s)

{

    GuestPhysBlock *block = *blockptr;

    hwaddr addr;

    uint8_t *buf;

    /* block == NULL means the start of the iteration */

    if (!block) {

        block = QTAILQ_FIRST(&s->guest_phys_blocks.head);

        *blockptr = block;

        assert(block->target_start % s->page_size == 0);

        assert(block->target_end % s->page_size == 0);

        *pfnptr = paddr_to_pfn(block->target_start);

        if (bufptr) {

            *bufptr = block->host_addr;

        }

        return true;

    }

    *pfnptr = *pfnptr + 1;

    addr = pfn_to_paddr(*pfnptr);

    if ((addr >= block->target_start) &&

        (addr + s->page_size <= block->target_end)) {

        buf = block->host_addr + (addr - block->target_start);

    } else {

        /* the next page is in the next block */

        block = QTAILQ_NEXT(block, next);

        *blockptr = block;

        if (!block) {

            return false;

        }

        assert(block->target_start % s->page_size == 0);

        assert(block->target_end % s->page_size == 0);

        *pfnptr = paddr_to_pfn(block->target_start);

        buf = block->host_addr;

    }

    if (bufptr) {

        *bufptr = buf;

    }

    return true;

}


static coroutine_fn int qcow2_co_writev(BlockDriverState *bs,

                           int64_t sector_num,

                           int remaining_sectors,

                           QEMUIOVector *qiov)

{

    BDRVQcowState *s = bs->opaque;

    int index_in_cluster;

    int n_end;

    int ret;

    int cur_nr_sectors; /* number of sectors in current iteration */

    uint64_t cluster_offset;

    QEMUIOVector hd_qiov;

    uint64_t bytes_done = 0;

    uint8_t *cluster_data = NULL;

    QCowL2Meta *l2meta;

    trace_qcow2_writev_start_req(qemu_coroutine_self(), sector_num,

                                 remaining_sectors);

    qemu_iovec_init(&hd_qiov, qiov->niov);

    s->cluster_cache_offset = -1; /* disable compressed cache */

    qemu_co_mutex_lock(&s->lock);

    while (remaining_sectors != 0) {

        l2meta = NULL;

        trace_qcow2_writev_start_part(qemu_coroutine_self());

        index_in_cluster = sector_num & (s->cluster_sectors - 1);

        n_end = index_in_cluster + remaining_sectors;

        if (s->crypt_method &&

            n_end > QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors) {

            n_end = QCOW_MAX_CRYPT_CLUSTERS * s->cluster_sectors;

        }

        ret = qcow2_alloc_cluster_offset(bs, sector_num << 9,

            index_in_cluster, n_end, &cur_nr_sectors, &cluster_offset, &l2meta);

        if (ret < 0) {

            goto fail;

        }

        if (l2meta->nb_clusters > 0 &&

            (s->compatible_features & QCOW2_COMPAT_LAZY_REFCOUNTS)) {

            qcow2_mark_dirty(bs);

        }

        assert((cluster_offset & 511) == 0);

        qemu_iovec_reset(&hd_qiov);

        qemu_iovec_concat(&hd_qiov, qiov, bytes_done,

            cur_nr_sectors * 512);

        if (s->crypt_method) {

            if (!cluster_data) {

                cluster_data = qemu_blockalign(bs, QCOW_MAX_CRYPT_CLUSTERS *

                                                 s->cluster_size);

            }

            assert(hd_qiov.size <=

                   QCOW_MAX_CRYPT_CLUSTERS * s->cluster_size);

            qemu_iovec_to_buf(&hd_qiov, 0, cluster_data, hd_qiov.size);

            qcow2_encrypt_sectors(s, sector_num, cluster_data,

                cluster_data, cur_nr_sectors, 1, &s->aes_encrypt_key);

            qemu_iovec_reset(&hd_qiov);

            qemu_iovec_add(&hd_qiov, cluster_data,

                cur_nr_sectors * 512);

        }

        qemu_co_mutex_unlock(&s->lock);

        BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO);

        trace_qcow2_writev_data(qemu_coroutine_self(),

                                (cluster_offset >> 9) + index_in_cluster);

        ret = bdrv_co_writev(bs->file,

                             (cluster_offset >> 9) + index_in_cluster,

                             cur_nr_sectors, &hd_qiov);

        qemu_co_mutex_lock(&s->lock);

        if (ret < 0) {

            goto fail;

        }

        if (l2meta != NULL) {

            ret = qcow2_alloc_cluster_link_l2(bs, l2meta);

            if (ret < 0) {

                goto fail;

            }

            run_dependent_requests(s, l2meta);

            g_free(l2meta);

            l2meta = NULL;

        }

        remaining_sectors -= cur_nr_sectors;

        sector_num += cur_nr_sectors;

        bytes_done += cur_nr_sectors * 512;

        trace_qcow2_writev_done_part(qemu_coroutine_self(), cur_nr_sectors);

    }

    ret = 0;

fail:

    if (l2meta != NULL) {

        run_dependent_requests(s, l2meta);

        g_free(l2meta);

    }

    qemu_co_mutex_unlock(&s->lock);

    qemu_iovec_destroy(&hd_qiov);

    qemu_vfree(cluster_data);

    trace_qcow2_writev_done_req(qemu_coroutine_self(), ret);

    return ret;

}