/**************************************************************************** M5b BIOS Function Call Utility ***************************************************************************** Known bugs: ***************************************************************************** Revision History: 0.0 - 10-31-90 grh First cut. Extracted from Format.c v2.01b. */ #define signon "\nM5b BIOS Function Test Utility Vers. 0.0\n" /****************************************************************************/ #include stdio.h #include ctype.h #include io.h #include farcall.h #include b:m5zf200.h BYTE this_bnk, /* Location of our memory bank */ fbuf[1024], /* Format data buffer */ sbuf[1024], /* Sector buffer */ *fdptr, *bytptr, *temp_p, /* Temporary ptr */ *cbptr; /* Ptr to command block array elements */ char *gets(), /* Tell cc that this is a char ptr */ *toupper(), *cptr, /* User command text ptr */ tbuf[80]; /* Input buffer */ WORD a, n_ents, /* Number of format track table entries */ *fmt_tblp, /* Format table ptr */ *trk_fmtp, /* Track format data ptr */ fmt_len; /* Length of format table */ int i, d, j, temp, c; unsigned int utemp, cnt; FILE *infile, *fopen(); /* IOPB definitions */ struct cb { /* Arguments */ BYTE pb_cmd; /* command */ BYTE pb_drv; /* drive */ WORD pb_trk; /* track */ WORD pb_sec; /* sector */ BYTE pb_flags; /* flags */ WORD pb_dma; /* Unused dma address */ BYTE pb_dmax;/* Unused dma extended address */ /* Argument in, Return value out */ WORD pb_bcnt; /* Xfer count */ /* Return values */ BYTE pb_sts; /* Command result status */ BYTE pb_st1; /* fdc status if pb_mod == 0x1f */ BYTE pb_st2; /* returned value #1 */ BYTE pb_st3; /* returned value #2 */ } cmd_blk, liopb; #define pb_fnskb 0x01 /* Inhibit implied seek flag mask */ #define pb_fmtd 0x20 /* Format drive option */ #define pb_inhx 0x40 /* Inhibit data xfer to host flag mask */ #define pb_fnrb 0x80 /* Inhibit retries flag mask */ /* Format overlay header data */ struct { WORD fov_txt; /* Text ptr */ WORD fov_tsz; /* Byte count of text */ WORD fov_idp; /* ID Sector image ptr */ WORD fov_ids; /* ID Sector byte count */ WORD fov_fmt; /* Format table ptr */ WORD fov_fsz; /* Format section byte count */ WORD fov_prt; /* Controller port # */ } *fmt_buf, /* Ptr to the structure */ *fov_p; /* Format overlay file data ptrs */ struct { BYTE fil_name[11]; /* FCB filename */ char fil_txt[]; /* File text description */ } *fov_file, /* Base ptr to array */ *fov_ptr[64]; /* Ptrs to each file data */ BYTE *file_bp; /* Ptr into array */ unsigned int max_files; /* max files found */ /* CP/M File Control Block */ struct fcb *srch_fst(), *srch_nxt(), f_cb, *fcb_ptr; /* farcall registers */ struct regs cpui, cpuo; /**************************************************************************** main program ****************************************************************************/ main () { /* Display signon */ printf(signon); /* Initialize data */ cpui.AF = (MF_GBNK) << 8; /* get current bank # */ farcall( (WORD) MR_FUN, 0, &cpui, &cpui); this_bnk = cpui.AF >> 8; /* drive = -1; Assume no controller */ cmd_blk.pb_sts = -1; /* Force error if not accessed */ /* Allocate heap buffer */ file_bp = fov_file = malloc(7000); /* Allocate Filename buffer */ if (fov_file == 0) { puts("\nInsufficient Memory...Aborting!"); exit(1); } (BYTE *) fmt_buf = ((BYTE *) fov_file) + 5976; /* Allocate format overlay buffer */ /* Top of command loop */ while (TRUE) { /**** Display Options */ printf("\n\n\ Command Options:\n\ 0 Display BIOS Version\n\ 1 Display monitor drive number assigned to CP/M drive\n\ 2 Disable dynamic format selection (LOGON)\n\ 3 Enable dynamic format selection\n\ 4 Set disk format\n\ \n\ ^C Exit to DOS\n\ \n\ Enter Command # - "); /**** Fetch command */ gets(tbuf); switch (tbuf[0]) { case '0': /* display BIOS version */ cpui.AF = 0; if (bf_exec() < 0) break; printf("\nBIOS Version = %d.%2d\n", cpui.HL / 100, cpui.HL % 100); break; case '1': /* display monitor drive # */ if ( (cpui.BC = get_drv()) < 0) break; cpui.AF = 1 << 8; if (bf_exec() < 0 ) break; printf("\nMonitor Drive for this CP/M drive = %u\n", cpui.AF >> 8); break; case '2': /* disable logon */ if ( (cpui.BC = get_drv()) < 0) break; cpui.AF = 2 << 8; bf_exec(); break; case '3': /* enable logon */ if ( (cpui.BC = get_drv()) < 0) break; cpui.AF = 3 << 8; bf_exec(); break; case '4': /* set disk format */ /******* Request drive for overlays */ f_cb.f_driv = 0; /* assume default */ printf("\n\ Enter drive letter containing format database files {A..P} - "); gets(tbuf); if ( *tbuf != '\0') f_cb.f_driv = ( toupper( *tbuf) - 'A' + 1); /******* Read directory */ for (i = 0, cptr = &f_cb.f_name[0]; i < 8; i++) *cptr++ = '?'; *cptr++ = 'F'; *cptr++ = 'O'; *cptr = 'V'; fcb_ptr = srch_fst(); if (fcb_ptr == -1) { printf("\nNo Format Overlays Found... Aborting!"); exit(1); } for (i = 0; i < 64 && fcb_ptr != -1; i++, file_bp += 11) { movmem( ((BYTE *) fcb_ptr) + 1, file_bp, 11); fov_ptr[i] = file_bp; fcb_ptr = srch_nxt(); } max_files = i; if (i < 63) fov_ptr[i] = -1; for (i = 0; i < max_files; i++ ) { if ( get_fov( &f_cb, fov_ptr[i] ) != 0) { printf("\nOverlay read error... aborting!"); exit(1); } /********** Insert text */ cnt = fmt_buf -> fov_tsz; file_bp = ((BYTE *) fov_ptr[i]) + 11; movmem( file_bp, &file_bp[cnt], 5975 - cnt - (file_bp - ((BYTE *) fov_file) ) ); bytptr = fmt_buf; movmem( &bytptr[fmt_buf -> fov_txt], file_bp, cnt); /********** Adjust ptrs */ for (j = i + 1; j < max_files; j++) { fov_ptr[j] = ((BYTE *) fov_ptr[j]) + cnt; } } /******* Sort the files */ for (d = TRUE; d == TRUE; ) { d = FALSE; /* Assume sorted */ for (i = 0; i < (max_files - 1); i++) { temp = strncmp( fov_ptr[i], fov_ptr[i+1], 8); /* Test for sort */ if (temp > 0) { /* If larger first then swap */ utemp = fov_ptr[i]; fov_ptr[i] = fov_ptr[i+1]; fov_ptr[i+1] = utemp; d = TRUE; /* Set changed flag */ } } } /******* Display formats */ for (i = j = 0; i < max_files; i++, j++) { if (j == 0) printf("\n\033E\ -------------------------- Format Directory ----------------------------"); if (j == 20) { printf("\n\n\ Space for additional, '-' to back up, # to select - "); c = getchar(); if (c == '-') { j -= 20; i -= 20; } else if (c == ' ') { j = 0; } else { ungetc( c, "stdin"); break; } } printf("\n%2d: ", i + 1); for (d = 0, cptr = &fov_ptr[i] -> fil_name; d < 8; d++, cptr++) { if (*cptr == '\0') putchar(' '); else putchar(*cptr); } printf(" - %s", &fov_ptr[i] -> fil_txt ); } printf("\nEnter selection - "); gets(tbuf); temp = atoi(tbuf); /******* Got selection, read format overlay */ if (get_fov(&f_cb, fov_ptr[temp - 1 ]) != 0) { printf("Cannot read overlay...aborting!"); exit(1); } /******* Transfer ID sector data to sector buffer */ setmem(&sbuf, 1024, 0); fdptr = fmt_buf; cnt = fmt_buf -> fov_idp; if ((fmt_buf -> fov_ids) > 1024) { printf("\nFormat ID sector data size error:(%d)! Aborting!", fmt_buf -> fov_ids); break; } movmem(&fdptr[cnt], sbuf, fmt_buf -> fov_ids); /******* Set function arguments */ cpui.BC = get_drv(); /* drive # */ cpui.DE = this_bnk; cpui.HL = &sbuf; /* ID sector buffer */ cpui.AF = 4 << 8; printf("\nID at %04x", &sbuf); temp = bf_exec(); if (temp != 0 && temp > 0) printf("\nError - %x", temp); break; /******* Unrecognized command */ default: printf("Command Not Implemented! Try again."); break; } } /* Done. */ exit(0); } /**************************************************************************** Get format overlay into buffer Entry - arg1= ptr to fcb to use arg2= ptr to filename from directory Returns 0: ok, /0: error ****************************************************************************/ int get_fov(f_cb, fnp) struct fcb *f_cb; BYTE *fnp; { int i, rv; BYTE *bp; /* Insert file name */ movmem(fnp, f_cb -> f_name, 11); /* Init fcb */ f_cb->f_ext = f_cb->f_resv[0] = f_cb->f_resv[1] = f_cb->f_rc = f_cb->f_cr = 0; /* Open the fcb */ rv = bdos(OPNFIL, f_cb); if (rv == 0xff) return rv; /* Read the file */ for (bp = fmt_buf, rv = 0, i = 1024; i > 0 && rv == 0; i -= 128, bp += 128 ) { bdos( SETDMA, bp); rv = bdos( READSQ, f_cb); } return 0; } /**************************************************************************** Get the CP/M drive from user exit - -1: abort 0..15: drive number = A..P ****************************************************************************/ get_drv() { /* Stay in loop until valid data given */ while (TRUE) { /**** Request drive data */ printf("\nEnter CP/M Drive {A..P} (X: abort) - "); gets(tbuf); tbuf[0] = toupper(tbuf[0]); /**** If abort requested then return -1 */ if (tbuf[0] == 'X') return -1; /**** Else if valid drive letter then return it's numeric value */ if (tbuf[0] >= 'A' && tbuf[0] <= 'P') return tbuf[0] - 'A'; /**** Else display error message & try again */ printf("\nDrive must be A..P! Try again!\n"); } } /**************************************************************************** Dump the fcb file data Assumes f_cb has proper name ****************************************************************************/ dmp_fcb(f_cb) struct fcb *f_cb; { int i; char *cp; printf("\n%2x ", f_cb -> f_driv ); for (i = 0, cp = &f_cb -> f_name; i < 8; i++, cp++ ) { if (*cp == '\0') putchar(' '); else putchar(*cp); } putchar('.'); for ( ; i < 11; i++, cp++ ) { if (*cp == '\0') putchar(' '); else putchar(*cp); } } /**************************************************************************** Search for 1st directory match Assumes f_cb has proper search name Returns ptr to directory fcb data (-1 = not found) ****************************************************************************/ struct fcb *srch_fst() { int r; /* Set buffer ptr to directory segment */ bdos( SETDMA, Wrkbuf); /* Search the directory */ r = bdos( SRCHFL, &f_cb); return (r < 4) ? (Wrkbuf + (r << 5 )) : -1; } /**************************************************************************** Search for next directory match Assumes f_cb has proper search name Returns ptr to directory fcb data (-1 = not found) ****************************************************************************/ struct fcb *srch_nxt() { int r; /* Set buffer ptr to directory segment */ bdos( SETDMA, Wrkbuf); /* Search the directory */ r = bdos( SRCHNX, &f_cb); return (r < 4) ? (Wrkbuf + (r << 5 )) : -1; } /**************************************************************************** Execute the BIOS function exit - TRUE: abort FALSE: no error any_other: error ****************************************************************************/ int bf_exec() { int i; /* Execute the command */ farcall( (WORD) 0x0028, this_bnk, &cpui, &cpui); /* if error then display it */ switch (cpui.AF >> 8) { case 255: printf("Illegal Function!"); return -1; case 254: printf("Argument Out of Range Error!"); return -2; default: return cpui.AF >> 8; break; } } /**************************************************************************** Dump command block ****************************************************************************/ dmp_cdb() { cpui.AF = (MF_DIOB) << 8; cpui.DE = this_bnk; cpui.HL = &cmd_blk; farcall( (WORD) MR_FUN, this_bnk, &cpui, &cpui); }