1File: BDOSRW.C Page 1 1 2 /**************************************************************** 3 * * 4 * CP/M-68K BDOS Disk Read/Write Module * 5 * * 6 * This module contains functions to perform sequential * 7 * or random access read or write to the disk for CP/M-68K * 8 * * 9 * It includes the following external functions: * 10 * * 11 * bdosrw() - sequential and random disk I/O * 12 * * 13 * * 14 * Compiled with Alcyon C on the VAX * 15 * * 16 ****************************************************************/ 17 18 #include "bdosinc.h" /* Standard I/O declarations */ 19 20 #include "bdosdef.h" /* Type and structure declarations for BDOS */ 21 22 23 /* External function definitions */ 24 EXTERN UWORD rdwrt(); /* disk read/write routine */ 25 EXTERN WORD getaloc(); /* allocate a block of disk space */ 26 EXTERN WORD swap(); /* assembly language byte swapper */ 27 EXTERN UWORD dirscan(); /* directory scanning routine */ 28 EXTERN BOOLEAN openfile(); /* open file function passed to dirscan */ 29 EXTERN UWORD close_fi(); /* close file function */ 30 EXTERN BOOLEAN create(); /* create file function passed to dirscan */ 31 EXTERN UWORD ro_err(); /* read-only file error handler */ 32 33 /* External variable definitions */ 34 EXTERN UWORD ro_dsk; /* read-only disk vector */ 35 36 37 /**********************************************************/ 38 /* First, some utility functions used by seqio and ranio */ 39 /**********************************************************/ 40 41 /****************************** 42 * FCB block number routines * 43 ******************************/ 44 45 WORD blkindx(fcbp) 46 /* return index into fcb disk map */ 47 48 REG struct fcb *fcbp; /* pointer to fcb */ 49 { 50 REG struct dpb *dparmp; /* pointer to disk parameter block */ 51 REG WORD i; 52 REG WORD blkshf; 53 BSETUP 54 55 dparmp = GBL.parmp; 56 blkshf = dparmp->bsh; 57 i = ((fcbp->extent) & dparmp->exm) << (7 - blkshf); 58 return (i + (UBWORD(fcbp->cur_rec) >> blkshf) ); 59 } 1File: BDOSRW.C Page 2 60 61 62 UWORD blknum(fcbp, index, wrdfcb) 63 /* return block number in fcb indicated by index */ 64 65 REG struct fcb *fcbp; /* pointer to fcb */ 66 REG WORD index; /* index into disk map of fcb */ 67 WORD wrdfcb; /* boolean, fcb disk map of words */ 68 { 69 if (wrdfcb) 70 return( swap(fcbp->dskmap.big[index]) ); 71 else return( UBWORD(fcbp->dskmap.small[index]) ); 72 } 73 74 75 setblk(fcbp, index, wrdfcb, block) 76 /* put block number into fcb */ 77 78 REG struct fcb *fcbp; /* pointer to fcb */ 79 REG WORD index; /* index into disk map of fcb */ 80 WORD wrdfcb; /* boolean, fcb disk map of words */ 81 REG UWORD block; /* block number */ 82 { 83 fcbp->s2 &= 0x7f; /* set file write flag */ 84 if (wrdfcb) 85 fcbp->dskmap.big[index] = swap(block); 86 else fcbp->dskmap.small[index] = (UBYTE)block; 87 } 88 89 90 /*************************** 91 * disk read/write routine * 92 ***************************/ 93 94 UWORD do_io(block, rcrd, parm) 95 96 UWORD block; /* block number */ 97 UBYTE rcrd; /* record number */ 98 REG WORD parm; /* write parameter */ 99 { 100 REG LONG lsec; 101 REG struct dpb *dparmp; 102 BSETUP 103 104 dparmp = GBL.parmp; /* init dpb pointer */ 105 lsec = ((LONG)block << (dparmp->bsh)) + 106 (LONG)(rcrd & (dparmp->blm)); 107 return( rdwrt(lsec, GBL.dmaadr, parm) ); 108 } 109 110 111 /******************************************* 112 * routine for crossing extent boundaries * 113 *******************************************/ 114 115 WORD new_ext(fcbp, reading, ran) 116 /* If sequential I/O, open the next extent */ 117 /* If random I/O, compute new extent from random record field */ 118 1File: BDOSRW.C Page 3 119 REG struct fcb *fcbp; /* pointer to fcb */ 120 BOOLEAN reading; /* read/write flag */ 121 WORD ran; /* random I/O flag */ 122 { 123 REG UBYTE mod; /* module number */ 124 REG UBYTE ext; /* extent number */ 125 REG UBYTE t_mod; /* temp mod number */ 126 REG UBYTE t_ext; /* temp extent */ 127 BSETUP 128 129 if (ran) 130 { 131 mod = ( (fcbp->ran0) << 4) | ( (fcbp->ran1) >> 4); 132 ext = ( ((fcbp->ran1) & 0x0f) << 1); 133 if ((fcbp->ran2) & 0x80) ext |= 1; 134 /* the calculation of ext was coded this way because of a */ 135 /* compiler bug from Alcyon */ 136 } 137 else 138 { 139 mod = (fcbp->s2) & 0x3f; 140 ext = (fcbp->extent) + 1; /* for sequential, incr extent */ 141 } 142 if (ext >= 32) 143 { 144 ext = 0; 145 mod += 1; 146 } 147 if (mod >= 64) return(6); /* past maximum file size */ 148 if ( mod == ((fcbp->s2) & 0x3f) ) 149 if ( ! ((ext ^ (fcbp->extent)) & ~((GBL.parmp)->exm) & 0x1f) ) 150 { /* we're in same logical extent */ 151 fcbp->extent = ext; 152 return(0); 153 } 154 /* Extent or Module numbers don't match */ 155 /* Close the old extent and open a one */ 156 if ( close_fi(fcbp) >= 255 ) return(3); 157 /* can't close old extent */ 158 t_mod = fcbp->s2; 159 t_ext = fcbp->extent; 160 fcbp->s2 = mod; 161 fcbp->extent = ext; 162 if ( dirscan(openfile, fcbp, 0) >= 255 ) /* open extent */ 163 { 164 if (reading) 165 { /* reading unwritten extent */ 166 fcbp->s2 = t_mod; 167 fcbp->extent = t_ext; 168 return(4); 169 } 170 if ( dirscan(create, fcbp, 8) >= 255 ) 171 return(5); /* can't create new extent */ 172 } 173 return(0); 174 } 175 176 177 /************************************ 1File: BDOSRW.C Page 4 178 * Routine to calculate the maximum * 179 * extent number of an FCB in a * 180 * extent-folded environment * 181 ************************************/ 182 183 UWORD calcext(fcbp) 184 185 REG struct fcb *fcbp; 186 187 { 188 REG UWORD i; 189 REG BYTE *p; 190 BSETUP 191 192 i = 15; 193 p = &(fcbp->dskmap.small[16]); 194 do 195 { 196 if (*--p) break; 197 i -= 1; 198 } while (i); 199 /* Now i contains the index of the last non-zero block in the FCB */ 200 if ((GBL.parmp)->dsm > 255) i >>= 1; 201 i >>= 7 - ((GBL.parmp)->bsh); 202 return ( (fcbp->extent) & ~((GBL.parmp)->exm) & 0x1f | i ); 203 } 204 205 206 /********************************* 207 * Routine to get the actual * 208 * record count of the currently * 209 * active logical extent of a FCB * 210 *********************************/ 211 212 UWORD get_rc(fcbp) 213 214 REG struct fcb *fcbp; 215 216 { 217 REG UWORD ext; 218 219 ext = calcext(fcbp); /* find last active extent in fcb */ 220 if (ext == fcbp->extent) return(UBWORD(fcbp->rcdcnt)); 221 /* if this is the last active fcb, return fcb's rc */ 222 else if (ext > fcbp->extent) return(128); 223 /* if the fcb has more extents past this one, then */ 224 /* the current one is logically full */ 225 else return (0); 226 /* if we seeked past the last active extent, rc = 0 */ 227 } 228 229 230 /************************ 231 * bdosrw entry point * 232 ************************/ 233 234 UWORD bdosrw(fcbp, reading, random) 235 236 REG struct fcb *fcbp; /* fcbp is a pointer to a fcb */ 1File: BDOSRW.C Page 5 237 REG BOOLEAN reading; /* boolean to tell whether to read or write */ 238 WORD random; /* 0 = sequential, 1 = random (normal), */ 239 /* 2 = random with zero fill */ 240 { 241 REG UWORD block; /* block number from fcb */ 242 REG WORD index; /* index into disk map of fcb */ 243 REG BYTE *old_dma; /* temp holding spot for dmaadr */ 244 REG WORD parm; /* parameter to do-io */ 245 REG WORD bigfile; /* file system is in word mode */ 246 REG UWORD rtn; /* return parameter */ 247 REG UBYTE rc; /* temp storage for rcdcnt */ 248 BSETUP 249 250 bigfile = ((GBL.parmp)->dsm) & ~0xff; 251 if ( ( ! reading) && (fcbp->ftype[robit] & 0x80) ) 252 ro_err(fcbp,((GBL.dpbp)->dpbp)->drm); 253 /* check for read-only file */ 254 if (random) 255 { 256 if ( rtn = new_ext(fcbp, reading, TRUE) ) return(rtn); 257 /* open new extent if necessary, return if error */ 258 fcbp->cur_rec = (fcbp->ran2) & 0x7f; 259 } 260 else /* sequential */ 261 if (fcbp->cur_rec == 128) 262 { /* time to try next extent */ 263 if ( new_ext(fcbp, reading, FALSE) ) 264 return(1); /* if can't open new extent, error */ 265 fcbp->cur_rec = 0; /* opened new extent, zero cur_rec */ 266 } 267 268 /* record is now in active fcb */ 269 rc = fcbp->rcdcnt; 270 if ( UBWORD(fcbp->cur_rec) >= get_rc(fcbp) ) 271 { 272 if (reading) return(1); /* reading unwritten data */ 273 fcbp->s2 &= 0x7f; /* set file write flag */ 274 rc = fcbp->cur_rec + 1; 275 } 276 index = blkindx(fcbp); /* get index into fcb disk map */ 277 block = blknum(fcbp, index, bigfile); 278 if (block) parm = (reading ? 0 : 1); 279 else /* if allocated block, parm is just read or write */ 280 { /* unallocated block */ 281 if (reading) return(1); /* reading unwritten data */ 282 283 /* Writing to new block */ 284 /* The parm passed to getaloc is the previously allocated block */ 285 /* or 0, if the previous block is not allocated */ 286 287 block = getaloc(blknum(fcbp, (index ? (index - 1) : 0), bigfile)); 288 if (block == ~0) return(2); /* out of space */ 289 setblk(fcbp, index, bigfile, block); 290 parm = 3; 291 if (random == 2) 292 { /* Write random with zero fill */ 293 old_dma = GBL.dmaadr; 294 GBL.dmaadr = GBL.dirbufp; /* Do DMA from dir_buf */ 295 index = SECLEN; 1File: BDOSRW.C Page 6 296 do GBL.dmaadr[--index] = 0; 297 while (index); /* zero the dma buffer */ 298 for (index = 0; index <= ((GBL.parmp)->blm); index++) 299 { 300 do_io(block, (UBYTE)index, parm); 301 /* write zeros to the block */ 302 parm = 1; /* next write is not to new block */ 303 } 304 GBL.dmaadr = old_dma; /* restore dma address */ 305 } 306 } 307 rtn = do_io(block, fcbp->cur_rec, parm); 308 if ( rtn == 0 ) 309 { 310 fcbp->rcdcnt = rc; 311 if ( ! random ) fcbp->cur_rec += 1; 312 } 313 return(rtn); 314 }