]> git.proxmox.com Git - qemu.git/commitdiff
low level host parallel port access
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 10 Nov 2005 23:58:52 +0000 (23:58 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Thu, 10 Nov 2005 23:58:52 +0000 (23:58 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1611 c046a42c-6fe2-441c-8c8c-71466251a162

Changelog
hw/parallel.c
qemu-doc.texi
vl.c

index 32c417b6f836673c55796085a802f199e1d2c7dd..6b8420fd9385293616b505556cf176dd2f492411 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -8,6 +8,7 @@ version 0.7.3:
   - ES1370 PCI audio device (malc)
   - Initial USB support
   - Linux host serial port access
+  - Linux host low level parallel port access
 
 version 0.7.2:
   
index a304d7fdf7ae24b4fcea7a5319f5e2460de45e04..95ac7fd688a10383451b0c37dfee18c0918377a9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * QEMU Parallel PORT emulation
  * 
- * Copyright (c) 2003-2004 Fabrice Bellard
+ * Copyright (c) 2003-2005 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
@@ -50,6 +50,7 @@ struct ParallelState {
     int irq;
     int irq_pending;
     CharDriverState *chr;
+    int hw_driver;
 };
 
 static void parallel_update_irq(ParallelState *s)
@@ -70,29 +71,39 @@ static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
 #endif
     switch(addr) {
     case 0:
-        s->data = val;
-        parallel_update_irq(s);
+        if (s->hw_driver) {
+            s->data = val;
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data);
+        } else {
+            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;
+        if (s->hw_driver) {
+            s->control = val;
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control);
+        } else {
+            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;
         }
-        parallel_update_irq(s);
-        s->control = val;
         break;
     }
 }
@@ -105,24 +116,35 @@ static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
     addr &= 7;
     switch(addr) {
     case 0:
+        if (s->hw_driver) {
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data);
+        } 
         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;
+        if (s->hw_driver) {
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status);
+            ret = s->status; 
+        } else {
+            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);
         }
-        parallel_update_irq(s);
         break;
     case 2:
+        if (s->hw_driver) {
+            qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
+        }
         ret = s->control;
         break;
     }
@@ -153,18 +175,20 @@ static void parallel_receive1(void *opaque, const uint8_t *buf, int size)
     parallel_receive_byte(s, buf[0]);
 }
 
-static void parallel_event(void *opaque, int event)
-{
-}
-
 /* If fd is zero, it means that the parallel device uses the console */
 ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
 {
     ParallelState *s;
+    uint8_t dummy;
 
     s = qemu_mallocz(sizeof(ParallelState));
     if (!s)
         return NULL;
+    s->chr = chr;
+    s->hw_driver = 0;
+    if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0)
+        s->hw_driver = 1;
+
     s->irq = irq;
     s->data = 0;
     s->status = PARA_STS_BUSY;
@@ -176,8 +200,6 @@ ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
 
     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;
 }
index 253484fcdad5dc9862d825e98f35865369dccc11..41b7422789b362bf693d254d3dc7563213ccdfa3 100644 (file)
@@ -364,8 +364,11 @@ Virtual console
 @item null
 void device
 @item /dev/XXX
-[Linux only]Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
+[Linux only] Use host tty, e.g. @file{/dev/ttyS0}. The host serial port
 parameters are set according to the emulated ones.
+@item /dev/parportN
+[Linux only, parallel port only] Use host parallel port
+@var{N}. Currently only SPP parallel port features can be used.
 @item file:filename
 Write output to filename. No character can be read.
 @item stdio
@@ -379,6 +382,15 @@ non graphical mode.
 This option can be used several times to simulate up to 4 serials
 ports.
 
+@item -parallel dev
+Redirect the virtual parallel port to host device @var{dev} (same
+devices as the serial port). On Linux hosts, @file{/dev/parportN} can
+be used to use hardware devices connected on the corresponding host
+parallel port.
+
+This option can be used several times to simulate up to 3 parallel
+ports.
+
 @item -monitor dev
 Redirect the monitor to host device @var{dev} (same devices as the
 serial port).
diff --git a/vl.c b/vl.c
index 75ec23bb37d2baed1aac867357cb1326f7e112ed..2ced8886843daceb92a04351e82108863d65e0c2 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -51,6 +51,7 @@
 #include <pty.h>
 #include <malloc.h>
 #include <linux/rtc.h>
+#include <linux/ppdev.h>
 #endif
 #endif
 
@@ -1013,21 +1014,13 @@ int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len)
     return s->chr_write(s, buf, len);
 }
 
-void qemu_chr_set_serial_parameters(CharDriverState *s,
-                                    int speed, int parity,
-                                    int data_bits, int stop_bits)
+int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg)
 {
-    if (s->chr_set_serial_parameters)
-        s->chr_set_serial_parameters(s, speed, parity, data_bits, stop_bits);
+    if (!s->chr_ioctl)
+        return -ENOTSUP;
+    return s->chr_ioctl(s, cmd, arg);
 }
 
-void qemu_chr_set_serial_break(CharDriverState *s, int enable)
-{
-    if (s->chr_set_serial_break)
-        s->chr_set_serial_break(s, enable);
-}
-
-
 void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
 {
     char buf[4096];
@@ -1379,7 +1372,11 @@ static void tty_serial_init(int fd, int speed,
     struct termios tty;
     speed_t spd;
 
-    tcgetattr (0, &tty);
+#if 0
+    printf("tty_serial_init: speed=%d parity=%c data=%d stop=%d\n", 
+           speed, parity, data_bits, stop_bits);
+#endif
+    tcgetattr (fd, &tty);
 
     switch(speed) {
     case 50:
@@ -1459,20 +1456,29 @@ static void tty_serial_init(int fd, int speed,
     tcsetattr (fd, TCSANOW, &tty);
 }
 
-static void tty_set_serial_parameters(CharDriverState *chr,
-                                      int speed, int parity,
-                                      int data_bits, int stop_bits)
+static int tty_serial_ioctl(CharDriverState *chr, int cmd, void *arg)
 {
     FDCharDriver *s = chr->opaque;
-    tty_serial_init(s->fd_in, speed, parity, data_bits, stop_bits);
-}
-
-static void tty_set_serial_break(CharDriverState *chr, int enable)
-{
-    FDCharDriver *s = chr->opaque;
-    /* XXX: find a better solution */
-    if (enable)
-        tcsendbreak(s->fd_in, 1);
+    
+    switch(cmd) {
+    case CHR_IOCTL_SERIAL_SET_PARAMS:
+        {
+            QEMUSerialSetParams *ssp = arg;
+            tty_serial_init(s->fd_in, ssp->speed, ssp->parity, 
+                            ssp->data_bits, ssp->stop_bits);
+        }
+        break;
+    case CHR_IOCTL_SERIAL_SET_BREAK:
+        {
+            int enable = *(int *)arg;
+            if (enable)
+                tcsendbreak(s->fd_in, 1);
+        }
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
 }
 
 CharDriverState *qemu_chr_open_tty(const char *filename)
@@ -1480,7 +1486,7 @@ CharDriverState *qemu_chr_open_tty(const char *filename)
     CharDriverState *chr;
     int fd;
 
-    fd = open(filename, O_RDWR);
+    fd = open(filename, O_RDWR | O_NONBLOCK);
     if (fd < 0)
         return NULL;
     fcntl(fd, F_SETFL, O_NONBLOCK);
@@ -1488,8 +1494,70 @@ CharDriverState *qemu_chr_open_tty(const char *filename)
     chr = qemu_chr_open_fd(fd, fd);
     if (!chr)
         return NULL;
-    chr->chr_set_serial_parameters = tty_set_serial_parameters;
-    chr->chr_set_serial_break = tty_set_serial_break;
+    chr->chr_ioctl = tty_serial_ioctl;
+    return chr;
+}
+
+static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
+{
+    int fd = (int)chr->opaque;
+    uint8_t b;
+
+    switch(cmd) {
+    case CHR_IOCTL_PP_READ_DATA:
+        if (ioctl(fd, PPRDATA, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_DATA:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWDATA, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_CONTROL:
+        if (ioctl(fd, PPRCONTROL, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    case CHR_IOCTL_PP_WRITE_CONTROL:
+        b = *(uint8_t *)arg;
+        if (ioctl(fd, PPWCONTROL, &b) < 0)
+            return -ENOTSUP;
+        break;
+    case CHR_IOCTL_PP_READ_STATUS:
+        if (ioctl(fd, PPRSTATUS, &b) < 0)
+            return -ENOTSUP;
+        *(uint8_t *)arg = b;
+        break;
+    default:
+        return -ENOTSUP;
+    }
+    return 0;
+}
+
+CharDriverState *qemu_chr_open_pp(const char *filename)
+{
+    CharDriverState *chr;
+    int fd;
+
+    fd = open(filename, O_RDWR);
+    if (fd < 0)
+        return NULL;
+
+    if (ioctl(fd, PPCLAIM) < 0) {
+        close(fd);
+        return NULL;
+    }
+
+    chr = qemu_mallocz(sizeof(CharDriverState));
+    if (!chr) {
+        close(fd);
+        return NULL;
+    }
+    chr->opaque = (void *)fd;
+    chr->chr_write = null_chr_write;
+    chr->chr_add_read_handler = null_chr_add_read_handler;
+    chr->chr_ioctl = pp_ioctl;
     return chr;
 }
 
@@ -1522,6 +1590,9 @@ CharDriverState *qemu_chr_open(const char *filename)
     } else 
 #endif
 #if defined(__linux__)
+    if (strstart(filename, "/dev/parport", NULL)) {
+        return qemu_chr_open_pp(filename);
+    } else 
     if (strstart(filename, "/dev/", NULL)) {
         return qemu_chr_open_tty(filename);
     } else