patch-2.4.14 linux/drivers/char/lp.c
Next file: linux/drivers/char/misc.c
Previous file: linux/drivers/char/joystick/analog.c
Back to the patch index
Back to the overall index
- Lines: 230
- Date:
Thu Oct 25 00:07:39 2001
- Orig file:
v2.4.13/linux/drivers/char/lp.c
- Orig date:
Sun Sep 23 11:40:57 2001
diff -u --recursive --new-file v2.4.13/linux/drivers/char/lp.c linux/drivers/char/lp.c
@@ -153,6 +153,10 @@
#undef LP_DEBUG
+/* Bits used to manage claiming the parport device */
+#define LP_PREEMPT_REQUEST 1
+#define LP_PARPORT_CLAIMED 2
+
/* --- low-level port access ----------------------------------- */
#define r_dtr(x) (parport_read_data(lp_table[(x)].dev->port))
@@ -160,15 +164,55 @@
#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)
+/* Claim the parport or block trying unless we've already claimed it */
+static void lp_claim_parport_or_block(struct lp_struct *this_lp)
+{
+ if (!test_and_set_bit(LP_PARPORT_CLAIMED, &this_lp->bits)) {
+ parport_claim_or_block (this_lp->dev);
+ }
+}
+
+/* Claim the parport or block trying unless we've already claimed it */
+static void lp_release_parport(struct lp_struct *this_lp)
+{
+ if (test_and_clear_bit(LP_PARPORT_CLAIMED, &this_lp->bits)) {
+ parport_release (this_lp->dev);
+ }
+}
+
+
+
+static int lp_preempt(void *handle)
+{
+ struct lp_struct *this_lp = (struct lp_struct *)handle;
+ set_bit(LP_PREEMPT_REQUEST, &this_lp->bits);
+ return (1);
+}
+
+
+/*
+ * Try to negotiate to a new mode; if unsuccessful negotiate to
+ * compatibility mode. Return the mode we ended up in.
+ */
+static int lp_negotiate(struct parport * port, int mode)
+{
+ if (parport_negotiate (port, mode) != 0) {
+ mode = IEEE1284_MODE_COMPAT;
+ parport_negotiate (port, mode);
+ }
+
+ return (mode);
+}
+
static int lp_reset(int minor)
{
int retval;
- parport_claim_or_block (lp_table[minor].dev);
+ lp_claim_parport_or_block (&lp_table[minor]);
w_ctr(minor, LP_PSELECP);
udelay (LP_DELAY);
w_ctr(minor, LP_PSELECP | LP_PINITP);
retval = r_str(minor);
- parport_release (lp_table[minor].dev);
+ lp_release_parport (&lp_table[minor]);
return retval;
}
@@ -180,10 +224,10 @@
return;
polling = lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE;
- if (polling) parport_release (lp_table[minor].dev);
+ if (polling) lp_release_parport (&lp_table[minor]);
interruptible_sleep_on_timeout (&lp_table[minor].waitq,
LP_TIMEOUT_POLLED);
- if (polling) parport_claim_or_block (lp_table[minor].dev);
+ if (polling) lp_claim_parport_or_block (&lp_table[minor]);
else parport_yield_blocking (lp_table[minor].dev);
}
@@ -229,6 +273,12 @@
static int lp_wait_ready(int minor)
{
int error = 0;
+
+ /* If we're not in compatibility mode, we're ready now! */
+ if (lp_table[minor].current_mode != IEEE1284_MODE_COMPAT) {
+ return (0);
+ }
+
do {
error = lp_check_status (minor);
if (error && (LP_F(minor) & LP_ABORT))
@@ -270,10 +320,10 @@
/* Claim Parport or sleep until it becomes available
*/
- parport_claim_or_block (lp_table[minor].dev);
-
- /* Go to compatibility mode. */
- parport_negotiate (port, IEEE1284_MODE_COMPAT);
+ lp_claim_parport_or_block (&lp_table[minor]);
+ /* Go to the proper mode. */
+ lp_table[minor].current_mode = lp_negotiate (port,
+ lp_table[minor].best_mode);
parport_set_timeout (lp_table[minor].dev,
lp_table[minor].timeout);
@@ -298,7 +348,13 @@
if (copy_size > 0) {
/* incomplete write -> check error ! */
- int error = lp_wait_ready (minor);
+ int error;
+
+ parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_COMPAT);
+ lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
+
+ error = lp_wait_ready (minor);
if (error) {
if (retv == 0)
@@ -307,6 +363,10 @@
}
parport_yield_blocking (lp_table[minor].dev);
+ lp_table[minor].current_mode
+ = lp_negotiate (port,
+ lp_table[minor].best_mode);
+
} else if (current->need_resched)
schedule ();
@@ -323,7 +383,14 @@
}
} while (count > 0);
- parport_release (lp_table[minor].dev);
+ if (test_and_clear_bit(LP_PREEMPT_REQUEST,
+ &lp_table[minor].bits)) {
+ printk(KERN_INFO "lp%d releasing parport\n", minor);
+ parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_COMPAT);
+ lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
+ lp_release_parport (&lp_table[minor]);
+ }
up (&lp_table[minor].port_mutex);
@@ -347,9 +414,9 @@
if (down_interruptible (&lp_table[minor].port_mutex))
return -EINTR;
- parport_claim_or_block (lp_table[minor].dev);
+ lp_claim_parport_or_block (&lp_table[minor]);
retval = parport_read (port, kbuf, count);
- parport_release (lp_table[minor].dev);
+ lp_release_parport (&lp_table[minor]);
if (retval > 0 && copy_to_user (buf, kbuf, retval))
retval = -EFAULT;
@@ -379,9 +446,9 @@
should most likely only ever be used by the tunelp application. */
if ((LP_F(minor) & LP_ABORTOPEN) && !(file->f_flags & O_NONBLOCK)) {
int status;
- parport_claim_or_block (lp_table[minor].dev);
+ lp_claim_parport_or_block (&lp_table[minor]);
status = r_str(minor);
- parport_release (lp_table[minor].dev);
+ lp_release_parport (&lp_table[minor]);
if (status & LP_POUTPA) {
printk(KERN_INFO "lp%d out of paper\n", minor);
LP_F(minor) &= ~LP_BUSY;
@@ -401,6 +468,21 @@
LP_F(minor) &= ~LP_BUSY;
return -ENOMEM;
}
+ /* Determine if the peripheral supports ECP mode */
+ lp_claim_parport_or_block (&lp_table[minor]);
+ if ( (lp_table[minor].dev->port->modes & PARPORT_MODE_ECP) &&
+ !parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_ECP)) {
+ printk (KERN_INFO "lp%d: ECP mode\n", minor);
+ lp_table[minor].best_mode = IEEE1284_MODE_ECP;
+ } else {
+ printk (KERN_INFO "lp%d: compatibility mode\n", minor);
+ lp_table[minor].best_mode = IEEE1284_MODE_COMPAT;
+ }
+ /* Leave peripheral in compatibility mode */
+ parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+ lp_release_parport (&lp_table[minor]);
+ lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
return 0;
}
@@ -408,6 +490,10 @@
{
unsigned int minor = MINOR(inode->i_rdev);
+ lp_claim_parport_or_block (&lp_table[minor]);
+ parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+ lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
+ lp_release_parport (&lp_table[minor]);
lock_kernel();
kfree(lp_table[minor].lp_buffer);
lp_table[minor].lp_buffer = NULL;
@@ -470,9 +556,9 @@
return -EFAULT;
break;
case LPGETSTATUS:
- parport_claim_or_block (lp_table[minor].dev);
+ lp_claim_parport_or_block (&lp_table[minor]);
status = r_str(minor);
- parport_release (lp_table[minor].dev);
+ lp_release_parport (&lp_table[minor]);
if (copy_to_user((int *) arg, &status, sizeof(int)))
return -EFAULT;
@@ -657,7 +743,7 @@
char name[8];
lp_table[nr].dev = parport_register_device(port, "lp",
- NULL, NULL, NULL, 0,
+ lp_preempt, NULL, NULL, 0,
(void *) &lp_table[nr]);
if (lp_table[nr].dev == NULL)
return 1;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)