From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1CmyQ7-00059C-NY for qemu-devel@nongnu.org; Fri, 07 Jan 2005 13:01:07 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1CmyQ6-00058Z-MA for qemu-devel@nongnu.org; Fri, 07 Jan 2005 13:01:07 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1CmyQ6-00058T-IS for qemu-devel@nongnu.org; Fri, 07 Jan 2005 13:01:06 -0500 Received: from [195.238.2.116] (helo=outmx017.isp.belgacom.be) by monty-python.gnu.org with esmtp (Exim 4.34) id 1CmyEJ-0000H8-Bp for qemu-devel@nongnu.org; Fri, 07 Jan 2005 12:48:55 -0500 Received: from outmx017.isp.belgacom.be (localhost [127.0.0.1]) by outmx017.isp.belgacom.be (8.12.11/8.12.11/Skynet-OUT-2.22) with ESMTP id j07HmmHg026412 for ; Fri, 7 Jan 2005 18:48:48 +0100 (envelope-from ) Received: from easynet.be (114-191.242.81.adsl.skynet.be [81.242.191.114]) by outmx017.isp.belgacom.be (8.12.11/8.12.11/Skynet-OUT-2.22) with ESMTP id j07Hmi5D026383 for ; Fri, 7 Jan 2005 18:48:44 +0100 (envelope-from ) Message-ID: <41DECDFE.1010801@easynet.be> Date: Fri, 07 Jan 2005 18:59:26 +0100 From: Mark Jonckheere MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------080508050401050807040306" Subject: [Qemu-devel] [PATCH] parallel port support for qemu. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org This is a multi-part message in MIME format. --------------080508050401050807040306 Content-Type: text/plain; charset=ISO-8859-15; format=flowed Content-Transfer-Encoding: 7bit This patch adds parallel printer ports to the emulated pc hardware. The code in hw/parallel.c has been derived from hw/serial.c. It has been tested on a linux host with a MSDOS-5 and a Knoppix 3.3 guest. What is missing: - EPP/ECP/IEEE-1284 mode. - redirecting printer output to an arbitrary filename. - redirecting printer output to a print spool. - redirecting printer output to a physical device. - an easy way to flush a spool before qemu is terminated: a fixed timeout, a formfeed character, a "flush" command, a key sequence, or something else, ... ? - documentation. If you like it, give it a try. Groeten, Mark. -- :wq --------------080508050401050807040306 Content-Type: text/plain; name="parallel.diff" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="parallel.diff" diff -urN qemu/Makefile.target qemu_parallel/Makefile.target --- qemu/Makefile.target Tue Jan 4 00:38:39 2005 +++ qemu_parallel/Makefile.target Fri Jan 7 13:41:31 2005 @@ -316,7 +316,7 @@ # Hardware support VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o -VL_OBJS+= cirrus_vga.o mixeng.o apic.o +VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o endif ifeq ($(TARGET_ARCH), ppc) VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) diff -urN qemu/hw/parallel.c qemu_parallel/hw/parallel.c --- qemu/hw/parallel.c Thu Jan 1 01:00:00 1970 +++ qemu_parallel/hw/parallel.c Fri Jan 7 17:25:35 2005 @@ -0,0 +1,188 @@ +/* + * QEMU Parallel PORT emulation + * + * Copyright (c) 2003-2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "vl.h" + +//#define DEBUG_PARALLEL + +/* + * These are the definitions for the Printer Status Register + */ +#define PARA_STS_BUSY 0x80 /* Busy complement */ +#define PARA_STS_ACK 0x40 /* Acknowledge */ +#define PARA_STS_PAPER 0x20 /* Out of paper */ +#define PARA_STS_ONLINE 0x10 /* Online */ +#define PARA_STS_ERROR 0x08 /* Error complement */ + +/* + * These are the definitions for the Printer Control Register + */ +#define PARA_CTR_INTEN 0x10 /* IRQ Enable */ +#define PARA_CTR_SELECT 0x08 /* Select In complement */ +#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */ +#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */ +#define PARA_CTR_STROBE 0x01 /* Strobe complement */ + +struct ParallelState { + uint8_t data; + uint8_t status; /* read only register */ + uint8_t control; + int irq; + int irq_pending; + CharDriverState *chr; +}; + +static void parallel_update_irq(ParallelState *s) +{ + if (s->irq_pending) + pic_set_irq(s->irq, 1); + else + pic_set_irq(s->irq, 0); +} + +static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val) +{ + ParallelState *s = opaque; + + addr &= 7; +#ifdef DEBUG_PARALLEL + printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val); +#endif + switch(addr) { + case 0: + s->data = val; + parallel_update_irq(s); + break; + case 2: + if ((val & PARA_CTR_INIT) == 0 ) { + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + } + else if (val & PARA_CTR_SELECT) { + if (val & PARA_CTR_STROBE) { + s->status &= ~PARA_STS_BUSY; + if ((s->control & PARA_CTR_STROBE) == 0) + qemu_chr_write(s->chr, &s->data, 1); + } else { + if (s->control & PARA_CTR_INTEN) { + s->irq_pending = 1; + } + } + } + parallel_update_irq(s); + s->control = val; + break; + } +} + +static uint32_t parallel_ioport_read(void *opaque, uint32_t addr) +{ + ParallelState *s = opaque; + uint32_t ret = 0xff; + + addr &= 7; + switch(addr) { + case 0: + ret = s->data; + break; + case 1: + ret = s->status; + s->irq_pending = 0; + if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) { + /* XXX Fixme: wait 5 microseconds */ + if (s->status & PARA_STS_ACK) + s->status &= ~PARA_STS_ACK; + else { + /* XXX Fixme: wait 5 microseconds */ + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_BUSY; + } + } + parallel_update_irq(s); + break; + case 2: + ret = s->control; + break; + } +#ifdef DEBUG_PARALLEL + printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret); +#endif + return ret; +} + +static int parallel_can_receive(ParallelState *s) +{ + return 0; +} + +static void parallel_receive_byte(ParallelState *s, int ch) +{ +} + +static void parallel_receive_break(ParallelState *s) +{ +} + +static int parallel_can_receive1(void *opaque) +{ + ParallelState *s = opaque; + return parallel_can_receive(s); +} + +static void parallel_receive1(void *opaque, const uint8_t *buf, int size) +{ + ParallelState *s = opaque; + parallel_receive_byte(s, buf[0]); +} + +static void parallel_event(void *opaque, int event) +{ + ParallelState *s = opaque; +} + +/* If fd is zero, it means that the parallel device uses the console */ +ParallelState *parallel_init(int base, int irq, CharDriverState *chr) +{ + ParallelState *s; + + s = qemu_mallocz(sizeof(ParallelState)); + if (!s) + return NULL; + s->irq = irq; + s->data = 0; + s->status = PARA_STS_BUSY; + s->status |= PARA_STS_ACK; + s->status |= PARA_STS_ONLINE; + s->status |= PARA_STS_ERROR; + s->control = PARA_CTR_SELECT; + s->control |= PARA_CTR_INIT; + + register_ioport_write(base, 8, 1, parallel_ioport_write, s); + register_ioport_read(base, 8, 1, parallel_ioport_read, s); + s->chr = chr; + qemu_chr_add_read_handler(chr, parallel_can_receive1, parallel_receive1, s); + qemu_chr_add_event_handler(chr, parallel_event); + return s; +} diff -urN qemu/hw/pc.c qemu_parallel/hw/pc.c --- qemu/hw/pc.c Tue Jan 4 00:30:09 2005 +++ qemu_parallel/hw/pc.c Fri Jan 7 14:06:31 2005 @@ -376,6 +376,9 @@ static int serial_io[MAX_SERIAL_PORTS] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 }; static int serial_irq[MAX_SERIAL_PORTS] = { 4, 3, 4, 3 }; +static int parallel_io[MAX_PARALLEL_PORTS] = { 0x378, 0x278, 0x3bc }; +static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 }; + /* PC hardware initialisation */ void pc_init(int ram_size, int vga_ram_size, int boot_device, DisplayState *ds, const char **fd_filename, int snapshot, @@ -538,6 +541,12 @@ } } + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_hds[i]) { + parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]); + } + } + if (pci_enabled) { for(i = 0; i < nb_nics; i++) { pci_ne2000_init(pci_bus, &nd_table[i]); diff -urN qemu/vl.c qemu_parallel/vl.c --- qemu/vl.c Thu Jan 6 21:43:38 2005 +++ qemu_parallel/vl.c Fri Jan 7 14:04:13 2005 @@ -136,6 +136,7 @@ int full_screen = 0; TextConsole *vga_console; CharDriverState *serial_hds[MAX_SERIAL_PORTS]; +CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; /***********************************************************/ /* x86 ISA bus support */ @@ -2671,6 +2672,7 @@ "Debug/Expert options:\n" "-monitor dev redirect the monitor to char device 'dev'\n" "-serial dev redirect the serial port to char device 'dev'\n" + "-parallel dev redirect the parallel port to char device 'dev'\n" "-pidfile file Write PID to 'file'\n" "-S freeze CPU at startup (use 'c' to start execution)\n" "-s wait gdb connection to port %d\n" @@ -2763,6 +2765,7 @@ QEMU_OPTION_std_vga, QEMU_OPTION_monitor, QEMU_OPTION_serial, + QEMU_OPTION_parallel, QEMU_OPTION_loadvm, QEMU_OPTION_full_screen, QEMU_OPTION_pidfile, @@ -2825,6 +2828,7 @@ { "std-vga", 0, QEMU_OPTION_std_vga }, { "monitor", 1, QEMU_OPTION_monitor }, { "serial", 1, QEMU_OPTION_serial }, + { "parallel", 1, QEMU_OPTION_parallel }, { "loadvm", HAS_ARG, QEMU_OPTION_loadvm }, { "full-screen", 0, QEMU_OPTION_full_screen }, { "pidfile", HAS_ARG, QEMU_OPTION_pidfile }, @@ -2907,6 +2911,8 @@ char monitor_device[128]; char serial_devices[MAX_SERIAL_PORTS][128]; int serial_device_index; + char parallel_devices[MAX_PARALLEL_PORTS][128]; + int parallel_device_index; const char *loadvm = NULL; #if !defined(CONFIG_SOFTMMU) @@ -2940,6 +2946,11 @@ serial_devices[i][0] = '\0'; serial_device_index = 0; + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "vc"); + for(i = 1; i < MAX_PARALLEL_PORTS; i++) + parallel_devices[i][0] = '\0'; + parallel_device_index = 0; + nb_tun_fds = 0; net_if_type = -1; nb_nics = 1; @@ -3036,6 +3047,7 @@ case QEMU_OPTION_nographic: pstrcpy(monitor_device, sizeof(monitor_device), "stdio"); pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio"); + pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "stdio"); nographic = 1; break; case QEMU_OPTION_kernel: @@ -3250,6 +3262,15 @@ sizeof(serial_devices[0]), optarg); serial_device_index++; break; + case QEMU_OPTION_parallel: + if (parallel_device_index >= MAX_PARALLEL_PORTS) { + fprintf(stderr, "qemu: too many parallel ports\n"); + exit(1); + } + pstrcpy(parallel_devices[parallel_device_index], + sizeof(parallel_devices[0]), optarg); + parallel_device_index++; + break; case QEMU_OPTION_loadvm: loadvm = optarg; break; @@ -3473,6 +3494,19 @@ } } + for(i = 0; i < MAX_PARALLEL_PORTS; i++) { + if (parallel_devices[i][0] != '\0') { + parallel_hds[i] = qemu_chr_open(parallel_devices[i]); + if (!parallel_hds[i]) { + fprintf(stderr, "qemu: could not open parallel device '%s'\n", + parallel_devices[i]); + exit(1); + } + if (!strcmp(parallel_devices[i], "vc")) + qemu_chr_printf(parallel_hds[i], "parallel%d console\n", i); + } + } + /* setup cpu signal handlers for MMU / self modifying code handling */ #if !defined(CONFIG_SOFTMMU) diff -urN qemu/vl.h qemu_parallel/vl.h --- qemu/vl.h Tue Jan 4 00:28:03 2005 +++ qemu_parallel/vl.h Fri Jan 7 13:54:29 2005 @@ -224,6 +224,12 @@ extern CharDriverState *serial_hds[MAX_SERIAL_PORTS]; +/* parallel ports */ + +#define MAX_PARALLEL_PORTS 3 + +extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS]; + /* network redirectors support */ #define MAX_NICS 8 @@ -632,6 +638,11 @@ typedef struct SerialState SerialState; SerialState *serial_init(int base, int irq, CharDriverState *chr); +/* parallel.c */ + +typedef struct ParallelState ParallelState; +ParallelState *parallel_init(int base, int irq, CharDriverState *chr); + /* i8259.c */ void pic_set_irq(int irq, int level); --------------080508050401050807040306--