BUFFERS.A86
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:37k
源码类别:

操作系统开发

开发平台:

Asm

  1. title 'BUFFERS - buffer handling routines'
  2. ;    File              : $BUFFERS.A86$
  3. ;
  4. ;    Description       :
  5. ;
  6. ;    Original Author   : DIGITAL RESEARCH
  7. ;
  8. ;    Last Edited By    : $CALDERA$
  9. ;
  10. ;-----------------------------------------------------------------------;
  11. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  12. ;      
  13. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  14. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  15. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  16. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  17. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  18. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  19. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  20. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  21. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  22. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  23. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  24. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  25. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  26. ;    CIVIL LIABILITY.
  27. ;-----------------------------------------------------------------------;
  28. ;
  29. ;    *** Current Edit History ***
  30. ;    *** End of Current Edit History ***
  31. ;
  32. ;    $Log$
  33. ;
  34. ;    BUFFERS.A86 1.13 94/11/30 16:26:08 
  35. ;    added support for using multiple FAT copies on reads if one fails    
  36. ;    BUFFERS.A86 1.12 93/08/06 16:19:11
  37. ;    make geblk public    
  38. ;    BUFFERS.A86 1.8 93/07/07 21:06:25
  39. ;    Smirnoff'd
  40. ;    BUFFERS.A86 1.6 93/03/16 22:30:29
  41. ;    UNDELETE support changes
  42. ;    BUFFERS.A86 1.5 93/03/05 18:00:26
  43. ;    Fix bug clearing cluster of new sub directory
  44. ;    ENDLOG
  45. ; Date    Who Modification
  46. ; ---------  --- ---------------------------------------
  47. ;    9 Sep 91 Initial version created for VLADIVAR
  48. ;    3 mar 93 correct zeroblk bug
  49. NOLIST
  50. eject ! include i:fdos.equ
  51. eject ! include bdos.equ
  52. eject ! include i:doshndl.def
  53. eject
  54. LIST
  55. eject
  56. PCMODE_DATA dseg
  57. extrn current_ddsc:dword
  58. if DELWATCH
  59. extrn fdos_stub:dword
  60. endif
  61. BDOS_DATA dseg word
  62. fatrec rw 1 ; current FAT record
  63. fatbytl rb 1 ; low byte of split FAT entry
  64. fatbyth rb 1 ; high byte of split FAT entry
  65. split_fat rb 1 ; 0/FFh to indicate split entry
  66. eject
  67. extrn adrive:byte
  68. EXTRN chdblk:WORD
  69. EXTRN clsize:WORD
  70. EXTRN cur_dma:WORD
  71. EXTRN cur_dma_seg:WORD
  72. extrn dosfat:WORD
  73. EXTRN fatadd:WORD
  74. extrn lastcl:word
  75. EXTRN mult_sec:WORD
  76. EXTRN nfatrecs:WORD
  77. EXTRN nfats:WORD
  78. extrn pblock:dword
  79. extrn physical_drv:byte
  80. extrn psecsiz:word
  81. extrn rwmode:byte ; data/directory/FAT, read/write
  82. extrn secperclu:word
  83. extrn bcb_root:dword ; PCMODE disk buffer root
  84. extrn deblock_seg:word
  85. BDOS_CODE cseg
  86. extrn clus2sec:near
  87. extrn discard_dirbuf:near
  88. extrn fdos_error:near
  89. extrn flush_dirbuf:near
  90. extrn hshdscrd:near
  91. extrn read_block:near
  92. extrn select_adrive:near ; select drive AL
  93. extrn write_block:near
  94. public alloc_cluster ; allocate data block
  95. public alloc_chain ; allocate a chain
  96. public buffers_check ; check if buffers exist for this drive
  97. PUBLIC delfat ; release data blocks
  98. PUBLIC discard_all ; discard all buffers on ADRIVE
  99. public discard_dir ; discard directory buffers on ADRIVE
  100. public discard_dirty ; discard directory buffers on ADRIVE
  101. PUBLIC fixfat ; set value of FAT entry
  102. public flush_drive ; flush buffers to disk
  103. public locate_buffer ; locate a buffer
  104. PUBLIC update_dat ; flush write pending buffers
  105. public update_ddsc_free ; count free blocks on drive
  106. PUBLIC update_dir ; update directory entry
  107. PUBLIC update_fat ; write out modified FAT records
  108. public zeroblk ; zero cluster (MKDIR)
  109. if DELWATCH
  110. public allocate_cluster ; allocate free cluster on adrive
  111. public change_fat_entry ; write a new value into the FAT
  112. endif
  113. update_ddsc_free:
  114. ;----------------
  115. ; make sure DDSC_FREE is up to date
  116. ; a by-product of this is to checksum the FAT, so we can spot changes
  117. ; of removable media
  118. push es
  119. les bx,ss:current_ddsc
  120. mov cx,es:DDSC_FREE[bx] ; get current free space
  121.  jcxz update_ddsc_free30 ; if none recount to make sure
  122. inc cx ; is count uninitialised ? (=FFFF)
  123.  jz update_ddsc_free30 ; if so better count the free space
  124. update_ddsc_free10:
  125. pop es
  126. ret
  127. update_ddsc_free30:
  128. ; rebuild our free space count
  129. xor ax,ax ; assume no free space yet
  130. lea di,DDSC_BLOCK[bx] ; ES:DI -> DDSC_BLOCK
  131. stosw ; DDSC_BLOCK = 0
  132. stosw ; DDSC_FREE = 0
  133. inc ax ; skip reserved block #'s 0 and 1
  134. update_ddsc_free40:
  135. inc ax ; move to next data block #
  136. cmp ax,lastcl ; are we beyond end of disk
  137.  ja update_ddsc_free10 ; stop if all free blocks counted
  138. push ax ; save current index
  139. call getblk ; get contents of FAT entry, update ZF
  140. pop ax ; restore current FAT index
  141.  jnz update_ddsc_free40 ; try next block if not free
  142. inc es:DDSC_FREE[bx] ; one more free block
  143. jmps update_ddsc_free40 ; try next block
  144. discard_dirty:
  145. ;-------------
  146. ; This gets called after a write-protect error is returned
  147. mov ah,BF_DIRTY ; discard dirty FAT, dir & data
  148. jmps discard_buffers
  149. discard_all:
  150. ;-----------
  151. mov ah,BF_ISFAT+BF_ISDIR+BF_ISDAT
  152. jmps discard_buffers ; discard all the buffers
  153. discard_dir:
  154. ;-----------
  155. mov ah,BF_ISDIR ; dir only, leave data and FAT
  156. ; jmps discard_buffers
  157. discard_buffers:
  158. ;---------------
  159. ; entry: adrive = drive to discard
  160. ; AH = flags for type to discard i.e. BF_ISFAT, etc.
  161. mov al,adrive ; get the work drive
  162. call discard_dirbuf ; discard 32-byte directory buffer
  163. call hshdscrd ; discard hashing info for drive
  164. les si,bcb_root ; get first buffer
  165. discard_buffers10:
  166. cmp al,es:BCB_DRV[si] ; does the drive match?
  167.  jne discard_buffers20 ; try next one if not
  168. test ah,es:BCB_FLAGS[si] ; does the type match?
  169.  jz discard_buffers20 ; try next one if not
  170. mov es:BCB_DRV[si],0FFh ; else discard the buffer
  171. mov es:BCB_FLAGS[si],0
  172. discard_buffers20:
  173. if DOS5
  174. mov si,es:BCB_NEXT[si] ; get next buffer address
  175. cmp si,word ptr bcb_root
  176. else
  177. les si,es:BCB_NEXT[si] ; get next buffer address
  178. cmp si,0ffffh
  179. endif
  180.  jne discard_buffers10 ; and repeat until all done
  181. discard_buffers30:
  182. push ds ! pop es ; restore ES and return
  183. ret
  184. ;-------------
  185. buffers_check:
  186. ;-------------
  187. ; entry: AL = drive to check (preserved)
  188. ; AH = flags
  189. ; exit: ZF = 1 if all buffers clean on this drive
  190. push ds ; we use DS here cause it's quicker...
  191. lds si,ss:bcb_root ; start with most recently used
  192. buffers_check10:
  193. cmp al,BCB_DRV[si] ; check if for different drive
  194.  jne buffers_check20 ;   skip if not our problem
  195. test ah,BCB_FLAGS[si] ; test if its one we are looking for
  196.  jnz buffers_check30 ;   return with non-zero condition
  197. buffers_check20:
  198. if DOS5
  199. mov si,BCB_NEXT[si] ; get next buffer address
  200. cmp si,ss:word ptr bcb_root
  201. else
  202. lds si,BCB_NEXT[si] ; get next buffer address
  203. cmp si,0ffffh
  204. endif
  205.  jne buffers_check10 ; loop back if more to do
  206. xor dx,dx ; set ZF = 1
  207. buffers_check30:
  208. pop ds ; restore DS after BCBs done
  209. ret
  210. eject
  211. ; entry: AX = first block to release
  212. ; exit: AX and following released
  213. delfat: ; release chain of clusters
  214. ;------
  215. cmp ax,2 ; is block number too small?
  216.  jb delfat10 ; yes, then stop it
  217. cmp ax,lastcl ; is block number too large?
  218.  ja delfat10 ; yes, then stop it
  219. push ax ; else save the number
  220. call getblk ; get the next link
  221. xchg ax,cx ; CX = link
  222. pop ax ; AX = this block
  223. sub bx,bx ; set it to 0000
  224. push cx ; save the link for next pass
  225. call fixfat ; release the block
  226. pop ax ; AX = next block or end
  227. jmps delfat ; try again until all released
  228. delfat10: ; all blocks in chain freed
  229. ret
  230. ; On Entry:
  231. ; AX = block to read
  232. ; On Exit:
  233. ; AX = next FAT block index
  234. ;
  235. Public getnblk
  236. getnblk: ;UWORD getnblk(blk);
  237. ;-------
  238. ;
  239. push ax
  240. call getblk ; get current setting
  241. pop bx
  242.  jz getnblk10 ; return if something there
  243. ret
  244. getnblk10:
  245. mov ax,dosfat ; if unallocated then allocate it
  246. push ax
  247. xchg ax,bx ; AX = blk, BX = i
  248. call fixfat
  249. pop ax
  250. mov dx,ax ; DX = end of chain
  251. xor cx,cx ; no blocks follow this one
  252. ret
  253. ; On Entry:
  254. ; AX = block to read
  255. ; On Exit:
  256. ; AX = contents
  257. ; ZF = 1 if AX == 0000h (disk full)
  258. Public getblk
  259. ;------
  260. getblk:
  261. ;------
  262. push es ! push bx
  263. call fatptr ; get address of block AX in buffer
  264. mov ax,es:[bx] ; get the word from FAT
  265.  jnz getblk10 ; skip if on odd address (must be 12 bit)
  266. cmp dosfat,FAT12 ; else check if 16 or 12 bit
  267.  je getblk20 ; skip if even 12 bit
  268. pop bx ! pop es
  269. test ax,ax ; update ZF
  270. ret
  271. getblk10:
  272. shr ax,1 ; shift top 12 bits down
  273. shr ax,1
  274. shr ax,1
  275. shr ax,1
  276. getblk20:
  277. and ax,0FFFh ; leave bottom 12 bits only
  278. pop bx ! pop es
  279. ret
  280. alloc_cluster:
  281. ;-------------
  282. ; On Entry:
  283. ; AX = previous cluster (hint for desired start)
  284. ; On Exit:
  285. ; AX = start of chain
  286. ; CY set on failure
  287. ;
  288. mov cx,1
  289. ; jmp alloc_chain
  290. alloc_chain:
  291. ;-----------
  292. ; On Entry:
  293. ; AX = previous cluster (hint for desired start)
  294. ; CX = # clusters wanted
  295. ; On Exit:
  296. ; AX = start of chain, 0 on failure
  297. ; CY set on failure
  298. ;
  299. ; We want to allocate a chain of CX clusters, AX was previous cluster
  300. ; We return with CY clear and AX = 1st cluster in chain on success,
  301. ; CY set on failure
  302. ;
  303. ; When allocating a new chain we first ask SSTOR how much physical space is
  304. ; present on the disk. Until SSTOR reports at least 2 clusters free we
  305. ; repeatedly call DELWATCH to purge files and recover space. If DELWATCH is
  306. ; unable to free space we return "disk full".
  307. ;
  308. ; When allocating a block we normally are normally given a target block to
  309. ; start searching from. We allow DELWATCH to alter this value when it frees
  310. ; space to optimise the search.
  311. ;
  312. push ax ! push cx ; save entry parameters
  313. call update_ddsc_free ; make sure DDSC_FREE is correct
  314. if DELWATCH
  315. alloc_chain10:
  316. pop dx ! push dx ; DX = clusters wanted
  317. les bx,ss:current_ddsc
  318. mov cx,es:DDSC_FREE[bx] ; CX = clusters available
  319. mov al,adrive ; AL = current drive
  320. cmp cx,dx ; do we have enough room in the FAT ?
  321.  jb alloc_chain20 ; if not ask DELWATCH to purge
  322. mov ah,SSTOR_SPACE ; does Superstore have room for data?
  323. callf ss:fdos_stub ; call stub routine
  324. test cx,cx ; are we out of space ?
  325.  jnz alloc_chain40 ; no, go ahead and allocate the chain
  326. mov es:DDSC_FREE[bx],cx ; SSTOR says there's none, lets agree
  327. call update_fat ; flush FAT to bring SSTOR up to date
  328. jmps alloc_chain10 ; go round again and ask DELWATCH to
  329. ;  free up some more space
  330. ; we loop until either SSTOR says OK
  331. ;  or DELWATCH frees all it can
  332. alloc_chain20:
  333. mov ah,DELW_FREECLU ; ask DELWATCH to purge a file
  334. callf ss:fdos_stub ; call stub routine
  335. cmp cx,es:DDSC_FREE[bx] ; can DELWATCH free up any space ?
  336.  jne alloc_chain10 ; yes, go and try again
  337. alloc_chain30:
  338. pop cx ! pop ax ; failure, restore stack
  339. jmps alloc_chain80 ;  and exit in failure
  340. alloc_chain40:
  341. endif
  342. pop cx ! pop ax ; restore entry parameters
  343. push cx ; save # required
  344. call allocate_cluster ; try to allocate 1st cluster
  345. pop cx ; recover # required
  346. test ax,ax ; could we ?
  347.  jz alloc_chain80
  348. dec cx ; one less to allocate
  349. push ax ; save head of chain
  350.  jcxz alloc_chain60
  351. alloc_chain50:
  352. push cx
  353. push ax ; save current end of chain
  354. call allocate_cluster ; allocate another cluster
  355. pop bx ; BX = end of chain
  356. test ax,ax ; could we allocate anything ?
  357.  jz alloc_chain70 ; no, bail out and free partial chain
  358. xchg ax,bx ; AX = previous cluster, link cluster
  359. push bx ;  BX to end of the chain
  360. call fixfat
  361. pop ax ; AX = new end of chain
  362. pop cx
  363. loop alloc_chain50
  364. alloc_chain60:
  365. pop ax ; return the start of the chain as it's
  366. clc ;  long enough now...
  367. ret
  368. alloc_chain70:
  369. ; We haven't enough free clusters - lets free what we allocated so far
  370. pop cx ; discard count
  371. pop ax ; AX = start of chain
  372. call delfat ; release the chain
  373. alloc_chain80:
  374. xor ax,ax
  375. stc ; we couldn't manage it
  376. ret
  377. allocate_cluster:
  378. ;----------------
  379. ; On Entry:
  380. ; AX = cluster to start from (AX = none known)
  381. ; On Exit:
  382. ; AX = cluster allocated
  383. ;
  384. test ax,ax ; previous block known?
  385.  jnz alloc_cl10 ; skip if it is
  386. push ds
  387. lds bx,ss:current_ddsc
  388. mov ax,ds:DDSC_BLOCK[bx] ; else continue from last allocated block
  389. pop ds
  390. alloc_cl10:
  391. mov bx,lastcl ; highest block number on current disk
  392. cmp ax,bx ; is it within disk size?
  393.  jb alloc_cl20 ; skip if it is
  394. sub ax,ax ; start at the beginning
  395. alloc_cl20:
  396. mov si,ax ; remember start of search
  397. test ax,ax ; is this the 1st block?
  398.  jnz alloc_cl30 ; no
  399. inc ax ; start at beginning
  400. alloc_cl30: ; main loop:
  401. inc ax ; skip to block after current
  402. push ax ! push si ; quick save
  403. call getblk ; get the content of this block
  404. pop si ! pop ax
  405.  jz alloc_cl50 ; return if free
  406. cmp ax,bx ; are we at the end yet?
  407.  jb alloc_cl30 ; no, try next block
  408. xor ax,ax ; wrap to start of disk
  409. mov bx,si ; remember starting position last time
  410. test bx,bx ; have we been all the way round ?
  411.  jnz alloc_cl20 ;  no, lets search from start
  412. push ds
  413. lds bx,ss:current_ddsc
  414. mov ds:DDSC_FREE[bx],ax ; we definitely have none left
  415. pop ds
  416. ret ; return (0);
  417. alloc_cl50:
  418. push ds ; block # AX is available
  419. lds bx,ss:current_ddsc
  420. mov ds:DDSC_BLOCK[bx],ax ; remember for next time
  421. pop ds
  422. push ax
  423. mov bx,dosfat ; mark this block as end of file
  424. call fixfat ; for convenience
  425. pop ax
  426. test ax,ax ; update ZF from AX
  427. ret ; return block number
  428. if DELWATCH
  429. ; Update a FAT entry with a new value
  430. change_fat_entry:
  431. ;----------------
  432. ; On Entry:
  433. ; AX = block number to change
  434. ; DX = new value
  435. ; On Exit:
  436. ; None
  437. ;
  438. mov bx,dx
  439. ; jmps fixfat
  440. endif
  441. ; entry: AX = block number to change
  442. ; BX = new value
  443. ; exit: DS,ES = sysdat
  444. ;------
  445. fixfat:
  446. ;------
  447. push bx ; save new value
  448. push ax
  449. call update_ddsc_free ; make sure DDSC_FREE is correct
  450. pop ax
  451. cmp dosfat,FAT16 ; check if 16-bit FAT
  452.  jne fixfat30 ; skip if 12 bit FAT
  453. call fatptr ; ES:BX -> FAT word to modify
  454. pop ax ; restore new value
  455. xor dx,dx ; get a zero (no change of space)
  456. test ax,ax ; are we setting to 0 or non-zero?
  457. xchg ax,es:[bx] ; set the word in the buffer
  458.  jnz fixfat10 ; skip if releasing block
  459. test ax,ax ; check if word was 0 before
  460.  jz fixfat20 ; skip if setting 0 to 0
  461. inc dx ; DX = 0001h, one free cluster more
  462. jmps fixfat15
  463. fixfat10: ; allocating or fixing block
  464. test ax,ax ; check if word was 0 before
  465.  jnz fixfat20 ; skip if setting non-0 to non-0
  466. dec dx ; one free cluster less now
  467. fixfat15: ; DX = change in free space (-1,1)
  468. les si,current_ddsc
  469. add es:DDSC_FREE[si],dx ; update free space count
  470. fixfat20:
  471. les si,bcb_root ; ES:SI -> buffer control block
  472. or es:BCB_FLAGS[si],BF_DIRTY
  473. ; mark the buffer as dirty
  474. push ds ! pop es ; ES back to local DS
  475. ret
  476. ; We're dealing with a 12-bit FAT...
  477. fixfat30: ; changing 12-bit FAT entry
  478. call fatptr ; get address of block AX in ES:BX
  479. pop cx ; get new value
  480. mov dx,es:[bx] ; get old value
  481.  jz fixfat40 ; skip if even word
  482. mov ax,0FFF0h ; set mask for new value
  483. add cx,cx ; else shift new value into top bits
  484. add cx,cx
  485. add cx,cx
  486. add cx,cx
  487. jmps fixfat50 ; set the new word
  488. fixfat40:
  489. mov ax,00FFFh ; set mask for new value
  490. and cx,ax
  491. fixfat50: ; AX = mask, CX = new, DX = old
  492. mov si,0 ; assume space doesn't change
  493.  jnz fixfat60 ; skip if new value is zero
  494. test dx,ax ; test if old value was zero as well
  495.  jz fixfat70 ; yes, no change in free space
  496. inc si ; else one more block available
  497. jmps fixfat70
  498. fixfat60: ; new value is non-zero
  499. test dx,ax ; is old value non-zero as well?
  500.  jnz fixfat70 ; yes, no change in free space
  501. dec si ; else one block less free now
  502. fixfat70:
  503. not ax ; flip the mask bits around
  504. and dx,ax ; zero out old value
  505. or dx,cx ; combine old & new value
  506. mov es:[bx],dx ; update the FAT
  507. xchg ax,si ; AX = free space change (-1, 0 , 1)
  508. les si,current_ddsc
  509. add es:DDSC_FREE[si],ax ; update free space count
  510. les si,bcb_root ; get buffer control block
  511. or es:BCB_FLAGS[si],BF_DIRTY
  512. ; mark the buffer as dirty
  513. cmp split_fat,0 ; is 12-bit entry split across sectors
  514.  je fixfat80 ; need some magic if so
  515. ; handle a split FAT update
  516. mov dx,fatrec ; lower sector number
  517. inc dx ; get the upper sector
  518. call locate_fat ; find the buffer
  519. or es:BCB_FLAGS[si],BF_DIRTY
  520. ; mark buffer as write pending
  521. mov al,fatbyth ; get the high byte
  522. mov es:BCB_DATA[si],al ; store the high byte at the beginning
  523. mov dx,fatrec ; get the previous sector
  524. call locate_fat ; read into memory
  525. or es:BCB_FLAGS[si],BF_DIRTY
  526. ; mark buffer as write pending
  527. mov bx,psecsiz
  528. dec bx ; BX = sector size - 1
  529. mov al,fatbytl ; get the low byte
  530. mov es:BCB_DATA[si+bx],al
  531. fixfat80:
  532. push ds ! pop es ; ES back to local DS
  533. ret
  534. ; On Entry:
  535. ; AX = cluster number
  536. ; On Exit:
  537. ; AX preserved
  538. ; ES:BX -> address of word
  539. ; BCBSEG = segment of FAT FCB
  540. ; ZF = 1 if word on even address
  541. ; SPLIT_FAT = 0FFh if xing sector boundary
  542. ;
  543. ; CX = entries left in sector (if FAT16 - performance optimisation)
  544. ;
  545. Public fatptr
  546. fatptr:
  547. ;------
  548. push ax ; save block number
  549. mov bx,ax
  550. sub dx,dx ; AX/DX = cluster #
  551. cmp dosfat,FAT16 ; is it 16 bit FAT?
  552.  je fatptr10
  553. shr ax,1 ; shift for 1 1/2 byte, else 2 byte
  554. fatptr10:
  555. add ax,bx ; AX = offset into FAT
  556. adc dx,0 ; AX/DX = 32 bit offset
  557. mov cx,psecsiz ; CX = sector size
  558. div cx ; AX = sector offset
  559. dec cx ; CX = sector size - 1
  560. push dx ; DX = offset within FAT sector
  561. push cx
  562. add ax,fatadd ; make it absolute sector address
  563. mov fatrec,ax ; save FAT sector for FIXFAT
  564. xchg ax,dx ; DX = FAT sector
  565. call locate_fat ; locate the sector
  566. pop cx ; CX = sector size - 1
  567. pop bx ; restore offset within FAT sector
  568. pop ax ; restore cluster #
  569. sub cx,bx ; CX = bytes left in sector - 1
  570. lea bx,BCB_DATA[si+bx] ; ES:BX -> buffer data
  571. cmp dosfat,FAT16 ; is it 16 bit media
  572.  jne fatptr20 ; skip if 12 bit media
  573. shr cx,1 ; CX = extra entries left in sector
  574. cmp ax,ax ; always set ZF = 1
  575. ret ; return ES:BX -> word in FAT
  576. fatptr20: ; it's a 12 bit FAT, is it a split FAT?
  577. mov split_fat,0 ; assume no boundary crossing
  578.  jcxz fatptr30 ; end of sector, it's a split FAT
  579. test al,1 ; ZF = 1 if even cluster
  580. ret ; return ES:BX -> word in FAT buffer
  581. fatptr30: ; block split across two sectors
  582. push ax
  583. mov split_fat,0FFh ; yes, the difficult case
  584. mov al,es:[bx] ; get the low byte from 1st sector
  585. mov fatbytl,al ; save it for later
  586. mov dx,fatrec ; get the FAT record is
  587. inc dx ; get 2nd sector
  588. call locate_fat ; read the 2nd sector
  589. sub bx,bx
  590. lea bx,BCB_DATA[si+bx] ; ES:BX -> buffer data
  591. mov al,es:[bx] ; get 1st byte from next sector
  592. mov fatbyth,al ; save the high byte
  593. push ds ; ES = local DS
  594. pop es
  595. mov bx,offset fatbytl ; ES:BX -> <fatbytl,fatbyh>
  596. pop ax
  597. test al,1 ; set non-zero condition, odd word
  598. ret
  599. if DOS5
  600. ; entry: DX = sector number to read
  601. ; exit: ES:SI = BCB
  602. locate_fat:
  603. ;----------
  604. mov ah,0 ; set sector address overflow = 0
  605. mov cx,0ff00h+BF_ISFAT ; request a FAT buffer w/ preread
  606. locate_buffer:
  607. ;-------------
  608. ; On Entry:
  609. ; AH:DX = sector to locate
  610. ; adrive = driver
  611. ; CH = 0FFh if preread required
  612. ; CL = buffer type
  613. ; On Exit:
  614. ; ES:SI -> BCB_
  615. ;
  616. mov al,adrive ; get our drive number
  617. les si,bcb_root ; get it from the right buffer list
  618. locate10:
  619. cmp dx,es:BCB_REC[si] ; does our sector address match?
  620.  jne locate20 ; skip if it doesn't
  621. cmp ah,es:BCB_REC2[si] ; does record address overflow match?
  622.  jne locate20 ; skip if not
  623. cmp al,es:BCB_DRV[si] ; does the drive match?
  624.  je locate30 ; found if it all matches
  625. locate20: ; MRU buffer doesn't match
  626. mov si,es:BCB_NEXT[si] ; try the next
  627. cmp si,word ptr bcb_root ; while there are more buffers
  628.  jne locate10
  629. push ax ! push cx ! push dx ; save all registers
  630. mov si,es:BCB_PREV[si] ; recycle least recently used buffer
  631. call flush_buffer ; write buffer to disk
  632. pop dx ! pop cx ! pop ax ; restore all registers
  633. mov es:BCB_DRV[si],al ; fill in the BCB: drive
  634. mov es:BCB_REC[si],dx ;    record low,middle
  635. mov es:BCB_REC2[si],ah ;    record high
  636. mov es:BCB_FLAGS[si],cl ; mark as clean, ISFAT,ISDIR or ISDAT
  637. test ch,ch ; is preread required?
  638.  jz locate30 ; skip if it isn't
  639. call fill_buffer ; read it from disk
  640. locate30:
  641. cmp si,word ptr bcb_root ; are we already at the head ?
  642.  jne locate40 ;  if not move ourself there
  643. ret
  644. locate40:
  645. mov bx,es:BCB_NEXT[si] ; BX = next buffer
  646. mov di,es:BCB_PREV[si] ; DI = previous buffer
  647. mov es:BCB_NEXT[di],bx ; unlink buffer from the
  648. mov es:BCB_PREV[bx],di ;  chain
  649. mov bx,si
  650. xchg bx,word ptr bcb_root ; become the new head, BX = old head
  651. mov es:BCB_NEXT[si],bx ; old chain follow us
  652. mov di,si
  653. xchg di,es:BCB_PREV[bx] ; back link to our buffer, DI = LRU buffer
  654. mov es:BCB_PREV[si],di ; link ourselves to LRU buffer
  655. mov es:BCB_NEXT[di],si ; forward link to our buffer
  656. ret
  657. ; Flush all dirty FAT buffers for drive AL
  658. ; entry: AL = drive to flush (0-15)
  659. ; exit: CY = 0 if no error
  660. ; ax,bx,cx,dx,es preserved
  661. flush_fat:
  662. ;---------
  663. ; entry: AL = drive for FAT flush
  664. mov ah,BF_ISFAT ; flush all dirty FAT buffers
  665. jmps flush_drive ; shared code for all flushes
  666. ;----------
  667. update_dir:
  668. ;----------
  669. call flush_dirbuf ; flush local dirbuf to buffers
  670. ;---------
  671. flush_dir:
  672. ;---------
  673. mov ah,BF_ISDIR ; write out dirty directories
  674. jmps flush_adrive ; update the disk
  675. ;----------
  676. update_dat:
  677. ;----------
  678. mov ah,BF_ISDAT ; write out dirty data
  679. jmps flush_adrive ; update the disk
  680. ;----------
  681. update_fat: ;write out modified FAT buffers
  682. ;----------
  683. mov ah,BF_ISFAT ; flush all dirty FAT buffers
  684. ; jmp flush_adrive ; update the disk if dirty
  685. flush_adrive:
  686. ;------------
  687. mov al,adrive ; AL = currently selected drive
  688. ; jmp flush_drive
  689. ; Write out all dirty data buffers for a given drive
  690. ; entry: AL = drive to be flushed
  691. ; AH = mask of buffer types to be flushed
  692. ; exit: AX,DX preserved
  693. ; Note: sector buffers will be written in the
  694. ; sequence in which they appear on disk (low to high)
  695. flush_drive:
  696. ;-----------
  697. push es
  698. push si
  699. flush_drive10:
  700. les si,bcb_root ; start with the first buffer
  701. mov bx,0FFFFh ; assume no buffer found
  702. flush_drive20:
  703. test es:BCB_FLAGS[si],BF_DIRTY
  704. ; has buffer been written to?
  705.  jz flush_drive40 ; no, do the next one
  706. test es:BCB_FLAGS[si],ah ; is it one of these buffers?
  707.  jz flush_drive40 ; no, do the next one
  708. cmp al,es:BCB_DRV[si] ; does the drive match?
  709.  jne flush_drive40 ; skip if wrong drive
  710. ; we've found a buffer to flush
  711. cmp bx,0FFFFh ; first buffer ever found in list?
  712.  jz flush_drive30 ; yes, save as new best candidate
  713. ; else check if < previous lowest addr
  714. mov dx,es:BCB_REC[si]
  715. sub dx,ds:BCB_REC[bx]
  716. mov dl,es:BCB_REC2[si] ; compare the disk addresss
  717. sbb dl,ds:BCB_REC2[bx]
  718.  jnb flush_drive40 ; CY = 0 if new BCB higher
  719. flush_drive30: ; else ES = best BCB so far
  720. mov bx,si ; save it for later
  721. flush_drive40:
  722. mov si,es:BCB_NEXT[si] ; get next buffer address
  723. cmp si,ss:word ptr bcb_root
  724.  jne flush_drive20
  725. cmp bx,0FFFFh ; did we find a dirty buffer?
  726.  jz flush_drive50 ; no, all buffers cleaned
  727. mov si,bx ; ES:SI -> BCB to flush
  728. call flush_buffer ; write sector to disk
  729. jmps flush_drive10 ; check if more dirty buffers
  730. flush_drive50:
  731. pop si
  732. pop es
  733. ret
  734. else    
  735. ; entry: DX = sector number to read
  736. ; exit: ES:SI = BCB
  737. locate_fat:
  738. ;----------
  739. mov ah,0 ; set sector address overflow = 0
  740. mov cx,0ff00h+BF_ISFAT ; request a FAT buffer w/ preread
  741. locate_buffer:
  742. ;-------------
  743. ; On Entry:
  744. ; AH:DX = sector to locate
  745. ; adrive = driver
  746. ; CH = 0FFh if preread required
  747. ; CL = buffer type
  748. ; On Exit:
  749. ; ES:SI -> BCB_
  750. ;
  751. mov al,adrive ; get our drive number
  752. les si,bcb_root ; get it from the right buffer list
  753. mov bx,0FFFFh ; no previous buffers yet
  754. locate1:
  755. cmp dx,es:BCB_REC[si] ; does our sector address match?
  756.  jne locate2 ; skip if it doesn't
  757. cmp ah,es:BCB_REC2[si] ; does record address overflow match?
  758.  jne locate2 ; skip if not
  759. cmp al,es:BCB_DRV[si] ; does the drive match?
  760.  je locate6 ; found if it all matches
  761. locate2: ; MRU buffer doesn't match
  762. cmp es:BCB_LINK_OFF[si],0FFFFh
  763.  je locate3 ; are there more buffers?
  764. push es ! pop ds
  765. mov bx,si ; remember previous buffer
  766. les si,es:BCB_NEXT[si] ; move on to next buffer
  767. jmps locate1
  768. locate3: ; we found the LRU buffer
  769. push ax ! push cx ! push dx ; save all registers
  770. call pick_cheapest ; determine cheapest buffer
  771. ; ES:SI -> cheapest buffer
  772. ; DS:BX -> previous link
  773. test es:BCB_FLAGS[si],BF_DIRTY
  774.  jz locate5 ; skip if buffer not dirty
  775. mov al,es:BCB_DRV[si] ; get the buffer's drive
  776. mov ah,es:BCB_FLAGS[si] ; flush all buffers of same type
  777. and ah,BF_ISFAT+BF_ISDIR+BF_ISDAT
  778. push ss ! pop ds
  779. call flush_drive ; gives us burst mode behaviour
  780. ;   but might re-arrange buffers
  781. call find_prev ; find preceding BCB for re-link
  782. ; so DS:BX -> BCB_LINK == ES:SI
  783. locate5:
  784. pop dx ! pop cx ! pop ax ; restore all registers
  785. mov es:BCB_DRV[si],al ; fill in the BCB: drive
  786. mov es:BCB_REC[si],dx ;    record low,middle
  787. mov es:BCB_REC2[si],ah ;    record high
  788. mov es:BCB_FLAGS[si],cl ; mark as clean, ISFAT,ISDIR or ISDAT
  789. test ch,ch ; is preread required?
  790.  jz locate6 ; skip if it isn't
  791. push es ! push si
  792. push ds ! push bx ; save the previous buffer segment
  793. push ss ! pop ds ;    for unlinking our buffer
  794. call fill_buffer ; read it from disk, don't return
  795. ;    on physical errors
  796. pop bx ! pop ds
  797. pop si ! pop es
  798. locate6:
  799. cmp bx,0FFFFh ; are we the MRU buffer
  800.  jz locate9 ; yes, leave it at the head
  801. locate8: ; arrive here if found as not 1st
  802. mov ax,es:BCB_LINK_OFF[si]
  803. mov BCB_LINK_OFF[bx],ax
  804. mov ax,es:BCB_LINK_SEG[si]
  805. mov BCB_LINK_SEG[bx],ax ; unlink this buffer
  806. ; we now want to attach the
  807. push ss ! pop ds ;   BCB at ES:BX to the root
  808. mov ax,ds:word ptr bcb_root
  809. mov es:BCB_LINK_OFF[si],ax
  810. mov ax,ds:word ptr bcb_root+2
  811. mov es:BCB_LINK_SEG[si],ax
  812. mov ds:word ptr bcb_root,si ; insert the new entry
  813. mov ds:word ptr bcb_root+2,es
  814. locate9:
  815. push ss ! pop ds ; DS back to normal
  816. ret
  817. pick_cheapest: ; find cheapest replacement sector
  818. ;-------------
  819. ; entry: ES:SI = least recently used BCB
  820. ; DS:BX = previous buffer
  821. ; exit: ES, BX unmodified if LRU buffer marked as cheap
  822. ;        or no other cheap buffer found
  823. ; -or-
  824. ; ES:SI, DS:BX modified to cheapest buffer and previous buffer
  825. test es:BCB_FLAGS[si],BF_DIRTY
  826. ; is this buffer very expensive?
  827.  jz pck_chp5 ; return if it is cheapest "cheap" buffer
  828. ; else is cheapest "expensive" buffer
  829. ; find the cheapest "cheap" buffer
  830. les si,ss:bcb_root ; as we start at the root with
  831. mov ax,0FFFFh ;  no previous buffer
  832. pck_chp1: ; check if buffer at DS is cheap
  833. test es:BCB_FLAGS[si],BF_ISFAT+BF_ISDIR+BF_DIRTY
  834. ; check the "not cheap" flag
  835.  jnz pck_chp2 ; skip if expensive buffer
  836. mov ds,dx
  837. mov bx,ax ; remember previous buffer
  838. pck_chp2:
  839. mov dx,es ; remember this buffer
  840. mov ax,si ;  when we move onto next one
  841. les si,es:BCB_NEXT[si] ; get next buffer
  842. cmp si,0FFFFh ; end of the line ?
  843.  jne pck_chp1 ; go again if still buffers
  844. pck_chp3: ; done all buffers
  845. cmp bx,0FFFFh ; did we find the root ?
  846.  jne pck_chp4
  847. les si,ss:bcb_root ; return ES:SI -> root
  848. ret
  849. pck_chp4:
  850. les si,ds:BCB_NEXT[bx] ; ES:SI = cheapest buffer
  851. pck_chp5: ; ES:SI = cheapest buffer
  852. ret ; DS:BX = previous
  853. find_prev:
  854. ;---------
  855. ; entry: ES:SI = BCB to find previous buffer for
  856. ; exit: DS:BX = predecessor, BX = FFFF if first
  857. ;
  858. mov ax,es
  859. mov dx,si ; AX:DX -> buffer we want to find link for
  860. mov bx,0FFFFh ; assume it's the first buffer
  861. les si,ss:bcb_root ; we start at the root with
  862. find_prv1:
  863. mov cx,es
  864. cmp dx,si ; does offset match ?
  865.  jne find_prv2
  866. cmp ax,cx ; does segment match ?
  867.  je find_prv3 ; yes, return this one then
  868. find_prv2:
  869. mov ds,cx ; remember previous link
  870. mov bx,si
  871. les si,es:BCB_NEXT[si] ; else have a go at the next one
  872. jmps find_prv1 ; and repeat until match
  873. find_prv3:
  874. ret
  875. ; Flush all dirty FAT buffers for drive AL
  876. ; entry: AL = drive to flush (0-15)
  877. ; exit: CY = 0 if no error
  878. ; ax,bx,cx,dx,es preserved
  879. flush_fat:
  880. ;---------
  881. ; entry: AL = drive for FAT flush
  882. mov ah,BF_ISFAT ; flush all dirty FAT buffers
  883. jmps flush_drive ; shared code for all flushes
  884. ;----------
  885. update_dir:
  886. ;----------
  887. call flush_dirbuf ; flush local dirbuf to buffers
  888. ;---------
  889. flush_dir:
  890. ;---------
  891. mov ah,BF_ISDIR ; write out dirty directories
  892. jmps flush_adrive ; update the disk
  893. ;----------
  894. update_dat:
  895. ;----------
  896. mov ah,BF_ISDAT ; write out dirty data
  897. jmps flush_adrive ; update the disk
  898. ;----------
  899. update_fat: ;write out modified FAT buffers
  900. ;----------
  901. mov ah,BF_ISFAT ; flush all dirty FAT buffers
  902. ; jmp flush_adrive ; update the disk if dirty
  903. flush_adrive:
  904. ;------------
  905. mov al,adrive ; AL = currently selected drive
  906. ; jmp flush_drive
  907. ; Write out all dirty data buffers for a given drive
  908. ; entry: AL = drive to be flushed
  909. ; AH = mask of buffer types to be flushed
  910. ; exit: AX,DX preserved
  911. ; Note: sector buffers will be written in the
  912. ; sequence in which they appear on disk (low to high)
  913. flush_drive:
  914. ;-----------
  915. push ds
  916. push es
  917. push bx ; save registers
  918. push si
  919. flush_dr0:
  920. les si,ss:bcb_root ; start with the first buffer
  921. mov bx,0FFFFh ; assume no buffer found
  922. flush_dr1:
  923. test es:BCB_FLAGS[si],BF_DIRTY
  924. ; has buffer been written to?
  925.  jz flush_dr3 ; no, do the next one
  926. test es:BCB_FLAGS[si],ah ; is it one of these buffers?
  927.  jz flush_dr3 ; no, do the next one
  928. cmp al,es:BCB_DRV[si] ; does the drive match?
  929.  jne flush_dr3 ; skip if wrong drive
  930. ; we've found a buffer to flush
  931. cmp bx,0FFFFh ; first buffer ever found in list?
  932.  jz flush_dr2 ; yes, save as new best candidate
  933. ; else check if < previous lowest addr
  934. mov dl,es:BCB_REC2[si] ; compare the disk addresss
  935. sub dl,ds:BCB_REC2[bx]
  936. mov dx,es:BCB_REC[si]
  937. sbb dx,ds:BCB_REC[bx]
  938.  jnb flush_dr3 ; CY = 0 if old BCB lower
  939. flush_dr2: ; else ES = best BCB so far
  940. push es
  941. pop ds
  942. mov bx,si ; save it for later
  943. flush_dr3:
  944. les si,es:BCB_NEXT[si] ; get next buffer address
  945. cmp si,0ffffh
  946.  jne flush_dr1
  947. flush_dr4: ; DS:BX = best BCB
  948. cmp bx,0FFFFh ; did we find a dirty buffer?
  949.  jz flush_dr5 ; no, all buffers cleaned
  950. mov si,bx ; ES:SI -> BCB to flush
  951. push ds ! pop es
  952. push ss ! pop ds
  953. call flush_buffer ; write sector to disk
  954. jmps flush_dr0 ; check if more dirty buffers
  955. flush_dr5:
  956. pop si
  957. pop bx
  958. pop es
  959. pop ds ; restore registers
  960. ret
  961. endif   
  962. flush_buffer:
  963. ;------------
  964. ; entry: ES:SI = address of BCB
  965. ; exit: buffer flushed if BCB_FLAGS & BF_DIRTY
  966. ; note: preserves AX,BX,CX,DX,ES
  967. test es:BCB_FLAGS[si],BF_DIRTY
  968. ; is the buffer dirty?
  969.  jz flush_buf9 ; skip update if not modified
  970. flush_buf1:
  971. push es  !  push si
  972. push ax  !  push bx ; else save all registers
  973. push cx  !  push dx
  974. mov al,es:BCB_DRV[si] ; get the buffer drive
  975. cmp al,adrive ; same as the selected drive?
  976.  je flush_buf2 ; skip if already selected
  977. push es ; save the BCB
  978. push si
  979. push ds ! pop es ; ES = SYSDAT
  980. call select_adrive ; select drive AL, ZF = 1 if logged in
  981. pop si
  982. pop es ; recover BCB
  983.  jc flush_buf5 ; don't flush to bad drive
  984. flush_buf2:
  985. mov cx,nfats ; else FAT sectors written CX times
  986. mov al,0000$0011b ; mark as FAT write
  987. test es:BCB_FLAGS[si],BF_ISFAT
  988.  jnz flush_buf3 ; go ahead
  989. mov cx,1 ; directory/data written once only
  990. mov al,0000$0101b ; mark as directory write
  991. test es:BCB_FLAGS[si],BF_ISDIR
  992.  jnz flush_buf3 ; if not dir, must be data
  993. mov al,0000$0111b ; mark as data buffer write
  994. flush_buf3: ; CX = # of times to write sector
  995. mov rwmode,al
  996. sub ax,ax ; offset for write = 0
  997. flush_buf4: ; loop back to here for other copies
  998. push ax
  999. push cx ; save loop variables
  1000. call setup_rwx ; compute disk address
  1001. call write_buff ; write the sector
  1002. pop cx
  1003. pop ax
  1004. add ax,nfatrecs ; move to next FAT copy
  1005. loop flush_buf4 ; repeat for all FAT copies
  1006. flush_buf5:
  1007. and es:BCB_FLAGS[si],not BF_DIRTY
  1008. ; mark it as no longer dirty
  1009. mov al,physical_drv ; work drive for BDOS function
  1010. cmp al,adrive ; drive from last IO_SELDSK
  1011.  je flush_buf6 ; skip if flush to work drive
  1012. ; else reselect BDOS drive after flush
  1013. push ds ! pop es ; ES = SYSDAT
  1014. call select_adrive ; reselect the work drive
  1015. flush_buf6:
  1016. pop dx  !  pop cx ; restore all registers
  1017. pop bx  !  pop ax
  1018. pop si  !  pop es
  1019. flush_buf9: ; all done, CY = 0 if O.K.
  1020. ret
  1021. ;-------
  1022. zeroblk: ; AX = blk
  1023. ;-------
  1024. xor bx,bx ; Start at begining of cluster
  1025. call clus2sec ; translate to sector address
  1026. xchg ax,dx ; DX = low 16 bits of address
  1027. mov ah,al ; AH:DX = 24 bit sector address
  1028. mov cx,secperclu ; CX == sectors/cluster
  1029. zeroblk10: ; repeat for all sectors in cluster
  1030. push ax
  1031. push cx
  1032. push dx
  1033. mov cx,BF_ISDIR ; locate directory sector w/o preread
  1034. call locate_buffer ; this will find the cheapest buffer
  1035. or es:BCB_FLAGS[si],BF_DIRTY
  1036. lea di,BCB_DATA[si] ; ES:DI -> disk buffer
  1037. mov cx,psecsiz ; CX = byte count for REP STOSB
  1038. xor ax,ax
  1039. rep stosb ; zero the whole data buffer
  1040. pop dx
  1041. pop cx
  1042. pop ax
  1043. add dx,1 ; onto the next block
  1044. adc ah,0
  1045. loop zeroblk10 ; repeat for all sectors in cluster
  1046. jmp flush_dir
  1047. fill_buffer:
  1048. ;-----------
  1049. ; On Entry:
  1050. ; ES:SI = address of BCB to be filled
  1051. ; On Exit:
  1052. ; ES:SI preserved
  1053. ; data read into buffer
  1054. ;
  1055. test es:BCB_FLAGS[si],BF_ISFAT
  1056. ; are we reading a FAT sector?
  1057.  jz fill_buf1 ; skip if directory/data
  1058. mov al,es:BCB_DRV[si] ; get the drive
  1059. call flush_fat ; write out all dirty buffers
  1060. mov al,0000$0010b ; reading from FAT area
  1061. jmps fill_buf3 ; go ahead
  1062. fill_buf1:
  1063. mov al,0000$0100b ; else mark as directory
  1064. test es:BCB_FLAGS[si],BF_ISDIR; test if directory read
  1065. jnz fill_buf3 ; go ahead
  1066. fill_buf2: ; neither FAT nor directory => data
  1067. mov al,0000$0110b ; mark read as data buffer read
  1068. fill_buf3:
  1069. mov rwmode,al
  1070. push cx
  1071. xor cx,cx
  1072. cmp al,0000$0010b
  1073.  jne fill_buf4
  1074. mov cx,nfats
  1075. dec cx
  1076. fill_buf4:
  1077. mov es:BCB_DRV[si],0FFh ; discard in case of error
  1078. sub ax,ax ; no offset for 2nd copy yet
  1079. fill_buf5:
  1080. push ax
  1081. call setup_rwx ; compute disk address
  1082. call read_buff ; read the sector
  1083. pop ax
  1084.  jns fill_buf6
  1085. ; we can end here only if CX was non-zero above and we failed to read a
  1086. ; FAT copy while there is still another one we could use
  1087. add ax,nfatrecs
  1088. dec cx
  1089. jmps fill_buf5
  1090. fill_buf6:
  1091. pop cx
  1092. mov al,adrive ; restore the drive
  1093. mov es:BCB_DRV[si],al ; set the drive #
  1094. ret
  1095. read_buff:
  1096. ;---------
  1097. push es
  1098. push si ; save BCB_
  1099. push cur_dma_seg
  1100. push cur_dma ; save DMA address
  1101. push cx
  1102. mov cx,ss:deblock_seg
  1103.  jcxz read_buff10
  1104. mov cur_dma_seg,cx
  1105. mov cur_dma,0 ; xfer via deblocking buffer
  1106. read_buff10:
  1107. pop cx
  1108. call read_block
  1109. pop cur_dma ; restore DMA address
  1110. pop cur_dma_seg
  1111.  js read_buff20 ; can happen only on FAT read
  1112. mov cx,ss:deblock_seg ; if deblocked, copy data
  1113.  jcxz read_buff20
  1114. les di,dword ptr cur_dma ; point to destination
  1115. mov cx,psecsiz ; CX = sector size
  1116. shr cx,1 ; CX = words per sector
  1117. push ds
  1118. mov ds,ss:deblock_seg
  1119. xor si,si ; DS:SI = source
  1120. rep movsw ; copy the data
  1121. pop ds
  1122. read_buff20: ; SF still indicating error here
  1123. pop si ; recover BCB_
  1124. pop es
  1125. ret
  1126. write_buff:
  1127. ;----------
  1128. push es
  1129. push si
  1130. push cur_dma_seg
  1131. push cur_dma
  1132. mov cx,ss:deblock_seg ; if deblocking we have to
  1133.  jcxz write_buff10 ;  copy the data first
  1134. push ds ; save SYSDAT
  1135. les si,dword ptr cur_dma ; ES:SI -> source
  1136. push es ; save source seg 
  1137. mov es,cx
  1138. xor di,di ; ES:DI -> deblocking buffer
  1139. mov cur_dma_seg,es
  1140. mov cur_dma,di ; do xfer via deblocking buffer
  1141. mov cx,psecsiz ; CX = sector size
  1142. shr cx,1 ; CX = words per sector
  1143. pop ds ; DS:SI -> source
  1144. rep movsw ; copy to deblocking buffer
  1145. pop ds ; restore SYSDAT
  1146. write_buff10:
  1147. call write_block
  1148. pop cur_dma
  1149. pop cur_dma_seg
  1150. pop si
  1151. pop es
  1152. ret
  1153. setup_rwx:
  1154. ;---------
  1155. ; entry: AX = sector offset (multiple FAT writes)
  1156. ; ES:SI = BCB, BCB_REC filled in
  1157. ; exit: all values set up for RWXIOSIF
  1158. mov cur_dma_seg,es ; segment = BCB_SEGMENT
  1159. lea dx,BCB_DATA[si]
  1160. mov cur_dma,dx ; offset
  1161. xor dx,dx
  1162. add ax,es:BCB_REC[si]
  1163. adc dl,es:BCB_REC2[si]
  1164. mov word ptr pblock,ax ; xfer starts at this block
  1165. mov word ptr pblock+WORD,dx
  1166. mov mult_sec,1 ; single sector transfer
  1167. ret
  1168. END