📄 usbhidio.asm
字号:
mov [interrupt_mask],A
ipret Global_Interrupt
;----------------------------------------------------------------------
;GPIO interrupt
;Can be configured to trigger when a port bit toggles.
;Unused here.
;----------------------------------------------------------------------
GPIO_ISR:
push A
push X
pop X
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.
;This will ensure that a ReadFile API call in a Windows application
;won't hang, waiting for the device to send something.
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
;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 prevent 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 sends 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:
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.
mov A, [X + Endpoint_0]
;For debugging, increment the received value.
;(Endpoint 1 will send it back to the host.)
;If the value is 255, reset to 0.
;Otherwise increment it.
cmp A, 255
jz ResetToZero
inc A
jmp NewValueSet
ResetToZero:
mov A, 0
NewValueSet:
;Save the value.
mov [X + Data_Byte0], A
;Decrement the number of bytes left to read.
dec [data_count]
;Increment the address to read.
inc X
;Do another
jmp Get_Received_Data
DoneWithReceivedData:
pop X
;For debugging, set Port 0 to match the value written.
; iowr Port0_Data
;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-class 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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -