1
0
mirror of https://github.com/rcornwell/sims.git synced 2026-02-26 08:44:10 +00:00

SCP: Updated to current.

This commit is contained in:
Richard Cornwell
2020-02-14 18:41:56 -05:00
parent ae8a6faacc
commit 2b49d85421
6 changed files with 736 additions and 46 deletions

View File

@@ -975,6 +975,18 @@ display_init(enum display_type type, int sf, void *dptr)
fprintf(stderr, "Display initialization failed\r\n");
return 0;
}
void
display_close(void *dptr)
{
if (!initialized)
return;
free (points);
ws_shutdown();
initialized = 0;
}
void
display_reset(void)

View File

@@ -65,6 +65,11 @@ enum display_type {
*/
extern int display_init(enum display_type, int scale, void *dptr);
/*
* close display
*/
extern void display_close(void *dptr);
/* return size of virtual display */
extern int display_xpoints(void);
extern int display_ypoints(void);

View File

@@ -1241,12 +1241,10 @@ if (Scb->scb_b_bitmapblks < 127)
ret_val = (((t_offset)Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeblks << 16) + Scb->scb_r_blocks[Scb->scb_b_bitmapblks].scb_w_freeptr) * 512;
else
ret_val = (((t_offset)Scb->scb_r_blocks[0].scb_w_freeblks << 16) + Scb->scb_r_blocks[0].scb_w_freeptr) * 512;
if (!sim_quiet) {
sim_printf ("%s%d: '%s' Contains an ODS1 File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_printf ("%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm1_t_volname);
sim_printf ("Format: %12.12s ", Home.hm1_t_format);
sim_printf ("Sectors In Volume: %u\n", (uint32)(ret_val / 512));
}
sim_messagef (SCPE_OK, "%s%d: '%s' Contains an ODS1 File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_messagef (SCPE_OK, "%s%d: Volume Name: %12.12s ", sim_dname (dptr), (int)(uptr-dptr->units), Home.hm1_t_volname);
sim_messagef (SCPE_OK, "Format: %12.12s ", Home.hm1_t_format);
sim_messagef (SCPE_OK, "Sectors In Volume: %u\n", (uint32)(ret_val / 512));
Return_Cleanup:
uptr->capac = saved_capac;
@@ -1297,10 +1295,8 @@ for (i = 0; i < 8; i++) {
max_lbn_partnum = i;
}
}
if (!sim_quiet) {
sim_printf ("%s%d: '%s' Contains Ultrix partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_printf ("Partition with highest sector: %c, Sectors On Disk: %u\n", 'a' + max_lbn_partnum, max_lbn);
}
sim_messagef (SCPE_OK, "%s%d: '%s' Contains Ultrix partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_messagef (SCPE_OK, "Partition with highest sector: %c, Sectors On Disk: %u\n", 'a' + max_lbn_partnum, max_lbn);
ret_val = ((t_offset)max_lbn) * 512;
Return_Cleanup:
@@ -1308,6 +1304,475 @@ uptr->capac = saved_capac;
return ret_val;
}
#pragma pack(push,1)
/*
* The first logical block of device cluster 1 is either:
* 1. MFD label entry (RSTS versions through 7.x)
* 2. Disk Pack label (RSTS version 8.0 and later)
*/
typedef struct _RSTS_MFDLABEL {
uint16 ml_ulnk;
uint16 ml_mbm1;
uint16 ml_reserved1;
uint16 ml_reserved2;
uint16 ml_pcs;
uint16 ml_pstat;
uint16 ml_packid[2];
} RSTS_MFDLABEL;
typedef struct _RSTS_PACKLABEL {
uint16 pk_mb01;
uint16 pk_mbm1;
uint16 pk_mdcn;
uint16 pk_plvl;
#define PK_LVL0 0000
#define PK_LVL11 0401
#define PK_LVL12 0402
uint16 pk_ppcs;
uint16 pk_pstat;
#define PK_UC_NEW 0020000
uint16 pk_packid[2];
uint16 pk_tapgvn[2];
uint16 pk_bckdat;
uint16 pk_bcktim;
} RSTS_PACKLABEL;
typedef union _RSTS_ROOT {
RSTS_MFDLABEL rt_mfd;
RSTS_PACKLABEL rt_pack;
uint8 rt_block[512];
} RSTS_ROOT;
typedef struct _RSTS_MFDBLOCKETTE {
uint16 mb_ulnk;
uint16 mb_mbm1;
uint16 mb_reserved1;
uint16 mb_reserved2;
uint16 mb_reserved3;
uint16 mb_malnk;
uint16 mb_lppn;
uint16 mb_lid;
#define MB_ID 0051064
} RSTS_MFDBLOCKETTE;
#define IS_VALID_RSTS_MFD(b) \
((((b)->mb_ulnk == 0) || ((b)->mb_ulnk == 1)) && \
((b)->mb_mbm1 == 0177777) && \
((b)->mb_reserved1 == 0) && \
((b)->mb_reserved2 == 0) && \
((b)->mb_reserved3 == 0) && \
((b)->mb_lppn == 0177777) && \
((b)->mb_lid == MB_ID))
typedef struct _RSTS_GFDBLOCKETTE {
uint16 gb_ulnk;
uint16 gb_mbm1;
uint16 gb_reserved1;
uint16 gb_reserved2;
uint16 gb_reserved3;
uint16 gb_reserved4;
uint16 gb_lppn;
uint16 gb_lid;
#define GB_ID 0026264
} RSTS_GFDBLOCKETTE;
#define IS_VALID_RSTS_GFD(b, g) \
((((b)->gb_ulnk == 0) || ((b)->gb_ulnk == 1)) && \
((b)->gb_mbm1 == 0177777) && \
((b)->gb_reserved1 == 0) && \
((b)->gb_reserved2 == 0) && \
((b)->gb_reserved3 == 0) && \
((b)->gb_reserved4 == 0) && \
((b)->gb_lppn == (((g) << 8) | 0377)) && \
((b)->gb_lid == GB_ID))
typedef struct _RSTS_UFDBLOCKETTE {
uint16 ub_ulnk;
uint16 ub_mbm1;
uint16 ub_reserved1;
uint16 ub_reserved2;
uint16 ub_reserved3;
uint16 ub_reserved4;
uint16 ub_lppn;
uint16 ub_lid;
#define UB_ID 0102064
} RSTS_UFDBLOCKETTE;
#define IS_VALID_RSTS_UFD(b, g, u) \
(((b)->ub_mbm1 == 0177777) && \
((b)->ub_reserved1 == 0) && \
((b)->ub_reserved2 == 0) && \
((b)->ub_reserved3 == 0) && \
((b)->ub_reserved4 == 0) && \
((b)->ub_lppn == (((g) << 8) | (u))) && \
((b)->ub_lid == UB_ID))
typedef struct _RSTS_UNAME {
uint16 un_ulnk;
uint16 un_unam;
uint16 un_reserved1;
uint16 un_reserved2;
uint16 un_ustat;
uint16 un_uacnt;
uint16 un_uaa;
uint16 un_uar;
} RSTS_UNAME;
typedef struct _RSTS_FNAME {
uint16 fn_ulnk;
uint16 fn_unam[3];
uint16 fn_ustat;
uint16 fn_uacnt;
uint16 fn_uaa;
uint16 fn_uar;
} RSTS_FNAME;
typedef struct _RSTS_ACNT {
uint16 ac_ulnk;
uint16 ac_udla;
uint16 ac_usiz;
uint16 ac_udc;
uint16 ac_utc;
uint16 ac_urts[2];
uint16 ac_uclus;
} RSTS_ACNT;
typedef struct _RSTS_RETR {
uint16 rt_ulnk;
uint16 rt_uent[7];
#define RT_ENTRIES 7
} RSTS_RETR;
typedef struct _RSTS_DCMAP {
uint16 dc_clus;
#define DC_MASK 0077777
uint16 dc_map[7];
} RSTS_DCMAP;
/*
* Directory link definitions
*/
#define DL_USE 0000001
#define DL_BAD 0000002
#define DL_CHE 0000004
#define DL_CLN 0000010
#define DL_ENO 0000760
#define DL_CLO 0007000
#define DL_BLO 0170000
#define DLSH_ENO 4
#define DLSH_CLO 9
#define DLSH_BLO 12
#define BLOCKETTE_SZ (8 * sizeof(uint16))
#define MAP_OFFSET (31 * BLOCKETTE_SZ)
#define SATT0 0073374
#define SATT1 0076400
#define SATT2 0075273
#pragma pack(pop)
typedef struct _rstsContext {
UNIT *uptr;
int dcshift;
int pcs;
char packid[8];
t_seccnt sects;
RSTS_DCMAP map;
} rstsContext;
static char rad50[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$.%0123456789";
static void r50Asc(uint16 val, char *buf)
{
buf[2] = rad50[val % 050];
val /= 050;
buf[1] = rad50[val % 050];
buf[0] = rad50[val / 050];
}
static t_stat rstsReadBlock(rstsContext *context, uint16 cluster, uint16 block, void *buf)
{
t_lba blk = (cluster << context->dcshift) + block;
t_seccnt sects_read;
if ((sim_disk_rdsect(context->uptr, blk * context->sects, (uint8 *)buf, &sects_read, context->sects) == SCPE_OK) &&
(sects_read == context->sects))
return SCPE_OK;
return SCPE_IOERR;
}
static t_stat rstsReadBlockette(rstsContext *context, uint16 link, void *buf)
{
uint16 block = (link & DL_BLO) >> DLSH_BLO;
uint16 dcn = (link & DL_CLO) >> DLSH_CLO;
uint16 blockette = (link & DL_ENO) >> DLSH_ENO;
uint8 temp[512];
if ((dcn != 7) && (blockette != 31) &&
(block <= (context->map.dc_clus & DC_MASK))) {
if (rstsReadBlock(context, context->map.dc_map[dcn], block, temp) == SCPE_OK) {
memcpy(buf, &temp[blockette * BLOCKETTE_SZ], BLOCKETTE_SZ);
return SCPE_OK;
}
}
return SCPE_IOERR;
}
static t_stat rstsFind01UFD(rstsContext *context, uint16 *ufd, uint16 *level)
{
uint16 dcs = 1 << context->dcshift;
RSTS_ROOT root;
uint16 buf[256];
if (rstsReadBlock(context, 1, 0, &root) == SCPE_OK) {
/*
* First validate fields which are common to both the MFD label and
* Pack label - we'll use Pack label offsets here.
*/
if ((root.rt_pack.pk_mbm1 == 0177777) && (root.rt_pack.pk_ppcs >= dcs)) {
char ch, *tmp = &context->packid[1];
uint16 mfd, gfd;
context->pcs = root.rt_pack.pk_ppcs;
r50Asc(root.rt_pack.pk_packid[0], &context->packid[0]);
r50Asc(root.rt_pack.pk_packid[1], &context->packid[3]);
context->packid[6] = '\0';
/*
* The Pack ID must consist of 1 - 6 alphanumeric characters
* padded at the end with spaces.
*/
if (!isalnum(context->packid[0]))
return SCPE_IOERR;
while ((ch = *tmp++) != 0) {
if (!isalnum(ch)) {
if (ch != ' ')
return SCPE_IOERR;
while (*tmp)
if (*tmp++ != ' ')
return SCPE_IOERR;
break;
}
}
/*
* Determine the pack revision level and, therefore, the path to
* [0,1]satt.sys which will allow us to determine the size of the
* pack used by RSTS.
*/
if ((root.rt_pack.pk_pstat & PK_UC_NEW) == 0) {
uint16 link = root.rt_mfd.ml_ulnk;
RSTS_UNAME uname;
/*
* Old format used by RSTS up through V07.x
*/
if (dcs > 16)
return SCPE_IOERR;
*level = PK_LVL0;
memcpy(&context->map, &root.rt_block[MAP_OFFSET], BLOCKETTE_SZ);
/*
* Scan the MFD name entries looking for [0,1]. Note there will
* always be at least 1 entry.
*/
do {
if (rstsReadBlockette(context, link, &uname) != SCPE_OK)
break;
if (uname.un_unam == ((0 << 8) | 1)) {
*ufd = uname.un_uar;
return SCPE_OK;
}
} while ((link = uname.un_ulnk) != 0);
}
else {
/*
* New format used by RSTS V08 and later
*/
switch (root.rt_pack.pk_plvl) {
case PK_LVL11:
if (dcs > 16)
return SCPE_IOERR;
break;
case PK_LVL12:
if (dcs > 64)
return SCPE_IOERR;
break;
default:
return SCPE_IOERR;
}
*level = root.rt_pack.pk_plvl;
mfd = root.rt_pack.pk_mdcn;
if (rstsReadBlock(context, mfd, 0, buf) == SCPE_OK) {
if (IS_VALID_RSTS_MFD((RSTS_MFDBLOCKETTE *)buf)) {
if (rstsReadBlock(context, mfd, 1, buf) == SCPE_OK)
if ((gfd = buf[0]) != 0)
if (rstsReadBlock(context, gfd, 0, buf) == SCPE_OK)
if (IS_VALID_RSTS_GFD((RSTS_GFDBLOCKETTE *)buf, 0)) {
if (rstsReadBlock(context, gfd, 1, buf) == SCPE_OK)
if ((*ufd = buf[1]) != 0)
return SCPE_OK;
}
}
}
}
}
}
return SCPE_IOERR;
}
static t_stat rstsLoadAndScanSATT(rstsContext *context, uint16 uaa, uint16 uar, t_offset *result)
{
t_offset blocks = 0;
uint8 bitmap[8192];
int i, j;
RSTS_ACNT acnt;
RSTS_RETR retr;
if (uar != 0) {
if (rstsReadBlockette(context, uaa, &acnt) == SCPE_OK) {
uint16 blocks = acnt.ac_usiz;
uint16 offset = 0;
memset(bitmap, 0xFF, sizeof(bitmap));
if (blocks != 0) {
do {
int i, j;
uint16 fcl;
if (rstsReadBlockette(context, uar, &retr) != SCPE_OK)
return SCPE_IOERR;
for (i = 0; i < RT_ENTRIES; i++) {
if ((fcl = retr.rt_uent[i]) == 0)
goto scanBitmap;
for (j = 0; j < acnt.ac_uclus; j++) {
if ((blocks == 0) || (offset >= sizeof(bitmap)))
goto scanBitmap;
if (rstsReadBlock(context, fcl, j, &bitmap[offset]) != SCPE_OK)
return SCPE_IOERR;
offset += 512;
blocks--;
}
}
} while ((uar = retr.rt_ulnk) != 0);
scanBitmap:
for (i = sizeof(bitmap) - 1; i != 0; i--)
if (bitmap[i] != 0xFF) {
blocks = i * 8;
for (j = 7; j >= 0; j--)
if ((bitmap[i] & (1 << j)) == 0) {
blocks += j + 1;
goto scanDone;
}
}
scanDone:
*result = (blocks + 1) * context->pcs;
return SCPE_OK;
}
}
}
return SCPE_IOERR;
}
static t_offset get_rsts_filesystem_size (UNIT *uptr)
{
DEVICE *dptr;
t_addr saved_capac;
struct disk_context *ctx = (struct disk_context *)uptr->disk_ctx;
t_addr temp_capac = (sim_toffset_64 ? (t_addr)0xFFFFFFFFu : (t_addr)0x7FFFFFFFu); /* Make sure we can access the largest sector */
uint8 buf[512];
t_offset ret_val = (t_offset)-1;
rstsContext context;
if ((dptr = find_dev_from_unit (uptr)) == NULL)
return ret_val;
saved_capac = uptr->capac;
uptr->capac = temp_capac;
context.uptr = uptr;
context.sects = 512 / ctx->sector_size;
/*
* Check all possible device cluster sizes
*/
for (context.dcshift = 0; context.dcshift < 8; context.dcshift++) {
uint16 ufd, level;
/*
* We need to find [0,1]SATT.SYS to compute the actual size of the disk.
* First find the DCN of the [0,1] UFD.
*/
if (rstsFind01UFD(&context, &ufd, &level) == SCPE_OK) {
if (rstsReadBlock(&context, ufd, 0, buf) == SCPE_OK) {
if (IS_VALID_RSTS_UFD((RSTS_UFDBLOCKETTE *)buf, 0, 1)) {
uint16 link = ((RSTS_UFDBLOCKETTE *)buf)->ub_ulnk;
RSTS_FNAME fname;
memcpy(&context.map, &buf[MAP_OFFSET], BLOCKETTE_SZ);
/*
* Scan the UFD looking for SATT.SYS - the allocation bitmap
*/
do {
if (rstsReadBlockette(&context, link, &fname) != SCPE_OK)
break;
if ((fname.fn_unam[0] == SATT0) &&
(fname.fn_unam[1] == SATT1) &&
(fname.fn_unam[2] == SATT2)) {
if (rstsLoadAndScanSATT(&context, fname.fn_uaa, fname.fn_uar, &ret_val) == SCPE_OK) {
const char *fmt = "???";
ret_val *= 512;
switch (level) {
case PK_LVL0:
fmt = "0.0";
break;
case PK_LVL11:
fmt = "1.1";
break;
case PK_LVL12:
fmt = "1.2";
break;
}
sim_messagef(SCPE_OK, "%s%d: '%s' Contains a RSTS File system\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_messagef(SCPE_OK, "%s%d: Pack ID: %6.6s ", sim_dname (dptr), (int)(uptr-dptr->units), context.packid);
sim_messagef(SCPE_OK, "Revision Level: %3s ", fmt);
sim_messagef(SCPE_OK, "Pack Clustersize: %d\n", context.pcs);
sim_messagef(SCPE_OK, "%s%d: Last Unallocated Sector In File System: %u\n", sim_dname (dptr), (int)(uptr-dptr->units), (uint32)(ret_val / 512));
goto cleanup_done;
}
}
} while ((link = fname.fn_ulnk) != 0);
}
}
}
}
cleanup_done:
uptr->capac = saved_capac;
return ret_val;
}
#pragma pack(push,1)
typedef struct _RT11_HomeBlock {
uint8 hb_b_bbtable[130];
@@ -1484,29 +1949,27 @@ Next_Partition:
Return_Cleanup:
if (partitions) {
if (!sim_quiet) {
const char *parttype;
const char *parttype;
switch (version) {
case HB_C_SYSVER_V3A:
parttype = "V3A";
break;
switch (version) {
case HB_C_SYSVER_V3A:
parttype = "V3A";
break;
case HB_C_SYSVER_V04:
parttype = "V04";
break;
case HB_C_SYSVER_V04:
parttype = "V04";
break;
case HB_C_SYSVER_V05:
parttype = "V05";
break;
case HB_C_SYSVER_V05:
parttype = "V05";
break;
default:
parttype = "???";
break;
}
sim_printf ("%s%d: '%s' Contains RT11 partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_printf ("%d valid partition%s, Type: %s, Sectors On Disk: %u\n", partitions, partitions == 1 ? "" : "s", parttype, (uint32)(ret_val / 512));
default:
parttype = "???";
break;
}
sim_messagef (SCPE_OK, "%s%d: '%s' Contains RT11 partitions\n", sim_dname (dptr), (int)(uptr-dptr->units), uptr->filename);
sim_messagef (SCPE_OK, "%d valid partition%s, Type: %s, Sectors On Disk: %u\n", partitions, partitions == 1 ? "" : "s", parttype, (uint32)(ret_val / 512));
}
uptr->capac = saved_capac;
return ret_val;
@@ -1520,6 +1983,7 @@ static FILESYSTEM_CHECK checks[] = {
&get_ods2_filesystem_size,
&get_ods1_filesystem_size,
&get_ultrix_filesystem_size,
&get_rsts_filesystem_size,
&get_rt11_filesystem_size, /* This should be the last entry
in the table to reduce the
possibility of matching an RT-11
@@ -2129,19 +2593,36 @@ fprintf (st, "was created. This metadata is therefore available whenever that V
fprintf (st, "attached to an emulated disk device in the future so the device type and\n");
fprintf (st, "size can be automatically be configured.\n\n");
if (0 == (uptr-dptr->units)) {
if (dptr->numunits > 1) {
uint32 i;
if (dptr->numunits > 1) {
uint32 i, attachable_count = 0, out_count = 0, skip_count;
for (i=0; i < dptr->numunits; ++i)
if (dptr->units[i].flags & UNIT_ATTABLE)
fprintf (st, " sim> ATTACH {switches} %s%d diskfile\n", dptr->name, i);
for (i=0; i < dptr->numunits; ++i)
if ((dptr->units[i].flags & UNIT_ATTABLE) &&
!(dptr->units[i].flags & UNIT_DIS))
++attachable_count;
for (i=0; (i < dptr->numunits) && (out_count < 2); ++i)
if ((dptr->units[i].flags & UNIT_ATTABLE) &&
!(dptr->units[i].flags & UNIT_DIS)) {
fprintf (st, " sim> ATTACH {switches} %s%d diskfile\n", dptr->name, i);
++out_count;
}
if (attachable_count > 4) {
fprintf (st, " .\n");
fprintf (st, " .\n");
fprintf (st, " .\n");
}
else
fprintf (st, " sim> ATTACH {switches} %s diskfile\n", dptr->name);
skip_count = attachable_count - 2;
for (i=0; i < dptr->numunits; ++i)
if ((dptr->units[i].flags & UNIT_ATTABLE) &&
!(dptr->units[i].flags & UNIT_DIS)) {
if (skip_count == 0)
fprintf (st, " sim> ATTACH {switches} %s%d diskfile\n", dptr->name, i);
else
--skip_count;
}
}
else
fprintf (st, " sim> ATTACH {switches} %s diskfile\n\n", dptr->name);
fprintf (st, " sim> ATTACH {switches} %s diskfile\n", dptr->name);
fprintf (st, "\n%s attach command switches\n", dptr->name);
fprintf (st, " -R Attach Read Only.\n");
fprintf (st, " -E Must Exist (if not specified an attempt to create the indicated\n");
@@ -2183,9 +2664,7 @@ fprintf (st, " sim> att rq2 -f vhd RA92.vhd\n");
fprintf (st, " RQ2: creating new file\n");
fprintf (st, " sim> sho rq2\n");
fprintf (st, " RQ2, 1505MB, attached to RA92.vhd, write enabled, RA92, autosize, VHD format\n");
fprintf (st, " sim> ! dir RA92.vhd\n");
fprintf (st, " Volume in drive H is New Volume\n");
fprintf (st, " Volume Serial Number is F8DE-510C\n\n");
fprintf (st, " sim> dir RA92.vhd\n");
fprintf (st, " Directory of H:\\Data\n\n");
fprintf (st, " 04/14/2011 12:57 PM 5,120 RA92.vhd\n");
fprintf (st, " 1 File(s) 5,120 bytes\n");
@@ -2196,9 +2675,7 @@ fprintf (st, " RQ3: Copied 1505MB. 99%% complete.\n");
fprintf (st, " RQ3: Copied 1505MB. Done.\n");
fprintf (st, " sim> sh rq3\n");
fprintf (st, " RQ3, 1505MB, attached to RA92-1.vhd, write enabled, RA92, autosize, VHD format\n");
fprintf (st, " sim> ! dir RA92*\n");
fprintf (st, " Volume in drive H is New Volume\n");
fprintf (st, " Volume Serial Number is F8DE-510C\n\n");
fprintf (st, " sim> dir RA92*\n");
fprintf (st, " Directory of H:\\Data\n\n");
fprintf (st, " 04/14/2011 01:12 PM 5,120 RA92-1.vhd\n");
fprintf (st, " 04/14/2011 12:58 PM 5,120 RA92.vhd\n");

View File

@@ -48,6 +48,14 @@
#include ".git-commit-id.h"
#endif
/*
Simh's git commit id would be undefined when working with an
extracted archive (zip file or tar ball). To address this
problem and record the commit id that the archive was created
from, the archive creation process populates the below
information as a consequence of the "sim_rev.h export-subst"
line in the .gitattributes file.
*/
#if !defined(SIM_GIT_COMMIT_ID)
#define SIM_GIT_COMMIT_ID $Format:%H$
#define SIM_GIT_COMMIT_TIME $Format:%aI$

View File

@@ -37,6 +37,10 @@ t_bool vid_mouse_b1 = FALSE;
t_bool vid_mouse_b2 = FALSE;
t_bool vid_mouse_b3 = FALSE;
static VID_QUIT_CALLBACK vid_quit_callback = NULL;
static VID_GAMEPAD_CALLBACK motion_callback[10];
static VID_GAMEPAD_CALLBACK button_callback[10];
static int vid_gamepad_inited = 0;
static int vid_gamepad_ok = 0; /* Or else just joysticks. */
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback)
{
@@ -44,6 +48,41 @@ vid_quit_callback = callback;
return SCPE_OK;
}
static t_stat register_callback (void **array, int n, void *callback)
{
int i, j = -1;
if (!vid_gamepad_inited) {
return SCPE_NOATT;
}
for (i = 0; i < n; i++) {
if (array[i] == callback)
return SCPE_ALATT;
if (array[i] == NULL)
j = i;
}
if (j != -1) {
array[j] = callback;
return SCPE_OK;
}
return SCPE_NXM;
}
t_stat vid_register_gamepad_motion_callback (VID_GAMEPAD_CALLBACK callback)
{
int n = sizeof (motion_callback) / sizeof (callback);
return register_callback ((void **)motion_callback, n, (void *)callback);
}
t_stat vid_register_gamepad_button_callback (VID_GAMEPAD_CALLBACK callback)
{
int n = sizeof (button_callback) / sizeof (callback);
return register_callback ((void **)button_callback, n, (void *)callback);
}
t_stat vid_show (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{
return vid_show_video (st, uptr, val, desc);
@@ -510,6 +549,64 @@ return SCPE_OK;
}
#endif
static t_stat vid_init_controllers (void)
{
SDL_Joystick *y;
SDL_version ver;
int i, n;
if (vid_gamepad_inited)
return SCPE_OK;
/* Chech that the SDL_GameControllerFromInstanceID function is
available at run time. */
SDL_GetVersion(&ver);
vid_gamepad_ok = (ver.major > 2 ||
(ver.major == 2 && (ver.minor > 0 || ver.patch >= 4)));
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
if (vid_gamepad_ok)
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
if (SDL_JoystickEventState (SDL_ENABLE) < 0) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
return SCPE_IOERR;
}
if (vid_gamepad_ok && SDL_GameControllerEventState (SDL_ENABLE) < 0) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
return SCPE_IOERR;
}
n = SDL_NumJoysticks();
for (i = 0; i < n; i++) {
if (vid_gamepad_ok && SDL_IsGameController (i)) {
SDL_GameController *x = SDL_GameControllerOpen (i);
if (x != NULL) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Game controller: %s\n", SDL_GameControllerNameForIndex(i));
}
}
else {
y = SDL_JoystickOpen (i);
if (y != NULL) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Joystick: %s\n", SDL_JoystickNameForIndex(i));
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Number of axes: %d, buttons: %d\n",
SDL_JoystickNumAxes(y),
SDL_JoystickNumButtons(y));
}
}
}
vid_gamepad_inited = 1;
return SCPE_OK;
}
t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags)
{
if (!vid_active) {
@@ -538,10 +635,18 @@ if (!vid_active) {
vid_dev = dptr;
memset (motion_callback, 0, sizeof motion_callback);
memset (button_callback, 0, sizeof button_callback);
stat = vid_create_window ();
if (stat != SCPE_OK)
return stat;
if (vid_init_controllers () != SCPE_OK) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"vid_open() - Failed initializing game controllers\n");
}
sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n");
}
return SCPE_OK;
@@ -553,6 +658,12 @@ if (vid_active) {
SDL_Event user_event;
int status;
vid_gamepad_inited = 0;
memset (motion_callback, 0, sizeof motion_callback);
memset (button_callback, 0, sizeof button_callback);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
vid_active = FALSE;
if (vid_ready) {
sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n");
@@ -1149,6 +1260,61 @@ switch (key) {
}
}
void vid_joy_motion (SDL_JoyAxisEvent *event)
{
int n = sizeof motion_callback / sizeof (VID_GAMEPAD_CALLBACK);
int i;
for (i = 0; i < n; i++) {
if (motion_callback[i]) {
motion_callback[i](event->which, event->axis, event->value);
}
}
}
void vid_joy_button (SDL_JoyButtonEvent *event)
{
int n = sizeof button_callback / sizeof (VID_GAMEPAD_CALLBACK);
int i;
for (i = 0; i < n; i++) {
if (button_callback[i]) {
button_callback[i](event->which, event->button, event->state);
}
}
}
void vid_controller_motion (SDL_ControllerAxisEvent *event)
{
SDL_JoyAxisEvent e;
e.which = event->which;
e.axis = event->axis;
e.value = event->value;
vid_joy_motion (&e);
}
void vid_controller_button (SDL_ControllerButtonEvent *event)
{
/* SDL_GameControllerFromInstanceID is only available from SDL
version 2.0.4, so check the version at compile time. The
version is also checked at run time. */
#if (SDL_MAJOR_VERSION > 2) || (SDL_MAJOR_VERSION == 2 && \
(SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 4))
SDL_JoyButtonEvent e;
SDL_GameControllerButtonBind b;
SDL_GameController *c;
SDL_GameControllerButton button = (SDL_GameControllerButton)event->button;
c = SDL_GameControllerFromInstanceID (event->which);
b = SDL_GameControllerGetBindForButton (c, button);
e.which = event->which;
e.button = b.value.button;
e.state = event->state;
vid_joy_button (&e);
#endif
}
void vid_key (SDL_KeyboardEvent *event)
{
SIM_KEY_EVENT ev;
@@ -1691,17 +1857,36 @@ while (vid_active) {
case SDL_KEYDOWN:
case SDL_KEYUP:
vid_key ((SDL_KeyboardEvent*)&event);
vid_key (&event.key);
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
vid_mouse_button ((SDL_MouseButtonEvent*)&event);
vid_mouse_button (&event.button);
break;
case SDL_MOUSEMOTION:
vid_mouse_move ((SDL_MouseMotionEvent*)&event);
vid_mouse_move (&event.motion);
break;
case SDL_JOYAXISMOTION:
vid_joy_motion (&event.jaxis);
break;
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
vid_joy_button (&event.jbutton);
break;
case SDL_CONTROLLERAXISMOTION:
vid_controller_motion (&event.caxis);
break;
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERBUTTONDOWN:
vid_controller_button (&event.cbutton);
break;
#if SDL_MAJOR_VERSION != 1
case SDL_WINDOWEVENT:
if (event.window.windowID == vid_windowID) {

View File

@@ -180,6 +180,9 @@ t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, i
/* code responsible for cursor display in video) */
typedef void (*VID_QUIT_CALLBACK)(void);
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback);
typedef void (*VID_GAMEPAD_CALLBACK)(int, int, int);
t_stat vid_register_gamepad_motion_callback (VID_GAMEPAD_CALLBACK);
t_stat vid_register_gamepad_button_callback (VID_GAMEPAD_CALLBACK);
t_stat vid_close (void);
t_stat vid_poll_kb (SIM_KEY_EVENT *ev);
t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev);