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