Re: [PARPORT] sneak preview


Andrea Arcangeli (arcangeli@mbox.queen.it)
Sun, 30 Nov 1997 18:16:08 +0100 (CET)


On Sat, 29 Nov 1997, Philip Blundell wrote:

>Hi.
>
>I just sent the appended patch to Linus, so hopefully it will show up in
>the kernel sometime soon. If anybody wants to try it in the meantime,
>feel free to let me know how you get on.
>
>Andrea, it would help if you could the next iteration of your lp changes
>relative to this.

Here the patch against your' s. Your patch add a bug in the use of
reuquest/free irq in parport_share.c. I hope to see it in 2.1.68.

Andrea[s] Arcangeli

diff -u -r linux_philip/Documentation/Configure.help linux/Documentation/Configure.help
--- linux_philip/Documentation/Configure.help Sun Nov 30 14:53:28 1997
+++ linux/Documentation/Configure.help Sun Nov 30 18:03:36 1997
@@ -4888,6 +4888,12 @@
   status indication when you read from it (for example, with `cat
   /dev/lp1'). To use this feature, say Y here.
 
+CONFIG_PRINTER_PCHARS
+ Set the number of chars to be sent to the printer to allow lp to
+ 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
diff -u -r linux_philip/drivers/char/Config.in linux/drivers/char/Config.in
--- linux_philip/drivers/char/Config.in Sun Nov 30 14:53:00 1997
+++ linux/drivers/char/Config.in Sun Nov 30 18:02:51 1997
@@ -45,6 +45,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
 
diff -u -r linux_philip/drivers/char/lp.c linux/drivers/char/lp.c
--- linux_philip/drivers/char/lp.c Sun Nov 30 15:49:15 1997
+++ linux/drivers/char/lp.c Sun Nov 30 17:55:46 1997
@@ -11,13 +11,9 @@
  * 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 is about due for a rewrite. */
-
 #include <linux/module.h>
 
 #include <linux/config.h>
@@ -38,16 +34,25 @@
 #include <linux/lp.h>
 
 /* if you have more than 3 printers, remember to increase LP_NO */
-struct lp_struct lp_table[] =
-{
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}},
- {NULL, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, 0, 0, 0, 0,
- {0}}
-};
 #define LP_NO 3
+#define LP_EMPTY \
+{NULL, /* dev */ \
+0, /* flags */ \
+LP_INIT_CHAR, /* chars */ \
+LP_INIT_TIME, /* time */ \
+LP_INIT_WAIT, /* wait */ \
+NULL, /* lp_wait_q */ \
+NULL, /* lp_buffer */ \
+0, /* lastcall */ \
+0, /* runchars */ \
+0, /* waittime */ \
+0, /* should_relinquish */ \
+{0}, /* stats */ \
+CONFIG_PRINTER_PCHARS, /* pchars */ \
+LP_PDEADLOCK /* pdeadlock */ \
+}
+struct lp_struct lp_table[LP_NO] =
+{ LP_EMPTY, LP_EMPTY, LP_EMPTY };
 
 /* Device name */
 static char *dev_name = "lp";
@@ -65,14 +70,14 @@
 #undef LP_READ_DEBUG
 
 /* Magic numbers */
-#define AUTO -3
-#define OFF -2
-#define UNSPEC -1
+#define LP_AUTO -3
+#define LP_OFF -2
+#define LP_UNSPEC -1
 
 static inline void lp_parport_release (int minor)
 {
- parport_release (lp_table[minor].dev);
         lp_table[minor].should_relinquish = 0;
+ parport_release (lp_table[minor].dev);
 }
 
 static inline void lp_parport_claim (int minor)
@@ -81,6 +86,19 @@
                 sleep_on (&lp_table[minor].lp_wait_q);
 }
 
+static inline void lp_schedule_pchars(int minor)
+{
+ if ((lp_table[minor].should_relinquish && !lp_table[minor].pchars)
+ || !lp_table[minor].pdeadlock--) {
+ lp_table[minor].pchars = CONFIG_PRINTER_PCHARS;
+ lp_table[minor].pdeadlock = LP_PDEADLOCK;
+ lp_parport_release (minor);
+ schedule();
+ lp_parport_claim (minor);
+ } else
+ schedule();
+}
+
 static inline void lp_schedule (int minor)
 {
         if (lp_table[minor].should_relinquish) {
@@ -92,11 +110,13 @@
                 schedule ();
 }
 
-
 static int lp_preempt (void *handle)
 {
         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;
 
@@ -118,7 +138,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;
@@ -128,26 +148,25 @@
         do {
                 status = r_str(minor);
                 count++;
- if (resched_needed())
- 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
            low, according spec. Some printers need it, others don't. */
- while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
- wait++;
+ udelay(LP_WAIT(minor));
         /* control port takes strobe high */
         w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
- while (wait) /* FIXME: should be a udelay() */
- wait--;
+ udelay(LP_WAIT(minor));
         /* take strobe low */
         w_ctr(minor, LP_PSELECP | LP_PINITP);
         /* update waittime statistics */
@@ -171,18 +190,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;
@@ -202,7 +244,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++;
@@ -210,36 +252,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)) { /* polling */
+ 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);
- } else {
+ lp_schedule_pchars(minor);
+ } else { /* interrupt */
                                         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);
@@ -249,13 +279,14 @@
                                                 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)
@@ -294,6 +325,7 @@
         retv = lp_write_buf(minor, buf, count);
  
          lp_parport_release (minor);
+ UPDATE_ATIME(file->f_dentry->d_inode);
          return retv;
 }
 
@@ -356,7 +388,7 @@
                         status=(r_str(minor) & 0x40);
                         udelay(50);
                         counter++;
- if (resched_needed())
+ if (need_resched)
                                 schedule ();
                 } while ( (status == 0x40) && (counter < 20) );
                 if ( counter == 20 ) { /* Timeout */
@@ -375,7 +407,7 @@
                         status=(r_str(minor) & 0x40);
                         udelay(20);
                         counter++;
- if (resched_needed())
+ if (need_resched)
                                 schedule ();
                 } while ( (status == 0) && (counter < 20) );
                 if (counter == 20) { /* Timeout */
@@ -403,6 +435,7 @@
         }
         lp_select_in_high(minor);
         parport_release(lp_table[minor].dev);
+ UPDATE_ATIME(file->f_dentry->d_inode);
         return temp-buf;
 }
 
@@ -571,7 +604,7 @@
         lp_release
 };
 
-static int parport[LP_NO] = { UNSPEC, };
+static int parport[LP_NO] = { [0 ... LP_NO-1] = LP_UNSPEC };
 
 #ifdef MODULE
 #define lp_init init_module
@@ -592,11 +625,11 @@
                         printk(KERN_INFO "lp: too many ports, %s ignored.\n",
                                str);
         } else if (!strcmp(str, "auto")) {
- parport[0] = AUTO;
+ parport[0] = LP_AUTO;
         } else {
                 if (ints[0] == 0 || ints[1] == 0) {
                         /* disable driver on "lp=" or "lp=0" */
- parport[0] = OFF;
+ parport[0] = LP_OFF;
                 } else {
                         printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
                 }
@@ -622,7 +655,7 @@
 static int inline lp_searchfor(int list[], int a)
 {
         int i;
- for (i = 0; i < LP_NO && list[i] != UNSPEC; i++) {
+ for (i = 0; i < LP_NO && list[i] != LP_UNSPEC; i++) {
                 if (list[i] == a) return 1;
         }
         return 0;
@@ -633,16 +666,16 @@
         int count = 0;
         struct parport *pb;
   
- if (parport[0] == OFF) return 0;
+ if (parport[0] == LP_OFF) return 0;
 
         pb = parport_enumerate();
 
         while (pb) {
                 /* We only understand PC-style ports. */
                 if (pb->modes & PARPORT_MODE_PCSPP) {
- if (parport[0] == UNSPEC ||
+ if (parport[0] == LP_UNSPEC ||
                             lp_searchfor(parport, count) ||
- (parport[0] == AUTO &&
+ (parport[0] == LP_AUTO &&
                              pb->probe_info.class == PARPORT_CLASS_PRINTER)) {
                                 lp_table[count].dev =
                                   parport_register_device(pb, dev_name,
diff -u -r linux_philip/drivers/misc/TODO-parport linux/drivers/misc/TODO-parport
--- linux_philip/drivers/misc/TODO-parport Sat Sep 20 20:43:22 1997
+++ linux/drivers/misc/TODO-parport Sun Nov 30 18:09:00 1997
@@ -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.
 
diff -u -r linux_philip/drivers/misc/parport_ieee1284.c linux/drivers/misc/parport_ieee1284.c
--- linux_philip/drivers/misc/parport_ieee1284.c Sun Nov 30 15:48:39 1997
+++ linux/drivers/misc/parport_ieee1284.c Sun Nov 30 16:55:52 1997
@@ -30,7 +30,7 @@
                 if ((status & mask) == result)
                         return 0;
                 udelay(25);
- if (resched_needed())
+ if (need_resched)
                         schedule();
         }
         current->state = TASK_INTERRUPTIBLE;
diff -u -r linux_philip/drivers/misc/parport_share.c linux/drivers/misc/parport_share.c
--- linux_philip/drivers/misc/parport_share.c Sun Nov 30 15:48:39 1997
+++ linux/drivers/misc/parport_share.c Sun Nov 30 17:49:49 1997
@@ -307,9 +307,9 @@
 
         /* Point IRQs somewhere harmless. */
         if (dev->port->irq != PARPORT_IRQ_NONE) {
- free_irq(dev->port->irq, dev->port);
+ free_irq(dev->port->irq, dev->private);
                 request_irq(dev->port->irq, parport_null_intr_func,
- SA_INTERRUPT, dev->port->name, NULL);
+ SA_INTERRUPT, dev->port->name, dev->port);
          }
 
         /* Walk the list, offering a wakeup callback to everybody other
diff -u -r linux_philip/include/linux/lp.h linux/include/linux/lp.h
--- linux_philip/include/linux/lp.h Tue Aug 26 23:52:45 1997
+++ linux/include/linux/lp.h Sun Nov 30 16:33:57 1997
@@ -83,7 +83,6 @@
 #define LP_TIME(minor) lp_table[(minor)].time /* wait time */
 #define LP_WAIT(minor) lp_table[(minor)].wait /* strobe wait */
 #define LP_IRQ(minor) lp_table[(minor)].dev->port->irq /* interrupt # */
- /* 0 means polled */
 #define LP_STAT(minor) lp_table[(minor)].stats /* statistics area */
 #define LP_BUFFER_SIZE 256
 
@@ -125,6 +124,8 @@
         unsigned int waittime;
         unsigned int should_relinquish;
         struct lp_stats stats;
+ unsigned int pchars;
+ unsigned int pdeadlock;
 };
 
 /*
@@ -169,6 +170,22 @@
  * It is used only in the lp_init() and lp_reset() routine.
  */
 #define LP_DELAY 50
+
+#ifndef CONFIG_PRINTER_PCHARS
+/*
+ * Number of chars that must be sent to the printer in order to release
+ * parport.
+ */
+#define CONFIG_PRINTER_PCHARS 10
+#endif
+
+/*
+ * Number of scheduling that lp must do without relase parport before force a
+ * parport release even if pchars != 0. This is for avoid deadlocks if the
+ * data to print is provided from another pardevice that is sharing parport
+ * with lp.
+ */
+#define LP_PDEADLOCK 10000
 
 /*
  * function prototypes

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