Previous Next Table of Contents

2. lp_char(char lpchar, int minor, int use_polling);

2.1 General Info

Function: lp_char sends a character to the parallel port.

Called from: lp_write_buf.

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

2.2 Code description

The function is called with three parameters: lpchar, which is the character that we wish to sent to the parallel device, minor, the minor device number for this device, and use_polling, which is 1 if we're polling this device, 0 if using an interrupt.

static inline int lp_char(char lpchar, int minor, int use_polling)
{
        int status;
        unsigned int wait = 0;
        unsigned long count = 0;
        struct lp_stats *stats;

The following do/while loop iterates until the parallel device signals that it is ready, or that it is busy. r_str gets the status of the device. A check is made in the middle of the loop to see if scheduling has been requested, and if so, it jumps off to lp_schedule. The count of the number of attempts is kept and when this reaches a certain cut off point (LP_CHAR(minor)), the loop exits.

        do {
                status = r_str(minor);
                count++;
                if (need_resched)
                        lp_schedule (minor);
        } while (((use_polling && !LP_READY(minor, status)) || 
                 (!use_polling && !(status & LP_PBUSY))) && (count < LP_CHAR(minor)));

If the number of attempts to get a status of "ready" from the device has reached the cutoff point, or if we're using an interrupt on this device and the device is still registering as ready, then exit lp_char.

        if (count == LP_CHAR(minor) ||
            (!use_polling && !LP_CAREFUL_READY(minor, status)))
                return 0;

Now we're past all the preliminary status checks, we can send the character to the device. w_dtr is just a macro that expands, in this case, to outb(lpchar,LP_BASE(minor)) -- ie, output a byte to the device.

        w_dtr(minor, lpchar);

Now that the character has been sent to the device, we can update the device statistics -- here, we just increment the number of characters that have been sent to the device in total:

        stats = & LP_STAT(minor);
        stats->chars++;

Strobe the parallel port -- this involves taking the strobe line high and then bringing it down again, which basically signals to the device on the port that there a character has been sent to the port, which can be read by the device.

        /* must wait before taking strobe high, and after taking strobe
           low, according spec.  Some printers need it, others don't. */
        while (wait != LP_WAIT(minor)) /* FIXME: should be a udelay() */
                wait++;
        /* control port takes strobe high */
        w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PSTROBE);
        while (wait)                    /* FIXME: should be a udelay() */
                wait--;
        /* take strobe low */
        w_ctr(minor, LP_PSELECP | LP_PINITP);

Now update the statistics, so that we can get an idea of the performance of the device, should we ever need to. After that, exit from this function, returning a successful value.

        /* update waittime statistics */
        if (count > stats->maxwait) {
#ifdef LP_DEBUG
                printk(KERN_DEBUG "lp%d success after %d counts.\n", minor, count);
#endif
                stats->maxwait = count;
        }
        count *= 256;
        wait = (count > stats->meanwait) ? count - stats->meanwait :
            stats->meanwait - count;
        stats->meanwait = (255 * stats->meanwait + count + 128) / 256;
        stats->mdev = ((127 * stats->mdev) + wait + 64) / 128;

        return 1;
}


Previous Next Table of Contents