Files
org-hyperion-cules/printer.c
Jan Jaeger 69ca87cc62 Rollback a number of changes :-(
git-svn-id: file:///home/jj/hercules.svn/trunk@1403 956126f8-22a0-4046-8f4a-272fa8102e63
2003-06-02 13:16:07 +00:00

696 lines
24 KiB
C

/* PRINTER.C (c) Copyright Roger Bowler, 1999-2003 */
/* ESA/390 Line Printer Device Handler */
/*-------------------------------------------------------------------*/
/* This module contains device handling functions for emulated */
/* System/370 line printer devices. */
/*-------------------------------------------------------------------*/
#include "hercules.h"
#include "devtype.h"
#include "opcode.h"
/*-------------------------------------------------------------------*/
/* Internal macro definitions */
/*-------------------------------------------------------------------*/
#define LINE_LENGTH 150
#define SPACE ((BYTE)' ')
/*-------------------------------------------------------------------*/
/* Subroutine to open the printer file or pipe */
/*-------------------------------------------------------------------*/
static int
open_printer (DEVBLK *dev)
{
int fd; /* File descriptor */
int rc; /* Return code */
int pipefd[2]; /* Pipe descriptors */
pid_t pid; /* Child process identifier */
/* Regular open if 1st char of filename is not vertical bar */
if (dev->filename[0] != '|')
{
fd = open (dev->filename,
O_WRONLY | O_CREAT | O_TRUNC /* | O_SYNC */,
S_IRUSR | S_IWUSR | S_IRGRP);
if (fd < 0)
{
logmsg (_("HHCPR004E Error opening file %s: %s\n"),
dev->filename, strerror(errno));
return -1;
}
/* Save file descriptor in device block and return */
dev->fd = fd;
return 0;
}
/* Filename is in format |xxx, set up pipe to program xxx */
/* Create a pipe */
rc = pipe (pipefd);
if (rc < 0)
{
logmsg (_("HHCPR005E %4.4X device initialization error: pipe: %s\n"),
dev->devnum, strerror(errno));
return -1;
}
/* Fork a child process to receive the pipe data */
pid = fork();
if (pid < 0)
{
logmsg (_("HHCPR006E %4.4X device initialization error: fork: %s\n"),
dev->devnum, strerror(errno));
return -1;
}
/* The child process executes the pipe receiver program... */
if (pid == 0)
{
/* Log start of child process */
logmsg (_("HHCPR007I pipe receiver (pid=%d) starting for %4.4X\n"),
getpid(), dev->devnum);
/* Close the write end of the pipe */
close (pipefd[1]);
/* Duplicate the read end of the pipe onto STDIN */
if (pipefd[0] != STDIN_FILENO)
{
rc = dup2 (pipefd[0], STDIN_FILENO);
if (rc != STDIN_FILENO)
{
logmsg (_("HHCPR008E %4.4X dup2 error: %s\n"),
dev->devnum, strerror(errno));
close (pipefd[0]);
_exit(127);
}
} /* end if(pipefd[0] != STDIN_FILENO) */
/* Close the original descriptor now duplicated to STDIN */
close (pipefd[0]);
/* Redirect stderr (screen) to hercules log task */
dup2(STDOUT_FILENO, STDERR_FILENO);
/* Relinquish any ROOT authority before calling shell */
SETMODE(TERM);
/* Execute the specified pipe receiver program */
#if defined(WIN32)
{
/* The dev=, pid= and extgui= arguments are for informational
purposes only so the spooler knows who/what it's spooling. */
BYTE cmdline[256];
snprintf(cmdline,256,"\"%s\" pid=%d dev=%4.4X extgui=%d",
dev->filename+1,getpid(),dev->devnum,
#ifdef EXTERNALGUI
extgui
#else /*!EXTERNALGUI*/
0
#endif /*EXTERNALGUI*/
);
rc = system (cmdline);
}
#else
rc = system (dev->filename+1);
#endif
if (rc == 0)
{
/* Log end of child process */
logmsg (_("HHCPR011I pipe receiver (pid=%d) terminating for %4.4X\n"),
getpid(), dev->devnum);
}
else
{
/* Log error */
logmsg (_("HHCPR012E %4.4X Unable to execute %s: %s\n"),
dev->devnum, dev->filename+1, strerror(errno));
}
/* The child process terminates using _exit instead of exit
to avoid invoking the panel atexit cleanup routine */
_exit(rc);
} /* end if(pid==0) */
/* The parent process continues as the pipe sender */
/* Close the read end of the pipe */
close (pipefd[0]);
/* Save pipe write descriptor in the device block */
dev->fd = pipefd[1];
return 0;
} /* end function open_printer */
/*-------------------------------------------------------------------*/
/* Subroutine to write data to the printer */
/*-------------------------------------------------------------------*/
static void
write_buffer (DEVBLK *dev, BYTE *buf, int len, BYTE *unitstat)
{
int rc; /* Return code */
/* Write data to the printer file */
rc = write (dev->fd, buf, len);
/* Equipment check if error writing to printer file */
if (rc < len)
{
logmsg (_("HHCPR003E %4.4X Error writing to %s: %s\n"),
dev->devnum, dev->filename,
(errno == 0 ? _("incomplete"): strerror(errno)));
dev->sense[0] = SENSE_EC;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
return;
}
} /* end function write_buffer */
/*-------------------------------------------------------------------*/
/* Initialize the device handler */
/*-------------------------------------------------------------------*/
static int printer_init_handler (DEVBLK *dev, int argc, BYTE *argv[])
{
int i; /* Array subscript */
/* The first argument is the file name */
if (argc == 0 || strlen(argv[0]) > sizeof(dev->filename)-1)
{
fprintf (stderr,
"HHCPR001E File name missing or invalid for printer %4.4X\n",
dev->devnum);
return -1;
}
/* Save the file name in the device block */
strcpy (dev->filename, argv[0]);
/* Initialize device dependent fields */
dev->fd = -1;
dev->printpos = 0;
dev->printrem = LINE_LENGTH;
dev->diaggate = 0;
dev->fold = 0;
dev->crlf = 0;
dev->stopprt = 0;
/* Process the driver arguments */
for (i = 1; i < argc; i++)
{
if (strcasecmp(argv[i], "crlf") == 0)
{
dev->crlf = 1;
continue;
}
fprintf (stderr, "HHCPR002E Invalid argument for printer %4.4X: %s\n",
dev->devnum, argv[i]);
return -1;
}
/* Set length of print buffer */
dev->bufsize = LINE_LENGTH + 8;
/* Set number of sense bytes */
dev->numsense = 1;
/* Initialize the device identifier bytes */
dev->devid[0] = 0xFF;
dev->devid[1] = 0x28; /* Control unit type is 2821-1 */
dev->devid[2] = 0x21;
dev->devid[3] = 0x01;
dev->devid[4] = dev->devtype >> 8;
dev->devid[5] = dev->devtype & 0xFF;
dev->devid[6] = 0x01;
dev->numdevid = 7;
/* Activate I/O tracing */
// dev->ccwtrace = 1;
return 0;
} /* end function printer_init_handler */
/*-------------------------------------------------------------------*/
/* Query the device definition */
/*-------------------------------------------------------------------*/
static void printer_query_device (DEVBLK *dev, BYTE **class,
int buflen, BYTE *buffer)
{
*class = "PRT";
snprintf (buffer, buflen, "%s%s%s",
dev->filename,
(dev->crlf ? " crlf" : ""),
(dev->stopprt ? " (stopped)" : ""));
} /* end function printer_query_device */
/*-------------------------------------------------------------------*/
/* Close the device */
/*-------------------------------------------------------------------*/
static int printer_close_device ( DEVBLK *dev )
{
/* Close the device file */
close (dev->fd);
dev->fd = -1;
dev->stopprt = 0;
return 0;
} /* end function printer_close_device */
/*-------------------------------------------------------------------*/
/* Execute a Channel Command Word */
/*-------------------------------------------------------------------*/
static void 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)
{
int rc = 0; /* Return code */
int i; /* Loop counter */
int num; /* Number of bytes to move */
char *eor; /* -> end of record string */
BYTE c; /* Print character */
/* Reset flags at start of CCW chain */
if (chained == 0)
{
dev->diaggate = 0;
}
/* Open the device file if necessary */
if (dev->fd < 0 && !IS_CCW_SENSE(code))
rc = open_printer (dev);
else
{
/* If printer stopped, return intervention required */
if (dev->stopprt && !IS_CCW_SENSE(code))
rc = -1;
else
rc = 0;
}
if (rc < 0)
{
/* Set unit check with intervention required */
dev->sense[0] = SENSE_IR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
return;
}
/* Process depending on CCW opcode */
switch (code) {
case 0x01:
/*---------------------------------------------------------------*/
/* WRITE WITHOUT SPACING */
/*---------------------------------------------------------------*/
eor = "\r";
goto write;
case 0x09:
/*---------------------------------------------------------------*/
/* WRITE AND SPACE 1 LINE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
goto write;
case 0x11:
/*---------------------------------------------------------------*/
/* WRITE AND SPACE 2 LINES */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n\n" : "\n\n";
goto write;
case 0x19:
/*---------------------------------------------------------------*/
/* WRITE AND SPACE 3 LINES */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n\n\n" : "\n\n\n";
goto write;
case 0x89:
/*---------------------------------------------------------------*/
/* WRITE AND SKIP TO CHANNEL 1 */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\f" : "\f";
goto write;
case 0xC9:
/*---------------------------------------------------------------*/
/* WRITE AND SKIP TO CHANNEL 9 */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
goto write;
case 0xE1:
/*---------------------------------------------------------------*/
/* WRITE AND SKIP TO CHANNEL 12 */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
goto write;
write:
/* Start a new record if not data-chained from previous CCW */
if ((chained & CCW_FLAGS_CD) == 0)
{
dev->printpos = 0;
dev->printrem = LINE_LENGTH;
} /* end if(!data-chained) */
/* Calculate number of bytes to write and set residual count */
num = (count < dev->printrem) ? count : dev->printrem;
*residual = count - num;
/* Copy data from channel buffer to print buffer */
for (i = 0; i < num; i++)
{
c = guest_to_host(iobuf[i]);
if (dev->fold) c = toupper(c);
if (c == 0) c = SPACE;
dev->buf[dev->printpos] = c;
dev->printpos++;
dev->printrem--;
} /* end for(i) */
/* Perform end of record processing if not data-chaining */
if ((flags & CCW_FLAGS_CD) == 0)
{
/* Truncate trailing blanks from print line */
for (i = dev->printpos; i > 0; i--)
if (dev->buf[i-1] != SPACE) break;
/* Append carriage return and line feed(s) */
strcpy (dev->buf + i, eor);
i += strlen(eor);
/* Write print line */
write_buffer (dev, dev->buf, i, unitstat);
if (*unitstat != 0) break;
} /* end if(!data-chaining) */
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x03:
/*---------------------------------------------------------------*/
/* CONTROL NO-OPERATION */
/*---------------------------------------------------------------*/
*unitstat = CSW_CE | CSW_DE;
break;
case 0x06:
/*---------------------------------------------------------------*/
/* DIAGNOSTIC CHECK READ */
/*---------------------------------------------------------------*/
/* If not 1403, reject if not preceded by DIAGNOSTIC GATE */
if (dev->devtype != 0x1403 && dev->diaggate == 0)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x07:
/*---------------------------------------------------------------*/
/* DIAGNOSTIC GATE */
/*---------------------------------------------------------------*/
/* Command reject if 1403, or if chained to another CCW
except a no-operation at the start of the CCW chain */
if (dev->devtype == 1403 || ccwseq > 1
|| (chained && prevcode != 0x03))
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Set diagnostic gate flag */
dev->diaggate = 1;
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x0A:
/*---------------------------------------------------------------*/
/* DIAGNOSTIC READ UCS BUFFER */
/*---------------------------------------------------------------*/
/* Reject if 1403 or not preceded by DIAGNOSTIC GATE */
if (dev->devtype == 0x1403 || dev->diaggate == 0)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x12:
/*---------------------------------------------------------------*/
/* DIAGNOSTIC READ FCB */
/*---------------------------------------------------------------*/
/* Reject if 1403 or not preceded by DIAGNOSTIC GATE */
if (dev->devtype == 0x1403 || dev->diaggate == 0)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x0B:
/*---------------------------------------------------------------*/
/* SPACE 1 LINE IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x13:
/*---------------------------------------------------------------*/
/* SPACE 2 LINES IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n\n" : "\n\n";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x1B:
/*---------------------------------------------------------------*/
/* SPACE 3 LINES IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n\n\n" : "\n\n\n";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x23:
/*---------------------------------------------------------------*/
/* UNFOLD */
/*---------------------------------------------------------------*/
dev->fold = 0;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x43:
/*---------------------------------------------------------------*/
/* FOLD */
/*---------------------------------------------------------------*/
dev->fold = 1;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x73:
/*---------------------------------------------------------------*/
/* BLOCK DATA CHECK */
/*---------------------------------------------------------------*/
*unitstat = CSW_CE | CSW_DE;
break;
case 0x7B:
/*---------------------------------------------------------------*/
/* ALLOW DATA CHECK */
/*---------------------------------------------------------------*/
*unitstat = CSW_CE | CSW_DE;
break;
case 0x8B:
/*---------------------------------------------------------------*/
/* SKIP TO CHANNEL 1 IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\f" : "\f";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0xCB:
/*---------------------------------------------------------------*/
/* SKIP TO CHANNEL 9 IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0xE3:
/*---------------------------------------------------------------*/
/* SKIP TO CHANNEL 12 IMMEDIATE */
/*---------------------------------------------------------------*/
eor = dev->crlf ? "\r\n" : "\n";
write_buffer (dev, eor, strlen(eor), unitstat);
if (*unitstat != 0) break;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x63:
/*---------------------------------------------------------------*/
/* LOAD FORMS CONTROL BUFFER */
/*---------------------------------------------------------------*/
/* Return normal status */
*residual = 0;
*unitstat = CSW_CE | CSW_DE;
break;
case 0xEB:
/*---------------------------------------------------------------*/
/* UCS GATE LOAD */
/*---------------------------------------------------------------*/
/* Command reject if not first command in chain */
if (chained != 0)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0xF3:
/*---------------------------------------------------------------*/
/* LOAD UCS BUFFER AND FOLD */
/*---------------------------------------------------------------*/
/* For 1403, command reject if not chained to UCS GATE */
if (dev->devtype == 0x1403 && prevcode != 0xEB)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Set fold indicator and return normal status */
dev->fold = 1;
*residual = 0;
*unitstat = CSW_CE | CSW_DE;
break;
case 0xFB:
/*---------------------------------------------------------------*/
/* LOAD UCS BUFFER (NO FOLD) */
/*---------------------------------------------------------------*/
/* For 1403, command reject if not chained to UCS GATE */
if (dev->devtype == 0x1403 && prevcode != 0xEB)
{
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
break;
}
/* Reset fold indicator and return normal status */
dev->fold = 0;
*residual = 0;
*unitstat = CSW_CE | CSW_DE;
break;
case 0x04:
/*---------------------------------------------------------------*/
/* SENSE */
/*---------------------------------------------------------------*/
/* Calculate residual byte count */
num = (count < dev->numsense) ? count : dev->numsense;
*residual = count - num;
if (count < dev->numsense) *more = 1;
/* Copy device sense bytes to channel I/O buffer */
memcpy (iobuf, dev->sense, num);
/* Clear the device sense bytes */
memset (dev->sense, 0, sizeof(dev->sense));
/* Return unit status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0xE4:
/*---------------------------------------------------------------*/
/* SENSE ID */
/*---------------------------------------------------------------*/
/* Calculate residual byte count */
num = (count < dev->numdevid) ? count : dev->numdevid;
*residual = count - num;
if (count < dev->numdevid) *more = 1;
/* Copy device identifier bytes to channel I/O buffer */
memcpy (iobuf, dev->devid, num);
/* Return unit status */
*unitstat = CSW_CE | CSW_DE;
break;
default:
/*---------------------------------------------------------------*/
/* INVALID OPERATION */
/*---------------------------------------------------------------*/
/* Set command reject sense byte, and unit check status */
dev->sense[0] = SENSE_CR;
*unitstat = CSW_CE | CSW_DE | CSW_UC;
} /* end switch(code) */
} /* end function printer_execute_ccw */
DEVHND printer_device_hndinfo = {
&printer_init_handler,
&printer_execute_ccw,
&printer_close_device,
&printer_query_device,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};