1 /* PRINTER.C (c) Copyright Roger Bowler, 1999-2010 */
2 /* (c) Copyright Enrico Sorichetti, 2012 */
3 /* ESA/390 Line Printer Device Handler */
4
5 /*-------------------------------------------------------------------*/
6 /* This module contains device handling functions for emulated */
7 /* System/370 line printer devices with fcb support and more */
8 /*-------------------------------------------------------------------*/
9
10 #include "hstdinc.h"
11 #include "hercules.h"
12 #include "devtype.h"
13 #include "opcode.h"
14
15 /*-------------------------------------------------------------------*/
16 /* Ivan Warren 20040227 */
17 /* This table is used by channel.c to determine if a CCW code is an */
18 /* immediate command or not */
19 /* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */
20 /* 0 : Command is NOT an immediate command */
21 /* 1 : Command is an immediate command */
22 /* Note : An immediate command is defined as a command which returns */
23 /* CE (channel end) during initialisation (that is, no data is */
24 /* actually transfered. In this case, IL is not indicated for a CCW */
25 /* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */
26 /* effect */
27 /*-------------------------------------------------------------------*/
28
29 /* Printer Specific : 1403 */
30 /* The following are considered IMMEDIATE commands : */
31 /* CTL-NOOP, Skip Channel 'n' Immediate, Block Data check , Allow Data Check
32 * Space 1,2,3 Lines Immediate, UCS Gate Load, Load UCS Buffer & Fold,
33 * Load UCS Buffer (No Fold)
34 */
35
36 static BYTE printer_immed_commands[256]=
37 /*
38 *0 1 2 3 4 5 6 7 8 9 A B C D E F
39 */
40
41 { 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
42 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
43 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
44 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
46 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
47 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
48 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
49 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
50 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
51 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
52 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
53 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
54 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
55 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,
56 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0};
57
58 /*-------------------------------------------------------------------*/
59 /* Internal macro definitions */
60 /*-------------------------------------------------------------------*/
61 //#define LINE_LENGTH 150
62 #define BUFF_SIZE 1500
63 #define BUFF_OVFL 150
64
65 int line;
66 int coun;
67 int chan;
68 int FCBMASK[] = {66,1,7,13,19,25,31,37,43,63,49,55,61};
69 int havechan;
70
71 #define LINENUM(n) ( 1 + ( ( (n)-1) % dev->lpp))
72
73 #define WRITE_LINE() \
74 do { \
75 /* Start a new record if not data-chained from previous CCW */ \
76 if ((chained & CCW_FLAGS_CD) == 0) \
77 { \
78 dev->bufoff = 0; \
79 dev->bufres = BUFF_SIZE; \
80 } /* end if(!data-chained) */ \
81 if ( dev->index > 1 ) \
82 { \
83 for (i = 1; i < dev->index; i++) \
84 { \
85 dev->buf[dev->bufoff] = SPACE; \
86 dev->bufoff++; \
87 dev->bufres--; \
88 } /* end for(i) */ \
89 } /* end if ( dev->index > 1 ) */ \
90 /* Calculate number of bytes to write and set residual count */ \
91 num = (count < dev->bufres) ? count : dev->bufres; \
92 *residual = count - num; \
93 /* Copy data from channel buffer to print buffer */ \
94 for (i = 0; i < num; i++) \
95 { \
96 c = guest_to_host(iobuf[i]); \
97 if (dev->fold) c = toupper(c); \
98 if (c == 0) c = SPACE; \
99 dev->buf[dev->bufoff] = c; \
100 dev->bufoff++; \
101 dev->bufres--; \
102 } /* end for(i) */ \
103 /* Perform end of record processing if not data-chaining */ \
104 if ((flags & CCW_FLAGS_CD) == 0) \
105 { \
106 /* Truncate trailing blanks from print line */ \
107 for (i = dev->bufoff; i > 0; i--) \
108 if (dev->buf[i-1] != SPACE) break; \
109 /* Write print line */ \
110 write_buffer (dev, (char *)dev->buf, i, unitstat); \
111 if (*unitstat != 0) return; \
112 if ( dev->crlf ) \
113 { \
114 write_buffer (dev, "\r", 1, unitstat); \
115 if (*unitstat != 0) return; \
116 } \
117 } /* end if(!data-chaining) */ \
118 /* Return normal status */ \
119 } while(0)
120
121 /* changed to */
122 /* search the fcb array starting at the CURRENT line position */
123 /* check if the previous operation was a write no space */
124 #define SKIP_TO_CHAN() \
125 do { \
126 havechan = 0; \
127 for ( i = 0; i < dev->lpp; i++ ) \
128 { \
129 line = LINENUM( dev->currline + i ); \
130 if ( dev->fcb[line] != chan ) \
131 continue; \
132 havechan = 1; \
133 dev->destline = line; \
134 break; \
135 } \
136 if ( havechan == 1 ) \
137 { \
138 if ( ( dev->destline < dev->currline ) || \
139 ( dev->chskip == 1 && dev->destline <= dev->currline ) ) \
140 { \
141 dev->chskip = 0; \
142 write_buffer (dev, "\f", 1, unitstat); \
143 if (*unitstat != 0) return; \
144 dev->currline = 1; \
145 } \
146 for (; dev->currline < dev->destline; dev->currline++ ) \
147 { \
148 write_buffer (dev, "\n", 1, unitstat); \
149 if (*unitstat != 0) return; \
150 } \
151 *unitstat = CSW_CE | CSW_DE; \
152 return; \
153 } \
154 /* channel not found */ \
155 { \
156 if ( dev->nofcbcheck ) \
157 { \
158 if ( ( code & 0x02 ) != 0 ) \
159 { \
160 write_buffer (dev, "\n", 1, unitstat); \
161 if (*unitstat != 0) return; \
162 } \
163 } \
164 else \
165 { \
166 dev->sense[0] = (dev->devtype == 0x1403 ) ? SENSE_EC :SENSE_EC; \
167 *unitstat = CSW_CE | CSW_DE | CSW_UC; \
168 return; \
169 } \
170 } \
171 } while (0)
172
173 static void* spthread (DEVBLK* dev); /* (forward reference) */
174
175 /*-------------------------------------------------------------------*/
176 /* Dump the FCB info */
177 /*-------------------------------------------------------------------*/
fcb_dump(DEVBLK * dev,char * buf,unsigned int buflen)178 static void fcb_dump(DEVBLK* dev, char *buf, unsigned int buflen)
179 {
180 int i;
181 char wrk[16];
182 char sep[1];
183 sep[0] = '=';
184 snprintf(buf, buflen, "LOADED lpi=%d index=%d lpp=%d fcb", dev->lpi, dev->index, dev->lpp );
185 for (i = 1; i <= dev->lpp; i++)
186 {
187 if (dev->fcb[i] != 0)
188 {
189 sprintf(wrk, "%c%d:%d", sep[0], i, dev->fcb[i]);
190 sep[0] = ',';
191 if (strlen(buf) + strlen(wrk) >= buflen - 4)
192 {
193 /* Too long, truncate it */
194 strcat(buf, ",...");
195 return;
196 }
197 strcat(buf, wrk);
198 }
199 }
200 return;
201 }
202
203 /*-------------------------------------------------------------------*/
204 /* Sockdev "OnConnection" callback function */
205 /*-------------------------------------------------------------------*/
onconnect_callback(DEVBLK * dev)206 static int onconnect_callback (DEVBLK* dev)
207 {
208 TID tid;
209 if (create_thread( &tid, DETACHED, spthread, dev, NULL ))
210 {
211 logmsg(_("HHCPR015E Create spthread failed for %4.4X: errno=%d: %s\n" ),
212 dev->devnum, errno, strerror( errno ) );
213 return 0;
214 }
215 return 1;
216 }
217
218 /*-------------------------------------------------------------------*/
219 /* Thread to monitor the sockdev remote print spooler connection */
220 /*-------------------------------------------------------------------*/
spthread(DEVBLK * dev)221 static void* spthread (DEVBLK* dev)
222 {
223 BYTE byte;
224 fd_set readset, errorset;
225 struct timeval tv;
226 int rc, fd = dev->fd; // (save original fd)
227
228 /* Fix thread name */
229 {
230 char thread_name[32];
231 thread_name[sizeof(thread_name)-1] = 0;
232 snprintf( thread_name, sizeof(thread_name)-1,
233 "spthread %4.4X", dev->devnum );
234 SET_THREAD_NAME( thread_name );
235 }
236
237 // Looooop... until shutdown or disconnect...
238
239 // PROGRAMMING NOTE: we do our select specifying an immediate
240 // timeout to prevent our select from holding up (slowing down)
241 // the device thread (which does the actual writing of data to
242 // the client). The only purpose for our thread even existing
243 // is to detect a severed connection (i.e. to detect when the
244 // client disconnects)...
245
246 while ( !sysblk.shutdown && dev->fd == fd )
247 {
248 if (dev->busy)
249 {
250 SLEEP(3);
251 continue;
252 }
253
254 FD_ZERO( &readset );
255 FD_ZERO( &errorset );
256
257 FD_SET( fd, &readset );
258 FD_SET( fd, &errorset );
259
260 tv.tv_sec = 0;
261 tv.tv_usec = 0;
262
263 rc = select( fd+1, &readset, NULL, &errorset, &tv );
264
265 if (rc < 0)
266 break;
267
268 if (rc == 0)
269 {
270 SLEEP(3);
271 continue;
272 }
273
274 if (FD_ISSET( fd, &errorset ))
275 break;
276
277 // Read and ignore any data they send us...
278 // Note: recv should complete immediately
279 // as we know data is waiting to be read.
280
281 ASSERT( FD_ISSET( fd, &readset ) );
282
283 rc = recv( fd, &byte, sizeof(byte), 0 );
284
285 if (rc <= 0)
286 break;
287 }
288
289 obtain_lock( &dev->lock );
290
291 // PROGRAMMING NOTE: the following tells us whether we detected
292 // the error or if the device thread already did. If the device
293 // thread detected it while we were sleeping (and subsequently
294 // closed the connection) then we don't need to do anything at
295 // all; just exit. If we were the ones that detected the error
296 // however, then we need to close the connection so the device
297 // thread can learn of it...
298
299 if (dev->fd == fd)
300 {
301 dev->fd = -1;
302 close_socket( fd );
303 logmsg (_("HHCPR016I %s (%s) disconnected from device %4.4X (%s)\n"),
304 dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec);
305 }
306
307 release_lock( &dev->lock );
308
309 return NULL;
310
311 } /* end function spthread */
312
313 /*-------------------------------------------------------------------*/
314 /* Initialize the device handler */
315 /*-------------------------------------------------------------------*/
printer_init_handler(DEVBLK * dev,int argc,char * argv[])316 static int printer_init_handler (DEVBLK *dev, int argc, char *argv[])
317 {
318 int iarg,i,j; /* Array subscripts */
319 char *ptr;
320 char *nxt;
321 int sockdev = 0; /* 1 == is socket device */
322
323 /* Forcibly disconnect anyone already currently connected */
324 if (dev->bs && !unbind_device_ex(dev,1))
325 return -1; // (error msg already issued)
326
327 /* The first argument is the file name */
328 if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
329 {
330 logmsg (_("HHCPR001E File name missing or invalid for printer %4.4X\n"),
331 dev->devnum);
332 return -1;
333 }
334
335 /* Save the file name in the device block */
336 strncpy (dev->filename, argv[0], sizeof(dev->filename));
337
338 if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
339 dev->devtype = 0x3211;
340
341 /* Initialize device dependent fields */
342 dev->fd = -1;
343 dev->diaggate = 0;
344 dev->fold = 0;
345 dev->crlf = 0;
346 dev->stopprt = 0;
347 dev->notrunc = 0;
348 dev->ispiped = (dev->filename[0] == '|');
349
350 /* initialize the new fields for FCB+ support */
351 dev->fcbsupp = 1;
352 dev->cc = 0;
353 dev->rawcc = 0;
354 dev->fcbcheck = 1;
355 dev->nofcbcheck = 0;
356 dev->ccpend = 0;
357 dev->chskip = 0;
358
359 dev->prevline = 1;
360 dev->currline = 1;
361 dev->destline = 1;
362
363 dev->print = 1;
364 dev->browse = 0;
365
366 dev->lpi = 6;
367 dev->index = 0;
368 dev->ffchan = 1;
369 for (i = 0; i < FCBSIZE; i++) dev->fcb[i] = 0;
370 for (i = 1; i <= 12; i++ )
371 {
372 if ( FCBMASK[i] != 0 )
373 dev->fcb[FCBMASK[i]] = i;
374 }
375 dev->lpp = FCBMASK[0];
376 dev->fcbisdef = 0;
377
378 /* Process the driver arguments */
379 for (iarg = 1; iarg < argc; iarg++)
380 {
381 if (strcasecmp(argv[iarg], "crlf") == 0)
382 {
383 dev->crlf = 1;
384 continue;
385 }
386
387 /* sockdev means the device file is actually
388 a connected socket instead of a disk file.
389 The file name is the socket_spec (host:port)
390 to listen for connections on.
391 */
392 if (!dev->ispiped && strcasecmp(argv[iarg], "sockdev") == 0)
393 {
394 sockdev = 1;
395 continue;
396 }
397
398 if (strcasecmp(argv[iarg], "noclear") == 0)
399 {
400 dev->notrunc = 1;
401 continue;
402 }
403
404 if (strcasecmp(argv[iarg], "cc") == 0)
405 {
406 dev->cc = 1;
407 dev->rawcc = 0;
408 continue;
409 }
410 if (strcasecmp(argv[iarg], "rawcc") == 0)
411 {
412 dev->cc = 0;
413 dev->rawcc = 1;
414 continue;
415 }
416
417 if (strcasecmp(argv[iarg], "nofcbcheck") == 0)
418 {
419 dev->fcbcheck = 0;
420 dev->nofcbcheck = 1;
421 continue;
422 }
423
424 if (strcasecmp(argv[iarg], "fcbcheck") == 0)
425 {
426 dev->fcbcheck = 1;
427 dev->nofcbcheck = 0;
428 continue;
429 }
430
431 if ( (strcasecmp(argv[iarg], "browse") == 0) ||
432 (strcasecmp(argv[iarg], "optbrowse") == 0 ) )
433 {
434 dev->print = 0;
435 dev->browse = 1;
436 continue;
437 }
438
439 if ( (strcasecmp(argv[iarg], "print") == 0 ) ||
440 (strcasecmp(argv[iarg], "optprint") == 0) )
441 {
442 dev->print = 1;
443 dev->browse = 0;
444 continue;
445 }
446
447 if (strncasecmp("lpi=", argv[iarg], 4) == 0)
448 {
449 ptr = argv[iarg]+4;
450 errno = 0;
451 dev->lpi = (int) strtoul(ptr,&nxt,10);
452 if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->lpi != 6 && dev->lpi != 8 ) )
453 {
454 j = ptr - argv[iarg];
455 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
456 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
457 return -1;
458 }
459 continue;
460 }
461
462 if (strncasecmp("index=", argv[iarg], 6) == 0)
463 {
464 if (dev->devtype != 0x3211 )
465 {
466 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
467 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, 1);
468 return -1;
469 }
470 ptr = argv[iarg]+6;
471 errno = 0;
472 dev->index = (int) strtoul(ptr,&nxt,10);
473 if (errno != 0 || nxt == ptr || *nxt != 0 || ( dev->index < 0 || dev->index > 15) )
474 {
475 j = ptr - argv[iarg];
476 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
477 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
478 return -1;
479 }
480 continue;
481 }
482
483 if (strncasecmp("lpp=", argv[iarg], 4) == 0)
484 {
485 ptr = argv[iarg]+4;
486 errno = 0;
487 dev->lpp = (int) strtoul(ptr,&nxt,10);
488 if (errno != 0 || nxt == ptr || *nxt != 0 ||dev->lpp > FCBSIZE)
489 {
490 j = ptr - argv[iarg];
491 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
492 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
493 return -1;
494 }
495 continue;
496 }
497 #if 0
498 if (strncasecmp("ffchan=", argv[iarg], 7) == 0)
499 {
500 ptr = argv[iarg]+7;
501 errno = 0;
502 dev->ffchan = (int) strtoul(ptr,&nxt,10);
503 if (errno != 0 || nxt == ptr || *nxt != 0 || dev->ffchan < 1 || dev->ffchan > 12)
504 {
505 j = ptr - argv[iarg];
506 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
507 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
508 return -1;
509 }
510 continue;
511 }
512 #endif
513
514 if (strncasecmp("fcb=", argv[iarg], 4) == 0)
515 {
516 for (line = 0; line <= FCBSIZE; line++) dev->fcb[line] = 0;
517 /* check for simple mode */
518 if ( strstr(argv[iarg],":") )
519 {
520 /* ':" found ==> new mode */
521 ptr = argv[iarg]+4;
522 while (*ptr)
523 {
524 errno = 0;
525 line = (int) strtoul(ptr,&nxt,10);
526 if (errno != 0 || *nxt != ':' || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 )
527 {
528 j = ptr - argv[iarg];
529 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
530 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
531 return -1;
532 }
533
534 ptr = nxt + 1;
535 errno = 0;
536 chan = (int) strtoul(ptr,&nxt,10);
537 if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || chan < 1 || chan > 12 )
538 {
539 j = ptr - argv[iarg];
540 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
541 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
542 return -1;
543 }
544 dev->fcb[line] = chan;
545 if ( *nxt == 0 )
546 break;
547 ptr = nxt + 1;
548 }
549
550 }
551 else
552 {
553 /* ':" NOT found ==> old mode */
554 ptr = argv[iarg]+4;
555 chan = 0;
556 while (*ptr)
557 {
558 errno = 0;
559 line = (int) strtoul(ptr,&nxt,10);
560 if (errno != 0 || (*nxt != ',' && *nxt != 0) || nxt == ptr || line > dev->lpp || dev->fcb[line] != 0 )
561 {
562 j = ptr - argv[iarg];
563 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
564 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
565 return -1;
566 }
567 chan += 1;
568 if ( chan > 12 )
569 {
570 j = ptr - argv[iarg];
571 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
572 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
573 return -1;
574 }
575 dev->fcb[line] = chan;
576 if ( *nxt == 0 )
577 break;
578 ptr = nxt + 1;
579 }
580 if ( chan != 12 )
581 {
582 j = 5;
583 logmsg("HHCPR103E %d:%4.4X Printer: parameter %s in argument %d at position %d is invalid\n",
584 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1, j);
585 return -1;
586 }
587 }
588
589 continue;
590 }
591
592 logmsg("HHCPR102E %d:%4.4X Printer: parameter %s in argument %d is invalid\n",
593 SSID_TO_LCSS(dev->ssid), dev->devnum, argv[iarg], iarg + 1);
594 return -1;
595 }
596
597 /* Check for incompatible options */
598 if (dev->rawcc && dev->browse)
599 {
600 logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n",
601 SSID_TO_LCSS(dev->ssid), dev->devnum, "rawcc/browse");
602 return -1;
603 }
604
605 if (sockdev && dev->crlf)
606 {
607 logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n",
608 SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/crlf");
609 return -1;
610 }
611
612 if (sockdev && dev->notrunc)
613 {
614 logmsg("HHCPR104E %d:%4.4X Printer: option %s is incompatible\n",
615 SSID_TO_LCSS(dev->ssid), dev->devnum, "sockdev/noclear");
616 return -1;
617 }
618
619 /* If socket device, create a listening socket
620 to accept connections on.
621 */
622 if (sockdev && !bind_device_ex( dev,
623 dev->filename, onconnect_callback, dev ))
624 {
625 return -1; // (error msg already issued)
626 }
627
628 /* Set length of print buffer */
629 // dev->bufsize = LINE_LENGTH + 8;
630 dev->bufsize = BUFF_SIZE + BUFF_OVFL;
631 dev->bufres = BUFF_SIZE;
632 dev->bufoff = 0;
633
634 /* Set number of sense bytes */
635 dev->numsense = 1;
636
637 /* Initialize the device identifier bytes */
638 dev->devid[0] = 0xFF;
639 dev->devid[1] = 0x28; /* Control unit type is 2821-1 */
640 dev->devid[2] = 0x21;
641 dev->devid[3] = 0x01;
642 dev->devid[4] = dev->devtype >> 8;
643 dev->devid[5] = dev->devtype & 0xFF;
644 dev->devid[6] = 0x01;
645 dev->numdevid = 7;
646
647 /* Activate I/O tracing */
648 // dev->ccwtrace = 1;
649
650 return 0;
651 } /* end function printer_init_handler */
652
653 /*-------------------------------------------------------------------*/
654 /* Query the device definition */
655 /*-------------------------------------------------------------------*/
printer_query_device(DEVBLK * dev,char ** class,int buflen,char * buffer)656 static void printer_query_device (DEVBLK *dev, char **class,
657 int buflen, char *buffer)
658 {
659 BEGIN_DEVICE_CLASS_QUERY( "PRT", dev, class, buflen, buffer );
660
661 snprintf (buffer, buflen, "%s%s%s%s%s%s%s",
662 dev->filename,
663 (dev->bs ? " sockdev" : ""),
664 (dev->crlf ? " crlf" : ""),
665 (dev->notrunc ? " noclear" : ""),
666 (dev->rawcc ? " rawcc" : dev->browse ? " brwse" : " print"),
667 (dev->nofcbcheck ? " nofcbck" : " fcbck"),
668 (dev->stopprt ? " (stopped)" : ""));
669
670 } /* end function printer_query_device */
671
672 /*-------------------------------------------------------------------*/
673 /* Subroutine to open the printer file or pipe */
674 /*-------------------------------------------------------------------*/
675 static int
open_printer(DEVBLK * dev)676 open_printer (DEVBLK *dev)
677 {
678 pid_t pid; /* Child process identifier */
679 char pathname[MAX_PATH]; /* file path in host format */
680 int open_flags; /* File open flags */
681 #if !defined( _MSVC_ )
682 int pipefd[2]; /* Pipe descriptors */
683 int rc; /* Return code */
684 #endif
685
686 /* Regular open if 1st char of filename is not vertical bar */
687 if (!dev->ispiped)
688 {
689 int fd;
690
691 /* Socket printer? */
692 if (dev->bs)
693 return (dev->fd < 0 ? -1 : 0);
694
695 /* Normal printer */
696 hostpath(pathname, dev->filename, sizeof(pathname));
697 open_flags = O_BINARY | O_WRONLY | O_CREAT /* | O_SYNC */;
698 if (dev->notrunc != 1)
699 {
700 open_flags |= O_TRUNC;
701 }
702 fd = hopen(pathname, open_flags,
703 S_IRUSR | S_IWUSR | S_IRGRP);
704 if (fd < 0)
705 {
706 logmsg (_("HHCPR004E Error opening file %s: %s\n"),
707 dev->filename, strerror(errno));
708 return -1;
709 }
710
711 /* Save file descriptor in device block and return */
712 dev->fd = fd;
713 return 0;
714 }
715
716 /* Filename is in format |xxx, set up pipe to program xxx */
717
718 #if defined( _MSVC_ )
719
720 /* "Poor man's" fork... */
721 pid = w32_poor_mans_fork ( dev->filename+1, &dev->fd );
722 if (pid < 0)
723 {
724 logmsg (_("HHCPR006E %4.4X device initialization error: fork: %s\n"),
725 dev->devnum, strerror(errno));
726 return -1;
727 }
728
729 /* Log start of child process */
730 logmsg (_("HHCPR007I pipe receiver (pid=%d) starting for %4.4X\n"),
731 pid, dev->devnum);
732 dev->ptpcpid = pid;
733
734 #else /* !defined( _MSVC_ ) */
735
736 /* Create a pipe */
737 rc = create_pipe (pipefd);
738 if (rc < 0)
739 {
740 logmsg (_("HHCPR005E %4.4X device initialization error: pipe: %s\n"),
741 dev->devnum, strerror(errno));
742 return -1;
743 }
744
745 /* Fork a child process to receive the pipe data */
746 pid = fork();
747 if (pid < 0)
748 {
749 logmsg (_("HHCPR006E %4.4X device initialization error: fork: %s\n"),
750 dev->devnum, strerror(errno));
751 close_pipe ( pipefd[0] );
752 close_pipe ( pipefd[1] );
753 return -1;
754 }
755
756 /* The child process executes the pipe receiver program... */
757 if (pid == 0)
758 {
759 /* Log start of child process */
760 logmsg (_("HHCPR007I pipe receiver (pid=%d) starting for %4.4X\n"),
761 getpid(), dev->devnum);
762
763 /* Close the write end of the pipe */
764 close_pipe ( pipefd[1] );
765
766 /* Duplicate the read end of the pipe onto STDIN */
767 if (pipefd[0] != STDIN_FILENO)
768 {
769 rc = dup2 (pipefd[0], STDIN_FILENO);
770 if (rc != STDIN_FILENO)
771 {
772 logmsg (_("HHCPR008E %4.4X dup2 error: %s\n"),
773 dev->devnum, strerror(errno));
774 close_pipe ( pipefd[0] );
775 _exit(127);
776 }
777 } /* end if(pipefd[0] != STDIN_FILENO) */
778
779 /* Close the original descriptor now duplicated to STDIN */
780 close_pipe ( pipefd[0] );
781
782 /* Redirect stderr (screen) to hercules log task */
783 dup2(STDOUT_FILENO, STDERR_FILENO);
784
785 /* Relinquish any ROOT authority before calling shell */
786 SETMODE(TERM);
787
788 /* Execute the specified pipe receiver program */
789 rc = system (dev->filename+1);
790
791 if (rc == 0)
792 {
793 /* Log end of child process */
794 logmsg (_("HHCPR011I pipe receiver (pid=%d) terminating for %4.4X\n"),
795 getpid(), dev->devnum);
796 }
797 else
798 {
799 /* Log error */
800 logmsg (_("HHCPR012E %4.4X Unable to execute %s: %s\n"),
801 dev->devnum, dev->filename+1, strerror(errno));
802 }
803
804 /* The child process terminates using _exit instead of exit
805 to avoid invoking the panel atexit cleanup routine */
806 _exit(rc);
807
808 } /* end if(pid==0) */
809
810 /* The parent process continues as the pipe sender */
811
812 /* Close the read end of the pipe */
813 close_pipe ( pipefd[0] );
814
815 /* Save pipe write descriptor in the device block */
816 dev->fd = pipefd[1];
817 dev->ptpcpid = pid;
818
819 #endif /* defined( _MSVC_ ) */
820
821 return 0;
822
823 } /* end function open_printer */
824
825 /*-------------------------------------------------------------------*/
826 /* Subroutine to write data to the printer */
827 /*-------------------------------------------------------------------*/
828 static void
write_buffer(DEVBLK * dev,char * buf,int len,BYTE * unitstat)829 write_buffer (DEVBLK *dev, char *buf, int len, BYTE *unitstat)
830 {
831 int rc; /* Return code */
832
833 /* Write data to the printer file */
834 if (dev->bs)
835 {
836 /* (socket printer) */
837 rc = write_socket (dev->fd, buf, len);
838
839 /* Check for socket error */
840 if (rc < len)
841 {
842 /* Close the connection */
843 if (dev->fd != -1)
844 {
845 int fd = dev->fd;
846 dev->fd = -1;
847 close_socket( fd );
848 logmsg (_("HHCPR017I %s (%s) disconnected from device %4.4X (%s)\n"),
849 dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec);
850 }
851
852 /* Set unit check with intervention required */
853 dev->sense[0] = SENSE_IR;
854 *unitstat = CSW_CE | CSW_DE | CSW_UC;
855 }
856 }
857 else
858 {
859 /* Write data to the printer file */
860 rc = write (dev->fd, buf, len);
861
862 /* Equipment check if error writing to printer file */
863 if (rc < len)
864 {
865 logmsg (_("HHCPR003E %4.4X Error writing to %s: %s\n"),
866 dev->devnum, dev->filename,
867 (errno == 0 ? _("incomplete"): strerror(errno)));
868 dev->sense[0] = SENSE_EC;
869 *unitstat = CSW_CE | CSW_DE | CSW_UC;
870 }
871 }
872
873 } /* end function write_buffer */
874
875 /*-------------------------------------------------------------------*/
876 /* Close the device */
877 /*-------------------------------------------------------------------*/
printer_close_device(DEVBLK * dev)878 static int printer_close_device ( DEVBLK *dev )
879 {
880 int fd = dev->fd;
881
882 if (fd == -1)
883 return 0;
884
885 dev->fd = -1;
886 dev->stopprt = 0;
887
888 /* Close the device file */
889 if ( dev->ispiped )
890 {
891 #if !defined( _MSVC_ )
892 close_pipe (fd);
893 #else /* defined( _MSVC_ ) */
894 close (fd);
895 /* Log end of child process */
896 logmsg (_("HHCPR011I pipe receiver (pid=%d) terminating for %4.4X\n"),
897 dev->ptpcpid, dev->devnum);
898 #endif /* defined( _MSVC_ ) */
899 dev->ptpcpid = 0;
900 }
901 else
902 {
903 if (dev->bs)
904 {
905 /* Socket printer */
906 close_socket (fd);
907 logmsg (_("HHCPR018I %s (%s) disconnected from device %4.4X (%s)\n"),
908 dev->bs->clientname, dev->bs->clientip, dev->devnum, dev->bs->spec);
909 }
910 else
911 {
912 /* Regular printer */
913 close (fd);
914 }
915 }
916
917 return 0;
918 } /* end function printer_close_device */
919
920 /*-------------------------------------------------------------------*/
921 /* Execute a Channel Command Word */
922 /*-------------------------------------------------------------------*/
printer_execute_ccw(DEVBLK * dev,BYTE code,BYTE flags,BYTE chained,U16 count,BYTE prevcode,int ccwseq,BYTE * iobuf,BYTE * more,BYTE * unitstat,U16 * residual)923 static void printer_execute_ccw (DEVBLK *dev, BYTE code, BYTE flags,
924 BYTE chained, U16 count, BYTE prevcode, int ccwseq,
925 BYTE *iobuf, BYTE *more, BYTE *unitstat, U16 *residual)
926 {
927 int rc = 0; /* Return code */
928 int i; /* Loop counter */
929 int num; /* Number of bytes to move */
930 char *eor; /* -> end of record string */
931 char *nls = "\n\n\n"; /* -> new lines */
932 BYTE c; /* Print character */
933 char hex[3]; /* for hex conversion */
934 char wbuf[150];
935
936 /* Reset flags at start of CCW chain */
937 if (chained == 0)
938 {
939 dev->diaggate = 0;
940 }
941
942 /* Open the device file if necessary */
943 if (dev->fd < 0 && !IS_CCW_SENSE(code))
944 rc = open_printer (dev);
945 else
946 {
947 /* If printer stopped, return intervention required */
948 if (dev->stopprt && !IS_CCW_SENSE(code))
949 rc = -1;
950 else
951 rc = 0;
952 }
953
954 if (rc < 0)
955 {
956 /* Set unit check with intervention required */
957 dev->sense[0] = SENSE_IR;
958 *unitstat = CSW_UC;
959 return;
960 }
961
962 /* Process depending on CCW opcode */
963
964 switch (code) {
965
966 case 0x01: /* Write No Space */
967 case 0x09: /* Write and Space 1 Line */
968 case 0x11: /* Write and Space 2 Lines */
969 case 0x19: /* Write and Space 3 Lines */
970
971
972 case 0x89: /* Write and Skip to Channel 1 */
973 case 0x91: /* Write and Skip to Channel 2 */
974 case 0x99: /* Write and Skip to Channel 3 */
975 case 0xA1: /* Write and Skip to Channel 4 */
976 case 0xA9: /* Write and Skip to Channel 5 */
977 case 0xB1: /* Write and Skip to Channel 6 */
978 case 0xB9: /* Write and Skip to Channel 7 */
979 case 0xC1: /* Write and Skip to Channel 8 */
980 case 0xC9: /* Write and Skip to Channel 9 */
981 case 0xD1: /* Write and Skip to Channel 10 */
982 case 0xD9: /* Write and Skip to Channel 11 */
983 case 0xE1: /* Write and Skip to Channel 12 */
984 if (dev->rawcc)
985 {
986 sprintf(hex,"%02x",code);
987 write_buffer(dev, hex, 2, unitstat);
988 if (*unitstat != 0) return;
989 WRITE_LINE();
990 write_buffer(dev, "\n", 1, unitstat);
991 if (*unitstat == 0)
992 *unitstat = CSW_CE | CSW_DE;
993 return;
994 }
995
996 if ( dev->browse && dev->ccpend && ((chained & CCW_FLAGS_CD) == 0) )
997 {
998 dev->ccpend = 0;
999 /* dev->currline++; */
1000 write_buffer(dev, "\n", 1, unitstat);
1001 if (*unitstat != 0) return;
1002 }
1003 WRITE_LINE();
1004 if ((flags & CCW_FLAGS_CD) == 0)
1005 {
1006 if ( code <= 0x80 ) /* line control */
1007 {
1008 coun = code / 8;
1009 if ( coun == 0 )
1010 {
1011 dev->chskip = 1;
1012 if ( dev->browse )
1013 {
1014 dev->ccpend = 1;
1015 *unitstat = 0;
1016 }
1017 else
1018 write_buffer(dev, "\r", 1, unitstat);
1019 if (*unitstat == 0)
1020 *unitstat = CSW_CE | CSW_DE;
1021 return;
1022 }
1023
1024 dev->ccpend = 0;
1025 dev->currline += coun;
1026 write_buffer(dev, nls, coun, unitstat);
1027 if (*unitstat == 0)
1028 *unitstat = CSW_CE | CSW_DE;
1029 return;
1030 }
1031 else /*code > 0x80*/ /* chan control */
1032 {
1033 /*
1034 if ( dev->browse )
1035 {
1036 dev->currline++;
1037 write_buffer(dev, "\n", 1, unitstat);
1038 if (*unitstat != 0) return;
1039 }
1040 */
1041 chan = ( code - 128 ) / 8;
1042 if ( chan == 1 )
1043 {
1044 write_buffer(dev, "\r", 1, unitstat);
1045 if (*unitstat != 0)
1046 return;
1047 }
1048 SKIP_TO_CHAN();
1049 if (*unitstat == 0)
1050 *unitstat = CSW_CE | CSW_DE;
1051 return;
1052 }
1053
1054 }
1055 *unitstat = CSW_CE | CSW_DE;
1056 return;
1057
1058 case 0x03: /* No Operation */
1059 *unitstat = CSW_CE | CSW_DE;
1060 break;
1061
1062 case 0x0B: /* Space 1 Line */
1063 case 0x13: /* Space 2 Lines */
1064 case 0x1B: /* Space 3 Lines */
1065
1066 case 0x8B: /* Skip to Channel 1 */
1067 case 0x93: /* Skip to Channel 2 */
1068 case 0x9B: /* Skip to Channel 3 */
1069 case 0xA3: /* Skip to Channel 4 */
1070 case 0xAB: /* Skip to Channel 5 */
1071 case 0xB3: /* Skip to Channel 6 */
1072 case 0xBB: /* Skip to Channel 7 */
1073 case 0xC3: /* Skip to Channel 8 */
1074 case 0xCB: /* Skip to Channel 9 */
1075 case 0xD3: /* Skip to Channel 10 */
1076 case 0xDB: /* Skip to Channel 11 */
1077 case 0xE3: /* Skip to Channel 12 */
1078 if (dev->rawcc)
1079 {
1080 sprintf(hex,"%02x",code);
1081 write_buffer(dev, hex, 2, unitstat);
1082 if (*unitstat != 0) return;
1083 eor = (dev->crlf) ? "\r\n" : "\n";
1084 write_buffer(dev, eor, strlen(eor), unitstat);
1085 if (*unitstat == 0)
1086 *unitstat = CSW_CE | CSW_DE;
1087 return;
1088 }
1089
1090 if ( code <= 0x80 ) /* line control */
1091 {
1092 coun = code / 8;
1093 dev->ccpend = 0;
1094 dev->currline += coun;
1095 write_buffer(dev, nls, coun, unitstat);
1096 if (*unitstat == 0)
1097 *unitstat = CSW_CE | CSW_DE;
1098 return;
1099 }
1100 else /*code > 0x80*/ /* chan control */
1101 {
1102 /*
1103 if ( dev->browse && dev->ccpend)
1104 {
1105 coun = 1;
1106 dev->ccpend = 0;
1107 dev->currline += coun;
1108 write_buffer(dev, nls, coun, unitstat);
1109 if (*unitstat != 0) return;
1110 }
1111 */
1112 chan = ( code - 128 ) / 8;
1113 SKIP_TO_CHAN();
1114 if (*unitstat == 0)
1115 *unitstat = CSW_CE | CSW_DE;
1116 return;
1117 }
1118 break;
1119
1120 case 0x63:
1121 /*---------------------------------------------------------------*/
1122 /* LOAD FORMS CONTROL BUFFER */
1123 /*---------------------------------------------------------------*/
1124 if (dev->rawcc)
1125 {
1126 sprintf(hex,"%02x",code);
1127 write_buffer(dev, hex, 2, unitstat);
1128 if (*unitstat != 0) return;
1129 for (i = 0; i < count; i++)
1130 {
1131 sprintf(hex,"%02x",iobuf[i]);
1132 dev->buf[i*2] = hex[0];
1133 dev->buf[i*2+1] = hex[1];
1134 } /* end for(i) */
1135 write_buffer(dev, (char *)dev->buf, i*2, unitstat);
1136 if (*unitstat != 0) return;
1137 eor = (dev->crlf) ? "\r\n" : "\n";
1138 write_buffer(dev, eor, strlen(eor), unitstat);
1139 if (*unitstat != 0) return;
1140 }
1141 else
1142 {
1143 int i = 0;
1144 int j = 1;
1145 int more = 1;
1146 for (i = 0; i <= FCBSIZE; i++) dev->fcb[i] = 0;
1147
1148 dev->lpi = 6;
1149 dev->index = 0;
1150 i = 0;
1151 if (iobuf[0] & 0xc0)
1152 {
1153 /* First byte is a print position index */
1154 if ((iobuf[0] & 0xc0) == 0x80)
1155 /* Indexing right */
1156 dev->index = iobuf[0] & 0x1f;
1157 else
1158 /* Indexing left */
1159 dev->index = - (iobuf[0] & 0x1f);
1160 i = 1;
1161 }
1162
1163 for (; i < count && j <= FCBSIZE && more; i++, j++)
1164 {
1165 dev->fcb[i] = iobuf[i] & 0x0f;
1166 if (dev->fcb[j] > 12)
1167 {
1168 *residual = count - i;
1169 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1170 dev->sense[0] = SENSE_CC;
1171 return;
1172 }
1173
1174 if (iobuf[i] & 0x10)
1175 {
1176 /* Flag bit is on */
1177 if (j == 1)
1178 /* Flag bit in first byte means eight lines per inch */
1179 dev->lpi = 8;
1180 else
1181 more = 0;
1182 }
1183 }
1184 if (more)
1185 {
1186 /* No flag in last byte or too many bytes */
1187 *residual = count - i;
1188 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1189 dev->sense[0] = SENSE_CC;
1190 return;
1191 }
1192 *residual = count - i;
1193 dev->lpp = j - 1;
1194
1195 fcb_dump(dev, wbuf, 150);
1196 logmsg("HHCPN210I %d:%4.4X %s\n",
1197 SSID_TO_LCSS(dev->ssid), dev->devnum, wbuf);
1198 }
1199 /* Return normal status */
1200 *residual = 0;
1201 *unitstat = CSW_CE | CSW_DE;
1202 break;
1203
1204 case 0x06:
1205 /*---------------------------------------------------------------*/
1206 /* DIAGNOSTIC CHECK READ */
1207 /*---------------------------------------------------------------*/
1208 /* If not 1403, reject if not preceded by DIAGNOSTIC GATE */
1209 if (dev->devtype != 0x1403 && dev->diaggate == 0)
1210 {
1211 dev->sense[0] = SENSE_CR;
1212 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1213 break;
1214 }
1215
1216 /* Return normal status */
1217 *unitstat = CSW_CE | CSW_DE;
1218 break;
1219
1220 case 0x07:
1221 /*---------------------------------------------------------------*/
1222 /* DIAGNOSTIC GATE */
1223 /*---------------------------------------------------------------*/
1224 /* Command reject if 1403, or if chained to another CCW
1225 except a no-operation at the start of the CCW chain */
1226 if (dev->devtype == 0x1403 || ccwseq > 1
1227 || (chained && prevcode != 0x03))
1228 {
1229 dev->sense[0] = SENSE_CR;
1230 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1231 break;
1232 }
1233
1234 /* Set diagnostic gate flag */
1235 dev->diaggate = 1;
1236
1237 /* Return normal status */
1238 *unitstat = CSW_CE | CSW_DE;
1239 break;
1240
1241 case 0x0A:
1242 /*---------------------------------------------------------------*/
1243 /* DIAGNOSTIC READ UCS BUFFER */
1244 /*---------------------------------------------------------------*/
1245 /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */
1246 if (dev->devtype == 0x1403 || dev->diaggate == 0)
1247 {
1248 dev->sense[0] = SENSE_CR;
1249 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1250 break;
1251 }
1252
1253 /* Return normal status */
1254 *unitstat = CSW_CE | CSW_DE;
1255 break;
1256
1257 case 0x12:
1258 /*---------------------------------------------------------------*/
1259 /* DIAGNOSTIC READ fcb */
1260 /*---------------------------------------------------------------*/
1261 /* Reject if 1403 or not preceded by DIAGNOSTIC GATE */
1262 if (dev->devtype == 0x1403 || dev->diaggate == 0)
1263 {
1264 dev->sense[0] = SENSE_CR;
1265 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1266 break;
1267 }
1268
1269 /* Return normal status */
1270 *unitstat = CSW_CE | CSW_DE;
1271 break;
1272
1273 case 0x23:
1274 /*---------------------------------------------------------------*/
1275 /* UNFOLD */
1276 /*---------------------------------------------------------------*/
1277 dev->fold = 0;
1278 *unitstat = CSW_CE | CSW_DE;
1279 break;
1280
1281 case 0x43:
1282 /*---------------------------------------------------------------*/
1283 /* FOLD */
1284 /*---------------------------------------------------------------*/
1285 dev->fold = 1;
1286 *unitstat = CSW_CE | CSW_DE;
1287 break;
1288
1289 case 0x73:
1290 /*---------------------------------------------------------------*/
1291 /* BLOCK DATA CHECK */
1292 /*---------------------------------------------------------------*/
1293 /*
1294 *residual = 0;
1295 */
1296 *unitstat = CSW_CE | CSW_DE;
1297 break;
1298
1299 case 0x7B:
1300 /*---------------------------------------------------------------*/
1301 /* ALLOW DATA CHECK */
1302 /*---------------------------------------------------------------*/
1303 /*
1304 *residual = 0;
1305 */
1306 *unitstat = CSW_CE | CSW_DE;
1307 break;
1308
1309 case 0xEB:
1310 /*---------------------------------------------------------------*/
1311 /* UCS GATE LOAD */
1312 /*---------------------------------------------------------------*/
1313 /* Command reject if not first command in chain */
1314 if (chained != 0)
1315 {
1316 dev->sense[0] = SENSE_CR;
1317 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1318 break;
1319 }
1320
1321 /* Return normal status */
1322 *unitstat = CSW_CE | CSW_DE;
1323 break;
1324
1325 case 0xF3:
1326 /*---------------------------------------------------------------*/
1327 /* LOAD UCS BUFFER AND FOLD */
1328 /*---------------------------------------------------------------*/
1329 /* For 1403, command reject if not chained to UCS GATE */
1330 /* Also allow ALLOW DATA CHECK to get TSS/370 working */
1331 /* -- JRM 11/28/2007 */
1332 if (dev->devtype == 0x1403 &&
1333 ((prevcode != 0xEB) && (prevcode != 0x7B)))
1334 {
1335 dev->sense[0] = SENSE_CR;
1336 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1337 break;
1338 }
1339
1340 /* Set fold indicator and return normal status */
1341 dev->fold = 1;
1342 dev->chskip = 1;
1343 /*
1344 *residual = 0;
1345 */
1346 *unitstat = CSW_CE | CSW_DE;
1347 break;
1348
1349 case 0xFB:
1350 /*---------------------------------------------------------------*/
1351 /* LOAD UCS BUFFER (NO FOLD) */
1352 /*---------------------------------------------------------------*/
1353 /* For 1403, command reject if not chained to UCS GATE */
1354 if (dev->devtype == 0x1403 && prevcode != 0xEB)
1355 {
1356 dev->sense[0] = SENSE_CR;
1357 *unitstat = CSW_CE | CSW_DE | CSW_UC;
1358 break;
1359 }
1360
1361 /* Reset fold indicator and return normal status */
1362 dev->fold = 0;
1363 dev->chskip = 1;
1364
1365 /*
1366 *residual = 0;
1367 */
1368 *unitstat = CSW_CE | CSW_DE;
1369 break;
1370
1371 case 0x04:
1372 /*---------------------------------------------------------------*/
1373 /* SENSE */
1374 /*---------------------------------------------------------------*/
1375 /* Calculate residual byte count */
1376 num = (count < dev->numsense) ? count : dev->numsense;
1377 *residual = count - num;
1378 if (count < dev->numsense) *more = 1;
1379
1380 /* Copy device sense bytes to channel I/O buffer */
1381 memcpy (iobuf, dev->sense, num);
1382
1383 /* Clear the device sense bytes */
1384 memset (dev->sense, 0, sizeof(dev->sense));
1385
1386 /* Return unit status */
1387 *unitstat = CSW_CE | CSW_DE;
1388 break;
1389
1390 case 0xE4:
1391 /*---------------------------------------------------------------*/
1392 /* SENSE ID */
1393 /*---------------------------------------------------------------*/
1394 /* Calculate residual byte count */
1395 num = (count < dev->numdevid) ? count : dev->numdevid;
1396 *residual = count - num;
1397 if (count < dev->numdevid) *more = 1;
1398
1399 /* Copy device identifier bytes to channel I/O buffer */
1400 memcpy (iobuf, dev->devid, num);
1401
1402 /* Return unit status */
1403 *unitstat = CSW_CE | CSW_DE;
1404 break;
1405
1406 default:
1407 /*---------------------------------------------------------------*/
1408 /* INVALID OPERATION */
1409 /*---------------------------------------------------------------*/
1410 /* Set command reject sense byte, and unit check status */
1411 dev->sense[0] = SENSE_CR;
1412 *unitstat = CSW_UC;
1413
1414 } /* end switch(code) */
1415
1416 } /* end function printer_execute_ccw */
1417
1418
1419 #if defined(OPTION_DYNAMIC_LOAD)
1420 static
1421 #endif
1422 DEVHND printer_device_hndinfo = {
1423 &printer_init_handler, /* Device Initialisation */
1424 &printer_execute_ccw, /* Device CCW execute */
1425 &printer_close_device, /* Device Close */
1426 &printer_query_device, /* Device Query */
1427 NULL, /* Device Start channel pgm */
1428 NULL, /* Device End channel pgm */
1429 NULL, /* Device Resume channel pgm */
1430 NULL, /* Device Suspend channel pgm */
1431 NULL, /* Device Read */
1432 NULL, /* Device Write */
1433 NULL, /* Device Query used */
1434 NULL, /* Device Reserve */
1435 NULL, /* Device Release */
1436 NULL, /* Device Attention */
1437 printer_immed_commands, /* Immediate CCW Codes */
1438 NULL, /* Signal Adapter Input */
1439 NULL, /* Signal Adapter Output */
1440 NULL, /* Hercules suspend */
1441 NULL /* Hercules resume */
1442 };
1443
1444 /* Libtool static name colision resolution */
1445 /* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
1446 #if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
1447 #define hdl_ddev hdt1403_LTX_hdl_ddev
1448 #define hdl_depc hdt1403_LTX_hdl_depc
1449 #define hdl_reso hdt1403_LTX_hdl_reso
1450 #define hdl_init hdt1403_LTX_hdl_init
1451 #define hdl_fini hdt1403_LTX_hdl_fini
1452 #endif
1453
1454 #if defined(OPTION_DYNAMIC_LOAD)
1455 HDL_DEPENDENCY_SECTION;
1456 {
1457 HDL_DEPENDENCY(HERCULES);
1458 HDL_DEPENDENCY(DEVBLK);
1459 }
1460 END_DEPENDENCY_SECTION
1461
1462
1463 HDL_DEVICE_SECTION;
1464 {
1465 HDL_DEVICE(1403, printer_device_hndinfo );
1466 HDL_DEVICE(3211, printer_device_hndinfo );
1467 }
1468 END_DEVICE_SECTION
1469 #endif
1470