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