; wicked v3.0 ; fix for N64 timing problem ;---------- ; code version 2.0 ; 01/06/1999 ; ; This code is copyright Simon Nield 1999. ; the code may not be used for any commercial purpose without the author's prior written consent ; email: simon_nield@hotmail.com ; homepage: http://www.users.globalnet.co.uk/~snandhe/ ; ; N64 report order is now: ; c-up, c-rt, c-dn, c-lf, a, b, l, r, a, b, z, st, up, rt, dn, lf ; PSX report order is: ; /\, O, X, [], l2, r2, l1, r1, slct, Lj, Rj, st, up, rt, dn, lf ; ********************************************************************** ; PSX to USB converter ; ; This code allows use of a PSX (Playstation) controller with the USB ; ; The controller connects to the ports as shown below: ; ; PSX PSX uC ; Con Function pin Port0 Port1 ; # (in) (out) ; ; 1 Data 1 p0.0 1k pull-up to VCC ; 2 Command 5 p1.0 1k pull-up to VCC ; 3 (+9v?) ; 4 GND ; 5 VCC ; 6 ATT 16 p1.1 1k pull-up to VCC ; 7 Clock 6 p1.2 1k pull-up to VCC ; 8 - ; 9 ACK 2 p0.1 ; ; ********************************************************************* ; N64 to USB converter ; This lets you use an N64 controller ; N64 data line connects to p1.0 (pin5), with a 1k pull-up to vcc ; N64 power is supplied through a couple of 1n4148s in series, to give ~3v6 ; ; p0.7 (pin 17) is used to select between N64 and PSX modes. ; if p0.7 is pulled low then PSX mode is used, otherwise N64 mode is used ;*********************************************************************** ; Cypress Semiconductor ; Joystick Demonstration Design Kit Firmware ; ; Features : ; Four Fire Buttons ; Four Hat Buttons ; X, Y, Z movement ; byte_5 ; Passes Chapter 9 and Hidview Tests ; Includes Suspend/Resume Feature ; ; This firmware file is for demonstration purposes only. ; Cypress Semiconductor will not assume any liability for its use. ; ;======================================================================= ; 1/20/98 wmh v5.0 Minor changes in One_msec_ISR ;======================================================================= ; 12/10/97 wmh v4.9 Minor changes in One_msec_ISR, main and Reset ; Watchdog timer reset in main. ;======================================================================= ; 10/27/97 wmh v4.8 Change in One_msec_ISR ; Code Naks whenever the joystick is not moved. ; Code also Naks after enumeration for a period approx. 230msec ; This solves blue screen problem when the power is turned off then on ;======================================================================= ; 10/13/97 wmh v4.6 Change in USB_EP0_ISR ; SetConfiguration request was changed so as to enable endpoint 1 ; GetReport is stalled ; GetReportDescriptor sends HID Report Descriptor ;======================================================================= ; 9/8/97 wmh v4.5 Joystick Jitter Solved ; Jitter Solution added to GPIO_ISR ;======================================================================= ; 8/13/97 wmh v4.3 Report Descriptor Change ; Solves unusual jump in joystick movement ;======================================================================= ; 8/11/97 wmh v4.2 ipret change ; changed ret to ipret whenever needed in all subroutines ;======================================================================= ; 8/8/97 wmh v4.0 One_msec and GPIO ISR changes ; Changes to prevent Endpoint_1 from interrupting capacitor charging ; to prevent jitter effect ;======================================================================== ; 8/8/97 wmh v3.9 change in Report Descriptor ; Logical and Physical Min and Max have been changed to 3 bytes if > 127 ; Other changes were also done ;======================================================================== ; 7/3/97 wmh v3.7 add features ; Suspend/Resume features have been added ; Main work done in the One_mSec_ISR ;======================================================================== ; 6/30/97 wmh v3.6 add features ; changes to allow the code to pass chapter 9 and hidview tests have been ; done. That meant major rework of the endpoint zero interrupt service ; routine (USB_EP0_ISR). ;======================================================= ; rev 3.5 4/17/97 gwg ; Changed the interrupt mask from a constant to a variable. ; This allows us to enable only the one msec timer and ; EP0 during enumeration. ; ; Tim Williams found a problem with the hat buttons. I ; forgot the buttons were in the upper nibble. ;======================================================= ; rev 3.4 4/15/97 gwg 664 bytes ; 1. The endpoint one ISR only toggles the Data 0/1 bit ; now. ; 2. Every four msec, the one msec ISR writes to the ; USB_EP1_TX_Config register to enable response to IN ; packets from the host. ; 3. Write measured data directly into the endpoint one ; dma buffer. ; 4. Code compatible with revision 2 and 3 silicon. ;======================================================= ; rev 3.3 4/11/97 gwg ; modified for IPRET instruction in an effort to improve ; the runtime. ;======================================================= ; rev 3.2 4/11/97 gwg ; Tim Williams found a bug in the GPIO_ISR that prevented ; the code from working in the chip. There was not enough ; time allowed to discharge the timing capacitors before ; interrupts were enabled. ;======================================================= ; rev 3.1 4/8/97 gwg ; Replaced Send_Buffer macro with a subroutine. ;======================================================= ; rev 3.0 4/8/97 gwg ; reworked the code to support the hat buttons and up to ; four analog channels. The analog channels are sampled ; one per msec. With a channel sample rate of 250 hz, ; each channel should have a bandwidth of 125 hz - good. ; ; The buttons are sampled in the main loop at a much ; higher rate. ; ; The Send_Buffer macro remains a code size problem as ; the result to date is 40 bytes over 2 kilobytes. ;======================================================= ; rev 2.1 3/29/97 gwg ; reworked the code to eliminate string indices in the ; descriptors. We don't have any strings. Also fixed ; an error in the HID length (114 => 116 bytes) ;======================================================= ; drastic rework of js63fa.asm on 3/25 by gwg ;******************************************************* ; This version of code supports the joystick function ; and four buttons. ;******************************************************* ; 1. Eliminated the "scaling" feature that tried to ; ensure the joystick returned full-range readings. ; 2. Converted the analog measurement sections into two ; subroutines. ; 3. Fixed several interrupt enable and stack problems ; with the USB interrupt service routines. ; 4. Initialized the part to work correctly in a joystick: ; - program pullup registers ; - program Isink registers ; 5. Enabled the one msec interrupt handler to clear the ; watchdog. ; 6. Patched the USB EP0 ISR to set the BadOuts bit to ; accomodate changes in the chip definition. ; 7. Rewrote the USB interrupt handlers for better flow ; and to remove redundant load instructions. ; 8. Commented the code to describe how it works. ;******************************************************* ; Suggested Changes ;------------------------------------------------------- ; 1. Convert the Send_Buffer macro to a subroutine to ; reduce the code size. The current version is 2 KB ; plus 22 bytes. ; 2. Add hat support as either: ; - third analog channel (software only) ; - four buttons (rework hardware) ; 3. Add byte_5 support as another analog channel. ; Consolidate the measure subroutines into one routine ; that can process a selectable channel. ;******************************************************* ; Suggestions for the Assembler ;------------------------------------------------------- ; 1. The assembler should be able to assign variable ; addresses automatically. One method is the concept ; of segments: "data" and "code". An ORG directive ; would include a parameter to indicate which type of ; segment was intended. Then DB, DW, etc. would ; allocate variable space and automatically assign ; the addresses. ; 2. We need a linker that allows us to write modular ; code and link modules together. ; 3. Conditional assembly directives would be useful to ; write common code to support multiple parts. ;******************************************************* ;**************** assembler directives ***************** label: XPAGEON ; I/O ports Port0_Data: equ 00h ; GPIO data port 0 Port1_Data: equ 01h ; GPIO data port 1 Port0_Interrupt: equ 04h ; Interrupt enable for port 0 Port1_Interrupt: equ 05h ; Interrupt enable for port 1 Port0_Pullup: equ 08h ; Pullup resistor control for port 0 Port1_Pullup: equ 09h ; Pullup resistor control for port 1 ; USB ports USB_EP0_TX_Config: equ 10h ; USB EP0 transmit configuration USB_EP1_TX_Config: equ 11h ; USB EP1 transmit configuration USB_Device_Address: equ 12h ; USB device address assigned by host USB_Status_Control: equ 13h ; USB status and control register USB_EP0_RX_Status: equ 14h ; USB EP0 receive status ; control ports Global_Interrupt: equ 20h ; Global interrupt enable Watchdog: equ 21h ; clear watchdog Timer Timer: equ 23h ; free-running Timer ; GPIO Isink registers Port0_Isink: equ 30h Port0_Isink0: equ 30h Port0_Isink1: equ 31h Port0_Isink2: equ 32h Port0_Isink3: equ 33h Port0_Isink4: equ 34h Port0_Isink5: equ 35h Port0_Isink6: equ 36h Port0_Isink7: equ 37h Port1_Isink: equ 38h Port1_Isink0: equ 38h Port1_Isink1: equ 39h Port1_Isink2: equ 3Ah Port1_Isink3: equ 3Bh ; control port Status_Control: equ FFh ; constants - gwg BUTTON_MASK: equ 0Fh ; button bits HAT_MASK: equ F0h ; hat bits FORWARD: equ 1 ; hat forward RIGHT: equ 3 ; hat right BACK: equ 5 ; hat back LEFT: equ 7 ; hat left ;********** Register constants ************************************ ; Processor Status and Control RunBit: equ 1h ; CPU Run bit USBReset: equ 20h ; USB Bus Reset bit WatchDogReset: equ 40h ; Watchdog Reset bit ; interrupt masks TIMER_ONLY: equ 4h ; one msec timer ENUMERATE_MASK: equ 0Ch ; one msec timer ; USB EP0 interrupt RUNTIME_MASK: equ 5Ch ; one msec timer ; USB EP0 interrupt ; USB EP1 interrupt ; GPIO interrupt ; USB EP1 transmit configuration DataToggle: equ 40h ; Data 0/1 bit ;======================================================================== ; constant declarations ;======================================================================== ; from USB Spec v1.0 from page 175 ;------------------------------------------------------------------------ ; standard request codes get_status: equ 0 clear_feature: equ 1 set_feature: equ 3 set_address: equ 5 get_descriptor: equ 6 set_descriptor: equ 7 get_configuration: equ 8 set_configuration: equ 9 get_interface: equ 10 set_interface: equ 11 synch_frame: equ 12 ; standard descriptor types device: equ 1 configuration: equ 2 string: equ 3 interface: equ 4 endpoint: equ 5 ; standard feature selectors endpoint_stalled: equ 0 ; recipient endpoint device_remote_wakeup: equ 1 ; recipient device ;======================================================================== ; from HID Class v1.0 Draft #4 ;------------------------------------------------------------------------ ; class specific descriptor types from section 7.1 Standard Requests HID: equ 21h report: equ 22h physical: equ 23h ; class specific request codes from section 7.2 Class Specific Requests get_report: equ 1 get_idle: equ 2 get_protocol: equ 3 set_report: equ 9 set_idle: equ 10 set_protocol: equ 11 ;======================================================================== ; USB packet constants (debug purposes) ;------------------------------------------------------------------------ setup: equ B4h in: equ 96h out: equ 87h data0: equ C3h data1: equ D2h ack: equ 4Bh nak: equ 5Ah DISABLE_REMOTE_WAKEUP: equ 0 ; bit[1] = 0 ENABLE_REMOTE_WAKEUP: equ 2 ; bit[1] = 1 ;======================================================================== ; data variable assignments ;======================================================================== ; control endpoint 0 fifo endpoint_0: equ 70h ; control endpoint ; definitions for SETUP packets bmRequestType: equ 70h bRequest: equ 71h wValue: equ 72h ; default wValue (8-bits) wValueHi: equ 73h wIndex: equ 74h ; default wIndex (8-bits) wIndexHi: equ 75h wLength: equ 76h ; default wLength (8-bits) wLengthHi: equ 77h ; data memory variables ;------------------------------------------------------------------------ ; To support the USB specification. remote_wakeup_status: equ 30h ; remote wakeup request ; zero is disabled ; two is enabled configuration_status: equ 31h ; configuration status ; zero is unconfigured ; one is configured ;idle_status: equ 33h ; support SetIdle and GetIdle protocol_status: equ 34h ; zero is boot protocol ; one is report protocol suspend_counter: equ 35h ; contains number of idle bus msecs jitter_temp: equ 36h loop_temp: equ 37h start_send: equ 38h byte_0_old: equ 39h byte_1_old: equ 40h byte_2_old: equ 41h byte_3_old: equ 42h byte_4_old: equ 43h byte_5_old: equ 44h ;------------------------------------------------------------------------ ; variable allocations temp: equ 25h start_time: equ 21h read_delay: equ 22h interrupt_mask: equ 20h endp0_data_toggle: equ 23h loop_counter: equ 24h data_start: equ 27h data_count: equ 28h endpoint_stall: equ 29h ; interrupt endpoint 1 fifo endpoint_1: equ 78h byte_0: equ 78h byte_1: equ 79h byte_2: equ 7Ah byte_3: equ 7Bh byte_4: equ 7Ch byte_5: equ 7Dh ;*************** interrupt vector table **************** ; begin execution here after a reset org 00h ; Reset vector jmp Reset org 02h ; 128us interrupt jmp DoNothing_ISR org 04h ; 1.024ms interrupt jmp One_mSec_ISR org 06h ; endpoint 0 interrupt jmp USB_EP0_ISR org 08h ; endpoint 1 interrupt jmp USB_EP1_ISR org 0Ah ; reserved interrupt jmp Reset org 0Ch ; general purpose I/O interrupt jmp DoNothing_ISR ; not used org 0Eh ; Wakeup_ISR or resume interrupt jmp DoNothing_ISR ; not used ORG 10h ;************************************************************************ ; The 128 uSec, Cext, is not used by the joystick code. ; If this interrupt occurs, the software should do nothing ; except re-enable the interrupts. DoNothing_ISR: push A ; save accumulator on stack mov A,[interrupt_mask] ipret Global_Interrupt ; enable interrupts and return ;************************************************************************ ; The 1 msec interrupt is used to check for suspend and start an ; analog measurement. One_mSec_ISR: push A ; save accumulator on stack mov A, [loop_temp] ; Before enumeration end value is zero cmp A, 0h jz not_main ; Enumeration has not ended dec [loop_temp] ; Enumeration ended decrement counter not_main: ; suspend checking iord USB_Status_Control ; check if there is no bus activity and A, 01h cmp A,0h jz Inc_counter ; no bus activity iord USB_Status_Control ; clear the bus activity bit and A, 0FEh iowr USB_Status_Control mov A, 0h ; clear the suspend counter mov [suspend_counter], A jmp Suspend_end Inc_counter: inc [suspend_counter] mov A, [suspend_counter] ; get idle msec counts cmp A, 03h ; check if 3msecs of bus inactivity passed jnz Suspend_end ; less than 3msecs mov A, 0h ; clear the suspend counter mov [suspend_counter], A ;mov A, 0h ; Enable Pullup on port1 lines ;iowr Port1_Pullup ;mov A, 0ffh ;iowr Port1_Data iord Status_Control ;set the suspend bit causing suspend or A, 08h iowr Status_Control nop ;mov A, 0ffh ; Disable Pullup on port1 lines ;iowr Port1_Pullup ;mov A, 0h ;iowr Port1_Data Suspend_end: ; start read from controller ; reinstate following with some mods to limit read frequency mov A, [read_delay] ; check if it's time to read again dec A mov [read_delay], A ; write back decrimented value jnz skip_it mov A, 15 ; initialize read delay (in ms) mov [read_delay], A iord USB_EP1_TX_Config cmp A,0 ; test whether endpoint enabled ;jz skip_it ; DOESN'T WORK !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! mov A, [start_send] cmp A, 01h jnz skip_it ; ***************************************************************************** ; check if we are in N64 mode. If so, then do N64 read, otherwise do PSX read ; N64 pad comms uses 4us symbols - low,data,data,high ; data is sent MSB first, with a high stopbit at the end of transmission iord Port0_Data rlc jnc psx_read n64_read: mov A, 0 mov [byte_0], A mov [byte_1], A mov A, 80h mov [byte_2], A ; Xaxis signed -> unsigned mov [byte_4], A ; not used mov [byte_5], A ; not used mov A, 7fh mov [byte_3], A ; Yaxis signed -> ~unsigned mov A, 80h ; bit-swapped '01h request data' command push A ; store command mov X, 9 ; 9 bits, 8 data + 1 stop-bit mov A, ffh rrc ; set carry bit = stop bit n64_writeloop: mov A, 00h ; 4c iowr Port1_Data ; 5c - low for 1us pop A ; 4c - retrieve command nop ; 4c iowr Port1_Data ; 5c - data for 2us rrc ; 4c - next command bit push A ; 5c - store command nop ; 4c nop ; 4c nop ; 4c mov A, 01h ; 4c iowr Port1_Data ; 5c - high for >1us dec X ; 4c jnz n64_writeloop ; 5c - if not done, next bit pop A ; 4c - clear crap from the stack mov X, 8 ; 4c jmp n64_readbyte1_in ; 5c n64_readbyte1: pop A ; 4c push A ; 5c ; move entry point later (= less delay) to see it jitter is better... worked! ;n64_readbyte1_in: nop ; 4c n64_readbyte1_in: nop ; 4c iord Port1_Data ; 5c rrc ; 4c pop A ; 4c rrc ; 4c push A ; 5c dec X ; 4c jnz n64_readbyte1 ; 5c mov X,8 ; 4c xor [X+(byte_0-8)], A ; 8c jmp n64_readbyte2_in ; 5c n64_readbyte2: nop ; 4c nop ; 4c pop A ; 4c push A ; 5c n64_readbyte2_in: iord Port1_Data ; 5c rrc ; 4c pop A ; 4c rrc ; 4c push A ; 5c dec X ; 4c jnz n64_readbyte2 ; 5c mov X,8 ; 4c xor [X+(byte_1-8)], A ; 8c jmp n64_readbyte3_in ; 5c n64_readbyte3: nop ; 4c nop ; 4c pop A ; 4c push A ; 5c n64_readbyte3_in: iord Port1_Data ; 5c rrc ; 4c pop A ; 4c rlc ; 4c push A ; 5c dec X ; 4c jnz n64_readbyte3 ; 5c mov X,8 ; 4c xor [X+(byte_2-8)], A ; 8c jmp n64_readbyte4_in ; 5c n64_readbyte4: nop ; 4c nop ; 4c pop A ; 4c push A ; 5c n64_readbyte4_in: iord Port1_Data ; 5c rrc ; 4c pop A ; 4c rlc ; 4c push A ; 5c dec X ; 4c jnz n64_readbyte4 ; 5c xor [byte_3], A ; 8c ; juggle buttons to put them in a similar order to the psx mov A, [byte_0] ; change from u,d,l,r to u,r,d,l push A mov A, 1fh and [byte_0], A pop A push A rlc and A, c0h or [byte_0], A pop A push A rrc rrc and A, 20h or [byte_0], A pop A ; copy A and B buttons to L2, R and A, 03h or [byte_1], A mov A, [byte_1] ; change from cu,cd,cl,cr to cu,cr,cd,cl push A mov A, 1fh and [byte_1], A pop A push A rlc and A, c0h or [byte_1], A pop A rrc rrc and A, 20h or [byte_1], A mov A, [byte_2] ; copy X and Y axes mov [byte_4], A mov A, [byte_3] mov [byte_5], A jmp got_new_data ; ***************************************************************************** ; Get data from PSX controller ; code presently assumes analogue controller in RED mode psx_read: mov A, 0Dh iowr Port1_Data ; ATT low ("listen up") mov A, 0fh ; c0h would be about the same as the psx attn_delay: dec A jnz attn_delay ; ensure attn low long enough before command mov A, 01h call psx_byte ; 01 start command mov A, 42h call psx_byte ; 02 request data, returns controller type mov A, FFh call psx_byte ; 03 will return 5A, 'here comes the data' mov A, FFh ; MSB ............................. LSB call psx_byte ; 04 LEFT DOWN RGHT UP STRT JOYR JOYL SLCT cpl A mov [byte_0], A mov A, FFh call psx_byte ; 05 [] X O /\ R1 L1 R2 L2 cpl A mov [byte_1],A mov A, FFh call psx_byte ; 06 RHSJoy 00h (L) to FFh(R) mov [byte_4], A mov A, FFh call psx_byte ; 07 RHSJoy 00h (U) to FFh(D) mov [byte_5], A mov A, FFh call psx_byte ; 08 LHSJoy 00h (L) to FFh(R) mov [byte_2], A mov A, FFh call psx_byte ; 09 LHSJoy 00h (U) to FFh(D) mov [byte_3], A mov A, 0Fh iowr Port1_Data ; ATT high ("that's all for now") got_new_data: ; re-arrange data already stored in [byte_x] locations... ; so's to put 'most useful' buttons first in case windows app can't see all the buttons mov A, [byte_0] push A mov A, [byte_1] push A rrc rrc rrc rrc and A, 0fh mov [byte_0], A pop A rlc rlc rlc rlc and A, f0h or [byte_0], A pop A mov [byte_1], A ; Check if values have changed ; mov A, [byte_0_old] ; cmp A, [byte_0] ; jnz send_value ; mov A, [byte_1_old] ; cmp A, [byte_1] ; jnz send_value ; mov A, [byte_2_old] ; cmp A, [byte_2] ; jnz send_value ; mov A, [byte_3_old] ; cmp A, [byte_3] ; jnz send_value ; mov A, [byte_4_old] ; cmp A, [byte_4] ; jnz send_value ; mov A, [byte_5_old] ; cmp A, [byte_5] ; jnz send_value ; jmp skip_it send_value: iord USB_EP1_TX_Config and A,40h ; keep the Data 0/1 bit or A,96h ; enable transmit 6 bytes iowr USB_EP1_TX_Config ; Save transmitted values as old values mov A, [byte_0] mov [byte_0_old], A mov A, [byte_1] mov [byte_1_old], A mov A, [byte_2] mov [byte_2_old], A mov A, [byte_3] mov [byte_3_old], A mov A, [byte_4] mov [byte_4_old], A mov A, [byte_5] mov [byte_5_old], A skip_it: mov A,[interrupt_mask] or A, 10h ; make sure endpoint 1 is enabled ipret Global_Interrupt ; enable interrupts and return ; Byte read subroutine ; Send a command byte to PSX controller, and read reply byte ; Entry: A = command byte ; Exit: A = data byte ; nb PSX transmissions are 8bit, LSB first psx_byte: mov X,8 ; 8 bits psxb_loop: push A ; store command and A, 1 ; clock low iowr Port1_Data ; write on falling edge of clock or A, 4 ; clock high nop nop iowr Port1_Data iord Port0_Data ; sample on rising edge of clock rrc ; data into carry pop A ; retrieve command rrc ; data into MSB, next command dec X jnz psxb_loop ; if not done, next bit push A mov A, 0fh ; 50h would be about the same as the psx... interbyte_delay: dec A jnz interbyte_delay pop A ret ; return data in A ; ***************************************************************************** ;********************** Endpoint_1_ISR ************************** USB_EP1_ISR: push A ; save accumulator on stack iord USB_EP1_TX_Config xor A,40h ; flip data 0/1 bit iowr USB_EP1_TX_Config mov A, [interrupt_mask] ipret Global_Interrupt ; enable interrupts and return ;************************************************************************ ; reset processing ; The idea is to put the microcontroller in a known state. As this ; is the entry point for the "reserved" interrupt vector, we may not ; assume the processor has actually been reset and must write to all ; of the I/O ports. Reset: mov A, endpoint_0 ; move data stack pointer swap A, dsp ; so it does not write over USB FIFOs mov A, 0ffh ; load accumulator with ones iowr Port1_Isink0 ; maximum sink current Port1 bit 0 iowr Port1_Isink1 ; maximum sink current Port1 bit 1 iowr Port1_Isink2 ; maximum sink current Port1 bit 2 iowr Port1_Data ; output 1's to port 1 iowr Port0_Data ; disable ISINK on port 0 (input) iowr Port1_Pullup ; disable port 1 pullups (external ones used) mov A, 0h ; load accumulator with zeros iowr Port0_Pullup ; enable port 0 pullups iowr Port0_Interrupt ; disable port 0 interrupts iowr Port1_Interrupt ; disable port 1 interrupts iowr Port1_Isink3 ; minimum sink current Port1 bit 3 (not used) iowr Port0_Isink0 ; minimum sink current Port0 bit 0 iowr Port0_Isink1 ; minimum sink current Port0 bit 1 iowr Port0_Isink2 ; minimum sink current Port0 bit 2 iowr Port0_Isink3 ; minimum sink current Port0 bit 3 iowr Port0_Isink4 ; minimum sink current Port0 bit 4 iowr Port0_Isink5 ; minimum sink current Port0 bit 5 iowr Port0_Isink6 ; minimum sink current Port0 bit 6 iowr Port0_Isink7 ; minimum sink current Port0 bit 7 mov [byte_3],A ; clear remembered hat bits mov A, 80h ; default the analog channels mov [byte_0],A ; X axis mov [byte_1],A ; Y axis mov [byte_2],A ; Z axis (rotation) mov [byte_5],A ; byte_5 mov A,15 ; initialize read delay (in ms) mov [read_delay],A mov A, 0h mov [endpoint_stall], A mov [remote_wakeup_status], A mov [configuration_status], A mov [loop_temp], A mov [start_send], A mov [byte_0_old], A mov [byte_1_old], A mov [byte_2_old], A mov [byte_3_old], A mov [byte_4_old], A mov [byte_5_old], A iowr Watchdog ; clear watchdog timer mov A, 0fh iowr Port1_Interrupt ; enable port 1 interrupts ; ; test what kind of reset occurred ; iord Status_Control and A, USBReset ; test for USB Bus Reset jnz BusReset iord Status_Control and A, WatchDogReset ; test for Watch Dog Reset jz suspendReset ; ; Process a watchdog reset. Wait for a Bus Reset to bring the system ; alive again. mov A, TIMER_ONLY ; enable one msec timer interrupt mov [interrupt_mask],A iowr Global_Interrupt WatchdogHandler: ; wait for USB Bus Reset jmp WatchdogHandler suspendReset: mov A, 09h iowr Status_Control ; go back to suspend nop jmp suspendReset ; wait until real bus reset ; ; A bus reset has occurred ; BusReset: mov A, RunBit ; clear all reset bits iowr Status_Control ; setup for enumeration mov A, ENUMERATE_MASK mov [interrupt_mask],A iowr Global_Interrupt wait: ; wait until configured iord USB_EP1_TX_Config cmp A, 0 iowr Watchdog ; clear watchdog timer jz wait mov A, 0ffh ; initializes loop temp mov [loop_temp], A ; loop_temp is used to add a delay in the start of transmission of data ; The delay will start after reaching this point. This means that the ; transmission of data from endpoint 1 will not start right after enumeration ; is complete but is going to be delayed. Until the transmission begins ; the controller will Nak any IN packets to endpoint 1. If data exists ; the first IN packet to enpoint 1 that will be responded to with data ; from the controller is after 230msec from enumeration end. ; This was done to solve driver problems when the joystick was plugged in and ; then the power was recycled or when the joystick was plugged in before the host ; was turned on. The joystick driver could not handle the data right after ; enumeration. ;************************************************************************ ; This is the main loop that endlessly repeats the same sequence over ; and over. main: mov A, [loop_temp] cmp A, 0Ah jnc no_set ; do not enable TX yet mov A, 01h ; enable transmission mov [start_send], A ; after this loop_temp value doesn't matter no_set: iowr Watchdog ; clear watchdog timer nochange: jmp main ; loop continuously ;======================================================================== ; The endpoint zero interrupt service routine supports the control ; endpoint. This firmware enumerates and configures the hardware. USB_EP0_ISR: push A ; save accumulator on stack iord USB_EP0_RX_Status ; load status register into accumulator and A, 01h ; check if SETUP packet received jz ep0_continue ; ignore unless SETUP packet mov A,[interrupt_mask] ; disable endpoint zero interrupts and A, 0F7h mov [interrupt_mask], A iowr Global_Interrupt call StageOne ; parse SETUP packet mov A, [interrupt_mask] ; enable endpoint zero interrupts or A, 08h mov [interrupt_mask], A ep0_continue: mov A, [interrupt_mask] ; enable the interrupts ipret Global_Interrupt ;======================================================================== ; stage one ... test bmRequestType ;======================================================================== StageOne: ;------------------------------------------------------------------------ ; Parse standard device requests as per Table 9.2 in USB Spec. ;------------------------------------------------------------------------ mov A, 00h ; clear the setup flag to write DMA iowr USB_EP0_RX_Status mov A, 8 ; set BadOut bit iowr USB_Status_Control mov A, [bmRequestType] ; load bmRequestType ; host to device cmp A, 00h jz RequestType00 ; bmRequestType = 00000000 device ; cmp A, 01h *** not required *** ; jz RequestType01 ; bmRequestType = 00000001 interface cmp A, 02h jz RequestType02 ; bmRequestType = 00000010 endpoint cmp A, 80h ; device to host jz RequestType80 ; bmRequestType = 10000000 device cmp A, 81h jz RequestType81 ; bmRequestType = 10000001 interface cmp A, 82h jz RequestType82 ; bmRequestType = 10000010 endpoint ;----------------------------------------------------------------------- ; Parse HID class device requests as per HID version 1.0 Draft #4 ;----------------------------------------------------------------------- ; host to device cmp A, 21h jz RequestType21 ; bmRequestType = 00100001 interface cmp A, 22h ; *** not in HID spec *** jz RequestType22 ; bmRequestType = 00100010 endpoint ; device to host cmp A, A1h jz RequestTypeA1 ; bmRequestType = 10100001 interface ;----------------------------------------------------------------------- ; Stall unsupported functions ;----------------------------------------------------------------------- SendStall: ; stall unsupported functions mov A, A0h ; send a stall to indicate the requested iowr USB_EP0_TX_Config ; function is not supported ret ; return ;======================================================================== ; stage two ... test bRequest ;======================================================================== ; host to device with device as recipient RequestType00: mov A, [bRequest] ; load bRequest ;------------------------------------------------------------------------ ; The only standard feature defined for a "device" recipient is ; device_remote_wakeup. Remote wakeup is the ability to "wakeup" a ; system from power down mode by pressing a key or moving a button. ; The default condition at reset is remote wakeup disabled. ;------------------------------------------------------------------------ ; Clear Feature bRequest = 1 cmp A, clear_feature jz ClearRemoteWakeup ; Set Feature bRequest = 3 cmp A, set_feature jz SetRemoteWakeup ;------------------------------------------------------------------------ ; Set the device address to a non-zero value. ; Set Address bRequest = 5 cmp A, set_address jz SetAddress ;------------------------------------------------------------------------ ; This request is optional. If a device supports this request, existing ; device descriptors may be updated or new descriptors may be added. ; Set Descriptor bRequest = 7 *** not supported *** ;------------------------------------------------------------------------ ; If wValue is zero, the device is unconfigured. The only other legal ; configuration for this version of firmware is one. ; Set Configuration bRequest = 9 cmp A, set_configuration jz SetConfiguration jmp SendStall ; stall unsupported function calls ;======================================================================== ; host to device with interface as recipient *** not required *** ; RequestType01: ; mov A, [bRequest] ; load bRequest ;------------------------------------------------------------------------ ; There are no interface features defined in the spec. ; Clear Feature bRequest = 1 *** not supported *** ; Set Feature bRequest = 3 *** not supported *** ;------------------------------------------------------------------------ ; This request allows the host to select an alternate setting for the ; specified interface. As the joystick only has one interface setting, ; this request is not supported. ; Set Interface bRequest = 11 *** not supported *** ; jmp SendStall ; stall unsupported functions ;======================================================================== ; host to device with endpoint as recipient RequestType02: mov A, [bRequest] ; load bRequest ;------------------------------------------------------------------------ ; The only standard feature defined for an endpoint is endpoint_stalled. ; Clear Feature bRequest = 1 cmp A, clear_feature jz ClearEndpointStall ; Set Feature bRequest = 3 cmp A, set_feature jz SetEndpointStall jmp SendStall ; stall unsupported functions ;======================================================================= ; device to host with device as recipient RequestType80: mov A, [bRequest] ; load bRequest ; Get Status bRequest = 0 cmp A, get_status jz GetDeviceStatus ; Get Descriptor bRequest = 6 cmp A, get_descriptor jz GetDescriptor ; Get Configuration bRequest = 8 cmp A, get_configuration jz GetConfiguration jmp SendStall ; stall unsuported functions ;======================================================================= ; device to host with interface as recipient RequestType81: mov A, [bRequest] ; load bRequest ; Get Status bRequest = 0 cmp A, get_status jz GetInterfaceStatus ;------------------------------------------------------------------------ ; This request returns the selected alternate setting for the specified ; interface. There are no alternate settings for the joystick. ; Get Interface bRequest = 10 *** not supported *** ;------------------------------------------------------------------------ ; HID class defines one more request for bmRequestType=10000001 ; Get Descriptor bRequest = 6 cmp A, get_descriptor jz GetDescriptor jmp SendStall ; stall unsupported functions ;======================================================================= ; device to host with endpoint as recipient RequestType82: mov A, [bRequest] ; load bRequest ; Get Status bRequest = 0 cmp A, get_status jz GetEndpointStatus ;------------------------------------------------------------------------ ; Not defined in the spec, but it must be decoded for the enumeration to ; complete under Memphis. ; Get Descriptor bRequest = 6 cmp A, get_descriptor jz GetDescriptor ; Sync Frame bRequest = 12 *** not supported *** jmp SendStall ; stall unsupported functions ;======================================================================== ; Now parse HID class Descriptor Types ;======================================================================== ; host to device with endpoint as recipient RequestType21: mov A, [bRequest] ; load bRequest ; Set Report bRequest = 9 cmp A, set_report jz SetReport ; Set Idle bRequest = 10 cmp A, set_idle jz SetIdle ; Set Protocol bRequest = 11 cmp A, set_protocol jz SetProtocol jmp SendStall ; stall unsupported functions ;======================================================================= ; This one is not in the spec, but has been captured with CATC while ; Memphis beta testing. RequestType22: mov A, [bRequest] ; load bRequest ; Set Report bRequest = 9 cmp A, set_report jz SetReport jmp SendStall ; stall unsupported functions ;======================================================================= ; device to host with endpoint as recipient RequestTypeA1: mov A, [bRequest] ; load bRequest ; Get Report bRequest = 1 cmp A, get_report jz GetReport ; Get Idle bRequest = 2 cmp A, get_idle jz GetIdle ; Get Protocol bRequest = 3 cmp A, get_protocol jz GetProtocol jmp SendStall ; stall unsupported functions ;======================================================================== ; stage three ... process the request ;======================================================================== ; Remote wakeup is the ability to wakeup a system from power down mode ; when the user presses a key or moves a joystick. These routines ; allow the host to enable/disable the ability to request remote wakeup. ; ; Disable the remote wakeup capability. ClearRemoteWakeup: mov A, [wValue] ; load wValue cmp A, device_remote_wakeup ; test for valid feature jnz SendStall ; stall unsupported features call no_data_control ; handshake with host mov A, DISABLE_REMOTE_WAKEUP ; disable remote wakeup mov [remote_wakeup_status], A ret ; return ; Enable the remote wakeup capability. SetRemoteWakeup: mov A, [wValue] ; load wValue cmp A, device_remote_wakeup ; test for valid feature jnz SendStall ; stall unsupported features call no_data_control ; handshake with host mov A, ENABLE_REMOTE_WAKEUP ; enable remote wakeup mov [remote_wakeup_status], A ret ; return ; Set the device address to the wValue in the SETUP packet at ; the completion of the current transaction. SetAddress: call no_data_control ; handshake with host mov A, [wValue] ; load wValue iowr USB_Device_Address ; write new USB device address ret ; return ; Set the configuration of the device to either unconfigured (0) or ; configured (1) based on wValue in the SETUP packet. According to ; the USB spec (page 178), a Set Configuration also clears the endpoint ; stall condition and re-initializes endpoints using data 0/1 toggle to ; Data0. SetConfiguration: call no_data_control mov A, [wValue] ; load wValue lsb mov [configuration_status], A ; store configuration byte mov A, 0 mov [endpoint_stall], A ; not stalled iord USB_EP1_TX_Config ; clear data 0/1 bit and A, ~DataToggle iowr USB_EP1_TX_Config mov A, [configuration_status] cmp A, 0 jnz device_configured ; device is unconfigured iord USB_EP1_TX_Config and A, EFh ; disable endpoint 1 iowr USB_EP1_TX_Config mov A, [interrupt_mask] ; disable endpoint one interrupts and A, EFh mov [interrupt_mask], A jmp done_configuration ; device is configured device_configured: iord USB_EP1_TX_Config ; NAK IN packets until data is and A,7Fh ; ready on endpoint one or A, 10h ; enable endpoint one iowr USB_EP1_TX_Config mov A, [interrupt_mask] ; enable endpoint one and GPIO interrupts or A, 50h mov [interrupt_mask], A iord USB_Status_Control ; NAK IN packets until data is and A,0EFh ; ready on endpoint one iowr USB_Status_Control done_configuration: ret ; return ; Clear the endpoint stall feature for the selected endpoint. This ; should also set the data 0/1 bit to Data0 if endpoint one is selected. ClearEndpointStall: mov A, [wValue] ; load wValue (which feature) cmp A, endpoint_stalled ; test for valid feature jnz SendStall ; stall unsupported features ; ; clear endpoint one stall feature ; call no_data_control ; handshake with host mov A,0 mov [endpoint_stall], A ; not stalled iord USB_EP1_TX_Config ; clear data 0/1 bit and A, ~DataToggle iowr USB_EP1_TX_Config iord USB_Status_Control ; NAK IN packets until data is and A,0EFh ; ready on endpoint one iowr USB_Status_Control ret ; return ; Set the endpoint stall feature for the selected endpoint. SetEndpointStall: mov A, [wValue] ; load wValue cmp A, endpoint_stalled ; test for valid feature jnz SendStall ; stall unsupported features call no_data_control ; handshake with host mov A,1 mov [endpoint_stall], A ; stalled mov A, 30h ; stall endpoint one iowr USB_EP1_TX_Config ret ; return ; The device status is a 16-bit value (two bytes) with only D[1:0] ; defined. D0=0 specifies bus-powered, which never changes. D1 ; reflects the status of the device_remote_wakeup feature. This ; feature can either be disabled (D1=0) or enabled (D1=1). GetDeviceStatus: mov A, 2 ; send two bytes mov [data_count], A mov A, (get_dev_status_table - control_read_table) add A, [remote_wakeup_status] ; get correct remote wakeup jmp execute ; send device status to host ; There are five descriptor types. The descriptor type will be in ; the high byte of wValue. The descriptor index will be in the low ; byte of wValue. The standard request to a device supports three ; of these types: device, configuration, and string. The standard ; request does not support interface or endpoint descriptor types. GetDescriptor: mov A, [wValueHi] ; load descriptor type ;------------------------------------------------------------------------ ; Test for standard descriptor types first. ; Get Descriptor (device) wValueHi = 1 cmp A, device jz GetDeviceDescriptor ; Get Descriptor (configuration) wValueHi = 2 cmp A, configuration jz GetConfigurationDescriptor ; Get Descriptor (string) wValueHi = 3 ; No strings in the joystick code, yet. ;------------------------------------------------------------------------ ; Then test for HID class descriptor types. ; Get Descriptor (HID) wValueHi = 21h cmp A, HID jz GetHIDDescriptor ; Get Descriptor (report) wValueHi = 22h cmp A, report jz GetReportDescriptor ; Get Descriptor (physical) wValueHi = 23h *** not supported *** jmp SendStall ; stall unsupported functions ; Return the current device configuration to the host. The possible ; values are zero (unconfigured) and one (configured). GetConfiguration: mov A, 1 ; send one byte mov [data_count], A mov A, (get_configuration_status_table - control_read_table) add A, [configuration_status] ; get correct configuration jmp execute ; send configuration to host ; The interface status is a 16-bit value (two bytes) that is always ; zero for both bytes. GetInterfaceStatus: mov A, 2 ; send two bytes mov [data_count], A mov A, (get_interface_status_table - control_read_table) jmp execute ; send interface status to host ; The endpoint status is a 16-bit value (two bytes) with only one ; bit (D0) defined. If D0=0, then the selected endpoint is not ; stalled. If D0=1, then the selected endpoint is stalled. GetEndpointStatus: mov A, 2 ; send two bytes mov [data_count], A mov A, [endpoint_stall] asl A ; select the correct entry add A, (get_endpoint_status_table - control_read_table) jmp execute ; send endpoint status to host ;------------------------------------------------------------------------ ; Set Report SetReport: jmp SendStall ; *** not supported *** ; Set Idle silences a particular report on the interrupt pipe until a new ; event occurs or the specified amount of time (wValue) passes. SetIdle: jmp SendStall ; *** not supported *** ; Set Protocol switches between the boot protocol and the report protocol. ; For boot protocol, wValue=0. For report protocol, wValue=1. ; Note, the joystick firmware does not actually do anything with the ; protocol status, yet. SetProtocol: mov A, [wValue] ; load wValue mov [protocol_status], A ; write new protocol value call no_data_control ; handshake with host ret ; return ; Get Report allows the host to receive a report via the control pipe. ; The report type is specified in the wValue high byte while the low ; byte has a report ID. GetReport: jmp SendStall ; currently not supported GetReportDescriptor: mov A, (end_hid_report_desc_table - hid_report_desc_table) mov [data_count], A ; save descriptor length mov A, (hid_report_desc_table - control_read_table) call execute ; send descriptor to host ; ; Enumeration is complete! ; ret ; return ; Get Idle reads the current idle rate for a particular input report. GetIdle: jmp SendStall ; *** not supported *** ; Get Protocol sends the current protocol status back to the host. GetProtocol: mov A, 1 ; send one byte mov [data_count], A mov A, (get_protocol_status_table - control_read_table) add A, [protocol_status] ; get correct configuration jmp execute ; send protocol to host ;======================================================================== ; Standard Get Descriptor routines ; ; Return the device descriptor to the host. GetDeviceDescriptor: mov A, 0 ; load the device descriptor length index device_desc_table mov [data_count], A ; save the device descriptor length mov A, (device_desc_table - control_read_table) jmp execute ; send the device descriptor ; Return the configuration, interface, and endpoint descriptors. GetConfigurationDescriptor: mov A, (end_config_desc_table - config_desc_table) mov [data_count], A ; save the descriptor length mov A, (config_desc_table - control_read_table) execute: ; send the descriptors mov [data_start], A ; save start index call get_descriptor_length ; correct the descriptor length call control_read ; perform control read function ret ; return ;------------------------------------------------------------------------ ; HID class Get Descriptor routines ; ; Return the HID descriptor and enable endpoint one. GetHIDDescriptor: mov A, (Endpoint_Descriptor - Class_Descriptor) mov [data_count], A ; save descriptor length mov A, ( Class_Descriptor - control_read_table) call execute ; send descriptor to host ret ; return ;**********USB library main routines******************* ;****************************************************** ; The host sometimes lies about the number of bytes it ; wants from a descriptor. Any request to get descriptor ; should return the lesser of the number of bytes requested ; or the actual length of the descriptor. get_descriptor_length: mov A, [wLengthHi] ; load requested transfer length cmp A, 0 ; confirm high byte is zero jnz use_actual_length ; no requests should be longer than 256b mov A, [wLength] ; test low byte against zero cmp A, 0 jz use_actual_length ; must request some data cmp A, [data_count] ; compare to the amount of data jnc use_actual_length mov [data_count], A ; use requested length use_actual_length: ret ; return ;======================================================================== ; function: no_data_control ; purpose: performs the no-data control operation ; as defined by the USB specifications no_data_control: mov A, C0h ; set up the transfer iowr USB_EP0_TX_Config ; register for data1 ; and 0 byte transfer mov A, [interrupt_mask] ; enable interrupts iowr Global_Interrupt wait_nodata_sent: iord USB_EP0_TX_Config ; wait for the data to be and A, 80h ; transferred jnz wait_nodata_sent ret ; return to caller ;======================================================================== ;****************************************************** ; ; function: Control_read ; Purpose: Performs the control read operation ; as defined by the USB specification ; SETUP-IN-IN-IN...OUT ; ; data_start: must be set to the descriptors info ; as an offset from the beginning of the ; control read table ; data count holds the ; data_count: must be set to the size of the ; descriptor ;****************************************************** control_read: push X ; save X on stack mov A, 00h ; clear data 0/1 bit mov [endp0_data_toggle], A control_read_data_stage: mov X, 00h mov A, 00h mov [loop_counter], A iowr USB_EP0_RX_Status ; clear setup bit ; Fixing a bug seen by NEC hosts iord USB_EP0_RX_Status ; check setup bit and A, 01h ; if not cleared, another setup jnz control_read_status_stage ; has arrived. Exit ISR mov A, 08h ; set BADOUTS BIT iowr USB_Status_Control mov A, [data_count] cmp A, 00h jz control_read_status_stage dma_load_loop: ; loop to load data into the data buffer mov A, [data_start] index control_read_table mov [X + endpoint_0], A ; load dma buffer inc [data_start] inc X inc [loop_counter] dec [data_count] ; exit if descriptor jz dma_load_done ; is done mov A, [loop_counter] ; or 8 bytes sent cmp A, 08h jnz dma_load_loop dma_load_done: iord USB_EP0_RX_Status ; check setup bit and A, 01h ; if not cleared, another setup jnz control_read_status_stage ; has arrived. Exit ISR mov A, [endp0_data_toggle] xor A, 40h mov [endp0_data_toggle], A or A, 80h or A, [loop_counter] iowr USB_EP0_TX_Config mov A, [interrupt_mask] iowr Global_Interrupt wait_control_read: iord USB_EP0_TX_Config ; wait for the data to be and A, 80h ; transfered jz control_read_data_stage iord USB_EP0_RX_Status and A, 02h ; check if out was sent by host jz wait_control_read control_read_status_stage: ; OUT at end of data transfer pop X ; restore X from stack mov A, [interrupt_mask] iowr Global_Interrupt ret ;********** ROM lookup tables ************************************* XPAGEOFF control_read_table: device_desc_table: db 12h ; Descriptor length (18 bytes) db 01h ; Descriptor type (Device) db 00h,01h ; Complies to USB Spec. Release (1.00) db 00h ; Class code (0) db 00h ; Subclass code (0) db 00h ; Protocol (No specific protocol) db 08h ; Max. packet size for EP0 (8 bytes) db 66h,66h ; Vendor ID (Me... this address is not being used) db 67h,06h ; Product ID (Simon Nield WickedStick) db 88h,02h ; Device release number (2.88) db 00h ; Mfr string descriptor index (None) db 00h ; Product string descriptor index (None) db 00h ; Serial Number string descriptor index (None) db 01h ; Number of possible configurations (1) end_device_desc_table: config_desc_table: db 09h ; Descriptor length (9 bytes) db 02h ; Descriptor type (Configuration) db 22h,00h ; Total data length (34 bytes) db 01h ; Interface supported (1) db 01h ; Configuration value (1) db 00h ; Index of string descriptor (None) db 80h ; Configuration (Bus powered) db 32h ; Maximum power consumption (100mA) Interface_Descriptor: db 09h ; Descriptor length (9 bytes) db 04h ; Descriptor type (Interface) db 00h ; Number of interface (0) db 00h ; Alternate setting (0) db 01h ; Number of interface endpoint (1) db 03h ; Class code () db 00h ; Subclass code () db 00h ; Protocol code () db 00h ; Index of string() Class_Descriptor: db 09h ; Descriptor length (9 bytes) db 21h ; Descriptor type (HID) db 00h,01h ; HID class release number (1.00) db 00h ; Localized country code (None) db 01h ; # of HID class dscrptr to follow (1) db 22h ; Report descriptor type (HID) ; Total length of report descriptor db (end_hid_report_desc_table - hid_report_desc_table),00h Endpoint_Descriptor: db 07h ; Descriptor length (7 bytes) db 05h ; Descriptor type (Endpoint) db 81h ; Encoded address (Respond to IN, 1 endpoint) db 03h ; Endpoint attribute (Interrupt transfer) db 06h,00h ; Maximum packet size (6 bytes) db 0Ah ; Polling interval (10 ms) end_config_desc_table: hid_report_desc_table: db 5h, 1h ; USAGE_PAGE (Generic Desktop) db 9h, 4h ; USAGE (Joystick) db a1h, 1h ; COLLECTION (Application) db 9h, 1h ; USAGE (Pointer) db a1h, 0h ; COLLECTION (Physical) db 5h, 9h ; USAGE_PAGE (Button) db 19h, 1h ; USAGE_MINIMUM (Button 1) db 29h, 10h ; USAGE_MAXIMUM (Button 16) db 15h, 0h ; LOGICAL_MINIMUM (0) db 25h, 1h ; LOGICAL_MAXIMUM (1) db 35h, 0h ; PHYSICAL_MINIMUM (0) db 45h, 1h ; PHYSICAL_MAXIMUM (1) db 75h, 1h ; REPORT_SIZE (1) db 95h, 10h ; REPORT_COUNT (16) db 81h, 2h ; INPUT (Data,Var,Abs) db 5h, 1h ; USAGE_PAGE (Generic Desktop) db 9h, 30h ; USAGE (X) db 9h, 31h ; USAGE (Y) db 15h, 0h ; LOGICAL_MINIMUM (0) db 26h, ffh, 0h ; LOGICAL_MAXIMUM (255) db 35h, 0h ; PHYSICAL_MINIMUM (0) db 46h, ffh, 0h ; PHYSICAL_MAXIMUM (255) db 66h, 00h, 00h; Unit (None (2 bytes)) db 75h, 8h ; REPORT_SIZE (8) db 95h, 2h ; REPORT_COUNT (2) db 81h, 2h ; INPUT (Data,Var,Abs) db 5h, 1h ; USAGE_PAGE (Generic Desktop) db 9h, 32h ; USAGE (RZ) db 9h, 35h ; USAGE (Slider) db 15h, 0h ; LOGICAL_MINIMUM (0) db 26h, ffh, 0h ; LOGICAL_MAXIMUM (255) db 35h, 0h ; PHYSICAL_MINIMUM (0) db 46h, ffh, 0h ; PHYSICAL_MAXIMUM (255) db 66h, 00h, 00h; Unit (None (2 bytes)) db 75h, 8h ; REPORT_SIZE (8) db 95h, 2h ; REPORT_COUNT (2) db 81h, 2h ; INPUT (Data,Var,Abs) db c0h ; END_COLLECTION db c0h ; END_COLLECTION end_hid_report_desc_table: ;======================================================================== ; These tables are the mechanism used to return status information to the ; host. The status can be either device, interface, or endpoint. get_dev_status_table: db 00h, 00h ; remote wakeup disabled, bus powered db 02h, 00h ; remote wakeup enabled, bus powered get_interface_status_table: db 00h, 00h ; always return both bytes zero get_endpoint_status_table: db 00h, 00h ; not stalled db 01h, 00h ; stalled get_configuration_status_table: db 00h ; not configured db 01h ; configured get_protocol_status_table: db 00h ; boot protocol db 01h ; report protocol ; look up table converts from 4 individual buttons to an 8bit direction dpad_lut: db ffh ; 0000 -not possible db ffh ; 0001 -not possible db ffh ; 0010 -not possible db f6h ; 0011 down-left db ffh ; 0100 -not possible db ffh ; 0101 -not possible db f8h ; 0110 up-left db f7h ; 0111 left db ffh ; 1000 -not possible db f4h ; 1001 down-right db ffh ; 1010 -not possible db f5h ; 1011 down db f2h ; 1100 up-right db f3h ; 1101 right db f1h ; 1110 up db f0h ; 1111 centered end_dpad_lut: