page 250,150 ;Header---------------------------------------------------------- ; ; MASM needs this cryptic piece of text to be able to make an ; .OBJ file. I have mainly copied it from a textbook. I do not ; really know what all this gougou means. ; code segment para 'code' ; define code segment org 0100h ; start at offset 0100H assume cs:code, ds:code, es:code, ss:code ; ; This is the starting address of the thing .... ; start: jmp init ; do init actions ; ;End------------------------------------------------------------ ;Params--------------------------------------------------------- ; ; ;End------------------------------------------------------------ ;Data----------------------------------------------------------- ; ;End------------------------------------------------------------ ;Defs----------------------------------------------------------- ; ; All defines of parameters that are not bytes etc.. ; ; constants ; cr equ 00DH ; ASCII Carriage Return lf equ 00AH ; ASCII Line Feed eom equ '$' ; PC's End Of Message ; ; The I/O ports of the IDE controller ; IoBase equ 8078H ; I/O base address for the disk IoDatL equ 8078H ; Low byte data IDE (port A) IoDatH equ 8079H ; High byte data IDE (port B) IoCtl equ 807AH ; Control byte for IDE (port C) IoMod equ 807BH ; I/O modus IDE and bit set/clr ; ; The I/O modi I use ; DMout equ 10000000B ; all output DMin equ 10010010B ; ctl = output, data input ; ; The bits of the control byte of the IDE bus ; DCNOP equ 00000000B ; Nothing on IDE ctl bus DCIow equ 10000000B ; /IOWR bit DCSetIow equ 00001111B ; Activate /IOWR DCClrIow equ 00001110B ; Negate /IOWR DCIor equ 01000000B ; /IORD bit DCSetIor equ 00001101B ; Assert /IORD DCClrIor equ 00001100B ; Negate /IORD DCCs1 equ 00100000B ; /CS1 bit DCCs0 equ 00010000B ; /CS0 bit DCRes equ 00001000B ; /reset bit DCADR equ 00000111B ; ADR mask bits ; ; IDE register adresses ; IDECmd equ 07H ; addres for command IDESts equ 07H ; addres status register IDEHd equ 06H ; addres head number IDECylH equ 05H ; addres cylinder number high IDECylL equ 04H ; addres cylinder number low IDEsec equ 03H ; addres sector number IDEnum equ 02H ; addres number of sectors IDEData equ 00H ; addres for data bus IDERIRQ equ 0EH ; addres Reset/IRQ register IDEErr equ 01H ; addres Error register ; ; The head number (0..F) also has the mask for master/slave ; I fix this at Master, I do not think I will use two drives ; on my IDE interface. ; IDEHdA equ 00001111B ; head number and mask IDEHdO equ 10100000B ; head number or mask ; ; The Reset/IRQ register has two interesting bits ; IDESRes equ 00000100B ; Soft Reset bit IDENIRQ equ 00000010B ; 0 = IRQ active ; ; The bits from IDE Status register ; StsBsy equ 10000000B ; busy flag StsRdy equ 01000000B ; ready flag StsWft equ 00100000B ; Write error StsSKC equ 00010000B ; seek complete StsDRQ equ 00001000B ; Data Request StsCorr equ 00000100B ; ECC executed StsIdx equ 00000010B ; Index found StsErr equ 00000001B ; error flag ; ; Command opcodes I use ; CmdRecal equ 010H ; recalibrate disk CmdRead equ 020H ; write a block CmdWrite equ 030H ; read block CmdStop equ 0E0H ; Stop disk CmdStrt equ 0E1H ; Start disk CmdIdent equ 0ECH ; Identify disk ; ; I use LBA internally on all disks, even on those that do not ; support it. I locally compute in LBA, the low-level routines ; (notably SetLBA) convert LBA to CHS notation. All ATA3 ; compliant disks support automatic geometry detection by means ; of disk ident. This means that I can read the disk's geometry ; from the disk itself. The routine IdentDisk does that. ; I have -till now- found one (very old) disk that does not give ; proper answers in an IdentDisk request. I will have to provide ; for a 'manual override' on this automatic disk size detection ; mechanism. Below are my findings of the results of IdentDisk ; on several disks I have. ; ;End------------------------------------------------------------ ;Debug---------------------------------------------------------- ; ; defines for debugging purposes ; ;End------------------------------------------------------------ ;Program-------------------------------------------------------- ; ; The transient program part. In the final code this part will ; have to move to the back of the program, so it can be released ; to DOS (DIP) when it is done. For now I keep it here.. I still ; have to find out how to combine uninitialized data with this ; transient program bahaviour. ; prog proc near ; the actual program ; main: call Stopdisk ; ; for the moment that is it... mainend:mov ax,04C00H ; int 21h ; ;--------------------------------------------------------------- ; Routine SetIn ; purp: set all ports of the 8255 for input from the IDE bus ; in : nothing ; out : nothing ; uses: nothing ; NB : This also resets ALL control lines and adr selection SetIn: push ax ; save accu push dx ; mov dx,IoMod ; write to modus port mov al,DMIn ; out dx,al ; pop dx ; restore registers pop ax ; ret ; ;--------------------------------------------------------------- ; Routine SetOut ; purp: set all ports of the 8255 for output to the IDE bus ; in : nothing ; out : nothing ; uses: nothing ; NB : This also resets ALL control lines and adr selection SetOut: push ax ; save accu push dx ; mov dx,IoMod ; mov al,DMout ; out dx,al ; pop dx ; pop ax ; ret ; ;--------------------------------------------------------------- ; Routine StopDisk ; purp: spin down the disk ; in : nothing ; out : nothing ; uses: al StopDisk: mov al,CMDStop ; give the command ; jmp DoCmd ; ;--------------------------------------------------------------- ; Fragment DoCmd ; purp: part of the execution of a command. This part waits till ; the disk is ready for the next command ; in : nothing ; out : nothing ; uses: al DoCmd: call WaitNBSY ; wait till disk ready for command ; jmp WriteCmd ; see code below ;--------------------------------------------------------------- ; Routine WriteCmd ; purp: Write one command byte to the IDE command register ; in : command in AL ; out : nothing ; uses: nothing WriteCmd: push ax ; save a call SetOut ; set bus to output mov al,IDECmd ; set address call SetAdr ; pop ax ; get command byte back ; jmp WriteByte ; see code below ;--------------------------------------------------------------- ; Routine WriteByte ; purp: Write one byte to the IDE bus ; in : byte in AL ; out : nothing ; uses: nothing WriteByte: push dx ; save dx push ax ; save ax too mov dx,IoDatL ; put data byte on port out dx,al ; mov dx,IoMod ; go make write pulse mov al,DCSetIow ; make write strobe out dx,al ; mov al,DCClrIow ; put original byte back out dx,al ; pop ax ; pop dx ; ret ; ;--------------------------------------------------------------- ; Routine SetAdr ; purp: Set an address on the IDE bus ; in : address in al [0 .. F] ; out : nothing ; uses: nothing ; NB : clears all other control bits in the process SetAdr: push dx ; save registers push bx ; push ax ; ; set which CS to assert and al,00001000B ; see if adres > 8 jz wrad1 ; mov al,DCCs1 ; high address jmp wrad2 ; wrad1: mov al,DCCs0 ; low address wrad2: ; put low bits in place pop bx ; addres -> BX push bx ; back on stack and bx,DCAdr ; low addres in BX or al,bl ; get low addres in A ; output address mov dx,IoCtl ; on control byte out dx,al ; ; get registers back pop ax ; pop bx ; pop dx ; ret ; ;--------------------------------------------------------------- ; Routine ReadSts ; purp: get status if the IDE device ; in : nothing ; out : status byte in al ; uses: nothing ReadSts: call SetIn ; set bus to input mov al,IDESts ; set address ; jmp ReadReg ; see code below here ;--------------------------------------------------------------- ; Routine ReadReg ; purp: get byte from the IDE device ; in : address in al ; out : data byte in al ; uses: nothing ReadReg:call SetAdr ; ; jmp ReadByte ; see code below ;--------------------------------------------------------------- ; Routine ReadByte ; purp: Read one byte from the IDE bus ; in : nothing ; out : byte in al ; uses: ax ; nb : assumes address and bus have been set ReadByte: push dx ; save dx mov dx,IoMod ; get current mov al,DCSetIor ; set Io read out dx,al ; set on port mov dx,IoDatL ; get data in al,dx ; mov ah,al ; save in ah mov dx,IoMod ; reset read strobe mov al,DCClrIor ; out dx,al ; mov al,ah ; get data from ah pop dx ; restore dx ret ; ;--------------------------------------------------------------- ; Routine WaitNBSY ; purp: wait till the drive indicates ready status ; in : nothing ; out : nothing ; uses: nothing WaitNBSY: push ax ; save registers ; test if device ready wtrdy1: call ReadSts ; get status byte and al,StsBsy ; get status bits jz FinWait ; jmp wtrdy1 ; wait for it ;--------------------------------------------------------------- ; Fragment FinWait ; purp: finishes up things when waiting for something is done ; in : ax still on stack ; out : nothing ; uses: nothing ; NB : this code fragment is a result of code compression ; it is used by the routines WaitDRQ, WaitNBSY and ; WaitDRDY FinWait:pop ax ; get ax back from stack ret ; routine done ; prog endp ; ; ;End------------------------------------------------- ;Init------------------------------------------------ ; ; Initialisation code, releases all unused memory to ; DOS (DIP in this case...). This part is for the ; transient program mainly. ; Init: mov ah,4AH ; free all unused memory mov bx,offset einde ; mov cl,4 ; shr bx,cl ; inc bx ; int 21H ; ; set the stackpointer mov sp,offset stackinit ; jmp main ; ; ;End------------------------------------------------- ;Unintialized data----------------------------------- ; ; This data is not stored on the disk. I get it when ; the program starts running, I just do not release ; it to DOS. ; ; The disk data I/O block, 512 bytes diskblock label near diskblocksize equ 0 ; not needed ; ;End------------------------------------------------- ;Stack----------------------------------------------- ; ; The program's stack space, not stored on disk. In fact ; this is uninitialized data too, I just use the special ; name it has... ; stackbegin equ diskblock + diskblocksize stacksize equ 256 ; 256 bytes stackinit equ stackbegin + stacksize ; ;End------------------------------------------------ ;End-Of-Code---------------------------------------- ; ; This part satifies MASM as for the segment etc.. ; define of the code. It contains the end-of-segment ; info and some other things needed to satify MASM ; ; All memory locations after the locations einde and ; endresident will be released... ; einde equ stackbegin + stacksize endresident equ einde ; ; some MASM-satisfiers ; code ends ; end of code segment ; end start ; end of the program ; entry point = start ;End------------------------------------------------