mirror of
https://github.com/marketideas/qasm.git
synced 2026-10-25 13:02:45 +00:00
Move the assembler to src/qasm. qlink links OMF 1.0 and 2.0 from a script. makeBin flattens a load file, qomf dumps OMF, and qpro builds ProDOS volumes. APW and MPW assemble through the ORCA front end. Relocatable modules emit OMF objects. Listings stay off unless -l is set. make boot assembles the GS/OS 6.0.1 ProDOS 8 kernel and BASIC.SYSTEM into an 800K volume. BASIC.SYSTEM accepts ls and pfx, and its splash reports PRODOS BASIC 2.0, copyright 1983-2026. IIGS.601.SRC is the source and the BASIC.SYSTEM oracle that image is built from.
1 line
39 KiB
Plaintext
1 line
39 KiB
Plaintext
string asis
|
|
blanks off
|
|
|
|
print push
|
|
print off
|
|
include 'common.equ.src'
|
|
include 'driver.equ.src'
|
|
print pop
|
|
|
|
* change the following equate to update the version number
|
|
VersNum Equ $0400 ;version 4.00
|
|
|
|
;================================================================
|
|
;
|
|
; CFST.EQUATES
|
|
;
|
|
; Equates file for the Character File System Translator.
|
|
;
|
|
; Created: July 8, 1987
|
|
; Modified: November 18, 1987
|
|
; Author: Andy Stadler
|
|
;
|
|
;================================================================
|
|
cfst_id equ 9 ; my ID number
|
|
read_access equ $01
|
|
write_access equ $02
|
|
read_write_acc equ $03
|
|
max_call equ $4A ; last valid command * 2
|
|
max_sys equ $4 ; last valid command * 2
|
|
|
|
;================================================================
|
|
;
|
|
; Dev_Data structure
|
|
;
|
|
; This specifies the structure of dev_data records. These are
|
|
; a linked list of structures, one for each open device.
|
|
;
|
|
; NOTE: A device may be multiply opened. For each open instance
|
|
; there is an FCR, however there is only one Dev_Data for
|
|
; each device.
|
|
;
|
|
;================================================================
|
|
dd_dev_num equ 0 ; device number
|
|
dd_next_dev equ dd_dev_num+2 ; VP to next device
|
|
dd_open_stat equ dd_next_dev+4 ; how many times opened.
|
|
dd_size equ dd_open_stat+2
|
|
|
|
;================================================================
|
|
;
|
|
; cfst's fcr
|
|
;
|
|
; Because devices opened as files have no associated "volume",
|
|
; there is no associated VCR. I need to store the device number
|
|
; somewhere - normally found in the VCR. So I add a field to
|
|
; the end of the fcr.
|
|
;
|
|
;================================================================
|
|
fcr_fst_ptr equ fcr_access+2
|
|
fcr_dev_num equ fcr_fst_ptr ; device number
|
|
my_fcr_length equ fcr_dev_num+2 ; length of cfst's fcr
|
|
|
|
;================================================================
|
|
;
|
|
; CFST's direct page usage. Starts at $80, the FST workspace.
|
|
;
|
|
;================================================================
|
|
my_ref_num equ fst_start ; working reference #
|
|
my_dev_num equ my_ref_num+2 ; working device #
|
|
cur_dev equ my_dev_num+2 ; vp of current dev_data
|
|
cur_dev_ptr equ cur_dev+4 ; ptr to current dev_data
|
|
prev_dev equ cur_dev_ptr+4 ; vp of previous dev_data
|
|
my_fcr equ prev_dev+4 ; vp of current fcr
|
|
my_fcr_ptr equ my_fcr+4 ; ptr to current fcr
|
|
newl_buf equ my_fcr_ptr+4 ; vp of fcr's newline buffer
|
|
newl_buf_ptr equ newl_buf+4 ; ptr to fcr's newline buffer
|
|
call_class_2 equ newl_buf_ptr+4 ; incoming call class x 2
|
|
my_open_flag equ call_class_2+2 ; used for open's error recovery
|
|
req_access equ my_open_flag+2 ; requested access bits
|
|
dev_access equ req_access+2 ; device's access bits
|
|
grant_access equ dev_access+2 ; computed access bits
|
|
my_req_count equ grant_access+2 ; request count for read/write
|
|
my_pcount equ my_req_count+4 ; incoming parameter count
|
|
my_newl_count equ my_pcount+2 ; newline list length
|
|
my_newl_mask equ my_newl_count+2 ; newline mask/enable
|
|
src_list_ptr equ my_newl_mask+2 ; source pointer for newline copy
|
|
my_trans_count equ src_list_ptr+4 ; working transfer count
|
|
|
|
;-----------------------------------------------
|
|
;
|
|
; Forward addresses and entries
|
|
;
|
|
;-----------------------------------------------
|
|
|
|
ENTRY bad_cmd
|
|
ENTRY block_cmd
|
|
ENTRY do_close
|
|
ENTRY do_flush
|
|
ENTRY do_open
|
|
ENTRY do_read
|
|
ENTRY do_shutdn
|
|
ENTRY do_startup
|
|
ENTRY do_write
|
|
ENTRY error_exit
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; CFST.MAIN
|
|
;
|
|
; Contains header, entry points, and exit points of the
|
|
; character file system translator.
|
|
;
|
|
; Created: July 27, 1987
|
|
; Modified: January 30, 1988
|
|
; Author: Andy Stadler
|
|
;
|
|
; Copyright (c) 1987-1988, Apple Computer, Inc.
|
|
; All Rights Reserved.
|
|
;
|
|
;================================================================
|
|
;
|
|
; This is the Character FST header.
|
|
;
|
|
; FST Header Definition:
|
|
;
|
|
; dc c'FST ' ; FST identifier
|
|
; dc I4'Application_Entry' ; Entry Point #1
|
|
; dc I4'System_Calls' ; Entry Point #2
|
|
; dc I2'FST_ID' ; FST's ID #
|
|
; dc I2'$C000' ; attribute 110xxxxxxxxxxxxx
|
|
; bit 15 = 1=uppercase paths
|
|
; 14 = 0=block/1=character
|
|
; 13 = 1=supports formatting
|
|
; dc I2'version'
|
|
; dc I2'0' ; block size
|
|
; dc I4'0' ; max blocks
|
|
; dc I4'0' ; min blocks
|
|
; dc I4'0' ; max file in bytes
|
|
; dc I4'0' ; reserved field, must be 0
|
|
; dc I1'name length' ; file system name
|
|
; dc c'Character FST'
|
|
; dc I2'Comment Length' ; install time comment
|
|
; dc C'Comment goes here'
|
|
; dc i2'0'
|
|
;
|
|
; Revision:
|
|
;
|
|
; Mar. 28, 1988 By Rob Turner
|
|
;
|
|
; Changed the open routine. The open routine was only
|
|
; setting up 'drvr_dev_num' if the driver was currently
|
|
; closed. This caused 'get_last_dev' to fail.
|
|
;
|
|
; files changed:
|
|
; (1) cfst.open
|
|
;
|
|
; Jun. 28, 1988 by Rob Turner
|
|
;
|
|
; We now set the block size to zero on entry to the
|
|
; character fst.
|
|
;
|
|
; Feb. 01, 1989 by Rob Turner
|
|
;
|
|
; Fixed a bug in Read and Write. These routines
|
|
; were not honoring the access that was assigned
|
|
; at the time of the open call.
|
|
;
|
|
; Mar 27, 1990 by Monte Benaresh
|
|
;
|
|
; The FLUSH call now supports two types of flush: a "full"
|
|
; flush, which flushes a file's dirty data blocks and dirty
|
|
; directory blocks, and a "fast" flush which flushed dirty
|
|
; data blocks only. Since this concept is only meaningful
|
|
; for block FST's, the code in this file was simply changed
|
|
; to allow a P_COUNT of 2. The FLUSH_TYPE parameter is
|
|
; ignored entirely.
|
|
;
|
|
; New FLUSH parameter block:
|
|
;
|
|
; |---------------|
|
|
; | P_COUNT | (word)
|
|
; |---------------|
|
|
; | REF_NUM | (word)
|
|
; |---------------|
|
|
; | FLUSH_TYPE | (word)
|
|
; |---------------|
|
|
;
|
|
; Valid values for FLUSH_TYPE are:
|
|
; $0000 = full flush (default)
|
|
; $8000 = fast flush
|
|
;
|
|
; August 31, 1991 by Greg Branche
|
|
;
|
|
; Logic added to speed up writes to the .CONSOLE driver.
|
|
; At Startup, the FST now scans the device list looking
|
|
; for the .CONSOLE driver. When it's found, it stores
|
|
; the device number for later comparisons, performs an
|
|
; Add_Trap call to the driver, and then a Reset_Trap to
|
|
; learn the address of the driver's internal entry point.
|
|
; During a Write call, the device number is compared to
|
|
; the .CONSOLE device number and, if they match, the write
|
|
; call to the driver is dispatched directly to the driver's
|
|
; internal entry point as opposed to going through the
|
|
; device dispatcher.
|
|
;
|
|
; December 8, 1991 by Greg Branche
|
|
;
|
|
; Now that SCM skips the pCount validation if the
|
|
; callers makes a Read or Write call to the
|
|
; Character FST, the FST has to do it for itself.
|
|
; I've changed setup_rw_params to check for a minimum
|
|
; pCount of 4 and return an invalid_pcount error if
|
|
; the caller's parameter contains less than that.
|
|
;
|
|
;================================================================
|
|
;Revisions
|
|
|
|
fst_header PROC
|
|
Import appl_call,system_call
|
|
|
|
DC.B 'FST '
|
|
DC.L appl_call
|
|
DC.L system_call
|
|
DC.W cfst_id
|
|
DC.W $C000
|
|
DC.W VersNum ; version number
|
|
DC.W 0
|
|
DC.L 0
|
|
DC.L 0
|
|
DC.L 0
|
|
DC.L 0
|
|
DC.B 13
|
|
DC.B 'Character FST'
|
|
string pascal
|
|
DC.B 'Character FST v04.00'
|
|
DC.W 0000
|
|
dc.b 'Character FST by Andy Stadler and Rob Turner'
|
|
string asis
|
|
ENDP
|
|
|
|
;================================================================
|
|
;
|
|
; appl_call
|
|
;
|
|
; This is the entry point for application calls.
|
|
;
|
|
; Input: X = Call number * 2
|
|
; Y = Class number * 2
|
|
;
|
|
;================================================================
|
|
|
|
appl_call PROC
|
|
Import cmd_tbl:data
|
|
|
|
phk
|
|
plb
|
|
rep #$30
|
|
|
|
cpx #max_call+1
|
|
bcs bad_cmd
|
|
stz <drvr_blk_size ; Set blk size to zero for char devices
|
|
|
|
jmp (|cmd_tbl-2,x)
|
|
|
|
;================================================================
|
|
;
|
|
; bad_cmd
|
|
;
|
|
; An out-of range system call was received.
|
|
;
|
|
;================================================================
|
|
|
|
Entry bad_cmd
|
|
bad_cmd
|
|
|
|
lda #bad_system_call
|
|
; bra error_exit
|
|
; fall into error_exit
|
|
|
|
;================================================================
|
|
;
|
|
; error_exit
|
|
;
|
|
; Return to the caller with an error condition.
|
|
;
|
|
; Input: A = Error Code
|
|
;
|
|
;================================================================
|
|
|
|
entry error_exit
|
|
error_exit
|
|
|
|
sec
|
|
jml sys_exit
|
|
|
|
ENDP
|
|
|
|
;================================================================
|
|
;
|
|
; system_call
|
|
;
|
|
; Entry point for FST system calls.
|
|
;
|
|
; Input: X = Call number * 2
|
|
; Y = Class number * 2
|
|
;
|
|
;================================================================
|
|
|
|
system_call PROC
|
|
Import sys_tbl:data
|
|
|
|
phk
|
|
plb
|
|
|
|
cpx #max_sys+1
|
|
blt system_call_1
|
|
|
|
lda #bad_system_call
|
|
sec
|
|
rtl
|
|
|
|
system_call_1
|
|
stz <drvr_blk_size ; Set blk size to zero for char devices
|
|
jmp (|sys_tbl-2,x)
|
|
ENDP
|
|
|
|
;================================================================
|
|
;
|
|
; block_cmd
|
|
;
|
|
; A block-oriented command was received. This is a character
|
|
; I/O program.
|
|
;
|
|
;================================================================
|
|
|
|
block_cmd PROC
|
|
|
|
lda #not_block_dev
|
|
bra error_exit
|
|
ENDP
|
|
|
|
;================================================================
|
|
;
|
|
; pcount_error
|
|
;
|
|
; A parameter block was received without enough parameters.
|
|
;
|
|
;================================================================
|
|
|
|
pcount_error PROC
|
|
|
|
lda #invalid_pcount
|
|
bra error_exit
|
|
ENDP
|
|
|
|
;================================================================
|
|
;
|
|
; ok_exit
|
|
;
|
|
; Return to the caller after a successful operation.
|
|
;
|
|
; OUTPUTS: A = no_error
|
|
; C = clear
|
|
;
|
|
;================================================================
|
|
|
|
ok_exit PROC
|
|
|
|
clc
|
|
lda #no_error
|
|
jml sys_exit
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; CFST.DATA
|
|
;
|
|
; Data Tables for Character File System Translator.
|
|
;
|
|
; Created: July 08, 1987
|
|
; Modified: See modification history
|
|
; Author: Andy Stadler
|
|
;
|
|
; Copyright 1987 Apple Computer, Inc.
|
|
; All rights reserved.
|
|
;
|
|
;================================================================
|
|
;
|
|
; Modification history:
|
|
;
|
|
; 01-Feb-88 ADS Initial release
|
|
; 02-Feb-88 ADS string_buffer added
|
|
; dispatch table cleaned up
|
|
;
|
|
;================================================================
|
|
|
|
|
|
|
|
;================================================================
|
|
;
|
|
; dispatch_tables
|
|
;
|
|
; These are the jump tables used for the various commands.
|
|
;
|
|
;================================================================
|
|
|
|
cmd_tbl Record
|
|
DC.W block_cmd ; $01 Create
|
|
DC.W block_cmd ; $02 Destroy
|
|
DC.W bad_cmd ; $03 no call here
|
|
DC.W block_cmd ; $04 Change Path
|
|
DC.W block_cmd ; $05 Set File Info
|
|
DC.W block_cmd ; $06 Get File Info
|
|
DC.W bad_cmd ; $07 no call here
|
|
DC.W block_cmd ; $08 Volume
|
|
DC.W bad_cmd ; $09 Set Prefix
|
|
DC.W bad_cmd ; $0A Get Prefix
|
|
DC.W block_cmd ; $0B Clear Backup Bit
|
|
DC.W bad_cmd ; $0C Destroy Purge
|
|
DC.W bad_cmd ; $0D Null
|
|
DC.W bad_cmd ; $0E Expand Path
|
|
DC.W bad_cmd ; $0F Alter Dir
|
|
DC.W do_open ; $10 Open
|
|
DC.W bad_cmd ; $11 Newline (handled by SCM)
|
|
DC.W do_read ; $12 Read
|
|
DC.W do_write ; $13 Write
|
|
DC.W do_close ; $14 Close
|
|
DC.W do_flush ; $15 Flush
|
|
DC.W block_cmd ; $16 Set_mark
|
|
DC.W block_cmd ; $17 get_mark
|
|
DC.W block_cmd ; $18 set_eof
|
|
DC.W block_cmd ; $19 get_eof
|
|
DC.W bad_cmd ; $1A set_level
|
|
DC.W bad_cmd ; $1B get_level
|
|
DC.W block_cmd ; $1C get_dir_entry
|
|
DC.W bad_cmd ; $1D Reserved
|
|
DC.W bad_cmd ; $1E Reserved
|
|
DC.W bad_cmd ; $1F Reserved
|
|
DC.W bad_cmd ; $20 Get_dev_number
|
|
DC.W bad_cmd ; $21 get_last_dev
|
|
DC.W block_cmd ; $22 read_block
|
|
DC.W block_cmd ; $23 write_block
|
|
DC.W block_cmd ; $24 format
|
|
DC.W block_cmd ; $25 erase_disk
|
|
EndR
|
|
|
|
sys_tbl Record
|
|
DC.W do_startup ; $01 Startup
|
|
DC.W do_shutdn ; $02 Shutdown
|
|
EndR
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; my_data
|
|
;
|
|
; Private data area for the CFST.
|
|
;
|
|
;================================================================
|
|
|
|
cfst_data Record
|
|
|
|
open_devices DC.L 0000 ; 1st vp of a linked list
|
|
|
|
string_buffer DS.B 33 ; for converting strings
|
|
|
|
cons_dev_num ds.w 1 ; console device number
|
|
|
|
cons_dib_ptr ds.l 1 ; console DIB pointer
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; add_dev
|
|
;
|
|
; Adds a device to the device list. Note that there better
|
|
; not be another occurence of this device, because I make no
|
|
; attempt to fish out duplicates.
|
|
;
|
|
; Inputs: A = Device Number
|
|
;
|
|
; Outputs: open_devices = VP of new device
|
|
; cur_dev = (same)
|
|
; cur_dev_ptr = Ptr to new device
|
|
; C = Set if couldn't allocate it
|
|
;
|
|
; New Device Initialized to:
|
|
;
|
|
; next_dev = previous first dev (head insertion)
|
|
; dev_num = new device number
|
|
; open_stat = 0 (not yet opened)
|
|
;
|
|
;================================================================
|
|
|
|
add_dev PROC
|
|
with cfst_data
|
|
|
|
pha ; remember new dev #
|
|
lda |open_devices+2 ; preserve link
|
|
pha
|
|
lda |open_devices
|
|
pha
|
|
|
|
lda #dd_size ; get some memory
|
|
jsl alloc_seg
|
|
bcc add_device_ok ; ok
|
|
|
|
pla ; clean up stack
|
|
pla
|
|
pla
|
|
lda #out_of_mem
|
|
rts ; error exit
|
|
|
|
add_device_ok
|
|
stx <cur_dev ; save the new vp in 2 places
|
|
sty <cur_dev+2
|
|
stx |open_devices
|
|
sty |open_devices+2
|
|
jsl deref
|
|
stx <cur_dev_ptr
|
|
sty <cur_dev_ptr+2
|
|
|
|
ldy #dd_next_dev ; reconnect chain
|
|
pla
|
|
sta [<cur_dev_ptr],y
|
|
iny
|
|
iny
|
|
pla
|
|
sta [<cur_dev_ptr],y
|
|
|
|
ldy #dd_dev_num ; store device number
|
|
pla
|
|
sta [<cur_dev_ptr],y
|
|
|
|
ldy #dd_open_stat ; store new open status
|
|
lda #0000
|
|
sta [<cur_dev_ptr],y
|
|
|
|
clc ; success exit
|
|
rts
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; find_dev
|
|
;
|
|
; Given a device number, see if it is currently open. We do
|
|
; this by looking for a Dev_Data record with the device number.
|
|
;
|
|
; Inputs: my_dev_num = Device Number
|
|
;
|
|
; Outputs: cur_dev = vp of the device record
|
|
; cur_dev_ptr = pointer to device record
|
|
; prev_dev = vp of the previous record (0 if 1st device)
|
|
; C = Set if not found, clear if found
|
|
; (above fields =0L if not found)
|
|
;================================================================
|
|
|
|
find_dev PROC
|
|
with cfst_data
|
|
|
|
stz <prev_dev
|
|
stz <prev_dev+2
|
|
|
|
lda |open_devices ; any open?
|
|
ora |open_devices+2
|
|
beq none_found
|
|
|
|
ldx |open_devices ; setup to check 1st
|
|
stx <cur_dev
|
|
ldy |open_devices+2
|
|
sty <cur_dev+2
|
|
jsl deref
|
|
|
|
find_dev_lp
|
|
stx <cur_dev_ptr ; check device number
|
|
sty <cur_dev_ptr+2
|
|
ldy #dd_dev_num
|
|
lda [<cur_dev_ptr],y
|
|
cmp <my_dev_num
|
|
beq dev_found
|
|
|
|
lda <cur_dev ; move to next open device
|
|
sta <prev_dev
|
|
lda <cur_dev+2
|
|
sta <prev_dev+2
|
|
|
|
ldy #dd_next_dev
|
|
lda [<cur_dev_ptr],y
|
|
sta <cur_dev
|
|
iny
|
|
iny
|
|
lda [<cur_dev_ptr],y
|
|
sta <cur_dev+2
|
|
ora <cur_dev ; end of list?
|
|
beq none_found
|
|
|
|
ldx <cur_dev
|
|
ldy <cur_dev+2
|
|
jsr deref
|
|
bra find_dev_lp
|
|
|
|
none_found
|
|
stz <cur_dev
|
|
stz <cur_dev+2
|
|
sec
|
|
rts
|
|
|
|
dev_found clc
|
|
rts
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; release_dev
|
|
;
|
|
; Removes a closed device from the device chain. Assumes the
|
|
; device was found using find_dev, i.e. cur_dev, cur_dev_ptr,
|
|
; and prev_dev are all set up.
|
|
;
|
|
;================================================================
|
|
|
|
release_dev PROC
|
|
with cfst_data
|
|
|
|
lda <prev_dev ; special case if 1st entry
|
|
ora <prev_dev+2
|
|
bne normal_remove
|
|
|
|
ldy #dd_next_dev ; remove the 1st item in the list
|
|
lda [<cur_dev_ptr],y ; by making the 2nd item into
|
|
sta |open_devices ; the 1st item
|
|
iny
|
|
iny
|
|
lda [<cur_dev_ptr],y
|
|
sta |open_devices+2
|
|
bra dispose_device ; and dump the memory
|
|
|
|
normal_remove
|
|
ldy #dd_next_dev ; get the link
|
|
lda [<cur_dev_ptr],y
|
|
pha
|
|
iny
|
|
iny
|
|
lda [<cur_dev_ptr],y
|
|
pha
|
|
|
|
ldx <prev_dev ; and connect it one back
|
|
ldy <prev_dev+2
|
|
jsl deref
|
|
stx <cur_dev_ptr
|
|
sty <cur_dev_ptr+2
|
|
|
|
ldy #dd_next_dev+2 ; (restore comes off backwards)
|
|
pla
|
|
sta [<cur_dev_ptr],y
|
|
dey
|
|
dey
|
|
pla
|
|
sta [<cur_dev_ptr],y
|
|
|
|
dispose_device
|
|
ldx <cur_dev ; and deallocate the memory
|
|
ldy <cur_dev+2
|
|
jsl release_seg
|
|
|
|
rts
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; setup_rw_params
|
|
;
|
|
; Copy the data out of a read or write parameter block and
|
|
; get the fcr.
|
|
;
|
|
; INPUTS: X = Call number x 2
|
|
; Y = Call Class x 2
|
|
;
|
|
; OUTPUTS: my_ref_num = file reference number
|
|
; drvr_buf_ptr = user buffer pointer
|
|
; my_req_count = requested transfer count
|
|
; my_fcr = vp of active fcr
|
|
; my_fcr_ptr = ptr to active fcr
|
|
;
|
|
; This call will return to the shell if there is a parameter
|
|
; count error.
|
|
;
|
|
;================================================================
|
|
|
|
setup_rw_params PROC
|
|
|
|
sty <call_class_2 ; which class
|
|
tya
|
|
beq read_params ; 0
|
|
|
|
lda [<param_blk_ptr] ; 1- get pcount
|
|
cmp #$0004 ; at least minimum pCount?
|
|
bcc @bad_pCount ; no...
|
|
cmp #$0006 ; max pcount + 1
|
|
blt read_params
|
|
@bad_pCount
|
|
brl pcount_error ; no.
|
|
|
|
read_params
|
|
lda [<param_blk_ptr],y
|
|
sta <my_ref_num
|
|
iny
|
|
iny
|
|
lda [<param_blk_ptr],y
|
|
sta <drvr_buf_ptr
|
|
iny
|
|
iny
|
|
lda [<param_blk_ptr],y
|
|
sta <drvr_buf_ptr+2
|
|
iny
|
|
iny
|
|
lda [<param_blk_ptr],y
|
|
sta <my_req_count
|
|
iny
|
|
iny
|
|
lda [<param_blk_ptr],y
|
|
sta <my_req_count+2
|
|
|
|
; Get this guy's fcr
|
|
|
|
;================================================================
|
|
;
|
|
; set_fcr_ptr
|
|
;
|
|
; On refnum calls, the SCM sets up fcr_ptr with the VP of
|
|
; the corresponding fcr. Pull that value and convert it
|
|
; to a true pointer 'my_fcr_ptr'.
|
|
;
|
|
;================================================================
|
|
Entry set_fcr_ptr
|
|
set_fcr_ptr
|
|
|
|
ldx <fcr_ptr
|
|
ldy <fcr_ptr+2
|
|
jsl deref
|
|
stx <my_fcr_ptr
|
|
sty <my_fcr_ptr+2
|
|
|
|
rts
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; store_transfer
|
|
;
|
|
; Compute an offset into the parameter block and save the
|
|
; transfer count passed in X. Used for read and write.
|
|
;
|
|
; Note: Since the minimum pcount for read/write includes
|
|
; the transfer_count position, we don't need to
|
|
; verify before writing into it.
|
|
;
|
|
; INPUTS: A,X = transfer count lo, hi
|
|
; call_class_2 = call class x 2
|
|
; param_block_ptr = ptr to paramter block
|
|
;
|
|
; OUTPUTS: transfer_count field of parameter block contains
|
|
; the transfer count.
|
|
;
|
|
;================================================================
|
|
|
|
store_transfer PROC
|
|
|
|
pha ; store 1/2 of xfer ct
|
|
|
|
clc ; determine xfer ct position
|
|
lda <call_class_2 ; class 0 - offset 10
|
|
adc #0010 ; class 1 - offset 12
|
|
tay ; offset -> Y
|
|
|
|
pla ; get lo word
|
|
sta [<param_blk_ptr],y
|
|
iny
|
|
iny
|
|
txa ; hi word -> A
|
|
sta [<param_blk_ptr],y
|
|
rts
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_startup
|
|
;
|
|
; Initialize the FST.
|
|
;
|
|
; Output: C = clear (call can't fail!)
|
|
;
|
|
;================================================================
|
|
|
|
do_startup PROC
|
|
with cfst_data
|
|
ConsVersNum equ $3000
|
|
|
|
stz |open_devices ; no open devices yet
|
|
stz |open_devices+2
|
|
|
|
; Scan the device list looking for the .CONSOLE driver
|
|
|
|
stz <drvr_dev_num ; call the dispatcher directly
|
|
lda #get_dib_ptr ; get_dib_ptr call
|
|
sta <drvr_call_num
|
|
stz <dev_id_ref ; start at device #0 (incremented before use)
|
|
@scan_loop
|
|
inc <dev_id_ref ; bump the device number
|
|
jsl <dev_dispatcher ; get the DIB pointer
|
|
bcc @check_info
|
|
@not_found
|
|
stz cons_dev_num ;we don't know where the console driver is
|
|
clc
|
|
rtl
|
|
|
|
@check_info
|
|
ldy #dev_id_num ; check the device ID first
|
|
lda [<drvr_dib_ptr],y
|
|
cmp #$000A
|
|
bne @scan_loop ; if not console driver, skip to next device
|
|
|
|
ldy #dev_char ; look at the characteristics
|
|
lda [<drvr_dib_ptr],y
|
|
and #%1111101111111111 ; doesn't matter whether the name is fixed or not (gab)
|
|
cmp #$0B60
|
|
bne @scan_loop ; sorry I don't know this console
|
|
ldy #slot_num ; check the slot number
|
|
lda [<drvr_dib_ptr],y
|
|
cmp #$8003 ; fake slot 3
|
|
bne @scan_loop
|
|
ldy #unit_num
|
|
lda [<drvr_dib_ptr],y
|
|
dec a
|
|
bne @scan_loop ; we want unit 1
|
|
ldy #ver_num
|
|
lda [<drvr_dib_ptr],y ; we can only use version 3 or greater
|
|
and #$FFF0 ; don't care about alpha, beta, or whatever
|
|
cmp #ConsVersNum
|
|
bcc @scan_loop
|
|
|
|
; this particular driver has passed all the tests, so it must be the REAL
|
|
; .CONSOLE driver.
|
|
|
|
lda <dev_id_ref ; passed all tests, copy info to
|
|
sta cons_dev_num ; private variables
|
|
sta <drvr_dev_num ; set up for following driver calls
|
|
lda <drvr_dib_ptr
|
|
sta cons_dib_ptr
|
|
lda <drvr_dib_ptr+2
|
|
sta cons_dib_ptr+2
|
|
|
|
; Now that we've found the console driver, make an add_trap call to tie into
|
|
; the console driver's execution sequence, then a reset_trap to get control during
|
|
; a driver call to learn the location of the driver's internal entry point.
|
|
|
|
;
|
|
;Before we can use the console driver we must open it first
|
|
;
|
|
lda #drvr_open
|
|
sta <drvr_call_num
|
|
|
|
jsl dev_dispatcher
|
|
bcs @not_found ;oops!
|
|
|
|
;
|
|
;Issue a reset_trap call to the console driver. This will nuke anyone's installed handler
|
|
;
|
|
|
|
stz <drvr_req_cnt ;zero request count for this call
|
|
stz <drvr_req_cnt+2
|
|
stz <drvr_clist_ptr ;no control list for this one
|
|
stz <drvr_clist_ptr+2
|
|
|
|
lda #$8007 ;reset trap address
|
|
sta <drvr_ctrl_code
|
|
|
|
lda #drvr_control ;it's a control call
|
|
sta <drvr_call_num
|
|
|
|
jsl dev_dispatcher ;call the dispatcher
|
|
bcs @error_close ;oops!
|
|
;
|
|
;Add in my console driver handling routine.
|
|
;
|
|
lda #$0004 ;setup the request count
|
|
sta <drvr_req_cnt
|
|
stz <drvr_req_cnt+2
|
|
|
|
lda #ctrl_list ;address of control list
|
|
sta <drvr_clist_ptr
|
|
lda #^ctrl_list
|
|
sta <drvr_clist_ptr+2
|
|
|
|
lda #$8006 ;Add_Trap address
|
|
sta <drvr_ctrl_code
|
|
|
|
lda #drvr_control ;it's a control call
|
|
sta <drvr_call_num
|
|
|
|
jsl dev_dispatcher ;call the dispatcher
|
|
bcs @error_close ;oops!
|
|
;
|
|
;Reset the handler again.
|
|
; Note: this call will cause our Trap_Handler to be called, then
|
|
; removed. How's that for trickyness?!?
|
|
;
|
|
stz <drvr_req_cnt ;zero request count for this call
|
|
stz <drvr_req_cnt+2
|
|
stz <drvr_clist_ptr ;no control list for this one
|
|
stz <drvr_clist_ptr+2
|
|
|
|
lda #$8007 ;reset trap address
|
|
sta <drvr_ctrl_code
|
|
|
|
lda #drvr_control ;it's a control call
|
|
sta <drvr_call_num
|
|
|
|
jsl dev_dispatcher ;call the dispatcher
|
|
|
|
;
|
|
; Now we can close the driver again
|
|
;
|
|
@error_close
|
|
php
|
|
pha ;save error code if any
|
|
lda #drvr_close
|
|
sta <drvr_call_num
|
|
jsl dev_dispatcher
|
|
pla
|
|
plp
|
|
bcc @all_done
|
|
brl @not_found
|
|
@all_done
|
|
rtl
|
|
|
|
ctrl_list dc.l trap_handler
|
|
|
|
;====================================================================================================
|
|
;trap_handler: This routine is called directly by the console driver!
|
|
;
|
|
;Input: A = call number
|
|
; X = undefined
|
|
; Y = undefined
|
|
; P = nvmxdizc
|
|
; ..000...
|
|
; b = console driver bank.
|
|
;
|
|
;
|
|
;Output: A = undefined
|
|
; X = undefined
|
|
; Y = undefined
|
|
; P = nvmxdizc
|
|
; ..000...
|
|
; b = console driver bank
|
|
;
|
|
;
|
|
;====================================================================================================
|
|
longa on
|
|
longi on
|
|
trap_handler
|
|
Import Console_Address
|
|
|
|
php
|
|
pha
|
|
;
|
|
;Picture of the stack:
|
|
;
|
|
; --------------
|
|
; A Register $0001
|
|
; --------------
|
|
; Process $0003
|
|
; --------------
|
|
; Return addr $0004
|
|
; --------------
|
|
;
|
|
sec
|
|
lda 4,s ;get the return address
|
|
sbc #$0003 ;get address of Vector call routine!
|
|
tax
|
|
lda 6,s
|
|
and #$00FF
|
|
sbc #$0000
|
|
;
|
|
;Console_Address jsl $000000 ;call console
|
|
;
|
|
; $22 00 00 00
|
|
;
|
|
xba ;put bank address in high byte of accum.
|
|
sta >console_address+2
|
|
txa ;low 16 bits of console address.
|
|
sta >console_address+1
|
|
|
|
pla ;restore A register and flags
|
|
plp
|
|
rtl ;let the call continue please
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_shutdn
|
|
;
|
|
; Shut down the FST.
|
|
;
|
|
; Output: C = Clear? gotta check this....
|
|
;
|
|
;================================================================
|
|
|
|
do_shutdn PROC
|
|
|
|
clc
|
|
rtl
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_open
|
|
;
|
|
; This is the entry point for the open command.
|
|
;
|
|
; If it's class 0, the device is opened as available,
|
|
; and a refnum is returned.
|
|
;
|
|
; If it's class 1, the device is opened per the request
|
|
; access, a refnum is returned, and if there are enough
|
|
; params, the access type is returned. All other fields
|
|
; are untouched.
|
|
;
|
|
; INPUTS: X = Call Number * 2
|
|
; Y = Class number * 2
|
|
; dev_num = device number (set up by SCM)
|
|
;
|
|
;================================================================
|
|
|
|
do_open PROC
|
|
with cfst_data
|
|
|
|
stz <req_access ; default=0=open as permitted
|
|
stz <my_pcount ; disables stores if class 0
|
|
|
|
sty <call_class_2 ; which class
|
|
tya
|
|
beq open_1
|
|
|
|
lda [<param_blk_ptr]
|
|
sta <my_pcount
|
|
cmp #$0010 ; max pcount + 1
|
|
blt open_0
|
|
brl pcount_error
|
|
|
|
open_0
|
|
cmp #0003
|
|
blt open_1 ; <req_access specified?
|
|
ldy #0008
|
|
lda [<param_blk_ptr],y
|
|
sta <req_access
|
|
|
|
;================================================================
|
|
;
|
|
; Step 1: Based on the access (a) requested and (b) allowed,
|
|
; generate an access bits word for this open.
|
|
;
|
|
; In addition, I check the driver type. If its a
|
|
; block device, I must coerce the SCM into more
|
|
; bouncing.... So I return 'File System Not Supported.'
|
|
;
|
|
;================================================================
|
|
|
|
open_1
|
|
stz <drvr_dev_num ; make get_dib_ptr call
|
|
lda #get_dib_ptr
|
|
sta <drvr_call_num
|
|
lda <dev_num
|
|
sta <drvr_buf_ptr
|
|
jsl dev_dispatcher
|
|
bcc got_the_dib
|
|
|
|
lda #file_not_found
|
|
brl error_exit ; probably bad device number
|
|
|
|
got_the_dib
|
|
ldy #8 ; address of characteristics
|
|
lda [<drvr_dib_ptr],y
|
|
and #$0080 ; block dev or char?
|
|
beq dib_says_char
|
|
|
|
lda #unknown_vol ; bounce!
|
|
brl error_exit
|
|
|
|
dib_says_char
|
|
lda [<drvr_dib_ptr],y ; now check access bits
|
|
asl a ; xxxxxxxxxWRxxxxx ->
|
|
asl a ; 00000000000000WR
|
|
asl a
|
|
xba
|
|
and #0003
|
|
sta <dev_access
|
|
|
|
lda <req_access ; did they request 'as available'
|
|
beq as_avail
|
|
|
|
and #$FFFC ; any other modes requested?
|
|
beq set_access
|
|
|
|
lda #invalid_access ; yes, they're not supported!
|
|
brl error_exit
|
|
|
|
set_access
|
|
lda <req_access ; ok, take the requested modes
|
|
and <dev_access
|
|
bra store_access
|
|
|
|
as_avail
|
|
lda <dev_access ; take whatever's available
|
|
|
|
store_access
|
|
sta <grant_access
|
|
ldx <my_pcount ; response requested?
|
|
cpx #0005
|
|
blt open_2
|
|
ldy #0012 ; yes, store it
|
|
sta [<param_blk_ptr],y
|
|
|
|
;================================================================
|
|
;
|
|
; Step 2: See if we already know this device. If so, just
|
|
; increment its open_stat. If not, create a new
|
|
; dev_data and actually open the device.
|
|
;
|
|
;================================================================
|
|
|
|
open_2
|
|
stz <my_open_flag
|
|
lda <dev_num
|
|
sta <my_dev_num
|
|
|
|
lda <dev_num ; open the driver
|
|
sta <drvr_dev_num
|
|
|
|
jsr find_dev ; do we already know it?
|
|
bcc inc_open
|
|
|
|
lda #drvr_open
|
|
sta <drvr_call_num
|
|
jsl dev_dispatcher
|
|
bcc open_ok
|
|
brl error_exit
|
|
|
|
open_ok
|
|
inc <my_open_flag ; 1 = opened this call
|
|
lda <dev_num ; create the new device data
|
|
jsr add_dev
|
|
bcc inc_open
|
|
pha ; (stack futz, see open_punt)
|
|
brl punt_2 ; can't add! close the driver.
|
|
|
|
inc_open ; ; flag of # opens
|
|
ldy #dd_open_stat
|
|
lda [<cur_dev_ptr],y
|
|
inc a
|
|
sta [<cur_dev_ptr],y
|
|
|
|
;================================================================
|
|
;
|
|
; Step 3: Create an FCR. Certain fields will have to be
|
|
; filled in.
|
|
;
|
|
;================================================================
|
|
|
|
ldy <call_class_2 ; class x 2 -> path ptr offset
|
|
iny
|
|
iny
|
|
|
|
lda [<param_blk_ptr],y
|
|
tax ; path ptr -> X,Y
|
|
iny
|
|
iny
|
|
lda [<param_blk_ptr],y
|
|
tay
|
|
|
|
lda <call_class_2 ; class 0 needs conversion
|
|
bne get_the_fcr
|
|
|
|
; convert class 0 string to class 1 string in local buffer
|
|
|
|
phy ; source ptr
|
|
phx
|
|
pea string_buffer>>16 ; dest ptr
|
|
pea string_buffer
|
|
jsl cvt_0to1
|
|
|
|
ldx #<string_buffer
|
|
ldy #^string_buffer
|
|
|
|
; insert the new (or the original) string into a new fcr
|
|
|
|
get_the_fcr
|
|
lda #my_fcr_length
|
|
jsl alloc_fcr ; get the fcr memory
|
|
bcc fcr_ok
|
|
|
|
lda #out_of_mem
|
|
brl open_punt
|
|
|
|
fcr_ok
|
|
stx <my_fcr ; make a real pointer to it
|
|
sty <my_fcr+2
|
|
jsl deref
|
|
stx <my_fcr_ptr
|
|
sty <my_fcr_ptr+2
|
|
|
|
lda <dev_num ; fill in the device number
|
|
ldy #fcr_dev_num
|
|
sta [<my_fcr_ptr],y
|
|
|
|
lda #cfst_id ; fill in my ID number
|
|
ldy #fcr_fst_id
|
|
sta [<my_fcr_ptr],y
|
|
|
|
lda #$FFFF ; 'no associated volume'
|
|
ldy #fcr_vol_id
|
|
sta [<my_fcr_ptr],y
|
|
|
|
lda <grant_access
|
|
ldy #fcr_access
|
|
sta [<my_fcr_ptr],y ; access
|
|
|
|
lda #0000 ; newline starts out disabled
|
|
ldy #fcr_mask
|
|
sta [<my_fcr_ptr],y
|
|
|
|
ldy #fcr_ref_num ; return file ref number
|
|
lda [<my_fcr_ptr],y
|
|
ldy <call_class_2 ; class + 0 = ref # index
|
|
sta [<param_blk_ptr],y
|
|
|
|
brl ok_exit ; success!
|
|
|
|
;================================================================
|
|
;
|
|
; open_punt
|
|
;
|
|
; Some sort of error occurred, probably out of memory. If
|
|
; this was the first instance of opening the driver, close
|
|
; it before returning the error.
|
|
;
|
|
;================================================================
|
|
|
|
open_punt
|
|
ldx <my_open_flag ; did we just open it?
|
|
beq go_error
|
|
|
|
; this call opened the driver. Since something along the line
|
|
; failed, we need to close it again.
|
|
|
|
pha ; remember the error code
|
|
|
|
jsr find_dev ; seek out the new record
|
|
jsr release_dev ; and nuke it
|
|
|
|
; entry point which just closes (from add_dev failure)
|
|
|
|
punt_2
|
|
lda <dev_num ; and close the driver
|
|
sta <drvr_dev_num
|
|
lda #drvr_close
|
|
sta <drvr_call_num
|
|
jsl dev_dispatcher
|
|
|
|
pla
|
|
|
|
go_error
|
|
brl error_exit
|
|
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_read
|
|
;
|
|
; This implements the read call. Basically its a straight-
|
|
; through translation from GS/OS to device-driver format.
|
|
; Newline is implemented at this level, so for optimization,
|
|
; there are two methods used: If newline is disabled, the
|
|
; entire requested block is transferred by the device. If
|
|
; newline is enabled, bytes are transferred one at a time
|
|
; until the newline is matched.
|
|
;
|
|
; Created: July 21, 1987
|
|
; Modified: November 4, 1987
|
|
; Author: Andy Stadler
|
|
;
|
|
; Copyright (C) 1987 Apple Computer, Inc.
|
|
; All Rights Reserved.
|
|
;
|
|
; INPUTS: X = Call number x 2
|
|
; Y = Call Class x 2
|
|
; Param_Block containing:
|
|
; Reference #
|
|
; Buffer Pointer
|
|
; Request Count
|
|
;
|
|
; OUTPUTS: C = clear if no error, set if error
|
|
; A = Error Code
|
|
; Param_Block with response:
|
|
; Transfer Count
|
|
;
|
|
; Possible Errors:
|
|
; $23 Driver not open
|
|
; $27 IO Error
|
|
; $2F Off-line error
|
|
; $4E Access error (not read-enabled)
|
|
;
|
|
;================================================================
|
|
|
|
do_read PROC
|
|
|
|
jsr setup_rw_params ; get data from param block
|
|
|
|
; setup default data for the device driver
|
|
|
|
ldy #fcr_access ; lets check the access please
|
|
lda [<my_fcr_ptr],y
|
|
and #read_access ; see if the caller has read access
|
|
bne @access_ok
|
|
|
|
lda #invalid_access
|
|
sec
|
|
bra @exit
|
|
@access_ok
|
|
ldy #fcr_dev_num ; get the device number
|
|
lda [<my_fcr_ptr],y
|
|
sta <drvr_dev_num
|
|
|
|
lda #drvr_read
|
|
sta <drvr_call_num
|
|
|
|
stz <drvr_blk_size ; 0 = character mode
|
|
|
|
; Split here for newline or raw modes
|
|
|
|
ldy #fcr_mask ; if mask == 0, newline disabled
|
|
lda [<my_fcr_ptr],y
|
|
bne newline_read
|
|
|
|
; Execute a raw read. Read the entire requested
|
|
; amount into the user's buffer.
|
|
|
|
lda <my_req_count ; read full amount
|
|
sta <drvr_req_cnt
|
|
lda <my_req_count+2
|
|
sta <drvr_req_cnt+2
|
|
jsl dev_dispatcher
|
|
@exit
|
|
pha ; save error status
|
|
php
|
|
|
|
lda <drvr_tran_cnt
|
|
ldx <drvr_tran_cnt+2
|
|
jsr store_transfer ; return transfer count
|
|
|
|
plp ; get the error status
|
|
pla
|
|
bcc ok_read_1
|
|
|
|
brl error_exit ; quit with error code
|
|
|
|
ok_read_1
|
|
brl ok_exit
|
|
|
|
; Execute a newline read. We must read characters from the
|
|
; device driver one-at-a-time into the destination buffer.
|
|
; Then we compare them with the newline data. If the newline
|
|
; character is found, terminate the read operation.
|
|
|
|
newline_read
|
|
ldy #fcr_newline ; get the newline data
|
|
lda [<my_fcr_ptr],y
|
|
tax
|
|
iny
|
|
iny
|
|
lda [<my_fcr_ptr],y
|
|
tay
|
|
jsl deref ; make a pointer
|
|
stx <newl_buf_ptr
|
|
sty <newl_buf_ptr+2
|
|
|
|
ldy #fcr_mask ; get mask
|
|
lda [my_fcr_ptr],y
|
|
and #$00FF ; make sure hi byte is 0's!!!!
|
|
sta <my_newl_mask
|
|
|
|
ldy #fcr_newline_len ; get count
|
|
lda [my_fcr_ptr],y
|
|
sta <my_newl_count
|
|
|
|
stz <my_trans_count
|
|
stz <my_trans_count+2
|
|
lda #0001 ; read 1 at a time
|
|
sta <drvr_req_cnt
|
|
stz <drvr_req_cnt+2
|
|
|
|
; loop here reading one character at a time
|
|
|
|
read_lp
|
|
jsl dev_dispatcher
|
|
bcc read_ok
|
|
|
|
pha ; read error!
|
|
php
|
|
|
|
lda <my_trans_count
|
|
ldx <my_trans_count+2 ; read stopped by error
|
|
jsr store_transfer
|
|
|
|
plp
|
|
pla
|
|
brl error_exit
|
|
|
|
read_ok
|
|
inc <my_trans_count ; are we full yet?
|
|
bne read_ok_1
|
|
inc <my_trans_count
|
|
|
|
read_ok_1
|
|
lda <my_trans_count
|
|
cmp <my_req_count
|
|
bne read_ok_2
|
|
|
|
lda <my_trans_count+1
|
|
cmp <my_req_count+1
|
|
beq q_read
|
|
|
|
read_ok_2
|
|
lda [<drvr_buf_ptr] ; take a look at the character
|
|
and <my_newl_mask ; (removing bits of next char)
|
|
pha
|
|
ldy <my_newl_count
|
|
|
|
newline_lp
|
|
dey
|
|
lda [<newl_buf_ptr],y ; packed byte array
|
|
and #$00FF
|
|
cmp 1,s
|
|
beq hit_newline
|
|
tyx
|
|
bne newline_lp
|
|
|
|
pla ; no, not end of line.
|
|
inc <drvr_buf_ptr ; move to next char position
|
|
bne read_lp
|
|
inc <drvr_buf_ptr+2
|
|
bra read_lp ; and keep reading.
|
|
|
|
hit_newline
|
|
pla ; trash work value
|
|
|
|
q_read
|
|
lda <my_trans_count
|
|
ldx <my_trans_count+2
|
|
jsr store_transfer
|
|
|
|
brl ok_exit
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_write
|
|
;
|
|
; Handles the write command for the character file system
|
|
; translator. Simply reprocesses the command into a device
|
|
; driver format and lets the device driver do the work.
|
|
;
|
|
; Created: July 22, 1987
|
|
; Modified: November 4, 1987
|
|
; Author: Andy Stadler
|
|
;
|
|
; INPUTS: X = Call number x 2
|
|
; Y = Call Class x 2
|
|
; Param_Block containing:
|
|
; Reference #
|
|
; Buffer Pointer
|
|
; Request Count
|
|
;
|
|
; OUTPUTS: C = clear if no error, set if error
|
|
; A = Error Code
|
|
; Param_Block with response:
|
|
; Transfer Count
|
|
;
|
|
; Possible Errors:
|
|
; $23 Driver not open
|
|
; $27 IO Error
|
|
; $2B Write protected
|
|
; $2F Off-line error
|
|
; $4E Access error (not write-enabled)
|
|
;
|
|
;================================================================
|
|
|
|
do_write PROC
|
|
entry Console_Address
|
|
with cfst_data
|
|
|
|
jsr setup_rw_params ; get info from param block
|
|
|
|
ldy #fcr_access ; lets check the access please
|
|
lda [<my_fcr_ptr],y
|
|
and #write_access ; see if the caller has write access
|
|
bne @access_ok
|
|
|
|
lda #invalid_access
|
|
sec
|
|
bra exit
|
|
@access_ok
|
|
lda #drvr_write
|
|
sta <drvr_call_num
|
|
|
|
stz <drvr_blk_size ; 0 = character mode
|
|
|
|
lda <my_req_count ; write full amount
|
|
sta <drvr_req_cnt
|
|
lda <my_req_count+2
|
|
sta <drvr_req_cnt+2
|
|
|
|
ldy #fcr_dev_num ; get the device number
|
|
lda [<my_fcr_ptr],y
|
|
sta <drvr_dev_num
|
|
cmp cons_dev_num ; is it the console driver?
|
|
beq @call_console ; yes, call the driver directly
|
|
|
|
jsl dev_dispatcher ; write the data
|
|
bra exit
|
|
|
|
@call_console
|
|
lda cons_dib_ptr ; copy the dib pointer to direct page
|
|
sta <drvr_dib_ptr
|
|
lda cons_dib_ptr+2
|
|
sta <drvr_dib_ptr
|
|
lda #drvr_write ; call # must be in accumulator
|
|
phb ; drivers are allowed to modify DBR
|
|
Console_Address jsl $000000 ; call console (address is filled in at startup
|
|
plb
|
|
|
|
exit
|
|
pha
|
|
php ; remember the error status
|
|
|
|
lda <drvr_tran_cnt
|
|
ldx <drvr_tran_cnt+2
|
|
jsr store_transfer ; return transfer count
|
|
|
|
plp
|
|
pla
|
|
bcc write_ok
|
|
|
|
brl error_exit ; exit with error status
|
|
|
|
write_ok
|
|
brl ok_exit
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_close
|
|
;
|
|
; Attempt to close the specified refnum. If the device is
|
|
; multiply open, simply decrement the open_stat flag in its
|
|
; dev_data record, and scrap the fcr. If it's really closing,
|
|
; issue a drvr_close call.
|
|
;
|
|
; INPUTS: X = Call Number * 2
|
|
; Y = Class number * 2
|
|
;
|
|
; POSSIBLE ERROR CODES:
|
|
;
|
|
; $27 drvr_io_error
|
|
;
|
|
;================================================================
|
|
|
|
do_close PROC
|
|
|
|
tyx ; test for max pcount
|
|
beq close_0
|
|
lda [<param_blk_ptr]
|
|
dec a ; must = 1
|
|
beq close_0
|
|
brl pcount_error
|
|
|
|
close_0
|
|
jsr set_fcr_ptr
|
|
|
|
lda [<my_fcr_ptr] ; ref # is 1st entry
|
|
sta <my_ref_num
|
|
|
|
ldy #fcr_dev_num ;get device # from fcr
|
|
lda [<my_fcr_ptr],y
|
|
sta <my_dev_num
|
|
|
|
ldy #fcr_mask ; if newline data, release it
|
|
lda [<my_fcr_ptr],y
|
|
beq close_1
|
|
|
|
ldy #fcr_newline ; kill the newline buffer
|
|
lda [<my_fcr_ptr],y
|
|
tax
|
|
iny
|
|
iny
|
|
lda [<my_fcr_ptr],y
|
|
tay
|
|
jsl release_seg
|
|
|
|
close_1
|
|
lda <my_ref_num ; kill the fcr
|
|
jsl release_fcr
|
|
|
|
jsr find_dev
|
|
ldy #dd_open_stat ;how many opens?
|
|
lda [<cur_dev_ptr],y
|
|
dec a
|
|
sta [<cur_dev_ptr],y ;if other opens,
|
|
bne sk_close ;don't close the device
|
|
|
|
; This is the last close for this device, remove its
|
|
; device info record and issue a close call.
|
|
|
|
lda <my_ref_num
|
|
jsr release_dev ; remove my device record
|
|
|
|
lda <my_dev_num ;close the device
|
|
sta <drvr_dev_num
|
|
lda #drvr_close
|
|
sta <drvr_call_num
|
|
jsl dev_dispatcher
|
|
bcc sk_close
|
|
|
|
brl error_exit
|
|
|
|
sk_close
|
|
brl ok_exit ; all done!
|
|
ENDP
|
|
|
|
eject
|
|
;================================================================
|
|
;
|
|
; do_flush
|
|
;
|
|
; Sends the flush command to the device driver, if that device
|
|
; is open.
|
|
;
|
|
; Inputs: X = Call number x 2
|
|
; Y = Class number x 2
|
|
;
|
|
; Outputs: A = error code
|
|
; C = clear if ok, set if error
|
|
;
|
|
; Error Codes:
|
|
;
|
|
; $27 not open (someone else closed the device)
|
|
; $2F off line
|
|
;
|
|
;================================================================
|
|
|
|
do_flush PROC
|
|
|
|
tya ; check class
|
|
beq params_ok
|
|
|
|
lda [<param_blk_ptr]
|
|
dec a ; pcount must = 1 or 2
|
|
beq params_ok
|
|
dec a ; pcount of 2 now allowed 3/27/90
|
|
beq params_ok ; by Monte Benaresh
|
|
brl pcount_error
|
|
|
|
params_ok
|
|
lda [<param_blk_ptr],y
|
|
sta <my_ref_num
|
|
|
|
jsr set_fcr_ptr
|
|
|
|
ldy #fcr_dev_num ; get device number
|
|
lda [<my_fcr_ptr],y
|
|
sta <drvr_dev_num
|
|
|
|
lda #drvr_flush ; send command to driver
|
|
sta <drvr_call_num
|
|
jsl dev_dispatcher
|
|
bcc flush_ok
|
|
|
|
brl error_exit ; send the error through
|
|
|
|
flush_ok
|
|
brl ok_exit
|
|
ENDP
|
|
END
|