Commit 6508fe59e07b263a8f9afd0f5f13e6240651f42c
1 parent
e5843bc8
PC parallel port support (Mark Jonckheere)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1221 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
244 additions
and
1 deletions
Changelog
Makefile.target
... | ... | @@ -316,7 +316,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) |
316 | 316 | # Hardware support |
317 | 317 | VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) |
318 | 318 | VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o |
319 | -VL_OBJS+= cirrus_vga.o mixeng.o apic.o | |
319 | +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o | |
320 | 320 | endif |
321 | 321 | ifeq ($(TARGET_ARCH), ppc) |
322 | 322 | VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) | ... | ... |
hw/parallel.c
0 → 100644
1 | +/* | |
2 | + * QEMU Parallel PORT 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 "vl.h" | |
25 | + | |
26 | +//#define DEBUG_PARALLEL | |
27 | + | |
28 | +/* | |
29 | + * These are the definitions for the Printer Status Register | |
30 | + */ | |
31 | +#define PARA_STS_BUSY 0x80 /* Busy complement */ | |
32 | +#define PARA_STS_ACK 0x40 /* Acknowledge */ | |
33 | +#define PARA_STS_PAPER 0x20 /* Out of paper */ | |
34 | +#define PARA_STS_ONLINE 0x10 /* Online */ | |
35 | +#define PARA_STS_ERROR 0x08 /* Error complement */ | |
36 | + | |
37 | +/* | |
38 | + * These are the definitions for the Printer Control Register | |
39 | + */ | |
40 | +#define PARA_CTR_INTEN 0x10 /* IRQ Enable */ | |
41 | +#define PARA_CTR_SELECT 0x08 /* Select In complement */ | |
42 | +#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ | |
43 | +#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ | |
44 | +#define PARA_CTR_STROBE 0x01 /* Strobe complement */ | |
45 | + | |
46 | +struct ParallelState { | |
47 | + uint8_t data; | |
48 | + uint8_t status; /* read only register */ | |
49 | + uint8_t control; | |
50 | + int irq; | |
51 | + int irq_pending; | |
52 | + CharDriverState *chr; | |
53 | +}; | |
54 | + | |
55 | +static void parallel_update_irq(ParallelState *s) | |
56 | +{ | |
57 | + if (s->irq_pending) | |
58 | + pic_set_irq(s->irq, 1); | |
59 | + else | |
60 | + pic_set_irq(s->irq, 0); | |
61 | +} | |
62 | + | |
63 | +static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) | |
64 | +{ | |
65 | + ParallelState *s = opaque; | |
66 | + | |
67 | + addr &= 7; | |
68 | +#ifdef DEBUG_PARALLEL | |
69 | + printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); | |
70 | +#endif | |
71 | + switch(addr) { | |
72 | + case 0: | |
73 | + s->data = val; | |
74 | + parallel_update_irq(s); | |
75 | + break; | |
76 | + case 2: | |
77 | + if ((val & PARA_CTR_INIT) == 0 ) { | |
78 | + s->status = PARA_STS_BUSY; | |
79 | + s->status |= PARA_STS_ACK; | |
80 | + s->status |= PARA_STS_ONLINE; | |
81 | + s->status |= PARA_STS_ERROR; | |
82 | + } | |
83 | + else if (val & PARA_CTR_SELECT) { | |
84 | + if (val & PARA_CTR_STROBE) { | |
85 | + s->status &= ~PARA_STS_BUSY; | |
86 | + if ((s->control & PARA_CTR_STROBE) == 0) | |
87 | + qemu_chr_write(s->chr, &s->data, 1); | |
88 | + } else { | |
89 | + if (s->control & PARA_CTR_INTEN) { | |
90 | + s->irq_pending = 1; | |
91 | + } | |
92 | + } | |
93 | + } | |
94 | + parallel_update_irq(s); | |
95 | + s->control = val; | |
96 | + break; | |
97 | + } | |
98 | +} | |
99 | + | |
100 | +static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) | |
101 | +{ | |
102 | + ParallelState *s = opaque; | |
103 | + uint32_t ret = 0xff; | |
104 | + | |
105 | + addr &= 7; | |
106 | + switch(addr) { | |
107 | + case 0: | |
108 | + ret = s->data; | |
109 | + break; | |
110 | + case 1: | |
111 | + ret = s->status; | |
112 | + s->irq_pending = 0; | |
113 | + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { | |
114 | + /* XXX Fixme: wait 5 microseconds */ | |
115 | + if (s->status & PARA_STS_ACK) | |
116 | + s->status &= ~PARA_STS_ACK; | |
117 | + else { | |
118 | + /* XXX Fixme: wait 5 microseconds */ | |
119 | + s->status |= PARA_STS_ACK; | |
120 | + s->status |= PARA_STS_BUSY; | |
121 | + } | |
122 | + } | |
123 | + parallel_update_irq(s); | |
124 | + break; | |
125 | + case 2: | |
126 | + ret = s->control; | |
127 | + break; | |
128 | + } | |
129 | +#ifdef DEBUG_PARALLEL | |
130 | + printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); | |
131 | +#endif | |
132 | + return ret; | |
133 | +} | |
134 | + | |
135 | +static int parallel_can_receive(ParallelState *s) | |
136 | +{ | |
137 | + return 0; | |
138 | +} | |
139 | + | |
140 | +static void parallel_receive_byte(ParallelState *s, int ch) | |
141 | +{ | |
142 | +} | |
143 | + | |
144 | +static void parallel_receive_break(ParallelState *s) | |
145 | +{ | |
146 | +} | |
147 | + | |
148 | +static int parallel_can_receive1(void *opaque) | |
149 | +{ | |
150 | + ParallelState *s = opaque; | |
151 | + return parallel_can_receive(s); | |
152 | +} | |
153 | + | |
154 | +static void parallel_receive1(void *opaque, const uint8_t *buf, int size) | |
155 | +{ | |
156 | + ParallelState *s = opaque; | |
157 | + parallel_receive_byte(s, buf[0]); | |
158 | +} | |
159 | + | |
160 | +static void parallel_event(void *opaque, int event) | |
161 | +{ | |
162 | + ParallelState *s = opaque; | |
163 | +} | |
164 | + | |
165 | +/* If fd is zero, it means that the parallel device uses the console */ | |
166 | +ParallelState *parallel_init(int base, int irq, CharDriverState *chr) | |
167 | +{ | |
168 | + ParallelState *s; | |
169 | + | |
170 | + s = qemu_mallocz(sizeof(ParallelState)); | |
171 | + if (!s) | |
172 | + return NULL; | |
173 | + s->irq = irq; | |
174 | + s->data = 0; | |
175 | + s->status = PARA_STS_BUSY; | |
176 | + s->status |= PARA_STS_ACK; | |
177 | + s->status |= PARA_STS_ONLINE; | |
178 | + s->status |= PARA_STS_ERROR; | |
179 | + s->control = PARA_CTR_SELECT; | |
180 | + s->control |= PARA_CTR_INIT; | |
181 | + | |
182 | + register_ioport_write(base, 8, 1, parallel_ioport_write, s); | |
183 | + register_ioport_read(base, 8, 1, parallel_ioport_read, s); | |
184 | + s->chr = chr; | |
185 | + qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); | |
186 | + qemu_chr_add_event_handler(chr, parallel_event); | |
187 | + return s; | |
188 | +} | ... | ... |
hw/pc.c
... | ... | @@ -376,6 +376,9 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; |
376 | 376 | static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
377 | 377 | static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; |
378 | 378 | |
379 | +static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; | |
380 | +static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; | |
381 | + | |
379 | 382 | /* PC hardware initialisation */ |
380 | 383 | void pc_init(int ram_size, int vga_ram_size, int boot_device, |
381 | 384 | DisplayState *ds, const char **fd_filename, int snapshot, |
... | ... | @@ -538,6 +541,12 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device, |
538 | 541 | } |
539 | 542 | } |
540 | 543 | |
544 | + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { | |
545 | + if (parallel_hds[i]) { | |
546 | + parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); | |
547 | + } | |
548 | + } | |
549 | + | |
541 | 550 | if (pci_enabled) { |
542 | 551 | for(i = 0; i < nb_nics; i++) { |
543 | 552 | pci_ne2000_init(pci_bus, &nd_table[i]); | ... | ... |
vl.c
... | ... | @@ -136,6 +136,7 @@ int graphic_depth = 15; |
136 | 136 | int full_screen = 0; |
137 | 137 | TextConsole *vga_console; |
138 | 138 | CharDriverState *serial_hds[MAX_SERIAL_PORTS]; |
139 | +CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; | |
139 | 140 | |
140 | 141 | /***********************************************************/ |
141 | 142 | /* x86 ISA bus support */ |
... | ... | @@ -2750,6 +2751,7 @@ void help(void) |
2750 | 2751 | "Debug/Expert options:\n" |
2751 | 2752 | "-monitor dev redirect the monitor to char device 'dev'\n" |
2752 | 2753 | "-serial dev redirect the serial port to char device 'dev'\n" |
2754 | + "-parallel dev redirect the parallel port to char device 'dev'\n" | |
2753 | 2755 | "-pidfile file Write PID to 'file'\n" |
2754 | 2756 | "-S freeze CPU at startup (use 'c' to start execution)\n" |
2755 | 2757 | "-s wait gdb connection to port %d\n" |
... | ... | @@ -2842,6 +2844,7 @@ enum { |
2842 | 2844 | QEMU_OPTION_std_vga, |
2843 | 2845 | QEMU_OPTION_monitor, |
2844 | 2846 | QEMU_OPTION_serial, |
2847 | + QEMU_OPTION_parallel, | |
2845 | 2848 | QEMU_OPTION_loadvm, |
2846 | 2849 | QEMU_OPTION_full_screen, |
2847 | 2850 | QEMU_OPTION_pidfile, |
... | ... | @@ -2904,6 +2907,7 @@ const QEMUOption qemu_options[] = { |
2904 | 2907 | { "std-vga", 0, QEMU_OPTION_std_vga }, |
2905 | 2908 | { "monitor", 1, QEMU_OPTION_monitor }, |
2906 | 2909 | { "serial", 1, QEMU_OPTION_serial }, |
2910 | + { "parallel", 1, QEMU_OPTION_parallel }, | |
2907 | 2911 | { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, |
2908 | 2912 | { "full-screen", 0, QEMU_OPTION_full_screen }, |
2909 | 2913 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, |
... | ... | @@ -2986,6 +2990,8 @@ int main(int argc, char **argv) |
2986 | 2990 | char monitor_device[128]; |
2987 | 2991 | char serial_devices[MAX_SERIAL_PORTS][128]; |
2988 | 2992 | int serial_device_index; |
2993 | + char parallel_devices[MAX_PARALLEL_PORTS][128]; | |
2994 | + int parallel_device_index; | |
2989 | 2995 | const char *loadvm = NULL; |
2990 | 2996 | |
2991 | 2997 | #if !defined(CONFIG_SOFTMMU) |
... | ... | @@ -3019,6 +3025,11 @@ int main(int argc, char **argv) |
3019 | 3025 | serial_devices[i][0] = '\0'; |
3020 | 3026 | serial_device_index = 0; |
3021 | 3027 | |
3028 | + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); | |
3029 | + for(i = 1; i < MAX_PARALLEL_PORTS; i++) | |
3030 | + parallel_devices[i][0] = '\0'; | |
3031 | + parallel_device_index = 0; | |
3032 | + | |
3022 | 3033 | nb_tun_fds = 0; |
3023 | 3034 | net_if_type = -1; |
3024 | 3035 | nb_nics = 1; |
... | ... | @@ -3115,6 +3126,7 @@ int main(int argc, char **argv) |
3115 | 3126 | case QEMU_OPTION_nographic: |
3116 | 3127 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
3117 | 3128 | pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); |
3129 | + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "stdio"); | |
3118 | 3130 | nographic = 1; |
3119 | 3131 | break; |
3120 | 3132 | case QEMU_OPTION_kernel: |
... | ... | @@ -3329,6 +3341,15 @@ int main(int argc, char **argv) |
3329 | 3341 | sizeof(serial_devices[0]), optarg); |
3330 | 3342 | serial_device_index++; |
3331 | 3343 | break; |
3344 | + case QEMU_OPTION_parallel: | |
3345 | + if (parallel_device_index >= MAX_PARALLEL_PORTS) { | |
3346 | + fprintf(stderr, "qemu: too many parallel ports\n"); | |
3347 | + exit(1); | |
3348 | + } | |
3349 | + pstrcpy(parallel_devices[parallel_device_index], | |
3350 | + sizeof(parallel_devices[0]), optarg); | |
3351 | + parallel_device_index++; | |
3352 | + break; | |
3332 | 3353 | case QEMU_OPTION_loadvm: |
3333 | 3354 | loadvm = optarg; |
3334 | 3355 | break; |
... | ... | @@ -3552,6 +3573,19 @@ int main(int argc, char **argv) |
3552 | 3573 | } |
3553 | 3574 | } |
3554 | 3575 | |
3576 | + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { | |
3577 | + if (parallel_devices[i][0] != '\0') { | |
3578 | + parallel_hds[i] = qemu_chr_open(parallel_devices[i]); | |
3579 | + if (!parallel_hds[i]) { | |
3580 | + fprintf(stderr, "qemu: could not open parallel device '%s'\n", | |
3581 | + parallel_devices[i]); | |
3582 | + exit(1); | |
3583 | + } | |
3584 | + if (!strcmp(parallel_devices[i], "vc")) | |
3585 | + qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i); | |
3586 | + } | |
3587 | + } | |
3588 | + | |
3555 | 3589 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
3556 | 3590 | #if !defined(CONFIG_SOFTMMU) |
3557 | 3591 | ... | ... |
vl.h
... | ... | @@ -224,6 +224,12 @@ void console_select(unsigned int index); |
224 | 224 | |
225 | 225 | extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; |
226 | 226 | |
227 | +/* parallel ports */ | |
228 | + | |
229 | +#define MAX_PARALLEL_PORTS 3 | |
230 | + | |
231 | +extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; | |
232 | + | |
227 | 233 | /* network redirectors support */ |
228 | 234 | |
229 | 235 | #define MAX_NICS 8 |
... | ... | @@ -632,6 +638,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm); |
632 | 638 | typedef struct SerialState SerialState; |
633 | 639 | SerialState *serial_init(int base, int irq, CharDriverState *chr); |
634 | 640 | |
641 | +/* parallel.c */ | |
642 | + | |
643 | +typedef struct ParallelState ParallelState; | |
644 | +ParallelState *parallel_init(int base, int irq, CharDriverState *chr); | |
645 | + | |
635 | 646 | /* i8259.c */ |
636 | 647 | |
637 | 648 | void pic_set_irq(int irq, int level); | ... | ... |