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 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) 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 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 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 **/ 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 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 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 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 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 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 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