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