; INT25_26.ASM -- Basic INT 25h and 26h procedures for reading or writing ; one or more disk sectors. FAT type of disk must be either ; 12-bit or 16-bit. DOS versions 2.xx through 7.xx. ; This code is free for any one to use or enhance. ; ; Created by: James Webster ; 113 Riverview Drive ; Lafollette, TN 37766 ; EMAIL: jwebste3@bellsouth.net include macro.inc .data? public sector sector db 8192d dup (?) ;Most sectors equal only 512 bytes. .data public disk_drive_no, sector_error_code, rw_sec_plist public current_sector_low, current_sector_high, no_sectors public ext_int_25h_flag public dos_version, dos_major, dos_minor disk_drive_no db 0 ;0=A, 1=B, 2=C, etc. ;--Set by: READ_SECTOR, WRITE_SECTOR--------------------------------- sector_error_code db 0 ;Error code if a sector read/write error. ; 00h = Disk is write-protected. ; 01h = Invalid drive number. ; 02h = Drive not ready. ; 04h = Bad CRC. ; 06h = Couldn't access track. ; 07h = Unrecognizable disk format. ; 08h = Sector not found. ; 0Ah = Write error. ; 0Bh = Read error. ; 0Ch = General unknown error. ;--Read by: READ_SECTOR, WRITE_SECTOR-------------------------------- ;--Set by: INIT_EXT_INT_25H_FLAG------------------------------------ ext_int_25h_flag dw 0 ;If = 0, use pre-DOS v4.0 INT 25h/26h. ;If = 1, use DOS v4.0+ INT 25h/26h. int_25h_data db 83h,0f9h,0ffh ;"CMP CX,-01". ;--Read by: READ_SECTOR, WRITE_SECTOR-------------------------------- ;--Set by: GET_DOS_VERSION------------------------------------------ dos_version label word dos_minor db 0 ;Example: 0Ah = version x.10 dos_major db 0 ;Example: 02h = version 2.xx ;--Read by: READ_SECTOR, WRITE_SECTOR-------------------------------- ;--Set by the remaining routines.------------------------------------ rw_sec_plist label word ;Pointer required by INT 25/26 for v4.xx +. current_sector_low dw 0 ;Current sector number, low word. current_sector_high dw 0 ;Current sector number, high word. no_sectors dw 1 ;Number of sectors to read or write. dw offset sector ;Offset address of buffer. dw seg sector ;Segment address of buffer. .code public read_sector, write_sector public init_ext_int_25h_flag public get_dos_version ;--------------------------------------------------------------------; ; This procedure reads the requested number of disk sectors into ; ; the buffer SECTOR. Compatible to DOS v7.xx. ; ; ; ; Uses: ; ; Reads: EXT_INT_25H_FLAG, DISK_DRIVE_NO, CURRENT_SECTOR_LOW, ; ; NO_SECTORS, RW_SEC_PLIST ; ; Writes: SECTOR, SECTOR_ERROR_CODE ; ; On exit: If unsuccessful: ; ; 1. Carry flag is set. ; ; 2. SECTOR_ERROR_CODE contains error code. ; ;--------------------------------------------------------------------; read_sector proc pushad pushr ;NOTE: DI, SI, and BP are destroyed. beg_read_s: mov al,disk_drive_no ;AL = disk drive number. cmp ext_int_25h_flag,0 ;Use pre-DOS v4.xx ? jz read_sector_2_3xx ;If = 0, yes. Jump. lea bx,rw_sec_plist ;DS:BX = address of parameter list. mov cx,-1 ;CX = -1. jmps cont_read_sector ;And jump to continue. read_sector_2_3xx: lea bx,sector ;DS:BX = addr of buffer to write to. mov cx,no_sectors ;CX = number of sectors to read. mov dx,current_sector_low ;DX = beginning sector # (0 based). cont_read_sector: int 25h ;Read Absolute Sector(s) Interrupt. jc err_read_sector ;If carry set, error occured. popf ;INT 25h pushes flags onto the stack. clc ;Clear the carry flag. jmps exit_read_sector ;And exit. err_read_sector: popf ;INT 25h pushes flags onto the stack. mov sector_error_code,al ;Store the error code. cmp al,2 ;Drive not ready ? jne stc_read_s ; call disp_door_open ;Tell user to close drive door. ; jmps beg_read_s ;And try again. stc_read_s: stc ;Set the carry flag. exit_read_sector: popr popad ret read_sector endp ;--------------------------------------------------------------------; ; This procedure writes the requested number of disk sectors from ; ; the buffer SECTOR. Compatible to DOS v7.xx. ; ; ; ; Uses: ; ; Reads: EXT_INT_25H_FLAG, DISK_DRIVE_NO, CURRENT_SECTOR_LOW, ; ; NO_SECTORS, RW_SEC_PLIST, SECTOR ; ; Writes: SECTOR_ERROR_CODE ; ; On exit: If unsuccessful: ; ; 1. Carry flag is set. ; ; 2. SECTOR_ERROR_CODE contains error code. ; ;--------------------------------------------------------------------; write_sector proc pushad pushr ;NOTE: DI, SI, and BP are destroyed. beg_wr_sec: mov al,disk_drive_no ;AL = disk drive number. cmp ext_int_25h_flag,0 ;Use pre-DOS v4.xx ? jz write_sector_2_3xx ;If = 0, yes. Jump. lea bx,rw_sec_plist ;DS:BX = address of parameter list. mov cx,-1 ;CX = -1. jmps cont_write_sector ;And jump to continue. write_sector_2_3xx: lea bx,sector ;DS:BX = addr of buffer to read from. mov cx,no_sectors ;CX = number of sectors to write. mov dx,current_sector_low ;DX = beginning sector # (0 based). cont_write_sector: int 26h ;Write Absolute Sector(s) Interrupt. jc err_write_sector ;If carry set, error occured. popf ;INT 26h pushes flags onto the stack. clc ;Clear the carry flag. jmps exit_write_sector ;And exit. err_write_sector: popf ;INT 26h pushes flags onto the stack. mov sector_error_code,al ;Store the error code. cmp al,0 ;Write protect error ? je write_sector_wp cmp al,2 ;Drive not ready ? jne stc_wr_sec ; call disp_door_open ;Tell user to close drive door. ; jmps beg_wr_sec ;And try again. write_sector_wp: ; call disp_write_protected ;Tell user to disable write protect. ; jnc beg_wr_sec ;If NC, user wishes to try again. stc_wr_sec: stc ;Set the carry flag. exit_write_sector: popr popad ret write_sector endp ;--------------------------------------------------------------------; ; This procedure first checks DOS_MAJOR and then (if < DOS v4.xx) ; ; the contents of INT 25h to see if the operating system will allow ; ; the use of the Extended INT 25h/26h to access > 32mb. ; ; NOTE: The Extended INT 25h/26h was actually implemented in DOS ; ; v3.3, but not in all OEM releases. ; ; ; ; Caller(s): GET_DOS_VERSION ; ; Reads: DOS_MAJOR, INT_25h_DATA ; ; Writes: EXT_INT_25H_FLAG ; ;--------------------------------------------------------------------; init_ext_int_25h_flag proc mov ext_int_25h_flag,1 ;Assume DOS v4.00+ INT 25h/26h. cmp dos_major,4 ;DOS major version 4.xx ? jae end_init_e25h_flag ;If = or > 4, exit. pushr ;If not, parse Interrupt 25h. mov ah,35h ;Get Interrupt Vector function. mov al,25h ;AL = the interrupt number. int 21h ;Call DOS. Returns ES:BX pointer. mov di,bx ;ES:DI = string to compare. inc di ;Advance past FB ("STI"). lea si,int_25h_data ;DS:SI = 83,F9,FF = "CMP CX,-01". mov cx,3 ;CX = length of string compare. cld ;Set direction for increment. repz cmpsb ;Compare DS:SI with ES:DI. popr jz end_init_e25h_flag ;If string match, exit. Else: clear_init_e25h_flag: mov ext_int_25h_flag,0 ;Use pre-DOS v4.xx+ INT 25h/26h. end_init_e25h_flag: ret init_ext_int_25h_flag endp ;--------------------------------------------------------------------; ; This procedure returns the DOS major and minor version numbers. ; ; ; ; Caller(s): ; ; Uses: INIT_EXT_INT_25H_FLAG ; ; Writes: DOS_MAJOR, DOS_MINOR ; ;--------------------------------------------------------------------; get_dos_version proc pushr mov ax,3000h ;Get DOS Version function. int 21h ;Returns: AL=major, AH=minor. or al,al ;Check for version 1.xx. jnz cont_get_dos_ver ;If AL > 0, jump. mov dos_major,1 ;Else, its DOS v1.xx jmps exit_get_dos_ver ;And exit. cont_get_dos_ver: mov dos_major,al ;Store the major version number. mov dos_minor,ah ;Store the minor version number. cmp al,5 ;Is this version 5.0 or greater ? jb exit_get_dos_ver ;If AL < 5 exit. Else: mov ax,3006h ;Get Actual DOS Version (v5.0+). int 21h ;Returns: AL=major, AH=minor. mov dos_major,al ;Store the major version number. mov dos_minor,ah ;Store the minor version number. exit_get_dos_ver: popr call init_ext_int_25h_flag ;See if Extended INT 25h/26h allowed. ret get_dos_version endp end