[PARPORT] [patch] support O_NONBLOCK in lp and ppdev

From: Tim Waugh (twaugh@redhat.com)
Date: Sun Jan 20 2002 - 17:10:19 EST

  • Next message: Igor Bujna: "[PARPORT] lp & parport"

    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