Here is an experimental patch to add support for O_NONBLOCK to lp and
ppdev. Comments, feedback, test results, etc welcome.
Tim.
*/
2002-01-04 Tim Waugh <twaugh@redhat.com>
* include/linux/parport.h: Define a special inactivity timeout
meaning 'caller wants to use O_NONBLOCK'.
* drivers/char/lp.c: Support O_NONBLOCK properly.
* drivers/char/ppdev.c: Likewise.
* drivers/parport/parport_pc.c: Likewise.
* drivers/parport/ChangeLog: Updated.
--- linux/include/linux/parport.h.nonblock Sun Jan 20 18:26:18 2002
+++ linux/include/linux/parport.h Sun Jan 20 22:05:34 2002
@@ -458,7 +458,10 @@
extern int parport_negotiate (struct parport *, int mode);
extern ssize_t parport_write (struct parport *, const void *buf, size_t len);
extern ssize_t parport_read (struct parport *, void *buf, size_t len);
+
+#define PARPORT_INACTIVITY_O_NONBLOCK 1
extern long parport_set_timeout (struct pardevice *, long inactivity);
+
extern int parport_wait_event (struct parport *, long timeout);
extern int parport_wait_peripheral (struct parport *port,
unsigned char mask,
--- linux/drivers/char/lp.c.nonblock Sun Jan 20 18:22:18 2002
+++ linux/drivers/char/lp.c Sun Jan 20 21:49:29 2002
@@ -270,7 +270,7 @@
return error;
}
-static int lp_wait_ready(int minor)
+static int lp_wait_ready(int minor, int nonblock)
{
int error = 0;
@@ -281,7 +281,7 @@
do {
error = lp_check_status (minor);
- if (error && (LP_F(minor) & LP_ABORT))
+ if (error && (nonblock || (LP_F(minor) & LP_ABORT)))
break;
if (signal_pending (current)) {
error = -EINTR;
@@ -300,6 +300,8 @@
ssize_t retv = 0;
ssize_t written;
size_t copy_size = count;
+ int nonblock = ((file->f_flags & O_NONBLOCK) ||
+ (LP_F(minor) & LP_ABORT));
#ifdef LP_STATS
if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
@@ -326,9 +328,10 @@
lp_table[minor].best_mode);
parport_set_timeout (lp_table[minor].dev,
- lp_table[minor].timeout);
+ (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK
+ : lp_table[minor].timeout));
- if ((retv = lp_wait_ready (minor)) == 0)
+ if ((retv = lp_wait_ready (minor, nonblock)) == 0)
do {
/* Write the data. */
written = parport_write (port, kbuf, copy_size);
@@ -354,12 +357,16 @@
IEEE1284_MODE_COMPAT);
lp_table[minor].current_mode = IEEE1284_MODE_COMPAT;
- error = lp_wait_ready (minor);
+ error = lp_wait_ready (minor, nonblock);
if (error) {
if (retv == 0)
retv = error;
break;
+ } else if (nonblock) {
+ if (retv == 0)
+ retv = -EAGAIN;
+ break;
}
parport_yield_blocking (lp_table[minor].dev);
@@ -407,6 +414,8 @@
struct parport *port = lp_table[minor].dev->port;
ssize_t retval = 0;
char *kbuf = lp_table[minor].lp_buffer;
+ int nonblock = ((file->f_flags & O_NONBLOCK) ||
+ (LP_F(minor) & LP_ABORT));
if (count > LP_BUFFER_SIZE)
count = LP_BUFFER_SIZE;
@@ -415,7 +424,54 @@
return -EINTR;
lp_claim_parport_or_block (&lp_table[minor]);
- retval = parport_read (port, kbuf, count);
+
+ parport_set_timeout (lp_table[minor].dev,
+ (nonblock ? PARPORT_INACTIVITY_O_NONBLOCK
+ : lp_table[minor].timeout));
+
+ parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+ if (parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_NIBBLE)) {
+ retval = -EIO;
+ goto out;
+ }
+
+ while (retval == 0) {
+ retval = parport_read (port, kbuf, count);
+
+ if (retval > 0)
+ break;
+
+ if (nonblock) {
+ retval = -EAGAIN;
+ break;
+ }
+
+ /* Wait for data. */
+
+ if (lp_table[minor].dev->port->irq == PARPORT_IRQ_NONE) {
+ parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_COMPAT);
+ lp_error (minor);
+ if (parport_negotiate (lp_table[minor].dev->port,
+ IEEE1284_MODE_NIBBLE)) {
+ retval = -EIO;
+ goto out;
+ }
+ } else
+ interruptible_sleep_on_timeout (&lp_table[minor].waitq,
+ LP_TIMEOUT_POLLED);
+
+ if (signal_pending (current)) {
+ retval = -ERESTARTSYS;
+ break;
+ }
+
+ if (current->need_resched)
+ schedule ();
+ }
+ parport_negotiate (lp_table[minor].dev->port, IEEE1284_MODE_COMPAT);
+ out:
lp_release_parport (&lp_table[minor]);
if (retval > 0 && copy_to_user (buf, kbuf, retval))
--- linux/drivers/char/ppdev.c.nonblock Sun Jan 20 18:22:18 2002
+++ linux/drivers/char/ppdev.c Sun Jan 20 22:08:26 2002
@@ -4,7 +4,7 @@
* This is the code behind /dev/parport* -- it allows a user-space
* application to use the parport subsystem.
*
- * Copyright (C) 1998-2000 Tim Waugh <tim@cyberelk.demon.co.uk>
+ * Copyright (C) 1998-2000, 2002 Tim Waugh <tim@cyberelk.demon.co.uk>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -80,6 +80,7 @@
unsigned char irqctl;
struct ieee1284_info state;
struct ieee1284_info saved_state;
+ long default_inactivity;
};
/* pp_struct.flags bitfields */
@@ -107,7 +108,6 @@
struct pp_struct *pp = file->private_data;
char * kbuffer;
ssize_t bytes_read = 0;
- ssize_t got = 0;
struct parport *pport;
int mode;
@@ -125,8 +125,13 @@
pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
- while (bytes_read < count) {
- ssize_t need = min_t(unsigned long, count - bytes_read, PP_BUFFER_SIZE);
+ parport_set_timeout (pp->pdev,
+ (file->f_flags & O_NONBLOCK) ?
+ PARPORT_INACTIVITY_O_NONBLOCK :
+ pp->default_inactivity);
+
+ while (bytes_read == 0) {
+ ssize_t need = min_t(unsigned long, count, PP_BUFFER_SIZE);
if (mode == IEEE1284_MODE_EPP) {
/* various specials for EPP mode */
@@ -144,37 +149,33 @@
} else {
fn = pport->ops->epp_read_data;
}
- got = (*fn)(pport, kbuffer, need, flags);
+ bytes_read = (*fn)(pport, kbuffer, need, flags);
} else {
- got = parport_read (pport, kbuffer, need);
+ bytes_read = parport_read (pport, kbuffer, need);
}
- if (got <= 0) {
- if (!bytes_read) {
- bytes_read = got;
- }
+ if (bytes_read != 0)
break;
- }
- if (copy_to_user (buf + bytes_read, kbuffer, got)) {
- bytes_read = -EFAULT;
+ if (file->f_flags & O_NONBLOCK) {
+ bytes_read = -EAGAIN;
break;
}
- bytes_read += got;
-
if (signal_pending (current)) {
- if (!bytes_read) {
- bytes_read = -EINTR;
- }
+ bytes_read = -ERESTARTSYS;
break;
}
- if (current->need_resched) {
+ if (current->need_resched)
schedule ();
- }
}
+ parport_set_timeout (pp->pdev, pp->default_inactivity);
+
+ if (bytes_read > 0 && copy_to_user (buf, kbuffer, bytes_read))
+ bytes_read = -EFAULT;
+
kfree (kbuffer);
pp_enable_irq (pp);
return bytes_read;
@@ -205,6 +206,11 @@
pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
+ parport_set_timeout (pp->pdev,
+ (file->f_flags & O_NONBLOCK) ?
+ PARPORT_INACTIVITY_O_NONBLOCK :
+ pp->default_inactivity);
+
while (bytes_written < count) {
ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE);
@@ -235,6 +241,12 @@
bytes_written += wrote;
+ if (file->f_flags & O_NONBLOCK) {
+ if (!bytes_written)
+ bytes_written = -EAGAIN;
+ break;
+ }
+
if (signal_pending (current)) {
if (!bytes_written) {
bytes_written = -EINTR;
@@ -247,6 +259,8 @@
}
}
+ parport_set_timeout (pp->pdev, pp->default_inactivity);
+
kfree (kbuffer);
pp_enable_irq (pp);
return bytes_written;
@@ -356,6 +370,8 @@
pp->saved_state.phase = info->phase;
info->mode = pp->state.mode;
info->phase = pp->state.phase;
+ pp->default_inactivity = parport_set_timeout (pp->pdev, 0);
+ parport_set_timeout (pp->pdev, pp->default_inactivity);
return 0;
}
--- linux/drivers/parport/parport_pc.c.nonblock Sun Jan 20 18:30:33 2002
+++ linux/drivers/parport/parport_pc.c Sun Jan 20 18:35:49 2002
@@ -821,8 +821,9 @@
long int expire;
const struct parport_pc_private *priv = port->physport->private_data;
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->physport->cad->timeout)
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
return parport_ieee1284_write_compat (port, buf,
length, flags);
@@ -897,8 +898,9 @@
long int expire;
const struct parport_pc_private *priv = port->physport->private_data;
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->physport->cad->timeout)
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (port->physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
return parport_ieee1284_ecp_write_data (port, buf,
length, flags);
@@ -1017,8 +1019,9 @@
DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
dump_parport_state ("enter fcn", port);
- /* Special case: a timeout of zero means we cannot call schedule(). */
- if (!port->cad->timeout)
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (port->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
return parport_ieee1284_ecp_read_data (port, buf,
length, flags);
--- linux/drivers/parport/ChangeLog.nonblock Sun Jan 20 18:43:16 2002
+++ linux/drivers/parport/ChangeLog Sun Jan 20 18:44:07 2002
@@ -0,0 +1,7 @@
+2002-01-20 Tim Waugh <twaugh@redhat.com>
+
+ * parport_pc.c (parport_pc_compat_write_block_pio,
+ parport_pc_ecp_write_block_pio, parport_pc_ecp_read_block_pio):
+ Use the default implementations if the caller wants to use
+ O_NONBLOCK.
+
-- 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 2b29 : Sun Jan 20 2002 - 17:13:53 EST