Source file: /~heha/ewa/Ofen/rauch.zip/webusb.i15

;******************
;* HID und WebUSB *
;******************
;Auch wenn sich das Datenblatt darüber auslässt, dass sich die
;„Buffer Descriptor Table“ ab der linearen Adresse 0x2000 befindet,
;befindet sie sich genauso im Bank 0 und belegt diese zwangsweise:
;Wenn man USB benutzt, dann geht effektiv die Bank 0 dafür drauf.

;So passt alles in Bank 0:
E0_SSH 		equ	4	; endpoint 0 buffer size = 16
E1I_SSH		equ	4	; endpoint 1 IN (HID interrupt) buffer size = 16
E2I_SSH		equ	4	; endpoint 2 IN (WebUSB interrupt) buffer size = 16

;Exy_STA bits (in Bank 0)
BSTALL		equ	2
DTSEN		equ	3
DTS		equ	6
UOWN		equ	7

;list of Bank0 RAM variables, starting with BDT
	cblock 0x20	;Bank 0 (geradeso voll)
E0O_STA
E0O_CNT
E0O_ADR:2
E0I_STA
E0I_CNT
E0I_ADR:2
E1O_STA		; unused
E1O_CNT		; unused
E1O_ADR:2	; unused
E1I_STA
E1I_CNT
E1I_ADR:2
E2O_STA		; unused
E2O_CNT		; unused
E2O_ADR:2	; unused
E2I_STA
E2I_CNT
E2I_ADR:2
; Normalerweise sind die Variablen E1O_xxx und E2O_xxx frei.
; Aber vielleicht will ja jemand später noch OUT-Endpoints dazufummeln.
USB_STATE	; some flags, see below
SETUPDAT_CNT	; remaining bytes to be sent
SETUPDAT_PTR:2	; pointer to descriptor to be sent
free:4

E0_BUF:1<<E0_SSH	;@0x40 shared buffer for EP0 Setup, Out, and In transfer
E1I_BUF:1<<E1I_SSH	;@0x50
E2I_BUF:1<<E1I_SSH	;@0x60
;Dadurch passt alles in die Bank 0, und die HID- und Interruptdaten können in einem Stück gesendet werden!
	endc

bmRequestType	equ	E0_BUF+0
bRequest	equ	E0_BUF+1
wValueL		equ	E0_BUF+2
wValueH		equ	E0_BUF+3
wIndexL		equ	E0_BUF+4
wIndexH		equ	E0_BUF+5
wLengthL	equ	E0_BUF+6
wLengthH	equ	E0_BUF+7
LIN_E0_BUF	equ	E0_BUF+0x1FE0	;0x2020 .. 0x202F
LIN_E1I_BUF	equ	E1I_BUF+0x1FE0	;0x2030 .. 0x203F
LIN_E2I_BUF	equ	E1I_BUF+0x1FE0	;0x2040 .. 0x204F

; USB_STATE bit flags
IS_CONTROL_READ	equ	7	; current EP0 transaction is a control read
DECOMP		equ	1	; for descriptor decompression
CONFIGURED	equ	0	; the device is configured

usbPoll
	banksel	UIR		; Bank 29
	btfsc	UIR,URSTIF	; reset?
	 goto	usbReset	; if so, reset the USB iface
; service transactions
	btfss	UIR,TRNIF
	 return
	movfwf	USTAT,FSR1H	; store the status (endpoint number + direction)
	bcf	UIR,TRNIF	; clear flag and advance USTAT fifo
	banksel	E0O_STA		; Bank 0
	andlw	0x78		; endpoint number !=0 ?
	skpz
	 retlw	0		; if not endpoint 0, trash it
; Handles a control transfer on endpoint 0.
; args:		BSR=0, FSR1H=USTAT
; clobbers:	W, FSR1H
	btfsc	FSR1H,DIR	; is it an IN transfer or an OUT/SETUP?
	 bra	_usb_ctrl_in
; it's an OUT or SETUP transfer
	movfw	E0O_STA		; All non-PID bits are zero here because SETUP comes with DATA0
	xorlw	13<<2		; 13=PID_SETUP — is it a SETUP packet?
	brnz	arm_e0o		; if not, it's a DATA or STATUS OUT, ignore data and rearm buffer

;=============================
;= EP0 SETUP packet received =
;=============================
; Handles a SETUP control transfer on endpoint 0.
; BSR=0
	assume	0
	clrf	E0O_STA		; let start with DATA1
	clrf	E0I_STA		; let start with DATA1
	clrf	SETUPDAT_CNT	; No data phase as standard
	bcf	USB_STATE,IS_CONTROL_READ
; get bmRequestType, but don't bother checking whether it's standard/class/vendor...
; the CDC and standard requests we'll receive have distinct bRequest numbers
	btfsc	bmRequestType,7	; is this device->host?
	 bsf	USB_STATE,IS_CONTROL_READ	; if so, this is a control read
	call	onSetup
	incfsz	WREG,w
	 bra	_ans
; Finishes a rejected SETUP transaction: the endpoints are stalled
;_usb_ctrl_invalid
	banksel	UCON
	bcf	UCON,PKTDIS	; reenable packet processing
	banksel	E0I_STA
	movlw	1<<DTSEN|1<<BSTALL
	call	arm_e0i_w
e0o_stall	;for next SETUP
	movlw	1<<DTSEN|1<<BSTALL
	bra	arm_e0o_w
; Prepare reception of next Endpoint 0 Out Data (or Setup) packet
arm_e0o
	comf	E0O_STA,w	; toggle DTS
	andlw	1<<DTS
	iorlw	1<<DTSEN
arm_e0o_w			; W specifies STAT flags
	;assume	E0_BUF
	movwf	E0O_STA
	movlwf	1<<E0_SSH,E0O_CNT	; reset the buffer count
	bsf	E0O_STA,UOWN	; arm the OUT endpoint
	return

_ans	decf	WREG,w
	banksel	SETUPDAT_CNT
	movwf	SETUPDAT_CNT
; If requested length is shorter, transfer less than descriptor size
	tstf	wLengthH
	brnz	_sc1	; more than 255 bytes requested (Windows 7: 0x109)
	subwf	wLengthL,w
	brc	_sc1	; if W <= f, no need to adjust
	movfwf	wLengthL,SETUPDAT_CNT
_sc1	movfwf2	FSR0,SETUPDAT_PTR
; Finishes a successful SETUP transaction.
; SETUPDAT_CNT contains transfer length.
	banksel	UCON
	bcf	UCON,PKTDIS		; reenable packet processing
	banksel	USB_STATE
	btfss	bmRequestType,7
	 bra	_cwrite
; this is a control read; prepare the IN endpoint for the data stage
; and the OUT endpoint for the status stage
	call	ep0_send_in		; read data into IN buffer
	movlw	1<<DTS|1<<DTSEN		; make OUT buffer ready for status stage
; value in W is used to specify the EP0 OUT flags
_armbfs	call	arm_e0o_w
; Send next packet to Endpoint 0 In, size already set to E0I_CNT
arm_e0i
	comf	E0I_STA,w	; toggle DTS
	andlw	1<<DTS
	iorlw	1<<DTSEN
arm_e0i_w			; W specifies STAT flags
	movwf	E0I_STA
	bsf	E0I_STA,UOWN
	return
; this is a control write: prepare the IN endpoint for the status stage
; and the OUT endpoint for the next SETUP transaction
_cwrite	bcf	E0I_STA,UOWN	; ensure we have ownership of the buffer
	clrf	E0I_CNT	; we'll be sending a zero-length packet
	movlw	1<<DTSEN|1<<BSTALL	; make OUT buffer ready for next SETUP packet
	bra	_armbfs			; arm OUT and IN buffers

;========================
;= EP0 Setup Dispatcher =
;========================
; Must return W = AnswerLength and FSR0 = AnswerPointer for queries (RAM or Flash)
; Or W == -1 for error. Caller will then handle data output.
onSetup
	assume	0
	movlwf2	ROM001,FSR0	; zur Rückgabe von 0, 0-0 oder 0-1 vorbereiten
	movfw	bmRequestType
	bz	_bm00
	xorlw	0x01
	bz	_bm01
	xorlw	0x21^0x01
	bz	_bm21
	xorlw	0x80^0x21
	bz	_bm80
	xorlw	0x81^0x80
	bz	_bm81
	xorlw	0xA1^0x81
	bz	_bmA1
	xorlw	0xC0^0xA1
	bz	_bmC0
	retlw	-1
_bm00	;OUT, STD, DEVICE
	decfsz	bRequest,w
	 retlw	0		;1 = Clear Feature (ignorieren)
	addlw	-2
	skpnz
	 retlw	0		;3 = Set Feature (ignorieren)
	addlw	-2
	skpnz
	 retlw	0		;5 = SET_ADDRESS (passiert später)
	addlw	-4
	skpz			;9 = SET_CONFIG?
	 retlw	-1
; Handles a Set Configuration request.
	movfw	wValueL		; should be 0 or 1
	movwf	USB_STATE
; Initializes the buffers for the CDC endpoints (1 OUT, 1 IN, and 2 IN).
; clobbers:	W, BSR=0
	movlw	1<<DTSEN	; expect DATA0 first
	;call	arm_e1o_w
	movwf	E1I_STA		; USB NAK and toggle bit set: Send first packet as DATA0
	;bra	_setup_complete
	retlw	0
_bm01	;OUT, STD, IFACE[wIndexL]
	movfw	bRequest
	addlw	-11		;11 = Set Iface
	skpz
	 retlw	-1
	retlw	0		;ignorieren und OK
_bm21	;OUT, CLASS, IFACE[wIndexL]
	movfw	bRequest
	addlw	-9		;9 = Set Report
	skpz
	 retlw	-1
	movfw	wValueL
	goto	onEp0SetReport
_bm80	;IN, STD, DEVICE
	movfw	bRequest	;0 = Get Status (BusPower)
	skpnz
	 retlw	2		;2 Nullbytes liefern
	xorlw	6		;6 = GET_DESCRIPTOR
	brz	getDesc
	xorlw	8^6
	skpz			;8 = Get Config
	 retlw	-1
	addfsr	FSR0,1
	btfsc	USB_STATE,CONFIGURED	; bit 0
	 addfsr	FSR0,1
	retlw	1		;0 oder 1 liefern
_bm81	;IN, STD, IFACE[wIndexL]
	movfw	bRequest	;0 = Get Status
	skpnz
	 retlw	2		;2 Nullbytes liefern
	xorlw	10
	skpnz
	 retlw	1		;10 = Get Iface: 1 Nullbyte liefern
	xorlw	6^10
	skpz
	 retlw	-1
	movfw	wValueH
	xorlw	0x22		; HID?
	skpz
	 retlw	-1
	movlwf2	HidRepDesc,FSR0
	retlw	HidRepDescLen
_bmA1	;IN, CLASS, IFACE[wIndexL]
	decfsz	bRequest,w
	 retlw	-1
	movfw	wValueL
	goto	onEp0GetReport
_bmC0	;IN, VENDOR, DEVICE
	decfsz	bRequest,w
	 bra	_nvr01
	movlwf2	LandingPageDesc,FSR0
	bra	retind		;Länge aus Deskriptor
_nvr01
	decfsz	WREG,w
	 retlw	-1
	movlwf2	MsOs20Desc,FSR0
	retlw	MsOs20DescLen

;=================================
;= Device-Deskriptoren festlegen =
;=================================
;PE: wValueH = Deskriptortyp
;PA: FSR0 = Zeiger auf (gepackten) Deskriptor
;    W = Länge in (ausgepackten) Bytes
;    W = -1 bei Fehler (EP0STALL)
getDesc:
	assume	0
; Handles a Get Descriptor request.
; check descriptor type
	decfsz	wValueH,w		;1 = DESC_DEVICE
	 bra	_ndesc01
	movlwf2	DeviceDesc,FSR0
	bra	retind
_ndesc01
	decfsz	WREG,w			;2 = DESC_CONFIG
	 bra	_ndesc02
	movlwf2	ConfigDesc,FSR0
	retlw	ConfigDescLen	; length includes all subordinate descriptors
_ndesc02
	decfsz	WREG,w			;3 = String-Deskriptor
	 bra	_ndesc03
	movlwf2	StringDesc,FSR0
	incf	wValueL,f
	bra	_d3f
_d3l	movfw	INDF0
	lsrf	WREG,w		;halbieren weil String-Deskriptoren gepackt abgelegt sind
	addwf	FSR0L,f
	skpnc
	 incf	FSR0H,f
_d3f	loop	wValueL,_d3l
retind	movfw	INDF0		;Länge aus Deskriptor
	return
_ndesc03
	addlw	3-0x0F		; BOS?
	skpz
	 retlw	-1		; Kein gültiger Deskriptor
	movlwf2	BosDesc,FSR0
	retlw	BosDescLen

; Handles an IN control transfer on endpoint 0.
; Can be (descriptor) data or an acknowledge zero-length packet
; BSR=0
_usb_ctrl_in
	btfss	USB_STATE,IS_CONTROL_READ	; is this a control read or write?
	 bra	_check_for_pending_address
; fetch more data and re-arm the IN endpoint
	call	ep0_send_in
	bra	arm_e0i			; arm the IN buffer
	
; if this is the status stage of a Set Address request, assign the address here.
; The OUT buffer has already been armed for the next SETUP.
_check_for_pending_address
	movfw	bRequest
	xorlw	5
	skpz
	 return
; read the address out of the setup packed in the OUT buffer
	movfw	wValueL
	banksel	UADDR
	movwf	UADDR
	return

; Reads descriptor data from SETUPDAT_PTR, copies it to the EP0 IN buffer,
; and decrements SETUPDAT_CNT.
; Cannot simply point EP0_ADDR to flash as it is not accessible by USB SIE
; args:		BSR=0
; returns:	SETUPDAT_PTR advanced
;		SETUPDAT_CNT decremented
; clobbers:	W, FSR0, FSR1
ep0_send_in
	clrf	E0I_CNT	; initialize transfer length to 0
	tstf	SETUPDAT_CNT	; do nothing if there are 0 bytes to send
	skpnz
	 return
	movfwf2	SETUPDAT_PTR,FSR0	; set up source pointer
	movlwf	E0_BUF,FSR1L	; Here: Banked address (not a problem), set up destination pointer
	clrf	FSR1H
	clrdc
	btfsc	USB_STATE,DECOMP
	 setdc			; copy DECOMP flag to STATUS.DC (free inside loop and non-banked)
; byte copy loop with decompression, STATUS.C is free too (for another compression)
_bcopy:	btfsc	E0I_CNT,E0_SSH	; 16 Bytes full?
	 bra	_bcdone
	btfss	FSR0H,7		;Flash?
	 bra	_bcram		;nein, vom RAM (Byte) lesen
	banksel	PMCON1
	brdc	_bchi
	clrf	PMCON1
	movfwf2	FSR0,PMADR
	bsf	PMCON1,RD	;vom Flash (14 bit) lesen
	nop
	nop
	movfw	PMDATH
	xorlw	0x34		; unpacked byte if == 0x34xx
	skpz	
	 setdc			; packed word if != 0x34xx
	movfw	PMDATL
	addfsr	FSR0,1
	bra	_bclo
_bchi:	clrdc
	movfw	PMDATH		; For next byte, deliver high byte (Bits 6 and 7 are zero)
_bclo:	banksel	USB_STATE
	bra	_bcput
_bcram:	moviw	FSR0++
_bcput:	movwi	FSR1++
	incf	E0I_CNT,f	; increase number of bytes in transmit buffer
	loop	SETUPDAT_CNT,_bcopy	; decrement number of bytes remaining
; write back the updated source pointer
_bcdone	bcf	USB_STATE,DECOMP
	skpndc
	 bsf	USB_STATE,DECOMP	;copy STATUS.DC to USB_STATE.DECOMP
	movfwf2	FSR0,SETUPDAT_PTR
	return

	if 0
;Send data chunk to host. Note that a short packet ends a transfer unit (= chunk for ReadFile).
;In case the last packet is full, a zero-length packet must be appended to mark the end of chunk.
;args:	W=Bytes (0..64)
;	EP1IN buffer filled with data
;clobbers: W,bank=0
usbTx	banksel	0
_u1	btfsc	E1I_STA,UOWN	; spinloop until previous buffer is read by USB host
	 bra	_u1		; (Bug: May hang if USB connection is somehow lost in between)
	movwf	E1I_CNT		; put transfer size
	comf	E1I_STA,w	; toggle DTS
	andlw	1<<DTS		; clear all other bits (STALL too)
	iorlw	1<<DTSEN	; 0↕001000 = use toggle bit
	movwf	E1I_STA
	bsf	E1I_STA,UOWN	; give to SIE
	return
	endif

;Stellt EP0 scharf und wartet auf OUT-Paket
usbEp0Recv
	banksel	UCON
	bcf	UCON,PKTDIS		; reenable packet processing
	banksel	0
	call	arm_e0o
_busy	banksel	UIR		; Bank 29
	btfsc	UIR,URSTIF	; reset?
	 goto	err		;Böse: Stack aufräumen lassen, USB-Reset später abarbeiten
; service transactions
	btfss	UIR,TRNIF
	 goto	_busy
	bcf	UIR,TRNIF
	banksel	E0O_STA		; Bank 0
	btfsc	E0O_STA,UOWN	;Daten vorhanden?
	 goto	_busy		;nein, anderes Ereignis, hier ignorieren
	movfw	E0O_STA		; All non-PID bits are zero here because SETUP comes with DATA0
	xorlw	13<<2		; 13=PID_SETUP — is it a SETUP packet?
	brz	err		;ja, aber es muss hier ein OUT-Paket sein!
	clrc
	return			;okay
err	setc
	return			;nicht okay

usbInit
; Configure the oscillator (48MHz from INTOSC using 3x PLL)
	banksel	OSCCON		; bank 1
	movlwf	0xFC,OSCCON
; Wait for the oscillator and PLL to stabilize
_wosc	comf	OSCSTAT,w
	andlw	(1<<PLLRDY)|(1<<HFIOFR)|(1<<HFIOFS)
	brnz	_wosc
; Enable active clock tuning
	banksel	ACTCON		; Bank 7
	movlwf	(1<<ACTSRC)|(1<<ACTEN),ACTCON		; source = USB
; Initialize USB
	call	usbReset
; Attach to the bus (could be a subroutine, but inlining it saves 2 instructions)
	banksel	UCON		; Bank 29
	clrf	UCON		; reset UCON
	bsf	UCON,USBEN	; enable USB module and wait until ready
ret	return

; Initializes the USB system and resets all associated registers.
; clobbers:	W,BSR=0,FSR0,FSR1L
usbReset
; clear USB registers
	banksel	UIR		; Bank 29
	clrf	UIR
; set configuration
	movlwf	(1<<UPUEN)|(1<<FSEN),UCFG	; enable pullups, full speed, no ping-pong buffering
	;movlwf	(1<<TRNIE)|(1<<URSTIE),UIE	; TODO: Need interrupts for CPU wakeup later
; clear all BDT entries, variables, and buffers
	clrf	FSR0H
	movlwf	0x20,FSR0L	; BDT starts at 0x2000 aka 0x20, clear all Bank0 variables except RxBuf
	call	ZeroMemory	; use 0x20 as loop count
; reset ping-pong buffers and address
	banksel	UCON		; Bank 29: All about USB
	bsf	UCON,PPBRST
	clrf	UADDR
	bcf	UCON,PKTDIS	; enable packet processing
	bcf	UCON,PPBRST	; clear ping-pong buffer reset flag
; flush pending transactions
_tflush	btfss	UIR,TRNIF
	 bra	_initep
	bcf	UIR,TRNIF
	call	ret		; need at least 6 cycles before checking TRNIF again
	bra	_tflush

; initialize endpoints:
; 0 for control
; 1 for HID interrupt
; 2 for WebUSB interrupt
_initep	movlwf	1<<EPHSHK|1<<EPOUTEN|1<<EPINEN,UEP0
	movlwf	1<<EPHSHK|1<<EPCONDIS|1<<EPINEN,UEP1
	movlwf	1<<EPHSHK|1<<EPCONDIS|1<<EPINEN,UEP2
; initialize endpoint buffers and counts
	banksel	E0O_ADR		; Bank 0
	movlwf	low LIN_E0_BUF, E0O_ADR	; set endpoint 0 address low
	movwf			E0I_ADR
	movlwf	low LIN_E1I_BUF,E1I_ADR	; set endpoint 1 IN address low
	movlwf	low LIN_E2I_BUF,E2I_ADR	; set endpoint 1 IN address low
	movlwf	high LIN_E0_BUF,E0O_ADR+1	; set all ADRH values to 0x20
	movwf			E0I_ADR+1
	movwf			E1I_ADR+1
	movwf			E2I_ADR+1
	goto	e0o_stall

; Descriptors
;########################################################################
;# Die Deskriptoren sind in die 14-Bit-Flash-Wörter derart gepackt,	#
;# dass WORD-Werte <0x4000 direkt im Flash abgelegt werden		#
;# und Byte-Werte mit dem High-Byte 0x34 (für Opcode retlw aus dt)	#
;# Der Spareffekt ist erheblich, weil WinUSB/WebUSB viel Platz braucht.	#
;# Größenberechnungen funktionieren so nicht mehr.			#
;########################################################################
dt2 macro x,y	; für Bytes, wenn das 2. Byte < 0x40 und nicht 0x34 ist
	dw	y<<8|x
 endm
 
; Es gibt folgende HID-Deskriptoren:
;Nr.1	Report-ID		8	(nur lesen: Interrupt)
;	Zustand Rauchmelder	1
;	Zustand Testalarm	1
;	Grenzwertalarm		4
;	A/D-Wert Gassensor	16
;	A/D-Wert Chiptemperatur	16
;	Wert vom Pyrosensor	16
;	Werte von DS18B20	4×16
;Nr.2	Report-ID		8	(schreiben/lesen: Feature)
;	Testalarm		1
;	Sprung zum Urlader	1	(write-only)
;	Kontroll-LED		1
;	Grenzwert Gassensor	16
;	Grenzwert Chiptemp.	16
;	Grenzwert Pyrosensor	16
;	Grenzwerte DS18B20	4×16
;Nr.3	Report-ID		8	(schreiben/lesen: Feature)
;	Cookies			15×8
;Nr.4	Report-ID		8	(schreiben/lesen: Feature)
;	Index DS18B20		2 (8)
;	ID der DS18B20		64 	(nur lesen)
; Die Größe ist auf 16 Bytes beschränkt.
; Die gleichen „Deskriptoren“ werden auch für WebUSB verwendet.
; Eine Umrechnung in °C muss das Anwendungsprogramm machen.
HidRepDesc
	dt2	0x06,0x3F
	dt	0xFF		;G Usage Page: Unknown (0xFF3F)
	dt2	0x09,1		;L Usage: 1
	dt2	0xA1,1		;M Collection
	dt2	 0x75,8		;G  Report Size
	dt2	 0x95,15	;G  Report Count
	dt2	 0x15,0		;G  Logical Minimum
	dt	 0x26;,255,0	;G  Logical Maximum
	dt2	255,0
;Nr.1
	dt2	 0x85,1		;M  Report ID (1)
	dt2	 0x09,1		;L  Usage: 1 (Byte-Array)
	dt2	 0x81,2		;M  Input: Variable
;Nr.2
	dt2	 0x85,2		;M  Report ID (2)
	dt2	 0x09,2		;L  Usage: 2 (Byte-Array)
	dt2	 0xB1,2		;M  Feature: Variable
;Nr.3
	dt2	 0x85,3		;M  Report ID (3)
	dt2	 0x09,3		;L  Usage: 3 (Byte-Array)
	dt2	 0xB1,2		;M  Feature: Variable
;Nr.4
	dt2	 0x85,4		;M  Report ID (3)
	dt2	 0x09,4		;L  Usage: 3 (Byte-Array)
	dt2	 0x95,9		;G  Report Count (hier nur 9 Bytes, Gesamtlänge 10)
	dt2	 0xB1,2		;M  Feature: Variable
	dt	0xC0		;M End Collection
HidRepDescLen equ (16+6+6+6+9)

DeviceDesc
	dt2	18,1		; bLength		; bDescriptorType
	dw	0x0210		; bcdUSB (USB 2.1)
	dt2	0,0		; bDeviceClass		; bDeviceSubclass
	dt2	0,1<<E0_SSH	; bDeviceProtocol	; bMaxPacketSize0 (16 bytes)
	dw	0x16C0		; idVendor (Voti)
	dw	0x27D9		; idProduct (HID no keyboard/mouse/joystick)
	dw	0x0300		; bcdDevice
	dt2	1,2		; iVendor		; iProduct
	dt2	3,1		; iSerialNo		; bNumConfig

ConfigDesc
	dt2	9,2		; bLength		; bDescType
	dw	ConfigDescLen	; wTotalLength
	dt2	2,1		; bNumIfaces		; bConfigValue
	dt	0		; iConfig
	dt2	0x80,50		; bmAttributes (BusPwr)	; bMaxPower (100 mA)
;iface 0
	dt2	9,4		; bLength		; bDescType (IFACE)
ROM001	; Three adjanced addresses containing [0,0,1]
	dt	0		; bIfaceNumber
	dt	0		; bAlternateSetting
	dt	1		; bNumEndpoints
	dt2	3,0		; bIfaceClass (HID)	; bIfaceSubclass
	dt2	0,4		; bIfaceProtocol	; iIface
;HID descr.
	dt2	9,0x21		; bLength		; bDescType
	dw	0x0110		; bcdHID
	dt2	0,1		; bCountryCode		; bNumDescs
	dt	0x22		; bDescType	Report 
	dw	HidRepDescLen	; wDescLength
;endpoint
	dt2	7,5		; bLength		; bDescType (ENDPOINT)
	dt2	0x81,3		; bEndpointAddr (1 IN)	; bmAttributes (interrupt)
	dw	1<<E1I_SSH	; wMaxPacketSize (16)
	dt	250		; bInterval (250 ms)
;iface 1
	dt2	9,4		; bLength		; bDescType (INTERFACE)
	dt2	1,0		; bIfaceNumber		; bAlternateSetting
	dt	1		; bNumEndpoints
	dt2	0xFF,0		; bIfaceClass (vendor)	; bIfaceSubclass
	dt2	0,5		; bIfaceProtocol	; iIface
;endpoint
	dt2	7,5		; bLength		; bDescType (ENDPOINT)
	dt2	0x82,3		; bEndpointAddr (2 IN)	; bmAttributes (interrupt)
	dw	1<<E2I_SSH	; wMaxPacketSize (16)
	dt	250		; bInterval (250 ms)
ConfigDescLen equ (9+9+9+7+9+7)

BosDesc
	dt2	5,0x0F		; Length		; Binary Object Store descriptor
	dw	57		; Total length
	dt	2		; Number of device capabilities
; WebUSB Platform Capability descriptor (bVendorCode == 0x01).
	dt2	0x18,0x10	; Length		; Device Capability descriptor
	dt2	0x05,0x00	; Platform Capability descriptor	; Reserved
	dt	0x38,0xB6,0x08,0x34,0xA9,0x09,0xA0,0x47,0x8B,0xFD,0xA0,0x76,0x88,0x15,0xB6,0x65	; WebUSB GUID
	dw	0x0100		; Version 1.0
	dt2	0x01,0x01	; Vendor request code	(-> bRequest)	; Landing page		(-> wValueL)
; Microsoft OS 2.0 Platform Capability Descriptor (MS_VendorCode == 0x02)
	dt2	0x1C,0x10	; Length		; Device Capability descriptor
	dt2	0x05,0x00	; Platform Capability descriptor	; Reserved
	dt	0xDF,0x60,0xDD,0xD8,0x89,0x45,0xC7,0x4C,0x9C,0xD2,0x65,0x9D,0x9E,0x64,0x8A,0x9F	; MS OS 2.0 GUID
	dw	0,0x0603	; Windows version
	dw	0x00B2		; Descriptor set length
	dt2	0x02,0x00	; Vendor request code	; Alternate enumeration code
BosDescLen equ 57

MsOs20Desc
	dw	10		; Descriptor size (10 bytes)
	dw	0		; MS OS 2.0 descriptor set header
	dw	0,0x0603	; Windows version (8.1) (0x06030000)
	dw	0x00B2		; Size, MS OS 2.0 descriptor set
; Microsoft OS 2.0 configuration subset header
	dw	8		; Descriptor size (8 bytes)
	dw	1		; MS OS 2.0 configuration subset header
	dw	0		; bConfigurationValue
	dw	0x00A8		; Size, MS OS 2.0 configuration subset
; Microsoft OS 2.0 function subset header
	dw	8		; Descriptor size (8 bytes)
	dw	2		; MS OS 2.0 function subset header
	dw	1		; iface number
	dw	0x00A0		; Size, MS OS 2.0 function subset
; Microsoft OS 2.0 compatible ID descriptor (table 13)
	dw	20		; wLength
	dw	3		; MS_OS_20_FEATURE_COMPATIBLE_ID
	dt	"WINUSB"	; compatID[8]
	dw	0
	dw	0,0,0,0		; subcompatID[8];
;CUSTOM_PROPERTY
	dw	4+21+1+40<<1	; wLength: 
	dw	4		; wDescType: MS_OS_20_FEATURE_REG_PROPERTY: 0x04 (Table 9)
	dw	7		; wPropertyDataType: REG_MULTI_SZ (Table 15)
	dw	21<<1		; wPropertyNameLength:
	dw	'D','e','v','i','c','e','I','n','t','e','r','f','a','c','e','G','U','I','D','s',0	; bPropertyName
	dw	40<<1		; wPropertyDataLength
	dw	'{','9','7','5','F','4','4','D','9','-','0','D','0','8','-','4','3','F','D','-','8','B','3','E','-'
	dw	'1','2','7','C','A','8','A','F','F','F','9','D','}',0,0	; bPropertyData
MsOs20DescLen equ (23+66<<1)

LandingPageDesc
	dw	0x032E		; strlen(landingPageUrl)+3	; descriptorType(String)
	dt	0x01		; landingPageScheme(https://)
	dt	"www.tu-chemnitz.de/~heha/ewa/Ofen/rauch.htm"

;Der String-Deskriptor darf laut Programmlogik nur aus "dw" bestehen, chinesisch geht dann nicht, Unicodes < 0x4000
StringDesc		; High-Teil = DTYPE_String, Low-Teil = (String-Länge+1)*2
	dw	0x0304
	dw	0x0407		; (0) Länge 1: deutsch
	dw	0x0322
	dw	'T','U',' ','C','h','e','m','n','i','t','z',',',' ','E','W','A'	; (1) Länge 16
	dw	0x0318
	dw	'R','a','u','c','h','m','e','l','d','e','r'			; (2) Länge 11
	dw	0x0330
	dw	'h','e','h','a','@','h','r','z','.','t','u','-','c','h','e','m','n','i','t','z','.','d','e'	;(3) Länge 23
	dw	0x0308
	dw	'H','I','D'			; (4) Länge 3
	dw	0x030E
	dw	'W','e','b','U','S','B'		; (5) Länge 6
StringDescEnd
Detected encoding: UTF-80