|
1 /* |
|
2 * QEMU Parallel PORT emulation |
|
3 * |
|
4 * Copyright (c) 2003-2005 Fabrice Bellard |
|
5 * Copyright (c) 2007 Marko Kohtala |
|
6 * |
|
7 * Permission is hereby granted, free of charge, to any person obtaining a copy |
|
8 * of this software and associated documentation files (the "Software"), to deal |
|
9 * in the Software without restriction, including without limitation the rights |
|
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
11 * copies of the Software, and to permit persons to whom the Software is |
|
12 * furnished to do so, subject to the following conditions: |
|
13 * |
|
14 * The above copyright notice and this permission notice shall be included in |
|
15 * all copies or substantial portions of the Software. |
|
16 * |
|
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
23 * THE SOFTWARE. |
|
24 */ |
|
25 #include "hw.h" |
|
26 #include "qemu-char.h" |
|
27 #include "isa.h" |
|
28 #include "pc.h" |
|
29 |
|
30 //#define DEBUG_PARALLEL |
|
31 |
|
32 #ifdef DEBUG_PARALLEL |
|
33 #define pdebug(fmt, arg...) printf("pp: " fmt, ##arg) |
|
34 #else |
|
35 #define pdebug(fmt, arg...) ((void)0) |
|
36 #endif |
|
37 |
|
38 #define PARA_REG_DATA 0 |
|
39 #define PARA_REG_STS 1 |
|
40 #define PARA_REG_CTR 2 |
|
41 #define PARA_REG_EPP_ADDR 3 |
|
42 #define PARA_REG_EPP_DATA 4 |
|
43 |
|
44 /* |
|
45 * These are the definitions for the Printer Status Register |
|
46 */ |
|
47 #define PARA_STS_BUSY 0x80 /* Busy complement */ |
|
48 #define PARA_STS_ACK 0x40 /* Acknowledge */ |
|
49 #define PARA_STS_PAPER 0x20 /* Out of paper */ |
|
50 #define PARA_STS_ONLINE 0x10 /* Online */ |
|
51 #define PARA_STS_ERROR 0x08 /* Error complement */ |
|
52 #define PARA_STS_TMOUT 0x01 /* EPP timeout */ |
|
53 |
|
54 /* |
|
55 * These are the definitions for the Printer Control Register |
|
56 */ |
|
57 #define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */ |
|
58 #define PARA_CTR_INTEN 0x10 /* IRQ Enable */ |
|
59 #define PARA_CTR_SELECT 0x08 /* Select In complement */ |
|
60 #define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ |
|
61 #define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ |
|
62 #define PARA_CTR_STROBE 0x01 /* Strobe complement */ |
|
63 |
|
64 #define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE) |
|
65 |
|
66 struct ParallelState { |
|
67 uint8_t dataw; |
|
68 uint8_t datar; |
|
69 uint8_t status; |
|
70 uint8_t control; |
|
71 qemu_irq irq; |
|
72 int irq_pending; |
|
73 CharDriverState *chr; |
|
74 int hw_driver; |
|
75 int epp_timeout; |
|
76 uint32_t last_read_offset; /* For debugging */ |
|
77 /* Memory-mapped interface */ |
|
78 int it_shift; |
|
79 }; |
|
80 |
|
81 static void parallel_update_irq(ParallelState *s) |
|
82 { |
|
83 if (s->irq_pending) |
|
84 qemu_irq_raise(s->irq); |
|
85 else |
|
86 qemu_irq_lower(s->irq); |
|
87 } |
|
88 |
|
89 static void |
|
90 parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val) |
|
91 { |
|
92 ParallelState *s = opaque; |
|
93 |
|
94 pdebug("write addr=0x%02x val=0x%02x\n", addr, val); |
|
95 |
|
96 addr &= 7; |
|
97 switch(addr) { |
|
98 case PARA_REG_DATA: |
|
99 s->dataw = val; |
|
100 parallel_update_irq(s); |
|
101 break; |
|
102 case PARA_REG_CTR: |
|
103 val |= 0xc0; |
|
104 if ((val & PARA_CTR_INIT) == 0 ) { |
|
105 s->status = PARA_STS_BUSY; |
|
106 s->status |= PARA_STS_ACK; |
|
107 s->status |= PARA_STS_ONLINE; |
|
108 s->status |= PARA_STS_ERROR; |
|
109 } |
|
110 else if (val & PARA_CTR_SELECT) { |
|
111 if (val & PARA_CTR_STROBE) { |
|
112 s->status &= ~PARA_STS_BUSY; |
|
113 if ((s->control & PARA_CTR_STROBE) == 0) |
|
114 qemu_chr_write(s->chr, &s->dataw, 1); |
|
115 } else { |
|
116 if (s->control & PARA_CTR_INTEN) { |
|
117 s->irq_pending = 1; |
|
118 } |
|
119 } |
|
120 } |
|
121 parallel_update_irq(s); |
|
122 s->control = val; |
|
123 break; |
|
124 } |
|
125 } |
|
126 |
|
127 static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val) |
|
128 { |
|
129 ParallelState *s = opaque; |
|
130 uint8_t parm = val; |
|
131 int dir; |
|
132 |
|
133 /* Sometimes programs do several writes for timing purposes on old |
|
134 HW. Take care not to waste time on writes that do nothing. */ |
|
135 |
|
136 s->last_read_offset = ~0U; |
|
137 |
|
138 addr &= 7; |
|
139 switch(addr) { |
|
140 case PARA_REG_DATA: |
|
141 if (s->dataw == val) |
|
142 return; |
|
143 pdebug("wd%02x\n", val); |
|
144 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm); |
|
145 s->dataw = val; |
|
146 break; |
|
147 case PARA_REG_STS: |
|
148 pdebug("ws%02x\n", val); |
|
149 if (val & PARA_STS_TMOUT) |
|
150 s->epp_timeout = 0; |
|
151 break; |
|
152 case PARA_REG_CTR: |
|
153 val |= 0xc0; |
|
154 if (s->control == val) |
|
155 return; |
|
156 pdebug("wc%02x\n", val); |
|
157 |
|
158 if ((val & PARA_CTR_DIR) != (s->control & PARA_CTR_DIR)) { |
|
159 if (val & PARA_CTR_DIR) { |
|
160 dir = 1; |
|
161 } else { |
|
162 dir = 0; |
|
163 } |
|
164 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_DATA_DIR, &dir); |
|
165 parm &= ~PARA_CTR_DIR; |
|
166 } |
|
167 |
|
168 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm); |
|
169 s->control = val; |
|
170 break; |
|
171 case PARA_REG_EPP_ADDR: |
|
172 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) |
|
173 /* Controls not correct for EPP address cycle, so do nothing */ |
|
174 pdebug("wa%02x s\n", val); |
|
175 else { |
|
176 struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; |
|
177 if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) { |
|
178 s->epp_timeout = 1; |
|
179 pdebug("wa%02x t\n", val); |
|
180 } |
|
181 else |
|
182 pdebug("wa%02x\n", val); |
|
183 } |
|
184 break; |
|
185 case PARA_REG_EPP_DATA: |
|
186 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) |
|
187 /* Controls not correct for EPP data cycle, so do nothing */ |
|
188 pdebug("we%02x s\n", val); |
|
189 else { |
|
190 struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 }; |
|
191 if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) { |
|
192 s->epp_timeout = 1; |
|
193 pdebug("we%02x t\n", val); |
|
194 } |
|
195 else |
|
196 pdebug("we%02x\n", val); |
|
197 } |
|
198 break; |
|
199 } |
|
200 } |
|
201 |
|
202 static void |
|
203 parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val) |
|
204 { |
|
205 ParallelState *s = opaque; |
|
206 uint16_t eppdata = cpu_to_le16(val); |
|
207 int err; |
|
208 struct ParallelIOArg ioarg = { |
|
209 .buffer = &eppdata, .count = sizeof(eppdata) |
|
210 }; |
|
211 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { |
|
212 /* Controls not correct for EPP data cycle, so do nothing */ |
|
213 pdebug("we%04x s\n", val); |
|
214 return; |
|
215 } |
|
216 err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); |
|
217 if (err) { |
|
218 s->epp_timeout = 1; |
|
219 pdebug("we%04x t\n", val); |
|
220 } |
|
221 else |
|
222 pdebug("we%04x\n", val); |
|
223 } |
|
224 |
|
225 static void |
|
226 parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val) |
|
227 { |
|
228 ParallelState *s = opaque; |
|
229 uint32_t eppdata = cpu_to_le32(val); |
|
230 int err; |
|
231 struct ParallelIOArg ioarg = { |
|
232 .buffer = &eppdata, .count = sizeof(eppdata) |
|
233 }; |
|
234 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) { |
|
235 /* Controls not correct for EPP data cycle, so do nothing */ |
|
236 pdebug("we%08x s\n", val); |
|
237 return; |
|
238 } |
|
239 err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg); |
|
240 if (err) { |
|
241 s->epp_timeout = 1; |
|
242 pdebug("we%08x t\n", val); |
|
243 } |
|
244 else |
|
245 pdebug("we%08x\n", val); |
|
246 } |
|
247 |
|
248 static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr) |
|
249 { |
|
250 ParallelState *s = opaque; |
|
251 uint32_t ret = 0xff; |
|
252 |
|
253 addr &= 7; |
|
254 switch(addr) { |
|
255 case PARA_REG_DATA: |
|
256 if (s->control & PARA_CTR_DIR) |
|
257 ret = s->datar; |
|
258 else |
|
259 ret = s->dataw; |
|
260 break; |
|
261 case PARA_REG_STS: |
|
262 ret = s->status; |
|
263 s->irq_pending = 0; |
|
264 if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { |
|
265 /* XXX Fixme: wait 5 microseconds */ |
|
266 if (s->status & PARA_STS_ACK) |
|
267 s->status &= ~PARA_STS_ACK; |
|
268 else { |
|
269 /* XXX Fixme: wait 5 microseconds */ |
|
270 s->status |= PARA_STS_ACK; |
|
271 s->status |= PARA_STS_BUSY; |
|
272 } |
|
273 } |
|
274 parallel_update_irq(s); |
|
275 break; |
|
276 case PARA_REG_CTR: |
|
277 ret = s->control; |
|
278 break; |
|
279 } |
|
280 pdebug("read addr=0x%02x val=0x%02x\n", addr, ret); |
|
281 return ret; |
|
282 } |
|
283 |
|
284 static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr) |
|
285 { |
|
286 ParallelState *s = opaque; |
|
287 uint8_t ret = 0xff; |
|
288 addr &= 7; |
|
289 switch(addr) { |
|
290 case PARA_REG_DATA: |
|
291 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret); |
|
292 if (s->last_read_offset != addr || s->datar != ret) |
|
293 pdebug("rd%02x\n", ret); |
|
294 s->datar = ret; |
|
295 break; |
|
296 case PARA_REG_STS: |
|
297 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret); |
|
298 ret &= ~PARA_STS_TMOUT; |
|
299 if (s->epp_timeout) |
|
300 ret |= PARA_STS_TMOUT; |
|
301 if (s->last_read_offset != addr || s->status != ret) |
|
302 pdebug("rs%02x\n", ret); |
|
303 s->status = ret; |
|
304 break; |
|
305 case PARA_REG_CTR: |
|
306 /* s->control has some bits fixed to 1. It is zero only when |
|
307 it has not been yet written to. */ |
|
308 if (s->control == 0) { |
|
309 qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret); |
|
310 if (s->last_read_offset != addr) |
|
311 pdebug("rc%02x\n", ret); |
|
312 s->control = ret; |
|
313 } |
|
314 else { |
|
315 ret = s->control; |
|
316 if (s->last_read_offset != addr) |
|
317 pdebug("rc%02x\n", ret); |
|
318 } |
|
319 break; |
|
320 case PARA_REG_EPP_ADDR: |
|
321 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) |
|
322 /* Controls not correct for EPP addr cycle, so do nothing */ |
|
323 pdebug("ra%02x s\n", ret); |
|
324 else { |
|
325 struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; |
|
326 if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) { |
|
327 s->epp_timeout = 1; |
|
328 pdebug("ra%02x t\n", ret); |
|
329 } |
|
330 else |
|
331 pdebug("ra%02x\n", ret); |
|
332 } |
|
333 break; |
|
334 case PARA_REG_EPP_DATA: |
|
335 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) |
|
336 /* Controls not correct for EPP data cycle, so do nothing */ |
|
337 pdebug("re%02x s\n", ret); |
|
338 else { |
|
339 struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 }; |
|
340 if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) { |
|
341 s->epp_timeout = 1; |
|
342 pdebug("re%02x t\n", ret); |
|
343 } |
|
344 else |
|
345 pdebug("re%02x\n", ret); |
|
346 } |
|
347 break; |
|
348 } |
|
349 s->last_read_offset = addr; |
|
350 return ret; |
|
351 } |
|
352 |
|
353 static uint32_t |
|
354 parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr) |
|
355 { |
|
356 ParallelState *s = opaque; |
|
357 uint32_t ret; |
|
358 uint16_t eppdata = ~0; |
|
359 int err; |
|
360 struct ParallelIOArg ioarg = { |
|
361 .buffer = &eppdata, .count = sizeof(eppdata) |
|
362 }; |
|
363 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { |
|
364 /* Controls not correct for EPP data cycle, so do nothing */ |
|
365 pdebug("re%04x s\n", eppdata); |
|
366 return eppdata; |
|
367 } |
|
368 err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); |
|
369 ret = le16_to_cpu(eppdata); |
|
370 |
|
371 if (err) { |
|
372 s->epp_timeout = 1; |
|
373 pdebug("re%04x t\n", ret); |
|
374 } |
|
375 else |
|
376 pdebug("re%04x\n", ret); |
|
377 return ret; |
|
378 } |
|
379 |
|
380 static uint32_t |
|
381 parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr) |
|
382 { |
|
383 ParallelState *s = opaque; |
|
384 uint32_t ret; |
|
385 uint32_t eppdata = ~0U; |
|
386 int err; |
|
387 struct ParallelIOArg ioarg = { |
|
388 .buffer = &eppdata, .count = sizeof(eppdata) |
|
389 }; |
|
390 if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) { |
|
391 /* Controls not correct for EPP data cycle, so do nothing */ |
|
392 pdebug("re%08x s\n", eppdata); |
|
393 return eppdata; |
|
394 } |
|
395 err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg); |
|
396 ret = le32_to_cpu(eppdata); |
|
397 |
|
398 if (err) { |
|
399 s->epp_timeout = 1; |
|
400 pdebug("re%08x t\n", ret); |
|
401 } |
|
402 else |
|
403 pdebug("re%08x\n", ret); |
|
404 return ret; |
|
405 } |
|
406 |
|
407 static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val) |
|
408 { |
|
409 addr &= 7; |
|
410 pdebug("wecp%d=%02x\n", addr, val); |
|
411 } |
|
412 |
|
413 static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr) |
|
414 { |
|
415 uint8_t ret = 0xff; |
|
416 addr &= 7; |
|
417 pdebug("recp%d:%02x\n", addr, ret); |
|
418 return ret; |
|
419 } |
|
420 |
|
421 static void parallel_reset(void *opaque) |
|
422 { |
|
423 ParallelState *s = opaque; |
|
424 |
|
425 s->datar = ~0; |
|
426 s->dataw = ~0; |
|
427 s->status = PARA_STS_BUSY; |
|
428 s->status |= PARA_STS_ACK; |
|
429 s->status |= PARA_STS_ONLINE; |
|
430 s->status |= PARA_STS_ERROR; |
|
431 s->status |= PARA_STS_TMOUT; |
|
432 s->control = PARA_CTR_SELECT; |
|
433 s->control |= PARA_CTR_INIT; |
|
434 s->control |= 0xc0; |
|
435 s->irq_pending = 0; |
|
436 s->hw_driver = 0; |
|
437 s->epp_timeout = 0; |
|
438 s->last_read_offset = ~0U; |
|
439 } |
|
440 |
|
441 /* If fd is zero, it means that the parallel device uses the console */ |
|
442 ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr) |
|
443 { |
|
444 ParallelState *s; |
|
445 uint8_t dummy; |
|
446 |
|
447 s = qemu_mallocz(sizeof(ParallelState)); |
|
448 if (!s) |
|
449 return NULL; |
|
450 s->irq = irq; |
|
451 s->chr = chr; |
|
452 parallel_reset(s); |
|
453 qemu_register_reset(parallel_reset, s); |
|
454 |
|
455 if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) { |
|
456 s->hw_driver = 1; |
|
457 s->status = dummy; |
|
458 } |
|
459 |
|
460 if (s->hw_driver) { |
|
461 register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s); |
|
462 register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s); |
|
463 register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s); |
|
464 register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s); |
|
465 register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s); |
|
466 register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s); |
|
467 register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s); |
|
468 register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s); |
|
469 } |
|
470 else { |
|
471 register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s); |
|
472 register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s); |
|
473 } |
|
474 return s; |
|
475 } |
|
476 |
|
477 /* Memory mapped interface */ |
|
478 static uint32_t parallel_mm_readb (void *opaque, target_phys_addr_t addr) |
|
479 { |
|
480 ParallelState *s = opaque; |
|
481 |
|
482 return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFF; |
|
483 } |
|
484 |
|
485 static void parallel_mm_writeb (void *opaque, |
|
486 target_phys_addr_t addr, uint32_t value) |
|
487 { |
|
488 ParallelState *s = opaque; |
|
489 |
|
490 parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFF); |
|
491 } |
|
492 |
|
493 static uint32_t parallel_mm_readw (void *opaque, target_phys_addr_t addr) |
|
494 { |
|
495 ParallelState *s = opaque; |
|
496 |
|
497 return parallel_ioport_read_sw(s, addr >> s->it_shift) & 0xFFFF; |
|
498 } |
|
499 |
|
500 static void parallel_mm_writew (void *opaque, |
|
501 target_phys_addr_t addr, uint32_t value) |
|
502 { |
|
503 ParallelState *s = opaque; |
|
504 |
|
505 parallel_ioport_write_sw(s, addr >> s->it_shift, value & 0xFFFF); |
|
506 } |
|
507 |
|
508 static uint32_t parallel_mm_readl (void *opaque, target_phys_addr_t addr) |
|
509 { |
|
510 ParallelState *s = opaque; |
|
511 |
|
512 return parallel_ioport_read_sw(s, addr >> s->it_shift); |
|
513 } |
|
514 |
|
515 static void parallel_mm_writel (void *opaque, |
|
516 target_phys_addr_t addr, uint32_t value) |
|
517 { |
|
518 ParallelState *s = opaque; |
|
519 |
|
520 parallel_ioport_write_sw(s, addr >> s->it_shift, value); |
|
521 } |
|
522 |
|
523 static CPUReadMemoryFunc *parallel_mm_read_sw[] = { |
|
524 ¶llel_mm_readb, |
|
525 ¶llel_mm_readw, |
|
526 ¶llel_mm_readl, |
|
527 }; |
|
528 |
|
529 static CPUWriteMemoryFunc *parallel_mm_write_sw[] = { |
|
530 ¶llel_mm_writeb, |
|
531 ¶llel_mm_writew, |
|
532 ¶llel_mm_writel, |
|
533 }; |
|
534 |
|
535 /* If fd is zero, it means that the parallel device uses the console */ |
|
536 ParallelState *parallel_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq, CharDriverState *chr) |
|
537 { |
|
538 ParallelState *s; |
|
539 int io_sw; |
|
540 |
|
541 s = qemu_mallocz(sizeof(ParallelState)); |
|
542 if (!s) |
|
543 return NULL; |
|
544 s->irq = irq; |
|
545 s->chr = chr; |
|
546 s->it_shift = it_shift; |
|
547 parallel_reset(s); |
|
548 qemu_register_reset(parallel_reset, s); |
|
549 |
|
550 io_sw = cpu_register_io_memory(0, parallel_mm_read_sw, parallel_mm_write_sw, s); |
|
551 cpu_register_physical_memory(base, 8 << it_shift, io_sw); |
|
552 return s; |
|
553 } |