On 2/5/07, Marko Kohtala <[EMAIL PROTECTED]> wrote:
Fabrice Bellard:
>Marko Kohtala wrote:
>
>Hi.
>
>With the attached patch I am able to use Kodak Advantix FD 300 APS
>scanner from Win98 when hosted under Linux ix86. It adds EPP support
>and fixes some register bits to match real hw so port identification
>works better.
>
>I tried to separate the linux dependencies with #ifdef __linux__, but
>can not test this does not break compilation for other ports of qemu.
>
>I don't understand why you need a #ifdef __linux__ in parallel.c.
Normally, the qemu >character device should suffice to do the
appropriate abstraction.
...
I am too new with qemu to say how to develop the qemu character device
abstraction for these requirements.
Thanks for the offline tip, Fabrice.
Here is a new patch for EPP support. This time all linux code is in
ioctls. I hope you find it good enough.
Marko
diff --git a/hw/parallel.c b/hw/parallel.c
index cba9561..8f3495a 100644
--- a/hw/parallel.c
+++ b/hw/parallel.c
@@ -2,6 +2,7 @@
* QEMU Parallel PORT emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2007 Marko Kohtala
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +26,18 @@
//#define DEBUG_PARALLEL
+#ifdef DEBUG_PARALLEL
+#define pdebug(fmt, arg...) printf("pp: " fmt, ##arg)
+#else
+#define pdebug(fmt, arg...) ((void)0)
+#endif
+
+#define PARA_REG_DATA 0
+#define PARA_REG_STS 1
+#define PARA_REG_CTR 2
+#define PARA_REG_EPP_ADDR 3
+#define PARA_REG_EPP_DATA 4
+
/*
* These are the definitions for the Printer Status Register
*/
@@ -33,24 +46,31 @@
#define PARA_STS_PAPER 0x20 /* Out of paper */
#define PARA_STS_ONLINE 0x10 /* Online */
#define PARA_STS_ERROR 0x08 /* Error complement */
+#define PARA_STS_TMOUT 0x01 /* EPP timeout */
/*
* These are the definitions for the Printer Control Register
*/
+#define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */
#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 */
+#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
+
struct ParallelState {
-uint8_t data;
-uint8_t status; /* read only register */
+uint8_t dataw;
+uint8_t datar;
+uint8_t status;
uint8_t control;
int irq;
int irq_pending;
CharDriverState *chr;
int hw_driver;
+int epp_timeout;
+uint32_t last_read_offset; /* For debugging */
};
static void parallel_update_irq(ParallelState *s)
@@ -61,96 +81,322 @@ static void parallel_update_irq(ParallelState *s)
pic_set_irq(s->irq, 0);
}
-static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void
+parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
{
ParallelState *s = opaque;
+pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
+
+addr &= 7;
+switch(addr) {
+case PARA_REG_DATA:
+ s->dataw = val;
+ parallel_update_irq(s);
+break;
+case PARA_REG_CTR:
+ 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->dataw, 1);
+ } else {
+ if (s->control & PARA_CTR_INTEN) {
+ s->irq_pending = 1;
+ }
+ }
+ }
+ parallel_update_irq(s);
+ s->control = val;
+break;
+}
+}
+
+static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
+{
+ParallelState *s = opaque;
+uint8_t parm = val;
+
+/* Sometimes programs do several writes for timing purposes on old
+ HW. Take care not to waste time on writes that do nothing. */
+
+s->last_read_offset = ~0U;
+
addr &= 7;
-#ifdef DEBUG_PARALLEL
-printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
switch(addr) {
-case 0:
-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);
-}
+case PARA_REG_DATA:
+if (s->dataw == val)
+ return;
+ pdebug("wd%02x\n", val);
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+ s->dataw = val;
break;
-case 2:
-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 ) {
-