
;*******************************************************
;
;	SCSI Driver 'Control' filter.
;
;	Written by Matt Gulick.		Started August 13,1988
;
;	Copyright Apple Computer, Inc. 1988-90
;
;*******************************************************

;*******************************************************
;
;	This file contains the 'Control' filter as defined
;	in the ERS.
;
;*******************************************************

;*******************************************************
;
;	Revision History:
;
;*******************************************************

;	Aug 13,		1988	File started.

				STRING		PASCAL
				BLANKS		OFF
				PAGESIZE	70
				PRINT		NOGEN
				PRINT		NOMDIR
				MACHINE		M65816

				IMPORT		call_type
				IMPORT		internal
				IMPORT		main_drvr
				IMPORT		f_partition
				IMPORT		direct_page
				IMPORT		gsos_dpage
				IMPORT		internal_buff
				IMPORT		set_our_dp
				IMPORT		chk_lnk_offline
				IMPORT		set_disk_sw
				IMPORT		disk_switch
				IMPORT		rebld_dibs
				IMPORT		trash_volume
				IMPORT		trash_it
				IMPORT		ko_cache
				IMPORT		trans_flag
				IMPORT		uses_dc
				IMPORT		dib_data_struct
				IMPORT		display_cnt
				IMPORT		current_fmt
				IMPORT		opt1_blk_cnt
				IMPORT		opt1_blk_siz
				IMPORT		opt1_interleave
				IMPORT		opt1_med_siz
				IMPORT		opt2_blk_cnt
				IMPORT		opt2_blk_siz
				IMPORT		opt2_interleave
				IMPORT		opt2_med_siz
				IMPORT		opt3_blk_cnt
				IMPORT		opt3_blk_siz
				IMPORT		opt3_interleave
				IMPORT		opt3_med_siz
				IMPORT		format_data
				IMPORT		check_532_rw
				IMPORT		sense_data
				IMPORT		t_dvc_blocks

				ENTRY		reset_dvc
				ENTRY		eject
				ENTRY		s_config_parms
				ENTRY		s_wait_mode
				ENTRY		format_opt
				ENTRY		assign_part
				ENTRY		arm_signal
				ENTRY		disarm_sig
				ENTRY		set_p_map
				ENTRY		format_dvc

				PRINT		OFF

				INCLUDE		'scsihd.equates'
				INCLUDE		'M16.MEMORY'
				INCLUDE		'M16.UTIL'
				PRINT		ON

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Control' filter.  This
;	"Filter" is called when a Control Command comes in.
;	See the headers of the seperate sections for the
;	details of the commands.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	control
control			PROC
												;
												; Is the device online?
												;
				ldy		#dib.dvcflag

				lda		[dib_ptr],y
				and		#dvc_online
				bne		@online					;Yes.
												;
												; Device is currently offline.
												;
				lda		#drvr_off_line
				sec
				rts
												;
												; Zero out the Data Chaining Flag
												;
@online			stz		|uses_dc
												;
												; Clear transfer count.
												;
				lda		#null
				ldy		#dib.trx_len
				sta		[dib_ptr],y
				ldy		#dib.trx_len+2
				sta		[dib_ptr],y
												;
												; Entry to the Control Call Filter.
												; This filter acts as a mini driver.
												; It examines the Control Code sent
												; and calls the appropriate routines.
												; If the Command is $8000 or greater,
												; then it will be routed to the device
												; specific section.
												;
				lda		<cont_code
				bmi		@do_dvc_spec			;Device Specific Code.
												;
												; Check the range of the command.
												;
				cmp		#max_c_cmd+1
				bge		@error
												;
												; Convert to an index
												;
				asl		a
				tax
				jsr		(@ncmd_tbl,x)
				rts
												;
												; Bad Command Error.
												;
@error			lda		#drvr_bad_req
				sec
				rts
												;
												; Normal Command Table.
												;
@ncmd_tbl		dc.w	reset_dvc
				dc.w	format_dvc
				dc.w	eject
				dc.w	s_config_parms
				dc.w	s_wait_mode
				dc.w	format_opt
				dc.w	assign_part
				dc.w	arm_signal
				dc.w	disarm_sig
				dc.w	set_p_map
												;
												; Device Specific Code handling
												; starts here.
												;
												; Check version of data structure
												;
@do_dvc_spec	lda		[buff_ptr]
				beq		@version_0
				cmp		#$0001
				bne		@error
												;
												; Version 1.  Preserve the data pointer
												; currently used in the DIB and replace
												; it with a pointer to the USER supplied
												; Data Chaining instructions.
												;
				clc
				ldy		#dib.trx_ptr
				lda		[dib_ptr],y
				sta		|dib_data_struct

				lda		<buff_ptr
				adc		#ds.DCcode				;Offset to first D.C. Data
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		[dib_ptr],y
				sta		|dib_data_struct+2

				lda		<buff_ptr+2
				adc		#^ds.DCcode
				sta		[dib_ptr],y
												;
												; Set flag to indicate that D.C. Commands
												; were used and that we need to restore
												; the pointer in the DIB to the normal
												; data descriptor.
												;
				dec		|uses_dc
												;
												; Do the rest normally and check the above
												; flag later.
												;
@version_0		clc
				lda		<buff_ptr
				adc		#$0002
				sta		<scsi_mdrvr

				lda		<buff_ptr+2
				adc		#null
				sta		<scsi_mdrvr+2
				
				ldy		#$000C
				lda		[scsi_mdrvr],y
				sta		<buff_ptr
				ldy		#$000C+2
				lda		[scsi_mdrvr],y
				sta		<buff_ptr+2
												;
												; Call Main Driver
												;
				lda		#scsit_cont
				sta		|call_type
				jsr		|main_drvr
				bcs		@exit
												;
												; Save transfer count.
												;
				ldy		#dib.trx_len
				lda		[dib_ptr],y
				sta		@call_trns_cnt
				ldy		#dib.trx_len+2
				lda		[dib_ptr],y
				sta		@call_trns_cnt+2
												;
												; Check to see if we need to handle
												; a Disk Switched Event.  If not,
												; then exit.
												;
				lda		disk_switch				;= $ffff
				bpl		@exit
												;
												; Don't Trash the Volumes.
												;
				jsr		set_disk_sw				;DISK_SW for each Linked DIB.
				jsr		rebld_dibs				;Rebuild DIBs.
												;
												; Restore Direct Page Values.
												;
@exit			pha
				php
												;
												; Check the D.C. Flag
												;
				lda		|uses_dc
				beq		@set_our_zp

				ldy		#dib.trx_ptr
				lda		|dib_data_struct
				sta		[dib_ptr],y

				ldy		#dib.trx_ptr+2
				lda		|dib_data_struct+2
				sta		[dib_ptr],y
				
				stz		|uses_dc				;Reset Flag

@set_our_zp		jsr		set_our_dp
												;
												; Set transfer count.
												;
				lda		@call_trns_cnt
				sta		<trans_cnt
				lda		@call_trns_cnt+2
				sta		<trans_cnt+2

;-------------------------------------------------------------------------------

				IF			cache_blks = true	THEN

												;
												; If it is a Data Call and has a timer
												; that is adjusted by the block count,
												; then this call could cause the cache
												; to be in-validated.
												;
				lda		|trans_flag
				and		#scsit_data++\			;Is it a data call
						scsic_tout++\			;with a block count
						scsit_cont				;Writing data?
				cmp		#scsit_data++\
						scsic_tout++\
						scsit_cont
				bne		@no_write				;No.
				jsr		ko_cache				;Yes. Kill the blocks.

				ENDIF

;-------------------------------------------------------------------------------

												;
												; Exit.
												;
@no_write		plp
				pla
				rts
												;
												; Data Area.
												;
@call_trns_cnt	dc.l	null					;Transfer count befor we steped on it.

				ENDP

				EJECT
			
;*******************************************************
;
;	This Control Call is used to reset a particular
;	device to it's default settings.  A Device Driver
;	should configure itself based on the contents of the
;	drivers configuration parameter list.  This call
;	should reset any media variables that were modified
;	through a Set_Format_Options call.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	reset_dvc
reset_dvc		PROC
												;
												; Issue a REeZero Unit Call to the device.
												;
												; Set Main Driver Pointer to
												; our data for the command.
												;
				lda		#cmd_$8001
				sta		<scsi_mdrvr
				lda		#^cmd_$8001
				sta		<scsi_mdrvr+2
												;
												; Call Main Driver
												;
				lda		#scsit_cont
				sta		|call_type
				jsr		|main_drvr
												;
												; Update Transfer Count.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
												;
												; Exit No Error.
												;
				lda		#$0000
				clc
				rts
												;
												; Command Data for this call.
												;
cmd_$8001		dc.b	$01
				dcb.b	11,$00

				ENDP

				EJECT
			
;*******************************************************
;
;	The Format call will ensure that the media is
;	formatted and ready to receive data.  If the DIB
;	points to a partition then the Format call will
;	return no error while taking no action (If it is
;	partitioned, then it must have been formatted or the
;	partition map could not have been written.  Right?).
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	format_dvc
format_dvc		PROC

;-------------------------------------------------------------------------------

				IF		character_dvc = true	THEN
												;
												; It's a character device and
												; the Acc is zero by virtue of
												; the missed branch.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd	THEN
												;
												; If the device is a CD_ROM, then
												; it is write protected.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#drvr_wrt_prot
				sec
				rts

				ENDIF

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN
												;
												; It's a block device.  But is
												; it partitioned?  If it has a
												; zero start block then there is
												; no partition.
												;
				stz		@error					;Set to No Error.
				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				beq		@over
												;
												; Well, it is a partition.  But is it
												; the only partition.  By this, I mean,
												; is it a disk with a partition map
												; containing only two entries, one for
												; the partition map and the other for
												; a single volume?
												;
												; First check if this is the first or
												; second entry in the Partition Map.
												;
				ldy		#dib.part_blk
				lda		[dib_ptr],y
				xba
				cmp		#$0003
				bge		@do_part_fmt			;Past the second entry.  Do as if multi
												;partition.
												;
												; Is it linked?  Let's see.
												;
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@over					;Not linked. Must be only one.

@do_part_fmt	jsr		trash_volume			;Trash this volume only.
				jmp		@clean_exit				;Sorry.  Not the only volume
												;
												; Well there is no getting around
												; it.  We need to issue a format
												; call to this device.
												;
												; Setup from last format options call
												;
@over			lda		|current_fmt
				dec		a
				asl		a
				asl		a
				asl		a
				asl		a
				tax

				ldy		#dib.blksize
				lda		|opt1_blk_siz,x
				sta		[dib_ptr],y
				xba
				sta		@blk_size+2

				lda		|opt1_blk_cnt,x
				sta		|t_dvc_blocks

				lda		|opt1_blk_cnt+2,x
				sta		|t_dvc_blocks+2

				stz		@blk_size
				shortm
				lda		opt1_interleave,x
				sta		@interleave
				longm
												;
												; Preserve the Current Direct
												; Page values stored in the
												; buff_ptr and rqst_cnt fields.
												;
				pei		<buff_ptr
				pei		<buff_ptr+2
				pei		<rqst_cnt
				pei		<rqst_cnt+2
												;
												; Set Format Parm Pointer.
												;
				lda		#@mode_select
				sta		<scsi_mdrvr
				lda		#^@mode_select
				sta		<scsi_mdrvr+2
												;
												; Set our own buffer pointer
												; for this call.
												;
				lda		#@mode_data
				sta		<buff_ptr
				lda		#^@mode_data
				sta		<buff_ptr+2
												;
												; Set our own request count
												; for this call.
												;
				lda		#$0000000c
				sta		<rqst_cnt
				lda		#^$0000000c
				sta		<rqst_cnt+2
												;
												; It's a Control Call.
												;
				lda		#scsit_cont
				sta		|call_type
												;
												; Set Internal Command Flag
												;
				dec		|internal
												;
												; Issue the Call
												;
				jsr		|main_drvr
												;
												; Set Format Parm Pointer.
												;
				lda		#@format_p
				sta		<scsi_mdrvr
				lda		#^@format_p
				sta		<scsi_mdrvr+2
												;
												; Set our own buffer pointer
												; for this call.
												;
				lda		#format_data
				sta		<buff_ptr
				lda		#^format_data
				sta		<buff_ptr+2
												;
												; Set our own request count
												; for this call.
												;
				stz		<rqst_cnt
				stz		<rqst_cnt+2
												;
												; It's a Control Call.
												;
				lda		#scsit_cont
				sta		|call_type
												;
												; Set Internal Command Flag
												;
				dec		|internal
												;
												; Issue the Call
												;
				jsr		|main_drvr
				bcc		@rebuild_dib
												;
												; Save error code
												;
				sta		@error
												;
												; Rebuild the DIB.
												;
@rebuild_dib	jsr		rebld_dibs
												;
												; Restore the Direct Page Values.
												;
@return_dp		pla
				sta		<rqst_cnt+2
				pla
				sta		<rqst_cnt
				pla
				sta		<buff_ptr+2
				pla
				sta		<buff_ptr
												;
												; Restore the Acc result.
												;
@clean_exit		jsr		set_disk_sw
				lda		@error
				cmp		#$0001
				rts
												;
												; Data for this call
												;
@error			dc.w	null
												;
												; MODE SELECT Command Packet
												;
@mode_select	dc.b	$15						;Command Number
				dc.b	$00						;Vendor Unique
				dc.b	$00						;Reserved
				dc.b	$00						;Reserved
				dc.b	$00						;Resolved by Main Driver
				dcb.b	6,$00					;Reserved
												;
												; MODE SELECT Data
												;
@mode_data		dc.b	$00						;Command Number
				dc.b	$00						;Reserved
				dc.b	$00						;Reserved
				dc.b	$08						;Length of extension
				dc.b	$00						;Block Count (MSB)
				dc.b	$00						;Block Count
				dc.b	$00						;Block Count
				dc.b	$00						;Block Count (LSB)
@blk_size		dc.b	$00						;Block Size (MSB)
				dc.b	$00						;Block Size
				dc.b	$02						;Block Size
				dc.b	$00						;Block Size (LSB)
												;
												; FORMAT Command Packet
												;
@format_p		dc.b	$04						;Command Number
				dc.b	$00						;Vendor Unique
				dc.b	$00						;Reserved
				dc.b	$00						;SCSI Interleave (MSB)
@interleave		dc.b	interleave				;SCSI Interleave (LSB)
				dcb.b	6,$00					;Reserved

				ENDIF

;-------------------------------------------------------------------------------

												;
												; Bad Parm Error
												;
@bad_parm		lda		#drvr_bad_parm
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	The EJECT command is used to cause the target to
;	eject the currently mounted device.  This could be a
;	CD Device, Tape Drive or Removable hard disk.  The
;	first thing that we will check is to see if the
;	removable bit is set.  It not then a DRVR_BAD_CODE
;	error will be returned.  Otherwise the call will be
;	sent to the device.  Any error, if any at all, will
;	be returned to the caller of this routine.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	eject
eject			PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN
												;
												; Verify request count.  Should be
												; zero
												;
				clc
				lda		<rqst_cnt
				bne		@bad_parm
												;
												; Check to see if it's removable
												;
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#removable
				beq		@bad_request
												;
												; Is this device linked to other
												; active devices?
												;
				jsr		chk_lnk_offline
				bcs		@mark_offline			;Yes.  Skip Eject and DISK SWITCH Calls
												;
												; Issue the eject call to the device.
												;
												; Set internal command flag
												;
				dec		|internal
												;
												; Tell the Main Driver where
												; our command structure resides.
												;
				lda		#@eject
				sta		<scsi_mdrvr
				lda		#^@eject
				sta		<scsi_mdrvr+2
												;
												; Set the Call Type and Issue the
												; INQUIRY Command.
												;
				lda		#scsit_cont
				sta		|call_type
				jsr		|main_drvr
				bcs		@rts
												;
												; Issue DISK_SW Call. This is only done
												;	when the media is actually EJECTed
												;	in response to this call.
												;
				jsr		set_disk_sw
												;
												; Mark this DIB as Switched and Hard
												; Offline.
												;
@mark_offline	ldy		#dib.dvcflag
				lda		[dib_ptr],y
				ora		#dvc_hardofl++\
						dvc_switch
				and		#dvc_online--\
						$ffff
				sta		[dib_ptr],y
												;
												; Clean Exit.
												;
				lda		#no_error
				clc
				rts
												;
												; Bad request
												;
@bad_request	lda		#drvr_bad_req
				sec
				rts
												;
												; Bad request length.
												;
@bad_parm		lda		#drvr_bad_parm
				sec
												;
												; Exit.
												;
@rts			rts

;-------------------------------------------------------------------------------

				IF		scsi_dtype = direct_acc		THEN

												;
												; Command Packet
												;
@eject 			dc.b	$1B
				dc.b	$00
				dcb.b	2,$00					;Reserved
				dc.b	$02						;Normal Unload. See document.
				dcb.b	7,$00

				ENDIF							;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				IF		scsi_dtype = apple_cd	THEN

												;
												; Command Packet
												;
@eject			dc.b	$C0
				dcb.b	11,$00

				ENDIF							;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				ENDIF							;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there is nothing to eject.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF							;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	This call set the configuration parms for the
;	specified device.  The parameters are device
;	specific.  The list is preceded by a word length
;	which must be equal to the transmit count.  If not
;	then a DRVR_BAD_PARM error is returned.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	s_config_parms
s_config_parms	PROC
												;
												; Lie for now.  Say that we did even
												; though we didn't.
												;
				clc
				lda		<rqst_cnt				;*************************
				beq		@rts					;*************************
												;
												; Bad request length.
												;
				lda		#drvr_bad_parm
				sec
												;
												; Exit.
												;
@rts			rts

				ENDP

				EJECT
			
;*******************************************************
;
;	This call is used to set the Wait or No Wait state
;	for a character device.  If in wait mode the device
;	will wait until request count bytes have been read
;	before returning to the caller.  Block devices will
;	return no error for this call.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				[buff_ptr]	=	Wait flag
;								$0000	=	Wait Mode
;								$8000	=	No Wait Mode
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	s_wait_mode
s_wait_mode		PROC
												;
												; Check the parameters list.
												; Should contain a WORD
												;
				lda		<rqst_cnt
				cmp		#$0002
				bne		@bad_parm
												;
												; Is it a block device?
												;
				ldy		#dib.dvcchar
				lda		[dib_ptr],y
				and		#blk_device
				bne		@clean_exit
												;
												; It's a character device.  Do we
												; set or clear the wait bit?
												;
@char_dvc		lda		[buff_ptr]
				beq		@set_wait				;Set the Wait Mode
				cmp		#$8000
				bne		@bad_parm
												;
												; Clear the Wait mode to No Wait.
												;
				ldy		#dib.dvcflag
				lda		[dib_ptr],y
				and		#wait_mode--\			;Generate a mask for this bit
						$ffff
												;
												; Save it and exit.
												;
				bra		@set_state
												;
												; Set Wait Mode
												;
@set_wait		ldy		#dib.dvcflag
				lda		[dib_ptr],y
				ora		#wait_mode
												;
												; Save New Mode
												;
@set_state		sta		[dib_ptr],y
												;
												; Clean Exit
												;
@clean_exit		lda		#null					;Clear the Acc.
				clc
				rts
												;
												; Bad Parm Error
												;
@bad_parm		lda		#drvr_bad_parm
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	The set format options call is not supported by this
;	driver.  No error is returned unless they send a
;	transfer length > 0000.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	format_opt
format_opt		PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd	THEN
												;
												; If the device is a CD_ROM, then there
												; are no format options.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#bad_dev_number
				sec
				rts

				ENDIF							;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN
												;
												; If we are partitioned, then no data.
												;
				ldy		#dib.dvcchar

				lda		[dib_ptr],y
				and		#linked_dvc
				beq		@no_link				;No.
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts
												;
												; Check the count
												;
@no_link		lda		<rqst_cnt
				beq		@bad_parm
				cmp		#$0002
				bne		@bad_parm
				sta		<trans_cnt
				stz		<trans_cnt+2
												;
												; Set default Option.
												;
				lda		[buff_ptr]
				sta		current_fmt
												;
												; Exit.
												;
				lda		#null
				clc
				rts
												;
												; Bad request length.
												;
@bad_parm		lda		#drvr_bad_parm
				sec
				rts

				ENDIF							;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				ENDIF							;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there are no format options.
												;
				lda		#drvr_bad_code
				sec
				rts

				ENDIF							;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	Main Entry point to the 'Control' filter.  This
;	"Filter" is called when a Control Command comes in.
;	See the headers of the seperate sections for the
;	details of the commands.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	assign_part
assign_part		PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd	THEN
													;
													; Exit Write Protect Error.
													;
				lda		#drvr_wrt_prot
				sec
				rts

				ENDIF								;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

													;
													; Validate that this DIB is from
													; a Partition Map Entry.
													;
				ldy		#dib.start_blk
				lda		[dib_ptr],y
				ldy		#dib.start_blk+2
				ora		[dib_ptr],y
				bne		@over
													;
													; Not from a partition.
													;
				lda		#bad_dev_number
				sec
				rts
													;
													; Get block that contains this
													; DIB's Partition Map Entry.
													;
@over			ldy		#dib.part_blk
				lda		[dib_ptr],y
				sta		@read_blk_num
				sta		@write_blk_num
													;
													; Tell the Main Driver where
													; our command structure resides.
													;
				lda		#@read_part
				sta		<scsi_mdrvr
				lda		#^@read_part
				sta		<scsi_mdrvr+2
													;
													; And our buffer
													;
				lda		#internal_buff
				sta		<buff_ptr
				lda		#^internal_buff
				sta		<buff_ptr+2
													;
													; And our length from the DIB's
													; Block Size value
													;
				ldy		#dib.blksize
				lda		[dib_ptr],y
				sta		<rqst_cnt
				ldy		#dib.blksize+2
				lda		[dib_ptr],y
				sta		<rqst_cnt+2
													;
													; Set internal command flag
													;
				dec		|internal
				dec		|f_partition
													;
													; Set the Call Type and Issue the
													; READ BLOCK Command.
													;
				lda		#scsit_stat
				sta		|call_type
				jsr		|main_drvr
													;
													; Restore Direct Page Values.
													;
				pha
				php
				jsr		set_our_dp
				plp
				pla
				bcs		@bad_exit					;There was an error.
													;
													; Is what we read a Partition Map?
													;
				lda		|pm.Sig\
						+internal_buff
				cmp		#Part_sig
				bne		@bad_exit					;Bad Data Read.
													;
													; Set a pointer to actual text.
													;
				clc
				lda		<buff_ptr
				adc		#$0002
				sta		<scsi_zp4
				lda		<buff_ptr+2
				adc		#null
				sta		<scsi_zp4+2
													;
													; Get length of data
													;
				lda		[buff_ptr]
				cmp		#$0020+1
				bge		@bad_exit		
				tay
				tax
				dey									;16 bit mode
				dex
													;
													; Are they the same?  If so we can
													; save a block write.
													;
@cmp_loop		lda		|pm.PartType\
						+internal_buff,y
				cmp		[scsi_zp4],y
				bne		@move_new
				dey
				bpl		@cmp_loop
				bra		@all_done
													;
													; Not the same.  Replace old with
													; the new.
													;
@move_new		txa
				tay
@move_loop		lda		[scsi_zp4],y
				sta		|pm.PartType\
						+internal_buff,y
				dey
				bpl		@move_loop
													;
													; Tell the Main Driver where
													; our command structure resides.
													;
				lda		#@write_part
				sta		<scsi_mdrvr
				lda		#^@write_part
				sta		<scsi_mdrvr+2
													;
													; And our buffer
													;
				lda		#internal_buff
				sta		<buff_ptr
				lda		#^internal_buff
				sta		<buff_ptr+2
													;
													; And our length from the DIB's
													; Block Size value
													;
				ldy		#dib.blksize
				lda		[dib_ptr],y
				sta		<rqst_cnt
				ldy		#dib.blksize+2
				lda		[dib_ptr],y
				sta		<rqst_cnt+2
													;
													; Set internal command flag
													;
				dec		|internal
				dec		|f_partition
													;
													; Set the Call Type and Issue the
													; READ BLOCK Command.
													;
				lda		#scsit_cont
				sta		|call_type
				jsr		|main_drvr
													;
													; Restore Direct Page Values.
													;
				pha
				php
				jsr		set_our_dp
				plp
				pla
				bcc		@all_done					;There was no error.
													;
													; Error exit point.
													;
@bad_exit		lda		#drvr_io
				sec
				bra		@finalize
													;
													; Clean Exit
													;
@all_done		lda		#no_error
				clc
													;
													; Finalize this call.  We must exit
													; with a disk switched because we have
													; effectivly changed the media.
													;
@finalize		pha
				php
				lda		|gsos_dpage
				tcd
				jsl		set_disksw
				lda		|direct_page
				tcd
				plp
				pla
				rts
													;
													; Data for the READ BLOCK Command
													;
@read_part		dc.b		$08
				dc.b		null
@read_blk_num	dc.w		null
				dcb.b		10,null
													;
													; Data for the WRITE BLOCK Command
													;
@write_part		dc.b		$0A
				dc.b		null
@write_blk_num	dc.w		null
				dcb.b		10,null

				ENDIF								;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				ENDIF							;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there are no Partitions to
												; assign.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF							;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
			
;*******************************************************
;
;	Entry point for the Arm Signal Drivcer Call.  This
;	call is not supported by this driver.  An error is
;	returned in all cases.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	arm_signal
arm_signal		PROC

				lda		#drvr_bad_code
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	Entry point for the Disarm Signal Drivcer Call.
;	This call is not supported by this driver.  An error
;	is returned in all cases.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	disarm_sig
disarm_sig		PROC

				lda		#drvr_bad_code
				sec
				rts

				ENDP

				EJECT
			
;*******************************************************
;
;	Most be the first device in a link!!!!
;
;	Entry point to the 'Set PMap' call.  This call
;	takes the information given by the caller on direct
;	page and builds the equivilent to a Write Status
;	Call to write request count bytes starting at
;	physical block number 1.  This is done by setting
;	the high bit of the partition call flag
;	'f_partition'.
;
;			Block Size				=	dib.blksize
;
;	We now Build the SCSI Main Driver Command and send
;	it.
;
;	The following will be validated by the Main Driver
;	when it builds the command. 
;
;			Request Count			=	Block Size * i
;			Block Number			=	Blk Num (No Offset)
;				This is for partitions.
;
;	After calling the Main driver and if no errors were
;	encountered, then the Transfer count will be
;	updated.
;
;	Called via 'JSR'
;
;	Inputs:		[dib_ptr]	=	Target DIB	l	(LONG)
;				Acc			=	Unspecified
;				Carry		=	Unspecified
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Returns via 'RTS'
;
;	Outputs:	Acc			=	0
;				Carry		=	0
;	or
;				Acc			=	Error
;				Carry		=	1
;
;				Y register	=	Unspecified
;				X register	=	Unspecified
;				P register	=	0=M=X=e
;				Direct Page	=	Ours
;				Data Bank	=	Ours
;
;	Errors:		See Spec.
;
;*******************************************************
			
				EXPORT	set_p_map
set_p_map		PROC

;-------------------------------------------------------------------------------

				IF			block_dvc = true\
				AND			character_dvc = false		THEN

;-------------------------------------------------------------------------------

				IF			scsi_dtype = apple_cd		THEN
												;
												; Exit Write Protect Error.
												;
				lda		#drvr_wrt_prot
				sec
				rts

				ENDIF							;scsi_dtype = apple_cd

;-------------------------------------------------------------------------------

				IF			scsi_dtype = direct_acc	THEN

				stz		@do_532
												;
												; Set the Block size on Direct Page.
												; It is not placed there for this call,
												; and we should not rely on it being
												; left behind by the last call.
												;
				lda		#block_size
				sta		<blk_size
												;
												; Check if first DIB in link if any.
												; If it is zero, then we are already
												; there.  If not then error out.
												;
				ldy		#dib.headptr+2
				lda		[dib_ptr],y
				ldy		#dib.headptr
				ora		[dib_ptr],y
				bne		@bad_dev_num
												;
												; Let's check the request count.  If
												; this is $00000000, then exit clean
												; with no data transfered.
												;
				lda		<rqst_cnt
				ora		<rqst_cnt+2
				bne		@cnt_non_zero
				jmp		@out_of_here
												;
												; Verify Block Size.
												;
@cnt_non_zero	ldy		#dib.blksize
				lda		[dib_ptr],y				;Block Size
				cmp		<blk_size
				bne		@chk_532

				ldy		#dib.blksize+2
				lda		[dib_ptr],y
				beq		@blk_size_ok

@bad_parm		lda		#drvr_bad_parm
				sec
				rts

@bad_dev_num	lda		#bad_dev_number
				sec
				rts
												;
												; Check for 532 byte block size
												;
@chk_532		tax

				lda		<blk_size
				cmp		#block_size
				bne		@bad_parm

				cpx		#$0214
				bne		@bad_parm
				dec		@do_532

@blk_size_ok
												;
												; Build the (Write Data)
												; Control Command $800A
				lda		#$0001					; Sent to me Low >> High.
				xba								; Send it out High >> Low.
				sta		|c_block_num
												;
												; Set Main Driver Pointer to
												; our data for the command.
												;
				lda		#cmd_$800A
				sta		<scsi_mdrvr
				lda		#^cmd_$800A
				sta		<scsi_mdrvr+2
												;
												; Set the Partition call flag
												;
				dec		|f_partition
												;
												; Call Main Driver
												;
				lda		#scsit_cont
				sta		|call_type
												;
												; Issue the call.
												;
				jsr		check_532_rw
				bcs		@rts
												;
												; Build the (Write Data) command
												; to write the Driver Descriptor
												; Map.
												;
@do_ddm			lda		#$5245					;Defined by MAC as $4552
				sta		|sense_data

				lda		#block_size
				sta		<rqst_cnt
				stz		<rqst_cnt+2
				xba
				sta		|sense_data+2			;Defined by MAC as $0200

				ldx		#$0040
@loop			stz		|sense_data+4,x
				dex
				dex
				bpl		@loop

				stz		|c_block_num
												;
												; Set our buffer pointer
												;
				lda		#sense_data
				sta		<buff_ptr
				lda		#^sense_data
				sta		<buff_ptr+2
												;
												; Set Main Driver Pointer to
												; our data for the command.
												;
				lda		#cmd_$800A
				sta		<scsi_mdrvr
				lda		#^cmd_$800A
				sta		<scsi_mdrvr+2
												;
												; Set the Partition call flag
												;
				dec		|f_partition
												;
												; Call Main Driver
												;
				lda		#scsit_cont
				sta		|call_type
												;
												; Issue the call.
												;
				jsr		check_532_rw
				bcs		@rts
												;
												; Rebuild the DIBs.
												; Trashing the Volumes.
												;
				dec		|trash_it
												;
				jsr		rebld_dibs				;Issues a DISK_SW for each rebuilt DIB.
												;
												; Reset The 'TRASH IT' Flag..
												;
				stz		|trash_it
												;
												; Restore the origonal Direct Page values.
												;
				jsr		set_our_dp
												;
												; Update Transfer Count.
												;
@out_of_here	lda		<rqst_cnt
				sta		<trans_cnt
				lda		<rqst_cnt+2
				sta		<trans_cnt+2
												;
												; Exit No Error.
												;
				lda		#$0000
				clc
@rts			rts
												;
												; Variables and storage for short call.
												;
@do_532			dc.w	null					;532 byte block flag
												;
												; Command Data for this call.
												;
cmd_$800A		dc.b	$0A
				dc.b	$00
c_block_num		dc.w	$0000
c_block_cnt		dc.b	$00
				dcb.b	7,$00

				ENDIF							;scsi_dtype = direct_acc

;-------------------------------------------------------------------------------

				ENDIF							;block_dvc = true

;-------------------------------------------------------------------------------

				IF			block_dvc = false\
				AND			character_dvc = true		THEN
												;
												; If the device is a Character Device,
												; then there are no Partitions to
												; write.
												;
				stz		<trans_cnt
				stz		<trans_cnt+2
				lda		#null
				clc
				rts

				ENDIF							;character_dvc = true

;-------------------------------------------------------------------------------

				ENDP

				EJECT
				
				END
