; eject.asm ; eject a tape (or CD) from a device ; ; written on Tue 01-17-1995 by Ed Beroset ; and placed into the public domain by the author ; ; note that this is a VERY terse code sample! It is assumed that the ; reader is already familiar with SCSI and ASPI to some degree. ; .MODEL small .STACK 1000h .386 ;/**************************************************************************** ;* structures * ;****************************************************************************/ SCSIRequestBlock struc CommandCode db 2 ; SCSI request Status db 0 ; returned after command HostAdapterNum db 0 ; default is 0 (first adapter) SCSIReqFlags db 0 ; Reserved1 db 4 dup (0) ; TargetID db 0 ; set to device target ID LUN db 0 ; defaults to 0 DataLength dd 0 ; SenseLength db 16 ; usu. sufficient length DataPointer dd 0 ; no data SRBLinkPointer dd 0 ; no linking CDBLength db 10 ; always sufficient length AdapterStatus db 0 ; TargetStatus db 0 ; PostRoutinePtr dd 0 ; no post routine is default ASPIWorkspace db 34 dup (0) ; req'd but not used CDB db 10 dup (0) ; SCSI Command Descriptor Blk SenseData db 16 dup (0) ; SCSIRequestBlock ends .DATA DOS_OPEN_HANDLE = 03dh DOS_CLOSE_HANDLE = 03eh DOS_IOCTL = 044h IOCTL_RX_CTL_DATA = 02h DOS_INT = 21h ASPI_Entry dd ? SRB SCSIRequestBlock <> crlf equ 13,10 ErrMsg db "ERROR: no ASPI manager detected. ",crlf,'$' OKMsg db "All is well.",crlf,'$' SCSIMgrString db "SCSIMGR$",0 .CODE begin proc .STARTUP call GetASPIAddress ; jnb @@AllOK ; mov dx, OFFSET ErrMsg ; jmp @@ErrorExit ; @@AllOK: ; ; here's the eject sequence ; mov [(SRB.CDB) + 0],01Bh ; load/unload command mov [(SRB.CDB) + 4],0 ; 00 = unload, 01=load, 02=retension mov [(SRB.TargetID)], 2 ; SCSI ID of target device push SEG SRB ; push OFFSET SRB ; call [ASPI_Entry] ; sometimes it takes 2 requests call [ASPI_Entry] ; add sp,4 ; mov dx,OFFSET OKMsg ; xor ah,ah ; mov al,[(SRB.Status)] ; @@ErrorExit: ; ds:dx ==> ASCIIZ error string push ax mov ah,9 ; int 21h ; pop ax ; @@NoError: .EXIT 0 begin endp GetASPIAddress proc C push bx push cx push ds xor ax,ax ; mov WORD PTR [ASPI_Entry],ax ; mov WORD PTR [ASPI_Entry+2],ax ; lea dx,[SCSIMgrString] ;ds:dx ==> 'SCSIMGR' string mov ah,DOS_OPEN_HANDLE ; open request int DOS_INT ; jb @@exit ; mov dx,ss ; mov ds,dx ; lea dx,[ASPI_Entry] ; mov cx,4 ; mov bx,ax ; mov ax,DOS_IOCTL SHL 8 OR IOCTL_RX_CTL_DATA int DOS_INT ; jb @@exit ; mov ah,DOS_CLOSE_HANDLE ; int DOS_INT ; @@exit: pop ds pop cx pop bx ret ; GetASPIAddress endp END comment ^ A few notes are probably in order here. First, if you're already familiar with the ASPI and SCSI stuff, it may be sufficient to tell you that the key part to this is to send the SCSI load/unload command (a 6-byte sequence) to the target device. Here are the bytes of that command: 1B 00 00 00 0? 00 The 0? can be 00 (unload) or 01 (load), 02 (unload with tape retension), or 03 (load with tape retension). Note that some devices will allow either 00 or 02, but some (like my CD-ROM) only accept one form. Also, you may wonder why the call [ASPI_Entry] appears twice. This is because some devices, in my experience, will essentially ignore the first request even though they return with a status that indicates all was well! The double call is a workaround for this problem and won't adversely affect anything (at least any device I've worked with) even if the first command is heeded. Of course, in a real application, you'd add more error checking to all of this... -> Ed <- ^