From: jhonan@kralizec.zeta.org.au (Jamie Honan) Subject: Problem and Solution with lp.c, timing. Date: 27 Feb 1993 07:54:54 +1100
Once again I apologize for posting to col, but I am very
constrained in not having cola, nor having membership of the digests.
I think there is a problem in lp.c in linux99.5, in
linux/kernel/chr_drv/lp.c.
At around line 59 the folowing code appears:
/* 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)) wait++;
/* control port takes strobe high */
! outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
! while(wait) wait--;
! /* take strobe low */
! outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
/* get something meaningful for return value */
return LP_S(minor);
}
Normally, the wait loop is not executed (not needed), only when
the LPWAIT ioctl value is used.
My postscript printer (NEC L890) needs the wait loop. However as presented
above, I beleive the code to be incorrect. The strobe length does not have
to be increased, but the time before and after must be increased. (actually
for my printer the timing diagrams show about 5uS after busy falling before
acknowledge.)
The code should be as follows:
/* 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)) wait++;
/* control port takes strobe high */
! outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor )));
! /* take strobe low */
! outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor )));
! while(wait) wait--;
/* get something meaningful for return value */
return LP_S(minor);
}
(You might make wait volatile, just to take it out of the registers)
This has been tested and works on my printer. For my 486sx25 and NEC L890, I use
an LPWAIT of 2000, and I bump up LPTIME from 2 to 20 (Postscript requires a lot
of thinking).
In addition, the source refers to tunelp(8). This does not come with SLS, so I
whipped up one of my own. Whether this is better or worse I don't know, however
it did the job for me.
============================================================================
lptune.c
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <sys/kd.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <linux/lp.h>
char *lpchar_desc[] = {
"Timeout for each character. This is relative to bus cycles -- it",
"is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you",
"have extremely slow printing, or if the machine seems to slow down",
"a lot when you print. If you have slow printing, increase this",
"number, and if your system gets bogged down, decrease this number.",
"Default value is 1000.",
""
};
char *lptime_desc[] = {
"This is the amount of time that the driver waits for the printer to",
"catch up when the printer's buffer appears to be filled. If you",
"want to tune this and have a fast printer (i.e. HPIIIP), decrease",
"this number, and if you have a slow printer, increase this number.",
"This is in hundredths of a second. Default 2, being .05 second.",
""
};
char *lpabort_desc[] = {
"Non zero to abort on error,",
"Zero to retry. Default is retry.",
""
};
char *lpwait_desc[] = {
"The parallel port specs apparently say that there needs to be",
"a .5usec wait before and after the strobe. Since there are wildly",
"different computers running linux, there is no perfect",
"value, but since it worked well on most printers before without,",
"Default value is 0.",
""
};
typedef struct
{
char *name;
int val;
char **desc;
}
NVALS;
NVALS nvals[] ={
{ "lpchar", LPCHAR, lpchar_desc},
{ "lptime", LPTIME, lptime_desc},
{ "lpabort", LPABORT,lpabort_desc},
{ "lpwait", LPWAIT, lpwait_desc},
};
void put_desc(int n)
{
int i;
char **desc;
if (n < 0 || n > (sizeof(nvals)/sizeof(nvals[0])))
return;
desc = nvals[n].desc;
printf("%s :\n", nvals[n].name);
for(i = 0 ; ; i++)
{
if (desc[i] && strlen(desc[i]))
printf("\t%s\n", desc[i]);
else
break;
}
printf("\n");
}
void put_all(void)
{
int n;
for(n = 0 ; n < sizeof(nvals)/sizeof(nvals[0]); n++)
put_desc(n);
}
void usage(void)
{
printf("usage : lptune <type> <value> < /dev/lp?\n");
put_all();
}
int search_val(char * str)
{
int n;
for(n = 0 ; n < sizeof(nvals)/sizeof(nvals[0]); n++)
{
if (!strcmp(nvals[n].name, str))
return nvals[n].val;
}
return -1;
}
int
main(int argc, char *argv[])
{
int i;
int stdin_fs;
char *argp;
int n;
int val;
if (argc < 2)
{
usage();
exit(0);
}
stdin_fs = fileno(stdin);
for (i=1; i<argc; i++)
{
if (argv[i][0] == '-')
argp = &argv[i][1];
else
argp = argv[i];
n = search_val(argp);
if (n < 0)
{
printf("Unknown type %s\n", argp);
usage();
exit(1);
}
if (i >= argc - 1)
{
printf("no value for %s\n", argp);
exit(1);
}
argp = argv[++i];
if (!isdigit(*argp))
{
printf("Expecting number for parameter\n");
exit(1);
}
val = atoi(argp);
if (ioctl(stdin_fs, n, val) < 0)
{
perror("ioctl");
exit(2);
}
}
exit(0);
}
=========================================================================================
end lptune.c
Regards, Jamie Honan