]>
Commit | Line | Data |
---|---|---|
6508fe59 FB |
1 | /* |
2 | * QEMU Parallel PORT emulation | |
3 | * | |
e57a8c0e | 4 | * Copyright (c) 2003-2005 Fabrice Bellard |
6508fe59 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 | //#define DEBUG_PARALLEL | |
27 | ||
28 | /* | |
29 | * These are the definitions for the Printer Status Register | |
30 | */ | |
31 | #define PARA_STS_BUSY 0x80 /* Busy complement */ | |
32 | #define PARA_STS_ACK 0x40 /* Acknowledge */ | |
33 | #define PARA_STS_PAPER 0x20 /* Out of paper */ | |
34 | #define PARA_STS_ONLINE 0x10 /* Online */ | |
35 | #define PARA_STS_ERROR 0x08 /* Error complement */ | |
36 | ||
37 | /* | |
38 | * These are the definitions for the Printer Control Register | |
39 | */ | |
40 | #define PARA_CTR_INTEN 0x10 /* IRQ Enable */ | |
41 | #define PARA_CTR_SELECT 0x08 /* Select In complement */ | |
42 | #define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ | |
43 | #define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ | |
44 | #define PARA_CTR_STROBE 0x01 /* Strobe complement */ | |
45 | ||
46 | struct ParallelState { | |
47 | uint8_t data; | |
48 | uint8_t status; /* read only register */ | |
49 | uint8_t control; | |
50 | int irq; | |
51 | int irq_pending; | |
52 | CharDriverState *chr; | |
e57a8c0e | 53 | int hw_driver; |
6508fe59 FB |
54 | }; |
55 | ||
56 | static void parallel_update_irq(ParallelState *s) | |
57 | { | |
58 | if (s->irq_pending) | |
59 | pic_set_irq(s->irq, 1); | |
60 | else | |
61 | pic_set_irq(s->irq, 0); | |
62 | } | |
63 | ||
64 | static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |
65 | { | |
66 | ParallelState *s = opaque; | |
67 | ||
68 | addr &= 7; | |
69 | #ifdef DEBUG_PARALLEL | |
70 | printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); | |
71 | #endif | |
72 | switch(addr) { | |
73 | case 0: | |
e57a8c0e FB |
74 | if (s->hw_driver) { |
75 | s->data = val; | |
76 | qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data); | |
77 | } else { | |
78 | s->data = val; | |
79 | parallel_update_irq(s); | |
80 | } | |
6508fe59 FB |
81 | break; |
82 | case 2: | |
e57a8c0e FB |
83 | if (s->hw_driver) { |
84 | s->control = val; | |
85 | qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control); | |
86 | } else { | |
87 | if ((val & PARA_CTR_INIT) == 0 ) { | |
88 | s->status = PARA_STS_BUSY; | |
89 | s->status |= PARA_STS_ACK; | |
90 | s->status |= PARA_STS_ONLINE; | |
91 | s->status |= PARA_STS_ERROR; | |
92 | } | |
93 | else if (val & PARA_CTR_SELECT) { | |
94 | if (val & PARA_CTR_STROBE) { | |
95 | s->status &= ~PARA_STS_BUSY; | |
96 | if ((s->control & PARA_CTR_STROBE) == 0) | |
97 | qemu_chr_write(s->chr, &s->data, 1); | |
98 | } else { | |
99 | if (s->control & PARA_CTR_INTEN) { | |
100 | s->irq_pending = 1; | |
101 | } | |
6508fe59 FB |
102 | } |
103 | } | |
e57a8c0e FB |
104 | parallel_update_irq(s); |
105 | s->control = val; | |
6508fe59 | 106 | } |
6508fe59 FB |
107 | break; |
108 | } | |
109 | } | |
110 | ||
111 | static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) | |
112 | { | |
113 | ParallelState *s = opaque; | |
114 | uint32_t ret = 0xff; | |
115 | ||
116 | addr &= 7; | |
117 | switch(addr) { | |
118 | case 0: | |
e57a8c0e FB |
119 | if (s->hw_driver) { |
120 | qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data); | |
121 | } | |
6508fe59 FB |
122 | ret = s->data; |
123 | break; | |
124 | case 1: | |
e57a8c0e FB |
125 | if (s->hw_driver) { |
126 | qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status); | |
127 | ret = s->status; | |
128 | } else { | |
129 | ret = s->status; | |
130 | s->irq_pending = 0; | |
131 | if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { | |
132 | /* XXX Fixme: wait 5 microseconds */ | |
133 | if (s->status & PARA_STS_ACK) | |
134 | s->status &= ~PARA_STS_ACK; | |
135 | else { | |
136 | /* XXX Fixme: wait 5 microseconds */ | |
137 | s->status |= PARA_STS_ACK; | |
138 | s->status |= PARA_STS_BUSY; | |
139 | } | |
6508fe59 | 140 | } |
e57a8c0e | 141 | parallel_update_irq(s); |
6508fe59 | 142 | } |
6508fe59 FB |
143 | break; |
144 | case 2: | |
e57a8c0e FB |
145 | if (s->hw_driver) { |
146 | qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control); | |
147 | } | |
6508fe59 FB |
148 | ret = s->control; |
149 | break; | |
150 | } | |
151 | #ifdef DEBUG_PARALLEL | |
152 | printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); | |
153 | #endif | |
154 | return ret; | |
155 | } | |
156 | ||
6508fe59 FB |
157 | /* If fd is zero, it means that the parallel device uses the console */ |
158 | ParallelState *parallel_init(int base, int irq, CharDriverState *chr) | |
159 | { | |
160 | ParallelState *s; | |
e57a8c0e | 161 | uint8_t dummy; |
6508fe59 FB |
162 | |
163 | s = qemu_mallocz(sizeof(ParallelState)); | |
164 | if (!s) | |
165 | return NULL; | |
e57a8c0e FB |
166 | s->chr = chr; |
167 | s->hw_driver = 0; | |
168 | if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) | |
169 | s->hw_driver = 1; | |
170 | ||
6508fe59 FB |
171 | s->irq = irq; |
172 | s->data = 0; | |
173 | s->status = PARA_STS_BUSY; | |
174 | s->status |= PARA_STS_ACK; | |
175 | s->status |= PARA_STS_ONLINE; | |
176 | s->status |= PARA_STS_ERROR; | |
177 | s->control = PARA_CTR_SELECT; | |
178 | s->control |= PARA_CTR_INIT; | |
179 | ||
180 | register_ioport_write(base, 8, 1, parallel_ioport_write, s); | |
181 | register_ioport_read(base, 8, 1, parallel_ioport_read, s); | |
6508fe59 FB |
182 | return s; |
183 | } |