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