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
@@ -12,6 +12,7 @@ version 0.6.2: | @@ -12,6 +12,7 @@ version 0.6.2: | ||
12 | - initial x86_64 target support | 12 | - initial x86_64 target support |
13 | - initial APIC support | 13 | - initial APIC support |
14 | - MMX/SSE/SSE2/PNI support | 14 | - MMX/SSE/SSE2/PNI support |
15 | + - PC parallel port support (Mark Jonckheere) | ||
15 | 16 | ||
16 | version 0.6.1: | 17 | version 0.6.1: |
17 | 18 |
Makefile.target
@@ -316,7 +316,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) | @@ -316,7 +316,7 @@ ifeq ($(TARGET_BASE_ARCH), i386) | ||
316 | # Hardware support | 316 | # Hardware support |
317 | VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) | 317 | VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) |
318 | VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o | 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 | endif | 320 | endif |
321 | ifeq ($(TARGET_ARCH), ppc) | 321 | ifeq ($(TARGET_ARCH), ppc) |
322 | VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) | 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,6 +376,9 @@ static int ne2000_irq[NE2000_NB_MAX] = { 9, 10, 11, 3, 4, 5 }; | ||
376 | static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; | 376 | static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; |
377 | static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; | 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 | /* PC hardware initialisation */ | 382 | /* PC hardware initialisation */ |
380 | void pc_init(int ram_size, int vga_ram_size, int boot_device, | 383 | void pc_init(int ram_size, int vga_ram_size, int boot_device, |
381 | DisplayState *ds, const char **fd_filename, int snapshot, | 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,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 | if (pci_enabled) { | 550 | if (pci_enabled) { |
542 | for(i = 0; i < nb_nics; i++) { | 551 | for(i = 0; i < nb_nics; i++) { |
543 | pci_ne2000_init(pci_bus, &nd_table[i]); | 552 | pci_ne2000_init(pci_bus, &nd_table[i]); |
vl.c
@@ -136,6 +136,7 @@ int graphic_depth = 15; | @@ -136,6 +136,7 @@ int graphic_depth = 15; | ||
136 | int full_screen = 0; | 136 | int full_screen = 0; |
137 | TextConsole *vga_console; | 137 | TextConsole *vga_console; |
138 | CharDriverState *serial_hds[MAX_SERIAL_PORTS]; | 138 | CharDriverState *serial_hds[MAX_SERIAL_PORTS]; |
139 | +CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; | ||
139 | 140 | ||
140 | /***********************************************************/ | 141 | /***********************************************************/ |
141 | /* x86 ISA bus support */ | 142 | /* x86 ISA bus support */ |
@@ -2750,6 +2751,7 @@ void help(void) | @@ -2750,6 +2751,7 @@ void help(void) | ||
2750 | "Debug/Expert options:\n" | 2751 | "Debug/Expert options:\n" |
2751 | "-monitor dev redirect the monitor to char device 'dev'\n" | 2752 | "-monitor dev redirect the monitor to char device 'dev'\n" |
2752 | "-serial dev redirect the serial port to char device 'dev'\n" | 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 | "-pidfile file Write PID to 'file'\n" | 2755 | "-pidfile file Write PID to 'file'\n" |
2754 | "-S freeze CPU at startup (use 'c' to start execution)\n" | 2756 | "-S freeze CPU at startup (use 'c' to start execution)\n" |
2755 | "-s wait gdb connection to port %d\n" | 2757 | "-s wait gdb connection to port %d\n" |
@@ -2842,6 +2844,7 @@ enum { | @@ -2842,6 +2844,7 @@ enum { | ||
2842 | QEMU_OPTION_std_vga, | 2844 | QEMU_OPTION_std_vga, |
2843 | QEMU_OPTION_monitor, | 2845 | QEMU_OPTION_monitor, |
2844 | QEMU_OPTION_serial, | 2846 | QEMU_OPTION_serial, |
2847 | + QEMU_OPTION_parallel, | ||
2845 | QEMU_OPTION_loadvm, | 2848 | QEMU_OPTION_loadvm, |
2846 | QEMU_OPTION_full_screen, | 2849 | QEMU_OPTION_full_screen, |
2847 | QEMU_OPTION_pidfile, | 2850 | QEMU_OPTION_pidfile, |
@@ -2904,6 +2907,7 @@ const QEMUOption qemu_options[] = { | @@ -2904,6 +2907,7 @@ const QEMUOption qemu_options[] = { | ||
2904 | { "std-vga", 0, QEMU_OPTION_std_vga }, | 2907 | { "std-vga", 0, QEMU_OPTION_std_vga }, |
2905 | { "monitor", 1, QEMU_OPTION_monitor }, | 2908 | { "monitor", 1, QEMU_OPTION_monitor }, |
2906 | { "serial", 1, QEMU_OPTION_serial }, | 2909 | { "serial", 1, QEMU_OPTION_serial }, |
2910 | + { "parallel", 1, QEMU_OPTION_parallel }, | ||
2907 | { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, | 2911 | { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, |
2908 | { "full-screen", 0, QEMU_OPTION_full_screen }, | 2912 | { "full-screen", 0, QEMU_OPTION_full_screen }, |
2909 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, | 2913 | { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, |
@@ -2986,6 +2990,8 @@ int main(int argc, char **argv) | @@ -2986,6 +2990,8 @@ int main(int argc, char **argv) | ||
2986 | char monitor_device[128]; | 2990 | char monitor_device[128]; |
2987 | char serial_devices[MAX_SERIAL_PORTS][128]; | 2991 | char serial_devices[MAX_SERIAL_PORTS][128]; |
2988 | int serial_device_index; | 2992 | int serial_device_index; |
2993 | + char parallel_devices[MAX_PARALLEL_PORTS][128]; | ||
2994 | + int parallel_device_index; | ||
2989 | const char *loadvm = NULL; | 2995 | const char *loadvm = NULL; |
2990 | 2996 | ||
2991 | #if !defined(CONFIG_SOFTMMU) | 2997 | #if !defined(CONFIG_SOFTMMU) |
@@ -3019,6 +3025,11 @@ int main(int argc, char **argv) | @@ -3019,6 +3025,11 @@ int main(int argc, char **argv) | ||
3019 | serial_devices[i][0] = '\0'; | 3025 | serial_devices[i][0] = '\0'; |
3020 | serial_device_index = 0; | 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 | nb_tun_fds = 0; | 3033 | nb_tun_fds = 0; |
3023 | net_if_type = -1; | 3034 | net_if_type = -1; |
3024 | nb_nics = 1; | 3035 | nb_nics = 1; |
@@ -3115,6 +3126,7 @@ int main(int argc, char **argv) | @@ -3115,6 +3126,7 @@ int main(int argc, char **argv) | ||
3115 | case QEMU_OPTION_nographic: | 3126 | case QEMU_OPTION_nographic: |
3116 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); | 3127 | pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); |
3117 | pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); | 3128 | pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); |
3129 | + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "stdio"); | ||
3118 | nographic = 1; | 3130 | nographic = 1; |
3119 | break; | 3131 | break; |
3120 | case QEMU_OPTION_kernel: | 3132 | case QEMU_OPTION_kernel: |
@@ -3329,6 +3341,15 @@ int main(int argc, char **argv) | @@ -3329,6 +3341,15 @@ int main(int argc, char **argv) | ||
3329 | sizeof(serial_devices[0]), optarg); | 3341 | sizeof(serial_devices[0]), optarg); |
3330 | serial_device_index++; | 3342 | serial_device_index++; |
3331 | break; | 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 | case QEMU_OPTION_loadvm: | 3353 | case QEMU_OPTION_loadvm: |
3333 | loadvm = optarg; | 3354 | loadvm = optarg; |
3334 | break; | 3355 | break; |
@@ -3552,6 +3573,19 @@ int main(int argc, char **argv) | @@ -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 | /* setup cpu signal handlers for MMU / self modifying code handling */ | 3589 | /* setup cpu signal handlers for MMU / self modifying code handling */ |
3556 | #if !defined(CONFIG_SOFTMMU) | 3590 | #if !defined(CONFIG_SOFTMMU) |
3557 | 3591 |
vl.h
@@ -224,6 +224,12 @@ void console_select(unsigned int index); | @@ -224,6 +224,12 @@ void console_select(unsigned int index); | ||
224 | 224 | ||
225 | extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; | 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 | /* network redirectors support */ | 233 | /* network redirectors support */ |
228 | 234 | ||
229 | #define MAX_NICS 8 | 235 | #define MAX_NICS 8 |
@@ -632,6 +638,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm); | @@ -632,6 +638,11 @@ void rtc_set_date(RTCState *s, const struct tm *tm); | ||
632 | typedef struct SerialState SerialState; | 638 | typedef struct SerialState SerialState; |
633 | SerialState *serial_init(int base, int irq, CharDriverState *chr); | 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 | /* i8259.c */ | 646 | /* i8259.c */ |
636 | 647 | ||
637 | void pic_set_irq(int irq, int level); | 648 | void pic_set_irq(int irq, int level); |