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
is_a_parallel_bpp(int fd)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)
BppState(int state)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
bpp_state(int fd)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
get_ecpp_status(int fd)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 **/
is_a_prnio(int fd)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
prnio_state(int fd)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
ByeByeParallel(int sig)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
printer_info(char * fmt,...)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
printer_error(int error)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
wait_state(int fd,int get_state ())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
parallel_comm(int fd,int get_state ())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