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