[PARPORT] lp patch -> [parport_sharing interrupt hack + pchars]


Andrea Arcangeli (arcangeli@mbox.queen.it)
Sat, 20 Dec 1997 19:27:10 +0100 (CET)


This is against your latest lp patch.

Andrea[s] Arcangeli

--- linux/include/linux/lp.h 1997/12/20 17:09:46 1.3
+++ linux/include/linux/lp.h 1997/12/20 17:20:13 1.5
@@ -116,6 +116,8 @@
         unsigned int waittime;
         unsigned int should_relinquish;
         struct lp_stats stats;
+ unsigned int pchars;
+ unsigned int pnodlk;
 };
 
 /*
@@ -160,6 +162,21 @@
  * It is used only in the lp_init() and lp_reset() routine.
  */
 #define LP_DELAY 50
+
+#ifndef CONFIG_PRINTER_PCHARS
+/*
+ * Minimum number of chars that must be sent to the printer
+ * before release parport.
+ */
+#define CONFIG_PRINTER_PCHARS 10
+#endif
+
+/*
+ * Maximum number of times that lp can lp_schedule() without relase parport.
+ * This is for avoid deadlocks if the data to print is provided from another
+ * pardevice that is sharing the same parparport with lp.
+ */
+#define LP_PRINTER_NODLK 10000
 
 /*
  * function prototypes
--- linux/drivers/char/Config.in 1997/12/20 17:03:54 1.1
+++ linux/drivers/char/Config.in 1997/12/20 17:04:36 1.2
@@ -51,6 +51,7 @@
   dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
   if [ "$CONFIG_PRINTER" != "n" ]; then
     bool ' Support IEEE1284 status readback' CONFIG_PRINTER_READBACK
+ int ' Number of chars to print before release parport' CONFIG_PRINTER_PCHARS 10 1 1000
   fi
 fi
 
--- linux/drivers/char/lp.c 1997/12/20 16:52:43 1.3
+++ linux/drivers/char/lp.c 1997/12/20 17:49:30 1.4
@@ -13,9 +13,7 @@
  * lp_read (Status readback) support added by Carsten Gross,
  * carsten@sol.wohnheim.uni-ulm.de
  * Support for parport by Philip Blundell <Philip.Blundell@pobox.com>
- * Reverted interrupt to polling at runtime if more than one device is parport
- * registered and joined the interrupt and polling code.
- * by Andrea Arcangeli <arcangeli@mbox.queen.it>
+ * parport_sharing hacking by Andrea Arcangeli <arcangeli@mbox.queen.it>
  */
 
 /* This driver should, in theory, work with any parallel port that has an
@@ -136,6 +134,9 @@
 {
         struct lp_struct *lps = (struct lp_struct *)handle;
 
+ if (waitqueue_active (&lps->lp_wait_q))
+ wake_up_interruptible(&lps->lp_wait_q);
+
         /* Just remember that someone wants the port */
         lps->should_relinquish = 1;
 
@@ -150,6 +151,19 @@
 #define w_ctr(x,y) do { parport_write_control(lp_table[(x)].dev->port, (y)); } while (0)
 #define w_dtr(x,y) do { parport_write_data(lp_table[(x)].dev->port, (y)); } while (0)
 
+static inline void lp_schedule_pchars(int minor)
+{
+ if ((lp_table[minor].should_relinquish && !lp_table[minor].pchars)
+ || !lp_table[minor].pnodlk--) {
+ lp_table[minor].pchars = CONFIG_PRINTER_PCHARS;
+ lp_table[minor].pnodlk = LP_PRINTER_NODLK;
+ lp_parport_release (minor);
+ schedule();
+ lp_parport_claim (minor);
+ } else
+ schedule();
+}
+
 static inline void lp_schedule (int minor)
 {
         if (lp_table[minor].should_relinquish) {
@@ -175,7 +189,7 @@
                       lp_table[minor].dev->port->devices->next;
 }
 
-static inline int lp_char(char lpchar, int minor, int use_polling)
+static inline int lp_char(char lpchar, int minor)
 {
         int status;
         unsigned int wait = 0;
@@ -185,16 +199,16 @@
         do {
                 status = r_str(minor);
                 count++;
- if (need_resched)
- lp_schedule (minor);
- } while (((use_polling && !LP_READY(minor, status)) ||
- (!use_polling && !(status & LP_PBUSY))) &&
- (count < LP_CHAR(minor)));
+ if (need_resched || lp_table[minor].should_relinquish)
+ lp_schedule_pchars(minor);
+ } while (!LP_READY(minor, status) && count < LP_CHAR(minor));
 
- if (count == LP_CHAR(minor) ||
- (!use_polling && !LP_CAREFUL_READY(minor, status)))
+ if (count == LP_CHAR(minor))
                 return 0;
+
         w_dtr(minor, lpchar);
+ if (lp_table[minor].pchars)
+ lp_table[minor].pchars--;
         stats = &LP_STAT(minor);
         stats->chars++;
         /* must wait before taking strobe high, and after taking strobe
@@ -228,18 +242,41 @@
         struct lp_struct *lp_dev = (struct lp_struct *) dev_id;
 
         if (waitqueue_active (&lp_dev->lp_wait_q))
- wake_up(&lp_dev->lp_wait_q);
+ wake_up_interruptible(&lp_dev->lp_wait_q);
 }
 
+#define LP_POLLING(minor) lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE
+
 static void lp_error(int minor)
 {
- if (must_use_polling(minor)) {
+ if (LP_POLLING(minor) || lp_table[minor].should_relinquish) {
                 current->state = TASK_INTERRUPTIBLE;
                 current->timeout = jiffies + LP_TIMEOUT_POLLED;
                 lp_schedule (minor);
         }
 }
 
+static int lp_check_status(int minor) {
+ unsigned char status = r_str(minor);
+ if ((status & LP_POUTPA)) {
+ printk(KERN_INFO "lp%d out of paper\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ } else if (!(status & LP_PSELECD)) {
+ printk(KERN_INFO "lp%d off-line\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ } else if (!(status & LP_PERRORP)) {
+ printk(KERN_ERR "lp%d printer error\n", minor);
+ if (LP_F(minor) & LP_ABORT)
+ return 1;
+ lp_error(minor);
+ }
+ return 0;
+}
+
 static inline int lp_write_buf(unsigned int minor, const char *buf, int count)
 {
         unsigned long copy_size;
@@ -259,7 +296,7 @@
                 copy_from_user(lp->lp_buffer, buf, copy_size);
 
                 while (copy_size) {
- if (lp_char(lp->lp_buffer[bytes_written], minor, must_use_polling(minor))) {
+ if (lp_char(lp->lp_buffer[bytes_written], minor)) {
                                 --copy_size;
                                 ++bytes_written;
                                 lp_table[minor].runchars++;
@@ -267,36 +304,24 @@
                                 int rc = total_bytes_written + bytes_written;
                                 if (lp_table[minor].runchars > LP_STAT(minor).maxrun)
                                         LP_STAT(minor).maxrun = lp_table[minor].runchars;
- status = r_str(minor);
- if ((status & LP_POUTPA)) {
- printk(KERN_INFO "lp%d out of paper\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -ENOSPC;
- lp_error(minor);
- } else if (!(status & LP_PSELECD)) {
- printk(KERN_INFO "lp%d off-line\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -EIO;
- lp_error(minor);
- } else if (!(status & LP_PERRORP)) {
- printk(KERN_ERR "lp%d printer error\n", minor);
- if (LP_F(minor) & LP_ABORT)
- return rc ? rc : -EIO;
- lp_error(minor);
- }
-
                                 LP_STAT(minor).sleeps++;
 
- if (must_use_polling(minor)) {
+ if (LP_POLLING(minor)) {
+ lp_polling:
+ if (lp_check_status(minor))
+ return rc ? rc : -EIO;
 #ifdef LP_DEBUG
                                         printk(KERN_DEBUG "lp%d sleeping at %d characters for %d jiffies\n", minor, lp_table[minor].runchars, LP_TIME(minor));
 #endif
- lp_table[minor].runchars = 0;
                                         current->state = TASK_INTERRUPTIBLE;
                                         current->timeout = jiffies + LP_TIME(minor);
- lp_schedule (minor);
+ lp_schedule_pchars(minor);
                                 } else {
                                         cli();
+ if (lp_table[minor].should_relinquish) {
+ sti();
+ goto lp_polling;
+ }
                                         enable_irq(lp->dev->port->irq);
                                         w_ctr(minor, LP_PSELECP|LP_PINITP|LP_PINTEN);
                                         status = r_str(minor);
@@ -306,13 +331,15 @@
                                                 sti();
                                                 continue;
                                         }
- lp_table[minor].runchars = 0;
                                         current->timeout = jiffies + LP_TIMEOUT_INTERRUPT;
                                         interruptible_sleep_on(&lp->lp_wait_q);
-
                                         w_ctr(minor, LP_PSELECP | LP_PINITP);
                                         sti();
+ if (lp_check_status(minor))
+ return rc ? rc : -EIO;
                                 }
+
+ lp_table[minor].runchars = 0;
 
                                 if (signal_pending(current)) {
                                         if (total_bytes_written + bytes_written)
--- linux/drivers/misc/TODO-parport 1997/12/20 17:05:02 1.1
+++ linux/drivers/misc/TODO-parport 1997/12/20 17:05:49 1.2
@@ -6,15 +6,13 @@
 
 2. Overhaul lp.c:
 
- a) It's a _mess_
-
- b) ECP support would be nice. This can only work if both the port and
+ a) ECP support would be nice. This can only work if both the port and
       the printer support it.
 
- c) Errors could do with being handled better. There's no point logging a
+ b) Errors could do with being handled better. There's no point logging a
       message every 10 seconds when the printer is out of paper.
 
- d) Handle status readback automatically. IEEE1284 printers can post status
+ c) Handle status readback automatically. IEEE1284 printers can post status
       bits when they have something to say. We should read out and deal
       with (maybe just log) whatever the printer wants to tell the world.
 
--- linux/Documentation/Configure.help 1997/12/20 17:00:59 1.1
+++ linux/Documentation/Configure.help 1997/12/20 18:19:21 1.3
@@ -5160,6 +5160,12 @@
   status indication when you read from it (for example, with `cat
   /dev/lp1'). To use this feature, say Y here.
 
+CONFIG_PRINTER_PCHARS
+ This allow you to choose the minimum number of chars to be sent to the
+ printer before release parport. More this number is big, more your
+ printer will have priority against other parallel port device that
+ are sharing the same parallel port. If unsure leave unchanged.
+
 Mouse Support (not serial mice)
 CONFIG_MOUSE
   This is for machines with a bus mouse or a PS/2 mouse as opposed to

-- 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:13 EST