Annotation of qemu/hw/esp.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * QEMU ESP emulation
                      3:  * 
                      4:  * Copyright (c) 2005 Fabrice Bellard
                      5:  * 
                      6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                      7:  * of this software and associated documentation files (the "Software"), to deal
                      8:  * in the Software without restriction, including without limitation the rights
                      9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     10:  * copies of the Software, and to permit persons to whom the Software is
                     11:  * furnished to do so, subject to the following conditions:
                     12:  *
                     13:  * The above copyright notice and this permission notice shall be included in
                     14:  * all copies or substantial portions of the Software.
                     15:  *
                     16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
                     19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     22:  * THE SOFTWARE.
                     23:  */
                     24: #include "vl.h"
                     25: 
                     26: /* debug ESP card */
                     27: //#define DEBUG_ESP
                     28: 
                     29: #ifdef DEBUG_ESP
                     30: #define DPRINTF(fmt, args...) \
                     31: do { printf("ESP: " fmt , ##args); } while (0)
1.1.1.2 ! root       32: #define pic_set_irq(irq, level) \
        !            33: do { printf("ESP: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
1.1       root       34: #else
                     35: #define DPRINTF(fmt, args...)
                     36: #endif
                     37: 
                     38: #define ESPDMA_REGS 4
                     39: #define ESPDMA_MAXADDR (ESPDMA_REGS * 4 - 1)
                     40: #define ESP_MAXREG 0x3f
1.1.1.2 ! root       41: #define TI_BUFSZ 65536
        !            42: #define DMA_VER 0xa0000000
        !            43: #define DMA_INTR 1
        !            44: #define DMA_INTREN 0x10
        !            45: #define DMA_LOADED 0x04000000
1.1       root       46: 
                     47: typedef struct ESPState {
                     48:     BlockDriverState **bd;
                     49:     uint8_t rregs[ESP_MAXREG];
                     50:     uint8_t wregs[ESP_MAXREG];
                     51:     int irq;
                     52:     uint32_t espdmaregs[ESPDMA_REGS];
                     53:     uint32_t ti_size;
1.1.1.2 ! root       54:     uint32_t ti_rptr, ti_wptr;
1.1       root       55:     int ti_dir;
1.1.1.2 ! root       56:     uint8_t ti_buf[TI_BUFSZ];
        !            57:     int dma;
1.1       root       58: } ESPState;
                     59: 
                     60: #define STAT_DO 0x00
                     61: #define STAT_DI 0x01
                     62: #define STAT_CD 0x02
                     63: #define STAT_ST 0x03
                     64: #define STAT_MI 0x06
                     65: #define STAT_MO 0x07
                     66: 
                     67: #define STAT_TC 0x10
                     68: #define STAT_IN 0x80
                     69: 
                     70: #define INTR_FC 0x08
                     71: #define INTR_BS 0x10
                     72: #define INTR_DC 0x20
1.1.1.2 ! root       73: #define INTR_RST 0x80
1.1       root       74: 
                     75: #define SEQ_0 0x0
                     76: #define SEQ_CD 0x4
                     77: 
1.1.1.2 ! root       78: /* XXX: stolen from ide.c, move to common ATAPI/SCSI library */
        !            79: static void lba_to_msf(uint8_t *buf, int lba)
        !            80: {
        !            81:     lba += 150;
        !            82:     buf[0] = (lba / 75) / 60;
        !            83:     buf[1] = (lba / 75) % 60;
        !            84:     buf[2] = lba % 75;
        !            85: }
        !            86: 
        !            87: static inline void cpu_to_ube16(uint8_t *buf, int val)
        !            88: {
        !            89:     buf[0] = val >> 8;
        !            90:     buf[1] = val;
        !            91: }
        !            92: 
        !            93: static inline void cpu_to_ube32(uint8_t *buf, unsigned int val)
        !            94: {
        !            95:     buf[0] = val >> 24;
        !            96:     buf[1] = val >> 16;
        !            97:     buf[2] = val >> 8;
        !            98:     buf[3] = val;
        !            99: }
        !           100: 
        !           101: /* same toc as bochs. Return -1 if error or the toc length */
        !           102: /* XXX: check this */
        !           103: static int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track)
        !           104: {
        !           105:     uint8_t *q;
        !           106:     int len;
        !           107:     
        !           108:     if (start_track > 1 && start_track != 0xaa)
        !           109:         return -1;
        !           110:     q = buf + 2;
        !           111:     *q++ = 1; /* first session */
        !           112:     *q++ = 1; /* last session */
        !           113:     if (start_track <= 1) {
        !           114:         *q++ = 0; /* reserved */
        !           115:         *q++ = 0x14; /* ADR, control */
        !           116:         *q++ = 1;    /* track number */
        !           117:         *q++ = 0; /* reserved */
        !           118:         if (msf) {
        !           119:             *q++ = 0; /* reserved */
        !           120:             lba_to_msf(q, 0);
        !           121:             q += 3;
        !           122:         } else {
        !           123:             /* sector 0 */
        !           124:             cpu_to_ube32(q, 0);
        !           125:             q += 4;
        !           126:         }
        !           127:     }
        !           128:     /* lead out track */
        !           129:     *q++ = 0; /* reserved */
        !           130:     *q++ = 0x16; /* ADR, control */
        !           131:     *q++ = 0xaa; /* track number */
        !           132:     *q++ = 0; /* reserved */
        !           133:     if (msf) {
        !           134:         *q++ = 0; /* reserved */
        !           135:         lba_to_msf(q, nb_sectors);
        !           136:         q += 3;
        !           137:     } else {
        !           138:         cpu_to_ube32(q, nb_sectors);
        !           139:         q += 4;
        !           140:     }
        !           141:     len = q - buf;
        !           142:     cpu_to_ube16(buf, len - 2);
        !           143:     return len;
        !           144: }
        !           145: 
        !           146: /* mostly same info as PearPc */
        !           147: static int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, 
        !           148:                               int session_num)
        !           149: {
        !           150:     uint8_t *q;
        !           151:     int len;
        !           152:     
        !           153:     q = buf + 2;
        !           154:     *q++ = 1; /* first session */
        !           155:     *q++ = 1; /* last session */
        !           156: 
        !           157:     *q++ = 1; /* session number */
        !           158:     *q++ = 0x14; /* data track */
        !           159:     *q++ = 0; /* track number */
        !           160:     *q++ = 0xa0; /* lead-in */
        !           161:     *q++ = 0; /* min */
        !           162:     *q++ = 0; /* sec */
        !           163:     *q++ = 0; /* frame */
        !           164:     *q++ = 0;
        !           165:     *q++ = 1; /* first track */
        !           166:     *q++ = 0x00; /* disk type */
        !           167:     *q++ = 0x00;
        !           168:     
        !           169:     *q++ = 1; /* session number */
        !           170:     *q++ = 0x14; /* data track */
        !           171:     *q++ = 0; /* track number */
        !           172:     *q++ = 0xa1;
        !           173:     *q++ = 0; /* min */
        !           174:     *q++ = 0; /* sec */
        !           175:     *q++ = 0; /* frame */
        !           176:     *q++ = 0;
        !           177:     *q++ = 1; /* last track */
        !           178:     *q++ = 0x00;
        !           179:     *q++ = 0x00;
        !           180:     
        !           181:     *q++ = 1; /* session number */
        !           182:     *q++ = 0x14; /* data track */
        !           183:     *q++ = 0; /* track number */
        !           184:     *q++ = 0xa2; /* lead-out */
        !           185:     *q++ = 0; /* min */
        !           186:     *q++ = 0; /* sec */
        !           187:     *q++ = 0; /* frame */
        !           188:     if (msf) {
        !           189:         *q++ = 0; /* reserved */
        !           190:         lba_to_msf(q, nb_sectors);
        !           191:         q += 3;
        !           192:     } else {
        !           193:         cpu_to_ube32(q, nb_sectors);
        !           194:         q += 4;
        !           195:     }
        !           196: 
        !           197:     *q++ = 1; /* session number */
        !           198:     *q++ = 0x14; /* ADR, control */
        !           199:     *q++ = 0;    /* track number */
        !           200:     *q++ = 1;    /* point */
        !           201:     *q++ = 0; /* min */
        !           202:     *q++ = 0; /* sec */
        !           203:     *q++ = 0; /* frame */
        !           204:     if (msf) {
        !           205:         *q++ = 0; 
        !           206:         lba_to_msf(q, 0);
        !           207:         q += 3;
        !           208:     } else {
        !           209:         *q++ = 0; 
        !           210:         *q++ = 0; 
        !           211:         *q++ = 0; 
        !           212:         *q++ = 0; 
        !           213:     }
        !           214: 
        !           215:     len = q - buf;
        !           216:     cpu_to_ube16(buf, len - 2);
        !           217:     return len;
        !           218: }
        !           219: 
1.1       root      220: static void handle_satn(ESPState *s)
                    221: {
                    222:     uint8_t buf[32];
                    223:     uint32_t dmaptr, dmalen;
                    224:     unsigned int i;
                    225:     int64_t nb_sectors;
                    226:     int target;
                    227: 
                    228:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
1.1.1.2 ! root      229:     target = s->wregs[4] & 7;
        !           230:     DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
        !           231:     if (s->dma) {
        !           232:        dmaptr = iommu_translate(s->espdmaregs[1]);
        !           233:        DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
        !           234:        cpu_physical_memory_read(dmaptr, buf, dmalen);
        !           235:     } else {
        !           236:        buf[0] = 0;
        !           237:        memcpy(&buf[1], s->ti_buf, dmalen);
        !           238:        dmalen++;
        !           239:     }
1.1       root      240:     for (i = 0; i < dmalen; i++) {
                    241:        DPRINTF("Command %2.2x\n", buf[i]);
                    242:     }
                    243:     s->ti_dir = 0;
                    244:     s->ti_size = 0;
1.1.1.2 ! root      245:     s->ti_rptr = 0;
        !           246:     s->ti_wptr = 0;
1.1       root      247: 
1.1.1.2 ! root      248:     if (target >= 4 || !s->bd[target]) { // No such drive
1.1       root      249:        s->rregs[4] = STAT_IN;
                    250:        s->rregs[5] = INTR_DC;
                    251:        s->rregs[6] = SEQ_0;
1.1.1.2 ! root      252:        s->espdmaregs[0] |= DMA_INTR;
1.1       root      253:        pic_set_irq(s->irq, 1);
                    254:        return;
                    255:     }
                    256:     switch (buf[1]) {
                    257:     case 0x0:
                    258:        DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
                    259:        break;
                    260:     case 0x12:
                    261:        DPRINTF("Inquiry (len %d)\n", buf[5]);
                    262:        memset(s->ti_buf, 0, 36);
                    263:        if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
                    264:            s->ti_buf[0] = 5;
                    265:            memcpy(&s->ti_buf[16], "QEMU CDROM     ", 16);
                    266:        } else {
                    267:            s->ti_buf[0] = 0;
                    268:            memcpy(&s->ti_buf[16], "QEMU HARDDISK  ", 16);
                    269:        }
                    270:        memcpy(&s->ti_buf[8], "QEMU   ", 8);
                    271:        s->ti_buf[2] = 1;
                    272:        s->ti_buf[3] = 2;
1.1.1.2 ! root      273:        s->ti_buf[4] = 32;
1.1       root      274:        s->ti_dir = 1;
                    275:        s->ti_size = 36;
                    276:        break;
                    277:     case 0x1a:
                    278:        DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
                    279:        break;
                    280:     case 0x25:
                    281:        DPRINTF("Read Capacity (len %d)\n", buf[5]);
                    282:        memset(s->ti_buf, 0, 8);
                    283:        bdrv_get_geometry(s->bd[target], &nb_sectors);
                    284:        s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
                    285:        s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
                    286:        s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
                    287:        s->ti_buf[3] = nb_sectors & 0xff;
                    288:        s->ti_buf[4] = 0;
                    289:        s->ti_buf[5] = 0;
1.1.1.2 ! root      290:        if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
        !           291:            s->ti_buf[6] = 8; // sector size 2048
        !           292:        else
        !           293:            s->ti_buf[6] = 2; // sector size 512
1.1       root      294:        s->ti_buf[7] = 0;
                    295:        s->ti_dir = 1;
                    296:        s->ti_size = 8;
                    297:        break;
                    298:     case 0x28:
                    299:        {
                    300:            int64_t offset, len;
                    301: 
1.1.1.2 ! root      302:            if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
        !           303:                offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
        !           304:                len = ((buf[8] << 8) | buf[9]) * 4;
        !           305:                s->ti_size = len * 2048;
        !           306:            } else {
        !           307:                offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
        !           308:                len = (buf[8] << 8) | buf[9];
        !           309:                s->ti_size = len * 512;
        !           310:            }
1.1       root      311:            DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
                    312:            bdrv_read(s->bd[target], offset, s->ti_buf, len);
1.1.1.2 ! root      313:            // XXX error handling
1.1       root      314:            s->ti_dir = 1;
                    315:            break;
                    316:        }
                    317:     case 0x2a:
                    318:        {
                    319:            int64_t offset, len;
                    320: 
1.1.1.2 ! root      321:            if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
        !           322:                offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
        !           323:                len = ((buf[8] << 8) | buf[9]) * 4;
        !           324:                s->ti_size = len * 2048;
        !           325:            } else {
        !           326:                offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
        !           327:                len = (buf[8] << 8) | buf[9];
        !           328:                s->ti_size = len * 512;
        !           329:            }
1.1       root      330:            DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
                    331:            bdrv_write(s->bd[target], offset, s->ti_buf, len);
1.1.1.2 ! root      332:            // XXX error handling
1.1       root      333:            s->ti_dir = 0;
                    334:            break;
                    335:        }
1.1.1.2 ! root      336:     case 0x43:
        !           337:         {
        !           338:             int start_track, format, msf, len;
        !           339: 
        !           340:             msf = buf[2] & 2;
        !           341:             format = buf[3] & 0xf;
        !           342:             start_track = buf[7];
        !           343:             bdrv_get_geometry(s->bd[target], &nb_sectors);
        !           344:             DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
        !           345:             switch(format) {
        !           346:             case 0:
        !           347:                 len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
        !           348:                 if (len < 0)
        !           349:                     goto error_cmd;
        !           350:                 s->ti_size = len;
        !           351:                 break;
        !           352:             case 1:
        !           353:                 /* multi session : only a single session defined */
        !           354:                 memset(buf, 0, 12);
        !           355:                 buf[1] = 0x0a;
        !           356:                 buf[2] = 0x01;
        !           357:                 buf[3] = 0x01;
        !           358:                 s->ti_size = 12;
        !           359:                 break;
        !           360:             case 2:
        !           361:                 len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
        !           362:                 if (len < 0)
        !           363:                     goto error_cmd;
        !           364:                 s->ti_size = len;
        !           365:                 break;
        !           366:             default:
        !           367:             error_cmd:
        !           368:                 DPRINTF("Read TOC error\n");
        !           369:                 // XXX error handling
        !           370:                 break;
        !           371:             }
        !           372:            s->ti_dir = 1;
        !           373:             break;
        !           374:         }
1.1       root      375:     default:
1.1.1.2 ! root      376:        DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
1.1       root      377:        break;
                    378:     }
                    379:     s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
                    380:     s->rregs[5] = INTR_BS | INTR_FC;
                    381:     s->rregs[6] = SEQ_CD;
1.1.1.2 ! root      382:     s->espdmaregs[0] |= DMA_INTR;
1.1       root      383:     pic_set_irq(s->irq, 1);
                    384: }
                    385: 
                    386: static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
                    387: {
                    388:     uint32_t dmaptr, dmalen;
                    389: 
                    390:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
1.1.1.2 ! root      391:     DPRINTF("Transfer status len %d\n", dmalen);
        !           392:     if (s->dma) {
        !           393:        dmaptr = iommu_translate(s->espdmaregs[1]);
        !           394:        DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
        !           395:        cpu_physical_memory_write(dmaptr, buf, len);
        !           396:        s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
        !           397:        s->rregs[5] = INTR_BS | INTR_FC;
        !           398:        s->rregs[6] = SEQ_CD;
        !           399:     } else {
        !           400:        memcpy(s->ti_buf, buf, len);
        !           401:        s->ti_size = dmalen;
        !           402:        s->ti_rptr = 0;
        !           403:        s->ti_wptr = 0;
        !           404:        s->rregs[7] = dmalen;
        !           405:     }
        !           406:     s->espdmaregs[0] |= DMA_INTR;
1.1       root      407:     pic_set_irq(s->irq, 1);
                    408: 
                    409: }
1.1.1.2 ! root      410: 
1.1       root      411: static const uint8_t okbuf[] = {0, 0};
                    412: 
                    413: static void handle_ti(ESPState *s)
                    414: {
                    415:     uint32_t dmaptr, dmalen;
                    416:     unsigned int i;
                    417: 
                    418:     dmalen = s->wregs[0] | (s->wregs[1] << 8);
1.1.1.2 ! root      419:     DPRINTF("Transfer Information len %d\n", dmalen);
        !           420:     if (s->dma) {
        !           421:        dmaptr = iommu_translate(s->espdmaregs[1]);
        !           422:        DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
        !           423:        for (i = 0; i < s->ti_size; i++) {
        !           424:            dmaptr = iommu_translate(s->espdmaregs[1] + i);
        !           425:            if (s->ti_dir)
        !           426:                cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
        !           427:            else
        !           428:                cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
        !           429:        }
        !           430:        s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
        !           431:        s->rregs[5] = INTR_BS;
        !           432:        s->rregs[6] = 0;
        !           433:        s->espdmaregs[0] |= DMA_INTR;
        !           434:     } else {
        !           435:        s->ti_size = dmalen;
        !           436:        s->ti_rptr = 0;
        !           437:        s->ti_wptr = 0;
        !           438:        s->rregs[7] = dmalen;
        !           439:     }  
1.1       root      440:     pic_set_irq(s->irq, 1);
                    441: }
                    442: 
                    443: static void esp_reset(void *opaque)
                    444: {
                    445:     ESPState *s = opaque;
                    446:     memset(s->rregs, 0, ESP_MAXREG);
                    447:     s->rregs[0x0e] = 0x4; // Indicate fas100a
                    448:     memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
                    449: }
                    450: 
                    451: static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
                    452: {
                    453:     ESPState *s = opaque;
                    454:     uint32_t saddr;
                    455: 
                    456:     saddr = (addr & ESP_MAXREG) >> 2;
1.1.1.2 ! root      457:     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
1.1       root      458:     switch (saddr) {
1.1.1.2 ! root      459:     case 2:
        !           460:        // FIFO
        !           461:        if (s->ti_size > 0) {
        !           462:            s->ti_size--;
        !           463:            s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
        !           464:            pic_set_irq(s->irq, 1);
        !           465:        }
        !           466:        if (s->ti_size == 0) {
        !           467:             s->ti_rptr = 0;
        !           468:             s->ti_wptr = 0;
        !           469:         }
        !           470:        break;
        !           471:     case 5:
        !           472:         // interrupt
        !           473:         // Clear status bits except TC
        !           474:         s->rregs[4] &= STAT_TC;
        !           475:         pic_set_irq(s->irq, 0);
        !           476:        s->espdmaregs[0] &= ~DMA_INTR;
        !           477:         break;
1.1       root      478:     default:
                    479:        break;
                    480:     }
                    481:     return s->rregs[saddr];
                    482: }
                    483: 
                    484: static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
                    485: {
                    486:     ESPState *s = opaque;
                    487:     uint32_t saddr;
                    488: 
                    489:     saddr = (addr & ESP_MAXREG) >> 2;
                    490:     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
                    491:     switch (saddr) {
1.1.1.2 ! root      492:     case 0:
        !           493:     case 1:
        !           494:         s->rregs[saddr] = val;
        !           495:         break;
        !           496:     case 2:
        !           497:        // FIFO
        !           498:        s->ti_size++;
        !           499:        s->ti_buf[s->ti_wptr++] = val & 0xff;
        !           500:        break;
1.1       root      501:     case 3:
1.1.1.2 ! root      502:         s->rregs[saddr] = val;
1.1       root      503:        // Command
1.1.1.2 ! root      504:        if (val & 0x80) {
        !           505:            s->dma = 1;
        !           506:        } else {
        !           507:            s->dma = 0;
        !           508:        }
1.1       root      509:        switch(val & 0x7f) {
                    510:        case 0:
                    511:            DPRINTF("NOP (%2.2x)\n", val);
                    512:            break;
                    513:        case 1:
                    514:            DPRINTF("Flush FIFO (%2.2x)\n", val);
1.1.1.2 ! root      515:             //s->ti_size = 0;
1.1       root      516:            s->rregs[5] = INTR_FC;
1.1.1.2 ! root      517:            s->rregs[6] = 0;
1.1       root      518:            break;
                    519:        case 2:
                    520:            DPRINTF("Chip reset (%2.2x)\n", val);
                    521:            esp_reset(s);
                    522:            break;
                    523:        case 3:
                    524:            DPRINTF("Bus reset (%2.2x)\n", val);
1.1.1.2 ! root      525:            s->rregs[5] = INTR_RST;
        !           526:             if (!(s->wregs[8] & 0x40)) {
        !           527:                 s->espdmaregs[0] |= DMA_INTR;
        !           528:                 pic_set_irq(s->irq, 1);
        !           529:             }
1.1       root      530:            break;
                    531:        case 0x10:
                    532:            handle_ti(s);
                    533:            break;
                    534:        case 0x11:
                    535:            DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
                    536:            dma_write(s, okbuf, 2);
                    537:            break;
                    538:        case 0x12:
                    539:            DPRINTF("Message Accepted (%2.2x)\n", val);
                    540:            dma_write(s, okbuf, 2);
                    541:            s->rregs[5] = INTR_DC;
                    542:            s->rregs[6] = 0;
                    543:            break;
                    544:        case 0x1a:
                    545:            DPRINTF("Set ATN (%2.2x)\n", val);
                    546:            break;
                    547:        case 0x42:
                    548:            handle_satn(s);
                    549:            break;
                    550:        case 0x43:
                    551:            DPRINTF("Set ATN & stop (%2.2x)\n", val);
                    552:            handle_satn(s);
                    553:            break;
                    554:        default:
1.1.1.2 ! root      555:            DPRINTF("Unhandled ESP command (%2.2x)\n", val);
1.1       root      556:            break;
                    557:        }
                    558:        break;
                    559:     case 4 ... 7:
                    560:        break;
1.1.1.2 ! root      561:     case 8:
        !           562:         s->rregs[saddr] = val;
        !           563:         break;
        !           564:     case 9 ... 10:
        !           565:         break;
        !           566:     case 11:
        !           567:         s->rregs[saddr] = val & 0x15;
        !           568:         break;
        !           569:     case 12 ... 15:
        !           570:         s->rregs[saddr] = val;
        !           571:         break;
1.1       root      572:     default:
                    573:        break;
                    574:     }
                    575:     s->wregs[saddr] = val;
                    576: }
                    577: 
                    578: static CPUReadMemoryFunc *esp_mem_read[3] = {
                    579:     esp_mem_readb,
                    580:     esp_mem_readb,
                    581:     esp_mem_readb,
                    582: };
                    583: 
                    584: static CPUWriteMemoryFunc *esp_mem_write[3] = {
                    585:     esp_mem_writeb,
                    586:     esp_mem_writeb,
                    587:     esp_mem_writeb,
                    588: };
                    589: 
                    590: static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
                    591: {
                    592:     ESPState *s = opaque;
                    593:     uint32_t saddr;
                    594: 
                    595:     saddr = (addr & ESPDMA_MAXADDR) >> 2;
1.1.1.2 ! root      596:     DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
        !           597: 
1.1       root      598:     return s->espdmaregs[saddr];
                    599: }
                    600: 
                    601: static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
                    602: {
                    603:     ESPState *s = opaque;
                    604:     uint32_t saddr;
                    605: 
                    606:     saddr = (addr & ESPDMA_MAXADDR) >> 2;
1.1.1.2 ! root      607:     DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
1.1       root      608:     switch (saddr) {
                    609:     case 0:
1.1.1.2 ! root      610:        if (!(val & DMA_INTREN))
1.1       root      611:            pic_set_irq(s->irq, 0);
1.1.1.2 ! root      612:        if (val & 0x80) {
        !           613:             esp_reset(s);
        !           614:         } else if (val & 0x40) {
        !           615:             val &= ~0x40;
        !           616:         } else if (val == 0)
        !           617:             val = 0x40;
        !           618:         val &= 0x0fffffff;
        !           619:         val |= DMA_VER;
        !           620:        break;
        !           621:     case 1:
        !           622:         s->espdmaregs[0] = DMA_LOADED;
        !           623:         break;
1.1       root      624:     default:
                    625:        break;
                    626:     }
                    627:     s->espdmaregs[saddr] = val;
                    628: }
                    629: 
                    630: static CPUReadMemoryFunc *espdma_mem_read[3] = {
                    631:     espdma_mem_readl,
                    632:     espdma_mem_readl,
                    633:     espdma_mem_readl,
                    634: };
                    635: 
                    636: static CPUWriteMemoryFunc *espdma_mem_write[3] = {
                    637:     espdma_mem_writel,
                    638:     espdma_mem_writel,
                    639:     espdma_mem_writel,
                    640: };
                    641: 
                    642: static void esp_save(QEMUFile *f, void *opaque)
                    643: {
                    644:     ESPState *s = opaque;
                    645:     unsigned int i;
                    646: 
                    647:     qemu_put_buffer(f, s->rregs, ESP_MAXREG);
                    648:     qemu_put_buffer(f, s->wregs, ESP_MAXREG);
                    649:     qemu_put_be32s(f, &s->irq);
                    650:     for (i = 0; i < ESPDMA_REGS; i++)
                    651:        qemu_put_be32s(f, &s->espdmaregs[i]);
1.1.1.2 ! root      652:     qemu_put_be32s(f, &s->ti_size);
        !           653:     qemu_put_be32s(f, &s->ti_rptr);
        !           654:     qemu_put_be32s(f, &s->ti_wptr);
        !           655:     qemu_put_be32s(f, &s->ti_dir);
        !           656:     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
        !           657:     qemu_put_be32s(f, &s->dma);
1.1       root      658: }
                    659: 
                    660: static int esp_load(QEMUFile *f, void *opaque, int version_id)
                    661: {
                    662:     ESPState *s = opaque;
                    663:     unsigned int i;
                    664:     
                    665:     if (version_id != 1)
                    666:         return -EINVAL;
                    667: 
                    668:     qemu_get_buffer(f, s->rregs, ESP_MAXREG);
                    669:     qemu_get_buffer(f, s->wregs, ESP_MAXREG);
                    670:     qemu_get_be32s(f, &s->irq);
                    671:     for (i = 0; i < ESPDMA_REGS; i++)
                    672:        qemu_get_be32s(f, &s->espdmaregs[i]);
1.1.1.2 ! root      673:     qemu_get_be32s(f, &s->ti_size);
        !           674:     qemu_get_be32s(f, &s->ti_rptr);
        !           675:     qemu_get_be32s(f, &s->ti_wptr);
        !           676:     qemu_get_be32s(f, &s->ti_dir);
        !           677:     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
        !           678:     qemu_get_be32s(f, &s->dma);
1.1       root      679: 
                    680:     return 0;
                    681: }
                    682: 
                    683: void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
                    684: {
                    685:     ESPState *s;
                    686:     int esp_io_memory, espdma_io_memory;
                    687: 
                    688:     s = qemu_mallocz(sizeof(ESPState));
                    689:     if (!s)
                    690:         return;
                    691: 
                    692:     s->bd = bd;
                    693:     s->irq = irq;
                    694: 
                    695:     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
                    696:     cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
                    697: 
                    698:     espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
                    699:     cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
                    700: 
                    701:     esp_reset(s);
                    702: 
                    703:     register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
                    704:     qemu_register_reset(esp_reset, s);
                    705: }
                    706: 

unix.superglobalmegacorp.com