Files
org-hyperion-cules/con1052c.c
2014-08-21 06:37:14 -07:00

473 lines
16 KiB
C

/* CON1052.C (c)Copyright Jan Jaeger, 2004-2012 */
/* Emulated 1052 on hercules console */
#include "hstdinc.h"
#include "hercules.h"
#include "devtype.h"
#include "opcode.h"
#include "sr.h"
#undef MOD
#define MOD "CON"
#if defined(OPTION_DYNAMIC_LOAD) && defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
SYSBLK *psysblk;
#define sysblk (*psysblk)
void* (*panel_command) (void*);
#endif
#if defined(OPTION_DYNAMIC_LOAD)
static void* con1052_panel_command (char *cmd);
#endif
#define BUFLEN_1052 256 /* 1052 Send/Receive buffer */
/*-------------------------------------------------------------------*/
/* Ivan Warren 20040227 */
/* This table is used by channel.c to determine if a CCW code is an */
/* immediate command or not */
/* The tape is addressed in the DEVHND structure as 'DEVIMM immed' */
/* 0 : Command is NOT an immediate command */
/* 1 : Command is an immediate command */
/* Note : An immediate command is defined as a command which returns */
/* CE (channel end) during initialisation (that is, no data is */
/* actually transfered. In this case, IL is not indicated for a CCW */
/* Format 0 or for a CCW Format 1 when IL Suppression Mode is in */
/* effect */
/*-------------------------------------------------------------------*/
static BYTE con1052_immed[256]=
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
{ 0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0, /* 00 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 10 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 20 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 30 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 40 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 50 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 60 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 70 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 80 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 90 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* A0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* B0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* C0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* D0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* E0 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* F0 */
/*-------------------------------------------------------------------*/
/* INITIALIZE THE 1052/3215 DEVICE HANDLER */
/*-------------------------------------------------------------------*/
static int
con1052_init_handler ( DEVBLK *dev, int argc, char *argv[] )
{
int ac=0;
/* For re-initialisation, close the existing file, if any */
if (dev->fd >= 0)
(dev->hnd->close)(dev);
/* reset excp count */
dev->excps = 0;
/* Integrated console is always connected */
dev->connected = 1;
/* Set number of sense bytes */
dev->numsense = 1;
/* Initialize device dependent fields */
dev->keybdrem = 0;
/* Set length of print buffer */
dev->bufsize = BUFLEN_1052;
/* Assume we want to prompt */
dev->prompt1052 = 1;
/* Default command character is "/" */
strlcpy(dev->filename,"/",sizeof(dev->filename));
/* Is there an argument? */
if (argc > 0)
{
/* Look at the argument and set noprompt flag if specified. */
if (strcasecmp(argv[ac], "noprompt") == 0)
{
dev->prompt1052 = 0;
ac++; argc--;
}
else
strlcpy(dev->filename,argv[ac],sizeof(dev->filename));
}
if(!sscanf(dev->typname,"%hx",&(dev->devtype)))
dev->devtype = 0x1052;
/* Initialize the device identifier bytes */
dev->devid[0] = 0xFF;
dev->devid[1] = dev->devtype >> 8;
dev->devid[2] = dev->devtype & 0xFF;
dev->devid[3] = 0x00;
dev->devid[4] = dev->devtype >> 8;
dev->devid[5] = dev->devtype & 0xFF;
dev->devid[6] = 0x00;
dev->numdevid = 7;
return 0;
} /* end function con1052_init_handler */
/*-------------------------------------------------------------------*/
/* QUERY THE 1052/3215 DEVICE DEFINITION */
/*-------------------------------------------------------------------*/
static void
con1052_query_device (DEVBLK *dev, char **devclass,
int buflen, char *buffer)
{
BEGIN_DEVICE_CLASS_QUERY( "CON", dev, devclass, buflen, buffer );
snprintf(buffer, buflen-1,
"*syscons cmdpref(%s)%s IO[%" I64_FMT "u]",
dev->filename,
!dev->prompt1052 ? " noprompt" : "",
dev->excps );
} /* end function con1052_query_device */
/*-------------------------------------------------------------------*/
/* CLOSE THE 1052/3215 DEVICE HANDLER */
/*-------------------------------------------------------------------*/
static int
con1052_close_device ( DEVBLK *dev )
{
UNREFERENCED(dev);
return 0;
} /* end function con1052_close_device */
/*-------------------------------------------------------------------*/
/* EXECUTE A 1052/3215 CHANNEL COMMAND WORD */
/*-------------------------------------------------------------------*/
static void
con1052_execute_ccw ( DEVBLK *dev, BYTE code, BYTE flags,
BYTE chained, U32 count, BYTE prevcode, int ccwseq,
BYTE *iobuf, BYTE *more, BYTE *unitstat, U32 *residual )
{
U32 len; /* Length of data */
U32 num; /* Number of bytes to move */
BYTE c; /* Print character */
UNREFERENCED(chained);
UNREFERENCED(prevcode);
UNREFERENCED(ccwseq);
/* Unit check with intervention required if no client connected */
if (dev->connected == 0 && !IS_CCW_SENSE(code))
{
dev->sense[0] = SENSE_IR;
*unitstat = CSW_UC;
return;
}
/* Process depending on CCW opcode */
switch (code) {
case 0x01:
/*---------------------------------------------------------------*/
/* WRITE NO CARRIER RETURN */
/*---------------------------------------------------------------*/
case 0x09:
/*---------------------------------------------------------------*/
/* WRITE AUTO CARRIER RETURN */
/*---------------------------------------------------------------*/
/* Calculate number of bytes to write and set residual count */
num = (count < BUFLEN_1052) ? count : BUFLEN_1052;
*residual = count - num;
/* Translate data in channel buffer to ASCII */
for (len = 0; len < num; len++)
{
c = guest_to_host(iobuf[len]);
if (!isprint(c) && c != 0x0a && c != 0x0d) c = SPACE;
iobuf[len] = c;
} /* end for(len) */
/* Perform end of record processing if not data-chaining,
and append carriage return and newline if required */
if ((flags & CCW_FLAGS_CD) == 0
&& len < BUFLEN_1052 && 0x09 == code)
iobuf[len++] = '\n';
iobuf[len] = '\0';
/* process multiline messages */
{
char * str = (char *) iobuf;
for (; str && *str;)
{
char * t = strchr(str, '\n');
if (t) *t++ = 0;
#ifdef OPTION_MSGCLR
#define CLR "<pnl,color(green,black)>"
#else
#define CLR ""
#endif
#ifdef OPTION_SCP_MSG_PREFIX
WRCMSG (CLR, HHC00001, "I", str);
#else /*!OPTION_SCP_MSG_PREFIX*/
logmsg (CLR "%s%s", str, (t ? "\n" : ""));
#endif /*OPTION_SCP_MSG_PREFIX*/
str = t;
}
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x03:
/*---------------------------------------------------------------*/
/* CONTROL NO-OPERATION */
/*---------------------------------------------------------------*/
*unitstat = CSW_CE | CSW_DE;
break;
case 0x0A:
/*---------------------------------------------------------------*/
/* READ INQUIRY */
/*---------------------------------------------------------------*/
/* Solicit console input if no data in the device buffer */
if (!dev->keybdrem)
{
/* Display prompting message on console if allowed */
if (dev->prompt1052)
WRCMSG ("<pnl,color(lightyellow,black)>", HHC00010, "A", SSID_TO_LCSS(dev->ssid), dev->devnum);
obtain_lock(&dev->lock);
dev->kbwaiters++;
wait_condition(&dev->kbcond, &dev->lock);
dev->kbwaiters--;
release_lock(&dev->lock);
}
/* Calculate number of bytes to move and residual byte count */
len = dev->keybdrem;
num = (count < len) ? count : len;
*residual = count - num;
if (count < len) *more = 1;
/* Copy data from device buffer to channel buffer */
memcpy (iobuf, dev->buf, num);
/* If data chaining is specified, save remaining data */
if ((flags & CCW_FLAGS_CD) && len > count)
{
memmove (dev->buf, dev->buf + count, len - count);
dev->keybdrem = len - count;
}
else
{
dev->keybdrem = 0;
}
/* Return normal status */
*unitstat = CSW_CE | CSW_DE;
break;
case 0x0B:
/*---------------------------------------------------------------*/
/* AUDIBLE ALARM */
/*---------------------------------------------------------------*/
WRCMSG ("<pnl,color(lightred,black)>", HHC00009, "I");
/*
*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 con1052_execute_ccw */
#if defined(OPTION_DYNAMIC_LOAD)
static
#endif
DEVHND con1052_device_hndinfo = {
&con1052_init_handler, /* Device Initialisation */
&con1052_execute_ccw, /* Device CCW execute */
&con1052_close_device, /* Device Close */
&con1052_query_device, /* Device Query */
NULL, /* Device Extended Query */
NULL, /* Device Start channel pgm */
NULL, /* Device End channel pgm */
NULL, /* Device Resume channel pgm */
NULL, /* Device Suspend channel pgm */
NULL, /* Device Halt channel pgm */
NULL, /* Device Read */
NULL, /* Device Write */
NULL, /* Device Query used */
NULL, /* Device Reserve */
NULL, /* Device Release */
NULL, /* Device Attention */
con1052_immed, /* Immediate CCW Codes */
NULL, /* Signal Adapter Input */
NULL, /* Signal Adapter Output */
NULL, /* Signal Adapter Sync */
NULL, /* Signal Adapter Output Mult */
NULL, /* QDIO subsys desc */
NULL, /* QDIO set subchan ind */
NULL, /* Hercules suspend */
NULL /* Hercules resume */
};
#if defined(OPTION_DYNAMIC_LOAD)
static void*
con1052_panel_command (char *cmd)
{
DEVBLK *dev;
char *input;
int i;
void* (*next_panel_command_handler)(char *cmd);
for(dev = sysblk.firstdev; dev; dev = dev->nextdev)
{
if(dev->allocated
&& dev->hnd == &con1052_device_hndinfo
&& !strncasecmp(cmd,dev->filename,strlen(dev->filename)) )
{
input = cmd + strlen(dev->filename);
WRCMSG ("<pnl,color(lightyellow,black)>", HHC00008, "I",
dev->filename, cmd+strlen(dev->filename) );
for(i = 0; i < dev->bufsize && input[i] != '\0'; i++)
dev->buf[i] = isprint(input[i]) ? host_to_guest(input[i]) : SPACE;
dev->keybdrem = dev->buflen = i;
obtain_lock(&dev->lock);
if(dev->kbwaiters)
{
signal_condition(&dev->kbcond);
release_lock(&dev->lock);
}
else
{
release_lock(&dev->lock);
device_attention (dev, CSW_ATTN);
}
return NULL;
}
}
next_panel_command_handler = HDL_FINDNXT(con1052_panel_command);
if (!next_panel_command_handler)
return NULL;
return next_panel_command_handler(cmd);
}
#endif
/* Libtool static name colision resolution */
/* note : lt_dlopen will look for symbol & modulename_LTX_symbol */
#if !defined(HDL_BUILD_SHARED) && defined(HDL_USE_LIBTOOL)
#define hdl_ddev hdt1052c_LTX_hdl_ddev
#define hdl_depc hdt1052c_LTX_hdl_depc
#define hdl_reso hdt1052c_LTX_hdl_reso
#define hdl_init hdt1052c_LTX_hdl_init
#define hdl_fini hdt1052c_LTX_hdl_fini
#endif
#if defined(OPTION_DYNAMIC_LOAD)
HDL_DEPENDENCY_SECTION;
{
HDL_DEPENDENCY(HERCULES);
HDL_DEPENDENCY(DEVBLK);
HDL_DEPENDENCY(SYSBLK);
}
END_DEPENDENCY_SECTION
#if defined(WIN32) && !defined(HDL_USE_LIBTOOL) && !defined(_MSVC_)
#undef sysblk
HDL_RESOLVER_SECTION;
{
HDL_RESOLVE_PTRVAR(psysblk, sysblk);
HDL_RESOLVE(panel_command);
}
END_RESOLVER_SECTION
#endif
HDL_DEVICE_SECTION;
{
HDL_DEVICE(1052-C, con1052_device_hndinfo);
HDL_DEVICE(3215-C, con1052_device_hndinfo);
}
END_DEVICE_SECTION
HDL_REGISTER_SECTION;
{
HDL_REGISTER (panel_command, con1052_panel_command);
}
END_REGISTER_SECTION
#endif