From bc62c81396de407c90930a54be5fa83de6778148 Mon Sep 17 00:00:00 2001 From: Thibault RICHARD Date: Thu, 7 Jun 2012 16:11:26 +0200 Subject: [PATCH] [sam] USB Host stack v1 with enumeration working okay using validation example --- hardware/arduino/sam/cores/arduino/Arduino.h | 3 + .../arduino/sam/cores/arduino/USB/USBCore.cpp | 2 +- .../build_gcc/libarduino_arduino_due_x.mk | 12 +- .../cores/arduino/libsam_sam3x8e_gcc_dbg.a | Bin 244890 -> 0 bytes .../arduino/libsam_sam3x8e_gcc_dbg.a.txt | 418 -------- hardware/arduino/sam/cores/arduino/main.cpp | 2 +- .../validation_usb_host/build_gcc/Makefile | 41 + .../validation_usb_host/build_gcc/debug.mk | 25 + .../validation_usb_host/build_gcc/gcc.mk | 85 ++ .../validation_usb_host/build_gcc/release.mk | 25 + .../build_gcc/test_usb_device.mk | 218 ++++ .../validation_usb_host/descriptor_parser.h | 288 +++++ .../validation_usb_host/test_usb_device.cpp | 780 ++++++++++++++ hardware/arduino/sam/sam.bat | 8 +- .../arduino/sam/system/USBHost/Max3421e.cpp | 295 ------ .../arduino/sam/system/USBHost/Max3421e.h | 54 - .../sam/system/USBHost/Max3421e_constants.h | 273 ----- hardware/arduino/sam/system/USBHost/Usb.cpp | 991 +++++++++++------- hardware/arduino/sam/system/USBHost/Usb.h | 273 ++--- hardware/arduino/sam/system/USBHost/ch9.h | 94 +- hardware/arduino/sam/system/libsam/chip.h | 4 +- .../sam/system/libsam/include/USB_device.h | 6 +- .../sam/system/libsam/include/USB_host.h | 59 ++ .../include/{uotghs.h => uotghs_device.h} | 6 +- .../sam/system/libsam/include/uotghs_host.h | 378 +++++++ .../arduino/sam/system/libsam/source/uotghs.c | 301 +----- .../sam/system/libsam/source/uotghs_device.c | 324 ++++++ .../sam/system/libsam/source/uotghs_host.c | 404 +++++++ .../build_gcc/libvariant_arduino_due_x.mk | 1 + .../arduino_due_x/libsam_sam3x8e_gcc_rel.a | Bin 75306 -> 81262 bytes .../libsam_sam3x8e_gcc_rel.a.txt | 88 +- 31 files changed, 3546 insertions(+), 1912 deletions(-) delete mode 100644 hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a delete mode 100644 hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a.txt create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/Makefile create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/debug.mk create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/gcc.mk create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/release.mk create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/test_usb_device.mk create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/descriptor_parser.h create mode 100644 hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_device.cpp delete mode 100644 hardware/arduino/sam/system/USBHost/Max3421e.cpp delete mode 100644 hardware/arduino/sam/system/USBHost/Max3421e.h delete mode 100644 hardware/arduino/sam/system/USBHost/Max3421e_constants.h create mode 100644 hardware/arduino/sam/system/libsam/include/USB_host.h rename hardware/arduino/sam/system/libsam/include/{uotghs.h => uotghs_device.h} (99%) create mode 100644 hardware/arduino/sam/system/libsam/include/uotghs_host.h create mode 100644 hardware/arduino/sam/system/libsam/source/uotghs_device.c create mode 100644 hardware/arduino/sam/system/libsam/source/uotghs_host.c diff --git a/hardware/arduino/sam/cores/arduino/Arduino.h b/hardware/arduino/sam/cores/arduino/Arduino.h index ced24761a..00b6715b1 100644 --- a/hardware/arduino/sam/cores/arduino/Arduino.h +++ b/hardware/arduino/sam/cores/arduino/Arduino.h @@ -193,6 +193,9 @@ extern const PinDescription g_APinDescription[] ; #include "WMath.h" #include "HardwareSerial.h" #include "wiring_pulse.h" + +#include "Usb.h" + #endif // __cplusplus // Include board variant diff --git a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp index b06a88f93..8a9d2410a 100644 --- a/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp +++ b/hardware/arduino/sam/cores/arduino/USB/USBCore.cpp @@ -540,7 +540,7 @@ uint32_t USBD_Connected(void) //======================================================================= //======================================================================= -USB_ USB; +//USB_ USB; USB_::USB_() { diff --git a/hardware/arduino/sam/cores/arduino/build_gcc/libarduino_arduino_due_x.mk b/hardware/arduino/sam/cores/arduino/build_gcc/libarduino_arduino_due_x.mk index 0a71c2f31..104eeda08 100644 --- a/hardware/arduino/sam/cores/arduino/build_gcc/libarduino_arduino_due_x.mk +++ b/hardware/arduino/sam/cores/arduino/build_gcc/libarduino_arduino_due_x.mk @@ -34,6 +34,7 @@ OUTPUT_BIN = .. # Libraries PROJECT_BASE_PATH = .. PROJECT_BASE_PATH_USB = ../USB +PROJECT_BASE_PATH_USB_HOST = ../../../system/USBHost SYSTEM_PATH = ../../../system CMSIS_ROOT_PATH = $(SYSTEM_PATH)/CMSIS CMSIS_ARM_PATH=$(CMSIS_ROOT_PATH)/CMSIS/Include @@ -45,15 +46,16 @@ VARIANT_PATH = ../../../variants/$(VARIANT) # Files #------------------------------------------------------------------------------- -#vpath %.h $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) $(SYSTEM_PATH) $(VARIANT_PATH) -vpath %.c $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) $(VARIANT_PATH) -vpath %.cpp $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) +#vpath %.h $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) $(PROJECT_BASE_PATH_USB_HOST) $(SYSTEM_PATH) $(VARIANT_PATH) +vpath %.c $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) $(PROJECT_BASE_PATH_USB_HOST) $(VARIANT_PATH) +vpath %.cpp $(PROJECT_BASE_PATH) $(PROJECT_BASE_PATH_USB) $(PROJECT_BASE_PATH_USB_HOST) VPATH+=$(PROJECT_BASE_PATH) INCLUDES = INCLUDES += -I$(PROJECT_BASE_PATH) INCLUDES += -I$(PROJECT_BASE_PATH_USB) +INCLUDES += -I$(PROJECT_BASE_PATH_USB_HOST) INCLUDES += -I$(VARIANT_PATH) INCLUDES += -I$(CMSIS_ARM_PATH) INCLUDES += -I$(CMSIS_ATMEL_PATH) @@ -90,7 +92,7 @@ OUTPUT_PATH=$(OUTPUT_OBJ)_$(VARIANT) #------------------------------------------------------------------------------- # C source files and objects #------------------------------------------------------------------------------- -C_SRC=$(wildcard $(PROJECT_BASE_PATH)/*.c $(PROJECT_BASE_PATH_USB)/*.c) +C_SRC=$(wildcard $(PROJECT_BASE_PATH)/*.c $(PROJECT_BASE_PATH_USB)/*.c $(PROJECT_BASE_PATH_USB_HOST)/*.c) C_OBJ_TEMP = $(patsubst %.c, %.o, $(notdir $(C_SRC))) @@ -102,7 +104,7 @@ C_OBJ=$(filter-out $(C_OBJ_FILTER), $(C_OBJ_TEMP)) #------------------------------------------------------------------------------- # CPP source files and objects #------------------------------------------------------------------------------- -CPP_SRC=$(wildcard $(PROJECT_BASE_PATH)/*.cpp $(PROJECT_BASE_PATH_USB)/*.cpp) +CPP_SRC=$(wildcard $(PROJECT_BASE_PATH)/*.cpp $(PROJECT_BASE_PATH_USB)/*.cpp $(PROJECT_BASE_PATH_USB_HOST)/*.cpp) CPP_OBJ_TEMP = $(patsubst %.cpp, %.o, $(notdir $(CPP_SRC))) diff --git a/hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a b/hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a deleted file mode 100644 index ad30b43b31a5d8361fc5ad26ef538bc1c8c6ceb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 244890 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 M_WI35kqBt@I;yBtk3McpxnFQ2|%xovO z82%Zo(7$&w$rB--x-x{?Z;v@c$%e>Cp?oM;JB0kwIV7fD07AJG`R+2L%jqi z&q%msIaMSpHGvCr$}s}(Rw-GV%`Jf31@1l(uFKxcj|zAJ|d)%vo0q(6u299Meg98NI@8alA8z=LA6^!OVj-*$G6xt>{Y zwW=F42Ewsx4Ali4ESOk}=$H#uDQutjb+kluv_*8RRvlv(An^_0fbN?xZg1+rGSY3Ba3Peoyyf@p&M?FMj-}(1<^O-%H_Q(u=2 z@u)?o`hq_?IvpTC?AdBX{Rw*yA~Yu02c8icd#+P5oZJ;T*CGw$lMAbz%C@P35s znZgLCUv`n0W&Gs>d^14Y`uXE+itv1Y?48jcdQ0-lALcC$^NNP~KvO2as5**_0}XYC z&40xIF*G4DhyAL7CO6<~Y~|wmntJ`MS=Z9J0iVD9kF-w9r7OF-*RR1>tJLa_&bFSF zE%-cc_6+adw9;BqYbH%fb$0Z&tz6ZyZY6wocC4DZrln`@?hReNjc{&Uhp^#}W(EC1Db@H} zS?-!e-iYTh&)N0&hdAl!ehn)!=YM+VhMT7f7t_Yo(`!8E@J8TRAv2#V`9hZ`|X0(n`vegiUY`O=0f7S@|kY-UM0G*oH` zLe(xUufna>g1Hryj6h9!g~UP&enGXBuDfQjD!X)Ld3P&zo>;#U-^5q8V+PI5&E0J) zf#QgpY-P`;p5C^#E74?-TD760v$YXz2ddD5WjeEFpy?(Jl^X1_1@#M-UA>^H*s->0 zz6~d~Di^!Es%@qtXB619+leWDA;>(I`h~2(kqtzUJPk3JhEju|oh4V-RGMm2wYXff zx1qAszH6%VCTpmirG>M+P6J)w$GeJiB^Iw=*U`Ja+elS5EUT5Bait1WmehVHWqx#Oawl4oBHFHNy zrpj3qTB-kw=Hd7cc02<391ic}F^$wHAk zH1H!WU_hFRBlQ2y@j;oRV-j(0;blw%#Y#`a*ZfJ0c0 zul2SsOIa&d2|I?|eRCM!ZZ@&ID2zHU(Aa49#zh(zQ#vKS8c zWrUl88^dKdHr$WF9@fXX8D(&@#)kV5IE3|i_@0=88})I#&g$C(dsyE}5aD~&>e~&u zu)ZSbv-y%6()VPVK8~lB!p$11?+G}B^>N>f6x!@B45F z>st}h$9UTG{v3Adv*u+G$8F_-qvibs_OQN<(6=8-7(aYs@%8;Kj309R%VTj0>6QW)3HC4FDVGya^p9DgzKAoM&Nq}Bc;Y#i81R4JdDifgTn;anK#tO zdd)Dy`c|Obct6~%vHC1+G3@?s%q?OY5SWC_zhf9|Cu0)ZfXlf=QTYrf1vcf|ap9d4 zzk%UgqNxE1Tb46TY373qI&8RKNmM^u(7?pe0!I045d*`yLs5Q|;@qI93tOzf@VtsB zpCuKTxU?W)8kHbq&gT4zkT}YpcS>M5H;DNagqjMNu*D^}1E;vmqzTjK`}>KEhcovR zSq5bJlnI^fv?Dfx?IxHGTkf0fo%Zi{;+M~+#lAPsTi?k%_s)4O()Itkfu9nmLutlNu!!fAq`CT zpDxc5rGGw42hx|$=OZYF29)7(4v@?Z0?OPVU;*97>D(Yp1)HpLY_ljoUvYtAt>RUR z?^SG3>{4Vo(f=)q+ZA^y?ooV1@iE13Djrb$2gO5*|DyP!;?EUdR^)S&;T}^wp~y-` z_e@28bs^2=f5d!6K8Hw8P`p@?&l9@OQk<(Ob1vX6UowDP!bdqi2Z+}xHYu)F>{OJw zO_1BD^eu{aD1KORhvFv`?^Aq0akt_Z71>u{__F^BaKF;Bp8)8CN(H1yv^gkEV!q3?0h@c#l4 z{$O=tDf8T=f6)tC^g>Ua@*9ZI*RFIY5qh^Ny`2dCyOe&A2<49}y`PBidT$>1Y?@Qf zwVOR#H&8kAT)QI$2n53pj5|x{a@-xE&m0K3#p!Cexr1DM5#g#)?4nZY6wwhIs9eJ> zt5XwG#?n}SbyZFMMFsOBH2qRM1@|S(YimgtHMh3n_}m_NE#6pKd{JuNycF}Xs3Xj% zt}Yhivz-p^(t;Q;zD4F^jL}g|Q(RiAqB|bF)8Ctfv+z!0HxdUslbpofAIYaN3r_cK zS#z4*Pq>Rp9%kPW`vk|{NP9}%JjDcX)RBGIeWem}1-Wy{XJ1XkPIipP88!Qw_jUYv zQv5Jy6mDsbA352<-A_(p9~fuSFAtsU$cpSD^T9L32F+{p$qt-%Q?ZY~g<~rBb&RPz z***qm{Y;RZUhLj6In^h-wrIR@>duXl2Tcf{^A6)Dn@+S>y>@xw{?~@a@2xoYLrNAQ z6-3TrJh_o)>co$|6~l}`ab-T7NeAXMV&50!@1Y=ncb_IjW~ShdZ|r!~oLj^lTf$}Y z<rOA{@0>>0$<6P11R=i=#QM9Zk=}w--dY(=<@Zh_ zzi)FqQpQi6M)suS|8-6KHcRPNpCsaJqsn7_%TD4vCc}RLxEW_1kuqmTnH_mfm5)C; zO^B=;KYGNTf)td6sXx*3`0Z)*oY=Uf{kj%2r#9Hb=y=m9%H!B=??Z0K_TvJ|Oj=+9 zbYj;P>E%)OTE;MNPa!=(c^td_G}@!(QTAHaX>>=*W4tX5o-~zS7N0zxDn8zRPH0xH zt=*hMYwP#e8{%>@l{tGV$oIa-yRJx=!$iSJXO{cXBXP7WQBAfU@Qko<36{M!?=)$> ztiABqO)Z5-M@R4AW1l`vUhsHxPKUKI(kNxdwbPODB*=vhV6IVIktY5h4slE2J z8phrb)cRo0t#ln7XV7sHdHkarPP7j%!%M^x({3#nArA0(;oY`zH!sNZ)(OfhA|S%+~Ey#B!?+%Lo8PQuS+#zma% z59Wk_7X7XGr{NH@bHe3KIVPPIY@_uX@`uB3%+3i<(d7yJ_-CyB1=(K4I%@H+m3Fl9f1virn}`+|n@n8~BO)hpydBYSIn{fLXcc;vFsRtjT3ph}G7glw)oicd3CQFbXq(0#Hd zXFoum?vqt)_Uw{F*J6b;vN_#7K5LAGP?~*!lC!BrCRlTBXS~#qcf_*Ck~_zc+hW^AglahhF7tfa9)ffZ`h4-4_D%^*W@Bq$5)2(An52_QZMp7WBQTfS>zbF?F5p%_m@k=NjI!-; zwlNoFbP#18=0uCKi=fBlO=I31cLTXL!NhsLDjUqu+;5pU-#GYT2)W-jv2Go_nYT&hhQSX(m{g7l2~d_x*7EJqDx;iRk)52A!verF`SNubcJ*fg;;}2Ke;YHHMwjP zumdnIzU_Y6SN0p54sKrT{zlUwaix%rtHce(NL3v6!rhKvzW8E#s>bUrt4gxu&#G$p z!}R00nkU00Ph3e}Z08NbCD@pfj)Z$5G}>^bXy_nG!m?lnH^RM>ksWKaFftQyZG+o& z;0~9{KGrp{>4o%9C_OPMy&rDdeCdfHX;~pr5=f_@`#7Y(>PwgS(j(npf{P^r;A4Ce zS21efpMA;8RI+n;A#3JknhWicPKw!dN>Pn;Ig*Rn`o6Yy_*#tN1CyqOQEdw&+9>90 zV@(=?X})l}#uYKfuL9RDXx!mzyvAyj2+=)F#e7DnEl^Phns@ileHCr0qIJ|;3~r4^ z%G_lX^EI+17%3}V+?z}i7eX5sdKTc}XOehRBtj){x89{D&_Qa#NGFq?Mn4Ok*bT0V zf^G(5m%jqhutyt4`4QGTpN(#&p=X*&=~;Fvxo4-6+j;0RJKfGh$8Kvf4;{11_1Hq( znFCMR9vq$TJtUZt%^BRX8(hus8M!3#?DlWNAQUQf;`u>bPd|M;yhmIy>WJAYH?(IPoTNK+roH9(Fv0Zc6y>c! zm4I7hx_US~nXX+WGQqTK`aOfc6yqsFi2pg^Nj$6HVLaJ7pGCfer=xT9TN+aM%Y)T7 z1LVuQ<}Za%&LX^i<;SKL{__1u3Qf1um-{>QSMm14llsCI=`6~jU;5ZGhSMiQqHseE zlwbZFR~zpE8rEqV)=?TuvkuX)PS8v=;A2W@<_(QSrkRFmpkbWC=D#xhg?MWG&pNEK zSB9KXg#OwC+?UuftP9H{Fh`f{cXC+e&+y2eFPkHBqkovwSsq7rapnO9Qg%FLS=FS>bg*kObCU5y~D=Eh{F-GT_Uhy31(HB?I`ISjC!Pvi3C&F$w(h?36@nv zCa%l(l7J_3+2I>gxT&N8A=~XAOMKfj*@lr*!$oEZ7K_*~A>vX;Z~6g79D;!zxOSSI zDwp0UEPss0?A6)B(U@}cxkdQ?n2x4N2aJLRB#bP_g=CzELR?F+ii1KV(uZ^gT6N&( zhpZBik2d~BJ)(qTO3T_>+B$I5sEHIyB)k$vzXJ)gVd1i1n@V4|&DgpI%~~qOU|H`# zyH)m>(^(}xl8S4t2zJ|~Lj$s0KPdJ40#^SYSf4@N+}V@JJw_#)`=!BbIuDU$NGjHx z;8R<4A6BrCK~%B~5!EF;k%brJ^&cvfV7andys}==(tvFmdseq~SE6Cvu{C@j;vZD~<%X)yYe|9KB{I~6& z9gvX!e)`!l3GqdLzKuMP9hUIAiL>RU()@+fv{87uJgfDNxSrPfcKGZZh2q>VP3$y< z`2F&Xov9FC{J*Vr7X9~4<(*)UW6)9MV66iytIsv{H_DV7E#1ksby0V}os2pM4~wX~ zG?`{7U3Y3lTq5mU)LB}pz^UIY8P)DL>QU$5F%Wgfqe`3ge(sTP22pPR=A-}Kva_ah zzu5JyI5c@mW8>-#>slHcr%azUZJ@nnXHA; zYe3h5;xKde%z9@d9X7fu!2tg-sm!y&A%Xl9^~?v!Kv zK7=c*?`7z-FSKBZ9Pu_>VSVk;M~{pjrpWpF?l;bU{=I^N87O}DLN20jRuDf-CHD0_ znx?N95ocR&jZN>D;SkohJEU(Ycs9NN1baBW+#inf)2y-j{vHlteJ?{F=dUrn{1RmK z{T%kNzB^F(MR2pm>iZ)c!g6~~A;-9c<(`9F$|?g|eUsAUjzNykSZk~t_mB#w4Ol{F$x#uSPwX782^5`b>apXNZ{_|+`Bi zdqsVGG+BM4R9`Wb!Q`BS_8?6k!z)OWTZF~}k6__rB{)lC@0}e2H}bS!w=*wRreQ2mcpKeQh|U|3PW~2gx^JiZj1m z=OTG#wTApJhka{^z7F>LLbPv%h5LX<)0g8kssN^ULw`|N9P)$H>) zCO^*ku1c8tS&$}wUYh)Q{(4;Y-CQS?CZCdbg}^bLUy#O64{v-LKRy11Y5es3n2^R# z&)*Bu_!k6Gg)NSer)YbSUf(WE<6oHOzbK8Lem`84#=j`d|HWzii_`d%()egxLnbay z_`o49D=5P>pTvQQN1hx^Kc9qwiOZ8LOwX3^gZ7Y5h`_|1bQ+!Mkcm5UoS%bc8-5%Y z_sRc5h)=zI_alF=@U!IX5Ykmb4{}n3PVe^m8Bu4Sta41XJMQw5a(D{mm{wd%w{-uVSYnr%luSPQ`l^Wp97De^qIo zAx6396n~-knxY#s{Ar5ZwV(23iX0y!y_lHoI6TCgxSWVe_Fm=79tM!xtTe~B=0+5k;;IiPbsIPnG@^5tWG>*Ast7g#Le5KIi$<|M`j>=ZG!A40fd#6VW(crMR5P z_$j|r@n#|l`7WjJCFbLKr}zL7{ywk#uPMr23JCuPO8-Jp&VjiS<(Ys#@JABy5$PPo zbBWM5QTa0zWzPjP8t+kh6%jYxYQ-Cf@YkdK4=8?2@m^vzp36#qfmq-;+`XLmC=vd@ zsr-YA+?Ad2{5Qqpidh%~qWNCRar2w;=a?TXT_!@XDOjf&fdC=`C@ zA>OSh?LFvSNv-ySaCmbBJLx_gNla~4=cW?_>$twipPnl3~ws(I}K@1QP$;w z9-;I&#grny!|*j zaUaX`2e?P+hZXtVg#5=94=6sRc$hfDab8q>N%3XHql(8A-&Dk4iTIOq%WyyQXcOMo za@+$jrF4ViOVRYE^6} zBCt+HNjK8jOBz_kdXDtoN<=z&dJNO|91-am!tzCWE+QiSRm1}9T|`8@rQRXF50FMY z_Yx5=sYi&H)DOf5tH&iCw!B9${Oh!Q5k8_QwB!fk(V(=X5Al)sLVhFN5wE+Ie-9Dy z+pF|rM8xwsr4JJk-(yN2CnDZ?Ods@(AR_*gl`bYC9SfDNC9>Wq-AP2cq@9BQ?WB>u z-OArXoPlu&r4JI3&l_61?2%|Gnlqh?HVylmh+yi>d$n*528=9!<{dHw|4y7e_V`k%cZrP8k)O!Af#9L*LCD$)2v$uO z&@qv?OLz%}pYbGqaCpkc32tUNAnO(U#BO7)#Co*|Kf;QxPD{F6oP%P^$(f%MN9^Ky zN(q*gAqwj5Nfy}COUwc+duB?%g;~F3Je;5M*F8C8Fk<5(y-dGrPFFa^xeoTgg#VI* z9qdUA)6FRinCIO8umu#lzd{1{TjocJlK$kw^xfZ(2Vn7rasa?eHtdx|EJ7XetUCSPdkUu?9JWTu?`1| z7(344aHe4G3y(%{rr>0NDb2mT-5sko^tSb&$j{cG*<^*6XDG~!geSEg>xwzQm@nU#$aaljGN?YGV ziyF(j6126G)d1q(REA)A7(Nj@<4MCM{aj0I4XwPI6|EfiDGcY0m1C<3Ru@3b?I7^T z@D1f?hT*b#OnNVf&9tboaztA;WbxhYVc=j~Ik=cFdAOK&VSRbXKm7Z~>hm4c5_W$# z<`jhW$Nk!7T)Dq)*l_>cu!%=%0Mmocg1OsGUlD0%eTcyu^N%QFVL*O6jv=Ek%q&F zysLeI7)tnzeSxElt@Z^@!2a&{1=uAyMPDGy`rp1l_z)=D0r}s)KzC$W*x5b%BRvM( zgf0Ku8^BEn^WUv6!12KUs=ff<8Lgp}SF>WVGB_@OHhqB)Lhfw(0$+vPyWJNE_pL%n z(i9j7yZ`^SFJSIt9XtB(*dJKmyC&QrIAecc_RLvkaNx{i18=f(92y&_b}Icd(@(xH zbPjrI>93b1|G3FLdcKR@BOT|2`)cL!@p-{%=yo5%|3_!7%U+0f&&RRtTbjDR`o!yv zAG0ppf0X->+P(R>Gh(oRV%Qb&)U(nzwp-sk3*DJCi2IMqo|0yNOzL0tReK7%P2WcU z{PWHJetWtPT_gvBU4HGVRL*3Fe@`w##-2Iu6pcUH*Zm}LAYR2$ z=ajtD`5TX2NKdKrv^=NcRQ{lIKwh$)p<&P2w6rDLD~^?|>hI1pS6E#r8P*gJJL2|z z!`71^_u|!C`stNCQ~%BrHq>X2CrabT`mo#U8;7hLP;yyf*d2<=Q7?9HbGRAoj@J*fa+_`En27$w#cd6YzCgY*YJ(^M|#cknm0w z8YDxZVSm)L&`$dM3t!fLZ^ieYHTz-OG&)}j=WTHb_bz4Lnp|K$rSowdXoPQL%sczZ z<4py&RB?Zx-3asqaW6B54f z@6m1kzSR5LPhvmnrN4f1di+(VKK{o3;rnEN>QPVIRGnzAKR&*AO!b!bXYrg(PY_hT0EID`r`FCRDn69WR(&V?Po8|rrYOB3hcs~W@Gmze~8&7thN$<(c zc4t`gJPY%$;U+#oUFLoDLbI*^OOH9@pFDoF zz}9QCkFn*lWvY#t8p>Mry+0i78D6&Z*Td`6p3}PjaoFFA*wUlf^0W-QZi_8F)>l68 zGc??e^^XVj4SyH)nRKD;pMLtZAoliYaP(FeIdb&YSaxOTso?V~WDofu73_xu`9AiB zG1ZlSI4=43tlyG2PuzmRE;9z0aJkmc-HqOSUbshZ`tSI>k+}+wf%q}-GVOl3pXTS3 zScXiph-KY?cd0lhbY$B7atok3{;zP(tXm5``0{f*bl}SmhfMM1XFnW+FF%b4KjW|9 zl)1|OWbup?H>-@F+r6)Y-|g{~mR|3t(7eIps>qwXLJU-H@mdkFt=^~Mev21}uUox0 zA@6vf1lRR);U4pDf=t}|KHL-DY778oc-@f9^j<@xv%Ft15bqQ4G|2lRLdo%#Lo(NU z8omZomovoUcCy2~@4zML9YyHFy}yKggx3o9ksfD7jqyNvv?mLJb#~k9WfLiT2_ zXCxO&K=DF+_?CQU`Xt|TuwO9jlJ5*$9I;6nXX<6{v>b*c94rdlPtNBphk*(w;bd^O zUM7Pb`dcQh#+`+N$Yc|g@f*sE4LPV`2+ey`=uE@Ez|w;ZJ=4dE{MUs9fy7P39D;gs$SBQ&$t6 zO02F=Q}Z;dYZdM!Z@SfW5%Sra;p^fS<=)KCK*#W6&zti&T8t!@(|ea%Wff?8yvvSC zG!w~vR5sTt`wk;EPn9L_gp4=eNaiI!Mt_$Z-iYKn^_SRs$blbq+}EoJK*FT5v_Tu*M@#X{~%BulC4DxR$uFMKMItVIysvN=NT z$V~Eu#;dT{vTlaFAWF_4 zITNAfvVp4s6>c+G$Av!M$#^d%DIl#YtB!D{I~g0vY2l9q_!qQEw0HV$pR#U7HGL6>t=ks7$tubB~L`jLCD}tw)eSgX<2fbsEk5#n23x^Xv+XQ&P?;R@DRNC z2k{g8z$(;^5zD7fa|T^UD<&_!Mt3jKhr%7{j!HDcFD6ITp(czz4<#JG+;!ul--Io( zlr~P@j?aKCe;NB255-X#&F5s||Ap^!q#yiHT&A7wyxGbBG$P@?Wdv73s1(=leZjY^ z;5nm>oWyHqmow($pksHq^B_vYPYYeRO7ZP`?3<_@u@8|I+u1v=3y2AGW`^QljN1%y z1ju|`vA=M}^b$Yf-UgrF+=^@HVDz>-P`D<4dJ)XEF-SIv_dZDSc{3YQk~tZxY?@N;0p4fk)Z_7x zdj)dmyRX8Qu|+($!kQ0Vx54wdBT>{DTQrb!x1kIy)dgP*QT!R40Ekx?Ty^mEUHV!I zOU8CuV>>&~<=(~_+YbuWK2|h-R5d!I5_HcXnQ~uZhTJdeQgGM?Eh+b6>Uz+3W3=jY$0AlbYYy4z4;GrsLJ#(}{WF6G|L zB!5rTjDh10I2O2E6_at$m*xw_<6!&{u z(^bDklC&(>DDH7CaxaG0jG;1Z(AfcdE7ZJh)eKcNt>=ipp{l0oLdg@$U0EcVGRzM| z!b~dJbuqGKxQ&l9$=!z=Jp;!+ATYV*?n8(Z-M?W`jt|Z#;B=O!z?qe&NgA&zdJ*Zj zkY^be8WnZagJNj3f)|Da?_@og8VHs`aGMpJ>I+VEJDH=ULGa8Lu7-Kk3YYrA7r9(c zlrhg}y%K`EA^1}Wp7RQ$GS8Qs>`q~-76fX?Lx785E_n_S!=%zI41i!#X&s!W9EW@C zw%cHJ-Ldmy@Hm$33fEBK*}#f%DWv7uFvuDEGp6j^MQ||!nHR%4b}6JX&TEdkMgxn4 z6P=Z^%w3*&wsTa?!3lO|YQl{V$;r7i=Q24j!7Fm&L&l*^u%{?w@Hhf{ib95-qA(bP zA@HGOu04Wbuswodh**#*Lv@}kB=Pb)+?9Ytx)Y*)VdX zb0OO9QTE)0(Nl~^oRW}2hUZT~Vi>XTp$X?i&s-RzGC9!`7sduNborbfcdk=1oChzg z$hj7Z&yAi5abBP!IGo{p|I7xc4xCd{96jT~cSegAmJJ{LFdoqe9VAg0_H5B6mp;fSCh5 zMIBJOr$3b1_4B9a(m*&Q>pbTW2fFPS{zjV2}@W&+h z=2UsD^+(D`@7=R1qyL~kiRTW)?rh`vcFH4sPrTE1jGYU_4gHhAoFNb89(j~q?>OF zG3Ret3*ON}D1Sz+^Ix(gD!f>$s_mwZmbR(o4T~4lPVH%4JAGsGR6AYzEaj&9C(2+* zWPNvAW6RnzEVfdqYV3DzR%NL}%{r{oF)ka-{Js_k?<4-&EM&Vxv9t|B=&JhxH>!9$ zyJE}hD;irRS&(AWV-GobD9gRp8_pGb{&_TSWw~n>c_W?|$3)CZ-r>6Q67l#xcXc8W z&r2m@@vq)8WkZ3S+!9EA1gFQOyX}D6PI&sJ+Y1G4Q{eR{x1?e`11FJT)u(vE3!@P@ zUEogLum)=k!fun?%Q3(ftL4v5{`@6=+{`O8D>q!b;XOOIJnwz!`RAX1abJAU*AJWH zTmpSZ9CzNvABub`^E2PL*&N#v@ZWIU;(eHm6AtgB<6gUTmp9_Bw76||-S;g1l{X^3 zX@^E2o^xfI%>Axwj;2Xv?n+bp;Hg=kciocPH>Amb1@iqI_l1<~OUur0(?gou_rxul zzJoZ@XX;tj&xg*5-)z|lUh?@ROk9RzPqW~!@MTGd#y?5cH6O(hOASzc8odyv9P{z zVSPhgP2GZJhJ|BhZgQ5(y@{5ib#1dR*1WE@v#s0N(An4xna0%}tJgPnVa;8jrfPBd zk`)bA^_5Ob*M`Q9?)Noz^fb1uYhKma*4ntbvw2OAgkH0*qt~flTxlZ3_*~Q6(ObQ~ zyJpGK?xo8ctj4MZS1+h*2(8uh7e{i@rUnZk1Y5auNy9QM%jGdRei#etLPF3~gHO^y zWRd0?oYN9fqp`27TV7LTIVO8*mMpuAwgxIMXPI5zTrf8+*F3dbDdbO3`F0x3Y8Ex_TOWS)`KB<-NVlE$z-i z6ekYsVI>PPfLV?Y?7Cjn)TxDN>VrB}j}ocldEHkVzZKQU+o*yCID)5ghGCaiBQJye zVrETuDmL^~H*e_dH6rzu6^#v>y4w7lDJc%D!2wbw(*oBZk4u6~E(vnEB*^BH*@3sx zz&gi9Du^DcB~Q;{j#hTIHHWLURwyJL+XHG5G%QzdcJ zaZRgnjTA?(J*di-T+I?cR@0oT8?l<~D~XlQ{KPS2lNc zngALqXBvyGN2Si<#VnT^*5vXUo^Dmef~YKCqOp&b7;Y--by|@5(@Jb6F>5GO@7G0X zk$3`2%Z&`nFJsdHR90Uh`B>E^Rjt0>R$59@;~9eJIk1Vxu;lY)C`$5|wbvE%nTI;2md{k`J`@tD#b( zC>5b`-719A+R?+?S%N|1vtZfP3#w3VYQv49Hryv_n_;7a{EmhmYKr};U*Fcdp{s^1 zHZoAFV#5l@Ewoyp4^K#HOCr-OX#;mTXwN3QxQsPJCvdWJG~(3W~=bJUnu_oUf;ugu1YCK7~D{1BW4Z(9wt1{BsP&v)0XSLMEO$%bCQ&nE65#L}l zbUB-L^|HJNjYp_?43fge)4wGV80l$|L)1)hwcO-)6j%&My_6H0sR|P-zx!<9B(TX3qk@g#RPEIcRjvZOiss>seLXsts!vuSe^!zT3oNS%bziNTJ-h zEF7(L0Y~EMzcWttUyYcZXcjv=@yY{#8W{3k6IEYlA0UCQ>Ltq;`^O_{r%SqXXmRD< zE^%+BM7e*h| zC|vXGX>3`&#_t{W;HX7&GvR)yv+?=Q*@;5d$A{0(3yT>*a8H`H-mIFuyP4*M>U+ zZq{%p$b>sMD;y?=u1*yn4reP*&aVsWOZmLPS!d(Up(`7HSpHP*93mS?o@pM)okM8W zJ)AEbQuFhzsDF8^^!*KyG=}r$bUY5pnec{))>EY^tnYMnkwbW@Pijrr-|2W9@;jA3 z4g-dH;W&ot!`s@+rMGQk@07I1ra8<{9K*MNaK@f(;iZ`{($=Zpdu4xL_PH=+RZq_p z`xYZazy5-CjlS0gDy12gBLdMu4LNJ4OJ9sb4DBg~W#OdnN+u=LsXf}jLAsZ9PMU+? z-wfRO!i)!G)Pb*U(MZ?_=>V=GEXBf@P+#Z;JkV=To%K5`0ZWtz?mY6(*C%g^(NO8c zlMKUR9BdfKEtD|x_zN^gJ4@;6?0e3D?&x#|dU#xAq?Zz~kS6DVD@V7m+*6>#akO$P;EtI>zS)13XZH3 zz_a-`0-gp+$44O(4);hXT)NwEcf%gezgpW9n7z=zRpwVI}W+9zC7ql!HxQ;m*F!0BjG=+ zZ##&G>7d5OZy4Od`ih~i4>Hu3#AWprL5|*Sxy?m|?E`HM3cX7KRy$!zBy_7 zI0bNmXfQukANv&HaF0N)bpW~dq{&r5LEiv!J!x_WAeS0I?v6CMmrfyfZ<-v&r~OZd zR10rnJ^{IKJ|9B9*m}S=g>o!6mJ$B_e4cy?eS6aM9SP~<9#vM~lWF=Ipl>et*4X%Q zZ9_O*t^*rqg@9J>-_zuH*5yEQ!_g3i^*seS-XqpneM2D^&X=P|#~}z+;bOmua?F>B zY5GQ>&%P4w)>wVx)Aa4HH~XYg-vnG%-=%5#x=x{wb1Eb83+bB}(zhf{-$CfxVI!w< zB(F@1zt>9KYkxcLYr8<9nsm*N~>Kd?L=(AybXjSC^*maJxA(k^0zfS$$2a zuUP#Lo`kj&uEY|mi{v)dXIT?a2xV}y#wO_w zxP|lOsg59D${}pi!KxPW?zGNvoWBY=Fn%<|P&IO1xx#V!(8er)`*paeFAo>P40(4t zF&DW$)5#(f{7 z@|jreZ1QM^$m0eH8SVoamG`7>QvWDiF?qrS9=K0rRDO_yW?#y{#6MiJj8Bf!5_pF# zhqsj&mWvBIY~mP2i^}IZ>r{YkJXXbq#i4(2n*3nr)`&bNd526KJ%tH8wZ78m8S2Nsw(cKM9**`o?f+&Mpue}2G(E$*b!_^C90K^ngxjXyq(KR%5= zA&oyFjXyDskH$7+;^;|4)5lsDm^e=Zyt0BJtG@bfzC2_w`R+=?2iB@yA(yc;|_RpB-ICc{EZ-eqvLZ9O_M(8oljY_lT zC2>FA9HGy3?E4pUI*I%3lgj72M$$<+eE-3}Oy^8uw1um_N%MU%i8lwXIwQ^JM-n~1 zrz7-4=SNEK5Pp%I-%NQEpNpN}DW5eViTcimFZp#sPnNR`0(y!wPWil3lBmBWN?$2- ziJS>Vd6R#rkN(#x98Q@w#M^Ih*N)%Hkgg^A4dz;g9m2&qn05fS-`Fi2qQkZWefEwF z;Mz}RI&4dx%t-25+hV`CceQnQbhS6Obl&KMTsL%Kjzml6dJF>7wddxJ-j?=8>|2bP z1-zu(}k z@5vvwrHc&KS_{7R8lU{`t2VLdcStxzhhUA69e52<7;ZIG+CVEELqn`2(*{>%%wQ@y zgKQg%fqZI`<~>82?mVxOy#bzAIY#+xQ^@y7<5A7t2hVRzC{1_L>;;gIf1#;oDjvOb zF9xPaBd`gifmNj6>o^NZ1DB9)bT|a&@I8k2=F}#~!M{_CANHB1HapG@q=6erBhp(* z13yF>eclg~24<2**9R;)Z*v{#;n*LDG?2X##*g{H_z8`82@Ra6{EL-8U+D^^8lB+5 zS1WcZb}MdFyhV}EX8QlI;toZQank)h#Rn93D}GUNuj1Dg_bYx^@t`7iW1+quD*jIK zPl~di7x;YkQf{*1T*X?&m5QB;TNOX0$i0y0pJOA$GDV)jKw8d01g=&3|0r@7GVF%q26yQ{*&U1ioa1jp*YAh^7)Dv zD$Y_|pxB_;qS&qY0mU7PpH}473XI1$6b~x?Nb%Q-e^m4^tU&qEiW3!QDpo1hE3Q&} zpJJcl#}w~Z{DR_i3`0==e8sC3uUG6;e4pYL#SbceO!1RM)TvJ?ewv6zcenB%Q`}EP z+72i_MTFeb%0HrbRPiJc*Pj*Rxkf&hh>)yKtMWgp?jKkD8^zBkK14)#UnXLR;8De|5uxYX%6~@jhs5(8=f{da zBSP+9mH!&Cz;XVdctZKZ(8pmo`NTrBcZw+@{9mN}If`Y(3y=?r3yF|hqWtB=3mxZL z#p{*7TKT<-cPM^@c#-3LOz|!v^xdcYhZG-Ed{*%V;v~oUiQ>= zI}!Xp5s}^m$}lz+{ZhqTBKS!n_~#Hyu%chFK=~Ice;RQ*#vBzdReqWB7ZGPV&QisC z}`%_`Kp9ihm-O<2@Je2E+^^{N)f4 zuhGOx%z;omU-_lVFC#8My;EGM{AT5M5U;>w*8-HP`p?k1ux?or&UDE(cy?^pVO;z7kjibsgZiXd4zZO`gbR7}xsq|-oE0u0iY*&>2EcjbV7hp_F zahu|H#k&>nQQW2YprZ6!(f&S08n|EafTHwU;eJTz!-_8|zCuL1d{ptc;+u+CK`DGs zky}TxotFMBaDviBip7dE6s6w_xiY1>i4@!I21V%ygKko~T~YeQaPL)mqat^WV*9;a z@ovR?6n7~;sJNGS3GzpAzv2PKgNpoyOSvP&si;4SuP7c>Jg)erBDbMpdoSn00`ryT zH&VJ!P?U3FL34L1w*Q=~Lab6;sK{@PbmzB8A~&t#^PpX^OOf9O>AqF5PjLqk&xgAe z?^E2RxLa|L;^Ra-FZL@wrFc;BImN?@M-*RDJVwNG!6f1JaO44%`IcG+mGm3SJ4T`NqJXhKkyA*pBxpgb~eTv%@w<~gssaQGQvlVwM z?or&U_?V(BC$BW$iDSU$=ng!rctnwNbLjqx;!#C@Hste&b8?8eirhDsbiU#^#R-Z< zirl7(&#SqLRf-E0>l8VshH`SAJFrP| zjtz0IqP*{c-mmll#e<566ps+`9DGUf6~&{9#}(gH#A}%oTWY=!uz#OV8qcQ`F~^LJ z^LbHBdYBovzlNF1J$e$UCr9|Y@T*WdX z@~cX5Arbjjt5`=w{xvABAR-@EDmD?3pRJ1RMC5CyViytl+pD;dh=ln4LFCrq}fenBERMn%Q1h0SgGwU^5quN$d9{;$Omahk^XOxM!H8Z-Ph>- zi*y$&J%fn!*D75{L_V}D-AP1#+@bU~BJ$-yrFRpNKl_zFKtw)CIUu|vq>*25D&Ju~ z7i#|w{1j>ApY-QImy$+4N`7Hf1@TFgd z{FZ(gXz7O`-(OPsmx;)K>2HDWu>58tzlfmoi71a5N|zE*F4B(zzkxK$NBT>kyGWy) zq@M&@`bp(zuhhTvi%@QlE4`nH@;j{bi$s*;F{P!ygYuOA4fKs*eL%TRCW0;|qI@^> zGw&0YRp-($coNRwj2U3W%{_)TdgacQE z8-MlB)3-FC>WBD84{g5lWcv%vbPZz7vp9@i=HtosXOHKW;LM+=X&VRI(5JuNezN_^ z<6gnZ_RYXtAWka5DO#xlo~1PGh?UG%$$XU@Cw%wFQazJu1kbJsooP0w=`zGNi8O3s z8st2rKOP!(gs!ot>1zn=Ovz=El0fRWNa3eCKJ`fY`6SVFB>Z%Y2&Kc(*d>?_IY}v; z4occ|qn0u-iMecL7Ha+kEAGIwD;Z+CC1U|wp;@>(>0J01<{ z1IsbVbAX)vxXNC;W*F=-*keFB-wl`mo!E87iH%#@UuZQoYX{H#(lcjR4>fPKeu!jq z)Gery)}KvJICsOmf!uj^*QM?E4p_ep?}Y(*(XwZ${wPwavQm~Gm}|OQo2xrIaT>hy zLv#qyG{Gcf*Iu^_4Gni7p9)AZ7c)rmlJ=I_E`;N$FlgijdNag zZ0TycBr^Cwh<|}HbsNPc>#JmY858N|W%0vOa74^kL1nCkTxKGJ;#m*i$D@rMia~ed zN9lu>PB_^`Zv3JzLu=0caExC}KX^9fJVR=dp%OWVNliACm-A61H-3qsa&s0S*!Yys ziNCy@rWmNHh8mHBhpH1VHdKDjAIK{){>J6}kkm9orE-Q-=X66&$l;SUKEqH&IeSRW zWF%vSlkr>zHOuhIa+bk0KHG#)mGf2dN;$7MR=6;Sxfq{gBx`eaQ}R+n)#dyZd6yZg zA?JEha}Bj3=P63g`vHDqg)4K0k~g2cc;QQK&J;2)XMpj-m))GFXer}~JMqF-+#Gfl z;^juTFP6g%v*Q(pyd##=!9-RXa$78?mN{2t$nCM5pHX;$A$P=b_*FArZOFT0IoTwy zFyuY4oFNomXvq6wIm;PtjUji%a^_L^N)t&uZKc{|uoh(PhrbMFs8kH5Q7T4(ll1~Q z-@#87#~nmEo=-iCSY5DjyL@)_64J|ay^A1}>n=lz+*ObYX7#@ZPJ>6o!CgfwHXa|` zL#l;UGq$s9FuNgctD!mvv$N^88LHhGlK3~#i{6yuepK{MfwdIZCw;viwR*=h^p8q6 zZf6f-^8;%BjPI)pzW&Mg^_hsT2LfNs^z}9Ibv1mjH#aO{)9`icYYpSM54{kip?mOr zQjdR1s7`07i{6przUWdZ4MRSH>snvWkFB0B(dSQgfyuo16RDqSUO0K~@8RykFdQ02 zh=uS8C>kc28go_CFo{FlHIe9oXPL8)O{&AOU?1}5zUT42XNg9ky9@dek6{vz32qP( zp6>JimG?E^Ssi8C=e*}lIJ^lV1X>ZWeMx9b%TEFXNLzmLM<6AEn1n)Ub`wZK6AK|< zehQ_y#X`T*E^49einMOAqN1X$THCH|ZLEB5b-OOER;%>~Eo!a36p>=JUETYhdFGrs zC!w_Hdg-@w<;^|!%rno-oHJ+6IrH-zeA*_^H5Gz<&dkMgvo1)5(dFd1*CEDT;o?7L zC-EDA?OP6s{_(*$}y(Zao4E=C(s&l-5)~K?RQnB;8m}sML6F46oyXPZ<0cqiw@kaq4Zer z4xSx!_F8&tAf4xKru24QB#eNoN88H+$?ZmRlxq3g<+ygEF5RrlZDB$_^Y#V_Z;K|p zEl8N_-ohO33Qx#na6Aw?oMhJJyUQeY&f!Iryfb+};#@c5YKWf8MFJT&y_;IxXnZ8< z>`iXZc4z=QlV+>YhiC)bzA>9U+?dTy*>>& zZDuCO4I*M@qDP4)vG|;4%Y}BKN7I&b_2}Yk+KwI*wJd#3-0<_cXJhzT8G*eWrvipg z+0Fuo(}u8!(c&a7UI*uq;mYtS`@^#_n0glJR5{rNy~%Q_bnFA)WI9zp$uAel19yhw z@+alTp6v}B&ur^FsQjvQx;K6PO5Rw0gUxG<2ksi;}+T1 z27^%AKC5NLRlUk~IJga3hGcP}Lbko9r@yRT`tiW{>?ya#4H7c|vG!tNU)>@nBvU!WAF*JWN<=3T!^lT0sb zowwzRiy{hs=(;d5t214?boIj3OKVDtl>JSU?e>IwRj6*^f{4EP5zzyQGb#HL%zIuJ z%itMU992b_m+2SHPtee;$@`~9VLG#umSo+`bf&gDYb0KV!ljWyyoQj%NXT~2y=s1> z*0&7`xyy5xnhbQMRx~tMRaaKSGF5Z^5*YGoXkJ+dvwmtwPn)aaOL$|?ny%groqagF z+F%;Yfzgyzv$DNW-oI`gUeC4NG-W@mp}DS+rrsKwYpR#QN)JsM!q5QZ%)msJu~i78b`8xsrLt+K^j7!Q zZ>FV?>m?uh#fvPlB)+d7HccCv8<(MY+U%YhqG4G5GL%5s)(i}61|CG$HNt!rP}xL- z1_%eH)U+wQ@HoLr-#VC5Zf=&mqoW(P`Oz@HKpBr~U>t5x=!`iqNw{`Re_PL*K67xP zUbYSdCvB)*6&u#{;~_Ld7#25%&eKnv9EJO`||$2sKL30=4Ff2 zF`4kW+DbhzOY5xFO-&u2$U!jYe^y|qw4u4Y9*qVG>v>uuwgy>Gw031WQ#U;}32Dbn zL7SU;n9k9=Kumk7?yZEW&9dv(bgoy{QwNXlX?+zNyViAH(+`Vw>-69ivqUj;Y^65V zSZx}9U4PK|AdYX3bZz+A z`c8rmCAU2$HwlSWA2x#Pf2mf#@d_7KNDLBvP2>d9=^ZFJj zv-QO)SalVIXkezbdFwPmbhr;-`#^lby7`fdCQii{L$l1IOCJ}zTshR0~dx1;2ILonoBS3Zym8s3uy$ z&e4fjZvrK3`?K+*J{(e&r>(E(LdUt(C_%jC1q+=W{^zjkV%J@lF3gK|T%z%qfv_Cy zwnXEt3legkGb|QA%u3C8KNim`Gjz1u64f7N9(D>xLoo1dIoffF#;Zx#K!SE#a5-Bp zn_D<6m#zAuus@1Q(~e72{|I%hQvuVs&N-GY)^}t~KAIctxJ31_rG(CNM#bXUDnmy* zFVXaQVI+K>GddQJi_vnl0~1Xj)|_G<>JvQz@%pic4IS;i*v<=%jt-^W7TeKIi|uHa z#daQ^l9+#ZRCtAk&WqfkS>F6G5x!M?ux{xoR0{fs^qiOk_O6GDLz82ZG~4k*6RoOF}?)9JhYdW zg!3Mohnl}8oJTef?I9b&l;^txcF;KkdgJ$(%ihJx3|5gPmK)8 z=zw{7(emMIi{{}Ai{`~?238#%s z#vc^q0w8j=?*^#$i35*HIH!Oaul9)pvvGqZA1}!7pp#!JxI}QJ;5xy6!5xBk2;L{C z*8f7!Z-xIskhA>MpCy<_#I5jL!Er=f-~|#tLvW#BtzfI*JBYXys&&M`9&)6=LE>)} ze81p+B0A;+f@&WMNTitibfj=NZ{$~>ZvY^_>j(Uy8Lka80uaPJ4 zGLkQNAra{cC4Ro(Qo*YQuOZ@AcCFw>BGPS^_*(?`3LYS$@vC*tK(${4@}HCV!-C%s zJSM32f#8;Pk{tL75$Rl<3zk1ma2yfOXXgp#6CpQ6;x7}d7HlM2DSJj|zU4h)&>P!AFUZQ~Nid=NXav5i#vJKN0-7$eoaQ4;_PQU&MTDBNbHp z`k`-v#7_~NCs;|Gg!d7_8Y1LZNPL^1+UJk*yo>xo$GKUMpK+(W+V_w6`^bTx6MRze zh#jH;NA&RDu_a26q5YgV}304X&5v&tz6l@Y~5$q=7I_MMJ zD!5H>r{FHZI|cU&9wg#=I3)O>;3I+qf`xj5sR6h%B65b-%A-G&kBA|@R;BWg0B!K$a;NXlKm^t7t9qLBRD}Y zEyzVsyxxih=Lwbys(v5wHNqPOR|#@i6t6=rc_sDvkQ#}WvUVF$Ge|7?ha&xIJ%Ue!Fd1*VE z<-3uHa_uIj9p^*DeDv2ut8xaz-9Pt{K$z3Qh>-%V}y?iucnnKft5+@d+NXAHf6X7;SP*hNFvlDctG zO%>LyqNLin7^w*v`T#wo5bU3sfOlB4reCkmU)>V!1PJ#KVBg9~r+nzRE!;ohef5OX zF#0rU@5Zhf&l_sL0CuQM@xF6I$7f&O(wz7X_j;tbN9IK@zw*>K8oqd9t@oi<6Qh^E zc*kfvwe!Spc??w*lkQ^p-OqruNu_PT+W(D|b$!0_V!^*&_do1OFmDE9maBG?%%FKG z@9!8=x0a&GVfzVw2FJ0m%AaP=!d3piLtF;sGH=GeVcFir)ac`f)%y&>>V1DX*%Zx^ zKAMW-O}$OUVWenfTc6`idoO7+SxxYhKL(`SU*f;J3fYA#phkgZ-GG1YDtfV+JBzPb z?ke@Nw7VOdtC@ewEnsMCkhTPLVUV^}(n79~ab`_4di0q9Zu*e_)LT*c|q_BlDvfMR9rzat7OV;6yq%!EJVrcIP{ zqw$fbKY3-WUJ^SD3t+P@%ep*^D^>mI0@&f_I-busuB1%`t5YMZVY8yEVYAI@*b%n4 zy&5(rzGQXe*(_OAOEWn*VlUAHRTsmVmaLv_I`nC0l^+|+*_4wF$4)m->ZfnDAaJY; zok5n7j(O5ihwY4l9kMbZ`@dz0A8$FYv%rthXS2NTStq^*?RkeQ*X#v;zd%TI zb=z;048Nvr*1P=|Lex67d6_i}^oO$f#Yn6tB47lp4yIiC&Yj!sBv`qq_({K8T%3ZYpG$#?IH=J`k+l>xlF5v*q}_IFuZp z_G~%6f28pVA z1f@la%lI6ITz;;|4U^}h_upPg- zVmr>w+m3VXwlm*Q38i?(L&tBV*p74Qw(~Hnh@lqM&UCv^s_`41Bh53^xEDF^$9Xtj zMIz6>kaN?#-!h(<$DT<)H|d#P>sD&tMCmuTPx`|fr!cu?@@ynfIUc11iq1AnWG#pj ziFo_FfQWWKRl;WpUM5&3SS8pXxJs~HaJ^u!;JXC(3VuZJLBS(}-xmD7;4vba+6#g& z5mES;CEmjUWBK1I$m@_}b&~`q6CpoC;>!fp*dCgc8oL6ju`9@3CGnktY78DtZ8JG= zD-m)xOZ;7e`-x}(YD^1wP~<)>@dJY25IicV=09-J(ZWj^qN*}rsr4RC| zJmAIDgLE}S@H!&WcL-lkgq|J3cM_pb?-${Avss(hzy{Ho#!lzXoi#J9+?mHt)4Gcc z#!lbHo^1GhjGsF9FF%=XJ$xd^gGHRR<64%VERC=M#m2wGJ5F0fd0$_CQiqhD8V*}7 za}(p%I!~CeySuanoKr_kh)Ctdq)u*|O!-|qK|fYb!^}qS3gHD^7i);H#%TUZBVR8-m=&wTuaLjSF(r8c@>F`M>w9e06IJ=PHK%T@7&wtx5RrwwtH{+2b}3|+o>&o>lkU&Zue!H_ zdG?bwE+RV2g)C*i>-uV{Dv>dbfr(+?M4)+CiN~x)@_qw=iyoj+>DB8QDzD(kXuSHaSa6 zPD(8#E7oz7Q->%yTTO}=Oiig-r8zpTD8*OX2xhA^~yP4v$hnCOePoTl69n}k}cG1eTpys z$xNd1G$)#*d!^dV^{7HnT9tX(? z+E4*BWdv<#H`!E{EK%U6I?1MKmYteQ7PO%Omb6eG<1vo+Q_`Y3=pW(I@~2ybe|Ydw z{~1^Y=3cF67i6b`=BPO}_karg0RmRxm%?Q~l4}9o11mu>CFtaS9W?XKBzK+2wA!fO zAknb%DdD=&_&i3rm#8SQ{Ns*tFUT34<>ide8RgcyD>6CXgt_>vtOW?f8N|$3j+q%t zN;sYsGsNnQ%&i%7Grlo5Gu)nSOGRhfvh3NmYzStUX}J;8orT#tzl*Z9VHg|>dx9;r z7BezBAD0`SZ5tJzZOgL*Xktb=96$7>gDt=C^k7N~$2D}PljT`^qq6EbT`bD*#M;wd zJoC&0mw@`uf2Nr*4?3o?-Rs4x^+V1FSQGcvoDpabF8mG~fo%w)vK@9B+6&7XYZuiN z>Idn<|BuXCpsL!`#ZdJOY+gj)BVK1}tbHAATHtC9&0*j(g7Ki<{_Y^Gr@gs#!z@VP ztVXlxz@QSGSiUH7i~2Y1-lOKd(wTSNA)YRo`@BgIteD~4(Z|8fP(_U7(VE2BT?*7WO$NUS<+f%UHFY;?6dJed5O@IG( z^S7h_I=te!Ze49fbJcQ8#wkw&cD2*PjqAh)?)Pt4Q3qcwX4pcj5Grit3YddvP@DWK zHukhDvjZ!-vAeh39GlLrPOOGszoxfCYgxGhTBx|LVo`lj;G5x8EL~jRyrN>Mu0Di8kmUAu2Hg{?6l&Jw_()E(_qU=A0*#Ps{@^Yy&s zh+!O0F^=~L6VCA!<9N?F>v>FWyq_LF{ozJ@9iv)SJTQKJ>zPbB8P-+)H$I!G=QDU? z<-MJbV_CM7TemY2ft16|L%FydD2TwnO)5I#jziJU243AlM~fH!#B zD2Jaf0mdCeBgzHgd<}0@)Xj2TjUV$h`Z(6tZ7PXyQwBb0+WJmH-|dj4zF{IqeVg#J z_3?WnM-gV6(RT*|C}-Rwh~Qoh<4hdi7wmj@;Qfzlq?s?D`Rj4f!Fbn=)dR@ zXW~8$Zu}|=N^UnoR@^7yxAT1sgQfcs#(XhU8RRmR^*siC%$NEwq#x+}3H&Avyv|YRTVSDYKYmW*5mJZK`_CVdCwW*8zm zNI56MG{)Tnxh6w^rsdpT7)*vc!^f^oP+1$7$OkO z;dSRdcOtXZMj6oPvx1b@4*zq^d$L}kGe<>-aNg6t$LO9Ql;$4kX#6nMmePTUjxVx! z;Dv|tn$h(3nP5B`pXCP6bMndx9rq~Pj(d)6$34Wh<2)uMa4N;|jE8RU9$=hI%W+=x zEy8)^MxnK^|K>SjAIm+tGlld1%z4fw!g*g-JD%eYD3jV8OnSy|y4I~W7IoSOXuUq8 z5dGf-l%)umMxLBknIt$_P`!I1yd0eJyk}6pUig*5`-E>6zEk)v;T+In`p*kLEc_|q zM}&V<_>YDER5%v}Gkr?R%i%I|TIFVWmI$vA&iN+BuNKa|o8(;FO?l2=l5_r&{6XQ5 z2!B%emxXgwl=4S}|5W&k!cPc4C44N-Ddi^ssh{>3$Z5ZUe1UN8g&_ZX;cJES9{SfX zFZ~G1fqB?33-bJs|5%WHBsm9)iDo{TYt6}P1v!pIZsw0UR7`H>i|-K5F++ymFUX-c z@_!Tjjv&Xk8UC^$hq=i|37#)FO;CL^2l3Uy)gD^#cHzB(?-EpdqY!_u@J|UoF8H+I zbAsv{I*`8xHv*QUUvRtNZozv6KPC8i!7mc=@bmu!zd}R@r1ri-pW6G1>rm}|1**NT zh(9Lje?df-_bb8QNcz_#J`0@?%cb_h0;dSSRIrMOc1Xu^fGW%uWIxDo_JTy-vxugD zU_Z|OqeO6?V5K1YHpZ_aqMW?n659kj1iJ;ZU7#zElm~j#5)V-2GUfNl z5wGe2ROz61jL36no%J|LMEpFSPZN(0+|*aq6Wr8O)eBtJ3-X0CW%@X+-I?Z_XB5qx zp;MfBzIiGOiyLgQg2_1cZ&kkkZU44??k0Ti#>_O{&|-X-w`}RSyklSa=p$L!Gc*qV zarlyq_v@s0Ile+dyrJc?4kNv<{H1Rg|K%;i@I@KSa$@Gsq_8EA2a-2nPIyDb*YK^C zEgkvCTgvl~-~N1DW*j`HJ9{l1{Y zdl#D$>|OkapK;y5AAaUMaUR+snjc)!Jr@nwy%HBMC-veE^LGa!=v~G}YrbQ08(VH7 zV+VvWmG@yJ^1 zq1hOp_jd1Q&BpqCUi1F1W)plqZ+N$8miAvJ+o{o9f?6_K%ts z`9~?aOS57>&13X#%}V?|Wbe^zp3gnB-fqoG{kvGBJ(^Ye+_&i6q1h6@f;#Witj2$w z>@Lmf{PC>qKWWzJ&tlyBG+X6gL$+75CiVFa@BNy!_`Iul`!s9wH&OC#%{u%C8F!Cn z>-{R0`U9GE`?PN6{j+9${t2>sHQVgJhg$Y)w$;Cz?1N-p!8X_bJw5kny2JHzn8$}S z-Rb(=*zXq*Kg7hIxzv=o1 zsOn)&pLPA~nb9Mfe$Vw^BK;RlkGlR-Eac}kJ?8qHoc12o^aa^A z>2cQ?p7glm+4};=CsMnTGu&20|tDPB|>wvD@ZRDIwreeNgbw^-J6h0qF`(mXU3D4OYEeqGSYcMCuf!8s3hkL zotnijwj>t_Ey|k7Vk{I|oHd(;EEQUk)r%aGWkTm=*I`gMS?<11eV3Z6+<#NFCF>tqjK!|9U{TPQ#hvKMB`PDYV5jSh;O(6C z%efVvEGLskbi`WtnYjwY>l2 z?3e3up5Eo2RlU2I_!d0UjG}1{_jmMS`gT+mifI@=Qj%nWM!T0#=6qKr=3@{awZ?Ev z4Era`5a7C*bqG3VJ92U-G7Y{g@+BrJ5b`R?Bq3jfBKHCzzhRmSh5Q}GE)sHS0_0*% zqPhJKW_0d+7GcK(+z{nkG#L|7Lg%cfrS*Jtrk@l93kV!eI^*#}^V0rgm@b_Do}}XN zPe~EOhRr-|$9(AQaAi6`4TzlORCFPYfVW=O)ZMf3nw~Wq(y*%C-rLlQ-G6$jy65^P z<4IpLWlDN|XJ32M+Rm;f%n`wuIFlEy>De%?YhzdYwDvV?I}6nwxI#UJr2j|b&D8Lj zCYgqki+)=HUs1p|#QtuxN_EievYK=+X*ZL|_JlE>&UkJd@3*d7de!Qs6FK$!FI&{7 z1m1Q1Rr}RU@T$!IFI-LE)d|;{2EG>zfki5?dtFy!#oXp4Yr5LjxA!=pW~yz59oSe= zVpGhN7TLVMu`xp1VY}?Q_O_XJAktVWuM4s%vgU%j!{FJDMdsKAE4H@btl?4bf@*@3X`e@%NdeMQ}h>PqI`aAidxT3&@oN>0F*z}P+F7S)!8kqs5) z&5hT0w=-f1Y}iNj1=F^Ot+bPox3BHLrgmdjkPpHdE5c$|a|)edE33n!-`w8Q4kP`X zDGz6gIYC?vTiDhyoQVUvu4~2e#>Gn-A{nf#woVHqXhJ&-31+OBnAYpe!EWX*+SY5G ziYgYW5{&wJtfL3NF+4Ke*I}z& zsBPa+yQT{rQIG(Em1PxSNx&N#LfYKk*S=Xd_d2U%fK+3}99xO1ZdkwO-k|6Bi!5K@ z7@WO!VFGVp;`ne-mgDog3uQU#YYuvh&cySf!K`6;Q~Rw^#p&0{RT{2Dh+gA*1w!=v z{*A9b;9M);6wJex9y>HglMi>=O$1O5uMx_{+ZG8vw9cLTDsE=ulzPH0~ z>tjLH>p#NjC`Z?cALWemA(xNW5#vl;I|A%{Clz2%9u5-oWw^<=AAXYtUgr`-PO}1x z_m-I4O1v7hF@ZQEw;kNhHybCY8)3|s*O|%ppWruX;B_8_zRC26GjV&sZGBszZ!E&7 zk2^+f@V+(f26)CJnsKtI&6o6=1v%BhJ?M zAoNiW_2uDb^!+RROv83a_f8y)Ow)M48OPs$3L3fXP-3@zBljHSa5}pI$~_FZ8HNBU zNB1lIjGz1k$St8q9Lq=d3;gVQ9JY=NrW1mCU}`70*5GxD@FMvdJ>pDWM02e%Y8OsM zDPEp={c}c|`SLh1Pt+rDPh(BSY%9R%3k1YthyOX&6yUH}&KwmT#J$p(nzEdA;t}!#Fi}2$ye-=OP zgM_chskRgAaCcu$Pq7~|ZBg1v2ZLV>290(MF@Rx@TMQath`rjz-#a63>Gk#-S-tgkW)J?@!!h>D zQ)Iv>G7=OSRIuOIBd_?8w`-8_?FS@$myNy9#l|vX?>~x$uU^rY+{hRUNH`MFV83M9 z?_u^ksr|lbzf;-+4fZ>sJsLx8D;Z<4duTpU7ZAWc(`f1{)cJ zkrz$tz0n$clDBGk~vdjc1VZCpHyt)e_`%Dk^8E_R$2;w7?9Ws2C6MW)>hpC)!8rehr$d7;=LKw);0 z<3Vv3ai(4uoWKO|o#e%ivzItq+uKRZ!MhLnT(K8XBK9KiQu6@AFT?sY;^ksDVxHKl z#mmtE!|{-Cn7Gh!o+6gQhBdJa>(z+mj`K}og?_F`RKk`H`68@8C02=jiN#`1WC?8Y zFuYoSGbn+F4&L7jm+E!WMZjG08ht*BfGC1fSgY3w76JL3Qn<`<@aGiaUkCYeef)}m zedKlexD^4PB*)9ymnjcq`3viH`HO(eKanl%0T0LcQ|qJnJjiuYIMvFAFHWgiH#b$n zX9%)EU10miZs8*qXzh5}lsWARw!7mFwBgp$T=4iIyfNSB1-WK|+)ZlC733lZhR+dPB-kj} zDtNEprvx7td|L21!50O8CpbGp>#r1S5L_$xEy3pnUnCB5oL>s6Z!V0$`?JIk#|6Xk zo-cS25wAz;TMNKKa>y4;{9?gI!8L+if;R~66ue7NeOm$fJRtmW!LJH_Tkx3RuLb`g zn1wp9oMVZ6VdZrKKMsq+Y(e%n3?D0qTY%z|1Sbok>(uM`1SK>j9`ER;e8s{|dHx$*`GHpe diff --git a/hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a.txt b/hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a.txt deleted file mode 100644 index d5c0cf942..000000000 --- a/hardware/arduino/sam/cores/arduino/libsam_sam3x8e_gcc_dbg.a.txt +++ /dev/null @@ -1,418 +0,0 @@ - -adc.o: -00000000 T adc_configure_power_save -00000000 T adc_configure_sequence -00000000 T adc_configure_timing -00000000 T adc_configure_trigger -00000000 T adc_disable_all_channel -00000000 T adc_disable_anch -00000000 T adc_disable_channel -00000000 T adc_disable_channel_differential_input -00000000 T adc_disable_channel_input_offset -00000000 T adc_disable_interrupt -00000000 T adc_disable_tag -00000000 T adc_disable_ts -00000000 T adc_enable_all_channel -00000000 T adc_enable_anch -00000000 T adc_enable_channel -00000000 T adc_enable_channel_differential_input -00000000 T adc_enable_channel_input_offset -00000000 T adc_enable_interrupt -00000000 T adc_enable_tag -00000000 T adc_enable_ts -00000000 T adc_get_actual_adc_clock -00000000 T adc_get_channel_status -00000000 T adc_get_channel_value -00000000 T adc_get_comparison_mode -00000000 T adc_get_interrupt_mask -00000000 T adc_get_latest_value -00000000 T adc_get_overrun_status -00000000 T adc_get_pdc_base -00000000 T adc_get_status -00000000 T adc_get_tag -00000000 T adc_get_writeprotect_status -00000000 T adc_init -00000000 T adc_set_bias_current -00000000 T adc_set_channel_input_gain -00000000 T adc_set_comparison_channel -00000000 T adc_set_comparison_mode -00000000 T adc_set_comparison_window -00000000 T adc_set_resolution -00000000 T adc_set_writeprotect -00000000 T adc_start -00000000 T adc_start_sequencer -00000000 T adc_stop -00000000 T adc_stop_sequencer - -adc12_sam3u.o: - -interrupt_sam_nvic.o: -00000000 D g_interrupt_enabled - -pio.o: -00000000 T PIO_Clear -00000000 T PIO_Configure -00000000 T PIO_DisableInterrupt -00000000 T PIO_Get -00000000 T PIO_GetOutputDataStatus -00000000 T PIO_PullUp -00000000 T PIO_Set -00000000 T PIO_SetDebounceFilter -00000000 T PIO_SetInput -00000000 T PIO_SetOutput -00000000 T PIO_SetPeripheral - -pmc.o: -00000000 T pmc_clr_fast_startup_input -00000000 T pmc_disable_all_pck -00000000 T pmc_disable_all_periph_clk -00000000 T pmc_disable_interrupt -00000000 T pmc_disable_pck -00000000 T pmc_disable_periph_clk -00000000 T pmc_disable_pllack -00000000 T pmc_disable_udpck -00000000 T pmc_disable_upll_clock -00000000 T pmc_enable_all_pck -00000000 T pmc_enable_all_periph_clk -00000000 T pmc_enable_backupmode -00000000 T pmc_enable_interrupt -00000000 T pmc_enable_pck -00000000 T pmc_enable_periph_clk -00000000 T pmc_enable_pllack -00000000 T pmc_enable_sleepmode -00000000 T pmc_enable_udpck -00000000 T pmc_enable_upll_clock -00000000 T pmc_enable_waitmode -00000000 T pmc_get_interrupt_mask -00000000 T pmc_get_status -00000000 T pmc_get_writeprotect_status -00000000 T pmc_is_locked_pllack -00000000 T pmc_is_locked_upll -00000000 T pmc_is_pck_enabled -00000000 T pmc_is_periph_clk_enabled -00000000 T pmc_mck_set_prescaler -00000000 T pmc_mck_set_source -00000000 T pmc_osc_disable_fastrc -00000000 T pmc_osc_disable_xtal -00000000 T pmc_osc_enable_fastrc -00000000 T pmc_osc_is_ready_32kxtal -00000000 T pmc_osc_is_ready_mainck -00000000 T pmc_pck_set_prescaler -00000000 T pmc_pck_set_source -00000000 T pmc_set_fast_startup_input -00000000 T pmc_set_writeprotect -00000000 T pmc_switch_mainck_to_fastrc -00000000 T pmc_switch_mainck_to_xtal -00000000 T pmc_switch_mck_to_mainck -00000000 T pmc_switch_mck_to_pllack -00000000 T pmc_switch_mck_to_sclk -00000000 T pmc_switch_mck_to_upllck -00000000 T pmc_switch_pck_to_mainck -00000000 T pmc_switch_pck_to_pllack -00000000 T pmc_switch_pck_to_sclk -00000000 T pmc_switch_pck_to_upllck -00000000 T pmc_switch_sclk_to_32kxtal -00000000 T pmc_switch_udpck_to_pllack -00000000 T pmc_switch_udpck_to_upllck - -pwmc.o: -00000024 r .LC0 -00000000 r .LC1 -0000016c r .LC10 -0000019c r .LC11 -000001cc r .LC12 -000001fc r .LC13 -00000204 r .LC14 -00000014 r .LC2 -00000050 r .LC3 -0000007c r .LC4 -000000a8 r .LC5 -000000dc r .LC6 -00000108 r .LC7 -00000134 r .LC8 -00000160 r .LC9 -00000000 t FindClockConfiguration -00000000 T PWMC_ConfigureChannel -00000000 T PWMC_ConfigureChannelExt -00000000 T PWMC_ConfigureClocks -00000000 T PWMC_ConfigureComparisonUnit -00000000 T PWMC_ConfigureEventLineMode -00000000 T PWMC_ConfigureSyncChannel -00000000 T PWMC_DisableChannel -00000000 T PWMC_DisableChannelIt -00000000 T PWMC_DisableIt -00000000 T PWMC_DisableOverrideOutput -00000000 T PWMC_EnableChannel -00000000 T PWMC_EnableChannelIt -00000000 T PWMC_EnableFaultProtection -00000000 T PWMC_EnableIt -00000000 T PWMC_EnableOverrideOutput -00000000 T PWMC_FaultClear -00000000 T PWMC_SetDeadTime -00000000 T PWMC_SetDutyCycle -00000000 T PWMC_SetFaultMode -00000000 T PWMC_SetFaultProtectionValue -00000000 T PWMC_SetOverrideValue -00000000 T PWMC_SetPeriod -00000000 T PWMC_SetSyncChannelUpdatePeriod -00000000 T PWMC_SetSyncChannelUpdateUnlock -00000000 T PWMC_WriteBuffer - U __assert_func -00000000 r __func__.3192 -00000000 r __func__.3203 -00000000 r __func__.3218 -00000000 r __func__.3229 -00000000 r __func__.3240 -00000000 r __func__.3247 -00000000 r __func__.3331 -00000000 r __func__.3337 - -rtc.o: -00000000 r .LC0 -00000010 r .LC1 -0000002c r .LC2 -00000000 T RTC_ClearSCCR -00000000 T RTC_DisableIt -00000000 T RTC_EnableIt -00000000 T RTC_GetDate -00000000 T RTC_GetHourMode -00000000 T RTC_GetSR -00000000 T RTC_GetTime -00000000 T RTC_SetDate -00000000 T RTC_SetDateAlarm -00000000 T RTC_SetHourMode -00000000 T RTC_SetTime -00000000 T RTC_SetTimeAlarm - U __assert_func -00000000 r __func__.3189 -00000000 r __func__.3198 -00000000 r __func__.3203 - -rtt.o: -00000000 r .LC0 -00000010 r .LC1 -0000002c r .LC2 -00000000 T RTT_EnableIT -00000000 T RTT_GetStatus -00000000 T RTT_GetTime -00000000 T RTT_SetAlarm -00000000 T RTT_SetPrescaler - U __assert_func -00000000 r __func__.3196 -00000000 r __func__.3204 - -spi.o: -00000000 T SPI_Configure -00000000 T SPI_ConfigureNPCS -00000000 T SPI_Disable -00000000 T SPI_DisableIt -00000000 T SPI_Enable -00000000 T SPI_EnableIt -00000000 T SPI_GetStatus -00000000 T SPI_IsFinished -00000000 T SPI_Read -00000000 T SPI_Write - U pmc_enable_periph_clk - -tc.o: -00000000 r .LC0 -00000010 r .LC1 -00000000 T TC_Configure -00000000 T TC_FindMckDivisor -00000000 T TC_Start -00000000 T TC_Stop - U __assert_func -00000000 r __func__.3191 -00000000 r __func__.3197 -00000000 r __func__.3203 - -timetick.o: -00000000 T GetTickCount -00000000 t NVIC_SetPriority -00000000 T Sleep -00000000 t SysTick_Config -00000000 T TimeTick_Configure -00000000 T TimeTick_Increment -00000000 T Wait -00000000 b _dwTickCount - -twi.o: -00000000 r .LC0 -00000010 r .LC1 -00000018 r .LC2 -00000024 r .LC3 -00000054 r .LC4 -00000064 r .LC5 -0000007c r .LC6 -0000009c r .LC7 -000000a8 r .LC8 -00000000 T TWI_ByteReceived -00000000 T TWI_ByteSent -00000000 T TWI_ConfigureMaster -00000000 T TWI_ConfigureSlave -00000000 T TWI_DisableIt -00000000 T TWI_EnableIt -00000000 T TWI_GetMaskedStatus -00000000 T TWI_GetStatus -00000000 T TWI_ReadByte -00000000 T TWI_SendSTOPCondition -00000000 T TWI_StartRead -00000000 T TWI_StartWrite -00000000 T TWI_Stop -00000000 T TWI_TransferComplete -00000000 T TWI_WriteByte - U __assert_func -00000000 r __func__.3556 -00000000 r __func__.3571 -00000000 r __func__.3575 -00000000 r __func__.3582 -00000000 r __func__.3586 -00000000 r __func__.3591 -00000000 r __func__.3599 -00000000 r __func__.3613 -00000000 r __func__.3618 -00000000 r __func__.3622 -00000000 r __func__.3627 -00000000 r __func__.3631 - -udp.o: - -udphs.o: - -uotghs.o: -00000000 t NVIC_EnableIRQ -00000000 t NVIC_SetPriority -00000000 T UDD_Attach -00000000 T UDD_ClearIN -00000000 T UDD_ClearOUT -00000000 T UDD_ClearSetupInt -00000000 T UDD_Detach -00000000 T UDD_FifoByteCount -00000000 T UDD_GetFrameNumber -00000000 T UDD_Init -00000000 T UDD_InitEP -00000000 T UDD_InitEndpoints -00000000 T UDD_ReadWriteAllowed -00000000 T UDD_ReceivedSetupInt -00000000 T UDD_Recv -00000000 T UDD_Recv8 -00000000 T UDD_ReleaseRX -00000000 T UDD_ReleaseTX -00000000 T UDD_Send -00000000 T UDD_Send8 -00000000 T UDD_SetAddress -00000000 T UDD_SetStack -00000000 T UDD_Stall -00000000 T UDD_WaitForINOrOUT -00000000 T UDD_WaitIN -00000000 T UDD_WaitOUT -00000000 T UOTGHS_Handler -00000000 t cpu_irq_is_enabled_flags -00000000 t cpu_irq_restore -00000000 t cpu_irq_save - U g_interrupt_enabled -00000000 b gpf_isr - U pmc_enable_periph_clk - U pmc_enable_udpck - U pmc_enable_upll_clock - U pmc_switch_udpck_to_upllck -00000000 b ul_recv_fifo_ptr -00000000 b ul_send_fifo_ptr - -usart.o: -00000000 r .LC0 -00000014 r .LC1 -00000000 T USART_Configure -00000000 T USART_DisableIt -00000000 T USART_EnableIt -00000000 T USART_GetChar -00000000 T USART_GetStatus -00000000 T USART_IsDataAvailable -00000000 T USART_IsRxReady -00000000 T USART_PutChar -00000000 T USART_Read -00000000 T USART_ReadBuffer -00000000 T USART_SetIrdaFilter -00000000 T USART_SetReceiverEnabled -00000000 T USART_SetTransmitterEnabled -00000000 T USART_Write -00000000 T USART_WriteBuffer - U __assert_func -00000000 r __func__.3477 - -wdt.o: -00000000 T WDT_Disable -00000000 T WDT_Enable -00000000 T WDT_GetPeriod -00000000 T WDT_GetStatus -00000000 T WDT_Restart - -system_sam3xa.o: -00000000 D SystemCoreClock -00000000 T SystemCoreClockUpdate -00000000 T SystemInit -00000000 T system_init_flash - -startup_sam3xa.o: -00000000 W ADC_Handler -00000000 W BusFault_Handler -00000000 W CAN0_Handler -00000000 W CAN1_Handler -00000000 W DACC_Handler -00000000 W DMAC_Handler -00000000 W DebugMon_Handler -00000000 T Dummy_Handler -00000000 W EFC0_Handler -00000000 W EFC1_Handler -00000000 W EMAC_Handler -00000000 W HSMCI_Handler -00000000 W HardFault_Handler -00000000 W MemManage_Handler -00000000 W NMI_Handler -00000000 W PIOA_Handler -00000000 W PIOB_Handler -00000000 W PIOC_Handler -00000000 W PIOD_Handler -00000000 W PMC_Handler -00000000 W PWM_Handler -00000000 W PendSV_Handler -00000000 W RSTC_Handler -00000000 W RTC_Handler -00000000 W RTT_Handler -00000000 T Reset_Handler -00000000 W SMC_Handler -00000000 W SPI0_Handler -00000000 W SSC_Handler -00000000 W SUPC_Handler -00000000 W SVC_Handler -00000000 W SysTick_Handler -00000000 W TC0_Handler -00000000 W TC1_Handler -00000000 W TC2_Handler -00000000 W TC3_Handler -00000000 W TC4_Handler -00000000 W TC5_Handler -00000000 W TC6_Handler -00000000 W TC7_Handler -00000000 W TC8_Handler -00000000 W TRNG_Handler -00000000 W TWI0_Handler -00000000 W TWI1_Handler -00000000 W UART_Handler -00000000 W UOTGHS_Handler -00000000 W USART0_Handler -00000000 W USART1_Handler -00000000 W USART2_Handler -00000000 W USART3_Handler -00000000 W UsageFault_Handler -00000000 W WDT_Handler - U __libc_init_array - U _erelocate - U _estack - U _etext - U _ezero - U _sfixed - U _srelocate - U _szero -00000000 R exception_table - U main diff --git a/hardware/arduino/sam/cores/arduino/main.cpp b/hardware/arduino/sam/cores/arduino/main.cpp index dcc6edb6a..818679f18 100644 --- a/hardware/arduino/sam/cores/arduino/main.cpp +++ b/hardware/arduino/sam/cores/arduino/main.cpp @@ -40,7 +40,7 @@ int main( void ) delay(1); #if defined(USBCON) - USB.attach(); + //USB.attach(); #endif setup(); diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/Makefile b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/Makefile new file mode 100644 index 000000000..3f88f26e1 --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (c) 2011 Arduino. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +SUBMAKE_OPTIONS=--no-builtin-rules --no-builtin-variables + +#------------------------------------------------------------------------------- +# Rules +#------------------------------------------------------------------------------- + +all: test_usb_device + +.PHONY: test_usb_device +test: + @echo --- Making test_usb_device + @$(MAKE) DEBUG=1 $(SUBMAKE_OPTIONS) -f test_usb_device.mk + +.PHONY: clean +clean: + @echo --- Cleaning test_usb_device + @$(MAKE) DEBUG=1 $(SUBMAKE_OPTIONS) -f test_usb_device.mk $@ + +.PHONY: debug +debug: + @echo --- Debugging test_usb_device + @$(MAKE) DEBUG=1 $(SUBMAKE_OPTIONS) -f test_usb_device.mk $@ + diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/debug.mk b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/debug.mk new file mode 100644 index 000000000..d0716744a --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/debug.mk @@ -0,0 +1,25 @@ +# +# Copyright (c) 2011 Arduino. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +# Optimization level +# -O1 Optimize +# -O2 Optimize even more +# -O3 Optimize yet more +# -O0 Reduce compilation time and make debugging produce the expected results +# -Os Optimize for size +OPTIMIZATION = -g -O0 -DDEBUG diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/gcc.mk b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/gcc.mk new file mode 100644 index 000000000..36951b468 --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/gcc.mk @@ -0,0 +1,85 @@ +# +# Copyright (c) 2011 Arduino. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +# Tool suffix when cross-compiling +#CROSS_COMPILE = ../../../../tools/CodeSourcery_arm/bin/arm-none-eabi- +#CROSS_COMPILE = C:/CodeSourcery_2011.03-42/bin/arm-none-eabi- +CROSS_COMPILE = $(ARM_GCC_TOOLCHAIN)/arm-none-eabi- + +# Compilation tools +AR = $(CROSS_COMPILE)ar +CC = $(CROSS_COMPILE)gcc +CXX = $(CROSS_COMPILE)g++ +AS = $(CROSS_COMPILE)as +GDB = $(CROSS_COMPILE)gdb +SIZE = $(CROSS_COMPILE)size +NM = $(CROSS_COMPILE)nm +OBJCOPY = $(CROSS_COMPILE)objcopy + +ifeq ($(OS),Windows_NT) +RM=cs-rm -Rf +else +RM=rm -Rf +endif + +SEP=\\ + +# --------------------------------------------------------------------------------------- +# C Flags + +CFLAGS += -Wall -Wchar-subscripts -Wcomment -Wformat=2 -Wimplicit-int +CFLAGS += -Werror-implicit-function-declaration -Wmain -Wparentheses +CFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused +CFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef +CFLAGS += -Wshadow -Wpointer-arith -Wbad-function-cast -Wwrite-strings +CFLAGS += -Wsign-compare -Waggregate-return -Wstrict-prototypes +CFLAGS += -Wmissing-prototypes -Wmissing-declarations +CFLAGS += -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations +CFLAGS += -Wpacked -Wredundant-decls -Wnested-externs -Winline -Wlong-long +CFLAGS += -Wunreachable-code +CFLAGS += -Wcast-align + +CFLAGS += --param max-inline-insns-single=500 -mcpu=cortex-m3 -mthumb -mlong-calls -ffunction-sections -nostdlib -std=c99 +CFLAGS += $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) -D$(VARIANT) + +# To reduce application size use only integer printf function. +CFLAGS += -Dprintf=iprintf + +# --------------------------------------------------------------------------------------- +# CPP Flags + +CPPFLAGS += -Wall -Wchar-subscripts -Wcomment -Wformat=2 +CPPFLAGS += -Wmain -Wparentheses -Wcast-align -Wunreachable-code +CPPFLAGS += -Wsequence-point -Wreturn-type -Wswitch -Wtrigraphs -Wunused +CPPFLAGS += -Wuninitialized -Wunknown-pragmas -Wfloat-equal -Wundef +CPPFLAGS += -Wshadow -Wpointer-arith -Wwrite-strings +CPPFLAGS += -Wsign-compare -Waggregate-return -Wmissing-declarations +CPPFLAGS += -Wformat -Wmissing-format-attribute -Wno-deprecated-declarations +CPPFLAGS += -Wpacked -Wredundant-decls -Winline -Wlong-long + +#-fno-rtti -fno-exceptions +CPPFLAGS += --param max-inline-insns-single=500 -mcpu=cortex-m3 -mthumb -mlong-calls -ffunction-sections -std=c++98 +CPPFLAGS += $(OPTIMIZATION) $(INCLUDES) -D$(CHIP) + +# To reduce application size use only integer printf function. +CPPFLAGS += -Dprintf=iprintf + +# --------------------------------------------------------------------------------------- +# ASM Flags + +ASFLAGS = -mcpu=cortex-m3 -mthumb -Wall -g $(OPTIMIZATION) $(INCLUDES) diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/release.mk b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/release.mk new file mode 100644 index 000000000..0d15157f4 --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/release.mk @@ -0,0 +1,25 @@ +# +# Copyright (c) 2011 Arduino. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +# Optimization level +# -O1 Optimize +# -O2 Optimize even more +# -O3 Optimize yet more +# -O0 Reduce compilation time and make debugging produce the expected results +# -Os Optimize for size +OPTIMIZATION = -Os diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/test_usb_device.mk b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/test_usb_device.mk new file mode 100644 index 000000000..336bbc609 --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/build_gcc/test_usb_device.mk @@ -0,0 +1,218 @@ +# +# Copyright (c) 2011 Arduino. All right reserved. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# See the GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +# + +# Makefile for compiling libArduino +.SUFFIXES: .o .a .c .s + +# putting default variant +ifeq ("$(VARIANT)", "") +#VARIANT=sam3s_ek +#VARIANT=sam3u_ek +VARIANT=arduino_due_x +endif + +ifeq ("$(VARIANT)", "sam3s_ek") +CHIP=__SAM3S4C__ +VARIANT_PATH = ../../../../atmel/sam/variants/$(VARIANT) +else ifeq ("$(VARIANT)", "sam3u_ek") +CHIP=__SAM3U4E__ +VARIANT_PATH = ../../../../atmel/sam/variants/$(VARIANT) +else ifeq ("$(VARIANT)", "sam3x_ek") +CHIP=__SAM3X8H__ +VARIANT_PATH = ../../../../atmel/sam/variants/$(VARIANT) +else ifeq ("$(VARIANT)", "arduino_due_u") +CHIP=__SAM3U4E__ +VARIANT_PATH = ../../../../variants/$(VARIANT) +else ifeq ("$(VARIANT)", "arduino_due_x") +CHIP=__SAM3X8E__ +VARIANT_PATH = ../../../../variants/$(VARIANT) +endif + +TOOLCHAIN=gcc + +#------------------------------------------------------------------------------- +# Path +#------------------------------------------------------------------------------- + +# Libraries +PROJECT_BASE_PATH = ./.. +SYSTEM_PATH = ../../../../system + +ifeq ($(CHIP), __SAM3S4C__) +CHIP_NAME=sam3s4c +CHIP_SERIE=sam3s +else ifeq ($(CHIP), __SAM3U4E__) +CHIP_NAME=sam3u4e +CHIP_SERIE=sam3u +else ifeq ($(CHIP), __SAM3N4C__) +CHIP_NAME=sam3n4c +CHIP_SERIE=sam3n +else ifeq ($(CHIP), __SAM3X8H__) +CHIP_NAME=sam3x8h +CHIP_SERIE=sam3xa +else ifeq ($(CHIP), __SAM3X8E__) +CHIP_NAME=sam3x8e +CHIP_SERIE=sam3xa +else +endif + +CMSIS_ROOT_PATH = $(SYSTEM_PATH)/CMSIS +CMSIS_ARM_PATH=$(CMSIS_ROOT_PATH)/CMSIS/Include +CMSIS_ATMEL_PATH=$(CMSIS_ROOT_PATH)/Device/ATMEL +CMSIS_CHIP_PATH=$(CMSIS_ROOT_PATH)/Device/ATMEL/$(CHIP_SERIE) + +ARDUINO_CORE_PATH=$(PROJECT_BASE_PATH)/.. +ARDUINO_USB_PATH=$(PROJECT_BASE_PATH)/../USB +ARDUINO_USB_HOST_PATH=$(PROJECT_BASE_PATH)/../../../system/USBHost + +# Output directories +OUTPUT_PATH = debug_$(VARIANT) + +#------------------------------------------------------------------------------- +# Files +#------------------------------------------------------------------------------- + +vpath %.h $(PROJECT_BASE_PATH)/.. $(VARIANT_PATH) $(SYSTEM_PATH) $(CMSIS_ARM_PATH) +vpath %.cpp $(PROJECT_BASE_PATH) + +VPATH+=$(PROJECT_BASE_PATH) + +INCLUDES = -I$(PROJECT_BASE_PATH)/.. +INCLUDES += -I$(VARIANT_PATH) +#INCLUDES += -I$(VARIANT_PATH)/.. +#INCLUDES += -I$(SYSTEM_PATH) +INCLUDES += -I$(SYSTEM_PATH)/libsam +INCLUDES += -I$(CMSIS_ARM_PATH) +INCLUDES += -I$(CMSIS_ATMEL_PATH) +INCLUDES += -I$(CMSIS_CHIP_PATH) +INCLUDES += -I$(ARDUINO_USB_PATH) +INCLUDES += -I$(ARDUINO_USB_HOST_PATH) + +#------------------------------------------------------------------------------- +ifdef DEBUG +include debug.mk +else +include release.mk +endif + +#------------------------------------------------------------------------------- +# Tools +#------------------------------------------------------------------------------- + +include $(TOOLCHAIN).mk + +#------------------------------------------------------------------------------- +ifdef DEBUG +OUTPUT_OBJ=debug +LIBS_POSTFIX=dbg +else +OUTPUT_OBJ=release +LIBS_POSTFIX=rel +endif + +OUTPUT_BIN=test_$(TOOLCHAIN)_$(LIBS_POSTFIX) +LIBS=-Wl,--start-group -lgcc -lc -lstdc++ -lsam_$(CHIP_NAME)_$(TOOLCHAIN)_$(LIBS_POSTFIX) -larduino_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX) -lvariant_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX) -Wl,--end-group + +LIB_PATH =-L$(PROJECT_BASE_PATH)/.. +LIB_PATH+=-L=/lib/thumb2 +#LIB_PATH+=-L=/../lib/gcc/arm-none-eabi/4.5.2/thumb2 + +LDFLAGS= -mcpu=cortex-m3 -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--entry=Reset_Handler -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align -Wl,--warn-unresolved-symbols + +#------------------------------------------------------------------------------- +# CPP source files and objects +#------------------------------------------------------------------------------- +CPP_SRC=$(wildcard $(PROJECT_BASE_PATH)/*.cpp) + +CPP_OBJ_TEMP = $(patsubst %.cpp, %.o, $(notdir $(CPP_SRC))) + +# during development, remove some files +CPP_OBJ_FILTER= + +CPP_OBJ=$(filter-out $(CPP_OBJ_FILTER), $(CPP_OBJ_TEMP)) + +#------------------------------------------------------------------------------- +# Rules +#------------------------------------------------------------------------------- +all: test + +test: create_output libsam_$(CHIP_NAME)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a libarduino_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a libvariant_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a $(OUTPUT_BIN) + + +.PHONY: create_output +create_output: + @echo --- Preparing $(VARIANT) files in $(OUTPUT_PATH) $(OUTPUT_BIN) +# @echo ------------------------- +# @echo *$(INCLUDES) +# @echo ------------------------- +# @echo *$(C_SRC) +# @echo ------------------------- +# @echo *$(C_OBJ) +# @echo ------------------------- +# @echo *$(addprefix $(OUTPUT_PATH)/, $(C_OBJ)) +# @echo ------------------------- +# @echo *$(CPP_SRC) +# @echo ------------------------- +# @echo *$(CPP_OBJ) +# @echo ------------------------- +# @echo *$(addprefix $(OUTPUT_PATH)/, $(CPP_OBJ)) +# @echo ------------------------- +# @echo *$(A_SRC) +# @echo ------------------------- + + -@mkdir $(OUTPUT_PATH) 1>NUL 2>&1 + +$(addprefix $(OUTPUT_PATH)/,$(CPP_OBJ)): $(OUTPUT_PATH)/%.o: %.cpp +# @"$(CC)" -c $(CPPFLAGS) $< -o $@ + @"$(CXX)" -c $(CPPFLAGS) $< -o $@ +# @"$(CXX)" -v -c $(CPPFLAGS) $< -o $@ + +$(OUTPUT_BIN): $(addprefix $(OUTPUT_PATH)/, $(C_OBJ)) $(addprefix $(OUTPUT_PATH)/, $(CPP_OBJ)) $(addprefix $(OUTPUT_PATH)/, $(A_OBJ)) + @"$(CC)" $(LIB_PATH) $(LDFLAGS) -T"$(VARIANT_PATH)/linker_scripts/gcc/flash.ld" -Wl,-Map,$(OUTPUT_PATH)/$@.map -o $(OUTPUT_PATH)/$@.elf $^ $(LIBS) +# @"$(CC)" $(LIB_PATH) $(LDFLAGS) -T"$(VARIANT_PATH)/linker_scripts/gcc/sram.ld" -Wl,-Map,$(OUTPUT_PATH)/$@.map -o $(OUTPUT_PATH)/$@.elf $^ $(LIBS) + @"$(NM)" $(OUTPUT_PATH)/$@.elf >$(OUTPUT_PATH)/$@.elf.txt + @"$(OBJCOPY)" -O binary $(OUTPUT_PATH)/$@.elf $(OUTPUT_PATH)/$@.bin + $(SIZE) $^ $(OUTPUT_PATH)/$@.elf + +.PHONY: clean +clean: + @echo --- Cleaning test files + -@$(RM) $(OUTPUT_PATH) 1>NUL 2>&1 + +# -$(RM) $(OUTPUT_PATH)/test.o +# -$(RM) $(OUTPUT_PATH)/$(OUTPUT_BIN).elf +# -$(RM) $(OUTPUT_PATH)/$(OUTPUT_BIN).elf.txt +# -$(RM) $(OUTPUT_PATH)/$(OUTPUT_BIN).bin +# -$(RM) $(OUTPUT_PATH)/$(OUTPUT_BIN).map + +debug: test + @"$(GDB)" -x "$(VARIANT_PATH)/debug_scripts/gcc/$(VARIANT)_flash.gdb" -ex "reset" -readnow -se $(OUTPUT_PATH)/$(OUTPUT_BIN).elf +# @"$(GDB)" -w -x "$(VARIANT_PATH)/debug_scripts/gcc/$(VARIANT)_sram.gdb" -ex "reset" -readnow -se $(OUTPUT_PATH)/$(OUTPUT_BIN).elf + +libsam_$(CHIP_NAME)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a: + @echo Building $@ + @$(MAKE) -C $(SYSTEM_PATH)/libsam/build_gcc -f Makefile $@ + +libarduino_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a: + @echo Building $@ + $(MAKE) -C $(ARDUINO_CORE_PATH)/build_gcc -f Makefile $(VARIANT) + +libvariant_$(VARIANT)_$(TOOLCHAIN)_$(LIBS_POSTFIX).a: + @echo Building $@ + $(MAKE) -C $(VARIANT_PATH)/build_gcc -f Makefile $(VARIANT) + diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/descriptor_parser.h b/hardware/arduino/sam/cores/arduino/validation_usb_host/descriptor_parser.h new file mode 100644 index 000000000..02df7d116 --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/descriptor_parser.h @@ -0,0 +1,288 @@ +#ifndef _DESCRIPTOR_PARSER_ +#define _DESCRIPTOR_PARSER_ + +typedef void (*PARSE)( uint8_t* buffer, uint8_t pkt_size ); + +/* Common Messages */ +const char descr_len[] = "Descriptor Length:\t"; +const char descr_type[] = "Descriptor type:\t"; +const char class_str[] = "Class:\t\t\t"; +const char subclass_str[] = "Subclass:\t\t"; +const char protocol_str[] = "Protocol:\t\t"; +const char maxpktsize_str[] = "Max.packet size:\t"; +const char unk_msg[] = " Unknown"; +const char reserved_msg[] = "Reserved"; +const char rcode_error_msg[] = "\r\nRequest error. Return code: "; + +/* Endpoint attributes */ +const char control_tr[] = "Control"; +const char iso_tr[] = "Isochronous"; +const char bulk_tr[] = "Bulk"; +const char int_tr[] = "Interrupt"; + +const char* transfer_types[] = +{ + control_tr, + iso_tr, + bulk_tr, + int_tr +}; + +const char nosync_type[] = "No Synchronization"; +const char async_type[] = "Asynchronous"; +const char adaptive_type[] = "Adaptive"; +const char sync_type[] = "Synchronous"; + +const char* sync_types[] = +{ + nosync_type, + async_type, + adaptive_type, + sync_type +}; + +const char data_usage[] = "Data"; +const char feedback_usage[] = "Feedback"; +const char implicit_usage[] = "Implicit Feedback Data"; +const char reserved_usage[] = "Reserved"; + +const char* usage_types[] = +{ + data_usage, + feedback_usage, + implicit_usage, + reserved_usage +}; + +/* HID Country Codes */ +const char notsupported_cc[] = "Not Supported"; +const char arabic_cc[] = "Arabic"; +const char belgian_cc[] = "Belgian"; +const char canadianbi_cc[] = "Canadian-Bilingual"; +const char canadianfr_cc[] = "Canadian-French"; +const char czech_cc[] = "Czech Republic"; +const char danish_cc[] = "Danish"; +const char finnish_cc[] = "Finnish"; +const char french_cc[] = "French"; +const char german_cc[] = "German"; +const char greek_cc[] = "Greek"; +const char hebrew_cc[] = "Hebrew"; +const char hungary_cc[] = "Hungary"; +const char intl_cc[] = "International (ISO)"; +const char italian_cc[] = "Italian"; +const char japan_cc[] = "Japan (Katakana)"; +const char korean_cc[] = "Korean"; +const char latam_cc[] = "Latin American"; +const char dutch_cc[] = "Netherlands/Dutch"; +const char norwegian_cc[] = "Norwegian"; +const char persian_cc[] = "Persian (Farsi)"; +const char poland_cc[] = "Poland"; +const char portuguese_cc[] = "Portuguese"; +const char russia_cc[] = "Russia"; +const char slovakia_cc[] = "Slovakia"; +const char spanish_cc[] = "Spanish"; +const char swedish_cc[] = "Swedish"; +const char swiss_fr_cc[] = "Swiss/French"; +const char swiss_ger_cc[] = "Swiss/German"; +const char swiss_cc[] = "Switzerland"; +const char taiwan_cc[] = "Taiwan"; +const char turkish_q_cc[] = "Turkish-Q"; +const char uk_cc[] = "UK"; +const char us_cc[] = "US"; +const char yugo_cc[] = "Yugoslavia"; +const char turkish_f_cc[] = "Turkish-F"; + +const char* HID_Country_Codes[] = +{ + notsupported_cc, + arabic_cc, + belgian_cc, + canadianbi_cc, + canadianfr_cc, + czech_cc, + danish_cc, + finnish_cc, + french_cc, + german_cc, + greek_cc, + hebrew_cc, + hungary_cc, + intl_cc, + italian_cc, + japan_cc, + korean_cc, + latam_cc, + dutch_cc, + norwegian_cc, + persian_cc, + poland_cc, + portuguese_cc, + russia_cc, + slovakia_cc, + spanish_cc, + swedish_cc, + swiss_fr_cc, + swiss_ger_cc, + swiss_cc, + taiwan_cc, + turkish_q_cc, + uk_cc, + us_cc, + yugo_cc, + turkish_f_cc +}; + +/* HID report descriptor parser string definitions */ +/* Item type strings */ +const char btype_main[] = "Main"; +const char btype_global[] = "Global"; +const char btype_local[] = "Local"; +const char btype_reserved[] = "Reserved"; + +/* Item types strings array. Array index corresponds to bType */ +const char* btypes[] = +{ + btype_main, + btype_global, + btype_local, + btype_reserved +}; + +/* Main Item Tag Strings */ +const char main_tag_input[] = "Input "; +const char main_tag_output[] = "Output "; +const char main_tag_collection[] = "Collection "; +const char main_tag_feature[] = "Feature "; +const char main_tag_endcoll[] = "End Collection\r\n"; + +/* Main Item Tags Strings Array */ +const char* maintags[] = +{ + main_tag_input, + main_tag_output, + main_tag_collection, + main_tag_feature, + main_tag_endcoll +}; + +/* Global Item Tag Strings */ +const char global_tag_usagepage[] = "Usage Page "; +const char global_tag_logmin[] = "Logical Minimum "; +const char global_tag_logmax[] = "Logical Maximum "; +const char global_tag_physmin[] = "Physical Minimum "; +const char global_tag_physmax[] = "Physical Maximum "; +const char global_tag_unitexp[] = "Unit Exponent "; +const char global_tag_unit[] = "Unit "; +const char global_tag_repsize[] = "Report Size "; +const char global_tag_repid[] = "Report ID "; +const char global_tag_repcount[] = "Report Count "; +const char global_tag_push[] = "Push"; +const char global_tag_pop[] = "Pop"; + +/* Global Item Tag Strings Array */ +const char* globaltags[] = +{ + global_tag_usagepage, + global_tag_logmin, + global_tag_logmax, + global_tag_physmin, + global_tag_physmax, + global_tag_unitexp, + global_tag_unit, + global_tag_repsize, + global_tag_repid, + global_tag_repcount, + global_tag_push, + global_tag_pop +}; + +/* Local Item Tag Strings */ +const char local_tag_usage[] = "Usage "; +const char local_tag_usagemin[] = "Usage Minimum "; +const char local_tag_usagemax[] = "Usage Maximum "; +const char local_tag_desidx[] = "Designator Index "; +const char local_tag_desmin[] = "Designator Minimum "; +const char local_tag_desmax[] = "Designator Maximum "; +const char local_tag_stridx[] = "String Index "; +const char local_tag_strmin[] = "String Minimum "; +const char local_tag_strmax[] = "String Maximum "; +const char local_tag_delimiter[] = "Delimiter "; + +/* Local Item Tag Strings Array */ +const char* localtags[] = +{ + local_tag_usage, + local_tag_usagemin, + local_tag_usagemax, + local_tag_desidx, + local_tag_desmin, + local_tag_desmax, + local_tag_stridx, + local_tag_strmin, + local_tag_strmax, + local_tag_delimiter +}; + +/* Collection Types Strings */ +const char coll_phy[] = "Physical (group of axes)"; +const char coll_app[] = "Application (mouse, keyboard)"; +const char coll_log[] = "Logical (interrelated data)"; +const char coll_rep[] = "Report"; +const char coll_arr[] = "Named Array"; +const char coll_usw[] = "Usage Switch"; +const char coll_umod[] = "Usage Modifier"; + +/* Collection Types Strings Array */ +const char* collections[] = +{ + coll_phy, + coll_app, + coll_log, + coll_rep, + coll_arr, + coll_usw, + coll_umod +}; + +/* Usage Pages Strings */ +const char up_undef[] = "Undefined"; +const char up_gendesk[] = "Generic Desktop Controls"; +const char up_sim[] = "Simulation Controls"; +const char up_vr[] = "VR Controls"; +const char up_sport[] = "Sport Controls"; +const char up_game[] = "Game Controls"; +const char up_gendev[] = "Generic Device Controls"; +const char up_kbd[] = "Keyboard/Keypad"; +const char up_led[] = "LEDs"; +const char up_button[] = "Button"; +const char up_ord[] = "Ordinal"; +const char up_tele[] = "Telephony"; +const char up_cons[] = "Consumer"; +const char up_dig[] = "Digitizer"; +//const char up_res[] = "Reserved"; +const char up_pid[] = "PID Page"; +const char up_uni[] = "Unicode"; + +/* Usage Pages Strings Array */ +const char * usage_pages[] = +{ + up_undef, + up_gendesk, + up_sim, + up_vr, + up_sport, + up_game, + up_gendev, + up_kbd, + up_led, + up_button, + up_ord, + up_tele, + up_cons, + up_dig, + reserved_msg, + up_pid, + up_uni +}; + +#endif //_DESCRIPTOR_PARSER_ diff --git a/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_device.cpp b/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_device.cpp new file mode 100644 index 000000000..5ea2fbc7e --- /dev/null +++ b/hardware/arduino/sam/cores/arduino/validation_usb_host/test_usb_device.cpp @@ -0,0 +1,780 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "variant.h" +#include +#include "descriptor_parser.h" + +#define LOBYTE(x) ((char*)(&(x)))[0] +#define HIBYTE(x) ((char*)(&(x)))[1] +#define BUFSIZE 256 +#define DEVADDR 1 + +#define getReportDescr(addr, ep, nbytes, buf) Usb.ctrlReq(addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, buf) + +USBHost Usb; + +/* Forward declarations */ +void HIDreport_parse(uint8_t* buffer, uint8_t pkt_size); +void print_mainbitfield(uint8_t byte_toparse); +void printunkdescr(uint8_t* descr_ptr); +void printhid_descr(uint8_t* descr_ptr); +void printepdescr(uint8_t* descr_ptr); +void printintfdescr(uint8_t* descr_ptr); +void printconfdescr(uint8_t* descr_ptr); +uint32_t getconfdescr(uint32_t addr, uint32_t conf); +void classname_parse(byte class_number); +uint32_t getstrdescr(uint32_t addr, uint32_t idx); +uint32_t getdevdescr(uint32_t addr); + +_Pragma("pack(1)") + +typedef struct +{ + uint8_t bDescriptorType; + uint16_t wDescriptorLength; +} HID_CLASS_DESCRIPTOR; + +_Pragma("pack()") + +void setup() +{ + cpu_irq_enable(); + printf("\r\nProgram started:\r\n"); + delay(200); +} + +void loop() +{ + uint8_t tmpbyte = 0; + + Usb.Task(); + + // If state configuring or higher + if (Usb.getUsbTaskState() >= USB_STATE_CONFIGURING) + { + // Printing device descriptor + printf("\r\nDevice addressed...\r\n"); + printf("Requesting device descriptor.\r\n"); + + // Number of configurations, 0 if error + tmpbyte = getdevdescr(DEVADDR); + if (tmpbyte == 0) + { + printf("\r\nDevice descriptor cannot be retrieved. Program Halted!\r\n"); + while (1) + ; + } + + // Print configuration descriptors for all configurations + for (uint8_t i = 0; i < tmpbyte; i++) + { + getconfdescr(DEVADDR, i); + } + + while (1) + ; + } +} + +/** + * Get device descriptor. + * Return number of configurations or zero on error. + */ +uint32_t getdevdescr(uint32_t addr) +{ + USB_DEVICE_DESCRIPTOR buf; + uint32_t rcode; + + rcode = Usb.getDevDescr(addr, 0, 0x12, (uint8_t*)&buf); + if (rcode) + { + printf("\r\n%s %lu\r\n", rcode_error_msg, rcode); + return 0; + } + printf("\r\nDevice descriptor: \r\n"); + + // Descriptor length + printf("%s0x%x\r\n", descr_len, buf.bLength); + + // Descriptor type + printf("%s0x%x\r\n", descr_type, buf.bDescriptorType); + + // USB Version + printf("USB version:\t\t0x%x\r\n", buf.bcdUSB); + + // Device class + printf("%s0x%x", class_str, buf.bDeviceClass); + classname_parse(buf.bDeviceClass); + printf("\r\n"); + + // Device Subclass + printf("%s0x%x\r\n", subclass_str, buf.bDeviceSubClass); + + // Device Protocol + printf("%s0x%x\r\n", protocol_str, buf.bDeviceProtocol); + + // Max.packet size + printf("%s0x%x\r\n", maxpktsize_str, buf.bMaxPacketSize0); + + // VID + printf("Vendor ID:\t\t0x%x\r\n", buf.idVendor); + + // PID + printf("Product ID:\t\t0x%x\r\n", buf.idProduct); + + // Revision + printf("Revision ID:\t\t0x%x\r\n", buf.bcdDevice); + + // Mfg.string + printf("Mfg.string index:\t0x%x", buf.iManufacturer); + getstrdescr(addr, buf.iManufacturer); + + // Prod.string + printf("Prod.string index:\t0x%x", buf.iProduct); + getstrdescr(addr, buf.iProduct); + + // Serial number string + printf("Serial number index:\t0x%x", buf.iSerialNumber); + getstrdescr(addr, buf.iSerialNumber); + + // Number of configurations + printf("Number of conf.:\t0x%x\r\n", buf.bNumConfigurations); + + return buf.bNumConfigurations; +} + +/** + * Get string descriptor. + * Takes device address and string index. + */ +uint32_t getstrdescr(uint32_t addr, uint32_t idx) +{ + uint8_t buf[BUFSIZE]; + uint32_t rcode; + uint32_t length; + uint32_t i; + uint16_t langid; + + if (idx == 0) + { + // Don't try to get index zero + printf("\r\n"); + return 0; + } + + rcode = Usb.getStrDescr(addr, 0, 1, 0, 0, buf); + // Get language table length + if (rcode) + { + printf("\r\nError retrieving LangID table length!\r\n"); + return rcode; + } + + // Length is the first byte + length = buf[0]; + // Get language table + rcode = Usb.getStrDescr(addr, 0, length, 0, 0, buf); + if (rcode) + { + printf("\r\nError retrieving LangID table!\r\n"); + return rcode; + } + + // Get first langid + langid = buf[3] << 8; + // Bytes are swapped to account for endiannes + langid |= (buf[2] & 0xff); + + rcode = Usb.getStrDescr(addr, 0, 1, idx, langid, buf); + if (rcode) + { + printf("\r\nError retrieving string length!\r\n"); + return rcode; + } + + length = (buf[0] < 254 ? buf[0] : 254); + printf(" Length: %lu", length); + rcode = Usb.getStrDescr(addr, 0, length, idx, langid, buf); + if (rcode) + { + printf("\r\nError retrieving string!\r\n"); + return rcode; + } + + printf(" Contents: "); + for (i = 2; i < length; i += 2) + { + printf("%c", buf[i]); + } + printf("\r\n"); + + return idx; +} + + +/** + * Returns string to class name + */ +void classname_parse(uint8_t class_number) +{ + switch(class_number) { + case 0x00: + printf(" Use class information in the Interface Descriptor"); + break; + case 0x01: + printf(" Audio"); + break; + case 0x02: + printf(" Communications and CDC Control"); + break; + case 0x03: + printf(" HID (Human Interface Device)"); + break; + case 0x05: + printf(" Physical"); + break; + case 0x06: + printf(" Image"); + break; + case 0x07: + printf(" Printer"); + break; + case 0x08: + printf(" Mass Storage"); + break; + case 0x09: + printf(" Hub"); + break; + case 0x0a: + printf(" CDC-Data"); + break; + case 0x0b: + printf(" Smart Card"); + break; + case 0x0d: + printf(" Content Security"); + break; + case 0x0e: + printf(" Video"); + break; + case 0x0f: + printf(" Personal Healthcare"); + break; + case 0xdc: + printf("Diagnostic Device"); + break; + case 0xe0: + printf(" Wireless Controller"); + break; + case 0xef: + printf(" Miscellaneous"); + break; + case 0xfe: + printf(" Application Specific"); + break; + case 0xff: + printf(" Vendor Specific"); + break; + default: + break; + } +} + + +/** + * Print configuration descriptor. + */ +uint32_t getconfdescr(uint32_t addr, uint32_t conf) +{ + uint8_t buf[BUFSIZE]; + uint8_t* buf_ptr = buf; + uint32_t rcode = 0; + uint8_t confdescr_length = 0; + uint8_t confdescr_type = 0; + uint32_t total_length = 0; + + printf("\r\nConfiguration number %lu:\r\n", conf); + + rcode = Usb.getConfDescr(addr, 0, 4, conf, buf); //get total length + if (rcode) + { + printf("\r\nError retrieving configuration length. Error code %lu\r\n", rcode); + return(0); + } + + total_length = buf[3] << 8; + total_length |= (buf[2] & 0xff); + + if (total_length > BUFSIZE) + { + // Check if total length is larger than buffer + printf("Total length truncated to %d bytes\r\n", BUFSIZE); + total_length = BUFSIZE; + } + + // Get the whole descriptor + rcode = Usb.getConfDescr(addr, 0, total_length, conf, buf); + + while (buf_ptr < buf + total_length) + { + // Parsing descriptors + confdescr_length = *(buf_ptr); + confdescr_type = *(buf_ptr + 1); + switch (confdescr_type) + { + case(USB_DESCRIPTOR_CONFIGURATION): + printconfdescr(buf_ptr); + break; + case(USB_DESCRIPTOR_INTERFACE): + printintfdescr(buf_ptr); + break; + case(USB_DESCRIPTOR_ENDPOINT): + printepdescr(buf_ptr); + break; + case(HID_DESCRIPTOR_HID): + printhid_descr(buf_ptr); + break; + default: + printunkdescr(buf_ptr); + break; + } + + // Advance buffer pointer + buf_ptr = (buf_ptr + confdescr_length); + } + + return 0; +} + +/** + * Print configuration descriptor. + */ +void printconfdescr(uint8_t* descr_ptr) +{ + USB_CONFIGURATION_DESCRIPTOR* conf_ptr = (USB_CONFIGURATION_DESCRIPTOR*)descr_ptr; + uint8_t tmpbyte = 0; + + printf("\r\n\nConfiguration descriptor:\r\n"); + printf("Total length:\t\t%d\r\n", conf_ptr->wTotalLength); + + printf("\r\nNumber of interfaces:\t%d\r\n", conf_ptr->bNumInterfaces); + + printf("Configuration value:\t%d\r\n", conf_ptr->bConfigurationValue); + + printf("Configuration string:\t"); + tmpbyte = conf_ptr->iConfiguration; + printf("0x%x", tmpbyte); + getstrdescr(DEVADDR, tmpbyte); + printf("Attributes:\t\t"); + tmpbyte = conf_ptr->bmAttributes; + printf("0x%x", tmpbyte); + + if (tmpbyte & 0x40) + { + // D6 + printf(" Self-powered\r\n"); + } + + if (tmpbyte & 0x20) + { + // D5 + printf(" Remote Wakeup\r\n"); + } + + printf("Max.power:\t\t"); + tmpbyte = conf_ptr->bMaxPower; + printf("0x%x", tmpbyte); + printf(" "); + printf("%d", (tmpbyte * 2)); + printf("ma\r\n"); +} + +/** + * Print interface descriptor. + */ +void printintfdescr(uint8_t* descr_ptr) +{ + USB_INTERFACE_DESCRIPTOR* intf_ptr = (USB_INTERFACE_DESCRIPTOR*)descr_ptr; + uint8_t tmpbyte = 0; + + printf("\r\nInterface descriptor:\r\n"); + printf("Interface number:\t%d\r\n", intf_ptr->bInterfaceNumber); + printf("Alternate setting:\t%d\r\n", intf_ptr->bAlternateSetting); + printf("Endpoints:\t\t%d\r\n", intf_ptr->bNumEndpoints); + + printf("%s", class_str); + tmpbyte = intf_ptr->bInterfaceClass; + printf("0x%x", tmpbyte); + classname_parse(tmpbyte); + printf("\r\n"); + + printf("%s%d\r\n", subclass_str, intf_ptr->bInterfaceSubClass); + printf("%s%d\r\n", protocol_str, intf_ptr->bInterfaceProtocol); + + printf("Interface string:\t"); + tmpbyte = intf_ptr->iInterface; + printf("0x%x", tmpbyte); + getstrdescr(DEVADDR, tmpbyte); +} + +/** + * Print endpoint descriptor. + */ +void printepdescr(uint8_t* descr_ptr) +{ + USB_ENDPOINT_DESCRIPTOR* ep_ptr = (USB_ENDPOINT_DESCRIPTOR*)descr_ptr; + uint8_t tmpbyte = 0; + + printf("\r\nEndpoint descriptor:\r\n"); + printf("Endpoint address:\t"); + tmpbyte = ep_ptr->bEndpointAddress; + printf("0x%x", tmpbyte & 0x0f); + printf(" Direction: "); + (tmpbyte & 0x80) ? printf("IN\r\n") : printf("OUT\r\n"); + + printf("Attributes:\t\t"); + tmpbyte = ep_ptr->bmAttributes; + printf("0x%x", tmpbyte); + printf(" Transfer type: %s", transfer_types[(tmpbyte & 0x03)]); + + if ((tmpbyte & 0x03) == 1) + { + // Isochronous Transfer + printf(", Sync Type: "); + printf("%s", sync_types[(tmpbyte & 0x0c)]); + printf(", Usage Type: "); + printf("%s", usage_types[(tmpbyte & 0x30)]); + } + printf("\r\n"); + printf("%s%d\r\n", maxpktsize_str, ep_ptr->wMaxPacketSize); + + printf("Polling interval:\t"); + tmpbyte = ep_ptr->bInterval; + printf("0x%x", tmpbyte); + printf(" "); + printf("%d", tmpbyte); + printf(" ms\r\n"); +} + +/** + * Print HID descriptor. + */ +void printhid_descr(uint8_t* descr_ptr) +{ + //PARSE pf = HIDreport_parse; + USB_HID_DESCRIPTOR* hid_ptr = (USB_HID_DESCRIPTOR*)descr_ptr; + uint8_t tmpbyte = 0; + + printf("\r\nHID descriptor:\r\n"); + printf("Descriptor length:\t"); + tmpbyte = hid_ptr->bLength; + printf("0x%x %d bytes\r\n", tmpbyte, tmpbyte); + printf("HID version:\t\t0x%x\r\n", hid_ptr->bcdHID); + tmpbyte = hid_ptr->bCountryCode; + printf("Country Code:\t\t%d ", tmpbyte); + (tmpbyte > 35) ? printf("Reserved\r\n") : printf("%s\r\n", HID_Country_Codes[tmpbyte]); + tmpbyte = hid_ptr->bNumDescriptors; + printf("Class Descriptors:\t%d\r\n", tmpbyte); + + // Printing class descriptors + // Advance buffer pointer + descr_ptr += 6; + for (uint8_t i = 0; i < tmpbyte; i++) + { + uint8_t tmpdata = 0; + HID_CLASS_DESCRIPTOR* hidclass_ptr = (HID_CLASS_DESCRIPTOR*)descr_ptr; + tmpdata = hidclass_ptr->bDescriptorType; + printf("Class Descriptor Type:\t0x%x", tmpdata); + + if ((tmpdata < 0x21) || (tmpdata > 0x2f)) + { + printf(" Invalid"); + } + + switch(tmpdata) + { + case 0x21: + printf(" HID\r\n"); + break; + case 0x22: + printf(" Report\r\n"); + break; + case 0x23: + printf(" Physical\r\n"); + break; + default: + printf(" Reserved\r\n"); + break; + } + + printf("Class Descriptor Size: %d bytes\r\n", hidclass_ptr->wDescriptorLength); + + printf("\r\nHID report descriptor:\r\n"); + uint8_t buf[hidclass_ptr->wDescriptorLength]; + getReportDescr(DEVADDR, 0 , hidclass_ptr->wDescriptorLength, (uint8_t*)&buf); + HIDreport_parse(buf, hidclass_ptr->wDescriptorLength); + + // Advance to the next record + descr_ptr += 3; + } + printf("\r\n"); +} + +/** + * Print unknown descriptor. + */ +void printunkdescr(uint8_t* descr_ptr) +{ + uint8_t length = *descr_ptr; + uint32_t i = 0; + + printf("\r\nUnknown descriptor:\r\n"); + printf("Length:\t\t%d\r\n", *descr_ptr); + printf("Type:\t\t %d\r\n", *(descr_ptr + 1)); + printf("Contents:\t"); + descr_ptr += 2; + + for (i = 0; i < length; i++) + { + printf("%d", *descr_ptr); + descr_ptr++; + } + + printf("\r\n"); +} + +/** + * Print bitfields in main items. + */ +void print_mainbitfield(uint8_t byte_toparse) +{ + (byte_toparse & 0x01) ? printf("Constant,") : printf("Data,"); //bit 0 + (byte_toparse & 0x02) ? printf("Variable,") : printf("Array,"); //bit 1 + (byte_toparse & 0x04) ? printf("Relative,") : printf("Absolute,"); //... + (byte_toparse & 0x08) ? printf("Wrap,") : printf("No Wrap,"); + (byte_toparse & 0x10) ? printf("Non Linear,") : printf("Linear,"); + (byte_toparse & 0x20) ? printf("No preferred,") : printf("Preferred State,"); + (byte_toparse & 0x40) ? printf("Null State,") : printf("No Null Position,"); //bit 6 + (byte_toparse & 0x40) ? printf("Volatile(ignore for Input),") : printf("Non-volatile(Ignore for Input),"); //bit 7 +} + +/** + * HID Report Desriptor Parser Callback. + * Called repeatedly from Control transfer function. + */ +void HIDreport_parse(uint8_t* buffer, uint8_t pkt_size) +{ +#define B_SIZE 0x03 //bSize bitmask +#define B_TYPE 0x0c //bType bitmask +#define B_TAG 0xf0 //bTag bitmask + + // Parser states + enum STATE { ITEM_START, DATA_PARSE }; + static STATE state = ITEM_START; + static uint8_t databytes_left = 0; + static uint8_t databytes_left2 = 0; + static uint8_t prefix; //item prefix - type and tag + uint8_t byte_toparse; + uint8_t bType; + uint8_t tmpbyte; + uint32_t i = 0, j = 0; + + while (1) + { + if (i < pkt_size) + { + i = i + 1; + byte_toparse = buffer[i]; + } + else + { + return; + } + + switch(state) + { + // Start of the record + case ITEM_START: + // Store prefix for databyte parsing + prefix = byte_toparse >> 2; + tmpbyte = byte_toparse & B_SIZE; + + // Get item length + (tmpbyte == 0x03) ? databytes_left = 4 : databytes_left = tmpbyte; + if (databytes_left) + { + // Read bytes after prefix + state = DATA_PARSE; + } + printf("bSize: %d", databytes_left); + databytes_left2 = databytes_left; + + // Get item type + bType = (byte_toparse & B_TYPE) >> 2; + printf(" bType: %s", btypes[bType]); + + // Get item tag + printf("\t\tbTag: "); + tmpbyte = (byte_toparse & B_TAG) >> 4 ; + switch(bType) + { + case 0: // Main + if (tmpbyte < 0x08) + { + printf("Invalid Tag"); + } + else if (tmpbyte > 0x0c) + { + printf("%s", reserved_msg); + } + else + { + printf("%s", maintags[tmpbyte - 8]); + } + break; + + case 1: // Global + (tmpbyte > 0x0b) ? printf("%s", reserved_msg) : printf("%s", globaltags[tmpbyte]); + break; + + case 2: // Local + (tmpbyte > 0x0a) ? printf("%s", reserved_msg) : printf("%s", localtags[tmpbyte]); + break; + + default: + break; + } + break; + + case DATA_PARSE: + switch(prefix) + { + case 0x20: // Main Input + case 0x24: // Main Output + case 0x2c: // Main Feature + // TODO: add parsing 8th bit + print_mainbitfield(byte_toparse); + break; + + case 0x28: //Main Collection + if ((byte_toparse > 0x06) && (byte_toparse < 0x80)) + { + printf("%s", reserved_msg); + } + else if ((byte_toparse > 0x7f) && (byte_toparse <= 0xff)) + { + printf("Vendor-defined"); + } + else + { + printf("%s", collections[byte_toparse]); + } + break; + + //case 0x30: //Main End Collection + case 0x01: //Global Usage Page + switch(byte_toparse) + { + // See HID Usage Tables doc v.1.12 page 14 + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + printf("%s", usage_pages[byte_toparse]); + break; + + case 0x14: + printf("Alphanumeric Display"); + break; + + case 0x40: + printf("Medical Instruments"); + break; + + case 0x80: + case 0x81: + case 0x82: + case 0x83: + printf("Monitor page"); + break; + + case 0x84: + case 0x85: + case 0x86: + case 0x87: + printf("Power page"); + break; + + case 0x8c: + printf("Bar Code Scanner page"); + break; + + case 0x8d: + printf("Scale page"); + break; + + case 0x8e: + printf("Magnetic Stripe Reading (MSR) Devices"); + break; + + case 0x8f: + printf("Reserved Point of Sale pages"); + break; + + case 0x90: + printf("Camera Control Page"); + break; + + case 0x91: + printf("Arcade Page"); + break; + + default: + break; + } + } + + databytes_left--; + + if (!databytes_left) + { + printf(" (data=0x"); + for (j = 0; j < databytes_left2; ++j) + printf("%02x", buffer[i - j]); + printf(")\r\n"); + + state = ITEM_START; + } + break; + } + } +} diff --git a/hardware/arduino/sam/sam.bat b/hardware/arduino/sam/sam.bat index e142728c9..27441877b 100644 --- a/hardware/arduino/sam/sam.bat +++ b/hardware/arduino/sam/sam.bat @@ -2,9 +2,9 @@ set Path=%ARM_GCC_TOOLCHAIN% export Path start "libsam" /d"system\libsam\build_gcc" /max "cd" -start "libarduino" /d"cores\sam\build_gcc" /max "cd" +start "libarduino" /d"cores\arduino\build_gcc" /max "cd" rem start "libvariant Arduino Due U" /d"variants\arduino_due_u\build_gcc" /max "cd" start "libvariant Arduino Due X" /d"variants\arduino_due_x\build_gcc" /max "cd" -start "libvariant ADK2" /d"..\..\google\sam\variants\adk2\build_gcc" /max "cd" -start "libvariant SAM3X-EK" /d"..\..\atmel\sam\variants\sam3x_ek\build_gcc" /max "cd" -start "test" /d"cores\sam\validation\build_gcc" /max "cd" +rem start "libvariant ADK2" /d"..\..\google\sam\variants\adk2\build_gcc" /max "cd" +rem start "libvariant SAM3X-EK" /d"..\..\atmel\sam\variants\sam3x_ek\build_gcc" /max "cd" +start "test" /d"cores\arduino\validation_usb_host\build_gcc" /max "cd" diff --git a/hardware/arduino/sam/system/USBHost/Max3421e.cpp b/hardware/arduino/sam/system/USBHost/Max3421e.cpp deleted file mode 100644 index de2f9f62a..000000000 --- a/hardware/arduino/sam/system/USBHost/Max3421e.cpp +++ /dev/null @@ -1,295 +0,0 @@ -/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ -/* MAX3421E USB host controller support */ - -#include "Max3421e.h" -// #include "Max3421e_constants.h" - -static byte vbusState; - -/* Functions */ - -/* Constructor */ -MAX3421E::MAX3421E() -{ - spi_init(); -#if !defined(TARGET_MEGA_ADK) - pinMode( MAX_INT, INPUT); - pinMode( MAX_GPX, INPUT ); -#else - // "Internal" pins so can't use Arduino helper functions. - INT_DDR &= ~_BV(INT); - GPX_DDR &= ~_BV(GPX); -#endif - pinMode( MAX_SS, OUTPUT ); - digitalWrite(MAX_SS,HIGH); -#if !defined(TARGET_MEGA_ADK) - pinMode( MAX_RESET, OUTPUT ); - digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset -#else - // "Internal" pins so can't use Arduino helper functions. - RST_DDR |= _BV(RST); - RST_PORT |= _BV(RST); // Equivalent to setRST(HIGH) from old code. -#endif -} - -byte MAX3421E::getVbusState( void ) -{ - return( vbusState ); -} -/* initialization */ -//void MAX3421E::init() -//{ -// /* setup pins */ -// pinMode( MAX_INT, INPUT); -// pinMode( MAX_GPX, INPUT ); -// pinMode( MAX_SS, OUTPUT ); -// //pinMode( BPNT_0, OUTPUT ); -// //pinMode( BPNT_1, OUTPUT ); -// //digitalWrite( BPNT_0, LOW ); -// //digitalWrite( BPNT_1, LOW ); -// Deselect_MAX3421E; -// pinMode( MAX_RESET, OUTPUT ); -// digitalWrite( MAX_RESET, HIGH ); //release MAX3421E from reset -//} -//byte MAX3421E::getVbusState( void ) -//{ -// return( vbusState ); -//} -//void MAX3421E::toggle( byte pin ) -//{ -// digitalWrite( pin, HIGH ); -// digitalWrite( pin, LOW ); -//} -/* Single host register write */ -void MAX3421E::regWr( byte reg, byte val) -{ - digitalWrite(MAX_SS,LOW); - SPDR = ( reg | 0x02 ); - while(!( SPSR & ( 1 << SPIF ))); - SPDR = val; - while(!( SPSR & ( 1 << SPIF ))); - digitalWrite(MAX_SS,HIGH); - return; -} -/* multiple-byte write */ -/* returns a pointer to a memory position after last written */ -char * MAX3421E::bytesWr( byte reg, byte nbytes, char * data ) -{ - digitalWrite(MAX_SS,LOW); - SPDR = ( reg | 0x02 ); - while( nbytes-- ) { - while(!( SPSR & ( 1 << SPIF ))); //check if previous byte was sent - SPDR = ( *data ); // send next data byte - data++; // advance data pointer - } - while(!( SPSR & ( 1 << SPIF ))); - digitalWrite(MAX_SS,HIGH); - return( data ); -} -/* GPIO write. GPIO byte is split between 2 registers, so two writes are needed to write one byte */ -/* GPOUT bits are in the low nibble. 0-3 in IOPINS1, 4-7 in IOPINS2 */ -/* upper 4 bits of IOPINS1, IOPINS2 are read-only, so no masking is necessary */ -void MAX3421E::gpioWr( byte val ) -{ - regWr( rIOPINS1, val ); - val = val >>4; - regWr( rIOPINS2, val ); - - return; -} -/* Single host register read */ -byte MAX3421E::regRd( byte reg ) -{ - byte tmp; - digitalWrite(MAX_SS,LOW); - SPDR = reg; - while(!( SPSR & ( 1 << SPIF ))); - SPDR = 0; //send empty byte - while(!( SPSR & ( 1 << SPIF ))); - digitalWrite(MAX_SS,HIGH); - return( SPDR ); -} -/* multiple-bytes register read */ -/* returns a pointer to a memory position after last read */ -char * MAX3421E::bytesRd ( byte reg, byte nbytes, char * data ) -{ - digitalWrite(MAX_SS,LOW); - SPDR = reg; - while(!( SPSR & ( 1 << SPIF ))); //wait - while( nbytes ) { - SPDR = 0; //send empty byte - nbytes--; - while(!( SPSR & ( 1 << SPIF ))); - *data = SPDR; - data++; - } - digitalWrite(MAX_SS,HIGH); - return( data ); -} -/* GPIO read. See gpioWr for explanation */ -/* GPIN pins are in high nibbles of IOPINS1, IOPINS2 */ -byte MAX3421E::gpioRd( void ) -{ - byte tmpbyte = 0; - tmpbyte = regRd( rIOPINS2 ); //pins 4-7 - tmpbyte &= 0xf0; //clean lower nibble - tmpbyte |= ( regRd( rIOPINS1 ) >>4 ) ; //shift low bits and OR with upper from previous operation. Upper nibble zeroes during shift, at least with this compiler - return( tmpbyte ); -} -/* reset MAX3421E using chip reset bit. SPI configuration is not affected */ -boolean MAX3421E::reset() -{ - unsigned short tmp = 0; - regWr( rUSBCTL, bmCHIPRES ); //Chip reset. This stops the oscillator - regWr( rUSBCTL, 0x00 ); //Remove the reset - while(!(regRd( rUSBIRQ ) & bmOSCOKIRQ )) { //wait until the PLL is stable - tmp++; //timeout after 256 attempts - if( tmp == 0 ) { - return( false ); - } - } - return( true ); -} -/* turn USB power on/off */ -/* does nothing, returns TRUE. Left for compatibility with old sketches */ -/* will be deleted eventually */ -///* ON pin of VBUS switch (MAX4793 or similar) is connected to GPOUT7 */ -///* OVERLOAD pin of Vbus switch is connected to GPIN7 */ -///* OVERLOAD state low. NO OVERLOAD or VBUS OFF state high. */ -boolean MAX3421E::vbusPwr ( boolean action ) -{ -// byte tmp; -// tmp = regRd( rIOPINS2 ); //copy of IOPINS2 -// if( action ) { //turn on by setting GPOUT7 -// tmp |= bmGPOUT7; -// } -// else { //turn off by clearing GPOUT7 -// tmp &= ~bmGPOUT7; -// } -// regWr( rIOPINS2, tmp ); //send GPOUT7 -// if( action ) { -// delay( 60 ); -// } -// if (( regRd( rIOPINS2 ) & bmGPIN7 ) == 0 ) { // check if overload is present. MAX4793 /FLAG ( pin 4 ) goes low if overload -// return( false ); -// } - return( true ); // power on/off successful -} -/* probe bus to determine device presense and speed and switch host to this speed */ -void MAX3421E::busprobe( void ) -{ - byte bus_sample; - bus_sample = regRd( rHRSL ); //Get J,K status - bus_sample &= ( bmJSTATUS|bmKSTATUS ); //zero the rest of the byte - switch( bus_sample ) { //start full-speed or low-speed host - case( bmJSTATUS ): - if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { - regWr( rMODE, MODE_FS_HOST ); //start full-speed host - vbusState = FSHOST; - } - else { - regWr( rMODE, MODE_LS_HOST); //start low-speed host - vbusState = LSHOST; - } - break; - case( bmKSTATUS ): - if(( regRd( rMODE ) & bmLOWSPEED ) == 0 ) { - regWr( rMODE, MODE_LS_HOST ); //start low-speed host - vbusState = LSHOST; - } - else { - regWr( rMODE, MODE_FS_HOST ); //start full-speed host - vbusState = FSHOST; - } - break; - case( bmSE1 ): //illegal state - vbusState = SE1; - break; - case( bmSE0 ): //disconnected state - regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ); - vbusState = SE0; - break; - }//end switch( bus_sample ) -} -/* MAX3421E initialization after power-on */ -void MAX3421E::powerOn() -{ - /* Configure full-duplex SPI, interrupt pulse */ - regWr( rPINCTL,( bmFDUPSPI + bmINTLEVEL + bmGPXB )); //Full-duplex SPI, level interrupt, GPX - if( reset() == false ) { //stop/start the oscillator - Serial.println("Error: OSCOKIRQ failed to assert"); - } - - /* configure host operation */ - regWr( rMODE, bmDPPULLDN|bmDMPULLDN|bmHOST|bmSEPIRQ ); // set pull-downs, Host, Separate GPIN IRQ on GPX - regWr( rHIEN, bmCONDETIE|bmFRAMEIE ); //connection detection - /* check if device is connected */ - regWr( rHCTL,bmSAMPLEBUS ); // sample USB bus - while(!(regRd( rHCTL ) & bmSAMPLEBUS )); //wait for sample operation to finish - busprobe(); //check if anything is connected - regWr( rHIRQ, bmCONDETIRQ ); //clear connection detect interrupt - regWr( rCPUCTL, 0x01 ); //enable interrupt pin -} -/* MAX3421 state change task and interrupt handler */ -byte MAX3421E::Task( void ) -{ - byte rcode = 0; - byte pinvalue; - //Serial.print("Vbus state: "); - //Serial.println( vbusState, HEX ); - -#if !defined(TARGET_MEGA_ADK) - pinvalue = digitalRead( MAX_INT ); -#else - // "Internal" pin so can't use Arduino helper functions. - pinvalue = INT_PIN & _BV(INT) ? HIGH : LOW; // from old `readINT()` -#endif - if( pinvalue == LOW ) { - rcode = IntHandler(); - } - -#if !defined(TARGET_MEGA_ADK) - pinvalue = digitalRead( MAX_GPX ); -#else - // "Internal" pin so can't use Arduino helper functions. - pinvalue = GPX_PIN & _BV(GPX) ? HIGH : LOW; // from old `readGPX()` -#endif - if( pinvalue == LOW ) { - GpxHandler(); - } -// usbSM(); //USB state machine - return( rcode ); -} -byte MAX3421E::IntHandler() -{ - byte HIRQ; - byte HIRQ_sendback = 0x00; - HIRQ = regRd( rHIRQ ); //determine interrupt source - //if( HIRQ & bmFRAMEIRQ ) { //->1ms SOF interrupt handler - // HIRQ_sendback |= bmFRAMEIRQ; - //}//end FRAMEIRQ handling - if( HIRQ & bmCONDETIRQ ) { - busprobe(); - HIRQ_sendback |= bmCONDETIRQ; - } - /* End HIRQ interrupts handling, clear serviced IRQs */ - regWr( rHIRQ, HIRQ_sendback ); - return( HIRQ_sendback ); -} -byte MAX3421E::GpxHandler() -{ - byte GPINIRQ = regRd( rGPINIRQ ); //read GPIN IRQ register -// if( GPINIRQ & bmGPINIRQ7 ) { //vbus overload -// vbusPwr( OFF ); //attempt powercycle -// delay( 1000 ); -// vbusPwr( ON ); -// regWr( rGPINIRQ, bmGPINIRQ7 ); -// } - return( GPINIRQ ); -} - -//void MAX3421E::usbSM( void ) //USB state machine -//{ -// -// -//} diff --git a/hardware/arduino/sam/system/USBHost/Max3421e.h b/hardware/arduino/sam/system/USBHost/Max3421e.h deleted file mode 100644 index 1aef86964..000000000 --- a/hardware/arduino/sam/system/USBHost/Max3421e.h +++ /dev/null @@ -1,54 +0,0 @@ -/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ -/* MAX3421E functions */ -#ifndef _MAX3421E_H_ -#define _MAX3421E_H_ - - -//#include -//#include -#include "Arduino.h" -#include "Max3421e_constants.h" - -class MAX3421E /* : public SPI */ { - // byte vbusState; - public: - MAX3421E( void ); - byte getVbusState( void ); -// void toggle( byte pin ); - static void regWr( byte, byte ); - char * bytesWr( byte, byte, char * ); - static void gpioWr( byte ); - byte regRd( byte ); - char * bytesRd( byte, byte, char * ); - byte gpioRd( void ); - boolean reset(); - boolean vbusPwr ( boolean ); - void busprobe( void ); - void powerOn(); - byte IntHandler(); - byte GpxHandler(); - byte Task(); - private: - static void spi_init() { - uint8_t tmp; - // initialize SPI pins - pinMode(SCK_PIN, OUTPUT); - pinMode(MOSI_PIN, OUTPUT); - pinMode(MISO_PIN, INPUT); - pinMode(SS_PIN, OUTPUT); - digitalWrite( SS_PIN, HIGH ); - /* mode 00 (CPOL=0, CPHA=0) master, fclk/2. Mode 11 (CPOL=11, CPHA=11) is also supported by MAX3421E */ - SPCR = 0x50; - SPSR = 0x01; - /**/ - tmp = SPSR; - tmp = SPDR; - } -// void init(); - friend class Max_LCD; -}; - - - - -#endif //_MAX3421E_H_ diff --git a/hardware/arduino/sam/system/USBHost/Max3421e_constants.h b/hardware/arduino/sam/system/USBHost/Max3421e_constants.h deleted file mode 100644 index 600e2ba0e..000000000 --- a/hardware/arduino/sam/system/USBHost/Max3421e_constants.h +++ /dev/null @@ -1,273 +0,0 @@ -/* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ -/* MAX3421E register/bit names and bitmasks */ - -#ifndef _MAX3421Econstants_h_ -#define _MAX3421Econstants_h_ - -/* SPI pins for diffrent Arduinos */ - -#define MEGA256_IS_ADK // Undefine this if you're using a non-ADK Mega256 - -// TODO: Check if the 2560 check should use `defined` too. -#if defined(__AVR_ATmega1280__) || (__AVR_ATmega2560__) - #define SCK_PIN 52 - #define MISO_PIN 50 - #define MOSI_PIN 51 -#if defined(__AVR_ATmega2560__) && defined(MEGA256_IS_ADK) - #define TARGET_MEGA_ADK - #define SS_PIN 53 // TODO: Handle this as an internal pin. -#else - // TODO: Test with Mega + shield combination - #define SS_PIN 53 -#endif -#elif defined(__AVR_ATmega168__) || defined(__AVR_ATmega328P__) - #define SCK_PIN 13 - #define MISO_PIN 12 - #define MOSI_PIN 11 - #define SS_PIN 10 -#else - #error The currently selected board needs to have its SPI pin definitions added to this file. -#endif - -#if !defined(TARGET_MEGA_ADK) - #define MAX_SS SS_PIN - #define MAX_INT 9 - #define MAX_GPX 8 - #define MAX_RESET 7 -#else - // Because the Arduino Mega ADK board uses "internal" pins (i.e. ones that - // are not broken out to headers, are not in `pins_arduino.h` and can't - // be used with functions like `pinMode()` & `digitalWrite()`) they need - // to be defined by the low-level AVR approach. - // These definitions and the code to use them comes from an older version - // of the `Max3421e.cpp` file. - // TODO: Add these internal pins to `pins_arduino.h` for the Mega ADK so - // we can usual the standard Arduino functions & not special-case this? - #define INT PE6 - #define INT_PORT PORTE - #define INT_DDR DDRE - #define INT_PIN PINE - - #define RST PJ2 - #define RST_PORT PORTJ - #define RST_DDR DDRJ - #define RST_PIN PINJ - - #define GPX PJ3 - #define GPX_PORT PORTJ - #define GPX_DDR DDRJ - #define GPX_PIN PINJ - - #define MAX_SS SS_PIN // TODO: Handle this as an internal pin. -#endif - -/* "Breakpoint" pins for debugging */ -//#define BPNT_0 3 -//#define BPNT_1 2 - -//#define Select_MAX3421E digitalWrite(MAX_SS,LOW) -//#define Deselect_MAX3421E digitalWrite(MAX_SS,HIGH) - -/* */ - -#define ON true -#define OFF false - -/* VBUS states */ -#define SE0 0 -#define SE1 1 -#define FSHOST 2 -#define LSHOST 3 - -/* MAX3421E command byte format: rrrrr0wa where 'r' is register number */ -// -// MAX3421E Registers in HOST mode. -// -#define rRCVFIFO 0x08 //1<<3 -#define rSNDFIFO 0x10 //2<<3 -#define rSUDFIFO 0x20 //4<<3 -#define rRCVBC 0x30 //6<<3 -#define rSNDBC 0x38 //7<<3 - -#define rUSBIRQ 0x68 //13<<3 -/* USBIRQ Bits */ -#define bmVBUSIRQ 0x40 //b6 -#define bmNOVBUSIRQ 0x20 //b5 -#define bmOSCOKIRQ 0x01 //b0 - -#define rUSBIEN 0x70 //14<<3 -/* USBIEN Bits */ -#define bmVBUSIE 0x40 //b6 -#define bmNOVBUSIE 0x20 //b5 -#define bmOSCOKIE 0x01 //b0 - -#define rUSBCTL 0x78 //15<<3 -/* USBCTL Bits */ -#define bmCHIPRES 0x20 //b5 -#define bmPWRDOWN 0x10 //b4 - -#define rCPUCTL 0x80 //16<<3 -/* CPUCTL Bits */ -#define bmPUSLEWID1 0x80 //b7 -#define bmPULSEWID0 0x40 //b6 -#define bmIE 0x01 //b0 - -#define rPINCTL 0x88 //17<<3 -/* PINCTL Bits */ -#define bmFDUPSPI 0x10 //b4 -#define bmINTLEVEL 0x08 //b3 -#define bmPOSINT 0x04 //b2 -#define bmGPXB 0x02 //b1 -#define bmGPXA 0x01 //b0 -// GPX pin selections -#define GPX_OPERATE 0x00 -#define GPX_VBDET 0x01 -#define GPX_BUSACT 0x02 -#define GPX_SOF 0x03 - -#define rREVISION 0x90 //18<<3 - -#define rIOPINS1 0xa0 //20<<3 - -/* IOPINS1 Bits */ -#define bmGPOUT0 0x01 -#define bmGPOUT1 0x02 -#define bmGPOUT2 0x04 -#define bmGPOUT3 0x08 -#define bmGPIN0 0x10 -#define bmGPIN1 0x20 -#define bmGPIN2 0x40 -#define bmGPIN3 0x80 - -#define rIOPINS2 0xa8 //21<<3 -/* IOPINS2 Bits */ -#define bmGPOUT4 0x01 -#define bmGPOUT5 0x02 -#define bmGPOUT6 0x04 -#define bmGPOUT7 0x08 -#define bmGPIN4 0x10 -#define bmGPIN5 0x20 -#define bmGPIN6 0x40 -#define bmGPIN7 0x80 - -#define rGPINIRQ 0xb0 //22<<3 -/* GPINIRQ Bits */ -#define bmGPINIRQ0 0x01 -#define bmGPINIRQ1 0x02 -#define bmGPINIRQ2 0x04 -#define bmGPINIRQ3 0x08 -#define bmGPINIRQ4 0x10 -#define bmGPINIRQ5 0x20 -#define bmGPINIRQ6 0x40 -#define bmGPINIRQ7 0x80 - -#define rGPINIEN 0xb8 //23<<3 -/* GPINIEN Bits */ -#define bmGPINIEN0 0x01 -#define bmGPINIEN1 0x02 -#define bmGPINIEN2 0x04 -#define bmGPINIEN3 0x08 -#define bmGPINIEN4 0x10 -#define bmGPINIEN5 0x20 -#define bmGPINIEN6 0x40 -#define bmGPINIEN7 0x80 - -#define rGPINPOL 0xc0 //24<<3 -/* GPINPOL Bits */ -#define bmGPINPOL0 0x01 -#define bmGPINPOL1 0x02 -#define bmGPINPOL2 0x04 -#define bmGPINPOL3 0x08 -#define bmGPINPOL4 0x10 -#define bmGPINPOL5 0x20 -#define bmGPINPOL6 0x40 -#define bmGPINPOL7 0x80 - -#define rHIRQ 0xc8 //25<<3 -/* HIRQ Bits */ -#define bmBUSEVENTIRQ 0x01 // indicates BUS Reset Done or BUS Resume -#define bmRWUIRQ 0x02 -#define bmRCVDAVIRQ 0x04 -#define bmSNDBAVIRQ 0x08 -#define bmSUSDNIRQ 0x10 -#define bmCONDETIRQ 0x20 -#define bmFRAMEIRQ 0x40 -#define bmHXFRDNIRQ 0x80 - -#define rHIEN 0xd0 //26<<3 -/* HIEN Bits */ -#define bmBUSEVENTIE 0x01 -#define bmRWUIE 0x02 -#define bmRCVDAVIE 0x04 -#define bmSNDBAVIE 0x08 -#define bmSUSDNIE 0x10 -#define bmCONDETIE 0x20 -#define bmFRAMEIE 0x40 -#define bmHXFRDNIE 0x80 - -#define rMODE 0xd8 //27<<3 -/* MODE Bits */ -#define bmHOST 0x01 -#define bmLOWSPEED 0x02 -#define bmHUBPRE 0x04 -#define bmSOFKAENAB 0x08 -#define bmSEPIRQ 0x10 -#define bmDELAYISO 0x20 -#define bmDMPULLDN 0x40 -#define bmDPPULLDN 0x80 - -#define rPERADDR 0xe0 //28<<3 - -#define rHCTL 0xe8 //29<<3 -/* HCTL Bits */ -#define bmBUSRST 0x01 -#define bmFRMRST 0x02 -#define bmSAMPLEBUS 0x04 -#define bmSIGRSM 0x08 -#define bmRCVTOG0 0x10 -#define bmRCVTOG1 0x20 -#define bmSNDTOG0 0x40 -#define bmSNDTOG1 0x80 - -#define rHXFR 0xf0 //30<<3 -/* Host transfer token values for writing the HXFR register (R30) */ -/* OR this bit field with the endpoint number in bits 3:0 */ -#define tokSETUP 0x10 // HS=0, ISO=0, OUTNIN=0, SETUP=1 -#define tokIN 0x00 // HS=0, ISO=0, OUTNIN=0, SETUP=0 -#define tokOUT 0x20 // HS=0, ISO=0, OUTNIN=1, SETUP=0 -#define tokINHS 0x80 // HS=1, ISO=0, OUTNIN=0, SETUP=0 -#define tokOUTHS 0xA0 // HS=1, ISO=0, OUTNIN=1, SETUP=0 -#define tokISOIN 0x40 // HS=0, ISO=1, OUTNIN=0, SETUP=0 -#define tokISOOUT 0x60 // HS=0, ISO=1, OUTNIN=1, SETUP=0 - -#define rHRSL 0xf8 //31<<3 -/* HRSL Bits */ -#define bmRCVTOGRD 0x10 -#define bmSNDTOGRD 0x20 -#define bmKSTATUS 0x40 -#define bmJSTATUS 0x80 -#define bmSE0 0x00 //SE0 - disconnect state -#define bmSE1 0xc0 //SE1 - illegal state -/* Host error result codes, the 4 LSB's in the HRSL register */ -#define hrSUCCESS 0x00 -#define hrBUSY 0x01 -#define hrBADREQ 0x02 -#define hrUNDEF 0x03 -#define hrNAK 0x04 -#define hrSTALL 0x05 -#define hrTOGERR 0x06 -#define hrWRONGPID 0x07 -#define hrBADBC 0x08 -#define hrPIDERR 0x09 -#define hrPKTERR 0x0A -#define hrCRCERR 0x0B -#define hrKERR 0x0C -#define hrJERR 0x0D -#define hrTIMEOUT 0x0E -#define hrBABBLE 0x0F - -#define MODE_FS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmSOFKAENAB) -#define MODE_LS_HOST (bmDPPULLDN|bmDMPULLDN|bmHOST|bmLOWSPEED|bmSOFKAENAB) - - -#endif //_MAX3421Econstants_h_ diff --git a/hardware/arduino/sam/system/USBHost/Usb.cpp b/hardware/arduino/sam/system/USBHost/Usb.cpp index d312acaa4..19d50ba3f 100644 --- a/hardware/arduino/sam/system/USBHost/Usb.cpp +++ b/hardware/arduino/sam/system/USBHost/Usb.cpp @@ -1,431 +1,712 @@ /* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ /* USB functions */ + +#include "Arduino.h" #include "Usb.h" +#include -static byte usb_error = 0; -static byte usb_task_state; -DEV_RECORD devtable[ USB_NUMDEVICES + 1 ]; -EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device +//#define TRACE_USBHOST(x) x +#define TRACE_USBHOST(x) +static uint32_t usb_error = 0; +static uint32_t usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; -/* constructor */ +DEV_RECORD devtable[USB_NUMDEVICES + 1]; -USB::USB () { - usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; //set up state machine - init(); +// Endpoint data structure used during enumeration for uninitialized device. +EP_RECORD dev0ep; + +/** + * Class Constructor. + */ +USBHost::USBHost () { + // Set up state machine + usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; + + // Init host stack + init(); } -/* Initialize data structures */ -void USB::init() + +/** + * Initialize data structures. + */ +void USBHost::init() { - byte i; - for( i = 0; i < ( USB_NUMDEVICES + 1 ); i++ ) { - devtable[ i ].epinfo = NULL; //clear device table - devtable[ i ].devclass = 0; - } - devtable[ 0 ].epinfo = &dev0ep; //set single ep for uninitialized device - // not necessary dev0ep.MaxPktSize = 8; //minimum possible - dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0 + + uint8_t i = 0; + + for (i = 0; i < (USB_NUMDEVICES + 1); i++) + { + // Clear device table + devtable[i].epinfo = 0; + devtable[i].devclass = 0; + } + + // Set single EP for uninitialized device + devtable[0].epinfo = &dev0ep; + /* dev0ep.sndToggle = bmSNDTOG0; //set DATA0/1 toggles to 0 dev0ep.rcvToggle = bmRCVTOG0; +*/ } -byte USB::getUsbTaskState( void ) + +/** + * Get USB state. + */ +uint32_t USBHost::getUsbTaskState(void) { - return( usb_task_state ); + return (usb_task_state); } -void USB::setUsbTaskState( byte state ) + +/** + * Set USB state. + */ +void USBHost::setUsbTaskState(uint32_t state) { usb_task_state = state; -} -EP_RECORD* USB::getDevTableEntry( byte addr, byte ep ) -{ - EP_RECORD* ptr; - ptr = devtable[ addr ].epinfo; - ptr += ep; - return( ptr ); -} -/* set device table entry */ -/* each device is different and has different number of endpoints. This function plugs endpoint record structure, defined in application, to devtable */ -void USB::setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr ) -{ - devtable[ addr ].epinfo = eprecord_ptr; - //return(); -} -/* Control transfer. Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer, */ -/* depending on request. Actual requests are defined as inlines */ -/* return codes: */ -/* 00 = success */ -/* 01-0f = non-zero HRSLT */ -byte USB::ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) -{ - boolean direction = false; //request direction, IN or OUT - byte rcode; - SETUP_PKT setup_pkt; - - regWr( rPERADDR, addr ); //set peripheral address - if( bmReqType & 0x80 ) { - direction = true; //determine request direction - } - /* fill in setup packet */ - setup_pkt.ReqType_u.bmRequestType = bmReqType; - setup_pkt.bRequest = bRequest; - setup_pkt.wVal_u.wValueLo = wValLo; - setup_pkt.wVal_u.wValueHi = wValHi; - setup_pkt.wIndex = wInd; - setup_pkt.wLength = nbytes; - bytesWr( rSUDFIFO, 8, ( char *)&setup_pkt ); //transfer to setup packet FIFO - rcode = dispatchPkt( tokSETUP, ep, nak_limit ); //dispatch packet - //Serial.println("Setup packet"); //DEBUG - if( rcode ) { //return HRSLT if not zero - Serial.print("Setup packet error: "); - Serial.print( rcode, HEX ); - return( rcode ); - } - //Serial.println( direction, HEX ); - if( dataptr != NULL ) { //data stage, if present - rcode = ctrlData( addr, ep, nbytes, dataptr, direction ); - } - if( rcode ) { //return error - Serial.print("Data packet error: "); - Serial.print( rcode, HEX ); - return( rcode ); - } - rcode = ctrlStatus( ep, direction ); //status stage - return( rcode ); -} -/* Control transfer with status stage and no data stage */ -/* Assumed peripheral address is already set */ -byte USB::ctrlStatus( byte ep, boolean direction, unsigned int nak_limit ) -{ - byte rcode; - if( direction ) { //GET - rcode = dispatchPkt( tokOUTHS, ep, nak_limit ); - } - else { - rcode = dispatchPkt( tokINHS, ep, nak_limit ); - } - return( rcode ); -} -/* Control transfer with data stage. Stages 2 and 3 of control transfer. Assumes preipheral address is set and setup packet has been sent */ -byte USB::ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit ) -{ - byte rcode; - if( direction ) { //IN transfer - devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; - rcode = inTransfer( addr, ep, nbytes, dataptr, nak_limit ); - return( rcode ); - } - else { //OUT transfer - devtable[ addr ].epinfo[ ep ].sndToggle = bmSNDTOG1; - rcode = outTransfer( addr, ep, nbytes, dataptr, nak_limit ); - return( rcode ); - } -} -/* IN transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ -/* Keep sending INs and writes data to memory area pointed by 'data' */ -/* rcode 0 if no errors. rcode 01-0f is relayed from dispatchPkt(). Rcode f0 means RCVDAVIRQ error, - fe USB xfer timeout */ -byte USB::inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit ) -{ - byte rcode; - byte pktsize; - byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; - unsigned int xfrlen = 0; - regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value - while( 1 ) { // use a 'return' to exit this loop - rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. - if( rcode ) { - return( rcode ); //should be 0, indicating ACK. Else return error code. - } - /* check for RCVDAVIRQ and generate error if not present */ - /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ - if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { - return ( 0xf0 ); //receive error - } - pktsize = regRd( rRCVBC ); //number of received bytes - data = bytesRd( rRCVFIFO, pktsize, data ); - regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer - xfrlen += pktsize; // add this packet's byte count to total transfer length - /* The transfer is complete under two conditions: */ - /* 1. The device sent a short packet (L.T. maxPacketSize) */ - /* 2. 'nbytes' have been transferred. */ - if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? - if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value - devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; - } - else { - devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0; - } - return( 0 ); - } - }//while( 1 ) } -/* Google variant of inTransfer. Pasted verbatim from ADK. Returns length instead of error code. Provided for compatibility with Google Open Accessory code */ -int USB::newInTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit ) +/** + * Get device table entry. + */ +EP_RECORD* USBHost::getDevTableEntry(uint32_t addr, uint32_t ep) { - byte rcode; - byte pktsize; - byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; - unsigned int xfrlen = 0; - regWr( rHCTL, devtable[ addr ].epinfo[ ep ].rcvToggle ); //set toggle value - while( 1 ) { // use a 'return' to exit this loop - rcode = dispatchPkt( tokIN, ep, nak_limit ); //IN packet to EP-'endpoint'. Function takes care of NAKS. - if( rcode ) { - return -1; //should be 0, indicating ACK. Else return error code. - } - /* check for RCVDAVIRQ and generate error if not present */ - /* the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that */ - if(( regRd( rHIRQ ) & bmRCVDAVIRQ ) == 0 ) { - return -1; //receive error - } - pktsize = regRd( rRCVBC ); //number of received bytes - if (xfrlen+pktsize <= nbytes) { - // Only copy the data to the buffer if the buffer's large enough. - data = bytesRd( rRCVFIFO, pktsize, data ); + EP_RECORD* ptr = 0; + + ptr = devtable[addr].epinfo; + ptr += ep; + return ptr; +} + +/** + * Set device table entry. + */ +void USBHost::setDevTableEntry(uint32_t addr, EP_RECORD* eprecord_ptr) +{ + devtable[addr].epinfo = eprecord_ptr; +} + +/** + * Send a control request. + * Sets address, endpoint, fills control packet with necessary data, dispatches control packet, and initiates bulk IN transfer depending on request. + * Actual requests are defined as inlines. + * + * return codes: + * 00 = success + * 01-0f = non-zero HRSLT + */ +uint32_t USBHost::ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit) +{ + // Request direction, IN or OUT + uint32_t direction = 0; + uint32_t rcode = 0; + SETUP_PKT setup_pkt; + + TRACE_USBHOST(printf(" => ctrlReq\r\n");) + + // Set peripheral address + //regWr(rPERADDR, addr); + + // Allocate EP0 with default 8 bytes size if not already initialized + rcode = UHD_EP0_Alloc(0, 8); + if (rcode) + { + TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : EP0 allocation error: %lu\r\n", rcode);) + return (rcode); } - regWr( rHIRQ, bmRCVDAVIRQ ); // Clear the IRQ & free the buffer - xfrlen += pktsize; // add this packet's byte count to total transfer length - /* The transfer is complete under two conditions: */ - /* 1. The device sent a short packet (L.T. maxPacketSize) */ - /* 2. 'nbytes' have been transferred. */ - if (( pktsize < maxpktsize ) || (xfrlen >= nbytes )) { // have we transferred 'nbytes' bytes? - if( regRd( rHRSL ) & bmRCVTOGRD ) { //save toggle value - devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG1; + + // Determine request direction + if (bmReqType & 0x80) + { + direction = 1; + } + + // Fill in setup packet + setup_pkt.ReqType_u.bmRequestType = bmReqType; + setup_pkt.bRequest = bRequest; + setup_pkt.wVal_u.wValueLo = wValLo; + setup_pkt.wVal_u.wValueHi = wValHi; + setup_pkt.wIndex = wInd; + setup_pkt.wLength = nbytes; + + // Transfer to setup packet FIFO + //bytesWr(rSUDFIFO, 8, (uint8_t *)&setup_pkt); + UHD_EP_Write(ep, 8, (uint8_t *)&setup_pkt); + + // Dispatch packet + rcode = dispatchPkt(tokSETUP, ep, nak_limit); + if (rcode) + { + // Return HRSLT if not zero + TRACE_USBHOST(printf("/!\\ USBHost::ctrlReq : Setup packet error: %lu\r\n", rcode);) + return (rcode); + } + + // Data stage (if present) + if (dataptr != 0) + { + rcode = ctrlData(addr, ep, nbytes, dataptr, direction); + if (rcode) + { + TRACE_USBHOST(printf("/!\\ USBHost::ctrlData : Data packet error: %lu\r\n", rcode);) + return (rcode); + } + } + + // Status stage + rcode = ctrlStatus(ep, direction); + return (rcode); + +} + +/** + * Control transfer with status stage and no data stage. + * Assumes peripheral address is already set. + */ +uint32_t USBHost::ctrlStatus(uint32_t ep, uint32_t direction, uint32_t nak_limit) +{ + uint32_t rcode = 0; + + if (direction) + { + // GET + TRACE_USBHOST(printf(" => ctrlStatus OUTHS\r\n");) + rcode = dispatchPkt(tokOUTHS, ep, nak_limit); + } + else + { + // SET + TRACE_USBHOST(printf(" => ctrlStatus INHS\r\n");) + rcode = dispatchPkt(tokINHS, ep, nak_limit); + } + + return (rcode); +} + +/** + * Control transfer with data stage. Stages 2 and 3 of control transfer. + * Assumes peripheral address is set and setup packet has been sent. + */ +uint32_t USBHost::ctrlData(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t direction, uint32_t nak_limit) +{ + uint32_t rcode = 0; + + if (direction) + { + // IN transfer + //devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1; + TRACE_USBHOST(printf(" => ctrlData IN\r\n");) + rcode = inTransfer(addr, ep, nbytes, dataptr, nak_limit); + return (rcode); + } + else + { + // OUT transfer + //devtable[addr].epinfo[ep].sndToggle = bmSNDTOG1; + TRACE_USBHOST(printf(" => ctrlData OUT\r\n");) + rcode = outTransfer(addr, ep, nbytes, dataptr, nak_limit); + return (rcode); + } +} + +/** + * IN transfer to arbitrary endpoint. + * Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. + * Keep sending INs and writes data to memory area pointed by 'data'. + * rcode 0 if no errors + * 01-0f is relayed from dispatchPkt() + * f0 means RCVDAVIRQ error + * fe USB xfer timeout + */ +uint32_t USBHost::inTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit) +{ + uint32_t rcode = 0; + uint32_t pktsize = 0; + uint32_t maxpktsize = devtable[addr].epinfo[ep].MaxPktSize; + uint32_t xfrlen = 0; + + // Set toggle value + //regWr(rHCTL, devtable[addr].epinfo[ep].rcvToggle); + + while (1) + { + // Use a 'return' to exit this loop + // IN packet to EP-'endpoint'. Function takes care of NAKS. + rcode = dispatchPkt(tokIN, ep, nak_limit); + if (rcode) + { + // Should be 0, indicating ACK. Else return error code. + return (rcode); + } + + // check for RCVDAVIRQ and generate error if not present + // the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that + /*if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) + { + // Receive error + return (0xf0); + }*/ + + // Number of received bytes + //pktsize = regRd(rRCVBC); + //data = bytesRd(rRCVFIFO, pktsize, data); + pktsize = uhd_byte_count(ep); + if (nbytes < pktsize) + printf("ce test n'a pas ete fait...\r\n"); + data += UHD_EP_Read(ep, pktsize, data); + + // Clear the IRQ & free the buffer + //regWr(rHIRQ, bmRCVDAVIRQ); + + // Add this packet's byte count to total transfer length + xfrlen += pktsize; + + // The transfer is complete under two conditions: + // 1. The device sent a short packet (L.T. maxPacketSize) + // 2. 'nbytes' have been transferred. + if ((pktsize < maxpktsize) || (xfrlen >= nbytes)) + { + /*// Have we transferred 'nbytes' bytes? + if (regRd(rHRSL) & bmRCVTOGRD) + { + // Save toggle value + devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1; } - else { - devtable[ addr ].epinfo[ ep ].rcvToggle = bmRCVTOG0; + else + { + devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG0; + }*/ + + return (0); + } + } +} + +/** + * Google variant of inTransfer. + * Pasted verbatim from ADK. Returns length instead of error code. + * Provided for compatibility with Google Open Accessory code. + */ +int32_t USBHost::newInTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit) +{ +/* + uint32_t rcode = 0; + uint32_t pktsize = 0; + uint32_t maxpktsize = devtable[addr].epinfo[ep].MaxPktSize; + uint32_t xfrlen = 0; + + // Set toggle value + regWr(rHCTL, devtable[addr].epinfo[ep].rcvToggle); + + while (1) + { + // Use a 'return' to exit this loop + // IN packet to EP-'endpoint'. Function takes care of NAKS. + rcode = dispatchPkt(tokIN, ep, nak_limit); + if (rcode) + { + // Should be 0, indicating ACK. Else return error code. + return -1; + } + + // check for RCVDAVIRQ and generate error if not present + // the only case when absense of RCVDAVIRQ makes sense is when toggle error occured. Need to add handling for that + if ((regRd(rHIRQ) & bmRCVDAVIRQ) == 0) + { + // Receive error + return -1; + } + + // Number of received bytes + pktsize = regRd(rRCVBC); + + if (xfrlen + pktsize <= nbytes) + { + // Only copy the data to the buffer if the buffer's large enough. + data = bytesRd(rRCVFIFO, pktsize, data); + } + + // Clear the IRQ & free the buffer + regWr(rHIRQ, bmRCVDAVIRQ); + + // Add this packet's byte count to total transfer length + xfrlen += pktsize; + + // The transfer is complete under two conditions: + // 1. The device sent a short packet (L.T. maxPacketSize) + // 2. 'nbytes' have been transferred. + if ((pktsize < maxpktsize) || (xfrlen >= nbytes)) + { + // Have we transferred 'nbytes' bytes? + if (regRd(rHRSL) & bmRCVTOGRD) + { + // Save toggle value + devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG1; } - if (xfrlen <= nbytes) { - return xfrlen; - } else { - // Buffer overflow avoided so treat it as an error rather - // than return partial data. - return -1; - } + else + { + devtable[addr].epinfo[ep].rcvToggle = bmRCVTOG0; + } + + if (xfrlen <= nbytes) + { + return xfrlen; + } + else + { + // Buffer overflow avoided so treat it as an error rather + // than return partial data. + return -1; + } } - }//while( 1 ) + } +*/ +printf("error2\r\n"); +return 1; } -/* OUT transfer to arbitrary endpoint. Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. */ -/* Handles NAK bug per Maxim Application Note 4000 for single buffer transfer */ -/* rcode 0 if no errors. rcode 01-0f is relayed from HRSL */ -/* major part of this function borrowed from code shared by Richard Ibbotson */ -byte USB::outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit ) +/** + * OUT transfer to arbitrary endpoint. + * Assumes PERADDR is set. Handles multiple packets if necessary. Transfers 'nbytes' bytes. + * Handles NAK bug per Maxim Application Note 4000 for single buffer transfer + * rcode 0 if no errors + * 01-0f is relayed from HRSL + * + * Major part of this function borrowed from code shared by Richard Ibbotson + */ +uint32_t USBHost::outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit) { - byte rcode, retry_count; - char* data_p = data; //local copy of the data pointer - unsigned int bytes_tosend, nak_count; - unsigned int bytes_left = nbytes; - byte maxpktsize = devtable[ addr ].epinfo[ ep ].MaxPktSize; - unsigned long timeout = millis() + USB_XFER_TIMEOUT; - - if (!maxpktsize) { //todo: move this check close to epinfo init. Make it 1< pktsize <64 - return 0xFE; - } - - regWr( rHCTL, devtable[ addr ].epinfo[ ep ].sndToggle ); //set toggle value - while( bytes_left ) { - retry_count = 0; - nak_count = 0; - bytes_tosend = ( bytes_left >= maxpktsize ) ? maxpktsize : bytes_left; - bytesWr( rSNDFIFO, bytes_tosend, data_p ); //filling output FIFO - regWr( rSNDBC, bytes_tosend ); //set number of bytes - regWr( rHXFR, ( tokOUT | ep )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); - while( rcode && ( timeout > millis())) { - switch( rcode ) { - case hrNAK: - nak_count++; - if( nak_limit && ( nak_count == USB_NAK_LIMIT )) { - return( rcode); //return NAK - } - break; - case hrTIMEOUT: - retry_count++; - if( retry_count == USB_RETRY_LIMIT ) { - return( rcode ); //return TIMEOUT - } - break; - default: - return( rcode ); - }//switch( rcode... - /* process NAK according to Host out NAK bug */ - regWr( rSNDBC, 0 ); - regWr( rSNDFIFO, *data_p ); - regWr( rSNDBC, bytes_tosend ); - regWr( rHXFR, ( tokOUT | ep )); //dispatch packet - while(!(regRd( rHIRQ ) & bmHXFRDNIRQ )); //wait for the completion IRQ - regWr( rHIRQ, bmHXFRDNIRQ ); //clear IRQ - rcode = ( regRd( rHRSL ) & 0x0f ); - }//while( rcode && .... - bytes_left -= bytes_tosend; - data_p += bytes_tosend; - }//while( bytes_left... - devtable[ addr ].epinfo[ ep ].sndToggle = ( regRd( rHRSL ) & bmSNDTOGRD ) ? bmSNDTOG1 : bmSNDTOG0; //update toggle - return( rcode ); //should be 0 in all cases -} -/* dispatch usb packet. Assumes peripheral address is set and relevant buffer is loaded/empty */ -/* If NAK, tries to re-send up to nak_limit times */ -/* If nak_limit == 0, do not count NAKs, exit after timeout */ -/* If bus timeout, re-sends up to USB_RETRY_LIMIT times */ -/* return codes 0x00-0x0f are HRSLT( 0x00 being success ), 0xff means timeout */ -byte USB::dispatchPkt( byte token, byte ep, unsigned int nak_limit ) -{ - unsigned long timeout = millis() + USB_XFER_TIMEOUT; - byte tmpdata; - byte rcode; - unsigned int nak_count = 0; - char retry_count = 0; +/* + uint32_t rcode, retry_count; + uint8_t* data_p = data; + uint32_t bytes_tosend, nak_count; + uint32_t bytes_left = nbytes; + uint32_t maxpktsize = devtable[addr].epinfo[ep].MaxPktSize; + uint32_t timeout = millis() + USB_XFER_TIMEOUT; - while( timeout > millis() ) { - regWr( rHXFR, ( token|ep )); //launch the transfer - rcode = 0xff; - while( millis() < timeout ) { //wait for transfer completion - tmpdata = regRd( rHIRQ ); - if( tmpdata & bmHXFRDNIRQ ) { - regWr( rHIRQ, bmHXFRDNIRQ ); //clear the interrupt - rcode = 0x00; - break; - }//if( tmpdata & bmHXFRDNIRQ - }//while ( millis() < timeout - if( rcode != 0x00 ) { //exit if timeout - return( rcode ); - } - rcode = ( regRd( rHRSL ) & 0x0f ); //analyze transfer result - switch( rcode ) { - case hrNAK: - nak_count ++; - if( nak_limit && ( nak_count == nak_limit )) { - return( rcode ); - } - break; - case hrTIMEOUT: - retry_count ++; - if( retry_count == USB_RETRY_LIMIT ) { - return( rcode ); - } - break; - default: - return( rcode ); - }//switch( rcode - }//while( timeout > millis() - return( rcode ); -} -/* USB main task. Performs enumeration/cleanup */ -void USB::Task( void ) //USB state machine -{ - byte i; - byte rcode; - static byte tmpaddr; - byte tmpdata; - static unsigned long delay = 0; - USB_DEVICE_DESCRIPTOR buf; - /**/ - tmpdata = getVbusState(); -// Serial.print("vbusState: "); -// Serial.print(tmpdata, HEX); -// -// Serial.print("\n"); - /**/ - /* modify USB task state if Vbus changed */ + if (!maxpktsize) + { + // Todo: move this check close to epinfo init. Make it 1< pktsize <64 + return 0xFE; + } - switch( tmpdata ) { - case SE1: //illegal state + // Set toggle value + regWr(rHCTL, devtable[addr].epinfo[ep].sndToggle); + + while (bytes_left) + { + retry_count = 0; + nak_count = 0; + bytes_tosend = (bytes_left >= maxpktsize) ? maxpktsize : bytes_left; + + // Fill output FIFO + bytesWr(rSNDFIFO, bytes_tosend, data_p); + // Set number of bytes + regWr(rSNDBC, bytes_tosend); + + // Dispatch packet + regWr(rHXFR, (tokOUT | ep)); + + // Wait for the completion IRQ + while (!(regRd(rHIRQ) & bmHXFRDNIRQ)) + ; + + // Clear IRQ + regWr(rHIRQ, bmHXFRDNIRQ); + rcode = (regRd(rHRSL) & 0x0f); + + while (rcode && (timeout > millis())) + { + switch (rcode) + { + case hrNAK: + nak_count++; + if (nak_limit && (nak_count == USB_NAK_LIMIT)) { + return (rcode); + } + break; + case hrTIMEOUT: + retry_count++; + if (retry_count == USB_RETRY_LIMIT) { + return (rcode); + } + break; + default: + return (rcode); + } + + // Process NAK according to Host out NAK bug + regWr(rSNDBC, 0); + regWr(rSNDFIFO, *data_p); + regWr(rSNDBC, bytes_tosend); + + // Dispatch packet + regWr(rHXFR, (tokOUT | ep)); + + // Wait for the completion IRQ + while (!(regRd(rHIRQ) & bmHXFRDNIRQ)) + ; + + // Clear IRQ + regWr(rHIRQ, bmHXFRDNIRQ); + rcode = (regRd(rHRSL) & 0x0f); + } + + bytes_left -= bytes_tosend; + data_p += bytes_tosend; + } + + // Update toggle + devtable[ addr ].epinfo[ ep ].sndToggle = (regRd(rHRSL) & bmSNDTOGRD) ? bmSNDTOG1 : bmSNDTOG0; + return (rcode); +*/ +printf("error3\r\n"); +return 1; + +} + +/** + * Dispatch USB packet. + * Assumes peripheral address is set and relevant buffer is loaded/empty. + * If NAK, tries to re-send up to nak_limit times. + * If nak_limit == 0, do not count NAKs, exit after timeout. + * If bus timeout, re-sends up to USB_RETRY_LIMIT times. + * rcode 0 for success + * 1 for naked + * 2 for timeout + */ +uint32_t USBHost::dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit) +{ + uint32_t timeout = millis() + USB_XFER_TIMEOUT; + uint32_t nak_count = 0; + + TRACE_USBHOST(printf(" => dispatchPkt token=%lu\r\n", token);) + + // Launch the transfer + //regWr(rHXFR, (token | ep)); + UHD_EP_Send(ep, token); + + while (timeout > millis()) + { + // Wait for transfer completion + if (UHD_EP_Is_Transfer_Complete(ep, token)) + { + return 0; + } + + // + if (Is_uhd_nak_received(ep)) + { + uhd_ack_nak_received(ep); + nak_count++; + if (nak_limit && (nak_count == nak_limit)) + { + return 1; + } + } + } + + return 2; +} + +/** + * USB main task. + * Performs enumeration/cleanup. + */ +void USBHost::Task(void) +{ + uint32_t i = 0; + uint32_t rcode = 0; + //static uint8_t tmpaddr = 0; + volatile uint32_t tmpdata = 0; + static uint32_t delay = 0; + USB_DEVICE_DESCRIPTOR buf; + + // Update USB task state on Vbus change + tmpdata = UHD_GetVBUSState(); + switch (tmpdata) + { + case UHD_STATE_ERROR: + // Illegal state usb_task_state = USB_DETACHED_SUBSTATE_ILLEGAL; break; - case SE0: //disconnected - if(( usb_task_state & USB_STATE_MASK ) != USB_STATE_DETACHED ) { + + case UHD_STATE_DISCONNECTED: + // Disconnected state + if ((usb_task_state & USB_STATE_MASK) != USB_STATE_DETACHED) + { usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE; } break; - case FSHOST: //attached - case LSHOST: - if(( usb_task_state & USB_STATE_MASK ) == USB_STATE_DETACHED ) { + + case UHD_STATE_CONNECTED: + // Attached state + if ((usb_task_state & USB_STATE_MASK) == USB_STATE_DETACHED) + { delay = millis() + USB_SETTLE_DELAY; usb_task_state = USB_ATTACHED_SUBSTATE_SETTLE; } break; - }// switch( tmpdata - //Serial.print("USB task state: "); - //Serial.println( usb_task_state, HEX ); - switch( usb_task_state ) { + } + + // USB state machine + switch (usb_task_state) + { case USB_DETACHED_SUBSTATE_INITIALIZE: + TRACE_USBHOST(printf(" + USB_DETACHED_SUBSTATE_INITIALIZE\r\n");) + + // Init USB stack and driver + UHD_Init(); init(); + usb_task_state = USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE; break; - case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: //just sit here + + case USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE: + // Nothing to do break; - case USB_DETACHED_SUBSTATE_ILLEGAL: //just sit here + + case USB_DETACHED_SUBSTATE_ILLEGAL: + // Nothing to do break; - case USB_ATTACHED_SUBSTATE_SETTLE: //setlle time for just attached device - if( delay < millis() ) { + + case USB_ATTACHED_SUBSTATE_SETTLE: + // Settle time for just attached device + if (delay < millis()) + { + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_SETTLE\r\n");) usb_task_state = USB_ATTACHED_SUBSTATE_RESET_DEVICE; } break; + case USB_ATTACHED_SUBSTATE_RESET_DEVICE: - regWr( rHCTL, bmBUSRST ); //issue bus reset + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_RESET_DEVICE\r\n");) + + // Trigger Bus Reset + UHD_BusReset(); usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE; break; + case USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE: - if(( regRd( rHCTL ) & bmBUSRST ) == 0 ) { - tmpdata = regRd( rMODE ) | bmSOFKAENAB; //start SOF generation - regWr( rMODE, tmpdata ); -// regWr( rMODE, bmSOFKAENAB ); + if (Is_uhd_reset_sent()) + { + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE\r\n");) + + // Clear Bus Reset flag + uhd_ack_reset_sent(); + + // Enable Start Of Frame generation + uhd_enable_sof(); + usb_task_state = USB_ATTACHED_SUBSTATE_WAIT_SOF; - delay = millis() + 20; //20ms wait after reset per USB spec + + // Wait 20ms after Bus Reset (USB spec) + delay = millis() + 20; } break; - case USB_ATTACHED_SUBSTATE_WAIT_SOF: //todo: change check order - if( regRd( rHIRQ ) & bmFRAMEIRQ ) { //when first SOF received we can continue - if( delay < millis() ) { //20ms passed - usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; - } + + case USB_ATTACHED_SUBSTATE_WAIT_SOF: + // Wait for SOF received first + if (Is_uhd_sof()) + { + if (delay < millis()) + { + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_WAIT_SOF\r\n");) + + // 20ms waiting elapsed + usb_task_state = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; + } } break; + case USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE: - // toggle( BPNT_0 ); - devtable[ 0 ].epinfo->MaxPktSize = 8; //set max.packet size to min.allowed - rcode = getDevDescr( 0, 0, 8, ( char* )&buf ); - if( rcode == 0 ) { - devtable[ 0 ].epinfo->MaxPktSize = buf.bMaxPacketSize0; - usb_task_state = USB_STATE_ADDRESSING; + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE\r\n");) + + // Get Device descriptor size + // Set max.packet size to the minimum allowed + devtable[0].epinfo->MaxPktSize = 8; + rcode = getDevDescr(0, 0, 8, (uint8_t*)&buf); + if (rcode == 0) + { + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE : max pkt size = %d\r\n", buf.bMaxPacketSize0);) + devtable[0].epinfo->MaxPktSize = buf.bMaxPacketSize0; + + // Reconfigure EP0 with max pkt size. (should be done after a USB reset) + UHD_EP_Free(0, 0); + if (UHD_EP0_Alloc(0, devtable[0].epinfo->MaxPktSize) == 0) + { + usb_task_state = USB_STATE_ADDRESSING; + } + else + { + TRACE_USBHOST(printf(" + USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE : realloc failure!\r\n");) + usb_task_state = USB_STATE_ERROR; + } } - else { + else + { usb_error = USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE; usb_task_state = USB_STATE_ERROR; } break; + case USB_STATE_ADDRESSING: - for( i = 1; i < USB_NUMDEVICES; i++ ) { - if( devtable[ i ].epinfo == NULL ) { - devtable[ i ].epinfo = devtable[ 0 ].epinfo; //set correct MaxPktSize - //temporary record - //until plugged with real device endpoint structure - rcode = setAddr( 0, 0, i ); - if( rcode == 0 ) { - tmpaddr = i; - usb_task_state = USB_STATE_CONFIGURING; + for (i = 1; i < USB_NUMDEVICES; i++) + { + TRACE_USBHOST(printf(" + USB_STATE_ADDRESSING (i=%lu)\r\n", i);) + + if (devtable[i].epinfo == 0) + { + // Set correct MaxPktSize + // Temporary record until plugged with real device endpoint structure + devtable[i].epinfo = devtable[0].epinfo; + + rcode = setAddr(0, 0, i); + if (rcode == 0) + { + // Free address 0 used to start enumeration + UHD_EP_Free(0, 0); + + // Alloc control endpoint with the new USB address + if (UHD_EP0_Alloc(i, devtable[i].epinfo->MaxPktSize) == 0) + { + usb_task_state = USB_STATE_CONFIGURING; + TRACE_USBHOST(printf(" + USB_STATE_CONFIGURING (i=%lu)\r\n", i);) + } + else + { + // Set address error + TRACE_USBHOST(printf(" + USB_STATE_CONFIGURING (i=%lu) : realloc failure!\r\n", i);) + usb_error = USB_STATE_ADDRESSING; + usb_task_state = USB_STATE_ERROR; + } } - else { - usb_error = USB_STATE_ADDRESSING; //set address error + else + { + // Set address error + usb_error = USB_STATE_ADDRESSING; usb_task_state = USB_STATE_ERROR; } - break; //break if address assigned or error occured during address assignment attempt + // Break if address assigned or error occured during address assignment attempt + break; } - }//for( i = 1; i < USB_NUMDEVICES; i++ - if( usb_task_state == USB_STATE_ADDRESSING ) { //no vacant place in devtable + } + + if (usb_task_state == USB_STATE_ADDRESSING) + { + // No vacant place in devtable usb_error = 0xfe; usb_task_state = USB_STATE_ERROR; } break; + case USB_STATE_CONFIGURING: break; + case USB_STATE_RUNNING: break; + case USB_STATE_ERROR: break; - }// switch( usb_task_state -} - \ No newline at end of file + } +} diff --git a/hardware/arduino/sam/system/USBHost/Usb.h b/hardware/arduino/sam/system/USBHost/Usb.h index e753962c1..adeb467c9 100644 --- a/hardware/arduino/sam/system/USBHost/Usb.h +++ b/hardware/arduino/sam/system/USBHost/Usb.h @@ -1,38 +1,36 @@ /* Copyright 2009-2011 Oleg Mazurov, Circuits At Home, http://www.circuitsathome.com */ /* USB functions */ -#ifndef _usb_h_ -#define _usb_h_ +#ifndef USB_H_INCLUDED +#define USB_H_INCLUDED -#include +#include #include "ch9.h" /* Common setup data constant combinations */ -#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //get descriptor request type -#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE //set request type for all but 'set feature' and 'set interface' -#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE //get interface request type +#define bmREQ_GET_DESCR USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE // Get descriptor request type +#define bmREQ_SET USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_DEVICE // Set request type for all but 'set feature' and 'set interface' +#define bmREQ_CL_GET_INTF USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE // Get interface request type + /* HID requests */ #define bmREQ_HIDOUT USB_SETUP_HOST_TO_DEVICE|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE -#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE +#define bmREQ_HIDIN USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_CLASS|USB_SETUP_RECIPIENT_INTERFACE #define bmREQ_HIDREPORT USB_SETUP_DEVICE_TO_HOST|USB_SETUP_TYPE_STANDARD|USB_SETUP_RECIPIENT_INTERFACE -#define USB_XFER_TIMEOUT 5000 //USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec -#define USB_NAK_LIMIT 32000 //NAK limit for a transfer. o meand NAKs are not counted -#define USB_RETRY_LIMIT 3 //retry limit for a transfer -#define USB_SETTLE_DELAY 200 //settle delay in milliseconds -#define USB_NAK_NOWAIT 1 //used in Richard's PS2/Wiimote code +#define USB_XFER_TIMEOUT 5000 // USB transfer timeout in milliseconds, per section 9.2.6.1 of USB 2.0 spec +#define USB_NAK_LIMIT 32000 // NAK limit for a transfer. o means NAKs are not counted +#define USB_RETRY_LIMIT 3 // Retry limit for a transfer +#define USB_SETTLE_DELAY 200 // Settle delay in milliseconds +#define USB_NAK_NOWAIT 1 // Used in Richard's PS2/Wiimote code -#define USB_NUMDEVICES 2 //number of USB devices +#define USB_NUMDEVICES 2 // Number of USB devices /* USB state machine states */ - -#define USB_STATE_MASK 0xf0 - #define USB_STATE_DETACHED 0x10 -#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11 +#define USB_DETACHED_SUBSTATE_INITIALIZE 0x11 #define USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE 0x12 #define USB_DETACHED_SUBSTATE_ILLEGAL 0x13 #define USB_ATTACHED_SUBSTATE_SETTLE 0x20 -#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30 +#define USB_ATTACHED_SUBSTATE_RESET_DEVICE 0x30 #define USB_ATTACHED_SUBSTATE_WAIT_RESET_COMPLETE 0x40 #define USB_ATTACHED_SUBSTATE_WAIT_SOF 0x50 #define USB_ATTACHED_SUBSTATE_GET_DEVICE_DESCRIPTOR_SIZE 0x60 @@ -40,137 +38,166 @@ #define USB_STATE_CONFIGURING 0x80 #define USB_STATE_RUNNING 0x90 #define USB_STATE_ERROR 0xa0 - -// byte usb_task_state = USB_DETACHED_SUBSTATE_INITIALIZE +#define USB_STATE_MASK 0xf0 /* USB Setup Packet Structure */ -typedef struct { - union { // offset description - byte bmRequestType; // 0 Bit-map of request type - struct { - byte recipient: 5; // Recipient of the request - byte type: 2; // Type of request - byte direction: 1; // Direction of data X-fer +typedef struct +{ + union + { // offset description + uint8_t bmRequestType; // 0 Bit-map of request type + struct + { + uint8_t recipient: 5; // Recipient of the request + uint8_t type: 2; // Type of request + uint8_t direction: 1; // Direction of data X-fer }; - }ReqType_u; - byte bRequest; // 1 Request - union { - unsigned int wValue; // 2 Depends on bRequest - struct { - byte wValueLo; - byte wValueHi; + } ReqType_u; + uint8_t bRequest; // 1 Request + union + { + uint16_t wValue; // 2 Depends on bRequest + struct + { + uint8_t wValueLo; + uint8_t wValueHi; }; - }wVal_u; - unsigned int wIndex; // 4 Depends on bRequest - unsigned int wLength; // 6 Depends on bRequest + } wVal_u; + uint16_t wIndex; // 4 Depends on bRequest + uint16_t wLength; // 6 Depends on bRequest } SETUP_PKT, *PSETUP_PKT; /* Endpoint information structure */ /* bToggle of endpoint 0 initialized to 0xff */ /* during enumeration bToggle is set to 00 */ -typedef struct { - byte epAddr; //copy from endpoint descriptor. Bit 7 indicates direction ( ignored for control endpoints ) - byte Attr; // Endpoint transfer type. - unsigned int MaxPktSize; // Maximum packet size. - byte Interval; // Polling interval in frames. - byte sndToggle; //last toggle value, bitmask for HCTL toggle bits - byte rcvToggle; //last toggle value, bitmask for HCTL toggle bits +typedef struct +{ + uint32_t epAddr; // Copy from endpoint descriptor. Bit 7 indicates direction (ignored for control endpoints) + uint8_t Attr; // Endpoint transfer type. + uint16_t MaxPktSize; // Maximum packet size. + uint8_t Interval; // Polling interval in frames. + uint8_t sndToggle; // Last toggle value, bitmask for HCTL toggle bits + uint8_t rcvToggle; // Last toggle value, bitmask for HCTL toggle bits /* not sure if both are necessary */ } EP_RECORD; -/* device record structure */ -typedef struct { - EP_RECORD* epinfo; //device endpoint information - byte devclass; //device class + +/* Device record structure */ +typedef struct +{ + EP_RECORD* epinfo; // Device endpoint information + uint8_t devclass; // Device class } DEV_RECORD; - - -class USB : public MAX3421E { -//data structures -/* device table. Filled during enumeration */ -/* index corresponds to device address */ -/* each entry contains pointer to endpoint structure */ -/* and device class to use in various places */ -//DEV_RECORD devtable[ USB_NUMDEVICES + 1 ]; -//EP_RECORD dev0ep; //Endpoint data structure used during enumeration for uninitialized device - -//byte usb_task_state; - +/** + * USBHost Class + * The device table is filled during enumeration. + * Index corresponds to device address and each entry contains pointer to endpoint structure and device class to use. + */ +class USBHost +{ public: - USB( void ); - byte getUsbTaskState( void ); - void setUsbTaskState( byte state ); - EP_RECORD* getDevTableEntry( byte addr, byte ep ); - void setDevTableEntry( byte addr, EP_RECORD* eprecord_ptr ); - byte ctrlReq( byte addr, byte ep, byte bmReqType, byte bRequest, byte wValLo, byte wValHi, unsigned int wInd, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - /* Control requests */ - byte getDevDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getConfDescr( byte addr, byte ep, unsigned int nbytes, byte conf, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getStrDescr( byte addr, byte ep, unsigned int nbytes, byte index, unsigned int langid, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte setAddr( byte oldaddr, byte ep, byte newaddr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte setConf( byte addr, byte ep, byte conf_value, unsigned int nak_limit = USB_NAK_LIMIT ); - /**/ - byte setProto( byte addr, byte ep, byte interface, byte protocol, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getProto( byte addr, byte ep, byte interface, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getReportDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte setReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte getIdle( byte addr, byte ep, byte interface, byte reportID, char* dataptr, unsigned int nak_limit = USB_NAK_LIMIT ); - byte setIdle( byte addr, byte ep, byte interface, byte reportID, byte duration, unsigned int nak_limit = USB_NAK_LIMIT ); - /**/ - byte ctrlData( byte addr, byte ep, unsigned int nbytes, char* dataptr, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT ); - byte ctrlStatus( byte ep, boolean direction, unsigned int nak_limit = USB_NAK_LIMIT ); - byte inTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit = USB_NAK_LIMIT ); - int newInTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit = USB_NAK_LIMIT); - byte outTransfer( byte addr, byte ep, unsigned int nbytes, char* data, unsigned int nak_limit = USB_NAK_LIMIT ); - byte dispatchPkt( byte token, byte ep, unsigned int nak_limit = USB_NAK_LIMIT ); - void Task( void ); + USBHost(void); + uint32_t getUsbTaskState(void); + void setUsbTaskState(uint32_t state); + EP_RECORD* getDevTableEntry(uint32_t addr, uint32_t ep); + void setDevTableEntry(uint32_t addr, EP_RECORD* eprecord_ptr); + uint32_t ctrlReq(uint32_t addr, uint32_t ep, uint8_t bmReqType, uint8_t bRequest, uint8_t wValLo, uint8_t wValHi, uint16_t wInd, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + + /* Control requests */ + uint32_t getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t conf, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t setConf(uint32_t addr, uint32_t ep, uint8_t conf_value, uint32_t nak_limit = USB_NAK_LIMIT); + + /* Status requests */ + uint32_t setProto(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t protocol, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getProto(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getReportDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t setReport(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getReport(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t getIdle(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t reportID, uint8_t* dataptr, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t setIdle(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, uint32_t nak_limit = USB_NAK_LIMIT); + + /* Transfer requests */ + uint32_t ctrlData(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t direction, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t ctrlStatus(uint32_t ep, uint32_t direction, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t inTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit = USB_NAK_LIMIT); + int32_t newInTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t outTransfer(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* data, uint32_t nak_limit = USB_NAK_LIMIT); + uint32_t dispatchPkt(uint32_t token, uint32_t ep, uint32_t nak_limit = USB_NAK_LIMIT); + void Task(void); + private: void init(); }; -//get device descriptor -inline byte USB::getDevDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr, nak_limit )); +// Get device descriptor +inline uint32_t USBHost::getDevDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, 0x00, USB_DESCRIPTOR_DEVICE, 0x0000, nbytes, dataptr, nak_limit)); } -//get configuration descriptor -inline byte USB::getConfDescr( byte addr, byte ep, unsigned int nbytes, byte conf, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr, nak_limit )); + +// Get configuration descriptor +inline uint32_t USBHost::getConfDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t conf, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, conf, USB_DESCRIPTOR_CONFIGURATION, 0x0000, nbytes, dataptr, nak_limit)); } -//get string descriptor -inline byte USB::getStrDescr( byte addr, byte ep, unsigned int nbytes, byte index, unsigned int langid, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, dataptr, nak_limit )); + +// Get string descriptor +inline uint32_t USBHost::getStrDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t index, uint16_t langid, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_GET_DESCR, USB_REQUEST_GET_DESCRIPTOR, index, USB_DESCRIPTOR_STRING, langid, nbytes, dataptr, nak_limit)); } -//set address -inline byte USB::setAddr( byte oldaddr, byte ep, byte newaddr, unsigned int nak_limit ) { - return( ctrlReq( oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, NULL, nak_limit )); + +// Set address +inline uint32_t USBHost::setAddr(uint32_t oldaddr, uint32_t ep, uint32_t newaddr, uint32_t nak_limit) +{ + return (ctrlReq(oldaddr, ep, bmREQ_SET, USB_REQUEST_SET_ADDRESS, newaddr, 0x00, 0x0000, 0x0000, 0, nak_limit)); } -//set configuration -inline byte USB::setConf( byte addr, byte ep, byte conf_value, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, NULL, nak_limit )); + +// Set configuration +inline uint32_t USBHost::setConf(uint32_t addr, uint32_t ep, uint8_t conf_value, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_SET, USB_REQUEST_SET_CONFIGURATION, conf_value, 0x00, 0x0000, 0x0000, 0, nak_limit)); } -//class requests -inline byte USB::setProto( byte addr, byte ep, byte interface, byte protocol, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, NULL, nak_limit )); + +// Class requests +inline uint32_t USBHost::setProto(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t protocol, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_PROTOCOL, protocol, 0x00, interface, 0x0000, 0, nak_limit)); } -inline byte USB::getProto( byte addr, byte ep, byte interface, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr, nak_limit )); + +inline uint32_t USBHost::getProto(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_PROTOCOL, 0x00, 0x00, interface, 0x0001, dataptr, nak_limit)); } -//get HID report descriptor -inline byte USB::getReportDescr( byte addr, byte ep, unsigned int nbytes, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, dataptr, nak_limit )); + +// Get HID report descriptor +inline uint32_t USBHost::getReportDescr(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDREPORT, USB_REQUEST_GET_DESCRIPTOR, 0x00, HID_DESCRIPTOR_REPORT, 0x0000, nbytes, dataptr, nak_limit)); } -inline byte USB::setReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit )); + +inline uint32_t USBHost::setReport(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit)); } -inline byte USB::getReport( byte addr, byte ep, unsigned int nbytes, byte interface, byte report_type, byte report_id, char* dataptr, unsigned int nak_limit ) { // ** RI 04/11/09 - return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit )); + +inline uint32_t USBHost::getReport(uint32_t addr, uint32_t ep, uint32_t nbytes, uint8_t interface, uint8_t report_type, uint8_t report_id, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_REPORT, report_id, report_type, interface, nbytes, dataptr, nak_limit)); } -/* returns one byte of data in dataptr */ -inline byte USB::getIdle( byte addr, byte ep, byte interface, byte reportID, char* dataptr, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr, nak_limit )); + +/* returns one uint8_t of data in dataptr */ +inline uint32_t USBHost::getIdle(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t reportID, uint8_t* dataptr, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDIN, HID_REQUEST_GET_IDLE, reportID, 0, interface, 0x0001, dataptr, nak_limit)); } -inline byte USB::setIdle( byte addr, byte ep, byte interface, byte reportID, byte duration, unsigned int nak_limit ) { - return( ctrlReq( addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, interface, 0x0000, NULL, nak_limit )); - } -#endif //_usb_h_ + +inline uint32_t USBHost::setIdle(uint32_t addr, uint32_t ep, uint8_t interface, uint8_t reportID, uint8_t duration, uint32_t nak_limit) +{ + return (ctrlReq(addr, ep, bmREQ_HIDOUT, HID_REQUEST_SET_IDLE, reportID, duration, interface, 0x0000, 0, nak_limit)); +} + +#endif /* USB_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/USBHost/ch9.h b/hardware/arduino/sam/system/USBHost/ch9.h index 476634686..d2bcdd734 100644 --- a/hardware/arduino/sam/system/USBHost/ch9.h +++ b/hardware/arduino/sam/system/USBHost/ch9.h @@ -3,6 +3,8 @@ #ifndef _ch9_h_ #define _ch9_h_ +#include + /* Misc.USB constants */ #define DEV_DESCR_LEN 18 //device descriptor length #define CONF_DESCR_LEN 9 //configuration descriptor length @@ -96,73 +98,77 @@ #define HID_PROTOCOL_MOUSE 0x02 +_Pragma("pack(1)") + /* descriptor data structures */ /* Device descriptor structure */ typedef struct { - byte bLength; // Length of this descriptor. - byte bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). - unsigned int bcdUSB; // USB Spec Release Number (BCD). - byte bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - byte bDeviceSubClass; // Subclass code (assigned by the USB-IF). - byte bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - byte bMaxPacketSize0; // Maximum packet size for endpoint 0. - unsigned int idVendor; // Vendor ID (assigned by the USB-IF). - unsigned int idProduct; // Product ID (assigned by the manufacturer). - unsigned int bcdDevice; // Device release number (BCD). - byte iManufacturer; // Index of String Descriptor describing the manufacturer. - byte iProduct; // Index of String Descriptor describing the product. - byte iSerialNumber; // Index of String Descriptor with the device's serial number. - byte bNumConfigurations; // Number of possible configurations. + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // DEVICE descriptor type (USB_DESCRIPTOR_DEVICE). + uint16_t bcdUSB; // USB Spec Release Number (BCD). + uint8_t bDeviceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bDeviceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bDeviceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bMaxPacketSize0; // Maximum packet size for endpoint 0. + uint16_t idVendor; // Vendor ID (assigned by the USB-IF). + uint16_t idProduct; // Product ID (assigned by the manufacturer). + uint16_t bcdDevice; // Device release number (BCD). + uint8_t iManufacturer; // Index of String Descriptor describing the manufacturer. + uint8_t iProduct; // Index of String Descriptor describing the product. + uint8_t iSerialNumber; // Index of String Descriptor with the device's serial number. + uint8_t bNumConfigurations; // Number of possible configurations. } USB_DEVICE_DESCRIPTOR; /* Configuration descriptor structure */ typedef struct { - byte bLength; // Length of this descriptor. - byte bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). - unsigned int wTotalLength; // Total length of all descriptors for this configuration. - byte bNumInterfaces; // Number of interfaces in this configuration. - byte bConfigurationValue; // Value of this configuration (1 based). - byte iConfiguration; // Index of String Descriptor describing the configuration. - byte bmAttributes; // Configuration characteristics. - byte bMaxPower; // Maximum power consumed by this configuration. + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // CONFIGURATION descriptor type (USB_DESCRIPTOR_CONFIGURATION). + uint16_t wTotalLength; // Total length of all descriptors for this configuration. + uint8_t bNumInterfaces; // Number of interfaces in this configuration. + uint8_t bConfigurationValue; // Value of this configuration (1 based). + uint8_t iConfiguration; // Index of String Descriptor describing the configuration. + uint8_t bmAttributes; // Configuration characteristics. + uint8_t bMaxPower; // Maximum power consumed by this configuration. } USB_CONFIGURATION_DESCRIPTOR; /* Interface descriptor structure */ typedef struct { - byte bLength; // Length of this descriptor. - byte bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). - byte bInterfaceNumber; // Number of this interface (0 based). - byte bAlternateSetting; // Value of this alternate interface setting. - byte bNumEndpoints; // Number of endpoints in this interface. - byte bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. - byte bInterfaceSubClass; // Subclass code (assigned by the USB-IF). - byte bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. - byte iInterface; // Index of String Descriptor describing the interface. + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // INTERFACE descriptor type (USB_DESCRIPTOR_INTERFACE). + uint8_t bInterfaceNumber; // Number of this interface (0 based). + uint8_t bAlternateSetting; // Value of this alternate interface setting. + uint8_t bNumEndpoints; // Number of endpoints in this interface. + uint8_t bInterfaceClass; // Class code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t bInterfaceSubClass; // Subclass code (assigned by the USB-IF). + uint8_t bInterfaceProtocol; // Protocol code (assigned by the USB-IF). 0xFF-Vendor specific. + uint8_t iInterface; // Index of String Descriptor describing the interface. } USB_INTERFACE_DESCRIPTOR; /* Endpoint descriptor structure */ typedef struct { - byte bLength; // Length of this descriptor. - byte bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). - byte bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). - byte bmAttributes; // Endpoint transfer type. - unsigned int wMaxPacketSize; // Maximum packet size. - byte bInterval; // Polling interval in frames. + uint8_t bLength; // Length of this descriptor. + uint8_t bDescriptorType; // ENDPOINT descriptor type (USB_DESCRIPTOR_ENDPOINT). + uint8_t bEndpointAddress; // Endpoint address. Bit 7 indicates direction (0=OUT, 1=IN). + uint8_t bmAttributes; // Endpoint transfer type. + uint16_t wMaxPacketSize; // Maximum packet size. + uint8_t bInterval; // Polling interval in frames. } USB_ENDPOINT_DESCRIPTOR; /* HID descriptor */ typedef struct { - byte bLength; - byte bDescriptorType; - unsigned int bcdHID; - byte bCountryCode; - byte bNumDescriptors; - byte bDescrType; - unsigned int wDescriptorLength; + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdHID; + uint8_t bCountryCode; + uint8_t bNumDescriptors; + uint8_t bDescrType; + uint16_t wDescriptorLength; } USB_HID_DESCRIPTOR; +_Pragma("pack()") + #endif // _ch9_h_ diff --git a/hardware/arduino/sam/system/libsam/chip.h b/hardware/arduino/sam/system/libsam/chip.h index fa0f9eb40..31f76f10b 100644 --- a/hardware/arduino/sam/system/libsam/chip.h +++ b/hardware/arduino/sam/system/libsam/chip.h @@ -56,9 +56,11 @@ #include "include/timetick.h" #include "include/USB_device.h" +#include "include/USB_host.h" #if SAM3XA_SERIES -#include "include/uotghs.h" +#include "include/uotghs_device.h" +#include "include/uotghs_host.h" #endif /* SAM3XA_SERIES */ #endif /* _LIB_SAM_ */ diff --git a/hardware/arduino/sam/system/libsam/include/USB_device.h b/hardware/arduino/sam/system/libsam/include/USB_device.h index 816b8bf17..6b6700831 100644 --- a/hardware/arduino/sam/system/libsam/include/USB_device.h +++ b/hardware/arduino/sam/system/libsam/include/USB_device.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _USB_DRIVER_ -#define _USB_DRIVER_ +#ifndef USB_DEVICE_H_INCLUDED +#define USB_DEVICE_H_INCLUDED #include @@ -403,4 +403,4 @@ typedef uint32_t iram_size_t; //! @} -#endif /* _USB_DRIVER_*/ +#endif /* USB_DEVICE_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/libsam/include/USB_host.h b/hardware/arduino/sam/system/libsam/include/USB_host.h new file mode 100644 index 000000000..4262f7aa6 --- /dev/null +++ b/hardware/arduino/sam/system/libsam/include/USB_host.h @@ -0,0 +1,59 @@ +/* + Copyright (c) 2011 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef USB_HOST_H_INCLUDED +#define USB_HOST_H_INCLUDED + +#include + +#define tokSETUP UOTGHS_HSTPIPCFG_PTOKEN_SETUP +#define tokIN UOTGHS_HSTPIPCFG_PTOKEN_IN +#define tokOUT UOTGHS_HSTPIPCFG_PTOKEN_OUT +#define tokINHS UOTGHS_HSTPIPCFG_PTOKEN_IN +#define tokOUTHS UOTGHS_HSTPIPCFG_PTOKEN_OUT + +//! \brief Device speed +/*typedef enum { + UHD_SPEED_LOW = 0, + UHD_SPEED_FULL = 1, + UHD_SPEED_HIGH = 2, +} uhd_speed_t;*/ + +//! States of USBB interface +typedef enum { + UHD_STATE_NO_VBUS = 0, + UHD_STATE_DISCONNECTED = 1, + UHD_STATE_CONNECTED = 2, + UHD_STATE_ERROR = 3, +} uhd_vbus_state_t; + +//extern uhd_speed_t uhd_get_speed(void); + + +extern void UHD_SetStack(void (*pf_isr)(void)); +extern void UHD_Init(void); +extern void UHD_BusReset(void); +extern uhd_vbus_state_t UHD_GetVBUSState(void); +extern uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size); +extern void UHD_EP_Free(uint32_t add, uint32_t endp); +extern uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data); +extern void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data); +extern void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type); +extern uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type); + +#endif /* USB_HOST_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/libsam/include/uotghs.h b/hardware/arduino/sam/system/libsam/include/uotghs_device.h similarity index 99% rename from hardware/arduino/sam/system/libsam/include/uotghs.h rename to hardware/arduino/sam/system/libsam/include/uotghs_device.h index 21b584977..13a113ae2 100644 --- a/hardware/arduino/sam/system/libsam/include/uotghs.h +++ b/hardware/arduino/sam/system/libsam/include/uotghs_device.h @@ -16,8 +16,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef UOTGHS_H_INCLUDED -#define UOTGHS_H_INCLUDED +#ifndef UOTGHS_DEVICE_H_INCLUDED +#define UOTGHS_DEVICE_H_INCLUDED #define MAX_ENDPOINTS 10 @@ -737,4 +737,4 @@ //! @} -#endif /* UOTGHS_H_INCLUDED */ +#endif /* UOTGHS_DEVICE_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/libsam/include/uotghs_host.h b/hardware/arduino/sam/system/libsam/include/uotghs_host.h new file mode 100644 index 000000000..d634f124f --- /dev/null +++ b/hardware/arduino/sam/system/libsam/include/uotghs_host.h @@ -0,0 +1,378 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef UOTGHS_HOST_H_INCLUDED +#define UOTGHS_HOST_H_INCLUDED + +//! \ingroup usb_host_group +//! \defgroup uhd_group USB Host Driver (UHD) +//! UOTGHS low-level driver for USB host mode +//! +//! @{ + +//! @name UOTGHS Host IP properties +//! +//! @{ +//! Get maximal number of endpoints +#define uhd_get_pipe_max_nbr() (9) +#define UOTGHS_EPT_NUM (uhd_get_pipe_max_nbr()+1) +//! @} + +//! @name Host Vbus line control +//! +//! VBOF is an optional output pin which allows to enable or disable +//! the external VBus generator. +//! +//! @{ +//! Enables hardware control of USB_VBOF output pin when a Vbus error occur +#define uhd_enable_vbus_error_hw_control() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSHWC)) +//! Disables hardware control of USB_VBOF output pin when a Vbus error occur +#define uhd_disable_vbus_error_hw_control() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSHWC)) + +//! Pin and function for USB_VBOF according to configuration from USB_VBOF +#define USB_VBOF_PIN USB_VBOF_GPIO +#define USB_VBOF_FUNCTION USB_VBOF_FLAGS +//! Output USB_VBOF onto its pin +#define uhd_output_vbof_pin() do {\ + pio_configure_pin(USB_VBOF_PIN, USB_VBOF_FUNCTION); \ +} while (0) + +//! Set USB_VBOF output pin polarity +#define uhd_set_vbof_active_high() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSPO)) +#define uhd_set_vbof_active_low() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBUSPO)) +//! Requests VBus activation +#define uhd_enable_vbus() (Set_bits(UOTGHS->UOTGHS_SFR, UOTGHS_SR_VBUSRQ)) +//! Requests VBus deactivation +#define uhd_disable_vbus() (Set_bits(UOTGHS->UOTGHS_SCR, UOTGHS_SR_VBUSRQ)) +//! Tests if VBus activation has been requested +#define Is_uhd_vbus_enabled() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBUSRQ)) +//! @} + +//! @name Host Vbus line monitoring +//! +//! The VBus level is always checked by USBC hardware. +//! +//! @{ +#define uhd_enable_vbus_error_interrupt() (Set_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBERRE)) +#define uhd_disable_vbus_error_interrupt() (Clr_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBERRE)) +#define Is_uhd_vbus_error_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBERRE)) +#define uhd_ack_vbus_error_interrupt() (Set_bits(UOTGHS->UOTGHS_SCR, UOTGHS_SCR_VBERRIC)) +#define Is_uhd_vbus_error_interrupt() (Tst_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_VBERRI)) +//! @} + +#define uhd_ack_errors_interrupt() (UOTGHS->UOTGHS_SCR = (UOTGHS_SCR_VBERRIC|UOTGHS_SCR_BCERRIC|UOTGHS_SCR_HNPERRIC|UOTGHS_SCR_STOIC)) +#define Is_uhd_errors_interrupt() (Tst_bits(UOTGHS->UOTGHS_CTRL, UOTGHS_CTRL_VBERRE|UOTGHS_CTRL_BCERRE|UOTGHS_CTRL_HNPERRE|UOTGHS_CTRL_STOE)) +#define uhd_enable_suspend_error_interrupt() +#define uhd_enable_hnp_error_interrupt() +#define uhd_enable_bconn_error_interrupt() + +//! @name USB device connection/disconnection monitoring +//! @{ +#define uhd_enable_connection_int() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_DCONNIES) +#define uhd_disable_connection_int() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_DCONNIEC) +#define Is_uhd_connection_int_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_DCONNIE)) +#define uhd_ack_connection() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_DCONNIC) +#define Is_uhd_connection() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_DCONNI)) + +#define uhd_enable_disconnection_int() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_DDISCIES) +#define uhd_disable_disconnection_int() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_DDISCIEC) +#define Is_uhd_disconnection_int_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_DDISCIE)) +#define uhd_ack_disconnection() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_DDISCIC) +#define Is_uhd_disconnection() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_DDISCI)) +//! @} + +//! @name USB device speed control +//! @{ +#define uhd_get_speed_mode() (Rd_bits(UOTGHS->UOTGHS_SR, UOTGHS_SR_SPEED_Msk)) +#define Is_uhd_low_speed_mode() (uhd_get_speed_mode() == UOTGHS_SR_SPEED_LOW_SPEED) +#define Is_uhd_full_speed_mode() (uhd_get_speed_mode() == UOTGHS_SR_SPEED_FULL_SPEED) +#define Is_uhd_high_speed_mode() (uhd_get_speed_mode() == UOTGHS_SR_SPEED_HIGH_SPEED) +//! Enable high speed mode +# define uhd_enable_high_speed_mode() (Wr_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_SPDCONF_Msk, UOTGHS_HSTCTRL_SPDCONF_HIGH_SPEED)) +//! Disable high speed mode +# define uhd_disable_high_speed_mode() (Wr_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_SPDCONF_Msk, UOTGHS_HSTCTRL_SPDCONF_FORCED_FS)) +//! @} + +//! @name Bus events control +//! These macros manage the bus events: reset, SOF, resume, wakeup. +//! @{ + +//! Initiates a reset event +//! @{ +#define uhd_start_reset() (Set_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_RESET)) +#define Is_uhd_starting_reset() (Tst_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_RESET)) +#define uhd_stop_reset() (Clr_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_RESET)) + +#define uhd_enable_reset_sent_interrupt() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_RSTIES) +#define uhd_disable_reset_sent_interrupt() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_RSTIEC) +#define Is_uhd_reset_sent_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_RSTIE)) +#define uhd_ack_reset_sent() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_RSTIC) +#define Is_uhd_reset_sent() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_RSTI)) +//! @} + +//! Initiates a SOF events +//! @{ +#define uhd_enable_sof() (Set_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_SOFE)) +#define uhd_disable_sof() (Clr_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_SOFE)) +#define Is_uhd_sof_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_SOFE)) +#define uhd_get_sof_number() ((UOTGHS->UOTGHS_HSTFNUM&UOTGHS_HSTFNUM_FNUM_Msk)>>UOTGHS_HSTFNUM_FNUM_Pos) +#define uhd_get_microsof_number() ((UOTGHS->UOTGHS_HSTFNUM&UOTGHS_HSTFNUM_MFNUM_Msk)>>UOTGHS_HSTFNUM_MFNUM_Pos) +#define uhd_get_frame_position() (Rd_bits(UOTGHS->UOTGHS_HSTFNUM, UOTGHS_HSTFNUM_FLENHIGH_Msk)) +#define uhd_enable_sof_interrupt() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_HSOFIES) +#define uhd_disable_sof_interrupt() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_HSOFIEC) +#define Is_uhd_sof_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_HSOFIE)) +#define uhd_ack_sof() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_HSOFIC) +#define Is_uhd_sof() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_HSOFI)) +//! @} + +//! Initiates a resume event +//! It is called downstream resume event. +//! @{ +#define uhd_send_resume() (Set_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_RESUME)) +#define Is_uhd_sending_resume() (Tst_bits(UOTGHS->UOTGHS_HSTCTRL, UOTGHS_HSTCTRL_RESUME)) + +#define uhd_enable_downstream_resume_interrupt() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_RSMEDIES) +#define uhd_disable_downstream_resume_interrupt() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_RSMEDIEC) +#define Is_uhd_downstream_resume_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_RSMEDIE)) +#define uhd_ack_downstream_resume() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_RSMEDIC) +#define Is_uhd_downstream_resume() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_RSMEDI)) +//! @} + +//! Detection of a wake-up event +//! A wake-up event is received when the host controller is in the suspend mode: +//! - and an upstream resume from the peripheral is detected. +//! - and a peripheral disconnection is detected. +//! @{ +#define uhd_enable_wakeup_interrupt() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_HWUPIES) +#define uhd_disable_wakeup_interrupt() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_HWUPIEC) +#define Is_uhd_wakeup_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_HWUPIE)) +#define uhd_ack_wakeup() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_HWUPIC) +#define Is_uhd_wakeup() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_HWUPI)) + +#define uhd_enable_upstream_resume_interrupt() (UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTIER_RXRSMIES) +#define uhd_disable_upstream_resume_interrupt() (UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_RXRSMIEC) +#define Is_uhd_upstream_resume_interrupt_enabled() (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_RXRSMIE)) +#define uhd_ack_upstream_resume() (UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_RXRSMIC) +#define Is_uhd_upstream_resume() (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_RXRSMI)) +//! @} +//! @} + + +//! @name Pipes management +//! @{ + +//! USB address of pipes +//! @{ +#define uhd_configure_address(p, addr) \ + (Wr_bitfield((&UOTGHS->UOTGHS_HSTADDR1)[(p)>>2], \ + UOTGHS_HSTADDR1_HSTADDRP0_Msk << (((p)&0x03)<<3), addr)) +#define uhd_get_configured_address(p) \ + (Rd_bitfield((&UOTGHS->UOTGHS_HSTADDR1)[(p)>>2], \ + UOTGHS_HSTADDR1_HSTADDRP0_Msk << (((p)&0x03)<<3))) +//! @} + +//! Pipe enable +//! Enable, disable, reset, freeze +//! @{ +#define uhd_enable_pipe(p) \ + (Set_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))) +#define uhd_disable_pipe(p) \ + (Clr_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))) +#define Is_uhd_pipe_enabled(p) \ + (Tst_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))) +#define uhd_reset_pipe(p) \ + (Set_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))); \ + (Clr_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))) +#define Is_uhd_resetting_pipe(p) \ + (Tst_bits(UOTGHS->UOTGHS_HSTPIP, UOTGHS_HSTPIP_PEN0 << (p))) +#define uhd_freeze_pipe(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_PFREEZES) +#define uhd_unfreeze_pipe(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_PFREEZEC) +#define Is_uhd_pipe_frozen(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_PFREEZE)) +#define uhd_reset_data_toggle(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_RSTDTS) +#define Is_uhd_data_toggle_reset(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_RSTDT)) +//! @} + +//! Pipe configuration +//! @{ +#define uhd_configure_pipe_int_req_freq(p,freq) (Wr_bitfield(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_INTFRQ_Msk, (freq))) +#define uhd_get_pipe_int_req_freq(p) (Rd_bitfield(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_INTFRQ_Msk)) +#define uhd_configure_pipe_endpoint_number(p,ep) (Wr_bitfield(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PEPNUM_Msk, (ep))) +#define uhd_get_pipe_endpoint_address(p) \ + (uhd_is_pipe_in(p) ?\ + (uhd_get_pipe_endpoint_number(p) | USB_EP_DIR_IN) :\ + (uhd_get_pipe_endpoint_number(p) | USB_EP_DIR_OUT)) +#define uhd_get_pipe_endpoint_number(p) (Rd_bitfield(UOTGHS->UOTGHS_HSTPIPCFG[p], (UOTGHS_HSTPIPCFG_PEPNUM_Msk))) +#define uhd_configure_pipe_type(p, type) (Wr_bitfield(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PTYPE_Msk, type)) +#define uhd_get_pipe_type(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PTYPE_Msk)) +#define uhd_enable_pipe_bank_autoswitch(p) (Set_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_AUTOSW)) +#define uhd_disable_pipe_bank_autoswitch(p) (Clr_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_AUTOSW)) +#define Is_uhd_pipe_bank_autoswitch_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_AUTOSW)) +#define uhd_configure_pipe_token(p, token) (Wr_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PTOKEN_Msk, token)) +#define uhd_get_pipe_token(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PTOKEN_Msk)) +#define uhd_is_pipe_in(p) (UOTGHS_HSTPIPCFG_PTOKEN_IN==uhd_get_pipe_token(p)) +#define uhd_is_pipe_out(p) (UOTGHS_HSTPIPCFG_PTOKEN_OUT==uhd_get_pipe_token(p)) +//! Bounds given integer size to allowed range and rounds it up to the nearest +//! available greater size, then applies register format of UOTGHS controller +//! for pipe size bit-field. +#define uhd_format_pipe_size(size) \ + (32 - clz(((uint32_t)min(max(size, 8), 1024) << 1) - 1) - 1 - 3) +#define uhd_configure_pipe_size(p,size) \ + (Wr_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PSIZE_Msk, uhd_format_pipe_size(size))) +#define uhd_get_pipe_size(p) (8<<((Rd_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], (UOTGHS_HSTPIPCFG_PSIZE_Msk)))>> UOTGHS_HSTPIPCFG_PSIZE_Pos)) +#define uhd_configure_pipe_bank(p,bank) (Wr_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PBK_Msk, (bank))) +#define uhd_get_pipe_bank(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PBK_Msk)) +#define uhd_allocate_memory(p) (Set_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_ALLOC)) +#define uhd_unallocate_memory(p) (Clr_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_ALLOC)) +#define Is_uhd_memory_allocated(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_ALLOC)) + +//! Enable PING management only available in HS mode +# define uhd_enable_ping(p) (Set_bits(UOTGHS->UOTGHS_HSTPIPCFG[p], UOTGHS_HSTPIPCFG_PINGEN)) +//#endif +#define uhd_configure_pipe(p, freq, ep_num, type, token, size, bank, bank_switch) \ + (Set_bits(UOTGHS->UOTGHS_HSTPIPCFG[p],\ + (bank)|\ + ((uhd_format_pipe_size(size)<UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_CFGOK)) +//! @} + +//! Pipe main interrupts management +//! @{ +#define uhd_enable_pipe_interrupt(p) (UOTGHS->UOTGHS_HSTIER = (UOTGHS_HSTIER_PEP_0 << (p))) +#define uhd_disable_pipe_interrupt(p) (UOTGHS->UOTGHS_HSTIDR = (UOTGHS_HSTIDR_PEP_0 << (p))) +#define Is_uhd_pipe_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTIMR, UOTGHS_HSTIMR_PEP_0 << (p))) +#define Is_uhd_pipe_interrupt(p) (Tst_bits(UOTGHS->UOTGHS_HSTISR, UOTGHS_HSTISR_PEP_0 << (p))) +//! returns the lowest pipe number generating a pipe interrupt or UOTGHS_EPT_NUM if none +#define uhd_get_interrupt_pipe_number() \ + (ctz(((UOTGHS->UOTGHS_HSTISR >> 8) & (UOTGHS->UOTGHS_HSTIMR >> 8)) | (1 << UOTGHS_EPT_NUM))) +//! @} + +//! Pipe overflow and underflow for isochronous and interrupt endpoints +//! @{ +#define uhd_enable_overflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_OVERFIES) +#define uhd_disable_overflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_OVERFIEC) +#define Is_uhd_overflow_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_OVERFIE)) +#define uhd_ack_overflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_OVERFIC) +#define Is_uhd_overflow(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_OVERFI)) + +#define uhd_enable_underflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_UNDERFIES) +#define uhd_disable_underflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_UNDERFIEC) +#define Is_uhd_underflow_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_UNDERFIE)) +#define uhd_ack_underflow_interrupt(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_UNDERFIC) +#define Is_uhd_underflow(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_UNDERFI)) +//! @} + +//! USB packet errors management +//! @{ +#define uhd_enable_stall_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_RXSTALLDES) +#define uhd_disable_stall_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_RXSTALLDEC) +#define Is_uhd_stall_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_RXSTALLDE)) +#define uhd_ack_stall(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_RXSTALLDIC) +#define Is_uhd_stall(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_RXSTALLDI)) + +#define uhd_enable_pipe_error_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_PERRES) +#define uhd_disable_pipe_error_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_PERREC) +#define Is_uhd_pipe_error_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_PERRE)) +#define uhd_ack_all_errors(p) (UOTGHS->UOTGHS_HSTPIPERR[p] = 0UL) +#define Is_uhd_pipe_error(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_PERRI)) +#define uhd_error_status(p) (UOTGHS->UOTGHS_HSTPIPERR[p]) +#define Is_uhd_bad_data_toggle(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_DATATGL)) +#define Is_uhd_data_pid_error(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_DATAPID)) +#define Is_uhd_pid_error(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_PID)) +#define Is_uhd_timeout_error(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_TIMEOUT)) +#define Is_uhd_crc16_error(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_CRC16)) +#define uhd_get_error_counter(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPERR[p], UOTGHS_HSTPIPERR_COUNTER)) +//! @} + +//! Pipe data management +//! @{ +#define uhd_data_toggle(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_DTSEQ)) + +#define uhd_enable_bank_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_NBUSYBKES) +#define uhd_disable_bank_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_NBUSYBKEC) +#define Is_uhd_bank_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_NBUSYBKE)) +#define uhd_nb_busy_bank(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_NBUSYBK_Msk)) +#define uhd_current_bank(p) (Rd_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_CURRBK_Msk )) + +#define uhd_enable_short_packet_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_SHORTPACKETES) +#define uhd_disable_short_packet_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_SHORTPACKETIEC) +#define Is_uhd_short_packet_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_SHORTPACKETIE)) ) +#define uhd_ack_short_packet(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_SHORTPACKETIC) +#define Is_uhd_short_packet(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_SHORTPACKETI)) +#define uhd_byte_count(p) (Rd_bitfield(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_PBYCT_Msk)) + +#define Is_uhd_fifocon(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_FIFOCON)) +#define uhd_ack_fifocon(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_FIFOCONC) + +#define uhd_enable_setup_ready_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_TXSTPES) +#define uhd_disable_setup_ready_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_TXSTPEC) +#define Is_uhd_setup_ready_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_TXSTPE)) +#define uhd_ack_setup_ready(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_TXSTPIC) +#define Is_uhd_setup_ready(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_TXSTPI)) + +#define uhd_enable_in_received_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_RXINES) +#define uhd_disable_in_received_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_RXINEC) +#define Is_uhd_in_received_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_RXINE)) +#define uhd_ack_in_received(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_RXINIC) +#define Is_uhd_in_received(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_RXINI)) + +#define uhd_enable_out_ready_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_TXOUTES) +#define uhd_disable_out_ready_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_TXOUTEC) +#define Is_uhd_out_ready_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_TXOUTE)) +#define uhd_ack_out_ready(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_TXOUTIC) +#define Is_uhd_out_ready(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_TXOUTI)) +#define uhd_raise_out_ready(p) (UOTGHS->UOTGHS_HSTPIPIFR[p] = UOTGHS_HSTPIPIFR_TXOUTIS) + +#define uhd_enable_nak_received_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIER[p] = UOTGHS_HSTPIPIER_NAKEDES) +#define uhd_disable_nak_received_interrupt(p) (UOTGHS->UOTGHS_HSTPIPIDR[p] = UOTGHS_HSTPIPIDR_NAKEDEC) +#define Is_uhd_nak_received_interrupt_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPIMR[p], UOTGHS_HSTPIPIMR_NAKEDE)) +#define uhd_ack_nak_received(p) (UOTGHS->UOTGHS_HSTPIPICR[p] = UOTGHS_HSTPIPICR_NAKEDIC) +#define Is_uhd_nak_received(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_NAKEDI)) + +#define Is_uhd_read_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_RWALL)) +#define Is_uhd_write_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPISR[p], UOTGHS_HSTPIPISR_RWALL )) + +#define uhd_enable_continuous_in_mode(p) (Set_bits(UOTGHS->UOTGHS_HSTPIPINRQ[p], UOTGHS_HSTPIPINRQ_INMODE)) +#define uhd_disable_continuous_in_mode(p) (Clr_bits(UOTGHS->UOTGHS_HSTPIPINRQ[p], UOTGHS_HSTPIPINRQ_INMODE)) +#define Is_uhd_continuous_in_mode_enabled(p) (Tst_bits(UOTGHS->UOTGHS_HSTPIPINRQ[p], UOTGHS_HSTPIPINRQ_INMODE)) + +#define uhd_in_request_number(p, in_num) (Set_bits(UOTGHS->UOTGHS_HSTPIPINRQ[p], (in_num)-1)) +#define uhd_get_in_request_number(p) (((Rd_bits(UOTGHS->UOTGHS_HSTPIPINRQ[p], UOTGHS_HSTPIPINRQ_INRQ_Msk))>>UOTGHS_HSTPIPINRQ_INRQ_Pos)+1) +//! @} + +//! Maximum transfer size on USB DMA +#define UHD_PIPE_MAX_TRANS 0x8000 + +//! Get 64-, 32-, 16- or 8-bit access to FIFO data register of selected pipe. +//! @param p Target Pipe number +//! @param scale Data scale in bits: 64, 32, 16 or 8 +//! @return Volatile 64-, 32-, 16- or 8-bit data pointer to FIFO data register +//! @warning It is up to the user of this macro to make sure that all accesses +//! are aligned with their natural boundaries except 64-bit accesses which +//! require only 32-bit alignment. +//! @warning It is up to the user of this macro to make sure that used HSB +//! addresses are identical to the DPRAM internal pointer modulo 32 bits. +#define uhd_get_pipe_fifo_access(p, scale) \ + (((volatile TPASTE2(U, scale) (*)[UHD_PIPE_MAX_TRANS / ((scale) / 8)])UOTGHS_RAM_ADDR)[(p)]) + +#endif /* UOTGHS_HOST_H_INCLUDED */ diff --git a/hardware/arduino/sam/system/libsam/source/uotghs.c b/hardware/arduino/sam/system/libsam/source/uotghs.c index 10d1c9505..061746571 100644 --- a/hardware/arduino/sam/system/libsam/source/uotghs.c +++ b/hardware/arduino/sam/system/libsam/source/uotghs.c @@ -17,22 +17,10 @@ */ #include "chip.h" -#include #if SAM3XA_SERIES -//#define TRACE_UOTGHS(x) x -#define TRACE_UOTGHS(x) - -static void (*gpf_isr)(void) = (0UL); - -static volatile uint32_t ul_send_fifo_ptr[MAX_ENDPOINTS]; -static volatile uint32_t ul_recv_fifo_ptr[MAX_ENDPOINTS]; - -void UDD_SetStack(void (*pf_isr)(void)) -{ - gpf_isr = pf_isr; -} +void (*gpf_isr)(void) = (0UL); void UOTGHS_Handler( void ) { @@ -40,291 +28,4 @@ void UOTGHS_Handler( void ) gpf_isr(); } -uint32_t UDD_Init(void) -{ - uint32_t i; - - for (i = 0; i < MAX_ENDPOINTS; ++i) - { - ul_send_fifo_ptr[i] = 0; - ul_recv_fifo_ptr[i] = 0; - } - - // Enables the USB Clock - pmc_enable_periph_clk(ID_UOTGHS); - pmc_enable_upll_clock(); - pmc_switch_udpck_to_upllck(0); // div=0+1 - pmc_enable_udpck(); - - // Configure interrupts - NVIC_SetPriority((IRQn_Type) ID_UOTGHS, 0UL); - NVIC_EnableIRQ((IRQn_Type) ID_UOTGHS); - - // Always authorize asynchrone USB interrupts to exit from sleep mode - // for SAM3 USB wake up device except BACKUP mode - //pmc_set_fast_startup_input(PMC_FSMR_USBAL); - - // ID pin not used then force device mode - otg_disable_id_pin(); - otg_force_device_mode(); - - // Enable USB hardware - otg_disable_pad(); - otg_enable_pad(); - otg_enable(); - otg_unfreeze_clock(); - - // Check USB clock - //while (!Is_otg_clock_usable()) - // ; - - udd_low_speed_disable(); - udd_high_speed_disable(); - - //otg_ack_vbus_transition(); - // Force Vbus interrupt in case of Vbus always with a high level - // This is possible with a short timing between a Host mode stop/start. - /*if (Is_otg_vbus_high()) { - otg_raise_vbus_transition(); - } - otg_enable_vbus_interrupt();*/ - otg_freeze_clock(); - - return 0UL ; -} - -void UDD_Attach(void) -{ - irqflags_t flags = cpu_irq_save(); - - TRACE_UOTGHS(printf("=> UDD_Attach\r\n");) - - otg_unfreeze_clock(); - - // Check USB clock because the source can be a PLL - while (!Is_otg_clock_usable()); - - // Authorize attach if Vbus is present - udd_attach_device(); - - // Enable USB line events - udd_enable_reset_interrupt(); - //udd_enable_sof_interrupt(); - - cpu_irq_restore(flags); -} - -void UDD_Detach(void) -{ - TRACE_UOTGHS(printf("=> UDD_Detach\r\n");) - UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_DETACH; -} - -void UDD_InitEP( uint32_t ul_ep_nb, uint32_t ul_ep_cfg ) -{ - ul_ep_nb = ul_ep_nb & 0xF; // EP range is 0..9, hence mask is 0xF. - - TRACE_UOTGHS(printf("=> UDD_InitEP : init EP %d\r\n", ul_ep_nb);) - - // Configure EP - UOTGHS->UOTGHS_DEVEPTCFG[ul_ep_nb] = ul_ep_cfg; - // Enable EP - udd_enable_endpoint(ul_ep_nb); - - if (!Is_udd_endpoint_configured(ul_ep_nb)) { - TRACE_UOTGHS(printf("=> UDD_InitEP : ERROR FAILED TO INIT EP %d\r\n", ul_ep_nb);) - } -} - - -void UDD_InitEndpoints(const uint32_t* eps_table, const uint32_t ul_eps_table_size) -{ - uint32_t ul_ep_nb ; - - for (ul_ep_nb = 1; ul_ep_nb < ul_eps_table_size; ul_ep_nb++) - { - // Configure EP - UOTGHS->UOTGHS_DEVEPTCFG[ul_ep_nb] = eps_table[ul_ep_nb]; - // Enable EP - udd_enable_endpoint(ul_ep_nb); - - if (!Is_udd_endpoint_configured(ul_ep_nb)) { - TRACE_UOTGHS(printf("=> UDD_InitEP : ERROR FAILED TO INIT EP %d\r\n", ul_ep_nb);) - } - } -} - -// Wait until ready to accept IN packet. -void UDD_WaitIN(void) -{ - while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_TXINI)) - ; -} - -void UDD_WaitOUT(void) -{ - while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXOUTI)) - ; -} - -// Send packet. -void UDD_ClearIN(void) -{ - TRACE_UOTGHS(printf("=> UDD_ClearIN: sent %d bytes\r\n", ul_send_fifo_ptr[EP0]);) - - UOTGHS->UOTGHS_DEVEPTICR[EP0] = UOTGHS_DEVEPTICR_TXINIC; - ul_send_fifo_ptr[EP0] = 0; -} - -void UDD_ClearOUT(void) -{ - UOTGHS->UOTGHS_DEVEPTICR[EP0] = UOTGHS_DEVEPTICR_RXOUTIC; - ul_recv_fifo_ptr[EP0] = 0; -} - -// Wait for IN FIFO to be ready to accept data or OUT FIFO to receive data. -// Return true if new IN FIFO buffer available. -uint32_t UDD_WaitForINOrOUT(void) -{ - while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & (UOTGHS_DEVEPTISR_TXINI | UOTGHS_DEVEPTISR_RXOUTI))) - ; - return ((UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXOUTI) == 0); -} - -uint32_t UDD_ReceivedSetupInt(void) -{ - return UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXSTPI; -} - -void UDD_ClearSetupInt(void) -{ - UOTGHS->UOTGHS_DEVEPTICR[EP0] = (UOTGHS_DEVEPTICR_RXSTPIC); -} - -uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len) -{ - const uint8_t *ptr_src = data; - uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); - uint32_t i; - - TRACE_UOTGHS(printf("=> UDD_Send (1): ep=%d ul_send_fifo_ptr=%d len=%d\r\n", ep, ul_send_fifo_ptr[ep], len);) - - if (ep == EP0) - { - if (ul_send_fifo_ptr[ep] + len > EP0_SIZE) - len = EP0_SIZE - ul_send_fifo_ptr[ep]; - } - else - { - if (ul_send_fifo_ptr[ep] + len > EPX_SIZE) - len = EPX_SIZE - ul_send_fifo_ptr[ep]; - } - - for (i = 0, ptr_dest += ul_send_fifo_ptr[ep]; i < len; ++i) - *ptr_dest++ = *ptr_src++; - - ul_send_fifo_ptr[ep] += i; - - - if (ep == EP0) - { - TRACE_UOTGHS(printf("=> UDD_Send (2): ep=%d ptr_dest=%d maxlen=%d\r\n", ep, ul_send_fifo_ptr[ep], EP0_SIZE);) - if (ul_send_fifo_ptr[ep] == EP0_SIZE) - { - UDD_ClearIN(); // Fifo is full, release this packet - UDD_WaitIN(); // Wait for new FIFO buffer to be ready - } - } - else - { - if (ul_send_fifo_ptr[ep] == EPX_SIZE) - { - UDD_ClearIN(); // Fifo is full, release this packet - UDD_WaitIN(); // Wait for new FIFO buffer to be ready - } - } - - return len; -} - -void UDD_Send8(uint32_t ep, uint8_t data ) -{ - uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); - - TRACE_UOTGHS(printf("=> UDD_Send8 : ul_send_fifo_ptr=%d data=0x%x\r\n", ul_send_fifo_ptr[ep], data);) - - ptr_dest[ul_send_fifo_ptr[ep]] = data; - ul_send_fifo_ptr[ep] += 1; -} - -uint8_t UDD_Recv8(uint32_t ep) -{ - uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); - uint8_t data = ptr_dest[ul_recv_fifo_ptr[ep]]; - - TRACE_UOTGHS(printf("=> UDD_Recv8 : ul_recv_fifo_ptr=%d\r\n", ul_recv_fifo_ptr[ep]);) - - ul_recv_fifo_ptr[ep] += 1; - return data; -} - -void UDD_Recv(uint32_t ep, uint8_t* data, uint32_t len) -{ - uint8_t *ptr_src = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); - uint8_t *ptr_dest = data; - uint32_t i; - - for (i = 0, ptr_src += ul_recv_fifo_ptr[ep]; i < len; ++i) - *ptr_dest++ = *ptr_src++; - - ul_recv_fifo_ptr[ep] += i; -} - -void UDD_Stall(void) -{ - UOTGHS->UOTGHS_DEVEPT = (UOTGHS_DEVEPT_EPEN0 << EP0); - UOTGHS->UOTGHS_DEVEPTIER[EP0] = UOTGHS_DEVEPTIER_STALLRQS; -} - - -uint32_t UDD_FifoByteCount(uint32_t ep) -{ - return ((UOTGHS->UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_BYCT_Msk) >> UOTGHS_DEVEPTISR_BYCT_Pos); -} - -void UDD_ReleaseRX(uint32_t ep) -{ - TRACE_UOTGHS(puts("=> UDD_ReleaseRX\r\n");) - UOTGHS->UOTGHS_DEVEPTICR[ep] = (UOTGHS_DEVEPTICR_NAKOUTIC | UOTGHS_DEVEPTICR_RXOUTIC); - UOTGHS->UOTGHS_DEVEPTIDR[ep] = UOTGHS_DEVEPTIDR_FIFOCONC; - ul_recv_fifo_ptr[ep] = 0; -} - -void UDD_ReleaseTX(uint32_t ep) -{ - TRACE_UOTGHS(printf("=> UDD_ReleaseTX ep=%d\r\n", ep);) - UOTGHS->UOTGHS_DEVEPTICR[ep] = (UOTGHS_DEVEPTICR_NAKINIC | UOTGHS_DEVEPTICR_RXOUTIC | UOTGHS_DEVEPTICR_TXINIC); - UOTGHS->UOTGHS_DEVEPTIDR[ep] = UOTGHS_DEVEPTIDR_FIFOCONC; - ul_send_fifo_ptr[ep] = 0; -} - -// Return true if the current bank is not full. -uint32_t UDD_ReadWriteAllowed(uint32_t ep) -{ - return (UOTGHS->UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_RWALL); -} - -void UDD_SetAddress(uint32_t addr) -{ - TRACE_UOTGHS(printf("=> UDD_SetAddress : setting address to %d\r\n", addr);) - - udd_configure_address(addr); - udd_enable_address(); -} - -uint32_t UDD_GetFrameNumber(void) -{ - return udd_frame_number(); -} - #endif /* SAM3XA_SERIES */ diff --git a/hardware/arduino/sam/system/libsam/source/uotghs_device.c b/hardware/arduino/sam/system/libsam/source/uotghs_device.c new file mode 100644 index 000000000..a589767f2 --- /dev/null +++ b/hardware/arduino/sam/system/libsam/source/uotghs_device.c @@ -0,0 +1,324 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "chip.h" +#include + +#if SAM3XA_SERIES + +//#define TRACE_UOTGHS(x) x +#define TRACE_UOTGHS(x) + +extern void (*gpf_isr)(void); + +static volatile uint32_t ul_send_fifo_ptr[MAX_ENDPOINTS]; +static volatile uint32_t ul_recv_fifo_ptr[MAX_ENDPOINTS]; + +void UDD_SetStack(void (*pf_isr)(void)) +{ + gpf_isr = pf_isr; +} + +uint32_t UDD_Init(void) +{ + uint32_t i; + + for (i = 0; i < MAX_ENDPOINTS; ++i) + { + ul_send_fifo_ptr[i] = 0; + ul_recv_fifo_ptr[i] = 0; + } + + // Enables the USB Clock + pmc_enable_periph_clk(ID_UOTGHS); + pmc_enable_upll_clock(); + pmc_switch_udpck_to_upllck(0); // div=0+1 + pmc_enable_udpck(); + + // Configure interrupts + NVIC_SetPriority((IRQn_Type) ID_UOTGHS, 0UL); + NVIC_EnableIRQ((IRQn_Type) ID_UOTGHS); + + // Always authorize asynchrone USB interrupts to exit from sleep mode + // for SAM3 USB wake up device except BACKUP mode + //pmc_set_fast_startup_input(PMC_FSMR_USBAL); + + // ID pin not used then force device mode + otg_disable_id_pin(); + otg_force_device_mode(); + + // Enable USB hardware + otg_disable_pad(); + otg_enable_pad(); + otg_enable(); + otg_unfreeze_clock(); + + // Check USB clock + //while (!Is_otg_clock_usable()) + // ; + + udd_low_speed_disable(); + udd_high_speed_disable(); + + //otg_ack_vbus_transition(); + // Force Vbus interrupt in case of Vbus always with a high level + // This is possible with a short timing between a Host mode stop/start. + /*if (Is_otg_vbus_high()) { + otg_raise_vbus_transition(); + } + otg_enable_vbus_interrupt();*/ + otg_freeze_clock(); + + return 0UL ; +} + +void UDD_Attach(void) +{ + irqflags_t flags = cpu_irq_save(); + + TRACE_UOTGHS(printf("=> UDD_Attach\r\n");) + + otg_unfreeze_clock(); + + // Check USB clock because the source can be a PLL + while (!Is_otg_clock_usable()); + + // Authorize attach if Vbus is present + udd_attach_device(); + + // Enable USB line events + udd_enable_reset_interrupt(); + //udd_enable_sof_interrupt(); + + cpu_irq_restore(flags); +} + +void UDD_Detach(void) +{ + TRACE_UOTGHS(printf("=> UDD_Detach\r\n");) + UOTGHS->UOTGHS_DEVCTRL |= UOTGHS_DEVCTRL_DETACH; +} + +void UDD_InitEP( uint32_t ul_ep_nb, uint32_t ul_ep_cfg ) +{ + ul_ep_nb = ul_ep_nb & 0xF; // EP range is 0..9, hence mask is 0xF. + + TRACE_UOTGHS(printf("=> UDD_InitEP : init EP %d\r\n", ul_ep_nb);) + + // Configure EP + UOTGHS->UOTGHS_DEVEPTCFG[ul_ep_nb] = ul_ep_cfg; + // Enable EP + udd_enable_endpoint(ul_ep_nb); + + if (!Is_udd_endpoint_configured(ul_ep_nb)) { + TRACE_UOTGHS(printf("=> UDD_InitEP : ERROR FAILED TO INIT EP %d\r\n", ul_ep_nb);) + } +} + + +void UDD_InitEndpoints(const uint32_t* eps_table, const uint32_t ul_eps_table_size) +{ + uint32_t ul_ep_nb ; + + for (ul_ep_nb = 1; ul_ep_nb < ul_eps_table_size; ul_ep_nb++) + { + // Configure EP + UOTGHS->UOTGHS_DEVEPTCFG[ul_ep_nb] = eps_table[ul_ep_nb]; + // Enable EP + udd_enable_endpoint(ul_ep_nb); + + if (!Is_udd_endpoint_configured(ul_ep_nb)) { + TRACE_UOTGHS(printf("=> UDD_InitEP : ERROR FAILED TO INIT EP %d\r\n", ul_ep_nb);) + } + } +} + +// Wait until ready to accept IN packet. +void UDD_WaitIN(void) +{ + while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_TXINI)) + ; +} + +void UDD_WaitOUT(void) +{ + while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXOUTI)) + ; +} + +// Send packet. +void UDD_ClearIN(void) +{ + TRACE_UOTGHS(printf("=> UDD_ClearIN: sent %d bytes\r\n", ul_send_fifo_ptr[EP0]);) + + UOTGHS->UOTGHS_DEVEPTICR[EP0] = UOTGHS_DEVEPTICR_TXINIC; + ul_send_fifo_ptr[EP0] = 0; +} + +void UDD_ClearOUT(void) +{ + UOTGHS->UOTGHS_DEVEPTICR[EP0] = UOTGHS_DEVEPTICR_RXOUTIC; + ul_recv_fifo_ptr[EP0] = 0; +} + +// Wait for IN FIFO to be ready to accept data or OUT FIFO to receive data. +// Return true if new IN FIFO buffer available. +uint32_t UDD_WaitForINOrOUT(void) +{ + while (!(UOTGHS->UOTGHS_DEVEPTISR[EP0] & (UOTGHS_DEVEPTISR_TXINI | UOTGHS_DEVEPTISR_RXOUTI))) + ; + return ((UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXOUTI) == 0); +} + +uint32_t UDD_ReceivedSetupInt(void) +{ + return UOTGHS->UOTGHS_DEVEPTISR[EP0] & UOTGHS_DEVEPTISR_RXSTPI; +} + +void UDD_ClearSetupInt(void) +{ + UOTGHS->UOTGHS_DEVEPTICR[EP0] = (UOTGHS_DEVEPTICR_RXSTPIC); +} + +uint32_t UDD_Send(uint32_t ep, const void* data, uint32_t len) +{ + const uint8_t *ptr_src = data; + uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); + uint32_t i; + + TRACE_UOTGHS(printf("=> UDD_Send (1): ep=%d ul_send_fifo_ptr=%d len=%d\r\n", ep, ul_send_fifo_ptr[ep], len);) + + if (ep == EP0) + { + if (ul_send_fifo_ptr[ep] + len > EP0_SIZE) + len = EP0_SIZE - ul_send_fifo_ptr[ep]; + } + else + { + if (ul_send_fifo_ptr[ep] + len > EPX_SIZE) + len = EPX_SIZE - ul_send_fifo_ptr[ep]; + } + + for (i = 0, ptr_dest += ul_send_fifo_ptr[ep]; i < len; ++i) + *ptr_dest++ = *ptr_src++; + + ul_send_fifo_ptr[ep] += i; + + + if (ep == EP0) + { + TRACE_UOTGHS(printf("=> UDD_Send (2): ep=%d ptr_dest=%d maxlen=%d\r\n", ep, ul_send_fifo_ptr[ep], EP0_SIZE);) + if (ul_send_fifo_ptr[ep] == EP0_SIZE) + { + UDD_ClearIN(); // Fifo is full, release this packet + UDD_WaitIN(); // Wait for new FIFO buffer to be ready + } + } + else + { + if (ul_send_fifo_ptr[ep] == EPX_SIZE) + { + UDD_ClearIN(); // Fifo is full, release this packet + UDD_WaitIN(); // Wait for new FIFO buffer to be ready + } + } + + return len; +} + +void UDD_Send8(uint32_t ep, uint8_t data ) +{ + uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); + + TRACE_UOTGHS(printf("=> UDD_Send8 : ul_send_fifo_ptr=%d data=0x%x\r\n", ul_send_fifo_ptr[ep], data);) + + ptr_dest[ul_send_fifo_ptr[ep]] = data; + ul_send_fifo_ptr[ep] += 1; +} + +uint8_t UDD_Recv8(uint32_t ep) +{ + uint8_t *ptr_dest = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); + uint8_t data = ptr_dest[ul_recv_fifo_ptr[ep]]; + + TRACE_UOTGHS(printf("=> UDD_Recv8 : ul_recv_fifo_ptr=%d\r\n", ul_recv_fifo_ptr[ep]);) + + ul_recv_fifo_ptr[ep] += 1; + return data; +} + +void UDD_Recv(uint32_t ep, uint8_t* data, uint32_t len) +{ + uint8_t *ptr_src = (uint8_t *) &udd_get_endpoint_fifo_access8(ep); + uint8_t *ptr_dest = data; + uint32_t i; + + for (i = 0, ptr_src += ul_recv_fifo_ptr[ep]; i < len; ++i) + *ptr_dest++ = *ptr_src++; + + ul_recv_fifo_ptr[ep] += i; +} + +void UDD_Stall(void) +{ + UOTGHS->UOTGHS_DEVEPT = (UOTGHS_DEVEPT_EPEN0 << EP0); + UOTGHS->UOTGHS_DEVEPTIER[EP0] = UOTGHS_DEVEPTIER_STALLRQS; +} + + +uint32_t UDD_FifoByteCount(uint32_t ep) +{ + return ((UOTGHS->UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_BYCT_Msk) >> UOTGHS_DEVEPTISR_BYCT_Pos); +} + +void UDD_ReleaseRX(uint32_t ep) +{ + TRACE_UOTGHS(puts("=> UDD_ReleaseRX\r\n");) + UOTGHS->UOTGHS_DEVEPTICR[ep] = (UOTGHS_DEVEPTICR_NAKOUTIC | UOTGHS_DEVEPTICR_RXOUTIC); + UOTGHS->UOTGHS_DEVEPTIDR[ep] = UOTGHS_DEVEPTIDR_FIFOCONC; + ul_recv_fifo_ptr[ep] = 0; +} + +void UDD_ReleaseTX(uint32_t ep) +{ + TRACE_UOTGHS(printf("=> UDD_ReleaseTX ep=%d\r\n", ep);) + UOTGHS->UOTGHS_DEVEPTICR[ep] = (UOTGHS_DEVEPTICR_NAKINIC | UOTGHS_DEVEPTICR_RXOUTIC | UOTGHS_DEVEPTICR_TXINIC); + UOTGHS->UOTGHS_DEVEPTIDR[ep] = UOTGHS_DEVEPTIDR_FIFOCONC; + ul_send_fifo_ptr[ep] = 0; +} + +// Return true if the current bank is not full. +uint32_t UDD_ReadWriteAllowed(uint32_t ep) +{ + return (UOTGHS->UOTGHS_DEVEPTISR[ep] & UOTGHS_DEVEPTISR_RWALL); +} + +void UDD_SetAddress(uint32_t addr) +{ + TRACE_UOTGHS(printf("=> UDD_SetAddress : setting address to %d\r\n", addr);) + + udd_configure_address(addr); + udd_enable_address(); +} + +uint32_t UDD_GetFrameNumber(void) +{ + return udd_frame_number(); +} + +#endif /* SAM3XA_SERIES */ diff --git a/hardware/arduino/sam/system/libsam/source/uotghs_host.c b/hardware/arduino/sam/system/libsam/source/uotghs_host.c new file mode 100644 index 000000000..ae5cdf176 --- /dev/null +++ b/hardware/arduino/sam/system/libsam/source/uotghs_host.c @@ -0,0 +1,404 @@ +/* + Copyright (c) 2012 Arduino. All right reserved. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "chip.h" +#include + +#if SAM3XA_SERIES + +#define TRACE_UOTGHS(x) x +//#define TRACE_UOTGHS(x) + +extern void (*gpf_isr)(void); + +static uhd_vbus_state_t uhd_state = UHD_STATE_NO_VBUS; + +static void UHD_ISR(void) +{ + // Manage dis/connection event + if (Is_uhd_disconnection() && Is_uhd_disconnection_int_enabled()) { + printf(">>> UHD_ISR : Disconnection INT\r\n"); + uhd_ack_disconnection(); + uhd_disable_disconnection_int(); + // Stop reset signal, in case of disconnection during reset + uhd_stop_reset(); + // Disable wakeup/resumes interrupts, + // in case of disconnection during suspend mode + //UOTGHS->UOTGHS_HSTIDR = UOTGHS_HSTIDR_HWUPIEC + // | UOTGHS_HSTIDR_RSMEDIEC + // | UOTGHS_HSTIDR_RXRSMIEC; + uhd_ack_connection(); + uhd_enable_connection_int(); + uhd_state = UHD_STATE_DISCONNECTED; + return; + } + if (Is_uhd_connection() && Is_uhd_connection_int_enabled()) { + printf(">>> UHD_ISR : Connection INT\r\n"); + uhd_ack_connection(); + uhd_disable_connection_int(); + uhd_ack_disconnection(); + uhd_enable_disconnection_int(); + //uhd_enable_sof(); + uhd_state = UHD_STATE_CONNECTED; + return; + } + + // Manage Vbus error + if (Is_uhd_vbus_error_interrupt()) + { + printf(">>> UHD_ISR : VBUS error INT\r\n"); + uhd_ack_vbus_error_interrupt(); + uhd_state = UHD_STATE_ERROR; + return; + } + + // Check USB clock ready after asynchronous interrupt + while (!Is_otg_clock_usable()) + ; + otg_unfreeze_clock(); + + // Manage Vbus state change + if (Is_otg_vbus_transition()) + { + otg_ack_vbus_transition(); + if (Is_otg_vbus_high()) + { + printf(">>> UHD_ISR : VBUS transition INT : UHD_STATE_DISCONNECT\r\n"); + uhd_state = UHD_STATE_DISCONNECTED; + } + else + { + printf(">>> UHD_ISR : VBUS transition INT : UHD_STATE_NO_VBUS\r\n"); + otg_freeze_clock(); + uhd_state = UHD_STATE_NO_VBUS; + } + printf(">>> UHD_ISR : VBUS transition INT : done.\r\n"); + return; + } + + // Other errors + if (Is_uhd_errors_interrupt()) + { + printf(">>> UHD_ISR : Other error INT\r\n"); + uhd_ack_errors_interrupt(); + return; + } +} + +void UHD_SetStack(void (*pf_isr)(void)) +{ + gpf_isr = pf_isr; +} + +void UHD_Init(void) +{ + irqflags_t flags; + + // To avoid USB interrupt before end of initialization + flags = cpu_irq_save(); + + // Setup USB Host interrupt callback + UHD_SetStack(&UHD_ISR); + + // Enables the USB Clock + pmc_enable_upll_clock(); + pmc_switch_udpck_to_upllck(0); // div=0+1 + pmc_enable_udpck(); + pmc_enable_periph_clk(ID_UOTGHS); + + // Always authorize asynchronous USB interrupts to exit of sleep mode + // For SAM3 USB wake up device except BACKUP mode + NVIC_SetPriority((IRQn_Type) ID_UOTGHS, 0); + NVIC_EnableIRQ((IRQn_Type) ID_UOTGHS); + + // ID pin not used then force host mode + otg_disable_id_pin(); + otg_force_host_mode(); + + // Signal is active low (because all SAM3X Pins are high after startup) + // Hence VBOF must be low after connection request to power up the remote device + uhd_set_vbof_active_low(); + + otg_enable_pad(); + otg_enable(); + + otg_unfreeze_clock(); + + // Check USB clock + while (!Is_otg_clock_usable()) + ; + + // Clear all interrupts that may have been set by a previous host mode + UOTGHS->UOTGHS_HSTICR = UOTGHS_HSTICR_DCONNIC | UOTGHS_HSTICR_DDISCIC + | UOTGHS_HSTICR_HSOFIC | UOTGHS_HSTICR_HWUPIC + | UOTGHS_HSTICR_RSMEDIC | UOTGHS_HSTICR_RSTIC + | UOTGHS_HSTICR_RXRSMIC; + + otg_ack_vbus_transition(); + + // Enable Vbus change and error interrupts + // Disable automatic Vbus control after Vbus error + Set_bits(UOTGHS->UOTGHS_CTRL, + UOTGHS_CTRL_VBUSHWC | UOTGHS_CTRL_VBUSTE | UOTGHS_CTRL_VBERRE); + + uhd_enable_vbus(); + + // Force Vbus interrupt when Vbus is always high + // This is possible due to a short timing between a Host mode stop/start. + if (Is_otg_vbus_high()) + { + otg_raise_vbus_transition(); + } + + // Enable main control interrupt + // Connection, SOF and reset + UOTGHS->UOTGHS_HSTIER = UOTGHS_HSTICR_DCONNIC;// | UOTGHS_HSTICR_RSTIC;// | UOTGHS_HSTICR_HSOFIC; + + otg_freeze_clock(); + + uhd_state = UHD_STATE_NO_VBUS; + + cpu_irq_restore(flags); +} + +void UHD_BusReset(void) +{ + uhd_start_reset(); +} + +uhd_vbus_state_t UHD_GetVBUSState(void) +{ + return uhd_state; +} + +/*uhd_speed_t uhd_get_speed(void) +{ + switch (uhd_get_speed_mode()) + { + case UOTGHS_SR_SPEED_HIGH_SPEED: + return UHD_SPEED_HIGH; + + case UOTGHS_SR_SPEED_FULL_SPEED: + return UHD_SPEED_FULL; + + case UOTGHS_SR_SPEED_LOW_SPEED: + return UHD_SPEED_LOW; + + default: + return UHD_SPEED_LOW; + } +}*/ + +/** + * \brief Allocate FIFO for pipe 0. + * + * \param ul_add Address of remote device for pipe 0. + * \param ul_ep_size Actual size of the FIFO in bytes. + * + * \retval 0 success. + * \retval 1 error. + */ +uint32_t UHD_EP0_Alloc(uint32_t ul_add, uint32_t ul_ep_size) +{ + if (ul_ep_size < 8) + { + TRACE_UOTGHS(printf("/!\\ UHD_EP0_Alloc : incorrect pipe size!\r\n");) + return 1; + } + + if (Is_uhd_pipe_enabled(0)) + { + // Pipe is already allocated + return 0; + } + + uhd_enable_pipe(0); + uhd_configure_pipe(0, // Pipe 0 + 0, // No frequency + 0, // Enpoint 0 + UOTGHS_HSTPIPCFG_PTYPE_CTRL, + UOTGHS_HSTPIPCFG_PTOKEN_SETUP, + ul_ep_size, + UOTGHS_HSTPIPCFG_PBK_1_BANK, 0); + + uhd_allocate_memory(0); + + if (!Is_uhd_pipe_configured(0)) + { + TRACE_UOTGHS(printf("/!\\ UHD_EP0_Alloc : incorrect pipe settings!\r\n");) + uhd_disable_pipe(0); + return 1; + } + + uhd_configure_address(0, ul_add); + + // Always enable stall and error interrupts of control endpoint + /*uhd_enable_stall_interrupt(0); + uhd_enable_pipe_error_interrupt(0); + uhd_enable_pipe_interrupt(0);*/ + return 0; +} + +void UHD_EP_Free(uint32_t add, uint32_t endp) +{ + // Search endpoint(s) in all pipes + for (uint8_t pipe = 0; pipe < UOTGHS_EPT_NUM; pipe++) + { + if (!Is_uhd_pipe_enabled(pipe)) + { + continue; + } + + if (add != uhd_get_configured_address(pipe)) + { + continue; + } + + /* if (endp != 0xFF) + { + // Disable specific endpoint number + if (endp != uhd_get_pipe_endpoint_address(pipe)) + { + continue; // Mismatch + } + } +*/ + // Unalloc pipe + uhd_disable_pipe(pipe); + uhd_unallocate_memory(pipe); + uhd_reset_pipe(pipe); + } +} + +uint32_t UHD_EP_Read(uint32_t ul_ep, uint32_t ul_size, uint8_t* data) +{ + uint8_t *ptr_ep_data = 0; + uint8_t nb_byte_received = 0; + uint32_t ul_nb_trans = 0; + + // Get information to read data + nb_byte_received = uhd_byte_count(ul_ep); + + ptr_ep_data = (uint8_t *) & uhd_get_pipe_fifo_access(ul_ep, 8); + + // Copy data from pipe to payload buffer + while (ul_size && nb_byte_received) { + *data++ = *ptr_ep_data++; + ul_nb_trans++; + ul_size--; + nb_byte_received--; + } + + return ul_nb_trans; +} + +void UHD_EP_Write(uint32_t ul_ep, uint32_t ul_size, uint8_t* data) +{ + volatile uint8_t *ptr_ep_data = 0; + uint32_t i = 0; + + // Check pipe + if (!Is_uhd_pipe_enabled(ul_ep)) + { + // Endpoint not valid + TRACE_UOTGHS(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");) + return; + } + + ptr_ep_data = (volatile uint8_t *)&uhd_get_pipe_fifo_access(ul_ep, 8); + for (i = 0; i < ul_size; ++i) + *ptr_ep_data++ = *data++; +} + +void UHD_EP_Send(uint32_t ul_ep, uint32_t ul_token_type) +{ + // Check pipe + if (!Is_uhd_pipe_enabled(ul_ep)) + { + // Endpoint not valid + TRACE_UOTGHS(printf("/!\\ UHD_EP_Send : pipe is not enabled!\r\n");) + return; + } + + // Set token type + uhd_configure_pipe_token(ul_ep, ul_token_type); + + // Clear interrupt flags + uhd_ack_setup_ready(ul_ep); + uhd_ack_in_received(ul_ep); + uhd_ack_out_ready(ul_ep); + uhd_ack_short_packet(ul_ep); + + // Send actual packet + uhd_ack_fifocon(ul_ep); + uhd_unfreeze_pipe(ul_ep); +} + +/** + * \brief Check is transfer is complete. + * + * \param ul_add Address of remote device for pipe 0. + * \param ul_ep_size Actual size of the FIFO in bytes. + * + * \retval 0 transfer is not complete. + * \retval 1 transfer is complete. + */ +uint32_t UHD_EP_Is_Transfer_Complete(uint32_t ul_ep, uint32_t ul_token_type) +{ + // Check for transfer completion depending on token type + switch (ul_token_type) + { + case UOTGHS_HSTPIPCFG_PTOKEN_SETUP: + if (Is_uhd_setup_ready(ul_ep)) + { + uhd_freeze_pipe(ul_ep); + uhd_ack_setup_ready(ul_ep); + return 1; + } + + case UOTGHS_HSTPIPCFG_PTOKEN_IN: + if (Is_uhd_in_received(ul_ep)) + { + // In case of low USB speed and with a high CPU frequency, + // a ACK from host can be always running on USB line + // then wait end of ACK on IN pipe. + while(!Is_uhd_pipe_frozen(ul_ep)) + ; + + // IN packet received + uhd_ack_in_received(ul_ep); + + return 1; + } + + case UOTGHS_HSTPIPCFG_PTOKEN_OUT: + if (Is_uhd_out_ready(ul_ep)) + { + // OUT packet sent + uhd_freeze_pipe(ul_ep); + uhd_ack_out_ready(ul_ep); + + return 1; + } + } + + // Nothing to report + return 0; +} + +#endif /* SAM3XA_SERIES */ diff --git a/hardware/arduino/sam/variants/arduino_due_x/build_gcc/libvariant_arduino_due_x.mk b/hardware/arduino/sam/variants/arduino_due_x/build_gcc/libvariant_arduino_due_x.mk index cd836513e..3f8b1b760 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/build_gcc/libvariant_arduino_due_x.mk +++ b/hardware/arduino/sam/variants/arduino_due_x/build_gcc/libvariant_arduino_due_x.mk @@ -58,6 +58,7 @@ INCLUDES += -I$(ARDUINO_PATH) INCLUDES += -I$(ARDUINO_PATH)/USB INCLUDES += -I$(SYSTEM_PATH) INCLUDES += -I$(SYSTEM_PATH)/libsam +INCLUDES += -I$(SYSTEM_PATH)/USBHost INCLUDES += -I$(VARIANT_BASE_PATH) INCLUDES += -I$(VARIANT_PATH) INCLUDES += -I$(CMSIS_ARM_PATH) diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a index 00960209f107115c1cdfe6cccce3e8d88424e8d7..baaae2e54c551fff6ff155b143d0081ec8bfe236 100644 GIT binary patch delta 10487 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 QMt;eOkInx39c+d9U$OxJGynhq diff --git a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt index 7447be8ba..0742e34b0 100644 --- a/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt +++ b/hardware/arduino/sam/variants/arduino_due_x/libsam_sam3x8e_gcc_rel.a.txt @@ -99,14 +99,14 @@ pwmc.o: 00000000 T PWMC_SetSyncChannelUpdateUnlock 00000000 T PWMC_WriteBuffer U __assert_func -00000000 r __func__.3192 -00000000 r __func__.3203 -00000000 r __func__.3218 -00000000 r __func__.3229 -00000000 r __func__.3240 -00000000 r __func__.3247 -00000000 r __func__.3331 -00000000 r __func__.3337 +00000000 r __func__.3227 +00000000 r __func__.3238 +00000000 r __func__.3253 +00000000 r __func__.3264 +00000000 r __func__.3275 +00000000 r __func__.3282 +00000000 r __func__.3366 +00000000 r __func__.3372 rtc.o: 00000000 T RTC_ClearSCCR @@ -122,9 +122,9 @@ rtc.o: 00000000 T RTC_SetTime 00000000 T RTC_SetTimeAlarm U __assert_func -00000000 r __func__.3189 -00000000 r __func__.3198 -00000000 r __func__.3203 +00000000 r __func__.3224 +00000000 r __func__.3233 +00000000 r __func__.3238 rtt.o: 00000000 T RTT_EnableIT @@ -133,8 +133,8 @@ rtt.o: 00000000 T RTT_SetAlarm 00000000 T RTT_SetPrescaler U __assert_func -00000000 r __func__.3196 -00000000 r __func__.3204 +00000000 r __func__.3231 +00000000 r __func__.3239 spi.o: 00000000 T SPI_Configure @@ -155,9 +155,9 @@ tc.o: 00000000 T TC_Start 00000000 T TC_Stop U __assert_func -00000000 r __func__.3191 -00000000 r __func__.3197 -00000000 r __func__.3203 +00000000 r __func__.3226 +00000000 r __func__.3232 +00000000 r __func__.3238 timetick.o: 00000000 T GetTickCount @@ -184,18 +184,18 @@ twi.o: 00000000 T TWI_TransferComplete 00000000 T TWI_WriteByte U __assert_func -00000000 r __func__.3556 -00000000 r __func__.3571 -00000000 r __func__.3575 -00000000 r __func__.3582 -00000000 r __func__.3586 00000000 r __func__.3591 -00000000 r __func__.3599 -00000000 r __func__.3613 -00000000 r __func__.3618 -00000000 r __func__.3622 -00000000 r __func__.3627 -00000000 r __func__.3631 +00000000 r __func__.3606 +00000000 r __func__.3610 +00000000 r __func__.3617 +00000000 r __func__.3621 +00000000 r __func__.3626 +00000000 r __func__.3634 +00000000 r __func__.3648 +00000000 r __func__.3653 +00000000 r __func__.3657 +00000000 r __func__.3662 +00000000 r __func__.3666 usart.o: 00000000 T USART_Configure @@ -214,7 +214,7 @@ usart.o: 00000000 T USART_Write 00000000 T USART_WriteBuffer U __assert_func -00000000 r __func__.3477 +00000000 r __func__.3512 wdt.o: 00000000 T WDT_Disable @@ -343,6 +343,13 @@ udp.o: udphs.o: uotghs.o: +00000000 T UOTGHS_Handler +00000000 B gpf_isr + +interrupt_sam_nvic.o: +00000000 D g_interrupt_enabled + +uotghs_device.o: 00000000 T UDD_Attach 00000000 T UDD_ClearIN 00000000 T UDD_ClearOUT @@ -367,9 +374,8 @@ uotghs.o: 00000000 T UDD_WaitForINOrOUT 00000000 T UDD_WaitIN 00000000 T UDD_WaitOUT -00000000 T UOTGHS_Handler U g_interrupt_enabled -00000000 b gpf_isr + U gpf_isr U pmc_enable_periph_clk U pmc_enable_udpck U pmc_enable_upll_clock @@ -377,5 +383,23 @@ uotghs.o: 00000000 b ul_recv_fifo_ptr 00000000 b ul_send_fifo_ptr -interrupt_sam_nvic.o: -00000000 D g_interrupt_enabled +uotghs_host.o: +00000000 T UHD_BusReset +00000000 T UHD_EP0_Alloc +00000000 T UHD_EP_Free +00000000 T UHD_EP_Is_Transfer_Complete +00000000 T UHD_EP_Read +00000000 T UHD_EP_Send +00000000 T UHD_EP_Write +00000000 T UHD_GetVBUSState +00000000 t UHD_ISR +00000000 T UHD_Init +00000000 T UHD_SetStack + U g_interrupt_enabled + U gpf_isr + U iprintf + U pmc_enable_periph_clk + U pmc_enable_udpck + U pmc_enable_upll_clock + U pmc_switch_udpck_to_upllck +00000000 b uhd_state