xref: /illumos-gate/usr/src/cmd/lp/filter/postscript/postio/parallel.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 extern char *postbegin;
30 
31 #include <stdio.h>
32 #include <errno.h>
33 #include <string.h>
34 #include <stdarg.h>
35 #include <signal.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/ioccom.h>
39 #include <sys/ioctl.h>
40 
41 #include <sys/bpp_io.h>
42 #include <sys/ecppsys.h>
43 #include <sys/prnio.h>
44 
45 #define PRINTER_IO_ERROR	129
46 
47 /*
48  * the parameter structure for the parallel port
49  */
50 struct ppc_params_t {
51 	int		flags;		/* same as above */
52 	int		state;		/* status of the printer interface */
53 	int		strobe_w;	/* strobe width, in uS */
54 	int		data_setup;	/* data setup time, in uS */
55 	int		ack_timeout;	/* ACK timeout, in secs */
56 	int		error_timeout;	/* PAPER OUT, etc... timeout, in secs */
57 	int		busy_timeout;	/* BUSY timeout, in seconds */
58 };
59 
60 
61 
62 extern char *block;
63 extern int head, tail;
64 extern int readblock(int);
65 extern FILE *fp_log;
66 static void printer_info(char *fmt, ...);
67 
68 /*	These are the routines avaliable to others for use 	*/
69 int is_a_parallel_bpp(int);
70 int bpp_state(int);
71 int parallel_comm(int, int());
72 int get_ecpp_status(int);
73 int is_a_prnio(int);
74 int prnio_state(int);
75 
76 #define PRINTER_ERROR_PAPER_OUT		1
77 #define PRINTER_ERROR_OFFLINE		2
78 #define PRINTER_ERROR_BUSY		3
79 #define PRINTER_ERROR_ERROR		4
80 #define PRINTER_ERROR_CABLE_POWER	5
81 #define PRINTER_ERROR_UNKNOWN		6
82 #define PRINTER_ERROR_TIMEOUT		7
83 
84 /****************************************************************************/
85 
86 /**
87  *	for BPP PARALLEL interfaces
88  **/
89 
90 int is_a_parallel_bpp(int fd)
91 {
92 	if (ioctl(fd, BPPIOC_TESTIO) == 0 || errno == EIO)
93 		return(1);
94 	return(0);
95 }
96 
97 
98 #if defined(DEBUG) && defined(NOTDEF)
99 char *BppState(int state)
100 {
101 	static char buf[BUFSIZ];
102 
103 	memset(buf, 0, sizeof(buf));
104 	sprintf(buf, "State (0x%.4x) - (%s%s%s%s)\n", state,
105 		((state & BPP_SLCT_ERR) ?  "offline " : ""),
106 		((state & BPP_BUSY_ERR) ?  "busy " : ""),
107 		((state & BPP_PE_ERR) ?  "paper " : ""),
108 		((state & BPP_ERR_ERR) ?  "error " : ""));
109 
110 	return(buf);
111 }
112 #endif
113 
114 int bpp_state(int fd)
115 {
116 	if (ioctl(fd, BPPIOC_TESTIO)) {
117 		struct bpp_error_status  bpp_stat;
118 		int state;
119 
120 		if (ioctl(fd, BPPIOC_GETERR, &bpp_stat) < 0)
121 			exit(PRINTER_IO_ERROR);
122 		state = bpp_stat.pin_status;
123 
124 #if defined(DEBUG) && defined(NOTDEF)
125 		logit("%s", BppState(state));
126 #endif
127 
128 		if (state == (BPP_PE_ERR | BPP_ERR_ERR | BPP_SLCT_ERR)) {
129 			/* paper is out */
130 			return(PRINTER_ERROR_PAPER_OUT);
131 		} else if (state & BPP_BUSY_ERR) {
132 			/* printer is busy */
133 			return(PRINTER_ERROR_BUSY);
134 		} else if (state & BPP_SLCT_ERR) {
135 			/* printer is offline */
136 			return(PRINTER_ERROR_OFFLINE);
137 		} else if (state & BPP_ERR_ERR) {
138 			/* printer is errored */
139 			return(PRINTER_ERROR_ERROR);
140 		} else if (state == BPP_PE_ERR) {
141 			/* printer is off/unplugged */
142 			return(PRINTER_ERROR_CABLE_POWER);
143 		} else if (state) {
144 			return(PRINTER_ERROR_UNKNOWN);
145 		} else
146 			return(0);
147 	}
148 	return(0);
149 }
150 
151 int
152 get_ecpp_status(int fd)
153 {
154 	int state;
155 	struct ecpp_transfer_parms transfer_parms;
156 
157 
158 	if (ioctl(fd, ECPPIOC_GETPARMS, &transfer_parms) == -1) {
159 		return(-1);
160 	}
161 
162 	state = transfer_parms.mode;
163 	/*
164 	 * We don't know what all printers will return in
165 	 * nibble mode, therefore if we support nibble mode we will
166 	 * force the printer to be in CENTRONICS mode.
167 	 */
168 
169 	if (state != ECPP_CENTRONICS) {
170 		transfer_parms.mode = ECPP_CENTRONICS;
171 		if (ioctl(fd, ECPPIOC_SETPARMS, &transfer_parms) == -1) {
172 			return(-1);
173 		} else {
174 			state = ECPP_CENTRONICS;
175 		}
176 	}
177 
178 	return(state);
179 }
180 
181 /**
182  * For prnio(7I) - generic printer interface
183  **/
184 int is_a_prnio(int fd)
185 {
186 	uint_t	cap;
187 
188 	/* check if device supports prnio */
189 	if (ioctl(fd, PRNIOC_GET_IFCAP, &cap) == -1) {
190 		return (0);
191 	}
192 	/* we will use 1284 status if available */
193 	if ((cap & PRN_1284_STATUS) == 0) {
194 		/* some devices may only support 1284 status in unidir. mode */
195 		if (cap & PRN_BIDI) {
196 			cap &= ~PRN_BIDI;
197 			(void) ioctl(fd, PRNIOC_SET_IFCAP, &cap);
198 		}
199 	}
200 	return (1);
201 }
202 
203 int prnio_state(int fd)
204 {
205 	uint_t	status;
206 	uchar_t	pins;
207 
208 	if ((ioctl(fd, PRNIOC_GET_STATUS, &status) == 0) &&
209 	    (status & PRN_READY)) {
210 		return(0);
211 	}
212 
213 	if (ioctl(fd, PRNIOC_GET_1284_STATUS, &pins) != 0) {
214 		return(PRINTER_ERROR_UNKNOWN);
215 	}
216 
217 	if ((pins & ~PRN_1284_BUSY) == PRN_1284_PE) {
218 		/* paper is out */
219 		return(PRINTER_ERROR_PAPER_OUT);
220 	} else if (pins == (PRN_1284_PE | PRN_1284_SELECT |
221 				PRN_1284_NOFAULT | PRN_1284_BUSY)) {
222 		/* printer is off/unplugged */
223 		return(PRINTER_ERROR_CABLE_POWER);
224 	} else if ((pins & PRN_1284_SELECT) == 0) {
225 		/* printer is offline */
226 		return(PRINTER_ERROR_OFFLINE);
227 	} else if ((pins & PRN_1284_NOFAULT) == 0) {
228 		/* printer is errored */
229 		return(PRINTER_ERROR_ERROR);
230 	} else if (pins & PRN_1284_PE) {
231 		/* paper is out */
232 		return(PRINTER_ERROR_PAPER_OUT);
233 	} else if (pins ^ (PRN_1284_SELECT | PRN_1284_NOFAULT)) {
234 		return(PRINTER_ERROR_UNKNOWN);
235 	}
236 	return(0);
237 }
238 
239 /**
240  *	Common routines
241  **/
242 
243 /*ARGSUSED0*/
244 static void
245 ByeByeParallel(int sig)
246 {
247 	/* try to shove out the EOT */
248 	(void) write(1, "\004", 1);
249 	exit(0);
250 }
251 
252 
253 /*ARGSUSED0*/
254 static void
255 printer_info(char *fmt, ...)
256 {
257 	char mesg[BUFSIZ];
258 	va_list ap;
259 
260 	va_start(ap, fmt);
261 	vsprintf(mesg, fmt, ap);
262 	va_end(ap);
263 
264 	fprintf(stderr,
265 		"%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
266 		mesg);
267 	fflush(stderr);
268 	fsync(2);
269 
270 	if (fp_log != stderr) {
271 		fprintf(fp_log,
272 		   "%%%%[ PrinterError: %s; source: parallel ]%%%%\n",
273 		   mesg);
274 		fflush(fp_log);
275 	}
276 }
277 
278 static void
279 printer_error(int error)
280 {
281 	switch (error) {
282 		case -1:
283 			printer_info("ioctl(): %s", strerror(errno));
284 			break;
285 		case PRINTER_ERROR_PAPER_OUT:
286 			printer_info("out of paper");
287 			break;
288 		case PRINTER_ERROR_OFFLINE:
289 			printer_info("offline");
290 			break;
291 		case PRINTER_ERROR_BUSY:
292 			printer_info("busy");
293 			break;
294 		case PRINTER_ERROR_ERROR:
295 			printer_info("printer error");
296 			break;
297 		case PRINTER_ERROR_CABLE_POWER:
298 			printer_info("printer powered off or disconnected");
299 			break;
300 		case PRINTER_ERROR_UNKNOWN:
301 			printer_info("unknown error");
302 			break;
303 		case PRINTER_ERROR_TIMEOUT:
304 			printer_info("communications timeout");
305 			break;
306 		default:
307 			printer_info("get_status() failed");
308 	}
309 }
310 
311 
312 static void
313 wait_state(int fd, int get_state())
314 {
315 	int state;
316 	int was_faulted = 0;
317 
318 	while (state = get_state(fd)) {
319 		was_faulted=1;
320 		printer_error(state);
321 		sleep(15);
322 	}
323 
324 	if (was_faulted) {
325 		fprintf(stderr, "%%%%[ status: idle ]%%%%\n");
326 		fflush(stderr);
327 		fsync(2);
328 		if (fp_log != stderr) {
329 			fprintf(fp_log, "%%%%[ status: idle ]%%%%\n");
330 			fflush(fp_log);
331 		}
332 	}
333 }
334 
335 
336 int
337 parallel_comm(int fd, int get_state())
338 {
339 	int  actual;		/* number of bytes successfully written */
340 	int count = 0;
341 
342 	(void) signal(SIGTERM, ByeByeParallel);
343 	(void) signal(SIGQUIT, ByeByeParallel);
344 	(void) signal(SIGHUP, ByeByeParallel);
345 	(void) signal(SIGINT, ByeByeParallel);
346 	(void) signal(SIGALRM, SIG_IGN);
347 
348 	/* is the device ready? */
349 
350 	/* bracket job with EOT */
351 	wait_state(fd, get_state);
352 	(void) write(fd, "\004", 1);
353 
354 /* 	write(fd, postbegin, strlen(postbegin)); */
355 
356 	while (readblock(fileno(stdin)) > 0) {
357 		wait_state(fd, get_state);
358 		alarm(120);
359 		if ((actual = write(fd, block + head, tail - head)) == -1) {
360 			alarm(0);
361 		  	if (errno == EINTR) {
362 				printer_error(PRINTER_ERROR_TIMEOUT);
363 				sleep(30);
364 				continue;
365 			} else {
366 				printer_info("I/O Error during write(): %s",
367 					strerror(errno));
368 				exit(2);
369 			}
370 		}
371 		alarm(0);
372 		if (actual >= 0)
373 			head += actual;
374 
375 #if defined(DEBUG) && defined(NOTDEF)
376 		logit("Writing (%d) at 0x%x actual: %d, %s\n", count++, head,
377 			actual, (actual < 1 ? strerror(errno) : ""));
378 #endif
379 	}
380 
381 	/* write the final EOT */
382 	wait_state(fd, get_state);
383 	(void) write(fd, "\004", 1);
384 
385 	return (0);
386 }
387