Tim Waugh (tim@cyberelk.demon.co.uk)
Thu, 6 May 1999 09:05:18 +0100 (GMT)
No-one on linux-kernel seems very interested in trying out parallel port-
or printer-related fixes for 2.2.7. Maybe I'll have more luck here. ;-)
This is patch-2.2.7-fixes-2, which I intend to send to Linus for 2.2.8.
Please test it out as much as you can; in particular, please check that
printing to a printer with no paper works as before.
There are basically three changes: softctr in parport_pc, SPP detection in
parport_pc, and nFault handling in lp.
Let me know how it goes; I can't send it to Linus untested.
Thanks,
Tim.
*/
diff -durN linux-2.2.7/drivers/char/lp.c linux/drivers/char/lp.c
--- linux-2.2.7/drivers/char/lp.c Wed Mar 24 01:42:57 1999
+++ linux/drivers/char/lp.c Mon May 3 18:20:26 1999
@@ -202,9 +202,7 @@
/* Test if the printer is not acking the strobe */
#define LP_NO_ACKING(status) ((status) & LP_PACK)
/* Test if the printer has error conditions */
-#define LP_NO_ERROR(status) \
- (((status) & (LP_POUTPA|LP_PSELECD|LP_PERRORP)) == \
- (LP_PSELECD|LP_PERRORP))
+#define LP_NO_ERROR(status) ((status) & LP_PERRORP)
#undef LP_DEBUG
#undef LP_READ_DEBUG
@@ -424,7 +422,10 @@
{
unsigned int last = lp_table[minor].last_error;
unsigned char status = r_str(minor);
- if ((status & LP_POUTPA)) {
+ if (status & LP_PERRORP)
+ /* No error. */
+ last = 0;
+ else if ((status & LP_POUTPA)) {
if (last != LP_POUTPA) {
last = LP_POUTPA;
printk(KERN_INFO "lp%d out of paper\n", minor);
@@ -434,13 +435,12 @@
last = LP_PSELECD;
printk(KERN_INFO "lp%d off-line\n", minor);
}
- } else if (!(status & LP_PERRORP)) {
+ } else {
if (last != LP_PERRORP) {
last = LP_PERRORP;
- printk(KERN_INFO "lp%d on fire!\n", minor);
+ printk(KERN_INFO "lp%d on fire\n", minor);
}
}
- else last = 0;
lp_table[minor].last_error = last;
diff -durN linux-2.2.7/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- linux-2.2.7/drivers/misc/parport_ieee1284.c Wed Mar 24 01:42:59 1999
+++ linux/drivers/misc/parport_ieee1284.c Thu May 6 08:52:02 1999
@@ -48,25 +48,22 @@
int parport_ieee1284_nibble_mode_ok(struct parport *port, unsigned char mode)
{
/* make sure it's a valid state, set nStrobe & nAutoFeed high */
- parport_write_control(port, (parport_read_control(port) \
- & ~1 ) & ~2);
+ parport_frob_control (port, (1|2), 0);
udelay(1);
parport_write_data(port, mode);
udelay(400);
/* nSelectIn high, nAutoFd low */
- parport_write_control(port, (parport_read_control(port) & ~8) | 2);
+ parport_frob_control(port, (2|8), 2);
if (parport_wait_peripheral(port, 0x78, 0x38)) {
- parport_write_control(port,
- (parport_read_control(port) & ~2) | 8);
+ parport_frob_control(port, (2|8), 8);
return 0;
}
/* nStrobe low */
- parport_write_control(port, parport_read_control(port) | 1);
+ parport_frob_control (port, 1, 1);
udelay(1); /* Strobe wait */
/* nStrobe high, nAutoFeed low, last step before transferring
* reverse data */
- parport_write_control(port, (parport_read_control(port) \
- & ~1) & ~2);
+ parport_frob_control (port, (1|2), 0);
udelay(1);
/* Data available? */
parport_wait_peripheral (port, PARPORT_STATUS_ACK, PARPORT_STATUS_ACK);
diff -durN linux-2.2.7/drivers/misc/parport_pc.c linux/drivers/misc/parport_pc.c
--- linux-2.2.7/drivers/misc/parport_pc.c Wed Mar 24 01:42:59 1999
+++ linux/drivers/misc/parport_pc.c Wed May 5 19:45:58 1999
@@ -53,6 +53,8 @@
than PARPORT_MAX (in <linux/parport.h>). */
#define PARPORT_PC_MAX_PORTS 8
+static int user_specified = 0;
+
static void parport_pc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
parport_generic_irq(irq, (struct parport *) dev_id, regs);
@@ -103,19 +105,24 @@
void parport_pc_write_control(struct parport *p, unsigned char d)
{
+ struct parport_pc_private *priv = p->private_data;
+ priv->ctr = d;/* update soft copy */
outb(d, p->base+CONTROL);
}
unsigned char parport_pc_read_control(struct parport *p)
{
- return inb(p->base+CONTROL);
+ struct parport_pc_private *priv = p->private_data;
+ return priv->ctr;
}
unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned char old = inb(p->base+CONTROL);
- outb(((old & ~mask) ^ val), p->base+CONTROL);
- return old;
+ struct parport_pc_private *priv = p->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ outb (ctr, p->base+CONTROL);
+ return priv->ctr = ctr; /* update soft copy */
}
void parport_pc_write_status(struct parport *p, unsigned char d)
@@ -345,6 +352,8 @@
*/
static int parport_SPP_supported(struct parport *pb)
{
+ unsigned char r, w;
+
/*
* first clear an eventually pending EPP timeout
* I (sailer@ife.ee.ethz.ch) have an SMSC chipset
@@ -354,14 +363,54 @@
parport_pc_epp_clear_timeout(pb);
/* Do a simple read-write test to make sure the port exists. */
- parport_pc_write_control(pb, 0xc);
- parport_pc_write_data(pb, 0xaa);
- if (parport_pc_read_data(pb) != 0xaa) return 0;
-
- parport_pc_write_data(pb, 0x55);
- if (parport_pc_read_data(pb) != 0x55) return 0;
+ w = 0xc;
+ parport_pc_write_control(pb, w);
- return PARPORT_MODE_PCSPP;
+ /* Can we read from the control register? Some ports don't
+ * allow reads, so read_control just returns a software
+ * copy. Some ports _do_ allow reads, so bypass the software
+ * copy here. In addition, some bits aren't writable. */
+ r = inb (pb->base+CONTROL);
+ if ((r & 0x3f) == w) {
+ w = 0xe;
+ parport_pc_write_control (pb, w);
+ r = inb (pb->base+CONTROL);
+ parport_pc_write_control (pb, 0xc);
+ if ((r & 0x3f) == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* That didn't work, but the user thinks there's a
+ * port here. */
+ printk (KERN_DEBUG "0x%lx: CTR: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* Try the data register. The data lines aren't tri-stated at
+ * this stage, so we expect back what we wrote. */
+ w = 0xaa;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w) {
+ w = 0x55;
+ parport_pc_write_data (pb, w);
+ r = parport_pc_read_data (pb);
+ if (r == w)
+ return PARPORT_MODE_PCSPP;
+ }
+
+ if (user_specified)
+ /* Didn't work with 0xaa, but the user is convinced
+ * this is the place. */
+ printk (KERN_DEBUG "0x%lx: DATA: wrote 0x%02x, read 0x%02x\n",
+ pb->base, w, r);
+
+ /* It's possible that we can't read the control register or
+ the data register. In that case just believe the user. */
+ if (user_specified)
+ return PARPORT_MODE_PCSPP;
+
+ return 0;
}
/* Check for ECP
@@ -712,6 +761,15 @@
if (check_region(base, 3)) return 0;
if (!(p = parport_register_port(base, irq, dma, &parport_pc_ops)))
return 0;
+ p->private_data = kmalloc (sizeof (struct parport_pc_private),
+ GFP_KERNEL);
+ if (!p->private_data) {
+ /* Not enough memory. */
+ printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
+ parport_unregister_port (p);
+ return 0;
+ }
+ ((struct parport_pc_private *) (p->private_data))->ctr = 0xc;
if (p->base != 0x3bc) {
if (!check_region(base+0x400,3)) {
p->modes |= parport_ECR_present(p);
@@ -725,6 +783,7 @@
}
if (!parport_SPP_supported(p)) {
/* No port. */
+ kfree (p->private_data);
parport_unregister_port (p);
return 0;
}
@@ -787,6 +846,7 @@
int count = 0, i = 0;
if (io && *io) {
/* Only probe the ports we were given. */
+ user_specified = 1;
do {
count += probe_one_port(*(io++), *(irq++), *(dma++));
} while (*io && (++i < PARPORT_PC_MAX_PORTS));
@@ -829,6 +889,7 @@
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
parport_proc_unregister(p);
+ kfree (p->private_data);
parport_unregister_port(p);
}
p = tmp;
diff -durN linux-2.2.7/include/linux/parport_pc.h linux/include/linux/parport_pc.h
--- linux-2.2.7/include/linux/parport_pc.h Tue Jan 26 00:04:37 1999
+++ linux/include/linux/parport_pc.h Mon May 3 13:28:04 1999
@@ -14,8 +14,15 @@
#define STATUS 0x1
#define DATA 0
+/* Private data for PC low-level driver. */
+struct parport_pc_private {
+ /* Contents of CTR. */
+ unsigned char ctr;
+};
+
extern int parport_pc_epp_clear_timeout(struct parport *pb);
+extern volatile unsigned char parport_pc_ctr;
extern __inline__ void parport_pc_write_epp(struct parport *p, unsigned char d)
{
@@ -62,19 +69,24 @@
extern __inline__ void parport_pc_write_control(struct parport *p, unsigned char d)
{
+ struct parport_pc_private *priv = p->private_data;
+ priv->ctr = d;/* update soft copy */
outb(d, p->base+CONTROL);
}
extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
{
- return inb(p->base+CONTROL);
+ struct parport_pc_private *priv = p->private_data;
+ return priv->ctr;
}
extern __inline__ unsigned char parport_pc_frob_control(struct parport *p, unsigned char mask, unsigned char val)
{
- unsigned char old = inb(p->base+CONTROL);
- outb(((old & ~mask) ^ val), p->base+CONTROL);
- return old;
+ struct parport_pc_private *priv = p->private_data;
+ unsigned char ctr = priv->ctr;
+ ctr = (ctr & ~mask) ^ val;
+ outb (ctr, p->base+CONTROL);
+ return priv->ctr = ctr; /* update soft copy */
}
extern __inline__ void parport_pc_write_status(struct parport *p, unsigned char d)
-- 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 Thu 06 May 1999 - 04:07:11 EDT