;;*****************************************************************************
;;*****************************************************************************
;;  FILENAME: USBUART_drv.asm
;;  Version: 1.0, Updated on 2008/04/07 at 12:05:03
;;  Generated by PSoC Designer ???
;;
;;  DESCRIPTION: USBUART control endpoint driver
;;               for the CY8C24090 and CY7C64215 family of devices
;;
;;  NOTE: User Module APIs conform to the fastcall16 convention for marshalling
;;        arguments and observe the associated "Registers are volatile" policy.
;;        This means it is the caller's responsibility to preserve any values
;;        in the X and A registers that are still needed after the API functions
;;        returns. For Large Memory Model devices it is also the caller's
;;        responsibility to preserve any value in the CUR_PP, IDX_PP, MVR_PP and
;;        MVW_PP registers. Even though some of these registers may not be modified
;;        now, there is no guarantee that will remain the case in future releases.
;;-----------------------------------------------------------------------------
;;  Copyright (c) Cypress Semiconductor 2006. All Rights Reserved.
;;*****************************************************************************
;;*****************************************************************************

include "m8c.inc"
include "memory.inc"
include "USBUART_macros.inc"
include "USBUART.inc"

;-----------------------------------------------
;  Global Symbols
;-----------------------------------------------
export  USBUART_EP0_ISR
export _USBUART_EP0_ISR
export  USBUART_InitControlRead
export _USBUART_InitControlRead
export  USBUART_InitControlWrite
export _USBUART_InitControlWrite
export  USBUART_InitNoDataStageControlTransfer
export _USBUART_InitNoDataStageControlTransfer
export  USBUART_NoDataStageControlTransfer

;-----------------------------------------------
;  Macro Definitions
;-----------------------------------------------

;-----------------------------------------------
;  Constant Definitions
;-----------------------------------------------

;-----------------------------------------------
; Variable Allocation
;-----------------------------------------------
AREA InterruptRAM (RAM,REL,CON)
;----------------------------------------------------------------------------
; Current Device
;----------------------------------------------------------------------------
EXPORT USBUART_bCurrentDevice, _USBUART_bCurrentDevice
 USBUART_bCurrentDevice:
_USBUART_bCurrentDevice:                BLK   1    ;  Current Device
;----------------------------------------------------------------------------
; Current Configuration
;----------------------------------------------------------------------------
EXPORT USBUART_Configuration, _USBUART_Configuration
 USBUART_Configuration:
_USBUART_Configuration:                 BLK   1    ;  Current Configuration
;----------------------------------------------------------------------------
; Current Device Status
;----------------------------------------------------------------------------
EXPORT USBUART_DeviceStatus, _USBUART_DeviceStatus
 USBUART_DeviceStatus:
_USBUART_DeviceStatus:                  BLK   1    ;  Current Device Status
;----------------------------------------------------------------------------
; Interface Setting
;----------------------------------------------------------------------------
EXPORT USBUART_InterfaceSetting, _USBUART_InterfaceSetting
 USBUART_InterfaceSetting:
_USBUART_InterfaceSetting:              BLK   2    ; Interface Setting
;----------------------------------------------------------------------------
; Endpoint Status--USB Status
;----------------------------------------------------------------------------
EXPORT USBUART_EndpointStatus, _USBUART_EndpointStatus
 USBUART_EndpointStatus:
_USBUART_EndpointStatus:                BLK   USB_NUM_ENDPOINTS    ; Endpoint Status
;----------------------------------------------------------------------------
; Last Packet Size
;----------------------------------------------------------------------------
EXPORT USBUART_LastSize 
 USBUART_LastSize:                      BLK   1    ; Last Packet Size
;----------------------------------------------------------------------------
; Control Transfer State Machine
; State values for Control Write
; State values for Control Read
;----------------------------------------------------------------------------
EXPORT USBUART_TransferType 
 USBUART_TransferType:                  BLK   1    ; Control Transfer State Machine
;----------------------------------------------------------------------------
; Control Transfer Intermediate Buffer--Shared among the requests
;----------------------------------------------------------------------------
EXPORT USBUART_TransferBuffer 
 USBUART_TransferBuffer:                BLK   8
;----------------------------------------------------------------------------
; Transfer Descriptor Data for Control Transfer
;  --The following data have the same format as the first 5 bytes of the TD_ENTRY
;----------------------------------------------------------------------------
; Control Transfer Data Source
;   USB_DS_ROM
;   USB_DS_RAM
;   USB_DS_RAM_AS_NEEDED
;----------------------------------------------------------------------------
EXPORT USBUART_CurrentTD, _USBUART_CurrentTD
_USBUART_CurrentTD:
 USBUART_CurrentTD:
EXPORT USBUART_DataSource, _USBUART_DataSource
_USBUART_DataSource:
 USBUART_DataSource:                    BLK   1
;----------------------------------------------------------------------------
; Control Transfer Data Size
;----------------------------------------------------------------------------
EXPORT USBUART_TransferSize, _USBUART_TransferSize
_USBUART_TransferSize:
 USBUART_TransferSize:                  BLK   2
;----------------------------------------------------------------------------
; Control Transfer Data Pointer
;   Source for Control Read
;   Destination for Control Write
;----------------------------------------------------------------------------
EXPORT USBUART_DataPtr, _USBUART_DataPtr
_USBUART_DataPtr: 
 USBUART_DataPtr:                       BLK   2
;----------------------------------------------------------------------------
; Transfer Completion Notification
;----------------------------------------------------------------------------
EXPORT USBUART_StatusBlockPtr, _USBUART_StatusBlockPtr
_USBUART_StatusBlockPtr: 
 USBUART_StatusBlockPtr:                BLK   2

;----------------------------------------------------------------------------
; Control Transfer _TransferByteCount (Actually transferred)
;----------------------------------------------------------------------------
 USBUART_TransferByteCount:             BLK   2

;----------------------------------------------------------------------------
; Control Endpoint Data toggle
EXPORT USBUART_EPDataToggle, _USBUART_EPDataToggle
 _USBUART_EPDataToggle:
 USBUART_EPDataToggle:
 USBUART_EP0DataToggle:                 BLK   1
;----------------------------------------------------------------------------
; Control Endpoint Data Pending Flag
EXPORT USBUART_fDataPending
 USBUART_fDataPending:                  BLK   1
;----------------------------------------------------------------------------
; Control Endpoint Data Pending Flag
;EXPORT USBUART_PendingData
;  USBUART_PendingData:                 BLK   1
;----------------------------------------------------------------------------
; Temporary Data registers
EXPORT USBUART_t2, USBUART_t1, USBUART_t0
 USBUART_t2:                            BLK   1    ; Temporary shared by the UM
 USBUART_t1:                            BLK   1    ; Temporary shared by the UM
 USBUART_t0:                            BLK   1    ; Temporary shared by the UM

;EXPORT USBUART_IntState
; USBUART_IntState:                     BLK  1
;EXPORT USBUART_StackPointer
; USBUART_StackPointer:                 BLK  1
;EXPORT USBUART_TempMode
; USBUART_TempMode:                     BLK 1
;----------------------------------------------------------------------------
; Endpoint Transfer--API Status
;----------------------------------------------------------------------------
EXPORT USBUART_EndpointAPIStatus, _USBUART_EndpointAPIStatus
 USBUART_EndpointAPIStatus:
_USBUART_EndpointAPIStatus:             BLK   USB_NUM_ENDPOINTS    ; Endpoint Status

AREA UserModules (ROM, REL)
;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_EP0_ISR

;
;  DESCRIPTION:   The EPO ISR serves the control endpoint interrupts and
;                 dispatches all SETUP, IN, and OUT transfers to the proper
;                 dispatch routines for all supported USB requests.
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:   n/a
;
;  RETURNS:     n/a
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
 USBUART_EP0_ISR:
_USBUART_EP0_ISR:
        push A
        push X
    REG_PRESERVE MVW_PP
    REG_PRESERVE MVR_PP

    RAM_SETPAGE_MVW 0
    RAM_SETPAGE_MVR 0

    ; Dispatch to setup/in/out handlers
    MOV  A, reg[USBUART_EP0MODE]        ; Get the mode reg

    ; MSB is the SETUP bit, followed by IN, then OUT
    ASL  A                              ; Shift to the carry and jump if SETUP bit set
    JC   USBUART_EP0_Setup

    ASL  A                              ; Shift to the carry and jump if IN bit set
    JC   USBUART_EP0_IN

    ASL  A                              ; Shift to the carry and jump if OUT bit set
    JC   USBUART_EP0_OUT

    JMP    USBUART_Not_Supported_Local_Drv

; ISR Exit Point to update the mode register
;   mode and count have been pushed onto the stack
EXPORT USBUART_EP0_UPD_MODE_EXIT
USBUART_EP0_UPD_MODE_EXIT:

    MOV    REG[USBUART_EP0CNT], A      ; Update the count
    MOV    A, X                        ; Get the new mode
    MOV    REG[USBUART_EP0MODE], A     ; Update the node

; Common Exit Point
USBUART_EP0_ISR_EXIT:
    REG_RESTORE MVR_PP
    REG_RESTORE MVW_PP
    POP  X                              ;
;       MOV  A, [USBUART_TempMode]
;       MOV  reg[USBUART_EP0MODE], A
    POP  A                              ; Restore Context
    RETI


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_EP0_Setup
;
;  DESCRIPTION:   Dispatch a USB SETUP
;
;-----------------------------------------------------------------------------
 USBUART_EP0_Setup:
_USBUART_EP0_Setup:
; Check the byte count and validity.  All SETUP are 8 bytes and 0 toggle
    PUSH    A                          ; Save the mode register
    MOV     A, USB_XFER_PREMATURE      ; Return a Premature Completion?
    CALL    USBUART_UpdateStatusBlock
    POP     A                          ; Restore the mode register
    MOV    A, REG[USBUART_EP0CNT]            ; Get the count reg
    CMP    A, (USB_CNT_VALID | 0x0A)
    JZ      .dispatch

    JMP    USBUART_Not_Supported_Local_Drv


;-----------------------------------------------------------------------------
; Jump here to dispatch the request
; The SETUP request is encoded in [bmRequestType]. Among the 8 bits in [bmRequestType], only bits
; 7,6,5,1,0 determine what the request is. Bits [2:4] are default to zero. The below code
; re-organizes [bmRequestType] to the following format:
; ( Zero, Zero, Bit7, Bit6, Bit5, Bit1, Bit0, Zero ), and depending on the value of this
; "re-organization", the firmware will jump to an appropriate table to handle the request.
;-----------------------------------------------------------------------------
.dispatch:
    MOV     A, REG[USBUART_EP0DATA+bmRequestType]   ; Get bmRequestType
    AND     A, E3h                           ; clear bits 4-3-2, these unused for our purposes
    PUSH    A                                ; store value on the stack
    ASR     A                                ; move bits 7-6-5 into 4-3-2's place
    ASR     A                                ; "asr" instruction shift all bits one place to the right.
    ASR     A                                ; Bit7 remains the same.
    MOV     [USBUART_t2], A                  ; store shifted value
    POP     A                                ; get original value
    OR      A, [USBUART_t2]                  ; or the two to get the 5-bit field
    AND     A, 1Fh                           ; clear bits 7-6-5 (asr wraps bit7)
                                             ; Bit0 is loaded with a Zero. This results in multiplying
                                             ; the accumulator by 2, and the reason to multiply it by 2
                                             ; is that each "jmp" instruction in the tables is two bytes long.

    LJMP USBUART_bmRequestType_Dispatch


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_EP0_IN
;
;  DESCRIPTION: Handles an IN request.  Depending on the state of the
;               enumeration sequence it decides what to do next
;
;-----------------------------------------------------------------------------
 USBUART_EP0_IN:
_USBUART_EP0_IN:

    MOV  A, [USBUART_TransferType]
;    CALL USBUART_ControlInDispatch
;    JMP  USBUART_EP0_ISR_EXIT               ; And exit
USBUART_ControlInDispatch:
    JACC    USBUART_ControlInDispatchTable
.LITERAL
USBUART_ControlInDispatchTable:
    JMP     USBUART_Not_Supported_Local_Drv  ; USB_TRANS_STATE_IDLE
    JMP     USBUART_ControlReadDataStage     ; USB_TRANS_STATE_CONTROL_READ
    JMP     USBUART_ControlWriteStatusStage  ; USB_TRANS_STATE_CONTROL_WRITE
    JMP     USBUART_NoDataControlStatusStage ; USB_TRANS_STATE_NO_DATA_CONTROL
.ENDLITERAL


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_EP0_OUT
;
;  DESCRIPTION: HANDles an OUT request.  Depending on the state of the
;               enumeration sequence it decides what to do next
;
;-----------------------------------------------------------------------------
 USBUART_EP0_OUT:
_USBUART_EP0_OUT:
    MOV     A, [USBUART_TransferType]
    JACC    USBUART_ControlOutDispatchTable
.LITERAL
USBUART_ControlOutDispatchTable:
    JMP     USBUART_Not_Supported_Local_Drv  ; USB_TRANS_STATE_IDLE
    JMP     USBUART_ControlReadStatusStage   ; USB_TRANS_STATE_CONTROL_READ
    JMP     USBUART_ControlWriteDataStage    ; USB_TRANS_STATE_CONTROL_WRITE
    JMP     USBUART_NoDataControlError       ; USB_TRANS_STATE_NO_DATA_CONTROL
.ENDLITERAL


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_InitControlRead
;
;  DESCRIPTION:   This routine initializes a control read.  It must be JUMPed to,
;                 not called.  It assumes a transfer descriptor has been loaded
;                 into the driver USBUART_CurrentTD data structure.
;
;-----------------------------------------------------------------------------
 USBUART_InitControlRead:
_USBUART_InitControlRead:
    MOV     [USBUART_LastSize], A      ; Save the packet size?
    CALL    USBUART_InitializeStatusBlock
    MOV     [USBUART_TransferType], USB_TRANS_STATE_CONTROL_READ

    ; Check the transfer size against the request size
    MOV    A, REG[USBUART_EP0DATA+wLengthHi] ; MSB of wLength
    CMP    A, [USBUART_TransferSize]
    JNZ    .L1

    MOV    A, REG[USBUART_EP0DATA+wLengthLo] ; LSB of wLength
    CMP    A, [USBUART_TransferSize+1]
    JZ     .L9
.L1:
    JNC    .L9
;
    MOV    [USBUART_TransferSize+1], A ;
    MOV    A, REG[USBUART_EP0DATA+wLengthHi] ;
    MOV    [USBUART_TransferSize], A   ;
.L9:
    MOV    [USBUART_TransferByteCount], 0 ;
    MOV    [USBUART_TransferByteCount+1], 0 ;

    OR     [USBUART_EP0DataToggle], 1 ; setup EP0 data toggle
    JMP    USBUART_LoadEndpoint        ;
;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_ControlReadDataStage
;
;  DESCRIPTION:   This routine processes the data stage of a control read.  It
;                 must be JUMPed to, not called.  It assumes a transfer descriptor
;                 has been loaded into the driver USBUART_CurrentTD
;                 data structure.
;
;-----------------------------------------------------------------------------
 USBUART_ControlReadDataStage:
    JMP     USBUART_LoadEndpoint

;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_ControlReadStatusStage
;
;  DESCRIPTION:   This routine processes the status stage of a control read.  It
;                 must be JUMPed to, not called.  It handles short or 0 packet
;                 It assumes a transfer descriptor has been loaded into the
;                 driver USBUART_CurrentTD data structure.
;
;-----------------------------------------------------------------------------
 USBUART_ControlReadStatusStage:
    MOV    A, [USBUART_LastSize]       ; Get the number of bytes from the last transfer
    ADD    [USBUART_TransferByteCount + 1], A ; Update the transfer byte count
    ADC    [USBUART_TransferByteCount], 0 ;
    MOV    A, USB_XFER_STATUS_ACK      ; Return a Status ACK Completion
    CALL   USBUART_UpdateStatusBlock
    MOV    [USBUART_TransferType], USB_TRANS_STATE_IDLE
    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STALL_IN_OUT
    JMP    USBUART_EP0_UPD_MODE_EXIT
;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_NoDataStageControlTransfer
;                 USBUART_InitNoDataStageControlTransfer
;
;  DESCRIPTION:   This routine processes the status stage of a no data control
;                 write.  It must be JUMPed to, not called.
;
;-----------------------------------------------------------------------------
 USBUART_NoDataStageControlTransfer:
_USBUART_InitNoDataStageControlTransfer:
 USBUART_InitNoDataStageControlTransfer:
    CALL    USBUART_InitializeStatusBlock

    MOV    [USBUART_TransferType], USB_TRANS_STATE_NO_DATA_CONTROL

    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STATUS_IN_ONLY
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_InitControlWrite
;
;  DESCRIPTION:   This routine initializes control write.  It must be JUMPed
;                 to, not called.  It assumes a transfer descriptor has been loaded
;                 into the driver USBUART_CurrentTD data structure.
;
;-----------------------------------------------------------------------------
 USBUART_InitControlWrite:
_USBUART_InitControlWrite:
    MOV     A, [USBUART_DataSource]    ; Need to make sure the destination is not ROM
    CMP     A, USB_DS_ROM
    JZ      USBUART_Not_Supported_Local_Drv

    CALL    USBUART_InitializeStatusBlock

    MOV    [USBUART_TransferType], USB_TRANS_STATE_CONTROL_WRITE

    OR     [USBUART_EP0DataToggle], 1 ; setup EP0 data toggle

    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_ACK_OUT_STATUS_IN
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_ControlWriteDataStage
;
;  DESCRIPTION:   This routine processes the data stage of a control
;                 write.  It must be JUMPed to, not called.  It assumes a
;                 transfer descriptor has been loaded into the driver
;                 USBUART_CurrentTD data structure.
;
;-----------------------------------------------------------------------------
 USBUART_ControlWriteDataStage:
    XOR    [USBUART_EP0DataToggle], 1  ; Update data toggle

    MOV    A,REG[USBUART_EP0CNT]       ; Get the count

    AND     A, 0x0F
    SUB     A, 2                       ; Count include the two byte checksum

    MOV     [USBUART_t2], A            ; Assume we have room to receive the whole packet

    MOV     A, 0
    CMP     A, [USBUART_TransferSize]  ; If the MSB has anything just use the count
    JNZ     .L1

    MOV     A, [USBUART_t2]
    CMP     A, [USBUART_TransferSize+1]  ;
    JZ      .L6
.L1:
    JC      .L6
    MOV     [USBUART_t2], [USBUART_TransferSize+1]

.L6:
    MOV     A, [USBUART_t2]
    SUB     [USBUART_TransferSize+1],A   ; Update the bytes remaining
    SBB     [USBUART_TransferSize], 0  ;

    ADD     [USBUART_TransferByteCount + 1], A ; Update the transfer byte count
    ADC     [USBUART_TransferByteCount], 0 ;

    MOV     X,0                        ; Start the index at 0

IF SYSTEM_LARGE_MEMORY_MODEL
    REG_PRESERVE MVW_PP
    mov     A, [USBUART_DataPtr]  ; set proper page for mvi command
    mov     reg[MVW_PP], A
ENDIF
.RAM_COPY:
    MOV     A, REG[X+USBUART_EP0DATA]  ; Get the data
    MVI     [USBUART_DataPtr+1], A     ; Store the data, bump the destination

    INC     X                          ; Bump the destination offset
    MOV     A,X                        ; Are we done?
    CMP     A, [USBUART_t2]
    JC      .RAM_COPY                  ; Not done

IF SYSTEM_LARGE_MEMORY_MODEL
    REG_RESTORE MVW_PP
ENDIF
    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_ACK_OUT_STATUS_IN
    JMP    USBUART_EP0_UPD_MODE_EXIT

; Jump here on data toggle error
.error:
    MOV    [USBUART_TransferType], USB_TRANS_STATE_IDLE  ; This simply aborts the transfer
    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STALL_IN_OUT
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_ControlWriteStatusStage
;
;  DESCRIPTION:   This routine processes the status stage of a control
;                 write.  It must be JUMPed to, not called.  It assumes a
;                 transfer descriptor has been loaded into the driver
;                 USBUART_CurrentTD data structure.
;
;-----------------------------------------------------------------------------
 USBUART_ControlWriteStatusStage:
    MOV    A, USB_XFER_STATUS_ACK      ; Return a Status ACK Completion
    CALL   USBUART_UpdateStatusBlock
    MOV    [USBUART_TransferType], USB_TRANS_STATE_IDLE  ; The packet is done
    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STALL_IN_OUT
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_NoDataControlStatusStage
;
;  DESCRIPTION:   This routine processes the status stage of a control
;                 write.  It must be JUMPed to, not called.  It assumes a
;                 transfer descriptor has been loaded into the driver
;                 USBUART_CurrentTD data structure.
;
;                 USB Device Addressing happens here because we can't change
;                 the SIE Address before the Status IN is received.
;
;-----------------------------------------------------------------------------
 USBUART_NoDataControlStatusStage:
    MOV     A, USB_XFER_STATUS_ACK     ; Return a Status ACK Completion
    CALL    USBUART_UpdateStatusBlock
    ; Dispatch to the proper handler
    CMP     [USBUART_fDataPending], USB_ADDRESS_CHANGE_PENDING
    JNZ     .L1

    ; USB ADDRESS CHANGE
    MOV     A, [USBUART_TransferBuffer]  ; Get the pending data

    OR      A, USB_ADDR_ENABLE         ; Set the enable bit
    MOV     REG[USBUART_ADDR], A       ; Update the SIE address
    JMP     .EXIT
.L1:

.EXIT:
    MOV     [USBUART_fDataPending], 0  ; Clear data pending

    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STATUS_IN_ONLY  ; Wait for the next SETUP
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_NoDataControlError
;
;  DESCRIPTION:   This routine handles the condition when we expected a
;                 status IN, but receive an OUT
;
;-----------------------------------------------------------------------------
 USBUART_NoDataControlError:
    MOV    A, USB_XFER_ERROR           ; Return Transaction Error
    CALL   USBUART_UpdateStatusBlock
    MOV    A, 0                        ; Count Register
    MOV    X, USB_MODE_STALL_IN_OUT    ; Set the mode register
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_LoadEndpoint
;
;  DESCRIPTION: Moves data from either RAM OR ROM - depending on the request
;               type AND then places the appropriate number of bytes -
;               depending on the request size into the endpoint FIFO.
;               It finally sets up the endpoint to send data.
;
USBUART_LoadEndpoint:
    MOV     A, [USBUART_LastSize]      ; Get the number of bytes from the last transfer
    ADD     [USBUART_TransferByteCount + 1], A ; Update the transfer byte count
    ADC     [USBUART_TransferByteCount], 0 ;
    MOV     A,  [USBUART_TransferSize] ; Check to see if we have any
    OR      A,  [USBUART_TransferSize+1] ;  more data to send
    JNZ     .cont                      ; Jump if we have to send more data

; Flow here if there is no more data to send (kvn restored following two lines to fix mod 8 descriptor issue
;                                             (no zero length EPt0 termination packets are sent with these lines gone)
    cmp     [USBUART_LastSize], 8      ; Was it a full packet?
    JZ      .START_TRANSFER            ; Jump if it was full (need to send a zero length)

; Flow here if we are entering the status stage
    MOV    A, 0                        ; Count Register
    MOV    [USBUART_LastSize], A       ; Clear the byte count
    MOV    X, USB_MODE_STATUS_OUT_ONLY ; Only ACK the Status Out
    JMP    USBUART_EP0_UPD_MODE_EXIT

; Jump here to determine how many bytes should we transfer
.cont:
    CMP     [USBUART_TransferSize], 0  ; Check the MSB
    JNZ     .L1

    CMP     [USBUART_TransferSize+1], 8  ; Check the LSB
    JNC     .L1

    MOV     A,[USBUART_TransferSize+1]   ; Transfer all the remaining data
    JMP     .L3

.L1:
    MOV     A, 8                       ; Just transfer the next 8 bytes

.L3:

    SUB     [USBUART_TransferSize+1],A   ; Update the bytes remaining
    SBB     [USBUART_TransferSize],0

    MOV     [USBUART_t2],A             ; Save the count
    MOV     X,0

    CMP     [USBUART_DataSource],USB_DS_ROM  ; RAM or ROM copy?
    JNZ     .RAM_COPY

; Copy data from a ROM source
.ROM_COPY:
    PUSH    X                          ; Save the destination offset
    MOV     A,[USBUART_DataPtr]        ; Get the transfer source MSB
    MOV     X,[USBUART_DataPtr+1]      ; Set the transfer source LSB
    INC     [USBUART_DataPtr+1]        ; Increment the data pointer
    ADC     [USBUART_DataPtr], 0       ;   MSB if necessary

    ROMX                               ; Get the data byte

    POP     X                          ; Get the destination offset
    MOV     REG[X + USBUART_EP0DATA], A; Load the data
    INC     X                          ; Bump the destination offset
    MOV     A,X                        ; Are we done?
    CMP     A, [USBUART_t2]
    JC      .ROM_COPY                  ; Not done
    JMP     .START_TRANSFER            ; Otherwise go start the transfer

; Copy data from a RAM source
.RAM_COPY:
IF SYSTEM_LARGE_MEMORY_MODEL
    REG_PRESERVE MVR_PP
    mov     A, [USBUART_DataPtr]  ; set proper page for mvi command
    mov     reg[MVR_PP], A
ENDIF
.CP1:
    MVI     A, [USBUART_DataPtr+1]     ; Get the data, bump the source

    MOV     REG[X +USBUART_EP0DATA], A ; Load the data
    INC     X                          ; Bump the destination offset
    MOV     A,X                        ; Are we done?
    CMP     A, [USBUART_t2]
    jc      .CP1                       ; Not done

IF SYSTEM_LARGE_MEMORY_MODEL
    REG_RESTORE MVR_PP
    mov     A, X                       ; Restore A
ENDIF

;; Set up the IN transfer count/mode/etc
;    A contains the byte count
.START_TRANSFER:
    MOV     [USBUART_LastSize], A      ; Save the packet size

    MOV     A, 1
    AND     A, [USBUART_EP0DataToggle]
    JZ      .BYPASS_T1
    MOV     A, USB_CNT_TOGGLE          ; Or T1 in the data toggle

.BYPASS_T1:
    OR      A, [USBUART_LastSize]
    XOR     [USBUART_EP0DataToggle], 1    ; Update the data toggle for next time

    MOV    X, USB_MODE_ACK_IN_STATUS_OUT  ; Set the mode register
    JMP    USBUART_EP0_UPD_MODE_EXIT


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_GetTableEntry
;
;  DESCRIPTION: This function figures out based on the various bytes in the
;               setup packet where to get the data from or put the data to.
;               Transfer Data structures are defined each of the supported
;               control transfers, this function finds the right one and
;               saves it in the CurrentTD structure in RAM.  It then
;               calls InitControlRead or InitControlWrite to being the
;               transaction.
;
;-----------------------------------------------------------------------------
EXPORT USBUART_GetTableEntry
USBUART_GetTableEntry:

    INC     X                          ; Point to the first table entry
    ADC     A, 0                       ;

    TD_INDEX_TO_OFFSET USBUART_t2 ; Convert the index

    SWAP    A, X
    ADD     A, [USBUART_t2]
    SWAP    A, X
    ADC     A, 0                       ; A:X now points to the descriptor table entry we want

; Flow here to load the Transfer Descriptor (TD_ENTRY)
    MOV     [USBUART_t2], USBUART_CurrentTD  ; Use Temp as MVI pointer
    CALL     USBUART_GETBYTE           ; Get the descriptor data source
    CALL     USBUART_GETWORD           ; Get the descriptor size
    CALL     USBUART_GETWORD           ; Get the descriptor address
    CALL     USBUART_GETWORD           ; Get the Status Pointer
; Dispatch to InitControlRead or InitControlWrite based on d2h/h2d in the request
    MOV    A, REG[USBUART_EP0DATA+bmRequestType] ; Get bmRequestType
    AND     A,0x80                          ; Control Read or Write
    JZ      .control_write

    JMP     USBUART_InitControlRead

.control_write:
    JMP     USBUART_InitControlWrite


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_LOOKUP
;
;  DESCRIPTION:    Returns the address of an entry in a lookup table (LT_ENTRY)
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:    A:X Point to the lookup table
;                USBUART_t2 contain the table index
;
;  RETURNS:      Address of the LT_ENTRY in A:X
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
EXPORT USBUART_LOOKUP
USBUART_LOOKUP:
    INC     X                          ; Point to the first table entry
    ADC     A, 0                       ;

    LT_INDEX_TO_OFFSET USBUART_t2      ; Convert the index
    SWAP    A, X
    ADD     A, [USBUART_t2]            ;
    SWAP    A, X
    ADC     A, 0
    RET


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_GETWORD/USBUART_GETBYTE
;
;  DESCRIPTION:    Get a word value from ROM
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:    A:X is the ROM Address
;                USBUART_t2 is the destination address
;
;  RETURNS:      USBUART_t1
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;                USES USBUART_t2
;                A:X points to the subsequent ROM location
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
EXPORT USBUART_GETWORD
USBUART_GETWORD:

    PUSH    A                          ; Don't loose the pointer MSB
    ROMX                               ; Data source flag
    MVI     [USBUART_t2], A            ; Save the data source
    POP     A                          ; Get the MSB back
    INC     X                          ; Point to the next  entry
    ADC     A, 0                       ;

EXPORT USBUART_GETBYTE
USBUART_GETBYTE:

    PUSH    A                          ; Don't loose the pointer MSB
    ROMX                               ; Data source flag
    MVI     [USBUART_t2], A            ; Save the data source
    POP     A                          ; Get the MSB back
    INC     X                          ; Point to the next  entry
    ADC     A, 0                       ;
    RET


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_GET_DEVICE_TABLE_ENTRY
;
;  DESCRIPTION:    Get the address of the current DEVICE_TABLE entry
;                  Not intended for use by C functions
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:
;
;  RETURNS:        A:X points the current DEVICE_TABLE entry
;                  Carry flag is set if the current device index is out of range
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
EXPORT USBUART_GET_DEVICE_TABLE_ENTRY
USBUART_GET_DEVICE_TABLE_ENTRY:
    MOV     [USBUART_t2], [USBUART_bCurrentDevice]  ; Use the UM temp var--Selector

    MOV     A,>USBUART_DEVICE_LOOKUP   ; Get the ROM Address MSB
    MOV     X,<USBUART_DEVICE_LOOKUP   ; Get the ROM Address LSB
    ROMX                               ; First entry is the table size (only a byte)
    CMP     A, [USBUART_t2]            ; Range check
    MOV     A,>USBUART_DEVICE_LOOKUP   ; Get the ROM Address MSB
    JC      .exit
; Flow here if the index is valid
    CALL    USBUART_LOOKUP             ; Look up the configuration
; Jump or flow here on exit
.exit:
    RET


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_GET_CONFIG_TABLE_ENTRY
;
;  DESCRIPTION:    Get the address of the current DEVICE_TABLE entry
;                  Not intended for use by C functions
;                  Does not do range checking on
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:
;
;  RETURNS:        A:X points the current CONFIG_TABLE entry
;                  Carry flag is set if the current device index is out of range
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
EXPORT USBUART_GET_CONFIG_TABLE_ENTRY
USBUART_GET_CONFIG_TABLE_ENTRY:
    CALL    USBUART_GET_DEVICE_TABLE_ENTRY  ; Get the selected device
    MOV     [USBUART_t2],USBUART_t1    ; Set the GETWORD destination
    CALL    USBUART_GETWORD            ; Get the pointer to the CONFIG_LOOKUP table
                                       ; ITempW has the address
    MOV     A, REG[USBUART_EP0DATA+wValueLo]  ; Get the configuration number
    MOV     [USBUART_t2],A             ; Save it
    MOV     A, [USBUART_t1]            ; Get the CONFIG_LOOKUP ROM Address MSB
    MOV     X, [USBUART_t1+1]          ; Get the CONFIG_LOOKUP ROM Address LSB

; A:X Points to the CONFIG_LOOKUP, so get the current entry
    MOV     [USBUART_t2], [USBUART_Configuration] ; Get the configuration number
    DEC     [USBUART_t2]               ; We don't populate the 0th entry
    CALL    USBUART_LOOKUP             ; Look up the configuration
    RET


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_UpdateStatusBlock
;
;  DESCRIPTION:    Update the Completion Status Block for a Request.  The
;                  block is updated with the completion code from the
;                  argument (A) and the _TransferByteCount.
;
;                  The StatusBlock Pointer (_StatusBlockPtr) is set to NULL (0)
;                  to make sure no other updates are made to the StatusBlock by
;                  the USB User Module.
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:      A contains the Completion Status Code
;
;  RETURNS:        None
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
USBUART_UpdateStatusBlock:
    MOV     X, [USBUART_StatusBlockPtr + 1] ;
    SWAP    A, X                       ; Don't loose the completion code
    CMP     A, 0                       ; NULL?
    JZ      .done                      ; No update on NULL
; Flow here to update the VSR Completion Status Block
    SWAP    A, X                       ; Completion code A, Pointer in X
    MOV     [X + 0], A                 ; Update the completion Code
    MOV     A, [USBUART_TransferByteCount] ; Actual Byte Count MSB
    MOV     [X + 1], A
    MOV     A, [USBUART_TransferByteCount + 1] ; Actual Byte Count LSB
    MOV     [X + 2], A
    MOV     [USBUART_StatusBlockPtr + 1], 0 ; Clear the Block Pointer
.done:
    RET                                ; All done


;-----------------------------------------------------------------------------
;  FUNCTION NAME: USBUART_InitializeStatusBlock
;
;  DESCRIPTION:    Initialize the Completion Status Block for a Request.
;                  The completion code is set to USB_XFER_IDLE.
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:      None
;
;  RETURNS:        None
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
USBUART_InitializeStatusBlock:
    MOV     A, [USBUART_StatusBlockPtr + 1] ;
    CMP     A, 0                       ; NULL?
    JZ      .done                      ; No update on NULL
; Flow here to initialize the Completion Status Block
    SWAP    A, X                       ; Pointer in X
    MOV     [X + 0], USB_XFER_IDLE     ; Initialize the completion code (0)
    MOV     [USBUART_TransferByteCount], 0 ; Clear the byte count
    MOV     [USBUART_TransferByteCount + 1], 0 ;
.done:
    RET                                ; All done


;-----------------------------------------------------------------------------
;  FUNCTION NAME: ;  USB 1st Tier Dispatch Jump Table (based on bmRequestType)
;
;  DESCRIPTION:
;
;-----------------------------------------------------------------------------
;
;  ARGUMENTS:
;
;  RETURNS:
;
;  SIDE EFFECTS: REGISTERS ARE VOLATILE: THE A AND X REGISTERS MAY BE MODIFIED!
;
;  THEORY of OPERATION or PROCEDURE:
;
;-----------------------------------------------------------------------------
MACRO BMREQUEST_DISPATCH
IF (USB_CB_@0_@1_@2 & 1)
    JMP     USBUART_DT_@0_@1_@2_Dispatch
ELSE
    JMP     USBUART_Not_Supported_Local_Drv
ENDIF
ENDM

USBUART_DT_bmRequestType::
    BMREQUEST_DISPATCH    h2d,std,dev
    BMREQUEST_DISPATCH    h2d,std,ifc
    BMREQUEST_DISPATCH    h2d,std,ep
    BMREQUEST_DISPATCH    h2d,std,oth
    BMREQUEST_DISPATCH    h2d,cls,dev
    BMREQUEST_DISPATCH    h2d,cls,ifc
    BMREQUEST_DISPATCH    h2d,cls,ep
    BMREQUEST_DISPATCH    h2d,cls,oth
    BMREQUEST_DISPATCH    h2d,vnd,dev
    BMREQUEST_DISPATCH    h2d,vnd,ifc
    BMREQUEST_DISPATCH    h2d,vnd,ep
    BMREQUEST_DISPATCH    h2d,vnd,oth
    BMREQUEST_DISPATCH    h2d,rsv,dev
    BMREQUEST_DISPATCH    h2d,rsv,ifc
    BMREQUEST_DISPATCH    h2d,rsv,ep
    BMREQUEST_DISPATCH    h2d,rsv,oth
    BMREQUEST_DISPATCH    d2h,std,dev
    BMREQUEST_DISPATCH    d2h,std,ifc
    BMREQUEST_DISPATCH    d2h,std,ep
    BMREQUEST_DISPATCH    d2h,std,oth
    BMREQUEST_DISPATCH    d2h,cls,dev
    BMREQUEST_DISPATCH    d2h,cls,ifc
    BMREQUEST_DISPATCH    d2h,cls,ep
    BMREQUEST_DISPATCH    d2h,cls,oth
    BMREQUEST_DISPATCH    d2h,vnd,dev
    BMREQUEST_DISPATCH    d2h,vnd,ifc
    BMREQUEST_DISPATCH    d2h,vnd,ep
    BMREQUEST_DISPATCH    d2h,vnd,oth
    BMREQUEST_DISPATCH    d2h,rsv,dev
    BMREQUEST_DISPATCH    d2h,rsv,ifc
    BMREQUEST_DISPATCH    d2h,rsv,ep
    BMREQUEST_DISPATCH    d2h,rsv,oth
USBUART_DT_End:
USBUART_DT_Size: equ (USBUART_DT_End-USBUART_DT_bmRequestType) / 2
USBUART_bmRequestType_Dispatch::
    DISPATCHER USBUART_DT_bmRequestType, USBUART_DT_Size, USBUART_Not_Supported_Local_Drv

USBUART_Not_Supported_Local_Drv:
        LJMP     USBUART_Not_Supported


;-----------------------------------------------
; Add custom application code for routines
;-----------------------------------------------

   ;@PSoC_UserCode_BODY_1@ (Do not change this line.)
   ;---------------------------------------------------
   ; Insert your custom code below this banner
   ;---------------------------------------------------

   ;---------------------------------------------------
   ; Insert your custom code above this banner
   ;---------------------------------------------------
   ;@PSoC_UserCode_END@ (Do not change this line.)

; End of File USBUART_drv.asm
