	.module main
	
	;; same as audiofirmware, but do not announce as
	;; audio class compliant
	
	;; ENDPOINTS
	;; EP0 in/out   Control
	;; EP1 in       Interrupt:  Status
	;;              Byte 0: Modem Status
	;;                Bit 0-1: Transmitter status
	;;                         0: idle (off)
	;;                         1: keyup
	;;                         2: transmitting packets
	;;                         3: tail
	;;                Bit 2:   PTT status (1=on)
	;;                Bit 3:   DCD
	;;                Bit 5:   UART transmitter empty
	;;                Bit 6-7: unused
	;;              Byte 1: Number of empty 64 byte chunks in TX fifo (sofcount)
	;;              Byte 2: Number of full 64 byte chunks in RX fifo (INISOVAL)
	;;              Byte 3: RSSI value
	;;              Byte 4:	IRQ count
	;;              Byte 5-20: (as needed) UART receiver chars
	;; EP8 out      audio output
	;; EP8 in       audio input

	;; COMMAND LIST
	;; C0 C0  read status (max. 23 bytes, first 6 same as EP1 in)
	;; C0 C8  read mode
	;;          Return:
	;;            Byte 0: 4 (MODE_AUDIO)
	;; C0 C9  return serial number string
	;; C0 D0  get/set PTT/DCD/RSSI
	;;          wIndex = 1:	set forced ptt to wValue
	;;          Return:
	;;            Byte 0: PTT status
	;;            Byte 1: DCD status
	;;            Byte 2: RSSI status
	;; 40 D2  set CON/STA led
	;;          Bits 0-1 of wValue
	;; 40 D3  send byte to UART
	;;          Byte in wValue
	;; C0 D4  get/set modem disconnect port (only if internal modem used, stalls otherwise)
	;;          wIndex = 1:	write wValue to output register
	;;          wIndex = 2:	write wValue to tristate mask register (1 = input, 0 = output)
	;;          Return:
	;;            Byte 0: Modem Disconnect Input
	;;            Byte 1: Modem Disconnect Output register
	;;            Byte 2: Modem Disconnect Tristate register
	;; C0 D5  get/set T7F port
	;;          wIndex = 1:	write wValue to T7F output register
	;;          Return:
	;;            Byte 0: T7F Input
	;;            Byte 1: T7F Output register
	;; C0 E0  get/set control register/counter values
	;;          wIndex = 1:	write wValue to control register
	;;          Return:
	;;            Byte 0: control register value
	;;            Byte 1-3: counter0 register
	;;            Byte 4-6: counter1 register
	;; C0 E1  get debug status
	;;          Return:
	;;            Byte 0: SOF count
	;;            Byte 1: framesize
	;;            Byte 2-3: divider
	;;            Byte 4: divrel
	;;            Byte 5: pllcorrvar
	;;            Byte 6: txfifocount
	;; C0 E2  xxdebug stuff
	
	;; define code segments link order
	.area CODE (CODE)
	.area CSEG (CODE)
	.area GSINIT (CODE)
	.area GSINIT2 (CODE)

	;; -----------------------------------------------------

	;; special function registers (which are not predefined)
	dpl0    = 0x82
	dph0    = 0x83
	dpl1    = 0x84
	dph1    = 0x85
	dps     = 0x86
	ckcon   = 0x8E
	spc_fnc = 0x8F
	exif    = 0x91
	mpage   = 0x92
	scon0   = 0x98
	sbuf0   = 0x99
	scon1   = 0xC0
	sbuf1   = 0xC1
	eicon   = 0xD8
	eie     = 0xE8
	eip     = 0xF8

	;; anchor xdata registers
	IN0BUF		= 0x7F00
	OUT0BUF		= 0x7EC0
	IN1BUF		= 0x7E80
	OUT1BUF		= 0x7E40
	IN2BUF		= 0x7E00
	OUT2BUF		= 0x7DC0
	IN3BUF		= 0x7D80
	OUT3BUF		= 0x7D40
	IN4BUF		= 0x7D00
	OUT4BUF		= 0x7CC0
	IN5BUF		= 0x7C80
	OUT5BUF		= 0x7C40
	IN6BUF		= 0x7C00
	OUT6BUF		= 0x7BC0
	IN7BUF		= 0x7B80
	OUT7BUF		= 0x7B40
	SETUPBUF	= 0x7FE8
	SETUPDAT	= 0x7FE8

	EP0CS		= 0x7FB4
	IN0BC		= 0x7FB5
	IN1CS		= 0x7FB6
	IN1BC		= 0x7FB7
	IN2CS		= 0x7FB8
	IN2BC		= 0x7FB9
	IN3CS		= 0x7FBA
	IN3BC		= 0x7FBB
	IN4CS		= 0x7FBC
	IN4BC		= 0x7FBD
	IN5CS		= 0x7FBE
	IN5BC		= 0x7FBF
	IN6CS		= 0x7FC0
	IN6BC		= 0x7FC1
	IN7CS		= 0x7FC2
	IN7BC		= 0x7FC3
	OUT0BC		= 0x7FC5
	OUT1CS		= 0x7FC6
	OUT1BC		= 0x7FC7
	OUT2CS		= 0x7FC8
	OUT2BC		= 0x7FC9
	OUT3CS		= 0x7FCA
	OUT3BC		= 0x7FCB
	OUT4CS		= 0x7FCC
	OUT4BC		= 0x7FCD
	OUT5CS		= 0x7FCE
	OUT5BC		= 0x7FCF
	OUT6CS		= 0x7FD0
	OUT6BC		= 0x7FD1
	OUT7CS		= 0x7FD2
	OUT7BC		= 0x7FD3

	IVEC		= 0x7FA8
	IN07IRQ		= 0x7FA9
	OUT07IRQ	= 0x7FAA
	USBIRQ		= 0x7FAB
	IN07IEN		= 0x7FAC
	OUT07IEN	= 0x7FAD
	USBIEN		= 0x7FAE
	USBBAV		= 0x7FAF
	BPADDRH		= 0x7FB2
	BPADDRL		= 0x7FB3

	SUDPTRH		= 0x7FD4
	SUDPTRL		= 0x7FD5
	USBCS		= 0x7FD6
	TOGCTL		= 0x7FD7
	USBFRAMEL	= 0x7FD8
	USBFRAMEH	= 0x7FD9
	FNADDR		= 0x7FDB
	USBPAIR		= 0x7FDD
	IN07VAL		= 0x7FDE
	OUT07VAL	= 0x7FDF
	AUTOPTRH	= 0x7FE3
	AUTOPTRL	= 0x7FE4
	AUTODATA	= 0x7FE5

	;; isochronous endpoints. only available if ISODISAB=0

	OUT8DATA	= 0x7F60
	OUT9DATA	= 0x7F61
	OUT10DATA	= 0x7F62
	OUT11DATA	= 0x7F63
	OUT12DATA	= 0x7F64
	OUT13DATA	= 0x7F65
	OUT14DATA	= 0x7F66
	OUT15DATA	= 0x7F67

	IN8DATA		= 0x7F68
	IN9DATA		= 0x7F69
	IN10DATA	= 0x7F6A
	IN11DATA	= 0x7F6B
	IN12DATA	= 0x7F6C
	IN13DATA	= 0x7F6D
	IN14DATA	= 0x7F6E
	IN15DATA	= 0x7F6F

	OUT8BCH		= 0x7F70
	OUT8BCL		= 0x7F71
	OUT9BCH		= 0x7F72
	OUT9BCL		= 0x7F73
	OUT10BCH	= 0x7F74
	OUT10BCL	= 0x7F75
	OUT11BCH	= 0x7F76
	OUT11BCL	= 0x7F77
	OUT12BCH	= 0x7F78
	OUT12BCL	= 0x7F79
	OUT13BCH	= 0x7F7A
	OUT13BCL	= 0x7F7B
	OUT14BCH	= 0x7F7C
	OUT14BCL	= 0x7F7D
	OUT15BCH	= 0x7F7E
	OUT15BCL	= 0x7F7F

	OUT8ADDR	= 0x7FF0
	OUT9ADDR	= 0x7FF1
	OUT10ADDR	= 0x7FF2
	OUT11ADDR	= 0x7FF3
	OUT12ADDR	= 0x7FF4
	OUT13ADDR	= 0x7FF5
	OUT14ADDR	= 0x7FF6
	OUT15ADDR	= 0x7FF7
	IN8ADDR		= 0x7FF8
	IN9ADDR		= 0x7FF9
	IN10ADDR	= 0x7FFA
	IN11ADDR	= 0x7FFB
	IN12ADDR	= 0x7FFC
	IN13ADDR	= 0x7FFD
	IN14ADDR	= 0x7FFE
	IN15ADDR	= 0x7FFF

	ISOERR		= 0x7FA0
	ISOCTL		= 0x7FA1
	ZBCOUNT		= 0x7FA2
	INISOVAL	= 0x7FE0
	OUTISOVAL	= 0x7FE1
	FASTXFR		= 0x7FE2

	;; CPU control registers

	CPUCS		= 0x7F92

	;; IO port control registers

	PORTACFG	= 0x7F93
	PORTBCFG	= 0x7F94
	PORTCCFG	= 0x7F95
	OUTA		= 0x7F96
	OUTB		= 0x7F97
	OUTC		= 0x7F98
	PINSA		= 0x7F99
	PINSB		= 0x7F9A
	PINSC		= 0x7F9B
	OEA		= 0x7F9C
	OEB		= 0x7F9D
	OEC		= 0x7F9E

	;; I2C controller registers

	I2CS		= 0x7FA5
	I2DAT		= 0x7FA6

	;; Xilinx FPGA registers
	AUDIORXFIFO	= 0xc000
	AUDIOTXFIFO	= 0xc000
	AUDIORXFIFOCNT	= 0xc001
	AUDIOTXFIFOCNT	= 0xc002
	AUDIODIVIDERLO	= 0xc001
	AUDIODIVIDERHI	= 0xc002
	AUDIORSSI	= 0xc004
	AUDIOCNTLOW	= 0xc005
	AUDIOCNTMID	= 0xc006
	AUDIOCNTHIGH	= 0xc007
	AUDIOCTRL	= 0xc008
	AUDIOSTAT	= 0xc009
	AUDIOT7FOUT	= 0xc00a
	AUDIOT7FIN	= 0xc00b
	AUDIOMDISCTRIS	= 0xc00c
	AUDIOMDISCOUT	= 0xc00d
	AUDIOMDISCIN	= 0xc00e

	AUDIOCTRLPTT	= 0x01
	AUDIOCTRLMUTE	= 0x02
	AUDIOCTRLLEDPTT	= 0x04
	AUDIOCTRLLEDDCD	= 0x08
	AUDIOCTRLCNTRES	= 0x00
	AUDIOCTRLCNTDIS	= 0x10
	AUDIOCTRLCNTCK0	= 0x40
	AUDIOCTRLCNTCK1	= 0x50
	AUDIOCTRLCNTCK2	= 0x60
	AUDIOCTRLCNTCK3	= 0x70
	AUDIOCTRLCNTRD1	= 0x80

	;; -----------------------------------------------------

	.area CODE (CODE)
	ljmp	startup
	ljmp	int0_isr
	.ds	5
	ljmp	timer0_isr
	.ds	5
	ljmp	int1_isr
	.ds	5
	ljmp	timer1_isr
	.ds	5
	ljmp	ser0_isr
	.ds	5
	ljmp	timer2_isr
	.ds	5
	ljmp	resume_isr
	.ds	5
	ljmp	ser1_isr
	.ds	5
	ljmp	usb_isr
	.ds	5
	ljmp	i2c_isr
	.ds	5
	ljmp	int4_isr
	.ds	5
	ljmp	int5_isr
	.ds	5
	ljmp	int6_isr
	
	;; Parameter block at 0xe0
	.ds	0x7a
parframesize:	.db	8
parpttmute:	.db	1

	;; Serial# string at 0xf0
	.ds	14
parserial:
	.db	'0,'0,'0,'0,'0,'0,'0,'0,0
	.ds	7

usb_isr:
	ljmp	usb_sudav_isr
	.ds	1
	ljmp	usb_sof_isr
	.ds	1
	ljmp	usb_sutok_isr
	.ds	1
	ljmp	usb_suspend_isr
	.ds	1
	ljmp	usb_usbreset_isr
	.ds	1
	reti
	.ds	3
	ljmp	usb_ep0in_isr
	.ds	1
	ljmp	usb_ep0out_isr
	.ds	1
	ljmp	usb_ep1in_isr
	.ds	1
	ljmp	usb_ep1out_isr
	.ds	1
	ljmp	usb_ep2in_isr
	.ds	1
	ljmp	usb_ep2out_isr
	.ds	1
	ljmp	usb_ep3in_isr
	.ds	1
	ljmp	usb_ep3out_isr
	.ds	1
	ljmp	usb_ep4in_isr
	.ds	1
	ljmp	usb_ep4out_isr
	.ds	1
	ljmp	usb_ep5in_isr
	.ds	1
	ljmp	usb_ep5out_isr
	.ds	1
	ljmp	usb_ep6in_isr
	.ds	1
	ljmp	usb_ep6out_isr
	.ds	1
	ljmp	usb_ep7in_isr
	.ds	1
	ljmp	usb_ep7out_isr

	;; -----------------------------------------------------

	NUMINTERFACES = 4
	
	.area	OSEG (OVR,DATA)
	.area	BSEG (BIT)
ctrl_ptt:	.ds	1
ctrl_pttmute:	.ds	1
ctrl_ledptt:	.ds	1
ctrl_leddcd:	.ds	1	
ctrl_cntmode0:	.ds	1
ctrl_cntmode1:	.ds	1
ctrl_cntmode2:	.ds	1
ctrl_cntsel:	.ds	1
ctrlreg		=	0x20	; ((ctrl_ptt/8)+0x20)

pttmute:	.ds	1
uartempty:	.ds	1


	.area	ISEG (DATA)
txsamples:	.ds	0x40
stack:		.ds	0x80-0x40

	.area	DSEG (DATA)
ctrlcode:	.ds	1
ctrlcount:	.ds	2
leddiv:		.ds	1
irqcount:	.ds	1
sofcount:	.ds	1
divider:	.ds	2
divrel:		.ds	1
framesize:	.ds	1
pllcorrvar:	.ds	1
txfifocount:	.ds	1
pttforce:	.ds	1

	;; UART receiver
uartbuf:	.ds	16
uartwr:		.ds	1
uartrd:		.ds	1

	;; Port state
t7fout:		.ds	1
mdisctris:	.ds	1
mdiscout:	.ds	1
	
	;; USB state
numconfig:	.ds	1
altsetting:	.ds	NUMINTERFACES

	.area	XSEG (DATA)
blah:	.ds	1


	.area	GSINIT (CODE)
	ar2 = 0x02
	ar3 = 0x03
	ar4 = 0x04
	ar5 = 0x05
	ar6 = 0x06
	ar7 = 0x07
	ar0 = 0x00
	ar1 = 0x01

startup:
	mov	sp,#stack	; -1
	clr	a
	mov	psw,a
	mov	dps,a
	;lcall	__sdcc_external_startup
	;mov	a,dpl0
	;jz	__sdcc_init_data
	;ljmp	__sdcc_program_startup
__sdcc_init_data:

	.area	GSINIT2 (CODE)
__sdcc_program_startup:
	;; assembler code startup
	clr	a
 	mov	irqcount,a
	mov	sofcount,a
	mov	pttforce,a
	mov	uartrd,a
	mov	uartwr,a
	mov	dps,a
	setb	uartempty
	;; some indirect register setup
	mov	ckcon,#0x30	; zero external wait states, to avoid chip bugs
	;; Timer setup:
	;; timer 0: LED blink    : T0M=0, CT0=0, MODE0=1
	;; timer 1: Baudrate gen : T1M=1, CT1=0, MODE1=2
	mov	tmod,#0x21
	mov	tcon,#0x55	; INT0/INT1 edge
	mov	th1,#256-156	; 1200 bauds
	mov	pcon,#0		; SMOD0=0
	;; init USB subsystem
	mov	a,#0x00		; IN8 FIFO at address 0x0000
	mov	dptr,#IN8ADDR
	movx	@dptr,a
	mov	a,#0x04		; OUT8 FIFO at address 0x0010
	mov	dptr,#OUT8ADDR
	movx	@dptr,a
	mov	dptr,#ISOCTL
	clr	a		; enable ISO endpoints
	movx	@dptr,a
	mov	dptr,#USBBAV
	mov	a,#1		; enable autovector, disable breakpoint logic
	movx	@dptr,a
	mov	a,#0x01		; enable ISO endpoint 8 for input/output
	mov	dptr,#INISOVAL
	movx	@dptr,a
	mov	dptr,#OUTISOVAL
	movx	@dptr,a
	mov	dptr,#USBPAIR
	mov	a,#0x89		; pair EP 2&3 for input & output, ISOSEND0
	movx	@dptr,a
	mov	dptr,#IN07VAL
	mov	a,#0x3		; enable EP0+EP1
	movx	@dptr,a
	mov	dptr,#OUT07VAL
	mov	a,#0x1		; enable EP0
	movx	@dptr,a
	;; USB:	init endpoint toggles
	mov	dptr,#TOGCTL
	mov	a,#0x12
	movx	@dptr,a
	mov	a,#0x32		; clear EP 2 in toggle
	movx	@dptr,a
	mov	a,#0x02
	movx	@dptr,a
	mov	a,#0x22		; clear EP 2 out toggle
	movx	@dptr,a
	;; configure IO ports
	mov	dptr,#PORTACFG
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#OUTA
	mov	a,#0x82		; set PROG hi
	movx	@dptr,a
	mov	dptr,#OEA
	mov	a,#0xc2		; out: TMS,TDI,PROG  in: DONE
	movx	@dptr,a
	mov	dptr,#PORTBCFG
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#OEB
	mov	a,#0
	movx	@dptr,a
	mov	dptr,#PORTCCFG
	mov	a,#0xc3		; RD/WR/TXD0/RXD0 are special function pins
	movx	@dptr,a
	mov	dptr,#OUTC
	mov	a,#0x28
	movx	@dptr,a
	mov	dptr,#OEC
	mov	a,#0x2a		; out: LEDCON,LEDSTA,TCK  in: TDO,INIT
	movx	@dptr,a
	;; enable interrupts
	mov	ie,#0x92	; enable timer 0 and ser 0 int
	mov	eie,#0x01	; enable USB interrupts
	mov	dptr,#USBIEN
	mov	a,#1		; enable SUDAV interrupt
	movx	@dptr,a
	mov	dptr,#IN07IEN
	mov	a,#3		; enable EP0+EP1 interrupt
	movx	@dptr,a
	mov	dptr,#OUT07IEN
	mov	a,#1		; enable EP0 interrupt
	movx	@dptr,a
	;; initialize UART 0 for T7F communication
	mov	scon0,#0x52	; Mode 1, Timer 1, Receiver enable
        ;; copy configuration to bit addressable variables
        mov     ctrlreg,#AUDIOCTRLCNTRES
        mov     r0,#parpttmute
        movx    a,@r0
        mov     c,acc.0
        mov     pttmute,c
        mov     ctrl_pttmute,c
	;; turn off transmitter
	mov	dptr,#AUDIOCTRL
	mov	a,ctrlreg
	movx	@dptr,a
	;; Initialize modem disc port / t7f port
	mov	dptr,#AUDIOMDISCTRIS
	mov	a,#0xff
	movx	@dptr,a
	mov	mdisctris,a
	mov	dptr,#AUDIOMDISCOUT
	clr	a
	movx	@dptr,a
	mov	mdiscout,a
	mov	dptr,#AUDIOT7FOUT
	mov	a,#0x1f
	movx	@dptr,a
	mov	t7fout,a
	;; Copy serial number
	mov	r0,#parserial
	mov	dptr,#stringserial+2
1$:	movx	a,@r0
	jz	2$
	movx	@dptr,a
	inc	dptr
	inc	dptr
	inc	r0
	sjmp	1$
2$:	mov	a,r0
	add	a,#1-0xf0	; 1-parserial
	add	a,acc
	mov	dptr,#stringserial
	movx	@dptr,a
	;; check parameters
chkparam:
	mov	divrel,#0x80
	mov	r0,#parframesize
	movx	a,@r0
	cjne	a,#02,11$
	sjmp	2$
11$:	cjne	a,#03,1$
	sjmp	2$
1$:	add	a,#-8
	jnc	3$
	add	a,#-16
	jc	4$
	movx	a,@r0
	sjmp	5$
	;; sampling rate is: 24000000Hz/(divider+2)
4$:	mov	a,#24
	sjmp	5$
3$:	mov	a,#8
	;; 16 bit by 8 bit divide
	;; r2:	divisor
	;; r3:	loop counter
	;; r4:	dividend/result low
	;; r5:	dividend/result mid
	;; r6:	dividend/result high
5$:	mov	r2,a
	mov	r3,#17
	mov	r4,#24000
	mov	r5,#24000>>8
	mov	r6,#0
6$:	clr	c
	mov	a,r6
	subb	a,r2
	jc	7$
	mov	r6,a
7$:	cpl	c
	mov	a,r4
	rlc	a
	mov	r4,a
	mov	a,r5
	rlc	a
	mov	r5,a
	mov	a,r6
	rlc	a
	mov	r6,a
	djnz	r3,6$
	;; subtract two
	mov	a,r4
	clr	c
	subb	a,#2
	mov	r4,a
	mov	a,r5
	subb	a,#0
	mov	r5,a
	;; store result into audio divider
	mov	dptr,#AUDIODIVIDERHI
	movx	@dptr,a
	mov	a,r4
	mov	dptr,#AUDIODIVIDERLO
	movx	@dptr,a
	clr	c
	subb	a,#0x08
	mov	divider,a
	mov	a,r5
	subb	a,#0
	mov	divider+1,a
	;; reload divider into accu
	mov	a,r2
2$:	mov	framesize,a
	mov	dptr,#descinframesize
	movx	@dptr,a
	mov	dptr,#descoutframesize
	movx	@dptr,a
	;; set sampling rate in descriptor
	.if 0
	mov	b,#1000
	mul	ab
	mov	dptr,#descinsrate
	movx	@dptr,a
	mov	dptr,#descoutsrate
	movx	@dptr,a
	mov	r3,b
	mov	a,framesize
	mov	b,#1000>>8
	mul	ab
	add	a,r3
	mov	dptr,#descinsrate+1
	movx	@dptr,a
	mov	dptr,#descoutsrate+1
	movx	@dptr,a
	clr	a
	addc	a,b
	mov	dptr,#descinsrate+2
	movx	@dptr,a
	mov	dptr,#descoutsrate+2
	movx	@dptr,a
	.endif
	;; initialize USB state
usbinit:

	.if	0
	;;  XXXXX
	;; check if windows needs 11025Hz
	mov	a,#12
	mov	dptr,#descinframesize
	movx	@dptr,a
	mov	dptr,#descoutframesize
	movx	@dptr,a
	mov	a,#0x11
	mov	dptr,#descinsrate
	movx	@dptr,a
	mov	dptr,#descoutsrate
	movx	@dptr,a
	mov	a,#0x2b
	mov	dptr,#descinsrate+1
	movx	@dptr,a
	mov	dptr,#descoutsrate+1
	movx	@dptr,a
	mov	a,#0
	mov	dptr,#descinsrate+2
	movx	@dptr,a
	mov	dptr,#descoutsrate+2
	movx	@dptr,a
	;;  XXXXX
	.endif
	
	clr	a
	mov	numconfig,a
	mov	r0,#altsetting
	mov	r2,#NUMINTERFACES
3$:	mov	@r0,a
	inc	r0
	djnz	r2,3$
	;; give Windows a chance to finish the writecpucs control transfer
	;; 20ms delay loop
	mov	dptr,#(-12000)&0xffff
2$:	inc	dptr		; 3 cycles
	mov	a,dpl0		; 2 cycles
	orl	a,dph0		; 2 cycles
	jnz	2$		; 3 cycles
	.if	1
	;; disconnect from USB bus
	mov	dptr,#USBCS
	mov	a,#10
	movx	@dptr,a
	;; wait 0.3 sec
	mov	r2,#30
	;; 10ms delay loop
0$:	mov	dptr,#(-6000)&0xffff
1$:	inc	dptr            ; 3 cycles
	mov	a,dpl0          ; 2 cycles
	orl	a,dph0          ; 2 cycles
	jnz	1$              ; 3 cycles
	djnz	r2,0$
	;; reconnect to USB bus
	mov	dptr,#USBCS
	;mov	a,#2		; 8051 handles control
	;movx	@dptr,a
	mov	a,#6		; reconnect, 8051 handles control
	movx	@dptr,a
	.endif

	;; final
	lcall	fillusbintr
fifoinit:
	;; first wait for a new frame
	mov	dptr,#USBFRAMEL
	movx	a,@dptr
	mov	r2,a
1$:	movx	a,@dptr
	cjne	a,ar2,2$
	sjmp	1$
2$:	mov	dptr,#AUDIORXFIFOCNT
	movx	a,@dptr
	add	a,#-4
	anl	a,#0x3f
	jz	4$
	mov	r2,a
	mov	dptr,#AUDIORXFIFO
3$:	movx	a,@dptr
	djnz	r2,3$
4$:	mov	dptr,#AUDIOTXFIFOCNT
	movx	a,@dptr
	add	a,#-4
	anl	a,#0x3f
	jz	4$
	mov	r2,a
	mov	dptr,#AUDIOTXFIFO
	clr	a
5$:	movx	@dptr,a
	djnz	r2,5$
6$:	;; clear SOFIR interrupt
	mov	dptr,#USBIRQ
	mov	a,#0x02
	movx	@dptr,a
	;; finally enable SOFIR interrupt
	mov	dptr,#USBIEN
	mov	a,#3		; enable SUDAV+SOFIR interrupt
	movx	@dptr,a	
	lcall	fillusbintr
	ljmp	mainloop


	.area	CSEG (CODE)
	ar2 = 0x02
	ar3 = 0x03
	ar4 = 0x04
	ar5 = 0x05
	ar6 = 0x06
	ar7 = 0x07
	ar0 = 0x00
	ar1 = 0x01

	;; WARNING!  The assembler doesn't check for
	;; out of range short jump labels!! Double check
	;; that the jump labels are within the range!
mainloop:
	mov	a,pttforce
	mov	c,acc.0
	mov	ctrl_ptt,c
	mov	ctrl_ledptt,c
	cpl	c
	anl	c,pttmute
	mov	ctrl_pttmute,c
	mov	dptr,#AUDIOCTRL
	mov	a,ctrlreg
	movx	@dptr,a
	ljmp	mainloop

	;; ------------------ interrupt handlers ------------------------

int0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+1
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

timer0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+5
	;; handle interrupt
	.if	0
	inc	leddiv
	mov	a,leddiv
	anl	a,#7
	jnz	0$
	mov	dptr,#OUTC
	movx	a,@dptr
	xrl	a,#0x08
	movx	@dptr,a
0$:
	.endif
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+3
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

timer1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	tcon+7
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

ser0_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	;; clear interrupt
	jbc	scon0+0,1$	; RI
0$:	jbc	scon0+1,2$	; TI
	;; handle interrupt
	;; epilogue
3$:	pop	ar0
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

2$:	setb	uartempty
	sjmp	0$

1$:	mov	a,uartwr
	add	a,#uartbuf
	mov	r0,a
	mov	a,sbuf0
	mov	@r0,a
	mov	a,uartwr
	inc	a
	anl	a,#0xf
	mov	uartwr,a
	sjmp	3$

timer2_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	t2con+7
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

resume_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	eicon+4
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

ser1_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	scon1+0
	clr	scon1+1
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

i2c_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.5
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int4_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.6
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int5_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.7
	mov	exif,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

int6_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	clr	eicon+3
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_sudav_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	push	ar7
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	mov	ctrlcode,#0		; reset control out code
	mov	dptr,#SETUPDAT+1
	movx	a,@dptr			; bRequest field
	;; standard commands
	;; USB_REQ_GET_DESCRIPTOR
	cjne	a,#USB_REQ_GET_DESCRIPTOR,cmdnotgetdesc
	mov	dptr,#SETUPDAT		; bRequestType == 0x80
	movx	a,@dptr
	cjne	a,#USB_DIR_IN,setupstallstd
	mov	dptr,#SETUPDAT+3
	movx	a,@dptr
	cjne	a,#USB_DT_DEVICE,cmdnotgetdescdev
	mov	dptr,#SUDPTRH
	mov	a,#>devicedescr
	movx	@dptr,a
	inc	dptr
	mov	a,#<devicedescr
	movx	@dptr,a
	sjmp	setupackstd
cmdnotgetdescdev:
	cjne	a,#USB_DT_CONFIG,cmdnotgetdesccfg
	mov	dptr,#SETUPDAT+2
	movx	a,@dptr
	jnz	setupstallstd
	mov	dptr,#SUDPTRH
	mov	a,#>config0descr
	movx	@dptr,a
	inc	dptr
	mov	a,#<config0descr
	movx	@dptr,a
	sjmp	setupackstd
cmdnotgetdesccfg:
	cjne	a,#USB_DT_STRING,setupstallstd
	mov	dptr,#SETUPDAT+2
	movx	a,@dptr
	add	a,#-numstrings
	jc	setupstallstd
	movx	a,@dptr
	add	a,acc
	add	a,#<stringdescr
	mov	dpl0,a
	clr	a
	addc	a,#>stringdescr
	mov	dph0,a
	movx	a,@dptr
	mov	b,a
	inc	dptr
	movx	a,@dptr
	mov	dptr,#SUDPTRH
	movx	@dptr,a
	inc	dptr
	mov	a,b
	movx	@dptr,a
	; sjmp	setupackstd	
setupackstd:
	ljmp	setupack
setupstallstd:
	ljmp	setupstall
cmdnotgetdesc:
	;; USB_REQ_SET_CONFIGURATION
	cjne	a,#USB_REQ_SET_CONFIGURATION,cmdnotsetconf
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	jnz	setupstallstd
	mov	dptr,#SETUPDAT+2
	movx	a,@dptr
	add	a,#-2
	jc	setupstallstd
	movx	a,@dptr
	mov	numconfig,a
cmdresettoggleshalt:
	mov	dptr,#TOGCTL
	mov	r0,#7
0$:	mov	a,r0
	orl	a,#0x10
	movx	@dptr,a
	orl	a,#0x30
	movx	@dptr,a
	mov	a,r0
	movx	@dptr,a
	orl	a,#0x20
	movx	@dptr,a
	djnz	r0,0$
	clr	a
	movx	@dptr,a
	mov	a,#2
	mov	dptr,#IN1CS
	mov	r0,#7
1$:	movx	@dptr,a
	inc	dptr
	inc	dptr
	djnz	r0,1$
	mov	dptr,#OUT1CS
	mov	r0,#7
2$:	movx	@dptr,a
	inc	dptr
	inc	dptr
	djnz	r0,2$
	lcall	fillusbintr
	sjmp	setupackstd
cmdnotsetconf:
	;; USB_REQ_SET_INTERFACE
	cjne	a,#USB_REQ_SET_INTERFACE,cmdnotsetint
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	cjne	a,#USB_RECIP_INTERFACE|USB_DIR_OUT,setupstallstd
	mov	a,numconfig
	cjne	a,#1,setupstallstd
	mov	dptr,#SETUPDAT+4
	movx	a,@dptr
	add	a,#-NUMINTERFACES
	jc	setupstallstd
	add	a,#NUMINTERFACES+altsetting
	mov	r0,a
	mov	dptr,#SETUPDAT+2
	movx	a,@dptr
	mov	@r0,a
	sjmp	cmdresettoggleshalt
cmdnotsetint:
	;; USB_REQ_GET_INTERFACE
	cjne	a,#USB_REQ_GET_INTERFACE,cmdnotgetint
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	cjne	a,#USB_RECIP_INTERFACE|USB_DIR_IN,setupstallstd
	mov	a,numconfig
	cjne	a,#1,setupstallstd
	mov	dptr,#SETUPDAT+4
	movx	a,@dptr
	add	a,#-NUMINTERFACES
	jc	setupstallstd
	add	a,#NUMINTERFACES+altsetting
	mov	r0,a
	mov	a,@r0
cmdrespondonebyte:
	mov	dptr,#IN0BUF
	movx	@dptr,a
	mov	dptr,#IN0BC
	mov	a,#1
	movx	@dptr,a	
	sjmp	setupackstd2
cmdnotgetint:
	;; USB_REQ_GET_CONFIGURATION
	cjne	a,#USB_REQ_GET_CONFIGURATION,cmdnotgetconf
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	cjne	a,#USB_RECIP_DEVICE|USB_DIR_IN,setupstallstd2
	mov	a,numconfig
	sjmp	cmdrespondonebyte	
cmdnotgetconf:
	;; USB_REQ_GET_STATUS (0)
	jnz	cmdnotgetstat
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	cjne	a,#USB_RECIP_DEVICE|USB_DIR_IN,cmdnotgetstatdev
	mov	a,#1
cmdrespondstat:
	mov	dptr,#IN0BUF
	movx	@dptr,a
	inc	dptr
	clr	a
	movx	@dptr,a
	mov	dptr,#IN0BC
	mov	a,#2
	movx	@dptr,a	
	sjmp	setupackstd2
cmdnotgetstatdev:
	cjne	a,#USB_RECIP_INTERFACE|USB_DIR_IN,cmdnotgetstatintf
	clr	a
	sjmp	cmdrespondstat
cmdnotgetstatintf:
	cjne	a,#USB_RECIP_ENDPOINT|USB_DIR_IN,setupstallstd2
	mov	dptr,#SETUPDAT+4
	movx	a,@dptr
	mov	dptr,#OUT1CS-2
	jnb	acc.7,0$
	mov	dptr,#IN1CS-2
0$:	anl	a,#15
	jz	setupstallstd2
	jb	acc.3,setupstallstd2
	add	a,acc
	add	a,dpl0
	mov	dpl0,a
	movx	a,@dptr
	sjmp	cmdrespondstat
setupackstd2:
	ljmp	setupack
setupstallstd2:
	ljmp	setupstall
cmdnotgetstat:
	;; USB_REQ_SET_FEATURE
	cjne	a,#USB_REQ_SET_FEATURE,cmdnotsetftr
	mov	b,#1
	sjmp	handleftr
cmdnotsetftr:
	;; USB_REQ_CLEAR_FEATURE
	cjne	a,#USB_REQ_CLEAR_FEATURE,cmdnotclrftr
	mov	b,#0
handleftr:
	mov	dptr,#SETUPDAT
	movx	a,@dptr
	cjne	a,#USB_RECIP_ENDPOINT|USB_DIR_OUT,setupstallstd2
	inc	dptr
	inc	dptr
	movx	a,@dptr
	jnz	setupstallstd2	; not ENDPOINT_HALT feature
	inc	dptr
	movx	a,@dptr
	jnz	setupstallstd2
	inc	dptr
	movx	a,@dptr
	mov	dptr,#OUT1CS-2
	jnb	acc.7,0$
	mov	dptr,#IN1CS-2
	orl	a,#0x10
0$:	jb	acc.3,setupstallstd2
	;; clear data toggle
	anl	a,#0x1f
	inc	dps
	mov	dptr,#TOGCTL
	movx	@dptr,a
	orl	a,#0x20
	movx	@dptr,a
	anl	a,#15
	movx	@dptr,a
	dec	dps	
	;; clear/set ep halt feature
	add	a,acc
	add	a,dpl0
	mov	dpl0,a
	mov	a,b
	movx	@dptr,a
	sjmp	setupackstd2

cmdnotc0_1:
	ljmp	cmdnotc0
setupstallc0_1:
	ljmp	setupstall
	
cmdnotclrftr:
	;; vendor specific commands
	;; 0xc0
	cjne	a,#0xc0,cmdnotc0_1
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallc0_1
	;; fill status buffer
	mov	a,pttforce
	mov	b,a
	mov	c,acc.0
	mov	b.2,c
	mov	dptr,#AUDIOSTAT
	movx	a,@dptr
	mov	c,acc.0
	cpl	c
	mov	b.3,c
	mov	c,uartempty
	mov	b.5,c
	clr	a
	mov	dptr,#(IN0BUF+4)
	movx	@dptr,a
	;; bytewide elements
	mov	dptr,#(IN0BUF)
	mov	a,b
	movx	@dptr,a
	clr	a
	mov	dptr,#(IN0BUF+1)
	movx	@dptr,a
	mov	dptr,#(IN0BUF+2)
	movx	@dptr,a
	mov	dptr,#AUDIORSSI
	movx	a,@dptr
	mov	dptr,#(IN0BUF+3)
	movx	@dptr,a
	;; counter
	inc	irqcount
	mov	a,irqcount
	mov	dptr,#(IN0BUF+5)
	movx	@dptr,a
	;; additional fields (HDLC state mach)
	clr	a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	inc	dptr
	movx	@dptr,a
	;; FPGA registers
	mov	dptr,#AUDIORXFIFOCNT
	movx	a,@dptr
	mov	dptr,#(IN0BUF+18)
	movx	@dptr,a
	mov	dptr,#AUDIOTXFIFOCNT
	movx	a,@dptr
	mov	dptr,#(IN0BUF+19)
	movx	@dptr,a
	mov	a,ctrlreg
	inc	dptr
	movx	@dptr,a
	mov	dptr,#AUDIOSTAT
	movx	a,@dptr
	mov	dptr,#(IN0BUF+21)
	movx	@dptr,a
	;; Anchor Registers
	mov	dptr,#OUT2CS
	movx	a,@dptr
	mov	dptr,#(IN0BUF+22)
	movx	@dptr,a
	;; set length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-(6+12+4+1)
	jnc	4$
	clr	a
4$:	add	a,#(6+12+4+1)
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
cmdnotc0:
	;; 0xc8
	cjne	a,#0xc8,cmdnotc8
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallc8
	mov	a,#4
	mov	dptr,#IN0BUF
	movx	@dptr,a
	mov	dptr,#IN0BC
	mov	a,#1
	movx	@dptr,a
	ljmp	setupack
setupstallc8:
	ljmp	setupstall
cmdnotc8:
	;; 0xc9
	cjne	a,#0xc9,cmdnotc9
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstallc9
	mov	dptr,#IN0BUF
	mov	r0,#parserial
0$:	movx	a,@r0
	jz	1$
	movx	@dptr,a
	inc	r0
	inc	dptr
	sjmp	0$
1$:	mov	a,r0
	add	a,#-0xf0	; -parserial
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstallc9:
	ljmp	setupstall
cmdnotc9:
	;; 0xd0
	cjne	a,#0xd0,cmdnotd0
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalld0
	mov	dptr,#SETUPDAT+4	; wIndex
	movx	a,@dptr
	cjne	a,#1,0$
	mov	dptr,#SETUPDAT+2	; wValue
	movx	a,@dptr
	anl	a,#1
	mov	pttforce,a
0$:	;; PTT status
	mov	dptr,#IN0BUF
	mov	a,pttforce
	movx	@dptr,a
	;; DCD status
	mov	dptr,#AUDIOSTAT
	movx	a,@dptr
	anl	a,#1
	xrl	a,#1
	mov	dptr,#IN0BUF+1
	movx	@dptr,a
	;; RSSI
	mov	dptr,#AUDIORSSI
	movx	a,@dptr
	mov	dptr,#IN0BUF+2
	movx	@dptr,a
	;; length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-3
	jnc	2$
	clr	a
2$:	add	a,#3
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstalld0:
	ljmp	setupstall
cmdnotd0:
	;; 0xd2
	cjne	a,#0xd2,cmdnotd2
	mov	dptr,#SETUPDAT	; bRequestType == 0x40
	movx	a,@dptr
	cjne	a,#0x40,setupstalld2
	mov	dptr,#SETUPDAT+2	; wValue
	movx	a,@dptr
	mov	b,a
	mov	dptr,#OUTC
	movx	a,@dptr
	mov	c,b.0
	mov	acc.3,c
	mov	c,b.1
	mov	acc.5,c
	movx	@dptr,a
	ljmp	setupack
setupstalld2:
	ljmp	setupstall
cmdnotd2:
	;; 0xd3
	cjne	a,#0xd3,cmdnotd3
	mov	dptr,#SETUPDAT	; bRequestType == 0x40
	movx	a,@dptr
	cjne	a,#0x40,setupstalld3
	mov	dptr,#SETUPDAT+2	; wValue
	movx	a,@dptr
	jbc	uartempty,cmdd2cont
setupstalld3:
	ljmp	setupstall
cmdd2cont:
	mov	sbuf0,a
	ljmp	setupack
cmdnotd3:
	;; 0xd4
	cjne	a,#0xd4,cmdnotd4
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalld4
	mov	dptr,#SETUPDAT+4	; wIndex
	movx	a,@dptr
	mov	dptr,#SETUPDAT+2	; wValue
	cjne	a,#1,0$
	movx	a,@dptr
	mov	dptr,#AUDIOMDISCOUT
	movx	@dptr,a
	mov	mdiscout,a
	sjmp	1$
0$:	cjne	a,#2,1$
	movx	a,@dptr
	mov	dptr,#AUDIOMDISCTRIS
	movx	@dptr,a
	mov	mdisctris,a
1$:	mov	dptr,#AUDIOMDISCIN
	movx	a,@dptr
	mov	dptr,#IN0BUF+0
	movx	@dptr,a
	mov	a,mdiscout
	inc	dptr
	movx	@dptr,a
	mov	a,mdisctris
	inc	dptr
	movx	@dptr,a
	;; length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-3
	jnc	2$
	clr	a
2$:	add	a,#3
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstalld4:
	ljmp	setupstall
cmdnotd4:
	;; 0xd5
	cjne	a,#0xd5,cmdnotd5
	mov	dptr,#SETUPDAT	; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalld5
	mov	dptr,#SETUPDAT+4	; wIndex
	movx	a,@dptr
	cjne	a,#1,0$
	mov	dptr,#SETUPDAT+2	; wValue
	movx	a,@dptr
	mov	dptr,#AUDIOT7FOUT
	movx	@dptr,a
	mov	t7fout,a
0$:	mov	dptr,#AUDIOT7FIN
	movx	a,@dptr
	mov	dptr,#IN0BUF+0
	movx	@dptr,a
	mov	a,t7fout
	inc	dptr
	mov	dptr,#IN0BUF+1
	movx	@dptr,a
	;; length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-2
	jnc	2$
	clr	a
2$:	add	a,#2
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstalld5:
setupstalle0:
	ljmp	setupstall
cmdnote0_0:
	ljmp    cmdnote0
cmdnotd5:
	;; 0xe0
	cjne	a,#0xe0,cmdnote0_0
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalle0
	;; set PTT, LED's and counter mode
	mov	dptr,#SETUPDAT+4	; wIndex
	movx	a,@dptr
	cjne	a,#1,1$
	mov	dptr,#SETUPDAT+2	; wValue
	movx	a,@dptr
	anl	a,#0x78
	xch	a,ctrlreg
	anl	a,#0x07
	orl	a,ctrlreg
	mov	ctrlreg,a
	mov	dptr,#AUDIOCTRL
	movx	@dptr,a
1$:	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	jz	3$
	cjne	a,#1,2$
	mov	a,ctrlreg
	mov	dptr,#IN0BUF
	anl	a,#0x7f
	movx	@dptr,a
	mov	a,#1
3$:	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
2$:	mov	dptr,#AUDIOCTRL
	setb	ctrl_cntsel
	mov	a,ctrlreg
	movx	@dptr,a
	mov	dptr,#AUDIOCNTLOW
	movx	a,@dptr
	mov	dptr,#IN0BUF+4
	movx	@dptr,a
	mov	dptr,#AUDIOCNTMID
	movx	a,@dptr
	mov	dptr,#IN0BUF+5
	movx	@dptr,a
	mov	dptr,#AUDIOCNTHIGH
	movx	a,@dptr
	mov	dptr,#IN0BUF+6
	movx	@dptr,a
	mov	dptr,#AUDIOCTRL
	clr	ctrl_cntsel
	mov	a,ctrlreg
	movx	@dptr,a
	mov	dptr,#IN0BUF
	movx	@dptr,a
	mov	dptr,#AUDIOCNTLOW
	movx	a,@dptr
	mov	dptr,#IN0BUF+1
	movx	@dptr,a
	mov	dptr,#AUDIOCNTMID
	movx	a,@dptr
	mov	dptr,#IN0BUF+2
	movx	@dptr,a
	mov	dptr,#AUDIOCNTHIGH
	movx	a,@dptr
	mov	dptr,#IN0BUF+3
	movx	@dptr,a
	;; length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-7
	jnc	4$
	clr	a
4$:	add	a,#7
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
cmdnote0:
	;; 0xe1
	cjne	a,#0xe1,cmdnote1
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalle1
	mov	dptr,#IN0BUF
	mov	a,sofcount
	movx	@dptr,a
	inc	dptr
	mov	a,framesize
	movx	@dptr,a
	inc	dptr
	mov	a,divider
	movx	@dptr,a
	inc	dptr
	mov	a,divider+1
	movx	@dptr,a
	inc	dptr
	mov	a,divrel
	movx	@dptr,a
	inc	dptr
	mov	a,pllcorrvar
	movx	@dptr,a
	inc	dptr
	mov	a,txfifocount
	movx	@dptr,a

	;mov	dptr,#AUDIOTXFIFOCNT
	;movx	a,@dptr
	;mov	dptr,#IN0BUF+6
	;movx	@dptr,a

	;; length
	mov	dptr,#SETUPDAT+6	; wLength
	movx	a,@dptr
	add	a,#-7
	jnc	1$
	clr	a
1$:	add	a,#7
	mov	dptr,#IN0BC
	movx	@dptr,a
	ljmp	setupack
setupstalle1:
	ljmp	setupstall
cmdnote1:
	;; 0xe2
	cjne	a,#0xe2,cmdnote2
	mov	dptr,#SETUPDAT		; bRequestType == 0xc0
	movx	a,@dptr
	cjne	a,#0xc0,setupstalle2
	mov	dptr,#IN0BUF
	mov	r0,#txsamples
	mov	r7,framesize
1$:	mov	a,@r0
	movx	@dptr,a
	inc	r0
	inc	dptr
	djnz	r7,1$
	mov	dptr,#IN0BC
	mov	a,framesize
	movx	@dptr,a
	ljmp	setupack
setupstalle2:
	ljmp	setupstall
cmdnote2:

	;; unknown commands fall through to setupstall

setupstall:
	mov	a,#3
	sjmp	endsetup
setupack:
	mov	a,#2
endsetup:
	mov	dptr,#EP0CS
	movx	@dptr,a
endusbisr:
	;; epilogue
	pop	ar7
	pop	ar0
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_sof_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar2
	push	ar3
	push	ar0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	inc	sofcount
	;; debugging: we have two cases
	;; if the ISO frame size is just 2 bytes,
	;; we return the frame number, otherwise
	;; the required numbers of samples
	mov	a,framesize
	cjne	a,#2,1$
	;; copy the frame number
	mov	dptr,#USBFRAMEL
	movx	a,@dptr
	inc	dptr
	inc	dps
	mov	dptr,#IN8DATA
	movx	@dptr,a
	dec	dps
	movx	a,@dptr
	inc	dps
	movx	@dptr,a
	ljmp	sofendisr
1$:	cjne	a,#3,sofsampleisr
	mov	dptr,#ISOERR
	movx	a,@dptr
	jb	acc.0,3$
	mov	dptr,#OUT8BCH
	movx	a,@dptr
	jnz	3$
	mov	dptr,#OUT8BCL
	movx	a,@dptr
	cjne	a,#3,3$
	mov	r2,a
	mov	dptr,#OUT8DATA
	inc	dps
	mov	dptr,#IN8DATA
	dec	dps
2$:	movx	a,@dptr
	inc	dps
	movx	@dptr,a
	dec	dps
	djnz	r2,2$
	ljmp	sofendisr
3$:	mov	r2,#3
	mov	dptr,#IN8DATA
	clr	a
4$:	movx	@dptr,a
	djnz	r2,4$
	ljmp	sofendisr
sofsampleisr:
	mov	dptr,#AUDIORXFIFOCNT
	movx	a,@dptr
	clr	c
	subb	a,framesize
	movx	a,@dptr
	jc	1$
	mov	a,framesize
1$:	mov	r2,a
	mov	r3,a
	jz	2$
	mov	dptr,#AUDIORXFIFO
	inc	dps
	mov	dptr,#IN8DATA
	dec	dps
3$:	movx	a,@dptr
	inc	dps
	movx	@dptr,a
	dec	dps
	djnz	r2,3$
2$:	mov	a,framesize
	clr	c
	subb	a,r3
	jz	4$
	mov	r2,a
	mov	dptr,#IN8DATA
	clr	a
5$:	movx	@dptr,a
	djnz	r2,5$
	;; sample rate adjustment
4$:	mov	dptr,#AUDIORXFIFOCNT
	movx	a,@dptr
	mov	pllcorrvar,a
	add	a,#-4
	jz	10$		; no adjustment
	rlc	a
	subb	a,acc
	setb	acc.0
10$:	mov	r3,a		; r3 & acc contain the adjust value
	add	a,divrel
	;; zero is the guard value
	jz	11$
	mov	divrel,a
11$:	mov	a,divrel
	rr	a
	rr	a
	rr	a
	rr	a
	anl	a,#0xf
	add	a,r3		; momentary correction
	add	a,divider
	mov	r2,a
	mov	a,divider+1
	addc	a,#0
	mov	dptr,#AUDIODIVIDERHI
	movx	@dptr,a
	mov	a,r2
	mov	dptr,#AUDIODIVIDERLO
	movx	@dptr,a
	;; OUT data
	mov	dptr,#ISOERR
	movx	a,@dptr
	jb	acc.0,20$
	mov	dptr,#OUT8BCH
	movx	a,@dptr
	jnz	20$
	mov	dptr,#OUT8BCL
	movx	a,@dptr
	clr	c
	subb	a,framesize
	jnz	20$
	mov	dptr,#AUDIOTXFIFOCNT
	movx	a,@dptr
	mov	txfifocount,a
	clr	c
	subb	a,framesize
	mov	a,txfifocount
	jc	14$
	mov	a,framesize
14$:	jz	13$
	mov	r2,a
	mov	dptr,#OUT8DATA
	inc	dps
	mov	dptr,#AUDIOTXFIFO
	dec	dps
	mov	r0,#txsamples
12$:	movx	a,@dptr
	inc	dps
	movx	@dptr,a
	dec	dps
	mov	@r0,a
	inc	r0
	djnz	r2,12$
13$:	sjmp	sofendisr
	;; initialize TX if invalid packet
20$:	mov	dptr,#AUDIOTXFIFOCNT
	movx	a,@dptr
	mov	txfifocount,a
	add	a,#-4
	anl	a,#0x3f
	jz	sofendisr
	mov	r2,a
	mov	dptr,#AUDIOTXFIFO
	clr	a
	mov	r0,#txsamples
21$:	movx	@dptr,a
	mov	@r0,a
	inc	r0
	djnz	r2,21$
	
sofendisr:
	;; epilogue
	pop	ar0
	pop	ar3
	pop	ar2
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti


usb_sutok_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_suspend_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_usbreset_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#USBIRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep0in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	push	ar7
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	ar7
	pop	ar0
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep0out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	dpl1
	push	dph1
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	push	ar0
	push	ar6
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x01
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	ar6
	pop	ar0
	pop	dps
	pop	psw
	pop	dph1
	pop	dpl1
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

fillusbintr::
	mov	a,pttforce
	mov	b,a
	mov	c,acc.0
	mov	b.2,c
	mov	dptr,#AUDIOSTAT
	movx	a,@dptr
	mov	c,acc.0
	mov	b.3,c
	mov	c,uartempty
	mov	b.5,c
	;; bytewide elements
	mov	dptr,#(IN1BUF)
	mov	a,b
	movx	@dptr,a
	mov	a,sofcount
	mov	dptr,#(IN1BUF+1)
	movx	@dptr,a
	mov	dptr,#INISOVAL
	movx	a,@dptr
	mov	dptr,#(IN1BUF+2)
	movx	@dptr,a
	mov	dptr,#AUDIORSSI
	movx	a,@dptr
	mov	dptr,#(IN1BUF+3)
	movx	@dptr,a
	; counter
	inc	irqcount
	mov	a,irqcount
	mov	dptr,#(IN1BUF+4)
	movx	@dptr,a
	; UART buffer
	mov	b,#5
	mov	dptr,#(IN1BUF+5)
2$:	mov	a,uartrd
	cjne	a,uartwr,3$
	; set length
	mov	dptr,#IN1BC
	mov	a,b
	movx	@dptr,a
	ret
	
3$:	add	a,#uartbuf
	mov	r0,a
	mov	a,@r0
	movx	@dptr,a
	inc	dptr
	inc	b
	mov	a,uartrd
	inc	a
	anl	a,#0xf
	mov	uartrd,a
	sjmp	2$

	
usb_ep1in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	lcall	fillusbintr
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep1out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x02
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep2in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep2out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x04
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep3in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep3out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x08
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep4in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep4out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x10
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep5in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x20
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep5out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x20
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep6in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x40
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep6out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x40
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep7in_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#IN07IRQ
	mov	a,#0x80
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti

usb_ep7out_isr:
	push	acc
	push	b
	push	dpl0
	push	dph0
	push	psw
	mov	psw,#0x00
	push	dps
	mov	dps,#0
	;; clear interrupt
	mov	a,exif
	clr	acc.4
	mov	exif,a
	mov	dptr,#OUT07IRQ
	mov	a,#0x80
	movx	@dptr,a
	;; handle interrupt
	;; epilogue
	pop	dps
	pop	psw
	pop	dph0
	pop	dpl0
	pop	b
	pop	acc
	reti
	
	;; -----------------------------------------------------
	;; USB descriptors
	;; -----------------------------------------------------

	;; Device and/or Interface Class codes
	USB_CLASS_PER_INTERFACE         = 0
	USB_CLASS_AUDIO                 = 1
	USB_CLASS_COMM                  = 2
	USB_CLASS_HID                   = 3
	USB_CLASS_PRINTER               = 7
	USB_CLASS_MASS_STORAGE          = 8
	USB_CLASS_HUB                   = 9
	USB_CLASS_VENDOR_SPEC           = 0xff

	USB_SUBCLASS_AUDIOCONTROL	= 1
	USB_SUBCLASS_AUDIOSTREAMING	= 2
	
	;; Descriptor types
	USB_DT_DEVICE                   = 0x01
	USB_DT_CONFIG                   = 0x02
	USB_DT_STRING                   = 0x03
	USB_DT_INTERFACE                = 0x04
	USB_DT_ENDPOINT                 = 0x05

	;; Audio Class descriptor types
	USB_DT_AUDIO_UNDEFINED		= 0x20
	USB_DT_AUDIO_DEVICE		= 0x21
	USB_DT_AUDIO_CONFIG		= 0x22
	USB_DT_AUDIO_STRING		= 0x23
	USB_DT_AUDIO_INTERFACE		= 0x24
	USB_DT_AUDIO_ENDPOINT		= 0x25

	USB_SDT_AUDIO_UNDEFINED		= 0x00
	USB_SDT_AUDIO_HEADER		= 0x01
	USB_SDT_AUDIO_INPUT_TERMINAL	= 0x02
	USB_SDT_AUDIO_OUTPUT_TERMINAL	= 0x03
	USB_SDT_AUDIO_MIXER_UNIT	= 0x04
	USB_SDT_AUDIO_SELECTOR_UNIT	= 0x05
	USB_SDT_AUDIO_FEATURE_UNIT	= 0x06
	USB_SDT_AUDIO_PROCESSING_UNIT	= 0x07
	USB_SDT_AUDIO_EXTENSION_UNIT	= 0x08
	
	;; Standard requests
	USB_REQ_GET_STATUS              = 0x00
	USB_REQ_CLEAR_FEATURE           = 0x01
	USB_REQ_SET_FEATURE             = 0x03
	USB_REQ_SET_ADDRESS             = 0x05
	USB_REQ_GET_DESCRIPTOR          = 0x06
	USB_REQ_SET_DESCRIPTOR          = 0x07
	USB_REQ_GET_CONFIGURATION       = 0x08
	USB_REQ_SET_CONFIGURATION       = 0x09
	USB_REQ_GET_INTERFACE           = 0x0A
	USB_REQ_SET_INTERFACE           = 0x0B
	USB_REQ_SYNCH_FRAME             = 0x0C

	;; Audio Class Requests
	USB_REQ_AUDIO_SET_CUR		= 0x01
	USB_REQ_AUDIO_GET_CUR		= 0x81
	USB_REQ_AUDIO_SET_MIN		= 0x02
	USB_REQ_AUDIO_GET_MIN		= 0x82
	USB_REQ_AUDIO_SET_MAX		= 0x03
	USB_REQ_AUDIO_GET_MAX		= 0x83
	USB_REQ_AUDIO_SET_RES		= 0x04
	USB_REQ_AUDIO_GET_RES		= 0x84
	USB_REQ_AUDIO_SET_MEM		= 0x05
	USB_REQ_AUDIO_GET_MEM		= 0x85
	USB_REQ_AUDIO_GET_STAT		= 0xff
	
	;; USB Request Type and Endpoint Directions
	USB_DIR_OUT                     = 0
	USB_DIR_IN                      = 0x80

	USB_TYPE_STANDARD               = (0x00 << 5)
	USB_TYPE_CLASS                  = (0x01 << 5)
	USB_TYPE_VENDOR                 = (0x02 << 5)
	USB_TYPE_RESERVED               = (0x03 << 5)

	USB_RECIP_DEVICE                = 0x00
	USB_RECIP_INTERFACE             = 0x01
	USB_RECIP_ENDPOINT              = 0x02
	USB_RECIP_OTHER                 = 0x03

	;; Request target types.
	USB_RT_DEVICE                   = 0x00
	USB_RT_INTERFACE                = 0x01
	USB_RT_ENDPOINT                 = 0x02

	VENDID	= 0xbac0
	PRODID	= 0x6137

devicedescr:
	.db	18			; bLength
	.db	USB_DT_DEVICE		; bDescriptorType
	.db	0x00, 0x01		; bcdUSB
	.db	USB_CLASS_VENDOR_SPEC	; bDeviceClass
	.db	0			; bDeviceSubClass
	.db	0xff			; bDeviceProtocol
	.db	0x40			; bMaxPacketSize0
	.db	<VENDID,>VENDID		; idVendor
	.db	<PRODID,>PRODID		; idProduct
	.db	0x01,0x00		; bcdDevice
	.db	1			; iManufacturer
	.db	2			; iProduct
	.db	3			; iSerialNumber
	.db	1			; bNumConfigurations

config0descr:
	.db	9			; bLength
	.db	USB_DT_CONFIG		; bDescriptorType
	.db	<config0sz,>config0sz	; wTotalLength
	.db	1			; bNumInterfaces
	.db	1			; bConfigurationValue
	.db	0			; iConfiguration
	.db	0b01000000		; bmAttributs (self powered)
	.db	0			; MaxPower (mA/2) (self powered so 0)
	;; standard packet interface (needed so the driver can hook to it)
	;; interface descriptor I0:A0
	.db	9			; bLength
	.db	USB_DT_INTERFACE	; bDescriptorType
	.db	0			; bInterfaceNumber
	.db	0			; bAlternateSetting
	.db	1			; bNumEndpoints
	.db	0xff			; bInterfaceClass (vendor specific)
	.db	0x00			; bInterfaceSubClass
	.db	0xff			; bInterfaceProtocol (vendor specific)
	.db	0			; iInterface
	;; endpoint descriptor I0:A0:E0
	.db	7			; bLength
	.db	USB_DT_ENDPOINT		; bDescriptorType
	.db	(USB_DIR_IN | 1)	; bEndpointAddress
	.db	0x02			; bmAttributes (bulk)
	.db	0x40,0x00		; wMaxPacketSize
	.db	0			; bInterval
	;; interface descriptor I0:A1
	.db	9			; bLength
	.db	USB_DT_INTERFACE	; bDescriptorType
	.db	0			; bInterfaceNumber
	.db	1			; bAlternateSetting
	.db	3			; bNumEndpoints
	.db	0xff			; bInterfaceClass (vendor specific)
	.db	0x00			; bInterfaceSubClass
	.db	0xff			; bInterfaceProtocol (vendor specific)
	.db	0			; iInterface
	;; endpoint descriptor I0:A1:E0
	.db	7			; bLength
	.db	USB_DT_ENDPOINT		; bDescriptorType
	.db	(USB_DIR_IN | 1)	; bEndpointAddress
	.db	0x03			; bmAttributes (interrupt)
	.db	0x40,0x00		; wMaxPacketSize
	.db	8			; bInterval
	;; endpoint descriptor I0:A1:E1
	.db	9			; bLength
	.db	USB_DT_ENDPOINT		; bDescriptorType
	.db	(USB_DIR_IN | 8)	; bEndpointAddress
	.db	0x01			; bmAttributes (iso)
descinframesize:
	.db	0x02,0x00		; wMaxPacketSize
	.db	1			; bInterval
	.db	0			; bRefresh
	.db	0			; bSynchAddress
	;; endpoint descriptor I0:A1:E2
	.db	9			; bLength
	.db	USB_DT_ENDPOINT		; bDescriptorType
	.db	(USB_DIR_OUT | 8)	; bEndpointAddress
	.db	0x01			; bmAttributes (iso)
descoutframesize:
	.db	0x02,0x00		; wMaxPacketSize
	.db	1			; bInterval
	.db	0			; bRefresh
	.db	0			; bSynchAddress
config0sz = . - config0descr

stringdescr:
	.db	<string0,>string0
	.db	<string1,>string1
	.db	<string2,>string2
	.db	<stringserial,>stringserial

numstrings = (. - stringdescr)/2

string0:
	.db	string0sz		; bLength
	.db	USB_DT_STRING		; bDescriptorType
	.db	0,0			; LANGID[0]: Lang Neutral
string0sz = . - string0

string1:
	.db	string1sz		; bLength
	.db	USB_DT_STRING		; bDescriptorType
	.db	'B,0,'a,0,'y,0,'c,0,'o,0,'m,0
string1sz = . - string1

string2:
	.db	string2sz		; bLength
	.db	USB_DT_STRING		; bDescriptorType
	.db	'U,0,'S,0,'B,0,'F,0,'L,0,'E,0,'X,0,' ,0
	.db	'(,0,'A,0,'u,0,'d,0,'i,0,'o,0,'),0
string2sz = . - string2
	
stringserial:
	.db	2			; bLength
	.db	USB_DT_STRING		; bDescriptorType
	.dw	0,0,0,0,0,0,0,0
	.dw	0,0,0,0,0,0,0,0

