Click here to see where it gets the Data
;Changes:

;V0.1: 10/1/02
;Uses the usbhidio.asm from USB Complete by Jan Axelson
; In Germany published by MITP


;======================================================================
;assembler directives (equates)
;======================================================================

;----------------------------------------------------------------------
;I/O registers
;----------------------------------------------------------------------

;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_intMask:	  equ 40h ; Mask for Port 0 GPIO interrupts.
128us_intMask:	equ 02h ; Mask to enable 128us only.


;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

;----------------------------------------------------------------------
;Register bit values
;----------------------------------------------------------------------

;CPU Status and Control (Status_Control)
RunBit:                 equ     1h     ; CPU Run bit
USBReset:               equ    20h     ; USB Bus Reset bit
WatchDogReset:          equ    40h     ; Watchdog Reset bit

; USB EP1 transmit configuration (USB_EP1_TX_Config)
DataToggle:               equ     40h     ; Data 0/1 bit

DISABLE_REMOTE_WAKEUP:  equ   0         ; bit[1] = 0
ENABLE_REMOTE_WAKEUP:   equ   2         ; bit[1] = 1

;----------------------------------------------------------------------
;Interrupt masks
;----------------------------------------------------------------------

;The timer-only mask enables the 1-millisecond timer interrupt.
TIMER_ONLY:               equ      4h

;The enumerate mask enables the following interrupts:
;1-millisecond timer, USB Endpoint 0
ENUMERATE_MASK:          equ     0Ch

;The runtime mask enables the following interrupts:
;1-millisecond timer, USB Endpoint 0, USB Endpoint 1, GPIO
RUNTIME_MASK:          equ     5Ch

;----------------------------------------------------------------------
; USB Constants
; from the USB Spec v1.1
;----------------------------------------------------------------------

;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

;----------------------------------------------------------------------
;HID-class descriptors
;from HID Class Definition v1.1 Draft
;----------------------------------------------------------------------

;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 buffer bytes
;----------------------------------------------------------------------

;Control Endpoint 0 buffer
Endpoint_0:             equ  70h        ; control endpoint
Endpoint0_Byte0:        equ  70h        ; Endpoint 0, byte 0
Endpoint0_Byte1:        equ  71h        ; Endpoint 0 byte 1
Endpoint0_Byte2:        equ  72h        ; Endpoint 0 byte 2
Endpoint0_Byte3:        equ  73h        ; Endpoint 0 byte 3
Endpoint0_Byte4:        equ  74h        ; Endpoint 0 byte 4
Endpoint0_Byte5:        equ  75h        ; Endpoint 0 byte 5
Endpoint0_Byte6:        equ  76h        ; Endpoint 0 byte 6
Endpoint0_Byte7:        equ  77h        ; Endpoint 0 byte 7


;Endpoint 0 SETUP packet bytes
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

;Endpoint 1 buffer
endpoint_1:             equ  78h
Endpoint1_Byte0:        equ  78h        ; Endpoint 1, byte 0
Endpoint1_Byte1:        equ  79h        ; Endpoint 1 byte 1
Endpoint1_Byte2:        equ  7Ah        ; Endpoint 1 byte 2
Endpoint1_Byte3:        equ  7Bh        ; Endpoint 1 byte 3
Endpoint1_Byte4:        equ  7Ch        ; Endpoint 1 byte 4
Endpoint1_Byte5:        equ  7Dh        ; Endpoint 1 byte 5
Endpoint1_Byte6:        equ  7Eh        ; Endpoint 1 byte 6
Endpoint1_Byte7:        equ  7Fh        ; Endpoint 1 byte 7

;----------------------------------------------------------------------
; Variables stored in data memory
;----------------------------------------------------------------------
;USB status
remote_wakeup_status:   equ  30h          ;0=disabled, 2-enabled
configuration_status:   equ  31h          ;0=unconfigured, 1=configured
;idle_status:           equ  33h          ;support SetIdle and GetIdle
protocol_status:        equ  34h          ;0=boot protocol, 1=report protocol

;Other variables:
suspend_counter:        equ  35h          ;number of idle bus milliseconds 
loop_temp:              equ  37h          ;temporary loop variable
start_send:             equ  32h          ;0=false, 1=true

;Received data:
Data_Byte0:               equ  38h
Data_Byte1:               equ  39h
Data_Byte2:               equ  3Ah
Data_Byte3:               equ  3Bh
Data_Byte4:               equ  3Ch
Data_Byte5:               equ  3Dh
Data_Byte6:               equ  3Eh
Data_Byte7:               equ  3Fh
msCounter:	         equ  40h
Data_Temp0:	         equ  41h
Data_Temp1:              equ  42h
Data_Temp2:              equ  43h
Data_Temp3:              equ  44h
Data_Temp4:              equ  45h
Data_Temp5:              equ  46h
Data_Temp6:              equ  47h
Data_Temp7:              equ  48h

temp:                   equ  25h
start_time:             equ  21h
testbit:                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 vectors
;======================================================================

org  00h                ; Reset vector; begin here after a reset.
jmp  Reset

org  02h                ; 128-microsecond interrupt
jmp  Serial_ISR

org  04h                ; 1024-millisecond 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  GPIO_ISR           ; not used

org  0Eh                ; Wakeup_ISR or resume interrupt 
jmp  DoNothing_ISR      ; not used

ORG  10h

;======================================================================
;Interrupt routines
;======================================================================

;----------------------------------------------------------------------
; 128-microsecond interrupt, Cext
; Unused. If this interrupt occurs, just push the accumulator (because
; ipret pops it) and re-enable the interrupts.
;----------------------------------------------------------------------
Serial_ISR:
 push A
  dec [msCounter]
   mov A,[msCounter]
   cmp A,0
   jnz weiter_128
   mov [interrupt_mask],A

weiter_128:
  mov A,[interrupt_mask]
  ipret Global_Interrupt
  

; include "serial.asm"
GPIO_ISR:
	push	A	; save the accumulator to stack
	push	X	; save X on stack
	pop	x			              ; Restore the index register.
;mov	A, 128us_intMask	  ; Load the 128us interrupt mask.
mov A,0
	ipret	Global_Interrupt	; Return to caller.
					                ; 128us interrupt enabled.

DoNothing_ISR:
     push A
     ;Enable interrupts and return
     mov A,[interrupt_mask]
     ipret Global_Interrupt

;----------------------------------------------------------------------
; 1-millisecond interrupt
; Check to see if the chip is in suspend mode and take appropriate action.
; Copy values to Endpoint 1's buffer for sending.
;----------------------------------------------------------------------

One_mSec_ISR:
     push A
iowr Watchdog
;Find out if enumeration is complete.
;If enumerating is in progress, loop_temp = 0.
     mov A, [loop_temp]
     cmp A, 0h
;If enumeration is still in progress, jump.
     jz not_main
;Enumeration has ended, so decrement the loop counter
;(so it no longer = 0).
     dec [loop_temp]

not_main:                         
;Check for bus activity.
     iord USB_Status_Control
     and A, 01h
     cmp A,0h
;If no bus activity, increment the suspend counter.
     jz Inc_counter
;If bus activity detected, clear the bus-activity bit,
     iord USB_Status_Control
     and A, 0FEh
     iowr USB_Status_Control
;and clear the suspend counter.
     mov A, 0h
     mov [suspend_counter], A
     jmp Suspend_end

Inc_counter:
;Keep track of the amount of time with no bus activity.
     inc [suspend_counter]
;Get the number of milliseconds the bus has been idle.
     mov A, [suspend_counter]
;Has it been 3 milliseconds?
     cmp A, 03h
;If no, there's nothing else to do.
     jnz Suspend_end
;If yes, put the chip in Suspend mode.
;Clear the Suspend counter.
     mov A, 0h
     mov [suspend_counter], A
;Enable pullups on Port 1; disable the output DAC.
     mov A, 0h
     iowr Port1_Pullup
     mov A, 0ffh
     iowr Port1_Data
;Set the Suspend bit. 
     iord Status_Control
     or A, 08h
     iowr Status_Control
;The chip is now in Suspend mode. 
;On exiting Suspend mode, the chip will begin 
;executing instructions here:
     nop     
;Disable pullups on Port 1. Enable the output DAC.
     mov A, 0ffh
     iowr Port1_Pullup
     mov A, 0h
     iowr Port1_Data

Suspend_end:
;Is endpoint 1 enabled?
     iord USB_EP1_TX_Config
     cmp A,0
;If no, do nothing.
     jz Select
;If yes, is start_send = 1?
;(Start_send adds a short delay after enumeration.)
     mov A, [start_send]
     cmp A, 01h
;If no, do nothing
     jnz Select
;If yes, send data:
     jmp send_value

send_value:
;Copies values from RAM into Endpoint 1's buffer
;and enables sending the bytes on the next poll.

;disable Endpoint 1 interrupts
     mov A,[interrupt_mask]
     and A, EFh
     mov [interrupt_mask],A
     iowr Global_Interrupt

;Copy values from RAM to Endpoint 1's buffer for transmitting to the host.
;Two bytes:
     mov A, [Data_Byte0]
     mov [Endpoint1_Byte0], A
     mov A, [Data_Byte1]
     mov [Endpoint1_Byte1], A
;Add more bytes if the report format specifies it:
;    mov A, [Data_Byte2]
;    mov [Endpoint1_Byte2], A
;    mov A, [Data_Byte3]
;    mov [Endpoint1_Byte3], A
;    mov A, [Data_Byte4]
;    mov [Endpoint1_Byte4], A
;    mov A, [Data_Byte5]
;    mov [Endpoint1_Byte5], A
;    mov A, [Data_Byte6]
;    mov [Endpoint1_Byte6], A
;    mov A, [Data_Byte7]
;    mov [Endpoint1_Byte7], A

;Other things to try:
;Set the value at Port 0 to equal byte 0 in Endpoint 1's buffer:
;     iord Port0_Data
;     mov [Endpoint1_Byte0], A

;Or set a value here and copy to Endpoint 1's buffer, byte 1:
;     mov A, A5h
;      mov [Endpoint1_Byte1], A

;Configure Endpoint 1's transmit register 
;so that the bytes will transmit on the next poll.
     iord USB_EP1_TX_Config
;Don't change the Data 0/1 bit.
     and A,40h
;Set bits 4 and 7 to 1 enable transmitting.
;The low nibble is the number of data bytes (2).
     or A,92h
     iowr USB_EP1_TX_Config

Select:
;Enable Endpoint 1 interrupts.
     mov A,[interrupt_mask]
     or A, 10h
     mov [interrupt_mask],A
     ipret Global_Interrupt

;----------------------------------------------------------------------
;Endpoint 1 ISR
;Endpoint 1 can do IN (device to host) transfers only.
;This interrupt triggers when the host acknowledges
;receiving data from endpoint 1.
;The ISR toggles the data 0/1 bit for the next transaction and
;sets the EnableRespondToIN bit so the chip will respond to the 
;next poll of the endpoint.
;----------------------------------------------------------------------

USB_EP1_ISR:
     push A
;Toggle the data 0/1 bit so it's correct for the next transaction.
     iord USB_EP1_TX_Config  
     xor A,40h
;The interrupt clears the EnableRespondToIN bit (bit 7) in the TX Config.
;Set this bit to 1 so data will go out on the next poll.
     or A, 92h
     iowr USB_EP1_TX_Config
;Enable interrupts and return.
     mov A, [interrupt_mask]
     ipret Global_Interrupt

;----------------------------------------------------------------------
; Reset processing
; Triggers on Reset or "reserved" interrupt.
;To be safe, initialize everything.
;----------------------------------------------------------------------

Reset:
;Place the data stack pointer at the lowest address of Endpoint 0's buffer.
;This keeps the stack from writing over the USB buffers.
;The USB buffers are in high RAM;
;the data stack pointer pre-decrements on a Push instruction.

     mov A, Endpoint_0
     swap A, dsp

;Initialize to FFh
     mov A, 0ffh
     iowr Port0_Data                 ; output ones to port 0
     iowr Port1_Pullup               ; disable port 1 pullups
                                     ; select rising edge interrupts
     iowr Port1_Isink0               ; maximum isink current Port1 bit 0
     iowr Port1_Isink1               ; maximum isink current Port1 bit 1
     iowr Port1_Isink2               ; maximum isink current Port1 bit 2
     iowr Port1_Isink3               ; maximum isink current Port1 bit 3

;Initialize to 00h
     mov A, 0h
     iowr Port1_Data                 ; output zeros to port 1
     iowr Port0_Interrupt            ; disable port 0 interrupts
     iowr Port0_Pullup               ; enable port 0 pullups
     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 [Endpoint1_Byte0],A
     mov [Endpoint1_Byte1],A
     mov [Endpoint1_Byte2],A
     mov [endpoint_stall], A
     mov [remote_wakeup_status], A
     mov [configuration_status], A
     mov [loop_temp], A
     mov [start_send], A
     iowr Watchdog                   ; clear watchdog timer
; clear readport_flag
    mov A,0
    mov [Data_Byte7],A

;initialize values to transmit at Endpoint 1.
     mov A, A5h
     mov [Data_Byte0], A
     mov A, F0h
     mov [Data_Byte1], A

;Enable Port 1, bit 0 interrupts.
;     mov A, 01h
;     iowr Port1_Interrupt
;
;Test what kind of reset occurred: bus or watchdog?
     iord Status_Control
;Was it a bus reset?
     and A, USBReset
;If yes, jump to handle it.
     jnz BusReset
     iord Status_Control
;Was it a watchdog reset?
     and A, WatchDogReset
;If no, continue to wait for a bus reset
     jz suspendReset
;
;Watchog reset:
;A watchdog reset means that the watchdog timer
;wasn't cleared for 8.192 milliseconds.
;Wait for a bus reset to bring the system alive again.
;Enable 1-millisecond interrupt only
     mov A, TIMER_ONLY
     mov [interrupt_mask],A
     iowr Global_Interrupt
;Wait for a bus reset.
WatchdogHandler:
     jmp WatchdogHandler

suspendReset:
;Return to suspend mode to wait for a USB bus reset.
     mov A, 09h
     iowr Status_Control
     nop
     jmp suspendReset

BusReset:
;Clear all reset bits.
;Set bit 0 (the run bit).
     mov A, RunBit
     iowr Status_Control
;Set up for enumeration (Endpoint 0 and 1-millisecond interrupts enabled)
     mov A, ENUMERATE_MASK
     mov [interrupt_mask],A
     iowr Global_Interrupt

wait:
;Wait until configured.
     iord USB_EP1_TX_Config
     cmp A, 0
;Clear the watchdog timer
     iowr Watchdog
;If not configured, continue to wait.
     jz wait     
;When configured, initialize loop_temp.
;Loop_temp adds a delay in the start of transmission of data.
;The chip will respond to the first IN packet no sooner than 
;230 milliseconds after enumeration is complete.
;The delay was included in Cypress' joystick code to prevents problems 
;that occurred when power cycled off and on or the joystick was plugged
;in before the host powered up.
;I've left it in because it does no harm and 
;other hardware might have similar behavior.
;During the delay, the chip will send a NAK in response to any IN packet.
     mov A, 0ffh
     mov [loop_temp], A

;Enable endpoint 1
     iord USB_EP1_TX_Config
     or A, 92h
     iowr USB_EP1_TX_Config

;======================================================================
; The main program loop.
;======================================================================

main:
;Find out if the loop_temp delay has timed out.
;Loop_temp =0 if not timed out, FFh if timed out.
     mov A, [loop_temp]
     cmp A, 0Ah
;If no, don't enable transmitting.
     jnc no_set
;If yes, enable transmitting.
     mov A, 01h
     mov [start_send], A
no_set:
;Clear the watchdog timer.
;This has to be done at least once every 8 milliseconds!
     iowr Watchdog
     iord Port0_Data
nochange:

   mov A,[Data_Byte7]
   cmp A,00h
   jz main

  include "readports.asm"
   
   mov A,0
   mov [Data_Byte7],A

jmp main

;----------------------------------------------------------------------
;The endpoint 0 ISR supports the control endpoint.
;This code enumerates and configures the hardware.
;It also responds to Set Report requests that receive data from the host.
;----------------------------------------------------------------------

USB_EP0_ISR:
     push A
     iord USB_EP0_RX_Status
;Has a Setup packet been received?
     and A, 01h
;If no, find out if it's an OUT packet.
     jz check_for_out_packet
;If yes, handle it.
;Disable endpoint 0 interrupts.
     mov A,[interrupt_mask]
     and A, 0F7h
     mov [interrupt_mask], A
     iowr Global_Interrupt
;Find out what the Setup packet contains and handle the request.
      call StageOne
;Re-enable Endpoint 0 interrupts.
     mov A, [interrupt_mask]
     or A, 08h
     mov [interrupt_mask], A
     jmp done_with_packet

check_for_out_packet:
     iord USB_EP0_RX_Status
;Is it an OUT packet?
     and A, 02h
;If no, ignore it.
     jz done_with_packet
;If yes, process the received data.
;Disable Endpoint 0 interrupts.
     mov A,[interrupt_mask]
     and A, 0F7h
     mov [interrupt_mask], A
     iowr Global_Interrupt

;For debugging: set Port 0, bit 1 to show that we're here.
;    iord Port0_Data
;    or a, 2
;    iowr Port0_Data

;Read the first byte in the buffer
     mov a, [Endpoint_0]
;For debugging: if the first byte =12h, bring Port 0, bit 0 high
      cmp a, 12h
      jnz not_a_match
;      iord Port0_Data
;      or a, 4
;      iowr Port0_Data

not_a_match:

;For debugging, add 1 to each byte read
;and copy the bytes to RAM.
;These bytes will be sent back to the host.

      push X
      ;data_count holds the number of bytes left to read.
      ;X holds the index of the address to read
      ;and the index of the address to store the received data.
      ;Initialize the X register.
      mov X, 0
      
    Get_Received_Data:
      ;Find out if there are any bytes to read.
      mov A, 0
      cmp A, [data_count]
      ;Jump if nothing to read.
      jz DoneWithReceivedData

      ;Get a byte and save it onto the data-stack 
      mov A, [X + Endpoint_0]
      mov [X + Data_Byte0], A
      ;Decrement the number of bytes to read.
      dec [data_count]
      ;Increment the address to read.
      inc X
      ;Do another
      jmp Get_Received_Data
	
     ;DBGdone:
	;nop
	;jmp DBGdone


    DoneWithReceivedData:
; Check what kind of command we got
;      jmp DBGdone
	mov A,[Data_Byte0]
      cmp A, 0
      jz SETPORT0
      mov A,[Data_Byte0]
      cmp A,1
      jz SETPORT1
      mov A,[Data_Byte0]
      cmp A,2
      jz READPORTA
      mov A,[Data_Byte0]
      cmp A,3
      jz READPORTB
      mov A,[Data_Byte0]
      cmp A,4
      jz SETIOPORT0
      mov A,[Data_Byte0]
      cmp A,5
      jz SETIOPORT1
      mov A,[Data_Byte0]
      cmp A,6
      jz SENDSERIAL
      mov A,[Data_Byte0]
      cmp A,10
      jz READPRT0
      mov A,[Data_Byte0]
      cmp A,11
      jz READPRT1
      mov A,[Data_Byte0]
      cmp A,12
      jz READPRT2
      mov A,[Data_Byte0]
      cmp A,13
      jz READPRT3
      mov A,[Data_Byte0]
      cmp A,14
      jz READPRT4
      mov A,[Data_Byte0]
      cmp A,15		
      jz READPRT5
      mov A,[Data_Byte0]
      cmp A,16
      jz READPRT6
      mov A,[Data_Byte0]
      cmp A,17
      jz READPRT7
      mov A,[Data_Byte0]
      cmp A,20
      jz READBYTE01
      mov A,[Data_Byte0]
      cmp A,21
      jz READBYTE23
      mov A,[Data_Byte0]
      cmp A,22
      jz READBYTE45
      mov A,[Data_Byte0]
      cmp A,23
      jz READBYTE67
      
      jmp FINISHED_COMMAND

READPRT0:
mov A,1
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT1:
mov A,2
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT2:
mov A,3
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT3:
mov A,4
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT4:
mov A,5
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT5:
mov A,6
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT6:
mov A,7
mov [Data_Byte7],A
jmp FINISHED_COMMAND
READPRT7:
mov A,8
mov [Data_Byte7],A
jmp FINISHED_COMMAND

READBYTE01: 
      mov A,[Data_Temp0]
      mov [Data_Byte0],A
      mov A,[Data_Temp1]
      mov [Data_Byte1],A
      jmp FINISHED_COMMAND
READBYTE23:
      mov A,[Data_Temp2]
      mov [Data_Byte0],A
      mov A,[Data_Temp3]
      mov [Data_Byte1],A
      jmp FINISHED_COMMAND
READBYTE45:
       mov A,[Data_Byte4]
      mov [Data_Byte0],A
      mov A,[Data_Byte5]
      mov [Data_Byte1],A
      jmp FINISHED_COMMAND
READBYTE67:
      mov A,[Data_Byte6]
      mov [Data_Byte0],A
      mov A,[Data_Byte7]
      mov [Data_Byte1],A
      jmp FINISHED_COMMAND


      
SETPORT0:
      mov A,[1+Data_Byte0]
      iowr Port0_Data
      jmp FINISHED_COMMAND

SETPORT1:
      mov A,[1+Data_Byte0]
      iowr Port1_Data
      jmp FINISHED_COMMAND
READPORTA:
      iord Port0_Data
      mov [1+Data_Byte0],A
      jmp FINISHED_COMMAND
READPORTB:
      iord Port1_Data
      mov [1+Data_Byte0],A
      jmp FINISHED_COMMAND

SETIOPORT0:
      mov A,[1+Data_Byte0]
      iowr Port0_Pullup
      jmp FINISHED_COMMAND

SETIOPORT1:
      mov A,[1+Data_Byte0]
      iowr Port1_Pullup
      jmp FINISHED_COMMAND
SENDSERIAL:
;      mov A,[1+Data_Byte0]
;      mov [txData],A
;      iord Global_Interrupt
;      mov [0+Data_Byte0],A
;      call txRoutine
;      mov A,[0+Data_Byte0]
;      iowr Global_Interrupt
      jmp FINISHED_COMMAND


FINISHED_COMMAND:

;For debugging, set Port 0 to match the value written
;IN transfers can read this value back.
      pop X

;Handshake by sending a 0-byte data packet.
call Send0ByteDataPacket

done_with_packet:
;Re-enable Endpoint 0 interrupts.
     mov A,[interrupt_mask]
     or A, 08h
     mov [interrupt_mask], A
     ipret Global_Interrupt

;========================================================================
;Control transfers
;========================================================================

;------------------------------------------------------------------------
;Control transfer, stage one.
;Find out whether the request is a standard device or HID request,
;the direction of data transfer, 
;and whether the request is to a device, interface, or endpoint.
;(from Table 9.2 in the USB spec)
;------------------------------------------------------------------------

StageOne:
;Clear the setup flag
     mov A, 00h
     iowr USB_EP0_RX_Status
;Set the StatusOuts bit to cause auto-handshake after receiving a data packet.
     mov A, 8
     iowr USB_Status_Control
;bmRequestType contains the request.
      mov A, [bmRequestType]

;Standard device requests. From the USB spec.
; host to device requests
        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 requests
        jz RequestType80                 ; bmRequestType = 10000000 device
        cmp A, 81h
        jz RequestType81                 ; bmRequestType = 10000001 interface
        cmp A, 82h
        jz RequestType82                 ; bmRequestType = 10000010 endpoint

;HID-class device requests. From the HID spec
; host to device requests
        cmp A, 21h
        jz RequestType21                 ; bmRequestType = 00100001 interface
        cmp A, 22h                       ; *** not in HID spec ***
        jz RequestType22                 ; bmRequestType = 00100010 endpoint
; device to host requests
        cmp A, A1h
        jz RequestTypeA1                 ; bmRequestType = 10100001 interface

; Stall unsupported requests
SendStall:
      mov A, A0h
     iowr USB_EP0_TX_Config
      ret

;----------------------------------------------------------------------
;Control transfer, stage two
;Find out which request it is.
;----------------------------------------------------------------------

;Host to device with device as recipient
RequestType00:

;The Remote Wakeup feature is disabled on reset.
     mov A, [bRequest]     ; load bRequest
; 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

; Set Descriptor is optional.
; Set Descriptor                bRequest = 7    *** not supported ***

;If wValue is zero, the device is not configured.
;The only other legal value for this firmware is 1.
;Set Configuration           bRequest = 9
    cmp A, set_configuration
    jz SetConfiguration

;Stall unsupported requests.
    jmp SendStall


;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 ***

; Set Interface is optional.
; Set Interface                 bRequest = 11   *** not supported ***

;Stall unsupported requests.
;        jmp SendStall

;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
 
;Stall unsupported functions.
    jmp SendStall

;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

;Stall unsupported requests.
     jmp SendStall

;Device to host with interface as recipient
RequestType81:
     mov A, [bRequest]     ; load bRequest

; Get Status               bRequest = 0
      cmp A, get_status
      jz GetInterfaceStatus

; Get Interface returns the selected alternate setting.
;  This firmware supports no alternate settings.
; Get Interface                 bRequest = 10   *** not supported ***

;The HID class defines one more request for bmRequestType=10000001
; Get Descriptor                bRequest = 6
      cmp A, get_descriptor
      jz GetDescriptor

;Stall unsupported functions
      jmp SendStall

;Device to host with endpoint as recipient
RequestType82:
     mov A, [bRequest]          ; load bRequest
; Get Status               bRequest = 0
     cmp A, get_status
      jz GetEndpointStatus

; Get Descriptor               bRequest = 6
     cmp A, get_descriptor
     jz GetDescriptor
; Sync Frame                  bRequest = 12   *** not supported ***

;Stall unsupported functions.
     jmp SendStall


;Check for HID class requests

;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

;Stall unsupported requests
     jmp SendStall

RequestType22:
        mov A, [bRequest]      ; load bRequest

; Set Report               bRequest = 9
     cmp A, set_report     
     jz SetReport

;Stall unsupported requests
     jmp SendStall


;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

;Stall unsupported requests
        jmp SendStall

;----------------------------------------------------------------------
;Control transfer, stage three
;Process the request.
;----------------------------------------------------------------------

;The host controls whether or not a device can request a remote wakeup.

; Disable the remote wakeup capability.
ClearRemoteWakeup:
        mov A, [wValue]
        cmp A, device_remote_wakeup
        jnz SendStall
;Handshake by sending a data packet
        call Send0ByteDataPacket
        mov A, DISABLE_REMOTE_WAKEUP
        mov [remote_wakeup_status], A
        ret

; Enable the remote wakeup capability.
SetRemoteWakeup:
        mov A, [wValue]
        cmp A, device_remote_wakeup
;If not a match, stall.
        jnz SendStall
;Handshake by sending a 0-byte data packet
        call Send0ByteDataPacket
;Perform the request.
        mov A, ENABLE_REMOTE_WAKEUP
        mov [remote_wakeup_status], A
        ret

SetAddress:
; Set the device address to match wValue in the Setup packet.
;Complete the requested action after completing the transaction.
;Handshake by sending a 0-byte data packet.
        call Send0ByteDataPacket
;Perform the request
        mov A, [wValue]
        iowr USB_Device_Address
        ret

SetConfiguration:
;Unconfigured: wValue=0, configured: wValue=1.
;Also clear any stall condition and set Data 0/1 to Data0.
;Handshake by sending a 0-byte data packet.
      call Send0ByteDataPacket
;Save the configuration status.
      mov A, [wValue]
      mov [configuration_status], A
;Clear any stall condtion
      mov A, 0
      mov [endpoint_stall], A
;Set data 0/1 to Data0
      iord USB_EP1_TX_Config
      and A, ~DataToggle

;Set the configuration status.
     iowr USB_EP1_TX_Config     
     mov A, [configuration_status]
     cmp A, 0
;If configured, jump.
     jnz device_configured

;If unconfigured:
;Disable Endpoint 1
     iord USB_EP1_TX_Config
     and A, EFh
     iowr USB_EP1_TX_Config
;Disable Endpoint 1 interrupts.
     mov A, [interrupt_mask]
     and A, EFh
          mov [interrupt_mask], A
     jmp done_configuration

;If configured:
device_configured:
;Send NAK in response to IN packets
     iord USB_EP1_TX_Config
     and A,7Fh
;Enable Endpoint 1
     or A, 10h
     iowr USB_EP1_TX_Config
;Enable interrupts: Endpoint 1 and GPIO
     mov A, [interrupt_mask]
     or A, 50h
     mov [interrupt_mask], A
;Send NAK in response to Endpoint 0 OUT packets.
     iord USB_Status_Control
     and A,0EFh
     iowr USB_Status_Control
done_configuration:
        ret

ClearEndpointStall:
;Clear the stall condition for an endpoint.
;For endpoint 1, also set Data 0/1 to Data 0.
        mov A, [wValue]
        cmp A, endpoint_stalled
        jnz SendStall
;
;Clear Endpoint 1 stall
;Handshake by sending a 0-byte data packet
      call Send0ByteDataPacket
;Clear the stall condition
      mov A,0
      mov [endpoint_stall], A
;Set Data 0/1 to Data0
      iord USB_EP1_TX_Config
      and A, ~DataToggle
      iowr USB_EP1_TX_Config
;Send NAK in response to Endpoint 0 OUT packets.
      iord USB_Status_Control
      and A,0EFh
      iowr USB_Status_Control
      ret

;Stall Endpoint 1
SetEndpointStall:
        mov A, [wValue]
        cmp A, endpoint_stalled
;Not a match, so stall
        jnz SendStall
;Handshake by sending a 0-byte data packet.
        call Send0ByteDataPacket
;Stall the endpoint.
        mov A,1         
        mov [endpoint_stall], A
        mov A, 30h
        iowr USB_EP1_TX_Config                 
        ret

GetDeviceStatus:
;Device Status is two bytes.
;Bit 0 must be 0 (bus-powered).
;Bit 1 is remote wakeup: 0=disabled, 1=enabled.
;All other bits are unused.
;Send two bytes.
        mov A, 2
        mov [data_count], A
;The control_read_table holds the two possible values for device status.
;Get the address of the first value.
        mov A, (get_dev_status_table - control_read_table)
;Add an index value to select the correct bytes.
        add A, [remote_wakeup_status]
;Send the value.
        jmp SendDescriptor

GetDescriptor:
;The high byte of wValue contains the descriptor type.
;The low byte of wValue contains the descriptor index.

        mov A, [wValueHi]               ; load descriptor type

;Test for standard descriptor types first.
;Supported descriptor types are device, configuration, string.
;Unsupported descriptor types are interface, endpoint.

; 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
     cmp A, string
     jz GetStringDescriptor

; 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 ***
;Stall unsupported requests.
     jmp SendStall

GetConfiguration:
;Send the current device configuration.
;0 = unconfigured, 1 = configured.

;Send 1 byte
        mov A, 1
        mov [data_count], A
;Get the address of the data to send.
        mov A, (get_configuration_status_table - control_read_table)
;Add an index to point to the correct configuration.
        add A, [configuration_status]
;Send the data.
        jmp SendDescriptor

GetInterfaceStatus:
;Interface status is 2 bytes, which are always 0.
;Send 2 bytes.
        mov A, 2
        mov [data_count], A
;Get the address of the data to send.
        mov A, (get_interface_status_table - control_read_table)
;Send the data.
        jmp SendDescriptor

GetEndpointStatus:
;Endpoint status is 2 bytes.
;Bit 0 = 0 when the endpoint is not stalled.
;Bit 0 = 1 when the endpoint is stalled.
;All other bits are unused.
;Send 2 bytes.
        mov A, 2
        mov [data_count], A
;Get the stall status.
        mov A, [endpoint_stall]
;Shift left to get an index (0 or 2) for the endpoint status table
        asl A
;Get the address of the data to send.
        add A, (get_endpoint_status_table - control_read_table)
;Send the data.
        jmp SendDescriptor

SetReport:
;The CY7C63000 doesn't support interrupt-mode OUT transfers.
;So the host uses Control transfers with Set_Report requests
;to get data from the device.

;Get the report data.

;For debugging: set Port 0, bit 0 =1 to show that we're here.
;      iord Port0_Data
;      or a, 1
;      iowr Port0_Data

;Find out how many bytes to read. This value is in WLength.
;Save the length in data_count.
     mov A, [wLength]
     mov [data_count], A

;Enable receiving data at endpoint 0 by setting the EnableOuts bit
;The bit is cleared following any Setup or OUT transaction.
     iord USB_Status_Control
     or A, 10h
;Clear the StatusOuts bit to disable auto-Ack after receiving a valid 
;status packet in a Control read (IN) transfer.
;Otherwise, the USB engine will respond to a data OUT packet with a stall.
     and A, F7h
     iowr USB_Status_Control
;Now we're ready to receive the report data.
;An Endpoint 0 OUT interrupt signals the arrival of the report data.
ret

SetIdle:
        jmp SendStall   ; *** not supported ***

SetProtocol:
;Switches between a boot protocol (wValue=0) and report protocol (wValue=1).
;This firmware doesn't distinguish between protocols.
        mov A, [wValue]
        mov [protocol_status], A
        call Send0ByteDataPacket
        ret

GetReport:
;Sends a report to the host.
;The high byte of wValue contains the report type. 
;The low byte of wValue contains the report ID.
;Not supported (Use interrupt transfers to send data.)
     jmp SendStall

GetReportDescriptor:
;Save the descriptor length
     mov A, (end_hid_report_desc_table - hid_report_desc_table)
     mov [data_count], A
;Get the descriptor's starting address.
     mov A, (hid_report_desc_table - control_read_table)
     call SendDescriptor

      ret

GetIdle:
;Not supported
        jmp SendStall

GetProtocol:
;Send the current protocol status.
;Send 1 byte.
        mov A, 1
        mov [data_count], A
;Get the address of the data to send.
        mov A, (get_protocol_status_table - control_read_table)
;Add an index that points to the correct data.
        add A, [protocol_status]
;Send the data.
        jmp SendDescriptor
        
; Standard Get Descriptor routines
;
;Send the device descriptor.
GetDeviceDescriptor:
;Get the length of the descriptor
;(stored in the first byte in the device descriptor table).
        mov A, 0
       index device_desc_table
        mov [data_count], A
;Get the starting address of the descriptor.
        mov A, (device_desc_table - control_read_table)
;Send the descriptor.
        jmp SendDescriptor

GetConfigurationDescriptor:
;Send the configuration descriptor.
;Get the length of the descriptor.
     mov A, (end_config_desc_table - config_desc_table)
      mov [data_count], A
;Get the starting address of the descriptor.
     mov A, (config_desc_table - control_read_table)
;Send the descriptor.
     jmp SendDescriptor

GetStringDescriptor:
;Use the string index to find out which string it is.
     mov A, [wValue]
     cmp A, 0h
     jz LanguageString
     cmp A, 01h
     jz ManufacturerString
     cmp A, 02h
     jz ProductString
;     cmp A, 03h
;     jz SerialNumString
;     cmp A, 04h
;     jz ConfigurationString
;     cmp A, 05h
;     jz InterfaceString
; No other strings supported
      jmp SendStall

SendDescriptor:
;The starting address of the descriptor is in the accumulator. Save it.
        mov [data_start], A
;Get the descriptor length.
        call get_descriptor_length
;Send the descriptor.
        call control_read
        ret

;Send the requested string.
;For each, store the descriptor length in data_count, then send the descriptor.
LanguageString:
     mov A, (USBStringDescription1 - USBStringLanguageDescription)
      mov [data_count], A
     mov A, (USBStringLanguageDescription - control_read_table)
      jmp SendDescriptor
ManufacturerString:     
     mov A, ( USBStringDescription2 - USBStringDescription1)
      mov [data_count], A
     mov A, (USBStringDescription1 - control_read_table)
      jmp SendDescriptor
ProductString:
     mov A, ( USBStringDescription3 - USBStringDescription2)
      mov [data_count], A
     mov A, (USBStringDescription2 - control_read_table)
      jmp SendDescriptor
;SerialNumString:
;     mov A, ( USBStringDescription4 - USBStringDescription3)
;      mov [data_count], A
;     mov A, (USBStringDescription3 - control_read_table)
;      jmp SendDescriptor
;ConfigurationString:
;     mov A, ( USBStringDescription5 - USBStringDescription4)
;      mov [data_count], A
;     mov A, (USBStringDescription4 - control_read_table)
;      jmp SendDescriptor
;InterfaceString:
;     mov A, ( USBStringEnd - USBStringDescription5)
;      mov [data_count], A
;     mov A, (USBStringDescription5 - control_read_table)
;      jmp SendDescriptor

; HID class Get Descriptor routines
;
GetHIDDescriptor:
;Send the HID descriptor.
;Get the length of the descriptor.
     mov A, (Endpoint_Descriptor - Class_Descriptor)
      mov [data_count], A
;Get the descriptor's starting address.
     mov A, ( Class_Descriptor - control_read_table)
;Send the descriptor.
      call SendDescriptor
      ret

;======================================================================
;USB support routines
;======================================================================

get_descriptor_length:
;The host sometimes lies about the number of bytes it
; wants from a descriptor.
;A request to get a descriptor should return the smaller of the number 
;of bytes requested or the actual length of the descriptor.
;Get the requested number of bytes to send
     mov A, [wLengthHi]
;If the requested high byte is >0, 
;ignore the high byte and use the firmware's value.
;(255 bytes is the maximum allowed.)
     cmp A, 0
     jnz use_actual_length
;If the low byte =0, use the firmware's value.
     mov A, [wLength]
     cmp A, 0
     jz use_actual_length
;If the requested number of bytes => the firmware's value,
;use the firmware's value.
     cmp A, [data_count]
     jnc use_actual_length
;If the requested number of bytes < the firmware's value,
;use the requested number of bytes.
     mov [data_count], A
use_actual_length:
        ret

Send0ByteDataPacket:
;Send a data packet with 0 bytes.
;Use this handshake after receiving an OUT data packet.
;Enable responding to IN packets and set Data 0/1 to Data 1.
     mov A, C0h
     iowr USB_EP0_TX_Config
;Enable interrupts.
     mov A, [interrupt_mask]
     iowr Global_Interrupt
WaitForDataToTransfer:
;Wait for the data to transfer.
;Clear the watchdog timer
     iowr Watchdog
;Bit 7 of USB_EP0_TX_Config is cleared when the host acknowledges
;receiving the data.
     iord USB_EP0_TX_Config
     and A, 80h
     jnz WaitForDataToTransfer
     ret

control_read: 
;Do a Control Read transfer.
;The device receives a Setup packet in the Setup stage,
;sends 1 or more data packets (IN) in the Data stage,
;and receives a 0-length data packet (OUT) in the Status stage.
;Before calling this routine, the firmware must set 2 values:
;data_start is the starting address of the descriptor to send,
;expressed as an offset from the control read table.
;data_count is the number of bytes in the descriptor.
     push X
;Set the Data 0/1 bit to 0.
     mov A, 00h
     mov [endp0_data_toggle], A

control_read_data_stage:
     mov X, 00h
     mov A, 00h
     mov [loop_counter], A

;Clear the Setup bit.
     iowr USB_EP0_RX_Status
;Check the Setup bit.
     iord USB_EP0_RX_Status
     and A, 01h
;If not cleared, another setup packet has arrived, 
;so exit the routine.
     jnz control_read_status_stage

;Set the StatusOuts bit to 1 to enable auto-ACK of the OUT Status stage.
     mov A, 08h
     iowr USB_Status_Control
;If there is no data to send, prepare a 0-length data packet.
;(The host might require a final 0-length packet if the descriptor is 
;a multiple of 8 bytes.)
     mov A, [data_count]
     cmp A, 00h
     jz dma_load_done

dma_load_loop:
;Copy up to 8 bytes for transmitting into Endpoint 0's buffer
;and increment/decrement the various counting variables.

;Place the byte to send in the accumulator:
;(control_read_table) + (data_start).
     mov A, [data_start]
     index control_read_table
;Place the byte in Endpoint 0's buffer.
     mov [X + Endpoint_0], A
;Increment the offset of the data being sent.
     inc [data_start]
;Increment the offset of Endpoint 0's buffer.
     inc X
;Increment the number of bytes stored in the buffer.
     inc [loop_counter]
;Decrement the number of bytes left to send.
     dec [data_count]
;If the count = 0, there's no more data to load.
     jz dma_load_done
;If 8 bytes haven't been loaded into the buffer, get another byte.
;If 8 bytes have been loaded, it's the maximum for the transaction,
;so send the data.
     mov A, [loop_counter]
     cmp A, 08h
     jnz dma_load_loop

dma_load_done:
;Send the data.

;Check the Setup bit.
;If it's not 0, another Setup packet has arrived, 
;so exit the routine.
     iord USB_EP0_RX_Status
     and A, 01h
     jnz control_read_status_stage

;Set the bits in the USB_EP0_TX_Config register.
;Toggle the Data 0/1 bit.
     mov A, [endp0_data_toggle]
     xor A, 40h
     mov [endp0_data_toggle], A
;Enable responding to IN token packets.
     or A, 80h
;The low 4 bits hold the number of bytes to send.
     or A, [loop_counter]
     iowr USB_EP0_TX_Config
;Enable interrupts
     mov A, [interrupt_mask]
     iowr Global_Interrupt

wait_control_read:

;Clear the watchdog timer
     iowr Watchdog

;Wait for the data to transfer and the host to acknowledge,
;indicated by Bit 7 = 0.
     iord USB_EP0_TX_Config
     and A, 80h
;When all of the transaction's data has transferred, 
;find out if there is more data to send in the transfer.
     jz control_read_data_stage
;Find out if the host has sent an OUT packet to acknowledge 
;and end the transfer.
     iord USB_EP0_RX_Status
     and A, 02h
     jz wait_control_read

control_read_status_stage:
;The transfer is complete.
     pop X
     mov A, [interrupt_mask]
     iowr Global_Interrupt
     ret

;======================================================================
;Lookup Tables
;Contain the descriptors and the codes for status indicators.
;The firmware accesses the information by referencing a specific
;table's address as an offset from the control_read_table.
;======================================================================

control_read_table:

device_desc_table:
     db 12h          ; Descriptor length (18 bytes)
     db 01h          ; Descriptor type (Device)
     db 10h,01h      ; Complies with USB Spec. Release (0110h = release 1.10)
     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 25h,09h      ; Vendor ID (Lakeview Research, 0925h)
     db 34h,12h      ; Product ID (1234)
     db 01h,00h      ; Device release number (0001)
     db 01h          ; Mfr string descriptor index
     db 02h          ; Product string descriptor index
     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:

;----------------------------------------------------------------------
;The HID-report descriptor table
;----------------------------------------------------------------------

hid_report_desc_table:   
     db 06h, A0h, FFh      ;         Usage Page (vendor defined) FFA0
     db 09h, 01h     ;               Usage (vendor defined)
     db A1h, 01h     ;               Collection (Application)
     db 09h, 02h     ;               Usage (vendor defined)
     db A1h, 00h     ;               Collection (Physical)
     db 06h, A1h, FFh ;               Usage Page (vendor defined) 

;The input report
     db 09h, 03h     ;               usage - vendor defined
     db 09h, 04h     ;               usage - vendor defined
     db 15h, 80h     ;               Logical Minimum (-128)
     db 25h, 7Fh     ;               Logical Maximum (127)
     db 35h, 00h     ;               Physical Minimum (0)
     db 45h, FFh;                    Physical Maximum (255)
;    db 66h, 00h, 00h;               Unit (None (2 bytes))
     db 75h, 08h     ;               Report Size (8)  (bits)
     db 95h, 02h     ;               Report Count (2)  (fields)
     db 81h, 02h     ;               Input (Data, Variable, Absolute)  

;The output report
     db 09h, 05h     ;               usage - vendor defined
     db 09h, 06h     ;               usage - vendor defined
     db 15h, 80h     ;               Logical Minimum (-128)
     db 25h, 7Fh     ;               Logical Maximum (127)
     db 35h, 00h     ;               Physical Minimum (0)
     db 45h, FFh     ;               Physical Maximum (255)
;    db 66h, 00h, 00h;               Unit (None (2 bytes))
     db 75h, 08h     ;               Report Size (8)  (bits)
     db 95h, 02h     ;               Report Count (2)  (fields)
     db 91h, 02h     ;               Output (Data, Variable, Absolute)  

     db C0h          ;               End Collection

     db C0h          ;               End Collection

end_hid_report_desc_table:

;----------------------------------------------------------------------
;String Descriptors
;----------------------------------------------------------------------

;Define the strings

; string 0
USBStringLanguageDescription:
    db 04h          ; Length
    db 03h          ; Type (3=string)
    db 09h          ; Language:  English
    db 04h          ; Sub-language: US
; string 1

;The Length value for each string =
;((number of characters) * 2) + 2

USBStringDescription1:     ; IManufacturerName
    db 42h          ; Length
    db 03h          ; Type (3=string)
    dsu "EWerkstatt Physik/Bochum" ;
    dsu "USB Complete"

; string 2
USBStringDescription2:     ; IProduct
    db 20h          ; Length
    db 03h          ; Type (3=string)
    dsu "8Port Voltmeter"  ;

;string 3
;If the firmware contains a serial number, it must be unique
;for each device or the devices may not enumerate properly.
USBStringDescription3:     ; serial number

; string 4                 
;USBStringDescription4:     ; configuration string descriptor
;    db 16h          ; Length
;    db 03h          ; Type (3=string)
;    dsu "Sample HID"  ;

;string 5
;USBStringDescription5:     ; configuration string descriptor
;    db 32h          ; Length
;    db 03h          ; Type (3=string)
;    dsu "EndPoint1 Interrupt Pipe"  ;

USBStringEnd:

;----------------------------------------------------------------------
;Status information.
;The status can be either device, interface, or endpoint.
;An index selects the correct value.
;----------------------------------------------------------------------
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