; This module is specific for the Dual Configuration example.

; It services USB Requests from the SIE.

; Interpretation of the Output Reports is handled by MAIN

;

 	CSEG

ServiceSetupPacket:

	MOV	DPTR, #SETUPDAT		; Point to Setup Packet data

	MOVX	A, @DPTR		; Get the RequestType

	MOV	C, ACC.7		; Bit 7 = 1 means IO device needs to send data to PC Host

	MOV	SendData, C

	ANL	A, #01011100b		; IF RequestType[6.4.3.2] = 1 THEN goto BadRequest

	JNZ	BadRequest

	MOVX	A, @DPTR		; IF RequestType[1&0] = 1 THEN goto BadRequest

	MOV	C, ACC.0

	ANL	C, ACC.1

	JC	BadRequest

	JNB	ACC.5, NotB5		; IF RequestType[5] = 1 THEN RequestType[1,0] = [1,1]

	MOV	A, #00000011b

NotB5:	ANL	A, #00000011b		; Set CommandIndex[5,4] = RequestType[1,0]

	SWAP	A

	MOV	Temp, A			; Save HI nibble of CommandIndex

					; Set CommandIndex[3,0] = Request[3,0]

	INC	DPTR			; Point to Request

	MOVX	A, @DPTR

	ANL	A, #00001111b		; Only 13 are defined today, handle in table

	ORL	A, Temp	

	CALL	CorrectSubroutine	; goto CommandTable(CommandIndex)

					; Returns STALL=1 if a stall is required

	JB	STALL, BadRequest

       	JNB	SendData, HandShake

	JB	IsDescriptor, LoadSUDPTR; EZ-USB has a short cut for descriptors

                                        ; Send data in ReplyBuffer

	MOV	DPTR, #EP0InBuffer+2

	MOV	R0, #ReplyBuffer+3

	MOV	Temp, #3		; Copy maximum byte count

CopyRB:	MOV	A, @R0

	MOVX	@DPTR, A

	DEC	DPL

	DEC	R0

	DJNZ	Temp, CopyRB

	MOV	A, @R0 			; Get real byte count

SendEP0InBuffer:

	MOV	DPTR, #In0ByteCount

StartXfer:

	MOVX	@DPTR, A		; This write initiates the transfer

HandShake:				; Handshake with host

	MOV	Temp, #00000010b 	; Set HSNAK to tell the SIE that we're done

SetEP0Control:

	MOV	DPTR, #EP0Control

	MOVX	A, @DPTR

	ORL	A, Temp

	MOVX	@DPTR, A

	RET

LoadSUDPTR:			      	; Send the data pointed to by DPTR

	MOV	Temp, DPL

	MOV	A, DPH

	MOV	DPTR, #SUDPTR

	MOVX	@DPTR, A

	MOV	A, Temp

	INC	DPTR

	JMP	StartXfer

BadRequest:				; Invalid Request was received

	MOV	Temp, #00000011b	; Set EP0STALL and HSNAK

	JMP	SetEP0Control



NextDPTR:				; Returns (DPTR + byte DPTR is pointing to)

	MOVX	A, @DPTR

BumpDPTR:				; Returns (DPTR + ACC)

	ADD	A, DPL

	MOV	DPL, A

	JNC	Skip

	INC	DPH			; Need 16 bit arithmetic here

Skip:	RET



CorrectSubroutine:			; Jump to the subroutine that DPTR is pointing to

	MOV	DPTR, #CommandTable

	CALL	BumpDPTR		; Point to entry

	MOVX	A, @DPTR		; Get the offset

	MOV	DPTR, #CommandTable

	CALL	BumpDPTR                ; Get the routine address

	PUSH	DPL			; Create a RETURN address on stack

	PUSH	DPH                     ; Note: JMP @A+DPTR not used since A, DPTR needed

	MOV	R0, #ReplyBuffer+2

	CLR	A

	MOV	@R0, A			; Clear ReplyBuffer

	DEC	R0

	MOV	@R0, A

	DEC	R0

	MOV	@R0, #1			; Default non-descriptor reply

	MOV	DPTR, #SETUPDAT+2	; Point to LOW(wValue)

	MOVX	A, @DPTR		; Many of the routines need these

	MOV	B, A                    ; LOW(wValue) in B

	INC	DPTR

	MOVX	A, @DPTR            	; HIGH(wValue) in A

	CLR	STALL

	CLR	IsDescriptor

	RET				; Go to service routine



; Since the table only contains byte offsets, it is important that all these routines are

; within one page (100H) of CommandTable

;

CommandTable:

; First 16 commands are for the Device

	DB Device_Get_Status - CommandTable

	DB Device_Clear_Feature - CommandTable

	DB Invalid - CommandTable

	DB Device_Set_Feature - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable		; SIE implements Device_Set_Address

	DB Get_Descriptor - CommandTable

	DB Set_Descriptor - CommandTable

	DB Get_Configuration - CommandTable

	DB Set_Configuration - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

; Next 16 commands are for the Interface

	DB Interface_Get_Status - CommandTable

	DB Interface_Clear_Feature - CommandTable

	DB Invalid - CommandTable

	DB Interface_Set_Feature - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Get_Class_Descriptor - CommandTable

	DB Set_Class_Descriptor - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Get_Interface - CommandTable

	DB Set_Interface - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

; Next 16 commands are for the Endpoint

	DB Endpoint_Get_Status - CommandTable

	DB Endpoint_Clear_Feature - CommandTable

	DB Invalid - CommandTable

	DB Endpoint_Set_Feature - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Endpoint_Sync_Frame - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

; Next 16 commands are Class Requests

	DB Invalid - CommandTable

	DB Get_Report - CommandTable

	DB Get_Idle - CommandTable

	DB Get_Protocol - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Set_Report - CommandTable

	DB Set_Idle - CommandTable

	DB Set_Protocol - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

	DB Invalid - CommandTable

;

; Many requests are INVALID for this example

Get_Protocol:			; We are not a Boot device

Set_Protocol: 			; We are not a Boot device

Set_Descriptor:			; Our Descriptors are static

Set_Class_Descriptor:          	; Our Descriptors are static

Set_Interface:			; We only have one Interface

Get_Interface:			; We do not have an Alternate setting

Device_Set_Feature: 		; We have no features that can be set or cleared

Interface_Set_Feature: 		; We have no features that can be set or cleared

Endpoint_Set_Feature: 		; We have no features that can be set or cleared

Device_Clear_Feature:		; We have no features that can be set or cleared 

Interface_Clear_Feature: 	; We have no features that can be set or cleared

Endpoint_Sync_Frame:		; We are not an Isonchronous device



Invalid:			; Invalid Request made, STALL the Endpoint

	SETB	STALL

;

Endpoint_Clear_Feature: 	; We have no features that can be set or cleared

;

Reply:	RET



Set_Report:				; Host wants to sent us a Report. 

; The ONLY case in this example where host sends data to us

	JNB	Configured, Invalid	; Need to be Configured to do this command

	MOV	DPTR, #Out0ByteCount	; Enable EP0OutBuffer to receive data

	MOVX	@DPTR, A 		; Any value will do

        MOV	DPTR, #OUT07IRQ		; Wait for valid data in EP0OutBuffer

Wait4D:	MOVX	A, @DPTR

	ANL	A, #00000001b

	JZ	Wait4D

	MOVX	@DPTR, A		; Clear the interrupt

	JMP	ProcessOutputReport	; RETurn via this subroutine

Get_Report:				; Host wants a Report

	JNB	Configured, Invalid	; Need to be Configured to do this command 

	INC	R0			; Point to ReplyBuffer(1)

	MOV	@R0, #18H               ; Reply with a recognizable (arbitary) value

	RET

Set_Idle:				; Host wants to tell us how often we should talk

	JNB	Configured, Invalid	; Need to be Configured to do this command 

	MOV	Idle_Time, A

	RET				; Handshake with host

Get_Idle:				; Host must have forgotten what he told us to do

	JNB	Configured, Invalid	; Need to be Configured to do this command 

        INC	R0			; Point to ReplyBuffer(1)

	MOV	@R0, Idle_Time

	RET

Get_Configuration:

	JNB	Configured, Reply

	INC	R0

	MOV	@R0, CurrentConfiguration

	RET

Device_Get_Status:			; Only two bits of Device Status are defined

	INC	R0			; Point to ReplyBuffer(1)

	MOV	@R0, #1			; Bit 1=Remote Wakeup(=0), Bit 0=Self Powered(=1)

	RET

Interface_Get_Status:			; Interface Status is currently defined as 0

Endpoint_Get_Status:

        MOV	@R0, #2

	RET

Set_Configuration:   			; Valid values are 0 and 1

	MOV	A, B			; Get LOW(wValue)

	JZ	Deconfigured

	CLR	C

	SUBB    A, ConfigurationCount+1	; This example supports two configurations

	JNC	Invalid

	MOV	CurrentConfiguration, B

	SETB	Configured

	RET

Deconfigured:

	CLR	Configured

Reply2:	RET

Get_Descriptor:		   		; Host wants to know who/what we are

	SETB	IsDescriptor

	DEC	A			; Valid Values are 1, 2 and 3

	MOV	DPTR, #DeviceDescriptor

	JZ	Reply

	DEC	A

	MOV	DPTR, #TextConfigurationDescriptor

	JNB	B.1, Other1		; B = Descriptor Index (=1 or 2)

	MOV	DPTR, #DotConfigurationDescriptor

Other1:	JZ	Reply

	DEC	A

	JNZ	Invalid

; Request is for a String Descriptor

	MOV	DPTR, #String0		; Point to String 0

	MOV	A, B			; Get String Index

NextString:

	JZ	FixUpthenReply

	MOV	Temp, A			; Save String Index

	CALL	NextDPTR

	MOVX	A, @DPTR		; Get the String Length (= 0 means we're at Backstop)

	JZ	Invalid			; Asked for a string I don't have 

	MOV	A, Temp

	DEC	A

	JMP	NextString		; Check if we are there yet

Get_Class_Descriptor: 			; Valid values are 21H, 22H, 23H for Class Request

	SETB	IsDescriptor

	CLR	C

	SUBB	A, #21H

	MOV	DPTR, #TextHIDDescriptor

	JNB	B.1, Other2		; B = Descriptor Index (=1 or 2)

	MOV	DPTR, #DotHIDDescriptor

Other2:	JZ	Reply2

	DEC	A

	MOV	DPTR, #TextReportDescriptor

	JNB	B.1, Other3		; B = Descriptor Index (=1 or 2)

	MOV	DPTR, #DotReportDescriptor

Other3:	JZ	Reply2

;	DEC	A			; This example does not use Physical Descriptors

;	JZ	Send_Physical_Descriptor

	JMP	Invalid

;

; Error check: this MUST be on within a page of CommandTable

WithinSamePage EQU $ - CommandTable	

;

FixUpthenReply:				; EZ-USB Rev D has a String Descriptor bug

					; Need to fill the IN0BUF (@ 7F00H) myself

	MOVX	A, @DPTR		; Get the string length

	MOV	R7, A			; Save counter

	MOV	B, A

	MOV	R0, #LOW(EP0InBuffer)	; PageReg = 7FH = HIGH(EP0InBuffer)

CopySD:	MOVX	@R0, A

	INC	R0

	INC	DPTR

        MOVX	A, @DPTR

	DJNZ	R7, CopySD

; Fixup complete, get back to the program flow

	POP	ACC			; Get rid of the return address

	POP	ACC

	MOV	A, B			; Retrieve byte count

	JMP	SendEP0InBuffer