This is pp.c in view mode; [Download] [Up]
/* * pp.c -- Do some special things to the printer (send some ioctls) * * $Header: /Users/marcel/src/pp/RCS/pp.c,v 1.5 96/01/24 19:01:27 marcel Exp $ * * (c) 1996 Marcel Waldvogel, mwa@nice.ch * * History * ======= * 960106 mwa Created * 960122 mwa Fine-tuned, beautified, * added fall-back for "interval" to "timeout", * eliminated the second open() call for "interval" * (removed possibility for another timeout to happen), * prepared for a more public release */ #include <objc/objc.h> #include <stdio.h> #include <libc.h> #include <errno.h> /* Compile with -DDRIVER_PRIVATE, to get extended status info from pp_extern.h */ #include <architecture/ARCH_INCLUDE.h> #include ARCH_INCLUDE(bsd/dev/, pp_extern.h) #ifndef STDIN_FILENO #define STDIN_FILENO 0 #endif #define DEFDEV "/dev/pp0" typedef struct{ int mask; char *name; } BITSTAT; BITSTAT driverbits[] = { PP_ST_INITIALIZED, "initialized", PP_ST_BUSY, "busy", PP_ST_NOPAPER, "paper out", PP_ST_NOTSELECTED, "!selected", PP_ST_TIMEOUT, "timeout", PP_ST_ERROR, "error", 0, NULL }; BITSTAT portbits[] = { 0x80, "!busy", 0x40, "!ack", 0x20, "paper out", 0x10, "!select", 0x08, "!error", 0x04, "rsvd2", 0x02, "rsvd1", 0x01, "rsvd0", 0, NULL }; BITSTAT controlbits[] = { 0x80, "rsvd7", 0x40, "rsvd6", 0x20, "rsvd5", 0x10, "irq enable", 0x08, "select in", 0x04, "!reset", 0x02, "autofeed", 0x01, "strobe", 0, NULL }; /** void usage(prog) * Print usage information. */ void usage(const char *prog) { fprintf(stderr, "Usage: %s [-f device] <cmd> [<args> ...]\n", prog); fprintf(stderr, "Parallel port setup/status, default device is %s.\n", DEFDEV); fputs( "<cmd> is one of: (can be abbreviated)\n" " status show printer status\n" " xstatus show extended status\n" " reset reset printer\n" " write write data from stdin and show status\n" " timeout <secs> set timeout\n" #if defined(PPIOCSRETRIES) && defined(PPIOCSRINTERVAL) " interval <retry> <interval> set fine-grain timeout, <interval> fractional\n" #else " interval <retry> <interval> set timeout to <retry>*<interval>\n" #endif , stderr); // end of fputs() exit(1); } /** void pperror(prog, func, device) * Print decent error information about the current errno. */ void pperror(const char *prog, const char *func, const char *device) { if (func == NULL) fprintf(stderr, "%s: %s: %s\n", prog, device, strerror(errno)); else { if (device == NULL) fprintf(stderr, "%s: %s: %s\n", prog, func, strerror(errno)); else fprintf(stderr, "%s: %s %s: %s\n", prog, func, device, strerror(errno)); } exit(2); } /** void bitstat(stream, status, bs) * Decode a flag bitmap to a human-readable format. * If negate is != 0, then flags whose text start with that char * are output if the bit is not set (useful for negated bits). */ void bitstat(FILE *stream, int status, const BITSTAT *bs, char negate) { int first = 1; int foundbits = 0; fputc('<', stream); while (bs->mask != 0) { foundbits |= bs->mask; // If you wanted alternate behavior (i.e. on multibit-stuff ALL bits // needed to be set, change the "!= 0" to "== bs->mask") if ((bs->mask & status) != 0 && (!negate || bs->name[0] != negate)) { if (!first) fputc(',', stream); else first = 0; fprintf(stream, bs->name); } if ((bs->mask & status) == 0 && negate && bs->name[0] == negate) { if (!first) fputc(',', stream); else first = 0; fprintf(stream, bs->name + 1); } bs++; } // Did we output text for all bits? if ((status & foundbits) != status) { if (!first) fputc(',', stream); fprintf(stream, "?"); } fputc('>', stream); } /** void ppshowstatus(prog, device, fd) * Prints status information for the given file descriptor * (prog and device are used for error messages only) */ void ppshowstatus(const char *prog, const char *device, int fd) { int status; // Official status if (ioctl(fd, PPIOCSW, &status) < 0) pperror(prog, "PPIOCSW", device); printf("Driver status = 0x%x ", status); bitstat(stdout, status, driverbits, '!'); printf("\n"); #ifdef PPIOCGSREG /* Defined, when compiled with -DDRIVER_PRIVATE */ if (ioctl(fd, PPIOCGSREG, &status) < 0) pperror(prog, "PPIOCGSREG", device); printf("Port status = 0x%x ", status); bitstat(stdout, status, portbits, '!'); printf("\n"); #endif /* PPIOCGSREG */ #if defined(PPIOCGRINTERVAL) && defined(PPIOCGRETRIES) /* Defined, when compiled with -DDRIVER_PRIVATE */ { int count, interval; if (ioctl(fd, PPIOCGRINTERVAL, &interval) < 0) pperror(prog, "PPIOCGRINTERVAL", device); if (ioctl(fd, PPIOCGRETRIES, &count) < 0) pperror(prog, "PPIOCGRETRIES", device); printf("Timeout = %ds (retries=%d, interval=%gs)\n", (interval * count +500) / 1000, count, (float)interval/1000.0); } #endif /* PPIOCGRINTERVAL && PPIOCGRETRIES */ } /** void ppshowextendedstatus(prog, device, fd) * Print extended status information for the given file descriptor * (prog and device are used for error messages only) */ void ppshowextendedstatus(const char *prog, const char *device, int fd) { int status; // The "easy" part #define GET(ctl, format) \ if (ioctl(fd, ctl, &status) < 0) \ pperror(prog, #ctl, device); \ printf(format, status); // I would have liked to put the #ifdef into the macro, // but this doesn't seem to work. Does anybody know how? #ifdef PPIOCGIHDELAY GET(PPIOCGIHDELAY, "Handler delay = %d usec\n"); #endif #ifdef PPIOCGIOTDELAY GET(PPIOCGIOTDELAY, "I/O task delay = %d usec\n"); #endif #ifdef PPIOCGMINPHYS GET(PPIOCGMINPHYS, "Max chunk size = %d\n"); #endif #ifdef PPIOCGBSIZE GET(PPIOCGBSIZE, "Block size = %d\n"); #endif #ifdef PPIOCGCREG GET(PPIOCGCREG, "Control register = 0x%2x "); bitstat(stdout, status, controlbits, '!'); printf("\n"); #endif #ifdef PPIOCGCREGDEF GET(PPIOCGCREGDEF, "Ctl register def = 0x%2x "); bitstat(stdout, status, controlbits, '!'); printf("\n"); #endif #undef GET } /** void ppstatus(prog, device, extended) * Opens the device and prints normal or extended status, depending * on the flag. */ void ppstatus(const char *prog, const char *device, BOOL extended) { int fd; fd = open(device, O_RDONLY | O_NDELAY); // O_NDELAY is (currently) ignored if (fd < 0) pperror(prog, "open", device); ppshowstatus(prog, device, fd); if (extended) ppshowextendedstatus(prog, device, fd); close(fd); } /** void ppreset(prog, device) * Resets the printer */ void ppreset(const char *prog, const char *device) { int fd; fd = open(device, O_RDONLY | O_NDELAY); if (fd < 0) pperror(prog, "open", device); if (ioctl(fd, PPIOCINIT) < 0) pperror(prog, "PPIOCINIT", device); close(fd); } /** void ppset(prog, device, ctl, ioctlname, value) * Does an ioctl on the device, setting the parameter to "value" */ void ppset(const char *prog, const char *device, int ctl, const char *text, int value) { int fd; fd = open(device, O_RDONLY | O_NDELAY); if (fd < 0) pperror(prog, "open", device); if (ioctl(fd, ctl, &value) < 0) pperror(prog, text, device); close(fd); } /** void ppinterval(prog, device, retry, interval) * Sets the timeout and retry intervals reasonably * (tries to fall back to documented stuff if needed) */ void ppinterval(const char *prog, const char *device, int retry, int interval) { int fd, timeout; fd = open(device, O_RDONLY | O_NDELAY); if (fd < 0) pperror(prog, "open", device); // First try it the "conventional" way, so that we have a timeout at all timeout = (retry * interval + 500) / 1000; if (ioctl(fd, PPIOCSETTIMO, &retry) < 0) pperror(prog, "PPIOCSETTIMO", device); #if defined(PPIOCSRETRIES) && defined(PPIOCSRINTERVAL) // Now try to set everything the way we really would like it if (ioctl(fd, PPIOCSRETRIES, &retry) < 0) pperror(prog, "PPIOCSRETRIES", device); if (ioctl(fd, PPIOCSRINTERVAL, &interval) < 0) pperror(prog, "PPIOCSRINTERVAL", device); #endif close(fd); } /** void ppwrite(prog, device) * Reads character by character from stdin and sends it to the printer, * giving full detail error messages in case anything should fail. * Mainly used for debugging. */ void ppwrite(const char *prog, const char *device) { int fd; char c; fd = open(device, O_WRONLY); if (fd < 0) pperror(prog, "open", device); // Read from stdin while (read(STDIN_FILENO, &c, 1) == 1) { switch (write(fd, &c, 1)) { case 0: puts("EOF on write?"); ppshowstatus(prog, device, fd); ppshowextendedstatus(prog, device, fd); close(fd); exit(3); case 1: break; default: perror("write"); ppshowstatus(prog, device, fd); ppshowextendedstatus(prog, device, fd); close(fd); exit(3); } } ppshowstatus(prog, device, fd); ppshowextendedstatus(prog, device, fd); close(fd); } /** void main(argc, argv) * Handles all options and dispatches the commands */ void main(int argc, char *argv[]) { const char *device = DEFDEV; int argp = 1; // At least two more arguments if (argc > argp + 1 && strcmp(argv[argp], "-f") == 0) { argp++; device = argv[argp++]; } // No more arguments? if (argc <= argp) usage(argv[0]); switch (argv[argp][0]) { case 'r': // reset ppreset(argv[0], device); break; case 's': // status case 'x': // xstatus // Show either normal or extended status ppstatus(argv[0], device, argv[argp][0] == 'x'); break; case 't': // timeout argp++; if (argc <= argp) usage(argv[0]); ppset(argv[0], device, PPIOCSETTIMO, "PPIOCSETTIMO", atoi(argv[argp])); break; case 'w': // write ppwrite(argv[0], device); break; case 'i': // interval argp += 2; if (argc <= argp) usage(argv[0]); ppinterval(argv[0], device, atoi(argv[argp - 1]), (int)(atof(argv[argp])*1000.0+0.5)); break; default: usage(argv[0]); } exit(0); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.