ESP DMA fix.
[qemu] / hw / esp.c
1 /*
2  * QEMU ESP emulation
3  * 
4  * Copyright (c) 2005-2006 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)
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)
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
41 #define TI_BUFSZ 1024*1024 // XXX
42 #define DMA_VER 0xa0000000
43 #define DMA_INTR 1
44 #define DMA_INTREN 0x10
45 #define DMA_LOADED 0x04000000
46 typedef struct ESPState ESPState;
47
48 typedef int ESPDMAFunc(ESPState *s, 
49                        target_phys_addr_t phys_addr, 
50                        int transfer_size1);
51
52 struct ESPState {
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;
59     uint32_t ti_rptr, ti_wptr;
60     int ti_dir;
61     uint8_t ti_buf[TI_BUFSZ];
62     int dma;
63     ESPDMAFunc *dma_cb;
64     int64_t offset, len;
65     int target;
66 };
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
81 #define INTR_RST 0x80
82
83 #define SEQ_0 0x0
84 #define SEQ_CD 0x4
85
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
228 static int esp_write_dma_cb(ESPState *s, 
229                             target_phys_addr_t phys_addr, 
230                             int transfer_size1)
231 {
232     int len;
233     if (bdrv_get_type_hint(s->bd[s->target]) == BDRV_TYPE_CDROM) {
234         len = transfer_size1/2048;
235     } else {
236         len = transfer_size1/512;
237     }
238     DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
239             s->offset, s->len, s->ti_size, transfer_size1);
240
241     bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_rptr, len);
242     s->offset+=len;
243     return 0;
244 }
245
246 static void handle_satn(ESPState *s)
247 {
248     uint8_t buf[32];
249     uint32_t dmaptr, dmalen;
250     unsigned int i;
251     int64_t nb_sectors;
252     int target;
253
254     dmalen = s->wregs[0] | (s->wregs[1] << 8);
255     target = s->wregs[4] & 7;
256     DPRINTF("Select with ATN len %d target %d\n", dmalen, target);
257     if (s->dma) {
258         dmaptr = iommu_translate(s->espdmaregs[1]);
259         DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
260         cpu_physical_memory_read(dmaptr, buf, dmalen);
261     } else {
262         buf[0] = 0;
263         memcpy(&buf[1], s->ti_buf, dmalen);
264         dmalen++;
265     }
266     for (i = 0; i < dmalen; i++) {
267         DPRINTF("Command %2.2x\n", buf[i]);
268     }
269     s->ti_dir = 0;
270     s->ti_size = 0;
271     s->ti_rptr = 0;
272     s->ti_wptr = 0;
273
274     if (target >= 4 || !s->bd[target]) { // No such drive
275         s->rregs[4] = STAT_IN;
276         s->rregs[5] = INTR_DC;
277         s->rregs[6] = SEQ_0;
278         s->espdmaregs[0] |= DMA_INTR;
279         pic_set_irq(s->irq, 1);
280         return;
281     }
282     switch (buf[1]) {
283     case 0x0:
284         DPRINTF("Test Unit Ready (len %d)\n", buf[5]);
285         break;
286     case 0x12:
287         DPRINTF("Inquiry (len %d)\n", buf[5]);
288         memset(s->ti_buf, 0, 36);
289         if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
290             s->ti_buf[0] = 5;
291             memcpy(&s->ti_buf[16], "QEMU CDROM     ", 16);
292         } else {
293             s->ti_buf[0] = 0;
294             memcpy(&s->ti_buf[16], "QEMU HARDDISK  ", 16);
295         }
296         memcpy(&s->ti_buf[8], "QEMU   ", 8);
297         s->ti_buf[2] = 1;
298         s->ti_buf[3] = 2;
299         s->ti_buf[4] = 32;
300         s->ti_dir = 1;
301         s->ti_size = 36;
302         break;
303     case 0x1a:
304         DPRINTF("Mode Sense(6) (page %d, len %d)\n", buf[3], buf[5]);
305         break;
306     case 0x25:
307         DPRINTF("Read Capacity (len %d)\n", buf[5]);
308         memset(s->ti_buf, 0, 8);
309         bdrv_get_geometry(s->bd[target], &nb_sectors);
310         s->ti_buf[0] = (nb_sectors >> 24) & 0xff;
311         s->ti_buf[1] = (nb_sectors >> 16) & 0xff;
312         s->ti_buf[2] = (nb_sectors >> 8) & 0xff;
313         s->ti_buf[3] = nb_sectors & 0xff;
314         s->ti_buf[4] = 0;
315         s->ti_buf[5] = 0;
316         if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM)
317             s->ti_buf[6] = 8; // sector size 2048
318         else
319             s->ti_buf[6] = 2; // sector size 512
320         s->ti_buf[7] = 0;
321         s->ti_dir = 1;
322         s->ti_size = 8;
323         break;
324     case 0x28:
325         {
326             int64_t offset, len;
327
328             if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
329                 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
330                 len = ((buf[8] << 8) | buf[9]) * 4;
331                 s->ti_size = len * 2048;
332             } else {
333                 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
334                 len = (buf[8] << 8) | buf[9];
335                 s->ti_size = len * 512;
336             }
337             DPRINTF("Read (10) (offset %lld len %lld)\n", offset, len);
338             if (s->ti_size > TI_BUFSZ) {
339                 DPRINTF("size too large %d\n", s->ti_size);
340             }
341             bdrv_read(s->bd[target], offset, s->ti_buf, len);
342             // XXX error handling
343             s->ti_dir = 1;
344             s->ti_rptr = 0;
345             break;
346         }
347     case 0x2a:
348         {
349             int64_t offset, len;
350
351             if (bdrv_get_type_hint(s->bd[target]) == BDRV_TYPE_CDROM) {
352                 offset = ((buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6]) * 4;
353                 len = ((buf[8] << 8) | buf[9]) * 4;
354                 s->ti_size = len * 2048;
355             } else {
356                 offset = (buf[3] << 24) | (buf[4] << 16) | (buf[5] << 8) | buf[6];
357                 len = (buf[8] << 8) | buf[9];
358                 s->ti_size = len * 512;
359             }
360             DPRINTF("Write (10) (offset %lld len %lld)\n", offset, len);
361             if (s->ti_size > TI_BUFSZ) {
362                 DPRINTF("size too large %d\n", s->ti_size);
363             }
364             s->dma_cb = esp_write_dma_cb;
365             s->offset = offset;
366             s->len = len;
367             s->target = target;
368             s->ti_rptr = 0;
369             // XXX error handling
370             s->ti_dir = 0;
371             break;
372         }
373     case 0x43:
374         {
375             int start_track, format, msf, len;
376
377             msf = buf[2] & 2;
378             format = buf[3] & 0xf;
379             start_track = buf[7];
380             bdrv_get_geometry(s->bd[target], &nb_sectors);
381             DPRINTF("Read TOC (track %d format %d msf %d)\n", start_track, format, msf >> 1);
382             switch(format) {
383             case 0:
384                 len = cdrom_read_toc(nb_sectors, buf, msf, start_track);
385                 if (len < 0)
386                     goto error_cmd;
387                 s->ti_size = len;
388                 break;
389             case 1:
390                 /* multi session : only a single session defined */
391                 memset(buf, 0, 12);
392                 buf[1] = 0x0a;
393                 buf[2] = 0x01;
394                 buf[3] = 0x01;
395                 s->ti_size = 12;
396                 break;
397             case 2:
398                 len = cdrom_read_toc_raw(nb_sectors, buf, msf, start_track);
399                 if (len < 0)
400                     goto error_cmd;
401                 s->ti_size = len;
402                 break;
403             default:
404             error_cmd:
405                 DPRINTF("Read TOC error\n");
406                 // XXX error handling
407                 break;
408             }
409             s->ti_dir = 1;
410             break;
411         }
412     default:
413         DPRINTF("Unknown SCSI command (%2.2x)\n", buf[1]);
414         break;
415     }
416     s->rregs[4] = STAT_IN | STAT_TC | STAT_DI;
417     s->rregs[5] = INTR_BS | INTR_FC;
418     s->rregs[6] = SEQ_CD;
419     s->espdmaregs[0] |= DMA_INTR;
420     pic_set_irq(s->irq, 1);
421 }
422
423 static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
424 {
425     uint32_t dmaptr;
426
427     DPRINTF("Transfer status len %d\n", len);
428     if (s->dma) {
429         dmaptr = iommu_translate(s->espdmaregs[1]);
430         DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
431         cpu_physical_memory_write(dmaptr, buf, len);
432         s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
433         s->rregs[5] = INTR_BS | INTR_FC;
434         s->rregs[6] = SEQ_CD;
435     } else {
436         memcpy(s->ti_buf, buf, len);
437         s->ti_size = len;
438         s->ti_rptr = 0;
439         s->ti_wptr = 0;
440         s->rregs[7] = len;
441     }
442     s->espdmaregs[0] |= DMA_INTR;
443     pic_set_irq(s->irq, 1);
444
445 }
446
447 static const uint8_t okbuf[] = {0, 0};
448
449 static void handle_ti(ESPState *s)
450 {
451     uint32_t dmaptr, dmalen, minlen, len, from, to;
452     unsigned int i;
453
454     dmalen = s->wregs[0] | (s->wregs[1] << 8);
455     if (dmalen==0) {
456       dmalen=0x10000;
457     }
458
459     minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
460     DPRINTF("Transfer Information len %d\n", minlen);
461     if (s->dma) {
462         dmaptr = iommu_translate(s->espdmaregs[1]);
463         DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_rptr, s->ti_dir);
464         from = s->espdmaregs[1];
465         to = from + minlen;
466         for (i = 0; i < minlen; i += len, from += len) {
467             dmaptr = iommu_translate(s->espdmaregs[1] + i);
468             if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
469                len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
470             } else {
471                len = to - from;
472             }
473             DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
474             if (s->ti_dir)
475                 cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_rptr + i], len);
476             else
477                 cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_rptr + i], len);
478         }
479         if (s->dma_cb) {
480             s->dma_cb(s, s->espdmaregs[1], minlen);
481         }
482         if (minlen < s->ti_size) {
483             s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir ? STAT_DO : STAT_DI);
484             s->ti_size -= minlen;
485             s->ti_rptr += minlen;
486         } else {
487             s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
488             s->dma_cb = NULL;
489             s->offset = 0;
490             s->len = 0;
491             s->target = 0;
492             s->ti_rptr = 0;
493         }
494         s->rregs[5] = INTR_BS;
495         s->rregs[6] = 0;
496         s->rregs[7] = 0;
497         s->espdmaregs[0] |= DMA_INTR;
498     } else {
499         s->ti_size = minlen;
500         s->ti_rptr = 0;
501         s->ti_wptr = 0;
502         s->rregs[7] = minlen;
503     }   
504     pic_set_irq(s->irq, 1);
505 }
506
507 static void esp_reset(void *opaque)
508 {
509     ESPState *s = opaque;
510     memset(s->rregs, 0, ESP_MAXREG);
511     memset(s->wregs, 0, ESP_MAXREG);
512     s->rregs[0x0e] = 0x4; // Indicate fas100a
513     memset(s->espdmaregs, 0, ESPDMA_REGS * 4);
514     s->ti_size = 0;
515     s->ti_rptr = 0;
516     s->ti_wptr = 0;
517     s->ti_dir = 0;
518     s->dma = 0;
519     s->dma_cb = NULL;
520 }
521
522 static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr)
523 {
524     ESPState *s = opaque;
525     uint32_t saddr;
526
527     saddr = (addr & ESP_MAXREG) >> 2;
528     DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]);
529     switch (saddr) {
530     case 2:
531         // FIFO
532         if (s->ti_size > 0) {
533             s->ti_size--;
534             s->rregs[saddr] = s->ti_buf[s->ti_rptr++];
535             pic_set_irq(s->irq, 1);
536         }
537         if (s->ti_size == 0) {
538             s->ti_rptr = 0;
539             s->ti_wptr = 0;
540         }
541         break;
542     case 5:
543         // interrupt
544         // Clear status bits except TC
545         s->rregs[4] &= STAT_TC;
546         pic_set_irq(s->irq, 0);
547         s->espdmaregs[0] &= ~DMA_INTR;
548         break;
549     default:
550         break;
551     }
552     return s->rregs[saddr];
553 }
554
555 static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
556 {
557     ESPState *s = opaque;
558     uint32_t saddr;
559
560     saddr = (addr & ESP_MAXREG) >> 2;
561     DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val);
562     switch (saddr) {
563     case 0:
564     case 1:
565         s->rregs[saddr] = val;
566         break;
567     case 2:
568         // FIFO
569         s->ti_size++;
570         s->ti_buf[s->ti_wptr++] = val & 0xff;
571         break;
572     case 3:
573         s->rregs[saddr] = val;
574         // Command
575         if (val & 0x80) {
576             s->dma = 1;
577         } else {
578             s->dma = 0;
579         }
580         switch(val & 0x7f) {
581         case 0:
582             DPRINTF("NOP (%2.2x)\n", val);
583             break;
584         case 1:
585             DPRINTF("Flush FIFO (%2.2x)\n", val);
586             //s->ti_size = 0;
587             s->rregs[5] = INTR_FC;
588             s->rregs[6] = 0;
589             break;
590         case 2:
591             DPRINTF("Chip reset (%2.2x)\n", val);
592             esp_reset(s);
593             break;
594         case 3:
595             DPRINTF("Bus reset (%2.2x)\n", val);
596             s->rregs[5] = INTR_RST;
597             if (!(s->wregs[8] & 0x40)) {
598                 s->espdmaregs[0] |= DMA_INTR;
599                 pic_set_irq(s->irq, 1);
600             }
601             break;
602         case 0x10:
603             handle_ti(s);
604             break;
605         case 0x11:
606             DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val);
607             dma_write(s, okbuf, 2);
608             break;
609         case 0x12:
610             DPRINTF("Message Accepted (%2.2x)\n", val);
611             dma_write(s, okbuf, 2);
612             s->rregs[5] = INTR_DC;
613             s->rregs[6] = 0;
614             break;
615         case 0x1a:
616             DPRINTF("Set ATN (%2.2x)\n", val);
617             break;
618         case 0x42:
619             handle_satn(s);
620             break;
621         case 0x43:
622             DPRINTF("Set ATN & stop (%2.2x)\n", val);
623             handle_satn(s);
624             break;
625         default:
626             DPRINTF("Unhandled ESP command (%2.2x)\n", val);
627             break;
628         }
629         break;
630     case 4 ... 7:
631         break;
632     case 8:
633         s->rregs[saddr] = val;
634         break;
635     case 9 ... 10:
636         break;
637     case 11:
638         s->rregs[saddr] = val & 0x15;
639         break;
640     case 12 ... 15:
641         s->rregs[saddr] = val;
642         break;
643     default:
644         break;
645     }
646     s->wregs[saddr] = val;
647 }
648
649 static CPUReadMemoryFunc *esp_mem_read[3] = {
650     esp_mem_readb,
651     esp_mem_readb,
652     esp_mem_readb,
653 };
654
655 static CPUWriteMemoryFunc *esp_mem_write[3] = {
656     esp_mem_writeb,
657     esp_mem_writeb,
658     esp_mem_writeb,
659 };
660
661 static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr)
662 {
663     ESPState *s = opaque;
664     uint32_t saddr;
665
666     saddr = (addr & ESPDMA_MAXADDR) >> 2;
667     DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]);
668
669     return s->espdmaregs[saddr];
670 }
671
672 static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
673 {
674     ESPState *s = opaque;
675     uint32_t saddr;
676
677     saddr = (addr & ESPDMA_MAXADDR) >> 2;
678     DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val);
679     switch (saddr) {
680     case 0:
681         if (!(val & DMA_INTREN))
682             pic_set_irq(s->irq, 0);
683         if (val & 0x80) {
684             esp_reset(s);
685         } else if (val & 0x40) {
686             val &= ~0x40;
687         } else if (val == 0)
688             val = 0x40;
689         val &= 0x0fffffff;
690         val |= DMA_VER;
691         break;
692     case 1:
693         s->espdmaregs[0] = DMA_LOADED;
694         break;
695     default:
696         break;
697     }
698     s->espdmaregs[saddr] = val;
699 }
700
701 static CPUReadMemoryFunc *espdma_mem_read[3] = {
702     espdma_mem_readl,
703     espdma_mem_readl,
704     espdma_mem_readl,
705 };
706
707 static CPUWriteMemoryFunc *espdma_mem_write[3] = {
708     espdma_mem_writel,
709     espdma_mem_writel,
710     espdma_mem_writel,
711 };
712
713 static void esp_save(QEMUFile *f, void *opaque)
714 {
715     ESPState *s = opaque;
716     unsigned int i;
717
718     qemu_put_buffer(f, s->rregs, ESP_MAXREG);
719     qemu_put_buffer(f, s->wregs, ESP_MAXREG);
720     qemu_put_be32s(f, &s->irq);
721     for (i = 0; i < ESPDMA_REGS; i++)
722         qemu_put_be32s(f, &s->espdmaregs[i]);
723     qemu_put_be32s(f, &s->ti_size);
724     qemu_put_be32s(f, &s->ti_rptr);
725     qemu_put_be32s(f, &s->ti_wptr);
726     qemu_put_be32s(f, &s->ti_dir);
727     qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
728     qemu_put_be32s(f, &s->dma);
729 }
730
731 static int esp_load(QEMUFile *f, void *opaque, int version_id)
732 {
733     ESPState *s = opaque;
734     unsigned int i;
735     
736     if (version_id != 1)
737         return -EINVAL;
738
739     qemu_get_buffer(f, s->rregs, ESP_MAXREG);
740     qemu_get_buffer(f, s->wregs, ESP_MAXREG);
741     qemu_get_be32s(f, &s->irq);
742     for (i = 0; i < ESPDMA_REGS; i++)
743         qemu_get_be32s(f, &s->espdmaregs[i]);
744     qemu_get_be32s(f, &s->ti_size);
745     qemu_get_be32s(f, &s->ti_rptr);
746     qemu_get_be32s(f, &s->ti_wptr);
747     qemu_get_be32s(f, &s->ti_dir);
748     qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
749     qemu_get_be32s(f, &s->dma);
750
751     return 0;
752 }
753
754 void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr)
755 {
756     ESPState *s;
757     int esp_io_memory, espdma_io_memory;
758
759     s = qemu_mallocz(sizeof(ESPState));
760     if (!s)
761         return;
762
763     s->bd = bd;
764     s->irq = irq;
765
766     esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s);
767     cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory);
768
769     espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s);
770     cpu_register_physical_memory(espdaddr, 16, espdma_io_memory);
771
772     esp_reset(s);
773
774     register_savevm("esp", espaddr, 1, esp_save, esp_load, s);
775     qemu_register_reset(esp_reset, s);
776 }
777