Commit d5d28282 authored by Tim Waugh's avatar Tim Waugh Committed by Linus Torvalds

[PATCH] 2.5.6-pre1: parport and O_NONBLOCK

This patch makes lp and ppdev do the Right Thing regarding O_NONBLOCK.

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.
parent e20c06c0
......@@ -270,7 +270,7 @@ static int lp_check_status(int minor)
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 @@ static int lp_wait_ready(int minor)
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 @@ static ssize_t lp_write(struct file * file, const char * buf,
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 @@ static ssize_t lp_write(struct file * file, const char * buf,
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 @@ static ssize_t lp_write(struct file * file, const char * buf,
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 @@ static ssize_t lp_read(struct file * file, char * buf,
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,53 @@ static ssize_t lp_read(struct file * file, char * buf,
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;
}
cond_resched ();
}
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))
......
......@@ -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.net>
*
* 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 @@ struct pp_struct {
unsigned char irqctl;
struct ieee1284_info state;
struct ieee1284_info saved_state;
long default_inactivity;
};
/* pp_struct.flags bitfields */
......@@ -107,7 +108,6 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
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 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
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,35 +149,32 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
} 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;
}
cond_resched();
}
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;
......@@ -203,6 +205,11 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
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);
......@@ -233,6 +240,12 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
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;
......@@ -243,6 +256,8 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
cond_resched();
}
parport_set_timeout (pp->pdev, pp->default_inactivity);
kfree (kbuffer);
pp_enable_irq (pp);
return bytes_written;
......@@ -352,6 +367,8 @@ static int pp_ioctl(struct inode *inode, struct file *file,
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;
}
......
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.
2002-02-25 Tim Waugh <twaugh@redhat.com>
* parport_pc.c: Make sure that priv->ctr_writable includes IntEn
......
......@@ -818,8 +818,9 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
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);
......@@ -894,8 +895,9 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
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);
......@@ -1014,8 +1016,9 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port,
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);
......
......@@ -459,7 +459,10 @@ extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
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,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment