mirror of
https://github.com/antoinevignau/source.git
synced 2025-01-01 15:30:02 +00:00
d29484938c
What we wrote to make audio hearable on a SCSI-2 CD-ROM drive ;-)
1 line
38 KiB
Plaintext
1 line
38 KiB
Plaintext
|
|
;*******************************************************
|
|
;
|
|
; SCSI Driver 'Startup' filter.
|
|
;
|
|
; Written by Matt Gulick. Started July 1,1988
|
|
;
|
|
; Copyright Apple Computer, Inc. 1988,89
|
|
;
|
|
;*******************************************************
|
|
|
|
;*******************************************************
|
|
;
|
|
; This file contains the 'Startup' filter as defined
|
|
; in the ERS.
|
|
;
|
|
;*******************************************************
|
|
|
|
;*******************************************************
|
|
;
|
|
; Revision History:
|
|
;
|
|
;*******************************************************
|
|
;
|
|
; July 1, 1988 File started.
|
|
; July 21, 1988 reworked logic and added
|
|
; a few new subroutines.
|
|
; April 10, 1989 Started to add code for
|
|
; character devices for the
|
|
; Scanner.
|
|
|
|
STRING PASCAL
|
|
BLANKS OFF
|
|
PAGESIZE 70
|
|
PRINT NOGEN
|
|
PRINT NOMDIR
|
|
MACHINE M65816
|
|
|
|
IMPORT wake_me_up
|
|
IMPORT get_mm_id
|
|
IMPORT get_dvc_ram
|
|
IMPORT set_512_mode
|
|
IMPORT select_page_num
|
|
IMPORT test_unit_rdy
|
|
IMPORT start_unit
|
|
IMPORT mode_sense
|
|
IMPORT read_capacity
|
|
IMPORT default_dib
|
|
IMPORT rebld_dibs
|
|
IMPORT dpi_overide
|
|
IMPORT set_our_dp
|
|
IMPORT direct_page
|
|
IMPORT gsos_dpage
|
|
IMPORT main_drvr
|
|
IMPORT internal
|
|
IMPORT internal_buff
|
|
IMPORT get_scsimgr
|
|
IMPORT call_type
|
|
IMPORT fre_dvc_ram
|
|
IMPORT dvc_count
|
|
IMPORT rpm_blk_num
|
|
IMPORT rebuild
|
|
IMPORT part_num
|
|
IMPORT do_part_dib
|
|
IMPORT first_time
|
|
IMPORT part_cnt
|
|
IMPORT chk_ram
|
|
IMPORT dibicise_new_ram
|
|
IMPORT dibicise_new_dib
|
|
IMPORT main_caller
|
|
IMPORT active_starts
|
|
IMPORT tot_dib_cnt
|
|
IMPORT t_dvc_blocks
|
|
IMPORT auto_sense_data
|
|
|
|
ENTRY do_inq_parms
|
|
ENTRY do_mode_parms
|
|
ENTRY do_read_cap
|
|
ENTRY do_partition
|
|
ENTRY get_nxt_dvc
|
|
|
|
PRINT OFF
|
|
|
|
INCLUDE 'scsihd.equates'
|
|
INCLUDE 'M16.MEMORY'
|
|
INCLUDE 'M16.UTIL'
|
|
PRINT ON
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; Main Entry point to the 'Startup' filter. This
|
|
; 'Filter' is called after the driver is loaded. The
|
|
; code that follows sets up the drivers environment,
|
|
; then calls 'get_dvc_ram'. On return from the
|
|
; 'get_dvc_ram' call, the following structure are in
|
|
; place if no error ocured.
|
|
;
|
|
; 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.
|
|
;
|
|
; This contains enough RAM for one DIB for
|
|
; each device in the device list. If more
|
|
; space is needed due to partitioning, then
|
|
; the startup filter will be responsible for
|
|
; getting that space from the memory manager.
|
|
;
|
|
; From this point, we need to build the DIB for each
|
|
; device.
|
|
;
|
|
; Inputs: None.
|
|
;
|
|
; Outputs: Acc = 0
|
|
; Carry = 0
|
|
; Y register = Unspecified
|
|
; X register = Unspecified
|
|
; P register = 0=M=X=e
|
|
; Direct Page = GS/OS Direct Page
|
|
; Data Bank = Ours
|
|
;
|
|
; Errors: See Spec.
|
|
;
|
|
;*******************************************************
|
|
|
|
EXPORT startup
|
|
startup PROC
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF warm_ss_suprt = true THEN
|
|
|
|
;
|
|
; Check to see if this is a WARM STARTUP
|
|
; Call. If it is, we will need to handle
|
|
; this a lot differently than a normal
|
|
; startup. First of all our DIBs are, for
|
|
; the most part, already built. The only
|
|
; possible changes might be in respect to
|
|
; removable media. In any case we will
|
|
; call the warm start routine in the Driver
|
|
; Mgmt file to take care of this for us.
|
|
;
|
|
; Is it a COLD STARTUP?
|
|
;
|
|
lda >warm_cold_flag
|
|
and #$0001
|
|
bne @do_warm ;It's Warm
|
|
@no_warm_start jmp @chk_dflt ;It's Cold
|
|
;
|
|
; Check to see if this is for the
|
|
; 'default_dib'. If it is, then we need
|
|
; to exit with an error. The error is so
|
|
; that our default DIB is purged from the
|
|
; startup list.
|
|
;
|
|
@do_warm lda <dib_ptr
|
|
cmp #default_dib
|
|
bne @not_dflt
|
|
|
|
lda <dib_ptr+2
|
|
cmp #^default_dib
|
|
bne @not_dflt
|
|
|
|
lda #drvr_io ;Error Out.
|
|
sec
|
|
rts
|
|
;
|
|
; Yeah, so it's a WARM STARTUP. But
|
|
; does this device know what that
|
|
; means? We'll see!
|
|
;
|
|
@not_dflt ldy #dib.dvcchar
|
|
lda [dib_ptr],y
|
|
and #restartable
|
|
beq @no_warm_start ;Not restartable.
|
|
;
|
|
; Yeah, so it knows what that means!
|
|
; But first let's see if it is a new
|
|
; DIB.
|
|
;
|
|
ldy #dib.dvcflag
|
|
lda [dib_ptr],y
|
|
tax
|
|
;
|
|
; Compare to default value.
|
|
;
|
|
cmp #wait_mode++\
|
|
cold_dib
|
|
beq @in_valid_dib ;Unused DIB. Reject it.
|
|
;
|
|
; One last check. Is it partitioned
|
|
; and if so, does it also have a valid
|
|
; block offset?
|
|
;
|
|
ldy #dib.dvcchar
|
|
lda [dib_ptr],y
|
|
and #linked_dvc
|
|
beq @valid_dib ;Used DIB. Start it.
|
|
|
|
ldy #dib.start_blk
|
|
lda [dib_ptr],y
|
|
ldy #dib.start_blk+2
|
|
ora [dib_ptr],y
|
|
bne @valid_dib ;Used DIB. Start it.
|
|
;
|
|
; Zero out the Device Number and
|
|
; remove link.
|
|
;
|
|
@in_valid_dib lda #null
|
|
ldy #dib.devnum
|
|
sta [dib_ptr],y
|
|
|
|
ldy #dib.dvcchar
|
|
lda [dib_ptr],y
|
|
and #linked_dvc--\
|
|
$ffff
|
|
sta [dib_ptr],y
|
|
|
|
lda #drvr_no_dev ;Error Out.
|
|
sec
|
|
rts
|
|
;
|
|
;
|
|
@valid_dib txa
|
|
and #cold_dib
|
|
bne @no_warm_start ;New DIB and Awake. Do Cold Start
|
|
;
|
|
; Old DIB. But is it asleep?
|
|
;
|
|
txa
|
|
and #relaxing
|
|
beq @over_wake_up ;Not asleep.
|
|
;
|
|
; Call the Warm Restart Routine.
|
|
;
|
|
jsr wake_me_up
|
|
;
|
|
; The device is now awake. If it is
|
|
; removable we need to see if the
|
|
; disk has been changed.
|
|
;
|
|
@over_wake_up ldy #dib.dvcchar
|
|
lda [dib_ptr],y
|
|
and #removable
|
|
beq @bra_been_had ;Not removable.
|
|
;
|
|
; Rebuild the DIBs for this device if
|
|
; this is the first partition for this
|
|
; device.
|
|
;
|
|
ldy #dib.unitnum
|
|
lda [dib_ptr],y
|
|
and #max_p_mask
|
|
bne @bra_been_had ;Not the head. They've been done already
|
|
;
|
|
; Current pointer is the first.
|
|
;
|
|
lda <dib_ptr+2
|
|
ldx <dib_ptr
|
|
@set_pointer stx <scsi_zp0
|
|
sta <scsi_zp0+2
|
|
;
|
|
; Set the Flags.
|
|
;
|
|
ldy #dib.dvcflag
|
|
lda [scsi_zp0],y
|
|
and #dvc_hardofl--\
|
|
$ffff
|
|
ora #dvc_switch++\
|
|
dvc_online
|
|
sta [scsi_zp0],y
|
|
;
|
|
; If there is a forward device
|
|
; pointer than get it.
|
|
;
|
|
ldy #dib.fdvcptr
|
|
lda [scsi_zp0],y
|
|
tax
|
|
ldy #dib.fdvcptr+2
|
|
lda [scsi_zp0],y
|
|
bne @set_pointer
|
|
|
|
jsr set_512_mode
|
|
lda #$ffff ;Don't Do Post Driver Installs
|
|
sta |dpi_overide
|
|
jsr rebld_dibs ;Rebuild DIBs and Issue a DISK_SW for each
|
|
php
|
|
stz |dpi_overide ;Clear the Overide
|
|
;
|
|
; Restore the origonal Direct Page values.
|
|
;
|
|
jsr set_our_dp
|
|
plp
|
|
bcc @bra_been_had
|
|
jsr test_unit_rdy
|
|
bcc @bra_been_had
|
|
;
|
|
; For some reason, we cannot talk to the
|
|
; device. It must be offline.
|
|
;
|
|
@chk_switch ldy #dib.dvcflag
|
|
lda [dib_ptr],y
|
|
and #dvc_online--\
|
|
$ffff
|
|
sta [dib_ptr],y
|
|
|
|
;@bra_been_had jmp @links_done
|
|
@bra_been_had bra @ive_been_had
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Check to see if this is for the
|
|
; 'default_dib'. If it is, then we need
|
|
; to build all the devices that we can and
|
|
; exit with an error. The error is so that
|
|
; our default DIB is purged from the startup
|
|
; list. The device dispatcher will then
|
|
; call us for the DIB pointed to in the
|
|
; 'default_dib's link pointer. This and any
|
|
; further 'STARTUP' calls will exit with no
|
|
; error, except that no action will be taken
|
|
; other than to increment the startup call
|
|
; count to be used as a balance for the
|
|
; shutdown calls that will eventually be
|
|
; issued.
|
|
;
|
|
@chk_dflt lda <dib_ptr
|
|
cmp #default_dib
|
|
bne @ive_been_had
|
|
|
|
lda <dib_ptr+2
|
|
cmp #^default_dib
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF part_suprt = false Then
|
|
|
|
beq @im_a_virgin
|
|
|
|
@ive_been_had ;
|
|
; Mark the device as started and
|
|
; as online.
|
|
;
|
|
ldy #dib.dvcflag
|
|
lda [dib_ptr],y
|
|
and #cold_dib--\
|
|
$ffff
|
|
|
|
;===============================================================================
|
|
|
|
IF character_dvc = true Then
|
|
|
|
ora #dvc_online
|
|
|
|
ENDIF
|
|
|
|
;===============================================================================
|
|
|
|
sta [dib_ptr],y
|
|
|
|
ELSE
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
bne @ive_been_had
|
|
|
|
jmp @im_a_virgin
|
|
|
|
@ive_been_had
|
|
;
|
|
; Clear the Cold Start Flag.
|
|
;
|
|
ldy #dib.dvcflag
|
|
lda [dib_ptr],y
|
|
and #cold_dib--\
|
|
$ffff
|
|
sta [dib_ptr],y
|
|
|
|
;
|
|
; Check the Partition Bits. If they
|
|
; are all clear, then we will set the
|
|
; head device link to this device.
|
|
;
|
|
ldy #dib.unitnum
|
|
lda [dib_ptr],y
|
|
cmp #$0001
|
|
beq @jmp_links_done
|
|
|
|
and #max_p_mask
|
|
bne @not_head
|
|
;
|
|
; Too far to branch to.
|
|
;
|
|
@jmp_links_done jmp @links_done
|
|
;
|
|
; This is not the first or boot device,
|
|
; nor is it the first or only logical
|
|
; device on this physical device. That
|
|
; means that it is probably partitioned.
|
|
; This means we need to set the head and
|
|
; forward links. The following code will
|
|
; do this for us.
|
|
;
|
|
; Get the Device Number for setting as
|
|
; a forward link. Also save the unit
|
|
; number (less the partition bits) to
|
|
; match the other DIBs from this device.
|
|
;
|
|
@not_head ldy #dib.devnum
|
|
lda [dib_ptr],y
|
|
sta @current_dev
|
|
|
|
ldy #dib.unitnum
|
|
lda [dib_ptr],y
|
|
and #max_p_mask\
|
|
--$ffff
|
|
sta @our_unit
|
|
|
|
ldy #dib.slotnum
|
|
lda [dib_ptr],y
|
|
sta @our_slot
|
|
;
|
|
; Start pointer out at the default DIB.
|
|
;
|
|
lda #default_dib
|
|
sta <scsi_zp4
|
|
|
|
lda #^default_dib
|
|
sta <scsi_zp4+2
|
|
;
|
|
; Main Search loop.
|
|
;
|
|
; Advance pointer to the next DIB. If
|
|
; link is = to zero, then exit loop.
|
|
;
|
|
@links_loop ldy #dib.linkptr+2
|
|
lda [scsi_zp4]
|
|
tax
|
|
ora [scsi_zp4],y
|
|
bne @non_zero
|
|
|
|
jmp @links_done
|
|
|
|
@non_zero lda [scsi_zp4],y
|
|
|
|
@advance sta <scsi_zp4+2
|
|
stx <scsi_zp4
|
|
;
|
|
; Check unit number to see if it is the same.
|
|
;
|
|
ldy #dib.unitnum
|
|
lda [scsi_zp4],y
|
|
and #max_p_mask\
|
|
--$ffff
|
|
cmp @our_unit ;Is it ours?
|
|
bne @links_loop ;No. Check the next one.
|
|
;
|
|
; Check Slot number to see if it is the same.
|
|
;
|
|
ldy #dib.slotnum
|
|
lda [scsi_zp4],y
|
|
cmp @our_slot ;Is it ours?
|
|
bne @links_loop ;No. Check the next one.
|
|
;
|
|
; They are equal. Is the forward link = zero?
|
|
;
|
|
ldy #dib.fdvclnk
|
|
lda [scsi_zp4],y
|
|
; beq @found_end
|
|
; cmp @current_dev
|
|
bne @links_loop ;No. Check the next one.
|
|
;
|
|
; Yes. This DIB has no forward device link.
|
|
; We will volunteer the users DIB for the Job.
|
|
; Set the head Link in the DIB called and the
|
|
; forward link in ours.
|
|
;
|
|
@found_end lda @current_dev
|
|
sta [scsi_zp4],y
|
|
|
|
ldy #dib.headlnk
|
|
lda [scsi_zp4],y
|
|
|
|
beq @stuff_head
|
|
;
|
|
; Set Head Pointer to scsi_zp4
|
|
;
|
|
pha
|
|
|
|
ldy #dib.headptr
|
|
lda [scsi_zp4],y
|
|
sta [dib_ptr],y
|
|
ldy #dib.headptr+2
|
|
lda [scsi_zp4],y
|
|
sta [dib_ptr],y
|
|
|
|
pla
|
|
bra @do_head
|
|
;
|
|
; Set head Pointer to the same as
|
|
; in scsi_zp4
|
|
;
|
|
@stuff_head ldy #dib.headptr
|
|
lda <scsi_zp4
|
|
sta [dib_ptr],y
|
|
ldy #dib.headptr+2
|
|
lda <scsi_zp4+2
|
|
sta [dib_ptr],y
|
|
|
|
ldy #dib.devnum
|
|
lda [scsi_zp4],y
|
|
|
|
@do_head ldy #dib.headlnk
|
|
sta [dib_ptr],y
|
|
;
|
|
; Also set the Forward Device Ptr.
|
|
;
|
|
ldy #dib.fdvcptr
|
|
lda <dib_ptr
|
|
sta [scsi_zp4],y
|
|
ldy #dib.fdvcptr+2
|
|
lda <dib_ptr+2
|
|
sta [scsi_zp4],y
|
|
;
|
|
; And the forward link.
|
|
;
|
|
ldy #dib.devnum
|
|
lda [dib_ptr],y
|
|
|
|
ldy #dib.fdvclnk
|
|
sta [scsi_zp4],y
|
|
;
|
|
; Is it a COLD STARTUP?
|
|
;
|
|
lda >warm_cold_flag
|
|
and #$0001
|
|
bne @links_done ;It's Warm. Skip the links
|
|
;
|
|
; Set the linked bit in both DIBs.
|
|
;
|
|
ldy #dib.dvcchar
|
|
|
|
lda [scsi_zp4],y
|
|
ora #linked_dvc
|
|
sta [scsi_zp4],y
|
|
|
|
lda [dib_ptr],y
|
|
ora #linked_dvc
|
|
sta [dib_ptr],y
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Not the first one, so increment the counter
|
|
; if we are not beyond what we have for an
|
|
; active dib count.
|
|
;
|
|
@links_done lda |active_starts
|
|
cmp |tot_dib_cnt
|
|
beq @over_inc
|
|
inc |active_starts
|
|
@over_inc clc
|
|
rts
|
|
;
|
|
; Local Data storage here.
|
|
;
|
|
@current_dev dc.w null ;Device Number for this DIB
|
|
@our_unit dc.w null ;His unit number less the partition bits.
|
|
@our_slot dc.w null ;His slot number
|
|
;
|
|
; Check to see if we've been called before.
|
|
; If not then we need to get the gs/os
|
|
; direct page address.
|
|
;
|
|
@im_a_virgin lda |direct_page
|
|
bne @we_have_it
|
|
;
|
|
; Where is GS/OS Direct Page?
|
|
;
|
|
tdc
|
|
sta |gsos_dpage
|
|
;
|
|
; We also need to get the SCSI Managers
|
|
; ID for the S_DISPATCHER.
|
|
;
|
|
jsr get_scsimgr
|
|
bcs @rts
|
|
;
|
|
; Get ID from the memory manager. All that
|
|
; this does is request a new ID.
|
|
;
|
|
@we_have_it jsr get_mm_id
|
|
;
|
|
; Call the get_dvc_ram subroutine.
|
|
; This will allocate the space
|
|
; that we need for the device list
|
|
; returned by the SCSI Manager.
|
|
; It then calculates a DIB count
|
|
; (Max 256) and allocates RAM for
|
|
; those structures. This can be
|
|
; increased later if it is needed.
|
|
; This can occur if some of the
|
|
; devices contain more than one
|
|
; partition.
|
|
;
|
|
jsr get_dvc_ram
|
|
bcc @do_dflt_dib ;Check for errors.
|
|
|
|
jsr fre_dvc_ram ;Dump Get Devices Ram
|
|
|
|
lda #drvr_no_dev ;Exit
|
|
sec
|
|
@rts rts
|
|
;
|
|
; Now we need to build the DIBs for
|
|
; these devices. The first one will
|
|
; not be built in the default_dib
|
|
; area. The default_dib will be
|
|
; copied first to the new memory that
|
|
; has been allocated. It is here
|
|
; that the first DIB will be built.
|
|
; After this the last DIB built will
|
|
; be copied into the space for the
|
|
; next DIB to be built and then
|
|
; updated accordingly. We do not use
|
|
; the default_dib because this will
|
|
; serve to keep this driver active
|
|
; even if no devices are present at
|
|
; boot time. Just in case a drive
|
|
; does come online later.
|
|
;
|
|
@do_dflt_dib lda <dvc_list ;Advance pointer to the first entry.
|
|
adc #$0004 ;Pass Direct page pointer and
|
|
sta <dvc_list ;device count. Carry was CLEAR!!!!
|
|
lda <dvc_list+2
|
|
adc #$0000
|
|
sta <dvc_list+2
|
|
|
|
lda #default_dib
|
|
sta <last_dib
|
|
lda #^default_dib
|
|
sta <last_dib+2
|
|
|
|
stz |main_caller ;tell the link setter that he was called
|
|
clc ;Do Links Also
|
|
jsr dibicise_new_ram ;by the main loop
|
|
bra @over
|
|
|
|
@over jsr do_mode_parms ;Do MODE SENSE supplied parms
|
|
|
|
jsr do_inq_parms ;Do INQUIRY supplied parms
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF block_dvc = true Then
|
|
|
|
jsr do_read_cap ;Do READ CAPACITY supplied parms
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF part_suprt = true Then
|
|
|
|
jsr do_partition ;Do partition DIBs
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
jsr get_nxt_dvc ;Go to the next physical device
|
|
|
|
bne @over ;But only if they exist.
|
|
;
|
|
; This SEC is extremely important. At
|
|
; this point the startup call was issued
|
|
; to the default DIB. We took this
|
|
; opertunity to build all of our DIBs
|
|
; and we have a count of how many we did
|
|
; build. We do not want the device manager
|
|
; to keep the default DIB as an active
|
|
; device and so we exit with the carry
|
|
; set. He will then check the link
|
|
; pointer and if it is not zero, he will
|
|
; call the startup routine for that dib.
|
|
; At that time we will exit with the carry
|
|
; clear.
|
|
;
|
|
; Free Get Devices Ram first.
|
|
;
|
|
jsr fre_dvc_ram
|
|
|
|
lda #drvr_io
|
|
sec
|
|
rts
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; 'do_inq_parms'
|
|
;
|
|
; This routine issues an INQUIRY call to the device and
|
|
; then uses the data returned to fill in some of the blank
|
|
; holes in the DIB.
|
|
;
|
|
; 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 = unchanged (LONG)
|
|
; [next_dib] = INQUIRY values set (PTR)
|
|
; Removable bit
|
|
; Command bitmap
|
|
; 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 do_inq_parms
|
|
do_inq_parms PROC
|
|
;
|
|
; Set internal command flag
|
|
;
|
|
dec |internal
|
|
;
|
|
; Tell the Main Driver where
|
|
; our command structure resides.
|
|
;
|
|
lda #@start_inq
|
|
sta <scsi_mdrvr
|
|
lda #^@start_inq
|
|
sta <scsi_mdrvr+2
|
|
;
|
|
; And our buffer
|
|
;
|
|
lda #internal_buff
|
|
sta <buff_ptr
|
|
lda #^internal_buff
|
|
sta <buff_ptr+2
|
|
;
|
|
; And our length 0f $40 Bytes
|
|
;
|
|
lda #$0040
|
|
sta <rqst_cnt
|
|
stz <rqst_cnt+2
|
|
;
|
|
; 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 INQUIRY Command
|
|
; that we will issue.
|
|
;
|
|
lda <next_dib
|
|
sta <dib_ptr
|
|
lda <next_dib+2
|
|
sta <dib_ptr+2
|
|
;
|
|
; Set the Call Type and Issue the
|
|
; INQUIRY Command.
|
|
;
|
|
lda #scsit_stat
|
|
sta |call_type
|
|
jsr |main_drvr
|
|
bcc @over_0 ;Was there an error?
|
|
|
|
rts ;Yes.
|
|
;
|
|
; Is the device removable?
|
|
;
|
|
@over_0 lda |inq.removable\
|
|
+internal_buff
|
|
and #bit_7
|
|
beq @non_remove
|
|
;
|
|
; Yes. Set the bit in the
|
|
; characteristics field.
|
|
;
|
|
ldy #dib.dvcchar
|
|
lda [next_dib],y
|
|
ora #removable
|
|
sta [next_dib],y
|
|
bra @over_1
|
|
;
|
|
; No. Clear the bit in the
|
|
; characteristics field.
|
|
;
|
|
@non_remove ldy #dib.dvcchar
|
|
lda [next_dib],y
|
|
and #removable--\
|
|
$ffff
|
|
sta [next_dib],y
|
|
;
|
|
; Set a ZP pointer to where the
|
|
; command bitmap information will
|
|
; be placed.
|
|
;
|
|
@over_1 clc
|
|
lda <next_dib
|
|
adc #dib.group0
|
|
sta <scsi_zp0
|
|
lda <next_dib+2
|
|
adc #^dib.group0
|
|
sta <scsi_zp0+2
|
|
;
|
|
; Not all devices conform to the
|
|
; Apple Command Command Set. We
|
|
; need to check if the Command
|
|
; Bitmap is available. If not
|
|
; then we will stuff the default
|
|
; bitmap and then clear bits as
|
|
; the device indicates. This will
|
|
; be done elsewhere in response to
|
|
; a command not supported error.
|
|
;
|
|
; First check the return length.
|
|
;
|
|
|
|
ldy #dib.trx_len
|
|
lda [dib_ptr],y
|
|
cmp #inq.group+5-1 ;End of first group - 1
|
|
blt @do_default
|
|
;
|
|
; We got those bytes. Are they 0?
|
|
;
|
|
short ;5 Bytes to check. Best done 8 bit
|
|
|
|
sec ;The Carry will be our flag
|
|
lda |inq.group\
|
|
+internal_buff
|
|
bne @chk_carry ;Must Start w/ Group Zero.
|
|
|
|
clc ;The Carry will be our flag
|
|
ldx #$0005
|
|
@chk_bm_loop lda |inq.group\
|
|
+internal_buff,x
|
|
bne @chk_carry
|
|
dex
|
|
bpl @chk_bm_loop
|
|
sec
|
|
@chk_carry longmx
|
|
bcs @do_default
|
|
;
|
|
; There are some devices out there
|
|
; that return bogus bitmaps. They
|
|
; look correct, but are not. We will
|
|
; check the first 4 bytes of the
|
|
; Bitmap to see if they support the
|
|
; Mandatory Commands. If not, then
|
|
; we will use our default bitmap.
|
|
;
|
|
lda |inq.group\
|
|
+internal_buff+1
|
|
and @min_cmnds
|
|
cmp @min_cmnds
|
|
bne @do_default
|
|
|
|
lda |inq.group\
|
|
+internal_buff+3
|
|
and @min_cmnds+2
|
|
cmp @min_cmnds+2
|
|
bne @do_default
|
|
;
|
|
; Zero out the current data in the
|
|
; dib. If there are any holes in
|
|
; the information then we are sure
|
|
; that those holes are null.
|
|
;
|
|
ldy #dib.group7\
|
|
-dib.group0\
|
|
+2
|
|
lda #null
|
|
@loop_0 sta [scsi_zp0],y
|
|
dey
|
|
dey
|
|
bpl @loop_0
|
|
;
|
|
; Get the group number for the next
|
|
; four bytes of bitmap.
|
|
;
|
|
; Group x (BYTE)
|
|
; Bitmap (LONG)
|
|
; Group y (BYTE)
|
|
; Bitmap (LONG)
|
|
; Group z (BYTE)
|
|
; Bitmap (LONG)
|
|
; Group '$FF (BYTE)
|
|
;
|
|
ldx #null
|
|
@loop_1 lda |inq.group\
|
|
+internal_buff,x
|
|
|
|
and #$00ff ;Real Code
|
|
cmp #$00ff
|
|
beq @over_2
|
|
|
|
cmp #$0007+1
|
|
bge @do_default
|
|
;
|
|
; Convert group number into an
|
|
; index into the group table in
|
|
; the dib.
|
|
;
|
|
asl a
|
|
asl a
|
|
tay
|
|
inx
|
|
;
|
|
; Transfer the bitmap.
|
|
;
|
|
lda |inq.group\
|
|
+internal_buff,x
|
|
sta [scsi_zp0],y
|
|
inx
|
|
inx
|
|
iny
|
|
iny
|
|
lda |inq.group\
|
|
+internal_buff,x
|
|
sta [scsi_zp0],y
|
|
inx
|
|
inx
|
|
bra @loop_1
|
|
;
|
|
; The device did not support
|
|
; the Command Bitmap in the
|
|
; INQUIRY Parms. We need to
|
|
; put the default bitmap in
|
|
; place.
|
|
;
|
|
@do_default ldy #dib.group7\
|
|
-dib.group0\
|
|
+2
|
|
@dflt_loop lda default_dib\
|
|
+dib.group0,y
|
|
sta [scsi_zp0],y
|
|
dey
|
|
dey
|
|
bpl @dflt_loop
|
|
;
|
|
; Clean exit when done.
|
|
;
|
|
@over_2 clc
|
|
rts
|
|
;
|
|
; Data Area.
|
|
;
|
|
; Inquiry Command Packet.
|
|
;
|
|
@start_inq dc.b $12
|
|
dcb.b 11,$00
|
|
;
|
|
; Data of Minimum Command set that
|
|
; must be supported.
|
|
;
|
|
@min_cmnds
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = direct_acc Then
|
|
;
|
|
; It is a Direct-Access Device.
|
|
;
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = direct_acc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = seq_acc THEN
|
|
;
|
|
; It is a Sequential-Access Device.
|
|
;
|
|
arl ;Cause error if used. Force definition
|
|
dc.B $D0,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = seq_acc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = appl_laser THEN
|
|
;
|
|
; It is an Apple LaserWriter Device.
|
|
;
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = appl_laser
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = proc_dvc THEN
|
|
;
|
|
; It is a Processor Device.
|
|
;
|
|
arl ;Cause error if used. Force definition
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = proc_dvc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = worm_dvc THEN
|
|
;
|
|
; It is a Write-once Read-multiple Device.
|
|
;
|
|
arl ;Cause error if used. Force definition
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = worm_dvc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = read_dacc THEN
|
|
;
|
|
; It is a Read-only Direct-Access Device.
|
|
;
|
|
dc.B $90,$00,$23,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = read_dacc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = scanner THEN
|
|
;
|
|
; It is a Scanner Device.
|
|
;
|
|
dc.B $90,$00,$23,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = scanner
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = optic_mem THEN
|
|
;
|
|
; It is a Optical Memory Device.
|
|
;
|
|
arl ;Cause error if used. Force definition
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = optic_mem
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = changer THEN
|
|
;
|
|
; It is a Changer Device.
|
|
;
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = changer
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = comm_dvc THEN
|
|
;
|
|
; It is a Communication Device.
|
|
;
|
|
arl ;Cause error if used. Force definition
|
|
dc.B $98,$A0,$20,$00 ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = comm_dvc
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = mcd_40 THEN
|
|
;
|
|
; It is a Direct Access Magnetic
|
|
; Tape Device.
|
|
;
|
|
dc.B $DF,$77,$FF,$7C ; Group 0 Commands
|
|
|
|
ENDIF ;scsi_dtype = mcd_40
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; 'do_mode_parms'
|
|
;
|
|
; This routine issues an MODE SENSE call to the device and
|
|
; then uses the data returned to fill in some of the blank
|
|
; holes in the DIB.
|
|
;
|
|
; 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 = unchanged (LONG)
|
|
; [next_dib] = MODE SENSE vals set (PTR)
|
|
; Write Protect bit
|
|
; 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 do_mode_parms
|
|
do_mode_parms PROC
|
|
;
|
|
; 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 MODE SENSE
|
|
; Command that we will issue.
|
|
;
|
|
lda <next_dib
|
|
sta <dib_ptr
|
|
lda <next_dib+2
|
|
sta <dib_ptr+2
|
|
;
|
|
; Start the Unit
|
|
;
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype <> scanner THEN
|
|
|
|
jsr start_unit
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype = mcd_40\
|
|
OR scsi_dtype = apple_cd\
|
|
OR scsi_dtype = changer THEN
|
|
|
|
;
|
|
; Check for no-media
|
|
;
|
|
bcc @cd_tape_ok
|
|
;
|
|
; Check for No Media Error
|
|
;
|
|
lda |auto_sense_data+\
|
|
rqst_sens.sense_key
|
|
beq @cd_tape_ok
|
|
|
|
and #$00ff
|
|
cmp #$0002 ;Is there Media?
|
|
bne @cd_tape_ok ;Yes.
|
|
;
|
|
; No Media. Mark the DIB Hard Ofline also.
|
|
;
|
|
ldy #dib.dvcflag
|
|
lda [dib_ptr],y
|
|
ora #dvc_hardofl
|
|
sta [dib_ptr],y
|
|
|
|
|
|
@cd_tape_ok
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Check if unit Ready
|
|
;
|
|
jsr test_unit_rdy
|
|
;
|
|
; Issue MODE SENSE Call
|
|
;
|
|
jsr mode_sense
|
|
bcs @rts ;Was there an error?
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype <> apple_cd\
|
|
AND scsi_dtype <> changer\
|
|
AND scsi_dtype <> scanner THEN
|
|
|
|
;
|
|
; Is the device writable? If CD-ROM
|
|
; then don't even bother with this
|
|
; code.
|
|
;
|
|
lda |mode.w_protect\
|
|
+internal_buff
|
|
and #bit_7
|
|
beq @over_1 ;No.
|
|
;
|
|
; Yes. Set the bit in the
|
|
; characteristics field.
|
|
;
|
|
ldy #dib.dvcchar
|
|
lda #write_allow
|
|
ora [next_dib],y
|
|
sta [next_dib],y
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
@over_1 ;Label must always be available.
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype <> mcd_40\
|
|
AND scsi_dtype <> scanner\
|
|
AND scsi_dtype <> appl_laser THEN
|
|
;
|
|
; Check to see if the device supports
|
|
; the page discriptors.
|
|
;
|
|
lda |mode.blk_disc\
|
|
+internal_buff
|
|
and #$00ff
|
|
beq @clc
|
|
;
|
|
; Ensure that the device is in
|
|
; 512 mode if possible and send
|
|
; data from page 1 back to the
|
|
; device.
|
|
;
|
|
lda |mode.page_number\
|
|
+internal_buff
|
|
and #$ff3f ;Clear the invalid bits.
|
|
sta |select_page_num
|
|
lda |mode.page_number\
|
|
+internal_buff+2
|
|
ora #bit_6++\ ;Set AWRE and ARRE bits.
|
|
bit_7
|
|
sta |select_page_num+2
|
|
lda |mode.page_number\
|
|
+internal_buff+4
|
|
sta |select_page_num+4
|
|
lda |mode.page_number\
|
|
+internal_buff+6
|
|
sta |select_page_num+6
|
|
|
|
jsr set_512_mode
|
|
bcs @rts
|
|
|
|
@clc
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Exit
|
|
;
|
|
clc
|
|
@rts rts
|
|
;
|
|
; Data for the MODE SENSE Command
|
|
;
|
|
@start_mode dc.b $1a
|
|
dc.b $00
|
|
dc.b $01
|
|
dcb.b 9,$00
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; 'do_read_cap'
|
|
;
|
|
; 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: <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 = unchanged (LONG)
|
|
; [next_dib] = READ CAP.. vals set (PTR)
|
|
; Block Count
|
|
; Block Size
|
|
; 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 do_read_cap
|
|
do_read_cap PROC
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF scsi_dtype <> scanner 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 CAPACITY
|
|
; Command that we will issue.
|
|
;
|
|
lda <next_dib
|
|
sta <dib_ptr
|
|
lda <next_dib+2
|
|
sta <dib_ptr+2
|
|
;
|
|
; Issue the READ CAPACITY Command.
|
|
;
|
|
jsr read_capacity
|
|
bcc @over_0 ;Was there an error?
|
|
|
|
rts ;Yes.
|
|
;
|
|
; 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.
|
|
;
|
|
@over_0 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
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF block_dvc = true THEN
|
|
|
|
beq @over_mo
|
|
;
|
|
; Some devices do not return a bitmap
|
|
; of the commands that they support.
|
|
; For these devices we use a default
|
|
; minimum command set. If the Block
|
|
; Count is > $ffff, then we need to
|
|
; update this to support the exrended
|
|
; read and write commands.
|
|
;
|
|
ldy #dib.group1
|
|
lda [next_dib],y
|
|
ora #$b000 ;Bit 15 = Extended Read
|
|
;Bit 13 = Extended Write
|
|
;Bit 12 = Extended Seek
|
|
sta [next_dib],y
|
|
|
|
@over_mo
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
;
|
|
; Get the devices block size (This
|
|
; also needs to be switched from
|
|
; High >> Low to Low >> High) and
|
|
; place it in the dib.
|
|
;
|
|
lda |block.size\
|
|
+internal_buff\
|
|
+2
|
|
xba
|
|
ldy #dib.blksize
|
|
sta [next_dib],y
|
|
sta <blk_size ;Place on direct page.
|
|
lda |block.size\
|
|
+internal_buff
|
|
xba
|
|
ldy #dib.blksize+2
|
|
sta [next_dib],y
|
|
sta <blk_size+2 ;Place on direct page.
|
|
;
|
|
; Clean exit.
|
|
;
|
|
clc
|
|
rts
|
|
|
|
ELSE
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
clc
|
|
rts
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; 'do_partition'
|
|
;
|
|
; This routine issues a READ call to the device and
|
|
; then uses the data returned to check for any
|
|
; partitions on the media.
|
|
;
|
|
; 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_partition
|
|
do_partition PROC
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
IF part_suprt = true Then
|
|
|
|
;
|
|
; Initialize a few values.
|
|
;
|
|
lda #$ffff ;The following values will be incrimented
|
|
sta |first_time ;with zero indication special action.
|
|
sta |part_num ;This is set to $ffff so that it will only
|
|
;occur on the first pass through.
|
|
|
|
stz |part_cnt
|
|
stz |rpm_blk_num
|
|
stz |rebuild
|
|
;
|
|
; MAIN LOOP OF CODE SEGMENT.
|
|
;
|
|
jsr do_part_dib
|
|
rts
|
|
|
|
ELSE
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
clc
|
|
rts
|
|
|
|
ENDIF
|
|
|
|
;-------------------------------------------------------------------------------
|
|
|
|
ENDP
|
|
|
|
EJECT
|
|
|
|
;*******************************************************
|
|
;
|
|
; 'get_nxt_dvc'
|
|
;
|
|
; This routine checks to see if there are any
|
|
; remaining devices in the list handed to us by the
|
|
; GET_DEVICES Call to the SCSI Manager. If there are
|
|
; devices, then we advance our pointers and exit with
|
|
; the Z flag set. The caller can the do a BNE to
|
|
; continue his loop ( Z(ero) indicates that there are
|
|
; no devices left ).
|
|
;
|
|
; 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)
|
|
; 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
|
|
; Z=1 if more devices
|
|
; Z=0 if no more devices
|
|
; Direct Page = Ours
|
|
; Data Bank = Ours
|
|
;
|
|
; Errors: None.
|
|
;
|
|
;*******************************************************
|
|
|
|
EXPORT get_nxt_dvc
|
|
get_nxt_dvc PROC
|
|
;
|
|
; Are there any more devices?
|
|
;
|
|
dec |dvc_count
|
|
bne @we_have_more
|
|
clc
|
|
rts ;Z Flag set here.
|
|
;
|
|
; Advance the Device Data Pointer
|
|
; in the device list from the SCSI
|
|
; Manager
|
|
;
|
|
@we_have_more clc
|
|
lda <dvc_list
|
|
adc #$0004
|
|
sta <dvc_list
|
|
lda <dvc_list+2
|
|
adc #null
|
|
sta <dvc_list+2
|
|
;
|
|
; Call Check Ram routine. This will
|
|
; check to see if there is room for an
|
|
; additional DIB. If not then room
|
|
; will be made for enough DIBs to cover
|
|
; the remaining partitions and devices.
|
|
; From this caller, there should be no
|
|
; partitions to account for.
|
|
;
|
|
stz |main_caller
|
|
jmp chk_ram
|
|
|
|
ENDP
|
|
|
|
END
|
|
|
|
EJECT
|