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