[PARPORT] lp


Philip Blundell (Philip.Blundell@pobox.com)
Sun, 12 Apr 1998 22:44:57 +0100


Hi Tim (and others),

Here's what I've come up with so far.

It's a lot better for me than the old one was. I've given it a test with the
two printers I have on hand here (my Stylus 600 and an old Epson LQ-850) and
not seen stalls or lost characters with either. To check for stalls I did `dd
if=/dev/zero of=/dev/lp0' and let it run for a while; to check for lost
characters I did `lptest >/dev/lp0', printed a couple of pages and eyeballed
the output.

The new code is certainly simpler than the old version in a few places, which
can only be good. The waitqueue is gone and replaced with a semaphore, and
this in turn means we don't have to be quite so jumpy about doing things
with interrupts off. Also, we don't ever do enable_irq()/disable_irq() any
more - we assume irqs are always on, and just use the PINTEN bit to mask them
out as appropriate (btw, I think the comment against PINTEN in lp.h is a bit
misleading). I think this should be safe. Hopefully I haven't broken it for
the polling case either.

Anybody who feels particularly intrepid, and especially anybody who was having
problems with 2.1.95, might like to give this a go. There are a pile of other
parport changes coming up in 2.1.96; this change doesn't actively conflict with
them but it's possible things will be close enough to spook out `patch' and
cause rejects anyway.

Some work is still needed. The `preempt' stuff is still almost certainly
broken - I haven't worked out yet whether I'm being stupid and not
understanding how it worked, or whether it was really as disastrous as it it
appeared.

Enjoy.

p.

--- /home/phil/clean/linux/drivers/char/lp.c Sun Apr 12 22:31:24 1998
+++ linux/drivers/char/lp.c Sun Apr 12 22:33:27 1998
@@ -87,6 +87,8 @@
 /* if you have more than 3 printers, remember to increase LP_NO */
 #define LP_NO 3
 
+#define LP_INT_CHAR 10 /* time to hang around when using irqs */
+
 struct lp_struct lp_table[LP_NO] =
 {
         [0 ... LP_NO-1] = {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT,
@@ -160,26 +162,14 @@
 
 static inline int lp_char(char lpchar, int minor)
 {
- int status;
         unsigned int wait = 0;
         unsigned long count = 0;
         struct lp_stats *stats;
 
- for (;;) {
- lp_yield(minor);
- status = r_str (minor);
- if (++count == LP_CHAR(minor))
+ while (!LP_READY(minor, r_str(minor))) {
+ if (++count == (LP_POLLING(minor)?LP_CHAR(minor):LP_INT_CHAR))
                         return 0;
- if (LP_POLLING(minor))
- {
- if (LP_READY(minor, status))
- break;
- } else {
- if (!LP_READY(minor, status))
- return 0;
- else
- break;
- }
+ lp_yield(minor);
         }
 
         w_dtr(minor, lpchar);
@@ -222,9 +212,7 @@
 static void lp_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
         struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
-
- if (waitqueue_active (&lp_dev->dev->wait_q))
- wake_up_interruptible(&lp_dev->dev->wait_q);
+ up(&lp_dev->sem);
 }
 
 static void lp_error(int minor)
@@ -259,13 +247,12 @@
         return 0;
 }
 
-static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
+static int lp_write_buf(unsigned int minor, const char *buf, int count)
 {
         unsigned long copy_size;
         unsigned long total_bytes_written = 0;
         unsigned long bytes_written;
         struct lp_struct *lp = &lp_table[minor];
- unsigned char status;
 
         if (minor >= LP_NO)
                 return -ENXIO;
@@ -301,25 +288,24 @@
                                         current->timeout = jiffies + LP_TIME(minor);
                                         lp_schedule (minor);
                                 } else {
- cli();
- if (LP_PREEMPTED(minor)) {
- sti();
+ int err;
+ unsigned char status;
+ /* If someone else wants the port, let go of it for a bit. */
+ if (LP_PREEMPTED(minor))
                                                 goto lp_polling;
- }
- enable_irq(lp->dev->port->irq);
- w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
+ /* Turn the IRQ on and wait for the fireworks. */
+ w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN);
                                         status = r_str(minor);
- if ((!(status & LP_PACK) || (status & LP_PBUSY))
- && LP_CAREFUL_READY(minor, status)) {
- w_ctr(minor, LP_PSELECP | LP_PINITP);
- sti();
+ if (!(status & LP_PACK) || LP_CAREFUL_READY(minor, status)) {
+ /* The printer went ready while we weren't looking. */
+ w_ctr(minor, LP_PSELECP|LP_PINITP);
                                                 continue;
                                         }
- current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
- interruptible_sleep_on(&lp->dev->wait_q);
- disable_irq(lp->dev->port->irq);
+ sti();
+ err = down_interruptible(&lp->sem);
                                         w_ctr(minor, LP_PSELECP | LP_PINITP);
- sti();
+ if (err)
+ return err;
                                         if (lp_check_status(minor))
                                                 return rc ? rc : -EIO;
                                 }
@@ -528,6 +514,7 @@
                 LP_F(minor) &= ~LP_BUSY;
                 return -ENOMEM;
         }
+ sema_init(&(lp_table[minor].sem), 0);
         return 0;
 }
 

-- 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 Wed 30 Dec 1998 - 10:17:36 EST