]>
Commit | Line | Data |
---|---|---|
6f7e9aec FB |
1 | /* |
2 | * QEMU ESP emulation | |
3 | * | |
4e9aec74 | 4 | * Copyright (c) 2005-2006 Fabrice Bellard |
6f7e9aec FB |
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 */ | |
2f275b8f | 27 | //#define DEBUG_ESP |
6f7e9aec FB |
28 | |
29 | #ifdef DEBUG_ESP | |
30 | #define DPRINTF(fmt, args...) \ | |
31 | do { printf("ESP: " fmt , ##args); } while (0) | |
9e61bde5 FB |
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) | |
6f7e9aec FB |
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 | |
2e5d83bb | 41 | #define TI_BUFSZ 32 |
4f6200f0 | 42 | #define DMA_VER 0xa0000000 |
9e61bde5 FB |
43 | #define DMA_INTR 1 |
44 | #define DMA_INTREN 0x10 | |
2e5d83bb | 45 | #define DMA_WRITE_MEM 0x100 |
4f6200f0 | 46 | #define DMA_LOADED 0x04000000 |
4e9aec74 | 47 | typedef struct ESPState ESPState; |
6f7e9aec | 48 | |
4e9aec74 | 49 | struct ESPState { |
6f7e9aec | 50 | BlockDriverState **bd; |
2f275b8f FB |
51 | uint8_t rregs[ESP_MAXREG]; |
52 | uint8_t wregs[ESP_MAXREG]; | |
6f7e9aec FB |
53 | int irq; |
54 | uint32_t espdmaregs[ESPDMA_REGS]; | |
2f275b8f | 55 | uint32_t ti_size; |
4f6200f0 | 56 | uint32_t ti_rptr, ti_wptr; |
4f6200f0 FB |
57 | uint8_t ti_buf[TI_BUFSZ]; |
58 | int dma; | |
2e5d83bb PB |
59 | SCSIDevice *scsi_dev[MAX_DISKS]; |
60 | SCSIDevice *current_dev; | |
4e9aec74 | 61 | }; |
6f7e9aec | 62 | |
2f275b8f FB |
63 | #define STAT_DO 0x00 |
64 | #define STAT_DI 0x01 | |
65 | #define STAT_CD 0x02 | |
66 | #define STAT_ST 0x03 | |
67 | #define STAT_MI 0x06 | |
68 | #define STAT_MO 0x07 | |
69 | ||
70 | #define STAT_TC 0x10 | |
71 | #define STAT_IN 0x80 | |
72 | ||
73 | #define INTR_FC 0x08 | |
74 | #define INTR_BS 0x10 | |
75 | #define INTR_DC 0x20 | |
9e61bde5 | 76 | #define INTR_RST 0x80 |
2f275b8f FB |
77 | |
78 | #define SEQ_0 0x0 | |
79 | #define SEQ_CD 0x4 | |
80 | ||
81 | static void handle_satn(ESPState *s) | |
82 | { | |
83 | uint8_t buf[32]; | |
84 | uint32_t dmaptr, dmalen; | |
2f275b8f | 85 | int target; |
2e5d83bb | 86 | int32_t datalen; |
2f275b8f | 87 | |
2f275b8f | 88 | dmalen = s->wregs[0] | (s->wregs[1] << 8); |
4f6200f0 FB |
89 | target = s->wregs[4] & 7; |
90 | DPRINTF("Select with ATN len %d target %d\n", dmalen, target); | |
91 | if (s->dma) { | |
92 | dmaptr = iommu_translate(s->espdmaregs[1]); | |
2e5d83bb PB |
93 | DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", |
94 | s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r', dmaptr); | |
4f6200f0 FB |
95 | cpu_physical_memory_read(dmaptr, buf, dmalen); |
96 | } else { | |
97 | buf[0] = 0; | |
98 | memcpy(&buf[1], s->ti_buf, dmalen); | |
99 | dmalen++; | |
100 | } | |
2e5d83bb | 101 | |
2f275b8f | 102 | s->ti_size = 0; |
4f6200f0 FB |
103 | s->ti_rptr = 0; |
104 | s->ti_wptr = 0; | |
2f275b8f | 105 | |
2e5d83bb PB |
106 | if (target >= 4 || !s->scsi_dev[target]) { |
107 | // No such drive | |
2f275b8f FB |
108 | s->rregs[4] = STAT_IN; |
109 | s->rregs[5] = INTR_DC; | |
110 | s->rregs[6] = SEQ_0; | |
9e61bde5 | 111 | s->espdmaregs[0] |= DMA_INTR; |
2f275b8f FB |
112 | pic_set_irq(s->irq, 1); |
113 | return; | |
114 | } | |
2e5d83bb PB |
115 | s->current_dev = s->scsi_dev[target]; |
116 | datalen = scsi_send_command(s->current_dev, 0, &buf[1]); | |
117 | if (datalen == 0) { | |
118 | s->ti_size = 0; | |
119 | } else { | |
120 | s->rregs[4] = STAT_IN | STAT_TC; | |
121 | if (datalen > 0) { | |
122 | s->rregs[4] |= STAT_DI; | |
123 | s->ti_size = datalen; | |
124 | } else { | |
125 | s->rregs[4] |= STAT_DO; | |
126 | s->ti_size = -datalen; | |
b9788fc4 | 127 | } |
2f275b8f | 128 | } |
2f275b8f FB |
129 | s->rregs[5] = INTR_BS | INTR_FC; |
130 | s->rregs[6] = SEQ_CD; | |
9e61bde5 | 131 | s->espdmaregs[0] |= DMA_INTR; |
2f275b8f FB |
132 | pic_set_irq(s->irq, 1); |
133 | } | |
134 | ||
135 | static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len) | |
136 | { | |
db59203d | 137 | uint32_t dmaptr; |
2f275b8f | 138 | |
db59203d | 139 | DPRINTF("Transfer status len %d\n", len); |
4f6200f0 FB |
140 | if (s->dma) { |
141 | dmaptr = iommu_translate(s->espdmaregs[1]); | |
2e5d83bb PB |
142 | DPRINTF("DMA Direction: %c\n", |
143 | s->espdmaregs[0] & DMA_WRITE_MEM ? 'w': 'r'); | |
4f6200f0 FB |
144 | cpu_physical_memory_write(dmaptr, buf, len); |
145 | s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | |
146 | s->rregs[5] = INTR_BS | INTR_FC; | |
147 | s->rregs[6] = SEQ_CD; | |
4f6200f0 FB |
148 | } else { |
149 | memcpy(s->ti_buf, buf, len); | |
db59203d | 150 | s->ti_size = len; |
4f6200f0 FB |
151 | s->ti_rptr = 0; |
152 | s->ti_wptr = 0; | |
db59203d | 153 | s->rregs[7] = len; |
4f6200f0 | 154 | } |
9e61bde5 | 155 | s->espdmaregs[0] |= DMA_INTR; |
2f275b8f FB |
156 | pic_set_irq(s->irq, 1); |
157 | ||
158 | } | |
4f6200f0 | 159 | |
2f275b8f FB |
160 | static const uint8_t okbuf[] = {0, 0}; |
161 | ||
2e5d83bb PB |
162 | static void esp_command_complete(void *opaque, uint32_t tag, int fail) |
163 | { | |
164 | ESPState *s = (ESPState *)opaque; | |
165 | ||
166 | DPRINTF("SCSI Command complete\n"); | |
167 | if (s->ti_size != 0) | |
168 | DPRINTF("SCSI command completed unexpectedly\n"); | |
169 | s->ti_size = 0; | |
170 | /* ??? Report failures. */ | |
171 | if (fail) | |
172 | DPRINTF("Command failed\n"); | |
173 | s->rregs[4] = STAT_IN | STAT_TC | STAT_ST; | |
174 | } | |
175 | ||
2f275b8f FB |
176 | static void handle_ti(ESPState *s) |
177 | { | |
db59203d | 178 | uint32_t dmaptr, dmalen, minlen, len, from, to; |
2f275b8f | 179 | unsigned int i; |
2e5d83bb PB |
180 | int to_device; |
181 | uint8_t buf[TARGET_PAGE_SIZE]; | |
2f275b8f | 182 | |
2f275b8f | 183 | dmalen = s->wregs[0] | (s->wregs[1] << 8); |
db59203d PB |
184 | if (dmalen==0) { |
185 | dmalen=0x10000; | |
186 | } | |
187 | ||
188 | minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size; | |
189 | DPRINTF("Transfer Information len %d\n", minlen); | |
4f6200f0 FB |
190 | if (s->dma) { |
191 | dmaptr = iommu_translate(s->espdmaregs[1]); | |
2e5d83bb PB |
192 | /* Check if the transfer writes to to reads from the device. */ |
193 | to_device = (s->espdmaregs[0] & DMA_WRITE_MEM) == 0; | |
194 | DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x\n", | |
195 | to_device ? 'r': 'w', dmaptr, s->ti_size); | |
db59203d PB |
196 | from = s->espdmaregs[1]; |
197 | to = from + minlen; | |
198 | for (i = 0; i < minlen; i += len, from += len) { | |
4f6200f0 | 199 | dmaptr = iommu_translate(s->espdmaregs[1] + i); |
db59203d PB |
200 | if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) { |
201 | len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK); | |
202 | } else { | |
203 | len = to - from; | |
204 | } | |
205 | DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to); | |
2e5d83bb PB |
206 | s->ti_size -= len; |
207 | if (to_device) { | |
208 | cpu_physical_memory_read(dmaptr, buf, len); | |
209 | scsi_write_data(s->current_dev, buf, len); | |
210 | } else { | |
211 | scsi_read_data(s->current_dev, buf, len); | |
212 | cpu_physical_memory_write(dmaptr, buf, len); | |
213 | } | |
4f6200f0 | 214 | } |
2e5d83bb PB |
215 | if (s->ti_size) { |
216 | s->rregs[4] = STAT_IN | STAT_TC | (to_device ? STAT_DO : STAT_DI); | |
4e9aec74 | 217 | } |
db59203d | 218 | s->rregs[5] = INTR_BS; |
4f6200f0 | 219 | s->rregs[6] = 0; |
db59203d | 220 | s->rregs[7] = 0; |
9e61bde5 | 221 | s->espdmaregs[0] |= DMA_INTR; |
4f6200f0 | 222 | } |
2f275b8f FB |
223 | pic_set_irq(s->irq, 1); |
224 | } | |
225 | ||
6f7e9aec FB |
226 | static void esp_reset(void *opaque) |
227 | { | |
228 | ESPState *s = opaque; | |
2f275b8f | 229 | memset(s->rregs, 0, ESP_MAXREG); |
4e9aec74 | 230 | memset(s->wregs, 0, ESP_MAXREG); |
2f275b8f | 231 | s->rregs[0x0e] = 0x4; // Indicate fas100a |
6f7e9aec | 232 | memset(s->espdmaregs, 0, ESPDMA_REGS * 4); |
4e9aec74 PB |
233 | s->ti_size = 0; |
234 | s->ti_rptr = 0; | |
235 | s->ti_wptr = 0; | |
4e9aec74 | 236 | s->dma = 0; |
6f7e9aec FB |
237 | } |
238 | ||
239 | static uint32_t esp_mem_readb(void *opaque, target_phys_addr_t addr) | |
240 | { | |
241 | ESPState *s = opaque; | |
242 | uint32_t saddr; | |
243 | ||
244 | saddr = (addr & ESP_MAXREG) >> 2; | |
9e61bde5 | 245 | DPRINTF("read reg[%d]: 0x%2.2x\n", saddr, s->rregs[saddr]); |
6f7e9aec | 246 | switch (saddr) { |
4f6200f0 FB |
247 | case 2: |
248 | // FIFO | |
249 | if (s->ti_size > 0) { | |
250 | s->ti_size--; | |
2e5d83bb PB |
251 | if ((s->rregs[4] & 6) == 0) { |
252 | /* Data in/out. */ | |
253 | scsi_read_data(s->current_dev, &s->rregs[2], 0); | |
254 | } else { | |
255 | s->rregs[2] = s->ti_buf[s->ti_rptr++]; | |
256 | } | |
4f6200f0 FB |
257 | pic_set_irq(s->irq, 1); |
258 | } | |
259 | if (s->ti_size == 0) { | |
260 | s->ti_rptr = 0; | |
261 | s->ti_wptr = 0; | |
262 | } | |
263 | break; | |
9e61bde5 FB |
264 | case 5: |
265 | // interrupt | |
266 | // Clear status bits except TC | |
267 | s->rregs[4] &= STAT_TC; | |
268 | pic_set_irq(s->irq, 0); | |
269 | s->espdmaregs[0] &= ~DMA_INTR; | |
270 | break; | |
6f7e9aec FB |
271 | default: |
272 | break; | |
273 | } | |
2f275b8f | 274 | return s->rregs[saddr]; |
6f7e9aec FB |
275 | } |
276 | ||
277 | static void esp_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | |
278 | { | |
279 | ESPState *s = opaque; | |
280 | uint32_t saddr; | |
281 | ||
282 | saddr = (addr & ESP_MAXREG) >> 2; | |
2f275b8f | 283 | DPRINTF("write reg[%d]: 0x%2.2x -> 0x%2.2x\n", saddr, s->wregs[saddr], val); |
6f7e9aec | 284 | switch (saddr) { |
4f6200f0 FB |
285 | case 0: |
286 | case 1: | |
287 | s->rregs[saddr] = val; | |
288 | break; | |
289 | case 2: | |
290 | // FIFO | |
2e5d83bb PB |
291 | if ((s->rregs[4] & 6) == 0) { |
292 | uint8_t buf; | |
293 | buf = val & 0xff; | |
294 | s->ti_size--; | |
295 | scsi_write_data(s->current_dev, &buf, 0); | |
296 | } else { | |
297 | s->ti_size++; | |
298 | s->ti_buf[s->ti_wptr++] = val & 0xff; | |
299 | } | |
4f6200f0 | 300 | break; |
6f7e9aec | 301 | case 3: |
4f6200f0 | 302 | s->rregs[saddr] = val; |
6f7e9aec | 303 | // Command |
4f6200f0 FB |
304 | if (val & 0x80) { |
305 | s->dma = 1; | |
306 | } else { | |
307 | s->dma = 0; | |
308 | } | |
6f7e9aec FB |
309 | switch(val & 0x7f) { |
310 | case 0: | |
2f275b8f FB |
311 | DPRINTF("NOP (%2.2x)\n", val); |
312 | break; | |
313 | case 1: | |
314 | DPRINTF("Flush FIFO (%2.2x)\n", val); | |
9e61bde5 | 315 | //s->ti_size = 0; |
2f275b8f | 316 | s->rregs[5] = INTR_FC; |
9e61bde5 | 317 | s->rregs[6] = 0; |
6f7e9aec FB |
318 | break; |
319 | case 2: | |
2f275b8f | 320 | DPRINTF("Chip reset (%2.2x)\n", val); |
6f7e9aec FB |
321 | esp_reset(s); |
322 | break; | |
323 | case 3: | |
2f275b8f | 324 | DPRINTF("Bus reset (%2.2x)\n", val); |
9e61bde5 FB |
325 | s->rregs[5] = INTR_RST; |
326 | if (!(s->wregs[8] & 0x40)) { | |
327 | s->espdmaregs[0] |= DMA_INTR; | |
328 | pic_set_irq(s->irq, 1); | |
329 | } | |
2f275b8f FB |
330 | break; |
331 | case 0x10: | |
332 | handle_ti(s); | |
333 | break; | |
334 | case 0x11: | |
335 | DPRINTF("Initiator Command Complete Sequence (%2.2x)\n", val); | |
336 | dma_write(s, okbuf, 2); | |
337 | break; | |
338 | case 0x12: | |
339 | DPRINTF("Message Accepted (%2.2x)\n", val); | |
340 | dma_write(s, okbuf, 2); | |
341 | s->rregs[5] = INTR_DC; | |
342 | s->rregs[6] = 0; | |
6f7e9aec FB |
343 | break; |
344 | case 0x1a: | |
2f275b8f | 345 | DPRINTF("Set ATN (%2.2x)\n", val); |
6f7e9aec FB |
346 | break; |
347 | case 0x42: | |
2f275b8f FB |
348 | handle_satn(s); |
349 | break; | |
350 | case 0x43: | |
351 | DPRINTF("Set ATN & stop (%2.2x)\n", val); | |
352 | handle_satn(s); | |
353 | break; | |
354 | default: | |
4f6200f0 | 355 | DPRINTF("Unhandled ESP command (%2.2x)\n", val); |
6f7e9aec FB |
356 | break; |
357 | } | |
358 | break; | |
359 | case 4 ... 7: | |
6f7e9aec | 360 | break; |
4f6200f0 FB |
361 | case 8: |
362 | s->rregs[saddr] = val; | |
363 | break; | |
364 | case 9 ... 10: | |
365 | break; | |
9e61bde5 FB |
366 | case 11: |
367 | s->rregs[saddr] = val & 0x15; | |
368 | break; | |
369 | case 12 ... 15: | |
4f6200f0 FB |
370 | s->rregs[saddr] = val; |
371 | break; | |
6f7e9aec | 372 | default: |
6f7e9aec FB |
373 | break; |
374 | } | |
2f275b8f | 375 | s->wregs[saddr] = val; |
6f7e9aec FB |
376 | } |
377 | ||
378 | static CPUReadMemoryFunc *esp_mem_read[3] = { | |
379 | esp_mem_readb, | |
380 | esp_mem_readb, | |
381 | esp_mem_readb, | |
382 | }; | |
383 | ||
384 | static CPUWriteMemoryFunc *esp_mem_write[3] = { | |
385 | esp_mem_writeb, | |
386 | esp_mem_writeb, | |
387 | esp_mem_writeb, | |
388 | }; | |
389 | ||
390 | static uint32_t espdma_mem_readl(void *opaque, target_phys_addr_t addr) | |
391 | { | |
392 | ESPState *s = opaque; | |
393 | uint32_t saddr; | |
394 | ||
395 | saddr = (addr & ESPDMA_MAXADDR) >> 2; | |
4f6200f0 FB |
396 | DPRINTF("read dmareg[%d]: 0x%8.8x\n", saddr, s->espdmaregs[saddr]); |
397 | ||
6f7e9aec FB |
398 | return s->espdmaregs[saddr]; |
399 | } | |
400 | ||
401 | static void espdma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val) | |
402 | { | |
403 | ESPState *s = opaque; | |
404 | uint32_t saddr; | |
405 | ||
406 | saddr = (addr & ESPDMA_MAXADDR) >> 2; | |
4f6200f0 | 407 | DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->espdmaregs[saddr], val); |
2f275b8f FB |
408 | switch (saddr) { |
409 | case 0: | |
9e61bde5 | 410 | if (!(val & DMA_INTREN)) |
2f275b8f | 411 | pic_set_irq(s->irq, 0); |
4f6200f0 FB |
412 | if (val & 0x80) { |
413 | esp_reset(s); | |
414 | } else if (val & 0x40) { | |
415 | val &= ~0x40; | |
416 | } else if (val == 0) | |
417 | val = 0x40; | |
418 | val &= 0x0fffffff; | |
419 | val |= DMA_VER; | |
2f275b8f | 420 | break; |
4f6200f0 | 421 | case 1: |
e4d165c2 | 422 | s->espdmaregs[0] |= DMA_LOADED; |
4f6200f0 | 423 | break; |
2f275b8f FB |
424 | default: |
425 | break; | |
426 | } | |
6f7e9aec FB |
427 | s->espdmaregs[saddr] = val; |
428 | } | |
429 | ||
430 | static CPUReadMemoryFunc *espdma_mem_read[3] = { | |
431 | espdma_mem_readl, | |
432 | espdma_mem_readl, | |
433 | espdma_mem_readl, | |
434 | }; | |
435 | ||
436 | static CPUWriteMemoryFunc *espdma_mem_write[3] = { | |
437 | espdma_mem_writel, | |
438 | espdma_mem_writel, | |
439 | espdma_mem_writel, | |
440 | }; | |
441 | ||
442 | static void esp_save(QEMUFile *f, void *opaque) | |
443 | { | |
444 | ESPState *s = opaque; | |
2f275b8f FB |
445 | unsigned int i; |
446 | ||
447 | qemu_put_buffer(f, s->rregs, ESP_MAXREG); | |
448 | qemu_put_buffer(f, s->wregs, ESP_MAXREG); | |
449 | qemu_put_be32s(f, &s->irq); | |
450 | for (i = 0; i < ESPDMA_REGS; i++) | |
451 | qemu_put_be32s(f, &s->espdmaregs[i]); | |
4f6200f0 FB |
452 | qemu_put_be32s(f, &s->ti_size); |
453 | qemu_put_be32s(f, &s->ti_rptr); | |
454 | qemu_put_be32s(f, &s->ti_wptr); | |
4f6200f0 FB |
455 | qemu_put_buffer(f, s->ti_buf, TI_BUFSZ); |
456 | qemu_put_be32s(f, &s->dma); | |
6f7e9aec FB |
457 | } |
458 | ||
459 | static int esp_load(QEMUFile *f, void *opaque, int version_id) | |
460 | { | |
461 | ESPState *s = opaque; | |
2f275b8f | 462 | unsigned int i; |
6f7e9aec FB |
463 | |
464 | if (version_id != 1) | |
465 | return -EINVAL; | |
466 | ||
2f275b8f FB |
467 | qemu_get_buffer(f, s->rregs, ESP_MAXREG); |
468 | qemu_get_buffer(f, s->wregs, ESP_MAXREG); | |
469 | qemu_get_be32s(f, &s->irq); | |
470 | for (i = 0; i < ESPDMA_REGS; i++) | |
471 | qemu_get_be32s(f, &s->espdmaregs[i]); | |
4f6200f0 FB |
472 | qemu_get_be32s(f, &s->ti_size); |
473 | qemu_get_be32s(f, &s->ti_rptr); | |
474 | qemu_get_be32s(f, &s->ti_wptr); | |
4f6200f0 FB |
475 | qemu_get_buffer(f, s->ti_buf, TI_BUFSZ); |
476 | qemu_get_be32s(f, &s->dma); | |
2f275b8f | 477 | |
6f7e9aec FB |
478 | return 0; |
479 | } | |
480 | ||
481 | void esp_init(BlockDriverState **bd, int irq, uint32_t espaddr, uint32_t espdaddr) | |
482 | { | |
483 | ESPState *s; | |
484 | int esp_io_memory, espdma_io_memory; | |
2e5d83bb | 485 | int i; |
6f7e9aec FB |
486 | |
487 | s = qemu_mallocz(sizeof(ESPState)); | |
488 | if (!s) | |
489 | return; | |
490 | ||
491 | s->bd = bd; | |
492 | s->irq = irq; | |
493 | ||
494 | esp_io_memory = cpu_register_io_memory(0, esp_mem_read, esp_mem_write, s); | |
495 | cpu_register_physical_memory(espaddr, ESP_MAXREG*4, esp_io_memory); | |
496 | ||
497 | espdma_io_memory = cpu_register_io_memory(0, espdma_mem_read, espdma_mem_write, s); | |
498 | cpu_register_physical_memory(espdaddr, 16, espdma_io_memory); | |
499 | ||
500 | esp_reset(s); | |
501 | ||
502 | register_savevm("esp", espaddr, 1, esp_save, esp_load, s); | |
503 | qemu_register_reset(esp_reset, s); | |
2e5d83bb PB |
504 | for (i = 0; i < MAX_DISKS; i++) { |
505 | if (bs_table[i]) { | |
506 | s->scsi_dev[i] = | |
507 | scsi_disk_init(bs_table[i], esp_command_complete, s); | |
508 | } | |
509 | } | |
6f7e9aec FB |
510 | } |
511 |