' Copyright Brad Campbell, 2007 - All rights reserved ' ' Thanks to Dick Dick Streefland and Igor Cesko (Not quite sure the unicode translates) ' for inspiration ' http://www.xs4all.nl/~dicks/avr/usbtiny/index.html ' http://cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm ' ' Thanks to Michael Hetherington for the lyrics ' http://www.sxlist.com/techref/scenix/lib/io/dev/keys/usbdemo-mh.htm ' The MAC COG relies on the CRC table defined in here, don't replace it without altering ' the MAC COG code! CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 VAR long ring ' Cog paramaters contiguous block of longs long transmit long crctable long rxstat long recieve[514] ' each endpoint in/out has 4 longs ' IN endpoints 1st ' byte counter ' bytes [0-3] ' bytes [4-7] ' spare ' OUT endpoints ' byte counter ' bytes [0-3] ' bytes [4-7] ' bytes [8-9] justified to LSB long endpoints[32] long packetcount long packetbad OBJ ll : "USB_lowlevel_003" PUB start : OK | i Ddevice := @dd_device Dconfig := @dd_config Dreport := @dd_report Dtext := @dd_hello Dlangid := @dd_langid Dvendor := @dd_vendor Ddevname := @dd_product ring := 0 Pcrcmask := @crc16table i := @endpoints epb := i longfill(i, 0, 32) longfill(@recieve, 0, 514) OK := ll.start(@crc16table, epb) OK := cognew(@USB_STACK, @crctable) PUB rx : val repeat while recieve[ring] == 0 val := recieve[ring] recieve[ring] := 0 ring++ ring := ring & $1FF PUB rxall : val val := recieve[ring] recieve[ring] := 0 ring++ ring := ring & $1FF DAT USB_STACK org mov aring, #0 mov ping, preload wrlong zero, epb ' Spark up MAC thread now we are running mov lflags, #0 :loop mov pointer, epb rdlong da, pointer test da, allones wz IF_NZ call #process_0i add pointer, #16 rdlong da, pointer test da, allones wz IF_NZ call #process_1i add pointer, #16 rdlong da, pointer test da, allones wz IF_NZ call #process_2i add pointer, #16 rdlong da, pointer test da, allones wz IF_NZ call #process_3i add pointer, #16 test out0, allones wz IF_Z jmp #:loop1 rdlong da, pointer test da, allones wz IF_Z call #process_0o :loop1 add pointer, #16 test out1, allones wz IF_Z jmp #:loop2 rdlong da, pointer test da, allones wz IF_Z call #process_1o :loop2 add pointer, #16 test out2, allones wz IF_Z jmp #:loop3 rdlong da, pointer test da, allones wz IF_Z call #process_2o :loop3 add pointer, #16 test out3, allones wz IF_Z jmp #:loop4 rdlong da, pointer test da, allones wz IF_Z call #process_3o ' This is a hacky way of getting debugging data from the low level thread ' wrlong , debug :loop4 rdlong da, debug test da, allones wz IF_Z jmp #:loop5 wrlong zero, debug mov data, #$1C1 call #wrhub mov data, da call #wrhub :loop5 sub delay, #1 wz IF_Z call #dreamin :loop6 jmp #:loop process_0i mov epoint, #0 call #rdbuf test buf0, flag_setup wz IF_Z jmp #:end mov data, #$B0 call #wrdebug mov dc, buf1 shr dc, #8 and dc, #$FF cmp dc, #6 wz ' GET_DESCRIPTOR IF_NZ jmp #:setup2 mov ep0bl, buf2 shr ep0bl, #16 and ep0bl, #$FF mov dd, buf1 shr dd, #24 and dd, #$FF mov ep0buf, #0 cmp dd, #1 wz IF_Z mov ep0buf, Ddevice cmp dd, #2 wz IF_Z mov ep0buf, Dconfig cmp dd, #3 wz IF_Z jmp #:ss_string_d cmp dd, #$22 wz IF_Z mov ep0buf, Dreport test ep0buf, allones wz IF_NZ jmp #:next jmp #:end :ss_string_d mov dd, buf1 shr dd, #16 and dd, #$FF cmp dd, #0 wz IF_Z mov ep0buf, Dlangid cmp dd, #1 wz IF_Z mov ep0buf, Dvendor cmp dd, #2 wz IF_Z mov ep0buf, Ddevname cmp dd, #3 wz IF_Z mov ep0buf, Dserialno tjz ep0buf, #:end or lflags, flag_debug :next rdbyte ep0len, ep0buf add ep0buf, #1 call #ep0send jmp #:end :setup2 :setup3 cmp dc, #5 wz IF_NZ jmp #:setup4 mov flags, flag_empty or flags, flag_address call #wrbuf jmp #:end :setup4 ' Just ack anything that comes along mov flags, flag_empty call #wrbuf jmp #:end :end mov da, epb wrlong zero, epb process_0i_ret ret dreamin mov out1, #1 mov ep1buf, Dtext rdbyte ep1len, ep1buf add ep1buf, #1 mov ep1toggle, #0 call #ep1send dreamin_ret ret process_1i mov epoint, #1 call #rdbuf test buf0, flag_setup wz IF_NZ jmp #:setup mov data, #$5C ' call #wrdebug jmp #:end :setup mov flags, flag_empty call #wrbuf mov data, #$6C ' call #wrdebug :end process_1i_ret ret process_2i mov epoint, #2 call #rdbuf mov data, #$4C ' call #wrdebug process_2i_ret ret process_3i mov epoint, #3 call #rdbuf mov data, #$3C ' call #wrdebug process_3i_ret ret process_0o call #ep0send process_0o_ret ret process_1o call #ep1send process_1o_ret ret process_2o mov epoint, #2 mov flags, #0 mov bytecnt, #0 call #wrbuf process_2o_ret ret process_3o mov epoint, #3 mov flags, #0 mov bytecnt, #0 call #wrbuf process_3o_ret ret rdbuf mov da, epoint shl da, #4 add da, epb rdlong buf0, da add da, #4 rdlong buf1, da add da, #4 rdlong buf2, da sub da, #8 wrlong zero, da ' Clear the buffer, we have it now rdbuf_ret ret wrbuf mov da, epoint shl da, #4 add da, epb add da, #68 ' 64 + skip 1st long wrlong buf0, da add da, #4 mov db, flags ' Interleaved wrlong buf1, da add da, #4 or db, bytecnt ' Interleaved wrlong buf2, da mov flags, #0 sub da, #12 wrlong db, da ' Byte Counter / Flags wrbuf_ret ret wrdebug mov da, bytecnt shl da, #12 or da, data shl da, #12 or da, #3 mov data, da call #wrhub mov data, buf0 call #wrhub mov data, buf1 call #wrhub mov data, buf2 call #wrhub wrdebug_ret ret packem mov buf0, b_1 mov da, b_2 shl da, #8 or buf0, da mov da, b_3 shl da, #16 or buf0, da mov da, b_4 shl da, #24 or buf0, da mov buf1, b_5 mov da, b_6 shl da, #8 or buf1, da mov da, b_7 shl da, #16 or buf1, da mov da, b_8 shl da, #24 or buf1, da mov buf2, b_9 mov da, b_10 shl da, #8 or buf2, da packem_ret ret pushbuf movd :pindr, bptr add bptr, #1 :pindr mov 0-0, data call #crc16byte add bytecnt, #1 pushbuf_ret ret pushcrc movd :pcrc1, bptr add bptr, #1 movd :pcrc2, bptr xor crc, allones mov data, crc and data, #$FF :pcrc1 mov 0-0, data mov data, crc shr data, #8 and data, #$FF :pcrc2 mov 0-0, data add bytecnt, #2 pushcrc_ret ret bufstart mov bptr, #b_1 mov crc, crcmask mov bytecnt, #0 bufstart_ret ret ep0send mov out0, #1 test ep0len, allones wz IF_Z jmp #:send_empty call #bufstart mov da, #8 :send_loop rdbyte data, ep0buf add ep0buf, #1 call #pushbuf sub da, #1 sub ep0len, #1 sub ep0bl, #1 tjz da, #:send_next tjz ep0bl, #:send_next tjnz ep0len, #:send_loop :send_next call #pushcrc call #packem mov epoint, #0 jmp #:next :send_empty mov bytecnt, #0 mov flags, flag_empty mov out0, #0 mov lflags, #0 :next call #wrbuf mov data, #$2C test lflags, flag_debug wz IF_NZ call #wrdebug cmp bytecnt, #$0A wz IF_NZ mov out0, #0 IF_NZ andn lflags, flag_debug ep0send_ret ret ep1send mov out1, #1 test ep1len, allones wz IF_Z mov out1, #0 IF_Z jmp #ep1send_ret call #bufstart mov data, #0 call #pushbuf call #pushbuf xor ep1toggle, #1 wz IF_Z jmp #:keyup rdbyte data, ep1buf call #pushbuf ' Key down mov data, #0 jmp #:next :keyup add ep1buf, #1 sub ep1len, #1 call #pushbuf ' Key up :next call #pushbuf call #pushbuf call #pushbuf call #pushbuf call #pushbuf call #pushcrc mov bytecnt, #$0A call #packem mov epoint, #1 call #wrbuf mov data, #$1C ' call #wrdebug ep1send_ret ret ' Mangles t, t1 ' paramater in data wrhub ' Write data in 'data' to the next hub address mov t, aring shl t, #2 add t, par add t, #8 wrlong data, t ' Write long counter << 8 + bitsremaining into 1st val signifying done add aring, #1 and aring, #$1FF wrhub_ret ret crcmask long $0000FFFF ' This is broken out so we can use it later in our transmit routines crc16byte ' dc has the byte to add to the crc mov t, data xor t, crc ' 1 and t, #$FF ' 2 shl t, #1 ' 3 add t, Pcrcmask ' 4 rdword t1, t ' 9.5 shr crc, #8 ' 10.5 xor crc, t1 ' 11.5 crc16byte_ret ret ' 12.5 deadbeef long $DEADBEEF allones long $FFFFFFFF zero long 0 aring long 0 Pcrcmask long 0 epb long 0 out0 long 0 out1 long 0 out2 long 0 out3 long 0 debug long $7FF0 ep0len long 0 ep0buf long 0 ep0bl long 0 ep1len long 0 ep1buf long 0 ep1bl long 0 ep1toggle long 0 bptr long 0 buf0 long 0 buf1 long 0 buf2 long 0 b_1 long 0 b_2 long 0 b_3 long 0 b_4 long 0 b_5 long 0 b_6 long 0 b_7 long 0 b_8 long 0 b_9 long 0 b_10 long 0 flag_debug long 1 << 10 flag_class long 1 << 11 flag_setupdone long 1 << 12 flag_address long 1 << 13 flag_empty long 1 << 14 flag_setup long 1 << 15 Ddevice long 0 Dconfig long 0 Dvendor long 0 Ddevname long 0 Dserialno long 0 Dlangid long 0 Dreport long 0 Dtext long 0 delay long $2FFFFF ping long $0 preload long $5FFFF flags res 1 lflags res 1 pointer res 1 epoint res 1 ' inbound endpoint t res 1 t1 res 1 data res 1 da res 1 db res 1 dc res 1 dd res 1 crc res 1 bytecnt res 1 fit $1F0 crc16table word $0000, $c0c1, $c181, $0140, $c301, $03c0, $0280, $c241, $c601, $06c0, $0780 word $c741, $0500, $c5c1, $c481, $0440, $cc01, $0cc0, $0d80, $cd41, $0f00, $cfc1 word $ce81, $0e40, $0a00, $cac1, $cb81, $0b40, $c901, $09c0, $0880, $c841, $d801 word $18c0, $1980, $d941, $1b00, $dbc1, $da81, $1a40, $1e00, $dec1, $df81, $1f40 word $dd01, $1dc0, $1c80, $dc41, $1400, $d4c1, $d581, $1540, $d701, $17c0, $1680 word $d641, $d201, $12c0, $1380, $d341, $1100, $d1c1, $d081, $1040, $f001, $30c0 word $3180, $f141, $3300, $f3c1, $f281, $3240, $3600, $f6c1, $f781, $3740, $f501 word $35c0, $3480, $f441, $3c00, $fcc1, $fd81, $3d40, $ff01, $3fc0, $3e80, $fe41 word $fa01, $3ac0, $3b80, $fb41, $3900, $f9c1, $f881, $3840, $2800, $e8c1, $e981 word $2940, $eb01, $2bc0, $2a80, $ea41, $ee01, $2ec0, $2f80, $ef41, $2d00, $edc1 word $ec81, $2c40, $e401, $24c0, $2580, $e541, $2700, $e7c1, $e681, $2640, $2200 word $e2c1, $e381, $2340, $e101, $21c0, $2080, $e041, $a001, $60c0, $6180, $a141 word $6300, $a3c1, $a281, $6240, $6600, $a6c1, $a781, $6740, $a501, $65c0, $6480 word $a441, $6c00, $acc1, $ad81, $6d40, $af01, $6fc0, $6e80, $ae41, $aa01, $6ac0 word $6b80, $ab41, $6900, $a9c1, $a881, $6840, $7800, $b8c1, $b981, $7940, $bb01 word $7bc0, $7a80, $ba41, $be01, $7ec0, $7f80, $bf41, $7d00, $bdc1, $bc81, $7c40 word $b401, $74c0, $7580, $b541, $7700, $b7c1, $b681, $7640, $7200, $b2c1, $b381 word $7340, $b101, $71c0, $7080, $b041, $5000, $90c1, $9181, $5140, $9301, $53c0 word $5280, $9241, $9601, $56c0, $5780, $9741, $5500, $95c1, $9481, $5440, $9c01 word $5cc0, $5d80, $9d41, $5f00, $9fc1, $9e81, $5e40, $5a00, $9ac1, $9b81, $5b40 word $9901, $59c0, $5880, $9841, $8801, $48c0, $4980, $8941, $4b00, $8bc1, $8a81 word $4a40, $4e00, $8ec1, $8f81, $4f40, $8d01, $4dc0, $4c80, $8c41, $4400, $84c1 word $8581, $4540, $8701, $47c0, $4680, $8641, $8201, $42c0, $4380, $8341, $4100 word $81c1, $8081, $4040 crc16tableend dd_device byte @dd_device_end-(@dd_device+1) byte @dd_device_end-(@dd_device+1) byte 01, 00, 01 , 00, 00, 00, 08, $88, $88, 02, 00, 01, 00, 01, 02, 00, 01 dd_device_end dd_config byte @dd_endpoint_e-(@dd_config+1) byte @dd_config_end-(@dd_config+1) byte 02 byte @dd_endpoint_e-(@dd_config+1) byte 00, 01, 01, 00, $A0, $32 dd_config_end dd_inter byte @dd_inter_e-@dd_inter byte 04, 00, 00, 01, 03, 01, 01, 00 dd_inter_e dd_class byte @dd_class_e-@dd_class byte $21, 00, 01, 00, 01, $22 byte @dd_report_e-(@dd_report+1), $0 dd_class_e dd_endpoint byte @dd_endpoint_e-@dd_endpoint byte 5, $81, $03, $08, $00, $0A dd_endpoint_e dd_report byte @dd_report_e-(@dd_report+1) byte $5, $1, $9, $6, $A1, $1, $5, $7, $19, $E0, $29, $E7, $15, $0, $25, $0 byte $75, $1, $95, $8, $81, $2, $95, $1, $75, $8, $81, $1, $95, $5, $75, $1 byte $5, $8, $19, $1, $29, $5, $91, $2, $95, $3, $75, $1, $91, $1, $95, $6 byte $75, $8, $15, $0, $25, $65, $5, $7, $19, $0, $29, $65, $81, 0, $c0 dd_report_e dd_hello byte @dd_hello_e-(@dd_hello+1) byte $28, $17,$12,$2C,$10,$1C,$2C,$13,$04,$15,$08,$11,$17,$16,$28,$28 'All the leaves are brown and the sky is gray byte $04,$0F,$0F,$2C,$17,$0B,$08,$2C,$0F,$08,$04,$19,$08,$16,$2C byte $04,$15,$08,$2C,$05,$15,$12,$1A,$11,$2C,$04,$11,$07,$2C byte $17,$0B,$08,$2C,$16,$0E,$1C,$2C,$0C,$16,$2C,$0A,$15,$04,$1C,$28 'I've been for a walk on a winter's day byte $0C,$34,$19,$08,$2C,$05,$08,$08,$11,$2C,$09,$12,$15,$2C,$04,$2C,$1A,$04,$0F,$0E,$2C byte $12,$11,$2C,$04,$2C,$1A,$0C,$11,$17,$08,$15,$34,$16,$2C,$07,$04,$1C,$28 'I'd be safe and warm if I was in L.A. byte $0C,$34,$07,$2C,$05,$08,$2C,$16,$04,$09,$08,$2C,$04,$11,$07,$2C byte $1A,$04,$15,$10,$2C,$0C,$09,$2C,$0C,$2C,$1A,$04,$16,$2C byte $0C,$11,$2C,$0F,$37,$04,$37,$28 'california dreamin' on such a winter's day byte $06,$04,$0F,$0C,$09,$12,$15,$11,$0C,$04,$2C,$07,$15,$08,$04,$10,$0C,$11,$34,$2C byte $12,$11,$2C,$16,$18,$06,$0B,$2C,$04,$2C,$1A,$0C,$11,$17,$08,$15,$34,$16,$2C byte $07,$04,$1C,$28 dd_hello_e dd_vendor byte @dd_vendor_e-(@dd_vendor+1) byte @dd_vendor_e-(@dd_vendor+1) byte 3 byte "H",0,"e",0,"l",0,"l",0,"s",0 dd_vendor_e dd_product byte @dd_product_e-(@dd_product+1) byte @dd_product_e-(@dd_product+1) byte 3 byte "W",0,"i",0,"l",0,"l",0,"i",0,"e",0 dd_product_e dd_langid byte 4 byte 4, 3, $04, $09 dd_langid_e