/**************************************************************************** Intelligent Sasi Host Adapter (ISHA) controller test/exercisor program ***************************************************************************** Revisions: 1.00 - 11-2-88 grh Convert from V2.00 of JDD.C exerciser. ****************************************************************************/ #define SIGNON "\nISHA Monitor/Controller Exercisor Vers. 1.00a\n" #include stdio.h #include ctype.h #define BYTE unsigned char #define WORD unsigned int #define DIAG FALSE /* Turn off execution code */ #define n_args 8 /* Max number of command args */ #define IDATA 0xd9 /* ISHA data port */ #define ICMD 0xd8 /* ISHA command port */ #define ISTAT 0xd8 /* ISHA status port */ /**************************************************************************** Local global vars ****************************************************************************/ char *cptr, /* module global text ptr */ tbuf[80]; /* Input buffer */ BYTE *sbuf, /* ptr to sector buffer dynamically allocated */ *memtop; /* ptr to last byte of buffer */ WORD arg[ n_args + 1 ]; /* storage for command arguments */ int hexfile; /* 'HEX' keyword found for file I/O */ FILE *filekey; /**************************************************************************** Function templates ****************************************************************************/ char CI(), /* Console input */ *gets(), /* Tell cc this is a char ptr */ *uc_gets(), *skip(), *ret_siz(); BYTE xwait(), execute_i(); WORD ret_cmd(), str_size(), get_n_args(), scan_hex(); FILE *fopen(); /**************************************************************************** Structure declarations ****************************************************************************/ /* I/O Parameter Block (IOPB) declaration */ struct iopb_struct{ BYTE pb_cmd, /* command */ pb_drv; /* drive */ WORD pb_trk, /* track */ pb_sec; /* sector */ BYTE pb_flg; /* flags */ WORD pb_dma; /* Unused dma address */ BYTE pb_dmax;/* Unused dma extended address */ WORD pb_bcnt; /* Byte count to xfer */ BYTE pb_stat, /* Controller status */ pb_st1, /* fdc status if dd_mod == 0x1f */ pb_st2, /* returned value #1 */ pb_st3; /* returned value #2 */ } iopb; /* SASI Command Descriptor Block (CDB) declaration */ struct { BYTE cmd, /* command */ lun, /* logical unit number */ la1, /* logical address 1 */ la0, /* logical address 0 */ blk_cnt, /* block count */ ctrl; /* control byte */ } cdb; /* Disk descriptor sector physical data declarations */ struct d { BYTE flags, spt0, ssz0, spt1, ssz1, sptd, sszd, type; WORD cyls; BYTE heads; WORD rwcc; BYTE pcm, pch, ecc, cntl; }; struct v { WORD hd_eng, /* Head engage time */ step, /* Step interval */ tls, /* Time after last step */ mo_dly; /* Motor on delay */ }; /**************************************************************************** main program ****************************************************************************/ main () { static WORD temp, /* temporary storage */ i; /* counter */ /* Display signon and prompt user with command list */ puts(SIGNON); help(); /* Initialize data buffer */ sbuf = malloc(8192); memtop = (*((BYTE *) 0x6) - 2048) & 0xff00; crlf(); puthxw(memtop - sbuf); puts(" byte buffer size."); /* Do forever (almost) */ while (TRUE) { /**** Prompt user for command */ crlf(); CO('-'); /**** Get user option */ uc_gets(cptr = tbuf); temp = ret_cmd(cptr); /**** Pre-position to possible argument */ nxt_field(); /**** Execute option */ switch (temp) { /*------------------------------------------------------------------------- H Display help message -------------------------------------------------------------------------*/ case 1: help(); break; /*------------------------------------------------------------------------- EX Exit to DOS -------------------------------------------------------------------------*/ case 2: exit(0); break; /*------------------------------------------------------------------------- DB 1st last Dump the sector buffer -------------------------------------------------------------------------*/ case 3: /******* Fetch & test user args */ if ((temp = get_n_args(2)) < 1) { invargs(); break; } /******* Set defaults */ if (temp < 2) arg[2] = arg[1] + 127; /******* Process */ for ( ; arg[1] <= arg[2] && CIS() == 0; arg[1] += 16) { crlf(); puthxw(arg[1]); puts(" : "); dump_16( &sbuf[ arg[1]], ((arg[2] - arg[1]) >= 16) ? 16 : (arg[2] - arg[1] + 1) ); } /******* Dump any abort character */ if (CIS()) CI(); break; /*------------------------------------------------------------------------- DC Display CDB -------------------------------------------------------------------------*/ case 4: /******* Process */ puts("\nCommand = "); puthxb(cdb.cmd); puts("\nLUN = "); puthxb(cdb.lun); puts("\nLA1 = "); puthxb(cdb.la1); puts("\nLA0 = "); puthxb(cdb.la0); puts("\nBlk Cnt = "); puthxb(cdb.blk_cnt); puts("\nControl = "); puthxb(cdb.ctrl); crlf(); break; /*------------------------------------------------------------------------- DI Dump the IOPB -------------------------------------------------------------------------*/ case 5: /******* Process */ dmp_iopb(); break; /*------------------------------------------------------------------------- FI 1st last value Fill buffer with data -------------------------------------------------------------------------*/ case 6: /******* Fetch & test user args */ if ((temp = get_n_args(3)) < 3) { invargs(); break; } if (arg[1] > arg[2]) { invargs(); break; } /******* Process */ while (arg[1] <= arg[2]) sbuf[ arg[1]++] = (BYTE) arg[3]; break; /*------------------------------------------------------------------------- MO 1st last dest Move buffer data -------------------------------------------------------------------------*/ case 7: /******* Fetch & test user args */ if ((temp = get_n_args(3)) < 3) { invargs(); break; } if (arg[1] > arg[2]) { invargs(); break; } /******* If overlap then use top down process */ if (arg[3] > arg[1] && arg[3] <= arg[2]) { arg[3] += (arg[2] - arg[1] + 1); while ( arg[1] <= arg[2]) sbuf[ arg[3]--] = sbuf[ arg[2]--]; } /******* Else bottom up process */ else { while ( arg[1] <= arg[2]) sbuf[ arg[3]++] = sbuf[ arg[1]++]; } break; /*------------------------------------------------------------------------- SU 1st Substitute buffer data -------------------------------------------------------------------------*/ case 8: /******* Fetch & test user args */ if ((temp = get_n_args(1)) < 1) { invargs(); break; } /******* Process */ for (temp = arg[1]; TRUE; temp += 1) { puthxw(temp); puts(" = "); puthxb( (BYTE) sbuf[temp]); puts(" - "); uc_gets(cptr = tbuf); if (tbuf[0] == '.') break; if (get_n_args(1) == 1) sbuf[temp] = (BYTE) arg[1]; } break; /*------------------------------------------------------------------------- LO 1st file.name Load data file into buffer -------------------------------------------------------------------------*/ case 9: /******* Fetch & test user args */ if ((temp = get_n_args(1)) < 1) { invargs(); break; } /******* Select file type */ if (strncmp(cptr, "HEX", 3) == 0) { hexfile = TRUE; nxt_field(); } else { hexfile = FALSE; } /******* Open file for reading */ filekey = fopen(cptr, "r"); if (filekey == 0) { puts("\nFile open error!\n"); break; } /******* Process */ notimp(); break; /*------------------------------------------------------------------------- SA 1st last file.name Save buffer data to file -------------------------------------------------------------------------*/ case 10: /******* Fetch & test user args */ if ((temp = get_n_args(2)) < 2) { invargs(); break; } /******* Select file type */ if (strncmp(cptr, "HEX", 3) == 0) { hexfile = TRUE; nxt_field(); } else { hexfile = FALSE; } /******* Open file for reading */ filekey = fopen(cptr, "w"); if (filekey == 0) { puts("\nFile open error!\n"); break; } /******* Process */ notimp(); break; /*------------------------------------------------------------------------- RE addr drv trk sect Read sector(s) -------------------------------------------------------------------------*/ case 11: /******* Fetch & test user args */ if ((temp = get_n_args(5)) < 4) { invargs(); break; } /******* Set defaults */ if (temp < 5) arg[5] = 1; /******* Set up iopb */ iopb.pb_cmd = 1; iopb.pb_drv = arg[2]; iopb.pb_trk = arg[3]; iopb.pb_sec = arg[4]; iopb.pb_dma = &sbuf[ arg[1]]; iopb.pb_dmax = 0; iopb.pb_flg = 0; iopb.pb_bcnt = 128; /******* Process */ for ( ; arg[5] > 0; arg[5]--) { if (execute_i( &iopb) != 0) break; } /******* Display results */ if (iopb.pb_stat != 0) { dmp_iopb(); puts("\nError!!"); } break; /*------------------------------------------------------------------------- WR addr drv trk sect Write sector(s) -------------------------------------------------------------------------*/ case 12: /******* Fetch & test user args */ if ((temp = get_n_args(5)) < 4) { invargs(); break; } /******* Set defaults */ if (temp < 5) arg[5] = 1; /******* Set up iopb */ iopb.pb_cmd = 2; iopb.pb_drv = arg[2]; iopb.pb_trk = arg[3]; iopb.pb_sec = arg[4]; iopb.pb_dma = &sbuf[ arg[1]]; iopb.pb_dmax = 0; iopb.pb_flg = 0; iopb.pb_bcnt = 128; /******* Process */ for ( ; arg[5] > 0; arg[5]--) { if (execute_i( &iopb) != 0) break; } /******* Display results */ if (iopb.pb_stat != 0) { dmp_iopb(); puts("\nError!!"); } break; /*------------------------------------------------------------------------- T Run diagnostics -------------------------------------------------------------------------*/ case 13: notimp(); break; /*------------------------------------------------------------------------- XC Execute the CDB -------------------------------------------------------------------------*/ case 14: notimp(); break; /*------------------------------------------------------------------------- XI execute the IOPB -------------------------------------------------------------------------*/ case 15: x_iopb(); break; /*------------------------------------------------------------------------- ?? Undocumented command -------------------------------------------------------------------------*/ default: /* Command error */ cmderr(); help(); break; } } } /*************************************************************************** Command error ***************************************************************************/ cmderr() { puts("\nCommand Error!\n"); } /*************************************************************************** command not implemented function ***************************************************************************/ notimp() { puts("\nThat command isn't implemented yet!\n"); } /*************************************************************************** Invalid arguments function ***************************************************************************/ invargs() { puts("\nInvalid Arguments!\n"); } /**************************************************************************** Display help message ****************************************************************************/ #define n_cmds 15 static char *cmds[n_cmds] = { /* command index */ "H Display Help messages", /* 1 */ "EX Exit to DOS", /* 2 */ "DB 1st last Display sector buffer data", /* 3 */ "DC Display CDB", /* 4 */ "DI Display IOPB data", /* 5 */ "FI 1st last value Fill buffer with value", /* 6 */ "MO 1st last dest Move buffer data", /* 7 */ "SU 1st Substitute buffer data", /* 8 */ "LO 1st file.name Load data file into buffer", /* 9 */ "SA 1st last file.name Save buffer data to file", /* 10 */ "RE addr drv trk sect Read sector(s)", /* 11 */ "WR addr drv trk sect Write sector(s)", /* 12 */ "T Execute self test", /* 13 */ "XC targt b1 b2 b3 b4 b5 b6 Execute CDB", /* 14 */ "XI Execute IOPB" /* 15 */ }; help() { register WORD i; /* counter */ puts("\nCommands:\n"); for (i = 0; i < n_cmds; i++) { puts(cmds[i]); crlf(); } } /**************************************************************************** Return command index function exit - 0: Command not found in table /0: command index {1..n} ****************************************************************************/ WORD ret_cmd(text) char *text; /* ptr to potential command text */ { register WORD i; /* command counter */ for (i = 0; i < n_cmds; i++) { if (strncmp(text, cmds[i], str_size( cmds[i])) == 0) return i + 1; } return 0; } /**************************************************************************** return size of null terminated character string function returns number of non-space chars in string, not counting the '\0' char. ****************************************************************************/ WORD str_size(sptr) char *sptr; /* ptr to string to size up */ { register WORD cnt; /* character counter */ for (cnt = 0; *sptr != '\0' && *sptr != ' '; cnt++, sptr++) {} return cnt; } /**************************************************************************** new line ****************************************************************************/ crlf() { puts("\n"); } /*************************************************************************** get text and convert to upper case ***************************************************************************/ char *uc_gets(tptr) char *tptr; /* ptr to text buffer */ { WORD i; /* character index */ /* Fetch text */ gets(tptr); /* Convert to upper case if needed */ for ( i = 0; tptr[i] != '\0'; i++) tptr[i] = toupper( tptr[i]); /* Return ptr for gets() compatability */ return tptr; } /*************************************************************************** Skip to next field procedure ***************************************************************************/ nxt_field() { cptr = skip(cptr, ' '); } /*************************************************************************** Skip chars function ***************************************************************************/ char *skip(ptr, c) char *ptr, /* ptr to string to skip */ c; /* character to skip over */ { register int flag; /* flag to determine when skip character is found */ for (flag = FALSE; *ptr != '\0'; ptr++) { if (*ptr != c && flag) break; else if (*ptr == c) flag = TRUE; } return ptr; } /*************************************************************************** Get argument(s) in text string function Uses global 'cptr' variable pointing to 1st argument field as text ptr & leaves cptr pointing to next field or '\0' Returns number of args actually processed. ***************************************************************************/ WORD get_n_args(n) WORD n; /* max number of args to scan */ { register unsigned argn; /* current argument number {1..n_args} */ /* If args out of range then return error */ if (n < 1 || n > n_args) return 0; /* Else process up to n arguments */ for (argn = 1; *cptr != '\0' && n > 0; n--, argn++) { arg[argn] = scan_hex(cptr); nxt_field(); } /* Return number of args processed */ return argn -1; } /*************************************************************************** Return hex word function ***************************************************************************/ WORD scan_hex(ptr) char *ptr; /* ptr to text to convert to binary */ { WORD acc; /* accumulator for value to return */ register char c; /* fast storage for current working char */ /* Convert chars until a non-hex char is encountered */ for (acc = 0, c = *ptr; TRUE; c = *(++ptr)) { /**** If char not hex then abort with current value */ if (c < '0' || (c > '9' && c < 'A') || c > 'F') break; /**** Else convert to binary and add to accumulated value */ acc = (acc << 4) + ( (c > '9') ? (c - 7 -'0') : (c - '0') ); } /* Done, return accumulated value */ return acc; } /**************************************************************************** Query function returns user option entry- ptr to text question exit - TRUE= user answered Yes FALSE= User did not answer Yes ****************************************************************************/ query(cptr) char *cptr; /* question prompt text */ { crlf(); puts(cptr); puts("? (Y/N) : "); uc_gets(tbuf); return ( tbuf[0] == 'Y') ? TRUE : FALSE; } /**************************************************************************** Dump IOPB function ****************************************************************************/ dmp_iopb() { puts("\nCommand: Status Returned:\n\ Command = " ); puthxb(iopb.pb_cmd); puts(" Status = "); puthxb(iopb.pb_stat); puts("\nDrive = "); puthxb(iopb.pb_drv); puts(" St1 = "); puthxb(iopb.pb_st1); puts("\nTrack = "); puthxw(iopb.pb_trk); puts( " St2 = "); puthxb(iopb.pb_st2); puts("\nSector = "); puthxw(iopb.pb_sec); puts( " St3 = "); puthxb(iopb.pb_st3); puts("\nFlags = "); puthxb(iopb.pb_flg); puts("\nDMA = "); puthxb(iopb.pb_dmax); puthxw(iopb.pb_dma); puts("\nByte Cnt= "); puthxw(iopb.pb_bcnt); } /**************************************************************************** Dump a line of buffer data to console in Hex - ASCII output format is ": " argument = address of data area ****************************************************************************/ dump_16(addr, cnt) BYTE *addr; /* ptr to data area to output */ WORD cnt; /* byte count to display */ { register char c; /* fast storage for current char */ unsigned int j; /* loop counter */ /* Display hex data bytes */ for (j = 0; j < 16; j++) { if (j == 8) puts("- "); if (j < cnt) { puthxb(addr[j]); CO(' '); } else puts(" "); } /* Now repeat for ascii */ puts(" "); for (j = 0; j < 16; j++) { if (j < cnt) { c = addr[j] & 0x7f; CO( (c >= ' ' && c < 0x7f) ? c : '.'); } else CO(' '); } } /*************************************************************************** Execute the IOPB function ***************************************************************************/ x_iopb() { register BYTE *bptr; /* ptr to data in sector buffer */ register WORD i; /* temporary storage */ static char *iopb_cmds[] = { "0 : Log on drive", /* 0 */ "3 : Format track", /* 1 */ "8 : Return Firmware Version", /* 2 */ "9 : Get Disk Physical Data", /* 3 */ "A : Set disk Physical Data", /* 4 */ "B : Seek track", /* 5 */ "F : Clear Controller" /* 6 */ }; /* Display commands */ for (i = 0; i < 7; i++) { puts(iopb_cmds[i]); crlf(); } /* Fetch user command */ puts("Enter Command - "); uc_gets(cptr = tbuf); for (i = 0; i < 7; i++) { if (strncmp( cptr, iopb_cmds[i], str_size( iopb_cmds[i])) == 0) break; } /* Select command */ switch (i) { /*--------------------------------------------------------------------------- 0 Log on drive ---------------------------------------------------------------------------*/ case 0: iopb.pb_cmd = 0; iopb.pb_flg = 0; iopb.pb_trk = 0; /* Now need to specify trk & sector */ iopb.pb_sec = 2; iopb.pb_bcnt = 128; if (get_drive()) break; /**** Get buffer location from user */ if ( get_bufr()) break; if ( execute_i( &iopb) ) dmp_iopb(); break; /*--------------------------------------------------------------------------- 3 Format Track ---------------------------------------------------------------------------*/ case 1: notimp(); break; /*--------------------------------------------------------------------------- 8 Return firmware version ---------------------------------------------------------------------------*/ case 2: /**** set up iopb */ iopb.pb_cmd = 8; /**** execute it */ if ( execute_i( &iopb) ) dmp_iopb(); /**** display version data */ i = (iopb.pb_st3 << 8) + iopb.pb_st2; puts("\nFirmware version = "); putdec(i / 100); CO('.'); putdec(i % 100 ); break; /*--------------------------------------------------------------------------- 9 Get Physical disk parameters ---------------------------------------------------------------------------*/ case 3: iopb.pb_cmd = 9; /**** Get buffer location from user */ if ( get_bufr()) break; /**** Get drive from user */ get_drive(); /**** Fetch user option */ iopb.pb_flg = 1 + (( query( "Disable logon") ) ? 0 : 2); /**** Execute the request */ if ( execute_i( &iopb) ) dmp_iopb(); /**** Display current data */ bptr = &sbuf[arg[1]]; puts("\nFlags = "); puthxb( *bptr++); puts("\nTrk0 SPT, Size = "); puthxb( *bptr++); puthxb( *bptr++); puts("\nTrk1 SPT, Size = "); puthxb( *bptr++); puthxb( *bptr++); puts("\nData SPT, Size = "); puthxb( *bptr++); puthxb( *bptr++); puts("\nDisk Type = "); puthxb( *bptr++); puts("\nCylinders = "); puthxw( *(WORD *) bptr++); puts("\nHeads = "); puthxb( *bptr++); puts("\nRed. Wr. I Cyl = "); puthxw( *(WORD *) bptr++); puts("\nPrecomp Cyl = "); puthxw( *(WORD *) bptr++); puts("\nECC Burst Len. = "); puthxb( *bptr++); puts("\nControl Byte = "); puthxb( *bptr++); crlf(); break; /*--------------------------------------------------------------------------- A Set disk physical data ---------------------------------------------------------------------------*/ case 4: notimp(); break; /*--------------------------------------------------------------------------- B Seek track ---------------------------------------------------------------------------*/ case 5: iopb.pb_cmd = 11; /**** Get drive from user */ get_drive(); /**** Get track from user */ if (get_trk()) break; /**** Execute it */ if ( execute_i( &iopb) ) dmp_iopb(); break; /*--------------------------------------------------------------------------- F Clear controller ---------------------------------------------------------------------------*/ case 6: iopb.pb_cmd = 15; if ( execute_i( &iopb) ) dmp_iopb(); break; /*--------------------------------------------------------------------------- ??? Unknown command ---------------------------------------------------------------------------*/ default: cmderr(); } } /*************************************************************************** Fetch console input status function exit - 0: no char ready, /0: char ready ***************************************************************************/ int CIS() { /* Use get console status CP/M function */ return bdos(11, 0); } /*************************************************************************** Return next console char function exit - char ***************************************************************************/ char CI() { /* Use console read CP/M function */ return bdos(1, 0); } /*************************************************************************** Console output procedure ***************************************************************************/ CO(c) char c; { bdos(2, c); } /*************************************************************************** Output hex nibble to console procedure ***************************************************************************/ puthxn(data) BYTE data; /* Nibble to convert */ { data &= 0xf; CO( (data <= 9) ? (data + '0') : (data + '0' + 7) ); } /*************************************************************************** Output hex byte to console procedure ***************************************************************************/ puthxb(data) BYTE data; /* Byte to convert */ { /* Do upper nibble 1st */ puthxn(data >> 4); /* Now do lower nibble */ puthxn( data ); } /*************************************************************************** Output hex word to console procedure ***************************************************************************/ puthxw(data) WORD data; /* word to convert to hex */ { /* Do upper byte 1st */ puthxb( data >> 8 ); /* Now do lower byte */ puthxb( data ); } /*************************************************************************** Output decimal number procedure does not output any preceeding blanks or zeros. ***************************************************************************/ putdec( n) WORD n; /* number to output */ { int flag; /* flag to determine when to output zeros */ WORD divisor, /* digit divisor */ a; /* accumulator for digit */ for (flag = FALSE, divisor = 10000; divisor > 0; divisor /= 10) { /**** Fetch digit from number */ a = n / divisor; /**** Extract remainder for next loop */ n %= divisor; /**** If not 0 then set flag for subsequent zero printing */ if (a > 0) flag = TRUE; /**** If flag set or last digit then start printing */ if (flag || divisor == 1) CO(a + '0'); /**** Do next digit until no more digits */ } } /*************************************************************************** Print text string on console procedure ***************************************************************************/ puts(tptr) char *tptr; /* text ptr */ { /* Do until end of text char */ for ( ; *tptr != '\0'; tptr++) { /**** If char == new line then output carriage return 1st */ if (*tptr == '\n') CO('\r'); /**** Now output character */ CO(*tptr); } /* Done */ } /*************************************************************************** Execute the IOPB function returns iopb.pb_stat ***************************************************************************/ BYTE execute_i(iptr) struct iopb_struct *iptr; /* ptr to the iopb data */ { BYTE temp; /* temporary result storage */ #if DIAG iptr->pb_stat = -1; return -1; } #else /* Output the iopb address to the host adapter */ out(IDATA, ((WORD) iptr) & 0xff); out(ICMD, 1); temp = xwait(); if (temp) { iptr->pb_stat = temp; return temp; } out(IDATA, ( ( (WORD) iptr) >> 8) & 0xff); out(ICMD, 3); temp = xwait(); if (temp) { iptr->pb_stat = temp; return temp; } out(IDATA, 0); out(ICMD, 5); temp = xwait(); if (temp) { iptr->pb_stat = temp; return temp; } /* Now execute the iopb */ out(ICMD, 0x41); temp = xwait(); if (temp) return temp; else return iptr->pb_stat; } #endif /*************************************************************************** Wait for command execution function returns command status ***************************************************************************/ BYTE xwait() { BYTE temp; /* temporary result storage */ WORD i; /* timer count */ /* Wait for busy bit to clear */ while (TRUE) { for (i = 0; i < 40000; i++) { if ((( temp = in( ISTAT) ) & 0x01) == 0) break; } /**** If timed out then ask user to continue */ if (i == 40000) { if (query("Controller timeout, Quit") ) return temp; } /**** Else stop */ else break; } /* Return no error */ return 0; } /**************************************************************************** Get drive from user returns TRUE if error, FALSE if ok ****************************************************************************/ int get_drive() { puts("\nEnter drive number {0..3}: "); uc_gets(cptr = tbuf); iopb.pb_drv = scan_hex( cptr); return FALSE; } /**************************************************************************** Get sector & track info from user returns TRUE if error, FALSE if ok ****************************************************************************/ int get_sec_trk() { puts("\nEnter sector number : "); uc_gets(tbuf); iopb.pb_sec = atoi(tbuf); get_trk(); } /**************************************************************************** Get track info from user returns TRUE if error, FALSE if ok ****************************************************************************/ int get_trk() { unsigned int d; /* temporary track storage */ puts("\nEnter decimal track number : "); uc_gets(cptr = tbuf); d = atoi(tbuf); iopb.pb_trk = d; return FALSE; } /*************************************************************************** get track data function entry - cptr= ptr to place to put data exit - cptr= sectors per track cptr + 1= sector size {0,1,..n} cptr = cptr + 2 ***************************************************************************/ gt_trk(tptr) char *tptr; { unsigned x; puts("\nEnter "); puts(tptr); puts(" sectors per track : "); uc_gets(tbuf); if (tbuf[0] != '\0') *cptr = atoi(tbuf); cptr++; puts("Enter "); puts(tptr); puts(" sector size {128, 256, 512, 1024}: "); uc_gets(tbuf); if (tbuf[0] != '\0') { x = atoi(tbuf); switch (x) { case 128: x = 0; break; case 256: x = 1; break; case 512: x = 2; break; case 1024: x = 3; break; default: x = 100; } if (x < 100) *cptr = x; } cptr++; } /*************************************************************************** get buffer address from user ***************************************************************************/ get_bufr() { WORD d; /* buffer offset address */ puts("\nEnter buffer address - "); uc_gets( cptr = tbuf); d = scan_hex(cptr); iopb.pb_dma = &sbuf[d]; iopb.pb_dmax = 0; }