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

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

unix.superglobalmegacorp.com