📄 ejcd.asm
字号:
%macro doscall 1 ; call to dos int 21 with a one-byte
%if %1 >= 0100h ; value in .ah, or a two-byte value
mov ax,%1 ; in .ax :
%else
mov ah,%1
%endif
int 21h
%endmacro
%macro dosprint 1 ; a simple wrapper for the dos 21/09
mov dx,%1 ; print-a-string function
mov ah,09h
int 21h
%endmacro
%macro zero 1 ; cheap way to zero a two-byte
xor %1,%1 ; register
%endmacro
%macro testzero 1 ; cheap way to test for zero
or %1,%1
%endmacro
org 0100h
begin:
doscall 19h ; get current drive
mov [current],al ; and save it
mov dx,crit_fail ; set address of
doscall 2524h ; new critical-error handler
mov si,0080h ; start of command line
mov dl,00h ; no drives specified yet
parse_loop:
inc si
mov al,byte [si] ; get a character from command line
call test_eol ; found the end of the line?
je parse_done ; if so, exit parse loop
call test_space ; space or tab?
je parse_loop ; ignore it and continue parsing
cmp al,':' ; colon?
je parse_loop ; ignore that as well
and al,0dfh ; force letters to uppercase
cmp al,'A'
jb syntax ; is it a letter?
cmp al,'Z' ; if not, go handle syntax error
ja syntax
sub al,'A' ; convert drive letter to zero-based
call get_drv_bit ; pointer to drive flag
or byte [drv_flags+bx],dl ; set drive flag
jmp parse_loop ; and continue parsing
syntax: ; handle error in arguments
dosprint msg_syntax
doscall 4c00h
parse_done: ; finished reading the command line :
call flush ; flush disk buffers
cmp dl,00h ; were any drives specified?
je find_cd ; if not, go find the first cd-rom
.drvloop:
mov al,[drv] ; get drive letter
call get_drv_bit ; convert to pointer and bit mask
test byte [drv_flags+bx],dl ; was this drive specified?
je .skip ; if so,
call try_eject ; attempt to eject disk
.skip:
inc byte [drv] ; next drive
cmp byte [drv],01ah ; done 26 yet?
jb .drvloop ; if not, loop back, do another
doscall 4c00h ; if so, exit with happiness
find_cd: ; attempt to locate first cd-rom :
call test_cd ; does [drv] refer to a cd-rom?
jc .cdrloop ; if so,
call try_eject ; attempt to eject disk
doscall 4c00h ; and exit to dos
.cdrloop ; if not,
inc byte [drv] ; move on to the next drive
cmp byte [drv],01ah ; done 26 yet?
jb find_cd ; no, loop back, keep looking
dosprint msg_no_cdrom ; yes, print an error message
doscall 4c00h ; and exit to dos
try_eject: ; attempt to eject disk :
dosprint msg_drive
mov dl,[drv]
add dl,'A' ; display drive and letter
doscall 02h
dosprint msg_colon
call test_cd ; is this drive a cd-rom?
jnc eject_cd ; if so, jump to the cd eject code
mov bl,[drv] ; get the drive number
inc bl ; as 1-based
doscall 04408h ; ioctl - check removable media
jc .baddrv ; if ioctl reports error, abort
cmp ax,0000h ; is the drive removable?
jne .nonremov ; if so,
dosprint msg_removable ; display 'removable' message
call force_root ; force root directory on the drive
mov bl,[drv] ; get the drive number
inc bl ; as one-based
mov cx,0849h ; eject media through
doscall 440dh ; ioctl block device request
jc .failed ; ioctl reports an error?
dosprint msg_ejected ; if not, display a happy message
call drv_fix ; change drive if this one was current
dosprint msg_crlf ; terminate the display line
ret ; and exit
.baddrv:
dosprint msg_bad_drv ; display an error message
ret ; and exit
.nonremov:
dosprint msg_not_removable ; display error message
ret ; and exit
.failed:
dosprint msg_eject_failed ; display error message
ret ; and exit
eject_cd: ; attempt to eject cd-rom tray :
dosprint msg_cdrom ; display 'cd-rom' message
call force_root ; change to root directory on drive
mov ax,0000h
mov [rq_status],ax
mov ax,cmd_unlock
mov [rq_address],ax
mov ax,0002h
mov [rq_strlen],ax
mov cl,[drv]
mov ch,00
mov bx,request_block
push cs
pop es
mov [rq_address+02h],es
clc
mov ax,1510h
int 2fh
mov ax,0000h
mov [rq_status],ax
mov ax,cmd_eject
mov [rq_address],ax
mov ax,0001h
mov [rq_strlen],ax
mov cl,[drv]
mov ch,00h
mov bx,request_block
push cs
pop es
mov [rq_address+02h],es
clc
mov ax,1510h
int 2fh
jc .cderror
test word [rq_status],08000h
jne .cderror
dosprint msg_ejected
call drv_fix
dosprint msg_crlf
ret
.cderror:
jmp try_eject.failed
request_block:
rq_length: db 01ah
rq_subunit: db 00h
rq_command: db 0ch
rq_status: dw 0000h
rq_reserved: db 00h,00h,00h,00h,00h,00h,00h,00h
rq_media: db 00h
rq_address: dw 0000h,0000h
rq_strlen: dw 0001h
rq_sector: dw 0000h
rq_volptr: dw 0000h,0000h
cmd_eject:
db 00h
cmd_unlock:
db 01h,00h
test_eol:
cmp al,0dh
je .l1
cmp al,00h
.l1:
ret
test_space:
cmp al,20h
je .l1
cmp al,09h
.l1:
ret
get_drv_bit:
cbw
mov bx,ax ; zero-based drive number in .bx
mov cl,03h ; divide by 8 to get
shr bx,cl ; pointer to flag byte in .bx
mov cl,al
and cl,07h ; drive number modulo 7 gives
mov dl,01h ; bit number; rotate to put
shl dl,cl ; bit in desired position
ret
test_cd: ; is this drive a cd-rom?
mov cl,byte [drv] ; get drive letter
mov ch,00 ; into .cx
zero bx
mov ax,150bh
int 2fh ; msdex - drive controlled by mscdex?
cmp bx,0adadh ; mscdex responding?
jnz .negative ; if not, exit with carry set
cmp ax,0000h ; drive controlled by mscdex?
jz .negative ; if not, exit with carry set
clc ; otherwise, exit with carry clear
ret
.negative: ; not a cd-rom drive :
stc ; exit with carry set
ret
force_root: ; cd to root director on the drive :
mov al,[drv] ; get the drive number
add al,'A' ; and convert to a letter
mov [str_root],al ; poke into the root-directory string
mov dx,str_root ; get offset of the string
doscall 3bh ; and change directories
ret
drv_fix: ; change current drive, if needed :
mov al,[drv] ; is this drive
cmp al,[current] ; the currently logged dos drive?
jne .nofix ; if not, no fix needed; exit
mov byte [current],00h ; start from drive A:
.fixloop:
mov bl,[current] ; get the drive number
cmp bl,[drv]
je .next
inc bl ; as one-based
doscall 4408h ; ioctl - is drive removable?
jc .next ; if ioctl error, on to the next drive
cmp ax,0000h ; is the drive removable?
jne .found ; if not, use this one
.next:
inc byte [current] ; not a suitable drive; increment
cmp byte [current],1ah ; ran out of drives to try?
jb .fixloop ; no, loop back and try the next one
mov byte [current],02h ; second attempt; start from C:
.fixloop2:
mov dl,[current] ; get the drive number
cmp dl,[drv]
je .next2
inc dl ; as one-based
doscall 36h ; attempt to get free space on drive
cmp ax,0ffffh ; successful?
jne .found ; if so, use this drive
.next2:
inc byte [current] ; not a suitable drive; increment
cmp byte [current],1ah ; passed drive Z?
jb .fixloop2 ; no, loop back and try again
.nofix:
ret ; yes, just give up in disgust
.found:
mov dl,[current] ; get the drive number
doscall 0eh ; and set dos logged drive
dosprint msg_new_drv ; display informative message
mov dl,[current]
add dl,'A'
doscall 02h ; and the new drive letter
dosprint msg_colon
ret
flush:
push dx
dosprint msg_flushing
call brief_delay
doscall 0dh ; dos - disk reset
dosprint msg_done
call brief_delay
pop dx
ret
brief_delay:
push es
push cx
push ax
mov ax,0040h
mov es,ax
mov cx,0008h
.brief:
mov al,[es:006ch]
.delay:
cmp al,[es:006ch]
jz .delay
loop .brief
pop ax
pop cx
pop es
ret
crit_fail: ; new critical-error handler :
mov al,03h ; always fail
iret
drv: ; drive number
db 00h
current: ; current logged drive (zero-based)
db 00h
drv_flags: ; bitmap of user-specified drives
db 00h,00h,00h,00h
msg_syntax:
db 0dh,0ah
db 'EJ.COM v1.04 2003-07-01 C. Dye raster@highfiber.com',0dh,0ah
db 'GPL Freeware. Copyright 2000-2003, Charles Dye. No warranty!',0dh,0ah
db 0ah
db 'Syntax: EJ [d:] [d:...]',0dh,0ah
db 0ah
db ' Ejects the media in the specified CD-ROM drive(s). If no drives',0dh,0ah
db ' are specified, the default is the first CD-ROM detected.',0dh,0ah
db 0ah,'$'
msg_flushing:
db 0dh,0ah,'Flushing disk buffers: $'
msg_done:
db 'Done.',0dh,0ah,0ah,'$'
msg_drive:
db 'Drive $'
msg_colon:
db ': $'
msg_crlf:
db 0dh,0ah,'$'
msg_cdrom:
db '(CD-ROM) $'
msg_removable:
db '(Removable) $'
msg_eject_failed:
db "Can't eject!",0dh,0ah,'$'
msg_bad_drv:
db 'Invalid drive!',0dh,0ah,'$'
msg_not_removable:
db 'Not a removable drive!',0dh,0ah,'$'
msg_ejected:
db 'Ejected.$'
msg_new_drv:
db ' Current drive is now $'
msg_no_cdrom:
db "Can't find a CD-ROM drive",0dh,0ah,'$'
str_root:
db 'A:\',00h
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -