;COMMENT /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ;************************************************************************** ;** ** ;** 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 ** ;************************************************************************** ; ; File: emb_func.asm ; ; Universal Serial Bus 931HX Embedded Function Firmware ; ; Revision History ; --------------------------------------------- ; 3.06 11-12-97 Charles H Linthicum Jr. ; Made changes to fix holes in loopback processing where ; data could get "stuck" in internal RAM buffer and never ; get transferred to the transmit FIFO. ; The previous version relied on having a receive to ever ; move data from RAM buffer to the TXFIFO, but what happens ; when we NAK TX transactions but there is still data in the RAM ? ; need to add an additional push mechanism to clear the stall if ; it ever happens - the push will be added to sof_isr. ; 3.05 10-20-97 Charles H Linthicum Jr. ; Added CHUB assembler directive to turn off ; heartbeat LED until hub gets the "set config 1" ; and its enumerated. ; 3.04 10-02-97 Charles H Linthicum Jr. ; Nothing changed for embedded function but added ; OVRI_DETECT switch for hub to disabled or ; enable the detection of overcurrent on the 931 hub ; 3.03 08-19-97 Charles H Linthicum Jr. ; Added ability to trip remote wakeup using P3.1 SOF# pin if ; in configuration 1 and not keyboard setup ; 3.02 08-04-97 Charles H Linthicum Jr. ; Added keyboard test code to configuration KEYBOARD_CONFIG ; added additional string for new configuration ; Modified SOF_ISR to show different LED pattern on LED3,2,1,0 ; when we are in keyboard test mode ; moved heartbeat to LED0 - and changed SOF ISR for CHUB board ; heartbeat move to LED0 ; updated config descriptors for bus/self powered ; 3.01 07-24-97 Charles H Linthicum Jr. ; Nothing changed here, but I want the rev number to ; match the hub code - so I bumped it here as well - ; in the HUB_EP0 code, I fixed the CheckGetStatus routine ; to correctly return bus/self powered status ; 3.00 07-24-97 Charles H Linthicum Jr. ; changes for integration with AX/HX code ; changed string descriptor to just say "Function" ; and not differ between embedded and alone ; 2.01 07-23-97 Cleaned up a bunch of variables that aren't used ; hard located data variables to ensure how they'll ; be used by the code - whether direct/indirect addressing ; Moved all loopback variables to indirect addressed internal RAM ; Changed buffer size - must use 40 byte buffer in WINUTB setting ! ; Updated Suspend/Resume code in SV_CODE.ASM ; fixed get string index 0 to return 0409 ; 2.0 07-14-97 Kenneth Schultz / Chip Linthicum ; updated for HONGKONG, updated loopback changes ; removed EP3 loopback - HK only has 3 EPP in the ; embedded function ; added BULK loopback on endpoint 2 ; added INTERRUPT loopback on endpoint 1 ; removed Ken's keyboard stuff ; added Serial IO for DEBUG purposes ; removed serial number string ; endpoint 1 is dual packet mode, 2 is single packet ; 1.7 03-10-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 ; Removed carriage returns from strings ; Moved all configuration switches to SWITCH.INC include file ; Moved PDATA variables and buffers to internal RAM - DATA segment ; Revised embedded function RWU set/clear/get status fns - ; adding sw flag to keep track of emb fn RWU. ; Changed code to work with Intel Compatibility turned on. ; Added several equates for port switches, port LED's, etc. to ; SWITCH.INC & one_oh.inc ; 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 with EVAL ; board to enable/disable the embedded function. ; 1.6 02-14-97 Charles H Linthicum Jr. ; Changed code in ResetFifos for Reset Data Toggle ; 1.5 02-13-97 Charles H Linthicum Jr. ; Added OHCI fix around setting TXCLR ; 1.4 12-03-96 Charles H Linthicum Jr. ; Added capability to enable SW fix for RXFFRC errata SW ; workaround, and ability to switch between LC and HC for ; Configuration 1 by changing CLOCK_LOW assembler directive ; 1.3 08-30-96 Kenneth Schultz ; Added Set & Clear RWU hooks to code ; Converted SJMP table to LJMP table to increase versitiliy on ; where the code was placed. ; Added EP0 sequenceing to protect the firmware from OHCI stacks. ; Added loopback to endpoints 1,2 & 3 ; Changed EP Interrupt processing to avoid starving the host. ; Added Get Configuration command ; Added EP0 Stall handling as defined in RR ; Added Set & Get Interface routines. Checked with Chap 9 Test. ; 0.5 08-20-96 Kenneth Schultz ; Cleaned up stuff, Added Suspend/Resume, ; Fixed COntrol Write with Data Stages ; 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 future products. ; 0.2 06-29-96 Kenneth Schultz ; 0.1 05-27-96 Abdul Rahman Ismail ; ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ ;INCLUDE "8x931ax.inc" INCLUDE "8X931HX.inc" INCLUDE "SWITCH.INC" FIFO_SIZE equ 008h GET_COMMAND equ 080h EP1_LOOP_BACK_FIFO_SIZE equ 08h ; 08 BYTE INTERRUPT LOOPBACK - double buffered EP2_LOOP_BACK_FIFO_SIZE equ 08h ; 08 BYTE BULK LOOPBACK - single buffered SETUP_PHASE equ 000h DATA_PHASE equ 001h STATUS_PHASE equ 002h EP0_MAX_PACKET_SIZE equ 08h NULL_DATA_PACKET equ 000h ; PUBLIC symbols which we want to be seen by other .ASM files ; Remember that if a symbol is not public is won't be seen by PLC debugger public FUNCTION_ISR, INT0_ISR public InitializeEmbeddedFunction, EmbeddedFunctionSofRoutine public FUNCTION_SUSPEND_RESUME_ROUTINE public fCurrentConfiguration public FN_RWU_FLG, EMB_FN_RWU_FLG public FbRequest,FwIndex,FwValue public Ep1WritePointer, Ep1ReadPointer, Ep1BytesInBuffer, Ep1LoopBackBuffer public Ep2WritePointer, Ep2ReadPointer, Ep2BytesInBuffer, Ep2LoopBackBuffer public Ep1RAM_TO_TX_PUSH, Ep2RAM_TO_TX_PUSH ; EXTERN symbols/routines which are declared externally in other .ASM files extern SV_SUSPEND_RESUME_ROUTINE:CODE extern SV_RESUME_ROUTINE:CODE extern SV_SOF_ROUTINE:CODE extern SV_ResetRoutine:CODE, EP1_KYBD_ISR:CODE extern VendorGetDeviceCommandExec:CODE, VendorSetDeviceCommandExec:CODE extern FLASH_LEDS:CODE extern init_serial, putc_ser, putret_ser, puts_ser, putc_hex_ser extern EMB_FN_FLG:XDATA extern DEVICE_TYPE:DATA extern Heart_Beat:DATA DEFINE EMBEDDED_CODE_SEGMENT, SPACE=CODE SEGMENT EMBEDDED_CODE_SEGMENT ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM ;M---------------------------------------------------------------------M ;M MAIN M ;M---------------------------------------------------------------------M ;MMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM InitializeEmbeddedFunction: lcall INIT_FN_VARIABLES ; Initialize the RAM space as required lcall INIT_FUNCTION_EP0 ret ;---------------------------------------------------------------- ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;SS FUNCTION SUSPEND RESUME ROUTINE ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;---------------------------------------------------------------- FUNCTION_SUSPEND_RESUME_ROUTINE: ; chl debug lcall SV_SUSPEND_RESUME_ROUTINE ret ;---------------------------------------------------------------- ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;SS INT0_ISR ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;---------------------------------------------------------------- ; COMMENT *------------------------------------------------------------ ; Function name : INTO_ISR ; Brief Description : ; Regs preserved : ;--------------------------------------------------------------------* INT0_ISR: mov A, DEVICE_TYPE ; Based on the device type do different setup jz SKIP_HX_SETUP ; ENABLE REMOTE WAKEUP orl HSTAT, #01000000b SKIP_HX_SETUP: anl IEN0, #0FEh ; disable the interrupt now that we tripped. anl TCON, #11111101b ; clear pending interrupt bit IE0 reti ;---------------------------------------------------------------- ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;SS SOF ISR ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS ;---------------------------------------------------------------- ; COMMENT *------------------------------------------------------------ ; Function name : SOF_ISR ; Brief Description : Service the SOF_ISR Interrupt ; For normal operation, once the embedded function is enabled, you ; shall see LED cycling on LED321 with SOF's, but in Keyboard test mode ; you'll see the toggleing of LED321 ; Regs preserved : Reg. A is saved ;--------------------------------------------------------------------* SCOPE SOF_ISR: EmbeddedFunctionSofRoutine: push ACC mov A, SOFH jnb ACC.ASOF_BIT, ExitEFSofIsr ; If this ASOF bit not set, the ISR could be a HUB interrupt. ; if Any Start of Frame interrupt bit is set, then anl SOFH, #ASOF_CLR_MASK ; clear it mov A, fCurrentConfiguration cjne A, #KEYBOARD_CONFIG, Normal_SOF_Handling Keyboard_SOF_Handling: mov A, SOFH jb ACC.2, Set_LEDS Clear_LEDS: orl LED_PORT, #0Eh sjmp ExitEFSofIsr Set_LEDS: anl LED_PORT, #0F1h sjmp ExitEFSofIsr Normal_SOF_Handling: mov A, LED_PORT anl A, #0F1h anl LED_PORT, A mov A, SOFH rl A anl A, #0Eh orl LED_PORT, A ; ********** added with version 3.06 ********** ; check to see if any data is stalled in the RAM buffer and try to move it to the ; transmit FIFO - this should clear any potential stalls ! lcall Ep1RAM_TO_TX_PUSH lcall Ep2RAM_TO_TX_PUSH ExitEFSofIsr: pop ACC ret ; return from subroutine call ;---------------------------------------------------------------- ;FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ;FF FUNCTION ISR ;FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF ;---------------------------------------------------------------- COMMENT *------------------------------------------------------------ Function name : FUNCTION_ISR Brief Description : Service the FUNCTION_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 : --------------------------------------------------------------------* SCOPE FUNCTION_ISR: push PSW push ACC push EPINDEX ProcessFunctionEndpoints: ;---------------------------------------------------------------- ;-- NOTE: Priority of the check sequence determines priority. -- ;---------------------------------------------------------------- F_EP0: mov A, FIFLG ; First check to see if this is EP0 Command anl A, #03h ; As they require extra overhead. Mask off all but EP0 Interrupts jz NonEp0ISR ;---------------------------------------------------------------- ;-- 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 jmp 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: F_EP0_TXA: jnb FTXD0, F_EP0_RXA mov EPINDEX,#00 lCall ProcessInToken ; 82930 has sent a packet to HC ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again F_EP0_RXA: jnb FRXD0, NonEp0ISR mov EPINDEX,#00 lCall ProcessOutToken ; 82930 has received a packet from HC ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again ;-------------------------------------------------------------------------------- DoRxFirst: ;---------------------------------------------------------------- ;-- Process the RX FIFO first ;---------------------------------------------------------------- F_EP0_RXB: jnb FRXD0, F_EP0_TXB mov EPINDEX,#00 lCall ProcessOutToken ; 82930 has received a packet from HC ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again F_EP0_TXB: jnb FTXD0, NonEp0ISR mov EPINDEX,#00 lCall ProcessInToken ; 82930 has sent a packet to HC ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again ;-------------------------------------------------------------------------------- ;-------------------------------------------------------------------------------- ;---------------------------------------------------------------- ;-- Process the Other EPs next ;---------------------------------------------------------------- NonEp0ISR: mov A, fCurrentConfiguration cjne A, #KEYBOARD_CONFIG, Non_Keyboard_FN_Handling Keyboard_FN_Handling: jnb FTXD1, EXIT_FUNCTION_ISR mov EPINDEX,#01 lcall EP1_KYBD_ISR ljmp ProcessFunctionEndpoints ljmp EXIT_FUNCTION_ISR Non_Keyboard_FN_Handling: F_EP1_TX: mov EPINDEX, #01 jnb FIFLG.2, F_EP1_RX lcall Ep1TxLoopBack F_EP1_RX: jnb FIFLG.3, F_EP2_TX lcall Ep1RxLoopBack ; Received a packet from Host lcall Ep1TxLoopBack ; Send out this packet to the TXFIFO mov A, FIFLG ; Check to see if any other Interrupts are pending. jz F_EP2_TX ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again F_EP2_TX: mov EPINDEX, #02 jnb FIFLG.4, F_EP2_RX lcall Ep2TxLoopBack F_EP2_RX: jnb FIFLG.5, EXIT_FUNCTION_ISR ; If no ENDP 2 interrupt pending, exit ! lcall Ep2RxLoopBack ; Received a packet from Host lcall Ep2TxLoopBack ; Send out this packet to the TXFIFO mov A, FIFLG ; Check to see if any other Interrupts are pending. jz EXIT_FUNCTION_ISR ljmp ProcessFunctionEndpoints ; Look at all Interrupt flags again EXIT_FUNCTION_ISR: pop EPINDEX pop ACC pop PSW reti ; return from Interrupt Service Routine 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: anl FIFLG, #EP0_RX_CLR ; Clear the interrupt bit. jmp ProcCommand 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 ; a null packet is still left. orl TXCON, #TXCLR_SET_MASK NoEP0Error: ; Check to see if the stall bit is set. mov A, EPCON anl A, #0C0h jz NoEp0Stall anl EPCON, #03Fh ; Clear the stalls orl TXSTAT, #88h ; Set data toggle on TX ep0. NoEp0Stall: lCall SetupReceived orl RXCON, #RXFFRC_SET_MASK anl RXSTAT, #RXSETUP_CLR_MASK jmp ReturnProcessOutToken CheckOutStatusPhase: mov A, gbSetupSeqRX cjne A, #STATUS_PHASE, CheckDataPhase ; Is this the status phase of a "GET" ; command? orl RXCON, #RXFFRC_SET_MASK ; Update receive FIFO state mov A, #SETUP_PHASE ; Update the state machine-Expect ; a setup packet mov gbSetupSeqRX, A mov gbSetupSeqTX, A jmp ReturnProcessOutToken ;--------------------------------------------------------------- ; - Control Write Data Stage ;--------------------------------------------------------------- ; If this is a control write command with a datastage then this ; routine will be called 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, BadOutToken ; 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 00h ; save register 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 00h ; restore register R0 RdDone: orl RXCON, #RXFFRC_SET_MASK ; 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 DPH ; Processing the jump table will push DPL ; 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 DPL ; Restore DPX pop DPH jmp ReturnProcessOutToken NeedMoreData: CheckCommand2: BadOutToken: orl EPCON, #0C0h ; Who knows what this was. Stall the EP. 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 anl RXSTAT, #EDOVW_CLR_MASK 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 push DPH ; Processing the jump table will push DPL ; corrupt DPX. Save it here lcall ProcessSetup pop DPL ; Restore DPX pop DPH 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 mov CntlWriteDataPntr, #0 ; Initilize the data pointer for future control write ; data stages. 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. jmp GoodCommand ReservedCommand: orl EPCON , #0C0h ; Stall EP0. ret ; THis code will branch to the correct jump statement ; in the bmRequestJumpTable below. GoodCommand: ; Code added to convert AJMP table to LJMP table. anl A, #3Eh ; Multiply SJMP offset by 3/2 to get LJMP offsett. mov B, A ; Save the original rr A ; Divide origianl by two anl A, #1fH ; clr CY ; ADD A, B ; 2/2 + 1/2 = 3/2 mov DPTR, #bmRequestJumpTable ; 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 ******************* mov gbFControlBufferLocation+0, #HIGH(BEGIN_EF_DEVICE_DESCRIPTOR) mov gbFControlBufferLocation+1, #LOW(BEGIN_EF_DEVICE_DESCRIPTOR) mov A, #LOW (END_EF_DEVICE_DESCRIPTOR - BEGIN_EF_DEVICE_DESCRIPTOR) mov B, #HIGH (END_EF_DEVICE_DESCRIPTOR - BEGIN_EF_DEVICE_DESCRIPTOR) jmp LoadBuffer CheckConfigDescriptor: cjne A, #CONFIG_DESCR, CheckStringDescriptor mov A, bDescriptorType+1 ; get low byte = Index cjne A, #KEYBOARD_CONFIG, Return_Normal_Config_Descr Return_Keyboard_Config_Descr: ; now check for self/bus power and return correct descriptor mov A, SWITCH_PORT jnb ACC.POWER_BIT, GiveBusPoweredKeybdDescr GiveSelfPoweredKeybdDescr: ; ************* GET DESCRIPTOR, CONFIGURATION - Keyboard - Self ************ mov gbFControlBufferLocation+0, #HIGH(BEGIN_CONFIG_DESCRIPTOR_K1) mov gbFControlBufferLocation+1, #LOW(BEGIN_CONFIG_DESCRIPTOR_K1) mov A, #LOW (END_CONFIG_DESCRIPTOR_K1 - BEGIN_CONFIG_DESCRIPTOR_K1) mov B, #HIGH (END_CONFIG_DESCRIPTOR_K1 - BEGIN_CONFIG_DESCRIPTOR_K1) ljmp LoadBuffer GiveBusPoweredKeybdDescr: ; ************* GET DESCRIPTOR, CONFIGURATION - Keyboard - Bus ************ mov gbFControlBufferLocation+0, #HIGH(BEGIN_CONFIG_DESCRIPTOR_K2) mov gbFControlBufferLocation+1, #LOW(BEGIN_CONFIG_DESCRIPTOR_K2) mov A, #LOW (END_CONFIG_DESCRIPTOR_K2 - BEGIN_CONFIG_DESCRIPTOR_K2) mov B, #HIGH (END_CONFIG_DESCRIPTOR_K2 - BEGIN_CONFIG_DESCRIPTOR_K2) ljmp LoadBuffer Return_Normal_Config_Descr: ; now check for self/bus power and return correct descriptor mov A, SWITCH_PORT jnb ACC.POWER_BIT, GiveBusPoweredNormalDescr GiveSelfPoweredNormalDescr: ; ************ GET DESCRIPTOR, CONFIGURATION - Normal - Self ************ mov gbFControlBufferLocation+0, #HIGH(BEGIN_EF_CONFIG_DESCRIPTOR_1) mov gbFControlBufferLocation+1, #LOW(BEGIN_EF_CONFIG_DESCRIPTOR_1) mov A, #LOW (END_EF_CONFIG_DESCRIPTOR_1 - BEGIN_EF_CONFIG_DESCRIPTOR_1) mov B, #HIGH (END_EF_CONFIG_DESCRIPTOR_1 - BEGIN_EF_CONFIG_DESCRIPTOR_1) ljmp LoadBuffer GiveBusPoweredNormalDescr: ; ************ GET DESCRIPTOR, CONFIGURATION - Normal - Bus ************ mov gbFControlBufferLocation+0, #HIGH(BEGIN_EF_CONFIG_DESCRIPTOR_2) mov gbFControlBufferLocation+1, #LOW(BEGIN_EF_CONFIG_DESCRIPTOR_2) mov A, #LOW (END_EF_CONFIG_DESCRIPTOR_2 - BEGIN_EF_CONFIG_DESCRIPTOR_2) mov B, #HIGH (END_EF_CONFIG_DESCRIPTOR_2 - BEGIN_EF_CONFIG_DESCRIPTOR_2) ljmp LoadBuffer CheckStringDescriptor: cjne A, #STRING_DESCR, Not_String_Descr sjmp Check4Index0 Not_String_Descr: 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 *********** mov gbFControlBufferLocation+0, #HIGH(STRING_0) mov gbFControlBufferLocation+1, #LOW(STRING_0) 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 A, wIndex+1 ; move low byte - Primary language ID to A cjne A, #09h ,Go_Bad_Lang_ID ; R11 == A ... low byte mov A, wIndex ; move high byte - Sub language ID to B cjne A, #04h ,Go_Bad_Lang_ID ; R11 == A ... low byte sjmp Get_Str CheckForOtherDescr: 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 ************* mov gbFControlBufferLocation+0, #HIGH(STRING_1) mov gbFControlBufferLocation+1, #LOW(STRING_1) mov A, #LOW (STRING_2-STRING_1) mov B, #HIGH(STRING_2-STRING_1) ljmp LoadBuffer CheckString2: cjne A, #2, CheckString3 ; *********** Return PRODUCT String ************* mov gbFControlBufferLocation+0, #HIGH(STRING_2) mov gbFControlBufferLocation+1, #LOW(STRING_2) 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 ************* mov gbFControlBufferLocation+0, #HIGH(STRING_3) mov gbFControlBufferLocation+1, #LOW(STRING_3) mov A, #LOW (STRING_4-STRING_3) mov B, #HIGH(STRING_4-STRING_3) ljmp LoadBuffer CheckString4: cjne A, #4, CheckString5 ; *********** Return CONFIGURATION String *********** mov gbFControlBufferLocation+0, #HIGH(STRING_4) mov gbFControlBufferLocation+1, #LOW(STRING_4) mov A, #LOW (STRING_5-STRING_4) mov B, #HIGH(STRING_5-STRING_4) ljmp LoadBuffer CheckString5: cjne A, #5, CheckString6 ; *********** Return KEYBOARD CONFIGURATION String *********** mov gbFControlBufferLocation+0, #HIGH(STRING_5) mov gbFControlBufferLocation+1, #LOW(STRING_5) mov A, #LOW (STRING_6-STRING_5) mov B, #HIGH(STRING_6-STRING_5) ljmp LoadBuffer CheckString6: cjne A, #6, ReturnBADSTDGetDeviceCommand ; *********** Return INTERFACE String *********** mov gbFControlBufferLocation+0, #HIGH(STRING_6) mov gbFControlBufferLocation+1, #LOW(STRING_6) mov A, #LOW (STRING_7-STRING_6) mov B, #HIGH(STRING_7-STRING_6) ljmp LoadBuffer 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 jmp LoadIt AskedFor_IsLarger: pop B pop ACC LoadIt: ; From now on, wLength = bytes remaining. mov gbFControlBufferBytesLeft, B mov gbFControlBufferBytesLeft+1, A Call LoadControlTXFifo jmp ReturnSTDGetDeviceCommand CheckGetConfiguration: cjne A, #GET_CONFIGURATION, CheckGetStatus ;------------------------------------------------ ;- GET CONFIGURATION ;------------------------------------------------ mov A, fCurrentConfiguration mov TXDAT , A mov TXCNTL, #01 ;------- TBD ------- jmp ReturnSTDGetDeviceCommand CheckGetStatus: cjne A, #GET_STATUS, ReturnSTDGetDeviceCommand ;------------------------------------------------ ;- GET DEVICE STATUS ;------------------------------------------------ mov A, #00h ; check the software RWU flag to see if embedded FN remote wakeup is enabled mov A, EMB_FN_RWU_FLG ; this will set or clear ACC.1 for RWU mov R7, A ; temporarily save to R7 MOV A, SWITCH_PORT jnb ACC.POWER_BIT, ClearBusPoweredStatusBit SetSelfPoweredStatusBit: mov A, R7 setb ACC.0 sjmp DoneGetDeviceStatus ClearBusPoweredStatusBit: mov A, R7 ; do nothing - ACC.0 should be 0 DoneGetDeviceStatus: mov TXDAT , A mov TXDAT , #00h mov TXCNTL, #02 ;------- TBD ------- jmp 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 mov 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.7, NotStalled mov A, #01 ; Return Stalled jmp DoneWithCommand GetInStallStatus: mov A, EPCON jnb ACC.6, NotStalled mov A, #01 jmp 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 SetUpSingleCntlReadStatusStage: mov wLength, #00 mov wLength+1, #00 mov gbSetupSeqRX, #STATUS_PHASE ; Advance State Machine to next state mov gbSetupSeqTX, #DATA_PHASE 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 jmp ReturnSTDSetEPCommand ClearNonEP0Stall: 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 EPCON , #CLEAR_OUT_STALL_MASK jmp ReturnSTDSetEPCommand ClearInStall: anl EPCON , #CLEAR_IN_STALL_MASK jmp 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 EPCON , #SET_OUT_STALL_MASK jmp ReturnSTDSetEPCommand SetInStall: orl EPCON , #SET_IN_STALL_MASK jmp ReturnSTDSetEPCommand ReturnBadSTDSetEPCommand: orl EPCON , #0C0h ;Stall EP0 ReturnSTDSetEPCommand: pop EPINDEX jmp 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 ;------------------------------------------------ ; Check to see what configuration we should take on. mov A, wValue+1 CheckConfig0: cjne A, #0, CheckConfig1 mov fCurrentConfiguration, A ; Set up the variables clr TR0 clr ET0 anl IEN1, #7Fh ; Disable Keyboard interrupts anl TMOD, #0F0h Call ResetFifos ; Empty out all of the FIFOs and return to ; the un configuraed state. mov A, PCON jb ACC.LC_BIT, ReturnSTDSetDevice ; Are we in low power state? orl PCON, #LC_SET_MASK ; If not then goto low power state. jmp ReturnSTDSetDevice CheckConfig1: cjne A, #01, CheckConfig_K mov fCurrentConfiguration, A ; Set up the variables IF LOW_CLOCK_MODE == ENABLED orl PCON, #LC_SET_MASK ; go to Low clock - 3 Mhz mode ELSE anl PCON, #LC_CLR_MASK ; go to High clock - 6 Mhz mode ENDIF call ResetFifos ; Place all FIFOs in known state lcall SetUpConfiguration1 ljmp ReturnSTDSetDevice CheckConfig_K: ; SCAN DOUG KEYS CONFIGURATION cjne A, #KEYBOARD_CONFIG, ReturnBadSetDeviceCommand mov fCurrentConfiguration, A ; Set up the variables clr TR0 clr ET0 anl IEN1, #7Fh ; Disable Keyboard interrupts anl TMOD, #0F0h Call ResetFifos ; Empty out all of the FIFOs and return to ; the un configuraed state. push EPINDEX mov EPINDEX, #01h mov EPCON, #13h ; SP Mode, TX Only mov TXCON, #14h ; Clear Buffer, ATM Mode pop EPINDEX anl FIE, #03h ; Disable all USB interrupts except EP0 jmp ReturnSTDSetDevice CheckSetDeviceAddress: cjne A, #SET_ADDRESS, CheckSetDeviceRWU ;------------------------------------------------ ;- SET DEVICE ADDRESS ;------------------------------------------------ ; Set Address should just return. The command will be executed following ; the status stage ljmp ReturnSTDSetDevice CheckSetDeviceRWU: cjne A, #SET_FEATURE, CheckClearDeviceRWU mov A, wValue+1 cjne A, #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand ; set sw flag for RWU enabled push ACC mov A, #02h mov EMB_FN_RWU_FLG, A ; set the emd fn remote wakeup flag to 02 setting status.1 pop ACC jmp ReturnSTDSetDevice CheckClearDeviceRWU: cjne A, #CLEAR_FEATURE, ReturnBadSetDeviceCommand mov A, wValue+1 cjne A, #DEVICE_REMOTE_WAKEUP, ReturnBadSetDeviceCommand ; clear sw flag for RWU disabled push ACC mov A, #00h mov EMB_FN_RWU_FLG, A ; set the emd fn remote wakeup flag to 00 clearing status.1 pop ACC jmp ReturnSTDSetDevice ReturnSTDSetDevice: jmp SetUpControlWriteStatusStage ReturnBadSetDeviceCommand: orl EPCON , #0C0h ; Stall Endpoint ret StandardSetInterfaceCommand: mov A, bRequest cjne A, #SET_INTERFACE, ReturnBadSetDeviceCommand mov A, wValue+1 orl A, wIndex+1 jnz ReturnBadSetDeviceCommand mov CurrentConfig1Interface, A sjmp ReturnSTDSetDevice StandardGetInterfaceCommand: mov A, bRequest cjne A, #GET_INTERFACE, ReturnBadSetDeviceCommand mov A, wValue+1 jnz ReturnBadSetDeviceCommand mov A, CurrentConfig1Interface mov TXDAT , A mov TXCNTL, #01 ret StandardSetOtherCommand: StandardGetOtherCommand: ;------------------------------------------ ; - Unknown Standard Command -- STALL ENDPOINT ;------------------------------------------ orl EPCON , #0C0h ; Stall Endpoint ret COMMENT *------------------------------------------------------------ Function name : SetUpConfiguration1 Brief Description : Setup the endpoints to the parameters specified in the : configuration 1 descriptor. : : See below for the actual values. : : Regs preserved : No reg. is saved --------------------------------------------------------------------* SCOPE SetUpConfiguration1: push EPINDEX call ResetFifos ; Place all FIFOs in known state mov EPINDEX, #01 ; EP1 mov EPCON, #0Fh ; Non Control, DUAL packet mode orl FIE, #0Ch ; ENable the interupts mov EPINDEX, #02 ; EP2 mov EPCON, #1FH ; Non Control, Single Packet mode orl FIE, #30h ; ENable the interupts ;orl IPL1, #02h orl SOFH, #SOFIE_SET_MASK ; Enable SOF Interrupts orl SOFH, #SOFDIS_SET_MASK orl IEN1, #03h ; Enable Function ISR mov A, DEVICE_TYPE ; Based on the device type do different setup jnz SKIP_EF_INT0_SETUP ; If I'm an HX then skip setup for INT0 orl TCON, #00h ; setup ext int 0 for level triggered (active low) orl IPH0, #01h ; set external interrup 0 priority bit high orl IPL0, #01h ; set external interrup 0 priority bit high orl IEN0, #01h ; enable external interrupt 0 SKIP_EF_INT0_SETUP: IF SIO_DEBUG == ENABLED anl PCON, #LC_CLR_MASK ; go to high clock mode lcall init_serial mov DPTR, #EMBDFN_UP_MSG lcall puts_ser ENDIF pop EPINDEX ret COMMENT *------------------------------------------------------------ Function name : SetUpConfiguration2 Brief Description : Setup the endpoints to the parameters specified in the : configuration 2 descriptor. : : See below for the actual values. : : Regs preserved : No reg. is saved --------------------------------------------------------------------* SCOPE SetUpConfiguration2: push EPINDEX anl PCON, #LC_CLR_MASK call ResetFifos ; Place all FIFOs in known state ret COMMENT *------------------------------------------------------------ Function name : SetUpConfiguration0 Brief Description : Setup the endpoints to the parameters specified in the : configuration 1 descriptor. : : See below for the actual values. : : Regs preserved : No reg. is saved --------------------------------------------------------------------* SCOPE ResetFifos: ; This routine flushes and clears all of the fifos. ; THe routine also sets data toggle back to zero as ; defined in the USB spec. This routine would be called ; when ever you change configurations. ; Subsets of this routine sould be called when changing interfaces. push EPINDEX anl FIE, #03h anl FIFLG, #03h mov A, #03h ; Number of FIFOS ResetFifoLoop: mov EPINDEX, A push ACC orl TXCON, #80h ; Flush the TX FIFOs orl RXCON, #80h ; Flush the RX FIFOs mov A, TXSTAT ; Reset data toggle back to zero anl A, #07Fh orl A, #08h mov TXSTAT, A mov A, RXSTAT ; Reset data toggle back to zero anl A, #07Fh orl A, #08h mov RXSTAT, A mov EPCON , #040h ; Reset value pop ACC djnz ACC, ResetFifoLoop pop EPINDEX ret ;----------------------------------------------------------------- ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs ;S ;S END OF STANDARD TYPE COMMANDS ;S ;SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSs ;----------------------------------------------------------------- ;----------------------------------------------------------------- ;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ;C ;C START OF CLASS COMMANDS ;C ;CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC ;----------------------------------------------------------------- ClassGetDeviceCommand: ClassGetOtherCommand: ClassSetDeviceCommand: ClassSetEndpointCommand: ClassSetOtherCommand: ClassSetInterfaceCommand: ClassGetInterfaceCommand: ClassGetEndpointCommand: 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: lcall VendorSetDeviceCommandExec lcall SetUpControlWriteStatusStage ; We know this will was a single packet only ret 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: anl FIFLG, #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 jmp ReturnProcessIn SendDataBack: cjne A, #DATA_PHASE, ReturnProcessIn call 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: ; SetFunctionAddress: mov FADDR, wValue+1 ; Set to new address IF SIO_DEBUG == ENABLED mov DPTR, #SET_ADDR_MSG lcall puts_ser push ACC mov A, FADDR lcall putc_hex_ser lcall putret_ser pop ACC ENDIF jmp 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 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 00h ; R0 is at address 0 ; Need to save this register push DPH push DPL mov DPH, gbFControlBufferLocation+0 mov DPL, gbFControlBufferLocation+1 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 ;----------------------------------------------- ; 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 jmp ControlTxUpd ; Done with this FIFO. ControlTxUpd: mov gbFControlBufferLocation, DPH ; Update read pointers. mov gbFControlBufferLocation+1, DPL ControlArmTx: mov TXCNTL, R0 ; Write count into TXCNT register ; setb TXOE ; Enable data transmit ReturnLoadCntl: pop DPL pop DPH pop 00h ; R0 is at address 0 ret COMMENT *------------------------------------------------------------ Function name : INIT_FUNCTION_EP0 Brief Description : Initialize USB SFRs Regs preserved : No reg. is saved --------------------------------------------------------------------* SCOPE INIT_FUNCTION_EP0: ; 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. push ACC push EPINDEX mov EPINDEX, #00 mov EPCON, #3Fh pop EPINDEX orl FIE, #03h ; Enable Function EP0 TX & RX ENpoint Interrupts. orl SOFH, #SOFIE_SET_MASK ; Enable SOF Interrupts mov A, DEVICE_TYPE ; Based on the device type do different setup jnz SKIP_INIT_INT0_SETUP ; If I'm an HX then skip setting up INT0 orl TCON, #00h ; setup ext int 0 for level triggered (active low) orl IPH0, #01h ; set external interrup 0 priority bit high orl IPL0, #01h ; set external interrup 0 priority bit high orl IEN0, #01h ; enable external interrupt 0 SKIP_INIT_INT0_SETUP: mov A, DEVICE_TYPE jnz IEN1_FOR_HX ; do this for AX only; not with embedded function of a hub IEN1_FOR_AX: orl IEN1, #07h ; Enable Function, SOF & Suspend/Resume ISR sjmp ReturnInit_FN_Ep0 IEN1_FOR_HX: orl IEN1, #02h ; Enable Function ReturnInit_FN_Ep0: setb EA pop ACC ret COMMENT *------------------------------------------------------------ Function name : INIT_FN_VARIABLES Brief Description : Initializes global variables Regs preserved : No reg. is saved --------------------------------------------------------------------* SCOPE INIT_FN_VARIABLES: ;Init SETUP VARIABLES push 00h ; save register 0 push ACC mov R0, #00h mov A, #00h mov A, DEVICE_TYPE jnz CONTINUE_FOR_EMBDFN ; only do this if we are an AX device mov A, #00h mov Heart_Beat, R0 mov Heart_Beat+1, R0 CONTINUE_FOR_EMBDFN: mov A, #00h mov gbSetupSeqRX, R0 mov gbSetupSeqTX, R0 mov gbFControlBufferLocation, R0 mov gbFControlBufferLocation+1, R0 mov gbFControlBufferLocation+2, R0 mov gbFControlBufferBytesLeft, R0 mov EMB_FN_RWU_FLG, R0 ; Initialize EMB_FN_RWU_FLG to 00h ; EP1 Loop back variables mov R0, #Ep1BytesInBuffer ; Initialize Ep1 bytes in buffer to 0 mov @R0, A ; Initialize the read & write pointers mov A, #Ep1LoopBackBuffer ; get address of beginning of Ep1 buffer mov R0, #Ep1WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep1ReadPointer mov @R0, A ; set read pointer to start of buffer mov R0, #00h ; need to reinitialize Register 0 mov A, #00h ; need to reinitialize Accumulator A ; EP2 Loop back variables mov R0, #Ep2BytesInBuffer ; Initialize Ep1 bytes in buffer to 0 mov @R0, A ; Initialize the read & write pointers mov A, #Ep2LoopBackBuffer ; get address of beginning of Ep1 buffer mov R0, #Ep2WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep2ReadPointer mov @R0, A ; set read pointer to start of buffer pop ACC pop 00h Ret ;======================================================================== ;************************************************************************ ;************************************************************************ ;************************************************************************ ; LOOP BACK DRIVERS HERE ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;************************************************************************ ;------------------------------------------------------------------------ ;************************************************************************ ;************************************************************************ ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 1 RX LOOPBACK ISR. ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep1RxLoopBack Brief Description : Acts as an Infinite source of 16 byte data packets. Regs preserved : Register 0 saved --------------------------------------------------------------------* Ep1RxLoopBack: push ACC push 00h ; Register 0 EP1_CHECK_MORE_DATA: anl FIFLG, #EP1_RX_CLR ; Clear Interrupt Pending Flag Ep1RXCheck4Error: mov A, RXSTAT jnb ACC.RXERR_BIT, NoEp1RxError ; Check for error on receive ljmp HandleEp1RxError NoEp1RxError: mov A, RXFLG jb ACC.RXFIF0_BIT, CheckEp1BufferFull jb ACC.RXFIF1_BIT, CheckEp1BufferFull ; No errors, check Ep1 for new data ljmp NoEp1RxDataReceived ; Check to make sure there is room in the buffer. CheckEp1BufferFull: mov R0, #Ep1BytesInBuffer mov A, @R0 cjne A, #Ep1LoopBackBufferSize, Ep1_RX_Buffer_NOT_Full Ep1_RX_Buffer_Full: ; adding another set of data would overfill the buffer ... ljmp NoEp1RxDataReceived Ep1_RX_Buffer_NOT_Full: ; additional check for situation where there is no data in the BUFFER ; and room in TXFIFO jnz Ep1_Normal_Get_Data mov A, TXFLG anl A, #0C0h ; mask out all but FIF bits cjne A, #0C0h, Ep1_FAST_RX_TX_DATA ljmp Ep1_Normal_Get_Data Ep1_FAST_RX_TX_DATA: ; move the data directly from RXDAT to TXDAT mov TXDAT, RXDAT ; *** Byte 1 *** mov TXDAT, RXDAT ; *** Byte 2 *** mov TXDAT, RXDAT ; *** Byte 3 *** mov TXDAT, RXDAT ; *** Byte 4 *** mov TXDAT, RXDAT ; *** Byte 5 *** mov TXDAT, RXDAT ; *** Byte 6 *** mov TXDAT, RXDAT ; *** Byte 7 *** mov TXDAT, RXDAT ; *** Byte 8 *** ; Stage the transmit FIFO with new data mov TXCNTL, #EP1_LOOP_BACK_FIFO_SIZE ; Go and release the receive FIFO ljmp Ep1_RELEASE_RXFIFO Ep1_Normal_Get_Data: mov R0, #Ep1WritePointer ; setup address of write pointer mov A, @R0 ; get value of write pointer mov R0, A ; transfer actual address to R0 ; Get the data and load it into the buffer ! Ep1_RX_08_BYTES: mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 1 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 2 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 3 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 4 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 5 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 6 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 7 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 8 *** inc R0 ; adjust the write pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep1WritePointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep1BytesInBuffer mov A, @R0 add A, #EP1_LOOP_BACK_FIFO_SIZE mov @R0, A Ep1_RELEASE_RXFIFO: orl RXCON, #RXFFRC_SET_MASK ; release the Receive FIFO ljmp EP1_CHECK_MORE_DATA NoEp1RxDataReceived: pop 00h ; Register 0 pop ACC ret HandleEp1RxError: ; presently this code won't try to recover from an error condition, ; but lock up the code and signify an error by LED's visible on Port 1 lcall FLASH_LEDS mov A, RXFLG ; Get the type of RX Error. anl A, #03h ; Mask off all but the error flags jnz CHK_EP1_OVF ; If these are both Zeros then it was a CRC Error. mov P1, #11h sjmp $ CHK_EP1_OVF: jnb ACC.0, CHK_EP1_URF ; Is the OVF flag set (Over flow) mov P1, #12h sjmp $ CHK_EP1_URF: ; receive underrun flag must have been set mov P1, #13h sjmp $ ;************************************************************************ ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 1 TX LOOPBACK ISR. ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep1TxLoopBack Brief Description : Acts as an Infinite source of 8 byte data packets. Regs preserved : Register 0 saved --------------------------------------------------------------------* ; Ep1TxLoopBack: push ACC push 00h ; Register 0 anl FIFLG, #EP1_TX_CLR ; Clear Interrupt Pending Flag Ep1TXCheck4Error: mov A, TXSTAT jnb ACC.TXERR_BIT, CheckEp1TxNewData ; Check for error on receive ljmp HandleEp1TxError CheckEp1TxNewData: mov A, TXFLG jnb ACC.TXFIF0_BIT, CheckEp1TxDataAvailable jnb ACC.TXFIF1_BIT, CheckEp1TxDataAvailable ; both TX fifos have data so don't load any more ljmp NoEp1TxDataReceived CheckEp1TxDataAvailable: ; check to see how many bytes are presently in the buffer mov R0, #Ep1BytesInBuffer mov A, @R0 jnz Ep1_Tx_Buffer_Has_Data ljmp Ep1TxBufferEmpty ; there are available bytes in the buffer to transmit out Ep1_Tx_Buffer_Has_Data: ; Get the data to transmit to the FIFO! mov R0, #Ep1ReadPointer mov A, @R0 ; get the value of the read pointer mov R0, A ; now use this address for indirect addressing Ep1_TX_08_BYTES: mov A, @R0 ; get a byte from memory - BYTE 1 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 2 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 3 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 4 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 5 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 6 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 7 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 8 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 ; adjust the read pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep1ReadPointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep1BytesInBuffer ; get present byte count mov A, @R0 clr CY ; clear the carry bit for subtraction subb A, #EP1_LOOP_BACK_FIFO_SIZE; subtract 8 bytes from the byte count mov @R0, A ; move new value back to byte count in memory ; are there any bytes left in the buffer ? jnz Ep1TxHasMoreDataInBuffer ; if 0 bytes in Buffer, then reset the read & write pointers mov A, #Ep1LoopBackBuffer ; get address of beginning of Ep1 buffer mov R0, #Ep1WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep1ReadPointer mov @R0, A ; set read pointer to start of buffer Ep1TxHasMoreDataInBuffer: mov TXCNTL, #EP1_LOOP_BACK_FIFO_SIZE ; Release the FIFO Ep1BufferNotEmpty: ljmp CheckEp1TxNewData Ep1TxBufferEmpty: NoEp1TxDataReceived: pop 00h ; Register 0 pop ACC ret ;----------------------------------- ; EP1 Transmit Error Handling ;----------------------------------- HandleEp1TxError: ; presently this code won't try to recover from an error condition, ; but lock up the code and signify an error by LED's visible on Port 1 lcall FLASH_LEDS mov A, TXFLG ; Get the type of TX Error. anl A, #03h ; Mask off all but the error flags jnz CHK_EP1_TX_OVF ; If these are both Zeros then it was a CRC Error. ljmp CheckEp1TxNewData ; If it was a CRC, go chack to see if there weas any other data. CHK_EP1_TX_OVF: jnb ACC.0, CHK_EP1_TX_URF ; Is the OVF flag set (Over flow) mov P1, #14h sjmp $ CHK_EP1_TX_URF: mov P1, #15h sjmp $ ret ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 1 RAM TO TXFIFO PUSH ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep1RAM_TO_TX_PUSH Brief Description : Trys to push data from RAM to Transmit FIFO Regs preserved : Register 0 and ACC saved --------------------------------------------------------------------* Ep1RAM_TO_TX_PUSH: push ACC push 00h push EPINDEX CheckEp1TxRAMNewData: mov EPINDEX, #01h ; select the endpoint mov A, TXFLG jnb ACC.TXFIF0_BIT, CheckEp1TxRAMDataAvail jnb ACC.TXFIF1_BIT, CheckEp1TxRAMDataAvail ; both TX fifos have data so don't load any more ljmp Ep1TxFIFOFull CheckEp1TxRAMDataAvail: ; check to see how many bytes are presently in the ram buffer mov R0, #Ep1BytesInBuffer mov A, @R0 jnz Ep1_TxRAMBuffer_Has_Data ljmp Ep1TxRAMBufferEmpty ; there are available bytes in the buffer to transmit out Ep1_TxRAMBuffer_Has_Data: ; Get the data to transmit to the FIFO! mov R0, #Ep1ReadPointer mov A, @R0 ; get the value of the read pointer mov R0, A ; now use this address for indirect addressing Ep1_PUSH_08_BYTES_TO_TX: mov A, @R0 ; get a byte from memory - BYTE 1 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 2 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 3 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 4 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 5 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 6 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 7 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 8 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 ; adjust the read pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep1ReadPointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep1BytesInBuffer ; get present byte count mov A, @R0 clr CY ; clear the carry bit for subtraction subb A, #EP1_LOOP_BACK_FIFO_SIZE; subtract 8 bytes from the byte count mov @R0, A ; move new value back to byte count in memory ; are there any bytes left in the buffer ? jnz Ep1TxHasMoreDataInRAMBuffer ; if 0 bytes in Buffer, then reset the read & write pointers mov A, #Ep1LoopBackBuffer ; get address of beginning of Ep1 buffer mov R0, #Ep1WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep1ReadPointer mov @R0, A ; set read pointer to start of buffer Ep1TxHasMoreDataInRAMBuffer: mov TXCNTL, #EP1_LOOP_BACK_FIFO_SIZE ; Release the FIFO Ep1RAMBufferNotEmpty: ljmp CheckEp1TxRAMNewData Ep1TxRAMBufferEmpty: Ep1TxFIFOFull: pop EPINDEX pop 00h ; Register 0 pop ACC ret ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 2 RX LOOPBACK ISR. ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep2RxLoopBack Brief Description : Acts as an Infinite source of 08 byte data packets. Regs preserved : Register 0 saved --------------------------------------------------------------------* Ep2RxLoopBack: push ACC push 00h ; Register 0 EP2_CHECK_MORE_DATA: anl FIFLG, #EP2_RX_CLR ; Clear Interrupt Pending Flag Ep2RXCheck4Error: mov A, RXSTAT jnb ACC.RXERR_BIT, NoEp2RxError ; Check for error on receive ljmp HandleEp2RxError NoEp2RxError: mov A, RXFLG jb ACC.RXFIF0_BIT, CheckEp2BufferFull ljmp NoEp2RxDataReceived ; Check to make sure there is room in the buffer. CheckEp2BufferFull: mov R0, #Ep2BytesInBuffer mov A, @R0 cjne A, #Ep2LoopBackBufferSize, Ep2_RX_Buffer_NOT_Full Ep2_RX_Buffer_Full: ; adding another set of data would overfill the buffer ... ljmp NoEp2RxDataReceived Ep2_RX_Buffer_NOT_Full: ; additional check for situation where there is no data in the BUFFER ; and room in TXFIFO jnz Ep2_Normal_Get_Data mov A, TXFLG anl A, #040h ; mask out all but FIF0 bits cjne A, #040h, Ep2_FAST_RX_TX_DATA ljmp Ep2_Normal_Get_Data Ep2_FAST_RX_TX_DATA: ; move the data directly from RXDAT to TXDAT mov TXDAT, RXDAT ; *** Byte 1 *** mov TXDAT, RXDAT ; *** Byte 2 *** mov TXDAT, RXDAT ; *** Byte 3 *** mov TXDAT, RXDAT ; *** Byte 4 *** mov TXDAT, RXDAT ; *** Byte 5 *** mov TXDAT, RXDAT ; *** Byte 6 *** mov TXDAT, RXDAT ; *** Byte 7 *** mov TXDAT, RXDAT ; *** Byte 8 *** ; Stage the transmit FIFO with new data mov TXCNTL, #EP2_LOOP_BACK_FIFO_SIZE ; Go and release the receive FIFO ljmp Ep2_RELEASE_RXFIFO Ep2_Normal_Get_Data: mov R0, #Ep2WritePointer ; setup address of write pointer mov A, @R0 ; get value of write pointer mov R0, A ; transfer actual address to R0 ; Get the data and load it into the buffer ! Ep2_RX_08_BYTES: mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 1 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 2 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 3 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 4 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 5 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 6 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 7 *** inc R0 mov @R0, RXDAT ; get a byte from RXDAT - *** BYTE 8 *** inc R0 ; adjust the write pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep2WritePointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep2BytesInBuffer mov A, @R0 add A, #EP2_LOOP_BACK_FIFO_SIZE mov @R0, A Ep2_RELEASE_RXFIFO: orl RXCON, #RXFFRC_SET_MASK ; release the Receive FIFO ljmp EP2_CHECK_MORE_DATA NoEp2RxDataReceived: pop 00h ; Register 0 pop ACC ret HandleEp2RxError: ; presently this code won't try to recover from an error condition, ; but lock up the code and signify an error by LED's visible on Port 1 lcall FLASH_LEDS mov A, RXFLG ; Get the type of RX Error. anl A, #03h ; Mask off all but the error flags jnz CHK_EP2_OVF ; If these are both Zeros then it was a CRC Error. mov P1, #21h sjmp $ CHK_EP2_OVF: jnb ACC.0, CHK_EP2_URF ; Is the OVF flag set (Over flow) mov P1, #22h sjmp $ CHK_EP2_URF: ; receive underrun flag must have been set mov P1, #23h sjmp $ ;************************************************************************ ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 2 TX LOOPBACK ISR. ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep2TxLoopBack Brief Description : Acts as an Infinite source of 8 byte data packets. Regs preserved : Register 0 saved --------------------------------------------------------------------* ; Ep2TxLoopBack: push ACC push 00h ; Register 0 anl FIFLG, #EP2_TX_CLR ; Clear Interrupt Pending Flag Ep2TXCheck4Error: mov A, TXSTAT jnb ACC.TXERR_BIT, CheckEp2TxNewData ; Check for error on receive ljmp HandleEp2TxError CheckEp2TxNewData: mov A, TXFLG jnb ACC.TXFIF0_BIT, CheckEp2TxDataAvailable ljmp NoEp2TxDataReceived CheckEp2TxDataAvailable: ; check to see how many bytes are presently in the buffer mov R0, #Ep2BytesInBuffer mov A, @R0 jnz Ep2_Tx_Buffer_Has_Data ljmp Ep2TxBufferEmpty ; there are available bytes in the buffer to transmit out Ep2_Tx_Buffer_Has_Data: ; Get the data to transmit to the FIFO! mov R0, #Ep2ReadPointer mov A, @R0 ; get the value of the read pointer mov R0, A ; now use this address for indirect addressing Ep2_TX_08_BYTES: mov A, @R0 ; get a byte from memory - BYTE 1 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 2 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 3 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 4 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 5 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 6 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 7 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 8 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 ; adjust the read pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep2ReadPointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep2BytesInBuffer ; get present byte count mov A, @R0 clr CY ; clear the carry bit for subtraction subb A, #EP2_LOOP_BACK_FIFO_SIZE; subtract 8 bytes from the byte count mov @R0, A ; move new value back to byte count in memory ; are there any bytes left in the buffer ? jnz Ep2TxHasMoreDataInBuffer ; if 0 bytes in Buffer, then reset the read & write pointers mov A, #Ep2LoopBackBuffer ; get address of beginning of Ep1 buffer mov R0, #Ep2WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep2ReadPointer mov @R0, A ; set read pointer to start of buffer Ep2TxHasMoreDataInBuffer: mov TXCNTL, #EP2_LOOP_BACK_FIFO_SIZE ; Release the FIFO Ep2BufferNotEmpty: ljmp CheckEp2TxNewData Ep2TxBufferEmpty: NoEp2TxDataReceived: pop 00h ; Register 0 pop ACC ret ;----------------------------------- ; EP2 Transmit Error Handling ;----------------------------------- HandleEp2TxError: ; presently this code won't try to recover from an error condition, ; but lock up the code and signify an error by LED's visible on Port 1 lcall FLASH_LEDS mov A, TXFLG ; Get the type of TX Error. anl A, #03h ; Mask off all but the error flags jnz CHK_EP2_TX_OVF ; If these are both Zeros then it was a CRC Error. ljmp CheckEp2TxNewData ; If it was a CRC, go chack to see if there weas any other data. CHK_EP2_TX_OVF: jnb ACC.0, CHK_EP2_TX_URF ; Is the OVF flag set (Over flow) mov P1, #24h sjmp $ CHK_EP2_TX_URF: mov P1, #25h sjmp $ ret ;------------------------------------------------------------------------ ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;EE ENDPOINT 2 RAM TO TXFIFO PUSH ;EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE ;------------------------------------------------------------------------ ;************************************************************************ COMMENT *------------------------------------------------------------ Function name : Ep2RAM_TO_TX_PUSH Brief Description : Trys to push data from RAM to Transmit FIFO Regs preserved : Register 0 and ACC saved --------------------------------------------------------------------* Ep2RAM_TO_TX_PUSH: push ACC push 00h push EPINDEX CheckEp2TxRAMNewData: mov EPINDEX, #02h ; select endpoint 2 mov A, TXFLG jnb ACC.TXFIF0_BIT, CheckEp2TxRAMDataAvail ; both TX fifos have data so don't load any more ljmp Ep2TxFIFOFull CheckEp2TxRAMDataAvail: ; check to see how many bytes are presently in the ram buffer mov R0, #Ep2BytesInBuffer mov A, @R0 jnz Ep2_TxRAMBuffer_Has_Data ljmp Ep2TxRAMBufferEmpty ; there are available bytes in the buffer to transmit out Ep2_TxRAMBuffer_Has_Data: ; Get the data to transmit to the FIFO! mov R0, #Ep2ReadPointer mov A, @R0 ; get the value of the read pointer mov R0, A ; now use this address for indirect addressing Ep2_PUSH_08_BYTES_TO_TX: mov A, @R0 ; get a byte from memory - BYTE 1 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 2 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 3 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 4 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 5 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 6 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 7 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 mov A, @R0 ; get a byte from memory - BYTE 8 mov TXDAT, A ; move byte to transmit FIFO inc R0 ; increment the read pointer in R0 by 1 ; adjust the read pointer now mov A, R0 ; R0 has new updated address - xfer to ACC mov R0, #Ep2ReadPointer ; setup R0 with address of read pointer mov @R0, A ; store new address back to read pointer ; adjust the bytes in buffer count now mov R0, #Ep2BytesInBuffer ; get present byte count mov A, @R0 clr CY ; clear the carry bit for subtraction subb A, #EP2_LOOP_BACK_FIFO_SIZE; subtract 8 bytes from the byte count mov @R0, A ; move new value back to byte count in memory ; are there any bytes left in the buffer ? jnz Ep2TxHasMoreDataInRAMBuffer ; if 0 bytes in Buffer, then reset the read & write pointers mov A, #Ep2LoopBackBuffer ; get address of beginning of Ep2 buffer mov R0, #Ep2WritePointer mov @R0, A ; set write pointer to start of buffer mov R0, #Ep2ReadPointer mov @R0, A ; set read pointer to start of buffer Ep2TxHasMoreDataInRAMBuffer: mov TXCNTL, #EP2_LOOP_BACK_FIFO_SIZE ; Release the FIFO Ep2RAMBufferNotEmpty: ljmp CheckEp2TxRAMNewData Ep2TxRAMBufferEmpty: Ep2TxFIFOFull: pop EPINDEX pop 00h ; Register 0 pop ACC ret ;************************************************************************ ;************* DEVICE DESCRIPTOR **************************************** ;************************************************************************ ; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the ; LSB in the numerically higher address. ;------------------------------------------------ ;-------- FUNCTION DESCRIPTOR ------------------- ;------------------------------------------------ ; ; NOTE!!!!! '251 is a Big Endian machine. Words and DWords are stored with the ; LSB in the numerically higher address. ; BEGIN_EF_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 00h ; 0 gDevice_bDeviceSubClass: db 00h ; 0 gDevice_bDeviceProtocol: db 00h ;0 for no class specific protocols gDevice_wMaxPacketSize0: db 08h ;8 byte max for EP0 ;*************************************************************************** ; NOTE ABOUT VENDOR ID: ;*************************************************************************** ; Presently the VID must still be 8086 for the AX and embedded ; function, as this is required for the Intel Test Board driver ; to get loaded on the host side. ;*************************************************************************** gDevice_widVendor: dw 8680h ;Intel Vendor ID (8086) gDevice_widProduct: dw 9098h ;product ID (9890) gDevice_bcdDevice: dw 0603h ;device version 3.06 gDevice_iManufacturer: db 01h ; Manufacturer string index gDevice_iProduct: db 02h ; Product string index ;*************************************************************************** ; NOTE ABOUT SERIAL NUMBER: ; Unless you are going to give a unique serial number for EACH rom burned ; with this code, DO NOT return an index to a serial number string here, but ; return 0 - this is vital to the correct operation of multiple, similar ; devices connected to a system running Memphis ;*************************************************************************** gDevice_iSerialNumber: db 0 gDevice_bNumConfigurations: db 2 ; Config 1 = enumeration w/loopback ; Config KEYBOARD_CONFIG = keyboard test configuration END_EF_DEVICE_DESCRIPTOR: ;************************************************************************ ;************* CONFIG DESCRIPTOR 1 SELF POWERED ************************* ;************************************************************************ ;/*--------------- Config descriptor 1----------------*/ ; This descriptor sets up the device for loopback on EP 1, 2 ; See below for the specifics. BEGIN_EF_CONFIG_DESCRIPTOR_1: g1Config_bLength: db 09h g1Config_bDescriptorType: db CONFIG_DESCR g1Config_bTotalLength: db END_EF_CONFIG_DESCRIPTOR_1 - BEGIN_EF_CONFIG_DESCRIPTOR_1 g1Config_bCorrection: db 0 g1Config_bNumInterfaces: db 1 ; NUM_OF_INTERFACES g1Config_bConfigurationValue: db 1 g1Config_iConfiguration: db 04h g1Config_bmAttributes: db 060h ; self - RWU enabled g1Config_MaxPower: db 025 ; 50ma ; /*------------- Initialize global Interface descriptor ---------------*/ BEGIN_INTERFACE_DESCRIPTOR1: g1Interface_bLength: db END_INTERFACE_DESCRIPTOR1 - BEGIN_INTERFACE_DESCRIPTOR1 g1Interface_bDescriptorType: db INTERFACE_DESCR g1Interface_bInterfaceNumber: db 0 g1Interface_bAlternateSetting: db 0 g1Interface_bNumEndpoints: db 04h ; in addition to endp 0, HK has Endp 1 and Endp 2 = 4 endpoints or 2 endpoint pairs g1Interface_bInterfaceClass: db 00h g1Interface_bInterfaceSubClass: db 00h g1Interface_bInterfaceProtocol: db 00h g1Interface_iInterface: db 06h END_INTERFACE_DESCRIPTOR1: ; /*------------- Initialize Endpoint 1 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR1_TX1: g1EP1Tx_Length: db END_ENDPOINT_DESCRIPTOR1_TX1 - BEGIN_ENDPOINT_DESCRIPTOR1_TX1 g1EP1Tx_bDescriptorType: db ENDPOINT_DESCR g1EP1Tx_bEndpointAddress: db 81h ;EP address 1, in g1EP1Tx_bmAtrributes: db 03h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g1EP1Tx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE g1EP1Tx_wMaxPacketSize_MSb: db 00 g1EP1Tx_bInterval: db 01h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR1_TX1: ; /*------------- Initialize Endpoint 1 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR1_RX1: g1EP1Rx_Length: db END_ENDPOINT_DESCRIPTOR1_RX1 - BEGIN_ENDPOINT_DESCRIPTOR1_RX1 g1EP1Rx_bDescriptorType: db ENDPOINT_DESCR g1EP1Rx_bEndpointAddress: db 01h ;EP address 1, out g1EP1Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g1EP1Rx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE g1EP1Rx_wMaxPacketSize_MSb: db 00 g1EP1Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR1_RX1: ; /*------------- Initialize Endpoint 2 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR1_TX2: g1EP2Tx_bLength: db END_ENDPOINT_DESCRIPTOR1_TX2 - BEGIN_ENDPOINT_DESCRIPTOR1_TX2 g1EP2Tx_bDescriptorType: db ENDPOINT_DESCR g1EP2Tx_bEndpointAddress: db 82h ;EP address 2, in g1EP2Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g1EP2Tx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE g1EP2Tx_wMaxPacketSize_MSb: db 00 g1EP2Tx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR1_TX2: ; /*------------- Initialize Endpoint 2 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR1_RX2: g1EP2Rx_bLength: db END_ENDPOINT_DESCRIPTOR1_RX2 - BEGIN_ENDPOINT_DESCRIPTOR1_RX2 g1EP2Rx_bDescriptorType: db ENDPOINT_DESCR g1EP2Rx_bEndpointAddress: db 02h ;EP address 2, Out g1EP2Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g1EP2Rx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE g1EP2Rx_wMaxPacketSize_MSb: db 00 g1EP2Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR1_RX2: END_EF_CONFIG_DESCRIPTOR_1: ;************************************************************************ ;************* CONFIG DESCRIPTOR 2 BUS POWERED ************************* ;************************************************************************ ;/*--------------- Config descriptor 2----------------*/ ; This descriptor sets up the device for loopback on EP 1, 2 ; See below for the specifics. BEGIN_EF_CONFIG_DESCRIPTOR_2: g2Config_bLength: db 09h g2Config_bDescriptorType: db CONFIG_DESCR g2Config_bTotalLength: db END_EF_CONFIG_DESCRIPTOR_2 - BEGIN_EF_CONFIG_DESCRIPTOR_2 g2Config_bCorrection: db 0 g2Config_bNumInterfaces: db 1 ; NUM_OF_INTERFACES g2Config_bConfigurationValue: db 1 g2Config_iConfiguration: db 04h g2Config_bmAttributes: db 0A0h ; bus - RWU enabled g2Config_MaxPower: db 025 ; 50ma ; /*------------- Initialize global Interface descriptor ---------------*/ BEGIN_INTERFACE_DESCRIPTOR2: g2Interface_bLength: db END_INTERFACE_DESCRIPTOR2 - BEGIN_INTERFACE_DESCRIPTOR2 g2Interface_bDescriptorType: db INTERFACE_DESCR g2Interface_bInterfaceNumber: db 0 g2Interface_bAlternateSetting: db 0 g2Interface_bNumEndpoints: db 04h ; in addition to endp 0, HK has Endp 1 and Endp 2 = 4 endpoints or 2 endpoint pairs g2Interface_bInterfaceClass: db 00h g2Interface_bInterfaceSubClass: db 00h g2Interface_bInterfaceProtocol: db 00h g2Interface_iInterface: db 06h END_INTERFACE_DESCRIPTOR2: ; /*------------- Initialize Endpoint 1 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR2_TX1: g2EP1Tx_Length: db END_ENDPOINT_DESCRIPTOR2_TX1 - BEGIN_ENDPOINT_DESCRIPTOR2_TX1 g2EP1Tx_bDescriptorType: db ENDPOINT_DESCR g2EP1Tx_bEndpointAddress: db 81h ;EP address 1, in g2EP1Tx_bmAtrributes: db 03h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g2EP1Tx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE g2EP1Tx_wMaxPacketSize_MSb: db 00 g2EP1Tx_bInterval: db 01h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR2_TX1: ; /*------------- Initialize Endpoint 1 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR2_RX1: g2EP1Rx_Length: db END_ENDPOINT_DESCRIPTOR2_RX1 - BEGIN_ENDPOINT_DESCRIPTOR2_RX1 g2EP1Rx_bDescriptorType: db ENDPOINT_DESCR g2EP1Rx_bEndpointAddress: db 01h ;EP address 1, out g2EP1Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g2EP1Rx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE g2EP1Rx_wMaxPacketSize_MSb: db 00 g2EP1Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR2_RX1: ; /*------------- Initialize Endpoint 2 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR2_TX2: g2EP2Tx_bLength: db END_ENDPOINT_DESCRIPTOR2_TX2 - BEGIN_ENDPOINT_DESCRIPTOR2_TX2 g2EP2Tx_bDescriptorType: db ENDPOINT_DESCR g2EP2Tx_bEndpointAddress: db 82h ;EP address 2, in g2EP2Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g2EP2Tx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE g2EP2Tx_wMaxPacketSize_MSb: db 00 g2EP2Tx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR2_TX2: ; /*------------- Initialize Endpoint 2 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR2_RX2: g2EP2Rx_bLength: db END_ENDPOINT_DESCRIPTOR2_RX2 - BEGIN_ENDPOINT_DESCRIPTOR2_RX2 g2EP2Rx_bDescriptorType: db ENDPOINT_DESCR g2EP2Rx_bEndpointAddress: db 02h ;EP address 2, Out g2EP2Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt g2EP2Rx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE g2EP2Rx_wMaxPacketSize_MSb: db 00 g2EP2Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR2_RX2: END_EF_CONFIG_DESCRIPTOR_2: ;*********************************************************************** ;****** CONFIG DESCRIPTOR for KEYBOARD CONFIG 1 - SELF Powered ********* ;*********************************************************************** ;/*--------------- Config descriptor K1----------------*/ ; This descriptor sets up the device for Keyboard test configuration BEGIN_CONFIG_DESCRIPTOR_K1: gK1Config_bLength: db 09h gK1Config_bDescriptorType: db CONFIG_DESCR gK1Config_bTotalLength: db END_CONFIG_DESCRIPTOR_K1 - BEGIN_CONFIG_DESCRIPTOR_K1 gK1Config_bCorrection: db 0 gK1Config_bNumInterfaces: db 1 ; NUM_OF_INTERFACES; gK1Config_bConfigurationValue: db KEYBOARD_CONFIG gK1Config_iConfiguration: db 05h gK1Config_bmAttributes: db 060h ; self - rwu capable gK1Config_MaxPower: db 025 ;50ma ; /*------------- Initialize global Interface descriptor ---------------*/ BEGIN_INTERFACE_DESCRIPTOR_K1: gK1Interface_bLength: db END_INTERFACE_DESCRIPTOR_K1 - BEGIN_INTERFACE_DESCRIPTOR_K1 gK1Interface_bDescriptorType: db INTERFACE_DESCR gK1Interface_bInterfaceNumber: db 0 gK1Interface_bAlternateSetting: db 0 gK1Interface_bNumEndpoints: db 04h gK1Interface_bInterfaceClass: db 00h gK1Interface_bInterfaceSubClass: db 00h gK1Interface_bInterfaceProtocol: db 00h gK1Interface_iInterface: db 06h END_INTERFACE_DESCRIPTOR_K1: ; /*------------- Initialize Endpoint 1 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K1_TX1: gK1EP1Tx_Length: db END_ENDPOINT_DESCRIPTOR_K1_TX1 - BEGIN_ENDPOINT_DESCRIPTOR_K1_TX1 gK1EP1Tx_bDescriptorType: db ENDPOINT_DESCR gK1EP1Tx_bEndpointAddress: db 81h ;EP address 1, in gK1EP1Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK1EP1Tx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE gK1EP1Tx_wMaxPacketSize_MSb: db 00 gK1EP1Tx_bInterval: db 01h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K1_TX1: ; /*------------- Initialize Endpoint 1 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K1_RX1: gK1EP1Rx_Length: db END_ENDPOINT_DESCRIPTOR_K1_RX1 - BEGIN_ENDPOINT_DESCRIPTOR_K1_RX1 gK1EP1Rx_bDescriptorType: db ENDPOINT_DESCR gK1EP1Rx_bEndpointAddress: db 01h ;EP address 1, out gK1EP1Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK1EP1Rx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE gK1EP1Rx_wMaxPacketSize_MSb: db 00 gK1EP1Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K1_RX1: ; /*------------- Initialize Endpoint 2 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K1_TX2: gK1EP2Tx_bLength: db END_ENDPOINT_DESCRIPTOR_K1_TX2 - BEGIN_ENDPOINT_DESCRIPTOR_K1_TX2 gK1EP2Tx_bDescriptorType: db ENDPOINT_DESCR gK1EP2Tx_bEndpointAddress: db 82h ;EP address 2, in gK1EP2Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK1EP2Tx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE gK1EP2Tx_wMaxPacketSize_MSb: db 00 gK1EP2Tx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K1_TX2: ; /*------------- Initialize Endpoint 2 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K1_RX2: gK1EP2Rx_bLength: db END_ENDPOINT_DESCRIPTOR_K1_RX2 - BEGIN_ENDPOINT_DESCRIPTOR_K1_RX2 gK1EP2Rx_bDescriptorType: db ENDPOINT_DESCR gK1EP2Rx_bEndpointAddress: db 02h ;EP address 2, Out gK1EP2Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK1EP2Rx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE gK1EP2Rx_wMaxPacketSize_MSb: db 00 gK1EP2Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K1_RX2: END_CONFIG_DESCRIPTOR_K1: ;*********************************************************************** ;****** CONFIG DESCRIPTOR for KEYBOARD CONFIG 2 - BUS Powered ********* ;*********************************************************************** ;/*--------------- Config descriptor K2----------------*/ ; This descriptor sets up the device for Keyboard test configuration BEGIN_CONFIG_DESCRIPTOR_K2: gK2Config_bLength: db 09h gK2Config_bDescriptorType: db CONFIG_DESCR gK2Config_bTotalLength: db END_CONFIG_DESCRIPTOR_K2 - BEGIN_CONFIG_DESCRIPTOR_K2 gK2Config_bCorrection: db 0 gK2Config_bNumInterfaces: db 1 ; NUM_OF_INTERFACES; gK2Config_bConfigurationValue: db KEYBOARD_CONFIG gK2Config_iConfiguration: db 05h gK2Config_bmAttributes: db 0A0h ; bus - rwu capable gK2Config_MaxPower: db 025 ;50ma ; /*------------- Initialize global Interface descriptor ---------------*/ BEGIN_INTERFACE_DESCRIPTOR_K2: gK2Interface_bLength: db END_INTERFACE_DESCRIPTOR_K2 - BEGIN_INTERFACE_DESCRIPTOR_K2 gK2Interface_bDescriptorType: db INTERFACE_DESCR gK2Interface_bInterfaceNumber: db 0 gK2Interface_bAlternateSetting: db 0 gK2Interface_bNumEndpoints: db 04h gK2Interface_bInterfaceClass: db 00h gK2Interface_bInterfaceSubClass: db 00h gK2Interface_bInterfaceProtocol: db 00h gK2Interface_iInterface: db 06h END_INTERFACE_DESCRIPTOR_K2: ; /*------------- Initialize Endpoint 1 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K2_TX1: gK2EP1Tx_Length: db END_ENDPOINT_DESCRIPTOR_K2_TX1 - BEGIN_ENDPOINT_DESCRIPTOR_K2_TX1 gK2EP1Tx_bDescriptorType: db ENDPOINT_DESCR gK2EP1Tx_bEndpointAddress: db 81h ;EP address 1, in gK2EP1Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK2EP1Tx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE gK2EP1Tx_wMaxPacketSize_MSb: db 00 gK2EP1Tx_bInterval: db 01h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K2_TX1: ; /*------------- Initialize Endpoint 1 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K2_RX1: gK2EP1Rx_Length: db END_ENDPOINT_DESCRIPTOR_K2_RX1 - BEGIN_ENDPOINT_DESCRIPTOR_K2_RX1 gK2EP1Rx_bDescriptorType: db ENDPOINT_DESCR gK2EP1Rx_bEndpointAddress: db 01h ;EP address 1, out gK2EP1Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK2EP1Rx_wMaxPacketSize_LSb: db EP1_LOOP_BACK_FIFO_SIZE gK2EP1Rx_wMaxPacketSize_MSb: db 00 gK2EP1Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K2_RX1: ; /*------------- Initialize Endpoint 2 TX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K2_TX2: gK2EP2Tx_bLength: db END_ENDPOINT_DESCRIPTOR_K2_TX2 - BEGIN_ENDPOINT_DESCRIPTOR_K2_TX2 gK2EP2Tx_bDescriptorType: db ENDPOINT_DESCR gK2EP2Tx_bEndpointAddress: db 82h ;EP address 2, in gK2EP2Tx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK2EP2Tx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE gK2EP2Tx_wMaxPacketSize_MSb: db 00 gK2EP2Tx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K2_TX2: ; /*------------- Initialize Endpoint 2 RX descriptor ---------------*/ BEGIN_ENDPOINT_DESCRIPTOR_K2_RX2: gK2EP2Rx_bLength: db END_ENDPOINT_DESCRIPTOR_K2_RX2 - BEGIN_ENDPOINT_DESCRIPTOR_K2_RX2 gK2EP2Rx_bDescriptorType: db ENDPOINT_DESCR gK2EP2Rx_bEndpointAddress: db 02h ;EP address 2, Out gK2EP2Rx_bmAtrributes: db 02h ;00-Control, 1-ISO, 2-Bulk,3-Interrupt gK2EP2Rx_wMaxPacketSize_LSb: db EP2_LOOP_BACK_FIFO_SIZE gK2EP2Rx_wMaxPacketSize_MSb: db 00 gK2EP2Rx_bInterval: db 00h ; Ignored for bulk and control, 1 for isoc, ; 1-255 for interrupt END_ENDPOINT_DESCRIPTOR_K2_RX2: END_CONFIG_DESCRIPTOR_K2: 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 'S',00,'y',00,'s',00,'.',00,' ',00,'V',00,'a',00,'l',00,'.',00,' ',00 ;*********** PRODUCT Bus Powered String Descriptor text *************** STRING_2: db LOW(STRING_3-STRING_2) db STRING_DESCR db '8',00,'x',00,'9',00,'3',00,'1',00,' ',00 db 'F',00,'u',00,'n',00,'c',00,'t',00,'i',00,'o',00,'n',00,'.',00 db ' ',00,'w',00,'/',00 db 'L',00,'o',00,'o',00,'p',00,'b',00,'a',00,'c',00,'k',00 ;*********** SERIAL # String Descriptor text *************** ; NOTE: serial number string will only be returned if the device is manually requested ; with a get string descriptor on index 3 ;*********************************************************** 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,'3',00,'.',00,'0',00,'6',00 ;*********** CONFIGURATION String Descriptor text ************** STRING_4: db LOW(STRING_5-STRING_4) db STRING_DESCR db '4',00,'0',00,' ',00,'B',00,'y',00,'t',00,'e',00,' ',00 db 'I',00,'n',00,'t',00,'e',00,'r',00,'r',00,'u',00,'p',00,'t',00,' ',00 db 'L',00,'o',00,'o',00,'p',00,'b',00,'a',00,'c',00,'k',00,' ',00 db 'O',00,'n',00,' ',00,'E',00,'n',00,'d',00,'p',00,'o',00,'i',00,'n',00,'t',00,' ',00,'1',00,0dh,00,0ah,00 db '4',00,'0',00,' ',00,'B',00,'y',00,'t',00,'e',00,' ',00 db 'B',00,'u',00,'l',00,'k',00,' ',00,'L',00,'o',00,'o',00,'p',00,'b',00,'a',00,'c',00,'k',00,' ',00 db 'O',00,'n',00,' ',00,'E',00,'n',00,'d',00,'p',00,'o',00,'i',00,'n',00,'t',00,' ',00,'2',00,0dh,00,0ah,00 ;*********** CONFIGURATION String Descriptor text ************** STRING_5: db LOW(STRING_6-STRING_5) db STRING_DESCR db 'K',00,'e',00,'y',00,'b',00,'o',00,'a',00,'r',00,'d',00,' ',00 db 'T',00,'e',00,'s',00,'t',00,' ',00 db 'C',00,'o',00,'n',00,'f',00,'i',00,'g',00,'u',00,'r',00,'a',00 db 't',00,'i',00,'o',00,'n',00 ;*********** INTERFACE String Descriptor text *************** STRING_6: db LOW(STRING_7-STRING_6) 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_7: IF SIO_DEBUG == ENABLED EMBDFN_UP_MSG: db " Embedded function up and configured ! ",CR,LF,NUL GOT_THERE_MSG: db " Got there chipper-do ! ",CR,LF,NUL SET_ADDR_MSG: db " Set the embedded function address to: ",NUL ENDIF ;############################################################# ;####### 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. ;---------------------------------------------------------------------------- DEFINE EMB_FUNC_DATA_SEG, SPACE=DATA, ORG=053h SEGMENT EMB_FUNC_DATA_SEG ;; ;; Buffer and associated variables for Control Endpoint management gbSetupSeqTX: ds 1 gbSetupSeqRX: ds 1 ; Embedded function needs separate data variables from hub COMMAND_BUFFER: StandardDeviceRequest: bmRequestType: ds 1 FbRequest: bRequest: ds 1 FwValue: wValue: bDescriptorType: ds 1 bDescriptorIndex: ds 1 FwIndex: wIndex: ds 2 wLength: ds 2 CntlWriteDataBuffer: ds 1 ;8 ; 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 fCurrentConfiguration: ds 1 ; current config of embedded function CurrentConfig1Interface: ds 1 FN_RWU_FLG: EMB_FN_RWU_FLG: ds 1 ;******************************************************************* ; Loopback variables ;******************************************************************* DEFINE EMB_FUNC_LOOPBACK_DATA_SEG, SPACE=DATA, ORG=07Fh SEGMENT EMB_FUNC_LOOPBACK_DATA_SEG ; all loopback stuff will be in "indirect" addressed internal RAM ; therefore all reads/writes must to indirect addressing with R0 ; or R1 ; Endpoint 1 variables and pointers Ep1BytesInBuffer: ds 1 Ep1WritePointer: ds 1 Ep1ReadPointer: ds 1 ; Endpoint 2 variables and pointers Ep2BytesInBuffer: ds 1 Ep2WritePointer: ds 1 Ep2ReadPointer: ds 1 ; Buffers Ep1LoopBackBufferSize: equ 028h ; 40 byte buffer for INTERRUPT loopback Ep1LoopBackBuffer: ds Ep1LoopBackBufferSize Ep2LoopBackBufferSize: equ 028h ; 40 byte buffer for BULK loopback Ep2LoopBackBuffer: ds Ep2LoopBackBufferSize END