⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ejcd.asm

📁 用汇编语言所写的光驱弹出程序
💻 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 + -