Previous Next Table of Contents

7. lp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

7.1 General info.

Function: lp_ioctl enables ioctls for parallel devices.

Called from: ioctl (Base driver operation).

Files: drivers/char/lp.c, include/linux/lp.h

7.2 Code description

lp_ioctl handles any miscellaneous control functions that are needed for printing devices. The arguments are the standard inode and file (see above), as well as cmd, the command which we wish to send and arg, any further arguments.

static int lp_ioctl(struct inode *inode, struct file *file,
                    unsigned int cmd, unsigned long arg)
{
        unsigned int minor = MINOR(inode->i_rdev);
        int retval = 0;

#ifdef LP_DEBUG
        printk(KERN_DEBUG "lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg);
#endif
        if (minor >= LP_NO)
                return -ENODEV;
        if ((LP_F(minor) & LP_EXIST) == 0)
                return -ENODEV;

Now go through each of the options. LPTIME sets the amount of time that the driver waits for the printer to catch up when the buffer fills up. LPCHAR sets the timeout for each character. Sending an LPABORT with a true argument will cause an abort upon error. Sending LPABORT will cause a retry upon error (default).

        switch ( cmd ) {
                case LPTIME:
                        LP_TIME(minor) = arg * HZ/100;
                        break;
                case LPCHAR:
                        LP_CHAR(minor) = arg;
                        break;
                case LPABORT:
                        if (arg)
                                LP_F(minor) |= LP_ABORT;
                        else
                                LP_F(minor) &= ~LP_ABORT;
                        break;

LPABORTOPEN with a true argument will abort future open() calls on error. Calling LPABORTOPEN with a false argument will cause errors on open() to be ignored. LPCAREFUL (true) causes the driver to ensure the the out-of-paper flags, etc, are checked on writes. LPCAREFUL (false) will ignore them.

                case LPABORTOPEN:
                        if (arg)
                                LP_F(minor) |= LP_ABORTOPEN;
                        else
                                LP_F(minor) &= ~LP_ABORTOPEN;
                        break;
                case LPCAREFUL:
                        if (arg)
                                LP_F(minor) |= LP_CAREFUL;
                        else
                                LP_F(minor) &= ~LP_CAREFUL;
                        break;

LPWAIT sets the amount of time that the driver waits before and after a strobe. LPSETIRQ and LPGETIRQ set and get the IRQ number for the driver respectively -- although, from the look of the code below, LPSETIRQ isn't working, or has been deprecated perhaps?

                case LPWAIT:
                        LP_WAIT(minor) = arg;
                        break;
                case LPSETIRQ: 
                        return -EINVAL;
                        break;
                case LPGETIRQ:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
                            sizeof(int));
                        if (retval)
                                return retval;
                        copy_to_user((int *) arg, & LP_IRQ(minor), sizeof(int));
                        break;

LPGETSTATUS gets the status of the printer, LPRESET resets the printer, LPGETSTATS gets the current statistics from the driver and LPGETFLAGS gets the status flags. In a couple of these cases, verify_area() is called to ensure that it is permitted to write to these areas. The copy_to_user() call copies the resulting structure back to user space.

                case LPGETSTATUS:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
                            sizeof(int));
                        if (retval)
                                return retval;
                        else {
                                int status = r_str(minor);
                                copy_to_user((int *) arg, & status, sizeof(int));
                        }
                        break;
                case LPRESET:
                        lp_reset(minor);
                        break;
                case LPGETSTATS:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
                            sizeof(struct lp_stats));
                        if (retval)
                                return retval;
                        else {
                                copy_to_user((int *) arg, & LP_STAT(minor), sizeof(struct lp_stats));
                                if (suser())
                                        memset(& LP_STAT(minor), 0, sizeof(struct lp_stats));
                        }
                        break;
                case LPGETFLAGS:
                        retval = verify_area(VERIFY_WRITE, (void *) arg,
                            sizeof(int));
                        if (retval)
                                return retval;
                        else {
                                int status = LP_F(minor);
                                copy_to_user((int *) arg, & status, sizeof(int));
                        }
                        break;
                default:
                        retval = -EINVAL;
        }
        return retval;
}


Previous Next Table of Contents