;**************************************************************************
;**                                                                      **
;**                  I N T E L   P R O P R I E T A R Y                   **
;**                                                                      **
;**     COPYRIGHT (c)  1996, 1997 BY  INTEL  CORPORATION.  ALL RIGHTS    **
;**     RESERVED.   NO  PART  OF THIS PROGRAM  OR  PUBLICATION  MAY      **
;**     BE  REPRODUCED,   TRANSMITTED,   TRANSCRIBED,   STORED  IN  A    **
;**     RETRIEVAL SYSTEM, OR TRANSLATED INTO ANY LANGUAGE OR COMPUTER    **
;**     LANGUAGE IN ANY FORM OR BY ANY MEANS, ELECTRONIC, MECHANICAL,    **
;**     MAGNETIC,  OPTICAL,  CHEMICAL, MANUAL, OR OTHERWISE,  WITHOUT    **
;**     THE PRIOR WRITTEN PERMISSION OF :                                **
;**                                                                      **
;**                        INTEL  CORPORATION                            **
;**                                                                      **
;**                     2200 MISSON COLLEGE BLVD                         **
;**                                                                      **
;**               SANTA  CLARA,  CALIFORNIA  95052-8119                  **
;**                                                                      **
;**************************************************************************
;   (C) Copyright Intel Corp., 1997
;
;   File: hub_ep0.asm
;
;   Universal Serial Bus 930 Test firmware
;   HUB ROM CODE Version
;
;   ;*** NOTE to Programmer !!!
;   Please change the Revision number in the device descriptor and in Serial #
;   String Descriptor (String_3) at end of code.
;
;   Revision History
;   ---------------------------------------------
;    1.51    7-23-98		Paul Luse
;				cleanup
;				changed includes to absolute	
;				fixed Keil org statements to CSEG at
;    1.5     07-23-97          Chip Linthicum
;                               Changed VID from 8086 to 042B for INTEL for hub
;    1.4     07-14-97          Chip Linthicum
;                               Removed serial number - set to 0 for compliance
;                               with new MS Memphis Beta 1 stack
;    1.3     05-29-97          Chip Linthicum
;                               Changed HUB_FIRM.ASM to fix problem when the
;                                embedded function is disabled and host continued
;                                to see status changes on port 4.
;    1.2     05-12-97          Chip / Ken
;                               Changed ONE_OH.INC hub_desc to 29h
;    1.1     03-27-97          Charles H Linthicum Jr.
;                              Added HELSINKI switch for HELSINKI ROM code -
;                               enabling the fourth downstream port
;                              This code supports both Helsinki and Halifax
;                               and EVAL boards and FUB board.
;    1.0     03-19-97          Charles H Linthicum Jr.
;                              Moved all configuration switches to SWITCH.INC
;                              Added checking P1 bit 1  to determine if
;                              Embedded Function will be enabled or disabled
;                              Mode 1 FUB jumper: P1 Bit 1.1 = 1 = attached or enabled
;                              Mode 1 FUB jumper: P1 Bit 1.1 = 0 = not attached
;                              Fixed strings for embedded function.
;                              Changed code to work with Intel Compatibility turned on.
;                              Added interface string descriptor as index 5
;                              Added display of SWITCH setup to display in the
;                               Configuration string descriptor
;                              Changed use of INTERNAL_PORT switch to be used by
;                                eval board setups to enable/disable the embedded
;                                function.
;    0.9     03-07-97          Charles H Linthicum Jr.
;                              Fixed Get Status to return correct status of
;                              part power - whether bus or self
;                              Added string for index 0 - English Lang. ID
;                              Added string for serial number = firmware rev
;                              Added configuration string to say "embedded fn disabled"
;                              Removed carriage returns from strings
;    0.8     03-05-97          Charles H Linthicum Jr.
;                              Added checking P1 bit 0  to determine if
;                              FUB HUB will be bus or self powered
;                              Bit 1.0 = 1 = Self Powered
;                              Bit 1.0 = 0 = Bus Powered
;                              fixed string descriptors
;                              Config 1 is self powered
;                              Config 2 is bus powered
;    0.7     02-13-97          Charles H Linthicum Jr.
;                              Added OHCI fix around setting TXCLR
;    0.6     12-03-96          Charles H Linthicum Jr.
;                              Added capability to enable LC toggle during heartbeat, by
;                              changing LC_TOGGLE assembler directive.
;    0.5     08-20-96          Kenneth Schultz
;                              Cleaned up stuff for hub and test out better.
;
;    0.4     08-01-96          Kenneth Schultz
;                              Cleaned up and documented better.  Also added hooks for
;                              control write command Data Stages, & Hub.
;    0.3     07-15-96          Kenneth Schultz
;                              Converted to using A Register only for furture products.
;    0.2     06-29-96          Kenneth Schultz
;    0.1     05-27-96          Abdul Rahman Ismail
;
 ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

;These two equate statements allow the user to switch between the PLC
;and Keil assemblers.  Place a 1 on the assembler that is to be used to
;assemble this file.
PLC EQU 1
KEIL EQU 0
;=======================================================================
;=                           Includes
;=======================================================================
IF PLC
  	include "8X930HX.INC"
	include "SWITCH.INC"
ENDIF
IF KEIL
 	$INCLUDE (Reg930.inc)
	$INCLUDE (SWITCH.INC)
ENDIF

IF DOUG == USE                  ; Use DOUG routines
  INCLUDE "c:\include\flags.inc"
  SV      equ  ENABLED
  ARCH    equ  251
  PROC    equ  i8X930HX
  INCLUDE "c:\include\sv.inc"
                            ; DON'T use DOUG
ENDIF



;=======================================================================
;=                           Equates
;=======================================================================

FIFO_SIZE             equ     008h
GET_COMMAND           equ     080h
EP1_TX_FIFO_SIZE      equ     20h     ; 32 bytes
EP2_TX_FIFO_SIZE      equ     08h     ; 8 bytes
SETUP_PHASE           equ     000h
DATA_PHASE            equ     001h
STATUS_PHASE          equ     002h


EP0_MAX_PACKET_SIZE     equ      08h
NULL_DATA_PACKET        equ     000h

;=======================================================================
;=                    External Routines / Code
;=======================================================================

IF PLC
	extern GetClassDeviceCommand:CODE
	extern GetClassOtherCommand:CODE
	extern SetClassDeviceCommand:CODE
	extern SetClassOtherCommand:CODE
	extern InitilizeHubVariables:CODE
	extern InitilizeEmbeddedFunction:CODE
	extern FifoWatchDog:CODE
ENDIF
IF KEIL
   	extern CODE (GetClassDeviceCommand)
	extern CODE (GetClassOtherCommand)
	extern CODE (SetClassDeviceCommand)
	extern CODE (SetClassOtherCommand)
	extern CODE (InitilizeHubVariables)
	extern CODE (InitilizeEmbeddedFunction)
	extern CODE (FifoWatchDog)
ENDIF

public LoadBuffer
public gbFControlBufferLocation
public EmbeddedFunctionInReset
public RightCylon, LeftCylon

IF PLC
	xdef bRequest
	xdef wValue
	xdef wIndex
	extern FUNCTION_ISR:CODE
	extern SV_SOF_ROUTINE
	extern EmbeddedFunctionSofRoutine:CODE
	extern FUNCTION_SUSPEND_ROUTINE:CODE, FUNCTION_RESUME_ROUTINE:CODE
	extern STACK_DATA:PDATA
ENDIF
IF KEIL
  	public bRequest
	public wValue
	public wIndex
	extern CODE (FUNCTION_ISR)
	extern CODE (SV_SOF_ROUTINE)
	extern CODE (EmbeddedFunctionSofRoutine)
	extern CODE (FUNCTION_SUSPEND_ROUTINE), CODE (FUNCTION_RESUME_ROUTINE)
	extern EDATA (STACK_DATA)
ENDIF


IF PLC
	extern VendorGetDeviceCommandExec:CODE
ENDIF
IF KEIL
	extern CODE (VendorGetDeviceCommandExec)
ENDIF
public FwValue, RWUTimer
public EMBD_FN_FLG

;------------------------------------------------------
;----------   Device Configuration Bytes --------------
;------------------------------------------------------

IF DOUG == USE
DEFINE CCB_SEGMENT, SPACE=CODE, ORG=0FFfff8H
ELSE
	IF PLC
		DEFINE CCB_SEGMENT, SPACE=CODE, ORG=0FF7ff8H
	ENDIF
	IF KEIL
		CCB_SEGMENT SEGMENT CODE AT 07ff8H
	ENDIF
	
ENDIF

IF RISM == DISABLED
  IF FUB_BOARD == DISABLED
        RSEG CCB_SEGMENT
        db 0D2h       ;Original Binary Mode- NON PAGED MODE
        ;db 0D3h       ;Original Source Mode- NON PAGED MODE - chl testing ...
        ;db 0D1h       ;Original Source Mode- PAGED MODE - chl testing ...
        db 0F7h
  ELSE
        ;FOR FUB BOARD USE THE FOLLOWING CCBS.
        rseg CCB_SEGMENT
        db 0D2h       ;Original Binary Mode - Paged Mode
        db 0F7h
  ENDIF
ELSE
  ; If RISM is enabled then there is no need for CCBs
ENDIF

;----------------------------------------------------
;- Reset Segment is ORGed at 00, but the linker will
;- Place the reset of the signigiant figures
;----------------------------------------------------


;-----------------------------------------------------
;----------   Interrupt Vectors   --------------------
;-----------------------------------------------------
IF PLC
	public END_VECTORS,RESET_VECTOR
ENDIF

IF RISM == ENABLED
	IF PLC
		DEFINE VECTOR_SEG, SPACE=CODE, ORG=004000h
	ENDIF
	IF KEIL
        VECTOR_SEG SEGMENT CODE AT 004000H
    ENDIF

ELSE
	IF PLC
		DEFINE VECTOR_SEG, SPACE=CODE, ORG=0FF0000h
    ENDIF
    IF KEIL
        VECTOR_SEG SEGMENT CODE AT 0FF0000H
    ENDIF

ENDIF
    
IF PLC
	SEGMENT VECTOR_SEG
          
	RESET_VECTOR:       LJMP main
	INT0_VECTOR:        LJMP $
    	                ds      5

	TIM0_VECTOR:        LJMP $
    	                ds      5

	INT1_VECTOR:        LJMP $
    	                ds      5

	TIM1_VECTOR:        LJMP $
    	                ds      5

	SER_VECTOR:         LJMP $
    	                ds      5

	TIM2_VECTOR:        LJMP $
    	                ds      5

	PCA_VECTOR:         LJMP $
    	                ds 13

	SOF_VECTOR:         LJMP SOF_ISR
    	                ds 5

	USB_FUNC_VECTOR:    LJMP FUNCTION_ISR
    	                ds 5

	SUS_RSM_VECTOR:     LJMP SUSPEND_RESUME_ISR
    	                ds 25h

	TRAP_VECTOR:        LJMP $
ENDIF
IF KEIL                             ;USB interrupts and the jump to the service routines
RSEG VECTOR_SEG 
       CSEG AT 0
        LJMP MAIN
        CSEG AT 043H 
        LJMP   SOF_ISR
        CSEG AT 04BH 
       LJMP FUNCTION_ISR
  	CSEG AT 053H   
       LJMP SUSPEND_RESUME_ISR

ENDIF
END_VECTORS:
   	


IF RISM == ENABLED
	IF PLC
		DEFINE HUB_EP0_CODE_SEGMENT, SPACE=CODE, ORG = 004080H
	ENDIF
	IF KEIL
     	HUB_EP0_CODE_SEGMENT SEGMENT CODE AT 004080H
    ENDIF

ELSE
	IF PLC
		DEFINE HUB_EP0_CODE_SEGMENT, SPACE=CODE, ORG= 0FF0080H
	ENDIF
	IF KEIL
		HUB_EP0_CODE_SEGMENT SEGMENT CODE AT 0FF0080H
    ENDIF
ENDIF

IF PLC
	SEGMENT HUB_EP0_CODE_SEGMENT
ENDIF
IF KEIL
	RSEG HUB_EP0_CODE_SEGMENT
ENDIF
	

;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
;M---------------------------------------------------------------------M
;M                   MAIN                                              M
;M---------------------------------------------------------------------M
;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM

main:
        mov     SP,     #LOW (STACK_DATA)
        mov     SPH,    #HIGH(STACK_DATA)  ; Set the stack to start @ 00:0500h
        mov     DPXL,   #0ffh              ; Set DPXL to point at the FLASH device
                                           ; to access constants

        inc     FTLOCK_FLG
IF DOUG == USE

        lcall   lc_init         ; set LC bit according to DOUG setting
        mov     DPTR,  #Header
        lcall    puts


        mov     WR16,  #0FFFFh
        mov     WR18,  #HEX_DSP_32
        mov     A, #0FFh
        mov     @DR16 ,R11
        mov     WR18,  #HEX_DSP_54
        mov     @DR16 ,R11

        mov     EP0_ERROR_CNT,  #0
        mov     FTLOCK_FLG,     #0
ENDIF


        lCall   INIT_VARIABLES             ; Initialize the RAM space as required
        lCall   INIT_USB




        Lcall   InitilizeHubVariables


                                           ;----------------------------------------
                                           ;--- Enable Function Interrupts
                                           ;----------------------------------------
                                           ;----------------------------------------
                                           ;--- Enable HUB Interrupts
                                           ;----------------------------------------
        mov     EPINDEX, #80h              ; Select Hub EP1
        mov     EPCON,  #03fh              ; CNTL, ENable all
        mov     HIE,    #03h               ; Enable the USB Function HUB EP0
        setb    IEN1.0                     ; Enable HUB/SOF ISR
        mov     EPINDEX, #00h


          ; Resume is set here
        mov     RWUTimer, #00h                  ; CLear RWU Timer
        mov     EmbeddedFunctionInReset, #00h   ; Used to track when we are sending a reset to the Embdeeded function.
       setb    IEN1.2                          ; ENable Suspend/Resume ISR
        setb    EA                              ; Enable Interrupts.

        SETB    LC                              ; (kls) SET LC will reduce current draw
                                                ; by dropping the clk frequency by 75%
                                                ; Default mode..



       ljmp    ActiveLoop


;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
;A---------------------------------------------------------------------A
;A                  ACTIVE LOOP                                        A
;A---------------------------------------------------------------------A
;AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

;COMMENT *------------------------------------------------------------
;Function name     : ActiveLoop
;Brief Description : This routine simply sets and clears HEARTBEAT_LED P1.3 at a periodic rate
;                  : It purpose is to let the user know the part is alive.
;                  : If a FUB board is being used this routine will also poll the
;                  : embedded function switch on the switch port to "enable" the
;                  : embedded function.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*


;SCOPE

ActiveLoop:


IF DOUG == USE
        mov     A, P1
        mov     WR16,  #0FFFFh
        mov     WR18,  #HEX_DSP_10
        mov     @DR16 ,R11
        mov     WR18,  #HEX_DSP_76
ENDIF

IF FUB_BOARD == ENABLED
        MOV     A,  SWITCH_PORT
        jnb     EMBD_FN_SWITCH, NO_EMBD_FN
        mov     R11, EMBD_FN_FLG
        jnz     NO_EMBD_FN

        push    HPINDEX
        mov     HPINDEX, #EMBEDDED_PORT_NUMBER  ; EMBEDDED fn on port #4
        setb    PCSC
        pop     HPINDEX

        mov     A, #02h
        mov     EMBD_FN_FLG, R11
ELSE
       ; If not a FUB board - use the INTERNAL_PORT switch to enable/disable the
       ; embedded function.
  IF INTERNAL_PORT == ENABLED
        mov     R11, EMBD_FN_FLG        ; check value of flag
        cjne    A, #02h, SHOW_EMB_FN
        sjmp    ALREADY_SHOWED_EMB_FN
SHOW_EMB_FN:
        push    HPINDEX
        mov     HPINDEX, #EMBEDDED_PORT_NUMBER  ; EMBEDDED fn on port #4
        setb    PCSC
        pop     HPINDEX
        mov     A, #02h
        mov     EMBD_FN_FLG, R11
  ENDIF
ENDIF
ALREADY_SHOWED_EMB_FN:
NO_EMBD_FN:
;------------------------------------------------------------------
;-- Heart Beat
;------------------------------------------------------------------
HeartBeat:

IF LC_TOGGLE == ENABLED                    ; if HC/LC ENABLED toggle LC bit
        cpl   LC
ENDIF

        ; ************* Heartbeat visual LED  ****************
        mov     WR0,    Heart1
        inc     WR0,    #1
        mov     Heart1, WR0
        cmp     WR0,    #7FFFh
        jl      ClearBit
        setb    HEARTBEAT_LED
        sjmp    ActiveLoop
ClearBit:
        clr     HEARTBEAT_LED
        sjmp    ActiveLoop



;----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;SS                 SUSPEND/RESUME ISR
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;----------------------------------------------------------------
;COMMENT *------------------------------------------------------------
;Function name     : SUSPEND_RESUME_ISR
;BrieS Description : Service the SUSPEND_RESUME Interrupt
;                  :
;Regs preserved    : Reg. A, B  & EPINDEX are saved
;--------------------------------------------------------------------*
;SCOPE
SUSPEND_RESUME_ISR:


        push   PSW
        push   PSW1

        lcall  FUNCTION_SUSPEND_ROUTINE


        push   ACC
        push   DR0

JNB GSUS,REALSUSPEND
RETI
REALSUSPEND:
	
        mov   R11, RWUTimer             ; If timmer is zero, do a normal suspend.
        orl   R11, RWUTimer+1
        JZ    DoSuspend                 ; Otherwise wait a delay and then resume.

DoRWU:
        push WR2
        mov  WR2,   RWUTimer
        mov  WR0,   #0
WaitLoop:
        dec  DR0,  #1h
        jne  WaitLoop

        setb RWU
D1:
        jb   RWU,   D1                   ; Wait until RWU is done.
         pop  WR2

        sjmp  RESUME_CODE



DoSuspend:

        setb  PD
        nop
        nop



RESUME_CODE:
       lcall   FUNCTION_RESUME_ROUTINE   ; Let function know that a resume signal was detected.
        clr    GRSM                      ; CLear Resume Flag
        clr    GSUS                      ; CLear Suspend Flag

        pop    DR0
        pop    ACC
        pop    PSW1
        pop    PSW

        reti


;----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;SS                 SOF ISR
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
;----------------------------------------------------------------
;COMMENT *------------------------------------------------------------
;Function name     : SOF_ISR
;Brief Description : Service the SOF_ISR Interrupt
;                  : This routine simply displays the upper three bytes of the
;                  : SOF in the lower three bits of the LEDs on P1.
;                  : It does not affect the other LEDS.  Very usefull
;                  : in determining when the function is receiveing SOFs
;Regs preserved    : Reg. A is saved
;--------------------------------------------------------------------*
;SCOPE

SOF_ISR:
        push   PSW
        push   PSW1
        push   R11

        jnb     ASOF,   ExitSofIsr              ; If this ASOF bit not set, the ISR could be a HUB.  Go Check.

        lcall    EmbeddedFunctionSofRoutine

ExitSofIsr:


                                   ; The HX shares this ISR with the hub.
                                   ; Check to see if there is a HUB pending ISR
                                   ; By checking this last, we give the SOF interrupt
                                   ; higher priority.
        jb      HRXD0, HUB_ISR     ;
        jb      HTXD0, HUB_ISR

ExitSofAndHubISR:

        pop    R11
        pop    PSW1
        pop    PSW
        reti



;----------------------------------------------------------------
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;HH                 HUB ISR
;HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
;----------------------------------------------------------------
;COMMENT *------------------------------------------------------------
;Function name     : HUB_ISR
;Brief Description : Service the HUB_ISR Interrupt
;                  : This routine scans the interrupt pending bits in order
;                  : and branches to any routines that have pending interrupts.
;                  : After finishing the routine jumps back to the top of
;                  : the scanning loop to preserve interrupt priority.
;                  :
;                  : NOTE: The order of precidence is set by the order in which the
;                  : user places the checks.
;                  :
;Regs preserved    : Reg. A, B  & EPINDEX are saved
;--------------------------------------------------------------------*
;SCOPE

HUB_ISR:

         push   ACC
         push   B
         push   EPINDEX


ProcessHubEndpoints:


H_EP0:

        mov     A,   HIFLG                  ; First check to see if this is EP0 Command
        anl     A,   #03h                   ; As they require extra overhead. Mask off all but EP0 Interrupts
        jz      ExitHub

                                             ;----------------------------------------------------------------
                                             ;-- Process the EP0 COmmand in the correct order
                                             ;----------------------------------------------------------------

                                            ; If this an EP0 command then we need to process TX & RX
                                            ; ISRs in the correct order if, for whatever reason they occurred
                                            ; back to back.  This happens in OHCI systems.
        mov     A, gbSetupSeqTX
        cjne    A, #SETUP_PHASE, CheckDataStatusStage
       sjmp     DoRxFirst                   ; If the status stage is Setup then check the RX First.

CheckDataStatusStage:
                                            ; Now check to see what stage the TX is in.
                                            ; If it is in the data stage then check it first.
                                            ; If it's in the status stage then check the RX first.

        cjne    A, #DATA_PHASE, DoRxFirst   ; If current stage a data stage->a control read
                                            ; and we should process TX before RX ISR

                                            ;----------------------------------------------------------------
                                            ;-- Process the TX FIFO first
                                            ;----------------------------------------------------------------

DoTxFirst:
H_EP0_TXA:
        jnb     HTXD0,  H_EP0_RXA
        mov     EPINDEX,#80h
        lCall   ProcessInToken              ; 82930 has sent a packet to HC
        ljmp     ProcessHubEndpoints         ; Look at all Interrupt flags again

H_EP0_RXA:
        jnb     HRXD0,  ExitHub
        mov     EPINDEX,#80h
        lCall   ProcessOutToken             ; 82930 has received a packet from HC
        ljmp     ProcessHubEndpoints    ; Look at all Interrupt flags again

;--------------------------------------------------------------------------------

DoRxFirst:
                                            ;----------------------------------------------------------------
                                            ;-- Process the RX FIFO first
                                            ;----------------------------------------------------------------
H_EP0_RXB:
        jnb     HRXD0,  H_EP0_TXB
        mov     EPINDEX,#80h
        lCall   ProcessOutToken             ; 82930 has received a packet from HC
        ljmp     ProcessHubEndpoints    ; Look at all Interrupt flags again

H_EP0_TXB:
        jnb     HTXD0,  ExitHub
        mov     EPINDEX,#80h
        lCall   ProcessInToken              ; 82930 has sent a packet to HC
        ljmp     ProcessHubEndpoints    ; Look at all Interrupt flags again

;--------------------------------------------------------------------------------
;------------------------------------------------------------------------------
                                            ;----------------------------------------------------------------
                                            ;-- Process the Other EPs next
                                            ;----------------------------------------------------------------

NonEp0ISR:

ExitHub:
        pop     EPINDEX
        pop     B
        pop     ACC
        sjmp   ExitSofAndHubISR

;        pop    PSW1
;        pop    PSW
;
;        reti











;COMMENT *------------------------------------------------------------
;Function name     : ProcessOutToken
;Brief Description : Services all OUTs on EP0.
;                  : This routine checks to see if this is an OUT token oor
;                  : SETUP token.  If a SETUP token then the Control COmmand
;                  : State machine is initilized to SETUP STAGE
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessOutToken:
        mov     A,     EPINDEX
        jb      ACC.7, HubCommand

HubCommand:
        anl     HIFLG, #EP0_RX_CLR                      ; Clear the interrupt bit.

ProcCommand:
        mov     A,     RXSTAT
        jnb     ACC.6, CheckOutStatusPhase              ; Is this a setup packet??



                                                        ; Now Check for Data still in FIFO.
                                                        ; If this is true then the function
                                                        ; did not see the ACK form the host.
        mov     A,      TXFLG
        anl     A,      #0C0h
        jZ      NoEP0Error
        setb    TXCLR
        mov     TXCNTL, #00h                            ; OHCI fix for device Errata
        setb    TXCLR                                   ; OHCI fix for device Errata

        inc     EP0_ERROR_CNT
NoEP0Error:
        anl     EPCON, #03Fh                            ; If a stall was set on EP0, this will clear it
                                                        ; as stated in the new updates of the spec.
        lCall   SetupReceived

        anl     RXSTAT, #0BFh


       sjmp     ReturnProcessOutToken

CheckOutStatusPhase:
        mov     A,     gbSetupSeqRX
        cjne    A,     #STATUS_PHASE, CheckDataPhase     ; Is this the status phase of a "GET"
                                                         ; command?

        setb    RXFFRC                                   ; Update receive FIFO state
        setb    TXCLR                                    ; Flush the Transmit FIFOS in case
                                                         ; a null packet is still left.
        mov     TXCNTL, #00h                            ; OHCI fix for device Errata
        setb    TXCLR                                   ; OHCI fix for device Errata


        mov     A,     #SETUP_PHASE                      ; Update the state machine-Expect
                                                         ; a setup packet
        mov     gbSetupSeqRX, A
        mov     gbSetupSeqTX, A
        ljmp    ReturnProcessOutToken

            ;---------------------------------------------------------------
            ; -   Control Write Data Stage
            ;---------------------------------------------------------------

                ; If this is a control write command with a datastage then this
                ; routine will belcalled on all data stages of the control write.
                ; When all the data has been collected(Bytes received=wLength)
                ; the actual routine is called.  The size of data is limited to this
                ; buffer length.
                ; THE CALLING CODE MUST THEN CALL SetUpControlWriteStatusStage to allow
                ; the status stage to continue.  The user must NOT do this themselves.
                ; Later in the life of this code, other features will be added here.

CheckDataPhase:
         cjne    A,     #DATA_PHASE, ReturnProcessOutToken ; Are we processing a Control Write,
                                                          ; i.e. Set Descr...
                                       ; Added to handle control writes with data stages.
                                       ; When a control Write with a data stage is detected
                                       ; the data is placed in the buffer 'CntlWriteDataBuffer'
                                       ; When all the data
                                       ; has been collected(Bytes received=wLength) the actual routine is
                                       ; called.  The size of data is limited to this buffer length.
                                       ;---------------------------------------------------------
                                       ;------------------- NOTE --------------------------------
                                       ;---------------------------------------------------------
                                       ; For this routine to work all the data must be stored below
                                       ; 100h as I am using byte addressing.  Also, since 80-FF is used
                                       ; as SFRs and I don't want to for the user to use indirect
                                       ; addressing, the data must ne stored between 20h-7Fh.
                                       ; Also, these routines will only work for data sets of less than
                                       ; 256.  But the above limitations put this the max much ower than
                                       ; this. MaxBuffer = (7F-20h-Other varaibles in this region)


         push    R0
         mov     A,     #CntlWriteDataBuffer         ; Get location of buffer

         add     A,     CntlWriteDataPntr            ; Add the offset
         mov     R0,    A                            ; R0 now contains the location to start storing the
                                                     ; data.

                                                     ; Update the data stored in memory
         mov     A,     RXCNTL                       ; Get number of bytes to move
         add     A,     CntlWriteDataPntr            ; Add number received
         mov     CntlWriteDataPntr,  A               ; update memory variable

         mov     A,     RXCNTL
         JZ      RdDone                              ; If no data in the buffer, then exit.

ReadData:
         mov     @R0,   RXDAT                        ; Get the data and store it.
         inc     R0
         djnz    ACC,   ReadData
         pop     R0
RdDone:
         setb    RXFFRC                              ; Update receive FIFO state

                                                     ; Now check to see if this was the last
                                                     ; read by checking if (Bytes received=wLength)
         mov     A,    CntlWriteDataPntr
         cjne    A,    wLength+1, NeedMoreData       ; If this is not equal to the expected, then jmp around.

                                                     ; When all the data has been received, the
                                                     ; other routines in this program will
                                                     ; be called to process it.
ProcessControlWriteData:

        push     DPX                                 ; Processing the jump table will
                                                     ; corrupt DPX.  Save it here
        lcall    DoJumpTable                         ; At this point all data has been
                                                     ; stored and all we need to do now is to
                                                     ; process it.
        pop      DPX                                 ; Restore DPX
        ljmp      ReturnProcessOutToken
NeedMoreData:

CheckCommand2:

ReturnProcessOutToken:
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : SetupReceived
;Brief Description : Service all Setup Tokens recd. on EP0
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetupReceived:
         mov     A,     RXCNTL                   ; Get the no. of bytes
         clr     CY

         subb    A,     #8                       ; 8 is length of all setup packets.
         JNZ     ReturnSetup                      ; If less than 8 bytes recd.
                                                 ; Return

                                                 ; Since buffer will reside within the
                                                 ; the first 255 bytes, I can use
                                                 ; register indirect addressing
        ; Move FIFO to command buffer.
        ; Notice byte swapping of word fields
        ; For Word Fields make USB Little Endian words->'251 Big Endian words
        clr      EDOVW
        mov      COMMAND_BUFFER,   RXDAT         ; bmRequestType
        mov      COMMAND_BUFFER+1, RXDAT         ; bRequest
        mov      COMMAND_BUFFER+3, RXDAT         ; wValue LSB
        mov      COMMAND_BUFFER+2, RXDAT         ; wValue MSB
        mov      COMMAND_BUFFER+5, RXDAT         ; wIndex LSB
        mov      COMMAND_BUFFER+4, RXDAT         ; wIndex MSB
        mov      COMMAND_BUFFER+7, RXDAT         ; wLength LSB
        mov      COMMAND_BUFFER+6, RXDAT         ; wLength MSB

        setb    RXFFRC                                  ; Update receive FIFO state
        clr     RXSETUP

        push     DPX                              ; Processing the jump table will
                                                  ; corrupt DPX.  Save it here
        lCall    ProcessSetup
        pop      DPX                              ; Restore DPX
ReturnSetup:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : ProcessSetup
;Brief Description : Process a Setup token recd. on EP0. Thile some of the
;                  : code may look sifficult to understand the end result is not.
;                  : The following simply prepares a byte of data for use in a jump table.
;                  : The code compresses the 8 byte bmRequestValue into 4 1/2
;                  : bits by removing bits 2,3 & 4.  These bits are never used
;                  : and it allows the jump table to be signfigantly smaller.
;                  : By using this jump table, the code size reduces by several
;                  : hundred bytes over the entire code!
;                  : THIS FIRMWARE IS ASSUMES BITS 2,3 & 4 are zero!!!!
;                  : By compressing the byte down, we limit the size
;                  : of the jump table.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessSetup:

        ; The First step is setting up the Stage tracing variable by examing the
        ; bmRequest value.  This will tell us if this is a control Write
        ; or control read command.  For right now we will assume that this
        ; is a no data command and will therefore pre-initilize the data
        ; byte counters used to send data back, to zero.

        mov     gbFControlBufferBytesLeft,     #00h
        mov     gbFControlBufferBytesLeft + 1, #00h
        mov     A,            bmRequestType
        jb      ACC.7,        SetupGetCommand

SetupSetCommand:
        mov     gbSetupSeqRX, #DATA_PHASE        ; Advance State Machine to next state
        mov     gbSetupSeqTX, #STATUS_PHASE
                                                 ; Now check to see if this is a control write with a data stage.
        mov     A,            wLength
        orl     A,            wLength+1
        jz      DoJumpTable                      ; If this is a no data command then process it
        ret                                      ; If we are expecting data then don't
                                                 ; process the command yet.  Exit and wait
                                                 ; for the rest of the data to come in.



SetupGetCommand:
        mov     gbSetupSeqRX, #STATUS_PHASE      ; Advance State Machine to next state
        mov     gbSetupSeqTX, #DATA_PHASE

DoJumpTable:
        ; This table will jump to the correct subroutine
        ; to handle the type of command contained in bmRequestType
        ; The new jmp table will be compressed by shifting and rotating
        ; out bits, 2,3 & 4.
        ; Place bmRequestType in the following order and then do the jump table
        ; on it.
        ; xx65107x
        ; if bits 65 == 11, Reserved = Error
        ; Unless you have time, don't spend a lot of time tracing the algorythm
        ; It's fancy and it works.  If you don't understand it go ask someone for a quarter.


        mov     A,      bmRequestType            ; Get the value.

        anl     A,      #0E3h                    ; Clear out bits 2,3,4 since
                                                 ; we don't need these
                                                 ; Reg A now looks like 765xxx10
        RL      A                                ; Put bits 1,0,& 7 in new placement
        RL      A                                ; Leave LSB cleared so jump is the number of words.
                                                 ; xxxx1076
CheckBit6:                                       ; 6 is currently in bit 0 position,
        jnb     ACC.0,  CheckBit5                ; Convert it to bit 5 position
        setb    ACC.5                            ; xx6x107x
 CheckBit5:                                      ; Bit 5 is currently at 7 position
        jnb     ACC.7,  CheckValidType           ; Convert it to bit 4 position
        setb    ACC.4                            ; xx65107x

CheckValidType:                                  ;
        jnb     ACC.5,  GoodCommand              ; If this bit (6) is clear we know
                                                 ; it's a valid value
        jb      ACC.4,  ReservedCommand          ; Bit (6) was set, if bit 5 is set it's
                                                 ; a reserved command.
        ljmp     GoodCommand

ReservedCommand:

        orl     EPCON, #0C0h                     ; Stall EP0.
        ret


                                                     ; THis code will branch to the correct jump statement
                                                     ; in the bmRequestJumpTable below.
GoodCommand:
        anl     A, #3Eh
        mov     B, A
        rr      A
        anl     A, #1fH
        clr     CY
        ADD     A, B
        mov     DPTR,   #bmRequestJumpTable
		IF PLC
	        mov     DPXL,   #LOW HIGH16(GoodCommand)     ; Get Page of Jump Table.
		ENDIF
		IF KEIL
			mov     DPXL,   #BYTE2(GoodCommand)
		ENDIF
                                                     ; Low byte of the upper 16 bits of the 32 bit address of the
                                                     ; jump table.
                                                     ; Is this code in RAM or ROM
        jmp     @A+DPTR                              ; Used because I use RISM sometimes
                                                     ; which places code in RAM

;---------------------------------------
;-- bmRequest Jump Table ---------------
;-- The order of these are based on the
;-- compresion algorythm used above.
;-- Each of these instructions occupy two bytes of
;-- ROM.  Do not change AJMP to LJMP as the algorytm depends on the
;-- 2 byte length of AJMP.  LJMP is 3 bytes long
;-- ------------------------------------
bmRequestJumpTable:
        LJMP    StandardSetDeviceCommand
        LJMP    StandardGetDeviceCommand
        LJMP    StandardSetInterfaceCommand
        LJMP    StandardGetInterfaceCommand
        LJMP    StandardSetEndpointCommand
        LJMP    StandardGetEndpointCommand
        LJMP    StandardSetOtherCommand
        LJMP    StandardGetOtherCommand

        LJMP    ClassSetDeviceCommand
        LJMP    ClassGetDeviceCommand
        LJMP    ClassSetInterfaceCommand
        LJMP    ClassGetInterfaceCommand
        LJMP    ClassSetEndpointCommand
        LJMP    ClassGetEndpointCommand
        LJMP    ClassSetOtherCommand
        LJMP    ClassGetOtherCommand

        LJMP    VendorSetDeviceCommand
        LJMP    VendorGetDeviceCommand
        LJMP    VendorSetInterfaceCommand
        LJMP    VendorGetInterfaceCommand
        LJMP    VendorSetEndpointCommand
        LJMP    VendorGetEndpointCommand
        LJMP    VendorSetOtherCommand
        LJMP    VendorGetOtherCommand





;-----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;S
;S          STANDARD TYPE COMMANDS FIRST
;S
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;-----------------------------------------------------------------

;COMMENT *------------------------------------------------------------
;Function name     : GetStandardDeviceCommand:
;Brief Description : Process a Get Standard Device Command Setup Token
;                  : This can only be a Get (Device or Configuration) Descriptor,
;                  : or Get Device Status, Get Configuration.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardGetDeviceCommand:
        mov     A,     bRequest
        cjne    A,     #GET_DESCRIPTOR, Jump2_CheckGetConfiguration
        sjmp    GET_DESCRIPTOR_TYPE
Jump2_CheckGetConfiguration:
        ljmp    CheckGetConfiguration
GET_DESCRIPTOR_TYPE:
        mov     A,     bDescriptorType
        cjne    A,     #DEVICE_DESCR, CheckConfigDescriptor

        ; ******************************************************************
        ; ********************** GET DESCRIPTOR,  DEVICE *******************
        ; ******************************************************************
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_DEVICE_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_DEVICE_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_DEVICE_DESCRIPTOR)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(BEGIN_DEVICE_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_DEVICE_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_DEVICE_DESCRIPTOR)
		ENDIF
        mov     A,  #12h
        mov     B,  #00h
        ljmp     LoadBuffer

CheckConfigDescriptor:
        cjne    A,     #CONFIG_DESCR, CheckStringDescriptor

        ; ******************************************************************
        ; ********************** GET DESCRIPTOR,  CONFIGURATION ************
        ; ******************************************************************

IF FUB_BOARD == DISABLED
   ; if not a FUB board just assume SELF powered
   ljmp    GiveSelfPoweredDescr
ELSE
   ;FUB BOARD - check Mode 0 Jumper to determine if bus or self powered
   ; Self Powered vs Bus Powered : Bit 1.0 = 1 = self Powered, 0 = bus powered
   jnb     PWR_SEL_SWITCH, GiveBusPoweredDescr
ENDIF

GiveSelfPoweredDescr:
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_CONFIG1_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_CONFIG1_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_CONFIG1_DESCRIPTOR)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(BEGIN_CONFIG1_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_CONFIG1_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_CONFIG1_DESCRIPTOR)
		ENDIF
        sjmp    DoConfigLoad

GiveBusPoweredDescr:
        IF PLC
			mov     gbFControlBufferLocation,   #LOW HIGH16(BEGIN_CONFIG2_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(BEGIN_CONFIG2_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(BEGIN_CONFIG2_DESCRIPTOR)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(BEGIN_CONFIG2_DESCRIPTOR)
    	    mov     gbFControlBufferLocation+1, #BYTE1(BEGIN_CONFIG2_DESCRIPTOR)
        	mov     gbFControlBufferLocation+2, #BYTE0(BEGIN_CONFIG2_DESCRIPTOR)
		ENDIF

DoConfigLoad:
        ; Note since config descriptors are same length - this routine works for
        ; both config1 and config2
        mov     A,  #LOW  (END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR)
        mov     B,  #HIGH (END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR)
        ljmp     LoadBuffer

CheckStringDescriptor:
        cmp     R11,      #STRING_DESCR    ; R11 == Accum A
        je      Check4Index0
        ljmp    CheckForOtherDescr      ; not string descriptor check for other
        ; ******************************************************************
        ; ********************** GET DESCRIPTOR,  STRING *******************
        ; ******************************************************************
Check4Index0:
        ; if string index = 0 ... regardless of language ID, return the language ID's
        ; supported by this device
        mov     A,    bDescriptorIndex
CheckString0:
        cjne    A,   #0, CheckStringLangId
        ; *********** Return list of Languages Supported ***********
		IF PLC
	        mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_0)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_0)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_0)
		ENDIF
		IF KEIL	
            mov     gbFControlBufferLocation,   #BYTE2(STRING_0)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_0)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_0)
		ENDIF

        mov     A,     #LOW (STRING_1-STRING_0)
        mov     B,     #HIGH(STRING_1-STRING_0)
        ljmp     LoadBuffer

CheckStringLangId:
; First check to make sure wIndex = language ID = 0 or 0x0409 -> English.  If not stall.
        mov     B, wIndex       ; move high byte - Sub language ID to B
        mov     A, wIndex+1     ; move low byte  - Primary language ID to A
        cmp     R11,    #09h    ; R11 == A ... low byte
        jne     Go_Bad_Lang_ID
        cmp     R10,    #04h    ; R10 == B ... high byte
        je      Get_Str
Go_Bad_Lang_ID:
        ljmp    ReturnBADSTDGetDeviceCommand

; NEW CODE-Return English ID Codes
Get_Str:
        mov     A,    bDescriptorIndex
CheckString1:
        cjne    A,   #1, CheckString2
        ; *********** Return MANUFACTURER String *************
		IF PLC
	        mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_1)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_1)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_1)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_1)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_1)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_1)
		ENDIF

        mov     A,     #LOW (STRING_2-STRING_1)
        mov     B,     #HIGH(STRING_2-STRING_1)
        ljmp    LoadBuffer


CheckString2:
        cjne    A,   #2, CheckString3
        ; *********** Return PRODUCT String *************
    	IF PLC
	        mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_2)
	        mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_2)
    	    mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_2)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_2)
	        mov     gbFControlBufferLocation+1, #BYTE1(STRING_2)
    	    mov     gbFControlBufferLocation+2, #BYTE0(STRING_2)
		ENDIF

        mov     A,     #LOW (STRING_3-STRING_2)
        mov     B,     #HIGH(STRING_3-STRING_2)
        ljmp    LoadBuffer
CheckString3:
        cjne    A,   #3, CheckString4
        ; *********** Return SERIAL Number String *************
		IF PLC
	        mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_3)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_3)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_3)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_3)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_3)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_3)
		ENDIF

        mov     A,     #LOW (STRING_4-STRING_3)
        mov     B,     #HIGH(STRING_4-STRING_3)
        ljmp    LoadBuffer
CheckString4:
        cjne    A,   #4, CheckString5
        ; *********** Return CONFIGURATION String ***********
		IF PLC
	        mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_4)
    	    mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_4)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_4)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_4)
    	    mov     gbFControlBufferLocation+1, #BYTE1(STRING_4)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_4)
		ENDIF

        mov     A,     #LOW (STRING_5-STRING_4)
        mov     B,     #HIGH(STRING_5-STRING_4)
        ljmp    LoadBuffer
CheckString5:
        cjne    A,   #5, ReturnBADSTDGetDeviceCommand
        ; *********** Return INTERFACE String ***********
		IF PLC
    	    mov     gbFControlBufferLocation,   #LOW HIGH16(STRING_5)
	        mov     gbFControlBufferLocation+1, #HIGH LOW16(STRING_5)
        	mov     gbFControlBufferLocation+2, #LOW  LOW16(STRING_5)
		ENDIF
		IF KEIL
            mov     gbFControlBufferLocation,   #BYTE2(STRING_5)
	        mov     gbFControlBufferLocation+1, #BYTE1(STRING_5)
        	mov     gbFControlBufferLocation+2, #BYTE0(STRING_5)
		ENDIF

        mov     A,     #LOW (STRING_6-STRING_5)
        mov     B,     #HIGH(STRING_6-STRING_5)
        ljmp    LoadBuffer


 CheckForOtherDescr:

        sjmp    ReturnBADSTDGetDeviceCommand
LoadBuffer:                                 ; Compare to see which is shorter.
                                            ; The amount asked for or the amount
                                            ; availible.

        push    ACC
        push    B
        clr     CY                          ; A=Actual-wLength=AskedFor
        subb    A,  wLength+1
        mov     A,  B
        subb    A,  wLength
        jc      AskedFor_IsLarger

LengthsMatch:
wLengthIsSmaller:                           ; If Asked for is smaller, replace
                                            ; actual with asked for.
        pop     B
        pop     ACC
        mov     B,  wLength
        mov     A,  wLength+1
       sjmp     LoadIt

AskedFor_IsLarger:
        pop     B
        pop     ACC
LoadIt:                                     ; From now on, wLength = bytes remaining.
        mov     gbFControlBufferBytesLeft,   B
        mov     gbFControlBufferBytesLeft+1, A
        lcall   LoadControlTXFifo
        ljmp    ReturnSTDGetDeviceCommand


CheckGetConfiguration:
        cjne    A,     #GET_CONFIGURATION, CheckGetStatus
                   ;------------------------------------------------
                   ;- GET CONFIGURATION
                   ;------------------------------------------------
        mov     R11, CurrentConfiguration
        mov     TXDAT, A
        mov     TXCNTL,#01h
        ljmp    ReturnSTDGetDeviceCommand
CheckGetStatus:
        cjne    A,     #GET_STATUS, ReturnSTDGetDeviceCommand
                   ;------------------------------------------------
                   ;- GET DEVICE STATUS
                   ;------------------------------------------------
        mov     A,      #00h

        jnb     HRWUPE, CheckBusSelfPwr

        setb    ACC.1   ; set RWU enabled bit

CheckBusSelfPwr:
IF FUB_BOARD == DISABLED
        setb    ACC.0                                   ; set self powered bit
ELSE
        ; check P1.0 Mode 0 jumper for Bus or Self Powered board
        jnb     PWR_SEL_SWITCH,   DoneGetDeviceStatus             ; don't set self powered bit
        setb    ACC.0                                   ; set self powered bit
ENDIF

DoneGetDeviceStatus:
        mov     TXDAT, A
        mov     TXDAT, #00h
        mov     TXCNTL,#02h
        ljmp    ReturnSTDGetDeviceCommand
ReturnBADSTDGetDeviceCommand:

        orl     EPCON, #0C0h                   ; Stall EP0

ReturnSTDGetDeviceCommand:
        ret


;COMMENT *------------------------------------------------------------
;Function name     : StandardGetEndpointCommand:
;Brief Description : Process a Standard Set Endpoint Command Setup Token
;                  : This can only be a Set,Clear Feature - Endpoint Stall
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardGetEndpointCommand:

        mov     A,     bRequest
        cjne    A,     #GET_STATUS,    ReturnBadSTDGetEPCommand
                   ;------------------------------------------------
                   ;- GET ENDPOINT STATUS
                   ;------------------------------------------------
        mov     A,      wIndex + 1
        anl     A,      #0Fh                     ; Mask off all but the endpoint value
        orl     EPINDEX,A                        ; Point the Index register at the

        mov     A,      wIndex + 1               ; Start by clearing out R0
        jb      ACC.7,  GetInStallStatus

GetOutStallStatus:
        mov     A,      EPCON
        jnb     ACC.6,  NotStalled
        mov     A,      #01                      ; Return Stalled
        ljmp    DoneWithCommand

GetInStallStatus:
        mov     A,      wIndex +1
        anl     A,      #0Fh
        cjne    A,      #00, GetEp1InStall

        mov     A,      EPCON
        jnb     ACC.7,  NotStalled
        mov     A,      #01
        sjmp    DoneWithCommand

GetEp1InStall:
        mov     A,      HSTAT                    ; GET EP1 Stall Information
        anl     A,      #020h                    ; Mask off all but stall bit.
        jz      NotStalled
        mov     A,      #01h
        sjmp    DoneWithCommand


NotStalled:
        mov     A,      #00h
DoneWithCommand:
        anl     EPINDEX,#80h                     ; Point the index back to EP0
        mov     TXDAT, A
        mov     TXDAT, #00h
        mov     TXCNTL, #02
        ret

ReturnBadSTDGetEPCommand:

        orl     EPCON, #0C0h                    ; Stall EP0
ReturnSTDGetEPCommand:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpSinglePacketControlReadStatusStage
;Brief Description : Sets the status in the IN buffer and initilizes all the
;                  : registers needed to do a single packet control read.
;                  : This needs to be done so the IN token is processed correctly.
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetUpSinglePacketControlReadStatusStage:

        mov     wLength,      #00
        mov     wLength+1,    #00
        mov     gbSetupSeqRX, #STATUS_PHASE      ; Advance State Machine to next state
        mov     gbSetupSeqTX, #DATA_PHASE
        setb    TXOE                             ; Enable data transmit
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : StandardSetEndpointCommand:
;Brief Description : Process a Standard Set Endpoint Command Setup Token
;                  : This can only be a Set,Clear Feature - Endpoint Stall
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardSetEndpointCommand:
        push    EPINDEX
        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        anl     A,      #0Fh                     ; Find out if this is an EP0 CLear Stall Command.
        orl     EPINDEX,A                        ; Setup the EPINDEX to point at correct index.

                               ; Check to make sure this is an Endpoint Stall.
                               ; If it is not then it's a wrong command plus you
                               ; save a few bytes doing it in this order.

        mov     A,      wValue+1
        cjne    A,      #ENDPOINT_STALL, ReturnBadSTDSetEPCommand

        mov     A,      bRequest
        cjne    A,      #CLEAR_FEATURE,  CheckSetEndpointFeature

ClearEndpointFeature:
                   ;------------------------------------------------
                   ;- CLEAR ENDPOINT STALL
                   ;------------------------------------------------
ClearEndpointStall:
        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        anl     A,      #0Fh                     ; Find out if this is an EP0 CLear Stall Command.
        JNZ     ClearNonEP0Stall

        anl     EPCON,  #03Fh                    ; For EP0 Clear both TX & RX stall bits
        ljmp     ReturnSTDSetEPCommand

ClearNonEP0Stall:                                ; Must be EP1 Clear Stall command.

        mov     A,      wIndex+1                 ; Get the endpoint of the stall to clear
        JB      ACC.7,  ClearInStall             ; For Non EP0, examing the direction bit as well.
ClearOutStall:
        anl     HSTAT, #5Ah                      ; Clear the stall on Hub EP1
        ljmp     ReturnSTDSetEPCommand
ClearInStall:
        anl     HSTAT, #5Ah                      ; Clear the stall on Hub EP1
        ljmp     ReturnSTDSetEPCommand


CheckSetEndpointFeature:
        cjne    A,      #SET_FEATURE, ReturnBadSTDSetEPCommand


SetEndpointFeature:
                   ;------------------------------------------------
                   ;- SET ENDPOINT STALL
                   ;------------------------------------------------
SetEndpointStall:

        mov     A,      wIndex+1                 ; Get the endpoint to stall
        JB      ACC.7,  SetInStall


SetOutStall:
        orl     HSTAT, #20h
        ljmp     ReturnSTDSetEPCommand
SetInStall:
        orl     HSTAT, #20h
        ljmp     ReturnSTDSetEPCommand

ReturnBadSTDSetEPCommand:
        push    EPINDEX
        mov     EPINDEX, #01
        mov     TXDAT,  #14h
        mov     TXCNTL, #01h
        pop     EPINDEX

        orl     EPCON, #0C0h                  ;Stall EP0
ReturnSTDSetEPCommand:
        pop     EPINDEX
        ljmp     SetUpControlWriteStatusStage


;COMMENT *------------------------------------------------------------
;Function name     : StandardSetDeviceCommand:
;Brief Description : Process a Standard Set Device Command Setup Token
;                  : The only valid commands are Set Address,
;                  : Set Configuration.  Other commands which have this
;                  : field but are un-defined are
;                  : ClearDeviceFeature, SetDescriptor, SetDeviceFeature.
;                  :
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
StandardSetDeviceCommand:

        mov     A,      bRequest
        cjne    A,      #SET_CONFIGURATION, CheckSetDeviceAddress
SetDeviceConfiguration:
                   ;------------------------------------------------
                   ;- SET DEVICE CONFIGURATION
                   ;------------------------------------------------

        mov      A,    wValue+1

CheckConfig0:
        cjne     A,    #0, CheckConfig1
        mov      CurrentConfiguration, R11   ; Set up the variables
        mov      EPINDEX,  #80h
        clr      HSTAT.4                     ; Disbale EP1
;(kls)        clr      HRWUPE
        ljmp      ReturnSTDSetDevice

CheckConfig1:
        cjne     A,    #1, ReturnBadSetDeviceCommand
        mov      CurrentConfiguration, R11   ; Set up the variables
        mov     EPINDEX, #80h              ; Select Hub EP1
        setb    HSTAT.4                    ; Enable EP1

        ljmp     ReturnSTDSetDevice

CheckConfig2:
        cjne     A,    #2, ReturnBadSetDeviceCommand


        sjmp     ReturnSTDSetDevice


        ;------- TBD -------
        ; Call SetConfiguration
        sjmp    ReturnSTDSetDevice

CheckSetDeviceAddress:
        cjne    A,      #SET_ADDRESS, CheckSetDeviceRWU
                   ;------------------------------------------------
                   ;- SET DEVICE ADDRESS
                   ;------------------------------------------------

        ; Set Address should just return.  The command will be executed following
        ; the status stage
        sjmp    ReturnSTDSetDevice

CheckSetDeviceRWU:
        cjne    A,      #SET_FEATURE, CheckClearDeviceRWU
        mov     A,      wValue+1
        cjne    A,      #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand
        setb    HRWUPE                                 ; Enable the hub to respnd to RWU.
        sjmp    ReturnSTDSetDevice

CheckClearDeviceRWU:
        cjne    A,      #CLEAR_FEATURE, ReturnBadSetDeviceCommand
        mov     A,      wValue+1
        cjne    A,      #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand
        clr     HRWUPE                                 ; Disable the hub to respnd to RWU.
        sjmp    ReturnSTDSetDevice


ReturnSTDSetDevice:
       ljmp     SetUpControlWriteStatusStage


StandardSetInterfaceCommand:
        mov     A,      bRequest
        cjne    A,      #SET_INTERFACE, ReturnBadSetDeviceCommand

        mov     A,      wValue+1
        orl     A,      wIndex+1
        jnz     ReturnBadSetDeviceCommand
        mov     CurrentConfig1Interface, R11
        sjmp    ReturnSTDSetDevice

StandardGetInterfaceCommand:
        mov     A,      bRequest
        cjne    A,      #GET_INTERFACE, ReturnBadSetDeviceCommand
        mov     A,      wValue+1
        jnz     ReturnBadSetDeviceCommand
        mov     R11,    CurrentConfig1Interface
        mov     TXDAT, A
        mov     TXCNTL, #01
        ret



StandardSetOtherCommand:
StandardGetOtherCommand:

            ;------------------------------------------
            ; - Unknown Standard Command -- STALL ENDPOINT
            ;------------------------------------------
ReturnBadSetDeviceCommand:

        orl    EPCON,       #0C0h                ; Stall Endpoint
        ret

;-----------------------------------------------------------------
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;S
;S          END OF STANDARD TYPE COMMANDS
;S
;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs
;-----------------------------------------------------------------

;-----------------------------------------------------------------
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;C
;C          START OF CLASS COMMANDS
;C
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;-----------------------------------------------------------------


ClassGetDeviceCommand:

       lcall    GetClassDeviceCommand
        ret

ClassGetOtherCommand:

       lcall    GetClassOtherCommand

        ret

ClassSetDeviceCommand:

       lcall    SetClassDeviceCommand
       lcall    SetUpControlWriteStatusStage      ; We know this will was a single packet only
        ret                                       ; command so go ahead and prepare/arm the status stage

ClassSetEndpointCommand:
ClassSetOtherCommand:

       lcall    SetClassOtherCommand
       lcall    SetUpControlWriteStatusStage      ; We know this will was a single packet only
                                                  ; command so go ahead and prepare/arm the status stage
        ret


ClassSetInterfaceCommand:
ClassGetInterfaceCommand:

ClassGetEndpointCommand:
            ;------------------------------------------
            ; - Unknown Class Command -- STALL ENDPOINT
            ;------------------------------------------


        orl    EPCON,       #0C0h         ;Stall Endpoint
        ret

;-----------------------------------------------------------------
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;C
;C          END OF CLASS COMMANDS
;C
;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
;-----------------------------------------------------------------

;-----------------------------------------------------------------
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;V
;V          START OF VENDOR COMMANDS
;V
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;-----------------------------------------------------------------

VendorSetDeviceCommand:

VendorGetDeviceCommand:
            lcall VendorGetDeviceCommandExec
            ret
VendorSetInterfaceCommand:
VendorGetInterfaceCommand:
VendorSetEndpointCommand:
VendorGetEndpointCommand:
VendorSetOtherCommand:
VendorGetOtherCommand:
            ;------------------------------------------
            ; - UnknownVendorCommand -- STALL ENDPOINT
            ;------------------------------------------

        orl    EPCON,       #0C0h         ;Stall Endpoint
        ret

;-----------------------------------------------------------------
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;V
;V          END OF VENDOR COMMANDS
;V
;VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
;-----------------------------------------------------------------

;-----------------------------------------------------------------
;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
;U
;U          UTILILITY ROUTINES
;U
;UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU
;-----------------------------------------------------------------

;COMMENT *------------------------------------------------------------
;Function name     : ProcessInToken
;Brief Description : Services all INs on EP0.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
ProcessInToken:
;(HUB)
        jb      EPINDEX.7, ProcessHubInToken        ; Is this a HUB or NON Hub Call?

        anl     FIFLG,    #EP0_TX_CLR                 ; clear the interrupt bit
       ljmp     CheckInStatusPhase

ProcessHubInToken:
        anl     HIFLG,   #EP0_TX_CLR                 ; clear the interrupt bit

CheckInStatusPhase:

        mov     A,      gbSetupSeqTX                ; read state variable
        cjne    A,      #STATUS_PHASE,SendDataBack  ; Should this be the end to
                                                    ; a setup sequence


StatusPhaseDone:
        lCall   CompleteSetCommand
        mov     gbSetupSeqTX, #SETUP_PHASE          ; Set state var. to expect setup.
        mov     gbSetupSeqRX, #SETUP_PHASE

       sjmp     ReturnProcessIn

SendDataBack:
        cjne    A,      #DATA_PHASE, ReturnProcessIn
       lcall    LoadControlTXFifo

ReturnProcessIn:
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : CompleteSetCommand
;Brief Description : Called after the status phase of a set command has
;                  : completed.  This is called everytime there is a
;                  : xmit status stage.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
CompleteSetCommand:
        mov     A,      bRequest                    ; If this was not a Std. Set
                                                    ; command then return.

        cjne    A,      #SET_ADDRESS, CheckNextCommand
   ;------------------------------------------------
   ;- SET ADDRESS
   ;------------------------------------------------
DoSetAddress:
        jnb     EPINDEX.7, SetFunctionAddress       ; Use EPINDEX to tell if this
SetHubAddress:                                      ; was a hub command or function command.

        mov     HADDR,     wValue+1                 ; Set to new address
        sjmp     ReturnCompleteSet

SetFunctionAddress:
        mov     FADDR,  wValue+1                    ; Set to new address
        sjmp     ReturnCompleteSet

CheckNextCommand:
ReturnCompleteSet:
        ret

;COMMENT *------------------------------------------------------------
;Function name     : SetUpControlWriteStatusStage
;Brief Description : Sets the status in the IN buffer.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
SetUpControlWriteStatusStage:
        mov     TXCNTL, #00                      ; Setup Null Packet
;        setb    TXOE0                            ; Enable data transmit
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : LoadControlTXFifo
;Brief Description : Copy data from the location pointed to by
;                  : the three byte value gbFControlBufferLocation.
;                  : The number of bytes left to transmit are stored in
;                  : gbFControlBufferBytesLeft.  If zero bytes are left then
;                  : a Null packet is loaded even if the null/short packet is
;                  : not needed.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
LoadControlTXFifo:
        push    R0                                  ; Need to save this register
        push    DPX
        mov     DPXL,   gbFControlBufferLocation    ; Get location of data to send.
        mov     DPH,    gbFControlBufferLocation+1
        mov     DPL,    gbFControlBufferLocation+2



        mov     A,      gbFControlBufferBytesLeft   ; First check to sei if any data is availble
        orl     A,      gbFControlBufferBytesLeft+1 ; to send.
        jnz     CntlDataAvail

        mov     R0,     #0                          ; if there is data do normal flow
        ljmp    ControlArmTx                        ; if none, do null packet

CntlDataAvail:
        mov     R0,     #0                          ; Number of bytes in FIFO- Awlays <=16
        mov     A,      DPXL
        JZ      DataInRAM

;-----------------------------------------------
; Data is in ROM, use instrcutions to pull from ROM.
;-----------------------------------------------
DataInROM:
        mov     A,      #00h
        movc    A,      @A+DPTR                     ; Get Data to transmit
        mov     TXDAT, A
        inc     DPTR
        inc     R0                                  ; Increment the number of bytes in FIFO
        djnz    gbFControlBufferBytesLeft+1, ROMCheckMaxPacket        ; If not zero, the continue.

ROMCheckUpper1:
        mov     A,       gbFControlBufferBytesLeft  ; If upper byte of wLength is also zero, buffer is empty.
        jz      ControlTxUpd                        ; Are we done with the buffer
        dec     A                                   ; If it's not zero dec. the upper byte as well.
        mov     gbFControlBufferBytesLeft, A        ; And store it.

ROMCheckMaxPacket:
        cjne    R0,      #EP0_MAX_PACKET_SIZE, DataInROM    ; Loop until FIFO is Full
        ljmp     ControlTxUpd                       ; Done with this FIFO.


;-----------------------------------------------
; Data is in RAM, use instrcutions to pull from RAM.
;-----------------------------------------------

DataInRAM:


        movx    A,      @DPTR                       ; Get Data to transmit
        mov     TXDAT, A
        inc     DPTR
        inc     R0                                  ; Increment the number of bytes in FIFO
        djnz    gbFControlBufferBytesLeft+1, RAMCheckMaxPacket        ; If not zero, the continue.

RAMCheckUpper1:
        mov     A,       gbFControlBufferBytesLeft  ; If upper byte of gbFControlBufferBytesLeft is also zero, buffer is empty.
        jz      ControlTxUpd                        ; Are we done with the buffer
        dec     A                                   ; If it's not zero dec. the upper byte as well.
        mov     gbFControlBufferBytesLeft, A        ; And store it.

RAMCheckMaxPacket:
        cjne    R0,      #EP0_MAX_PACKET_SIZE, DataInRAM    ; Loop until FIFO is Full


ControlTxUpd:
        mov     gbFControlBufferLocation+1, DPH      ; Update read pointers.
        mov     gbFControlBufferLocation+2, DPL

ControlArmTx:
        mov     TXCNTL, R0                          ; Write count into TXCNT register
        setb    TXOE                                ; Enable data transmit
ReturnLoadCntl:
        pop     DPX
        pop     R0
        Ret


;COMMENT *------------------------------------------------------------
;Function name     : GetOUTData
;Brief Description : takes data from the FIFO, Puts it in memory and
;                  : then updates writes it to the fifo.
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
;GetOUTData:
;        mov     WR26, #LOW16(OUT_BUFFERS)
;        mov     R7, RXCNTL                      ; Read count of bytes rec'd
;        mov     @WR26, R7                       ; Store the count in the OUT_BUFFERS space.
;        add     WR26, #01h                      ; Increment mem pointer

;        orl     R7, R7                          ; Set flags
;        je      Return

;WriteToOUTBuffer:
;        mov     R8, RXDAT
;        mov     @WR26, R8
;        inc     WR26, #01h
;        djnz    R7, WriteToOUTBuffer

;Return:
;        Ret



;COMMENT *------------------------------------------------------------
;Function name     : INIT_USB
;Brief Description : Initialize USB SFRs
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
INIT_USB:                          ; EP0 Comes up as it should except that
                                   ; all flow control is turned off except for
                                   ; OE bits.  This will turn them on so we can
                                   ; accept all data.
                                   ; All other endpoints should not be configured
                                   ; until a Set Configuration command is given.
        mov     EPINDEX, #80
        mov     EPCON,   #3Fh
ReturnInitUSB:
        Ret

;COMMENT *------------------------------------------------------------
;Function name     : INIT_VARIABLES
;Brief Description : Initializes global variables
;Regs preserved    : No reg. is saved
;--------------------------------------------------------------------*
;SCOPE
INIT_VARIABLES:
;Init SETUP VARIABLES

        mov     R0, #00h
        mov     Heart1, R0
        mov     Heart1+1, R0
        mov     gbSetupSeqRX, R0                       ; SetupSeq is set to

        mov     gbSetupSeqTX, R0                       ; STATUS_PHASE
        mov     gbFControlBufferLocation, R0
        mov     gbFControlBufferLocation+1, R0
        mov     gbFControlBufferLocation+2, R0

        mov     gbFControlBufferBytesLeft, R0
        mov     CurrentConfiguration, R0
        mov     CurrentConfig1Interface, R0
        mov     WR0, #0                    ; Zero Out Counter
        mov     WR2, WR0
        mov     SWITCH_PORT,     #0FFH
        mov     EMBD_FN_FLG,     R0      ; init to 00h
ReturnInit:
        Ret

;========================================================================
;====================== RightCylon ======================================
;========================================================================
;This routine does a cylon pattern to the right.  The time between steps is
; contained in WR2.  Only the flag register is modified during this routine.

RightCylon:
        push   WR2
        push   ACC
        mov    A,   #80h
CylonRightLoop:
        dec   WR2, #1
        cmp   R2,  #00h
        jne   CylonRightLoop
        srl   R11
        mov   LED_PORT, A
        pop   WR2
        push  WR2
        jnb   ACC.0, CylonRightLoop
        pop   ACC
        pop   WR2
        ret

;========================================================================
;====================== LeftCylon ======================================
;========================================================================
;This routine does a cylon pattern to the left.  The time between steps is
; contained in WR2.  Only the flag register is modified during this routine.

LeftCylon:

        push   WR2
        push   ACC

        mov    A,   #01h
CylonLeftLoop:
        dec   WR2, #1
        cmp   R2,  #0h
        jne   CylonLeftLoop
        sll   R11
        mov   LED_PORT, A
        pop   WR2
        push  WR2
        jnb   ACC.7, CylonLeftLoop
        pop   ACC
        pop   WR2
        ret

;========================================================================
;====================== Delay ======================================
;========================================================================
; This routine delays by the delay specified in DR0.
; If Fixed delay is called, the

FixedDelay:
        mov   WR2, #0
        mov   WR0, #20h

VaraibleDelay:
delay1:
        dec   DR0, #01
        jne   delay1
        ret

;************************************************************************
;************* DEVICE DESCRIPTOR ****************************************
;************************************************************************


; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the
; LSB in the numerically higher address.


;------------------------------------------------
;-------- HUB DESCRIPTOR ------------------------
;------------------------------------------------

;
; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the
; LSB in the numerically higher address.
;
IF PLC
	DEFINE  DESCRIPTORS_CODE_SEG, SPACE=CODE
	SEGMENT DESCRIPTORS_CODE_SEG
ENDIF
IF KEIL
    DESCRIPTORS_CODE_SEG SEGMENT CODE
	RSEG DESCRIPTORS_CODE_SEG
ENDIF

Header:     db "HUB FIRMWARE ",10,13,00

BEGIN_DEVICE_DESCRIPTOR:
        gDevice_bLength:            db  12h;   DEVICE_DESCRIPTOR_LENGTH
        gDevice_bDescriptorType:    db  DEVICE_DESCR
        gDevice_bcdUSB:             dw  0001h  ; Version 1.00 compliant
        gDevice_bDeviceClass:       db  09h    ;  9
        gDevice_bDeviceSubClass:    db  00h
        gDevice_bDeviceProtocol:    db  00h
        gDevice_wMaxPacketSize0:    db  08h    ;8 byte max for EP0
        gDevice_widVendor:          dw  2B04h  ;Intel Vendor ID (042B)
IF HELSINKI == ENABLED
        gDevice_widProduct:         dw  0593h  ;product ID 9305h 930 hub with 5 downstream ports
                                                ;downstream ports
ELSE
        gDevice_widProduct:         dw  0493h  ;product ID 9304h 930 hub with 4 downstream ports
                                                ;downstream ports
ENDIF
        ;**********************************************************************
        ; Change the device number to match the firmware version number:
        gDevice_bcdDevice:          dw  5001h  ;device version 1.50
        ;**********************************************************************


        gDevice_iManufacturer:      db  01h    ; Manufacturer String
        gDevice_iProduct:           db  02h    ; Product String
        gDevice_iSerialNumber:      db  00h    ; No Serial Number String - Rev 1.4 change
        gDevice_bNumConfigurations: db  1
END_DEVICE_DESCRIPTOR:

; SELF POWERED Descriptors
;/*--------------- Initialize Config 1 descriptor ----------------*/
BEGIN_CONFIG1_DESCRIPTOR:
        gConfig1_bLength:               db 09h
        gConfig1_bDescriptorType:       db CONFIG_DESCR
        gConfig1_bTotalLength:          db END_CONFIG1_DESCRIPTOR - BEGIN_CONFIG1_DESCRIPTOR
        gConfig1_bCorrection:           db 0
        gConfig1_bNumInterfaces:        db 1  ; NUM_OF_INTERFACES;
        gConfig1_bConfigurationValue:   db 1
        gConfig1_iConfiguration:        db 04h
        gConfig1_bmAttributes:          db 060h ; Self Powered, RWU Enabled
        gConfig1_MaxPower:              db 001        ;2 ma

;       /*------------- Initialize Interface 1 descriptor ---------------*/
BEGIN_INTERFACE1_DESCRIPTOR:
        gInterface1_bLength:            db END_INTERFACE1_DESCRIPTOR - BEGIN_INTERFACE1_DESCRIPTOR
        gInterface1_bDescriptorType:    db INTERFACE_DESCR
        gInterface1_bInterfaceNumber:   db 0
        gInterface1_bAlternateSetting:  db 0
        gInterface1_bNumEndpoints:      db 01h
        gInterface1_bInterfaceClass:    db 09h
        gInterface1_bInterfaceSubClass: db 00h
        gInterface1_bInterfaceProtocol: db 00h
        gInterface1_iInterface:         db 05H
END_INTERFACE1_DESCRIPTOR:

;      /*------------- Initialize Endpoint 1 descriptor 1---------------*/
BEGIN_ENDPOINT1_DESCRIPTOR:
        gEP1_bLength1:            db  END_ENDPOINT1_DESCRIPTOR - BEGIN_ENDPOINT1_DESCRIPTOR
        gEP1_bDescriptorType1:    db  ENDPOINT_DESCR
        gEP1_bEndpointAddress1:   db  81h     ;EP address 1, in
        gEP1_bmAtrributes1:       db  03h     ;Interrupt
        gEP1_wMaxPacketSize1:     dw  0100h   ;Max Packet 8 bytes
        gEP1_bInterval1:          db  20h     ; 32 milliseconds
END_ENDPOINT1_DESCRIPTOR:
END_CONFIG1_DESCRIPTOR:

; BUS  POWERED Descriptors
;/*--------------- Initialize Config 2 descriptor ----------------*/
BEGIN_CONFIG2_DESCRIPTOR:
        gConfig2_bLength:               db 09h
        gConfig2_bDescriptorType:       db CONFIG_DESCR
        gConfig2_bTotalLength:          db END_CONFIG2_DESCRIPTOR - BEGIN_CONFIG2_DESCRIPTOR
        gConfig2_bCorrection:           db 0
        gConfig2_bNumInterfaces:        db 1  ; NUM_OF_INTERFACES;
        gConfig2_bConfigurationValue:   db 1
        gConfig2_iConfiguration:        db 04h
        gConfig2_bmAttributes:          db 0A0h ; Bus  Powered, RWU Capable
        gConfig2_MaxPower:              db 045        ;90ma

;       /*------------- Initialize Interface 2 descriptor ---------------*/
BEGIN_INTERFACE2_DESCRIPTOR:
        gInterface2_bLength:            db END_INTERFACE2_DESCRIPTOR - BEGIN_INTERFACE2_DESCRIPTOR
        gInterface2_bDescriptorType:    db INTERFACE_DESCR
        gInterface2_bInterfaceNumber:   db 0
        gInterface2_bAlternateSetting:  db 0
        gInterface2_bNumEndpoints:      db 01h
        gInterface2_bInterfaceClass:    db 09h
        gInterface2_bInterfaceSubClass: db 00h
        gInterface2_bInterfaceProtocol: db 00h
        gInterface2_iInterface:         db 05H
END_INTERFACE2_DESCRIPTOR:

;      /*------------- Initialize Endpoint 1 descriptor 2---------------*/
BEGIN_ENDPOINT2_DESCRIPTOR:
        gEP1_bLength2:            db  END_ENDPOINT2_DESCRIPTOR - BEGIN_ENDPOINT2_DESCRIPTOR
        gEP1_bDescriptorType2:    db  ENDPOINT_DESCR
        gEP1_bEndpointAddress2:   db  81h     ;EP address 1, in
        gEP1_bmAtrributes2:       db  03h     ;Interrupt
        gEP1_wMaxPacketSize2:     dw  0100h   ;Max Packet 8 bytes
        gEP1_bInterval2:          db  20h     ; 32 milliseconds
END_ENDPOINT2_DESCRIPTOR:
END_CONFIG2_DESCRIPTOR:

IF PLC
	DEFINE  HUB_STRINGS_CODE_SEG, SPACE=CODE
	SEGMENT HUB_STRINGS_CODE_SEG
ENDIF
IF KEIL
    HUB_STRINGS_CODE_SEG SEGMENT CODE
	RSEG HUB_STRINGS_CODE_SEG
ENDIF
STRING_LOC_TABLE:

;*********** LANGUAGE ID's supported text ***************
STRING_0:      db  LOW(STRING_1-STRING_0)
               db  STRING_DESCR
               db  09h,04h              ; 2 Byte lang id for English: ie. 0409h
;*********** MANUFACTURER String Descriptor text ***************
STRING_1:      db  LOW(STRING_2-STRING_1)
               db  STRING_DESCR
               db  'I',00,'n',00,'t',00,'e',00,'l',00,' ',00,' ',00,'1',00,'9',00,'9',00,'7',00,' ',00
               db  'C',00,'E',00,'G',00,' ',00,'-',00,' ',00,'C',00,'L',00,'E',00,' ',00,'-',00,' ',00,'U',00,'S',00,'B',00,0Dh,00,0Ah,00
               db  'W',00,'r',00,'i',00,'t',00,'t',00,'e',00,'n',00,' ',00,'b',00,'y',00,' ',00
               db  'K',00,'e',00,'n',00,' ',00,'S',00,'c',00,'h',00,'u',00,'l',00,'t',00,'z',00,' ',00,'&',00,' ',00
               db  'C',00,'h',00,'i',00,'p',00,' ',00
               db  'L',00,'i',00,'n',00,'t',00,'h',00,'i',00,'c',00,'u',00,'m',00
;*********** PRODUCT String Descriptor text ***************
STRING_2:      db  LOW(STRING_3-STRING_2)
               db  STRING_DESCR
               db  '8',00,'X',00,'9',00,'3',00,'0',00,'H',00,'X',00,' ',00
               db  'S',00,'t',00,'a',00,'n',00,'d',00,' ',00,'A',00,'l',00,'o',00,'n',00,'e',00,' ',00
               db  'H',00,'u',00,'b',00
IF HELSINKI == ENABLED
               db  ',',00,' ',00,'5',00,' ',00,'D',00,'S',00,' ',00,'P',00,'o',00,'r',00,'t',00,'s',00
ELSE
               db  ',',00,' ',00,'4',00,' ',00,'D',00,'S',00,' ',00,'P',00,'o',00,'r',00,'t',00,'s',00
ENDIF
               db  ' ',00,'(',00,'1',00,' ',00,'I',00,'n',00,'t',00,'e',00,'r',00,'n',00,'a',00,'l',00,')',00
;*********** SERIAL # String Descriptor text ***************
STRING_3:      db  LOW(STRING_4-STRING_3)
               db  STRING_DESCR
               db  'F',00,'i',00,'r',00,'m',00,'w',00,'a',00,'r',00,'e',00,' ',00,':',00,' ',00
               ;******  CHANGE FIRMWARE REV HERE WITH EACH RELEASE *****
               db  'R',00,'e',00,'v',00,'.',00,' ',00,'1',00,'.',00,'5',00,'0',00
;*********** CONFIGURATION String Descriptor text **************
STRING_4:
               db  LOW(STRING_5-STRING_4)
               db  STRING_DESCR
IF FUB_BOARD == ENABLED         ; fub board setup message
               db  'F',00,'U',00,'B',00,' ',00,'B',00,'o',00,'a',00,'r',00,'d',00,' ',00,'S',00,'e',00,'t',00,'u',00,'p',00,',',00,' ',00
ELSE                            ; eval board setup message
               db  'E',00,'V',00,'A',00,'L',00,' ',00,'B',00,'o',00,'a',00,'r',00,'d',00,' ',00,'S',00,'e',00,'t',00,'u',00,'p',00,',',00,' ',00
ENDIF
               db  'E',00,'m',00,'b',00,'e',00,'d',00,'d',00,'e',00,'d',00,' ',00
               db  'F',00,'u',00,'n',00,'c',00,'t',00,'i',00,'o',00,'n',00,' ',00
IF FUB_BOARD == ENABLED
               db  'E',00,'n',00,'a',00,'b',00,'l',00,'e',00,'d',00,' ',00
               db  'b',00,'y',00,' ',00,'J',00,'P',00,'6',00
ELSE
  IF INTERNAL_PORT == ENABLED
               db  'E',00,'n',00,'a',00,'b',00,'l',00,'e',00,'d',00,' ',00
  ELSE
               db  'D',00,'i',00,'s',00,'a',00,'b',00,'l',00,'e',00,'d',00,' ',00
  ENDIF
ENDIF

;*********** INTERFACE String Descriptor text ***************
STRING_5:      db  LOW(STRING_6-STRING_5)
               db  STRING_DESCR
               db  '<',00,' ',00,'I',00,'n',00,'t',00,'e',00,'r',00,'f',00,'a',00,'c',00,'e',00,' ',00
               db  'S',00,'t',00,'r',00,'i',00,'n',00,'g',00,' ',00,'>',00
STRING_6:

;#############################################################
;####### RAM MEMORY MAP ######################################
;#############################################################

;----------------------------------------------------------------------------
;- Control varaibles need to be placed between 20h & 7fh for the addressing mode
;- If RISM is running, RISM needs 20h-3fH so be careful running RISM.
;----------------------------------------------------------------------------
IF PLC
	DEFINE HUB_DATA_SEG, SPACE=DATA
	SEGMENT HUB_DATA_SEG
ENDIF
IF KEIL
	HUB_DATA_SEG SEGMENT DATA
	RSEG HUB_DATA_SEG
ENDIF

;;
;; Buffer and associated variables for Control Endpoint management

gbSetupSeqTX:             ds 1
gbSetupSeqRX:             ds 1
SuspendResumeFlag:        ds 1         ; If 0, then we are not suspended, and no suspend event is pending
                                       ; If 1, then we are not suspended, but a suspend event is pending
                                       ; If 2, then we are suspended, and no resume event is pending
                                       ; If 3, then we are suspended, but a  resume event is pending


COMMAND_BUFFER:
StandardDeviceRequest:
bmRequestType:            ds  1
bRequest:                 ds  1
wValue:
FwValue:
wFeatureSelector:
bDescriptorType:          ds  1
bDescriptorIndex:         ds  1
wTargetSelector:
wIndex:                   ds  2
wLength:                  ds  2

; --------------------------------------------------------
; CntlWriteDataBuffer is Not Needed for a Hub as there
; are no control writes with a data stage for a hub
; --------------------------------------------------------
CntlWriteDataBuffer:      ;ds  0        ; Added to handle control writes with data stages.
                                       ; When a control Write with a data stage is detected
                                       ; the data is placed in this buffer.  When all the data
                                       ; has been collected(Bytes received=wLength) the actual routine is
                                       ; called.  The size of data is limited to this buffer length.

CntlWriteDataPntr:      ; ds  1        ; Used to point into the CntlWriteDataBuffer.

gbFControlBufferLocation:  ds  3
gbFControlBufferBytesLeft: ds  2

Heart1:                   ds  2

EP0_ERROR_CNT:            ds  1
FTLOCK_FLG:               ds  1

RWUTimer:                 ds  1
EmbeddedFunctionInReset:  ds  1

IF PLC
	DEFINE HUB_PDATA_SEG, SPACE=PDATA
	SEGMENT HUB_PDATA_SEG
ENDIF
IF KEIL
   	HUB_PDATA_SEG SEGMENT EDATA
    RSEG HUB_PDATA_SEG
ENDIF
CurrentConfiguration:     ds  1
CurrentConfig1Interface:  ds  1
EMBD_FN_FLG:              ds  1


END
