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

操作系统开发

开发平台:

Asm

  1. ;    File              : $DISK.ASM$
  2. ;
  3. ;    Description       :
  4. ;
  5. ;    Original Author   : 
  6. ;
  7. ;    Last Edited By    : $Author: RGROSS$
  8. ;
  9. ;-----------------------------------------------------------------------;
  10. ;    Copyright Unpublished Work of Novell, Inc. All Rights Reserved.
  11. ;      
  12. ;    THIS WORK IS AN UNPUBLISHED WORK AND CONTAINS CONFIDENTIAL,
  13. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF NOVELL, INC.
  14. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) NOVELL, INC. EMPLOYEES
  15. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  16. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN NOVELL, INC. WHO
  17. ;    HAVE ENTERED INTO APPROPRIATE LICENSE AGREEMENTS. NO PART OF THIS
  18. ;    WORK MAY BE USED, PRACTICED, PERFORMED, COPIED, DISTRIBUTED,
  19. ;    REVISED, MODIFIED, TRANSLATED, ABRIDGED, CONDENSED, EXPANDED,
  20. ;    COLLECTED, COMPILED, LINKED, RECAST, TRANSFORMED OR ADAPTED
  21. ;    WITHOUT THE PRIOR WRITTEN CONSENT OF NOVELL, INC. ANY USE OR
  22. ;    EXPLOITATION OF THIS WORK WITHOUT AUTHORIZATION COULD SUBJECT
  23. ;    THE PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY.
  24. ;-----------------------------------------------------------------------;
  25. ;
  26. ;    *** Current Edit History ***
  27. ;    *** End of Current Edit History ***
  28. ;
  29. ;    $Log: $
  30. ;    DISK.ASM 1.1 93/11/18 17:20:12 RGROSS
  31. ;    
  32. ;    DISK.ASM 1.41 93/11/18 17:20:25 IJACK
  33. ;    
  34. ;    DISK.ASM 1.40 93/11/10 00:28:12 IJACK
  35. ;    Format changes so you can format your hard disk
  36. ;    DISK.ASM 1.39 93/11/08 21:47:25 IJACK
  37. ;    Add hidden sectors to ioctl format etc of hard disks
  38. ;    DISK.ASM 1.38 93/11/02 16:09:29 IJACK
  39. ;    Always zero BPB_HIDDEN_SECTORS on floppies - problem with PCW free disk which
  40. ;    has garbage in those fields.
  41. ;    DISK.ASM 1.37 93/10/18 17:33:18 IJACK
  42. ;    format c: fix
  43. ;    DISK.ASM 1.36 93/10/11 18:37:24 IJACK
  44. ;    media-change checks serial-numbers for 3.5" disks
  45. ;    DISK.ASM 1.35 93/10/06 22:09:16 IJACK
  46. ;    vec_save extrn replaced by orgInt13 extrn
  47. ;    DISK.ASM 1.34 93/09/03 20:13:32 IJACK
  48. ;    Fix bug in disk formatting
  49. ;    DISK.ASM 1.33 93/09/01 17:40:31 IJACK
  50. ;    update UDSC_TIMER after media check forced by drive change
  51. ;    (DBASE IV slow installation problem)
  52. ;    DISK.ASM 1.32 93/08/12 15:33:07 IJACK
  53. ;    Handle DMA error from multi-track read (ancient PC-XT hard disk)
  54. ;    DISK.ASM 1.31 93/08/03 15:29:01 IJACK
  55. ;    use serial numbers for media change detection
  56. ;    DISK.ASM 1.30 93/08/02 18:44:50 IJACK
  57. ;    don't trust the changeline if switching drives
  58. ;    DISK.ASM 1.29 93/08/02 18:38:19 IJACK
  59. ;    
  60. ;    DISK.ASM 1.28 93/08/02 14:47:38 IJACK
  61. ;    
  62. ;    DISK.ASM 1.27 93/07/29 21:00:24 IJACK
  63. ;    get rid of genpb_ptr and genpb_minor
  64. ;    DISK.ASM 1.26 93/07/26 21:18:25 IJACK
  65. ;    Correctly return UDSC_ root from Int 2F/0803
  66. ;    DISK.ASM 1.25 93/07/26 18:07:21 IJACK
  67. ;    Switch ms-windows to full screen when prompting for disk
  68. ;    DISK.ASM 1.24 93/07/23 17:34:27 IJACK
  69. ;    fix floppy/driver.sys support
  70. ;    DISK.ASM 1.23 93/07/22 20:37:42 IJACK
  71. ;    
  72. ;    DISK.ASM 1.22 93/07/22 19:43:46 IJACK
  73. ;    switch over to REQUEST.EQU
  74. ;    change floppy drive order, add get/set serial number
  75. ;    DISK.ASM 1.21 93/07/19 18:57:21 IJACK
  76. ;    Add header
  77. ;
  78. ;    ENDLOG
  79. include BIOSGRPS.EQU
  80. include DRMACROS.EQU ; standard DR macros
  81. include IBMROS.EQU ; ROM BIOS equates
  82. include REQUEST.EQU ; request header equates
  83. include BPB.EQU ; BIOS parameter block equates
  84. include UDSC.EQU ; unit descriptor equates
  85. include DRIVER.EQU ; device driver equates
  86. int_____DISK_INT macro
  87. call Int13
  88. endm
  89. FASTSETTLE equ FALSE ; disable "head settle == 0 ms"
  90. RETRY_MAX equ 3 ; do 3 retries if we get an error
  91. MAX_SPT equ 40 ; maximum sectors per track
  92. SECSIZE equ 512
  93. IDOFF equ SECSIZE-2 ; last word in boot sector is ID
  94. PTOFF equ IDOFF-40h ; 4*16 bytes for partition def's
  95. DOS20_ID equ 1 ; DOS 2.0 partition, < 4086 clusters
  96. DOS30_ID equ 4 ; DOS 3.0 partition, < 65536 sectors
  97. DOSEX_ID equ 5 ; DOS 3.3 extended partition
  98. DOS331_ID equ 6 ; COMPAQ DOS 3.31 partition > 32 Mb
  99. ; Now for the secure partition types
  100. SEC_ID          equ     0C0h            ; New DR secure partition types
  101. SEC_ID2         equ     0D0h            ; Old DR secure partition types
  102. page
  103. CGROUP group CODE, RCODE, ICODE, RESBIOS, IDATA
  104. CG equ offset CGROUP
  105. Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
  106. IVECT segment at 0000h
  107. org 0013h*4
  108. i13off dw ?
  109. i13seg dw ?
  110. org 001Eh*4
  111. i1eptr dd ?
  112. org 002Fh*4
  113. i2Foff dw ?
  114. i2Fseg dw ?
  115. org 0472h
  116. reset_flag dw ?
  117. org 0504h
  118. dual_byte db ? ; multiple drive byte at 50:4
  119. IVECT ends
  120. ROS segment at 0F000h
  121. org 0FFF0h
  122. reset proc far
  123. reset endp
  124. ROS ends
  125. CODE segment 'CODE'
  126. extrn endbios:word ; for device driver INIT function
  127. extrn read_system_ticks:near ; get system tick count in CX/DX
  128. extrn Int13Trap:near
  129. extrn Int2FTrap:near
  130. extrn orgInt13:dword
  131. extrn i13pointer:dword
  132. extrn i13off_save:word
  133. extrn i13seg_save:word
  134. extrn NumDiskUnits:byte
  135. extrn DeblockSeg:word
  136. extrn local_parms:byte
  137. extrn parms_spt:byte
  138. extrn parms_gpl:byte
  139. extrn local_buffer:byte
  140. extrn local_pt:word
  141. extrn local_id:word
  142. extrn layout_table:word
  143. extrn bpbs:word
  144. extrn bpb160:byte
  145. extrn bpb360:byte
  146. extrn bpb720:byte
  147. extrn NBPBS:abs
  148. extrn bpbtbl:word
  149. extrn req_off:word
  150. extrn req_seg:word
  151. udsc_root label dword
  152. dw -1,-1
  153. orig_int1e_off dw 522h
  154. orig_int1e_seg dw 0
  155. new_int1e_off dw 522h
  156. new_int1e_seg dw 0
  157. Public i13_AX
  158. i13_AX label word
  159. i13_size db ? ; number of sectors to xfer
  160. i13_op db ? ; Int13 Operation
  161. i13_dma_ptr label dword
  162. i13_dma_off dw ?
  163. i13_dma_seg dw ?
  164. activeRosUnit db ? ; currently active ROS unit
  165. include biosmsgs.def ; Include TFT Header File
  166. ifdef JAPAN
  167. extrn disk_msgA_jpn :byte
  168. extrn disk_msgB_jpn :byte
  169. endif
  170. ;disk_msgA db 13,10,'Insert disk for drive '
  171. ;disk_msgB db ': any press any key when ready ', 0
  172. page
  173. Assume DS:nothing, SS:nothing, ES:nothing
  174. CODE ends
  175. RCODE segment 'RCODE'
  176. extrn DataSegment:word
  177. even
  178. Int13 proc near
  179. clc
  180. push bp
  181. int DISK_INT
  182. pop bp
  183. ret
  184. Int13 endp
  185. ros_errors db 03h, 80h, 08h, 10h, 40h, 04h, 06h, 00h
  186. dos_errors db 00h, 02h, 04h, 04h, 06h, 08h, 0Fh, 0Ch
  187. NUMROSERR equ dos_errors - ros_errors
  188. ; The following  code  is required  in order  to cope  with
  189. ; application  programs  invoking  Int  13h  directly.   It
  190. ; handles applications  that format floppies  or access the
  191. ; disk via Int 13h after a floppy disk change.
  192. Assume CS:CGROUP, DS:Nothing, ES:Nothing, SS:Nothing
  193. Public Int13Unsure
  194. ;----------
  195. Int13Unsure proc far
  196. ;----------
  197. sti
  198. cld
  199. push ds
  200. mov ds,cs:DataSegment
  201. Assume DS:CGROUP
  202. call i13_unsure ; no longer sure of this drive
  203. pop ds
  204. ret
  205. Int13Unsure endp
  206. Public Int13Deblock
  207. ;-----------
  208. Int13Deblock proc far
  209. ;-----------
  210. ; handle user programs formatting the disk
  211. sti
  212. cld
  213. push ds
  214. mov ds,cs:DataSegment
  215. Assume DS:CGROUP
  216. pushx <es, bx, cx, si, di> ; save work registers
  217. mov i13_dma_off,bx
  218. mov i13_dma_seg,es
  219. i13_deblock10:
  220. pushx <cx, dx>
  221. mov cl,4
  222. mov ax,i13_dma_seg ; get transfer address
  223. shl ax,cl ; get A4..A15 from segment
  224. add ax,i13_dma_off ; combine with A0..A15 from offset
  225. not ax ; AX = # of bytes left in 64K bank
  226. xor dx,dx
  227. mov cx,SECSIZE
  228. div cx ; convert this to physical sectors
  229. mov dl,i13_size ; see if we can xfer amount wanted
  230. cmp al,dl ; capable of more than requested?
  231.  jb i13_deblock20 ; skip if we can do it all
  232. xchg ax,dx ; we can do them all
  233. i13_deblock20:
  234. les bx,i13_dma_ptr ; do the xfer to here
  235. popx <dx, cx>
  236. mov ah,i13_op ; get read/write/verify operation
  237. test al,al ; if zero length possible
  238.  jz i13_deblock30 ;  then deblock
  239. mov di,es ; get transfer address
  240. cmp di,DeblockSeg ;  is this in high memory ?
  241.  jb i13_deblock50 ;  then force through deblock buffer
  242. i13_deblock30:
  243. push ds ; if deblocking then we'd better
  244. pop es ;  point at local buffer we
  245. mov bx,CG:local_buffer ;  will be using for actual I/O
  246. cmp i13_op,ROS_WRITE
  247.  jne i13_deblock40 ; skip data copy if not writing to disk
  248. push ds
  249. push cx
  250. mov di,bx ; ES:DI -> local buffer
  251. lds si,i13_dma_ptr ; DS:SI -> data to write
  252. mov cx,SECSIZE/2
  253. rep movsw ; copy to deblocking buffer
  254. pop cx
  255. pop ds
  256. i13_deblock40:
  257. mov al,1 ; do a single sector via buffer
  258. clc
  259. pushf ; fake an Int
  260. call i13pointer ;  to the track handler
  261.  jc i13_deblock90 ; stop on error
  262. mov al,1 ; restore AL for buggy bios's
  263. cmp i13_op,ROS_READ ; if we are reading then we'll
  264.  jne i13_deblock60 ;  have to copy data out of
  265. push cx ;  the deblocking buffer
  266. les di,i13_dma_ptr ; ES:DI -> dest for data
  267. mov si,CG:local_buffer ; point at local buffer which
  268. mov cx,SECSIZE/2 ;  contains actual data
  269. rep movsw ; copy from deblocking buffer
  270. pop cx
  271. jmps i13_deblock60
  272. i13_deblock50:
  273. push ax ; save # sectors in xfer
  274. clc
  275. pushf ; fake an Int
  276. call i13pointer ; do the operation
  277. pop bx
  278. mov al,bl ; restore AL for buggy bios's
  279.  jc i13_deblock90 ; stop on error
  280. i13_deblock60: ; we succeeded in doing AL sectors
  281. sub i13_size,al ; forget about those we have done
  282.  jbe i13_deblock90 ;  and do more if there are any
  283. push ax
  284. mov ah,SECSIZE/16
  285. mul ah ; AX = paras to inc DMA address
  286. add i13_dma_seg,ax ;  up DMA address by this amount
  287. pop ax
  288. call i13_point_unit ; ES:DI -> UDSC_
  289.  jc i13_deblock90 ; exit if we can't find it
  290. mov bx,cx ; get sector/cylinder in BX
  291. and bx,0003Fh ; BX = sector
  292. and cx,0FFC0h ; CX = mandled cylinder bits
  293. add bl,al ; work out new sector
  294. i13_deblock70:
  295. mov ax,es:UDSC_BPB+BPB_SPT[di]
  296. cmp bx,ax ; still on the same track ?
  297.  jbe i13_deblock80 ; easy if no overflow onto next track
  298. sub bx,ax ; subtract a tracks worth
  299. inc dh ;  and move onto next head
  300. mov al,dh ; isolate head from cylinder
  301. and ax,003Fh ;  bits 10/11
  302. cmp ax,es:UDSC_BPB+BPB_HEADS[di]
  303.  jb i13_deblock70 ; onto next track yet ?
  304. and dh,0C0h ; back to head zero
  305. add ch,1 ; onto next track (bits 0-7)
  306.  jnc i13_deblock70 ; overflow to bits 8-9 ?
  307. add cl,040h ; yes, "inc" bits 8/9 of cylinder
  308.  jnc i13_deblock70 ; overflow to bits 10-11 ?
  309. add dh,040h ; yes, "inc" bits 10/11 of cylinder
  310. jmps i13_deblock70
  311. i13_deblock80:
  312. or cx,bx ; recombine sector/cylinder
  313. jmp i13_deblock10 ;  and do some more
  314. i13_deblock90:
  315. popx <di, si, cx, bx, es> ; restore work registers
  316. pop ds ; recover user DS
  317. ret 2 ; return to user with result
  318. i13_point_unit proc near
  319. ;-------------
  320. ; On Entry:
  321. ; DL = ROS unit
  322. ; On Exit:
  323. ; ES:DI -> UDSC_ for that unit
  324. ; All other regs preserved
  325. ;
  326. les di,udsc_root ; ES:DI -> 1st es:UDSC_
  327. i13_point_unit10:
  328. cmp dl,es:UDSC_RUNIT[di] ; find the physical unit
  329.  je i13_point_unit20
  330. les di,es:UDSC_NEXT[di]
  331. cmp di,0FFFFh ; else try the next es:UDSC_
  332.  jne i13_point_unit10
  333. mov ah,09h ; return DMA error to caller as we
  334. stc ;  don't know about this unit
  335. i13_point_unit20:
  336. ret
  337. i13_point_unit endp
  338. Int13Deblock endp
  339. i13_unsure proc near
  340. ;---------
  341. ; mark physical drive DL as unsure
  342. ;
  343. pushx <ds, si>
  344. lds si,udsc_root
  345. i13_unsure10:
  346. cmp dl,ds:UDSC_RUNIT[si] ; does it match ROS drive?
  347.  jne i13_unsure20 ; skip if not
  348. or ds:UDSC_FLAGS[si],UDF_UNSURE
  349. i13_unsure20: ; next drive
  350. lds si,ds:UDSC_NEXT[si]
  351. cmp si,0FFFFh
  352.  jne i13_unsure10
  353. popx <si, ds> ; restore registers
  354. ret
  355. i13_unsure endp
  356. Assume DS:Nothing, SS:Nothing, ES:Nothing
  357. Public Int2FHandler
  358. Int2FHandler proc far
  359. ;-----------
  360. ; On Entry we have offset/seg of next in chain on the stack
  361. ; (ie. we can pass on by a RETF)
  362. ;
  363. cmp ah,8 ; DRIVER.SYS support
  364.  je i2F_driver
  365. cmp ah,13h ; int13 intercept
  366.  jne i2F_iret
  367. ;
  368. ; Int 13 interception support
  369. ; ---------------------------
  370. ;
  371. ; On Entry:
  372. ; DS:DX -> New Int 13 vector
  373. ; ES:BX -> Int 13 vector restored by Int 19
  374. ;
  375. ; On Exit:
  376. ; DS:DX -> Old Int 13 vector
  377. ; ES:BX -> Old Int 13 vector restored by Int 19
  378. ;
  379. i2F_i13_intercept:
  380. mov ax,ds
  381. mov ds,cs:DataSegment
  382. Assume DS:CGROUP
  383. xchg dx,ds:i13off_save
  384. xchg ax,ds:i13seg_save
  385. push ax
  386. xchg bx,ds:word ptr orgInt13
  387. mov ax,es
  388. xchg ax,ds:word ptr orgInt13+2
  389. mov es,ax
  390. pop ds
  391. Assume DS:Nothing
  392. i2F_iret:
  393. iret
  394. ;
  395. ; DRIVER.SYS support
  396. ; -------------------
  397. ;
  398. ; On Entry:
  399. ; AX=0800, installation check
  400. ; AX=0801, add new block device at DS:SI
  401. ; AX=0802, execute driver request at ES:BX
  402. ; AX=0803, return address of first es:UDSC_
  403. ;
  404. i2F_driver:
  405. cmp al,1
  406.  jb i2F_driver_check
  407.  je i2F_driver_add
  408. cmp al,3
  409.  jb i2F_driver_req
  410.  je i2F_driver_point
  411. iret
  412. i2F_driver_check:
  413. ;
  414. ; Installation check
  415. ;
  416. mov al,0ffh ; say we are installed
  417. iret
  418. i2F_driver_add:
  419. ;
  420. ; Add new block device DS:DI
  421. ;
  422. push ds
  423. push es
  424. push ds
  425. pop es ; ES:DI -> unit
  426. mov ds,cs:DataSegment
  427. call add_unit
  428. pop es
  429. pop ds
  430. iret
  431. i2F_driver_point:
  432. ;
  433. ; return DS:DI -> first UDSC_
  434. ;
  435. mov ds,cs:DataSegment ; DS -> our data
  436. lds di,ds:udsc_root
  437. iret
  438. ;
  439. ; Execute DRIVER.SYS request ES:BX
  440. ;
  441. i2F_driver_req:
  442. push ds
  443. mov ds,cs:DataSegment
  444. Assume DS:CGROUP
  445. mov ds:req_off,bx ; fill in request pointer
  446. mov ds:req_seg,es ;  as if it was local
  447. pop ds
  448. Assume DS:Nothing
  449. push cs:driverTable ; fiddle the table address
  450. jmp DriverFunction ;  then go to normal handler
  451. extrn DriverFunction:near
  452. extrn IntDiskTable:word ; = DiskTable
  453. driverTable dw CG:IntDiskTable ; push address of table on
  454. ; stack as DriverFunction
  455. ; examines it
  456. Int2FHandler endp
  457. Assume DS:CGROUP, SS:Nothing, ES:Nothing
  458. Public DiskTable
  459. DiskTable label word
  460. db 24 ; Last supported function
  461. dw CG:dd_init ; 0-initialize driver
  462. dw CG:dd_medchk ; 1-media change check
  463. dw CG:dd_build_bpb ; 2-build BIOS Parameter Block
  464. dw CG:dd_error ; 3-IOCTL string input
  465. dw CG:dd_input ; 4-input
  466. dw CG:dd_error ; 5-nondestructive input (char only)
  467. dw CG:dd_error ; 6-input status (char only)
  468. dw CG:dd_error ; 7-input flush
  469. dw CG:dd_output ; 8-output
  470. dw CG:dd_output_vfy ; 9-output with verify
  471. dw CG:dd_error ; 10-output status (char only)
  472. dw CG:dd_error ; 11-output flush (char only)
  473. dw CG:dd_error ; 12-IOCTL string output
  474. dw CG:dd_open ; 13-device open
  475. dw CG:dd_close ; 14-device close
  476. dw CG:dd_remchk ; 15-removable media check
  477. dw CG:dd_error ; 16-n/a
  478. dw CG:dd_error ; 17-n/a
  479. dw CG:dd_error ; 18-n/a
  480. dw CG:dd_genioctl ; 19-generic IOCTL
  481. dw CG:dd_error ; 20-n/a
  482. dw CG:dd_error ; 21-n/a
  483. dw CG:dd_error ; 22-n/a
  484. dw CG:dd_getdev ; 23-get logical drive
  485. dw CG:dd_setdev ; 24-set logical drive
  486. driver proc near
  487. point_unit: ; get unit descriptor for work drive
  488. ;----------
  489. ; On Entry:
  490. ; ES:BX -> Request Header
  491. ; On Exit:
  492. ; AL = logical drive
  493. ; ES:DI -> es:UDSC_
  494. ; (All other registers preserved)
  495. ;
  496. mov al,es:RH_UNIT[bx] ; get the unit number (0=A:, 1=B:, etc)
  497. les di,udsc_root ; ES:DI -> 1st es:UDSC_
  498. point_unit10:
  499. cmp al,es:UDSC_DRIVE[di] ; stop if the logical drive matches
  500.  je point_unit20
  501. les di,es:UDSC_NEXT[di]
  502. cmp di,0FFFFh ; else try the next es:UDSC_
  503.  jne point_unit10
  504. pop ax ; don't return to the caller
  505. mov ax,RHS_ERROR+1 ; return "invalid unit" error
  506. point_unit20:
  507. ret
  508. add_unit: ; add a new unit to the list
  509. ;--------
  510. ; On Entry:
  511. ; ES:DI -> UDSC to add
  512. ; On Exit:
  513. ; ES:DI preserved
  514. ;
  515. mov al,es:UDSC_DRIVE[di] ; get the logical unit
  516. cmp al,MAXPART ; is it too many ?
  517.  jae add_unit40
  518. push ds
  519. mov es:word ptr UDSC_NEXT[di],0FFFFh
  520. ; make sure it's terminated
  521. and es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
  522. lea si,udsc_root ; DS:SI -> [first UDSC_]
  523. add_unit10:
  524. cmp ds:word ptr UDSC_NEXT[si],0FFFFh
  525.  je add_unit30
  526. lds si,ds:UDSC_NEXT[si] ; DS:SI -> UDSC_ we already have
  527. mov al,es:UDSC_RUNIT[di]
  528. cmp al,ds:UDSC_RUNIT[si] ; do the logical units match ?
  529.  jne add_unit10
  530. mov ax,ds:UDSC_FLAGS[si] ; inherit some flags
  531. push ax
  532. and ax,UDF_HARD+UDF_CHGLINE
  533. mov es:UDSC_FLAGS[di],ax ; hard disk/changeline inherited
  534. pop ax
  535. test ax,UDF_HARD
  536.  jnz add_unit10 ; skip owner stuff on hard drive
  537. test ax,UDF_VFLOPPY ; is this a multiple drive anyway ?
  538.  jnz add_unit20
  539. or ax,UDF_OWNER+UDF_VFLOPPY
  540. mov ds:UDSC_FLAGS[si],ax ; no, 1st person becomes owner
  541. add_unit20:
  542. or es:UDSC_FLAGS[di],UDF_VFLOPPY
  543. jmps add_unit10 ; go and try the next
  544. add_unit30:
  545. mov ds:word ptr UDSC_NEXT[si],di
  546. mov ds:word ptr UDSC_NEXT+2[si],es
  547. pop ds
  548. add_unit40:
  549. ret
  550. dd_error: ; 3-IOCTL string input
  551. ;--------
  552. mov ax,RHS_ERROR+3 ; "invalid command" error
  553. ret
  554. dd_medchk: ; 1-media change check
  555. ;---------
  556. ; entry: ES:BX -> request header
  557. ; exit: RH1_RETURN = 0, 1 or FF
  558. ;   00 = media may have changed
  559. ;   01 = media hasn't changed
  560. ;   FF = media has been changed
  561. call point_unit ; get unit descriptor
  562. test es:UDSC_FLAGS[di],UDF_HARD
  563.  jnz medchk2 ; "hasn't changed" if hard disk
  564. call ask_for_disk ; make sure we've got correct floppy
  565. mov ax,es:UDSC_FLAGS[di] ; get flags
  566. test ax,UDF_UNSURE ; has format/diskcopy occurred?
  567.  jnz medchk6 ; may have changed to different format
  568. test ax,UDF_CHGLINE
  569.  jz medchk3 ; skip ROS call if no change line
  570. mov dl,es:UDSC_RUNIT[di]
  571. mov al,dl ; don't trust changeline if we are
  572. xchg al,activeRosUnit ;  changing floppies
  573. cmp al,dl ; return may have changed
  574.  jne medchk3
  575. mov ah,ROS_DSKCHG ; get disk change status function
  576. int_____DISK_INT ; AH=0: DC low, AH=6: DC active
  577.  jc medchk5 ; disk change not active?
  578. medchk2:
  579. mov al,01h ; disk hasn't changed
  580. jmps medchk_ret
  581. medchk3: ; no changeline support, use timer
  582. call read_system_ticks ; get system tick count in CX/DX
  583. mov ax,dx
  584. xchg ax,es:UDSC_TIMER[di] ; get previous time and update
  585. sub dx,ax
  586. mov ax,cx
  587. xchg ax,es:UDSC_TIMER+2[di]
  588. sbb cx,ax ; CX/DX = # ticks since last access
  589.  jne medchk5 ; media could have changed if > 64k
  590. cmp dx,18*3 ; more than three seconds expired?
  591.  jb medchk2 ; "not changed" if access too recent
  592. medchk5:
  593. mov cx,1 ; read track 0, sector 1 (boot sector)
  594. call login_read ; to check the builtin BPB
  595.  jc medchk6 ; may have changed if read error
  596. mov al,local_buffer+11+BPB_FATID
  597. cmp al,0F0h ; check if we find a BPB
  598.  jb medchk6 ; may have changed if not good BPB
  599. cmp al,es:UDSC_BPB+BPB_FATID[di]
  600.  jne medchk8 ; has media byte changed ?
  601. mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
  602. lodsb ; get extended boot
  603. sub al,29h ; do we have an extended boot ?
  604.  je medchk7 ; no, test against our dummy value
  605. push cs
  606. pop ds ; DS:SI -> our dummy value
  607. mov si,offset CGROUP:dummyMediaID
  608. medchk7:
  609. push di
  610. lea di,UDSC_SERIAL[di]
  611. mov cx,2
  612. repe cmpsw ; is serial number unchanged ?
  613. pop di
  614.  je medchk6 ; then return may have changed
  615. medchk8:
  616. lea ax,UDSC_LABEL[di] ; ES:AX -> ASCII label
  617. lds bx,REQUEST[bp]
  618. mov ds:word ptr RH1_VOLID[bx],ax
  619. mov ds:word ptr RH1_VOLID+2[bx],es
  620. mov al,0FFH ; return disk changed
  621. jmps medchk_ret
  622. medchk6:
  623. mov al,00h ; disk may have changed
  624. medchk_ret:
  625. and es:UDSC_FLAGS[di],not UDF_UNSURE
  626. les bx,REQUEST[bp]
  627. mov es:RH1_RETURN[bx],al ; set return value
  628. sub ax,ax
  629. ret
  630. page
  631. dd_build_bpb: ; 2-build BIOS Parameter Block
  632. ;------------
  633. call point_unit ; get unit descriptor
  634. test es:UDSC_FLAGS[di],UDF_HARD
  635.  jnz bldbpb1 ; BPB doesn't change for hard disks
  636. call login_media ; try to determine media type (BPB)
  637.  jc bldbpb_err
  638. bldbpb1:
  639. mov es:UDSC_OPNCNT[di],0 ; no files open at this time
  640. and es:UDSC_FLAGS[di],not UDF_UNSURE
  641. ; media is sure
  642. lea si,UDSC_BPB[di]
  643. mov ax,es
  644. les bx,REQUEST[bp]
  645. mov es:RH2_BPBOFF[bx],si ; return the current BPB
  646. mov es:RH2_BPBSEG[bx],ax
  647. xor ax,ax
  648. ret
  649. bldbpb_err:
  650. jmp xlat_error ; return error code
  651. ; ret
  652. login_media: ; determine BPB for new floppy disk
  653. ;-----------
  654. push ds
  655. mov cx,1 ; read track 0, sector 1 (boot)
  656. call login_read ; to determine media type
  657.  jc login_media_err ; abort if physical error
  658. cmp local_buffer+11+BPB_FATID,0F0h
  659.  jb login_media10 ; fail unless FATID sensible
  660. lodsw ; get JMP instruction from boot sector
  661. xchg ax,bx ; save in BX
  662. lodsb ; get next 3rd byte in AX
  663. add si,8 ; skip JMP, OEM name, SI -> BPB
  664. cmp bl,0E9h ; does it start with a JMP ?
  665.  je login_media40
  666. cmp bl,069h
  667.  je login_media40
  668. cmp bl,0EBh ; how about a JMPS ?
  669.  jne login_media10
  670. cmp al,090h ; then we need a NOP
  671.  je login_media40
  672. login_media10:
  673. mov cx,2 ; read track 0, sector 2 (FAT)
  674. call login_read ; try to read the sector
  675.  jc login_media_err ; abort if physical error
  676. cmp word ptr 1[si],-1 ; bytes 1, 2 must be 0FFh, 0FFh
  677.  jne login_media30 ; default media if bad FAT
  678. lodsb ; else get FAT ID byte
  679. mov si,CG:bpb160 ; look through builtin BPB table
  680. mov cx,NBPBS ; # of builtin BPBs
  681. login_media20:
  682. cmp al,BPB_FATID[si] ; does it match one we know?
  683.  je login_media40 ; yes, use builtin BPB
  684. add si,BPB_LENGTH ; else move to next BPB
  685. loop login_media20 ; repeat for all BPBs
  686. login_media30: ; can't find that FAT ID
  687. lea si,UDSC_DEVBPB[di] ; use the default type
  688. push es
  689. pop ds ; use BPB at DS:SI ->
  690. login_media40:
  691. push di
  692. lea di,UDSC_BPB[di] ; ES:DI -> unit descriptor (UDSC)
  693. mov cx,UDSC_BPB_LENGTH ; size of a BPB (less reserved stuff)
  694. rep movsb ; copy into unit descriptor
  695. pop di
  696. mov es:UDSC_BPB+BPB_SECSIZ[di],SECSIZE
  697. ; mov cx,0
  698. mov es:word ptr (UDSC_BPB+BPB_HIDDEN)[di],cx
  699. mov es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di],cx
  700. cmp si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11
  701.  jne login_media50 ; is the BPB from the boot sector ?
  702. ; mov ax,ds ; if so then check for media id
  703. ; cmp ax,cs:DataSegment ; seg check redundant as UDSC_DEVBPB
  704. ;  jne login_media50 ;  is followed by 7 bytes of zero
  705. lodsw ; skip 2 bytes
  706. lodsb ; now get possible boot signature
  707. cmp al,29h ; is it an extended boot sector ?
  708.  je login_media60 ; yes, use it
  709. login_media50:
  710. push cs
  711. pop ds ; DS:SI -> our dummy value
  712. mov si,offset CGROUP:dummyMediaID
  713. login_media60:
  714. call UpdateMediaID ; update UDSC_ with media info
  715. clc
  716. login_media_err:
  717. pop ds
  718. ret
  719. dummyMediaID dd 0 ; serial number 0
  720. db 'NO NAME    '
  721. db 'FAT12   '
  722. UpdateMediaID:
  723. ;-------------
  724. ; On Entry:
  725. ; DS:SI -> extended boot record info
  726. ; ES:DI -> UDSC_ to update
  727. ; On Exit:
  728. ; ES:DI preserved
  729. ;
  730. push di
  731. xor ax,ax ; AX = a handy zero
  732. lea di,UDSC_SERIAL[di]
  733. movsw
  734. movsw ; copy serial number
  735. pop di
  736. push di
  737. lea di,UDSC_LABEL[di]
  738. mov cx,11
  739. rep movsb ; copy the volume label
  740. stosb ; zero terminate it
  741. pop di
  742. push di
  743. lea di,UDSC_FSTYPE[di]
  744. movsw
  745. movsw
  746. movsw
  747. movsw ; copy the file system type
  748. stosb ; zero terminate it
  749. pop di
  750. ret
  751. login_read:
  752. ; entry: CH, CL = cylinder/sector to read
  753. ; exit: CY = 1, AH = status if error
  754. ; else local_buffer filled in
  755. mov dl,es:UDSC_RUNIT[di] ; DL = ROS drive
  756. mov dh,0 ; DH = head number
  757. login_read_dx: ; read on drive DL, head DH
  758. ;------------- ; (entry for hard disk login)
  759. mov P_RETRY[bp],RETRY_MAX ; initialize retry count
  760. logrd1:
  761. push es
  762. mov ax,ROS_READ*256 + 1 ; read one sector from ROS
  763. push ds
  764. pop es ; ES = DS = local segment
  765. mov bx,CG:local_buffer
  766. int_____DISK_INT ; call the ROM BIOS
  767. pop es
  768.  jnc logrd3 ; skip if no disk error
  769. push ax
  770. ; mov ah,ROS_RESET
  771. xor ax,ax
  772. int_____DISK_INT ; reset the drive
  773. pop ax
  774. dec P_RETRY[bp]
  775.  jnz logrd1 ; loop back if more retries
  776. logrd2:
  777. stc
  778. logrd3:
  779. mov si,CG:local_buffer
  780. ret
  781. page
  782. dd_output: ; 8-output
  783. ;---------
  784. mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
  785. jmps io_common
  786. dd_output_vfy: ; 9-output with verify
  787. ;-------------
  788. mov P_ROSCMD[bp],ROS_VERIFY ; write & verify floppy/hard disk
  789. jmps io_common
  790. dd_input: ; 4-input
  791. ;--------
  792. mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
  793. ; jmps io_common
  794. io_common: ; common code for the above three
  795. call point_unit ; get unit descriptor
  796. call ask_for_disk ; make sure we've got correct floppy
  797. call setup_rw ; setup for read/write operation
  798.  jc io_ret ; return if bad parameters
  799. io_loop:
  800. call track_rw ; read as much as possible on track
  801.  jc xlat_error ; return if physical disk error
  802. cmp P_COUNT[bp],0 ; test if any more stuff to read
  803.  jne io_loop ; yes, loop back for more
  804. mov al,es:UDSC_RUNIT[di] ; remember the drive that is active
  805. mov activeRosUnit,al
  806. test es:UDSC_FLAGS[di],UDF_HARD+UDF_CHGLINE
  807.  jnz io_exit ; skip timer read for hard/changeline
  808. call read_system_ticks ; get system tick count in CX/DX
  809. mov es:UDSC_TIMER[di],dx
  810. mov es:UDSC_TIMER+2[di],cx ; save time of successful access
  811. io_exit:
  812. xor ax,ax ; all done, no error encountered
  813. io_ret:
  814. ret
  815. xlat_error: ;  translate ROS error to DOS error
  816. ;----------
  817. ; entry: AH = ROS disk error code, CY = 1
  818. ; exit: AX = status to be returned to BDOS
  819. pushx <es, di> ; save some registers
  820. mov al,ah ; AL = ROS error code
  821. push cs
  822. pop es
  823. mov di,CG:ros_errors ; ES:DI -> ROS error code table
  824. mov cx,NUMROSERR
  825. repne scasb ; scan for match
  826. mov ax,RHS_ERROR ; get basic error indication
  827. or al,cs:(CG:dos_errors-CG:ros_errors-1)[di]
  828. ; combine with type of error
  829. popx <di, es>
  830. stc
  831. ret
  832. setup_rw: ; prepare for INPUT, OUTPUT or OUTPUT_VFY
  833. ;--------
  834. ; On Entry:
  835. ; ES:DI -> UDSC
  836. ; On Exit:
  837. ; if CY == 0:
  838. ;   P_CYL, P_HEAD, P_SECTOR,
  839. ;   P_DMAOFF, P_DMASEG, P_COUNT initialized
  840. ; if CY == 1: invalid parameters detected
  841. ; ES:DI preserved
  842. push ds
  843. lds bx,REQUEST[bp]
  844. mov ax,ds:RH4_BUFOFF[bx] ; get offset of transfer buffer
  845. mov P_DMAOFF[bp],ax ; set transfer offset
  846. mov ax,ds:RH4_BUFSEG[bx] ; get segment of transfer buffer
  847. mov P_DMASEG[bp],ax ; set transfer segment
  848. mov ax,ds:RH4_COUNT[bx] ; get sector count from request header
  849. mov P_COUNT[bp],ax ; save it locally for later
  850. mov ax,ds:RH4_SECTOR[bx] ; get low 16 bit of sector #
  851. sub dx,dx ; assume value is 16 bit only
  852. cmp ds:RH_LEN[bx],22 ; check if small request
  853.  je setrw2 ; if so forget the rest
  854. cmp ds:RH_LEN[bx],24 ; check if large request
  855.      jne    setrw1          
  856. mov dx,ds:RH4_SECTOR+2[bx] ; yes, get 32-bit record number
  857. jmps setrw2
  858. setrw1:
  859. cmp ds:RH_LEN[bx],30
  860.      jne    setrw2          
  861. cmp ax,-1 ; magic number indicating it's
  862.  jne setrw2 ; a 32-bit record number
  863. mov ax,ds:RH4_BIGSECTORLO[bx]
  864. mov dx,ds:RH4_BIGSECTORHI[bx]
  865. setrw2:
  866. pop ds
  867. mov cx,P_COUNT[bp] ; get requested count
  868.  jcxz setrw3 ; invalid count
  869. dec cx ; CX = count - 1
  870. cmp es:word ptr (UDSC_BPB+BPB_TOTSEC)[di],0
  871.  jne setrw4 ; skip if < 65536 sectors on disk
  872. add ax,cx
  873. adc dx,0 ; AX/DX = # of last sector for I/O
  874.  jc setrw3 ; error if > 32 bits
  875. cmp dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
  876.  ja setrw3 ; skip if too large
  877.  jb setrw5 ; O.K. if small enough
  878. cmp ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
  879.  jb setrw5 ; fail if too large
  880. setrw3:
  881. mov ax,RHS_ERROR+8 ; return "sector not found"
  882. stc
  883. ret
  884. setrw4: ; less than 65536 records
  885. add ax,cx ; compute end of transfer
  886.  jc setrw3 ; skip if overflow
  887. cmp ax,es:UDSC_BPB+BPB_TOTSEC[di]
  888.  jae setrw3 ; skip if too large
  889. setrw5:
  890. sub ax,cx
  891. sbb dx,0 ; add partition address for hard disk
  892. add ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
  893. adc dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
  894. push ax ; AX/DX = 32 bit starting record address
  895. push dx ; save starting record
  896. mov ax,es:UDSC_BPB+BPB_SPT[di]
  897. mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
  898. mov cx,ax ; CX = sectors per cylinder
  899. pop dx ; recover 32 bit start block
  900. pop ax
  901. div cx ; AX = cylinder #, DX = head/sec offset
  902. mov P_CYL[bp],ax ; save physical cylinder number
  903. xor ax,ax ; make remainder 32 bit so
  904. xchg ax,dx ; DX:AX = (head # * SPT) + sector #
  905. div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
  906. mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
  907. mov P_HEAD[bp],al ; save physical sector/head for later
  908. clc ; tell them we like the parameters
  909. ret ; we've figured out starting address
  910. track_rw:
  911. ;--------
  912. ; entry: P_CYL    = cylinder for start of transfer
  913. ; P_HEAD   = head # for start of transfer
  914. ; P_SECTOR = sector # for start of transfer
  915. ; P_COUNT  = remaining sector count
  916. ; P_DMAOFF = transfer offset
  917. ; P_DMASEG = transfer segment
  918. ; ES:DI -> UDSC structure
  919. ; exit: CY = 0 if no error, P_COUNT = remaining sectors
  920. ; CY = 1 if error, AH = ROS error code
  921. call track_setup ; compute size of transfer
  922. if FASTSETTLE
  923. call new_settle ; set new head settle delay
  924. endif
  925. cmp P_DIRECT[bp],0 ; DMA boundary problem?
  926.  jne trkrw10 ; no, direct transfer performed
  927. cmp P_ROSCMD[bp],ROS_READ
  928.  je trkrw10 ; skip if not writing to disk
  929. pushx <ds, es, di>
  930. mov cx,SECSIZE/2 ; CX = # of word per sector
  931. push ds
  932. pop es ; ES:DI -> destination
  933. mov di,CG:local_buffer
  934. lds si,P_DMA[bp] ; DS:SI -> source
  935. rep movsw ; copy from deblocking buffer
  936. popx <di, es, ds>
  937. trkrw10:
  938. mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
  939. trkrw20: ; loop back here for retries
  940. mov cx,P_CYL[bp] ; get cylinder #
  941. xchg cl,ch ; CH = bits 0..7, CL = bits 8..11
  942. ror cl,1
  943. ror cl,1 ; cylinder bits 8..9 in bits 6..7
  944. mov dh,cl ; cylinder bits 10.11 in bits 0..1
  945. and cl,11000000b ; isolate cylinder bits 8..9
  946. add cl,P_SECTOR[bp] ; bits 0..5 are sector number
  947. inc cx ; make it one-relative for ROS
  948. ror dh,1
  949. ror dh,1 ; cylinder bits 10..11 in bits 6..7
  950. and dh,11000000b ; isolate cylinder bits 10..11
  951. add dh,P_HEAD[bp] ; add physical head number
  952. mov dl,es:UDSC_RUNIT[di] ; get ROS unit #
  953. push es
  954. mov ax,ds
  955. mov es,ax
  956. mov bx,CG:local_buffer ; point at our local buffer
  957. cmp P_DIRECT[bp],0 ; DMA boundary problem?
  958.  je trkrw30 ; no, direct transfer performed
  959. les bx,P_DMA[bp] ; ES:BX -> transfer address
  960. trkrw30:
  961. mov ax,P_MCNT[bp] ; AL = physical sector count
  962. mov ah,P_ROSCMD[bp] ; AH = ROS read command
  963. cmp ah,ROS_VERIFY ; write with verify?
  964.  jne trkrw40 ; skip if ROS_READ or ROS_WRITE
  965. mov ah,ROS_WRITE ; else first perform normal write
  966. int_____DISK_INT ; call ROS to write to disk
  967.  jc trkrw50 ; skip if any errors occurred
  968. mov ax,P_MCNT[bp] ; else get sector count
  969. mov ah,ROS_VERIFY ; verify disk sectors
  970. trkrw40: ; AH = function, AL = count
  971. int_____DISK_INT ; read/write/verify via ROM BIOS
  972. trkrw50: ; CY = 1, AH = error code
  973. pop es
  974.  jnc trkrw70 ; skip if no errors occurred
  975. call disk_reset ; reset the hardware
  976. cmp ah,11h ; ECC corrected data?
  977.  je trkrw60 ; first sector known to be good
  978. cmp ah,03h ; write protect error
  979.  je trkrw_error ; don't recover, report to user
  980. dec P_RETRY[bp] ; count # of errors so far
  981.  jnz trkrw20 ; retries done, declare it permanent
  982. trkrw_error: ; disk error occurred
  983. if FASTSETTLE
  984. call old_settle ; restore head settle delay
  985. endif
  986. stc ; CY = 1 indicates error, AH = code
  987. ret
  988. trkrw60: ; ECC error, only 1st sector OK
  989. mov P_MCNT[bp],1 ; say we have done one sector
  990. trkrw70: ; read/write/verify succeeded
  991. cmp P_DIRECT[bp],0 ; DMA boundary problem?
  992.  jne trkrw80 ; no, direct transfer performed
  993. cmp P_ROSCMD[bp],ROS_READ
  994.  jne trkrw80 ; skip if not reading from disk
  995. pushx <di, ds, es>
  996. mov cx,SECSIZE/2 ; CX = # of word per sector
  997. mov si,CG:local_buffer
  998. les di,P_DMA[bp] ; DS:SI -> source, ES:DI -> destination
  999. rep movsw ; copy from deblocking buffer
  1000. popx <es, ds, di>
  1001. trkrw80:
  1002. mov ax,P_MCNT[bp] ; get physical transfer length
  1003. sub P_COUNT[bp],ax ; subtract from total transfer length
  1004.  jz trkrw90 ; exit if none left
  1005. add P_SECTOR[bp],al ; update current sector
  1006. mov ah,SECSIZE/16
  1007. mul ah ; AX = paras to inc DMA address
  1008. add P_DMASEG[bp],ax ; update DMA segment
  1009. xor ax,ax
  1010. mov al,P_SECTOR[bp] ; get current sector
  1011. cmp ax,es:UDSC_BPB+BPB_SPT[di]
  1012.  jb trkrw90 ; skip if on same track
  1013. mov P_SECTOR[bp],0 ; else start at beginning of new track
  1014. inc P_HEAD[bp] ; move to the next head
  1015. mov al,P_HEAD[bp] ; get current head
  1016. cmp ax,es:UDSC_BPB+BPB_HEADS[di]
  1017.  jb trkrw90 ; did we go over end of cylinder?
  1018. mov P_HEAD[bp],0 ; start with first head...
  1019. inc P_CYL[bp] ;  ... on the next cylinder
  1020. trkrw90:
  1021. if FASTSETTLE
  1022. call old_settle ; restore head settle delay
  1023. endif
  1024. clc ; indicate no errors
  1025. ret
  1026. disk_reset:
  1027. ;----------
  1028. ; entry: DL = ROS drive code
  1029. push ax ; save the error status
  1030. ; mov ah,ROS_RESET ; try a restore
  1031. xor ax,ax
  1032. int_____DISK_INT ; might sort things out
  1033. pop ax ; restore error status
  1034. ret
  1035. track_setup: ; prepare for I/O on disk track
  1036. ;-----------
  1037. ; entry: P_CYL    = cylinder for start of transfer
  1038. ; P_HEAD   = head # for start of transfer
  1039. ; P_SECTOR = sector # for start of transfer
  1040. ; P_COUNT  = remaining sector count
  1041. ; P_DMAOFF = transfer offset
  1042. ; P_DMASEG = transfer segment
  1043. ; ES:DI -> UDSC structure
  1044. ; exit: P_DIRECT = 1 if no deblocking
  1045. ; P_MCNT = # of sectors possible in one ROS call
  1046. mov ax,P_DMASEG[bp] ; get transfer address
  1047. cmp ax,DeblockSeg ; is this in high memory ?
  1048.  jae trksu20 ;  then force through deblock buffer
  1049. mov ax,P_COUNT[bp] ; assume we can transfer all
  1050. mov P_MCNT[bp],ax ;  that's requested this time
  1051. mov P_DIRECT[bp],1 ;  directly to destination
  1052. test es:UDSC_RUNIT[di],80h ; is it a hard disk transfer ?
  1053.  jnz trksu30 ;  yes, transfer the lot
  1054. ; floppy transfer, break up into tracks
  1055. mov dx,es:UDSC_BPB+BPB_SPT[di]
  1056. ; DX = sectors per track
  1057. sub dl,P_SECTOR[bp] ; subtract starting sector
  1058. cmp dx,ax ; more than we want?
  1059.  jae trksu10 ; no, use this count
  1060. mov P_MCNT[bp],dx ; set count for this pass
  1061. trksu10:
  1062. mov ax,P_DMASEG[bp] ; get transfer address
  1063. mov cl,4
  1064. shl ax,cl ; get A4..A15 from segment
  1065. add ax,P_DMAOFF[bp] ; combine with A0..A15 from offset
  1066. not ax ; AX = # of bytes left in 64K bank
  1067. sub dx,dx
  1068. mov cx,SECSIZE
  1069. div cx ; convert this to physical sectors
  1070. cmp ax,P_MCNT[bp] ; capable of more than requested?
  1071.  jae trksu30 ; skip if we can do it all
  1072. mov P_MCNT[bp],ax ; else update possible transfer length
  1073. test ax,ax ; can we transfer anything at all?
  1074.  jnz trksu30 ; yes, perform the transfer
  1075. trksu20:
  1076. mov P_MCNT[bp],1 ; single sector transfer via buffer
  1077. mov P_DIRECT[bp],0 ; if DIRECT = 0, deblocked transfer
  1078. trksu30:
  1079. ret
  1080. if FASTSETTLE
  1081. new_settle:
  1082. ;----------
  1083. test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
  1084.  jnz new_settle9
  1085. cmp P_ROSCMD[bp],ROS_READ
  1086.  jne new_settle9
  1087. push ax
  1088. pushx <bx, ds>
  1089. sub ax,ax
  1090. mov ds,ax
  1091. Assume DS:IVECT
  1092. lds bx,i1eptr
  1093. xchg al,9[bx]
  1094. Assume DS:CGROUP
  1095. popx <ds, bx>
  1096. mov P_SETTLE[bp],al
  1097. pop ax
  1098. new_settle9:
  1099. ret
  1100. old_settle:
  1101. ;----------
  1102. test es:UDSC_FLAGS[di],UDF_HARD ; fix head settle on floppies
  1103.  jnz old_settle9
  1104. cmp P_ROSCMD[bp],ROS_READ
  1105.  jne old_settle9
  1106. pushx <ax, bx, ds>
  1107. mov al,P_SETTLE[bp]
  1108. sub bx,bx
  1109. mov ds,bx
  1110. Assume DS:IVECT
  1111. lds bx,i1eptr
  1112. mov 9[bx],al
  1113. Assume DS:CGROUP
  1114. popx <ds, bx, ax>
  1115. old_settle9:
  1116. ret
  1117. endif
  1118. dd_open: ; 13-device open
  1119. ;-------
  1120. call point_unit ; get unit descriptor
  1121. inc es:UDSC_OPNCNT[di] ; increment open count
  1122. sub ax,ax
  1123. ret
  1124. dd_close: ; 14-device close
  1125. ;--------
  1126. call point_unit ; get unit descriptor
  1127. dec es:UDSC_OPNCNT[di] ; decrement open count
  1128. sub ax,ax
  1129. ret
  1130. dd_remchk: ; 15-removable media check
  1131. ;---------
  1132. call point_unit ; get unit descriptor
  1133. sub ax,ax ; assume floppy disk
  1134. test es:UDSC_FLAGS[di],UDF_HARD
  1135.  jz remchk1 ; skip if it really is a floppy
  1136. mov ax,RHS_BUSY ; else return "busy" for hard disk
  1137. remchk1:
  1138. ret
  1139. dd_genioctl: ; 19-generic IOCTL
  1140. ;-----------
  1141. mov cx,es:RH19_CATEGORY[bx] ; get major & minor function
  1142. xchg cl,ch ; swap them around
  1143. call point_unit ; get unit descriptor
  1144. cmp ch,8 ; is it the right major category?
  1145.  jne ioctl20 ; no, return an error
  1146. or es:UDSC_FLAGS[di],UDF_UNSURE
  1147. ; media unsure after IOCTL
  1148. mov si,offset CGROUP:genioctlTable
  1149. ioctl10:
  1150. lods cs:byte ptr [si] ; get category
  1151. mov ch,al ; keep in CH
  1152. lods cs:word ptr [si] ; AX = function address
  1153. cmp cl,ch ; is it the category we want ?
  1154.  je ioctl30 ; yes, go do it
  1155. test ch,ch ; is it the end of the list ?
  1156.  jnz ioctl10 ; no, do another one
  1157. ioctl20:
  1158. mov ax,RHS_ERROR+3 ; "unknown command"
  1159. ret
  1160. ioctl30:
  1161. jmp ax ; go do our routine
  1162. genioctlTable label byte
  1163. db RQ19_SET ; set device parameters
  1164. dw offset CGROUP:ioctl_set
  1165. db RQ19_GET ; get device parameters
  1166. dw offset CGROUP:ioctl_get
  1167. db RQ19_WRITE ; write track
  1168. dw offset CGROUP:ioctl_write
  1169. db RQ19_READ ; read track
  1170. dw offset CGROUP:ioctl_read
  1171. db RQ19_FORMAT ; format & verify track
  1172. dw offset CGROUP:ioctl_format
  1173. db RQ19_VERIFY ; verify track
  1174. dw offset CGROUP:ioctl_verify
  1175. db RQ19_GETMEDIA ; get media id
  1176. dw offset CGROUP:ioctl_getmedia
  1177. db RQ19_SETMEDIA ; set media id
  1178. dw offset CGROUP:ioctl_setmedia
  1179. db 0 ; terminate the list
  1180. point_ioctl_packet:
  1181. ;------------------
  1182. ; On Entry:
  1183. ; None
  1184. ; On Exit:
  1185. ; DS:BX -> ioctl request packet
  1186. ; All other regs preserved
  1187. ;
  1188. lds bx,REQUEST[bp]
  1189. lds bx,ds:RH19_GENPB[bx] ; ES:BX -> request packet
  1190. ret
  1191. ioctl_get:
  1192. ;---------
  1193. push ds
  1194. call point_ioctl_packet ; DS:BX -> ioctl packet
  1195. mov al,es:UDSC_TYPE[di] ; get drive type
  1196. mov ds:1[bx],al ; return drive type (0/1/2/5/7)
  1197. mov ax,es:UDSC_FLAGS[di] ; get device attributes
  1198. and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
  1199. mov ds:2[bx],ax ; return device attributes
  1200. mov ax,es:UDSC_NCYL[di] ; get # of cylinders
  1201. mov ds:4[bx],ax ; return # of cylinders
  1202. sub ax,ax ; for now always say "default"
  1203. mov ds:6[bx],al ; return media type
  1204. test ds:byte ptr [bx],1 ; return default BPB?
  1205. pop ds
  1206. lea si,UDSC_DEVBPB[di] ; assume we want device BPB
  1207.  jz get1 ; skip if yes
  1208. test es:UDSC_FLAGS[di],UDF_HARD
  1209.  jnz get1 ; BPB doesn't change for hard disks
  1210. call ask_for_disk ; make sure we've got correct floppy
  1211. call login_media ; determine floppy disk type
  1212.  jc get_err ; abort if can't login disk
  1213. lea si,es:UDSC_BPB[di] ; get current BPB
  1214. get1:
  1215. push ds
  1216. push es
  1217. push di
  1218. push es
  1219. call point_ioctl_packet ; DS:BX -> ioctl packet
  1220. push ds
  1221. pop es
  1222. lea di,7[bx] ; ES:DI -> BPB in parameter block
  1223. pop ds ; DS:SI -> BPB to copy
  1224. mov cx,UDSC_BPB_LENGTH
  1225. rep movsb ; copy the BPB across to user
  1226. pop di
  1227. pop es
  1228. pop ds
  1229. xor ax,ax ; return success
  1230. ret
  1231. get_err:
  1232. jmp xlat_error ; return error code
  1233. ; ret
  1234. ioctl_set: ; set device parameters
  1235. ;---------
  1236. push ds
  1237. push es
  1238. call point_ioctl_packet ; DS:BX -> ioctl packet
  1239. test ds:byte ptr [bx],2 ; ignore all but track layout?
  1240.  jnz set2 ; yes, skip BPB stuff
  1241. mov al,ds:1[bx] ; get new drive type (0/1/2/5/7)
  1242. mov es:UDSC_TYPE[di],al ; set drive type
  1243. and es:UDSC_FLAGS[di],not (UDF_HARD+UDF_CHGLINE)
  1244. mov ax,ds:2[bx] ; get new device attributes
  1245. and ax,UDF_HARD+UDF_CHGLINE ; isolate hard disk + change line bits
  1246. or es:UDSC_FLAGS[di],ax ; combine the settings
  1247. mov ax,ds:4[bx] ; get new # of cylinders
  1248. mov es:UDSC_NCYL[di],ax ; set # of cylinders
  1249. lea ax,UDSC_BPB[di] ; AX -> media BPB in es:UDSC_
  1250. test ds:byte ptr [bx],1 ; fix BPB for "build BPB" call?
  1251.  jnz set1 ; skip if new media BPB only
  1252. lea ax,UDSC_DEVBPB[di] ; AX -> device BPB in es:UDSC_
  1253. set1:
  1254. lea si,7[bx] ; DS:SI -> new BPB from user
  1255. xchg ax,di ; ES:DI -> BPB in es:UDSC_
  1256. mov cx,UDSC_BPB_LENGTH
  1257. rep movsb ; copy BPB into UDSC as new default
  1258. xchg ax,di ; ES:DI -> UDSC_ again
  1259. set2: ; now set track layout
  1260. lea si,BPB_LENGTH+7[bx] ; DS:SI -> new user layout
  1261. mov es,cs:DataSegment
  1262. mov di,CG:layout_table ; ES:DI -> BIOS layout table
  1263. lodsw ; get sector count
  1264. test ax,ax ; make sure this is good value
  1265.      jz set6            
  1266. cmp ax,MAX_SPT ; make sure this is good value
  1267.  ja set6 ;   so we don't overflow table
  1268. xchg ax,cx ; CX = sector count
  1269. set3: ; loop here for every sector
  1270. inc di
  1271. inc di
  1272. lodsw ; get sector number
  1273. stosb ; write sector number
  1274. lodsw ; get sector size (0080, 0100, 0200, 0400)
  1275. shl ax,1 ; double it (0100, 0200, 0400, 0800)
  1276. set4:
  1277. shr ah,1 ; halve the sector size until = 128
  1278.  jc set5 ; we've shifted out bottom bit
  1279. inc al ; count the # of bits
  1280.  jnz set4 ; (this should always jump)
  1281. set5:
  1282. stosb ; store LOG2 (sector size/128)
  1283. loop set3 ; repeat for all sectors
  1284. set6:
  1285. pop es
  1286. pop ds
  1287. xor ax,ax
  1288. ret
  1289. ioctl_read:
  1290. ;----------
  1291. mov P_ROSCMD[bp],ROS_READ ; read physical track
  1292. jmps ioctl_rw_common ; use common code
  1293. ioctl_write:
  1294. ;-----------
  1295. mov P_ROSCMD[bp],ROS_WRITE ; write physical track
  1296. ; jmps ioctl_rw_common ; use common code
  1297. ioctl_rw_common:
  1298. call ask_for_disk ; make sure we've got correct floppy
  1299. push ds
  1300. call point_ioctl_packet ; DS:BX -> ioctl packet
  1301. mov al,ds:5[bx] ; get logical sector (0..SPT-1)
  1302. mov P_SECTOR[bp],al
  1303. mov ax,ds:7[bx] ; get sector count
  1304. mov P_COUNT[bp],ax
  1305. mov ax,ds:9[bx] ; get transfer address
  1306. mov P_DMAOFF[bp],ax
  1307. mov ax,ds:11[bx]
  1308. mov P_DMASEG[bp],ax
  1309. mov ax,ds:1[bx] ; get head number
  1310. mov P_HEAD[bp],al
  1311. mov ax,ds:3[bx] ; get cylinder number
  1312. mov P_CYL[bp],ax
  1313. pop ds
  1314. rw_loop:
  1315. call track_rw ; read as much as possible on track
  1316.  jc rw_err ; return if physical disk error
  1317. cmp P_COUNT[bp],0 ; test if any more stuff to read
  1318.  jne rw_loop ; yes, loop back for more
  1319. sub ax,ax ; all done, no error encountered
  1320. ret ; return O.K. code
  1321. rw_err:
  1322. jmp xlat_error ; translate ROS code to DOS error
  1323. ; ret
  1324. ioctl_verify:
  1325. ;------------
  1326. ioctl_format:
  1327. ;------------
  1328. call ask_for_disk ; make sure we've got correct floppy
  1329. mov P_RETRY[bp],RETRY_MAX ; perform up to three retries
  1330. format_retry:
  1331. call set_format ; attempt data rate setup
  1332. push ds
  1333. call point_ioctl_packet ; DS:BX -> ioctl packet
  1334. test ds:byte ptr [bx],1 ; are we testing parameters only ?
  1335.  jz format10
  1336. mov ds:[bx],al ; return AL
  1337. pop ds
  1338. xor ax,ax ; we succeeded
  1339. ret
  1340. format10:
  1341. mov ax,es:UDSC_BPB+BPB_SPT[di]
  1342. test ds:byte ptr [bx],2 ; is it undocumented "do 2 tracks" bit?
  1343.  jz format20
  1344. add ax,ax ; yes, double the count
  1345. format20:
  1346. mov P_COUNT[bp],ax ; save it locally for later
  1347. mov dh,ds:1[bx] ; get head #
  1348. mov cx,ds:3[bx] ; get cylinder #
  1349. ror ch,1
  1350. ror ch,1
  1351. xchg cl,ch
  1352. or cl,1 ; start with sector 1
  1353. mov dl,es:UDSC_RUNIT[di] ; get ROS drive #
  1354. lds bx,REQUEST[bp] ; DS:BX -> Request Header
  1355. mov bx,ds:RH19_CATEGORY[bx] ; get major & minor function
  1356. pop ds
  1357. push es
  1358. xor ax,ax
  1359. mov es,ax
  1360. mov ax,new_int1e_off ; point floppy paramters at local
  1361. xchg ax,es:[4*1Eh]
  1362. mov orig_int1e_off,ax ; save old value
  1363. mov ax,new_int1e_seg
  1364. xchg ax,es:[4*1Eh+2]
  1365. mov orig_int1e_seg,ax
  1366. pop es
  1367. format30:
  1368. cmp bh,RQ19_FORMAT ; skip if verify only
  1369.  jne format40
  1370. test es:UDSC_FLAGS[di],UDF_HARD
  1371.  jnz format40 ; hard disks are always verify
  1372. mov ax,P_COUNT[bp]
  1373. mov ah,ROS_FORMAT
  1374. push es
  1375. push bx
  1376. push ds
  1377. pop es
  1378. mov bx,CG:layout_table ; ES:BX -> parameter table
  1379. int_____DISK_INT
  1380. pop bx
  1381. pop es
  1382.  jc format50
  1383. format40: ; no error on format, try verify
  1384. mov ax,P_COUNT[bp]
  1385. mov ah,ROS_VERIFY
  1386. push es
  1387. push bx
  1388. xor bx,bx
  1389. mov es,bx
  1390. int_____DISK_INT
  1391. pop bx
  1392. pop es
  1393.  jc format50
  1394. xor ax,ax ; return success
  1395. format50:
  1396. push es
  1397. push di
  1398. push ax
  1399. mov ax,0
  1400. mov es,ax
  1401. mov di,78h
  1402. mov ax,orig_int1e_off
  1403. stosw
  1404. mov ax,orig_int1e_seg
  1405. stosw
  1406. pop ax
  1407. pop di
  1408. pop es
  1409.  jnc format60 ; if no error's just exit
  1410. call xlat_error ; translate to DOS error
  1411. dec P_RETRY[bp] ; any more retries ?
  1412.  jz format60 ; no, just exit with error
  1413. ; mov ah,ROS_RESET
  1414. xor ax,ax
  1415. int_____DISK_INT ; reset the drive
  1416. jmp format_retry ; now give it another go
  1417. format60:
  1418. ret
  1419. ; The following table indicates which combinations of drive
  1420. ; types, sectors per track and tracks per disk are O.K. and
  1421. ; which value in AL is required for those combinations  for
  1422. ; INT 13h, AH = 17h ("set DASD type for format").
  1423. ; +---------------------- 0 = 360Kb, 1 = 1.2Mb, 2 = 720Kb
  1424. ; |   +------------------ # of sectors/track (9, 15, 18)
  1425. ; |   |  +--------------- # of tracks per disk (40 or 80)
  1426. ; |   |  |   +----------- 1 = 360 Kb in 360 Kb
  1427. ; |   |  |   | 2 = 360 Kb in 1.2 Mb
  1428. ; |   |  |   | 3 = 1.2 Mb in 1.2 Mb
  1429. ; |   |  |   |   4 = 720 Kb in 720 Kb
  1430. ; |   |  |   |  +-------- gap length for format
  1431. ; |   |  |   |  |
  1432. ; V   V  V   V  V
  1433. ok_fmt_table db 0,  9, 40, 1, 50h ; 360 Kb
  1434. db 1,  9, 40, 2, 50h ; 360 Kb in 1.2 Mb
  1435. db 1, 15, 80, 3, 54h ; 1.2 Mb in 1.2 Mb
  1436. db 2,  9, 80, 4, 50h ; 720 Kb in 720 Kb
  1437. db -1 ; end of table
  1438. set_format:
  1439. ;----------
  1440. ; On Entry:
  1441. ; ES:DI -> UDSC_
  1442. ; On Exit:
  1443. ; AL = 0 on success, else value to return in parameter block
  1444. ; ES:DI preserved
  1445. ;
  1446. push ds
  1447. call point_ioctl_packet ; DS:BX -> ioctl packet
  1448. mov dh,ds:1[bx] ; get the head number
  1449. mov cx,ds:3[bx] ; get the cylinder number
  1450. pop ds
  1451. mov si,CG:layout_table ; SI -> track layout table
  1452. mov ax,MAX_SPT ; AX = # of sectors per track
  1453. set_format10:
  1454. mov 0[si],cl ; set cylinder number
  1455. mov 1[si],dh ; set head number
  1456. add si,4 ; next sector entry
  1457. dec ax ; count down # of sectors
  1458.  jnz set_format10 ; repeat until all done
  1459. call get_ncyl ; return # of tracks
  1460. dec ax ; AX = max. cylinder #
  1461. ror ah,1
  1462. ror ah,1 ; move bits 8,9 into 6,7
  1463. xchg al,ah
  1464. mov cx,es:UDSC_BPB+BPB_SPT[di]
  1465. ; get desired sectors/track
  1466. or cx,ax ; CL, CH = max. cylinder/max. sector #
  1467. cmp cx,2708h ; check for 40 track, 8 sectors/track
  1468.  jne set_format20 ; we convert 160, 320 to 180, 360
  1469. inc cx ; make it 9 sectors per track
  1470. set_format20:
  1471. mov dl,es:UDSC_RUNIT[di] ; get ROS unit number
  1472. pushx <es, di>
  1473. mov ah,ROS_SETMEDIA ; set type for format
  1474. int_____DISK_INT ; check if combination is legal
  1475. mov new_int1e_off,di
  1476. mov new_int1e_seg,es ; ES:DI -> new parameters if legal
  1477. popx <di, es>
  1478.  jc set_format40 ; did we succeed ?
  1479. set_format30:
  1480. xor ax,ax ; success, return no errors
  1481. ret
  1482. set_format40:
  1483. ; ROM BIOS has given an error, if the function isn't supported drop
  1484. ; thru' and try the older method's
  1485. ;
  1486. mov al,2 ; assume ROS doesn't support it
  1487. cmp ah,0Ch ; media combination not supported ?
  1488.  je set_format80 ; return AL=2
  1489. inc ax ; AL = 3
  1490. cmp ah,80h ; drive not ready ?
  1491.  je set_format80 ; return AL=3
  1492. ; Lets look for a match in our tables
  1493. call get_ncyl ; AX = number of cylinders
  1494. mov cx,es:UDSC_BPB+BPB_SPT[di]
  1495. ; CL = sectors per track
  1496. mov ch,al ; CH = tracks per disk
  1497. cmp cx,2808h ; 40 tracks, 8 sectors?
  1498.      jne    set_format50        
  1499. inc cx ; force it to 9 sectors/track
  1500. set_format50:
  1501. mov si,CG:ok_fmt_table-4
  1502. set_format60:
  1503. add si,4 ; next table entry
  1504. lods cs:byte ptr [si] ; get drive type
  1505. cmp al,0FFh ; end of device/media list?
  1506.  je set_format70 ; yes, can't handle this combination
  1507. cmp al,es:UDSC_TYPE[di] ; does the drive type match?
  1508.  jne set_format60 ; try next one if wrong drive
  1509. cmp cx,cs:[si] ; do tracks/sectors match?
  1510.  jne set_format60 ; no, try next one
  1511. mov parms_spt,cl ; set sectors/track
  1512. mov al,cs:3[si] ; get required gap length from table
  1513. mov parms_gpl,al ; set gap length for format
  1514. mov ax,CG:local_parms
  1515. mov new_int1e_off,ax ; use local parameters for formatting
  1516. mov new_int1e_seg,ds ; set new interrupt vector address
  1517. mov dl,es:UDSC_RUNIT[di]
  1518. mov al,cs:2[si] ; get media/drive combination
  1519. mov ah,ROS_SETTYPE ; set the drive type
  1520. int_____DISK_INT
  1521.  jnc set_format30 ; return if no errors
  1522. cmp es:UDSC_TYPE[di],0 ; is this a 360 K drive?
  1523.  je set_format30 ; go ahead, might be old ROS
  1524. cmp es:UDSC_TYPE[di],2 ; is this a 720 K drive?
  1525.  je set_format30 ; go ahead, might be old ROS
  1526. set_format70:
  1527. mov al,1 ; return not supported
  1528. set_format80:
  1529. ret
  1530. get_ncyl:
  1531. ;--------
  1532. mov ax,es:UDSC_BPB+BPB_TOTSEC[di]
  1533. xor dx,dx ; get sectors on disk
  1534. test ax,ax ; zero means we use 32 bit value
  1535.  jnz get_ncyl10
  1536. mov ax,es:word ptr (UDSC_BPB+BPB_SIZE)[di]
  1537. mov dx,es:word ptr (UDSC_BPB+BPB_SIZE+2)[di]
  1538. get_ncyl10:
  1539. div es:UDSC_BPB+BPB_SPT[di] ; AX = # of cylinders * heads
  1540. call get_ncyl20 ; round up
  1541. div es:UDSC_BPB+BPB_HEADS[di]; AX = # of cylinders
  1542. get_ncyl20:
  1543. test dx,dx ; do we have overflow ?
  1544.  jz get_ncyl30
  1545. inc ax ; round up
  1546. xor dx,dx ; make it a 32 bit value
  1547. get_ncyl30:
  1548. ret
  1549. ioctl_getmedia:
  1550. ;--------------
  1551. mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
  1552. call rw_media ; read the boot sector
  1553.  jc getmedia10
  1554. push es
  1555. push di
  1556. push ds
  1557. call point_ioctl_packet ; DS:BX -> ioctl packet
  1558. push ds
  1559. pop es
  1560. lea di,2[bx] ; ES:DI -> skip info word
  1561. pop ds ; DS:SI -> boot sector media id
  1562. mov cx,4+11+8
  1563. rep movsb ; copy the boot sector image
  1564. pop di
  1565. pop es
  1566. xor ax,ax
  1567. getmedia10:
  1568. ret
  1569. ioctl_setmedia:
  1570. ;--------------
  1571. mov P_ROSCMD[bp],ROS_READ ; read from floppy/hard disk
  1572. call rw_media ; read the boot sector
  1573.  jc setmedia10
  1574. push ds
  1575. push si
  1576. push es
  1577. push di
  1578. push ds
  1579. push si
  1580. call point_ioctl_packet ; DS:BX -> ioctl packet
  1581. lea si,2[bx] ; DS:SI -> skip info word
  1582. pop di
  1583. pop es ; ES:DI -> boot sector image
  1584. mov cx,4+11+8
  1585. rep movsb ; update the boot sector image
  1586. pop di
  1587. pop es
  1588. pop si
  1589. pop ds
  1590. mov P_ROSCMD[bp],ROS_WRITE ; write to floppy/hard disk
  1591. jmp rw_media ; write the boot sector
  1592. setmedia10:
  1593. ret
  1594. rw_media:
  1595. ;--------
  1596. ; On Entry:
  1597. ; ES:DI -> UDSC
  1598. ; On Exit:
  1599. ; ES:DI preserved
  1600. ; CY clear, SI -> boot record info
  1601. ; CY set on error, AX = error code
  1602. ;
  1603. ; setup parameters to read/write boot sector to/from local buffer
  1604. ;
  1605. call ask_for_disk ; make sure we've got correct floppy
  1606. mov P_DMAOFF[bp],CG:local_buffer
  1607. mov P_DMASEG[bp],ds ; set transfer address
  1608. mov P_COUNT[bp],1 ; read 1 sector
  1609. mov ax,es:UDSC_BPB+BPB_SPT[di]
  1610. mul es:UDSC_BPB+BPB_HEADS[di]; get sectors per track * heads
  1611. xchg ax,cx ; CX = sectors per cylinder
  1612. mov ax,es:word ptr (UDSC_BPB+BPB_HIDDEN)[di]
  1613. mov dx,es:word ptr (UDSC_BPB+BPB_HIDDEN+2)[di]
  1614. div cx ; AX = cylinder #, DX = head/sec offset
  1615. mov P_CYL[bp],ax ; save physical cylinder number
  1616. xor ax,ax ; make remainder 32 bit so
  1617. xchg ax,dx ; DX:AX = (head # * SPT) + sector #
  1618. div es:UDSC_BPB+BPB_SPT[di] ; divide by sectors per track
  1619. mov P_SECTOR[bp],dl ; DX = sector #, AX = head #
  1620. mov P_HEAD[bp],al ; save physical sector/head for later
  1621. call rw_loop ; read the boot sector
  1622.  jc rw_media20
  1623. cmp local_buffer+11+BPB_FATID,0F0h
  1624.  jb rw_media10
  1625. mov si,offset CGROUP:local_buffer+UDSC_BPB_LENGTH+11+2
  1626. lodsb ; get extended boot
  1627. sub al,29h ; do we have an extended boot ?
  1628.  je rw_media20 ; no, well we can't write a new one
  1629. rw_media10:
  1630. mov ax,RHS_ERROR+3 ; "unknown command"
  1631. rw_media20:
  1632. ret
  1633. dd_getdev: ; 23-get logical drive
  1634. ;---------
  1635. ; get logical drive that corresponds to the physical drive
  1636. call point_unit ; get unit descriptor
  1637. call get_owner ; DL = owning drive (zero not owned)
  1638. jmps dd_setdev10 ; return the owner
  1639. dd_setdev: ; 24-set logical drive
  1640. ;---------
  1641. ; set logical drive that corresponds to the physical drive
  1642. ;
  1643. call point_unit ; get unit descriptor
  1644. call set_owner ; set new owner
  1645. dd_setdev10:
  1646. les bx,REQUEST[bp]
  1647. mov es:RH_UNIT[bx],dl ; return current logical drive
  1648. xor ax,ax
  1649. ret
  1650. get_owner:
  1651. ;---------
  1652. ; On Entry:
  1653. ; ES:DI -> UDSC_
  1654. ; On Exit:
  1655. ; DL = owning drive (zero = no owner)
  1656. ;
  1657. xor dx,dx ; assume one unit per physical drive
  1658. mov ax,es:UDSC_FLAGS[di]
  1659. test ax,UDF_HARD
  1660.  jnz get_owner40
  1661. test ax,UDF_VFLOPPY
  1662.  jz get_owner40
  1663. push ds
  1664. mov ds,dx ; DS -> low memory
  1665. Assume DS:IVECT
  1666.     mov dl,dual_byte        
  1667. pop ds
  1668. Assume DS:CGROUP
  1669. mov al,es:UDSC_RUNIT[di] ; lets look for this ROS drive
  1670. test al,al ; is it physical unit zero ?
  1671.  jz get_owner30 ; yes, return dual_byte
  1672. push ds ; no, search our internal info
  1673. lds si,udsc_root
  1674. Assume DS:Nothing
  1675. get_owner10:
  1676. cmp al,ds:UDSC_RUNIT[si] ; do we use the same drive ?
  1677.  jne get_owner20
  1678. test ds:UDSC_FLAGS[si],UDF_OWNER
  1679.  jz get_owner20 ; do we own it ?
  1680. mov dl,ds:UDSC_DRIVE[si] ; get the logical drive owner
  1681. get_owner20:
  1682. lds si,ds:UDSC_NEXT[si]
  1683. cmp si,0FFFFh ; try the next drive
  1684.  jne get_owner10
  1685. pop ds
  1686. Assume DS:CGROUP
  1687. get_owner30:
  1688. inc dx ; make drive one based
  1689. get_owner40:
  1690. ret
  1691. set_owner:
  1692. ;---------
  1693. ; On Entry:
  1694. ; ES:DI -> UDSC_
  1695. ; On Exit:
  1696. ; ES:DI preserved
  1697. ; DL = owning drive (zero = no owner)
  1698. ;
  1699. xor dx,dx ; assume one unit per physical drive
  1700. mov ax,es:UDSC_FLAGS[di]
  1701. test ax,UDF_HARD
  1702.  jnz set_owner40
  1703. test ax,UDF_VFLOPPY
  1704.  jz set_owner40
  1705. mov al,es:UDSC_DRIVE[di]
  1706. mov ah,es:UDSC_RUNIT[di] ; get ROS unit
  1707. test ah,ah ; is it unit zero ?
  1708.  jnz set_owner10
  1709. push ds
  1710. mov ds,dx ; DS -> low memory
  1711. Assume DS:IVECT
  1712. mov dual_byte,al ; set dual drive support byte
  1713. pop ds
  1714. Assume DS:CGROUP
  1715. set_owner10:
  1716. push ds
  1717. lds si,udsc_root
  1718. Assume DS:Nothing
  1719. set_owner20:
  1720. cmp ah,ds:UDSC_RUNIT[si] ; does this unit use the same drive ?
  1721.  jne set_owner30
  1722. or ds:UDSC_FLAGS[si],UDF_UNSURE+UDF_OWNER
  1723. cmp al,ds:UDSC_DRIVE[di]
  1724.  je set_owner30
  1725. and ds:UDSC_FLAGS[si],not UDF_OWNER
  1726. set_owner30:
  1727. lds si,ds:UDSC_NEXT[si]
  1728. cmp si,0FFFFh ; end of the line ?
  1729.  jne set_owner20
  1730. pop ds
  1731. Assume DS:CGROUP
  1732. xchg ax,dx ; DL = owning drive
  1733. inc dx ; make it one based
  1734. set_owner40:
  1735. ret
  1736. ask_for_disk: ; make sure the right disk is in the floppy drive
  1737. ;------------
  1738. call get_owner ; DL = owning drive
  1739. dec dx ; make DL zero based
  1740.  js askfdsk30 ; stop if not a logical drive
  1741. mov dh,es:UDSC_DRIVE[di] ; DH = new drive, DL = old drive
  1742. cmp dl,dh ; do we own the drive ?
  1743.  je askfdsk30 ; yes, stop now
  1744. push dx ; save for broadcast
  1745. mov dl,dh ; new owner in DL
  1746. call set_owner ; we are now the owner
  1747. push es
  1748. push di
  1749. push cs
  1750.     call    FullScreen      
  1751. pop di
  1752. pop es
  1753. pop dx
  1754. mov ax,4A00h ; should we prompt ?
  1755. xor cx,cx
  1756. int 2Fh ; lets ask
  1757. inc cx ; CX = FFFF ?
  1758.  jcxz askfdsk30 ; then skip prompt
  1759. ifdef JAPAN
  1760. mov ax,5001h ; get adaptor mode
  1761. int VIDEO_INT ; ..
  1762. cmp bx,81 ; japanese mode ?
  1763. mov si,CG:disk_msgA_jpn ; get message to print for Japanese
  1764.  je askfdsk10 ; yes
  1765. endif
  1766. mov si,CG:disk_msgA ; get message to print
  1767. askfdsk10:
  1768. call WriteASCIIZ ; output the string
  1769. mov al,es:UDSC_DRIVE[di] ; get drive letter for new drive
  1770. add al,'A'
  1771. dec si ; point to NUL
  1772. call WriteNext ; output char, stop at NUL
  1773. ifdef JAPAN
  1774. mov ax,5001h ; get adaptor mode
  1775. int VIDEO_INT ; ..
  1776. cmp bx,81 ; japanese mode ?
  1777. mov si,CG:disk_msgB_jpn ; get message to print for Japanese
  1778.  je askfdsk20 ; yes
  1779. endif
  1780. mov si,CG:disk_msgB ; get message to print
  1781. askfdsk20:
  1782. call WriteASCIIZ ; output the string
  1783. mov ah,0 ; wait for any key to be pressed
  1784. int KEYBOARD_INT ; read one key from keyboard
  1785. askfdsk30:
  1786. ret ; we've got the right drive
  1787. WriteNext:
  1788. int 29h ; output via fastconsole entry
  1789. WriteASCIIZ:
  1790. lods cs:byte ptr [si] ; get next char
  1791. test al,al
  1792.  jnz WriteNext ; stop at NUL
  1793. ret
  1794. FullScreen:
  1795. xor di,di
  1796. mov es,di
  1797. mov ax,1684h ; get the entry point
  1798. mov bx,21 ;  for DOSMGR
  1799. int 2Fh
  1800. mov bx,es
  1801. or bx,di ; anyone there ?
  1802.  jz FullScreen10
  1803. mov ax,1 ; yes, go full screen please
  1804. push es ; fake a JMPF to ES:DI
  1805. push di
  1806. FullScreen10:
  1807. retf
  1808. driver endp
  1809. RCODE ends ; end of device driver code
  1810. page
  1811. ICODE segment 'ICODE' ; initialization code
  1812. Assume CS:CGROUP, DS:CGROUP, ES:Nothing, SS:Nothing
  1813. dd_init: ; 0-initialize driver
  1814. ;-------
  1815. call hard_init ; setup hard disk units
  1816. call floppy_init ; setup floppy units
  1817. les bx,REQUEST[bp]
  1818. mov al,nunits ; get # of units installed
  1819. mov es:RH0_NUNITS[bx],al ; return value to the BDOS
  1820. mov NumDiskUnits,al ; also set it in device header
  1821. mov ax,endbios ; get pointer to last resident byte
  1822. mov es:RH0_RESIDENT[bx],ax ; set end of device driver
  1823. mov es:RH0_RESIDENT+2[bx],ds
  1824. mov ax,CG:bpbtbl
  1825. mov es:RH0_BPBOFF[bx],ax ; set BPB table array
  1826. mov es:RH0_BPBSEG[bx],ds
  1827. sub ax,ax ; initialization succeeded
  1828. ret ; (BIOS init always does...)
  1829. floppy_init:
  1830. ;-----------
  1831. mov nunits,0 ; floppies start at drive A:
  1832. mov ah,ROS_RESET ; reset the disk system
  1833. xor dx,dx ; for NEAT hard disk boot bug
  1834. int_____DISK_INT
  1835. int EQUIPMENT_INT ; determine equipment status
  1836. mov cl,6
  1837. shr ax,cl ; shift down floppy bits
  1838. and  ax,03h ; mask for floppy
  1839. inc ax ; correct 0 based code
  1840. mov nfloppy,al
  1841. cmp al,1 ; if there is only one floppy
  1842.  jne equip_check_des ;   then use 2 designators
  1843. inc ax ;   this fakes a B: drive
  1844. equip_check_des:
  1845. mov cx,ax ; CX = # of units to set up
  1846. xor dx,dx ; DL = physical drive
  1847. equip_loop:
  1848. push cx
  1849. call new_unit ; ES:DI -> UDSC
  1850. mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
  1851. call floppy_type ; determine type, build default BPB
  1852. cmp nfloppy,1 ; do we only have single drive?
  1853.  je equip_single ; yes, use same physical drive for all
  1854. inc dx ; else use new drive for each unit
  1855. equip_single: ; we only have one physical drive
  1856. call add_unit ; add ES:DI to list of UDSC_'s
  1857. pop cx
  1858. loop equip_loop ; repeat for all logical floppies
  1859. pushx <ds, es>
  1860. push ds ; DS -> i13_trap segment
  1861. mov di,ds
  1862. mov es,di
  1863. sub si,si
  1864. mov ds,si
  1865. lds si,78h[si]
  1866. mov di,CG:local_parms ; copy parameters to template
  1867. mov cx,11
  1868. rep movsb
  1869. pop es ; now ES -> i13_trap segment
  1870. Assume ES:CGROUP
  1871. sub ax,ax
  1872. mov ds,ax ; DS -> interrupt vectors
  1873. Assume DS:IVECT
  1874. mov ax,CG:Int2FTrap ; hook Int 2F
  1875. mov i2Foff,ax
  1876. mov i2Fseg,es
  1877. mov ax,CG:Int13Trap ; hook Int 13
  1878. xchg ax,i13off
  1879. mov es:i13off_save,ax
  1880. mov ax,es
  1881. xchg ax,i13seg
  1882. mov es:i13seg_save,ax
  1883. mov di,500h ; dual drive byte & friends live here
  1884. mov cx,20h/2 ; zero some bytes at 50h:0
  1885. sub ax,ax ; get a quick zero
  1886. mov es,ax ; ES:DI -> 0:500h
  1887. rep stosw ; setup dual drive byte & friends
  1888. Assume DS:CGROUP, ES:Nothing
  1889. popx <es, ds>
  1890. ret
  1891. floppy_type:
  1892. ;-----------
  1893. ; entry: DI -> unit descriptor
  1894. mov UDSC_TYPE[di],0 ; assume 360K 5.25" floppy
  1895. mov UDSC_NCYL[di],40 ; 40 tracks only
  1896. mov ah,ROS_GETTYPE ; "Read DASD type"
  1897. int_____DISK_INT ; find out if disk change line available
  1898.  jc equip_no_chgline ; skip if function not supported
  1899. cmp ah,2 ; floppy with disk change line?
  1900.  jne equip_no_chgline ; no, must be old 360K
  1901. or es:UDSC_FLAGS[di],UDF_CHGLINE
  1902. mov es:UDSC_TYPE[di],1 ; assume 1.2Mb floppy
  1903. mov es:UDSC_NCYL[di],80 ; 80 tracks
  1904. equip_no_chgline:
  1905. pushx <es, di, dx> ; save our registers
  1906. mov ah,ROS_PARAM ; read drive parameters
  1907. int_____DISK_INT ; find out floppy type
  1908. popx <dx, di, es>
  1909.  jc equip_no_type ; skip if PC,XT,jr,AT before 10 Jan 84
  1910. dec bx ; make values 0 based
  1911.  jns equip_type ; (CMOS invalid - type = 0)
  1912. xor bx,bx ; assume 360K
  1913. cmp ch,4fh ; is it 80 track ?
  1914.  jne equip_no_type ; if not forget it
  1915. mov bl,1 ; BL = 1 (ie. 1.2M)
  1916. cmp cl,15 ; 15 spt ?
  1917.  je equip_type
  1918. inc bx ; BL = 2 (ie. 720k)
  1919. cmp cl,9 ; 9 spt ?
  1920.  je equip_type
  1921. inc bx ; BL = 3 (ie. 1.4M)
  1922. cmp cl,18 ; 18 spt ?
  1923.  je equip_type
  1924. inc bx
  1925. inc bx ; BL = 5 (ie. 2.8M)
  1926. cmp cl,36 ; 36 spt ?
  1927.  jne equip_no_type ; don't recognise anything
  1928. equip_type:
  1929. cmp bl,3 ; is it 1.44 Mb 3.5" type?
  1930.  jb equip_type_ok ; skip if 360K, 1.2Mb, 720K (0, 1, 2)
  1931. mov bl,7 ; use reserved "Other" type
  1932.      je equip_type_ok      
  1933. inc bx ; else make it 2.88 Mb type 9
  1934. inc bx
  1935. equip_type_ok:
  1936. mov es:UDSC_TYPE[di],bl ; set the default drive type for format
  1937. equip_no_type:
  1938. mov al,es:UDSC_TYPE[di] ; AL = 0, 1, 2 or 7 (360/1.2/720/1.44)
  1939. cbw ; make it a word
  1940. xchg ax,si ; SI = drive type
  1941. shl si,1 ; SI = drive type * 2
  1942. mov si,bpbs[si] ; get default BPB for drive
  1943. cmp si,CG:bpb360 ; is this is a 360 K drive?
  1944.  jne equip_360 ; skip if any other type
  1945. mov bpbtbl[bx],CG:bpb720 ; use larger default BPB
  1946. equip_360:
  1947. mov cx,UDSC_BPB_LENGTH ; CX = size of BPB
  1948. pushx <es, di, si, cx>
  1949. lea di,es:UDSC_BPB[di]
  1950. mov ax,ds
  1951. mov es,ax ; ES = DS
  1952. rep movsb ; make default BPB current BPB in UDSC
  1953. popx <cx, si, di, es>
  1954. pushx <es, di>
  1955. lea di,es:UDSC_DEVBPB[di]
  1956. rep movsb ; copy default BPB device BPB in UDSC
  1957. popx <di, es>
  1958. ret
  1959. page
  1960. LOG_PRIM equ 01h ; log in primary partitions
  1961. LOG_EXTD equ 02h ; log in extended partitions
  1962. log_flag dw LOG_PRIM ; scan for primary only initially
  1963. hard_init: ; setup all hard disk units
  1964. ;---------
  1965. ; mov log_flag,LOG_PRIM ; log in primary only initially
  1966. call hardi0 ; C: & D:
  1967. mov log_flag,LOG_EXTD ; log in extended only
  1968. ; call hardi0
  1969. ; ret
  1970. hardi0:
  1971. mov ah,ROS_PARAM ; get hard disk parameters
  1972. mov dl,80h
  1973. int_____DISK_INT ; get # of hard disks we have
  1974.  jc hardi9 ; skip if hard disks not supported
  1975. test dl,dl ; test if any hard disks found
  1976.  jz hardi9 ; skip if there weren't any
  1977. mov al,dl
  1978. cbw
  1979. xchg ax,cx ; CX = # of hard disks
  1980. mov dl,80h ; start with first hard disk
  1981. hardi1:
  1982. pushx <cx, dx> ; save drive count, physical drive
  1983. call login_hdisk ; find all partitions on hard disk
  1984. popx <dx, cx> ; restore physical drive, drive count
  1985. inc dx ; next physical hard disk
  1986. loop hardi1 ; next physical hard disk
  1987. hardi9: ; all hard disks done
  1988. ret
  1989. login_hdisk: ; find all partitions on a hard disk
  1990. ;-----------
  1991. ; entry: DL = 80h, 81h for 1st/2nd hard disk
  1992. push log_flag ; save state for next drive
  1993. mov p_unit,dl ; save physical drive
  1994. mov cx,0001h ; track 0, sector 1
  1995. mov dh,0 ; partition tables start on head 0
  1996. log_h1:
  1997. mov dl,p_unit ; get physical unit
  1998. call login_read_dx
  1999.  jnc log_h1a
  2000. jmp log_h9 ; give up if disk error
  2001. log_h1a:
  2002. push cx
  2003. push dx
  2004. mov ah,ROS_PARAM
  2005. int_____DISK_INT ; return disk drive parameters
  2006. inc dh ; DH = number of heads
  2007. mov nhead,dh ; set # of heads on drive
  2008. and cl,3Fh ; isolate sector count
  2009. mov nsect,cl ; set sectors per track
  2010. pop dx
  2011. pop cx
  2012. ;; cmp local_id,0AA55h
  2013. ;;  jne log_h9 ; give up if not initialized
  2014. test log_flag,LOG_PRIM ; scanning for primary?
  2015.  jz log_h5 ; no, ignore all primary partitions
  2016. mov si,CG:local_pt ; point to partition table
  2017. log_h2:
  2018. ;** SECURE PARTITIONS **
  2019. mov al,init_runit
  2020. test al,al ; booting from a hard disk ?
  2021. ;** SECURE PARTITIONS **
  2022. mov al,4[si] ; get system ID
  2023. ;** SECURE PARTITIONS **
  2024.  jns log_h2a ; booting from a hard disk ?
  2025. mov ah,al ; yes, allow secure partitions
  2026. and ah,0F0h
  2027. cmp ah,SEC_ID
  2028.  je log_h02
  2029. cmp ah,SEC_ID2
  2030.  jne log_h2a
  2031. log_h02:
  2032. sub al,ah ; turn into a sensible partition ID
  2033. log_h2a:
  2034. ;** SECURE PARTITIONS **
  2035. cmp al,DOS20_ID ; is this a DOS 2.x partition?
  2036.  je log_h3 ; yes, try to log it in
  2037. cmp al,DOS30_ID ; is this a DOS 3.0/3.1/3.2 partition?
  2038.  je log_h3 ; yes, try to log it in
  2039. cmp al,DOS331_ID ; is this a DOS 3.31/4.0 partition?
  2040.  jne log_h4 ; skip if not a good partition
  2041. log_h3:
  2042. push si ; save partition table index
  2043. pushx <cx, dx> ; save partition table address
  2044. call login_primary ; login primary partition
  2045. popx <dx, cx> ; get partition table address
  2046. call login_read_dx ; re-read partition table
  2047. pop si ; get partition table index
  2048.  jc log_h9 ; give up if error
  2049. log_h4:
  2050. add si,16 ; next partition table entry
  2051. cmp si,CG:local_id ; all partitions checked?
  2052.  jb log_h2 ; loop back if more
  2053. log_h5: ; primary partitions done
  2054. test log_flag,LOG_EXTD ; scanning for extended?
  2055.  jz log_h9 ; skip if no extended scan
  2056. or log_flag,LOG_PRIM ; scan for both types now
  2057. mov si,CG:local_pt ; SI -> partition table
  2058. ; RG-01
  2059. log_h6:
  2060. ;** SECURE PARTITIONS **
  2061. mov al,init_runit
  2062. test al,al ; booting from a hard disk ?
  2063. ;** SECURE PARTITIONS **
  2064. mov al,4[si] ; get system ID
  2065. ;** SECURE PARTITIONS **
  2066.  jns log_h6a ; booting from a hard disk ?
  2067. mov ah,al ; yes, allow secure partitions
  2068. and ah,0F0h
  2069. cmp ah,SEC_ID
  2070.  je log_sec2
  2071. cmp ah,SEC_ID2
  2072.  jne log_h6a
  2073. log_sec2:
  2074. sub al,ah
  2075. log_h6a:
  2076. ;** SECURE PARTITIONS **
  2077. cmp al,DOSEX_ID ; DOS 3.3 extended partition found?
  2078.  jne log_h7
  2079. log_h6b:
  2080. mov dh,1[si] ; get head # for next table
  2081. mov cx,2[si] ; get cylinder, sector for next table
  2082. jmp log_h1 ; read & scan next partition table
  2083. log_h7: ; entry not an extended partition
  2084. add si,16 ; next partition table entry
  2085. cmp si,CG:local_buffer+IDOFF; all partitions checked?
  2086.  jb log_h6 ; loop back if more
  2087. log_h9: ; drive login done
  2088. pop log_flag ; restore state for next drive
  2089. ret
  2090. login_primary:
  2091. ;-------------
  2092. ; entry: SI -> partition table entry
  2093. mov ax,12[si] ; get size of partition (low)
  2094. mov part_size,ax
  2095. mov ax,14[si] ; get size of partition (high)
  2096. mov part_size+2,ax
  2097. mov cl,2
  2098. mov bx,5[si] ; get last head/sector
  2099. and bx,1100000011000000b ; isolate cylinder bits 10..11,8..9
  2100. rol bl,cl ; bits 10..11 from head into position
  2101. or bh,bl ;  or in bits 8..9
  2102. rol bh,cl ; bits 8..11 into place
  2103. mov bl,7[si] ; get cylinder bits 0..7
  2104. mov dh,1[si] ; get head of DOS partition
  2105. mov cx,2[si] ; get cylinder, sector of DOS partition
  2106. pushx <bx,cx,dx>
  2107. call login_read_dx ; try to read the partition boot
  2108. popx <dx,cx,bx>
  2109.  jc login_p9 ; skip if partition not readable
  2110. ; CX, DX = disk addr of 1st sector
  2111. ; SI -> boot sector
  2112. ; PART_SIZE = 32 bit partition address
  2113. cmp nunits,MAXPART ; do we already have the maximum?
  2114.  jb log_p0 ; skip if space for more units
  2115. login_p9:
  2116. ret ; else ignore this partition
  2117. log_p0:
  2118. call new_unit ; ES:DI -> new UDSC
  2119. mov es:UDSC_FLAGS[di],UDF_HARD
  2120. mov es:UDSC_RUNIT[di],dl ; set physical drive (ROS code)
  2121. mov es:UDSC_TYPE[di],5 ; set type = hard disk
  2122. mov al,dh ; copy head byte
  2123. and al,11000000b ; cylinder # bits 10..11 are in 6..7
  2124. rol al,1 ; shift bits to bottom of word
  2125. rol al,1
  2126. mov ah,cl ; cylinder # bits 8..9 are in 6..7
  2127. and ah,11000000b ; strip off non-cylinder # bits
  2128. or ah,al ; combine the bits
  2129. rol ah,1 ; shift the bits into place
  2130. rol ah,1
  2131. mov al,ch ; cylinder # bits 0..7
  2132. sub bx,ax ; bx = # cylinders
  2133. inc bx ; make it inclusive
  2134. mov es:UDSC_NCYL[di],bx ; and save it
  2135. push ax ; save # CYLINDERS
  2136. mov al,nsect
  2137. and dh,00111111b ; DH = head offset
  2138. mul dh ; AX = HEAD_OFF * NSECT
  2139. xchg ax,bx ; keep in BX
  2140. mov al,nsect
  2141. mul nhead ; AX = HEADS * NSECT
  2142. pop dx ; recover # CYLINDERS
  2143. mul dx ; DX:AX = CYLINDERS * HEADS * NSECT
  2144. add ax,bx
  2145. adc dx,0 ; DX:AX = (CYL*HEADS + HEAD_OFF)*NSECT
  2146. and cx,00111111b ; isolate bottom 6 bits (sector #)
  2147. dec cx ; sector numbers are one-relative
  2148. add ax,cx ; add in non-partition sectors
  2149. adc dx,0 ;   (usually 2.x partition table)
  2150. lea bx,UDSC_BPB[di] ; BX -> BPB to build
  2151. add si,11 ; skip JMP + OEM name in boot sector
  2152. mov es:word ptr BPB_HIDDEN[bx],ax ; set the partition address
  2153. mov word ptr BPB_HIDDEN+2[bx],dx ;   (32 bit sector offset)
  2154. mov ax,part_size
  2155. mov dx,part_size+2
  2156. mov word ptr BPB_SIZE[bx],ax ; set partition size in sectors
  2157. mov word ptr BPB_SIZE+2[bx],dx
  2158. mov BPB_TOTSEC[bx],ax ; set partition size for < 32 Mb
  2159. ; we'll zero this later if > 32 Mb
  2160. push es
  2161. push di
  2162. push ax
  2163. push dx
  2164. push si
  2165. call hd_bpb ; build BPB from scratch
  2166. pop si
  2167. pop dx
  2168. pop ax
  2169. pop di
  2170. pop es
  2171. cmp byte ptr -11[si],0E9h ; look for a jmp
  2172. jz log_p1a
  2173. cmp word ptr -11[si],0EB90h ; look for a nop!jmps
  2174. jz log_p1a
  2175. cmp byte ptr -11[si],0EBh ; look for a jmps
  2176. jnz log_p1 ; at the start of the boot sector. 
  2177. cmp byte ptr -9[si],90h ; EJH 7-1-91
  2178. jnz log_p1
  2179. log_p1a:
  2180. test BPB_SECSIZ[si],SECSIZE-1; not a multiple of 512 byte?
  2181.  jnz log_p1
  2182. cmp BPB_FATID[si],0F8h ; is this a good hard disk?
  2183.  jne log_p1
  2184. cmp BPB_NFATS[si],2 ; too many FATs?
  2185.  ja log_p1
  2186. cmp BPB_NFATS[si],1 ; no FATs at all?
  2187.  jae log_p2 ; continue if BPB is valid
  2188. ; elsa build new BPB
  2189. log_p1: ; any of the above:  BPB invalid
  2190. ; (propably FDISKed, not FORMATted yet)
  2191. jmps log_p9
  2192. log_p2: ; valid BPB for partition, AX/DX = size
  2193. push ax
  2194. mov al,BPB_ALLOCSIZ[si] ; copy a few parameters from the 
  2195. mov BPB_ALLOCSIZ[bx],al ; Boot Sector BPB to our new BPB
  2196. mov ax,BPB_DIRMAX[si] ; EJH 7-1-91
  2197. mov BPB_DIRMAX[bx],ax
  2198. mov ax,BPB_FATSEC[si]
  2199. mov BPB_FATSEC[bx],ax
  2200. mov ax,BPB_SECSIZ[si]
  2201. mov BPB_SECSIZ[bx],ax
  2202. mov ax,BPB_FATADD[si]
  2203. mov BPB_FATADD[bx],ax
  2204. mov al,BPB_NFATS[si]
  2205. mov BPB_NFATS[bx],al
  2206. pop ax
  2207. cmp BPB_TOTSEC[bx],0 ; is it an 32 bit sector partition ?
  2208.  jne log_p3 ; no, carry on
  2209. test dx,dx ; would it fit in 16 bit sector sizes ?
  2210.  jnz log_p3 ; yes, then make BPB_TOTSEC
  2211. mov BPB_TOTSEC[bx],ax ;  a valid 16 bit value too
  2212. log_p3: ; valid BPB for partition, AX/DX = size
  2213. cmp BPB_SECSIZ[bx],SECSIZE
  2214.  jbe log_p9 ; skip if no large sectors
  2215. shr BPB_SECSIZ[bx],1 ; halve the sector size
  2216. shl BPB_ALLOCSIZ[bx],1 ; double the cluster size
  2217. shl BPB_FATSEC[bx],1 ; double the FAT size
  2218. shl BPB_FATADD[bx],1 ; double the FAT address
  2219. shl BPB_TOTSEC[bx],1 ; double # of sectors
  2220.  jnc log_p3 ; skip if still < 65536 sectors
  2221. mov BPB_TOTSEC[bx],0 ; else indicate large partition
  2222. jmps log_p3 ; try again
  2223. ; we've adjusted the sector size
  2224. log_p9:
  2225. pushx <ds, di>
  2226. push es
  2227. pop ds
  2228. lea si,UDSC_BPB[di] ; DS:SI -> new BPB
  2229. lea di,UDSC_DEVBPB[di] ; ES:DI -> fixed BPB
  2230. mov cx,UDSC_BPB_LENGTH
  2231. rep movsb ; make this the fixed BPB
  2232. popx <di, ds>
  2233. call add_unit ; register this DDSC_
  2234. inc nhard ; yet another hard disk
  2235. ret
  2236. hd_bpb:
  2237. ;------
  2238. mov BPB_SECSIZ[bx],SECSIZE ; set standard sector size
  2239. mov BPB_FATADD[bx],1 ; one reserved (boot) sector
  2240. mov BPB_NFATS[bx],2 ; two FAT copies
  2241. mov BPB_DIRMAX[bx],512 ; assume 512 entry root directory
  2242. ; BPB_TOTSEC set up already
  2243. mov BPB_FATID[bx],0F8h ; standard hard disk ID
  2244. mov al,nsect
  2245. mov ah,0
  2246. mov BPB_SPT[bx],ax ; set sectors/track
  2247. mov al,nhead
  2248. mov BPB_HEADS[bx],ax ; set # of heads
  2249. ; determine FAT size:
  2250. mov BPB_ALLOCSIZ[bx],2*2 ; assume 2 K clusters
  2251. mov ax,word ptr BPB_SIZE[bx]; AX/DX = 32 bit sector count
  2252. mov dx,word ptr BPB_SIZE+2[bx]
  2253. test dx,dx ; have we got huge partition (type 6)?
  2254.  jnz hd_bpb10 ; yes, it's 16-bit
  2255. cmp ax,7FCEh ; more than 16 Mb?
  2256.  jae hd_bpb20 ; yes, use 16 bit FAT
  2257. mov cx,4*2 ; else we've got old 12-bit FAT
  2258. mov BPB_ALLOCSIZ[bx],cl ; we use 4 K clusters
  2259. add ax,cx ; adjust DX:AX for rounding
  2260. dec ax ;  when we work out num clusters
  2261. div cx ; AX = # of clusters
  2262. mov cx,ax
  2263. add ax,ax ; * 2
  2264. add ax,cx ; * 3
  2265. shr ax,1 ; AX = num clus * 3/2 = bytes
  2266. adc ax,512-1 ; allow for rounding
  2267. xor dx,dx
  2268. mov cx,512
  2269. div cx ; AX = # fat sectors
  2270. mov BPB_FATSEC[bx],ax ; remember FAT size
  2271. ret
  2272. hd_bpb10:
  2273. mov BPB_TOTSEC[bx],0 ; zero this if BPB_SIZE is required
  2274. cmp dx,2 ; less than 2*65536 sectors (64 Mb)?
  2275.  jb hd_bpb20 ; yes, leave cluster size the same
  2276. mov BPB_ALLOCSIZ[bx],4*2 ; use 4 K clusters if 64-128 Mb
  2277. cmp dx,4 ; less than 4*65536 sectors (128 Mb)?
  2278.  jb hd_bpb20 ; yes, leave cluster size the same
  2279. mov BPB_ALLOCSIZ[bx],8*2 ; use 8 K clusters if 128-512 Mb
  2280. cmp dx,16 ; less than 16*65536 sectors (512 Mb)?
  2281.  jb hd_bpb20 ; yes, leave cluster size the same
  2282. mov BPB_ALLOCSIZ[bx],16*2 ; use 16 K clusters if 512-1024 Mb
  2283. cmp dx,32 ; less than 32*65536 sectors (1 Gb)?
  2284.  jb hd_bpb20 ; yes, leave cluster size the same
  2285. mov BPB_ALLOCSIZ[bx],32*2 ; use 32 K clusters if 1-2 Gb
  2286. hd_bpb20: ; cluster size determined
  2287. sub ax,1+(512*32/SECSIZE) ; subtract reserved+root directory
  2288. sbb dx,0 ; (note: 32 bytes per entry)
  2289. xor cx,cx
  2290. mov ch,BPB_ALLOCSIZ[bx] ; CX = (256 * # of clusters on drive)
  2291. dec cx
  2292. add ax,cx ; add in for rounding error
  2293. adc dx,0
  2294. inc cx
  2295. div cx ; AX = # of fat sectors
  2296. mov BPB_FATSEC[bx],ax ; remember FAT size
  2297. mov es:UDSC_FSTYPE+4[di],'6'; change "FAT12" to "FAT16"
  2298. ret
  2299. new_unit:
  2300. push ds
  2301. push ax
  2302. push bx
  2303. push cx
  2304. push dx
  2305. push si
  2306. mov es,cs:DataSegment
  2307. mov di,endbios ; get next unit descriptor
  2308. mov cx,UDSC_LENGTH
  2309. add endbios,cx ; grow the BIOS size
  2310. xor ax,ax
  2311. push di
  2312. rep stosb ; zero the UDSC
  2313. pop di
  2314. xor bx,bx
  2315. mov bl,nunits ; BX = unit we are working on
  2316. mov es:UDSC_DRIVE[di],bl ; make that our logical unit
  2317. shl bx,1 ; make it a BPB index
  2318. lea ax,es:UDSC_DEVBPB[di] ; get storage area for device BPB
  2319. mov bpbtbl[bx],ax ; update entry in BPB table
  2320. shr bx,1 ; get the latest drive
  2321. inc bx ; onto next unit
  2322. cmp bl,2 ; 3rd floppy ?
  2323.  jne new_unit10
  2324. add bl,nhard ; yes, skip past hard disks
  2325. new_unit10:
  2326. mov nunits,bl ; store ready for next time
  2327. mov es:UDSC_RUNIT[di],0FFh ; set physical drive (ROS code)
  2328. push cs
  2329. pop ds ; DS:SI -> our dummy value
  2330. mov si,offset CGROUP:dummyMediaID
  2331. call UpdateMediaID ; update UDSC_ with media info
  2332. pop si
  2333. pop dx
  2334. pop cx
  2335. pop bx
  2336. pop ax
  2337. pop ds
  2338. ret
  2339. ICODE ends
  2340. RESBIOS segment 'RESBIOS'
  2341. ; NOTE: we extend the resident BIOS size by the amount of
  2342. ; memory required by the disk driver.
  2343. db MAXPART*UDSC_LENGTH dup (?)
  2344. RESBIOS ends
  2345. IDATA segment
  2346. p_unit db ? ; 80h, 81h for hard disks
  2347. nsect db ? ; # of sectors per track
  2348. nhead db ? ; # of heads on disk
  2349. part_size dw 2 dup (?) ; temporary save address for size
  2350. nunits db 2 ; start with driver C:
  2351. nhard db 0 ; # of hard disk partitions
  2352. nfloppy db 0 ; # of floppy drives
  2353. Public init_runit
  2354. init_runit db 0 ; poked with ROS Unit at boot
  2355. IDATA ends
  2356. end