Frederick Barnes (frmb@mail.cern.ch)
Sat, 25 Sep 1999 21:44:26 +0200 (CEST)
All,
Due to a somewhat urgent need for a working parport device driver, myself
and Jamie Lokier have been fixing some bugs. We don't claim that we've
fixed them properly, but it's made ECP transfers work :-). Tacked onto
the mail are the patches. The bugs (if they were really bugs) fixed are:
ecp_forward_to_reverse() incorrecly setting nAutoFeed
__frob_control() masking direction bit. (and inline version)
change_mode() testing direction bit incorrectly. (and inline version)
parport_pc_frob_control() now calls data_forward and data_reverse
depending on situation.
ECP bi-directional port detection broken, fixed now
Some incorrect polarities, fixed
Some places attempt to change direction when not in PS/2 mode, and
fail, fixed
Instances of ((HZ + 99) / 25) replaced with ((HZ + 24) / 25). [if
indeed this is correct]
If there any problems, please mail me (Frederick.Barnes@cern.ch), or Jamie
Lokier (Jamie.Lokier@cern.ch).
Enjoy :-),
Fred.
+--------------------------------------------------------------------------+
| Fred Barnes |
| Frederick.Barnes@cern.ch http://teddy.xylene.com/ |
+--------------------------------------------------------------------------+
diff -u linux-pcetb/drivers/parport/ieee1284_ops.c.orig linux-pcetb/drivers/parport/ieee1284_ops.c
--- linux-pcetb/drivers/parport/ieee1284_ops.c.orig Sat Sep 25 21:13:35 1999
+++ linux-pcetb/drivers/parport/ieee1284_ops.c Sat Sep 25 22:42:36 1999
@@ -9,8 +9,10 @@
* Note: Make no assumptions about hardware or architecture in this file!
*
* Author: Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Fixed AUTOFD polarity in ecp_forward_to_reverse(). Fred Barnes, 1999
*/
+
#include <linux/config.h>
#include <linux/parport.h>
#include <linux/delay.h>
@@ -336,7 +338,7 @@
/* Event 38: Set nAutoFd low */
parport_frob_control (port,
PARPORT_CONTROL_AUTOFD,
- 0);
+ PARPORT_CONTROL_AUTOFD);
parport_data_reverse (port);
udelay (5);
@@ -524,12 +526,12 @@
if (count && dev->port->irq != PARPORT_IRQ_NONE) {
parport_release (dev);
current->state = TASK_INTERRUPTIBLE;
- schedule_timeout ((HZ + 99) / 25);
+ schedule_timeout ((HZ + 24) / 25);
parport_claim_or_block (dev);
}
else
/* We must have the device claimed here. */
- parport_wait_event (port, (HZ + 99) / 25);
+ parport_wait_event (port, (HZ + 24) / 25);
/* Is there a signal pending? */
if (signal_pending (current))
@@ -610,10 +612,11 @@
count += rle_count;
DPRINTK (KERN_DEBUG "%s: decompressed to %d bytes\n",
port->name, rle_count);
- }
- else
+ } else {
/* Normal data byte. */
- *buf++ = byte, count++;
+ *buf = byte;
+ buf++, count++;
+ }
}
out:
diff -u linux-pcetb/drivers/parport/parport_pc.c.orig linux-pcetb/drivers/parport/parport_pc.c
--- linux-pcetb/drivers/parport/parport_pc.c.orig Sat Sep 25 21:12:49 1999
+++ linux-pcetb/drivers/parport/parport_pc.c Sat Sep 25 22:42:19 1999
@@ -10,6 +10,7 @@
*
* Cleaned up include files - Russell King <linux@arm.uk.linux.org>
* DMA support - Bert De Jonghe <bert@sophis.be>
+ * Many ECP bugs fixed. Fred Barnes & Jamie Lokier, 1999
*/
/* This driver should work with any hardware that is broadly compatible
@@ -73,7 +74,12 @@
static void frob_econtrol (struct parport *pb, unsigned char m,
unsigned char v)
{
- outb ((inb (ECONTROL (pb)) & ~m) ^ v, ECONTROL (pb));
+ unsigned char ectr = inb (ECONTROL (pb));
+#ifdef DEBUG_PARPORT
+ printk (KERN_DEBUG "frob_econtrol(%02x,%02x): %02x -> %02x\n",
+ m, v, ectr, (ectr & ~m) ^ v);
+#endif
+ outb ((ectr & ~m) ^ v, ECONTROL (pb));
}
#ifdef CONFIG_PARPORT_PC_FIFO
@@ -94,11 +100,8 @@
oecr = inb (ecr);
mode = (oecr >> 5) & 0x7;
if (mode == m) return 0;
- if (mode && m)
- /* We have to go through mode 000 */
- change_mode (p, ECR_SPP);
- if (m < 2 && !(parport_read_control (p) & 0x20)) {
+ if (mode >= 2 && !(priv->ctr & 0x20)) {
/* This mode resets the FIFO, so we may
* have to wait for it to drain first. */
long expire = jiffies + p->physport->cad->timeout;
@@ -127,6 +130,13 @@
}
}
+ if (mode >= 2 && m >= 2) {
+ /* We have to go through mode 001 */
+ oecr &= ~(7 << 5);
+ oecr |= ECR_PS2 << 5;
+ outb (oecr, ecr);
+ }
+
/* Set the mode. */
oecr &= ~(7 << 5);
oecr |= m << 5;
@@ -160,11 +170,11 @@
residue);
/* Reset the FIFO. */
- frob_econtrol (p, 0xe0, 0x20);
+ frob_econtrol (p, 0xe0, ECR_PS2 << 5);
parport_frob_control (p, PARPORT_CONTROL_STROBE, 0);
/* Now change to config mode and clean up. FIXME */
- frob_econtrol (p, 0xe0, 0xe0);
+ frob_econtrol (p, 0xe0, ECR_CNF << 5);
cnfga = inb (CONFIGA (p));
printk (KERN_DEBUG "%s: cnfgA contains 0x%02x\n", p->name, cnfga);
@@ -177,7 +187,7 @@
* PWord != 1 byte. */
/* Back to PS2 mode. */
- frob_econtrol (p, 0xe0, 0x20);
+ frob_econtrol (p, 0xe0, ECR_PS2 << 5);
return residue;
}
@@ -229,21 +239,6 @@
return inb (DATA (p));
}
-unsigned char __frob_control (struct parport *p, unsigned char mask,
- unsigned char val)
-{
- const unsigned char wm = (PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_INIT |
- PARPORT_CONTROL_SELECT);
- struct parport_pc_private *priv = p->physport->private_data;
- unsigned char ctr = priv->ctr;
- ctr = (ctr & ~mask) ^ val;
- ctr &= priv->ctr_writable; /* only write writable bits. */
- outb (ctr, CONTROL (p));
- return priv->ctr = ctr & wm; /* update soft copy */
-}
-
void parport_pc_write_control(struct parport *p, unsigned char d)
{
const unsigned char wm = (PARPORT_CONTROL_STROBE |
@@ -253,9 +248,9 @@
/* Take this out when drivers have adapted to the newer interface. */
if (d & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
- parport_pc_data_reverse (p);
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
}
__frob_control (p, wm, d & wm);
@@ -263,8 +258,12 @@
unsigned char parport_pc_read_control(struct parport *p)
{
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
const struct parport_pc_private *priv = p->physport->private_data;
- return priv->ctr; /* Use soft copy */
+ return priv->ctr & wm; /* Use soft copy */
}
unsigned char parport_pc_frob_control (struct parport *p, unsigned char mask,
@@ -277,9 +276,13 @@
/* Take this out when drivers have adapted to the newer interface. */
if (mask & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
+ printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+ p->name, p->cad->name,
+ (val & 0x20) ? "reverse" : "forward");
+ if (val & 0x20)
parport_pc_data_reverse (p);
+ else
+ parport_pc_data_forward (p);
}
/* Restrict mask and val to control lines. */
@@ -469,7 +472,7 @@
frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
/* Forward mode. */
- parport_pc_data_forward (port);
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
while (left) {
unsigned char byte;
@@ -559,7 +562,7 @@
frob_econtrol (port, (1<<4), (1<<4)); /* nErrIntrEn */
/* Forward mode. */
- parport_pc_data_forward (port);
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
while (left) {
long expire = jiffies + port->physport->cad->timeout;
@@ -656,8 +659,8 @@
length, flags);
/* Set up parallel port FIFO mode.*/
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
change_mode (port, ECR_PPF); /* Parallel port FIFO */
- parport_pc_data_forward (port);
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -687,8 +690,8 @@
outb (0, FIFO (port));
}
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
+ /* Reset the FIFO and return to PS2 mode. */
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
/* De-assert strobe. */
parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
@@ -727,8 +730,8 @@
}
/* Set up ECP parallel port mode.*/
+ parport_pc_data_forward (port); /* Must be in PS2 mode */
change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_forward (port);
port->physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
/* Write the data to the FIFO. */
@@ -758,17 +761,20 @@
outb (0, FIFO (port));
}
- /* Reset the FIFO. */
- frob_econtrol (port, 0xe0, 0);
+ /* Reset the FIFO and return to PS2 mode. */
+ frob_econtrol (port, 0xe0, ECR_PS2 << 5);
+
+ /* De-assert strobe. */
parport_frob_control (port, PARPORT_CONTROL_STROBE, 0);
/* Host transfer recovery. */
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
+ udelay (5);
+ parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
+ parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
parport_frob_control (port,
PARPORT_CONTROL_INIT,
PARPORT_CONTROL_INIT);
- parport_pc_data_reverse (port);
- parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
- parport_frob_control (port, PARPORT_CONTROL_INIT, 0);
parport_wait_peripheral (port,
PARPORT_STATUS_PAPEROUT,
PARPORT_STATUS_PAPEROUT);
@@ -819,21 +825,21 @@
parport_frob_control (port,
PARPORT_CONTROL_AUTOFD,
PARPORT_CONTROL_AUTOFD);
- parport_pc_data_reverse (port);
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
udelay (5);
/* Event 39: Set nInit low to initiate bus reversal */
parport_frob_control (port,
PARPORT_CONTROL_INIT,
- PARPORT_CONTROL_INIT);
+ 0);
/* Event 40: PError goes low */
parport_wait_peripheral (port, PARPORT_STATUS_PAPEROUT, 0);
}
/* Set up ECP parallel port mode.*/
+ parport_pc_data_reverse (port); /* Must be in PS2 mode */
change_mode (port, ECR_ECP); /* ECP FIFO */
- parport_pc_data_reverse (port);
port->ieee1284.phase = IEEE1284_PH_REV_DATA;
/* Do the transfer. */
@@ -1054,7 +1060,6 @@
struct parport_pc_private *priv = pb->private_data;
unsigned char r = 0xc;
- priv->ecr = 0;
outb (r, CONTROL (pb));
if ((inb (ECONTROL (pb)) & 0x3) == (r & 0x3)) {
outb (r ^ 0x2, CONTROL (pb)); /* Toggle bit 1 */
@@ -1120,9 +1125,9 @@
/* cancel input mode */
parport_pc_data_forward (pb);
- if (ok)
+ if (ok) {
pb->modes |= PARPORT_MODE_TRISTATE;
- else {
+ } else {
struct parport_pc_private *priv = pb->private_data;
priv->ctr_writable &= ~0x20;
}
@@ -1180,8 +1185,8 @@
priv->writeIntrThreshold = i;
/* Find out readIntrThreshold */
- frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO */
- parport_pc_data_reverse (pb);
+ frob_econtrol (pb, 0xe0, ECR_PS2 << 5); /* Reset FIFO and enable PS2 */
+ parport_pc_data_reverse (pb); /* Must be in PS2 mode */
frob_econtrol (pb, 0xe0, ECR_TST << 5); /* Test FIFO */
frob_econtrol (pb, 1<<2, 1<<2);
frob_econtrol (pb, 1<<2, 0);
@@ -1544,12 +1549,10 @@
if (base_hi && !check_region(base_hi,3)) {
parport_ECR_present(p);
parport_ECP_supported(p);
- parport_ECPPS2_supported(p);
}
if (base != 0x3bc) {
if (!check_region(base+0x3, 5)) {
- parport_EPP_supported(p);
- if (!(p->modes & PARPORT_MODE_EPP))
+ if (!parport_EPP_supported(p))
parport_ECPEPP_supported(p);
}
}
@@ -1558,8 +1561,10 @@
kfree (priv);
return NULL;
}
-
- parport_PS2_supported (p);
+ if (priv->ecr)
+ parport_ECPPS2_supported(p);
+ else
+ parport_PS2_supported (p);
if (!(p = parport_register_port(base, PARPORT_IRQ_NONE,
PARPORT_DMA_NONE, ops))) {
@@ -1672,9 +1677,10 @@
/* Done probing. Now put the port into a sensible start-up state.
* SELECT | INIT also puts IEEE1284-compliant devices into
* compatibility mode. */
- if (p->modes & PARPORT_MODE_ECP)
+ if (priv->ecr)
/*
* Put the ECP detected port in PS2 mode.
+ * Do this also for ports that have ECR but don't do ECP.
*/
outb (0x34, ECONTROL (p));
diff -u linux-pcetb/include/linux/parport_pc.h.orig linux-pcetb/include/linux/parport_pc.h
--- linux-pcetb/include/linux/parport_pc.h.orig Sat Sep 25 21:37:25 1999
+++ linux-pcetb/include/linux/parport_pc.h Sat Sep 25 21:37:54 1999
@@ -41,28 +41,37 @@
extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
{
+#ifdef DEBUG_PARPORT
+ printk (KERN_DEBUG "parport_pc_write_data(%p,0x%02x)\n", p, d);
+#endif
outb(d, DATA(p));
}
extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
{
- return inb(DATA(p));
+ unsigned char val = inb (DATA (p));
+#ifdef DEBUG_PARPORT
+ printk (KERN_DEBUG "parport_pc_read_data(%p) = 0x%02x\n",
+ p, val);
+#endif
+ return val;
}
extern __inline__ unsigned char __frob_control (struct parport *p,
unsigned char mask,
unsigned char val)
{
- const unsigned char wm = (PARPORT_CONTROL_STROBE |
- PARPORT_CONTROL_AUTOFD |
- PARPORT_CONTROL_INIT |
- PARPORT_CONTROL_SELECT);
struct parport_pc_private *priv = p->physport->private_data;
unsigned char ctr = priv->ctr;
+#ifdef DEBUG_PARPORT
+ printk (KERN_DEBUG "__frob_control(%02x,%02x): %02x -> %02x\n",
+ mask, val, ctr, ((ctr & ~mask) ^ val) & priv->ctr_writable);
+#endif
ctr = (ctr & ~mask) ^ val;
ctr &= priv->ctr_writable; /* only write writable bits. */
outb (ctr, CONTROL (p));
- return priv->ctr = ctr & wm; /* update soft copy */
+ priv->ctr = ctr; /* Update soft copy */
+ return ctr;
}
extern __inline__ void parport_pc_data_reverse (struct parport *p)
@@ -70,6 +79,11 @@
__frob_control (p, 0x20, 0x20);
}
+extern __inline__ void parport_pc_data_forward (struct parport *p)
+{
+ __frob_control (p, 0x20, 0x00);
+}
+
extern __inline__ void parport_pc_write_control (struct parport *p,
unsigned char d)
{
@@ -80,9 +94,9 @@
/* Take this out when drivers have adapted to newer interface. */
if (d & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
- parport_pc_data_reverse (p);
+ printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
+ p->name, p->cad->name);
+ parport_pc_data_reverse (p);
}
__frob_control (p, wm, d & wm);
@@ -90,8 +104,12 @@
extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
{
+ const unsigned char wm = (PARPORT_CONTROL_STROBE |
+ PARPORT_CONTROL_AUTOFD |
+ PARPORT_CONTROL_INIT |
+ PARPORT_CONTROL_SELECT);
const struct parport_pc_private *priv = p->physport->private_data;
- return priv->ctr; /* Use soft copy */
+ return priv->ctr & wm; /* Use soft copy */
}
extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
@@ -105,9 +123,13 @@
/* Take this out when drivers have adapted to newer interface. */
if (mask & 0x20) {
- printk (KERN_DEBUG "%s (%s): use data_reverse for this!\n",
- p->name, p->cad->name);
+ printk (KERN_DEBUG "%s (%s): use data_%s for this!\n",
+ p->name, p->cad->name,
+ (val & 0x20) ? "reverse" : "forward");
+ if (val & 0x20)
parport_pc_data_reverse (p);
+ else
+ parport_pc_data_forward (p);
}
/* Restrict mask and val to control lines. */
@@ -122,10 +144,6 @@
return inb(STATUS(p));
}
-extern __inline__ void parport_pc_data_forward (struct parport *p)
-{
- __frob_control (p, 0x20, 0x00);
-}
extern __inline__ void parport_pc_disable_irq(struct parport *p)
{
-- To unsubscribe, send mail to: linux-parport-request@torque.net --
-- with the single word "unsubscribe" in the body of the message. --
This archive was generated by hypermail 2.0b3 on Sat 25 Sep 1999 - 15:46:00 EDT