--- esp.c 2006-04-10 14:51:37.000000000 +0200 +++ esp.c.new 2006-04-10 14:54:44.000000000 +0200 @@ -63,6 +63,8 @@ ESPDMAFunc *dma_cb; int64_t offset, len; int target; + int blocksize; + int ti_bufstart; }; #define STAT_DO 0x00 @@ -229,12 +231,12 @@ target_phys_addr_t phys_addr, int transfer_size1) { + int len = transfer_size1/s->blocksize; DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n", s->offset, s->len, s->ti_size, transfer_size1); - bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len); - s->offset = 0; - s->len = 0; - s->target = 0; + + bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_bufstart, len); + s->offset+=len; return 0; } @@ -265,6 +267,7 @@ s->ti_size = 0; s->ti_rptr = 0; s->ti_wptr = 0; + s->ti_bufstart = 0; if (target >= 4 || !s->bd[target]) { // No such drive s->rregs[4] = STAT_IN; @@ -293,6 +296,7 @@ s->ti_buf[3] = 2; s->ti_buf[4] = 32; s->ti_dir = 1; + s->ti_bufstart = 0; s->ti_size = 36; break; case 0x1a: @@ -314,6 +318,7 @@ s->ti_buf[6] = 2; // sector size 512 s->ti_buf[7] = 0; s->ti_dir = 1; + s->ti_bufstart = 0; s->ti_size = 8; break; case 0x28: @@ -336,6 +341,7 @@ bdrv_read(s->bd[target], offset, s->ti_buf, len); // XXX error handling s->ti_dir = 1; + s->ti_bufstart = 0; break; } case 0x2a: @@ -346,10 +352,12 @@ offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4; len = ((buf[8] << 8) | buf[9]) * 4; s->ti_size = len * 2048; + s->blocksize=2048; } else { offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]; len = (buf[8] << 8) | buf[9]; s->ti_size = len * 512; + s->blocksize=512; } DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len); if (s->ti_size > TI_BUFSZ) { @@ -359,6 +367,7 @@ s->offset = offset; s->len = len; s->target = target; + s->ti_bufstart = 0; // XXX error handling s->ti_dir = 0; break; @@ -400,6 +409,7 @@ break; } s->ti_dir = 1; + s->ti_bufstart = 0; break; } default: @@ -415,10 +425,9 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr; - dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer status len %d\n", dmalen); + DPRINTF("Transfer status len %d\n", len); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r'); @@ -428,10 +437,10 @@ s->rregs[6] = SEQ_CD; } else { memcpy(s->ti_buf, buf, len); - s->ti_size = dmalen; + s->ti_size = len; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = len; } s->espdmaregs[0] |= DMA_INTR; pic_set_irq(s->irq, 1); @@ -442,34 +451,58 @@ static void handle_ti(ESPState *s) { - uint32_t dmaptr, dmalen; + uint32_t dmaptr, dmalen, minlen, len, from, to; unsigned int i; dmalen = s->wregs[0] | (s->wregs[1] << 8); - DPRINTF("Transfer Information len %d\n", dmalen); + if (dmalen==0) { + dmalen=0x10000; + } + + minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; + DPRINTF("Transfer Information len %d\n", minlen); if (s->dma) { dmaptr = iommu_translate(s->espdmaregs[1]); - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr); - for (i = 0; i < s->ti_size; i++) { + DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_bufstart, s->ti_dir); + from=s->espdmaregs[1]; + to=from+minlen; + for (i = 0; i < minlen; i+=len, from+=len) { dmaptr = iommu_translate(s->espdmaregs[1] + i); + if ((from&TARGET_PAGE_MASK)!=(to&TARGET_PAGE_MASK)) { + len=TARGET_PAGE_SIZE-(from&~TARGET_PAGE_MASK); + } else { + len=to-from; + } + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); if (s->ti_dir) - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1); + cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_bufstart+i], len); else - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1); + cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_bufstart+i], len); } if (s->dma_cb) { - s->dma_cb(s, s->espdmaregs[1], dmalen); + s->dma_cb(s, s->espdmaregs[1], minlen); + } + if (minlenti_size) { + s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir?STAT_DO:STAT_DI); + s->ti_size-=minlen; + s->ti_bufstart+=minlen; + } else { + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; s->dma_cb = NULL; + s->offset = 0; + s->len = 0; + s->target = 0; + s->ti_bufstart = 0; } - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; - s->rregs[5] = INTR_BS; + s->rregs[5] = INTR_BS; s->rregs[6] = 0; + s->rregs[7] = 0; s->espdmaregs[0] |= DMA_INTR; } else { - s->ti_size = dmalen; + s->ti_size = minlen; s->ti_rptr = 0; s->ti_wptr = 0; - s->rregs[7] = dmalen; + s->rregs[7] = minlen; } pic_set_irq(s->irq, 1); } @@ -485,8 +518,10 @@ s->ti_rptr = 0; s->ti_wptr = 0; s->ti_dir = 0; + s->ti_bufstart = 0; s->dma = 0; s->dma_cb = NULL; + s->blocksize = 0; } static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)