--- /dev/null
+
+;-----------------------------------------------------------------------------
+; ElTorito.asm
+;
+; El Torito Bootable CD-ROM driver which does not reset the CD-ROM drive upon
+; loading, but instead accesses the drive through BIOS system calls
+;
+; MIT License
+;
+; (c) 2000 by Gary Tong
+; (c) 2001-2009 by Bart Lagerweij
+;
+; Permission is hereby granted, free of charge, to any person obtaining a copy
+; of this software and associated documentation files (the "Software"), to deal
+; in the Software without restriction, including without limitation the rights
+; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+; copies of the Software, and to permit persons to whom the Software is
+; furnished to do so, subject to the following conditions:
+;
+; The above copyright notice and this permission notice shall be included in
+; all copies or substantial portions of the Software.
+;
+; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+; THE SOFTWARE.
+;
+;-----------------------------------------------------------------------------
+
+; To assemble and link, use these commands in TASM 5.0:
+; tasm file
+; tlink /t file,file.sys
+
+; To enable Trace markers uncomment the line below
+; DEBUG_TRACERS=1
+
+; To enable debug info uncomment the line below
+; DEBUG=1
+
+%ifdef DEBUG_TRACERS
+ %macro TRACER 1
+ call debug_tracer
+ db %1
+ %endmacro
+%else
+ %macro TRACER 1
+ %endmacro
+%endif ; DEBUG_TRACERS
+
+%define Ver '1.5'
+%define CR 0DH, 0Ah
+RPolyH equ 0EDB8h
+RPolyL equ 08320h
+
+ section .text align=16
+ org 0
+
+;=============================================================================
+
+Cdrom:
+
+NextDriver dd -1 ;\
+Attributes dw 0C800h ; |
+Pointers dw Strategy ; |
+ dw Commands ; | MSCDEX requires this
+DeviceName db 'ELTORITO' ; | data in these locations
+ dw 0 ; |
+DriveLetter db 0 ; |
+NumUnitsSupp db 1 ;/
+
+DriverName db 'El-Torito CD-ROM Device Driver',0
+ReqHdrLoc dw 0,0 ; 35h
+DriveNumber db 0 ; 39h
+XferAddr dw 0,0 ; 3ah
+Checksum dw -1,-1
+ReadBytes db 0 ;0 --> 2048 bytes/sector
+ ;1 --> 1024 bytes/sector
+ ;2 --> 512 bytes/sector
+
+Routines dw Init ;Init ;0
+ dw Unsupported ;MediaCheck ;1
+ dw Unsupported ;BuildBPB ;2
+ dw IoctlInput ;IoctlInput ;3
+ dw Unsupported ;Input ;4
+ dw Unsupported ;NonDesInput ;5
+ dw Unsupported ;InputStatus ;6
+ dw Unsupported ;InputFlush ;7
+ dw Unsupported ;Output ;8
+ dw Unsupported ;OutputVerify ;9
+ dw Unsupported ;OutputStatus ;10
+ dw Unsupported ;OutputFlush ;11
+ dw IoctlOutput ;IoctlOutput ;12
+ dw DoNothing ;DeviceOpen ;13
+ dw DoNothing ;DeviceClose ;14
+ dw ReadL ;ReadL ;128
+
+IoctlICtrl dw Raddr ;Raddr ;0
+ dw Unsupported ;LocHead ;1
+ dw Unsupported ;(Reserved) ;2
+ dw Unsupported ;ErrStat ;3
+ dw Unsupported ;AudInfo ;4
+ dw DrvBytes ;DrvBytes ;5
+ dw DevStat ;DevStat ;6
+ dw SectSize ;SectSize ;7
+ dw VolSize ;VolSize ;8
+ dw MedChng ;MedChng ;9
+
+SpecPkt times 19 db 0 ; offset 77h in 1.4
+ times 13 db 0 ; unknown extra 00s in 1.4
+
+Greeting db 'El-Torito Bootable CD-ROM Driver for Dos v',Ver,', http://www.nu2.nu/eltorito/',CR
+ db ' (c) 2000 by Gary Tong',CR
+ db ' (c) 2001-2002 by Bart Lagerweij',CR,0
+DblSpace db ' ',0
+
+;=============================================================================
+
+Strategy:
+
+ mov word [cs:ReqHdrLoc],bx
+ mov word [cs:ReqHdrLoc+2],es
+ retf
+
+
+;=============================================================================
+
+Commands:
+
+ push ax
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+; pushad
+ push ds
+ push es
+ TRACER 'C'
+
+ cld ;Clear direction
+ sti ;Enable interrupts
+
+ mov ax, cs ;ds=cs
+ mov ds, ax
+
+ les bx,[ReqHdrLoc] ;seg:offset ptr into es:bx
+ xor ax,ax
+ mov al,[es:bx+2] ;Get Command code
+%ifdef DEBUG
+ call print_hex8
+%endif
+ cmp al,15
+ jb Mult2 ;If 0-14
+ cmp al,128
+ jb UnknownCmd ;If 15-127
+ cmp al,129
+ jb ShiftDown ;If 128
+UnknownCmd: mov al,121 ;8 = Unsupported (Reserved)
+ShiftDown: sub al,113 ;128 --> 15, 121 --> 8
+Mult2: shl al,1 ;Convert into offset (*2)
+ mov di,Routines
+ add di,ax
+ call word [di] ;Execute desired command
+ or ax,100h ;Set Return Status's Done bit
+ lds bx,[ReqHdrLoc] ;seg:offset ptr into ds:bx
+ mov [bx+3],ax ;Save Status
+
+%ifdef DEBUG
+ cmp byte [cs:buffer+2048], 96h
+ je buffer_ok
+ mov al, '!'
+ call print_char
+ jmp $
+buffer_ok:
+%endif
+
+ TRACER 'c'
+ pop es
+ pop ds
+; popad
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ retf
+
+
+;=============================================================================
+
+Unsupported: ;Unsupported Command
+
+ mov ax,8003h ;Set Status Error bit,
+ TRACER 'U'
+ TRACER 'C'
+ retn ; Error 3 = Unknown Command
+
+
+;=============================================================================
+
+IoctlInput: ;IOCTL Input Routine
+
+ mov di,[es:bx+14] ;es:bx --> Request Header
+ mov es,[es:bx+16] ;Get Xfer Address into es:di
+ xor ax,ax ;Get Control Block Code
+ mov al,[es:di]
+%ifdef DEBUG
+ TRACER 'I'
+ TRACER 'O'
+ call print_hex8
+%endif
+ cmp al,10
+ jb UnkIoctlI ;If 0-9
+ mov al,2 ;Map to Unsupported
+UnkIoctlI: shl al,1 ;Convert into offset (*2)
+ mov si,IoctlICtrl
+ add si,ax
+ call word [si] ;Execute desired command
+ retn
+
+
+;=============================================================================
+
+Raddr: ;Return Device Header Address
+
+ TRACER 'A'
+ mov word [es:di+1],0
+ mov [es:di+3],cs
+ xor ax, ax ;Set Return Status = success
+ TRACER 'a'
+ retn
+
+
+;=============================================================================
+
+DrvBytes: ;Read Drive Bytes
+
+ TRACER 'B'
+ push di ;Save original Xfer Addr
+ add di,2 ;Point to 1st dest byte
+ mov si,Greeting ;Point to Greeting
+DrvB: movsb ;Copy over a byte
+ cmp byte [si],13 ;Is next char a CR?
+ jne DrvB ;Loop if not
+
+ sub di,2 ;Get #bytes copied into ax
+ mov ax,di
+ pop di ;Retrieve original Xfer Addr
+ sub ax,di
+ mov byte [es:di+1],al ;and save it
+ mov ax,0 ;Set Return Status = success
+ TRACER 'b'
+ retn
+
+
+;=============================================================================
+
+DevStat: ;Return Device Status
+
+ TRACER 'D'
+ mov word [es:di+1],202h ;Door closed
+ mov word [es:di+3],0 ;Door unlocked
+ ;Supports only cooked reading
+ ;Read only
+ ;Data read only
+ ;No interleaving
+ ;No prefetching
+ ;No audio channel manipulation
+ ;Supports both HSG and Redbook
+ ; addressing modes
+
+ xor ax, ax ;Set Return Status = success
+ TRACER 'd'
+ retn
+
+
+;=============================================================================
+
+SectSize: ;Return Sector Size
+
+ TRACER 'S'
+ mov word [es:di+2],2048
+ mov ax,0 ;Set Return Status = success
+ TRACER 's'
+ retn
+
+
+;=============================================================================
+
+VolSize: ;Return Volume Size
+
+ TRACER 'V'
+ call PriVolDesc ;Get and Check Primary Volume
+ ; Descriptor
+ mov ax,800Fh ;Assume Invalid Disk Change
+ jc VolExit ;If Read Failure
+
+ mov ax,word [Buffer+80] ;Read Successful
+ mov word [es:di+1],ax ;Copy over Volume Size
+ mov ax,word [Buffer+82]
+ mov word [es:di+3],ax
+ mov ax,0 ;Set Return Status = success
+VolExit:
+ TRACER 'v'
+ retn
+
+
+;=============================================================================
+
+MedChng: ;Return Media Changed Status
+
+ TRACER 'M'
+ call PriVolDesc ;Get and Check Primary Volume
+ ; Descriptor
+ mov byte [es:di+1],-1 ;Assume Media Changed
+ mov ax,800Fh ; and Invalid Disk Change
+ jc MedExit ;If Media Changed or Bad
+
+ mov byte [es:di+1],1 ;Media has not changed
+ mov ax,0 ;Set Return Status = success
+MedExit:
+ TRACER 'm'
+ retn
+
+
+;=============================================================================
+
+PriVolDesc: ;Get and Check Primary Volume
+ ; Descriptor
+ TRACER 'P'
+ mov ax,cs ;Set ds:si --> SpecPkt
+ mov ds,ax
+
+ mov cx, 5
+PriVolAgain:
+ mov byte [SpecPkt],16 ;SpecPkt Size
+ mov byte [SpecPkt+1],0 ;Reserved
+ mov word [SpecPkt+2],1 ;Transfer one 2048-byte sector
+ push cx
+ mov cl,byte [ReadBytes] ;Multiply by 4 if reading 512
+ shl word [SpecPkt+2],cl ; bytes at a time
+ pop cx
+ mov word [SpecPkt+6],cs ;Into our Buffer
+ mov word [SpecPkt+4], Buffer
+ mov word [SpecPkt+8],16 ;From CD Sector 16
+ mov word [SpecPkt+10],0
+ mov word [SpecPkt+12],0
+ mov word [SpecPkt+14],0
+
+ mov si, SpecPkt
+ mov dl, [DriveNumber]
+ mov ah, 42h ;Extended Read
+ int 13h
+ jnc PriVolPass ;If success
+
+; TRACER '1'
+ ; read error
+ loop PriVolAgain
+
+ TRACER '2'
+ ; read retries exhausted
+ ; flow into below
+ jmp PriReadErr
+
+PriVolPass:
+ mov si,Buffer ;Point input to Buffer
+ mov ax,-1 ;Init Checksum registers
+ mov bx,ax ; bx,ax = 0FFFFFFFFh
+ jc PriNew ;If Read Failure
+
+ push di ;Read Successful,
+ ; so Calculate Checksum
+ mov di,1024 ;Init Word counter
+PriWord: mov dx,[cs:si] ;Grab next word from buffer
+ mov cx,16 ;Init bit counter
+PriBit: shr dx,1 ;Shift everything right 1 bit
+ rcr bx,1
+ rcr ax,1
+ jnc NoMult ;If a zero shifted out
+
+ xor bx,RPolyH ;A one shifted out, so XOR
+ xor ax,RPolyL ; Checksum with RPoly
+NoMult:
+ loop PriBit
+
+ add si,2 ;Inc Word Pointer
+ dec di
+ ja PriWord
+ TRACER '3'
+
+ pop di ;Checksum calculation complete
+ cmp bx,[Checksum+2] ;Has Checksum changed?
+ jne PriNew ;If Checksum Changed
+
+ cmp ax,[Checksum]
+ jne PriNew ;If Checksum Changed
+
+ clc ;Checksum not changed, CF=0
+ mov ax,0 ;Status = success
+ jmp PriOld
+
+PriReadErr:
+ mov WORD [Checksum+2],bx ;Save New Checksum
+ mov [Checksum],ax ; or 0FFFFFFFFh if bad read
+ stc ;Checksum change, CF=1
+ mov ax, 800bh ;Status = read fault
+ jmp PriOld
+
+PriNew: mov WORD [Checksum+2],bx ;Save New Checksum
+ mov [Checksum],ax ; or 0FFFFFFFFh if bad read
+ stc ;Checksum Changed, CF=1
+ mov ax,800Fh ;Status = Invalid Media Change
+PriOld:
+ TRACER 'p'
+ retn
+
+
+;=============================================================================
+
+IoctlOutput: ;IOCTL Output Routine
+
+ TRACER 'O'
+ mov di,[es:bx+14] ;es:bx --> Request Header
+ mov es,[es:bx+16] ;Get Xfer Address into es:di
+ xor ax,ax ;Get Control Block Code
+ mov al,[es:di]
+ cmp al,2
+ jne UnkIoctlO ;If not 2 (ResetDrv)
+ call DoNothing ;Reset Drive
+ jmp IoctlODone
+UnkIoctlO:
+ call Unsupported ;Unsupported command
+IoctlODone:
+ TRACER 'o'
+ retn
+
+
+;=============================================================================
+
+DoNothing: ;Do Nothing Command
+
+ mov ax,0 ;Set Return Status = success
+ retn
+
+
+;=============================================================================
+
+ReadL: ;Read Long Command
+
+ TRACER 'R'
+ mov ax,cs ;Set ds=cs
+ mov ds,ax
+ ;es:bx --> Request Header
+ cmp byte [es:bx+24],0 ;Check Data Read Mode
+ jne ReadLErr ;If Cooked Mode
+
+ cmp byte [es:bx+13],2 ;Check Addressing Mode
+ jb ReadLOK ;If HSG or Redbook Mode
+
+ReadLErr:
+ TRACER '8'
+ mov ax,8003h ;Set Return Status = Unknown
+ jmp ReadLExit ; Command Error and exit
+
+ReadLOK:
+ mov ax,[es:bx+20] ;Get Starting Sector Number,
+ mov dx,[es:bx+22] ; Assume HSG Addressing Mode
+ cmp byte [es:bx+13],0 ;Check Addressing Mode again
+ je ReadLHSG ;If HSG Addressing Mode
+
+ TRACER '7'
+ ;Using Redbook Addressing Mode. Convert to HSG format
+ mov al,dl ;Get Minutes
+ mov dl,60
+ mul dl ;ax = Minutes * 60
+ add al,byte [es:bx+21] ;Add in Seconds
+ adc ah,0
+ mov dx,75 ;dx:ax =
+ mul dx ; ((Min * 60) + Sec) * 75
+ add al,byte [es:bx+20] ;Add in Frames
+ adc ah,0
+ adc dx,0
+ sub ax,150 ;Subtract 2-Second offset
+ sbb dx,0 ;dx:ax = HSG Starting Sector
+
+ReadLHSG:
+ mov word [SpecPkt+8], ax ;Store Starting
+ mov word [SpecPkt+10], dx ; Sector Number
+ mov word [SpecPkt+12], 0 ; (HSG Format)
+ mov word [SpecPkt+14], 0
+
+ mov ax,[es:bx+14] ;Get Transfer Address
+ mov word [SpecPkt+4],ax
+ mov ax,[es:bx+16]
+ mov word [SpecPkt+6],ax
+
+ mov byte [SpecPkt],16 ;Size of Disk Address Packet
+ mov byte [SpecPkt+1],0 ;Reserved
+
+ mov cx, 5
+ReadLAgain:
+ mov ax,[es:bx+18] ;Get number of sectors to read
+ mov word [SpecPkt+2],ax
+ cmp ax, 3FFFh ;Too large?
+ ja ReadLBad ;If yes
+
+ push cx
+ mov cl,byte [ReadBytes] ;Multiply by 4 if reading 512
+ shl word [SpecPkt+2],cl ; bytes at a time
+ pop cx
+
+%ifdef DEBUG
+ push ax
+ push cx
+ push si
+ mov cx, 16
+ mov si,SpecPkt
+ReadDump: mov al, ' '
+ call print_char
+ mov al, byte [si] ;Hexdump a SpecPkt byte
+ call print_hex8
+ inc si ;Point to next byte
+ loop ReadDump
+ pop si
+ pop cx
+ pop ax
+%endif
+ mov si,SpecPkt
+ mov dl,[DriveNumber]
+ mov ah,42h ;Extended Read
+ int 13h
+ jnc ReadLGd ;If success
+
+;hang:
+; jmp hang
+; TRACER '1'
+ loop ReadLAgain
+ TRACER '2'
+ jmp short ReadLBad
+ReadLGd:
+ TRACER '3'
+ xor ax, ax ;Status 0 = success
+ jmp short ReadLExit
+
+ReadLBad:
+ TRACER '9'
+ mov ax, 800Bh ;Set Read Fault Error
+ ; flow into ReadLExit
+ReadLExit:
+ TRACER 'r'
+ retn
+
+
+
+%ifdef DEBUG_TRACERS
+debug_tracer: pushad
+ pushfd
+
+ mov al, '['
+ mov ah,0Eh ;BIOS video teletype output
+ xor bh, bh
+ int 10h ;Print it
+
+ mov bp,sp
+ mov bx,[bp+9*4] ; Get return address
+ mov al,[cs:bx] ; Get data byte
+ inc word [bp+9*4] ; Return to after data byte
+
+ mov ah,0Eh ;BIOS video teletype output
+ xor bh, bh
+ int 10h ;Print it
+
+ mov al, ']'
+ mov ah,0Eh ;BIOS video teletype output
+ xor bh, bh
+ int 10h ;Print it
+
+ popfd
+ popad
+ retn
+%endif
+
+;-----------------------------------------------------------------------------
+; PRINT_HEX4
+;-----------------------------------------------------------------------------
+; print a 4 bits integer in hex
+;
+; Input:
+; AL - 4 bits integer to print (low)
+;
+; Output: None
+;
+; Registers destroyed: None
+;
+print_hex4:
+
+ push ax
+ and al, 0fh ; we only need the first nibble
+ cmp al, 10
+ jae hex_A_F
+ add al, '0'
+ jmp hex_0_9
+hex_A_F:
+ add al, 'A'-10
+hex_0_9:
+ call print_char
+ pop ax
+ retn
+
+
+;-----------------------------------------------------------------------------
+; print_hex8
+;-----------------------------------------------------------------------------
+; print a 8 bits integer in hex
+;
+; Input:
+; AL - 8 bits integer to print
+;
+; Output: None
+;
+; Registers destroyed: None
+;
+print_hex8:
+
+ push ax
+ push bx
+
+ mov ah, al
+ shr al, 4
+ call print_hex4
+
+ mov al, ah
+ and al, 0fh
+ call print_hex4
+
+ pop bx
+ pop ax
+ retn
+
+
+;=============================================================================
+; print_hex16 - print a 16 bits integer in hex
+;
+; Input:
+; AX - 16 bits integer to print
+;
+; Output: None
+;
+; Registers destroyed: None
+;=============================================================================
+print_hex16:
+
+ push ax
+ push bx
+ push cx
+
+ mov cx, 4
+print_hex16_loop:
+ rol ax, 4
+ call print_hex4
+ loop print_hex16_loop
+
+ pop cx
+ pop bx
+ pop ax
+ retn
+
+;=============================================================================
+; print_hex32 - print a 32 bits integer in hex
+;
+; Input:
+; EAX - 32 bits integer to print
+;
+; Output: None
+;
+; Registers destroyed: None
+;=============================================================================
+print_hex32:
+
+ push eax
+ push bx
+ push cx
+
+ mov cx, 8
+print_hex32_loop:
+ rol eax, 4
+ call print_hex4
+ loop print_hex32_loop
+
+ pop cx
+ pop bx
+ pop eax
+ retn
+
+;=============================================================================
+; print_string - print string at current cursor location
+;
+; Input:
+; DS:SI - ASCIIZ string to print
+;
+; Output: None
+;
+; Registers destroyed: None
+;=============================================================================
+print_string:
+ push ax
+ push si
+
+print_string_again:
+ mov al, [si]
+ or al, al
+ jz print_string_exit
+ call print_char
+ inc si
+ jmp print_string_again
+
+print_string_exit:
+ pop si
+ pop ax
+ retn
+
+;-----------------------------------------------------------------------------
+; PRINT_CHAR
+;-----------------------------------------------------------------------------
+; Print's a character at current cursor position
+;
+; Input:
+; AL - Character to print
+;
+; Output: None
+;
+; Registers destroyed: None
+;
+print_char:
+
+ push ax
+ push bx
+
+ mov ah,0Eh ;BIOS video teletype output
+ xor bh, bh
+ int 10h ;Print it
+
+print_char_exit:
+ pop bx
+ pop ax
+ retn
+
+
+;=============================================================================
+
+;This space is used as a 2048-byte read buffer plus one test byte.
+;The 96h data is used for testing the number of bytes returned by an Extended
+; CD-ROM sector read
+
+Buffer times 2049 db 96h
+
+;=============================================================================
+
+Init: ;Initialization Routine
+
+ TRACER 'I'
+ mov ax,cs ;ds=cs
+ mov ds,ax
+
+%ifdef DEBUG
+; print CS value (load segment)
+ call print_hex16
+%endif
+
+ mov si, Greeting ;Display Greeting
+ call print_string
+
+ mov ax,Unsupported ;Init is executed only once
+ mov [Routines],ax
+
+ mov ax, 5400h
+ int 13h ; Get diskemu status
+ jc FindBoot ; If CF=1 no diskemu loaded
+
+ mov [DriveNumber], cl ; Store drive number
+
+ call keyflag
+ and al, 8 ; alt key ?
+ jz extread
+
+ mov si, DrvNumMsg ; Display "drive number="
+ call print_string
+ mov al, [DriveNumber]
+ call print_hex8
+ mov si, LineEnd ; CR/LF
+ call print_string
+ jmp extread
+
+; Diskemu is not loaded
+; so loop to find drive number
+ ; *** start of 1.4 changes ***
+ ; ??? mov dl, 0ffh ;Start at Drive 0xff
+ ; *** FindBoot at c47 in 1.4, at c0c in 1.3 ***
+FindBoot: call ScanDrives ; call new helper in 1.4
+ jnc FoundBoot ; ded*df3
+; mov si,offset SpecPkt ;Locate booted CD-ROM drive
+; mov [SpecPkt],0 ;Clear 1st byte of SpecPkt
+; mov ax,4B01h ;Get Bootable CD-ROM Status
+; int 13h
+; jnc FindPass ;If booted CD found
+;
+; Carry is not cleared in buggy Dell BIOSes,
+; so I'm checking packet size byte
+; some bogus bioses (Dell Inspiron 2500) returns packet size 0xff when failed
+; Dell Dimension XPsT returns packet size 0x14 when OK
+
+; cmp [SpecPkt], 0
+; jne FoundBoot
+
+; cmp [SpecPkt], 13h ; anything between 13h and 20h should be OK
+; jb FindFail
+; cmp [SpecPkt], 20h
+; ja FindFail
+; jmp short FoundBoot
+;
+; FindFail:
+; dec dl ;Next drive
+; cmp dl, 80h
+; jae FindBoot ;Check from ffh..80h
+ ; *** end of 1.4 changes ***
+
+ mov si,NoBootCD ;No booted CD found,
+ call print_string
+ jmp NoEndAddr ;Do not install driver
+
+FoundBoot:
+; mov dl, [SpecPkt+2] ; 1.4 change
+ ; *** next line at c57 in 1.4, at c3d in 1.3 ***
+ mov [DriveNumber],dl ;Booted CD-ROM found,
+ ; so save Drive #
+
+ call keyflag
+ and al, 8 ; alt key ?
+ jz extread
+
+ mov si, CDStat
+ call print_string
+ mov si, SpecPkt ;Point to returned CD SpecPkt
+ mov cx, 19 ; containing 19 bytes
+StatDump: mov al, ' ' ;Print a space
+ call print_char
+ mov al, byte [si] ;Hexdump a SpecPkt byte
+ call print_hex8
+ inc si ;Point to next byte
+ loop StatDump
+
+ mov si, LineEnd ;Print a CR/LF
+ call print_string
+
+extread:
+;See how many CD Sector bytes are returned by an Extended Read
+ mov byte [SpecPkt],16 ;SpecPkt Size
+ mov byte [SpecPkt+1],0 ;Reserved
+ mov word [SpecPkt+2],1 ;Transfer one sector
+ mov word [SpecPkt+6],cs ;Into our Buffer
+ mov word [SpecPkt+4],Buffer
+ mov word [SpecPkt+8],16 ;From CD Sector 16
+ mov word [SpecPkt+10],0
+ mov word [SpecPkt+12],0
+ mov word [SpecPkt+14],0
+
+ mov si, SpecPkt ;Set ds:si --> SpecPkt
+ mov dl, [DriveNumber]
+ mov ah, 42h ;Extended Read
+ int 13h
+ jnc SecSize ;If success
+
+ mov ah, 42h ;Always make 2 read attempts
+ int 13h
+ ;How many bytes did we get?
+SecSize: std ;Count down
+ mov ax,cs ;Point to end of Buffer
+ mov es,ax
+ mov di,Buffer+2047 ;Find end of read data
+ mov si,Buffer+2048
+ mov cx,2049
+ repe cmpsb ;cx = number of bytes read
+
+ cld ;Restore count direction to up
+ mov si,CDBytes ;Display number of bytes read
+ call print_string
+
+ mov al, [DriveNumber]
+ call print_hex8
+
+ mov si,CDBytesA ;Remainder A of message
+ call print_string
+
+ mov al,ch ;Hex-dump cx
+ and al,0Fh ;Second nibble
+ call print_hex8 ; (don't need the First)
+ mov al,cl
+ call print_hex8 ; (don't need the First)
+
+ mov si,CDBytesB ;Remainder B of message
+ call print_string
+
+ cmp cx,2048 ;Did we read 2048 bytes?
+ je ParseParm ;If yes <-- O.K.
+
+ mov byte [ReadBytes],1
+ cmp cx,1024 ;Did we read 1024 bytes?
+ je ParseParm ;If yes <-- O.K.
+
+ mov byte [ReadBytes],2
+ cmp cx,512 ;Did we read 512 bytes?
+ jne NoEndAddr ;If not, do not load driver
+
+ParseParm: mov bx,word [cs:ReqHdrLoc] ;Parse command line
+ mov es,word [cs:ReqHdrLoc+2] ; parameters
+ mov si,[es:bx+18] ;Get BPB array ptr into DS:SI
+ mov ds,[es:bx+20]
+FindParm: inc si
+FindParm1: cmp byte [si],0Dh ;CR? (End of parameters)
+ je EndOfParms
+
+ cmp byte [si],0Ah ;LF?
+ je EndOfParms
+
+ cmp byte [si],'/' ;A parameter?
+ jne FindParm
+
+ inc si
+ cmp byte [si],'D' ;Device Name parameter?
+ jne FindParm1
+
+ inc si
+ cmp byte [si],':'
+ jne FindParm1
+
+;bbb
+ push si
+ mov si, DevName ;Device Name is at ds:si
+ push ds ;Keep ptr to Device Name
+ mov ax, cs
+ mov ds, ax
+ call print_string
+ pop ds ;Retrieve Device Name ptr
+ pop si
+ mov cx, 8 ;Get next 8 chars
+ inc si ; = Device Name
+ mov ax, cs
+ mov es, ax
+ mov di, DeviceName
+NextChar: cmp byte [si],' '
+ ja AboveSpace
+
+ mov ax,cs ;Pad end of Device Name with
+ mov ds,ax ; spaces if necessary
+ mov si,DblSpace ;A space
+AboveSpace: mov al, [si]
+ call print_char
+ movsb ;ds:[si] --> es:[di]
+ loop NextChar
+
+ mov si,LineEnd
+ mov ax,cs
+ mov ds,ax
+ call print_string
+
+ mov ax,Init-2 ;Last byte of driver to keep
+ jmp EndAddr ;Install driver
+
+EndOfParms:
+ mov ax, cs ; Restore segment registers (fix)
+ mov ds, ax
+ mov es, ax
+
+ mov si,NoDevName ;No Device Name Found
+ call print_string
+
+NoEndAddr: mov ax,0 ;Do not install driver
+
+EndAddr: mov es,[ReqHdrLoc+2] ;Write End Address
+ mov bx,[ReqHdrLoc]
+ mov [es:bx+14],ax
+ mov [es:bx+16],cs
+ mov bx,ax ;Hold onto install status
+
+ mov si, DrvInst ;Display driver install status
+ call print_string
+ mov si, DrvInst1 ;Assume driver installed
+ cmp bx,0 ;Was driver installed?
+ jne DrvStatus ;If yes
+ mov si, NoDrvInst ;Driver not installed
+DrvStatus: call print_string
+
+ mov ax,0 ;Set Return Status = success
+ cmp bx,0 ;Was INIT successful?
+ jne InitStat ;If yes
+ mov ax,800Ch ;Status = General Failure
+InitStat:
+ push ax ;Save Return Status
+
+ call keyflag
+ and al, 8 ; alt key ?
+ jz InitExit
+
+WaitHere:
+ mov si, WaitMsg ;Display Halted message
+ call print_string
+
+AltWait:
+ call keyflag
+ and al, 8 ; Alt key?
+ jnz AltWait ; Pressed? yes -> wait
+
+InitExit:
+ pop ax ;Retrieve Return Status
+ TRACER 'i'
+ retn ;That's it for Init!
+
+ ; *** start 1.4 changes at ded ***
+SpecGo: mov si,SpecPkt
+ int 13h
+ retn
+
+ScanDrives: push ax ; at df3 in 1.4
+ push si
+ mov dl, 0ffh ;Start at Drive 0xff
+NextDrv: mov ax,4B01h ;Get Bootable CD-ROM Status
+ mov BYTE [SpecPkt],0 ;Clear 1st byte of SpecPkt
+ call SpecGo
+; Carry is not cleared in buggy Dell BIOSes,
+; so I'm checking packet size byte
+; some bogus bioses (Dell Inspiron 2500) returns packet size 0xff when failed
+; Dell Dimension XPsT returns packet size 0x14 when OK
+
+ cmp BYTE [SpecPkt], 13h ; anything between 13h and 20h should be OK
+ jb FindFail
+ cmp BYTE [SpecPkt], 20h
+ ja FindFail ; in 1.4 at e16
+ jmp short SendFound ; in 1.4 at e26
+
+FindFail: dec dl ;Next drive
+ cmp dl, 80h
+ jb SendFail ; Check from ffh..80h
+ jmp short NextDrv
+SendFail: xor dl,dl
+ stc
+ jmp short ThingDone
+SendFound: mov dl, [SpecPkt+2]
+ clc
+ThingDone: pop si
+ pop ax
+ retn
+ ; *** end 1.4 changes ***
+
+;=============================================================================
+
+;------------------------------------------------------------
+; keyboard flags - return keyboard flags in AL
+; bit 3 = ALT key
+keyflag: ; at dbc in 1.3, at e2e in 1.4
+ push bx
+ mov ah, 2
+ int 16h
+ pop bx
+ retn
+
+;=============================================================================
+
+DrvNumMsg db ' Diskemxx.bin returned drive number=', 0
+NoBootCD db ' No booted CD-ROM found.',CR,0
+
+CDStat db ' INT 13h / AX=4B01h Specification Packet for '
+ db 'Booted CD-ROM:',CR,' ', 0
+
+CDBytes db ' Drive ', 0
+CDBytesA db ' returns ', 0
+CDBytesB db 'h bytes per Sector.',CR,0
+
+DevName db ' Device Name: ', 0
+NoDevName db ' No Device Name found. '
+ db 'Usage: device=eltorito.sys /D:<DevName>',CR,0
+
+DrvInst db ' Driver ', 0
+NoDrvInst db 7,'not ' ;7 = Ctrl-G = Beep
+DrvInst1 db 'installed',CR,0
+
+WaitMsg db ' Alt pressed, waiting...', CR, 0
+;ContMsg db ' Continuing...'
+LineEnd db CR,0
+
+
+;=============================================================================