[PARPORT] 2.2.7 fixes


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