mirror of
https://github.com/antoinevignau/source.git
synced 2024-11-19 22:31:52 +00:00
d29484938c
What we wrote to make audio hearable on a SCSI-2 CD-ROM drive ;-)
1 line
163 KiB
Plaintext
1 line
163 KiB
Plaintext
|
||
;*******************************************************
|
||
;
|
||
; SCSI Driver Management Routines.
|
||
;
|
||
; Written by Matt Gulick. Started May 16,1988
|
||
;
|
||
; Copyright Apple Computer, Inc. 1988,89
|
||
;
|
||
;*******************************************************
|
||
|
||
;*******************************************************
|
||
;
|
||
; This file contains the subroutines needed by the
|
||
; SCSI Driver for things such as Getting RAM, Building
|
||
; data areas, calling outside routines for DIB
|
||
; management, as well as other generic routines that
|
||
; are used to make life easier for the driver. Also
|
||
; included in this file is the record definition for
|
||
; the DIB structure including all it's extensions.
|
||
;
|
||
;*******************************************************
|
||
|
||
;*******************************************************
|
||
;
|
||
; Revision History:
|
||
;
|
||
;*******************************************************
|
||
|
||
; May 16, 1988 File started.
|
||
; May 17, 1988 DIB Record defined.
|
||
; June 6, 1988 Main Driver Written.
|
||
; Jun 20, 1988 Update Input/Output Data in Comments
|
||
; Apr 14, 1989 Added Conditional Logic to remove
|
||
; block routines from character device
|
||
; assemblies.
|
||
|
||
STRING PASCAL
|
||
BLANKS OFF
|
||
PAGESIZE 70
|
||
PRINT NOGEN
|
||
PRINT NOMDIR
|
||
MACHINE M65816
|
||
|
||
IMPORT stat_cont
|
||
|
||
IMPORT master_uid
|
||
IMPORT scsi_uid
|
||
IMPORT scsi_mgrnum
|
||
IMPORT rout2_s_disp
|
||
IMPORT hndl_offset
|
||
IMPORT buff_len
|
||
IMPORT page_cnt
|
||
IMPORT dpi_overide
|
||
IMPORT call_type
|
||
IMPORT main_drvr
|
||
IMPORT internal
|
||
; IMPORT disk_switch
|
||
IMPORT ram_page_cnt
|
||
IMPORT internal_buff
|
||
IMPORT default_dib
|
||
IMPORT first_time
|
||
IMPORT only_one
|
||
IMPORT part_cnt
|
||
IMPORT t_dvc_blocks
|
||
IMPORT f_partition
|
||
IMPORT part_num
|
||
IMPORT vPart_cnt
|
||
IMPORT rebuild
|
||
IMPORT trash_it
|
||
IMPORT direct_page
|
||
IMPORT exit_dpage
|
||
IMPORT gsos_dpage
|
||
IMPORT saved_zp
|
||
IMPORT valid
|
||
IMPORT dvc_ram
|
||
IMPORT sense_data
|
||
IMPORT dvc_count
|
||
IMPORT result
|
||
IMPORT divend
|
||
IMPORT divsor
|
||
IMPORT max_blk_cnt
|
||
IMPORT tot_dib_cnt
|
||
IMPORT dib_data_struct
|
||
IMPORT main_caller
|
||
IMPORT curr_hndl
|
||
IMPORT new_dib
|
||
IMPORT scratch0
|
||
IMPORT scratch1
|
||
IMPORT scratch2
|
||
IMPORT scratch3
|
||
IMPORT killer_blk
|
||
IMPORT auto_sense_data
|
||
IMPORT temp_acc
|
||
IMPORT pdi_flag
|
||
IMPORT new_list
|
||
IMPORT new_dib_cnt
|
||
IMPORT new_dib_list
|
||
IMPORT real_unit ;*************************
|
||
|
||
IMPORT m_blk_size
|
||
IMPORT m_blk_cnt
|
||
IMPORT m_rslt
|
||
|
||
ENTRY zero_mem
|
||
ENTRY get_space
|
||
|
||
ENTRY make_dib
|
||
ENTRY find_empty
|
||
ENTRY chk_ram
|
||
|
||
ENTRY rebld_dibs
|
||
ENTRY dibicise_new_ram
|
||
ENTRY dibicise_new_dib
|
||
ENTRY set_link_ptrs
|
||
ENTRY major_update
|
||
ENTRY minor_update
|
||
|
||
ENTRY fix_unit_1
|
||
ENTRY add_dib_ptr
|
||
ENTRY do_post_install
|
||
|
||
ENTRY read_pm_blk
|
||
ENTRY rpm_blk_num
|
||
; ENTRY wpm_blk_num
|
||
ENTRY chk_map
|
||
ENTRY no_partition
|
||
ENTRY check_map_entry
|
||
|
||
ENTRY c_strt_buffer
|
||
ENTRY c_strt_rqst_cnt
|
||
ENTRY c_strt_blk_num
|
||
ENTRY cache_valid
|
||
ENTRY put_in_cache
|
||
ENTRY get_from_cache
|
||
|
||
ENTRY test_unit_rdy
|
||
ENTRY read_capacity
|
||
ENTRY mode_sense
|
||
ENTRY mode_sense2
|
||
|
||
ENTRY start_unit
|
||
ENTRY stop_unit
|
||
ENTRY set_512_mode
|
||
|
||
ENTRY notify_me
|
||
|
||
ENTRY set_disk_sw
|
||
ENTRY trash_volume
|
||
ENTRY save_dp
|
||
ENTRY restore_dp
|
||
ENTRY set_our_dp
|
||
ENTRY check_532_rw
|
||
ENTRY munge_532
|
||
ENTRY divide
|
||
|
||
PRINT OFF
|
||
|
||
INCLUDE 'scsihd.equates'
|
||
INCLUDE 'M16.MEMORY'
|
||
INCLUDE 'M16.UTIL'
|
||
INCLUDE 'M16.MISCTOOL'
|
||
PRINT ON
|
||
|
||
EJECT
|
||
;____Mem_Manager_____
|
||
;*******************************************************
|
||
;
|
||
; This routine is used to Get a User ID from the
|
||
; memory manager for the SCSI Driver. This is
|
||
; required to get a userID for access reference.
|
||
;
|
||
; Inputs: None.
|
||
;
|
||
; Outputs: SCSID_uID = userID.
|
||
; Registers = Scrambled
|
||
;
|
||
; Errors: $0207 iderr Invalid userID.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_mm_id
|
||
get_mm_id PROC
|
||
;
|
||
; Get userID.
|
||
;
|
||
pushword #$0000
|
||
|
||
pushword #scsi_duid
|
||
|
||
_GetNewID
|
||
pla
|
||
sta |master_uid
|
||
sta |scsi_uid
|
||
@rts rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This routine is used to get the SCSI Manager Number
|
||
; from the Supervisory Dispatcher at startup time.
|
||
;
|
||
; Inputs: None.
|
||
;
|
||
; Outputs: scsi_mgrnum = SCSI Manager Number
|
||
; All Registers = scrambled
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_scsimgr
|
||
get_scsimgr PROC
|
||
;
|
||
; Get userID.
|
||
;
|
||
lda #$0000 ; Supervisor Driver Number (Unknown at this time)
|
||
tax ; Supervisor Call Number ($0000)
|
||
ldy #$0002 ; Spervisor ID for SCSI Manager ($0002)
|
||
jsr |rout2_s_disp
|
||
stx |scsi_mgrnum ; Preserve SCSI Driver Number for later use.
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'zero_mem'
|
||
;
|
||
; This routine will fill a section of memory with
|
||
; $00s.
|
||
;
|
||
; Inputs: Acc = Buffer Size
|
||
; X = Low Byte of new RAM Address
|
||
; Y = High Byte of new RAM Address
|
||
;
|
||
; Outputs: scsi_zp0 = Long Pointer to new RAM
|
||
; Address
|
||
; Acc = Scrambled
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT zero_mem
|
||
zero_mem PROC
|
||
;
|
||
; Save the buffer size.
|
||
;
|
||
sta @buff_size
|
||
;
|
||
; Setup MOVE_INFO call for a
|
||
; non-incrementing source and an
|
||
; incrementing destination.
|
||
;
|
||
pushlong #null_buff ;Source
|
||
phy ;Destination High Word
|
||
phx ;Destination Low Word
|
||
;
|
||
; Restore buffer size. If = 0 then
|
||
; we are to do an entire bank or at
|
||
; least 64k bytes. This may cross
|
||
; banks.
|
||
;
|
||
lda @buff_size
|
||
beq @do_64k
|
||
pea $0000
|
||
pha
|
||
bra @move_type
|
||
|
||
@do_64k pea $0001
|
||
pea $0000
|
||
|
||
@move_type pea #move_scon_dinc
|
||
jsl move_info
|
||
|
||
@rts rts
|
||
;
|
||
; Data for this call
|
||
;
|
||
@buff_size dc.w null
|
||
null_buff dc.w null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This routine is used to request a section of RAM from
|
||
; the memory manager for use by the driver. This
|
||
; routine allocates space for as requested by the byte
|
||
; count in the Acc.
|
||
;
|
||
; Inputs: Acc = Number of bytes requested.
|
||
; 0 = 1 bank
|
||
;
|
||
; Y = Offset to where the Handle
|
||
; should be stored within
|
||
; the allocated structure.
|
||
;
|
||
; Outputs: X = Low Word of new RAM Address
|
||
; Y = High Word of new RAM Address
|
||
; scsi_zp0 = Long Pointer to new RAM
|
||
; Address
|
||
; Acc = Scrambled
|
||
;
|
||
; Errors: Not enough memory if carry set.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_space
|
||
get_space PROC
|
||
;
|
||
; Request Acc bytes of RAM from
|
||
; Memory Manager.
|
||
;
|
||
sty |hndl_offset
|
||
|
||
pushlong #00000000 ;Space for result handle
|
||
|
||
cmp $0000 ;Is it Null?
|
||
beq @null ;Yes. Request 1 bank
|
||
|
||
pushword #0000 ;Size in bytes of requested memory.
|
||
bra @stuff_a
|
||
|
||
@null pushword #0001 ;Request 1 bank
|
||
|
||
@stuff_a sta |buff_len
|
||
pha
|
||
|
||
pushword scsi_uid ;Our User ID
|
||
|
||
;Attributes of requested mem.
|
||
pea attrfixed++\
|
||
attrnospec++\
|
||
attrpage
|
||
|
||
pushlong #00000000 ;Location Pointer. Unused.
|
||
|
||
_newhandle
|
||
|
||
plx ; Get handle
|
||
ply
|
||
|
||
bcs @rts ; Exit if an error.
|
||
|
||
;
|
||
; Save Handle for later
|
||
;
|
||
phy
|
||
phx
|
||
;
|
||
; DEREF the Handle and get a
|
||
; pointer for the new RAM.
|
||
;
|
||
stx <scsi_zp0
|
||
sty <scsi_zp0+2
|
||
ldy #$0002
|
||
lda [scsi_zp0]
|
||
tax
|
||
lda [scsi_zp0],y
|
||
tay
|
||
;
|
||
; Stuff pointer for indirect access.
|
||
;
|
||
stx <scsi_zp0
|
||
sty <scsi_zp0+2
|
||
;
|
||
; Call routine to zero out the
|
||
; new memory
|
||
;
|
||
lda |buff_len
|
||
jsr zero_mem
|
||
;
|
||
; Stuff Handle in RAM. Low byte first
|
||
;
|
||
ldy |hndl_offset
|
||
pullword [scsi_zp0],y
|
||
iny
|
||
iny
|
||
pullword [scsi_zp0],y
|
||
;
|
||
; Restore X and Y to pointer status
|
||
;
|
||
ldx <scsi_zp0
|
||
ldy <scsi_zp0+2
|
||
;
|
||
; Clean Exit.
|
||
;
|
||
clc
|
||
@rts rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This routine is used to request a section of RAM from
|
||
; the memory manager for use by the driver. This
|
||
; routine allocates space for the get_devices call to
|
||
; the SCSI Manager.
|
||
;
|
||
; Inputs: None.
|
||
;
|
||
; Outputs: dvc_list = Long Pointer to device List
|
||
; next_dib = Long Pointer to First DIB
|
||
; first_dib = Long Pointer to the beginning
|
||
; of the RAM Allocated for the
|
||
; new DIBs.
|
||
; Acc = Scrambled
|
||
;
|
||
; Errors: Not enough memory if carry set.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_dvc_ram
|
||
get_dvc_ram PROC
|
||
;
|
||
; Request the maximum device list
|
||
; size bytes of RAM from GS/OS
|
||
; System Service calls.
|
||
;
|
||
lda #max_gdvc_buf+4 ; Allocate space for list.
|
||
ldy #$0000
|
||
|
||
ldx |direct_page ;If this is the first time, then
|
||
bne @use_ours
|
||
phx ;we don't want a DP setting of
|
||
;NULL
|
||
;
|
||
; Save away GS/OS Direct Page values
|
||
; until we have our own direct Page.
|
||
;
|
||
jsr save_dp
|
||
|
||
lda #max_gdvc_buf+4 ; Allocate space for list.
|
||
ldy #$0000
|
||
|
||
ldx |gsos_dpage
|
||
stx |direct_page
|
||
|
||
jsr |get_space
|
||
|
||
pla ;Restore our settings preserving X & Y
|
||
sta |direct_page
|
||
sta |exit_dpage
|
||
bra @over_use_ours
|
||
|
||
@use_ours jsr |get_space
|
||
;
|
||
; Store newly allocated buffer
|
||
; pointer into the parm list for
|
||
; the get devices call. Account
|
||
; for the first 4 bytes that
|
||
; contain the handle associated
|
||
; with this memory segment.
|
||
;
|
||
@over_use_ours bcs @rts_long
|
||
clc
|
||
txa
|
||
sta |dvc_ram
|
||
adc #$0004
|
||
sta |dvc_buff
|
||
sta <dvc_list
|
||
tya
|
||
sta |dvc_ram+2
|
||
adc #$0000
|
||
sta |dvc_buff+2
|
||
sta <dvc_list+2
|
||
;
|
||
; Setup Pointer to our parm list
|
||
; in GS/OS Direct Page.
|
||
;
|
||
ldx |gsos_dpage
|
||
lda #get_dev_lst
|
||
sta >smgr_pl_ptr,x
|
||
lda #^get_dev_lst
|
||
sta >smgr_pl_ptr+2,x
|
||
;
|
||
; Load registers with their
|
||
; required values.
|
||
;
|
||
lda |scsi_mgrnum
|
||
ldx #cmd_get_dvc
|
||
jsr |rout2_s_disp
|
||
@rts_long bcs @rts
|
||
;
|
||
; Restore our direct page Device List
|
||
;
|
||
lda |dvc_buff
|
||
sta <dvc_list
|
||
lda |dvc_buff+2
|
||
sta <dvc_list+2
|
||
;
|
||
; First word in [dvc_list}] contains
|
||
; the address of a 1 page area that
|
||
; we will be using for our direct
|
||
; page. Get it and move the
|
||
; 'dvc_list' pointer to our direct
|
||
; page area, but only if we have not
|
||
; yet done it.
|
||
;
|
||
lda |direct_page
|
||
bne @we_did_it ;It's already been done.
|
||
|
||
lda [dvc_list]
|
||
tax
|
||
lda <dvc_list
|
||
sta >dvc_list,x
|
||
lda <dvc_list+2
|
||
sta >dvc_list+2,x
|
||
txa
|
||
sta |direct_page
|
||
sta |exit_dpage
|
||
;
|
||
; Undocumented feature. Store the SCSI
|
||
; Managers Direct Page in the Default DIB
|
||
; for external Access.
|
||
;
|
||
clc
|
||
adc #$0100
|
||
sta >default_dib+dib.handle
|
||
;
|
||
; Set our Direct Page with the first
|
||
; 'x' Bytes equal to the GS/OS DP
|
||
; settings.
|
||
;
|
||
;
|
||
clc ; Calculate Source Address of GS/OS
|
||
tdc ; Direct Page that we want.
|
||
sta |gsos_dpage ; Preserving GS/OS DP for later use.
|
||
adc #dev_num
|
||
pea $0000
|
||
pha
|
||
;
|
||
clc ; Calculate Destination Address of
|
||
lda |direct_page ; our Direct Page that we want.
|
||
adc #dev_num
|
||
pea $0000
|
||
pha
|
||
|
||
pushlong #dib_ptr+4 ;Length of the move
|
||
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
;
|
||
; Restore the Direct Page that we
|
||
; borrowed until this was done.
|
||
;
|
||
jsr restore_dp
|
||
;
|
||
; Set our Direct Page.
|
||
;
|
||
lda |direct_page
|
||
tcd
|
||
;
|
||
; Check for zero Devices.
|
||
;
|
||
@we_did_it ldy #$0002
|
||
lda [dvc_list],y
|
||
beq @no_devices
|
||
;
|
||
; Ensure that device count is
|
||
; in range.
|
||
;
|
||
cmp #$0100+1 ;No more than 256 devices
|
||
blt @count_ok
|
||
lda #max_dvc_cnt ;Max Count
|
||
@count_ok sta |dvc_count
|
||
jsr |make_dib
|
||
stx <next_dib
|
||
stx <first_dib
|
||
sty <next_dib+2
|
||
sty <first_dib+2
|
||
|
||
lda #no_error
|
||
clc
|
||
;
|
||
; Restore the Direct Page that we
|
||
; borrowed until this was done.
|
||
;
|
||
@rts pha
|
||
php
|
||
jsr restore_dp
|
||
plp
|
||
pla
|
||
rts
|
||
;
|
||
; No Devices Error.
|
||
;
|
||
; Restore the Direct Page that we
|
||
; borrowed until this was done.
|
||
;
|
||
@no_devices jsr restore_dp
|
||
lda #drvr_no_dev
|
||
sec
|
||
rts
|
||
|
||
get_dev_lst dc.w scsi_dtype
|
||
dc.l notify_me
|
||
dvc_buff dc.l null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This routine is the inverse of the above routine.
|
||
; It calls the memory manager to deallocate the space
|
||
; we used to request the device list from the SCSI
|
||
; manager.
|
||
;
|
||
; Inputs: X = Low byte of Buffer pointer
|
||
; Y = High byte of Buffer pointer
|
||
;
|
||
; Outputs: All Regs = Scrambled
|
||
;
|
||
; Errors: Not enough memory if carry set.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT fre_dvc_ram
|
||
fre_dvc_ram PROC
|
||
;
|
||
; Remove the device list from
|
||
; active use and free the mem.
|
||
;
|
||
; Stuff pointer for indirect access.
|
||
;
|
||
lda |dvc_ram
|
||
sta <scsi_zp0
|
||
lda |dvc_ram+2
|
||
sta <scsi_zp0+2
|
||
|
||
ldy #$0002 ;High byte first on stack
|
||
pushword [scsi_zp0],y
|
||
pushword [scsi_zp0]
|
||
|
||
_disposehandle
|
||
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____DIB_Mem_Mgr_____
|
||
;*******************************************************
|
||
;
|
||
; This routine is used to request a section of RAM from
|
||
; the memory manager for use by the driver. This
|
||
; routine allocates space for 1 DIB.
|
||
;
|
||
; Inputs: Acc = $00xx = DIB Count.
|
||
; Null = $0100
|
||
;
|
||
; Outputs: X = Low Byte of new RAM Address
|
||
; Y = High Byte of new RAM Address
|
||
; scsi_zp0 = Long Pointer to new RAM
|
||
; Address
|
||
; Acc = Scrambled
|
||
;
|
||
; Errors: Not enough memory if carry set.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT make_dib
|
||
make_dib PROC
|
||
;
|
||
; Request $100 bytes of RAM for
|
||
; each DIB from GS/OS System
|
||
; Service calls.
|
||
;
|
||
and #$00ff
|
||
sta |ram_page_cnt
|
||
xba ;Cheap multiply by $0100
|
||
ldy #dib.handle ;Offset to where we want the handle
|
||
jsr |get_space ;Allocate space for DIBs.
|
||
bcc @rts
|
||
stz |ram_page_cnt
|
||
@rts rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This routine is called via a 'jsl' and returns the
|
||
; page number of the caller in X and Y with X being
|
||
; the low byte. This is intended for use by the
|
||
; completion routines in the DIB as a tool to find
|
||
; the DIB's starting location in memory
|
||
;
|
||
; Inputs: None.
|
||
;
|
||
; Outputs: X = Low byte of callers page
|
||
; Y = High byte of callers page
|
||
; Acc = Scrambled
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT g_dib_ptr
|
||
g_dib_ptr PROC
|
||
;
|
||
; Get the callers return
|
||
; address from the stack,
|
||
; strip down to a page number,
|
||
; transfer to X and Y and
|
||
; return to caller via an 'rtl'
|
||
;
|
||
lda <1,s
|
||
sec
|
||
sbc #dib.complet+3-dib.linkptr
|
||
tax
|
||
lda <3,s
|
||
and #$00ff
|
||
tay
|
||
rtl
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'ADD_DIB_RAM'
|
||
;
|
||
; This routine searches for the last DIB for this
|
||
; driver, allocates enough ram for 4 additional DIBs
|
||
; and links them in.
|
||
;
|
||
; Inputs: dib_ptr = Last DIB in Device link
|
||
; add_dib_here = Where the new DIB is to be built
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if not enough memory
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT add_dib_ram
|
||
add_dib_ram PROC
|
||
;
|
||
; 'ADD_DIB_HERE' Pointer now points
|
||
; to the last DIB currently allocated
|
||
; and preserve location of last DIB.
|
||
;
|
||
lda <add_dib_here
|
||
sta <last_dib
|
||
pha ;Save and later restore
|
||
lda <add_dib_here+2
|
||
sta <last_dib+2
|
||
pha ;Save and later restore
|
||
;
|
||
; Get some RAM for a few more DIBs..
|
||
;
|
||
lda #dibs_2_make
|
||
jsr make_dib
|
||
bcc @over_0
|
||
;
|
||
; Got an Error. Fix the Stack and Exit.
|
||
;
|
||
tax
|
||
|
||
pla ;Saved, and now restore
|
||
sta <last_dib+2
|
||
pla ;Saved, and now restore
|
||
sta <last_dib
|
||
|
||
txa
|
||
|
||
rts
|
||
;
|
||
; Do First link
|
||
;
|
||
@over_0 sty <first_dib+2
|
||
stx <first_dib
|
||
;
|
||
; Dibicise first new DIB in the new
|
||
; Memory.
|
||
;
|
||
sec ;Don't do the links.
|
||
jsr dibicise_new_ram
|
||
;
|
||
; Do the Head and Forward links also.
|
||
;
|
||
lda #null
|
||
ldy #dib.headlnk
|
||
sta [first_dib],y
|
||
|
||
ldy #dib.fdvclnk
|
||
sta [first_dib],y
|
||
|
||
ldy #dib.unitnum ;Don't forget the unit number
|
||
sta [first_dib],y
|
||
;
|
||
; Finalise the new DIB Structure.
|
||
;
|
||
dec |main_caller
|
||
;********
|
||
;******** 6/12/89 Begin fix MSG
|
||
;******** rebuild flag being destroyed.
|
||
;********
|
||
lda |rebuild ;The state of this flag must be preserved.
|
||
pha
|
||
stz |rebuild ;Set to zero. (Full Rebuild)
|
||
|
||
jsr set_link_ptrs ;Now we do the links.
|
||
|
||
pla
|
||
sta |rebuild ;Restore the callers state for this flag.
|
||
|
||
; stz |rebuild ;Set to zero. (Full Rebuild)
|
||
|
||
; jsr set_link_ptrs ;Now we do the links.
|
||
;********
|
||
;******** 6/12/89 End fix MSG
|
||
;******** rebuild flag being destroyed.
|
||
;********
|
||
;
|
||
; Finish the last three links. They
|
||
; live in the new memory segment.
|
||
;
|
||
lda #dibs_2_make-1
|
||
sta @loop_cnt
|
||
|
||
@link_loop clc
|
||
|
||
lda <next_dib
|
||
sta <last_dib
|
||
adc #dib_size
|
||
sta <next_dib
|
||
|
||
lda <next_dib+2
|
||
sta <last_dib+2
|
||
adc #^dib_size
|
||
sta <next_dib+2
|
||
|
||
dec |main_caller
|
||
;********
|
||
;******** 6/12/89 Begin fix MSG
|
||
;******** rebuild flag being destroyed.
|
||
;********
|
||
lda |rebuild ;The state of this flag must be preserved.
|
||
pha
|
||
stz |rebuild ;Set to zero. (Full Rebuild)
|
||
|
||
jsr dibicise_new_dib
|
||
|
||
pla
|
||
sta |rebuild ;Restore the callers state for this flag.
|
||
|
||
; stz |rebuild
|
||
|
||
; jsr dibicise_new_dib
|
||
;********
|
||
;******** 6/12/89 End fix MSG
|
||
;******** rebuild flag being destroyed.
|
||
;********
|
||
dec @loop_cnt
|
||
bne @link_loop
|
||
;
|
||
; Clean Exit
|
||
;
|
||
; Reinitialise mem_dib_cnt to zero.
|
||
;
|
||
lda #null
|
||
ldy #dib.mem_dib_cnt
|
||
sta [first_dib],y
|
||
;
|
||
; Wipe out last link pointer to no where.
|
||
;
|
||
sta [next_dib]
|
||
ldy #dib.linkptr+2
|
||
sta [next_dib],y
|
||
|
||
pla ;Saved, and now restore
|
||
sta <last_dib+2
|
||
pla ;Saved, and now restore
|
||
sta <last_dib
|
||
|
||
clc
|
||
rts
|
||
;
|
||
; Data Area.
|
||
;
|
||
@loop_cnt dc.w null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; FIND_EMPTY
|
||
;
|
||
; This routine serches forward from the current DIB
|
||
; looking for an empty. If it exits with the carry
|
||
; clear, then one has been found. If the carry is
|
||
; set, then it points to the last DIB in the linked
|
||
; list and found non empty.
|
||
;
|
||
; Inputs: <DIB_PTR = Last DIB Location
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <ADD_DIB_HERE = Empty DIB if found
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if no empties were found
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT find_empty
|
||
find_empty PROC
|
||
;
|
||
; Are we at the last DIB? Set beginning
|
||
; pointer for check.
|
||
;
|
||
lda <dib_ptr
|
||
sta <last_dib
|
||
sta <add_dib_here
|
||
lda <dib_ptr+2
|
||
sta <last_dib+2
|
||
sta <add_dib_here+2
|
||
;
|
||
; Are we at the last DIB? (LOOP)
|
||
;
|
||
@fnd_empty_lup ldy #$0002
|
||
lda [add_dib_here]
|
||
tax
|
||
|
||
lda [add_dib_here],y;Should never be in Bank $00
|
||
bne @advance_ptr ;No.
|
||
|
||
@sec sec ;Yes. Exit
|
||
rts
|
||
;
|
||
; Advance Ptr to next DIB.
|
||
;
|
||
@advance_ptr sta <add_dib_here+2
|
||
stx <add_dib_here
|
||
;
|
||
; Is it Free?
|
||
;
|
||
; Must have a zero Head Link Ptr,
|
||
; Forward Device Link Ptr, and
|
||
; DIB Device Number to be considered
|
||
; free.
|
||
;
|
||
ldy #dib.devnum
|
||
lda [add_dib_here],y
|
||
bne @fnd_empty_lup ;No. Check next one.
|
||
|
||
ldy #dib.headlnk
|
||
lda [add_dib_here],y
|
||
bne @fnd_empty_lup ;No. Check next one.
|
||
|
||
ldy #dib.fdvclnk
|
||
lda [add_dib_here],y
|
||
bne @fnd_empty_lup ;No. Check next one.
|
||
;
|
||
; Make the DIB Device Number non-zero
|
||
; to prvent it from being selected
|
||
; again before it is started up by
|
||
; the operating system.
|
||
;
|
||
ldy #dib.devnum
|
||
lda [add_dib_here],y
|
||
inc a
|
||
sta [add_dib_here],y
|
||
|
||
clc ;Yes. Exit
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'chk_ram'
|
||
;
|
||
; This routine checks to see if we have any room left
|
||
; in this memory segment for another DIB. If not then
|
||
; the memory manager is called and the new RAM is
|
||
; dibicised.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Carry = 1
|
||
; Acc = Error
|
||
; Carry = 0
|
||
; Acc = ram_page_cnt
|
||
; = 0 no more devices
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
;
|
||
; Start of the code segment for this.
|
||
;
|
||
EXPORT chk_ram
|
||
chk_ram PROC
|
||
;
|
||
; All done with the DIB Update now
|
||
; do we have any more RAM left to
|
||
; build further DIBs?
|
||
;
|
||
dec |ram_page_cnt
|
||
bne @adv_ptrs ;Yes we do. Continue on.
|
||
|
||
;
|
||
; Account for 'part_cnt' being equal
|
||
; to the Actual Partition Count - 1
|
||
;
|
||
sec
|
||
; clc ;Bug Fix 4/3/89
|
||
|
||
lda |dvc_count ;No we don't. Get the remaining device
|
||
adc |part_cnt ;count and add the remaining Part count
|
||
; dec a ;Subtract our current working device
|
||
; dec a ;Subtract our current working DIB
|
||
beq @exit ;Are we done? Yes.
|
||
bmi @exit ;Yes.
|
||
cmp #$00ff+1 ;No. Bound check the result and
|
||
blt @call_make_dib
|
||
|
||
@set_max lda #$00ff ;Set to max if greater.
|
||
@call_make_dib jsr make_dib ;Call routine to make the DIB RAM
|
||
bcc @update_new ;available. ERROR?
|
||
cmp #drvr_no_dev ;Yes. Then Exit
|
||
bne @sec
|
||
clc
|
||
rts
|
||
@sec sec
|
||
rts
|
||
;
|
||
; We had room in the current RAM
|
||
; Space so we will advance all the
|
||
; pointers to their next values
|
||
; within that space.
|
||
;
|
||
@adv_ptrs clc
|
||
lda <next_dib
|
||
sta <last_dib
|
||
adc #dib_size
|
||
sta <next_dib
|
||
lda <next_dib+2
|
||
sta <last_dib+2
|
||
adc #^dib_size
|
||
sta <next_dib+2
|
||
jsr dibicise_new_dib
|
||
bra @exit
|
||
;
|
||
; We have a new memory segment so
|
||
; we need to account for this when
|
||
; we advance our pointers.
|
||
;
|
||
@update_new stx <first_dib
|
||
sty <first_dib+2
|
||
lda <next_dib
|
||
sta <last_dib
|
||
lda <next_dib+2
|
||
sta <last_dib+2
|
||
clc ;Do Links Also
|
||
jsr dibicise_new_ram
|
||
;
|
||
; Clean exit.
|
||
;
|
||
@exit lda |ram_page_cnt
|
||
clc
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____DIB_Building____
|
||
;*******************************************************
|
||
;
|
||
; REBLD_DIBS
|
||
;
|
||
; It is the function of this routine to blindly
|
||
; rebuild the DIBs for the physical device attached to
|
||
; the current DIB. If that device is non-partitioned,
|
||
; then only one DIB will be built, and a DISK SWITCHED
|
||
; will be issued. If there are more than one device,
|
||
; as in partitioned media, then all the DIBs for the
|
||
; partitions will be re-built. This is treated as if
|
||
; the device just came online for the first time. If
|
||
; the new device has fewer partitions than there are
|
||
; DIBs that are already allocated, then the left over
|
||
; will be marked as being offline. If, on the other
|
||
; hand, there are more partitions than DIBs, then new
|
||
; ones will be allocated and built. These will then be
|
||
; permanantly linked to that physical device.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if operation could not be
|
||
; completed. Out of memory for example.
|
||
;
|
||
;*******************************************************
|
||
;
|
||
; Start of the code segment for this.
|
||
;
|
||
EXPORT rebld_dibs
|
||
rebld_dibs PROC
|
||
;
|
||
; Clear Linked Device Flag. This will
|
||
; account for the situation where a
|
||
; partitioned disk has been reduced to
|
||
; a single volume.
|
||
;
|
||
stz @linked
|
||
;
|
||
; Zero the count of new devices to be
|
||
; started.
|
||
;
|
||
stz |new_dib_cnt
|
||
;
|
||
; Point to first DIB in link if any.
|
||
; If it is zero, then we are already
|
||
; there.
|
||
;
|
||
ldy #dib.headptr+2
|
||
lda [dib_ptr],y
|
||
ldy #dib.headptr
|
||
ora [dib_ptr],y
|
||
beq @over
|
||
;
|
||
; It's non-zero. Set up DIB_PTR
|
||
;
|
||
lda [dib_ptr],y
|
||
tax
|
||
ldy #dib.headptr+2
|
||
lda [dib_ptr],y
|
||
sta <dib_ptr+2
|
||
stx <dib_ptr
|
||
;
|
||
; Set Temp Pointer to first DIB in the link.
|
||
;
|
||
@over lda <dib_ptr
|
||
sta <scsi_zp6
|
||
lda <dib_ptr+2
|
||
sta <scsi_zp6+2
|
||
;
|
||
; Mark each DIB in the link as offline
|
||
; and switched.
|
||
;
|
||
@loop ldy #dib.dvcflag
|
||
lda [scsi_zp6],y
|
||
and #(dvc_online++\
|
||
pdos_part)--\
|
||
$ffff
|
||
ora #dvc_switch++\
|
||
dvc_hardofl
|
||
sta [scsi_zp6],y
|
||
;
|
||
; Mark each DIB in the link as Unlinked.
|
||
;
|
||
ldy #dib.dvcchar
|
||
lda [scsi_zp6],y
|
||
and #linked_dvc--\
|
||
$ffff
|
||
sta [scsi_zp6],y
|
||
;
|
||
; Zero Partition Offset for each DIB
|
||
;
|
||
lda #null
|
||
ldy #dib.start_blk
|
||
sta [scsi_zp6],y
|
||
ldy #dib.start_blk+2
|
||
sta [scsi_zp6],y
|
||
;
|
||
; It's non-zero. Set up next DIB_PTR
|
||
;
|
||
clc
|
||
ldy #dib.fdvcptr
|
||
lda [scsi_zp6],y
|
||
tax
|
||
beq @null
|
||
|
||
sec
|
||
|
||
@null ldy #dib.fdvcptr+2
|
||
lda [scsi_zp6],y
|
||
bne @doit
|
||
bcc @over_0
|
||
|
||
@doit sta <scsi_zp6+2
|
||
stx <scsi_zp6
|
||
|
||
bra @loop
|
||
;
|
||
; Initialize a few values.
|
||
;
|
||
@over_0 lda #$ffff ;The following values will be incrimented
|
||
sta |first_time ;with zero indicating special action.
|
||
sta |rebuild ;This is set to $ffff so that it will only
|
||
sta |only_one ;occur on the first pass through.
|
||
|
||
stz |part_cnt
|
||
stz |rpm_blk_num
|
||
stz |new_dib
|
||
;
|
||
; MAIN LOOP OF CODE SEGMENT.
|
||
;
|
||
@main_loop jsr read_pm_blk
|
||
bcc @with_data ;This device is with data
|
||
lda auto_sense_data+\ ;Is it an audio disk?
|
||
rqst_sens.addnl_sens_code
|
||
and #$00fe ;Checking for $84, $64, or $63
|
||
cmp #$0064 ;This cover $63, $64
|
||
beq @single
|
||
cmp #$0084
|
||
beq @single
|
||
sec
|
||
rts ;There was an error!
|
||
;
|
||
; Valid Partition Map?
|
||
;
|
||
@with_data jsr chk_map
|
||
bcs @done
|
||
bne @main
|
||
;
|
||
; We have a vaild Partition Map so
|
||
; we need to make an entry for each
|
||
; partition other than those with
|
||
; the partition types of 'MAP',
|
||
; 'SCRATCH', and 'FREE'. All others
|
||
; will be considered valid. We also
|
||
; only accept up to 'max_partitions'
|
||
; partitions per disk.
|
||
;
|
||
; How many partitions are there?
|
||
;
|
||
lda |pm.MapBlkCnt\
|
||
+internal_buff
|
||
bne @force_max
|
||
lda |pm.MapBlkCnt+2\
|
||
+internal_buff
|
||
xba ;Value is High --> Low
|
||
cmp #max_partitions+1
|
||
blt @cnt_ok
|
||
@force_max lda #max_partitions
|
||
@cnt_ok sta |part_cnt
|
||
|
||
cmp #$0002+1
|
||
blt @non_linked
|
||
dec @linked
|
||
@non_linked dec |part_cnt
|
||
bpl @main
|
||
;
|
||
; No valid entry. Set as if no
|
||
; partitions.
|
||
;
|
||
@single jsr no_partition ;Marks DIB as online and switched also.
|
||
jsr trash_volume ;Trash the volume if caller wishes.
|
||
;See |trash_it flag in trash_volume
|
||
lda #null
|
||
clc
|
||
rts
|
||
;
|
||
; Check validity of partiton map.
|
||
;
|
||
@main jsr check_map_entry
|
||
bcc @chk_pdos
|
||
;
|
||
; It was undefined or unusable
|
||
;
|
||
; Is the Pointer good?
|
||
;
|
||
; Is it a cold DIB?
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [add_dib_here],y
|
||
and #cold_dib
|
||
beq @over_cold ;No. Skip clear code.
|
||
;
|
||
; Mark DIB to the Default.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda #wait_mode++\ ; Wait Mode is default
|
||
cold_dib ; and they start cold.
|
||
sta [add_dib_here],y
|
||
;
|
||
; Must set Head Link Ptr, Forward
|
||
; Device Link Ptr, and DIB Device
|
||
; Number to Null.
|
||
;
|
||
lda #null
|
||
|
||
ldy #dib.devnum
|
||
sta [add_dib_here],y
|
||
|
||
ldy #dib.headlnk
|
||
sta [add_dib_here],y
|
||
|
||
ldy #dib.fdvclnk
|
||
sta [add_dib_here],y
|
||
;
|
||
; And skip it.
|
||
; Is there more to do?
|
||
;
|
||
@over_cold dec |part_cnt
|
||
bmi @do_dpi ;No!
|
||
jmp @main_loop ;Yes!
|
||
;
|
||
; Check to see if the post driver install
|
||
; list contains any entries.
|
||
;
|
||
@do_dpi jsr do_post_install
|
||
;
|
||
; Check the only one flag. If true
|
||
; then unlink it.
|
||
;
|
||
lda |only_one
|
||
bne @done
|
||
|
||
ldy #dib.dvcchar
|
||
lda [rebuild_zp],y
|
||
and #linked_dvc--\
|
||
$ffff
|
||
sta [rebuild_zp],y
|
||
;
|
||
; Clean exit.
|
||
;
|
||
@done
|
||
|
||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
|
||
IF scsi_dtype = mcd_40\
|
||
OR scsi_dtype = direct_acc THEN
|
||
|
||
jsr mode_sense
|
||
|
||
lda |internal_buff+1
|
||
bpl @write_enable
|
||
|
||
@write_protect ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
and #write_allow--\
|
||
$ffff
|
||
bra @wp_chk
|
||
|
||
@write_enable ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
ora #write_allow
|
||
|
||
@wp_chk sta [dib_ptr],y
|
||
lda #$0000
|
||
|
||
ENDIF
|
||
|
||
;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||
|
||
clc
|
||
@rts rts
|
||
;
|
||
; Check the Overflow bit. If it is set,
|
||
; then this is a ProDOS Partition and we
|
||
; need to set the correct bit in the DIB.
|
||
;
|
||
@chk_pdos bvc @over_1
|
||
;
|
||
; Set the ProDOS Bit.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
ora #pdos_part
|
||
sta [dib_ptr],y
|
||
;
|
||
; Issue call to fix unit 1. This will
|
||
; guarantee that the first unit is also
|
||
; the first ProDOS Partition on the disk.
|
||
;
|
||
jsr fix_unit_1
|
||
;
|
||
; Get the Block Count for this
|
||
; Partition and store it in the
|
||
; DIB. The count as it exists
|
||
; in the partition data is stored
|
||
; High byte to Low byte. We will
|
||
; need to alter this to Low --> High
|
||
; format.
|
||
;
|
||
@over_1 ldy #dib.blkcnt
|
||
lda |pm.PartBlkCnt+2\
|
||
+internal_buff
|
||
xba
|
||
sta [dib_ptr],y
|
||
ldy #dib.blkcnt+2
|
||
lda |pm.PartBlkCnt\
|
||
+internal_buff
|
||
xba
|
||
sta [dib_ptr],y
|
||
;
|
||
; Now we need to get the starting
|
||
; location for this partition. This
|
||
; will be added to the requested
|
||
; block to generate a real block
|
||
; address. Also in High --> Low format.
|
||
;
|
||
ldy #dib.start_blk+2
|
||
lda |pm.PyPartStart+2\
|
||
+internal_buff
|
||
sta [dib_ptr],y
|
||
ldy #dib.start_blk
|
||
lda |pm.PyPartStart\
|
||
+internal_buff
|
||
sta [dib_ptr],y
|
||
;
|
||
; Get Location of this partition on disk.
|
||
;
|
||
ldy #dib.part_blk
|
||
lda |rpm_blk_num
|
||
sta [dib_ptr],y
|
||
;
|
||
; Mark DIB as online and switched.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
and #dvc_hardofl--\
|
||
$ffff
|
||
ora #dvc_switch++\
|
||
dvc_online
|
||
sta [dib_ptr],y
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
;
|
||
; Set the Write Allow/Read Allow
|
||
; Mask byte to allow all bits to pass.
|
||
;
|
||
; This is used to filter or strip out the
|
||
; Write Enable bit in the case where the
|
||
; DIB Status says that the partition is
|
||
; write enabled but the disk is physically
|
||
; write protected. This can happen with a
|
||
; Partitioned Syquest Drive.
|
||
;
|
||
lda #$ffff
|
||
sta @mask_flag
|
||
;
|
||
; Is the device Removable?
|
||
;
|
||
ldy #dib.dvcchar
|
||
|
||
lda [dib_ptr],y
|
||
and #removable
|
||
beq @non_remove ;No.
|
||
;
|
||
; Issue the MODE SENSE Call to see if
|
||
; Write Protected.
|
||
;
|
||
jsr mode_sense2 ;Issue call to use Sense Buffer
|
||
bcs @non_remove
|
||
;
|
||
; Check the Write Protected Bit.
|
||
;
|
||
lda |sense_data+\
|
||
mode.w_protect-1 ;But bit in Hi Byte
|
||
bpl @non_remove
|
||
;
|
||
; Set the Write Allow/Read Allow
|
||
; Mask byte to filter the Write Allow out.
|
||
;
|
||
lda #write_allow--\
|
||
$ffff
|
||
sta @mask_flag
|
||
;
|
||
; Set the Characteristics to Match the
|
||
; Read and Write Enables in the Partition
|
||
; Status Field.
|
||
;
|
||
@non_remove lda |pm.PartStatus+2\
|
||
+internal_buff
|
||
xba
|
||
and #vconf_wr_enable++\
|
||
vconf_rd_enable
|
||
asl a
|
||
sta @temp
|
||
ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
and #write_allow++\
|
||
read_allow--\
|
||
$ffff
|
||
ora @temp
|
||
and @mask_flag
|
||
sta [dib_ptr],y
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Mark DIB as Linked.
|
||
;
|
||
lda @linked
|
||
bpl @skip_link
|
||
ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
ora #linked_dvc
|
||
sta [dib_ptr],y
|
||
;
|
||
; Inc the ONLY_ONE Flag. If it is
|
||
; null then save the dib_ptr. On
|
||
; exit we will check this flag and
|
||
; if = 0 we will use this pointer
|
||
; to clear the linked flag.
|
||
;
|
||
inc |only_one
|
||
bne @skip_link
|
||
|
||
lda <dib_ptr
|
||
sta <rebuild_zp
|
||
lda <dib_ptr+2
|
||
sta <rebuild_zp+2
|
||
;
|
||
; Wipe out block 2 of partition or
|
||
; volume
|
||
;
|
||
@skip_link jsr trash_volume
|
||
;
|
||
; Is this a new dib?
|
||
;
|
||
bit |new_dib
|
||
bpl @set_dsw ;No. Set disk switch
|
||
|
||
ldx <dib_ptr
|
||
ldy <dib_ptr+2
|
||
jsr add_dib_ptr ;Yes. Add to the list for post driver
|
||
bra @over_dsw ; install.
|
||
;
|
||
; Set the DISK SWITCHED
|
||
;
|
||
@set_dsw
|
||
; jsr set_disk_sw
|
||
;
|
||
; Is there more to do?
|
||
;
|
||
@over_dsw stz |new_dib
|
||
dec |part_cnt
|
||
bpl @over_do_dpi ;Yes!
|
||
jmp @do_dpi ;No!
|
||
;
|
||
; All done with the DIB Update now
|
||
; do we have any more DIBs, for this
|
||
; linked device?
|
||
;
|
||
@over_do_dpi ldy #dib.fdvcptr
|
||
lda [dib_ptr],y
|
||
tax
|
||
|
||
ldy #dib.fdvcptr+2
|
||
ora [dib_ptr],y
|
||
beq @over_2
|
||
lda [dib_ptr],y
|
||
|
||
sta <dib_ptr+2
|
||
stx <dib_ptr
|
||
;
|
||
; Do the next one.
|
||
;
|
||
@jmp_main jmp @main_loop
|
||
;
|
||
; It's zero. Need to add DIBs
|
||
;
|
||
; Is there an empty DIB some where?
|
||
;
|
||
@over_2 jsr find_empty
|
||
bcc @found_empty
|
||
;
|
||
; Get room for some more DIBs.
|
||
;
|
||
jsr add_dib_ram
|
||
bcc @over_2
|
||
|
||
|
||
rts
|
||
;
|
||
; We need to set some pointers for
|
||
; the routines that we will be
|
||
; calling. These pointers are similar
|
||
; to those used in the startup code
|
||
;
|
||
; 1st. Set the pointer to the next
|
||
; DIB to be build.
|
||
;
|
||
@found_empty lda <add_dib_here
|
||
sta <dib_ptr
|
||
sta <next_dib
|
||
lda <add_dib_here+2
|
||
sta <dib_ptr+2
|
||
sta <next_dib+2
|
||
;
|
||
; Preserve the Link Pointer. Otherwise
|
||
; it will be destroyed by the dibicise
|
||
; routine.
|
||
;
|
||
ldy #dib.linkptr+2
|
||
lda [next_dib]
|
||
pha
|
||
lda [next_dib],y
|
||
pha
|
||
;
|
||
; Preserve the Handle for this RAM Segment.
|
||
; Otherwise it will be destroyed by the
|
||
; dibicise routine.
|
||
;
|
||
ldy #dib.handle+2
|
||
lda [next_dib],y
|
||
pha
|
||
ldy #dib.handle
|
||
lda [next_dib],y
|
||
pha
|
||
;
|
||
; Preserve the current Device Flags.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [next_dib],y
|
||
pha
|
||
;
|
||
; Set the 'first_dib' pointer to the
|
||
; first dib in the same memory segment
|
||
; from the memory manager as the one
|
||
; that contains the space to be used
|
||
; for this new dib. first we get the
|
||
; handle.
|
||
;
|
||
ldy #dib.handle
|
||
lda [next_dib],y
|
||
sta <first_dib
|
||
|
||
ldy #dib.handle+2
|
||
lda [next_dib],y
|
||
sta <first_dib+2
|
||
;
|
||
; then we deref the handle.
|
||
;
|
||
ldy #$0002
|
||
lda [first_dib]
|
||
tax
|
||
lda [first_dib],y
|
||
sta <first_dib+2
|
||
stx <first_dib
|
||
;
|
||
; Tell the dibicize routine that this
|
||
; is not from the startup code. This
|
||
; also forces the descriptive names
|
||
; minor id to be changed leaving the
|
||
; major or device portion as it is.
|
||
;
|
||
dec |main_caller
|
||
;
|
||
; Dibicise the new dib.
|
||
;
|
||
jsr dibicise_new_dib
|
||
;
|
||
; Restore the current Device Flags.
|
||
;
|
||
pla
|
||
ldy #dib.dvcflag
|
||
sta [next_dib],y
|
||
;
|
||
; Restore the Handle for this RAM.
|
||
; Otherwise it is destroyed by the
|
||
; dibicise routine.
|
||
;
|
||
pla
|
||
ldy #dib.handle
|
||
sta [next_dib],y
|
||
pla
|
||
ldy #dib.handle+2
|
||
sta [next_dib],y
|
||
;
|
||
; Restore the Link Pointer. Otherwise
|
||
; it is destroyed by the dibicise
|
||
; routine.
|
||
;
|
||
pla
|
||
ldy #dib.linkptr+2
|
||
sta [next_dib],y
|
||
pla
|
||
sta [next_dib]
|
||
;
|
||
; Restore the DIB Extension Pointer.
|
||
; Otherwise it is destroyed by the
|
||
; dibicise routine.
|
||
;
|
||
clc ;we are going to add
|
||
lda <next_dib ;get low word of this dib
|
||
|
||
adc #dib.start_blk ;adc offset to ext dib ptr
|
||
ldy #dib.ext_ptr ;get offset to where this goes
|
||
sta [next_dib],y ;and store low word of ptr
|
||
|
||
lda <next_dib+2 ;get low word of this dib
|
||
adc #^dib.start_blk ;adc high offset to ext ptr
|
||
ldy #dib.ext_ptr+2 ;get offset to where this goes
|
||
sta [next_dib],y ;and store the high word ptr
|
||
;
|
||
; Rev the unit number to be unique
|
||
;
|
||
ldy #dib.unitnum
|
||
lda [next_dib],y
|
||
tax
|
||
and #max_p_mask
|
||
cmp #max_p_mask
|
||
beq @all_done
|
||
|
||
txa
|
||
clc
|
||
adc #p_mask_adder
|
||
sta [next_dib],y
|
||
;
|
||
; This flag indicates that this is a
|
||
; new dib and that the routine that
|
||
; finalizes this dib will have to
|
||
; issue a post driver install call.
|
||
;
|
||
dec |new_dib
|
||
;
|
||
; Go back to the main loop where this
|
||
; dib will be finalized and installed.
|
||
;
|
||
jmp @main_loop
|
||
;
|
||
; Clean Exit
|
||
;
|
||
@all_done clc
|
||
rts
|
||
;
|
||
; Misc Data for this sub-routine
|
||
;
|
||
@linked dc.w null
|
||
@part_num dc.w null
|
||
@vPart_cnt dc.w null
|
||
@temp dc.w null
|
||
@mask_flag dc.w null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'do_part_dib'
|
||
;
|
||
; This routine issues a READ call to the device and
|
||
; then uses the data returned to check for any
|
||
; partitions on the media. If partitions do exist, it
|
||
; then creates the needed dibs from those that have
|
||
; been allocated but unused, or if needed will create
|
||
; a new memory segment and continue on.
|
||
;
|
||
; Inputs: <next_dib = Next DIB start (LONG)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <next_dib = last DIB Built (LONG)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
;
|
||
; Start of the code segment for this.
|
||
;
|
||
EXPORT do_part_dib
|
||
do_part_dib PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; MAIN LOOP OF CODE SEGMENT.
|
||
;
|
||
@main_loop jsr read_pm_blk
|
||
bcc @chk_map ;Was there an error?
|
||
|
||
jsr no_partition ;
|
||
bra @done
|
||
; Valid Partition Map?
|
||
;
|
||
@chk_map jsr chk_map
|
||
bcs @done
|
||
bne @main
|
||
;
|
||
; We have a vaild Partition Map so
|
||
; we need to make an entry for each
|
||
; partition other than those with
|
||
; the partition types of 'MAP',
|
||
; 'SCRATCH', and 'FREE'. All others
|
||
; will be considered valid. We also
|
||
; only accept up to 'max_partitions'
|
||
; partitions per disk.
|
||
;
|
||
; How many partitions are there?
|
||
;
|
||
lda |pm.MapBlkCnt\
|
||
+internal_buff
|
||
bne @force_max
|
||
lda |pm.MapBlkCnt+2\
|
||
+internal_buff
|
||
xba ;Value is High --> Low
|
||
cmp #max_partitions+1
|
||
blt @cnt_ok
|
||
@force_max lda #max_partitions
|
||
@cnt_ok sta |part_cnt
|
||
|
||
dec |part_cnt
|
||
bpl @main
|
||
;
|
||
; No valid entry. Set as if no
|
||
; partitions.
|
||
;
|
||
jsr no_partition
|
||
clc
|
||
rts
|
||
;
|
||
; Check validity of partiton map.
|
||
;
|
||
@main jsr check_map_entry
|
||
bcc @chk_pdos
|
||
;
|
||
; It was undefined or unusable
|
||
; Mark DIB to the Default.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda #wait_mode++\ ; Wait Mode is default
|
||
cold_dib ; and they start cold.
|
||
sta [next_dib],y
|
||
;
|
||
; Must set Head Link Ptr, Forward
|
||
; Device Link Ptr, and DIB Device
|
||
; Number to Null.
|
||
;
|
||
lda #null
|
||
|
||
ldy #dib.devnum
|
||
sta [next_dib],y
|
||
|
||
ldy #dib.headlnk
|
||
sta [next_dib],y
|
||
|
||
ldy #dib.fdvclnk
|
||
sta [next_dib],y
|
||
;
|
||
; And skip it.
|
||
; Is there more to do?
|
||
;
|
||
dec |part_cnt
|
||
bpl @main_loop
|
||
;
|
||
; Clean exit.
|
||
;
|
||
@done clc
|
||
@rts rts
|
||
;
|
||
; Check the Overflow bit. If it is set,
|
||
; then this is a ProDOS Partition and we
|
||
; need to set the correct bit in the DIB.
|
||
;
|
||
@chk_pdos bvc @over
|
||
;
|
||
; Set the ProDOS Bit.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [next_dib],y
|
||
ora #pdos_part
|
||
sta [next_dib],y
|
||
;
|
||
; Issue call to fix unit 1. This will
|
||
; guarantee that the first unit is also
|
||
; the first ProDOS Partition on the disk.
|
||
;
|
||
jsr fix_unit_1
|
||
;
|
||
; Get the Block Count for this
|
||
; Partition and store it in the
|
||
; DIB. The count as it exists
|
||
; in the partition data is stored
|
||
; High byte to Low byte. We will
|
||
; need to alter this to Low --> High
|
||
; format.
|
||
;
|
||
@over ldy #dib.blkcnt
|
||
lda |pm.PartBlkCnt+2\
|
||
+internal_buff
|
||
xba
|
||
sta [next_dib],y
|
||
ldy #dib.blkcnt+2
|
||
lda |pm.PartBlkCnt\
|
||
+internal_buff
|
||
xba
|
||
sta [next_dib],y
|
||
;
|
||
; Now we need to get the starting
|
||
; location for this partition. This
|
||
; will be added to the requested
|
||
; block to generate a real block
|
||
; address. Also in High --> Low format.
|
||
;
|
||
ldy #dib.start_blk+2
|
||
lda |pm.PyPartStart+2\
|
||
+internal_buff
|
||
sta [next_dib],y
|
||
ldy #dib.start_blk
|
||
lda |pm.PyPartStart\
|
||
+internal_buff
|
||
sta [next_dib],y
|
||
;
|
||
; Get Location of this partition on disk.
|
||
;
|
||
ldy #dib.part_blk
|
||
lda |rpm_blk_num
|
||
sta [next_dib],y
|
||
;
|
||
; Set this device to ONLINE.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [next_dib],y
|
||
ora #dvc_online
|
||
sta [next_dib],y
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
;
|
||
; Set the Characteristics to Match the
|
||
; Read and Write Enables in the Partition
|
||
; Status Field.
|
||
;
|
||
lda |pm.PartStatus+2\
|
||
+internal_buff
|
||
xba
|
||
and #vconf_wr_enable++\
|
||
vconf_rd_enable
|
||
asl a
|
||
sta @temp
|
||
ldy #dib.dvcchar
|
||
lda [next_dib],y
|
||
and #write_allow++\
|
||
read_allow--\
|
||
$ffff
|
||
ora @temp
|
||
sta [next_dib],y
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Increment the partition count.
|
||
;
|
||
inc |part_num
|
||
beq @chk_ram
|
||
;
|
||
; Update the High seven bits of the
|
||
; unit number checking for the max
|
||
; value of 'max_partitions'.
|
||
;
|
||
ldy #dib.unitnum
|
||
lda [next_dib],y
|
||
tax
|
||
and #max_p_mask
|
||
cmp #max_p_mask
|
||
beq @all_done
|
||
txa
|
||
clc
|
||
adc #p_mask_adder
|
||
sta [next_dib],y
|
||
inc |vPart_cnt
|
||
;
|
||
; All done with the DIB Update now
|
||
; do we have any more DIBs, and if
|
||
; so, do we have any more RAM left
|
||
; to build further DIBs?
|
||
;
|
||
@chk_ram dec |part_cnt
|
||
bmi @all_done
|
||
dec |main_caller
|
||
jsr chk_ram
|
||
bcs @bad_call ;ERROR?
|
||
jmp @main_loop ;No. Do the next one.
|
||
@bad_call cmp #drvr_no_dev ;Yes. Then Exit
|
||
bne @sec
|
||
clc
|
||
rts
|
||
@sec sec
|
||
rts
|
||
;
|
||
; Clean Exit
|
||
;
|
||
@all_done clc
|
||
rts
|
||
;
|
||
; Data Area
|
||
;
|
||
@temp dc.w null
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Clean Exit
|
||
;
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'dibicise_new_ram'
|
||
;
|
||
; This routine takes the DIB located at [last_dib] and
|
||
; copies it into the new ram space. It does this
|
||
; while preserving the handle at offset 'dib.handle'.
|
||
; By so doing, it will be possible to free this ram
|
||
; space at some later time if that is deemed correct.
|
||
;
|
||
; Inputs: <last_dib = Last DIB built (LONG)
|
||
; <first_dib = Pointer to new (LONG)
|
||
; ram space.
|
||
; Acc = Unspecified
|
||
; Carry Clear = Do Link Pointers
|
||
; Set = Skip Link Pointers
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <last_dib = unchanged (LONG)
|
||
; <first_dib = unchanged (LONG)
|
||
; <next_dib = <first_dib (LONG)
|
||
; |curr_hndl = Handle for new ram (LONG)
|
||
;
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; If Carry Set on entry then
|
||
;
|
||
; |tot_dib_cnt = $0000 (WORD)
|
||
;
|
||
; If Carry Clear on entry then
|
||
;
|
||
; [last_dib] = points to this DIB (LONG)
|
||
; [first_dib] = defaults set (PTR)
|
||
; 'Int Pntrs' = Set to this DIB (LONG)s
|
||
; 'dispname' = Device Name (STR)
|
||
; |tot_dib_cnt = # of valid DIBs (WORD)
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT dibicise_new_ram
|
||
dibicise_new_ram PROC
|
||
;
|
||
; Save Do Links Flag.
|
||
;
|
||
php
|
||
;
|
||
; Preserve Handle for this
|
||
; memory segment.
|
||
;
|
||
ldy #dib.handle
|
||
lda [first_dib],y
|
||
sta |curr_hndl
|
||
ldy #dib.handle+2
|
||
lda [first_dib],y
|
||
sta |curr_hndl+2
|
||
;
|
||
; Using the built in move routine,
|
||
; copy the last DIB built to the
|
||
; first_dib location for the next
|
||
; dib to be built.
|
||
;
|
||
pushlong <last_dib
|
||
pushlong <first_dib
|
||
pushlong #dib_size
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
;
|
||
; Restore the handle to it's
|
||
; origonal location. This will
|
||
; then be copied to every other
|
||
; dib that is built in this
|
||
; memory segment.
|
||
;
|
||
ldy #dib.handle
|
||
lda |curr_hndl
|
||
sta [first_dib],y
|
||
ldy #dib.handle+2
|
||
lda |curr_hndl+2
|
||
sta [first_dib],y
|
||
;
|
||
; Set 'next_dib' pointer to the
|
||
; first dib in this memory
|
||
; segment.
|
||
;
|
||
lda <first_dib
|
||
sta <next_dib
|
||
lda <first_dib+2
|
||
sta <next_dib+2
|
||
|
||
ldy #dib.dvcflag
|
||
|
||
; lda [first_dib],y
|
||
; ora #cold_dib ;New DIB. Do Cold Start.
|
||
lda #wait_mode++\ ;New DIB. Do Cold Start and in Wait Mode.
|
||
cold_dib
|
||
|
||
sta [first_dib],y
|
||
;
|
||
; Reinitialise mem_dib_cnt to zero.
|
||
;
|
||
lda #null
|
||
ldy #dib.mem_dib_cnt
|
||
sta [first_dib],y
|
||
;
|
||
; Reinitialise DIB Dev Number also.
|
||
;
|
||
ldy #dib.devnum
|
||
sta [first_dib],y
|
||
;
|
||
; Finalise the new DIB Structure?
|
||
;
|
||
plp
|
||
bcc set_link_ptrs
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'dibicise_new_dib'
|
||
;
|
||
; This routine takes the DIB located at [last_dib] and
|
||
; copies it into the new ram space.
|
||
;
|
||
; Inputs: <last_dib = Last DIB built (LONG)
|
||
; <next_dib = Next DIB start (LONG)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <last_dib = unchanged (LONG)
|
||
; <next_dib = unchanged (LONG)
|
||
; [last_dib] = points to this DIB (LONG)
|
||
; [next_dib] = defaults set (PTR)
|
||
; 'Int Pntrs' = Set to this DIB (LONG)s
|
||
; 'dispname' = Device Name (STR)
|
||
; |tot_dib_cnt= # of valid DIBs (WORD)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT dibicise_new_dib
|
||
dibicise_new_dib PROC
|
||
;
|
||
; Using the built in move routine,
|
||
; copy the last DIB built to the
|
||
; next_dib location for the next
|
||
; dib to be built.
|
||
;
|
||
pushlong <last_dib
|
||
pushlong <next_dib
|
||
pushlong #dib_size
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
|
||
;
|
||
; Finalise the new DIB Structure.
|
||
;
|
||
EXPORT set_link_ptrs
|
||
;
|
||
; Update Links and DIB ext ptrs
|
||
;
|
||
set_link_ptrs bit |rebuild
|
||
bmi @rebuild_links
|
||
|
||
clc ;we are going to add
|
||
lda <next_dib ;get low word of this dib
|
||
sta [last_dib] ;store in last dib (implied y = 0)
|
||
|
||
adc #dib.start_blk ;adc offset to ext dib ptr
|
||
ldy #dib.ext_ptr ;get offset to where this goes
|
||
sta [next_dib],y ;and store low word of ptr
|
||
|
||
ldy #dib.linkptr+2 ;get offset to high word
|
||
lda <next_dib+2 ;get the high word and
|
||
sta [last_dib],y ;store it in the last dib
|
||
|
||
adc #^dib.start_blk ;adc high offset to ext ptr
|
||
ldy #dib.ext_ptr+2 ;get offset to where this goes
|
||
sta [next_dib],y ;and store the high word ptr
|
||
;
|
||
; Zero out the Link for this DIB
|
||
;
|
||
lda #null
|
||
sta [next_dib]
|
||
ldy #dib.linkptr+2
|
||
sta [next_dib],y
|
||
;
|
||
; Zero out the Starting Block for this DIB
|
||
;
|
||
@rebuild_links lda #null
|
||
ldy #dib.start_blk
|
||
sta [next_dib],y
|
||
ldy #dib.start_blk+2
|
||
sta [next_dib],y
|
||
;
|
||
; Increment the number of active DIBs in
|
||
; this memory segement.
|
||
;
|
||
ldy #dib.mem_dib_cnt
|
||
lda [first_dib],y
|
||
inc a
|
||
sta [first_dib],y
|
||
;
|
||
; In the DIB Extension as defined for this
|
||
; driver is the root structure of the
|
||
; pointers that are used to call the SCSI
|
||
; Manager. At this time we need to update
|
||
; them so that they too point into this
|
||
; dib and not the last one.
|
||
;
|
||
clc
|
||
lda <next_dib ;Low word of Completion Pointer
|
||
adc #dib.complet
|
||
ldy #dib.compvec
|
||
sta [next_dib],y
|
||
|
||
lda <next_dib+2 ;High word of Completion Pointer
|
||
adc #^dib.complet
|
||
ldy #dib.compvec+2
|
||
sta [next_dib],y
|
||
|
||
clc
|
||
lda <next_dib ;Low word of Command Packet Pointer
|
||
adc #dib.scsicmd
|
||
ldy #dib.cp_ptr
|
||
sta [next_dib],y
|
||
|
||
lda <next_dib+2 ;High word of Command Packet Pointer
|
||
adc #^dib.scsicmd
|
||
ldy #dib.cp_ptr+2
|
||
sta [next_dib],y
|
||
|
||
clc
|
||
lda <next_dib ;Low word of Send Structure Pointer
|
||
adc #dib.trx_buff
|
||
ldy #dib.trx_ptr
|
||
sta [next_dib],y
|
||
|
||
lda <next_dib+2 ;High word of Send Structure Pointer
|
||
adc #^dib.trx_buff
|
||
ldy #dib.trx_ptr+2
|
||
sta [next_dib],y
|
||
;
|
||
; Were we called from the
|
||
; main outside loop?
|
||
;
|
||
lda |main_caller
|
||
bne @skip_links ; No. Do device links.
|
||
;
|
||
; Zero out the HEAD LINK and FORWARD LINK
|
||
; pointers.
|
||
;
|
||
ldy #dib.headlnk
|
||
sta [next_dib],y ;Acc = 0. See Load.
|
||
ldy #dib.fdvclnk
|
||
sta [next_dib],y
|
||
ldy #dib.headptr
|
||
sta [next_dib],y ;Acc = 0. See Load.
|
||
ldy #dib.fdvcptr
|
||
sta [next_dib],y
|
||
ldy #dib.headptr+2
|
||
sta [next_dib],y ;Acc = 0. See Load.
|
||
ldy #dib.fdvcptr+2
|
||
sta [next_dib],y
|
||
;
|
||
; Set slot and device words in dib
|
||
;
|
||
lda [dvc_list]
|
||
|
||
ldy #dib.slotnum
|
||
sta [next_dib],y
|
||
|
||
ldy #$0002
|
||
lda [dvc_list],y
|
||
|
||
ldy #dib.unitnum
|
||
sta [next_dib],y
|
||
;
|
||
; Set pointer to the descriptive or
|
||
; device name so that we can rev the
|
||
; name to prevent duplicates.
|
||
;
|
||
@skip_links clc
|
||
lda <next_dib
|
||
adc #dib.namelen
|
||
sta <scsi_zp0
|
||
lda <next_dib+2
|
||
adc #^dib.namelen
|
||
sta <scsi_zp0+2
|
||
;
|
||
; Was internal or externally called?
|
||
; If internal, then we need to update
|
||
; the major revision part of the
|
||
; descriptive name. If it was external,
|
||
; then we will update the minor revision
|
||
; part only.
|
||
;
|
||
lda |main_caller
|
||
beq @do_major
|
||
;
|
||
; Do the minor revision.
|
||
;
|
||
jsr minor_update
|
||
bra @clear_busy
|
||
;
|
||
; Do the major revision.
|
||
;
|
||
@do_major jsr major_update
|
||
;
|
||
; Clear artifacts. We copied this data
|
||
; from the first dib that has the
|
||
; call_active bit set. Clear the sucker.
|
||
;
|
||
@clear_busy ldy #dib.dvcchar
|
||
lda [next_dib],y
|
||
and #call_active--\
|
||
$ffff
|
||
sta [next_dib],y
|
||
;
|
||
; Clear the ProDOS Bit.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [next_dib],y
|
||
and #pdos_part--\
|
||
$ffff
|
||
sta [next_dib],y
|
||
;
|
||
; Inc the DIB Count at this point.
|
||
; Every DIB that is succesfully built
|
||
; will be modified by the above code.
|
||
;
|
||
stz |main_caller
|
||
inc |tot_dib_cnt
|
||
clc
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; MAJOR_UPDATE
|
||
;
|
||
; This routine updates the major revision portion of
|
||
; the descriptive name portion of the DIB.
|
||
;
|
||
; Inputs: <DIB_PTR = DIB Location
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Better be none.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT major_update
|
||
major_update PROC
|
||
;
|
||
; Change name so as not to conflict
|
||
; with any other name already built.
|
||
; All names end with '00' - '99'.
|
||
;
|
||
short
|
||
|
||
ldx #$02 ;Don't change this value.
|
||
sec
|
||
lda [scsi_zp0]
|
||
;
|
||
; Reset Minor Revision to '00'.
|
||
;
|
||
pha
|
||
tay
|
||
lda #'0'
|
||
sta [scsi_zp0],y
|
||
dey
|
||
sta [scsi_zp0],y
|
||
pla
|
||
|
||
sbc #$03
|
||
tay
|
||
@name_loop lda [scsi_zp0],y
|
||
inc a
|
||
cmp #'9'+1
|
||
blt @update
|
||
lda #'0'
|
||
dex
|
||
@update sta [scsi_zp0],y
|
||
dey
|
||
dex
|
||
beq @name_loop
|
||
|
||
longmx
|
||
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; MINOR_UPDATE
|
||
;
|
||
; This routine updates the minor revision portion of
|
||
; the descriptive name portion of the DIB.
|
||
;
|
||
; Inputs: <DIB_PTR = DIB Location
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Better be none.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT minor_update
|
||
minor_update PROC
|
||
;
|
||
; Change name so as not to conflict
|
||
; with any other name already built.
|
||
; All names end with '00' - '99'.
|
||
;
|
||
short
|
||
|
||
ldx #$02 ;Don't change this value.
|
||
lda [scsi_zp0]
|
||
;
|
||
; Check the length of the string. If
|
||
; it is different from the one in the
|
||
; Default DIB, then we need to assume
|
||
; that it has been renamed. In this
|
||
; case, we will crank the count up by
|
||
; 2 but not past the max count of 31
|
||
; and append the version number
|
||
; change to that.
|
||
;
|
||
cmp |default_dib+\
|
||
dib.namelen
|
||
beq @len_ok
|
||
;
|
||
; Has it already been adjusted?
|
||
;
|
||
tay
|
||
lda [scsi_zp0],y
|
||
cmp #'0'
|
||
blt @fix_it
|
||
cmp #'9'+1
|
||
bge @fix_it
|
||
dey
|
||
lda [scsi_zp0],y
|
||
cmp #'0'
|
||
blt @fix_it
|
||
cmp #'9'+1
|
||
bge @fix_it
|
||
iny
|
||
bra @name_loop
|
||
|
||
@fix_it lda [scsi_zp0]
|
||
inc a
|
||
inc a
|
||
cmp #$31
|
||
blt @set_new_len
|
||
|
||
lda #$31
|
||
@set_new_len sta [scsi_zp0]
|
||
|
||
@len_ok tay
|
||
@name_loop lda [scsi_zp0],y
|
||
inc a
|
||
|
||
cmp #'1'
|
||
blt @force_zero
|
||
|
||
cmp #'9'+1
|
||
blt @update
|
||
|
||
@force_zero lda #'0'
|
||
dex
|
||
@update sta [scsi_zp0],y
|
||
dey
|
||
dex
|
||
beq @name_loop
|
||
|
||
longmx
|
||
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____DIB_Support_____
|
||
;*******************************************************
|
||
;
|
||
; This call is used to determine if the current DIB is
|
||
; the first device. This routine will return true
|
||
; (with the carry clear) if the device is unlinked or,
|
||
; if linked, then it will return true if this is the
|
||
; head device.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit is not the first
|
||
; device or it's equivelent.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT chk_first_dvc
|
||
chk_first_dvc PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; Check Linkes to see if single device.
|
||
;
|
||
ldy #dib.headlnk
|
||
lda [dib_ptr],y
|
||
bne @check_devnum
|
||
;
|
||
; Head Link = 0. Return True.
|
||
;
|
||
@true clc
|
||
rts
|
||
;
|
||
; Check to see if the Device Number and
|
||
; Head Links are the same. If not then
|
||
; we return false (carry set).
|
||
;
|
||
@check_devnum ldy #dib.devnum
|
||
cmp [dib_ptr],y
|
||
beq @true
|
||
;
|
||
; Return False.
|
||
;
|
||
sec
|
||
rts
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; This call checks to see if the other device tied to
|
||
; it are offline. If they are then the carry will be
|
||
; clear on exit. If this device is tied to any other
|
||
; device that is currently online, then the carry will
|
||
; be set on exit.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit is not the only
|
||
; device in this link that is still
|
||
; online.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT chk_lnk_offline
|
||
chk_lnk_offline PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; Get the Head Pointer. Check for null.
|
||
;
|
||
clc
|
||
ldy #dib.headptr
|
||
lda [dib_ptr],y
|
||
sta <scsi_zp6
|
||
beq @over_0
|
||
sec
|
||
@over_0 ldy #dib.headptr+2
|
||
lda [dib_ptr],y
|
||
sta <scsi_zp6+2
|
||
;
|
||
; Check if <20> null.
|
||
;
|
||
bne @check_it_loop
|
||
bcs @check_it_loop
|
||
;
|
||
; It was null. This may be the head
|
||
; of the link. Check it out.
|
||
;
|
||
ldy #dib.fdvcptr
|
||
lda [dib_ptr],y
|
||
ldy #dib.fdvcptr+2
|
||
ora [dib_ptr],y
|
||
beq @no_link ;No. Return to the caller with the carry clear.
|
||
;
|
||
; Yes. This was the head of the link.
|
||
; Set our pointer to this DIB.
|
||
;
|
||
lda <dib_ptr
|
||
sta <scsi_zp6
|
||
lda <dib_ptr+2
|
||
sta <scsi_zp6+2
|
||
;
|
||
; At this point, 'scsi_zp6' points to the
|
||
; head of the link. Now walk the links
|
||
; checking for online. If a device is
|
||
; online we will need to check if it is the
|
||
; callers device. if so, then we will
|
||
; continue the search. If not, we will then
|
||
; exit with the carry set.
|
||
;
|
||
@check_it_loop ldy #dib.dvcflag
|
||
|
||
lda [scsi_zp6],y
|
||
and #dvc_online ;Is it online?
|
||
beq @not_online ;No.
|
||
|
||
lda [scsi_zp6],y ;Yes. Maybe. Check hard offline
|
||
and #dvc_hardofl ;Is it hard offline?
|
||
bne @not_online ;Yes.
|
||
|
||
lda <scsi_zp6+2 ;Is it the caller device?
|
||
cmp <dib_ptr+2
|
||
bne @linked ;No.
|
||
lda <scsi_zp6
|
||
cmp <dib_ptr
|
||
bne @linked ;No.
|
||
;
|
||
; Point to next device.
|
||
;
|
||
@not_online clc
|
||
ldy #dib.fdvcptr
|
||
lda [scsi_zp6],y
|
||
tax
|
||
beq @over_2
|
||
sec
|
||
@over_2 ldy #dib.fdvcptr+2
|
||
lda [scsi_zp6],y
|
||
bne @save_it
|
||
bcc @no_link
|
||
@save_it sta <scsi_zp6+2
|
||
stx <scsi_zp6
|
||
|
||
bra @check_it_loop
|
||
|
||
;
|
||
; Only device online.
|
||
;
|
||
@no_link clc
|
||
rts
|
||
;
|
||
; Not the only device online.
|
||
;
|
||
@linked sec
|
||
rts
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'wake_me_up'
|
||
;
|
||
; This call walks the DIBs, slaps them in the face and
|
||
; pours cold water on them. It seems that they have
|
||
; been sleeping while P8 was running.
|
||
;
|
||
; !!!! WAAAAAAAAKE UUUUUUUP !!!!
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT wake_me_up
|
||
wake_me_up PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF warm_ss_suprt = true THEN
|
||
|
||
;
|
||
; Start with the first DIB after
|
||
; the default DIB
|
||
;
|
||
lda |default_dib
|
||
sta <first_dib
|
||
sta <next_dib
|
||
lda |default_dib+2
|
||
sta <first_dib+2
|
||
sta <next_dib+2
|
||
;
|
||
; Is he asleep?
|
||
;
|
||
@check_it_loop ldy #dib.dvcflag
|
||
lda [next_dib],y
|
||
tax
|
||
and #relaxing
|
||
beq @next_dib ;No he is not asleep
|
||
;
|
||
; Yes he is! Is he also Hard
|
||
; Offline?
|
||
;
|
||
txa
|
||
and #dvc_hardofl
|
||
beq @not_hardofl ;No. Wake him up all the way then.
|
||
|
||
txa ;Yes. Only Clear Sleep Bit.
|
||
and #relaxing--\ ;Don't set online.
|
||
$ffff
|
||
sta [next_dib],y
|
||
|
||
bra @next_dib
|
||
;
|
||
; Yes he is, wake him up.
|
||
;
|
||
@not_hardofl txa
|
||
and #relaxing--\
|
||
$ffff
|
||
ora #dvc_online
|
||
sta [next_dib],y
|
||
;
|
||
; Advance to the next one
|
||
;
|
||
@next_dib clc
|
||
ldy #dib.linkptr
|
||
lda [next_dib],y
|
||
tax
|
||
beq @over_0
|
||
sec
|
||
@over_0 ldy #dib.linkptr+2
|
||
lda [next_dib],y
|
||
sta <next_dib+2
|
||
stx <next_dib
|
||
;
|
||
; Check if <20> null.
|
||
;
|
||
bne @check_it_loop
|
||
bcs @check_it_loop
|
||
;
|
||
; That was the last one.
|
||
;
|
||
; By default of the branches above,
|
||
; the Acc. = 0 and the carry is clear.
|
||
;
|
||
rts
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'fix_unit_1'
|
||
;
|
||
; This call walks the DIBs, ensuring that unit 1 is
|
||
; the first ProDOS Partition on the disk..
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT fix_unit_1
|
||
fix_unit_1 PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; Check the pdos Bit for the Unit number 1.
|
||
; This may or may not be the head device.
|
||
;
|
||
ldy #dib.headptr
|
||
lda [dib_ptr],y
|
||
sta <scsi_zp0
|
||
ldy #dib.headptr+2
|
||
lda [dib_ptr],y
|
||
sta <scsi_zp0+2
|
||
ora <scsi_zp0 ;Are we at the Head Now?
|
||
bne @check_it ;No.
|
||
;
|
||
; We were already at the head. Set pointer
|
||
; to this DIB before going on.
|
||
;
|
||
lda <dib_ptr
|
||
sta <scsi_zp0
|
||
lda <dib_ptr+2
|
||
sta <scsi_zp0+2
|
||
;
|
||
; Is this unit number 1?
|
||
;
|
||
@check_it ldy #dib.unitnum
|
||
lda [scsi_zp0],y
|
||
and #max_p_mask
|
||
beq @unit_1 ;Yes.
|
||
;
|
||
; No. It's not unit number one. Check the
|
||
; next DIB in the link if it is non-zero.
|
||
;
|
||
clc
|
||
ldy #dib.fdvcptr
|
||
lda [scsi_zp0],y
|
||
tax
|
||
|
||
beq @over_sec
|
||
sec
|
||
|
||
@over_sec ldy #dib.fdvcptr+2
|
||
lda [scsi_zp0],y
|
||
|
||
bne @set_ptr
|
||
bcc @out
|
||
|
||
@set_ptr sta <scsi_zp0+2
|
||
stx <scsi_zp0
|
||
bra @check_it
|
||
;
|
||
; This is unit 1. Is it a ProDOS Partition?
|
||
;
|
||
@unit_1 ldy #dib.dvcflag
|
||
lda [scsi_zp0],y
|
||
and #pdos_part
|
||
bne @out ;It's ProDOS, Get out of here.
|
||
;
|
||
; We're out of here.
|
||
;
|
||
@out clc
|
||
rts
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ELSE ;part_suprt = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
clc
|
||
rts
|
||
|
||
ENDIF ;part_suprt = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
ENDP ;fix_unit_1
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; ADD_DIB_PTR
|
||
;
|
||
; This routine adds a pointer to a list of dibs to be
|
||
; installed by the 'POST_DRIVER_INSTALL' System
|
||
; Service call. Refer to the System Service ERS for
|
||
; details of how this works.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = High word of dib ptr
|
||
; X register = Low word of dib ptr
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <DIB_PTR = Empty DIB if found
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT add_dib_ptr
|
||
add_dib_ptr PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; Check to see if this has an overide
|
||
; placed on it.
|
||
;
|
||
lda |dpi_overide
|
||
bmi @exit ;Yes.
|
||
;
|
||
; Is this the first time that this has been
|
||
; called for this session. Only the
|
||
; do_post_install can clear this flag.
|
||
;
|
||
lda |new_list
|
||
beq @start_over ; Acc. = 0
|
||
;
|
||
; Inc the count of new devices to be started.
|
||
;
|
||
lda |new_dib_cnt
|
||
@start_over pha
|
||
inc a
|
||
sta |new_dib_cnt
|
||
sta |new_list
|
||
pla
|
||
;
|
||
; Calculate offset for next ptr.
|
||
;
|
||
asl a
|
||
asl a
|
||
pha
|
||
txa
|
||
plx
|
||
sta |new_dib_list,x ;Place Ptr in list
|
||
sta <scsi_zp0 ;and on zero page.
|
||
|
||
tya
|
||
sta |new_dib_list+2,x ;Place Ptr in list
|
||
sta <scsi_zp0+2 ;and on zero page.
|
||
|
||
ldy #dib.dvcflag
|
||
lda [scsi_zp0],y
|
||
ora #cold_dib ;New DIB. Do Cold Start.
|
||
sta [scsi_zp0],y
|
||
|
||
@exit clc
|
||
rts
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; DO_POST_INSTALL
|
||
;
|
||
; This routine calls the 'POST_DRIVER_INSTALL' System
|
||
; Service call. Refer to the System Service ERS for
|
||
; details of how this works.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = High word of dib ptr
|
||
; X register = Low word of dib ptr
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: <DIB_PTR = Empty DIB if found
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT do_post_install
|
||
do_post_install PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;
|
||
; Check to see if this has an overide
|
||
; placed on it.
|
||
;
|
||
lda |dpi_overide
|
||
bmi @exit ;Yes.
|
||
;
|
||
; Clear flag indicating that the call was
|
||
; sent.
|
||
;
|
||
stz |pdi_flag
|
||
stz |new_list
|
||
;
|
||
; Check the count of new devices to be
|
||
; started.
|
||
;
|
||
lda |new_dib_cnt
|
||
beq @exit
|
||
;
|
||
; Make the call
|
||
;
|
||
lda |gsos_dpage
|
||
tcd
|
||
ldx #new_dib_cnt
|
||
ldy #^new_dib_cnt
|
||
|
||
jsl install_driver
|
||
pha
|
||
lda |direct_page
|
||
tcd
|
||
pla
|
||
|
||
bcs @exit
|
||
dec |pdi_flag
|
||
|
||
@exit clc
|
||
rts
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____Part_Support____
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF part_suprt = true THEN
|
||
|
||
;*******************************************************
|
||
;
|
||
; READ_PM_BLK
|
||
;
|
||
;
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if operation could not be
|
||
; completed. Out of memory for example.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT read_pm_blk
|
||
read_pm_blk PROC
|
||
;
|
||
; 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
|
||
;
|
||
; Was this from the STARTUP Call?
|
||
;
|
||
bit |rebuild
|
||
bmi @over ;No.
|
||
;
|
||
; Yes, then stuff the pointer to
|
||
; the dib that we are building into
|
||
; the Direct Page locations. The
|
||
; main driver will use this to build
|
||
; the SCSI READ BLOCK Command that
|
||
; we will issue.
|
||
;
|
||
lda <next_dib
|
||
sta <dib_ptr
|
||
lda <next_dib+2
|
||
sta <dib_ptr+2
|
||
;
|
||
; And our length from the DIB's
|
||
; Block Size value
|
||
;
|
||
@over lda #block_size
|
||
sta <rqst_cnt
|
||
lda #^block_size
|
||
sta <rqst_cnt+2
|
||
;
|
||
; Was this from a Status or Control Call?
|
||
;
|
||
bit |stat_cont
|
||
bmi @block_set
|
||
;
|
||
; Set block to read for the next
|
||
; partition map block. This field
|
||
; is initialized to zero. Because
|
||
; the first partition map block is
|
||
; on block 1, this will be initialized
|
||
; to zero and then blindly incremented
|
||
; until we are finished.
|
||
;
|
||
; *** This is High --> Low format ***
|
||
;
|
||
lda |rpm_blk_num
|
||
xba
|
||
inc a
|
||
xba
|
||
sta |rpm_blk_num
|
||
;
|
||
; Set internal command flag
|
||
;
|
||
@block_set stz |stat_cont ;We used the flag, now clear it.
|
||
dec |internal
|
||
;
|
||
; Set the Partition call flag
|
||
;
|
||
dec |f_partition
|
||
;
|
||
; Set the Call Type and Issue the
|
||
; READ BLOCK Command.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
;
|
||
; Issue the call.
|
||
;
|
||
jsr check_532_rw
|
||
|
||
@rts rts
|
||
;
|
||
; Data for the READ BLOCK Command
|
||
;
|
||
@read_part dc.b $08
|
||
dc.b null
|
||
EXPORT rpm_blk_num
|
||
rpm_blk_num dc.w null
|
||
dcb.b 10,null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'write_pm_blk'
|
||
;
|
||
;
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if operation could not be
|
||
; completed. Out of memory for example.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT write_pm_blk
|
||
write_pm_blk PROC
|
||
;
|
||
; 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
|
||
;
|
||
lda #block_size
|
||
sta <rqst_cnt
|
||
lda #^block_size
|
||
sta <rqst_cnt+2
|
||
;
|
||
; Set internal command flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set the Partition call flag
|
||
;
|
||
dec |f_partition
|
||
;
|
||
; Set the Call Type and Issue the
|
||
; READ BLOCK Command.
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the call.
|
||
;
|
||
jsr check_532_rw
|
||
|
||
@rts rts
|
||
;
|
||
; Data for the READ BLOCK Command
|
||
;
|
||
@write_part dc.b $0A
|
||
dc.b null
|
||
EXPORT wpm_blk_num
|
||
wpm_blk_num dc.w null
|
||
dcb.b 10,null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; CHK_MAP
|
||
;
|
||
; This routine checks the validity of the partition
|
||
; map block currently loaded in the internal buffer.
|
||
; This need only be called once per device. If the
|
||
; map is valid, then the carry will be clear. The 'Z'
|
||
; flag will also be set if this is not the first time
|
||
; that this routine was called for this device. If
|
||
; the carry is set, then the map was invalid and the
|
||
; block count at 'T_DVC_BLOCKS' has been placed in the
|
||
; DIB pointed to by 'DIB_PTR'. The starting block will
|
||
; also have been set to null.
|
||
;
|
||
; Inputs: <DIB_PTR = DIB Location
|
||
; |T_DVC_BLOCKS = Total blocks for this device
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; = Z = 0 if routine called before
|
||
; = C = 1 if not a partition map
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if 'internal_buff does not
|
||
; contain a valid Partition map entry.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT chk_map
|
||
chk_map PROC
|
||
;
|
||
; Valid Partition Map?
|
||
;
|
||
@over_0 inc |first_time ;Don't need to do this but once.
|
||
bne @clc ;Already done if taken.
|
||
|
||
lda |pm.Sig\
|
||
+internal_buff
|
||
cmp #Part_sig
|
||
bne no_partition ;No.
|
||
|
||
@clc clc
|
||
rts
|
||
;
|
||
; We didn't have a valid partition
|
||
; map, so this device will be
|
||
; treated as a single non-partitioned
|
||
; device.
|
||
;
|
||
EXPORT no_partition
|
||
;
|
||
; Issue the READ CAPACITY Command.
|
||
;
|
||
no_partition jsr read_capacity
|
||
bcs @over_0 ;Was there an error?
|
||
;
|
||
; Get the Block Count (Stored
|
||
; High >> Low. Must be switched
|
||
; to Low >> High). This is the last
|
||
; readable block number. Add 1 to
|
||
; it for comparison reasons.
|
||
;
|
||
lda |block.count\
|
||
+internal_buff\
|
||
+2
|
||
xba
|
||
adc #$0001
|
||
|
||
ldy #dib.blkcnt
|
||
sta [dib_ptr],y
|
||
|
||
lda |block.count\
|
||
+internal_buff
|
||
xba
|
||
adc #null
|
||
|
||
ldy #dib.blkcnt+2
|
||
sta [dib_ptr],y
|
||
|
||
@over_0 ldy #dib.start_blk
|
||
lda #null
|
||
sta [dib_ptr],y
|
||
ldy #dib.start_blk+2
|
||
sta [dib_ptr],y
|
||
;
|
||
; Set Read and Write Enables
|
||
;
|
||
lda >default_dib+dib.dvcchar ;Get Default Settings for
|
||
and #write_allow++\ ;Write Enable
|
||
read_allow++\ ;Read Enable
|
||
format_allow ;And Format Allowed
|
||
ldy #dib.dvcchar
|
||
ora [dib_ptr],y ;Combine with the current
|
||
sta [dib_ptr],y ;Settings for this device
|
||
;
|
||
; Mark DIB as online and switched.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
and #dvc_hardofl--\
|
||
$ffff
|
||
ora #dvc_switch++\
|
||
dvc_online
|
||
sta [dib_ptr],y
|
||
|
||
sec
|
||
rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'check_map_entry'
|
||
;
|
||
; Check the Partition Map Entry currently loaded in
|
||
; the internal buffer. If it is of type
|
||
; 'Apple_partition_map', 'Apple_Driver', 'Apple_Free',
|
||
; or 'Apple_Scratch', then this routine will return
|
||
; with the carry set. Any other type will return
|
||
; with the carry clear. In addition, 'Apple_ProDOS'
|
||
; will return with the overflow flag set.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Partition Map Entry is not
|
||
; for a valid Volume. Overflow set if the
|
||
; Partition is a ProDOS Partition.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT check_map_entry
|
||
check_map_entry PROC
|
||
;
|
||
; This routine runs in
|
||
; 8 bit m and x only.
|
||
;
|
||
short
|
||
;
|
||
; Is it ProDOS?
|
||
;
|
||
ldx #@p_map-@prodos-2
|
||
ldy #null
|
||
|
||
@loop lda |pm.PartType\
|
||
+internal_buff,y
|
||
beq @over_0 ;Yes or null. Either way we do the rest.
|
||
cmp @prodos,y
|
||
beq @next
|
||
eor #'A'--'a'
|
||
cmp @prodos,y
|
||
bne @over_0 ;No. Continue on.
|
||
@next iny
|
||
dex
|
||
bpl @loop
|
||
brl @pdos_part ;Skip over 8 bit code area to 16 bit area.
|
||
;
|
||
; Is it the Partition Map?
|
||
;
|
||
@over_0 ldx #32-1
|
||
ldy #null
|
||
|
||
@loop_0 lda |pm.PartType\
|
||
+internal_buff,y
|
||
beq @skip ;Yes or null. Either way we skip it.
|
||
cmp @p_map,y
|
||
beq @next_0
|
||
eor #'A'--'a'
|
||
cmp @p_map,y
|
||
bne @over_1 ;No. Continue on.
|
||
@next_0 iny
|
||
dex
|
||
bpl @loop_0
|
||
bra @skip ;Yes. Skip it.
|
||
;
|
||
; Is it a FREE Partition?
|
||
;
|
||
@over_1 ldx #32-1
|
||
ldy #null
|
||
|
||
@loop_1 lda |pm.PartType\
|
||
+internal_buff,y
|
||
beq @skip ;Yes or null. Either way we skip it.
|
||
cmp @free,y
|
||
beq @next_1
|
||
eor #'A'--'a'
|
||
cmp @free,y
|
||
bne @over_2 ;No. Continue on.
|
||
@next_1 iny
|
||
dex
|
||
bpl @loop_1
|
||
bra @skip ;Yes. Skip it.
|
||
;
|
||
; Is it a SCRATCH Partition?
|
||
;
|
||
@over_2 ldx #32-1
|
||
ldy #null
|
||
|
||
@loop_2 lda |pm.PartType\
|
||
+internal_buff,y
|
||
beq @skip ;Yes or null. Either way we skip it.
|
||
cmp @scratch,y
|
||
beq @next_2
|
||
eor #'A'--'a'
|
||
cmp @scratch,y
|
||
bne @over_3 ;No. Continue on.
|
||
@next_2 iny
|
||
dex
|
||
bpl @loop_2
|
||
;
|
||
; Is it a Driver Partition?
|
||
;
|
||
@over_3 ldx #32-1
|
||
ldy #null
|
||
|
||
@loop_3 lda |pm.PartType\
|
||
+internal_buff,y
|
||
beq @skip ;Yes or null. Either way we skip it.
|
||
cmp @driver,y
|
||
beq @next_3
|
||
eor #'A'--'a'
|
||
cmp @driver,y
|
||
bne @over_4 ;No. Continue on.
|
||
@next_3 iny
|
||
dex
|
||
bpl @loop_3
|
||
;
|
||
; At this point the Current Partition
|
||
; Type matched one of the three types
|
||
; checked for. Exit with the carry
|
||
; set.
|
||
;
|
||
@skip longmx
|
||
sec
|
||
rts
|
||
;
|
||
; At this point the Current Partition
|
||
; Type did not match one of the three
|
||
; types checked for and it was not a
|
||
; ProDOS Partition.. Exit with the
|
||
; Carry and Overflow bits clear.
|
||
;
|
||
@over_4 longmx
|
||
clc
|
||
clv
|
||
rts
|
||
;
|
||
; At this point the Current Partition
|
||
; Type is a ProDOS Partition. Exit with
|
||
; the Carry clear and Overflow set.
|
||
;
|
||
@pdos_part longmx
|
||
clc
|
||
sep #%01000000 ;Set the v flag
|
||
rts
|
||
;
|
||
; Inactive Partion Types to check for.
|
||
;
|
||
STRING ASIS
|
||
|
||
@prodos dc.b 'Apple_ProDOS'
|
||
dc.b $00
|
||
@driver dc.b 'Apple_Driver'
|
||
dc.b $00
|
||
@p_map dc.b 'Apple_partition_map'
|
||
dc.b $00
|
||
@free dc.b 'Apple_Free'
|
||
dc.b $00
|
||
@scratch dc.b 'Apple_Scratch'
|
||
dc.b $00
|
||
|
||
STRING PASCAL
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
ELSE ;part_suprt = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
EXPORT read_pm_blk
|
||
read_pm_blk PROC
|
||
|
||
EXPORT check_map_entry
|
||
check_map_entry
|
||
lda #null
|
||
clc
|
||
clv
|
||
rts
|
||
|
||
|
||
EXPORT rpm_blk_num
|
||
rpm_blk_num dc.w null
|
||
|
||
EXPORT chk_map
|
||
chk_map
|
||
;
|
||
; We can't have a valid partition
|
||
; map, so this device will be
|
||
; treated as a single non-partitioned
|
||
; device.
|
||
;
|
||
EXPORT no_partition
|
||
;
|
||
; Issue the READ CAPACITY Command.
|
||
;
|
||
no_partition jsr read_capacity
|
||
bcs @over_0 ;Was there an error?
|
||
;
|
||
; Get the Block Count (Stored
|
||
; High >> Low. Must be switched
|
||
; to Low >> High). This is the last
|
||
; readable block number. Add 1 to
|
||
; it for comparison reasons.
|
||
;
|
||
lda |block.count\
|
||
+internal_buff\
|
||
+2
|
||
xba
|
||
adc #$0001
|
||
|
||
ldy #dib.blkcnt
|
||
sta [dib_ptr],y
|
||
|
||
lda |block.count\
|
||
+internal_buff
|
||
xba
|
||
adc #null
|
||
|
||
ldy #dib.blkcnt+2
|
||
sta [dib_ptr],y
|
||
|
||
@over_0 ldy #dib.start_blk
|
||
lda #null
|
||
sta [dib_ptr],y
|
||
ldy #dib.start_blk+2
|
||
sta [dib_ptr],y
|
||
;
|
||
; Mark DIB as online and switched.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
and #dvc_hardofl--\
|
||
$ffff
|
||
ora #dvc_switch++\
|
||
dvc_online
|
||
sta [dib_ptr],y
|
||
|
||
sec
|
||
rts
|
||
|
||
ENDIF ;part_suprt = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;____Cache_Suport____
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF cache_blks = true THEN
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'r_all_in_cache'
|
||
;
|
||
; This routine is used to check if the entire
|
||
; requested block count is in the cache. This routine
|
||
; will check each block individually, incrementing the
|
||
; block count and subtracting the block size from the
|
||
; request count until either a block is found that is
|
||
; not in the cache (Exit Carry Set) or request count
|
||
; has been exausted (Exit Carry Clear).
|
||
;
|
||
; On entry this routine clears some values to indicate
|
||
; it's starting point for this call. As it goes
|
||
; throughthe cache looking for blocks, it will fetch
|
||
; the block from the cache and advance the starting
|
||
; point. What this does is eliminate double searches
|
||
; throughthe cache and if a read is needed, these
|
||
; blocks will not have to be transfered. When this
|
||
; routine exits, the caller will think that the first
|
||
; block that we found that was not in the cache was
|
||
; the first block requested. For this reason, any
|
||
; code that uses this call will need to preserve those
|
||
; values so that they can be restored on exit.
|
||
;
|
||
; If we receive a Read Call for 256 blocks and the
|
||
; first 128 are in the cache, then we don't want to
|
||
; re-read them, and we don't want to do a find again
|
||
; later when we fetch them. let's fetch them now and
|
||
; advance our pointers.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; <buff_ptr = Original Starting Buffer
|
||
; <rqst_cnt = Original Request Count
|
||
; <block_num = Original Starting Block
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; <buff_ptr = New Starting Buffer
|
||
; <rqst_cnt = New Request Count
|
||
; <block_num = New Starting Block
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Acc = 0 and Carry set if 1 or more
|
||
; blocks of the request are not in the
|
||
; cache.
|
||
;
|
||
; Acc <> 0 if any other error occurs.
|
||
; Error code is in Acc.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT r_all_in_cache
|
||
r_all_in_cache PROC
|
||
;
|
||
; Switch Direct Pages.
|
||
;
|
||
lda |gsos_dpage
|
||
tcd
|
||
;
|
||
; Get the requested count and devide
|
||
; by block size to get the loop counter.
|
||
; If Count = 0, then exit.
|
||
;
|
||
lda <rqst_cnt
|
||
sta |divend
|
||
lda <rqst_cnt+2
|
||
sta |divend+2
|
||
|
||
ora <rqst_cnt
|
||
bne @continue
|
||
|
||
lda |direct_page
|
||
tcd
|
||
lda #null
|
||
clc
|
||
@rts rts
|
||
|
||
;
|
||
; Call divide routine.
|
||
;
|
||
@continue lda <blk_size
|
||
sta |divsor
|
||
|
||
jsr divide
|
||
bcc @over_divide
|
||
|
||
lda |direct_page
|
||
tcd
|
||
|
||
lda #drvr_bad_cnt ;non-integral rqst count.
|
||
sec
|
||
rts
|
||
;
|
||
; Count = count -1. This way we can
|
||
; use a BMI to exit with.
|
||
;
|
||
@over_divide lda |result+2
|
||
sta @blk_cnt+2
|
||
lda |result
|
||
sta @blk_cnt
|
||
bne @over_dec_high
|
||
dec @blk_cnt+2
|
||
@over_dec_high dec @blk_cnt
|
||
;
|
||
; Setup is now completed. Now we start to
|
||
; check to see if the blocks are in the
|
||
; cache.
|
||
;
|
||
@chk_blk_loop sec ;return error if not in cache. Don't add.
|
||
jsr |get_from_cache
|
||
bcc @found
|
||
lda #null ;Not there. Clear the Acc. and Exit.
|
||
bra @restore
|
||
;
|
||
; Are there any more to do?
|
||
;
|
||
@found lda @blk_cnt
|
||
bne @over_dec
|
||
dec @blk_cnt+2
|
||
bpl @over_dec
|
||
;
|
||
; No. Count is exausted.
|
||
;
|
||
lda #null
|
||
clc
|
||
bra @restore
|
||
;
|
||
; Yes. Finish the DEC and update the
|
||
; Buffer Pointer, Request Count, and
|
||
; the Block Number.
|
||
;
|
||
@over_dec dec @blk_cnt
|
||
|
||
clc ;Bump Buffer Pointer
|
||
lda <buff_ptr
|
||
adc <blk_size
|
||
sta <buff_ptr
|
||
lda <buff_ptr+2
|
||
adc #null
|
||
sta <buff_ptr+2
|
||
|
||
sec ;Back off Request Count
|
||
lda <rqst_cnt
|
||
sbc <blk_size
|
||
sta <rqst_cnt
|
||
lda <rqst_cnt+2
|
||
sbc #null
|
||
sta <rqst_cnt+2
|
||
|
||
inc <block_num ;Inc the Block Number
|
||
bne @chk_blk_loop
|
||
inc <block_num+2
|
||
bra @chk_blk_loop
|
||
;
|
||
; We are finished. We don't need to
|
||
; know if we were succesfull. We only
|
||
; need to restore the state of the
|
||
; corrupted direct page values while
|
||
; preserving the Acc. and Carry bit.
|
||
;
|
||
@restore pha
|
||
php
|
||
|
||
ldx |direct_page
|
||
|
||
lda <buff_ptr
|
||
sta >buff_ptr,x
|
||
sta |c_strt_buffer
|
||
lda <buff_ptr+2
|
||
sta >buff_ptr+2,x
|
||
sta |c_strt_buffer+2
|
||
|
||
lda <rqst_cnt
|
||
sta >rqst_cnt,x
|
||
sta |c_strt_rqst_cnt
|
||
lda <rqst_cnt+2
|
||
sta >rqst_cnt+2,x
|
||
sta |c_strt_rqst_cnt+2
|
||
|
||
lda <block_num
|
||
sta >block_num,x
|
||
sta |c_strt_blk_num
|
||
lda <block_num+2
|
||
sta >block_num+2,x
|
||
sta |c_strt_blk_num+2
|
||
;
|
||
; Validate Flag for the Read Cache
|
||
; Routines
|
||
;
|
||
dec |cache_valid
|
||
|
||
txa
|
||
tcd
|
||
|
||
plp
|
||
pla
|
||
rts
|
||
;
|
||
; Internal Data
|
||
;
|
||
@blk_cnt dc.l null
|
||
;
|
||
; The following values are used to advance
|
||
; the starting point of the cache calls.
|
||
;
|
||
EXPORT c_strt_buffer
|
||
EXPORT c_strt_rqst_cnt
|
||
EXPORT c_strt_blk_num
|
||
EXPORT cache_valid
|
||
|
||
c_strt_buffer dc.l null ;Starting Buffer Pointer
|
||
c_strt_rqst_cnt dc.l null ;Starting Request Count
|
||
c_strt_blk_num dc.l null ;Starting Block Number
|
||
cache_valid dc.w null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'w_update_cache'
|
||
;
|
||
; This routine is used when writting data to the disk
|
||
; with a cache priority of $0000. If the block is in
|
||
; the cache, then the cache will be updated. If not,
|
||
; then nothing will happen.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
; Carry Clear = Always place in cache
|
||
; Carry set = Only place in cache if
|
||
; already there.
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if requested block is not
|
||
; added to the cache.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT w_update_cache
|
||
w_update_cache PROC
|
||
;
|
||
; Zero Deferred Write failed flag.
|
||
;
|
||
stz @deferred
|
||
;
|
||
; Preserve Carry Flag for later.
|
||
;
|
||
php
|
||
;
|
||
; Set GS/OS Direct Page
|
||
;
|
||
lda |gsos_dpage
|
||
tcd
|
||
;
|
||
; Preserve Block Number and request
|
||
; count. Set count to 1 block per
|
||
; call.
|
||
;
|
||
lda <buff_ptr
|
||
sta @orig_buff
|
||
|
||
lda <rqst_cnt
|
||
sta @bytes_rem
|
||
|
||
lda <block_num
|
||
sta @start_blk
|
||
|
||
lda <buff_ptr+2
|
||
sta @orig_buff+2
|
||
|
||
lda <rqst_cnt+2
|
||
sta @bytes_rem+2
|
||
|
||
lda <block_num+2
|
||
sta @start_blk+2
|
||
;
|
||
; Is the requested block in the cache?
|
||
;
|
||
@do_cache plp
|
||
php
|
||
jsr put_in_cache
|
||
bcc @cached ;Carry set only if a deferred write
|
||
dec @deferred ;failed to go in the cache.
|
||
;
|
||
; Advance to the next block.
|
||
;
|
||
@cached inc <block_num
|
||
bne @over
|
||
inc <block_num+2
|
||
;
|
||
; Bump Buffer Pointer.
|
||
;
|
||
@over clc
|
||
lda <buff_ptr
|
||
adc <blk_size
|
||
sta <buff_ptr
|
||
bcc @over_1
|
||
inc <buff_ptr+2
|
||
;
|
||
; Any Data Left
|
||
;
|
||
@over_1 sec
|
||
lda @bytes_rem
|
||
sbc <blk_size
|
||
sta @bytes_rem
|
||
sta |temp_acc
|
||
|
||
lda @bytes_rem+2
|
||
sbc #null
|
||
sta @bytes_rem+2
|
||
ora |temp_acc
|
||
|
||
bne @do_cache ;Yes.
|
||
clc
|
||
;
|
||
; Restore Values.
|
||
;
|
||
|
||
@restore lda @orig_buff
|
||
sta <buff_ptr
|
||
|
||
lda @start_blk
|
||
sta <block_num
|
||
|
||
lda @orig_buff+2
|
||
sta <buff_ptr+2
|
||
|
||
lda @start_blk+2
|
||
sta <block_num+2
|
||
;
|
||
; Exit.
|
||
;
|
||
lda |direct_page
|
||
tcd
|
||
|
||
lda @deferred
|
||
beq @clean_out
|
||
plp ;Restore the Stack.
|
||
sec
|
||
rts
|
||
|
||
@clean_out plp ;Restore the Stack.
|
||
clc
|
||
rts
|
||
;
|
||
; Internal Data
|
||
;
|
||
@deferred dc.w null
|
||
@orig_buff dc.l null
|
||
@bytes_rem dc.l null
|
||
@start_blk dc.l null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'put_in_cache'
|
||
;
|
||
; This routine is used to place the current block in
|
||
; the cache. First we will check if the requested
|
||
; block is in the cache. If the block is not in the
|
||
; cache then we will add it. if there is no room and
|
||
; the driver call was issued in deferred mode then we
|
||
; will exit with the carry set. In all other cases
|
||
; we will exit Carry Clear.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
; Carry Clear = Always place in cache
|
||
; Carry set = Only place in cache if
|
||
; already there.
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if requested block is not
|
||
; added to the cache in deferred mode
|
||
; only.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT put_in_cache
|
||
put_in_cache PROC
|
||
;
|
||
; Is the requested block in the cache?
|
||
;
|
||
php
|
||
|
||
clc
|
||
jsl cache_find_blk
|
||
|
||
bcc @move_it_in ;Yes. It is.
|
||
plp
|
||
bcs @clc
|
||
;
|
||
; Not there. Allocate space.
|
||
;
|
||
jsl cache_add_blk
|
||
bcc @skip_fix
|
||
lda <cache_prio ;Deferred Mode?
|
||
bpl @clc ;No. Exit Carry Clear.
|
||
rts ;Yes. Exit carry set
|
||
;
|
||
; Move the block in.
|
||
;
|
||
@move_it_in plp ;Restore the stack.
|
||
|
||
@skip_fix pei <buff_ptr+2
|
||
pei <buff_ptr
|
||
pei <cache_ptr+2
|
||
pei <cache_ptr
|
||
pea $0000
|
||
pei <blk_size
|
||
pea |move_sinc_dinc
|
||
jsl move_info
|
||
;
|
||
; Exit.
|
||
;
|
||
@clc clc
|
||
@rts rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'r_get_cache'
|
||
;
|
||
; This routine is used when reading data from the disk
|
||
; with a cache priority of $0000. If the block is in
|
||
; the cache, then the data will be updated. If not,
|
||
; then nothing will happen.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
; Carry Clear = Always place in cache
|
||
; Carry set = Only place in cache if
|
||
; already there.
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if requested block is not
|
||
; added to the cache.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT r_get_cache
|
||
r_get_cache PROC
|
||
;
|
||
; Preserve Carry Flag for later.
|
||
;
|
||
php
|
||
;
|
||
; Check Validity of the call.
|
||
;
|
||
lda |cache_valid
|
||
bmi @valid
|
||
|
||
plp
|
||
lda #drvr_bad_code
|
||
sec
|
||
rts
|
||
;
|
||
; Set GS/OS Direct Page
|
||
;
|
||
@valid lda |gsos_dpage
|
||
tcd
|
||
;
|
||
; Get Request count.
|
||
;
|
||
lda |c_strt_rqst_cnt
|
||
sta @bytes_rem
|
||
lda |c_strt_rqst_cnt+2
|
||
sta @bytes_rem+2
|
||
;
|
||
; Is the requested block in the cache?
|
||
;
|
||
@do_cache plp
|
||
php
|
||
jsr get_from_cache
|
||
;
|
||
; Advance to the next block.
|
||
;
|
||
inc <block_num
|
||
bne @over
|
||
inc <block_num+2
|
||
;
|
||
; Bump Buffer Pointer.
|
||
;
|
||
@over clc
|
||
lda <buff_ptr
|
||
adc <blk_size
|
||
sta <buff_ptr
|
||
bcc @over_1
|
||
inc <buff_ptr+2
|
||
;
|
||
; Any Data Left
|
||
;
|
||
@over_1 sec
|
||
lda @bytes_rem
|
||
sbc <blk_size
|
||
sta @bytes_rem
|
||
sta |temp_acc
|
||
|
||
lda @bytes_rem+2
|
||
sbc #null
|
||
sta @bytes_rem+2
|
||
ora |temp_acc
|
||
|
||
bne @do_cache ;Yes.
|
||
;
|
||
; Exit.
|
||
;
|
||
stz |cache_valid ;Cache Values no longer valid
|
||
|
||
lda |direct_page
|
||
tcd
|
||
|
||
plp ;Restore the Stack.
|
||
clc
|
||
rts
|
||
;
|
||
; Internal Data
|
||
;
|
||
@bytes_rem dc.l null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'get_from_cache'
|
||
;
|
||
; This routine is used to get the current block from
|
||
; the cache. First we will check if the requested
|
||
; block is in the cache. If the block is not in the
|
||
; cache then we will exit with the Carry Set. If it
|
||
; is found, then we will move it to the requested ram
|
||
; and exit Carry Clear.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if requested block is not
|
||
; in the cache.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_from_cache
|
||
get_from_cache PROC
|
||
;
|
||
; Is the requested block in the cache?
|
||
;
|
||
php
|
||
|
||
clc
|
||
jsl cache_find_blk
|
||
|
||
bcc @move_it_in ;Yes. It is.
|
||
plp
|
||
bcs @rts
|
||
;
|
||
; Not there. Allocate space.
|
||
;
|
||
jsl cache_add_blk
|
||
bcs @rts
|
||
|
||
pei <buff_ptr+2
|
||
pei <buff_ptr
|
||
pei <cache_ptr+2
|
||
pei <cache_ptr
|
||
pea $0000
|
||
pei <blk_size
|
||
pea |move_sinc_dinc
|
||
jsl move_info
|
||
|
||
bra @clc
|
||
;
|
||
; Move the block in.
|
||
;
|
||
@move_it_in plp ;Restore the stack.
|
||
|
||
@skip_fix pei <cache_ptr+2
|
||
pei <cache_ptr
|
||
pei <buff_ptr+2
|
||
pei <buff_ptr
|
||
pea $0000
|
||
pei <blk_size
|
||
pea |move_sinc_dinc
|
||
jsl move_info
|
||
;
|
||
; Exit.
|
||
;
|
||
@clc clc
|
||
@rts rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'ko_cache'
|
||
;
|
||
; This routine is used to kill all blocks that are
|
||
; cached that are included in a device specific write
|
||
; type call.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT ko_cache
|
||
ko_cache PROC
|
||
;
|
||
; Switch Direct Pages.
|
||
;
|
||
lda |gsos_dpage
|
||
tcd
|
||
;
|
||
; Preserve the block number on direct
|
||
; page.
|
||
;
|
||
lda <block_num
|
||
sta |scratch0
|
||
lda <block_num+2
|
||
sta |scratch1
|
||
;
|
||
; Set our starting block number on
|
||
; direct page.
|
||
;
|
||
lda |killer_blk
|
||
sta <block_num
|
||
lda |killer_blk+2
|
||
sta <block_num+2
|
||
;
|
||
; Get the requested count and devide
|
||
; by block size to get the loop counter.
|
||
; If Count = 0, then exit.
|
||
;
|
||
lda <rqst_cnt+2
|
||
sta |divend+2
|
||
lda <rqst_cnt
|
||
sta |divend
|
||
ora <rqst_cnt+2
|
||
bne @do_devide
|
||
|
||
clc
|
||
@rts bra @restore
|
||
;
|
||
; Call divide routine.
|
||
;
|
||
@do_devide lda <blk_size
|
||
sta |divsor
|
||
|
||
jsr divide
|
||
bcc @over_divide
|
||
lda #drvr_bad_cnt ;non-integral rqst count.
|
||
sec
|
||
bra @restore
|
||
;
|
||
; Count = count -1. This way we can
|
||
; use a BMI to exit with.
|
||
;
|
||
@over_divide lda |result+2
|
||
sta @blk_cnt+2
|
||
lda |result
|
||
sta @blk_cnt
|
||
bne @over_dec_high
|
||
dec @blk_cnt+2
|
||
@over_dec_high dec @blk_cnt
|
||
;
|
||
; Setup is now completed. Now we start to
|
||
; check to see if the blocks are in the
|
||
; cache.
|
||
;
|
||
@chk_blk_loop jsl cache_kil_blk
|
||
;
|
||
; Are there any more to do?
|
||
;
|
||
lda @blk_cnt
|
||
bne @over_dec
|
||
dec @blk_cnt+2
|
||
bpl @over_dec
|
||
;
|
||
; No. Count is exausted.
|
||
;
|
||
clc
|
||
bra @restore
|
||
;
|
||
; Yes. Finish the DEC and update
|
||
; the block number.
|
||
;
|
||
@over_dec dec @blk_cnt
|
||
|
||
inc <block_num
|
||
bne @chk_blk_loop
|
||
inc <block_num+2
|
||
bra @chk_blk_loop
|
||
;
|
||
; We are finished. We don't need to
|
||
; know if we were succesfull. We only
|
||
; need to restore the state of the
|
||
; corrupted direct page values while
|
||
; preserving the Acc. and Carry bit.
|
||
;
|
||
@restore pha
|
||
php
|
||
lda |scratch0
|
||
sta <block_num
|
||
lda |scratch1
|
||
sta <block_num+2
|
||
|
||
lda |direct_page
|
||
tcd
|
||
|
||
plp
|
||
pla
|
||
rts
|
||
;
|
||
; Internal Data
|
||
;
|
||
@blk_cnt dc.l null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
put_in_cache PROC Export
|
||
|
||
EXPORT get_from_cache
|
||
EXPORT c_strt_buffer
|
||
EXPORT c_strt_rqst_cnt
|
||
EXPORT c_strt_blk_num
|
||
EXPORT cache_valid
|
||
|
||
get_from_cache sec
|
||
rts
|
||
|
||
c_strt_buffer
|
||
c_strt_rqst_cnt
|
||
c_strt_blk_num
|
||
cache_valid dc.w null
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;____Device_Tests____
|
||
;*******************************************************
|
||
;
|
||
; 'unit_state'
|
||
;
|
||
; Tests the Target Device to see if it is ready to
|
||
; accept our commands. If the device responds with a
|
||
; CHECK CONDITION, then we will find out why and
|
||
; perform the correct actions.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
; <dib_ptr = Called DIB
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
; <dib_ptr = Called DIB
|
||
;
|
||
; Errors: Carry set if Unit no ready.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT unit_state
|
||
unit_state PROC
|
||
|
||
stz |un_formatted ;**** test Code ****
|
||
;
|
||
; This device is removable. Now we
|
||
; need to check to see if the unit
|
||
; has gone offline, (then we need to
|
||
; report that to the OS) or if the
|
||
; unit has come back online (Rebuild
|
||
; the DIBs).
|
||
;
|
||
@try_again jsr test_unit_rdy ;Is there anything that we should know about?
|
||
bcs @turdy_fail ;Yes.
|
||
@rtg brl @ready_to_go ;No.
|
||
|
||
@turdy_fail
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
cmp #$FE16
|
||
bne @not_down
|
||
brl @off_line
|
||
@not_down
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda |auto_sense_data+\
|
||
rqst_sens.sense_key
|
||
beq @rtg
|
||
cmp #$ffff
|
||
beq @try_again
|
||
|
||
and #$00ff
|
||
cmp #$0006
|
||
beq @do_switch
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
cmp #$0002
|
||
bne @on_line_hd
|
||
brl @off_line
|
||
@on_line_hd lda auto_sense_data+\ ;Was it a RESET?
|
||
rqst_sens.addnl_sens_code
|
||
and #$00fe
|
||
cmp #$0028 ;Checking for $28 (Medium Changed), $29 (RESET)
|
||
bne @io_error
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
|
||
lda auto_sense_data+\ ;Was it a RESET?
|
||
rqst_sens.addnl_sens_code
|
||
and #$00ff
|
||
cmp #$00b7 ;Checking for $B7 (Media being mounted)
|
||
beq @do_switch
|
||
cmp #$00b0 ;Checking for $B0 (NO MEDIA)
|
||
bne @on_line_cd
|
||
brl @off_line
|
||
@on_line_cd and #$00fe
|
||
cmp #$0028 ;Checking for $28 (Medium Changed), $29 (RESET)
|
||
|
||
beq @no_error_cd
|
||
brl @io_error
|
||
@no_error_cd
|
||
;
|
||
; Set this location to a $B0. This will
|
||
; prevent problems if the device is reset
|
||
; durring startup while auto sensing is
|
||
; off.
|
||
;
|
||
lda #$00b0
|
||
sta auto_sense_data+\
|
||
rqst_sens.addnl_sens_code
|
||
bra unit_state
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
|
||
cmp #$0008 ;**** test Code ****
|
||
bne @err_8 ;**** test Code ****
|
||
@no_format dec |un_formatted ;**** test Code ****
|
||
brl @io_error ;**** test Code ****
|
||
|
||
@err_8 lda auto_sense_data+\ ;Was it a RESET?
|
||
rqst_sens.addnl_sens_code
|
||
and #$00ff
|
||
|
||
cmp #$00a7 ;Checking for $A7 (Load Error, UnFormatted)
|
||
beq @no_format
|
||
|
||
cmp #$0010 ;Checking for $10 (ID CRC Medium Error)
|
||
beq @no_format
|
||
|
||
cmp #$0011 ;Checking for $11 (Unrecovered Read Error)
|
||
beq @no_format
|
||
|
||
cmp #$0015 ;Checking for $15 (Seek Position Error)
|
||
beq @no_format
|
||
|
||
cmp #$0019 ;Checking for $19 (Defect List Error)
|
||
beq @no_format
|
||
|
||
cmp #$0031 ;Checking for $31 (Medium Format corrupted)
|
||
beq @no_format
|
||
|
||
cmp #$0032 ;Checking for $32 (No Defect Spare Location Avail.)
|
||
beq @no_format
|
||
|
||
cmp #$00a8 ;Checking for $A8 (Media being mounted)
|
||
beq @do_switch
|
||
|
||
cmp #$00b0 ;Checking for $B0 (NO MEDIA)
|
||
bne @chk_other
|
||
;
|
||
; No Media. Mark the DIB Hard Ofline also.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
and #dvc_online--\
|
||
$ffff
|
||
ora #dvc_hardofl++\
|
||
dvc_switch++\
|
||
dvc_hard_sw
|
||
sta [dib_ptr],y
|
||
|
||
brl @off_line
|
||
|
||
@chk_other cmp #$0028 ;Checking for $28 (Medium Changed), $29 (RESET)
|
||
bne @io_error
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Rebuild the DIBs.
|
||
;
|
||
@do_switch jsr test_unit_rdy ;Is it ready yet?
|
||
bcc @its_ready ;Yes.
|
||
|
||
;**** test Code ****
|
||
lda |auto_sense_data+\
|
||
rqst_sens.sense_key
|
||
and #$00ff
|
||
cmp #$0008
|
||
bne @not_err_8
|
||
@no_format2 dec |un_formatted
|
||
bra @its_ready
|
||
; brl @io_error
|
||
;**** test Code ****
|
||
|
||
@not_err_8 lda auto_sense_data+\ ;Is there media in the drive?
|
||
rqst_sens.addnl_sens_code
|
||
and #$00ff
|
||
|
||
cmp #$00a7 ;Checking for $A7 (Load Error, UnFormatted)
|
||
beq @no_format2
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
|
||
cmp #$0028 ;Checking for $28 (Medium Changed)
|
||
beq @do_switch ;Yes.
|
||
cmp #$0029 ;Checking for $29 (Power On/Reset)
|
||
beq @do_switch ;Yes.
|
||
cmp #$00A8 ;Checking for $A8 (Cart Loading)
|
||
beq @do_switch ;Yes.
|
||
cmp #$00b0 ;Checking for $B0 (NO MEDIA)
|
||
bne @no_format2 ;No.
|
||
|
||
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
cmp #$00b0 ;Checking for $B0 (NO MEDIA)
|
||
bne @do_switch ;No.
|
||
; bcs @do_switch ;*************************
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
|
||
@its_ready
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype <> mcd_40 THEN
|
||
|
||
jsr set_512_mode
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Issue the READ CAPACITY Command.
|
||
;
|
||
jsr read_capacity
|
||
bcs @over_0 ;Was there an error?
|
||
;
|
||
; Get the Block Count (Stored
|
||
; High >> Low. Must be switched
|
||
; to Low >> High). This is the last
|
||
; readable block number. Add 1 to
|
||
; it for comparison reasons.
|
||
;
|
||
lda |block.count\
|
||
+internal_buff\
|
||
+2
|
||
xba
|
||
adc #$0001
|
||
sta |t_dvc_blocks
|
||
lda |block.count\
|
||
+internal_buff
|
||
xba
|
||
adc #null
|
||
sta |t_dvc_blocks+2
|
||
|
||
@over_0 stz |trash_it ;DO NOT TRASH THIS DISK.
|
||
|
||
pei <dib_ptr
|
||
pei <dib_ptr+2
|
||
|
||
jsr rebld_dibs ;Rebuild DIBs and Issue a DISK_SW for each
|
||
|
||
tax
|
||
pla
|
||
sta <dib_ptr+2
|
||
pla
|
||
sta <dib_ptr
|
||
txa
|
||
|
||
php
|
||
;
|
||
; Restore the original Direct Page values.
|
||
;
|
||
jsr set_our_dp
|
||
plp
|
||
bcc @switch_error
|
||
jsr test_unit_rdy
|
||
bcs @io_error
|
||
;
|
||
; Disk Switched Error.
|
||
;
|
||
@switch_error lda #drvr_dsk_swch
|
||
sec
|
||
rts
|
||
;
|
||
; Some kind of I/O Error.
|
||
;
|
||
@io_error lda #drvr_io
|
||
sec
|
||
rts
|
||
;
|
||
; Are we really ready to go? If the
|
||
; dvc_hard_sw flag is set, then we
|
||
; will clear it and report the device
|
||
; as switched.
|
||
;
|
||
@ready_to_go ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
tax
|
||
|
||
and #dvc_hard_sw
|
||
beq @no_switch
|
||
|
||
txa
|
||
and #dvc_hard_sw--\
|
||
$ffff
|
||
sta [dib_ptr],y
|
||
|
||
@no_switch lda #null
|
||
clc
|
||
@rts rts
|
||
;
|
||
; Device is currently offline.
|
||
;
|
||
@off_line lda #drvr_off_line
|
||
sec
|
||
rts
|
||
|
||
EXPORT un_formatted ;**** test Code ****
|
||
un_formatted dc.w null ;**** test Code ****
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'test_unit_rdy'
|
||
;
|
||
; Test the Target Device to see if it is ready to
|
||
; accept our commands. If the device responds with a
|
||
; CHECK CONDITION, then it will be up to the caller of
|
||
; this routine to find out why. This is not a test
|
||
; routine.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit no ready.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT test_unit_rdy
|
||
test_unit_rdy PROC
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@test_unit_p
|
||
sta <scsi_mdrvr
|
||
lda #^@test_unit_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; It's a Status Call.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jmp |main_drvr
|
||
;
|
||
; Data for this call
|
||
; TEST UNIT READY Command Packet
|
||
;
|
||
@test_unit_p dc.b $00 ;Command Number
|
||
dc.b $00 ;SCSI Command Flags
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Resrved
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'CHK_PLAY_MODE'
|
||
;
|
||
; This command is used to tell if the device is
|
||
; currently in Audio Play Mode.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set not in play mode
|
||
;
|
||
;*******************************************************
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
|
||
EXPORT chk_play_mode
|
||
chk_play_mode PROC
|
||
;
|
||
; First, disable auto sensing.
|
||
;
|
||
ldy #dib.rslt_ptr
|
||
lda [dib_ptr],y
|
||
pha
|
||
lda #null
|
||
sta [dib_ptr],y
|
||
|
||
ldy #dib.rslt_ptr+2
|
||
lda [dib_ptr],y
|
||
pha
|
||
lda #null
|
||
sta [dib_ptr],y
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm length.
|
||
;
|
||
lda #$0006
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@chk_play
|
||
sta <scsi_mdrvr
|
||
lda #^@chk_play
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; Set Buff Pointer.
|
||
;
|
||
lda #@play_data
|
||
sta <buff_ptr
|
||
lda #^@play_data
|
||
sta <buff_ptr+2
|
||
;
|
||
; It's a Status Call.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jsr |main_drvr
|
||
bcs @restore_dp ;Carry is set. Not play mode
|
||
;
|
||
; Check the Status.
|
||
;
|
||
; Status $00 = In play mode
|
||
; $01 = Pause (Play Mode)
|
||
; $02 = Muting (Play Mode)
|
||
;
|
||
; $03 = Play completed (No Play)
|
||
; $04 = Error (No Play)
|
||
; $05 = Play not requested.
|
||
;
|
||
lda @play_data
|
||
and #$0007
|
||
cmp #$0003 ; <3 = Carry Clear. =>3 = Carry set
|
||
;
|
||
; Restore the Direct Page Values.
|
||
;
|
||
@restore_dp php
|
||
jsr set_our_dp
|
||
plp
|
||
;
|
||
; Restore Auto Sensing Pointer.
|
||
;
|
||
ldy #dib.rslt_ptr+2
|
||
pla
|
||
sta [dib_ptr],y
|
||
|
||
ldy #dib.rslt_ptr
|
||
pla
|
||
sta [dib_ptr],y
|
||
|
||
rts
|
||
;
|
||
; AUDIO STATUS Command Packet
|
||
;
|
||
@chk_play dc.b $cc ;Command Number
|
||
dc.b null ;SCSI Command Flags
|
||
dcb.b 10,null ;Reserved
|
||
;
|
||
; Data received for this call
|
||
;
|
||
@play_data dcb.b 6,null
|
||
|
||
ENDP
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; The REQUEST SENSE Call is used to request any
|
||
; information from the target device that might tell
|
||
; us something about the way that the last call
|
||
; competed. This call should always be issued if any
|
||
; SCSI Command returns from the SCSI Manager with a
|
||
; CHECK CONDITION in the status result field. The
|
||
; data returned will be kept until the next REQUEST
|
||
; SENSE Command is issued. A flag however will be set
|
||
; if any other commands are received by the SCSI Driver
|
||
; indicating that this data is outdated.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; |sense_data = Data returned by the device
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit no ready.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT rqst_sense
|
||
rqst_sense PROC
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@rqst_sens_p
|
||
sta <scsi_mdrvr
|
||
lda #^@rqst_sens_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; 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 our own buffer pointer
|
||
; for this call.
|
||
;
|
||
lda #sense_data
|
||
sta <buff_ptr
|
||
lda #^sense_data
|
||
sta <buff_ptr+2
|
||
;
|
||
; Set our own request count
|
||
; for this call.
|
||
;
|
||
lda #$0012
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; It's a Status Call.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
stz @error
|
||
jsr |main_drvr
|
||
bcc @return_dp
|
||
;
|
||
; Save error code
|
||
;
|
||
sta @error
|
||
;
|
||
; 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 resutl.
|
||
;
|
||
lda @error
|
||
cmp #$0001
|
||
rts
|
||
;
|
||
; Data for this call
|
||
;
|
||
@error dc.w null
|
||
;
|
||
; REQUEST SENSE Command Packet
|
||
;
|
||
@rqst_sens_p dc.b $03 ;Command Number
|
||
dc.b $00 ;SCSI Command Flags
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Reserved
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'reserve_unit'
|
||
;
|
||
; The RESERVE UNIT Call is used to reserve the target
|
||
; device for use by this host only.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; |sense_data = Data returned by the device
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit already reserved.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT reserve_unit
|
||
reserve_unit PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = scanner THEN
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@rsrv_unit_p
|
||
sta <scsi_mdrvr
|
||
lda #^@rsrv_unit_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; It's a Control Call.
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jmp |main_drvr
|
||
;
|
||
; RESERVE UNIT Command Packet
|
||
;
|
||
@rsrv_unit_p dc.b $16 ;Command Number
|
||
dc.b $00 ;SCSI Command Flags
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Reserved
|
||
|
||
ELSE ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'release_unit'
|
||
;
|
||
; The RELEASE UNIT Call is used to release the target
|
||
; device from use by this host only.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; |sense_data = Data returned by the device
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT release_unit
|
||
release_unit PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = scanner THEN
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@rles_unit_p
|
||
sta <scsi_mdrvr
|
||
lda #^@rles_unit_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; It's a Control Call.
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jmp |main_drvr
|
||
;
|
||
; RELEASE UNIT Command Packet
|
||
;
|
||
@rles_unit_p dc.b $17 ;Command Number
|
||
dc.b $00 ;SCSI Command Flags
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Reserved
|
||
|
||
ELSE ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'mode_sense'
|
||
;
|
||
; This routine issues an MODE SENSE call to the device.
|
||
;
|
||
; Inputs: <dib_ptr = DIB start (LONG)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT mode_sense
|
||
mode_sense PROC
|
||
;
|
||
; And our buffer
|
||
;
|
||
lda #internal_buff
|
||
sta <buff_ptr
|
||
lda #^internal_buff
|
||
sta <buff_ptr+2
|
||
bra command_ptr
|
||
|
||
EXPORT mode_sense2
|
||
;
|
||
; And our buffer
|
||
;
|
||
mode_sense2 lda #sense_data
|
||
sta <buff_ptr
|
||
lda #^sense_data
|
||
sta <buff_ptr+2
|
||
;
|
||
; Tell the Main Driver where
|
||
; our command structure resides.
|
||
;
|
||
command_ptr lda #@start_mode
|
||
sta <scsi_mdrvr
|
||
lda #^@start_mode
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; And our length of $ff Bytes
|
||
;
|
||
lda #$0014
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; Initialize the Page code to 1
|
||
;
|
||
lda #$0001
|
||
sta @page_code
|
||
;
|
||
; Set internal command flag
|
||
;
|
||
@try_again dec |internal
|
||
;
|
||
; Set the Call Type and Issue the
|
||
; MODE SENSE Command.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
jsr |main_drvr
|
||
bcc @rts
|
||
pha
|
||
lda @page_code
|
||
beq @pla
|
||
pla
|
||
stz @page_code
|
||
bra @try_again
|
||
|
||
@pla pla
|
||
@rts rts
|
||
;
|
||
; Data for the MODE SENSE Command
|
||
;
|
||
@start_mode dc.b $1a
|
||
dc.b $00
|
||
@page_code dc.b $01
|
||
dcb.b 9,$00
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'read_capacity'
|
||
;
|
||
; This routine issues an READ CAPACITY call to the
|
||
; device and then uses the data returned to fill in
|
||
; some of the blank holes in the DIB.
|
||
;
|
||
; Inputs: <dib_ptr = DIB start (LONG)
|
||
; Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Carry = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT read_capacity
|
||
read_capacity PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF block_dvc = true\
|
||
AND character_dvc = false THEN
|
||
;
|
||
; Set internal command flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Tell the Main Driver where
|
||
; our command structure resides.
|
||
;
|
||
lda #@read_cap
|
||
sta <scsi_mdrvr
|
||
lda #^@read_cap
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; And our buffer
|
||
;
|
||
lda #internal_buff
|
||
sta <buff_ptr
|
||
lda #^internal_buff
|
||
sta <buff_ptr+2
|
||
;
|
||
; And our length of $ff Bytes
|
||
;
|
||
lda #$0008
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
; Set the Call Type and Issue the
|
||
; READ CAPACITY Command.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
jsr |main_drvr
|
||
rts
|
||
;
|
||
; Data for the READ CAPACITY Command
|
||
;
|
||
@read_cap dc.b $25
|
||
dcb.b 11,$00
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'get_data_status'
|
||
;
|
||
; The GET DATA STATUS Call is used to find out how
|
||
; much data is available to be read from the Scanner.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; |sense_data = Data returned by the device
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT get_data_status
|
||
get_data_status PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = scanner THEN
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@get_d_stat_p
|
||
sta <scsi_mdrvr
|
||
lda #^@get_d_stat_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; 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 our own buffer pointer
|
||
; for this call.
|
||
;
|
||
lda #sense_data
|
||
sta <buff_ptr
|
||
lda #^sense_data
|
||
sta <buff_ptr+2
|
||
;
|
||
; Set our own request count
|
||
; for this call.
|
||
;
|
||
lda #$000C
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; It's a Status Call.
|
||
;
|
||
lda #scsit_stat
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jsr |main_drvr
|
||
;
|
||
; Save error code
|
||
;
|
||
sta @error
|
||
;
|
||
; 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 resutl.
|
||
;
|
||
lda @error
|
||
cmp #$0001
|
||
rts
|
||
;
|
||
; Data for this call
|
||
;
|
||
@error dc.w null
|
||
;
|
||
; GET DATA STATUS Command Packet
|
||
;
|
||
@get_d_stat_p dc.b $34 ;Command Number
|
||
dc.b $00 ;SCSI Command Flags
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Reserved
|
||
|
||
ELSE ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF ;scsi_dtype = scanner
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____Dvc_Controls____
|
||
;*******************************************************
|
||
;
|
||
; 'start_unit'
|
||
;
|
||
; Issue a START UNIT Command to the target device
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT start_unit
|
||
start_unit PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
and #removable
|
||
bne @do_it
|
||
rts
|
||
|
||
@do_it
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Set Stop Flag
|
||
;
|
||
lda #$0001
|
||
tsb |stop_bit
|
||
bra start_stop
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'stop_unit'
|
||
;
|
||
; Issue a STOP UNIT Command to the target device
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT stop_unit
|
||
stop_unit
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
and #removable
|
||
bne @do_it
|
||
rts
|
||
|
||
@do_it
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Set Stop Flag
|
||
;
|
||
lda #$0001
|
||
trb |stop_bit
|
||
;
|
||
; Secondary entry point for START_UNIT
|
||
; Command
|
||
;
|
||
EXPORT start_stop
|
||
start_stop
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #@start_stop_p
|
||
sta <scsi_mdrvr
|
||
lda #^@start_stop_p
|
||
sta <scsi_mdrvr+2
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
|
||
;
|
||
; Set IMMED Bit
|
||
;
|
||
lda #immed_load
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Set IMMED Bit
|
||
;
|
||
lda #immed_loc
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
tsb @immed_loc
|
||
;
|
||
; It's a Control Call.
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jmp |main_drvr
|
||
;
|
||
; Data for this call
|
||
; TEST UNIT READY Command Packet
|
||
;
|
||
@start_stop_p dc.b $1B ;Command Number
|
||
@immed_loc dc.b $00 ;SCSI Command Flags
|
||
dcb.b 2,$00 ;Reserved
|
||
EXPORT stop_bit
|
||
stop_bit dc.b $00 ;Start/Stop Bit
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Resrved
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'SET 512 MODE'
|
||
;
|
||
; This command is used to tell the device to set it's
|
||
; block size to 512 mode. This is used for the CD-ROM
|
||
; Drives as well as any others that may need this
|
||
; function.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Error Code if any
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if call failed
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT set_512_mode
|
||
set_512_mode PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF block_dvc = true\
|
||
AND character_dvc = false THEN
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
|
||
clc
|
||
rts
|
||
|
||
ELSE ;scsi_dtype = mcd_40 THEN
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;
|
||
; Set try twice flag.
|
||
;
|
||
dec @try_twice
|
||
;
|
||
; Set Internal Command Flag
|
||
;
|
||
dec |internal
|
||
;
|
||
; Set Parm length.
|
||
;
|
||
lda #end_4_512-\
|
||
data_4_512
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
@try_again lda #@set_512_p
|
||
sta <scsi_mdrvr
|
||
lda #^@set_512_p
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; Set Parm Pointer.
|
||
;
|
||
lda #data_4_512
|
||
sta <buff_ptr
|
||
lda #^data_4_512
|
||
sta <buff_ptr+2
|
||
;
|
||
; It's a Control Call.
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the Call
|
||
;
|
||
jsr |main_drvr
|
||
bcc @alles_klar
|
||
;
|
||
; Set Parm length.
|
||
;
|
||
lda #$0000000c
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
|
||
inc @try_twice
|
||
beq @try_again
|
||
;
|
||
; Restore the values we destroyed
|
||
;
|
||
@alles_klar stz @try_twice
|
||
php
|
||
pha
|
||
jsr set_our_dp
|
||
pla
|
||
plp
|
||
rts
|
||
;
|
||
; Data for this call
|
||
;
|
||
@try_twice dc.w null
|
||
;
|
||
; TEST UNIT READY Command Packet
|
||
;
|
||
@set_512_p dc.b $15 ;Command Number
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
;
|
||
; Set bit to save these values
|
||
;
|
||
dc.b $01
|
||
|
||
ENDIF ;scsi_dtype = direct_acc
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
;
|
||
; Clear bit to save these values
|
||
;
|
||
dc.b $00
|
||
|
||
ENDIF ;scsi_dtype = apple_cd or changer
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
dcb.b 3,$00 ;Reserved
|
||
dc.b $00 ;Vendor Unique
|
||
dcb.b 6,$00 ;Resrved
|
||
;
|
||
; Data sent durring this call
|
||
;
|
||
data_4_512 dc.b null
|
||
dc.b $00
|
||
dc.b null
|
||
dc.b $08
|
||
;number of blocks
|
||
dc.b null
|
||
dc.b $00
|
||
dc.b $00
|
||
dc.b $00
|
||
;block size
|
||
dc.b null
|
||
dc.b $00
|
||
dc.b $02
|
||
dc.b $00
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
|
||
end_4_512
|
||
|
||
EXPORT select_page_num
|
||
select_page_num dc.b $01 ;Page Number
|
||
dc.b $06 ;Page Length
|
||
dc.b $e4 ;Error Correction Flags
|
||
dc.b $03 ;Retry Count
|
||
dc.b $00 ;Correction Span
|
||
dc.b $00 ;Head Offset Count
|
||
dc.b $00 ;Data Strobe Offset
|
||
dc.b $00 ;Recovery Time Limit
|
||
|
||
ELSE ;scsi_dtype = apple_cd or changer
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
;Page 1 Data
|
||
EXPORT select_page_num
|
||
select_page_num dc.b $01 ;Page Number
|
||
dc.b $06 ;Page Length
|
||
dc.b $e4 ;Error Correction Flags
|
||
dc.b $03 ;Retry Count
|
||
dc.b $00 ;Correction Span
|
||
dc.b $00 ;Head Offset Count
|
||
dc.b $00 ;Data Strobe Offset
|
||
dc.b $00 ;Recovery Time Limit
|
||
end_4_512
|
||
|
||
ENDIF ;scsi_dtype = apple_cd or changer
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDIF ;scsi_dtype = mcd_40
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ELSE ;block_dvc = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF ;block_dvc = true
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____Evnt_Support____
|
||
;*******************************************************
|
||
;
|
||
; 'notify_me'
|
||
;
|
||
; This routine gets called by the SCSI Manager when
|
||
; some event occurs that is out of the ordinary.
|
||
;
|
||
; Inputs: None Yet
|
||
;
|
||
; Outputs: All Regs = Scrambled
|
||
;
|
||
; Errors: None Yet
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT notify_me
|
||
notify_me PROC
|
||
;
|
||
; Vector for the SCSI Manager
|
||
; to call when an event occurs
|
||
; that affects my DIB
|
||
; structures. This could be a
|
||
; new device online or media
|
||
; insertion.
|
||
;
|
||
clc ;Add CODE LATER
|
||
rtl
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;____Misc_Support____
|
||
;*******************************************************
|
||
;
|
||
; SET_DISK_SW
|
||
;
|
||
; This routine checks the validity of the partition
|
||
; map block currently loaded in the internal buffer.
|
||
; This need only be called once per device. If the
|
||
; map is valid, then the carry will be clear. The 'Z'
|
||
; flag will also be set if this is not the first time
|
||
; that this routine was called for this device. If
|
||
; the carry is set, then the map was invalid and the
|
||
; block count at 'T_DVC_BLOCKS' has been placed in the
|
||
; DIB pointed to by 'DIB_PTR'. The starting block will
|
||
; also have been set to null.
|
||
;
|
||
; Inputs: <DIB_PTR = DIB Location
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; = Z = 0 if routine called before
|
||
; = C = 1 if not a partition map
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Only those allowed by the System Service
|
||
; Call SET_DISKSW.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT set_disk_sw
|
||
set_disk_sw PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF block_dvc = true\
|
||
AND character_dvc = false THEN
|
||
;
|
||
; Check the removable flag. If the media
|
||
; is removable, then we will only set the
|
||
; switch flag and let the status calls do
|
||
; their thing before this device goes
|
||
; online. If it is non-removable, then
|
||
; we need to say that the device is
|
||
; switched, but also set the online bits.
|
||
;
|
||
ldy #dib.dvcchar
|
||
lda [dib_ptr],y
|
||
and #removable
|
||
beq @non_removable
|
||
;
|
||
; Set the Disk Switched Bit in Status.
|
||
;
|
||
ldy #dib.dvcflag
|
||
lda [dib_ptr],y
|
||
ora #dvc_switch
|
||
sta [dib_ptr],y
|
||
bra @over1
|
||
;
|
||
; Set the Disk Online Bit in Status.
|
||
;
|
||
@non_removable lda leave_switched ; *** MSG 12/12/91 ***
|
||
bmi @over1 ; *** MSG 12/12/91 ***
|
||
|
||
ldy #dib.dvcflag ; *** MSG 12/12/91 ***
|
||
;@non_removable ldy #dib.dvcflag ; *** MSG 12/12/91 ***
|
||
lda [dib_ptr],y
|
||
and #$ffff--\
|
||
dvc_switch--\
|
||
dvc_hardofl
|
||
ora #dvc_online
|
||
sta [dib_ptr],y
|
||
;
|
||
; Preserve the World from this.
|
||
;
|
||
@over1 ldx |gsos_dpage
|
||
|
||
lda >dev_num,x
|
||
pha
|
||
lda >dib_ptr,x
|
||
pha
|
||
lda >dib_ptr+2,x
|
||
pha
|
||
lda <dev_num
|
||
sta >dev_num,x
|
||
lda <dib_ptr
|
||
sta >dib_ptr,x
|
||
lda <dib_ptr+2
|
||
sta >dib_ptr+2,x
|
||
|
||
txa
|
||
tcd
|
||
|
||
jsl set_disksw
|
||
tay
|
||
|
||
lda |direct_page
|
||
tcd
|
||
|
||
ldx |gsos_dpage
|
||
pla
|
||
sta >dib_ptr+2,x
|
||
pla
|
||
sta >dib_ptr,x
|
||
pla
|
||
sta >dev_num,x
|
||
|
||
stz leave_switched ;Clear this flag *** MSG 12/12/91 ***
|
||
|
||
tya
|
||
cmp #$0001
|
||
rts
|
||
;
|
||
; Data for this call
|
||
;
|
||
EXPORT leave_switched
|
||
leave_switched dc.w null ; *** MSG 12/12/91 ***
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; TRASH_VOLUME
|
||
;
|
||
; This routine write a non-formatted pattern to block
|
||
; 2 of the volume whose DIB is [dib_ptr]. This is to
|
||
; force the OS to re-format or lay down the OS data for
|
||
; that volume rather than using what is already there
|
||
; and appears to be valid.
|
||
;
|
||
; Inputs: <DIB_PTR = DIB Location
|
||
; |trash_it = Boolean
|
||
; 0 = Trash the Volume
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Better be none.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT trash_volume
|
||
trash_volume PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
;
|
||
; Should we really trash the volume?
|
||
;
|
||
lda |trash_it
|
||
beq @dont_trash
|
||
;
|
||
; Set Main Driver Pointer to
|
||
; our data for the command.
|
||
;
|
||
lda #@cmd_$800A
|
||
sta <scsi_mdrvr
|
||
lda #^@cmd_$800A
|
||
sta <scsi_mdrvr+2
|
||
;
|
||
; Set our buffer Pointer to
|
||
; our Code for the data for
|
||
; the command.
|
||
;
|
||
lda #trash_volume
|
||
sta <buff_ptr
|
||
lda #^trash_volume
|
||
sta <buff_ptr+2
|
||
;
|
||
; Set length of our data for the
|
||
; command.
|
||
;
|
||
lda #block_size
|
||
sta <rqst_cnt
|
||
stz <rqst_cnt+2
|
||
;
|
||
; Call Main Driver
|
||
;
|
||
lda #scsit_cont
|
||
sta |call_type
|
||
;
|
||
; Issue the call.
|
||
;
|
||
jsr check_532_rw
|
||
|
||
@dont_trash rts
|
||
|
||
;
|
||
; Command Data for this call.
|
||
;
|
||
@cmd_$800A dc.b $0A
|
||
dc.b $00
|
||
dc.b $00
|
||
dc.b $02
|
||
dc.b $01
|
||
dcb.b 7,$00
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'SAVE_DP'
|
||
;
|
||
; This routine is only called durring the initial
|
||
; startup. It saves away the current values on GS/OS
|
||
; Direct Page so that we can use the space until we
|
||
; have our own Direct Page.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT save_dp
|
||
save_dp PROC
|
||
;
|
||
; Check to see if this call was
|
||
; nested.
|
||
;
|
||
lda |valid
|
||
bne @exit
|
||
;
|
||
; Calculate Source Address.
|
||
;
|
||
clc
|
||
lda |gsos_dpage
|
||
adc #start_our_zp
|
||
pea $0000
|
||
pha
|
||
;
|
||
; Destination Address of temporary
|
||
; storage
|
||
;
|
||
pushlong #saved_zp
|
||
|
||
pushlong #end_our_zp-\ ;Length of the move
|
||
start_our_zp
|
||
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
|
||
dec |valid
|
||
|
||
@exit rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; Move the contents of the first $20 bytes of GS/OS
|
||
; Direct Page to our Direct Page.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit is not the only
|
||
; device in this linke that is still
|
||
; online.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT restore_dp
|
||
restore_dp PROC
|
||
;
|
||
; Check to see if this call was
|
||
; nested.
|
||
;
|
||
lda |valid
|
||
beq @exit
|
||
;
|
||
; Source Address of temporary
|
||
; storage
|
||
;
|
||
pushlong #saved_zp
|
||
;
|
||
; Calculate Destination Address.
|
||
;
|
||
clc
|
||
lda |gsos_dpage
|
||
adc #start_our_zp
|
||
pea $0000
|
||
pha
|
||
|
||
pushlong #end_our_zp-\ ;Length of the move
|
||
start_our_zp
|
||
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
|
||
stz |valid
|
||
|
||
@exit rts
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; Move the contents of the first $20 bytes of GS/OS
|
||
; Direct Page to our Direct Page.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if Unit is not the only
|
||
; device in this linke that is still
|
||
; online.
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT set_our_dp
|
||
set_our_dp PROC
|
||
;
|
||
; Calculate Source Address.
|
||
;
|
||
clc
|
||
lda |gsos_dpage
|
||
adc #dev_num
|
||
pea $0000
|
||
pha
|
||
;
|
||
; Calculate Destination Address of
|
||
; our Direct Page that we want.
|
||
;
|
||
clc
|
||
lda |direct_page
|
||
adc #dev_num
|
||
pea $0000
|
||
pha
|
||
|
||
pushlong #dib_ptr+4 ;Length of the move
|
||
|
||
pushword #move_sinc_dinc
|
||
|
||
jsl move_info ;Move the data
|
||
rts
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'check_532_rw'
|
||
;
|
||
; There are a few drives that have been formated with
|
||
; 512 ($214) bytes per block. These devices work
|
||
; perfectly fine in single block I/O, padding the end
|
||
; with 20 bytes in a write, or stripping them for a
|
||
; read, but when doing a multi-block transaction we
|
||
; need to account for the 20 bytes between the end of
|
||
; real data for this block and the beginning of the
|
||
; next block. Because of this, we will need to build
|
||
; a data chaining structure that will read or write
|
||
; 512 bytes of data to the users buffer, followed by
|
||
; 20 bytes read or written to ROM space. Doing this
|
||
; will hinder performance and will prevent caching
|
||
; from working. If these are important to the user,
|
||
; they can reformat their drive.
|
||
;
|
||
; This routine is called in place of calling the Main
|
||
; Driver. It decides if the call should go via the
|
||
; normal or 532 method. All Inputs, Outputs and Setup
|
||
; Structures are the same.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT check_532_rw
|
||
check_532_rw PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
;
|
||
; Check for 532 byte block.
|
||
;
|
||
ldy #dib.blksize
|
||
lda [dib_ptr],y
|
||
cmp #$214
|
||
beq @do_532
|
||
jmp |main_drvr
|
||
|
||
@do_532 jmp munge_532
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ELSE
|
||
|
||
jmp |main_drvr
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'munge_532'
|
||
;
|
||
; There are a few drives that have been formated with
|
||
; 512 ($214) bytes per block. These devices work
|
||
; perfectly fine in single block I/O, padding the end
|
||
; with 20 bytes in a write, or stripping them for a
|
||
; read, but when doing a multi-block transaction we
|
||
; need to account for the 20 bytes between the end of
|
||
; real data for this block and the beginning of the
|
||
; next block. Because of this, we will need to build
|
||
; a data chaining structure that will read or write
|
||
; 512 bytes of data to the users buffer, followed by
|
||
; 20 bytes read or written to ROM space. Doing this
|
||
; will hinder performance and will prevent caching
|
||
; from working. If these are important to the user,
|
||
; they can reformat their drive.
|
||
;
|
||
; This routine is called in place of calling the Main
|
||
; Driver. All Inputs, Outputs and Setup Structures
|
||
; are the same.
|
||
;
|
||
; Inputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = Ours
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT munge_532
|
||
munge_532 PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
|
||
;
|
||
; Set User's buffer location
|
||
;
|
||
lda <buff_ptr
|
||
sta |@User_buff
|
||
lda <buff_ptr+2
|
||
sta |@User_buff+2
|
||
;
|
||
; Generate a block count.
|
||
;
|
||
stz @block_cnt
|
||
lda <rqst_cnt+2
|
||
sta @block_cnt+1
|
||
lda <rqst_cnt
|
||
and #$fe00
|
||
cmp <rqst_cnt
|
||
beq @equal_512
|
||
|
||
lda #drvr_bad_cnt
|
||
sec
|
||
rts
|
||
|
||
@equal_512 lsr @block_cnt+1
|
||
ror a
|
||
tsb @block_cnt-1
|
||
;
|
||
; Adjust users request cnt to reflect
|
||
; that there are 20 bytes/block more
|
||
; to transfer than the user requested.
|
||
; This is done by multiplying the block
|
||
; count that we just calculated bu $14.
|
||
;
|
||
; First preserve the old value.
|
||
;
|
||
lda <rqst_cnt+2
|
||
sta @rqst_cnt+2
|
||
lda <rqst_cnt
|
||
sta @rqst_cnt
|
||
;
|
||
; Now adjust count.
|
||
;
|
||
lda @block_cnt+2
|
||
sta |scratch0+2
|
||
lda @block_cnt
|
||
sta |scratch0
|
||
;
|
||
; x4 first
|
||
;
|
||
asl |scratch0 ;x2
|
||
asl |scratch0+2
|
||
|
||
asl |scratch0 ;x2 (x4)
|
||
asl |scratch0+2
|
||
;
|
||
; Save the x4.
|
||
;
|
||
lda |scratch0
|
||
sta |scratch2
|
||
lda |scratch0+2
|
||
sta |scratch2+2
|
||
;
|
||
; Finish the x16
|
||
;
|
||
asl |scratch0 ;x2 (x8)
|
||
asl |scratch0+2
|
||
|
||
asl |scratch0 ;x2 (x16)
|
||
asl |scratch0+2
|
||
;
|
||
; Add the x4 to x16 for x20
|
||
;
|
||
clc
|
||
lda |scratch0
|
||
adc |scratch2
|
||
sta |scratch0
|
||
lda |scratch0+2
|
||
adc |scratch2+2
|
||
sta |scratch0+2
|
||
;
|
||
; Add the x20 to the original
|
||
; request count.
|
||
;
|
||
clc
|
||
lda |scratch0
|
||
adc <rqst_cnt
|
||
sta <rqst_cnt
|
||
lda |scratch0+2
|
||
adc <rqst_cnt+2
|
||
sta <rqst_cnt+2
|
||
;
|
||
; Drop the Loop Counter by 1.
|
||
;
|
||
sec
|
||
lda @block_cnt
|
||
sbc #$0001
|
||
sta @block_cnt
|
||
lda @block_cnt+2
|
||
sbc #$0000
|
||
sta @block_cnt+2
|
||
;
|
||
; Preserve the data pointer currently
|
||
; used in the DIB and replace it with
|
||
; a pointer to our 532 byte block
|
||
; Data Chaining instructions.
|
||
;
|
||
clc
|
||
ldy #dib.trx_ptr
|
||
lda [dib_ptr],y
|
||
sta |dib_data_struct
|
||
|
||
lda #@munger_DC
|
||
sta [dib_ptr],y
|
||
|
||
ldy #dib.trx_ptr+2
|
||
lda [dib_ptr],y
|
||
sta |dib_data_struct+2
|
||
|
||
lda #^@munger_DC
|
||
sta [dib_ptr],y
|
||
;
|
||
; Preserve the Block size and replace
|
||
; it with $0214
|
||
;
|
||
lda <blk_size
|
||
sta @blk_size
|
||
lda #$0214
|
||
sta <blk_size
|
||
;
|
||
; Issue the call.
|
||
;
|
||
jsr |main_drvr
|
||
;
|
||
; Preserve the result.
|
||
;
|
||
pha
|
||
php
|
||
;
|
||
; Restore the Block size.
|
||
;
|
||
lda @blk_size
|
||
sta <blk_size
|
||
;
|
||
; Restore DIB's data pointer.
|
||
;
|
||
|
||
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
|
||
;
|
||
; Restore the original request count.
|
||
;
|
||
lda @rqst_cnt+2
|
||
sta <rqst_cnt+2
|
||
lda @rqst_cnt
|
||
sta <rqst_cnt
|
||
;
|
||
; Restore state of the call's exit.
|
||
;
|
||
plp
|
||
pla
|
||
;
|
||
; Exit.
|
||
;
|
||
rts
|
||
;
|
||
; Temp Storage area.
|
||
;
|
||
@rqst_cnt dc.l null
|
||
@blk_size dc.w null
|
||
|
||
@munger_DC ;
|
||
; Data Chaining Structure.
|
||
;
|
||
@User_buff dc.l $00000000 ;Users Buffer Space
|
||
dc.l $00000200 ;Request Count
|
||
dc.l $00000200 ;Add to buffer at each pass
|
||
dc.l $00000000 ;Reserved.
|
||
|
||
dc.l $00ff0600 ;Location for spare bytes (ROM)
|
||
dc.l $00000014 ;Number of bogus bytes
|
||
dc.l $00000000 ;Leave buffer pointer alone
|
||
dc.l $00000000 ;Reserved.
|
||
|
||
dc.l $ffffffff ;Looping Command
|
||
@block_cnt dc.l $00000000 ;Block Count
|
||
dc.l $00000000-2 ;Go Back 2 commands
|
||
dc.l $00000000 ;Reserved
|
||
|
||
dc.l $00000000 ;DCStop Command
|
||
dc.l $00000000 ;DCStop Command
|
||
dc.l $00000000 ;DCStop Command
|
||
dc.l $00000000 ;DCStop Command
|
||
|
||
dc.l $00000000 ;Safety space
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ELSE
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'divide'
|
||
;
|
||
; This routine divides a 16 bit number stored in
|
||
; 'divsor' into the 32 bit number stored in 'divend'.
|
||
; The result will be in 'result' if no error occured.
|
||
; If 'divend' is not an integral multiple of 'divsor'
|
||
; an error will be returned.
|
||
;
|
||
; Inputs: 'divsor' = 16 bit number
|
||
; 'divend' = 32 bit number
|
||
; 'max_blk_cnt' = Max Result Allowed
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: 'result' = result of division
|
||
; Acc = Error Code if Carry Set
|
||
; 'max_blk_cnt' = null if no error
|
||
; Intact if an error is returned
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: Carry set if non-integral result
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT divide
|
||
divide PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF block_dvc = true\
|
||
AND character_dvc = false THEN
|
||
;
|
||
; Clear Result field
|
||
;
|
||
stz |result
|
||
stz |result+2
|
||
;
|
||
; 32 bits in result.
|
||
;
|
||
ldx #32-1
|
||
;
|
||
; Make 'divsor' an odd value.
|
||
; This is nothing more than
|
||
; deviding both numbers by 16
|
||
; until 'divsor' is an odd value.
|
||
; If any bits roll out of 'divend'
|
||
; then this was an incorrect call.
|
||
;
|
||
@div16_loop lda |divsor
|
||
cmp #block_size ;Special Case /block_size
|
||
bne @not_512
|
||
lda |divend
|
||
and #block_size-1
|
||
bne @error
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
;
|
||
; Quick Divide by block_size
|
||
;
|
||
lda |divend+3
|
||
and #$00ff
|
||
lsr a
|
||
sta |result+2
|
||
|
||
lda |divend+1
|
||
ror a
|
||
sta |result
|
||
|
||
jmp @chk_rslt
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
;
|
||
; Quick Divide by $0200
|
||
;
|
||
lda |divend+3
|
||
and #$00ff
|
||
lsr a
|
||
sta |result+2
|
||
|
||
lda |divend+1
|
||
ror a
|
||
sta |result
|
||
|
||
jmp @chk_rslt
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
;
|
||
; Quick Divide by $2000
|
||
;
|
||
stz |result
|
||
stz |result+2
|
||
lda |divend+2
|
||
sta |result
|
||
|
||
lda |divend ;$2000
|
||
asl a ;$4000
|
||
rol |result ;x2
|
||
rol |result+2 ;x2
|
||
|
||
asl a ;$8000
|
||
rol |result ;x4
|
||
rol |result+2 ;x4
|
||
|
||
asl a ;$0000
|
||
rol |result ;x8
|
||
rol |result+2 ;x8
|
||
|
||
jmp @chk_rslt
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
@not_512 and #bit_0
|
||
bne @do_divide
|
||
lsr |divsor
|
||
lsr |divend+2
|
||
ror |divend
|
||
bcc @div16_loop
|
||
bra @error
|
||
;
|
||
; Main division loop. We will
|
||
; continue to divide the divsor
|
||
; by 16 until finished. Each
|
||
; time that divsor becomes odd,
|
||
; we will subtract divend and
|
||
; roll a bit into the high end
|
||
; of result.
|
||
;
|
||
@do_divide lda |divend
|
||
and #bit_0
|
||
clc ;We must clear the carry incase
|
||
beq @do_div16 ;the branch is taken.
|
||
;
|
||
; We are odd. Do the subtraction.
|
||
;
|
||
sec
|
||
lda |divend
|
||
sbc |divsor
|
||
sta |divend
|
||
lda |divend+2
|
||
sbc #$0000
|
||
sta |divend+2
|
||
bcc @error ;If this is taken, bad data.
|
||
;
|
||
; Divide both the divsor and
|
||
; results by 16. The carry will
|
||
; roll into the reult from the
|
||
; high bit end.
|
||
;
|
||
@do_div16 php
|
||
lsr |divend+2
|
||
ror |divend
|
||
plp
|
||
@clean_up ror |result+2
|
||
ror |result
|
||
;
|
||
; Have we done 32 bits yet?
|
||
;
|
||
dex
|
||
bmi @chk_rslt ;Yes.
|
||
;
|
||
; No we havent. If divsor is
|
||
; non-zero then do next itteration.
|
||
; If it is = zero then clean up
|
||
; result and exit.
|
||
;
|
||
lda |divend+2
|
||
ora |divend
|
||
bne @do_divide
|
||
;
|
||
; Clean up Result.
|
||
;
|
||
clc
|
||
bra @clean_up
|
||
;
|
||
; Here for bcs offset.
|
||
;
|
||
@error sec
|
||
lda #drvr_bad_cnt
|
||
rts
|
||
;
|
||
; Check to see if the result is within
|
||
; the max.
|
||
;
|
||
@chk_rslt lda |max_blk_cnt
|
||
ora |max_blk_cnt+2
|
||
beq @out
|
||
|
||
sec
|
||
lda |max_blk_cnt
|
||
sbc |result
|
||
sta @temp
|
||
lda |max_blk_cnt+2
|
||
sbc |result+2
|
||
bge @clean
|
||
;
|
||
; Exit
|
||
;
|
||
sec
|
||
lda #drvr_bad_parm
|
||
rts
|
||
|
||
@clean stz |max_blk_cnt
|
||
stz |max_blk_cnt+2
|
||
@out clc
|
||
rts
|
||
;
|
||
; Data Area.
|
||
;
|
||
@temp dc.w null
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
;*******************************************************
|
||
;
|
||
; 'calc_bytes'
|
||
;
|
||
; This routine Multiplies a 16 bit number stored in
|
||
; 'm_blk_size' by a 32 bit number stored in 'm_blk_cnt'.
|
||
; The result will be in 'm_rslt'.
|
||
;
|
||
; Inputs: 'm_blk_size'= 16 bit Block Size
|
||
; 'm_blk_cnt' = 32 bit Block Count
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Outputs: 'm_rslt' = result of division
|
||
; Acc = Unspecified
|
||
; Y register = Unspecified
|
||
; X register = Unspecified
|
||
; P register = 0=M=X=e
|
||
; Direct Page = GS/OS Direct Page
|
||
; Data Bank = Ours
|
||
;
|
||
; Errors: None
|
||
;
|
||
;*******************************************************
|
||
|
||
EXPORT calc_bytes
|
||
calc_bytes PROC
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF block_dvc = true\
|
||
AND character_dvc = false THEN
|
||
;
|
||
; Clear Result field
|
||
;
|
||
stz |m_rslt
|
||
stz |m_rslt+2
|
||
;
|
||
; Check 'm_blk_size' against the block
|
||
; size for this device. If it is Equal,
|
||
; the do cheap processing. Otherwise do
|
||
; full multiply logic.
|
||
;
|
||
@div16_loop lda |m_blk_size
|
||
cmp #block_size ;Special Case *block_size
|
||
bne @not_512
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = direct_acc THEN
|
||
;
|
||
; Quick Multiply by $0200
|
||
;
|
||
lda |m_blk_cnt
|
||
asl a
|
||
sta |m_rslt+1
|
||
|
||
lda |m_blk_cnt+2
|
||
and #$007f
|
||
rol a
|
||
ora |m_rslt+3 ;Watch out for that +4 value.
|
||
sta |m_rslt+3 ;It doesn't belong to us.
|
||
|
||
jmp @clean
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = apple_cd\
|
||
OR scsi_dtype = changer THEN
|
||
;
|
||
; Quick Multiply by $0200
|
||
;
|
||
lda |m_blk_cnt
|
||
asl a
|
||
sta |m_rslt+1
|
||
|
||
lda |m_blk_cnt+2
|
||
and #$007f
|
||
rol a
|
||
ora |m_rslt+3 ;Watch out for that +4 value.
|
||
sta |m_rslt+3 ;It doesn't belong to us.
|
||
|
||
jmp @clean
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
IF scsi_dtype = mcd_40 THEN
|
||
;
|
||
; Quick Multiply by $2000
|
||
;
|
||
lda |m_blk_cnt
|
||
sta |m_rslt+2 ;Cheap * $10000
|
||
|
||
lda |m_blk_cnt+2
|
||
lsr a
|
||
ror |m_rslt+2 ;Cheap * $8000 ( * $10000/2 )
|
||
ror |m_rslt ;Cheap * $8000 ( * $10000/2 )
|
||
|
||
lsr a
|
||
ror |m_rslt+2 ;Cheap * $4000 ( * $10000/4 )
|
||
ror |m_rslt ;Cheap * $4000 ( * $10000/4 )
|
||
|
||
lsr a
|
||
ror |m_rslt+2 ;Cheap * $2000 ( * $10000/8 )
|
||
ror |m_rslt ;Cheap * $2000 ( * $10000/8 )
|
||
|
||
jmp @clean
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
@not_512
|
||
;
|
||
; Actual Multiply Loop.
|
||
;
|
||
lsr |m_blk_size
|
||
bcc @shift_cnt ;Don't Add this one.
|
||
;
|
||
; Add in Current Byte Count.
|
||
clc
|
||
lda |m_rslt
|
||
adc |m_blk_cnt
|
||
sta |m_rslt
|
||
lda |m_rslt+2
|
||
adc |m_blk_cnt+2
|
||
sta |m_rslt+2
|
||
;
|
||
; Multiply Count by 2.
|
||
;
|
||
@shift_cnt asl |m_blk_cnt
|
||
rol |m_blk_cnt+2
|
||
|
||
lda |m_blk_size
|
||
bne @not_512 ;only do till 0 ( <16 times )
|
||
;
|
||
; Clean Exit.
|
||
;
|
||
@clean clc
|
||
rts
|
||
|
||
ELSE
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
lda #null
|
||
clc
|
||
rts
|
||
|
||
ENDIF
|
||
|
||
;-------------------------------------------------------------------------------
|
||
|
||
ENDP
|
||
|
||
EJECT
|
||
|
||
END |