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