	page	82,132
;
; MS-DOS CD-ROM Driver
;  (C) S.Unozawa
;
; Rev.  Description                                       Date      Auther
;--------------------------------------------------------------------------
; 1st   CD-SD Rev.12 Based                                92/12/25  Uno
; 2nd   beta-Version                                      93/01/05  Uno
; 3rd   1st Release                                       93/01/18  Uno
; 4th   Support Photo-CD/EB-XA for CD-ROM/XA Drive        93/02/15  Uno
; 5th   Change Drive Ready & TestUnit Read Routine        93/02/23  Uno
; 6th   Add /U Option                                     94/07/02  Uno
;

; Assemble:
;----------------------------------------------------------------------
; Microsoft MASM V5.1 or 4.0
;   masm /mx /DIF_TYPE=yyyy mini.asm;
; Microsoft MASM V6.0
;   ml /DIF_TYPE=yyyy mini.asm
; Borland Turbo ASM V1.0/2.0/3.0
;   tasm /DIF_TYPE=yyyy mini.asm
; SLR OptASM
;   optasm /DIF_TYPE=yyyy mini;
; PharLap 386|ASM V2.0/V2.5
;   386asm -8086 -twocase -define IF_TYPE=yyyy mini.asm
;
;   yyyy =Interface Name (see. cddrv.inc)
;
	.186
;DEBUG	equ	0	; Define Debug Flag

	include	mini.inc

DrvParm	struc
CurAdr	dw	2 dup (?)	; Current Seek Posision
BlkSiz	dw	2048		; Physical Block Size
SecCnt	dw	0		; Physical Block Count
TempPtr	dw	offset TempBuf	; Work Buffer
; Use for SCSI Routine
ScsiID	db	-1		; SCSI-ID for Target
Lun	db	0		; Controler LUN Number (CDB Posision)
PhasePtr dw	offset Phase		; SCSI Phase Routine
SetScPtr dw	offset SetupSc		; CDB & SCSI Pointer Setup Routine
DrvParm	ends

; Driver Body
cseg	segment	public
	assume	cs:cseg,ds:cseg,es:cseg,ss:cseg

	org	0
; Device Header
DevHead	label	word
	dd	-1		; Link Information (Last Device)
	dw	0C800h		; Attribute (Char, IOCTL, Open/Close/Remove)
	dw	Strategy	; Strategy Entry point
	dw	Interrupt	; Interrupt Entry
DevNam	db	'        '	; Device Name
	dw	0		; Reserved
	db	0		; Drive Letter
MaxUnit	db	1		; Number of Drive

; Driver Work Area
packet	dd	1 dup (?)
Work	DrvParm	<>

	even
 ifdef  DEBUG
ErrCDB	db	32 dup ('D')
FuncReq	db	32 dup ('F')
IOCReq	db	32 dup ('I')
 endif

; Temporary Buffer & Reserve Stack Area
TempBuf	db	12 dup('T')	; Temp. Buffer
	dw	72 dup(5353h)	; Driver Stack Area
Stack	equ	$

; 00h -> 0Fh Command Table
ComTbl0	label	word
	dw	Init		; 0 Initialize / 8 None
	dw	None		; 1 None / 9 None
	dw	None		; 2 None / 10 None
	dw	IOCTL		; 3 IOCTL Input / 11 None
	dw	Done		; 4 None / 12 IOCTL Output
	dw	Done		; 5 None / 13 Device Open
	dw	Done		; 6 None / 14 Device Close
	dw	Done		; 7 Flush Input Buffer / 15 Removable Media
; 80h -> 88h Command Table
ComTbl8	label	word
	dw	Read		; 80h Read Long
	dw	None		; 81h
	dw	Done		; 82h Read PreFetch
	dw	Seek		; 83h Seek

; IOCTL Input Function Table
IIOCTbl	label	word
	dw	DevAdr		; 0   Return Address of Device Header
	dw	LocHead		; 1   Location Head
	dw	None		; 2   (reserve)
	dw	None		; 3   Return Error Status
	dw	None		; 4   Return Audio Channel Info.
	dw	None		; 5   Return Drive Status
	dw	DevStatus	; 6   Return Device Status
	dw	SecSize		; 7   Return Sector Size
	dw	VolSize		; 8   Return Volume Size
	dw	MedChg 		; 9   Check Media Changed

; Strategy Entry
Strategy proc	far
	mov	word ptr cs:[packet],bx
	mov	word ptr cs:[packet+2],es
	ret
Strategy endp

; Interrupt Entry
Interrupt proc	far
	pushf
	push	es
	push	ds
	pushall

; Reserve Driver Stack Area
	mov	bx,sp
	mov	dx,ss
	mov	ax,offset Stack
	mov	cx,cs
	cli
	mov	ss,cx
	mov	sp,ax
	sti
	push	dx
	push	bx

; Driver Interrupt Routine Main
	push	cs		; |-> ds = cs
	pop	ds		; |
	mov	bp,offset Work	; Set Parameter Work Area
	les	di,[packet]	; Get Request Header Address
	mov	al,es:[di.Unit]	; Get Unit Number
	cmp	al,[MaxUnit]	; Check Drive Number
	jae	Intr0		; Branch Drive Number Error (Function Error)
	mov	[bp.Lun],al	; LUN is Drive Number
	mov	al,es:[di.Cmd]	; Get Request Command Code
	test	al,80h
	jz	Intr1		; 0 - 7fh, branch
	and	al,7fh		; Strip MSB
	mov	bx,offset ComTbl8
	cmp	al,04h		; 80h - 83h ?
	jb	Intr3
Intr0:
	mov	al,16		; Turn Function Error
Intr1:
	cmp	al,16
	jb	Intr2
	mov	al,02h		; Function Error (See Function Table)
Intr2:
	and	al,07h		; 08h-15h -> 00h-07h
	mov	bx,offset ComTbl0
Intr3:
	cbw
	shl	ax,1
	add	bx,ax
	call	word ptr [bx]
Exit:
	or	ax,0100h	; Set Done Bit
Intret:
	les	di,cs:[packet]	; Get Request Header Address
	mov	es:[di.Stat],ax	; Set Status

  ifdef DEBUG
	test	ax,8000h
	jz	DBG_Ret
	push	es
	push	ds
	push	di
	push	si
	push	cx
; Copy Request Packet to Debug Buffer
	mov	si,es
	mov	ds,si
	mov	si,di
	mov	di,cs
	mov	es,di
	mov	di,offset FuncReq
	xor	cx,cx
	mov	cl,byte ptr [si]
	and	cl,1fh
	cld
	rep	movsb
;
	pop	cx
	pop	si
	pop	di
	pop	ds
	pop	es
DBG_Ret:
  endif
; Restore Stack pointer
	pop	ax
	pop	bx
	cli
	mov	ss,bx
	mov	sp,ax
	sti
;
	popall
	pop	ds
	pop	es
	popf
	ret
Interrupt endp

; Not Execute
None	proc	near
	mov	ax,8003h	; Unknown Function
	stc
	ret
None	endp

; ------------------ IOCTL Jump Routine ---------------------
IOCTL	proc	near
	mov	bx,offset IIOCTbl
	push	es
	push	di
	les	di,es:[di.IOCParm]	; IOCTL Parameter Address
  ifdef DEBUG
	push	es
	push	ds
	push	di
	push	si
	push	cx
	mov	si,es
	mov	ds,si
	mov	si,di
	mov	di,cs
	mov	es,di
	mov	di,offset IOCReq
	xor	cx,cx
	mov	cl,32
	cld
	rep	movsb
	pop	cx
	pop	si
	pop	di
	pop	ds
	pop	es
  endif
	mov	al,es:[di]	; Get IOCTL Function Code
	cmp	al,10		; Support Function Check
	jb	IIOC2
	mov	al,02h		; Not Support Function (See Table)
IIOC2:
	cbw
	shl	ax,1
	add	bx,ax
	call	word ptr [bx]
	pop	di
	pop	es
	jnc	RetIOC
	mov	es:[di.IOCCnt],0	; Not Transfer Byte
RetIOC:
	ret
IOCTL	endp

;------------------ Driver IOCTL Function Sub-Routines --------------------
IOCFUNC	proc	near
; FUNCTION 0 Return Device Driver Header Address
DevAdr:
	mov	dx,offset DevHead
	mov	bx,cs
	jmp	IOCComm

; FUNCTION 1 CD-ROM Head Address
LocHead:
	mov	dx,[bp.CurAdr]
	mov	bx,[bp.CurAdr+2]
	inc	di		; Store to "dword ptr [di+2]"
	jmp	IOCComm

; FUNCTION 6 Return Device Status
DevStatus:
	mov	dx,0c82h	; Support Pre-Fetch / Door UnLocked
	call	TestUnit	; Test Unit Ready, Check Media Insert
	jc	NotRdy0
	cmp	al,00h		; Media Insert ?
	je	DevSta2		; Yes, Branch
	cmp	al,01h		; Change Media ?
	je	DevSta2		; No, Branch
	or	dx,0001h	; Set Door Open bit
DevSta2:
	xor	bx,bx
IOCComm:
	mov	es:[di+3],bx
IOCComm2:
	mov	es:[di+1],dx
	jmp	Done

; FUNCTION 7 Return Sector Size
SecSize:
	cmp	byte ptr es:[di+1],0	; Cooked Mode ?
	jnz	None		; Else, Error
SecSiz2:
	mov	dx,2048
	inc	di		; Set Block Size to word ptr es:[di+2]
	jmp	IOCComm2

; FUNCTION 8 Return Volume Size
VolSize:
	call	ReadCap		; Read CD-ROM Max. Block Address in HSG
	jnc	IOCComm
;
NotRdy0:
	mov	ax,8002h	; Drive Not Ready
	stc
	ret

; FUNCTION 9 Check Disk Change
MedChg:
	call	TestUnit
	jc	NotRdy0
	cmp	al,02h		; Disk Not Present ?
	jae	NotRdy0
	cmp	al,00h		; Change Disk ?
	jnz	MedChg2		; Yes, Branch
	mov	al,01h		; Disk Not Changed
	jmp	MedChg3
MedChg2:
	mov	al,0ffh		; Set Disk Change
MedChg3:
	mov	es:[di+1],al	; Set Disk Change
Done:
	xor	ax,ax
	ret
IOCFUNC	endp

;------------------ Driver Main Function Sub-Routines --------------------
; Read Entry
Read	proc	near
	call	TestUnit
	jc	NotRdy0
	cmp	al,01h		; Media Insert ?
	ja	NotRdy0

; Setup Offset Address to Minimum
Read3:
	mov	si,es:[di.BufAdr]	; Set Transfer Offset Address
	mov	ax,si
	mov	cl,4
	and	ax,0fff0h
	shr	ax,cl			; AX = 0fffh Max.
	mov	bx,es:[di.BufAdr+2]	; BX < Maybe 0f000h
	add	ax,bx
	jc	Read4			; Branch, Over 1MB Bound
	and	si,000fh
	mov	bx,ax
Read4:
	push	ds
	mov	ds,bx
	mov	cx,es:[di.TfrCnt]	; Request Transfer Count
	call	SetParm
	mov	[bp.SecCnt],cx
; -- Multi-Block Data Read of Mode-1 --
Read6:
	call	RedDsk			; Read From Drive
Read7:
	pop	ds
	mov	es:[di.TfrCnt],cx
	jc	NotRdy0			; if Carry, Error Read/Seek
	add	dx,cx			; Add Logical Sector Count
	adc	bx,0
Read75:
	mov	[bp.CurAdr],dx
	mov	[bp.CurAdr+2],bx
	jmp	Done
Read	endp

; Seek Entry
Seek	proc	near
	call	SetParm
	jmp	Read75
Seek	endp

;
; Setup Parameters
;  IN: [es:di] = Command Packet Header Address
; OUT: bx:dx = Physical Block Address
;      al = Drive Number
;
SetParm	proc	near
; Setup Block Address
	mov	dx,es:[di.BlkAdr]	; Set Block Address (Low)
	mov	bx,es:[di.BlkAdr+2]	;  "    "      "    (High)
	ret
SetParm	endp

;
; Hardware Oriented Routine
;
	include	BAS-SCSI.ASM

; Initialize Routine Entry
Init	proc	near
  ifdef DEBUG
	push	es
	push	di
	mov	di,cs
	mov	es,di
	mov	di,offset HeadPrt
	mov	ax,cs
	call	itoh
	mov	dx,offset HeadPrt
	mov	ah,09h
	int	21h
	pop	di
	pop	es
  endif
	mov	dx,offset OpenMsg	; Opening Message
	mov	ah,09h			; Print Message
	int	21h

; Set SCSI-ID and Other Options
Init0:
	call	GetArgs
	mov	al,[bp.ScsiID]
	cmp	al,0ffh			;SCSI-ID Set ?
	jne	Init1
	mov	dx,offset IDErrMsg	; ID Error Message
	jmp	Init8

; Display SCSI-ID & LUN
Init1:
	push	es
	push	di
;
	push	cs
	pop	es
	mov	al,[bp.ScsiID]		; SCSI-ID
	mov	di,offset IDMsg1
	call	ctoh
	mov	al,MaxUnit		; LUN
	mov	di,offset IDMsg2
	call	ctoh
	mov	si,offset DevNam
	mov	di,offset IDMsg3
	mov	cx,8
	rep	movsb
	mov	dx,offset IDMsg0
	mov	ah,09h
	int	21h
;
	pop	di
	pop	es

; Check SCSI Driver Install
	call	ChkSCSI
	jnc	Init2
	mov	dx,offset ScErrMsg	; Driver Error Message
	jmp	Init8

; Check Hardware Ready
Init2:
	cmp	byte ptr cs:ChkInq,0
	jz	Init5
	mov	byte ptr TempBuf,88h	; Check Error of Inquiry
	call	Inquiry			; Check Inquiry
	jnc	Init4
	mov	dx,offset InqErrMsg	; Inquiry Error Message
	jmp	Init8

; Check Medium Type (in Inquiry Data)
Init4:
	cmp	al,05h			; CD-ROM ?
	je	Init5			; Yes, Branch This is CD-ROM
	cmp	al,04h			; Write Once Medium ?
	jne	Init7			; No, It's Illegal Medium

; Setup Request Header Parameters
Init5:
	mov	bx,offset Break		; Break Address
	jmp	Init9

; Initialize Error (DX = Message Pointer)
Init8:
	mov	ah,9			; Print Message
	int	21h
	xor	bx,bx

; Return of Init Routine
Init9:
	mov	word ptr es:[di+14],bx	; | ->Set Break Address
	mov	word ptr es:[di+16],cs	; |
	mov	word ptr ComTbl0,offset None	; Set Init Routine is None
	xor	ax,ax
	ret

; Illegal Medium
Init7:
	mov	dx,offset DrvErrMsg	; Driver Not Connect Message
	cmp	al,88h
	je	Init8
	push	es
	push	di
	push	cs
	pop	es
	mov	di,offset MedNum
	call	ctoh
	pop	di
	pop	es
	mov	dx,offset MedErrMsg	; Illegal Medium Message
	jmp	Init8
;
Init	endp

IDMsg0	db	'    SCSI-ID = '
IDMsg1	db	'  , Unit = '
IDMsg2	db	'  , Device Name = '
IDMsg3	db	'         ',0dh,0ah,'$'
;
ChkInq	db	0ffh
OpenMsg	db	0dh,0ah,'CD-SD Mini /'
  if IF_TYPE eq ASPI
	db	' ASPI Version'
  endif
  if IF_TYPE eq FM
	db	' FM-R/TOWNS BIOS Version'
  endif
  if IF_TYPE eq PC9801
	db	' PC9801-55 BIOS Version'
  endif
	db	' 6th Release 94/07/02',0dh,0ah
	db	' Copyright(C) Uno 1992-94',0dh,0ah
	db	'$'
IDErrMsg db	07h
	db	'    !!!!!!!  SCSI-ID ERROR  !!!!!!!',0dh,0ah,'$'
ScErrMsg db	07h
	db	'    !!!!!!!  SCSI-DRIVER NOT INSTALLED  !!!!!!!',0dh,0ah,'$'
InqErrMsg db	07h
	db	'    !!!!!!!  INQUIRY ERROR  !!!!!!!',0dh,0ah,'$'
DrvErrMsg db	07h
	db	'    !!!!!!!  DRIVE NOT CONNECT  !!!!!!!',0dh,0ah,'$'
MedErrMsg db	07h
	db	'    !!!!!!! INQUIRY DATA '
MedNum	db	'  h - NOT SUPPORT THIS MEDIA  !!!!!!!',0dh,0ah,'$'
HeadPrt	db	'    :0000',0dh,0ah,'$'
OptErrMsg db	07h
	db	'    !!!!!!!  OPTION ERROR   !!!!!!!',0dh,0ah
;	db	'Option Parameter',0dh,0ah
;	db	'   /I<ID>    SCSI-ID Set. (Must Requirement)',0dh,0ah
;	db	'             <ID> = 0 to 6',0dh,0ah
;	db	'   /D:<Name> Device Name (Must Requirement)',0dh,0ah
;	db	'             <Name> = Strings of Device Name (Max. 8 byte)',0dh,0ah
;	db	'   /C<No.>   Sub Unit Count for Changer',0dh,0ah
;	db	'             <No.> = 1 to 7 (Default = 1)',0dh,0ah,
	db	'$'

;
; Get Arguments
;   Driver Option Parameter is
;   /I<ID>   SCSI-ID Set. (Must Required)
;   /C<No.>  Sub-Unit Count for CD-ROM Changer (Default=1)
;   /D:<Device Name> Set Device Name
;
GetArgs	proc	near
	push	ds
	push	si
	lds	si,dword ptr es:[di+18]	; Get CONFIG.SYS Parameter Ptr.
GetArg1:
	lodsb
GetArg2:
	cmp	al,0dh		; CR ?
	je	GetArg9
	cmp	al,'/'		; Separator ?
	jne	GetArg1
;
	lodsb
	cmp	al,41h		; Illegale Option ?
	jb	GetArg2
	and	al,1fh		; Only Code
	cmp	al,03h		; /C ?
	je	GetArg3
	cmp	al,04h		; /D ?
	je	GetArg6
	cmp	al,15h		; /U ?
	je	GetArg4
	cmp	al,09h		; /I ?
	jne	GetArg8

; /I Option
	call	GetArg5
	cmp	al,7			; SCSI-ID is 0 to 6 ?
	ja	GetArg8
	mov	[bp.ScsiID],al	; Set SCSI-ID
	jmp	GetArg1

; /C Option
GetArg3:
	call	GetArg5
	cmp	al,7			; LUN is 0 to 7 ?
	ja	GetArg8
	mov	byte ptr cs:MaxUnit,al
	jmp	GetArg1

; /U Not Check SCSI Inquiry Parameter
GetArg4:
	mov	byte ptr cs:ChkInq,0
	jmp	GetArg1

; /D: Option
GetArg6:
	lodsb
	cmp	al,20h		; Charactor ?
	jbe	GetArg8
	cmp	al,':'		; Colon ?
	jne	GetArg8
	push	es
	push	di
	mov	di,cs
	mov	es,di		; Set Segment
	mov	di,offset DevNam
	mov	cx,8
GetArg65:
	mov	al,[si]
	cmp	al,20h		; Charactor ?
	jbe	GetArg67
	inc	si
	stosb
	loop	GetArg65
GetArg67:
	pop	di
	pop	es
	jmp	GetArg1

; Option Error
GetArg8:
	pop	si
	pop	ds
	mov	dx,offset OptErrMsg
	mov	ah,9			; Print Message
	int	21h
	xor	bx,bx			; Top of Device Driver
	mov	ax,800ch		; General Error
	stc
	ret

GetArg9:
	xor	ax,ax
	pop	si
	pop	ds
	ret

; ASCII -> Binary
GetArg5:
	lodsb
	cmp	al,30h		; 030h - 039h ?
	jb	GetArg55
	cmp	al,39h
	ja	GetArg55
	and	al,0fh
	ret
GetArg55:
	mov	al,0fh
	ret
GetArgs	endp

;
; Integer to Hex-Ascii
;  IN : ax = Data
;       es:di = String Pointor
;
itoh	proc	near
	push	ax
	mov	al,ah	; Set Lower 8 bit
	call	itoh_0
	pop	ax
ctoh:
	mov	ah,al	; Save Original Data
itoh_0:
	and	al,0f0h	; Only Higer 4 bits
	shr	al,1	; |
	shr	al,1	; |-> shift right 4 times
	shr	al,1	; |
	shr	al,1	; |
	call	itoh_1
	mov	al,ah	; Restore Original Data
	and	al,00fh	; Only Lower 4 bits
itoh_1:
	cmp	al,10	; 0 to 9 ?
	jb	itoh_2	; Yes, Branch
	add	al,7	; (41h - 30h) - 10 + al
itoh_2:
	add	al,30h	; Convert ASCII Code
	stosb		; Set Char
	ret
itoh	endp
;
cseg	ends
	end
