Commit 80cabfad16384ca47f783a7c494bd1c3c6e3c4bc
1 parent
38ca2abc
separated more devices from emulator
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@656 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
8 changed files
with
2677 additions
and
2 deletions
Too many changes to show.
To preserve performance only 8 of 10 files are displayed.
Makefile.target
1 | 1 | include config.mak |
2 | 2 | |
3 | 3 | TARGET_PATH=$(SRC_PATH)/target-$(TARGET_ARCH) |
4 | -VPATH=$(SRC_PATH):$(TARGET_PATH) | |
4 | +VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw | |
5 | 5 | CFLAGS=-Wall -O2 -g |
6 | 6 | LDFLAGS=-g |
7 | 7 | LIBS= |
... | ... | @@ -204,7 +204,8 @@ ifeq ($(ARCH),alpha) |
204 | 204 | endif |
205 | 205 | |
206 | 206 | # must use static linking to avoid leaving stuff in virtual address space |
207 | -VL_OBJS=vl.o block.o ide.o vga.o sb16.o dma.o oss.o fdc.o osdep.o | |
207 | +VL_OBJS=vl.o osdep.o block.o ide.o ne2000.o pckbd.o vga.o sb16.o dma.o oss.o \ | |
208 | + fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | |
208 | 209 | ifeq ($(TARGET_ARCH), ppc) |
209 | 210 | VL_OBJS+= hw.o |
210 | 211 | endif | ... | ... |
hw/i8254.c
0 → 100644
1 | +/* | |
2 | + * QEMU 8253/8254 interval timer emulation | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +#define RW_STATE_LSB 0 | |
47 | +#define RW_STATE_MSB 1 | |
48 | +#define RW_STATE_WORD0 2 | |
49 | +#define RW_STATE_WORD1 3 | |
50 | +#define RW_STATE_LATCHED_WORD0 4 | |
51 | +#define RW_STATE_LATCHED_WORD1 5 | |
52 | + | |
53 | +PITChannelState pit_channels[3]; | |
54 | + | |
55 | +static int pit_get_count(PITChannelState *s) | |
56 | +{ | |
57 | + uint64_t d; | |
58 | + int counter; | |
59 | + | |
60 | + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
61 | + switch(s->mode) { | |
62 | + case 0: | |
63 | + case 1: | |
64 | + case 4: | |
65 | + case 5: | |
66 | + counter = (s->count - d) & 0xffff; | |
67 | + break; | |
68 | + case 3: | |
69 | + /* XXX: may be incorrect for odd counts */ | |
70 | + counter = s->count - ((2 * d) % s->count); | |
71 | + break; | |
72 | + default: | |
73 | + counter = s->count - (d % s->count); | |
74 | + break; | |
75 | + } | |
76 | + return counter; | |
77 | +} | |
78 | + | |
79 | +/* get pit output bit */ | |
80 | +int pit_get_out(PITChannelState *s) | |
81 | +{ | |
82 | + uint64_t d; | |
83 | + int out; | |
84 | + | |
85 | + d = muldiv64(cpu_get_ticks() - s->count_load_time, PIT_FREQ, ticks_per_sec); | |
86 | + switch(s->mode) { | |
87 | + default: | |
88 | + case 0: | |
89 | + out = (d >= s->count); | |
90 | + break; | |
91 | + case 1: | |
92 | + out = (d < s->count); | |
93 | + break; | |
94 | + case 2: | |
95 | + if ((d % s->count) == 0 && d != 0) | |
96 | + out = 1; | |
97 | + else | |
98 | + out = 0; | |
99 | + break; | |
100 | + case 3: | |
101 | + out = (d % s->count) < ((s->count + 1) >> 1); | |
102 | + break; | |
103 | + case 4: | |
104 | + case 5: | |
105 | + out = (d == s->count); | |
106 | + break; | |
107 | + } | |
108 | + return out; | |
109 | +} | |
110 | + | |
111 | +/* get the number of 0 to 1 transitions we had since we call this | |
112 | + function */ | |
113 | +/* XXX: maybe better to use ticks precision to avoid getting edges | |
114 | + twice if checks are done at very small intervals */ | |
115 | +int pit_get_out_edges(PITChannelState *s) | |
116 | +{ | |
117 | + uint64_t d1, d2; | |
118 | + int64_t ticks; | |
119 | + int ret, v; | |
120 | + | |
121 | + ticks = cpu_get_ticks(); | |
122 | + d1 = muldiv64(s->count_last_edge_check_time - s->count_load_time, | |
123 | + PIT_FREQ, ticks_per_sec); | |
124 | + d2 = muldiv64(ticks - s->count_load_time, | |
125 | + PIT_FREQ, ticks_per_sec); | |
126 | + s->count_last_edge_check_time = ticks; | |
127 | + switch(s->mode) { | |
128 | + default: | |
129 | + case 0: | |
130 | + if (d1 < s->count && d2 >= s->count) | |
131 | + ret = 1; | |
132 | + else | |
133 | + ret = 0; | |
134 | + break; | |
135 | + case 1: | |
136 | + ret = 0; | |
137 | + break; | |
138 | + case 2: | |
139 | + d1 /= s->count; | |
140 | + d2 /= s->count; | |
141 | + ret = d2 - d1; | |
142 | + break; | |
143 | + case 3: | |
144 | + v = s->count - ((s->count + 1) >> 1); | |
145 | + d1 = (d1 + v) / s->count; | |
146 | + d2 = (d2 + v) / s->count; | |
147 | + ret = d2 - d1; | |
148 | + break; | |
149 | + case 4: | |
150 | + case 5: | |
151 | + if (d1 < s->count && d2 >= s->count) | |
152 | + ret = 1; | |
153 | + else | |
154 | + ret = 0; | |
155 | + break; | |
156 | + } | |
157 | + return ret; | |
158 | +} | |
159 | + | |
160 | +/* val must be 0 or 1 */ | |
161 | +void pit_set_gate(PITChannelState *s, int val) | |
162 | +{ | |
163 | + switch(s->mode) { | |
164 | + default: | |
165 | + case 0: | |
166 | + case 4: | |
167 | + /* XXX: just disable/enable counting */ | |
168 | + break; | |
169 | + case 1: | |
170 | + case 5: | |
171 | + if (s->gate < val) { | |
172 | + /* restart counting on rising edge */ | |
173 | + s->count_load_time = cpu_get_ticks(); | |
174 | + s->count_last_edge_check_time = s->count_load_time; | |
175 | + } | |
176 | + break; | |
177 | + case 2: | |
178 | + case 3: | |
179 | + if (s->gate < val) { | |
180 | + /* restart counting on rising edge */ | |
181 | + s->count_load_time = cpu_get_ticks(); | |
182 | + s->count_last_edge_check_time = s->count_load_time; | |
183 | + } | |
184 | + /* XXX: disable/enable counting */ | |
185 | + break; | |
186 | + } | |
187 | + s->gate = val; | |
188 | +} | |
189 | + | |
190 | +static inline void pit_load_count(PITChannelState *s, int val) | |
191 | +{ | |
192 | + if (val == 0) | |
193 | + val = 0x10000; | |
194 | + s->count_load_time = cpu_get_ticks(); | |
195 | + s->count_last_edge_check_time = s->count_load_time; | |
196 | + s->count = val; | |
197 | + if (s == &pit_channels[0] && val <= pit_min_timer_count) { | |
198 | + fprintf(stderr, | |
199 | + "\nWARNING: qemu: on your system, accurate timer emulation is impossible if its frequency is more than %d Hz. If using a 2.6 guest Linux kernel, you must patch asm/param.h to change HZ from 1000 to 100.\n\n", | |
200 | + PIT_FREQ / pit_min_timer_count); | |
201 | + } | |
202 | +} | |
203 | + | |
204 | +void pit_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
205 | +{ | |
206 | + int channel, access; | |
207 | + PITChannelState *s; | |
208 | + | |
209 | + addr &= 3; | |
210 | + if (addr == 3) { | |
211 | + channel = val >> 6; | |
212 | + if (channel == 3) | |
213 | + return; | |
214 | + s = &pit_channels[channel]; | |
215 | + access = (val >> 4) & 3; | |
216 | + switch(access) { | |
217 | + case 0: | |
218 | + s->latched_count = pit_get_count(s); | |
219 | + s->rw_state = RW_STATE_LATCHED_WORD0; | |
220 | + break; | |
221 | + default: | |
222 | + s->mode = (val >> 1) & 7; | |
223 | + s->bcd = val & 1; | |
224 | + s->rw_state = access - 1 + RW_STATE_LSB; | |
225 | + break; | |
226 | + } | |
227 | + } else { | |
228 | + s = &pit_channels[addr]; | |
229 | + switch(s->rw_state) { | |
230 | + case RW_STATE_LSB: | |
231 | + pit_load_count(s, val); | |
232 | + break; | |
233 | + case RW_STATE_MSB: | |
234 | + pit_load_count(s, val << 8); | |
235 | + break; | |
236 | + case RW_STATE_WORD0: | |
237 | + case RW_STATE_WORD1: | |
238 | + if (s->rw_state & 1) { | |
239 | + pit_load_count(s, (s->latched_count & 0xff) | (val << 8)); | |
240 | + } else { | |
241 | + s->latched_count = val; | |
242 | + } | |
243 | + s->rw_state ^= 1; | |
244 | + break; | |
245 | + } | |
246 | + } | |
247 | +} | |
248 | + | |
249 | +uint32_t pit_ioport_read(CPUState *env, uint32_t addr) | |
250 | +{ | |
251 | + int ret, count; | |
252 | + PITChannelState *s; | |
253 | + | |
254 | + addr &= 3; | |
255 | + s = &pit_channels[addr]; | |
256 | + switch(s->rw_state) { | |
257 | + case RW_STATE_LSB: | |
258 | + case RW_STATE_MSB: | |
259 | + case RW_STATE_WORD0: | |
260 | + case RW_STATE_WORD1: | |
261 | + count = pit_get_count(s); | |
262 | + if (s->rw_state & 1) | |
263 | + ret = (count >> 8) & 0xff; | |
264 | + else | |
265 | + ret = count & 0xff; | |
266 | + if (s->rw_state & 2) | |
267 | + s->rw_state ^= 1; | |
268 | + break; | |
269 | + default: | |
270 | + case RW_STATE_LATCHED_WORD0: | |
271 | + case RW_STATE_LATCHED_WORD1: | |
272 | + if (s->rw_state & 1) | |
273 | + ret = s->latched_count >> 8; | |
274 | + else | |
275 | + ret = s->latched_count & 0xff; | |
276 | + s->rw_state ^= 1; | |
277 | + break; | |
278 | + } | |
279 | + return ret; | |
280 | +} | |
281 | + | |
282 | +void pit_init(void) | |
283 | +{ | |
284 | + PITChannelState *s; | |
285 | + int i; | |
286 | + | |
287 | + for(i = 0;i < 3; i++) { | |
288 | + s = &pit_channels[i]; | |
289 | + s->mode = 3; | |
290 | + s->gate = (i != 2); | |
291 | + pit_load_count(s, 0); | |
292 | + } | |
293 | + | |
294 | + register_ioport_write(0x40, 4, pit_ioport_write, 1); | |
295 | + register_ioport_read(0x40, 3, pit_ioport_read, 1); | |
296 | +} | |
297 | + | ... | ... |
hw/i8259.c
0 → 100644
1 | +/* | |
2 | + * QEMU 8259 interrupt controller emulation | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +/* debug PIC */ | |
47 | +//#define DEBUG_PIC | |
48 | + | |
49 | +typedef struct PicState { | |
50 | + uint8_t last_irr; /* edge detection */ | |
51 | + uint8_t irr; /* interrupt request register */ | |
52 | + uint8_t imr; /* interrupt mask register */ | |
53 | + uint8_t isr; /* interrupt service register */ | |
54 | + uint8_t priority_add; /* highest irq priority */ | |
55 | + uint8_t irq_base; | |
56 | + uint8_t read_reg_select; | |
57 | + uint8_t poll; | |
58 | + uint8_t special_mask; | |
59 | + uint8_t init_state; | |
60 | + uint8_t auto_eoi; | |
61 | + uint8_t rotate_on_auto_eoi; | |
62 | + uint8_t special_fully_nested_mode; | |
63 | + uint8_t init4; /* true if 4 byte init */ | |
64 | +} PicState; | |
65 | + | |
66 | +/* 0 is master pic, 1 is slave pic */ | |
67 | +PicState pics[2]; | |
68 | +int pic_irq_requested; | |
69 | + | |
70 | +/* set irq level. If an edge is detected, then the IRR is set to 1 */ | |
71 | +static inline void pic_set_irq1(PicState *s, int irq, int level) | |
72 | +{ | |
73 | + int mask; | |
74 | + mask = 1 << irq; | |
75 | + if (level) { | |
76 | + if ((s->last_irr & mask) == 0) | |
77 | + s->irr |= mask; | |
78 | + s->last_irr |= mask; | |
79 | + } else { | |
80 | + s->last_irr &= ~mask; | |
81 | + } | |
82 | +} | |
83 | + | |
84 | +/* return the highest priority found in mask (highest = smallest | |
85 | + number). Return 8 if no irq */ | |
86 | +static inline int get_priority(PicState *s, int mask) | |
87 | +{ | |
88 | + int priority; | |
89 | + if (mask == 0) | |
90 | + return 8; | |
91 | + priority = 0; | |
92 | + while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0) | |
93 | + priority++; | |
94 | + return priority; | |
95 | +} | |
96 | + | |
97 | +/* return the pic wanted interrupt. return -1 if none */ | |
98 | +static int pic_get_irq(PicState *s) | |
99 | +{ | |
100 | + int mask, cur_priority, priority; | |
101 | + | |
102 | + mask = s->irr & ~s->imr; | |
103 | + priority = get_priority(s, mask); | |
104 | + if (priority == 8) | |
105 | + return -1; | |
106 | + /* compute current priority. If special fully nested mode on the | |
107 | + master, the IRQ coming from the slave is not taken into account | |
108 | + for the priority computation. */ | |
109 | + mask = s->isr; | |
110 | + if (s->special_fully_nested_mode && s == &pics[0]) | |
111 | + mask &= ~(1 << 2); | |
112 | + cur_priority = get_priority(s, mask); | |
113 | + if (priority < cur_priority) { | |
114 | + /* higher priority found: an irq should be generated */ | |
115 | + return (priority + s->priority_add) & 7; | |
116 | + } else { | |
117 | + return -1; | |
118 | + } | |
119 | +} | |
120 | + | |
121 | +/* raise irq to CPU if necessary. must be called every time the active | |
122 | + irq may change */ | |
123 | +void pic_update_irq(void) | |
124 | +{ | |
125 | + int irq2, irq; | |
126 | + | |
127 | + /* first look at slave pic */ | |
128 | + irq2 = pic_get_irq(&pics[1]); | |
129 | + if (irq2 >= 0) { | |
130 | + /* if irq request by slave pic, signal master PIC */ | |
131 | + pic_set_irq1(&pics[0], 2, 1); | |
132 | + pic_set_irq1(&pics[0], 2, 0); | |
133 | + } | |
134 | + /* look at requested irq */ | |
135 | + irq = pic_get_irq(&pics[0]); | |
136 | + if (irq >= 0) { | |
137 | + if (irq == 2) { | |
138 | + /* from slave pic */ | |
139 | + pic_irq_requested = 8 + irq2; | |
140 | + } else { | |
141 | + /* from master pic */ | |
142 | + pic_irq_requested = irq; | |
143 | + } | |
144 | +#if defined(DEBUG_PIC) | |
145 | + { | |
146 | + int i; | |
147 | + for(i = 0; i < 2; i++) { | |
148 | + printf("pic%d: imr=%x irr=%x padd=%d\n", | |
149 | + i, pics[i].imr, pics[i].irr, pics[i].priority_add); | |
150 | + | |
151 | + } | |
152 | + } | |
153 | + printf("pic: cpu_interrupt req=%d\n", pic_irq_requested); | |
154 | +#endif | |
155 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); | |
156 | + } | |
157 | +} | |
158 | + | |
159 | +#ifdef DEBUG_IRQ_LATENCY | |
160 | +int64_t irq_time[16]; | |
161 | +int64_t cpu_get_ticks(void); | |
162 | +#endif | |
163 | +#if defined(DEBUG_PIC) | |
164 | +int irq_level[16]; | |
165 | +#endif | |
166 | + | |
167 | +void pic_set_irq(int irq, int level) | |
168 | +{ | |
169 | +#if defined(DEBUG_PIC) | |
170 | + if (level != irq_level[irq]) { | |
171 | + printf("pic_set_irq: irq=%d level=%d\n", irq, level); | |
172 | + irq_level[irq] = level; | |
173 | + } | |
174 | +#endif | |
175 | +#ifdef DEBUG_IRQ_LATENCY | |
176 | + if (level) { | |
177 | + irq_time[irq] = cpu_get_ticks(); | |
178 | + } | |
179 | +#endif | |
180 | + pic_set_irq1(&pics[irq >> 3], irq & 7, level); | |
181 | + pic_update_irq(); | |
182 | +} | |
183 | + | |
184 | +/* acknowledge interrupt 'irq' */ | |
185 | +static inline void pic_intack(PicState *s, int irq) | |
186 | +{ | |
187 | + if (s->auto_eoi) { | |
188 | + if (s->rotate_on_auto_eoi) | |
189 | + s->priority_add = (irq + 1) & 7; | |
190 | + } else { | |
191 | + s->isr |= (1 << irq); | |
192 | + } | |
193 | + s->irr &= ~(1 << irq); | |
194 | +} | |
195 | + | |
196 | +int cpu_x86_get_pic_interrupt(CPUState *env) | |
197 | +{ | |
198 | + int irq, irq2, intno; | |
199 | + | |
200 | + /* signal the pic that the irq was acked by the CPU */ | |
201 | + irq = pic_irq_requested; | |
202 | +#ifdef DEBUG_IRQ_LATENCY | |
203 | + printf("IRQ%d latency=%0.3fus\n", | |
204 | + irq, | |
205 | + (double)(cpu_get_ticks() - irq_time[irq]) * 1000000.0 / ticks_per_sec); | |
206 | +#endif | |
207 | +#if defined(DEBUG_PIC) | |
208 | + printf("pic_interrupt: irq=%d\n", irq); | |
209 | +#endif | |
210 | + | |
211 | + if (irq >= 8) { | |
212 | + irq2 = irq & 7; | |
213 | + pic_intack(&pics[1], irq2); | |
214 | + irq = 2; | |
215 | + intno = pics[1].irq_base + irq2; | |
216 | + } else { | |
217 | + intno = pics[0].irq_base + irq; | |
218 | + } | |
219 | + pic_intack(&pics[0], irq); | |
220 | + return intno; | |
221 | +} | |
222 | + | |
223 | +void pic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
224 | +{ | |
225 | + PicState *s; | |
226 | + int priority, cmd, irq; | |
227 | + | |
228 | +#ifdef DEBUG_PIC | |
229 | + printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val); | |
230 | +#endif | |
231 | + s = &pics[addr >> 7]; | |
232 | + addr &= 1; | |
233 | + if (addr == 0) { | |
234 | + if (val & 0x10) { | |
235 | + /* init */ | |
236 | + memset(s, 0, sizeof(PicState)); | |
237 | + s->init_state = 1; | |
238 | + s->init4 = val & 1; | |
239 | + if (val & 0x02) | |
240 | + hw_error("single mode not supported"); | |
241 | + if (val & 0x08) | |
242 | + hw_error("level sensitive irq not supported"); | |
243 | + } else if (val & 0x08) { | |
244 | + if (val & 0x04) | |
245 | + s->poll = 1; | |
246 | + if (val & 0x02) | |
247 | + s->read_reg_select = val & 1; | |
248 | + if (val & 0x40) | |
249 | + s->special_mask = (val >> 5) & 1; | |
250 | + } else { | |
251 | + cmd = val >> 5; | |
252 | + switch(cmd) { | |
253 | + case 0: | |
254 | + case 4: | |
255 | + s->rotate_on_auto_eoi = cmd >> 2; | |
256 | + break; | |
257 | + case 1: /* end of interrupt */ | |
258 | + case 5: | |
259 | + priority = get_priority(s, s->isr); | |
260 | + if (priority != 8) { | |
261 | + irq = (priority + s->priority_add) & 7; | |
262 | + s->isr &= ~(1 << irq); | |
263 | + if (cmd == 5) | |
264 | + s->priority_add = (irq + 1) & 7; | |
265 | + pic_update_irq(); | |
266 | + } | |
267 | + break; | |
268 | + case 3: | |
269 | + irq = val & 7; | |
270 | + s->isr &= ~(1 << irq); | |
271 | + pic_update_irq(); | |
272 | + break; | |
273 | + case 6: | |
274 | + s->priority_add = (val + 1) & 7; | |
275 | + pic_update_irq(); | |
276 | + break; | |
277 | + case 7: | |
278 | + irq = val & 7; | |
279 | + s->isr &= ~(1 << irq); | |
280 | + s->priority_add = (irq + 1) & 7; | |
281 | + pic_update_irq(); | |
282 | + break; | |
283 | + default: | |
284 | + /* no operation */ | |
285 | + break; | |
286 | + } | |
287 | + } | |
288 | + } else { | |
289 | + switch(s->init_state) { | |
290 | + case 0: | |
291 | + /* normal mode */ | |
292 | + s->imr = val; | |
293 | + pic_update_irq(); | |
294 | + break; | |
295 | + case 1: | |
296 | + s->irq_base = val & 0xf8; | |
297 | + s->init_state = 2; | |
298 | + break; | |
299 | + case 2: | |
300 | + if (s->init4) { | |
301 | + s->init_state = 3; | |
302 | + } else { | |
303 | + s->init_state = 0; | |
304 | + } | |
305 | + break; | |
306 | + case 3: | |
307 | + s->special_fully_nested_mode = (val >> 4) & 1; | |
308 | + s->auto_eoi = (val >> 1) & 1; | |
309 | + s->init_state = 0; | |
310 | + break; | |
311 | + } | |
312 | + } | |
313 | +} | |
314 | + | |
315 | +static uint32_t pic_poll_read (PicState *s, uint32_t addr1) | |
316 | +{ | |
317 | + int ret; | |
318 | + | |
319 | + ret = pic_get_irq(s); | |
320 | + if (ret >= 0) { | |
321 | + if (addr1 >> 7) { | |
322 | + pics[0].isr &= ~(1 << 2); | |
323 | + pics[0].irr &= ~(1 << 2); | |
324 | + } | |
325 | + s->irr &= ~(1 << ret); | |
326 | + s->isr &= ~(1 << ret); | |
327 | + if (addr1 >> 7 || ret != 2) | |
328 | + pic_update_irq(); | |
329 | + } else { | |
330 | + ret = 0x07; | |
331 | + pic_update_irq(); | |
332 | + } | |
333 | + | |
334 | + return ret; | |
335 | +} | |
336 | + | |
337 | +uint32_t pic_ioport_read(CPUState *env, uint32_t addr1) | |
338 | +{ | |
339 | + PicState *s; | |
340 | + unsigned int addr; | |
341 | + int ret; | |
342 | + | |
343 | + addr = addr1; | |
344 | + s = &pics[addr >> 7]; | |
345 | + addr &= 1; | |
346 | + if (s->poll) { | |
347 | + ret = pic_poll_read(s, addr1); | |
348 | + s->poll = 0; | |
349 | + } else { | |
350 | + if (addr == 0) { | |
351 | + if (s->read_reg_select) | |
352 | + ret = s->isr; | |
353 | + else | |
354 | + ret = s->irr; | |
355 | + } else { | |
356 | + ret = s->imr; | |
357 | + } | |
358 | + } | |
359 | +#ifdef DEBUG_PIC | |
360 | + printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret); | |
361 | +#endif | |
362 | + return ret; | |
363 | +} | |
364 | + | |
365 | +/* memory mapped interrupt status */ | |
366 | +uint32_t pic_intack_read(CPUState *env) | |
367 | +{ | |
368 | + int ret; | |
369 | + | |
370 | + ret = pic_poll_read(&pics[0], 0x00); | |
371 | + if (ret == 2) | |
372 | + ret = pic_poll_read(&pics[1], 0x80) + 8; | |
373 | + /* Prepare for ISR read */ | |
374 | + pics[0].read_reg_select = 1; | |
375 | + | |
376 | + return ret; | |
377 | +} | |
378 | + | |
379 | +void pic_init(void) | |
380 | +{ | |
381 | +#if defined (TARGET_I386) || defined (TARGET_PPC) | |
382 | + register_ioport_write(0x20, 2, pic_ioport_write, 1); | |
383 | + register_ioport_read(0x20, 2, pic_ioport_read, 1); | |
384 | + register_ioport_write(0xa0, 2, pic_ioport_write, 1); | |
385 | + register_ioport_read(0xa0, 2, pic_ioport_read, 1); | |
386 | +#endif | |
387 | +} | |
388 | + | ... | ... |
hw/mc146818rtc.c
0 → 100644
1 | +/* | |
2 | + * QEMU MC146818 RTC emulation | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +//#define DEBUG_CMOS | |
47 | + | |
48 | +#define RTC_SECONDS 0 | |
49 | +#define RTC_SECONDS_ALARM 1 | |
50 | +#define RTC_MINUTES 2 | |
51 | +#define RTC_MINUTES_ALARM 3 | |
52 | +#define RTC_HOURS 4 | |
53 | +#define RTC_HOURS_ALARM 5 | |
54 | +#define RTC_ALARM_DONT_CARE 0xC0 | |
55 | + | |
56 | +#define RTC_DAY_OF_WEEK 6 | |
57 | +#define RTC_DAY_OF_MONTH 7 | |
58 | +#define RTC_MONTH 8 | |
59 | +#define RTC_YEAR 9 | |
60 | + | |
61 | +#define RTC_REG_A 10 | |
62 | +#define RTC_REG_B 11 | |
63 | +#define RTC_REG_C 12 | |
64 | +#define RTC_REG_D 13 | |
65 | + | |
66 | +/* PC cmos mappings */ | |
67 | +#define REG_IBM_CENTURY_BYTE 0x32 | |
68 | +#define REG_IBM_PS2_CENTURY_BYTE 0x37 | |
69 | + | |
70 | +RTCState rtc_state; | |
71 | + | |
72 | +static void cmos_ioport_write(CPUState *env, uint32_t addr, uint32_t data) | |
73 | +{ | |
74 | + RTCState *s = &rtc_state; | |
75 | + | |
76 | + if ((addr & 1) == 0) { | |
77 | + s->cmos_index = data & 0x7f; | |
78 | + } else { | |
79 | +#ifdef DEBUG_CMOS | |
80 | + printf("cmos: write index=0x%02x val=0x%02x\n", | |
81 | + s->cmos_index, data); | |
82 | +#endif | |
83 | + switch(addr) { | |
84 | + case RTC_SECONDS_ALARM: | |
85 | + case RTC_MINUTES_ALARM: | |
86 | + case RTC_HOURS_ALARM: | |
87 | + /* XXX: not supported */ | |
88 | + s->cmos_data[s->cmos_index] = data; | |
89 | + break; | |
90 | + case RTC_SECONDS: | |
91 | + case RTC_MINUTES: | |
92 | + case RTC_HOURS: | |
93 | + case RTC_DAY_OF_WEEK: | |
94 | + case RTC_DAY_OF_MONTH: | |
95 | + case RTC_MONTH: | |
96 | + case RTC_YEAR: | |
97 | + s->cmos_data[s->cmos_index] = data; | |
98 | + break; | |
99 | + case RTC_REG_A: | |
100 | + case RTC_REG_B: | |
101 | + s->cmos_data[s->cmos_index] = data; | |
102 | + break; | |
103 | + case RTC_REG_C: | |
104 | + case RTC_REG_D: | |
105 | + /* cannot write to them */ | |
106 | + break; | |
107 | + default: | |
108 | + s->cmos_data[s->cmos_index] = data; | |
109 | + break; | |
110 | + } | |
111 | + } | |
112 | +} | |
113 | + | |
114 | +static inline int to_bcd(int a) | |
115 | +{ | |
116 | + return ((a / 10) << 4) | (a % 10); | |
117 | +} | |
118 | + | |
119 | +static void cmos_update_time(RTCState *s) | |
120 | +{ | |
121 | + struct tm *tm; | |
122 | + time_t ti; | |
123 | + | |
124 | + ti = time(NULL); | |
125 | + tm = gmtime(&ti); | |
126 | + s->cmos_data[RTC_SECONDS] = to_bcd(tm->tm_sec); | |
127 | + s->cmos_data[RTC_MINUTES] = to_bcd(tm->tm_min); | |
128 | + s->cmos_data[RTC_HOURS] = to_bcd(tm->tm_hour); | |
129 | + s->cmos_data[RTC_DAY_OF_WEEK] = to_bcd(tm->tm_wday); | |
130 | + s->cmos_data[RTC_DAY_OF_MONTH] = to_bcd(tm->tm_mday); | |
131 | + s->cmos_data[RTC_MONTH] = to_bcd(tm->tm_mon + 1); | |
132 | + s->cmos_data[RTC_YEAR] = to_bcd(tm->tm_year % 100); | |
133 | + s->cmos_data[REG_IBM_CENTURY_BYTE] = to_bcd((tm->tm_year / 100) + 19); | |
134 | + s->cmos_data[REG_IBM_PS2_CENTURY_BYTE] = s->cmos_data[REG_IBM_CENTURY_BYTE]; | |
135 | +} | |
136 | + | |
137 | +static uint32_t cmos_ioport_read(CPUState *env, uint32_t addr) | |
138 | +{ | |
139 | + RTCState *s = &rtc_state; | |
140 | + int ret; | |
141 | + if ((addr & 1) == 0) { | |
142 | + return 0xff; | |
143 | + } else { | |
144 | + switch(s->cmos_index) { | |
145 | + case RTC_SECONDS: | |
146 | + case RTC_MINUTES: | |
147 | + case RTC_HOURS: | |
148 | + case RTC_DAY_OF_WEEK: | |
149 | + case RTC_DAY_OF_MONTH: | |
150 | + case RTC_MONTH: | |
151 | + case RTC_YEAR: | |
152 | + case REG_IBM_CENTURY_BYTE: | |
153 | + case REG_IBM_PS2_CENTURY_BYTE: | |
154 | + cmos_update_time(s); | |
155 | + ret = s->cmos_data[s->cmos_index]; | |
156 | + break; | |
157 | + case RTC_REG_A: | |
158 | + ret = s->cmos_data[s->cmos_index]; | |
159 | + /* toggle update-in-progress bit for Linux (same hack as | |
160 | + plex86) */ | |
161 | + s->cmos_data[RTC_REG_A] ^= 0x80; | |
162 | + break; | |
163 | + case RTC_REG_C: | |
164 | + ret = s->cmos_data[s->cmos_index]; | |
165 | + pic_set_irq(s->irq, 0); | |
166 | + s->cmos_data[RTC_REG_C] = 0x00; | |
167 | + break; | |
168 | + default: | |
169 | + ret = s->cmos_data[s->cmos_index]; | |
170 | + break; | |
171 | + } | |
172 | +#ifdef DEBUG_CMOS | |
173 | + printf("cmos: read index=0x%02x val=0x%02x\n", | |
174 | + s->cmos_index, ret); | |
175 | +#endif | |
176 | + return ret; | |
177 | + } | |
178 | +} | |
179 | + | |
180 | +void rtc_timer(void) | |
181 | +{ | |
182 | + RTCState *s = &rtc_state; | |
183 | + if (s->cmos_data[RTC_REG_B] & 0x50) { | |
184 | + pic_set_irq(s->irq, 1); | |
185 | + } | |
186 | +} | |
187 | + | |
188 | +void rtc_init(int base, int irq) | |
189 | +{ | |
190 | + RTCState *s = &rtc_state; | |
191 | + | |
192 | + cmos_update_time(s); | |
193 | + | |
194 | + s->irq = irq; | |
195 | + s->cmos_data[RTC_REG_A] = 0x26; | |
196 | + s->cmos_data[RTC_REG_B] = 0x02; | |
197 | + s->cmos_data[RTC_REG_C] = 0x00; | |
198 | + s->cmos_data[RTC_REG_D] = 0x80; | |
199 | + | |
200 | + register_ioport_write(base, 2, cmos_ioport_write, 1); | |
201 | + register_ioport_read(base, 2, cmos_ioport_read, 1); | |
202 | +} | |
203 | + | ... | ... |
hw/ne2000.c
0 → 100644
1 | +/* | |
2 | + * QEMU NE2000 emulation | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +/* debug NE2000 card */ | |
47 | +//#define DEBUG_NE2000 | |
48 | + | |
49 | +/***********************************************************/ | |
50 | +/* ne2000 emulation */ | |
51 | + | |
52 | +#define E8390_CMD 0x00 /* The command register (for all pages) */ | |
53 | +/* Page 0 register offsets. */ | |
54 | +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ | |
55 | +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ | |
56 | +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ | |
57 | +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ | |
58 | +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ | |
59 | +#define EN0_TSR 0x04 /* Transmit status reg RD */ | |
60 | +#define EN0_TPSR 0x04 /* Transmit starting page WR */ | |
61 | +#define EN0_NCR 0x05 /* Number of collision reg RD */ | |
62 | +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ | |
63 | +#define EN0_FIFO 0x06 /* FIFO RD */ | |
64 | +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ | |
65 | +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ | |
66 | +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ | |
67 | +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ | |
68 | +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ | |
69 | +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ | |
70 | +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ | |
71 | +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ | |
72 | +#define EN0_RSR 0x0c /* rx status reg RD */ | |
73 | +#define EN0_RXCR 0x0c /* RX configuration reg WR */ | |
74 | +#define EN0_TXCR 0x0d /* TX configuration reg WR */ | |
75 | +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ | |
76 | +#define EN0_DCFG 0x0e /* Data configuration reg WR */ | |
77 | +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ | |
78 | +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ | |
79 | +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ | |
80 | + | |
81 | +#define EN1_PHYS 0x11 | |
82 | +#define EN1_CURPAG 0x17 | |
83 | +#define EN1_MULT 0x18 | |
84 | + | |
85 | +/* Register accessed at EN_CMD, the 8390 base addr. */ | |
86 | +#define E8390_STOP 0x01 /* Stop and reset the chip */ | |
87 | +#define E8390_START 0x02 /* Start the chip, clear reset */ | |
88 | +#define E8390_TRANS 0x04 /* Transmit a frame */ | |
89 | +#define E8390_RREAD 0x08 /* Remote read */ | |
90 | +#define E8390_RWRITE 0x10 /* Remote write */ | |
91 | +#define E8390_NODMA 0x20 /* Remote DMA */ | |
92 | +#define E8390_PAGE0 0x00 /* Select page chip registers */ | |
93 | +#define E8390_PAGE1 0x40 /* using the two high-order bits */ | |
94 | +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ | |
95 | + | |
96 | +/* Bits in EN0_ISR - Interrupt status register */ | |
97 | +#define ENISR_RX 0x01 /* Receiver, no error */ | |
98 | +#define ENISR_TX 0x02 /* Transmitter, no error */ | |
99 | +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ | |
100 | +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ | |
101 | +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ | |
102 | +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ | |
103 | +#define ENISR_RDC 0x40 /* remote dma complete */ | |
104 | +#define ENISR_RESET 0x80 /* Reset completed */ | |
105 | +#define ENISR_ALL 0x3f /* Interrupts we will enable */ | |
106 | + | |
107 | +/* Bits in received packet status byte and EN0_RSR*/ | |
108 | +#define ENRSR_RXOK 0x01 /* Received a good packet */ | |
109 | +#define ENRSR_CRC 0x02 /* CRC error */ | |
110 | +#define ENRSR_FAE 0x04 /* frame alignment error */ | |
111 | +#define ENRSR_FO 0x08 /* FIFO overrun */ | |
112 | +#define ENRSR_MPA 0x10 /* missed pkt */ | |
113 | +#define ENRSR_PHY 0x20 /* physical/multicast address */ | |
114 | +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ | |
115 | +#define ENRSR_DEF 0x80 /* deferring */ | |
116 | + | |
117 | +/* Transmitted packet status, EN0_TSR. */ | |
118 | +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ | |
119 | +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ | |
120 | +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ | |
121 | +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ | |
122 | +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ | |
123 | +#define ENTSR_FU 0x20 /* A "FIFO underrun" occurred during transmit. */ | |
124 | +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ | |
125 | +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ | |
126 | + | |
127 | +#define NE2000_MEM_SIZE 32768 | |
128 | + | |
129 | +typedef struct NE2000State { | |
130 | + uint8_t cmd; | |
131 | + uint32_t start; | |
132 | + uint32_t stop; | |
133 | + uint8_t boundary; | |
134 | + uint8_t tsr; | |
135 | + uint8_t tpsr; | |
136 | + uint16_t tcnt; | |
137 | + uint16_t rcnt; | |
138 | + uint32_t rsar; | |
139 | + uint8_t isr; | |
140 | + uint8_t dcfg; | |
141 | + uint8_t imr; | |
142 | + uint8_t phys[6]; /* mac address */ | |
143 | + uint8_t curpag; | |
144 | + uint8_t mult[8]; /* multicast mask array */ | |
145 | + int irq; | |
146 | + uint8_t mem[NE2000_MEM_SIZE]; | |
147 | +} NE2000State; | |
148 | + | |
149 | +static NE2000State ne2000_state; | |
150 | +int net_fd = -1; | |
151 | + | |
152 | +static void ne2000_reset(NE2000State *s) | |
153 | +{ | |
154 | + int i; | |
155 | + | |
156 | + s->isr = ENISR_RESET; | |
157 | + s->mem[0] = 0x52; | |
158 | + s->mem[1] = 0x54; | |
159 | + s->mem[2] = 0x00; | |
160 | + s->mem[3] = 0x12; | |
161 | + s->mem[4] = 0x34; | |
162 | + s->mem[5] = 0x56; | |
163 | + s->mem[14] = 0x57; | |
164 | + s->mem[15] = 0x57; | |
165 | + | |
166 | + /* duplicate prom data */ | |
167 | + for(i = 15;i >= 0; i--) { | |
168 | + s->mem[2 * i] = s->mem[i]; | |
169 | + s->mem[2 * i + 1] = s->mem[i]; | |
170 | + } | |
171 | +} | |
172 | + | |
173 | +static void ne2000_update_irq(NE2000State *s) | |
174 | +{ | |
175 | + int isr; | |
176 | + isr = s->isr & s->imr; | |
177 | + if (isr) | |
178 | + pic_set_irq(s->irq, 1); | |
179 | + else | |
180 | + pic_set_irq(s->irq, 0); | |
181 | +} | |
182 | + | |
183 | +/* return true if the NE2000 can receive more data */ | |
184 | +int ne2000_can_receive(void) | |
185 | +{ | |
186 | + NE2000State *s = &ne2000_state; | |
187 | + int avail, index, boundary; | |
188 | + | |
189 | + if (s->cmd & E8390_STOP) | |
190 | + return 0; | |
191 | + index = s->curpag << 8; | |
192 | + boundary = s->boundary << 8; | |
193 | + if (index < boundary) | |
194 | + avail = boundary - index; | |
195 | + else | |
196 | + avail = (s->stop - s->start) - (index - boundary); | |
197 | + if (avail < (MAX_ETH_FRAME_SIZE + 4)) | |
198 | + return 0; | |
199 | + return 1; | |
200 | +} | |
201 | + | |
202 | +void ne2000_receive(uint8_t *buf, int size) | |
203 | +{ | |
204 | + NE2000State *s = &ne2000_state; | |
205 | + uint8_t *p; | |
206 | + int total_len, next, avail, len, index; | |
207 | + | |
208 | +#if defined(DEBUG_NE2000) | |
209 | + printf("NE2000: received len=%d\n", size); | |
210 | +#endif | |
211 | + | |
212 | + index = s->curpag << 8; | |
213 | + /* 4 bytes for header */ | |
214 | + total_len = size + 4; | |
215 | + /* address for next packet (4 bytes for CRC) */ | |
216 | + next = index + ((total_len + 4 + 255) & ~0xff); | |
217 | + if (next >= s->stop) | |
218 | + next -= (s->stop - s->start); | |
219 | + /* prepare packet header */ | |
220 | + p = s->mem + index; | |
221 | + p[0] = ENRSR_RXOK; /* receive status */ | |
222 | + p[1] = next >> 8; | |
223 | + p[2] = total_len; | |
224 | + p[3] = total_len >> 8; | |
225 | + index += 4; | |
226 | + | |
227 | + /* write packet data */ | |
228 | + while (size > 0) { | |
229 | + avail = s->stop - index; | |
230 | + len = size; | |
231 | + if (len > avail) | |
232 | + len = avail; | |
233 | + memcpy(s->mem + index, buf, len); | |
234 | + buf += len; | |
235 | + index += len; | |
236 | + if (index == s->stop) | |
237 | + index = s->start; | |
238 | + size -= len; | |
239 | + } | |
240 | + s->curpag = next >> 8; | |
241 | + | |
242 | + /* now we can signal we have receive something */ | |
243 | + s->isr |= ENISR_RX; | |
244 | + ne2000_update_irq(s); | |
245 | +} | |
246 | + | |
247 | +static void ne2000_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
248 | +{ | |
249 | + NE2000State *s = &ne2000_state; | |
250 | + int offset, page; | |
251 | + | |
252 | + addr &= 0xf; | |
253 | +#ifdef DEBUG_NE2000 | |
254 | + printf("NE2000: write addr=0x%x val=0x%02x\n", addr, val); | |
255 | +#endif | |
256 | + if (addr == E8390_CMD) { | |
257 | + /* control register */ | |
258 | + s->cmd = val; | |
259 | + if (val & E8390_START) { | |
260 | + /* test specific case: zero length transfert */ | |
261 | + if ((val & (E8390_RREAD | E8390_RWRITE)) && | |
262 | + s->rcnt == 0) { | |
263 | + s->isr |= ENISR_RDC; | |
264 | + ne2000_update_irq(s); | |
265 | + } | |
266 | + if (val & E8390_TRANS) { | |
267 | + net_send_packet(net_fd, s->mem + (s->tpsr << 8), s->tcnt); | |
268 | + /* signal end of transfert */ | |
269 | + s->tsr = ENTSR_PTX; | |
270 | + s->isr |= ENISR_TX; | |
271 | + ne2000_update_irq(s); | |
272 | + } | |
273 | + } | |
274 | + } else { | |
275 | + page = s->cmd >> 6; | |
276 | + offset = addr | (page << 4); | |
277 | + switch(offset) { | |
278 | + case EN0_STARTPG: | |
279 | + s->start = val << 8; | |
280 | + break; | |
281 | + case EN0_STOPPG: | |
282 | + s->stop = val << 8; | |
283 | + break; | |
284 | + case EN0_BOUNDARY: | |
285 | + s->boundary = val; | |
286 | + break; | |
287 | + case EN0_IMR: | |
288 | + s->imr = val; | |
289 | + ne2000_update_irq(s); | |
290 | + break; | |
291 | + case EN0_TPSR: | |
292 | + s->tpsr = val; | |
293 | + break; | |
294 | + case EN0_TCNTLO: | |
295 | + s->tcnt = (s->tcnt & 0xff00) | val; | |
296 | + break; | |
297 | + case EN0_TCNTHI: | |
298 | + s->tcnt = (s->tcnt & 0x00ff) | (val << 8); | |
299 | + break; | |
300 | + case EN0_RSARLO: | |
301 | + s->rsar = (s->rsar & 0xff00) | val; | |
302 | + break; | |
303 | + case EN0_RSARHI: | |
304 | + s->rsar = (s->rsar & 0x00ff) | (val << 8); | |
305 | + break; | |
306 | + case EN0_RCNTLO: | |
307 | + s->rcnt = (s->rcnt & 0xff00) | val; | |
308 | + break; | |
309 | + case EN0_RCNTHI: | |
310 | + s->rcnt = (s->rcnt & 0x00ff) | (val << 8); | |
311 | + break; | |
312 | + case EN0_DCFG: | |
313 | + s->dcfg = val; | |
314 | + break; | |
315 | + case EN0_ISR: | |
316 | + s->isr &= ~val; | |
317 | + ne2000_update_irq(s); | |
318 | + break; | |
319 | + case EN1_PHYS ... EN1_PHYS + 5: | |
320 | + s->phys[offset - EN1_PHYS] = val; | |
321 | + break; | |
322 | + case EN1_CURPAG: | |
323 | + s->curpag = val; | |
324 | + break; | |
325 | + case EN1_MULT ... EN1_MULT + 7: | |
326 | + s->mult[offset - EN1_MULT] = val; | |
327 | + break; | |
328 | + } | |
329 | + } | |
330 | +} | |
331 | + | |
332 | +static uint32_t ne2000_ioport_read(CPUState *env, uint32_t addr) | |
333 | +{ | |
334 | + NE2000State *s = &ne2000_state; | |
335 | + int offset, page, ret; | |
336 | + | |
337 | + addr &= 0xf; | |
338 | + if (addr == E8390_CMD) { | |
339 | + ret = s->cmd; | |
340 | + } else { | |
341 | + page = s->cmd >> 6; | |
342 | + offset = addr | (page << 4); | |
343 | + switch(offset) { | |
344 | + case EN0_TSR: | |
345 | + ret = s->tsr; | |
346 | + break; | |
347 | + case EN0_BOUNDARY: | |
348 | + ret = s->boundary; | |
349 | + break; | |
350 | + case EN0_ISR: | |
351 | + ret = s->isr; | |
352 | + break; | |
353 | + case EN1_PHYS ... EN1_PHYS + 5: | |
354 | + ret = s->phys[offset - EN1_PHYS]; | |
355 | + break; | |
356 | + case EN1_CURPAG: | |
357 | + ret = s->curpag; | |
358 | + break; | |
359 | + case EN1_MULT ... EN1_MULT + 7: | |
360 | + ret = s->mult[offset - EN1_MULT]; | |
361 | + break; | |
362 | + default: | |
363 | + ret = 0x00; | |
364 | + break; | |
365 | + } | |
366 | + } | |
367 | +#ifdef DEBUG_NE2000 | |
368 | + printf("NE2000: read addr=0x%x val=%02x\n", addr, ret); | |
369 | +#endif | |
370 | + return ret; | |
371 | +} | |
372 | + | |
373 | +static void ne2000_asic_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
374 | +{ | |
375 | + NE2000State *s = &ne2000_state; | |
376 | + uint8_t *p; | |
377 | + | |
378 | +#ifdef DEBUG_NE2000 | |
379 | + printf("NE2000: asic write val=0x%04x\n", val); | |
380 | +#endif | |
381 | + p = s->mem + s->rsar; | |
382 | + if (s->dcfg & 0x01) { | |
383 | + /* 16 bit access */ | |
384 | + p[0] = val; | |
385 | + p[1] = val >> 8; | |
386 | + s->rsar += 2; | |
387 | + s->rcnt -= 2; | |
388 | + } else { | |
389 | + /* 8 bit access */ | |
390 | + p[0] = val; | |
391 | + s->rsar++; | |
392 | + s->rcnt--; | |
393 | + } | |
394 | + /* wrap */ | |
395 | + if (s->rsar == s->stop) | |
396 | + s->rsar = s->start; | |
397 | + if (s->rcnt == 0) { | |
398 | + /* signal end of transfert */ | |
399 | + s->isr |= ENISR_RDC; | |
400 | + ne2000_update_irq(s); | |
401 | + } | |
402 | +} | |
403 | + | |
404 | +static uint32_t ne2000_asic_ioport_read(CPUState *env, uint32_t addr) | |
405 | +{ | |
406 | + NE2000State *s = &ne2000_state; | |
407 | + uint8_t *p; | |
408 | + int ret; | |
409 | + | |
410 | + p = s->mem + s->rsar; | |
411 | + if (s->dcfg & 0x01) { | |
412 | + /* 16 bit access */ | |
413 | + ret = p[0] | (p[1] << 8); | |
414 | + s->rsar += 2; | |
415 | + s->rcnt -= 2; | |
416 | + } else { | |
417 | + /* 8 bit access */ | |
418 | + ret = p[0]; | |
419 | + s->rsar++; | |
420 | + s->rcnt--; | |
421 | + } | |
422 | + /* wrap */ | |
423 | + if (s->rsar == s->stop) | |
424 | + s->rsar = s->start; | |
425 | + if (s->rcnt == 0) { | |
426 | + /* signal end of transfert */ | |
427 | + s->isr |= ENISR_RDC; | |
428 | + ne2000_update_irq(s); | |
429 | + } | |
430 | +#ifdef DEBUG_NE2000 | |
431 | + printf("NE2000: asic read val=0x%04x\n", ret); | |
432 | +#endif | |
433 | + return ret; | |
434 | +} | |
435 | + | |
436 | +static void ne2000_reset_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
437 | +{ | |
438 | + /* nothing to do (end of reset pulse) */ | |
439 | +} | |
440 | + | |
441 | +static uint32_t ne2000_reset_ioport_read(CPUState *env, uint32_t addr) | |
442 | +{ | |
443 | + NE2000State *s = &ne2000_state; | |
444 | + ne2000_reset(s); | |
445 | + return 0; | |
446 | +} | |
447 | + | |
448 | +void ne2000_init(int base, int irq) | |
449 | +{ | |
450 | + NE2000State *s = &ne2000_state; | |
451 | + | |
452 | + register_ioport_write(base, 16, ne2000_ioport_write, 1); | |
453 | + register_ioport_read(base, 16, ne2000_ioport_read, 1); | |
454 | + | |
455 | + register_ioport_write(base + 0x10, 1, ne2000_asic_ioport_write, 1); | |
456 | + register_ioport_read(base + 0x10, 1, ne2000_asic_ioport_read, 1); | |
457 | + register_ioport_write(base + 0x10, 2, ne2000_asic_ioport_write, 2); | |
458 | + register_ioport_read(base + 0x10, 2, ne2000_asic_ioport_read, 2); | |
459 | + | |
460 | + register_ioport_write(base + 0x1f, 1, ne2000_reset_ioport_write, 1); | |
461 | + register_ioport_read(base + 0x1f, 1, ne2000_reset_ioport_read, 1); | |
462 | + s->irq = irq; | |
463 | + | |
464 | + ne2000_reset(s); | |
465 | +} | ... | ... |
hw/pc.c
0 → 100644
1 | +/* | |
2 | + * QEMU PC System Emulator | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +#define BIOS_FILENAME "bios.bin" | |
47 | +#define VGABIOS_FILENAME "vgabios.bin" | |
48 | +#define LINUX_BOOT_FILENAME "linux_boot.bin" | |
49 | + | |
50 | +#define KERNEL_LOAD_ADDR 0x00100000 | |
51 | +#define INITRD_LOAD_ADDR 0x00400000 | |
52 | +#define KERNEL_PARAMS_ADDR 0x00090000 | |
53 | +#define KERNEL_CMDLINE_ADDR 0x00099000 | |
54 | + | |
55 | +int speaker_data_on; | |
56 | +int dummy_refresh_clock; | |
57 | + | |
58 | +static void ioport80_write(CPUState *env, uint32_t addr, uint32_t data) | |
59 | +{ | |
60 | +} | |
61 | + | |
62 | +#define REG_EQUIPMENT_BYTE 0x14 | |
63 | + | |
64 | +static void cmos_init(int ram_size, int boot_device) | |
65 | +{ | |
66 | + RTCState *s = &rtc_state; | |
67 | + int val; | |
68 | + | |
69 | + /* various important CMOS locations needed by PC/Bochs bios */ | |
70 | + | |
71 | + s->cmos_data[REG_EQUIPMENT_BYTE] = 0x02; /* FPU is there */ | |
72 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x04; /* PS/2 mouse installed */ | |
73 | + | |
74 | + /* memory size */ | |
75 | + val = (ram_size / 1024) - 1024; | |
76 | + if (val > 65535) | |
77 | + val = 65535; | |
78 | + s->cmos_data[0x17] = val; | |
79 | + s->cmos_data[0x18] = val >> 8; | |
80 | + s->cmos_data[0x30] = val; | |
81 | + s->cmos_data[0x31] = val >> 8; | |
82 | + | |
83 | + val = (ram_size / 65536) - ((16 * 1024 * 1024) / 65536); | |
84 | + if (val > 65535) | |
85 | + val = 65535; | |
86 | + s->cmos_data[0x34] = val; | |
87 | + s->cmos_data[0x35] = val >> 8; | |
88 | + | |
89 | + switch(boot_device) { | |
90 | + case 'a': | |
91 | + case 'b': | |
92 | + s->cmos_data[0x3d] = 0x01; /* floppy boot */ | |
93 | + break; | |
94 | + default: | |
95 | + case 'c': | |
96 | + s->cmos_data[0x3d] = 0x02; /* hard drive boot */ | |
97 | + break; | |
98 | + case 'd': | |
99 | + s->cmos_data[0x3d] = 0x03; /* CD-ROM boot */ | |
100 | + break; | |
101 | + } | |
102 | +} | |
103 | + | |
104 | +void cmos_register_fd (uint8_t fd0, uint8_t fd1) | |
105 | +{ | |
106 | + RTCState *s = &rtc_state; | |
107 | + int nb = 0; | |
108 | + | |
109 | + s->cmos_data[0x10] = 0; | |
110 | + switch (fd0) { | |
111 | + case 0: | |
112 | + /* 1.44 Mb 3"5 drive */ | |
113 | + s->cmos_data[0x10] |= 0x40; | |
114 | + break; | |
115 | + case 1: | |
116 | + /* 2.88 Mb 3"5 drive */ | |
117 | + s->cmos_data[0x10] |= 0x60; | |
118 | + break; | |
119 | + case 2: | |
120 | + /* 1.2 Mb 5"5 drive */ | |
121 | + s->cmos_data[0x10] |= 0x20; | |
122 | + break; | |
123 | + } | |
124 | + switch (fd1) { | |
125 | + case 0: | |
126 | + /* 1.44 Mb 3"5 drive */ | |
127 | + s->cmos_data[0x10] |= 0x04; | |
128 | + break; | |
129 | + case 1: | |
130 | + /* 2.88 Mb 3"5 drive */ | |
131 | + s->cmos_data[0x10] |= 0x06; | |
132 | + break; | |
133 | + case 2: | |
134 | + /* 1.2 Mb 5"5 drive */ | |
135 | + s->cmos_data[0x10] |= 0x02; | |
136 | + break; | |
137 | + } | |
138 | + if (fd0 < 3) | |
139 | + nb++; | |
140 | + if (fd1 < 3) | |
141 | + nb++; | |
142 | + switch (nb) { | |
143 | + case 0: | |
144 | + break; | |
145 | + case 1: | |
146 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x01; /* 1 drive, ready for boot */ | |
147 | + break; | |
148 | + case 2: | |
149 | + s->cmos_data[REG_EQUIPMENT_BYTE] |= 0x41; /* 2 drives, ready for boot */ | |
150 | + break; | |
151 | + } | |
152 | +} | |
153 | + | |
154 | +void speaker_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
155 | +{ | |
156 | + speaker_data_on = (val >> 1) & 1; | |
157 | + pit_set_gate(&pit_channels[2], val & 1); | |
158 | +} | |
159 | + | |
160 | +uint32_t speaker_ioport_read(CPUState *env, uint32_t addr) | |
161 | +{ | |
162 | + int out; | |
163 | + out = pit_get_out(&pit_channels[2]); | |
164 | + dummy_refresh_clock ^= 1; | |
165 | + return (speaker_data_on << 1) | pit_channels[2].gate | (out << 5) | | |
166 | + (dummy_refresh_clock << 4); | |
167 | +} | |
168 | + | |
169 | +/***********************************************************/ | |
170 | +/* PC floppy disk controler emulation glue */ | |
171 | +#define PC_FDC_DMA 0x2 | |
172 | +#define PC_FDC_IRQ 0x6 | |
173 | +#define PC_FDC_BASE 0x3F0 | |
174 | + | |
175 | +static void fdctrl_register (unsigned char **disknames, int ro, | |
176 | + char boot_device) | |
177 | +{ | |
178 | + int i; | |
179 | + | |
180 | + fdctrl_init(PC_FDC_IRQ, PC_FDC_DMA, 0, PC_FDC_BASE, boot_device); | |
181 | + for (i = 0; i < MAX_FD; i++) { | |
182 | + if (disknames[i] != NULL) | |
183 | + fdctrl_disk_change(i, disknames[i], ro); | |
184 | + } | |
185 | +} | |
186 | + | |
187 | +/***********************************************************/ | |
188 | +/* Bochs BIOS debug ports */ | |
189 | + | |
190 | +void bochs_bios_write(CPUX86State *env, uint32_t addr, uint32_t val) | |
191 | +{ | |
192 | + switch(addr) { | |
193 | + /* Bochs BIOS messages */ | |
194 | + case 0x400: | |
195 | + case 0x401: | |
196 | + fprintf(stderr, "BIOS panic at rombios.c, line %d\n", val); | |
197 | + exit(1); | |
198 | + case 0x402: | |
199 | + case 0x403: | |
200 | +#ifdef DEBUG_BIOS | |
201 | + fprintf(stderr, "%c", val); | |
202 | +#endif | |
203 | + break; | |
204 | + | |
205 | + /* LGPL'ed VGA BIOS messages */ | |
206 | + case 0x501: | |
207 | + case 0x502: | |
208 | + fprintf(stderr, "VGA BIOS panic, line %d\n", val); | |
209 | + exit(1); | |
210 | + case 0x500: | |
211 | + case 0x503: | |
212 | +#ifdef DEBUG_BIOS | |
213 | + fprintf(stderr, "%c", val); | |
214 | +#endif | |
215 | + break; | |
216 | + } | |
217 | +} | |
218 | + | |
219 | +void bochs_bios_init(void) | |
220 | +{ | |
221 | + register_ioport_write(0x400, 1, bochs_bios_write, 2); | |
222 | + register_ioport_write(0x401, 1, bochs_bios_write, 2); | |
223 | + register_ioport_write(0x402, 1, bochs_bios_write, 1); | |
224 | + register_ioport_write(0x403, 1, bochs_bios_write, 1); | |
225 | + | |
226 | + register_ioport_write(0x501, 1, bochs_bios_write, 2); | |
227 | + register_ioport_write(0x502, 1, bochs_bios_write, 2); | |
228 | + register_ioport_write(0x500, 1, bochs_bios_write, 1); | |
229 | + register_ioport_write(0x503, 1, bochs_bios_write, 1); | |
230 | +} | |
231 | + | |
232 | + | |
233 | +int load_kernel(const char *filename, uint8_t *addr, | |
234 | + uint8_t *real_addr) | |
235 | +{ | |
236 | + int fd, size; | |
237 | + int setup_sects; | |
238 | + | |
239 | + fd = open(filename, O_RDONLY); | |
240 | + if (fd < 0) | |
241 | + return -1; | |
242 | + | |
243 | + /* load 16 bit code */ | |
244 | + if (read(fd, real_addr, 512) != 512) | |
245 | + goto fail; | |
246 | + setup_sects = real_addr[0x1F1]; | |
247 | + if (!setup_sects) | |
248 | + setup_sects = 4; | |
249 | + if (read(fd, real_addr + 512, setup_sects * 512) != | |
250 | + setup_sects * 512) | |
251 | + goto fail; | |
252 | + | |
253 | + /* load 32 bit code */ | |
254 | + size = read(fd, addr, 16 * 1024 * 1024); | |
255 | + if (size < 0) | |
256 | + goto fail; | |
257 | + close(fd); | |
258 | + return size; | |
259 | + fail: | |
260 | + close(fd); | |
261 | + return -1; | |
262 | +} | |
263 | + | |
264 | +/* PC hardware initialisation */ | |
265 | +void pc_init(int ram_size, int vga_ram_size, int boot_device, | |
266 | + DisplayState *ds, const char **fd_filename, int snapshot, | |
267 | + const char *kernel_filename, const char *kernel_cmdline, | |
268 | + const char *initrd_filename) | |
269 | +{ | |
270 | + char buf[1024]; | |
271 | + int ret, linux_boot, initrd_size; | |
272 | + | |
273 | + linux_boot = (kernel_filename != NULL); | |
274 | + | |
275 | + /* allocate RAM */ | |
276 | + cpu_register_physical_memory(0, ram_size, 0); | |
277 | + | |
278 | + /* BIOS load */ | |
279 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); | |
280 | + ret = load_image(buf, phys_ram_base + 0x000f0000); | |
281 | + if (ret != 0x10000) { | |
282 | + fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf); | |
283 | + exit(1); | |
284 | + } | |
285 | + | |
286 | + /* VGA BIOS load */ | |
287 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME); | |
288 | + ret = load_image(buf, phys_ram_base + 0x000c0000); | |
289 | + | |
290 | + /* setup basic memory access */ | |
291 | + cpu_register_physical_memory(0xc0000, 0x10000, 0xc0000 | IO_MEM_ROM); | |
292 | + cpu_register_physical_memory(0xf0000, 0x10000, 0xf0000 | IO_MEM_ROM); | |
293 | + | |
294 | + bochs_bios_init(); | |
295 | + | |
296 | + if (linux_boot) { | |
297 | + uint8_t bootsect[512]; | |
298 | + | |
299 | + if (bs_table[0] == NULL) { | |
300 | + fprintf(stderr, "A disk image must be given for 'hda' when booting a Linux kernel\n"); | |
301 | + exit(1); | |
302 | + } | |
303 | + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, LINUX_BOOT_FILENAME); | |
304 | + ret = load_image(buf, bootsect); | |
305 | + if (ret != sizeof(bootsect)) { | |
306 | + fprintf(stderr, "qemu: could not load linux boot sector '%s'\n", | |
307 | + buf); | |
308 | + exit(1); | |
309 | + } | |
310 | + | |
311 | + bdrv_set_boot_sector(bs_table[0], bootsect, sizeof(bootsect)); | |
312 | + | |
313 | + /* now we can load the kernel */ | |
314 | + ret = load_kernel(kernel_filename, | |
315 | + phys_ram_base + KERNEL_LOAD_ADDR, | |
316 | + phys_ram_base + KERNEL_PARAMS_ADDR); | |
317 | + if (ret < 0) { | |
318 | + fprintf(stderr, "qemu: could not load kernel '%s'\n", | |
319 | + kernel_filename); | |
320 | + exit(1); | |
321 | + } | |
322 | + | |
323 | + /* load initrd */ | |
324 | + initrd_size = 0; | |
325 | + if (initrd_filename) { | |
326 | + initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR); | |
327 | + if (initrd_size < 0) { | |
328 | + fprintf(stderr, "qemu: could not load initial ram disk '%s'\n", | |
329 | + initrd_filename); | |
330 | + exit(1); | |
331 | + } | |
332 | + } | |
333 | + if (initrd_size > 0) { | |
334 | + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR); | |
335 | + stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size); | |
336 | + } | |
337 | + pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096, | |
338 | + kernel_cmdline); | |
339 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x20, 0xA33F); | |
340 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x22, | |
341 | + KERNEL_CMDLINE_ADDR - KERNEL_PARAMS_ADDR); | |
342 | + /* loader type */ | |
343 | + stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01); | |
344 | + } | |
345 | + | |
346 | + /* init basic PC hardware */ | |
347 | + register_ioport_write(0x80, 1, ioport80_write, 1); | |
348 | + | |
349 | + vga_initialize(ds, phys_ram_base + ram_size, ram_size, | |
350 | + vga_ram_size); | |
351 | + | |
352 | + rtc_init(0x70, 8); | |
353 | + cmos_init(ram_size, boot_device); | |
354 | + register_ioport_read(0x61, 1, speaker_ioport_read, 1); | |
355 | + register_ioport_write(0x61, 1, speaker_ioport_write, 1); | |
356 | + | |
357 | + pic_init(); | |
358 | + pit_init(); | |
359 | + serial_init(0x3f8, 4); | |
360 | + ne2000_init(0x300, 9); | |
361 | + ide_init(); | |
362 | + kbd_init(); | |
363 | + AUD_init(); | |
364 | + DMA_init(); | |
365 | + SB16_init(); | |
366 | + | |
367 | + fdctrl_register((unsigned char **)fd_filename, snapshot, boot_device); | |
368 | +} | ... | ... |
hw/pckbd.c
0 → 100644
1 | +/* | |
2 | + * QEMU PC keyboard emulation | |
3 | + * | |
4 | + * Copyright (c) 2003 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +/* debug PC keyboard */ | |
47 | +//#define DEBUG_KBD | |
48 | + | |
49 | +/* debug PC keyboard : only mouse */ | |
50 | +//#define DEBUG_MOUSE | |
51 | + | |
52 | +/* Keyboard Controller Commands */ | |
53 | +#define KBD_CCMD_READ_MODE 0x20 /* Read mode bits */ | |
54 | +#define KBD_CCMD_WRITE_MODE 0x60 /* Write mode bits */ | |
55 | +#define KBD_CCMD_GET_VERSION 0xA1 /* Get controller version */ | |
56 | +#define KBD_CCMD_MOUSE_DISABLE 0xA7 /* Disable mouse interface */ | |
57 | +#define KBD_CCMD_MOUSE_ENABLE 0xA8 /* Enable mouse interface */ | |
58 | +#define KBD_CCMD_TEST_MOUSE 0xA9 /* Mouse interface test */ | |
59 | +#define KBD_CCMD_SELF_TEST 0xAA /* Controller self test */ | |
60 | +#define KBD_CCMD_KBD_TEST 0xAB /* Keyboard interface test */ | |
61 | +#define KBD_CCMD_KBD_DISABLE 0xAD /* Keyboard interface disable */ | |
62 | +#define KBD_CCMD_KBD_ENABLE 0xAE /* Keyboard interface enable */ | |
63 | +#define KBD_CCMD_READ_INPORT 0xC0 /* read input port */ | |
64 | +#define KBD_CCMD_READ_OUTPORT 0xD0 /* read output port */ | |
65 | +#define KBD_CCMD_WRITE_OUTPORT 0xD1 /* write output port */ | |
66 | +#define KBD_CCMD_WRITE_OBUF 0xD2 | |
67 | +#define KBD_CCMD_WRITE_AUX_OBUF 0xD3 /* Write to output buffer as if | |
68 | + initiated by the auxiliary device */ | |
69 | +#define KBD_CCMD_WRITE_MOUSE 0xD4 /* Write the following byte to the mouse */ | |
70 | +#define KBD_CCMD_DISABLE_A20 0xDD /* HP vectra only ? */ | |
71 | +#define KBD_CCMD_ENABLE_A20 0xDF /* HP vectra only ? */ | |
72 | +#define KBD_CCMD_RESET 0xFE | |
73 | + | |
74 | +/* Keyboard Commands */ | |
75 | +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ | |
76 | +#define KBD_CMD_ECHO 0xEE | |
77 | +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ | |
78 | +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ | |
79 | +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ | |
80 | +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ | |
81 | +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ | |
82 | +#define KBD_CMD_RESET 0xFF /* Reset */ | |
83 | + | |
84 | +/* Keyboard Replies */ | |
85 | +#define KBD_REPLY_POR 0xAA /* Power on reset */ | |
86 | +#define KBD_REPLY_ACK 0xFA /* Command ACK */ | |
87 | +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ | |
88 | + | |
89 | +/* Status Register Bits */ | |
90 | +#define KBD_STAT_OBF 0x01 /* Keyboard output buffer full */ | |
91 | +#define KBD_STAT_IBF 0x02 /* Keyboard input buffer full */ | |
92 | +#define KBD_STAT_SELFTEST 0x04 /* Self test successful */ | |
93 | +#define KBD_STAT_CMD 0x08 /* Last write was a command write (0=data) */ | |
94 | +#define KBD_STAT_UNLOCKED 0x10 /* Zero if keyboard locked */ | |
95 | +#define KBD_STAT_MOUSE_OBF 0x20 /* Mouse output buffer full */ | |
96 | +#define KBD_STAT_GTO 0x40 /* General receive/xmit timeout */ | |
97 | +#define KBD_STAT_PERR 0x80 /* Parity error */ | |
98 | + | |
99 | +/* Controller Mode Register Bits */ | |
100 | +#define KBD_MODE_KBD_INT 0x01 /* Keyboard data generate IRQ1 */ | |
101 | +#define KBD_MODE_MOUSE_INT 0x02 /* Mouse data generate IRQ12 */ | |
102 | +#define KBD_MODE_SYS 0x04 /* The system flag (?) */ | |
103 | +#define KBD_MODE_NO_KEYLOCK 0x08 /* The keylock doesn't affect the keyboard if set */ | |
104 | +#define KBD_MODE_DISABLE_KBD 0x10 /* Disable keyboard interface */ | |
105 | +#define KBD_MODE_DISABLE_MOUSE 0x20 /* Disable mouse interface */ | |
106 | +#define KBD_MODE_KCC 0x40 /* Scan code conversion to PC format */ | |
107 | +#define KBD_MODE_RFU 0x80 | |
108 | + | |
109 | +/* Mouse Commands */ | |
110 | +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ | |
111 | +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ | |
112 | +#define AUX_SET_RES 0xE8 /* Set resolution */ | |
113 | +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ | |
114 | +#define AUX_SET_STREAM 0xEA /* Set stream mode */ | |
115 | +#define AUX_POLL 0xEB /* Poll */ | |
116 | +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ | |
117 | +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ | |
118 | +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ | |
119 | +#define AUX_GET_TYPE 0xF2 /* Get type */ | |
120 | +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ | |
121 | +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ | |
122 | +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ | |
123 | +#define AUX_SET_DEFAULT 0xF6 | |
124 | +#define AUX_RESET 0xFF /* Reset aux device */ | |
125 | +#define AUX_ACK 0xFA /* Command byte ACK. */ | |
126 | + | |
127 | +#define MOUSE_STATUS_REMOTE 0x40 | |
128 | +#define MOUSE_STATUS_ENABLED 0x20 | |
129 | +#define MOUSE_STATUS_SCALE21 0x10 | |
130 | + | |
131 | +#define KBD_QUEUE_SIZE 256 | |
132 | + | |
133 | +typedef struct { | |
134 | + uint8_t data[KBD_QUEUE_SIZE]; | |
135 | + int rptr, wptr, count; | |
136 | +} KBDQueue; | |
137 | + | |
138 | +typedef struct KBDState { | |
139 | + KBDQueue queues[2]; | |
140 | + uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ | |
141 | + uint8_t status; | |
142 | + uint8_t mode; | |
143 | + /* keyboard state */ | |
144 | + int kbd_write_cmd; | |
145 | + int scan_enabled; | |
146 | + /* mouse state */ | |
147 | + int mouse_write_cmd; | |
148 | + uint8_t mouse_status; | |
149 | + uint8_t mouse_resolution; | |
150 | + uint8_t mouse_sample_rate; | |
151 | + uint8_t mouse_wrap; | |
152 | + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ | |
153 | + uint8_t mouse_detect_state; | |
154 | + int mouse_dx; /* current values, needed for 'poll' mode */ | |
155 | + int mouse_dy; | |
156 | + int mouse_dz; | |
157 | + uint8_t mouse_buttons; | |
158 | +} KBDState; | |
159 | + | |
160 | +KBDState kbd_state; | |
161 | +int reset_requested; | |
162 | + | |
163 | +/* update irq and KBD_STAT_[MOUSE_]OBF */ | |
164 | +/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be | |
165 | + incorrect, but it avoids having to simulate exact delays */ | |
166 | +static void kbd_update_irq(KBDState *s) | |
167 | +{ | |
168 | + int irq12_level, irq1_level; | |
169 | + | |
170 | + irq1_level = 0; | |
171 | + irq12_level = 0; | |
172 | + s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); | |
173 | + if (s->queues[0].count != 0 || | |
174 | + s->queues[1].count != 0) { | |
175 | + s->status |= KBD_STAT_OBF; | |
176 | + if (s->queues[1].count != 0) { | |
177 | + s->status |= KBD_STAT_MOUSE_OBF; | |
178 | + if (s->mode & KBD_MODE_MOUSE_INT) | |
179 | + irq12_level = 1; | |
180 | + } else { | |
181 | + if ((s->mode & KBD_MODE_KBD_INT) && | |
182 | + !(s->mode & KBD_MODE_DISABLE_KBD)) | |
183 | + irq1_level = 1; | |
184 | + } | |
185 | + } | |
186 | + pic_set_irq(1, irq1_level); | |
187 | + pic_set_irq(12, irq12_level); | |
188 | +} | |
189 | + | |
190 | +static void kbd_queue(KBDState *s, int b, int aux) | |
191 | +{ | |
192 | + KBDQueue *q = &kbd_state.queues[aux]; | |
193 | + | |
194 | +#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) | |
195 | + if (aux) | |
196 | + printf("mouse event: 0x%02x\n", b); | |
197 | +#ifdef DEBUG_KBD | |
198 | + else | |
199 | + printf("kbd event: 0x%02x\n", b); | |
200 | +#endif | |
201 | +#endif | |
202 | + if (q->count >= KBD_QUEUE_SIZE) | |
203 | + return; | |
204 | + q->data[q->wptr] = b; | |
205 | + if (++q->wptr == KBD_QUEUE_SIZE) | |
206 | + q->wptr = 0; | |
207 | + q->count++; | |
208 | + kbd_update_irq(s); | |
209 | +} | |
210 | + | |
211 | +void kbd_put_keycode(int keycode) | |
212 | +{ | |
213 | + KBDState *s = &kbd_state; | |
214 | + kbd_queue(s, keycode, 0); | |
215 | +} | |
216 | + | |
217 | +static uint32_t kbd_read_status(CPUState *env, uint32_t addr) | |
218 | +{ | |
219 | + KBDState *s = &kbd_state; | |
220 | + int val; | |
221 | + val = s->status; | |
222 | +#if defined(DEBUG_KBD) | |
223 | + printf("kbd: read status=0x%02x\n", val); | |
224 | +#endif | |
225 | + return val; | |
226 | +} | |
227 | + | |
228 | +static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val) | |
229 | +{ | |
230 | + KBDState *s = &kbd_state; | |
231 | + | |
232 | +#ifdef DEBUG_KBD | |
233 | + printf("kbd: write cmd=0x%02x\n", val); | |
234 | +#endif | |
235 | + switch(val) { | |
236 | + case KBD_CCMD_READ_MODE: | |
237 | + kbd_queue(s, s->mode, 0); | |
238 | + break; | |
239 | + case KBD_CCMD_WRITE_MODE: | |
240 | + case KBD_CCMD_WRITE_OBUF: | |
241 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
242 | + case KBD_CCMD_WRITE_MOUSE: | |
243 | + case KBD_CCMD_WRITE_OUTPORT: | |
244 | + s->write_cmd = val; | |
245 | + break; | |
246 | + case KBD_CCMD_MOUSE_DISABLE: | |
247 | + s->mode |= KBD_MODE_DISABLE_MOUSE; | |
248 | + break; | |
249 | + case KBD_CCMD_MOUSE_ENABLE: | |
250 | + s->mode &= ~KBD_MODE_DISABLE_MOUSE; | |
251 | + break; | |
252 | + case KBD_CCMD_TEST_MOUSE: | |
253 | + kbd_queue(s, 0x00, 0); | |
254 | + break; | |
255 | + case KBD_CCMD_SELF_TEST: | |
256 | + s->status |= KBD_STAT_SELFTEST; | |
257 | + kbd_queue(s, 0x55, 0); | |
258 | + break; | |
259 | + case KBD_CCMD_KBD_TEST: | |
260 | + kbd_queue(s, 0x00, 0); | |
261 | + break; | |
262 | + case KBD_CCMD_KBD_DISABLE: | |
263 | + s->mode |= KBD_MODE_DISABLE_KBD; | |
264 | + kbd_update_irq(s); | |
265 | + break; | |
266 | + case KBD_CCMD_KBD_ENABLE: | |
267 | + s->mode &= ~KBD_MODE_DISABLE_KBD; | |
268 | + kbd_update_irq(s); | |
269 | + break; | |
270 | + case KBD_CCMD_READ_INPORT: | |
271 | + kbd_queue(s, 0x00, 0); | |
272 | + break; | |
273 | + case KBD_CCMD_READ_OUTPORT: | |
274 | + /* XXX: check that */ | |
275 | +#ifdef TARGET_I386 | |
276 | + val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1); | |
277 | +#else | |
278 | + val = 0x01; | |
279 | +#endif | |
280 | + if (s->status & KBD_STAT_OBF) | |
281 | + val |= 0x10; | |
282 | + if (s->status & KBD_STAT_MOUSE_OBF) | |
283 | + val |= 0x20; | |
284 | + kbd_queue(s, val, 0); | |
285 | + break; | |
286 | +#ifdef TARGET_I386 | |
287 | + case KBD_CCMD_ENABLE_A20: | |
288 | + cpu_x86_set_a20(env, 1); | |
289 | + break; | |
290 | + case KBD_CCMD_DISABLE_A20: | |
291 | + cpu_x86_set_a20(env, 0); | |
292 | + break; | |
293 | +#endif | |
294 | + case KBD_CCMD_RESET: | |
295 | + reset_requested = 1; | |
296 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
297 | + break; | |
298 | + case 0xff: | |
299 | + /* ignore that - I don't know what is its use */ | |
300 | + break; | |
301 | + default: | |
302 | + fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val); | |
303 | + break; | |
304 | + } | |
305 | +} | |
306 | + | |
307 | +static uint32_t kbd_read_data(CPUState *env, uint32_t addr) | |
308 | +{ | |
309 | + KBDState *s = &kbd_state; | |
310 | + KBDQueue *q; | |
311 | + int val, index; | |
312 | + | |
313 | + q = &s->queues[0]; /* first check KBD data */ | |
314 | + if (q->count == 0) | |
315 | + q = &s->queues[1]; /* then check AUX data */ | |
316 | + if (q->count == 0) { | |
317 | + /* NOTE: if no data left, we return the last keyboard one | |
318 | + (needed for EMM386) */ | |
319 | + /* XXX: need a timer to do things correctly */ | |
320 | + q = &s->queues[0]; | |
321 | + index = q->rptr - 1; | |
322 | + if (index < 0) | |
323 | + index = KBD_QUEUE_SIZE - 1; | |
324 | + val = q->data[index]; | |
325 | + } else { | |
326 | + val = q->data[q->rptr]; | |
327 | + if (++q->rptr == KBD_QUEUE_SIZE) | |
328 | + q->rptr = 0; | |
329 | + q->count--; | |
330 | + /* reading deasserts IRQ */ | |
331 | + if (q == &s->queues[0]) | |
332 | + pic_set_irq(1, 0); | |
333 | + else | |
334 | + pic_set_irq(12, 0); | |
335 | + } | |
336 | + /* reassert IRQs if data left */ | |
337 | + kbd_update_irq(s); | |
338 | +#ifdef DEBUG_KBD | |
339 | + printf("kbd: read data=0x%02x\n", val); | |
340 | +#endif | |
341 | + return val; | |
342 | +} | |
343 | + | |
344 | +static void kbd_reset_keyboard(KBDState *s) | |
345 | +{ | |
346 | + s->scan_enabled = 1; | |
347 | +} | |
348 | + | |
349 | +static void kbd_write_keyboard(KBDState *s, int val) | |
350 | +{ | |
351 | + switch(s->kbd_write_cmd) { | |
352 | + default: | |
353 | + case -1: | |
354 | + switch(val) { | |
355 | + case 0x00: | |
356 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
357 | + break; | |
358 | + case 0x05: | |
359 | + kbd_queue(s, KBD_REPLY_RESEND, 0); | |
360 | + break; | |
361 | + case KBD_CMD_GET_ID: | |
362 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
363 | + kbd_queue(s, 0xab, 0); | |
364 | + kbd_queue(s, 0x83, 0); | |
365 | + break; | |
366 | + case KBD_CMD_ECHO: | |
367 | + kbd_queue(s, KBD_CMD_ECHO, 0); | |
368 | + break; | |
369 | + case KBD_CMD_ENABLE: | |
370 | + s->scan_enabled = 1; | |
371 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
372 | + break; | |
373 | + case KBD_CMD_SET_LEDS: | |
374 | + case KBD_CMD_SET_RATE: | |
375 | + s->kbd_write_cmd = val; | |
376 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
377 | + break; | |
378 | + case KBD_CMD_RESET_DISABLE: | |
379 | + kbd_reset_keyboard(s); | |
380 | + s->scan_enabled = 0; | |
381 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
382 | + break; | |
383 | + case KBD_CMD_RESET_ENABLE: | |
384 | + kbd_reset_keyboard(s); | |
385 | + s->scan_enabled = 1; | |
386 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
387 | + break; | |
388 | + case KBD_CMD_RESET: | |
389 | + kbd_reset_keyboard(s); | |
390 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
391 | + kbd_queue(s, KBD_REPLY_POR, 0); | |
392 | + break; | |
393 | + default: | |
394 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
395 | + break; | |
396 | + } | |
397 | + break; | |
398 | + case KBD_CMD_SET_LEDS: | |
399 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
400 | + s->kbd_write_cmd = -1; | |
401 | + break; | |
402 | + case KBD_CMD_SET_RATE: | |
403 | + kbd_queue(s, KBD_REPLY_ACK, 0); | |
404 | + s->kbd_write_cmd = -1; | |
405 | + break; | |
406 | + } | |
407 | +} | |
408 | + | |
409 | +static void kbd_mouse_send_packet(KBDState *s) | |
410 | +{ | |
411 | + unsigned int b; | |
412 | + int dx1, dy1, dz1; | |
413 | + | |
414 | + dx1 = s->mouse_dx; | |
415 | + dy1 = s->mouse_dy; | |
416 | + dz1 = s->mouse_dz; | |
417 | + /* XXX: increase range to 8 bits ? */ | |
418 | + if (dx1 > 127) | |
419 | + dx1 = 127; | |
420 | + else if (dx1 < -127) | |
421 | + dx1 = -127; | |
422 | + if (dy1 > 127) | |
423 | + dy1 = 127; | |
424 | + else if (dy1 < -127) | |
425 | + dy1 = -127; | |
426 | + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); | |
427 | + kbd_queue(s, b, 1); | |
428 | + kbd_queue(s, dx1 & 0xff, 1); | |
429 | + kbd_queue(s, dy1 & 0xff, 1); | |
430 | + /* extra byte for IMPS/2 or IMEX */ | |
431 | + switch(s->mouse_type) { | |
432 | + default: | |
433 | + break; | |
434 | + case 3: | |
435 | + if (dz1 > 127) | |
436 | + dz1 = 127; | |
437 | + else if (dz1 < -127) | |
438 | + dz1 = -127; | |
439 | + kbd_queue(s, dz1 & 0xff, 1); | |
440 | + break; | |
441 | + case 4: | |
442 | + if (dz1 > 7) | |
443 | + dz1 = 7; | |
444 | + else if (dz1 < -7) | |
445 | + dz1 = -7; | |
446 | + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); | |
447 | + kbd_queue(s, b, 1); | |
448 | + break; | |
449 | + } | |
450 | + | |
451 | + /* update deltas */ | |
452 | + s->mouse_dx -= dx1; | |
453 | + s->mouse_dy -= dy1; | |
454 | + s->mouse_dz -= dz1; | |
455 | +} | |
456 | + | |
457 | +void kbd_mouse_event(int dx, int dy, int dz, int buttons_state) | |
458 | +{ | |
459 | + KBDState *s = &kbd_state; | |
460 | + | |
461 | + /* check if deltas are recorded when disabled */ | |
462 | + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) | |
463 | + return; | |
464 | + | |
465 | + s->mouse_dx += dx; | |
466 | + s->mouse_dy -= dy; | |
467 | + s->mouse_dz += dz; | |
468 | + s->mouse_buttons = buttons_state; | |
469 | + | |
470 | + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && | |
471 | + (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) { | |
472 | + for(;;) { | |
473 | + /* if not remote, send event. Multiple events are sent if | |
474 | + too big deltas */ | |
475 | + kbd_mouse_send_packet(s); | |
476 | + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) | |
477 | + break; | |
478 | + } | |
479 | + } | |
480 | +} | |
481 | + | |
482 | +static void kbd_write_mouse(KBDState *s, int val) | |
483 | +{ | |
484 | +#ifdef DEBUG_MOUSE | |
485 | + printf("kbd: write mouse 0x%02x\n", val); | |
486 | +#endif | |
487 | + switch(s->mouse_write_cmd) { | |
488 | + default: | |
489 | + case -1: | |
490 | + /* mouse command */ | |
491 | + if (s->mouse_wrap) { | |
492 | + if (val == AUX_RESET_WRAP) { | |
493 | + s->mouse_wrap = 0; | |
494 | + kbd_queue(s, AUX_ACK, 1); | |
495 | + return; | |
496 | + } else if (val != AUX_RESET) { | |
497 | + kbd_queue(s, val, 1); | |
498 | + return; | |
499 | + } | |
500 | + } | |
501 | + switch(val) { | |
502 | + case AUX_SET_SCALE11: | |
503 | + s->mouse_status &= ~MOUSE_STATUS_SCALE21; | |
504 | + kbd_queue(s, AUX_ACK, 1); | |
505 | + break; | |
506 | + case AUX_SET_SCALE21: | |
507 | + s->mouse_status |= MOUSE_STATUS_SCALE21; | |
508 | + kbd_queue(s, AUX_ACK, 1); | |
509 | + break; | |
510 | + case AUX_SET_STREAM: | |
511 | + s->mouse_status &= ~MOUSE_STATUS_REMOTE; | |
512 | + kbd_queue(s, AUX_ACK, 1); | |
513 | + break; | |
514 | + case AUX_SET_WRAP: | |
515 | + s->mouse_wrap = 1; | |
516 | + kbd_queue(s, AUX_ACK, 1); | |
517 | + break; | |
518 | + case AUX_SET_REMOTE: | |
519 | + s->mouse_status |= MOUSE_STATUS_REMOTE; | |
520 | + kbd_queue(s, AUX_ACK, 1); | |
521 | + break; | |
522 | + case AUX_GET_TYPE: | |
523 | + kbd_queue(s, AUX_ACK, 1); | |
524 | + kbd_queue(s, s->mouse_type, 1); | |
525 | + break; | |
526 | + case AUX_SET_RES: | |
527 | + case AUX_SET_SAMPLE: | |
528 | + s->mouse_write_cmd = val; | |
529 | + kbd_queue(s, AUX_ACK, 1); | |
530 | + break; | |
531 | + case AUX_GET_SCALE: | |
532 | + kbd_queue(s, AUX_ACK, 1); | |
533 | + kbd_queue(s, s->mouse_status, 1); | |
534 | + kbd_queue(s, s->mouse_resolution, 1); | |
535 | + kbd_queue(s, s->mouse_sample_rate, 1); | |
536 | + break; | |
537 | + case AUX_POLL: | |
538 | + kbd_queue(s, AUX_ACK, 1); | |
539 | + kbd_mouse_send_packet(s); | |
540 | + break; | |
541 | + case AUX_ENABLE_DEV: | |
542 | + s->mouse_status |= MOUSE_STATUS_ENABLED; | |
543 | + kbd_queue(s, AUX_ACK, 1); | |
544 | + break; | |
545 | + case AUX_DISABLE_DEV: | |
546 | + s->mouse_status &= ~MOUSE_STATUS_ENABLED; | |
547 | + kbd_queue(s, AUX_ACK, 1); | |
548 | + break; | |
549 | + case AUX_SET_DEFAULT: | |
550 | + s->mouse_sample_rate = 100; | |
551 | + s->mouse_resolution = 2; | |
552 | + s->mouse_status = 0; | |
553 | + kbd_queue(s, AUX_ACK, 1); | |
554 | + break; | |
555 | + case AUX_RESET: | |
556 | + s->mouse_sample_rate = 100; | |
557 | + s->mouse_resolution = 2; | |
558 | + s->mouse_status = 0; | |
559 | + kbd_queue(s, AUX_ACK, 1); | |
560 | + kbd_queue(s, 0xaa, 1); | |
561 | + kbd_queue(s, s->mouse_type, 1); | |
562 | + break; | |
563 | + default: | |
564 | + break; | |
565 | + } | |
566 | + break; | |
567 | + case AUX_SET_SAMPLE: | |
568 | + s->mouse_sample_rate = val; | |
569 | +#if 0 | |
570 | + /* detect IMPS/2 or IMEX */ | |
571 | + switch(s->mouse_detect_state) { | |
572 | + default: | |
573 | + case 0: | |
574 | + if (val == 200) | |
575 | + s->mouse_detect_state = 1; | |
576 | + break; | |
577 | + case 1: | |
578 | + if (val == 100) | |
579 | + s->mouse_detect_state = 2; | |
580 | + else if (val == 200) | |
581 | + s->mouse_detect_state = 3; | |
582 | + else | |
583 | + s->mouse_detect_state = 0; | |
584 | + break; | |
585 | + case 2: | |
586 | + if (val == 80) | |
587 | + s->mouse_type = 3; /* IMPS/2 */ | |
588 | + s->mouse_detect_state = 0; | |
589 | + break; | |
590 | + case 3: | |
591 | + if (val == 80) | |
592 | + s->mouse_type = 4; /* IMEX */ | |
593 | + s->mouse_detect_state = 0; | |
594 | + break; | |
595 | + } | |
596 | +#endif | |
597 | + kbd_queue(s, AUX_ACK, 1); | |
598 | + s->mouse_write_cmd = -1; | |
599 | + break; | |
600 | + case AUX_SET_RES: | |
601 | + s->mouse_resolution = val; | |
602 | + kbd_queue(s, AUX_ACK, 1); | |
603 | + s->mouse_write_cmd = -1; | |
604 | + break; | |
605 | + } | |
606 | +} | |
607 | + | |
608 | +void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val) | |
609 | +{ | |
610 | + KBDState *s = &kbd_state; | |
611 | + | |
612 | +#ifdef DEBUG_KBD | |
613 | + printf("kbd: write data=0x%02x\n", val); | |
614 | +#endif | |
615 | + | |
616 | + switch(s->write_cmd) { | |
617 | + case 0: | |
618 | + kbd_write_keyboard(s, val); | |
619 | + break; | |
620 | + case KBD_CCMD_WRITE_MODE: | |
621 | + s->mode = val; | |
622 | + kbd_update_irq(s); | |
623 | + break; | |
624 | + case KBD_CCMD_WRITE_OBUF: | |
625 | + kbd_queue(s, val, 0); | |
626 | + break; | |
627 | + case KBD_CCMD_WRITE_AUX_OBUF: | |
628 | + kbd_queue(s, val, 1); | |
629 | + break; | |
630 | + case KBD_CCMD_WRITE_OUTPORT: | |
631 | +#ifdef TARGET_I386 | |
632 | + cpu_x86_set_a20(env, (val >> 1) & 1); | |
633 | +#endif | |
634 | + if (!(val & 1)) { | |
635 | + reset_requested = 1; | |
636 | + cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT); | |
637 | + } | |
638 | + break; | |
639 | + case KBD_CCMD_WRITE_MOUSE: | |
640 | + kbd_write_mouse(s, val); | |
641 | + break; | |
642 | + default: | |
643 | + break; | |
644 | + } | |
645 | + s->write_cmd = 0; | |
646 | +} | |
647 | + | |
648 | +void kbd_reset(KBDState *s) | |
649 | +{ | |
650 | + KBDQueue *q; | |
651 | + int i; | |
652 | + | |
653 | + s->kbd_write_cmd = -1; | |
654 | + s->mouse_write_cmd = -1; | |
655 | + s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; | |
656 | + s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; | |
657 | + for(i = 0; i < 2; i++) { | |
658 | + q = &s->queues[i]; | |
659 | + q->rptr = 0; | |
660 | + q->wptr = 0; | |
661 | + q->count = 0; | |
662 | + } | |
663 | +} | |
664 | + | |
665 | +void kbd_init(void) | |
666 | +{ | |
667 | + kbd_reset(&kbd_state); | |
668 | + register_ioport_read(0x60, 1, kbd_read_data, 1); | |
669 | + register_ioport_write(0x60, 1, kbd_write_data, 1); | |
670 | + register_ioport_read(0x64, 1, kbd_read_status, 1); | |
671 | + register_ioport_write(0x64, 1, kbd_write_command, 1); | |
672 | +} | ... | ... |
hw/serial.c
0 → 100644
1 | +/* | |
2 | + * QEMU 16450 UART emulation | |
3 | + * | |
4 | + * Copyright (c) 2003-2004 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 <stdlib.h> | |
25 | +#include <stdio.h> | |
26 | +#include <stdarg.h> | |
27 | +#include <string.h> | |
28 | +#include <getopt.h> | |
29 | +#include <inttypes.h> | |
30 | +#include <unistd.h> | |
31 | +#include <sys/mman.h> | |
32 | +#include <fcntl.h> | |
33 | +#include <signal.h> | |
34 | +#include <time.h> | |
35 | +#include <sys/time.h> | |
36 | +#include <malloc.h> | |
37 | +#include <termios.h> | |
38 | +#include <sys/poll.h> | |
39 | +#include <errno.h> | |
40 | +#include <sys/wait.h> | |
41 | +#include <netinet/in.h> | |
42 | + | |
43 | +#include "cpu.h" | |
44 | +#include "vl.h" | |
45 | + | |
46 | +//#define DEBUG_SERIAL | |
47 | + | |
48 | +#define UART_LCR_DLAB 0x80 /* Divisor latch access bit */ | |
49 | + | |
50 | +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ | |
51 | +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ | |
52 | +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ | |
53 | +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ | |
54 | + | |
55 | +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ | |
56 | +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ | |
57 | + | |
58 | +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ | |
59 | +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ | |
60 | +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ | |
61 | +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ | |
62 | + | |
63 | +/* | |
64 | + * These are the definitions for the Modem Control Register | |
65 | + */ | |
66 | +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ | |
67 | +#define UART_MCR_OUT2 0x08 /* Out2 complement */ | |
68 | +#define UART_MCR_OUT1 0x04 /* Out1 complement */ | |
69 | +#define UART_MCR_RTS 0x02 /* RTS complement */ | |
70 | +#define UART_MCR_DTR 0x01 /* DTR complement */ | |
71 | + | |
72 | +/* | |
73 | + * These are the definitions for the Modem Status Register | |
74 | + */ | |
75 | +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ | |
76 | +#define UART_MSR_RI 0x40 /* Ring Indicator */ | |
77 | +#define UART_MSR_DSR 0x20 /* Data Set Ready */ | |
78 | +#define UART_MSR_CTS 0x10 /* Clear to Send */ | |
79 | +#define UART_MSR_DDCD 0x08 /* Delta DCD */ | |
80 | +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ | |
81 | +#define UART_MSR_DDSR 0x02 /* Delta DSR */ | |
82 | +#define UART_MSR_DCTS 0x01 /* Delta CTS */ | |
83 | +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ | |
84 | + | |
85 | +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ | |
86 | +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ | |
87 | +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ | |
88 | +#define UART_LSR_FE 0x08 /* Frame error indicator */ | |
89 | +#define UART_LSR_PE 0x04 /* Parity error indicator */ | |
90 | +#define UART_LSR_OE 0x02 /* Overrun error indicator */ | |
91 | +#define UART_LSR_DR 0x01 /* Receiver data ready */ | |
92 | + | |
93 | +typedef struct SerialState { | |
94 | + uint8_t divider; | |
95 | + uint8_t rbr; /* receive register */ | |
96 | + uint8_t ier; | |
97 | + uint8_t iir; /* read only */ | |
98 | + uint8_t lcr; | |
99 | + uint8_t mcr; | |
100 | + uint8_t lsr; /* read only */ | |
101 | + uint8_t msr; | |
102 | + uint8_t scr; | |
103 | + /* NOTE: this hidden state is necessary for tx irq generation as | |
104 | + it can be reset while reading iir */ | |
105 | + int thr_ipending; | |
106 | + int irq; | |
107 | +} SerialState; | |
108 | + | |
109 | +SerialState serial_ports[1]; | |
110 | + | |
111 | +void serial_update_irq(void) | |
112 | +{ | |
113 | + SerialState *s = &serial_ports[0]; | |
114 | + | |
115 | + if ((s->lsr & UART_LSR_DR) && (s->ier & UART_IER_RDI)) { | |
116 | + s->iir = UART_IIR_RDI; | |
117 | + } else if (s->thr_ipending && (s->ier & UART_IER_THRI)) { | |
118 | + s->iir = UART_IIR_THRI; | |
119 | + } else { | |
120 | + s->iir = UART_IIR_NO_INT; | |
121 | + } | |
122 | + if (s->iir != UART_IIR_NO_INT) { | |
123 | + pic_set_irq(s->irq, 1); | |
124 | + } else { | |
125 | + pic_set_irq(s->irq, 0); | |
126 | + } | |
127 | +} | |
128 | + | |
129 | +void serial_ioport_write(CPUState *env, uint32_t addr, uint32_t val) | |
130 | +{ | |
131 | + SerialState *s = &serial_ports[0]; | |
132 | + unsigned char ch; | |
133 | + int ret; | |
134 | + | |
135 | + addr &= 7; | |
136 | +#ifdef DEBUG_SERIAL | |
137 | + printf("serial: write addr=0x%02x val=0x%02x\n", addr, val); | |
138 | +#endif | |
139 | + switch(addr) { | |
140 | + default: | |
141 | + case 0: | |
142 | + if (s->lcr & UART_LCR_DLAB) { | |
143 | + s->divider = (s->divider & 0xff00) | val; | |
144 | + } else { | |
145 | + s->thr_ipending = 0; | |
146 | + s->lsr &= ~UART_LSR_THRE; | |
147 | + serial_update_irq(); | |
148 | + | |
149 | + ch = val; | |
150 | + do { | |
151 | + ret = write(1, &ch, 1); | |
152 | + } while (ret != 1); | |
153 | + s->thr_ipending = 1; | |
154 | + s->lsr |= UART_LSR_THRE; | |
155 | + s->lsr |= UART_LSR_TEMT; | |
156 | + serial_update_irq(); | |
157 | + } | |
158 | + break; | |
159 | + case 1: | |
160 | + if (s->lcr & UART_LCR_DLAB) { | |
161 | + s->divider = (s->divider & 0x00ff) | (val << 8); | |
162 | + } else { | |
163 | + s->ier = val; | |
164 | + serial_update_irq(); | |
165 | + } | |
166 | + break; | |
167 | + case 2: | |
168 | + break; | |
169 | + case 3: | |
170 | + s->lcr = val; | |
171 | + break; | |
172 | + case 4: | |
173 | + s->mcr = val; | |
174 | + break; | |
175 | + case 5: | |
176 | + break; | |
177 | + case 6: | |
178 | + s->msr = val; | |
179 | + break; | |
180 | + case 7: | |
181 | + s->scr = val; | |
182 | + break; | |
183 | + } | |
184 | +} | |
185 | + | |
186 | +uint32_t serial_ioport_read(CPUState *env, uint32_t addr) | |
187 | +{ | |
188 | + SerialState *s = &serial_ports[0]; | |
189 | + uint32_t ret; | |
190 | + | |
191 | + addr &= 7; | |
192 | + switch(addr) { | |
193 | + default: | |
194 | + case 0: | |
195 | + if (s->lcr & UART_LCR_DLAB) { | |
196 | + ret = s->divider & 0xff; | |
197 | + } else { | |
198 | + ret = s->rbr; | |
199 | + s->lsr &= ~(UART_LSR_DR | UART_LSR_BI); | |
200 | + serial_update_irq(); | |
201 | + } | |
202 | + break; | |
203 | + case 1: | |
204 | + if (s->lcr & UART_LCR_DLAB) { | |
205 | + ret = (s->divider >> 8) & 0xff; | |
206 | + } else { | |
207 | + ret = s->ier; | |
208 | + } | |
209 | + break; | |
210 | + case 2: | |
211 | + ret = s->iir; | |
212 | + /* reset THR pending bit */ | |
213 | + if ((ret & 0x7) == UART_IIR_THRI) | |
214 | + s->thr_ipending = 0; | |
215 | + serial_update_irq(); | |
216 | + break; | |
217 | + case 3: | |
218 | + ret = s->lcr; | |
219 | + break; | |
220 | + case 4: | |
221 | + ret = s->mcr; | |
222 | + break; | |
223 | + case 5: | |
224 | + ret = s->lsr; | |
225 | + break; | |
226 | + case 6: | |
227 | + if (s->mcr & UART_MCR_LOOP) { | |
228 | + /* in loopback, the modem output pins are connected to the | |
229 | + inputs */ | |
230 | + ret = (s->mcr & 0x0c) << 4; | |
231 | + ret |= (s->mcr & 0x02) << 3; | |
232 | + ret |= (s->mcr & 0x01) << 5; | |
233 | + } else { | |
234 | + ret = s->msr; | |
235 | + } | |
236 | + break; | |
237 | + case 7: | |
238 | + ret = s->scr; | |
239 | + break; | |
240 | + } | |
241 | +#ifdef DEBUG_SERIAL | |
242 | + printf("serial: read addr=0x%02x val=0x%02x\n", addr, ret); | |
243 | +#endif | |
244 | + return ret; | |
245 | +} | |
246 | + | |
247 | +int serial_can_receive(void) | |
248 | +{ | |
249 | + SerialState *s = &serial_ports[0]; | |
250 | + return !(s->lsr & UART_LSR_DR); | |
251 | +} | |
252 | + | |
253 | +void serial_receive_byte(int ch) | |
254 | +{ | |
255 | + SerialState *s = &serial_ports[0]; | |
256 | + | |
257 | + s->rbr = ch; | |
258 | + s->lsr |= UART_LSR_DR; | |
259 | + serial_update_irq(); | |
260 | +} | |
261 | + | |
262 | +void serial_receive_break(void) | |
263 | +{ | |
264 | + SerialState *s = &serial_ports[0]; | |
265 | + | |
266 | + s->rbr = 0; | |
267 | + s->lsr |= UART_LSR_BI | UART_LSR_DR; | |
268 | + serial_update_irq(); | |
269 | +} | |
270 | + | |
271 | +void serial_init(int base, int irq) | |
272 | +{ | |
273 | + SerialState *s = &serial_ports[0]; | |
274 | + | |
275 | + s->irq = irq; | |
276 | + s->lsr = UART_LSR_TEMT | UART_LSR_THRE; | |
277 | + s->iir = UART_IIR_NO_INT; | |
278 | + | |
279 | + register_ioport_write(base, 8, serial_ioport_write, 1); | |
280 | + register_ioport_read(base, 8, serial_ioport_read, 1); | |
281 | +} | ... | ... |