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) ...@@ -270,7 +270,7 @@ static int lp_check_status(int minor)
return error; return error;
} }
static int lp_wait_ready(int minor) static int lp_wait_ready(int minor, int nonblock)
{ {
int error = 0; int error = 0;
...@@ -281,7 +281,7 @@ static int lp_wait_ready(int minor) ...@@ -281,7 +281,7 @@ static int lp_wait_ready(int minor)
do { do {
error = lp_check_status (minor); error = lp_check_status (minor);
if (error && (LP_F(minor) & LP_ABORT)) if (error && (nonblock || (LP_F(minor) & LP_ABORT)))
break; break;
if (signal_pending (current)) { if (signal_pending (current)) {
error = -EINTR; error = -EINTR;
...@@ -300,6 +300,8 @@ static ssize_t lp_write(struct file * file, const char * buf, ...@@ -300,6 +300,8 @@ static ssize_t lp_write(struct file * file, const char * buf,
ssize_t retv = 0; ssize_t retv = 0;
ssize_t written; ssize_t written;
size_t copy_size = count; size_t copy_size = count;
int nonblock = ((file->f_flags & O_NONBLOCK) ||
(LP_F(minor) & LP_ABORT));
#ifdef LP_STATS #ifdef LP_STATS
if (jiffies-lp_table[minor].lastcall > LP_TIME(minor)) if (jiffies-lp_table[minor].lastcall > LP_TIME(minor))
...@@ -326,9 +328,10 @@ static ssize_t lp_write(struct file * file, const char * buf, ...@@ -326,9 +328,10 @@ static ssize_t lp_write(struct file * file, const char * buf,
lp_table[minor].best_mode); lp_table[minor].best_mode);
parport_set_timeout (lp_table[minor].dev, 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 { do {
/* Write the data. */ /* Write the data. */
written = parport_write (port, kbuf, copy_size); written = parport_write (port, kbuf, copy_size);
...@@ -354,12 +357,16 @@ static ssize_t lp_write(struct file * file, const char * buf, ...@@ -354,12 +357,16 @@ static ssize_t lp_write(struct file * file, const char * buf,
IEEE1284_MODE_COMPAT); IEEE1284_MODE_COMPAT);
lp_table[minor].current_mode = 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 (error) {
if (retv == 0) if (retv == 0)
retv = error; retv = error;
break; break;
} else if (nonblock) {
if (retv == 0)
retv = -EAGAIN;
break;
} }
parport_yield_blocking (lp_table[minor].dev); parport_yield_blocking (lp_table[minor].dev);
...@@ -407,6 +414,8 @@ static ssize_t lp_read(struct file * file, char * buf, ...@@ -407,6 +414,8 @@ static ssize_t lp_read(struct file * file, char * buf,
struct parport *port = lp_table[minor].dev->port; struct parport *port = lp_table[minor].dev->port;
ssize_t retval = 0; ssize_t retval = 0;
char *kbuf = lp_table[minor].lp_buffer; char *kbuf = lp_table[minor].lp_buffer;
int nonblock = ((file->f_flags & O_NONBLOCK) ||
(LP_F(minor) & LP_ABORT));
if (count > LP_BUFFER_SIZE) if (count > LP_BUFFER_SIZE)
count = LP_BUFFER_SIZE; count = LP_BUFFER_SIZE;
...@@ -415,7 +424,53 @@ static ssize_t lp_read(struct file * file, char * buf, ...@@ -415,7 +424,53 @@ static ssize_t lp_read(struct file * file, char * buf,
return -EINTR; return -EINTR;
lp_claim_parport_or_block (&lp_table[minor]); 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]); lp_release_parport (&lp_table[minor]);
if (retval > 0 && copy_to_user (buf, kbuf, retval)) if (retval > 0 && copy_to_user (buf, kbuf, retval))
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
* This is the code behind /dev/parport* -- it allows a user-space * This is the code behind /dev/parport* -- it allows a user-space
* application to use the parport subsystem. * 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 * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
...@@ -80,6 +80,7 @@ struct pp_struct { ...@@ -80,6 +80,7 @@ struct pp_struct {
unsigned char irqctl; unsigned char irqctl;
struct ieee1284_info state; struct ieee1284_info state;
struct ieee1284_info saved_state; struct ieee1284_info saved_state;
long default_inactivity;
}; };
/* pp_struct.flags bitfields */ /* pp_struct.flags bitfields */
...@@ -107,7 +108,6 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, ...@@ -107,7 +108,6 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
struct pp_struct *pp = file->private_data; struct pp_struct *pp = file->private_data;
char * kbuffer; char * kbuffer;
ssize_t bytes_read = 0; ssize_t bytes_read = 0;
ssize_t got = 0;
struct parport *pport; struct parport *pport;
int mode; int mode;
...@@ -125,8 +125,13 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, ...@@ -125,8 +125,13 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
pport = pp->pdev->port; pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR);
while (bytes_read < count) { parport_set_timeout (pp->pdev,
ssize_t need = min_t(unsigned long, count - bytes_read, PP_BUFFER_SIZE); (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) { if (mode == IEEE1284_MODE_EPP) {
/* various specials for EPP mode */ /* various specials for EPP mode */
...@@ -144,35 +149,32 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count, ...@@ -144,35 +149,32 @@ static ssize_t pp_read (struct file * file, char * buf, size_t count,
} else { } else {
fn = pport->ops->epp_read_data; fn = pport->ops->epp_read_data;
} }
got = (*fn)(pport, kbuffer, need, flags); bytes_read = (*fn)(pport, kbuffer, need, flags);
} else { } else {
got = parport_read (pport, kbuffer, need); bytes_read = parport_read (pport, kbuffer, need);
} }
if (got <= 0) { if (bytes_read != 0)
if (!bytes_read) {
bytes_read = got;
}
break; break;
}
if (copy_to_user (buf + bytes_read, kbuffer, got)) { if (file->f_flags & O_NONBLOCK) {
bytes_read = -EFAULT; bytes_read = -EAGAIN;
break; break;
} }
bytes_read += got;
if (signal_pending (current)) { if (signal_pending (current)) {
if (!bytes_read) { bytes_read = -ERESTARTSYS;
bytes_read = -EINTR;
}
break; break;
} }
cond_resched(); 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); kfree (kbuffer);
pp_enable_irq (pp); pp_enable_irq (pp);
return bytes_read; return bytes_read;
...@@ -203,6 +205,11 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count, ...@@ -203,6 +205,11 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
pport = pp->pdev->port; pport = pp->pdev->port;
mode = pport->ieee1284.mode & ~(IEEE1284_DEVICEID | IEEE1284_ADDR); 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) { while (bytes_written < count) {
ssize_t n = min_t(unsigned long, count - bytes_written, PP_BUFFER_SIZE); 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, ...@@ -233,6 +240,12 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
bytes_written += wrote; bytes_written += wrote;
if (file->f_flags & O_NONBLOCK) {
if (!bytes_written)
bytes_written = -EAGAIN;
break;
}
if (signal_pending (current)) { if (signal_pending (current)) {
if (!bytes_written) { if (!bytes_written) {
bytes_written = -EINTR; bytes_written = -EINTR;
...@@ -243,6 +256,8 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count, ...@@ -243,6 +256,8 @@ static ssize_t pp_write (struct file * file, const char * buf, size_t count,
cond_resched(); cond_resched();
} }
parport_set_timeout (pp->pdev, pp->default_inactivity);
kfree (kbuffer); kfree (kbuffer);
pp_enable_irq (pp); pp_enable_irq (pp);
return bytes_written; return bytes_written;
...@@ -352,6 +367,8 @@ static int pp_ioctl(struct inode *inode, struct file *file, ...@@ -352,6 +367,8 @@ static int pp_ioctl(struct inode *inode, struct file *file,
pp->saved_state.phase = info->phase; pp->saved_state.phase = info->phase;
info->mode = pp->state.mode; info->mode = pp->state.mode;
info->phase = pp->state.phase; info->phase = pp->state.phase;
pp->default_inactivity = parport_set_timeout (pp->pdev, 0);
parport_set_timeout (pp->pdev, pp->default_inactivity);
return 0; 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> 2002-02-25 Tim Waugh <twaugh@redhat.com>
* parport_pc.c: Make sure that priv->ctr_writable includes IntEn * 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, ...@@ -818,8 +818,9 @@ size_t parport_pc_compat_write_block_pio (struct parport *port,
long int expire; long int expire;
const struct parport_pc_private *priv = port->physport->private_data; const struct parport_pc_private *priv = port->physport->private_data;
/* Special case: a timeout of zero means we cannot call schedule(). */ /* Special case: a timeout of zero means we cannot call schedule().
if (!port->physport->cad->timeout) * 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, return parport_ieee1284_write_compat (port, buf,
length, flags); length, flags);
...@@ -894,8 +895,9 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port, ...@@ -894,8 +895,9 @@ size_t parport_pc_ecp_write_block_pio (struct parport *port,
long int expire; long int expire;
const struct parport_pc_private *priv = port->physport->private_data; const struct parport_pc_private *priv = port->physport->private_data;
/* Special case: a timeout of zero means we cannot call schedule(). */ /* Special case: a timeout of zero means we cannot call schedule().
if (!port->physport->cad->timeout) * 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, return parport_ieee1284_ecp_write_data (port, buf,
length, flags); length, flags);
...@@ -1014,8 +1016,9 @@ size_t parport_pc_ecp_read_block_pio (struct parport *port, ...@@ -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"); DPRINTK (KERN_DEBUG "parport_pc: parport_pc_ecp_read_block_pio\n");
dump_parport_state ("enter fcn", port); dump_parport_state ("enter fcn", port);
/* Special case: a timeout of zero means we cannot call schedule(). */ /* Special case: a timeout of zero means we cannot call schedule().
if (!port->cad->timeout) * 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, return parport_ieee1284_ecp_read_data (port, buf,
length, flags); length, flags);
......
...@@ -459,7 +459,10 @@ extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *); ...@@ -459,7 +459,10 @@ extern void parport_ieee1284_interrupt (int, void *, struct pt_regs *);
extern int parport_negotiate (struct parport *, int mode); 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_write (struct parport *, const void *buf, size_t len);
extern ssize_t parport_read (struct parport *, 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 long parport_set_timeout (struct pardevice *, long inactivity);
extern int parport_wait_event (struct parport *, long timeout); extern int parport_wait_event (struct parport *, long timeout);
extern int parport_wait_peripheral (struct parport *port, extern int parport_wait_peripheral (struct parport *port,
unsigned char mask, 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