Mercurial > hg > Members > kono > nitros9-code
view 3rdparty/fmgrs/msf/msf.asm @ 2624:b8c7b7fbf3c9
Major changes:
o os9defs, rbfdefs, scfdefs now os9.d, rbf.d, and scf.d
o vtiodefs now broken into cocovtio.d (for coco and dragon) and atarivtio.d
o systype now broken into coco.d, dragon.d and atari.d
o all references to the above in other files have changed
author | Boisy Pitre <boisy.pitre@nuance.com> |
---|---|
date | Fri, 24 Feb 2012 08:51:08 -0600 |
parents | c9a215fbb25d |
children |
line wrap: on
line source
********************************************************************* * MSF (msf.v2.3.a) * * copyright 1988 by * Clearbrook Software Group Inc. * Box 8000-499 * Abbotsford, B.C. * CANADA V2S 6H1 * (604)853-9118 * * author: Paul Kehler * * MSF source and object code and any product derived from the * MSF source code is a copyrighted product of Clearbrook * Software Group Inc. It may be used by a licensed user on one * computer system and may not be sold or given away except as * authorized by Clearbrook Software Group Inc. * * Oct 15, 1988 - added check for busy before FAT checked * * MSDOS file manager for OS9 Level 2 with SDisk3 disk driver ********************************************************************* ifp1 use defsfile endc type set FlMgr+Objct revs set Reent+1 edition set $23 version 2.3 mod modlen,modname,type,revs,modexec,modmem modname fcs 'MSF' fcb edition * information determined from the FAT ID byte *** Revision 2.1 to support 640 and 720k disk *** Revision 2.2 to support 1.2meg floppies * and follow the MSDOS v2+ standard for the * information sector and FAT ID byte. * double sided, 8 sectors/track doubles8 fcb $00,$02 512 bytes/sector fcb $02 sectors/cluster fcb $01,$00 reserved sectors fcb $02 number of FATs fcb $70,$00 112 root directory entries fcb $80,$02 640 sectors fcb $FF ID byte fcb $01,$00 1 sector/FAT fcb $08,$00 8 sectors/track fcb $02,$00 2 heads fcb $00,$00 no hidden sectors * single sided, 8 sectors/track singles8 fcb $00,$02 512 bytes/sector fcb $01 sectors/cluster fcb $01,$00 reserved sectors fcb $02 number of FATs fcb $40,$00 64 root directory entries fcb $40,$01 320 sectors fcb $FE ID byte fcb $01,$00 1 sector/FAT fcb $08,$00 8 sectors/track fcb $01,$00 1 head fcb $00,$00 no hidden sectors * double sided, 9 sectors/track doubles9 fcb $00,$02 512 bytes/sector fcb $02 sectors/cluster fcb $01,$00 reserved sectors fcb $02 number of FATs fcb $70,$00 112 root directory entries fcb $D0,$02 720 sectors fcb $FD ID byte fcb $02,$00 2 sector/FAT fcb $09,$00 9 sectors/track fcb $02,$00 2 heads fcb $00,$00 no hidden sectors * single sided, 9 sectors/track singles9 fcb $00,$02 512 bytes/sector fcb $01 sectors/cluster fcb $01,$00 reserved sectors fcb $02 number of FATs fcb $40,$00 64 root directory entries fcb $68,$01 360 sectors fcb $FC ID byte fcb $02,$00 2 sector/FAT fcb $09,$00 9 sectors/track fcb $01,$00 1 head fcb $00,$00 no hidden sectors ********************************* * Subroutine: expchn * * function - add a cluster to a file chain * * On entry: * Y points to path descriptor * D is number of last cluster in file * * On exit: * D is number of added cluster * or * Carry set and error code in B expchn ldx msp.dtb,y ldx V.FAT,x point to FAT ********************************* * Subroutine: expchain * * function - add a cluster to a file chain * * On entry: * X points to FAT * D is number of last cluster in file ($FFF if none) * * On exit: * D is number of added cluster * or * Carry set and error code in B expchain pshs d,u lbsr findhole find first available sector beq expbad ..media full tfr d,u save cluster number of hole ldd ,s++ get current last cluster beq expch5 ..this is first cmpd #$FF8 bhs expch5 bsr updFAT make it the second last one expch5 tfr u,d get number of hole ldu #$FFF bsr updFAT make it the last cluster in file puls u,pc return last cluster number in D expbad leas 4,s comb set carry ldb #E$Full rts return carry set and media full ******************************************* * Subroutine: delchain * * function - delete a file chain from the FAT * * On entry: * X points to FAT * D is first cluster in file * * On exit: * D==0 if error delchain pshs d,x,u ldu #0 bra delch2 delch1 bsr findnext find the next cluster in the chain std 2,s save it ldd ,s get previous cluster number bsr updFAT mark it as unused ldd 2,s get current cluster std ,s make it the previous beq delerror ..bad FAT delch2 cmpd #$FF8 end of file? blo delch1 ..no, remove another cluster delerror ldd ,s leas 4,s puls u,pc ************************************************** * Subroutine: updFAT * * function - update the FAT * * On entry: * X points to FAT * D cluster to update * U next cluster to cluster D * U==$FFF if D is last cluster in file * U==0 if D is an unused cluster * * On exit: * all registers unchanged updFAT pshs d,x,u lslb rola addd ,s lsra rorb offset in FAT=cluster# * 1.5 leax d,x point to FAT entry ldd ,x get current value in FAT bcs updodd ..nomalize for odd cluster number * 12bit value is put in fat in the following order * nibble1, nibble0, neighbour, nibble2 andb #$F0 keep neighbour nibble pshs b ldd 5,s get new value anda #$F isolate most significant nibble ora ,s+ combine with neighbouring nibble sta 1,x stb ,x put in second and third nibbles bra updend updodd anda #$F keep neighbour nibble pshs a ldd 5,s get new value lsra rorb rora rorb rora rorb rora rorb rora rearrange the word nibble0, neighbour, nibble2, nibble1 ora ,s+ combine with neighbour std ,x and put it in FAT updend lda #1 ldx msp.dir,y sta dir.stat,x set dir.stat to update FAT puls d,x,u,pc ******************************************** * Subroutine: findnext * * function - find the next cluster in a chain * * On entry: * X points to FAT * D current cluster number * * On exit: * D is next cluster number findnext pshs d lslb rola addd ,s++ lsra rorb offset=cluster*1.5 /carry set if cluster is odd ldd d,x get mixed up cluster # exg a,b bcs oddcl ..unjumble odd cluster anda #$F normalize next cluster # for an even cluster rts oddcl lsra rorb lsra rorb lsra rorb lsra rorb rts ********************************************** * Subroutine: findhole * * function - find an unused cluster * * On entry: * Y points to path descriptor * * On exit: * D - first unused cluster or 0 if media full * X - points to FAT findhole ldx msp.dtb,y ldx V.BPB,x point to disk info ldd ID.clus,x get number of clusters ldx msp.dtb,y ldx V.FAT,x point to file allocation table findh02 pshs d ldd #2 first usable cluster pshs d findh1 bsr findnext get next cluster std -2,s is there one? beq holefnd ..no, its unused ldd ,s addd #1 std ,s cmpd 2,s end of FAT? bne findh1 ..no, check it out clra clrb std ,s holefnd ldd ,s++ return cluster # in D leas 2,s rts ************************************************* * Subroutine: rootdat * * function - return info about size and location * of root directory. * * On entry: * Y points to path descriptor * * On exit: * A is cluster size * B is size of directory in sectors * U is location of directory (logical sector) rootdat pshs x ldx msp.dtb,y ldx V.BPB,x point to info lda ID.spf,x get sectors/fat ldb ID.FATs,x get number of FATs mul addb ID.res,x add reserved sectors tfr d,u ldb ID.BPS+1,x get MSB of sector size pshs b ldd ID.RDE,x get root directory entries exg a,b lsra rorb lsra rorb rootd5 lsra rorb lsr ,s bne rootd5 calculate number of directory sectors puls a lda ID.SPA,x get sectors/cluster puls x,pc ************************************************* * Subroutine: sepecl * * function - return sectors per cluster * * On entry: * Y points to path descriptor * * On exit: * A - number of sectors per cluster * sepecl pshs x ldx msp.dtb,y ldx V.BPB,x point to disk info lda ID.SPA,x get Sectors Per Allocation unit puls x,pc ************************************************* * Subroutine: secsiz * * function - return sector size * * On entry: * Y points to path descriptor * * On exit: * D - sector size * secsiz pshs x ldx msp.dtb,y ldx V.BPB,x point to disk info ldd ID.BPS,x get Sector size exg a,b convert to Motorola format puls x,pc ************************************************* * Subroutine: findfile * * function - find a file in the directory * * On entry: * Y points to path descriptor * * On exit: * Carry set if error (error code in B) * X points to directory entry if file found findf91 rts * link path into list findfile ldx msp.dev,y ldx V$STAT,x point to device static storage ldb PD.DRV,y get drive number lda #DRVMEM mul leax d,x leax DRVBEG2,x stx msp.dtb,y save address of drive table inc V.CNT,x path count open001 ldu <D.MSF beq open1 sty msp.prev,u stu msp.next,y open1 sty <D.MSF tfr Y,U LDX <D.PthDBT OS9 F$All64 get 64 bytes of storage bcs findf91 ..return error exg Y,U stu msp.dir,y place to store directory entry clra clrb std dir.msd+msd.strt,u mark file as root directory std dir.msd+msd.size+2,u ldx <D.Proc point to user process ldb P$Task,x get DAT task number ldx PD.RGS,y point to stacked parameters ldx R$X,x point to file name pshs b,x,y save registers leas -4,s save temporary space clr 1,s directory mode inc 1,s OS9 F$LDABX get first character of path list sta ,s cmpa #'/ complete path list? beq findf1 ..yes cmpa #'@ entire disk? lbeq findf201 ..yes bsr getrdy get ready to access disk lbcs findf24 lbsr setdir select current default directory lbcs findf24 ..return error ldb 4,s recover task number lda ,s lbra findf20 * Read the FAT if required * return: * carry set and error in B * NE if buffer already set up getFAT pshs x,u *** rev 2.3 ldu PD.DEV,y ldu V$STAT,u point to static storage getFAT0 tst V.BUSY,u is driver busy? beq getFAT1 ..no ldx #1 OS9 F$SLEEP sleep until ready bra getFAT0 getFAT1 *** ldu msp.dtb,y clrb clear carry ldd V.FAT,u has FAT been read? bne open012 ..yes open01 lbsr readFAT read the file allocation table bcs open013 open012 ldd PD.BUF,y is buffer already allocated? bne open013 ..yes lbsr secsiz get sector size os9 F$SRQMEM request memory bcs open013 ..return error stu PD.BUF,y clrb open013 puls x,u,pc * read the file allocation table if needed * and setup the root directory getrdy bsr getFAT bcs getrdy9 lbsr rootdat get root information lbsr setsec ldu msp.dir,y pshs x ldx msp.dtb,y ldx V.BPB,x point to info ldd ID.RDE,x get root directory entries puls x exg a,b lslb rola lslb rola lslb rola root directory entries * 16 exg a,b std dir.msd+msd.size,u set size of root directory (bytes) ldb #attr.DR stb dir.msd+msd.attr,u set directory attribute ldd #1 std msp.pos+1,y getrdy9 rts findf1 pshs y OS9 F$PrsNam skip device name tfr y,x puls y anda #$7f cmpa #'/ beq findf19 cmpa #'@ is it entire disk? beq findf201 ..yes bsr getrdy get ready for directory search lbcs findf24 ..report error bra findf23 5 ..end of path list findf19 bsr getrdy get ready for directory search lbcs findf24 ..report error ldb 4,s recover task number findf2 leax 1,x point to next character OS9 F$LDABX get next character findf20 anda #$7f remove terminator bit cmpa #'. subdirectory? beq findf21 ..yes cmpa #'@ entire disk bne findf26 ..no findf201 lbsr setdisk open entire disk leax 1,x clr 1,s ..not directory inc msp.wrt,y don't allow writing to this file bra findf23 findf21 leax 1,x OS9 F$LDABX get next char sta ,s anda #$7f cmpa #'@ entire disk? beq findf201 ..yes cmpa #'. parent directory? bne findf22 ..no lbsr setparnt bcs findf24 ..report error ldb 4,s restore task number bra findf21 check for more findf22 tst 1,s directory mode? beq findf225 ..no cmpa #'/ end of name? beq findf2 ..yes check next name in list findf225 tst ,s is name terminated? bmi findf23 ..yes cmpa #SP space? bls findf23 ..yes, or control cmpa #', comma? bne findf25 ..no findf23 pshs y OS9 F$PrsNam skip trailing spaces and comma tfr y,x puls y findf235 ldu PD.RGS,y point to register stack stx R$X,u update pointer past path list clrb clear carry ldb 1,s return NE if pathlist is directory beq findf237 ..not directory ldb PD.MOD,Y get mode bpl NoPerm ..no permission to open directory findf236 inc msp.wrt,y don't allow writing to file bra Findf24 findf237 ldx msp.dir,y lda dir.msd+msd.attr,x get file attribute anda #attr.RO read only? beq findf238 ..no lda PD.MOD,Y anda #WRITE. are we opening for write? beq findf238 ..no, we have permission NoPerm comb ldb #E$FNA ..no permission bra findf24 findf238 lda PD.MOD,y directory? bmi NoPerm ..yes, wrong mode findf24 leas 7,s fix stack puls y,pc findf25 comb set carry ldb #E$BPNam bad path name bra findf24 * search directory for file name at X findf26 lbsr findname look for the name in current directory std ,s bcs findf24 ..report error ldb 4,s get task number bra findf22 check next section of path list * set current directory setdir pshs x,u ldx <D.Proc point to user process ldu P$DIO+3,x get default directory location lda PD.MOD,y get access mode anda #EXEC. is it execution directory? beq setdir2 ..no ldu P$DIO+9,x get default execution directory setdir2 tfr u,d lbsr setcls set current directory ldx msp.dir,y stu dir.prnt,x save parent start cluster cmpu #1 ROOT or entire disk? bls setdir3 ..yes lbsr readsec read the sector bcs setdir9 clra clrb std msp.pos+1,y point to "." directory entry ldx PD.BUF,y point to parent directory entry bra copydir1 copy directory entry to buffer setdir3 ldd #1 std msp.pos+1,y make position unique tfr u,d exg a,b ldu msp.dir,y std dir.msd+msd.strt,u beq setdir4 ..ROOT ldu #0 bra setdir7 * setdir4 lbsr rootdat setdir7 bsr setsec setdir9 puls x,u,pc setsec cmpu msp.sec,y same sector? beq setsec9 stu msp.sec,y clr msp.sest,y ..sector buffer is not sector U setsec9 rts setcls tst msp.clss,y beq setcls0 std msp.cls,y setcls00 clr msp.clss,y bra setcls2 setcls0 cmpd msp.cls,y has cluster changed? beq setsec9 ..no std msp.cls,y setcls2 pshs d ldb msp.sest,y andb #^SECGOOD orb #SECBUF stb msp.sest,y msp.sec is OK but msp.cls is not setcls9 puls d,pc clss0 tst msp.clss,y bne setcls00 rts * make entry for entire disk setdisk pshs x,u ldx msp.dir,y *?????????????????? ldd #2 std dir.msd+msd.size,x ldu #1 .. if start cluster is 1 then entire disk is open bra setdir2 * make parent the current directory setparnt pshs x,u clrb clear carry ldu msp.cls,y is there a current directory? beq setdir9 ..no, its root lbsr readsec bcs setdir9 ..error ldu PD.BUF,y point to current directory ldd MSDSIZE+msd.strt,u get parent cluster exg a,b tfr d,u lbra setdir2 copydir pshs x,u copydir1 ldu msp.dir,y point to directory buffer leau dir.msd,u ldb #MSDSIZE copydir5 lda ,x+ sta ,u+ decb bne copydir5 puls x,u,pc ******************************************************* * find file with name at X in current directory * on entry: * B=DAT task number of file name * * return A=last character of name * B=mode(NE=directory) or error if carry set * X points to last character findname pshs d,x,y,u ldu msp.dir,y clra clrb stb msp.pos,y std msp.pos+1,y start of directory std dir.esec,u std dir.eoff,u ..entry not found ldd msp.cls,y get current cluster number (of subdirectory) std dir.prnt,u save it (for use by makdir) leau dir.msd,u point to place for file name pshs u tfr u,x lbsr clrname clear the directory entry ldx 4,s ldb 3,s task number lbsr movename lbeq findnerr sta 2,s this will be the character returned stx 4,s return value of X pshs d,x,y lbsr readit read the first sector in directory lbcs findn70 ..error findn52 lbsr secsiz get sector size lsra rorb lsra rorb lsra rorb lsra rorb lsra rorb number of directory entries per sector stb ,s ldx PD.BUF,Y point to directory buffer findn55 ldu 6,s point to file name stx 4,s ldb #11 number of bytes to compare * this section of code is used to save values * for the CREATE process lda ,x get first char of directory entry beq findn57 cmpa #$E5 unused entry? bne findn6 ..no findn57 pshs a ldx msp.dir,y ldd dir.esec,x unused entry already found? bne findn58 ..yes, ignore it ldd msp.sec,y get current sector number std dir.esec,x lbsr secsiz get sector size subd #1 anda msp.pos+1,y get position andb msp.pos+2,y get offset in sector std dir.eoff,x findn58 lda ,s+ bne findn7 bra findnNF ..file not found findn6 lda ,u+ cmpa ,x+ bne findn7 ..no match decb bne findn6 ..compare more * match found lbsr secsiz get sector size subd #1 anda msp.pos+1,y get position andb msp.pos+2,y std msp.pos+1,y ldx 4,s point to directory entry lbsr copydir copy directory entry lda msd.attr,x get attribute anda #attr.DR is it directory? sta 9,s beq findn67 ..no ldd msd.strt,x exg a,b lbsr setcls set cluster number findn67 leas 8,s fix stack clrb clear carry puls d,x,y,u,pc findn7 ldd msp.pos+1,y addd #MSDSIZE std msp.pos+1,y update directory entry position ldx 4,s leax MSDSIZE,x dec ,s end of sector? bne findn55 ..no findn72 lbsr readnxt read the next sector lbcc findn52 cmpb #E$EOF end of file? bne findn70 ..no report error findnNF ldb #E$PNNF path name not found findn70 coma set carry lda 8,s return last character read so CREATE can tell if name terminated OK. leas 10,s fix stack puls x,y,u,pc findnerr comb ldb #E$BPNam bad path name leas 4,s puls x,y,u,pc ******************************* * B is DAT task # * X points to file name * U point to destination * * On exit: * A is last character of name or first non-name character * B is number of bytes in name movename pshs d,u lda #11 sta 1,s findn2 OS9 F$LDABX get character leax 1,x sta ,s bsr validc check for valid file character beq findn5 cmpa #'. start of extension? bne findn4 ..no lda 1,s cmpa #11 first character? beq findn5 ..yes, illegal ldu 2,s leau 8,u point to start of extension lda #3 sta 1,s lda #SP sta ,u sta 1,u sta 2,u bra findn2 get next character findn4 tst 1,s beq findn45 ..past end of name sta ,u+ dec 1,s findn45 lda ,s bpl findn2 findn5 leax -1,x puls d,u pshs d,x leax <resrvd,pcr point to reserved names findn.3 clrb findn.5 lda ,x+ beq findn.9 anda #$7F cmpa b,u bne findn.7 incb lda -1,x end of name? bpl findn.5 ..no, check remainder of name lda b,u cmpa #SP end of file name? bne findn.3 ..no match clrb puls d,x,pc signal error in file name findn.9 puls d,x cmpb #11 no good characters in name? rts findn.7 leax -1,x findn.8 lda ,x+ bpl findn.8 bra findn.3 validc anda #$7f mask hi bit cmpa #'a blo findn3 cmpa #'z bhi findn3 anda #$5f findn3 cmpa #'! beq findnyes cmpa #'# blo findnno cmpa #') bls findnyes cmpa #'' beq findnyes cmpa #'- beq findnyes cmpa #'. start of extension? beq findnyes cmpa #'0 blo findnno cmpa #'9 bls findnyes cmpa #'@ blo findnno cmpa #'Z bls findnyes cmpa #'^ blo findnno cmpa #'` bls findnyes cmpa #'{ beq findnyes cmpa #'} beq findnyes cmpa #'~ beq findnyes findnno clra findnyes tsta rts resrvd fcs "AUX" fcs "COM1" fcs "COM2" fcs "CON" fcs "LPT1" fcs "LPT2" fcs "LPT3" fcs "NUL" fcs "PRN" fcb 0 ************************************************* * Subroutine: DirFull * * funtion - try to expand the directory * * On entry: * Y points to path descriptor * * On exit: * Carry set and error code in B if error * D offset to directory entry in sector buffer * X address of sector buffer * U sector number of sector at X DirFull ldd msp.cls,y is this root directory? bne dirfull1 ..no dirfull0 comb set carry ldb #E$SLF segment (directory) list full dirfret rts ..return error dirfull1 lbsr expchn add cluster to file bcs dirfret ..error * another entry point (MAKDIR) DirFull9 lbsr setcls save number of new cluster lbsr cluslog convert to logical sector number tfr d,u pshs u ldx PD.BUF,y point to sector buffer lbsr secsiz get sector size subd #MSDSIZE dirfull2 clr d,x clear the first byte of each directory entry subd #MSDSIZE bpl dirfull2 ldx PD.BUF,y lbsr sepecl get sectors per cluster deca only one? beq dirfull3 ..yes dirf25 pshs a leau 1,u lbsr dwritel write second sector of cluster puls a bcs dirfull4 ..error deca bne dirf25 dirfull3 clra return offset to unused directory entry (first) clrb dirfull4 puls u,pc ************************************************* * Subroutine: create1 * * funtion - make sure file can be created * * On entry: * Y points to path descriptor * U points to caller's register stack * * On exit: * Carry set and error code in B if error * D offset to directory entry in sector buffer * X address of sector buffer * U sector number of sector at X create1 lbsr findfile find the file bcs create2 ..can't OPEN file create10 ldb #E$CEF ..file already exists bra create25 ..report error create2 cmpb #E$PNNF file not found? beq create3 ..yes, create it cmpb #E$FNA beq create10 create25 coma set carry rts create3 tsta is file name hi bit terminated? bmi create5 ..yes cmpa #SP space or control? bls create4 ..yes ldb #E$BPNam cmpa #', comma? bne create25 ..report bad path name error create4 pshs y OS9 F$PrsNam skip trailing junk tfr y,x puls y create5 ldu PD.RGS,y point to stacked registers stx R$X,u return X pointing past name ldx msp.dir,y clra file can be read or written ldb R$B,u get file permissions bitb #WRITE.+PWRIT. create for write? bne create52 ..yes lda #attr.RO file is read only create52 bitb #DIR. is is subdirectory beq create53 ..no ora #attr.DR create53 sta dir.msd+msd.attr,x file access mode clra clrb std dir.msd+msd.size,x std dir.msd+msd.size+2,x set file size to 0 *** I'm not sure if MSDOS does it this way ldd #$FF0F end of file mark std dir.msd+msd.strt,x ..no clusters in file yet *** lbsr setdate copy date and time to dir entry ldu msp.dir,y ldx PD.BUF,y ldd dir.eoff,u get offset to entry in sector std msp.pos+1,y ldu dir.esec,u get sector number bne create58 ..there is room in directory lbsr DirFull .. directory full, expand if possible bcs create25 ..return error pshs d,x,u save pointer to directory entry, buffer and sector # tfr u,d ldu msp.dir,y std dir.esec,u update directory sector number bra create59 create58 lbsr dreadl read directory sector bcs create25 .. report error ldd msp.pos+1,y recover offset pshs d,x,u leax d,x point to start of entry ldu msp.dir,y create59 leau dir.msd,u point to directory info ldb #msd.res clrres clr b,u clear the reserved bytes in the directory incb cmpb #msd.time blo clrres ldb #msd.size clrsize clr b,u incb cmpb #MSDSIZE blo clrsize create6 lda ,u+ sta ,x+ copy entry into sector decb bne create6 puls d,x,u,pc ************************************************* * Subroutine: create * * funtion - create file (initialize path descriptor) * * On entry: * Y points to path descriptor * U points to caller's register stack * * On exit: * Carry set and error code in B if error create pshs x,u lda R$B,u anda #^DIR. can't create a directory sta R$B,u *** rev 2.3 * lda PD.CPR,y * sta msp.ncpr,y *** lbsr create1 bcs open10 ..return error *** rev 2.3 * clr msp.ncpr,y ..so driver will be freed after write *** lbsr dwritel update the directory lbsr lockeof get control of end of file lock bra open10 ************************************************* * Subroutine: open * * funtion - open file (initialize path descriptor) * * On entry: * Y points to path descriptor * U points to caller's register stack * * On exit: * Carry set and error code in B if error open pshs x,u lbsr findfile try to find the file open10 bcs openerr * check if file is already open tfr y,x open11 ldx msp.next,x beq open2 ..end of files reached with no match ldd msp.dnxt,x is it last path to file bne open11 ..no, check next one ldu msp.dir,x point to directory info ldb PD.DRV,y cmpb dir.drv,x is it on same drive? bne open11 ..no ldd msp.sec,y cmpd dir.loc,u same sector? bne open11 ..no ldd msp.pos+1,y cmpd dir.pos,u same entry? bne open11 ..no * path to same file has been found lda PD.MOD,y get access mode bita #SHARE. non-sharable? bne FileBusy ..yes, busy lda [msp.dir,y] get block number ldx <D.PthDBT os9 F$Ret64 return the directory entry to the system stu msp.dir,y point to matching entry bra open6 open2 ldu msp.dir,y point to directory info ldb PD.DRV,y get drive number stb dir.drv,u ldd msp.sec,y std dir.loc,u save sector number containing directory ldd msp.pos+1,y get current position std dir.pos,u open6 ldx dir.last,u point to previous path to same file beq open7 ..only one path to this file sty msp.dprv,x stx msp.dnxt,y open7 sty dir.last,u point to last path open to this file ldd dir.msd+msd.strt,u get starting cluster # exg a,b lbsr setcls set cluster number clra clrb std msp.pos,y we are at beginning of file stb msp.pos+2,y std msp.lksz,y no part of file is locked stb msp.lksz+1,y clr msp.sest,y sector buffer is invalid (and clear carry) puls x,u,pc FileBusy comb ldb #E$Share non-sharable file is busy openerr puls x,u lbra closef go return buffers etc. ************************************************* * Subroutine: chkeof * * function - make sure read will not go past end of file * * On entry: * Y points to path descriptor * U points to stacked registers * * On exit: * D number of bytes to read * Carry set and error in B if error chkeof ldd R$Y,u get number of bytes wanted pshs d,x,u * if read length is greater than what is left in file * then make length the remaining size of file ldu msp.dir,y point to directory entry info ldd dir.msd+msd.size,u get least significant part of file size exg a,b convert to Motorola format subd msp.pos+1,y pshs d ldb dir.msd+msd.attr,u get file attribute andb #attr.DR is it subdirectory? bne read08 ..yes ldd dir.msd+msd.size+2,u get most significant word of file size sbca #0 bcs readerr ..read past end of file suba msp.pos,y bcs readerr ..read past end of file bne read08 ..more than 2^16 bytes left in file ldd ,s beq readerr ..its end of file cmpd 2,s will we read past end of file? bhs read08 ..no std 2,s ..yes, don't read past end of file * read08 *** * lbsr readit make sure the buffer is good * bcc reader2 * bra reader1 *** clrb bra reader2 * readerr ldb #E$EOF reader1 stb 3,s comb reader2 leas 2,s puls d,x,u,pc ************************************************* * Subroutine: read * * function - read data from the open file * * On entry: * Y point to path descriptor * U point to stacked registers X=address to read to * Y=number of bytes * * On exit: * stacked register Y is number of bytes read * Carry set and error in B if error read clra bra read0 * read98 std msp.lksz,y stb msp.lksz+2,y read99 puls a,pc return with error ************************************************* * Subroutine: readln * * function - read a line from the open file * * On entry: * Y point to path descriptor * U points to stacked registers X=address to read to * Y=number of bytes * * On exit: * stacked register Y = number of bytes read * Carry set and error in B if error readln lda #EOL read0 pshs a read01 ldd R$Y,u beq read98 bsr chkeof bcs read99 *** * bsr chklck check for record lock * bcs read99 report error * beq read01 ..yes, try again *** ldx R$X,u get destination address pshs d,x clra clrb pshs d,x ldx <D.Proc ldb P$Task,x get task number pshs b lbsr getFAT read the FAT and set up sector buffer if needed lbcs read9 ..error readln0 ldu PD.BUF,y point to buffer lbsr secsiz get sector size leax d,u point to end of buffer subd #1 anda msp.pos+1,y get position andb msp.pos+2,y leau d,u point to start of data stx 3,s ldx 7,s readln1 ldd 1,s cmpd 5,s beq read2 addd #1 incriment byte count std 1,s ldb msp.sest,y bitb #SECGOOD is current sector good? bne readln12 ..yes lbsr readit ..no, read the correct one bcs read9 readln12 ldb ,s lda ,u+ get a byte OS9 F$STABX leax 1,x cmpu 3,s was last byte read the last in the sector? bne read25 ..no ldu PD.BUF,y ldb #SECREAD orb msp.sest,y andb #^SECGOOD stb msp.sest,y ..yes, sector is now completely read read25 tst 9,s EOL char? beq readln1 ..no cmpa 9,s is it end of line? beq read2 ..yes cmpa #MSDEOF end of text file? bne readln1 ..no read15 ldd 1,s subd #1 std 1,s read2 ldb PD.MOD,y get file access mode bitb #WRITE.+PWRIT. is file open for write? beq read26 ..no, don't lock the record ldd msp.pos,y std msp.lolk,y ldb msp.pos+2,y stb msp.lolk+2,y update start of file lock ldu PD.RGS,y ldd R$Y,u clr msp.lksz,y std msp.lksz+1,y update the lock size lbsr unlock unlock waiting procs read26 ldd 1,s addd msp.pos+1,y std msp.pos+1,y lda #0 adca msp.pos,y sta msp.pos,y update file position clrb clear carry ldd 1,s get byte read count ldu PD.RGS,y std R$Y,u bne read9 comb ldb #E$EOF return end of file error read9 leas 10,s rts return with carry set and error in B * ifeq 1 ************************************************* * Subroutine: chklck * * function - check if current position is locked * if it is, sleep until it is free * return error if deadlock or signal * * On entry: * D is current offset (plus 1) from msp.pos,y * Y points to path descriptor * * On exit: * Carry set and error in B if error chklck pshs x,y,u ldu msp.dir,y chklck0 ldx dir.last,u point to last path to this file chklck1 cmpx 2,s is it current path? beq chklck8 ..yes, ignore it ldd msp.lksz,x bne chklck2 tst msp.lksz+2,x beq chklck8 ..path has no lock chklck2 * check if path is locked * b?? chklck8 ..no * check if deadlock lda msp.LID,x get lock process waiting ID cmpa msp.ID,y is it waiting for current process? bne chklck5 ..no ldb #E$DeadLk ..yes, report deadlock bra chklck7 * make sure driver is not reserved chklck5 lbsr reldrvr * sleep lda msp.ID,x get ID of process we are waiting for sta msp.LID,y lda msp.ID,y sta msp.WID,y mark path as waiting ldx #0 OS9 F$SLEEP sleep until signalled pshs b,cc * remove path from locked list clr msp.WID,y mark path as not waiting clr msp.LID,y puls b,cc bcs chklck9 ..return error ldx <D.Proc ldb P$Signal,x was process signalled? beq chklck0 ..no, check for other locks chklck7 coma return signal which was received puls x,y,u,pc chklck8 ldx msp.dprv,x point to previous file bne chklck1 clrb chklck9 puls x,y,u,pc endc ************************************************* * Subroutine: write * * function - write data to the current position of the file * * On entry: * Y points to path descriptor * X point to data to write * D is the number of bytes to write * * On exit: * D is number of bytes written * Carry set and error in B if error write clra ..no end of line character bra write0 ************************************************* * Subroutine: writeln * * function - write data up to count or first EOL * to the current position of the file * * On entry: * Y points to path descriptor * U points to stacked register X=address of data * Y=number of bytes * * On exit: * stacked register Y is number of bytes written * Carry set and error in B if error writeln lda #EOL write0 ldb msp.wrt,y can we write? beq writln00 ..yes FNA comb ldb #E$FNA file is not accessible rts writln00 pshs a save EOL character ldx R$X,u point to data ldd R$Y,u get size of data lbeq read98 pshs d,x,u ldu PD.BUF,y point to buffer lbsr secsiz get sector size leax d,u point to end of buffer subd #1 anda msp.pos+1,y get position andb msp.pos+2,y leau d,u point to start of data clra clrb pshs d,x ldx <D.Proc ldb P$Task,x get task number pshs b *** * bsr chklck check if record is locked * bcs write9 *** ldx 7,s writln1 ldd 1,s cmpd 5,s beq write2 addd #1 incriment byte count std 1,s ldb msp.sest,y bitb #SECGOOD bne write12 ..yes lbsr seekwr get ready to write lbcs write9 write12 ldb ,s get task number OS9 F$LDABX get byte leax 1,x sta ,u+ ldb #SECUPD+SECGOOD sector is valid and needs update cmpu 3,s is it end of sector? bne writln15 ldu PD.BUF,y ldb #SECUPD+SECREAD sector needs update and next one writln15 stb msp.sest,y set sector status tst 11,s EOL char? beq writln1 ..no cmpa 11,s end of line? bne writln1 ..no write2 clra clrb stb msp.lksz,y std msp.lksz+1,y no part of file is locked after write ldd 1,s addd msp.pos+1,y std msp.pos+1,y lda #0 adca msp.pos,y sta msp.pos,y update file position * update file size if position is greater than current size write3 ldx msp.dir,y lda dir.chg,x ora #attr.AR set archive bit sta dir.chg,x ldb dir.msd+msd.attr,x get attribute bitb #attr.DR sub-directory? bne write35 ..yes, don't update size ldd dir.msd+msd.size+2,x get most significant file size cmpa msp.pos,y blo write35 ..position is past end of file bhi write36 ..position is not past end of file ldd dir.msd+msd.size,x get least sig file size exg a,b cmpd msp.pos+1,y bhs write36 ..position is not past end of file write35 ldd msp.pos+1,y exg a,b to INTEL format std dir.msd+msd.size,x update least sig size lda msp.pos,y sta dir.msd+msd.size+2,x update most sig size bsr lockeof write36 bsr unlock unlock path waiting for this one clrb clear carry ldd 1,s get byte read count ldu PD.RGS,y point to registers std R$Y,u return number of bytes written write9 leas 12,s rts return with carry set and error in B lockeof pshs b,cc ldd msp.pos,y std msp.lolk,y lda msp.pos+2,y sta msp.lolk+2,y clra clrb std msp.lksz,y inca sta msp.lksz+2,y puls b,cc,pc * unlock any waiting path(s) unlock ifeq 1 ldx msp.dir,y point to path which is waiting for this one ldx dir.last,x unlock2 lda msp.WID,x get waiting process ID beq unlock3 ..none ldb #S$Wake OS9 F$SEND wake up the waiting process unlock3 ldx msp.dprv,x bne unlock2 endc rts ******************************************************* * Subroutine: seekwr * * function - get ready to write to the current position * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error seekwr pshs d,x,u ldb msp.sest,y get buffer status bitb #SECUPD does sector need updating? beq seekwr2 ..no lbsr writsec update the sector bcs seekwr99 ldb msp.sest,y seekwr2 bitb #SECREAD is next sector the one we want? bne seekwr3 ..yes bsr expand bra seekwr4 seekwr3 bsr expnxt get number of next sector in the file seekwr4 bcs seekwr99 seekwr8 lbsr readsec bcs seekwr99 ldb #SECGOOD stb msp.sest,y seekwr9 clrb clear carry puls d,x,u,pc seekwr99 stb 1,s puls d,x,u,pc ******************************************************* * Subroutine: expand * * function - seek to the current file position * and expand file if needed * * On entry: * Y point to path descriptor * * On exit: * Carry set and error in B if error expand ldd msp.pos,y * * On entry: * D is position/256 to expand to * expand0 pshs d,u ldu msp.dir,y point to directory entry ldd dir.msd+msd.strt,u get number of first cluster exg a,b convert to Motorola format lbsr setcls set cluster number cmpd #$0FF8 blo expand3 ..not first cluster bsr expnxt0 add cluster if file is empty bcs expand9 exg a,b std dir.msd+msd.strt,u ..first cluster expand3 lbsr secsiz get sector size exg a,b pshs d ldd 2,s get 256 byte sector count *!!!!!!!!!!!!!!!!!!!!!!!!!!!! subd ,s++ subtract pages/sector blo expand4 ..position found std ,s bsr expnxt find next sector (add one if needed) bcs expand9 bra expand3 expand4 clrb expand9 leas 2,s puls u,pc expnxt0 pshs x,u expand from beginning of file bra expnxt00 expnxt pshs x,u seek or expand to next sector lbsr seeknxt expnxt00 cmpd #$FF8 blo expnxt1 ldd msp.cls,y last cluster in file lbsr expchn add next used cluster to chain bcs expnxt2 pshs d ldb msp.sest,y orb #SECEXP sector is expanded, don't read it stb msp.sest,y puls d lbsr clss0 first sector in cluster expnxt1 lbsr setcls0 set cluster number andcc #$fe clear carry expnxt2 puls x,u,pc ******************************************************* * Subroutine: seek * * function - seek to a new position in the file * * On entry: * Y points to path descriptor * U points to stacked registers * * On exit: * Carry set and error in B if error seek lbsr secsiz get sector size addd #1 tfr a,b andb R$U,u pshs b anda msp.pos+1,y cmpa ,s+ is seek within current sector? bne seek2 ..no, position is in different sector ldd R$X,u MSW cmpb msp.pos,y bne seek2 ..position is in different sector seek1 stb msp.pos,y ldd R$U,u std msp.pos+1,y update position in current sector clrb ..no error seek9 rts seek2 ldb msp.sest,y andb #SECUPD does sector need updating? beq seek3 ..no lbsr writsec write the current sector bcs seek9 ldb msp.sest,y seek3 andb #^(SECREAD!SECGOOD!SECUPD) sector is no longer valid stb msp.sest,y ldd R$X,u bra seek1 * Clear directory entry at X clrentry bsr clrname makd4 clr ,x+ clear the rest of the entry incb cmpb #MSDSIZE blo makd4 rts clrname clrb lda #SP makd3 sta ,x+ write spaces for file name incb cmpb #11 blo makd3 rts ******************************************************* * Subroutine: makdir * * function - make a new directory * * On entry: * Y points to path descriptor * U points to caller's register stack * * On exit: * Carry set and error in B if error makdir *** rev 2.3 * lda PD.CPR,y * sta msp.ncpr,y ..so disk driver won't be released *** lda R$B,u get access mode ora #DIR.+WRITE. set the directory bit anda #^(EXEC.+PEXEC.) sta R$B,u sta PD.MOD,y lbsr create1 create a new file lbcs closef close file and report error pshs x,u save offset, buffer address and sector # leax d,x point to directory entry pshs x clra clrb no clusters in file yet lbsr expchn add next unused cluster to chain puls x bcs closem close file and report error lbsr setcls save cluster number exg a,b convert to INTEL std msd.strt,x put starting cluster of new directory puls x,u get address and number of sector lbsr dwritel update the directory bcs closef ..error ldd msp.cls,y get cluster number of new directory lbsr DirFull9 ..clear directory entries bcs closef ..error pshs x,u bsr clrentry bsr clrentry ldx PD.BUF,y ldu msp.dir,y lda #attr.DR subdirectories sta msd.attr,x sta MSDSIZE+msd.attr,x ldd dir.msd+msd.time,u get time std msd.time,x std MSDSIZE+msd.time,x ldd dir.msd+msd.date,u get date std msd.date,x std MSDSIZE+msd.date,x ldd msp.cls,y get starting cluster number exg a,b std msd.strt,x ldd dir.prnt,u get parent directory start cluster exg a,b std MSDSIZE+msd.strt,x ldd #".. stb msd.name,x std MSDSIZE+msd.name,x puls x,u lbsr dwritel write the new subdirectory bcs closef lbsr writFAT update the file allocation table bra closef closem puls x,u bra closef ******************************************************* * Subroutine: close * * function - close the current path * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error close clra clear carry tst msp.cnt,y any duped paths? lbne close5 ..yes, don't deallocate ldb PD.MOD,y get access mode bitb #WRITE. open for write? beq close10 ..no ldb msp.sest,y get sector status bitb #SECUPD does sector need update? beq close1 ..no lbsr writsec write sector bcs closef close1 ldx msp.dir,y point to directory info ldb dir.stat,x update FAT? beq close10 ..no clr dir.stat,x lbsr writFAT update the FAT bcs closef close10 bsr writdir update the directory entry closef pshs cc,b save condition codes and B in case of error ldu PD.BUF,y point to sector buffer beq close3 ..no buffer lbsr secsiz get sector size os9 F$SRTMem return system memory close3 ldx msp.prev,y point to previous MSF path descriptor ldu msp.next,y beq close35 stx msp.prev,u bne close38 tfr u,x bra close37 close35 stx -2,s bne close38 close37 stx <D.MSF bra close4 close38 stu msp.next,x close4 ldx msp.dprv,y point to previous desc for same file ldu msp.dnxt,y point to next desc for same file beq close45 stx msp.dprv,u close45 stx -2,s bne close48 ldx msp.dir,y stu dir.last,x beq close47 .. no one is using directory entry bra close49 close48 stu msp.dnxt,x bra close49 close47 lda ,x get block number ldx <D.PthDBT os9 F$Ret64 return the directory entry to the system close49 ldx msp.dtb,y point to device table dec V.CNT,x *** mod so it works with VAR bne close50 ldu V.FAT,x beq close50 ..FAT hadn't been read clra clrb std V.FAT,x lda V.FS,x get FAT size (in pages) os9 F$SRTMem return system memory lda [V.BPB,x] get page number ldx <D.PthDBT OS9 F$Ret64 close50 bsr close5 release the driver for other use puls cc,b,pc return with error or not close5 *** rev 2.3 * clr msp.ncpr,y * lbra reldrvr release the driver for other use *** rts writdir ldx msp.dir,y ldb dir.chg,x has directory entry changed? beq writdir9 ..no writdir0 lda PD.CPR,y sta msp.ncpr,y so driver will remain locked clr dir.chg,x andb #attr.AR has file been updated? beq writdir1 ..no orb dir.msd+msd.attr,x set ARchive bit stb dir.msd+msd.attr,x lbsr setdate writdir1 ldd dir.msd+msd.strt,x exg a,b cmpd #1 bls permiss ldu dir.loc,x get directory sector # ldx PD.BUF,y point to buffer lbsr dreadl read the sector bcs writdir9 ..error pshs x,u ldu msp.dir,y ldd dir.pos,u get offset to entry leau dir.msd,u skip file name leax d,x ldb #MSDSIZE number of bytes to copy writdir2 lda ,u+ sta ,x+ decb bne writdir2 puls x,u lbsr dwritel write the updated sector writdir9 pshs cc,b bra close50 permiss comb ldb #E$BMode rts ******************************************************* * Subroutine: chgdir * * function - change the current execution or data directory * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error chgdir ldb PD.MOD,y get access mode orb #DIR. make sure we find a directory stb PD.MOD,y dec PD.CNT,y so file will close properly lbsr findfile open the directory lbcs closef close the file ldx <D.Proc point to the user process descriptor ldu msp.dir,y ldd dir.msd+msd.strt,u get starting cluster number exg a,b convert to motorola tfr d,u lda PD.DRV,y get drive number ldb PD.MOD,y get access mode bitb #READ.+WRITE. read or write? beq chgdir2 ..no sta P$DIO+2,x stu P$DIO+3,x chgdir2 bitb #EXEC. execution dir? beq chgdir4 ..no sta P$DIO+8,x stu P$DIO+9,x chgdir4 clrb lbra closef go close the file ******************************************************* * Subroutine: readit * * function read the current sector if it is valid * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error readit clrb clear carry pshs x,u ldb msp.sest,y get sector status bitb #SECGOOD is current sector OK? bne readit9 ..yes bitb #SECUPD does sector need updating? beq readit1 ..no lbsr writsec write the current sector bcs readit9 ldb msp.sest,y readit1 bitb #SECREAD read next sector? bne readnxt1 ..yes bsr seekit find cluster number of sector bcs readit9 bra readnxt2 * read the next sector in a file readnxt pshs x,u read the next sector in the file readnxt1 lbsr seeknxt seek to the next sector cmpd #$FF8 last cluster? bhs readit99 lbsr setcls0 set current cluster number readnxt2 lbsr readsec read the current sector bcs readit9 ldb #SECGOOD stb msp.sest,y readit9 puls x,u,pc readit99 coma set carry ldb #E$EOF puls x,u,pc ******************************************************* * Subroutine: seekit * * function - seek to the current file position * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error seekit pshs x,u ldd msp.cls,y beq seekit01 ..root directory cmpd #1 bne seekit03 ..not entire disk lbsr disksize seekit00 ldu #0 bra seekit02 seekit01 lbsr rootdat ldx msp.dtb,y ldx V.BPB,x lda ID.BPS+1,x get MSB of sector size skit012 lsra beq skit015 lslb bra skit012 skit015 clra ldx msp.dir,y std dir.msd+msd.size,x seekit02 lbsr setsec currect sector is start of root or disk ldx msp.dir,y lbsr secsiz get sector size pshs a ldd dir.msd+msd.size+1,x get file size exg a,b skit02 lsr ,s beq skit025 ..done lsra rorb divide number of 256 byte sector to get actual sectors bra skit02 skit025 leas 1,s leau d,u first sector past last one stu msp.end,y seekit03 lbsr clss0 first sector in cluster ldu msp.dir,y point to directory entry ldd dir.msd+msd.strt,u get number of first cluster exg a,b convert to Motorola format ldx msp.pos,y get position to seek to seekit1 cmpd #$FF8 end of chain? bhs readit99 ..yes lbsr setcls0 set current cluster number lbsr secsiz get sector size exg a,b pshs d tfr x,d subd ,s++ subtract pages/sector bcs seekit4 pshs d bsr seeknxt seek to the next sector puls x bra seekit1 seekit4 clrb seekit5 puls x,u,pc .. position has been found seekroot pshs u ldu msp.sec,y get current sector number leau 1,u cmpu msp.end,y end of directory or disk? bhs seekrt9 ..yes lbsr setsec ldd msp.cls,y puls u,pc seekrt9 lda #$FF return EOF indicator puls u,pc seeknxt ldd msp.cls,y root directory? cmpd #1 or entire disk? bls seekroot ..yes ldx msp.dtb,y point to drive info table lbsr sepecl get sectors per cluster deca cmpa msp.clss,y last sector in cluster? bne seeknxt8 ..no seeknxt7 ldd msp.cls,y get current cluster number ldx V.FAT,x point to FAT lbsr findnext find next cluster in chain lbsr clss0 ..it's the first sector in the cluster seeknxt9 rts seeknxt8 inc msp.clss,y point to next sector in cluster ldb msp.sest,y andb #^SECGOOD orb #SECBUF stb msp.sest,y clrb ldd msp.cls,y rts ******************************************************* * Subroutine: readsec * * function - read the current sector * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error readsec pshs x,u ldu msp.sec,y root directory? ldd msp.cls,y get cluster number cmpd #1 ROOT or entire disk? bls readsec2 ..yes bsr cluslog convert cluster number to logical sector # addb msp.clss,y add cluster sector # adca #0 tfr d,u readsec2 lbsr dreadl puls x,u,pc ******************************************************* * Subroutine: writsec * * function - write the current sector * * On entry: * Y points to path descriptor * * On exit: * Carry set and error in B if error writsec pshs x,u ldu msp.sec,y ldd msp.cls,y get cluster number cmpd #1 ROOT or entire disk bls writsec2 ..yes bsr cluslog convert cluster number to logical sector # addb msp.clss,y add cluster sector # adca #0 tfr d,u writsec2 ldx PD.BUF,y point to sector buffer lbsr dwritel bcs writsec9 ldb msp.sest,y get sector status andb #^SECUPD stb msp.sest,y ldx msp.dir,y point to directory info ldb dir.chg,x get directory change flag orb #attr.AR set the archive bit stb dir.chg,x writsec9 puls x,u,pc ************************************************* * Subroutine: cluslog * * function - convert cluster # to logical sector # * * On entry: * D is cluster # * Y points to path descriptor * * On exit: * D is logical sector # cluslog subd #2 pshs d,x,u lbsr rootdat get root info cluslog1 lsra cluster done? beq cluslog5 ..no lsl 1,s rol ,s multiply by 2 bra cluslog1 cluslog5 pshs u starting sector of directory addd ,s++ directory size + starting sector addd ,s++ + data offset puls x,u,pc ************************************************* * Subroutine: readFAT * * function - read the File Allocation Table * * On entry: * Y points to path descriptor * * On exit: * X points to FAT * Carry set if error (error code in B) readFAT ldb PD.DNS,y get density lslb andb #%00001010 get hi and double density bits orb #%01000000 1024 byte sector size ldx msp.dtb,y stb V.dns,x save density info pshs x,u ldd #1024 allow for up to 1k sector size sta V.FS,x current FAT size (it may change yet) OS9 F$SRQMEM lbcs readFAT9 stu V.FAT,x save pointer to FAT tfr u,x ldu #1 boot sector clrb side 0 lbsr dread read the boot sector lbcs readFAT8 ldb ,x get version byte tfr x,u ldx msp.dtb,y lda V.dns,x leax ID.skip,u point to disk information cmpb #$E9 version 2? beq maketabl ..yes cmpb #$EB version 3? beq maketabl ..yes bita #%00001000 is it hi density? bne maketabl ..yes, sector 0 must be good (FM R60) ldx msp.dtb,y ldb #%00100010 stb V.dns,x set up for double density 512 byte sectors tfr u,x ldu #$0002 track 0 sector 2 first sector of FAT clrb side 0 lbsr dread read the first sector of FAT lbcs readFAT8 ldb ,x get format type cmpb #$FC is it valid byte? lblo readFAT5 ..no leax doubles8,pcr nxttbl incb beq maketabl ..yes, table found leax IDsize,x point to next table bra nxttbl maketabl tfr x,u pshs y ldx <D.PthDBT os9 F$ALL64 allocate 64 bytes tfr y,x point x to buffer puls y lbcs readFAT5 ..no memory pshs u ldu msp.dtb,y stx V.BPB,u save pointer to disk info puls u pshs x leax 1,x lda #IDsize get size of info table maketlp ldb ,u+ stb ,x+ deca bne maketlp copy the disk info to safe place puls x point to info *** calculate usable clusters ldb ID.SPA,x cluster size pshs b ldd ID.res,x exg a,b pshs d lda ID.spf,x ldb ID.FATs,x mul pshs d ldd ID.RDE,x exg a,b lsra rorb lsra rorb lsra rorb lsra rorb divide directory entries by 16 to get sectors pshs d ldd ID.secs,x get total sectors exg a,b subd ,s++ subd ,s++ subd ,s++ usable sectors divsec lsr ,s end of cluster? beq divdone lsra rorb bra divsec divdone addd #2 std ID.clus,x save usable cluster count puls b *** calculate track density ldb #40 pshs b lda ID.spt,x get sectors/track ldb ID.hds,x get heads mul pshs d sectors/cylinder ldd ID.secs,x total sectors exg a,b calctrks subd ,s ble calctrk1 dec 2,s bne calctrks ldb #4 bra calctrk2 calctrk1 clrb calctrk2 leas 3,s lda ID.BPS+1,x lbeq readFAT5 ..sector size not supported lsla lsla lsla lsla pshs a lda ID.spf,x get sectors per FAT ldx 1,s orb V.dns,x andb #$f mask out density info orb ,s+ stb V.dns,x update density ldu V.FAT,x get FAT address pshs a save FAT sector count ldd #1024 buffer size OS9 F$SRTMem return the memory clra clrb std V.FAT,x lbsr secsiz get sector size tfr a,b lda ,s get FAT sector count calct2 lsrb beq calct3 lsla convert sectors to pages bra calct2 calct3 sta V.FS,x save FAT size (in pages) OS9 F$SRQMem puls a recover sector count bcs readFAT9 ..report error stu V.FAT,x onesec tfr u,x ldu #$0002 first sector of FAT RFloop pshs a clrb side 0 lbsr dread puls a bcs readFAT8 ..report error pshs a lbsr secsiz get sector size leax d,x puls a leau 1,u track 0 sector 3 deca bne RFloop ..more puls x ldx V.FAT,x clrb clear carry puls u,pc readFAT5 comb ldb #E$BTyp wrong media readFAT8 ldx ,s pshs b,cc ldu V.FAT,x get FAT address lda V.FS,x get FAT size clrb OS9 F$SRTMem return the memory puls b,cc readFAT9 ldx ,s pshs b,cc lda [V.BPB,x] get info buffer page number ldx <D.PthDBT OS9 F$Ret64 puls cc,b,x,u,pc ******************************************* * set the disk size disksize pshs x ldx msp.dtb,y ldx V.BPB,x point to disk info ldb ID.BPS+1,x get pages/sector pshs b ldd ID.secs,x get total number of sectors on disk disksiz3 lsr ,s beq disksiz5 ..done lsla rolb bra disksiz3 disksiz5 ldx msp.dir,y std dir.msd+msd.size+1,x save disk size clr dir.msd+msd.size,x clr dir.msd+msd.size+3,x puls a,x,pc ******************************************* * Subroutine: dreadl * * function read logical sector * * On entry: * U is logical sector number * Y points to path descriptor * * On exit: * D is garbage * data read to PD.BUF * Carry set and error in B if error dreadl pshs u,x * lbsr getFAT read the FAT and set up sector buffer if needed * bcs dreadl9 ..error * bne dreadl2 buffer was already set * bsr disksize this must be the first read of entire disk (@) dreadl2 ldb msp.sest,y is sector valid? beq dreadl5 ..no bitb #SECEXP bne dreadl8 ..yes, don't read sector cmpu msp.sec,y is it current sector? beq dreadl9 ..yes, return ldx <D.MSF follow file chain to see if other path has this sector ldb PD.DRV,y dreadl3 tst msp.sest,x is sector valid? beq dreadl4 ..no cmpb PD.DRV,x bne dreadl4 ..no cmpu msp.sec,x same sector? bne dreadl4 ..no stu msp.sec,y lbsr secsiz get sector size ldu PD.BUF,x leau d,u ldx PD.BUF,y leax d,x dreadl35 ldd ,--u std ,--x cmpx PD.BUF,y bne dreadl35 bra dreadl9 dreadl4 ldx msp.next,x point to next path bne dreadl3 dreadl5 stu msp.sec,y clr msp.sest,y ldx PD.BUF,y bsr logphys convert logical sector number to track/sector/side bsr dread read the sector bcs dreadl9 dread7 ldb #SECBUF mark sector as valid stb msp.sest,y indicate the buffer contains sector msp.sec dreadl9 puls x,u,pc dreadl8 stu msp.sec,y bra dread7 ******************************************* * Subroutine: dread * * Function - Read an MSDOS sector * * On entry: * X points to buffer * U MSB track #, LSB sector # * B - bit 0 set = side 1 * Y points to path descriptor * * On exit: * Carry Set and error in B if error dread pshs x pshs y ldy msp.dtb,y orb V.dns,y mask in track density (bit2 set=96tpi) ldy ,s recover y ldy PD.RGS,y pshs y clra tfr d,y ldb #SS.SREAD ifeq H6309-1 pshs pc,u,y,x,dp pshsw pshs d,cc else pshs pc,u,y,x,dp,d,cc push all parameters endc ldy R$Size+4,s point to path descriptor sts PD.RGS,y save pointer to register params lbsr getstat0 leas R$Size,s puls x,y stx PD.RGS,y puls x,pc ******************************************* * Subroutine: logphys * * function - convert logical sector number to * track/sector/side * * On entry: * U is logical sector number * Y points to path descriptor * * On exit: * B is side (0 or 1) * U is track and sector number logphys pshs x,y ldy msp.dtb,y ldy V.BPB,y point to disk info ldd ID.spt,y get sectors/track exg a,b logph0 pshs d save sectors/track ldx #0 start on track 0 tfr u,d logph1 subd ,s bcs logph5 ..track found leax 1,x bra logph1 logph5 addd ,s++ incb sector number to read pshs b tfr x,d tfr b,a ldb ID.hds,y get number of heads/sides decb double sided? beq logph6 ..no lsra divide tracks by 2 ldb #0 rolb logph6 pshs a track number puls u MSB=track, LSB=sector puls x,y,pc ************************************************* * Subroutine: writFAT * * function - write the File Allocation Table * * On entry: * Y points to path descriptor * * On exit: * X points to FAT * Carry set if error (error code in B) writFAT ldx msp.dtb,y lda V.FS,x get FAT size (in pages) lsra convert to sectors ldx V.FAT,x point to FAT pshs a,x,u ldu #$0002 track 0 sector 2 WFloop clrb side 0 bsr dwrite bcs writFAT9 lbsr secsiz get sector size leax d,x leau 1,u next sector dec ,s bne WFloop clrb writFAT9 puls a,x,u,pc ******************************************* * Subroutine: dwritel * * function - write logical sector * * On entry: * X points to buffer (512 bytes) * U is logical sector number * Y points to path descriptor * * On exit: * D is garbage * data written from X * Carry set and error in B if error dwritel pshs u stu msp.sec,y bsr logphys convert logical sector number to track/sector/side ldx PD.BUF,y lda msp.sest,y pshs a clr msp.sest,y bsr dwrite write the sector puls a bcs dwritel9 anda #^(SECUPD+SECEXP) ..sector doesn't need update anymore dwritel9 sta msp.sest,y puls u,pc ******************************************* * Subroutine: dwrite * * Function - Write an MSDOS sector * * On entry: * X points to buffer * U MSB track #, LSB sector # * B - bit 0 set - side 1 * Y points to path descriptor * * On exit: * Carry Set and error in B if error dwrite pshs x pshs y ldy msp.dtb,y orb V.dns,y set bit 2 if 96tpi ldy ,s recover y ldy PD.RGS,y pshs y clra tfr d,y ldb #SS.SREAD ifeq H6309-1 pshs pc,u,y,x,dp pshsw pshs d,cc else pshs pc,u,y,x,dp,d,cc push all parameters endc ldy R$Size+4,s point to path descriptor sts PD.RGS,y save pointer to register params lbsr putstat0 call the driver leas R$Size,s puls x,y stx PD.RGS,y puls x,pc ******************************************** * Subroutine: newdate * * function - place the date in the FD in * the files directory entry * * On entry: * X points to directory entry * U points to stacked registers (X point to FD) * * On exit: * date and time placed in entry newdate pshs d,x leas -6,s ldx <D.Proc ldb P$Task,x ldx R$X,u leax FD.DAT,x point to new date lda #5 size of date info pshs a,u leau 3,s newdate1 OS9 F$LDABX leax 1,x sta ,u+ dec ,s bne newdate1 clr ,u ..no seconds info available puls a,u bra setdate0 ******************************************** * Subroutine: setdate * * function - place the current date and time in * the files directory entry * * On entry: * X points to directory entry * * On exit: * date and time placed in entry setdate pshs d,x leas -6,s reserve space for time tfr s,x ldd <D.Proc user process pshs d ldd <D.SysPrc system process std <D.Proc os9 F$TIME puls x stx <D.Proc fix user process bcs setdate9 ..time not set setdate0 ldx 8,s point to time in directory clra clrb std dir.msd+msd.time,x ldd 4,s get minutes and seconds lsrb andb #%00011111 pshs b asla asla asla asla asla ora ,s+ combine with part of minutes sta dir.msd+msd.time,x ldd 3,s get hours and minutes lsrb lsrb lsrb andb #%00000111 pshs b lsla lsla lsla ora ,s+ sta dir.msd+msd.time+1,x clra clrb std dir.msd+msd.date,x ldd 1,s get month and day andb #$1f pshs b lsla lsla lsla lsla lsla ora ,s+ sta dir.msd+msd.date,x ldd ,s get year and month lsrb lsrb lsrb andb #1 suba #80 MSDOS is base 1980 not 1900 bcs setdate9 ..number too low pshs b lsla ora ,s+ sta dir.msd+msd.date+1,x setdate9 leas 6,s fix stack puls d,x,pc ******************************************************* * Subroutine: delete * * function - delete a file * * On entry: * Y points to path descriptor * U points to stacked registers * * On exit: * Carry set and error in B if error delete *** rev 2.3 * lda PD.CPR,y * sta msp.ncpr,y to lock out other processes *** lda PD.MOD,y get access mode ora #SHARE.+WRITE. sta PD.MOD,y make sure no one else is using file dec PD.CNT,y ..so file will close completely lbsr open open file bcs derror ldx msp.dir,y ldb #$E5 deleted entry mark stb dir.msd+msd.name,x lda #^attr.AR set all but the archive bit so entry (not date) will be updated sta dir.chg,x ldd dir.msd+msd.strt,x get starting cluster # exg a,b to MOTOROLA cmpd #1 is it ROOT or entire disk? bls CantDel ..no permission ldx msp.dtb,y ldx V.FAT,x point to file allocation table lbsr delchain delete the cluster chain for this file lbne close close the file damaged ldb #E$NES ..return non-existent segment (structure damaged) bra delerr derror rts CantDel ldb #E$FNA file not accessible delerr coma set carry lbra closef * return carry set if position is at end of file iseof ldx msp.dir,y ldb dir.msd+msd.attr,x get file attribute bitb #attr.DR is it subdirectory? bne isnteof ..yes ldd dir.msd+msd.size+2,x get MSW of file size cmpa msp.pos,y blo itiseof ..its past end of file bhi isnteof ..its not end of file ldd dir.msd+msd.size,x get LSW of file size exg a,b convert to MOTOROLA cmpd msp.pos+1,y bls itiseof ..its at or past end of file isnteof clrb rts itiseof comb rts .. return carry set if end of file ***************************************************** * getstat - get file options * * On entry: * Y points to path descriptor * U points to stacked registers * * On exit: * Carry set and error in B if error * Some stacked registers changed depending on status code getstat ldb R$B,u get status code cmpb #SS.Opt beq greturn ..return nothing cmpb #SS.Ready bne getst2 ..no noteof clr R$B,u ..return ready greturn rts getst2 cmpb #SS.EOF bne getst3 bsr iseof is it end of file? bcc noteof ..no comb ldb #E$EOF return end of file error rts getst3 cmpb #SS.Size get file size bne getst4 ..no ldx msp.dir,y ldd dir.msd+msd.size,x get LSW exg a,b std R$U,u LSW returned in U ldd dir.msd+msd.size+2,x exg a,b std R$X,u MSW returned in X rts getst4 cmpb #SS.Pos get file position bne getst5 ..no ldd msp.pos+1,y get LSW std R$U,u ldb msp.pos,y get MSW clra std R$X,u rts getst5 cmpb #SS.FD get FD sector? lbne getst6 ..no leas -16,s leave room for first part of FD sector ldx msp.dir,y ldb dir.msd+msd.attr,x get file attribute lda #READ.+WRITE. bitb #attr.RO read only? beq getst51 ..no lda #READ. getst51 bitb #attr.DR directory? beq getst52 ..no ora #DIR. getst52 sta ,s place attribute in FD buffer clra clrb std 1,s owner is user 0 sta 8,s link count is 0 ldd dir.msd+msd.size,x get LS file size exg a,b std 11,s ldd dir.msd+msd.size+2,x get MS file size exg a,b std 9,s ldd dir.msd+msd.time,x get time lsla rolb lsla rolb lsla rolb andb #%00111111 stb 7,s ldb dir.msd+msd.time+1,x get hour lsrb lsrb lsrb stb 6,s ldd dir.msd+msd.date,x get date anda #%00011111 sta 5,s day sta 15,s ldd dir.msd+msd.date,x lsrb rora lsra lsra lsra lsra sta 4,s sta 14,s month lda dir.msd+msd.date+1,x get year lsra adda #80 sta 3,s sta 13,s year ldx <D.Proc ldb P$Task,x get DAT task number ldy R$Y,u get byte count beq getst58 ldx R$X,u point to FD leau 16,s pshs u leau 2,s getst55 lda ,u+ getst56 OS9 F$STABX leax 1,x leay -1,y beq getst57 cmpu ,s into segment list? blo getst55 ..no clra bra getst56 getst57 leas 2,s fix stack getst58 leas 16,s rts getst6 cmpb #SS.ATTR get file attribute? bne getst7 ..no ldx msp.dir,y ldb dir.msd+msd.attr,x get file attribute stb R$X+1,u return attribute in LS byte of X rts getst7 getstat0 lda #D$GSTA *********************************************************** * CallDrvr - call a device driver subroutine * * On entry: * Y points to path descriptor * A is offset in subroutine dispatch table * * On exit: * carry set and error in B if error CallDrvr pshs d,x,y,u ldu PD.DEV,y point to device table ldu V$STAT,u point to static storage bra CallDr1 CallDr0 OS9 F$IOQu CallDr1 lda V.Busy,u is device busy? *** rev 2.3 * beq CallDr2 * cmpa PD.CPR,y *** bne CallDr0 ..yes, wait CallDr2 lda PD.CPR,y sta V.Busy,u current process is using device ldd ,s ldx 2,s bsr CallDr3 call driver subroutine ldy 4,s bsr reldrvr release driver for other's use bcc CallDr9 stb 1,s CallDr9 puls d,x,y,u,pc CallDr3 pshs d,x,pc ldx PD.DEV,y ldd V$DRIV,x point to driver module ldx V$DRIV,x addd M$Exec,x get execution offset addb ,s add execution offset adca #0 std 4,s puls d,x,pc go do driver subroutine * release the driver software for use by another process * Condition Codes not affected reldrvr pshs a,cc,u ldu PD.DEV,y point to device table ldu V$STAT,u point to static storage *** rev 2.3 * lda PD.CPR,y * cmpa V.Busy,u * bne reldrvr9 ..this process doesn't control driver * lda msp.ncpr,y * sta V.Busy,u device is no longer busy (maybe) *** clr V.Busy,u *** reldrvr9 puls a,cc,u,pc ***************************************************** * putstat - set file options * * On entry: * Y points to path descriptor * U points to stacked registers * * On exit: * Carry set and error in B if error * Some stacked registers changed depending on status code putstat ldb R$B,u get status code cmpb #SS.Opt bne putst2 rts putst2 cmpb #SS.Size set file size? bne putst3 ldd R$X,u get MSW of new size bne putst22 ldd R$U,u get LSW of new size bne putst22 ldx msp.dir,y ldd dir.msd+msd.strt,x get starting cluster exg a,b cmpd #$FF8 last cluster in file? beq putst21 ..yes, file is right size ldx msp.dtb,y ldx V.FAT,x point to FAT lbsr delchain delete the file cluster chain ldx msp.dir,y ldd #$FF0F std dir.msd+msd.strt,x set starting cluster number clrb putst21 rts putst22 ldd R$U,u get LSW of new size subd #1 convert to base 0 tfr a,b lda R$X+1,u get third byte of new size sbca #0 lbsr expand0 and expand file bcs putst21 ldd msp.cls,y get last cluster number ldx msp.dtb,y ldx V.FAT,x point to FAT lbsr findnext cmpd #$0FF8 last cluster? bhs putst24 ..yes lbsr delchain delete remainder of chain ldd msp.cls,y ldu #$FFF lbsr updFAT mark last cluster in file putst24 ldu msp.rgs,y point to stacked params ldx msp.dir,y ldd R$U,u get LSW exg a,b std dir.msd+msd.size,x ldd R$X,u get MSW stb dir.msd+msd.size+2,x set new file size clrb rts putst3 cmpb #SS.FD update file descriptor? bne putst4 ldx msp.dir,y point to directory entry lbsr newdate get the new date bra putst65 update the directory entry putst4 cmpb #SS.Lock lock/release record? bne putst5 ..no rts putst5 cmpb #SS.Ticks set lockout duration? bne putst6 ..no putst55 rts putst6 cmpb #SS.ATTR set file attribute? bne putst7 ..no ldx msp.dir,y ldb R$X+1,u return attribute in LS byte of X tfr b,a eorb dir.msd+msd.attr,x andb #attr.DR has directory changed beq putst64 ..no ldb dir.msd+msd.attr,x bitb #attr.DR are we removing directory attribute? beq putst63 ..no * make sure this is only path to file ldd msp.dnxt,y cmpd msp.dprv,y beq putst600 ..this is the only path to the directory comb ldb #E$Share report error, can't change to regular file rts because another process has directory open * make sure directory is empty * read the first sector putst600 ldx msp.pos,y clra clrb std msp.pos,y lbsr readit stx msp.pos,y bra putst620 putst60 lbsr secsize get sector size lsra rorb lsra rorb lsra rorb lsra rorb lsra rorb sector size / 32 = directory entries/sector ldx PD.BUF,y point to data buffer putst61 lda ,x beq putst630 cmpa #'. . or .. entry? beq putst610 ..yes, skip it cmpa #$E5 deleted? lbne permiss ..no permission, directory not empty putst610 leax MSDSIZE,x point to next entry decb bne putst61 ..next sector putst62 lbsr readnxt putst620 lda #0 sta msp.sest,y bcc putst60 cmpb #E$EOF beq putst630 ..yes, directory is empty coma set carry rts putst630 lda R$X+1,u ldx msp.dir,y bra putst64 putst63 anda #^attr.DR make sure directory bit is clear putst64 anda #attr.DR+attr.AR+attr.VL+attr.SY+attr.HD+attr.RO sta dir.msd+msd.attr,x set file attribute putst65 ldb dir.chg,x orb #^attr.AR directory entry is changed lbsr writdir0 update the directory putst69 rts putst7 cmpb #SS.RENAM rename file? bne putst8 ..no ldb #11 putst71 lda #SP pshs a decb bne putst71 ldx <D.Proc ldb P$Task,x DAT task number ldx R$X,u point to new name tfr s,u point to place for converted name lbsr movename beq putst79 ..bad name tsta bmi putst72 cmpa #SP space terminated? bls putst72 ..yes cmpa #', comma terminated? beq putst72 putst79 leas 11,s comb ldb #E$BPNam ..bad name rts putst72 pshs y os9 F$PrsNam skip trailing spaces tfr y,x puls y ldu PD.RGS,y stx R$X,u ldx msp.dir,y leax dir.msd,x ldb msd.attr,x get file attribute bitb #attr.DR subdirectory? beq putst73 ..no ldb 8,s is there a file extension? cmpb #SP bne putst79 ..yes, error putst73 ldb #11 putst74 puls a sta ,x+ decb bne putst74 copy new directory name ldx msp.dir,y bra putst65 and update directory entry putst8 cmpb #SS.ALLOW allow writes to directories and entire disk? bne putst9 ..no clr msp.wrt,y allow writes rts putst9 putstat0 lda #D$PSTA lbra CallDrvr call driver putstat routine ******************************************************* * Subroutine dispatch table modexec lbra create lbra open lbra makdir lbra chgdir lbra delete lbra seek lbra read lbra write lbra readln lbra writeln lbra getstat lbra putstat lbra close emod modlen equ * end