;
; Ullrich von Bassewitz, 2002-11-17, 2009-02-22
;
; Handle disk command channels
;

        .export         isdisk
        .export         opencmdchannel
        .export         closecmdchannel
        .export         readdiskerror
        .export         writediskcmd
        .export         writefndiskcmd

        .import         fncmd, fnlen, fnunit
        .importzp       tmp1, ptr1

        .include        "cbm.inc"
        .include        "filedes.inc"

;--------------------------------------------------------------------------
; isdisk: Return carry clear if the unit number in X is a disk, return
; carry set if not.

.proc   isdisk

        cpx     #FIRST_DRIVE    ; Disk unit?
        bcc     @L1             ; Branch if no disk
        cpx     #FIRST_DRIVE+MAX_DRIVES
        rts

@L1:    sec
        rts

.endproc

;--------------------------------------------------------------------------
; Open the command channel for the disk unit in X. The function returns an
; error code in A and sets the flags according to the contents of A.

opencmdchannel:

        jsr     isdisk          ; Disk unit?
        bcs     success

; Is this channel already open?

        ldy     opentab-FIRST_DRIVE,x
        bne     isopen

; Open the command channel, Carry is still clear

        stx     tmp1            ; Save the unit number
        txa                     ; Get unit number
        adc     #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
        ldy     #15             ; Secondary address for cmd channel
        jsr     SETLFS

        lda     #0
        jsr     SETNAM          ; No name supplied to OPEN

        jsr     OPEN
        bcs     done            ; Error, code is in A

; Command channel is open now. Increment the count

        ldx     tmp1            ; Unit number
        ldy     opentab-FIRST_DRIVE,x
isopen: iny
        tya
        sta     opentab-FIRST_DRIVE,x

; Done, return success

success:lda     #$00
done:   cmp     #$00            ; Set flags for return code
        rts


;--------------------------------------------------------------------------
; closecmdchannel: Decrement the counter for the disk command channel and
; close the channel if the counter drops to zero. The function expects the
; drive number in X and returns an error code in A. The flags for the return
; code are set when the function returns.

closecmdchannel:

        jsr     isdisk          ; Disk unit?
        bcs     success

; Is this channel really open?

        ldy     opentab-FIRST_DRIVE,x
        beq     success         ; OOPS! Channel is not open

; Decrement the count and stor it back

        dey
        tya
        sta     opentab-FIRST_DRIVE,x

; If the counter is now zero, close the channel. We still have carry clear
; when we come here.

        bne     success
        txa                     ; Make LFN from drive number
        adc     #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
        jsr     CLOSE
        bcs     done
        bcc     success

;--------------------------------------------------------------------------
; readdiskerror: Read a disk error from an already open command channel.
; Returns an error code in A, which may either be the code read from the
; command channel, or another error when accessing the command channel failed.

readdiskerror:

        jsr     isdisk
        bcs     success

; Read the command channel. We won't check the status after the channel is
; open, because this seems to be unnecessary in most cases.

        txa
        clc                     ; Make LFN from drive number
        adc     #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
        tax
        jsr     CHKIN           ; Make the command channel input
        bcs     done            ; Bail out with error code in A

        jsr     BASIN
        and     #$0F            ; Make digit value from PETSCII
        sta     tmp1
        asl     a               ; * 2
        asl     a               ; * 4, carry clear
        adc     tmp1            ; * 5
        asl     a               ; * 10
        sta     tmp1

        jsr     BASIN
        and     #$0F            ; Make digit value from PETSCII
        clc
        adc     tmp1

; Errors below 20 are not real errors. Fix that

        cmp     #20+1
        bcs     @L1
        lda     #$00
@L1:    pha

; Read the remainder of the message and throw it away

@L2:    jsr     BASIN
        cmp     #$0D
        bne     @L2

; Close the input channel

        jsr     CLRCH

; Restore the error code (will also set the flags) and return

        pla
        rts

;--------------------------------------------------------------------------
; writefndiskcmd: Write the contents of fncmd to the command channel of the
; drive in fnunit. Returns an error code in A, flags are set according to
; the contents of A.

writefndiskcmd:
        lda     #<fncmd
        sta     ptr1
        lda     #>fncmd
        sta     ptr1+1

        ldx     fnlen
        inx                     ; Account for command char in fncmd
        txa                     ; Length of name into A
        ldx     fnunit          ; Unit

; Run directly into writediskcmd

;       jmp     writediskcmd

;--------------------------------------------------------------------------
; writediskcmd: Gets pointer to data in ptr1, length in A. Writes all data
; to the command channel of the drive in X. Returns an error code in A,
; flags are set according to the contents of A.

writediskcmd:

        jsr     isdisk
        bcs     success         ; No disk - already done

; Remember the length

        sta     tmp1

; Write to the command channel.

        txa
        clc                     ; Make LFN from drive number
        adc     #(LFN_OFFS+MAX_FDS-FIRST_DRIVE)
        tax
        jsr     CKOUT           ; Make the command channel output
        bcs     done            ; Bail out with error code in A

        ldy     #$00
@L1:    cpy     tmp1
        bcs     @L3
        lda     (ptr1),y
        iny
        jsr     BSOUT
        bcc     @L1

@L2:    pha
        jsr     CLRCH
        pla
        rts

@L3:    jsr     CLRCH
        lda     #$00
        rts


;--------------------------------------------------------------------------
; Data

.bss

opentab:        .res    MAX_DRIVES, 0